/* SMB2SBL */

/* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */

/* Scans SMB message base for messages to "SBL" and adds them to the SBL    */
/* database. */

#define  uint unsigned int

#include <dos.h>
#include "smblib.h"
#include "sbldefs.h"

extern int	daylight=0;
extern long timezone=0L;
smb_t		smb;

char *loadmsgtxt(smbmsg_t msg, int tails)
{
	char	*buf=NULL,*lzhbuf;
	ushort	xlat;
	int 	i,lzh;
	long	l=0,lzhlen,length;

for(i=0;i<msg.hdr.total_dfields;i++) {
	if(!(msg.dfield[i].type==TEXT_BODY
		|| (tails && msg.dfield[i].type==TEXT_TAIL)))
		continue;
	fseek(smb.sdt_fp,msg.hdr.offset+msg.dfield[i].offset
		,SEEK_SET);
	fread(&xlat,2,1,smb.sdt_fp);
	lzh=0;
	if(xlat==XLAT_LZH) {
		lzh=1;
		fread(&xlat,2,1,smb.sdt_fp); }
	if(xlat!=XLAT_NONE) 		/* no other translations supported */
		continue;

	length=msg.dfield[i].length-2;
	if(lzh) {
		length-=2;
		if((lzhbuf=MALLOC(length))==NULL) {
			printf("ERR_ALLOC lzhbuf of %lu\n",length);
			return(buf); }
		fread(lzhbuf,1,length,smb.sdt_fp);
		lzhlen=*(long *)lzhbuf;
		if((buf=REALLOC(buf,l+lzhlen+3))==NULL) {
			FREE(lzhbuf);
			printf("ERR_ALLOC lzhoutbuf of %l\n",l+lzhlen+1);
			return(buf); }
		lzh_decode(lzhbuf,length,buf+l);
		FREE(lzhbuf);
		l+=lzhlen; }
	else {
		if((buf=REALLOC(buf,l+msg.dfield[i].length+3))==NULL) {
			printf("ERR_ALLOC of %lu\n",l+msg.dfield[i].length+1);
			return(buf); }
		l+=fread(buf+l,1,length,smb.sdt_fp); }
	buf[l]=CR;
	l++;
	buf[l]=LF;
	l++;
	buf[l]=0; }
return(buf);
}


/***************************************************************************/
/* Truncates white-space chars off end of 'str' and terminates at first CR  */
/****************************************************************************/
void truncsp(char *str)
{
	char c;

str[strcspn(str,"\r")]=0;
c=strlen(str);
while(c && (uchar)str[c-1]<=SP) c--;
str[c]=0;
}

/****************************************************************************/
/* Checks the disk drive for the existence of a file. Returns 1 if it       */
/* exists, 0 if it doesn't.                                                 */
/****************************************************************************/
char fexist(char *filespec)
{
    struct ffblk f;

if(findfirst(filespec,&f,0)==0)
    return(1);
return(0);
}

/****************************************************************************/
/* Returns the length of the file in 'filespec'                             */
/****************************************************************************/
long flength(char *filespec)
{
    struct ffblk f;

if(findfirst(filespec,&f,0)==0)
    return(f.ff_fsize);
return(-1L);
}


/****************************************************************************/
/* Converts a date string in format MM/DD/YY into unix time format			*/
/****************************************************************************/
time_t dstrtounix(char *str)
{
	struct date date;
	struct time curtime;

if(!strncmp(str,"00/00/00",8))
	return(0);
curtime.ti_hour=curtime.ti_min=curtime.ti_sec=0;
if(str[6]<7)
	date.da_year=2000+((str[6]&0xf)*10)+(str[7]&0xf);
else
	date.da_year=1900+((str[6]&0xf)*10)+(str[7]&0xf);
date.da_mon=((str[0]&0xf)*10)+(str[1]&0xf);
date.da_day=((str[3]&0xf)*10)+(str[4]&0xf);
return(dostounix(&date,&curtime));
}

/****************************************************************************/
/* Updates 16-bit "rcrc" with character 'ch'                                */
/****************************************************************************/
void ucrc16(uchar ch, ushort *rcrc) {
	ushort i, cy;
    uchar nch=ch;
 
for (i=0; i<8; i++) {
    cy=*rcrc & 0x8000;
    *rcrc<<=1;
    if (nch & 0x80) *rcrc |= 1;
    nch<<=1;
    if (cy) *rcrc ^= 0x1021; }
}

/****************************************************************************/
/* Returns 16-crc of string (not counting terminating NULL) 				*/
/****************************************************************************/
ushort crc16(char *str)
{
	int 	i=0;
	ushort	crc=0;

ucrc16(0,&crc);
while(str[i])
	ucrc16(str[i++],&crc);
ucrc16(0,&crc);
ucrc16(0,&crc);
return(crc);
}

time_t checktime()
{
	struct tm tm;

memset(&tm,0,sizeof(tm));
tm.tm_year=94;
tm.tm_mday=1;
return(mktime(&tm)^0x2D24BD00L);
}

int main(int argc, char **argv)
{
	uchar	str[128],*buf,*p;
	int 	i,file,sysop,number,network,terminal,desc;
	ulong	l,last,high;
	ushort	sbl;
	bbs_t	bbs;
	smbmsg_t msg;
	FILE	*stream;

fprintf(stderr,"\nSMB2SBL v2.00 - Updates SBL via SMB - Developed 1994-1997 "
	"Rob Swindell\n\n");

if(checktime()) {
    printf("Time problem!\n");
    return(-1); }

if(argc<3) {
	fprintf(stderr,"usage: smb2sbl <smb_file> <sbl.dab>\n\n");
	fprintf(stderr,"ex: smb2sbl c:\\sbbs\\data\\subs\\syncdata "
		"c:\\sbbs\\xtrn\\sbl\\sbl.dab \n");
	return(1); }

strcpy(smb.file,argv[1]);
strupr(smb.file);

strcpy(str,argv[2]);
strupr(str);
if((file=open(str,O_RDWR|O_BINARY|O_DENYNONE|O_CREAT,S_IWRITE|S_IREAD))==-1) {
	printf("error opening %s\n",str);
	return(1); }
if((stream=fdopen(file,"r+b"))==NULL) {
	printf("error fdopening %s\n",str);
	return(1); }
setvbuf(stream,NULL,_IOFBF,4096);

sprintf(str,"%s.SBL",smb.file);
if((file=open(str,O_RDWR|O_BINARY|O_CREAT,S_IWRITE|S_IREAD))==-1) {
	printf("error opening %s\n",str);
	return(1); }
if(read(file,&last,4)!=4)
	last=0;
high=last;

sprintf(str,"%s.SHD",smb.file);
if(!fexist(str)) {
	printf("%s doesn't exist\n",smb.file);
	return(0); }
sprintf(str,"%s.SID",smb.file);
if(!flength(str)) {
	printf("%s is empty\n",smb.file);
    return(0); }
fprintf(stderr,"Opening %s\n",smb.file);
smb.retry_time=30;
if((i=smb_open(&smb))!=0) {
	printf("smb_open returned %d\n",i);
	return(1); }

sbl=crc16("sbl");

if((i=smb_locksmbhdr(&smb))!=0) {				/* Be sure noone deletes or */
	printf("Error locking %d\n",i);             /* adds while we're reading */
	return(1); }

while(!feof(smb.sid_fp)) {
	if(!fread(&msg.idx,sizeof(idxrec_t),1,smb.sid_fp))
        break;
	fprintf(stderr,"\r%lu  ",msg.idx.number);
	if(msg.idx.number<=last || msg.idx.to!=sbl)
		continue;
	high=msg.idx.number;
	if((i=smb_lockmsghdr(&smb,&msg))!=0) {
		printf("\7Error %d locking msg #%lu\n",i,msg.idx.number);
		continue; }
	if((i=smb_getmsghdr(&smb,&msg))!=0) {
		smb_unlockmsghdr(&smb,&msg);
		printf("\7Error %d reading msg #%lu\n",i,msg.idx.number);
		continue; }
	smb_unlockmsghdr(&smb,&msg);
	if(!msg.from_net.type) {		/* ignore local message */
		smb_freemsgmem(&msg);
        continue; }

	printf("\nMessage #%lu by %s on %.24s\n"
		,msg.hdr.number,msg.from,ctime(&(time_t)msg.hdr.when_written.time));

	truncsp(msg.subj);
	if(!msg.subj[0]) {
		smb_freemsgmem(&msg);
		continue; }
	fprintf(stderr,"Searching for %s...",msg.subj);
	fseek(stream,0L,SEEK_SET);
	memset(&bbs,0,sizeof(bbs_t));
	while(1) {
		l=ftell(stream);
		if(!fread(&bbs,sizeof(bbs_t),1,stream)) {
			memset(&bbs,0,sizeof(bbs_t));
			break; }
		if(msg.subj[0] && !stricmp(bbs.name,msg.subj)) {
			fseek(stream,l,SEEK_SET);
			break; } }
	fprintf(stderr,"\n");
	if(bbs.name[0] && strnicmp(bbs.user,msg.from,25)) {
		printf("%s didn't create the entry for %s\n",msg.from,msg.subj);
		smb_freemsgmem(&msg);
		continue; }
	if(!bbs.name[0]) {
		fprintf(stderr,"Searching for unused record...");
		fseek(stream,0L,SEEK_SET);
		while(1) {					/* Find deleted record */
			l=ftell(stream);
			if(!fread(&bbs,sizeof(bbs_t),1,stream))
				break;
			if(!bbs.name[0]) {
				fseek(stream,l,SEEK_SET);
				break; } }
		fprintf(stderr,"\n");
		memset(&bbs,0,sizeof(bbs_t));
		bbs.created=time(NULL);
		if(!bbs.birth)
			bbs.birth=bbs.created;
		sprintf(bbs.user,"%-.25s",msg.from); }
	sprintf(bbs.name,"%-.25s",msg.subj);
	bbs.updated=time(NULL);
	bbs.misc|=FROM_SMB;
	sprintf(bbs.userupdated,"%-.25s",msg.from);
	buf=loadmsgtxt(msg,0);
	sysop=number=network=terminal=desc=0;
	l=0;
	while(buf[l]) {
		while(buf[l] && buf[l]<=SP) 		/* Find first text on line */
			l++;
		if(!strnicmp(buf+l,"NAME:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.name,"%-.25s",buf+l);
			truncsp(bbs.name); }
		if(!strnicmp(buf+l,"BIRTH:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.birth=dstrtounix(buf+l); }
		if(!strnicmp(buf+l,"SOFTWARE:",9)) {
			l+=9;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.software,"%-.15s",buf+l);
			truncsp(bbs.software); }
		if(!strnicmp(buf+l,"SYSOP:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.sysop[sysop],"%-.25s",buf+l);
			truncsp(bbs.sysop[sysop]);
			if(sysop<MAX_SYSOPS-1)
				sysop++; }
		if(!strnicmp(buf+l,"NUMBER:",7)) {
			l+=7;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.number[number].number,"%-.12s",buf+l);
			truncsp(bbs.number[number].number);
			if(number<MAX_NUMBERS-1)
				number++; }
		if(!strnicmp(buf+l,"MODEM:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			i=number;
			if(i) i--;
			sprintf(bbs.number[i].modem,"%-.15s",buf+l);
			truncsp(bbs.number[i].modem); }
		if(!strnicmp(buf+l,"LOCATION:",9)) {
			l+=9;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			i=number;
            if(i) i--;
			sprintf(bbs.number[i].location,"%-.30s",buf+l);
			truncsp(bbs.number[i].location); }
		if(!strnicmp(buf+l,"MINRATE:",8)) {
			l+=8;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			i=number;
            if(i) i--;
			bbs.number[i].min_rate=atoi(buf+l); }
		if(!strnicmp(buf+l,"MAXRATE:",8)) {
			l+=8;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			i=number;
            if(i) i--;
			bbs.number[i].max_rate=atoi(buf+l); }
		if(!strnicmp(buf+l,"NETWORK:",8)) {
			l+=8;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.network[network],"%-.15s",buf+l);
			truncsp(bbs.network[network]);
			if(network<MAX_NETS-1)
				network++; }
		if(!strnicmp(buf+l,"ADDRESS:",8)) {
			l+=8;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			i=network;
			if(i) i--;
			sprintf(bbs.address[i],"%-.25s",buf+l);
			truncsp(bbs.address[i]); }
		if(!strnicmp(buf+l,"TERMINAL:",9)) {
			l+=9;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.terminal[terminal],"%-.15s",buf+l);
			truncsp(bbs.terminal[terminal]);
			if(terminal<MAX_TERMS-1)
				terminal++; }
		if(!strnicmp(buf+l,"DESC:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			sprintf(bbs.desc[desc],"%-.50s",buf+l);
			truncsp(bbs.desc[desc]);
			if(desc<4)
				desc++; }

		if(!strnicmp(buf+l,"MEGS:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.megs=atol(buf+l); }
		if(!strnicmp(buf+l,"MSGS:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.msgs=atol(buf+l); }
		if(!strnicmp(buf+l,"FILES:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.files=atol(buf+l); }
		if(!strnicmp(buf+l,"NODES:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.nodes=atoi(buf+l); }
		if(!strnicmp(buf+l,"USERS:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.users=atoi(buf+l); }
		if(!strnicmp(buf+l,"SUBS:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.subs=atoi(buf+l); }
		if(!strnicmp(buf+l,"DIRS:",5)) {
			l+=5;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.dirs=atoi(buf+l); }
		if(!strnicmp(buf+l,"XTRNS:",6)) {
			l+=6;
			while(buf[l] && buf[l]<=SP && buf[l]!=CR)
				l++;
			bbs.xtrns=atoi(buf+l); }
		while(buf[l] && buf[l]>=SP) {	 /* Go to end of line */
			putchar(buf[l]);
			l++; }
		printf("\n"); }
	if(bbs.total_sysops<sysop)
		bbs.total_sysops=sysop;
	if(bbs.total_networks<network)
		bbs.total_networks=network;
	if(bbs.total_terminals<terminal)
		bbs.total_terminals=terminal;
	if(bbs.total_numbers<number)
		bbs.total_numbers=number;
	fwrite(&bbs,sizeof(bbs_t),1,stream);
	FREE(buf);
	smb_freemsgmem(&msg);
	}
lseek(file,0L,SEEK_SET);
write(file,&high,4);
close(file);
return(0);
}

