File:  [Synchronet] / sbbs / sbbs2 / fido / sbbsfido.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:39:17 2018 UTC (8 years, 3 months ago) by root
Branches: digitaldynamics, MAIN
CVS tags: v3_00c, HEAD
3.00c Win32

/* SBBSFIDO.C */

/* Synchronet FidoNet EchoMail Scanning/Tossing and NetMail Tossing Utility */

#define VER "2.24"

#include "sbbs.h"
#include "crc32.h"
#include "lzh.h"
#include "post.h"
#include "scfglib.h"

#define IMPORT_NETMAIL	(1L<<0)
#define IMPORT_ECHOMAIL (1L<<1)
#define EXPORT_ECHOMAIL (1L<<2)
#define DELETE_NETMAIL	(1L<<3)
#define DELETE_ECHOMAIL (1L<<4)
#define IGNORE_POINT	(1L<<5)
#define IGNORE_ZONE 	(1L<<6)
#define IGNORE_MSGPTRS	(1L<<7)
#define UPDATE_MSGPTRS	(1L<<8)
#define LEAVE_MSGPTRS	(1L<<9)
#define KILL_ECHOMAIL	(1L<<10)
#define ASCII_ONLY		(1L<<11)
#define LOGFILE 		(1L<<12)
#define REPORT			(1L<<13)
#define EXPORT_ALL		(1L<<14)
#define PURGE_ECHOMAIL	(1L<<15)
#define UNKNOWN_NETMAIL (1L<<16)
#define IGNORE_ADDRESS	(1L<<17)
#define IMPORT_LOCAL	(1L<<18)
#define IMPORT_NEW_ONLY (1L<<19)
#define DONT_SET_RECV	(1L<<20)
#define IGNORE_RECV 	(1L<<21)
#define CONVERT_TEAR	(1L<<22)
#define IMPORT_PRIVATE	(1L<<23)
#define LOCAL_NETMAIL	(1L<<24)
#define NOTIFY_RECEIPT	(1L<<25)

char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
            ,"Jul","Aug","Sep","Oct","Nov","Dec"};

long misc=(IMPORT_NETMAIL|IMPORT_ECHOMAIL|EXPORT_ECHOMAIL
			|DELETE_NETMAIL|DELETE_ECHOMAIL|KILL_ECHOMAIL);
char tmp[256];

FILE *fidologfile=NULL;
#ifdef __TURBOC__
	unsigned _stklen=20000;
#endif
int startmsg=1;
int nodefile;

#ifdef __WATCOMC__
	#define O_DENYNONE SH_DENYNO
#endif

long lputs(char FAR16 *str)
{
    char tmp[256];
    int i,j,k;

if(misc&LOGFILE && fidologfile!=NULL)
    fputs(str,fidologfile);
j=strlen(str);
for(i=k=0;i<j;i++)      /* remove CRs */
    if(str[i]==CR && str[i+1]==LF)
        continue;
    else
        tmp[k++]=str[i];
tmp[k]=0;
return(fputs(tmp,stdout));
}

/******************************************/
/* CRC-16 routines required for SMB index */
/******************************************/

/****************************************************************************/
/* 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);
}

/****************************************************************************/
/* Returns 32-crc of string (not counting terminating NULL) 				*/
/****************************************************************************/
ulong crc32(char *str)
{
	int i=0;
	ulong crc=0xffffffffUL;

	while(str[i])
		crc=ucrc32(str[i++],crc);
	crc=~crc;
	return(crc);
}



/****************************************************************************/
/* Performs printf() through local assembly routines                        */
/* Called from everywhere                                                   */
/****************************************************************************/
int lprintf(char *fmat, ...)
{
	va_list argptr;
	char sbuf[256];
	int chcount;

va_start(argptr,fmat);
chcount=vsprintf(sbuf,fmat,argptr);
va_end(argptr);
lputs(sbuf);
return(chcount);
}

/****************************************************************************/
/* Reads the data for node number 'number' into the structure 'node'        */
/* from NODE.DAB															*/
/* if lockit is non-zero, locks this node's record. putnodedat() unlocks it */
/****************************************************************************/
void getnodedat(uint number, node_t *node, char lockit)
{
	char str[256];
	int count=0;

number--;	/* make zero based */
while(count<LOOP_NODEDAB) {
	lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
	if(lockit
		&& lock(nodefile,(long)number*sizeof(node_t),sizeof(node_t))==-1) {
		count++;
		continue; }
	if(read(nodefile,node,sizeof(node_t))==sizeof(node_t))
		break;
	count++; }
if(count==LOOP_NODEDAB)
	lprintf("\7Error unlocking and reading NODE.DAB\r\n");
}

/****************************************************************************/
/* Write the data from the structure 'node' into NODE.DAB  					*/
/* getnodedat(num,&node,1); must have been called before calling this func  */
/*          NOTE: ------^   the indicates the node record has been locked   */
/****************************************************************************/
void putnodedat(uint number, node_t node)
{
	char str[256];
	int count;

number--;	/* make zero based */
lseek(nodefile,(long)number*sizeof(node_t),SEEK_SET);
if(write(nodefile,&node,sizeof(node_t))!=sizeof(node_t)) {
	unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
	lprintf("\7Error writing NODE.DAB for node %u\r\n",number+1);
	return; }
unlock(nodefile,(long)number*sizeof(node_t),sizeof(node_t));
}


/****************************************************************************/
/* Creates a short message for 'usernumber' than contains 'strin'			*/
/****************************************************************************/
void putsmsg(int usernumber, char *strin)
{
	char str[256];
	int file,i;
    node_t node;

sprintf(str,"%sMSGS\\%4.4u.MSG",data_dir,usernumber);
if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1) {
	lprintf("\7Error opening/creating %s for creat/append access\r\n",str);
	return; }
i=strlen(strin);
if(write(file,strin,i)!=i) {
	close(file);
	lprintf("\7Error writing %u bytes to %s\r\n",i,str);
	return; }
close(file);
for(i=1;i<=sys_nodes;i++) {		/* flag node if user on that msg waiting */
	getnodedat(i,&node,0);
	if(node.useron==usernumber
		&& (node.status==NODE_INUSE || node.status==NODE_QUIET)
		&& !(node.misc&NODE_MSGW)) {
		getnodedat(i,&node,1);
		node.misc|=NODE_MSGW;
        putnodedat(i,node); } }
}


/****************************************************************************/
/* Converts an ASCII Hex string into an ulong                       */
/****************************************************************************/
ulong ahtoul(char *str)
{
	ulong l,val=0;

while((l=(*str++)|0x20)!=0x20)
	val=(l&0xf)+(l>>6&1)*9+val*16;
return(val);
}

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

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

/****************************************************************************/
/* Puts a backslash on path strings 										*/
/****************************************************************************/
void backslash(char *str)
{
    int i;

i=strlen(str);
if(i && str[i-1]!='\\') {
    str[i]='\\'; str[i+1]=0; }
}

void remove_re(char *str)
{
while(!strnicmp(str,"RE:",3)) {
	strcpy(str,str+3);
	while(str[0]==SP)
		strcpy(str,str+1); }
}

/****************************************************************************/
/* Network open function. Opens all files DENYALL and retries LOOP_NOPEN    */
/* number of times if the attempted file is already open or denying access	*/
/* for some other reason.	All files are opened in BINARY mode.			*/
/****************************************************************************/
int nopen(char *str, int access)
{
	char logstr[256];
	int file,share,count=0;

if(access&O_DENYNONE) {
	share=SH_DENYNO;
	access&=~O_DENYNONE; }
else if(access==O_RDONLY) share=SH_DENYWR;
else share=SH_DENYRW;
while(((file=sopen(str,O_BINARY|access,share,S_IWRITE))==-1)
	&& errno==EACCES && count++<LOOP_NOPEN);
if(file==-1 && errno==EACCES)
	lputs("\7\r\nNOPEN: ACCESS DENIED\r\n\7");
return(file);
}

/****************************************************************************/
/* This function performs an nopen, but returns a file stream with a buffer */
/* allocated.																*/
/****************************************************************************/
FILE *fnopen(int *file, char *str, int access)
{
	char mode[128];
	FILE *stream;

if(((*file)=nopen(str,access))==-1)
	return(NULL);

if(access&O_APPEND) {
	if(access&O_RDONLY)
		strcpy(mode,"a+");
	else
		strcpy(mode,"a"); }
else {
	if(access&O_WRONLY)
		strcpy(mode,"r+");
	else
		strcpy(mode,"r"); }
stream=fdopen((*file),mode);
if(stream==NULL) {
	close(*file);
	return(NULL); }
setvbuf(stream,NULL,_IOFBF,16*1024);
return(stream);
}


/****************************************************************************/
/* Moves or copies a file from one dir to another                           */
/* both 'src' and 'dest' must contain full path and filename                */
/* returns 0 if successful, -1 if error                                     */
/****************************************************************************/
int mv(char *src, char *dest, char copy)
{
	char buf[4096],str[256];
	int  ind,outd;
	long length,chunk=4096,l;
	ushort ftime,fdate;
    FILE *inp,*outp;

if(!strcmp(src,dest))	/* source and destination are the same! */
	return(0);
if(!fexist(src)) {
	lprintf("\r\nMV ERROR: Source doesn't exist\r\n'%s'\r\n"
		,src);
	return(-1); }
if(!copy && fexist(dest)) {
	lprintf("\r\nMV ERROR: Destination already exists\r\n'%s'\r\n"
		,dest);
	return(-1); }
if(!copy && ((src[1]!=':' && dest[1]!=':')
	|| (src[1]==':' && dest[1]==':' && toupper(src[0])==toupper(dest[0])))) {
	if(rename(src,dest)) {						/* same drive, so move */
		lprintf("\r\nMV ERROR: Error renaming '%s'"
				"\r\n                      to '%s'\r\n",src,dest);
		return(-1); }
	return(0); }
if((ind=nopen(src,O_RDONLY))==-1) {
	lprintf("\r\nMV ERROR: ERR_OPEN %s\r\n",src);
	return(-1); }
if((inp=fdopen(ind,"rb"))==NULL) {
	close(ind);
	lprintf("\r\nMV ERROR: ERR_FDOPEN %s\r\n",str);
	return(-1); }
setvbuf(inp,NULL,_IOFBF,8*1024);
if((outd=nopen(dest,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
	fclose(inp);
	lprintf("\r\nMV ERROR: ERR_OPEN %s\r\n",dest);
	return(-1); }
if((outp=fdopen(outd,"wb"))==NULL) {
	close(outd);
	fclose(inp);
	lprintf("\r\nMV ERROR: ERR_FDOPEN %s\r\n",str);
	return(-1); }
setvbuf(outp,NULL,_IOFBF,8*1024);
length=filelength(ind);
l=0L;
while(l<length) {
	if(l+chunk>length)
		chunk=length-l;
	fread(buf,chunk,1,inp);
	fwrite(buf,chunk,1,outp);
	l+=chunk; }
_dos_getftime(ind,&fdate,&ftime);
_dos_setftime(outd,fdate,ftime);
fclose(inp);
fclose(outp);
if(!copy && remove(src)) {
	lprintf("MV ERROR: ERR_REMOVE %s\r\n",src);
	return(-1); }
return(0);
}

/****************************************************************************/
/* Returns the total number of msgs in the sub-board and sets 'ptr' to the  */
/* date of the last message in the sub (0) if no messages.					*/
/****************************************************************************/
ulong getlastmsg(uint subnum, ulong *ptr, time_t *t)
{
	char str[256];
	int i;
	smbstatus_t status;

sprintf(smb_file,"%s%s",sub[subnum]->data_dir,sub[subnum]->code);
if((i=smb_open(10))!=0) {
	lprintf("ERR_OPEN %s %d\r\n",smb_file,i);
	return(0); }

if(!filelength(fileno(shd_fp))) {			/* Empty base */
	if(ptr) (*ptr)=0;
	smb_close();
	return(0); }
if((i=smb_locksmbhdr(10))!=0) {
	smb_close();
	lprintf("ERR_LOCK %s %d\r\n",smb_file,i);
	return(0); }
if((i=smb_getstatus(&status))!=0) {
	smb_unlocksmbhdr();
	smb_close();
	lprintf("ERR_READ %s %d\r\n",smb_file,i);
	return(0); }
smb_unlocksmbhdr();
smb_close();
if(ptr) (*ptr)=status.last_msg;
return(status.total_msgs);
}


ulong loadmsgs(post_t HUGE16 **post, ulong ptr)
{
	int i;
	long l=0;
	idxrec_t idx;


if((i=smb_locksmbhdr(10))!=0) { 				/* Be sure noone deletes or */
	lprintf("ERR_LOCK %s %d\r\n",smb_file,i);   /* adds while we're reading */
	return(0L); }

fseek(sid_fp,0L,SEEK_SET);
while(!feof(sid_fp)) {
    if(!fread(&idx,sizeof(idxrec_t),1,sid_fp))
        break;

	if(idx.number<=ptr || idx.attr&MSG_DELETE)
		continue;

	if(idx.attr&MSG_MODERATED && !(idx.attr&MSG_VALIDATED))
		break;

	if(((*post)=(post_t HUGE16 *)REALLOC((*post),sizeof(post_t)*(l+1)))
        ==NULL) {
		smb_unlocksmbhdr();
		lprintf("ERR_ALLOC %s %lu\r\n",smb_file,sizeof(post_t *)*(l+1));
		return(l); }
	(*post)[l].offset=idx.offset;
	(*post)[l].number=idx.number;
	l++; }
smb_unlocksmbhdr();
return(l);
}


void allocfail(uint size)
{
lprintf("\7Error allocating %u bytes of memory.\r\n",size);
bail(1);
}

void bail(int code)
{
exit(code);
}

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

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

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

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

typedef struct {
	ulong	alias,
			real;
			} username_t;

/****************************************************************************/
/* Note: Wrote another version of this function that read all userdata into */
/****************************************************************************/
/* Looks for a perfect match amoung all usernames (not deleted users)		*/
/* Returns the number of the perfect matched username or 0 if no match		*/
/* Called from functions waitforcall and newuser							*/
/* memory then scanned it from memory... took longer - always.              */
/****************************************************************************/
ulong matchname(char *inname)
{
	static ulong total_users;
	static username_t *username;
	int userdat,file,i;
	char str[256],c;
	ulong l,crc;
	FILE *namedat;

if(!total_users) {		/* Load CRCs */
	fprintf(stderr,"%-25s","Loading user names...");
	sprintf(str,"%sUSER\\NAME.DAT",data_dir);
	if((namedat=fnopen(&file,str,O_RDONLY))==NULL)
		return(0);
	sprintf(str,"%sUSER\\USER.DAT",data_dir);
	if((userdat=nopen(str,O_RDONLY|O_DENYNONE))==-1) {
		fclose(namedat);
		return(0); }
	while(!feof(namedat) && !eof(userdat)) {
		if(!fread(str,LEN_ALIAS+2,1,namedat))
			break;
		if((username=(username_t *)REALLOC(username
			,(total_users+1)*sizeof(username_t)))==NULL)
			break;

		for(c=0;c<LEN_ALIAS;c++)
			if(str[c]==ETX) break;
		str[c]=0;
		strlwr(str);
		username[total_users].alias=crc32(str);
		i=0;
		while(i<LOOP_NODEDAB
			&& lock(userdat,(long)((long)(total_users)*U_LEN)+U_NAME
				,LEN_NAME)==-1) {
			i++; }
		if(i>=LOOP_NODEDAB) 	   /* Couldn't lock USER.DAT record */
			continue;
		lseek(userdat,(long)((long)(total_users)*U_LEN)+U_NAME,SEEK_SET);
		read(userdat,str,LEN_NAME);
		unlock(userdat,(long)((long)(total_users)*U_LEN)+U_NAME,LEN_NAME);
		for(c=0;c<LEN_NAME;c++)
			if(str[c]==ETX || str[c]==CR) break;
		str[c]=0;
		strlwr(str);
		username[total_users].real=crc32(str);
		total_users++; }
	fclose(namedat);
	close(userdat);
	fprintf(stderr,
		"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
		"%25s"
		"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
		,""); }

strcpy(str,inname);
strlwr(str);
crc=crc32(str);
for(l=0;l<total_users;l++)
	if(crc==username[l].alias || crc==username[l].real)
		return(l+1);
return(0);
}

/****************************************************************************/
/* Converts goofy FidoNet time format into Unix format						*/
/****************************************************************************/
time_t fmsgtime(char *str)
{
	char month[4];
	struct tm tm;

memset(&tm,0,sizeof(tm));
if(isdigit(str[1])) {	/* Regular format: "01 Jan 86  02:34:56" */
	tm.tm_mday=atoi(str);
	sprintf(month,"%3.3s",str+3);
	if(!stricmp(month,"jan"))
		tm.tm_mon=0;
	else if(!stricmp(month,"feb"))
		tm.tm_mon=1;
	else if(!stricmp(month,"mar"))
		tm.tm_mon=2;
	else if(!stricmp(month,"apr"))
		tm.tm_mon=3;
	else if(!stricmp(month,"may"))
		tm.tm_mon=4;
	else if(!stricmp(month,"jun"))
		tm.tm_mon=5;
	else if(!stricmp(month,"jul"))
		tm.tm_mon=6;
	else if(!stricmp(month,"aug"))
		tm.tm_mon=7;
	else if(!stricmp(month,"sep"))
		tm.tm_mon=8;
	else if(!stricmp(month,"oct"))
		tm.tm_mon=9;
	else if(!stricmp(month,"nov"))
		tm.tm_mon=10;
	else
		tm.tm_mon=11;
	tm.tm_year=atoi(str+7);
	tm.tm_hour=atoi(str+11);
	tm.tm_min=atoi(str+14);
	tm.tm_sec=atoi(str+17); }

else {					/* SEAdog  format: "Mon  1 Jan 86 02:34" */
	tm.tm_mday=atoi(str+4);
	sprintf(month,"%3.3s",str+7);
	if(!stricmp(month,"jan"))
		tm.tm_mon=0;
	else if(!stricmp(month,"feb"))
		tm.tm_mon=1;
	else if(!stricmp(month,"mar"))
		tm.tm_mon=2;
	else if(!stricmp(month,"apr"))
		tm.tm_mon=3;
	else if(!stricmp(month,"may"))
		tm.tm_mon=4;
	else if(!stricmp(month,"jun"))
		tm.tm_mon=5;
	else if(!stricmp(month,"jul"))
		tm.tm_mon=6;
	else if(!stricmp(month,"aug"))
		tm.tm_mon=7;
	else if(!stricmp(month,"sep"))
		tm.tm_mon=8;
	else if(!stricmp(month,"oct"))
		tm.tm_mon=9;
	else if(!stricmp(month,"nov"))
		tm.tm_mon=10;
	else
		tm.tm_mon=11;
	tm.tm_year=atoi(str+11);
	tm.tm_hour=atoi(str+14);
	tm.tm_min=atoi(str+17);
	tm.tm_sec=0; }

if(tm.tm_year<70)
	tm.tm_year+=100;

return(mktime(&tm));
}

/****************************************************************************/
/* Returns the FidoNet address kept in str as ASCII.                        */
/****************************************************************************/
faddr_t atofaddr(char *str)
{
    char *p;
    faddr_t addr;

addr.zone=addr.net=addr.node=addr.point=0;
if((p=strchr(str,':'))!=NULL) {
    addr.zone=atoi(str);
    addr.net=atoi(p+1); }
else {
    if(total_faddrs)
		addr.zone=faddr[0].zone;
    else
        addr.zone=1;
    addr.net=atoi(str); }
if(!addr.zone)              /* no such thing as zone 0 */
    addr.zone=1;
if((p=strchr(str,'/'))!=NULL)
    addr.node=atoi(p+1);
else {
    if(total_faddrs)
		addr.net=faddr[0].net;
    else
        addr.net=1;
    addr.node=atoi(str); }
if((p=strchr(str,'.'))!=NULL)
    addr.point=atoi(p+1);
return(addr);
}

/****************************************************************************/
/* Returns an ASCII string for FidoNet address 'addr'                       */
/****************************************************************************/
char *faddrtoa(faddr_t addr)
{
    static char str[25];
    char point[25];

sprintf(str,"%u:%u/%u",addr.zone,addr.net,addr.node);
if(addr.point) {
    sprintf(point,".%u",addr.point);
    strcat(str,point); }
return(str);
}

#ifndef __OS2__
/****************************************************************************/
/* This function reads files that are potentially larger than 32k.  		*/
/* Up to one megabyte of data can be read with each call.                   */
/****************************************************************************/
long lread(int file, char HUGE16 *buf,long bytes)
{
	long count;

for(count=bytes;count>32767;count-=32767,buf+=32767)
	if(read(file,(char *)buf,32767)!=32767)
		return(-1L);
if(read(file,(char *)buf,(int)count)!=count)
	return(-1L);
return(bytes);
}
#endif

/****************************************************************************/
/* Coverts a FidoNet message into a Synchronet message						*/
/****************************************************************************/
void fmsgtosmsg(int file, fmsghdr_t fmsghdr, smbstatus_t status, uint user
	,uint subnum)
{
	uchar	ch,HUGE16 *fbuf,HUGE16 *sbody,HUGE16 *stail,HUGE16 *outbuf
			,done,col,esc,cr,*p,str[128];
	int 	i,chunk,lzh=0,storage;
	ushort	xlat,net;
	ulong	l,m,length,lzhlen,bodylen,taillen,crc;
	faddr_t faddr,origaddr,destaddr;
	smbmsg_t	msg;

memset(&msg,0,sizeof(smbmsg_t));
memcpy(msg.hdr.id,"SHD\x1a",4);
msg.hdr.version=SMB_VERSION;
if(fmsghdr.attr&FIDO_PRIVATE)
	msg.idx.attr|=MSG_PRIVATE;
msg.hdr.attr=msg.idx.attr;

if(fmsghdr.attr&FIDO_FILE)
	msg.hdr.auxattr|=MSG_FILEATTACH;

msg.hdr.when_imported.time=time(NULL);
msg.hdr.when_imported.zone=sys_timezone;
msg.hdr.when_written.time=fmsgtime(fmsghdr.time);

origaddr.zone=fmsghdr.origzone; 	/* only valid if NetMail */
origaddr.net=fmsghdr.orignet;
origaddr.node=fmsghdr.orignode;
origaddr.point=fmsghdr.origpoint;

destaddr.zone=fmsghdr.destzone; 	/* only valid if NetMail */
destaddr.net=fmsghdr.destnet;
destaddr.node=fmsghdr.destnode;
destaddr.point=fmsghdr.destpoint;

smb_hfield(&msg,SENDER,strlen(fmsghdr.from),fmsghdr.from);
strlwr(fmsghdr.from);
msg.idx.from=crc16(fmsghdr.from);

smb_hfield(&msg,RECIPIENT,strlen(fmsghdr.to),fmsghdr.to);
strlwr(fmsghdr.to);
msg.idx.to=crc16(fmsghdr.to);

if(user) {
	sprintf(str,"%u",user);
	smb_hfield(&msg,RECIPIENTEXT,strlen(str),str);
	msg.idx.to=user;
	msg.idx.from=0; }

smb_hfield(&msg,SUBJECT,strlen(fmsghdr.subj),fmsghdr.subj);
remove_re(fmsghdr.subj);
strlwr(fmsghdr.subj);
msg.idx.subj=crc16(fmsghdr.subj);

length=filelength(file)-sizeof(fmsghdr_t);
if((fbuf=(char *)LMALLOC(length+1))==NULL) {
	printf("alloc error\r\n");
	smb_freemsgmem(msg);
	return; }
if((sbody=(char *)LMALLOC((length+1)*2L))==NULL) {
	printf("alloc error\n");
	LFREE((char *)fbuf);
	smb_freemsgmem(msg);
	return; }
if((stail=(char *)LMALLOC((length+1)*2L))==NULL) {
	printf("alloc error\n");
	LFREE((char *)fbuf);
	LFREE((char *)sbody);
	smb_freemsgmem(msg);
	return; }
lread(file,fbuf,length);

for(col=l=esc=done=bodylen=taillen=0,cr=1;l<length;l++) {
	ch=fbuf[l];
	if(ch==1 && cr) {	/* kludge line */

		if(!strncmp((char *)fbuf+l+1,"TOPT ",5))
			destaddr.point=atoi((char *)fbuf+l+6);

		else if(!strncmp((char *)fbuf+l+1,"FMPT ",5))
			origaddr.point=atoi((char *)fbuf+l+6);

		else if(!strncmp((char *)fbuf+l+1,"INTL ",5)) {
			faddr=atofaddr((char *)fbuf+l+6);
			destaddr.zone=faddr.zone;
			destaddr.net=faddr.net;
			destaddr.node=faddr.node;
			l+=6;
			while(l<length && fbuf[l]!=SP) l++;
			faddr=atofaddr((char *)fbuf+l+1);
			origaddr.zone=faddr.zone;
			origaddr.net=faddr.net;
			origaddr.node=faddr.node; }

		else if(!strncmp((char *)fbuf+l+1,"MSGID:",6)) {
			l+=7;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOMSGID,m-l,fbuf+l); }

		else if(!strncmp((char *)fbuf+l+1,"REPLY:",6)) {
			l+=7;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOREPLYID,m-l,fbuf+l); }

		else if(!strncmp((char *)fbuf+l+1,"FLAGS:",6)) {
			l+=7;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOFLAGS,m-l,fbuf+l); }

		else if(!strncmp((char *)fbuf+l+1,"PATH:",5)) {
			l+=6;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOPATH,m-l,fbuf+l); }

		else if(!strncmp((char *)fbuf+l+1,"PID:",4)) {
			l+=5;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOPID,m-l,fbuf+l); }

		else {		/* Unknown kludge line */
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOCTRL,m-l,fbuf+l); }

		while(l<length && fbuf[l]!=CR) l++;
		continue; }

	if(ch!=LF && ch!=0x8d) {	/* ignore LF and soft CRs */
		if(cr && (!strncmp((char *)fbuf+l,"--- ",4)
			|| !strncmp((char *)fbuf+l,"---\r",4)))
			done=1; 			/* tear line and down go into tail */
		if(done && cr && !strncmp((char *)fbuf+l,"SEEN-BY:",8)) {
			l+=8;
			while(l<length && fbuf[l]<=SP) l++;
			m=l;
			while(m<length && fbuf[m]!=CR) m++;
			while(m && fbuf[m-1]<=SP) m--;
			if(m>l)
				smb_hfield(&msg,FIDOSEENBY,m-l,fbuf+l);
			while(l<length && fbuf[l]!=CR) l++;
			continue; }
		if(done)
			stail[taillen++]=ch;
		else
			sbody[bodylen++]=ch;
		col++;
		if(ch==CR) {
			cr=1;
			col=0;
			if(done)
				stail[taillen++]=LF;
			else
				sbody[bodylen++]=LF; }
		else {
			cr=0;
			if(col==1 && !strncmp((char *)fbuf+l," * Origin: ",11)) {
				p=strchr((char *)fbuf+l+11,CR); 	 /* find carriage return */
				while(p && *p!='(') p--;     /* rewind to '(' */
				if(p)
					origaddr=atofaddr(p+1); 	/* get orig address */
				done=1; }
			if(done)
				continue;

			if(ch==ESC) esc=1;		/* ANSI codes */
			if(ch==SP && col>40 && !esc) {	/* word wrap */
				for(m=l+1;m<length;m++) 	/* find next space */
					if(fbuf[m]<=SP)
						break;
				if(m<length && m-l>80-col) {  /* if it's beyond the eol */
					sbody[bodylen++]=CR;
					sbody[bodylen++]=LF;
					col=0; } }
			} } }

LFREE(fbuf);

if(bodylen>=2 && sbody[bodylen-2]==CR && sbody[bodylen-1]==LF)
	bodylen-=2; 						/* remove last CRLF if present */

if(status.max_crcs) {
	for(l=0,crc=0xffffffff;l<bodylen;l++)
		crc=ucrc32(sbody[l],crc);
	crc=~crc;

	i=smb_addcrc(status.max_crcs,crc,10);
	if(i) {
		if(i==1)
			lprintf("Duplicate message\r\n");
		else
			lprintf("smb_addcrc returned %d\r\n",i);
		smb_freemsgmem(msg);
		LFREE(sbody);
		LFREE(stail);
		return; } }

while(taillen && stail[taillen-1]<=SP)	/* trim all garbage off the tail */
	taillen--;

net=NET_FIDO;	/* Record origin address */
smb_hfield(&msg,SENDERNETTYPE,sizeof(ushort),&net);
smb_hfield(&msg,SENDERNETADDR,sizeof(fidoaddr_t),&origaddr);

if(subnum==INVALID_SUB) { /* No origin line means NetMail, so add dest addr */
	smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(ushort),&net);
	smb_hfield(&msg,RECIPIENTNETADDR,sizeof(fidoaddr_t),&destaddr); }

if(subnum!=INVALID_SUB && sub[subnum]->misc&SUB_LZH
	&& bodylen+2+taillen+2>=SDT_BLOCK_LEN && bodylen) {
	if((outbuf=(char *)LMALLOC(bodylen*2))==NULL) {
		printf("alloc error for lzh: %lu\n",bodylen*2);
		smb_freemsgmem(msg);
		LFREE(sbody);
		LFREE(stail);
		return; }
	lzhlen=lzh_encode((uchar *)sbody,bodylen,(uchar *)outbuf);
	if(lzhlen>1 &&
		smb_datblocks(lzhlen+4+taillen+2)<smb_datblocks(bodylen+2+taillen+2)) {
		bodylen=lzhlen; 	/* Compressable */
		l=bodylen+4;
		LFREE(sbody);
		lzh=1;
		sbody=outbuf; }
	else {					/* Uncompressable */
		l=bodylen+2;
		LFREE(outbuf); } }
else
	l=bodylen+2;

if(taillen)
	l+=(taillen+2);


if(status.attr&SMB_HYPERALLOC) {
	if((i=smb_locksmbhdr(10))!=0) {
		printf("smb_locksmbhdr returned %d\n",i);
		smb_freemsgmem(msg);
		LFREE(sbody);
		LFREE(stail);
		return; }
	msg.hdr.offset=smb_hallocdat();
	storage=SMB_HYPERALLOC; }
else {
	if(smb_open_da(10)) {
		smb_freemsgmem(msg);
		printf("error opening %s.SDA\r\n",smb_file);
		LFREE(sbody);
		LFREE(stail);
		return; }
	if(subnum!=INVALID_SUB && sub[subnum]->misc&SUB_FAST) {
		msg.hdr.offset=smb_fallocdat(l,1);
		storage=SMB_FASTALLOC; }
	else {
		msg.hdr.offset=smb_allocdat(l,1);
		storage=SMB_SELFPACK; }
	fclose(sda_fp); }

if(msg.hdr.offset && msg.hdr.offset<1L) {
	smb_unlocksmbhdr();
	smb_freemsgmem(msg);
	LFREE(sbody);
	LFREE(stail);
	printf("error %ld allocating records\r\n",msg.hdr.offset);
	return; }
fseek(sdt_fp,msg.hdr.offset,SEEK_SET);
if(lzh) {
	xlat=XLAT_LZH;
	fwrite(&xlat,2,1,sdt_fp); }
xlat=XLAT_NONE;
fwrite(&xlat,2,1,sdt_fp);
chunk=30000;
for(l=0;l<bodylen;l+=chunk) {
	if(l+chunk>bodylen)
		chunk=bodylen-l;
	fwrite(sbody+l,1,chunk,sdt_fp); }
if(taillen) {
	fwrite(&xlat,2,1,sdt_fp);
	fwrite(stail,1,taillen,sdt_fp); }
fflush(sdt_fp);
LFREE(sbody);
LFREE(stail);

if(status.attr&SMB_HYPERALLOC)
	smb_unlocksmbhdr();

if(lzh)
	bodylen+=2;
bodylen+=2;
smb_dfield(&msg,TEXT_BODY,bodylen);
if(taillen)
	smb_dfield(&msg,TEXT_TAIL,taillen+2);

smb_addmsghdr(&msg,&status,storage,10);
smb_freemsgmem(msg);
}

/****************************************************************/
/* Get zone and point from kludge lines in 'file' if they exist */
/****************************************************************/
void getzpt(int file, fmsghdr_t *hdr)
{
	char buf[0x1000];
	int i,len,cr=0;
	faddr_t faddr;

len=read(file,buf,0x1000);
for(i=0;i<len;i++) {
	if((!i || cr) && buf[i]==1) {	/* kludge */
		if(!strncmp(buf+i+1,"TOPT ",5))
			hdr->destpoint=atoi(buf+i+6);
		else if(!strncmp(buf+i+1,"FMPT ",5))
			hdr->origpoint=atoi(buf+i+6);
		else if(!strncmp(buf+i+1,"INTL ",5)) {
			faddr=atofaddr(buf+i+6);
			hdr->destzone=faddr.zone;
			hdr->destnet=faddr.net;
			hdr->destnode=faddr.node;
			i+=6;
			while(buf[i] && buf[i]!=SP) i++;
			faddr=atofaddr(buf+i+1);
			hdr->origzone=faddr.zone;
			hdr->orignet=faddr.net;
			hdr->orignode=faddr.node; }
		while(i<len && buf[i]!=CR) i++;
		cr=1;
		continue; }
	if(buf[i]==CR)
		cr=1;
	else
		cr=0; }
lseek(file,sizeof(fmsghdr_t),SEEK_SET);
}

/***********************************/
/* Synchronet/FidoNet Message util */
/***********************************/
int main(int argc, char **argv)
{
	char	ch,str[512],fname[256],touser[512],subj[512],path[512],sub_code[9]
			,*p,*tp,*sp,*buf,*outbuf,cr,tear,lzh;
	ushort	xlat;
	int 	i,j,k,n,x,last,file,fmsg,nextmsg,g;
	ulong	files,msgfiles,echomail=0,netmail=0,exported=0,crc,
			l,m,length,lastmsg,posts,msgs,exp;
	time_t	ptr,now,start,lastimport;
	read_cfg_text_t txt;
	struct	find_t ff;
	struct	tm tm,*tm_p;
	fmsghdr_t hdr;
	faddr_t addr,sys_faddr;
	post_t	HUGE16 *post;
	FILE	*stream,*fstream;
	smbstatus_t status;
	smbmsg_t msg;

lprintf("\nSynchronet <=> FidoNet Utility  Version %s  "
	"Developed by Rob Swindell\n",VER);

putenv("TZ=UCT0");
_fmode=O_BINARY;
setvbuf(stdout,NULL,_IONBF,0);

txt.openerr="\7\r\nError opening %s for read.\r\n";
txt.reading="\r\nReading %s...";
txt.readit="\rRead %s       ";
txt.allocerr="\7\r\nError allocating %u bytes of memory\r\n";
txt.error="\7\r\nERROR: Offset %lu in %s\r\n\r\n";

node_dir[0]=sub_code[0]=0;
for(i=1;i<argc;i++) {
	if(argv[i][0]=='/') {
		j=1;
		while(argv[i][j]) {
			switch(toupper(argv[i][j])) {
				case 'A':
                    misc|=ASCII_ONLY;
                    break;
				case 'B':
					misc|=LOCAL_NETMAIL;
					break;
				case 'C':
                    misc|=PURGE_ECHOMAIL;
                    break;
				case 'D':
                    misc&=~DELETE_NETMAIL;
                    break;
				case 'E':
                    misc&=~EXPORT_ECHOMAIL;
                    break;
				case 'F':
                    misc|=IMPORT_LOCAL;
                    break;
				case 'G':
                    misc|=IMPORT_NEW_ONLY;
                    break;
				case 'H':
                    misc|=EXPORT_ALL;
                    break;
				case 'I':
                    misc&=~IMPORT_ECHOMAIL;
                    break;
                case 'J':
                    misc|=IGNORE_RECV;
                    break;
				case 'K':
                    misc&=~KILL_ECHOMAIL;
                    break;
                case 'L':
                    misc|=LOGFILE;
                    break;
				case 'M':
                    misc|=IGNORE_MSGPTRS;
                    break;
				case 'N':
					misc&=~IMPORT_NETMAIL;
					break;
				case 'O':
                    misc|=IGNORE_ADDRESS;
                    break;
				case 'P':
					misc|=IGNORE_POINT;
					break;
				case 'Q':
					misc|=DONT_SET_RECV;
					break;
				case 'R':
                    misc|=REPORT;
                    break;
				case 'S':
                    misc|=IMPORT_PRIVATE;
                    break;
				case 'T':
                    misc|=LEAVE_MSGPTRS;
                    break;
                case 'U':
                    misc|=UPDATE_MSGPTRS;
                    misc&=~EXPORT_ECHOMAIL;
                    break;
				case 'X':
                    misc&=~DELETE_ECHOMAIL;
                    break;
                case 'Y':
                    misc|=UNKNOWN_NETMAIL;
                    break;
				case 'Z':
                    misc|=IGNORE_ZONE;
                    break;

				case '=':
					misc|=CONVERT_TEAR;
					break;
				case '!':
					misc|=NOTIFY_RECEIPT;
					break;
				case '2':
					startmsg=2;
					break;
				default:
					printf("\nusage: sbbsfido [sbbsnode] [/switches] "
						"[sub_code]");
					printf("\nwhere: sbbsnode is the path for your "
						"NODE1 directory (example: c:\\sbbs\\node1)\n");
					printf("       sub_code is the internal code for a "
						"sub-board (default is ALL subs)\n");
					printf("\nvalid switches:\n\n");
					printf("n:do not import netmail               "
						   "i:do not import echomail\n");
					printf("p:ignore point in netmail address     "
						   "e:do not export echomail\n");
					printf("z:ignore zone in netmail address      "
						   "h:export all echomail (hub rescan)\n");
					printf("o:ignore entire netmail address       "
						   "m:ignore message pointers (export all)\n");
					printf("y:import netmail for unknown users    "
						   "u:update message pointers (export none)\n");
					printf("d:do not delete netmail after import  "
						   "x:do not delete echomail after import\n");
					printf("l:output to SBBSFIDO.LOG (verbose)    "
						   "k:do not kill echomail after export\n");
					printf("r:create report of import totals      "
						   "t:do not update message pointers\n");
					printf("a:export ASCII characters only        "
						   "c:delete all messages (echomail purge)\n");
					printf("j:ignore recieved bit on import       "
						   "s:import private override (strip pvt)\n");
					printf("q:do not set received bit on import   "
                           "g:import new echomail only\n");
					printf("b:import locally created netmail too  "
                           "f:import locally created echomail too\n");
					printf("=:change existing tear lines to ===   "
                           "2:export/import/delete starting at 2.MSG\n");
					printf("!:notify users of received echomail\n");
					exit(0); }
			j++; } }
	else {
		if(strchr(argv[i],'\\') || argv[i][1]==':')
			sprintf(node_dir,"%.40s",argv[i]);
		else
			sprintf(sub_code,"%.8s",argv[i]); }  }

if(!node_dir[0]) {
	p=getenv("SBBSNODE");
	if(p==NULL) {
		printf("\7\nSBBSNODE environment variable not set.\n");
		exit(1); }
	strcpy(node_dir,p); }

strupr(node_dir);

if(node_dir[strlen(node_dir)-1]!='\\')
	strcat(node_dir,"\\");

read_node_cfg(txt);
if(ctrl_dir[0]=='.') {   /* Relative path */
	strcpy(str,ctrl_dir);
	sprintf(ctrl_dir,"%s%s",node_dir,str);
	if(_fullpath(str,ctrl_dir,40))
		strcpy(ctrl_dir,str); }
backslash(ctrl_dir);

read_main_cfg(txt);
if(data_dir[0]=='.') {   /* Relative path */
	strcpy(str,data_dir);
	sprintf(data_dir,"%s%s",node_dir,str);
	if(_fullpath(str,data_dir,40))
		strcpy(data_dir,str); }
backslash(data_dir);
if(text_dir[0]=='.') {   /* Relative path */
	strcpy(str,text_dir);
	sprintf(text_dir,"%s%s",node_dir,str);
	if(_fullpath(str,text_dir,40))
		strcpy(text_dir,str); }
backslash(text_dir);
read_msgs_cfg(txt);

if(total_faddrs<1) {
	sys_faddr.zone=sys_faddr.net=sys_faddr.node=1;
	sys_faddr.point=0; }
else
	sys_faddr=faddr[0];


if(misc&LOGFILE)
	if((fidologfile=fnopen(&i,"SBBSFIDO.LOG"
		,O_WRONLY|O_APPEND|O_CREAT))==NULL) {
		lprintf("\7ERROR opening SBBSFIDO.LOG\r\n");
		exit(1); }

sprintf(str,"%s%s",ctrl_dir,"NODE.DAB");
if((nodefile=sopen(str,O_BINARY|O_RDWR,SH_DENYNO))==-1) {
	lprintf("\r\n\7Error opening %s\r\n",str);
    exit(1); }

if(misc&IMPORT_NETMAIL) {

lputs("\r\n\r\nScanning for Inbound NetMail...\r\n");

sprintf(smb_file,"%sMAIL",data_dir);
if((i=smb_open(10))!=0) {
	lprintf("Error %d opening %s\r\n",i,smb_file);
	exit(1); }

if(!filelength(fileno(shd_fp)))
	if((i=smb_create(mail_maxcrcs,MAX_SYSMAIL,mail_maxage,SMB_EMAIL,10))!=0) {
		lprintf("Error %d creating %s\r\n",i,smb_file);
		exit(1); }

if((i=smb_locksmbhdr(10))!=0) {
	lprintf("Error %d locking %s\r\n",i,smb_file);
	exit(1); }
if((i=smb_getstatus(&status))!=0) {
	lprintf("Error %d reading %s status header\r\n",i,smb_file);
	exit(1); }
smb_unlocksmbhdr();

sprintf(str,"%s*.MSG",netmail_dir);

for(last=findfirst(str,&ff,0);!last;last=findnext(&ff)) {
	sprintf(path,"%s%s",netmail_dir,ff.name);
	strupr(path);
	lprintf("\r%s    ",path);
	if((fmsg=nopen(path,O_RDWR))==-1) {
		lprintf("\7ERROR opening");
		continue; }
	if(filelength(fmsg)<sizeof(fmsghdr_t)) {
		lprintf("\7Invalid length of %u bytes\r\n",filelength(fmsg));
		close(fmsg);
		continue; }
	if(read(fmsg,&hdr,sizeof(fmsghdr_t))!=sizeof(fmsghdr_t)) {
		close(fmsg);
		lprintf("\7ERROR reading %u bytes"
			,sizeof(fmsghdr_t));
		continue; }
	if(hdr.attr&FIDO_ORPHAN) {
		close(fmsg);
		lprintf("Orphan (%s).\r\n",hdr.to);
		continue; }
	if(misc&IGNORE_ZONE)				/* default to system's zone */
		hdr.destzone=hdr.origzone=sys_faddr.zone;
	if(misc&IGNORE_POINT)				/* default to no point */
		hdr.destpoint=hdr.origpoint=0;
	getzpt(fmsg,&hdr);					/* use kludge if found */
	for(i=0;i<total_faddrs;i++)
		if(hdr.destzone==faddr[i].zone
			&& hdr.destnet==faddr[i].net
			&& hdr.destnode==faddr[i].node
			&& hdr.destpoint==faddr[i].point)
			break;
	lprintf("%u:%u/%u.%u  "
		,hdr.destzone,hdr.destnet,hdr.destnode,hdr.destpoint);
	if(misc&IGNORE_ADDRESS || i<total_faddrs) {
		if(!(misc&IGNORE_RECV) && hdr.attr&FIDO_RECV) {
            close(fmsg);
			lputs("Already received.\r\n");
            continue; }
		if(hdr.attr&FIDO_LOCAL && !(misc&LOCAL_NETMAIL)) {
			close(fmsg);
			lputs("Created locally.\r\n");
			continue; }
		i=atoi(hdr.to);
		if(!stricmp(hdr.to,"SYSOP"))  /* NetMail to "sysop" goes to #1 */
			i=1;
		if(!i)
			i=matchname(hdr.to);
		if(!i) {
			if(misc&UNKNOWN_NETMAIL)	/* receive unknown user mail to 1 */
				i=1;
			else {
				lprintf("\7ERROR unknown user '%s'\r\n",hdr.to);
				hdr.attr|=FIDO_ORPHAN;
				lseek(fmsg,0L,SEEK_SET);
				write(fmsg,&hdr,sizeof(fmsghdr_t));
				close(fmsg);
				continue; } }
		lprintf("%s\r\n",hdr.to);

		/*********************/
		/* Importing NetMail */
		/*********************/

		fmsgtosmsg(fmsg,hdr,status,i,INVALID_SUB);

		addr.zone=hdr.origzone;
		addr.net=hdr.orignet;
		addr.node=hdr.orignode;
		addr.point=hdr.origpoint;
		sprintf(str,"\7\1n\1hSBBSFIDO: \1m%.36s \1n\1msent you NetMail from "
			"\1h%s\1n\r\n"
			,hdr.from,faddrtoa(addr));
		putsmsg(i,str);

		if(hdr.attr&FIDO_FILE) {	/* File attachment */
			strcpy(subj,hdr.subj);
			tp=subj;
			while(1) {
				p=strchr(tp,SP);
				if(p) *p=0;
				sp=strrchr(tp,'/');              /* sp is slash pointer */
				if(!sp) sp=strrchr(tp,'\\');
				if(sp) tp=sp+1;
				sprintf(str,"%s%s",fidofile_dir,tp);
				sprintf(tmp,"%sFILE\\%04u.IN",data_dir,i);
				mkdir(tmp);
				strcat(tmp,"\\");
				strcat(tmp,tp);
				mv(str,tmp,0);
				if(!p)
					break;
				tp=p+1; } }
		netmail++;

		/***************************/
		/* Updating message header */
		/***************************/
		if(!(misc&DONT_SET_RECV)) {
			hdr.attr|=FIDO_RECV;
			lseek(fmsg,0L,SEEK_SET);
			write(fmsg,&hdr,sizeof(fmsghdr_t)); }

		/**************************************/
		/* Delete source netmail if specified */
		/**************************************/
		close(fmsg);
		if(misc&DELETE_NETMAIL)
			remove(path); }
	else
		close(fmsg); }
smb_close(); }


if(misc&IMPORT_ECHOMAIL) {

start=time(NULL);

lputs("\r\n\r\nScanning for Inbound EchoMail...\r\n");

sprintf(path,"%sSBBSFIDO.DAB",data_dir);
if((file=nopen(path,O_RDWR|O_CREAT))==-1)
	lastimport=0L;
else {
	read(file,&lastimport,4);
	now=time(NULL);
	lseek(file,0L,SEEK_SET);
	write(file,&now,4);
	close(file); }

for(g=files=0;g<total_grps;g++)
for(i=0;i<total_subs;i++)
	if(sub[i]->misc&SUB_FIDO && sub[i]->grp==g) {
		if(sub_code[0] && stricmp(sub_code,sub[i]->code))
			continue;
		if(!sub[i]->echopath[0])
			sprintf(sub[i]->echopath,"%s%s\\",echomail_dir,sub[i]->code);
		if(files) {
			lputs("\r\n");
			files=0; }
		lprintf("\r\n%-15.15s %s\r\n"
			,grp[sub[i]->grp]->sname,sub[i]->lname);

		sprintf(path,"%s*.MSG",sub[i]->echopath);
		l=findfirst(path,&ff,0);
		if(startmsg==2 && !strcmp(ff.name,"1.MSG"))
			l=findnext(&ff);
		if(l)
			continue;
		lprintf("Counting %s",path);
		msgfiles=0;
		while(!l) {
			memset(&tm,0,sizeof(tm));
			tm.tm_mday=ff.wr_date&31;
			tm.tm_mon=(ff.wr_date>>5)&15;
			tm.tm_year=80+((ff.wr_date>>9)&127);
			tm.tm_hour=(ff.wr_time>>11)&31;
			tm.tm_min=(ff.wr_time>>5)&63;
			tm.tm_sec=(ff.wr_time&0x1f)<<1;
			if(isdigit(ff.name[0])
				&& !(startmsg==2 && !strcmp(ff.name,"1.MSG"))
				&& !(misc&IMPORT_NEW_ONLY && mktime(&tm)<=lastimport))
				msgfiles++; 		/* msgfiles= messages to import */
			l=findnext(&ff); }

		lprintf("\r\n%u messages.\r\n",msgfiles);
		if(!msgfiles)				/* no messages, so continue. */
			continue;

		sprintf(smb_file,"%s%s",sub[i]->data_dir,sub[i]->code);
		if((j=smb_open(10))!=0) {
			lprintf("Error %d opening %s\r\n",j,smb_file);
			continue; }
		if(!filelength(fileno(shd_fp)))
			if((j=smb_create(sub[i]->maxcrcs,sub[i]->maxmsgs
				,sub[i]->maxage
				,sub[i]->misc&SUB_HYPER ? SMB_HYPERALLOC:0
				,10))!=0) {
				lprintf("Error %d creating %s\r\n",j,smb_file);
				smb_close();
				continue; }

		if((j=smb_locksmbhdr(10))!=0) {
			lprintf("Error %d locking SMB header\r\n",j);
			smb_close();
			continue; }
		if((j=smb_getstatus(&status))!=0) {
			lprintf("Error %d reading SMB header\r\n",j);
			smb_close();
			continue; }
		smb_unlocksmbhdr();

		for(l=startmsg;l<0x8000 && msgfiles;l++) {
			sprintf(path,"%s%lu.MSG",sub[i]->echopath,l);
			if(findfirst(path,&ff,0))	/* doesn't exist */
				continue;				/* was break */
			tm.tm_mday=ff.wr_date&31;
			tm.tm_mon=(ff.wr_date>>5)&15;
			tm.tm_year=80+((ff.wr_date>>9)&127);
			tm.tm_hour=(ff.wr_time>>11)&31;
			tm.tm_min=(ff.wr_time>>5)&63;
			tm.tm_sec=(ff.wr_time&0x1f)<<1;
			if(misc&IMPORT_NEW_ONLY && mktime(&tm)<=lastimport)
				continue;
			if(startmsg==2 && !strcmp(ff.name,"1.MSG"))
				continue;
			msgfiles--; 		/* so we only look for as many as are there */
			strupr(path);
			lprintf("\r%s    ",path);
			files++;
			if((fmsg=nopen(path,O_RDWR))==-1) {
				lprintf("\7ERROR opening\r\n");
				continue; }
			if(filelength(fmsg)<sizeof(fmsghdr_t)) {
				lprintf("\7Invalid length of %u bytes\r\n",filelength(fmsg));
				close(fmsg);
				continue; }
			if(read(fmsg,&hdr,sizeof(fmsghdr_t))!=sizeof(fmsghdr_t)) {
				close(fmsg);
				lprintf("\7ERROR reading %u bytes\r\n"
					,sizeof(fmsghdr_t));
				continue; }
			if(misc&IMPORT_LOCAL || !(hdr.attr&FIDO_LOCAL)) {

				if(!(misc&IGNORE_RECV) && hdr.attr&FIDO_RECV) {
					close(fmsg);
					lputs("Already received.\r\n");
					continue; }

				if(hdr.attr&FIDO_SENT) {
					close(fmsg);
					lputs("Sent.");
					if(hdr.attr&FIDO_KILLSENT)
						if(!remove(path))
							lputs(" Killed.");
					lputs("\r\n");
					continue; }

				if(hdr.attr&FIDO_PRIVATE && !(sub[i]->misc&SUB_PRIV)) {
					if(misc&IMPORT_PRIVATE)
						hdr.attr&=~FIDO_PRIVATE;
					else {
						close(fmsg);
						lputs("Private posts disallowed.\r\n");
						continue; } }

				if(!(hdr.attr&FIDO_PRIVATE) && sub[i]->misc&SUB_PONLY)
					hdr.attr|=MSG_PRIVATE;

				/**********************/
				/* Importing EchoMail */
				/**********************/

				fmsgtosmsg(fmsg,hdr,status,0,i);

				echomail++;

				/* Updating message header */
				if(!(misc&DONT_SET_RECV)) {
					hdr.attr|=FIDO_RECV;
					lseek(fmsg,0L,SEEK_SET);
					write(fmsg,&hdr,sizeof(fmsghdr_t)); }

				close(fmsg);
				if(misc&NOTIFY_RECEIPT && (m=matchname(hdr.to))!=0) {
					sprintf(str
					,"\7\1n\1hSBBSFIDO: \1m%.36s \1n\1msent you EchoMail on "
						"\1h%s \1n\1m%s\1n\r\n"
						,hdr.from,grp[sub[i]->grp]->sname,sub[i]->sname);
					putsmsg(m,str); }

				/* Delete source EchoMail if specified */
				if(misc&DELETE_ECHOMAIL)
					remove(path); }
			else
				close(fmsg); }
		smb_close();
		}

now=time(NULL);
if(now-start)
	lprintf("\r\nImported %lu EchoMail messages in %lu seconds "
		"(%lu messages/second).\r\n"
		,echomail,now-start,echomail/(now-start));
}

if(misc&EXPORT_ECHOMAIL) {

start=time(NULL);

lputs("\r\n\r\nScanning for Outbound EchoMail...\r\n");

for(g=files=0;g<total_grps;g++)
for(i=0;i<total_subs;i++)
	if(sub[i]->misc&SUB_FIDO && sub[i]->grp==g) {
		if(sub_code[0] && stricmp(sub_code,sub[i]->code))
            continue;
		if(!sub[i]->echopath[0])
            sprintf(sub[i]->echopath,"%s%s\\",echomail_dir,sub[i]->code);
		if(files) {
			lputs("\r\n");
			files=0; }
		lprintf("\r\n%-15.15s %s\r\n"
			,grp[sub[i]->grp]->sname,sub[i]->lname);
		ptr=0;
		if(!(misc&IGNORE_MSGPTRS)) {
			sprintf(str,"%s%s.SFP",sub[i]->data_dir,sub[i]->code);
			if((file=nopen(str,O_RDONLY))!=-1) {
				read(file,&ptr,sizeof(time_t));
				close(file); } }

		msgs=getlastmsg(i,&lastmsg,0);
		if(!msgs || (!(misc&IGNORE_MSGPTRS) && ptr>=lastmsg)) {
			if(ptr>lastmsg && !(misc&LEAVE_MSGPTRS)) {	/* fix ptr */
                sprintf(str,"%s%s.SFP",sub[i]->data_dir,sub[i]->code);
				if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
					lprintf("\7ERROR opening/creating %s",str);
				else {
					write(file,&lastmsg,4);
					close(file); } }
			continue; }
		nextmsg=startmsg;

		sprintf(smb_file,"%s%s"
			,sub[i]->data_dir,sub[i]->code);
		if((j=smb_open(10))!=0) {
			lprintf("Error %d opening %s\r\n",j,smb_file);
			continue; }

		post=NULL;
		posts=loadmsgs(&post,ptr);

		if(!posts)	{ /* no new messages */
			smb_close();
			if(post)
				FREE(post);
			continue; }

		for(m=exp=0;m<posts;m++) {
			printf("\rScanning: %lu of %lu     "
				,m+1,posts);

			msg.idx.offset=post[m].offset;
			if((k=smb_lockmsghdr(msg,10))!=0) {
				lprintf("ERR_LOCK %s %d\r\n",smb_file,k);
				continue; }
			k=smb_getmsghdr(&msg);
			if(k || msg.hdr.number!=post[m].number) {
				smb_unlockmsghdr(msg);
				smb_freemsgmem(msg);

				msg.hdr.number=post[m].number;
				if((k=smb_getmsgidx(&msg))!=0) {
					lprintf("ERR_READ %s %d\r\n",smb_file,k);
					continue; }
				if((k=smb_lockmsghdr(msg,10))!=0) {
					lprintf("ERR_LOCK %s %d\r\n",smb_file,k);
					continue; }
				if((k=smb_getmsghdr(&msg))!=0) {
					smb_unlockmsghdr(msg);
					lprintf("ERR_READ %s %d\r\n",smb_file,k);
					continue; } }

			if((!(misc&EXPORT_ALL) && msg.from_net.type==NET_FIDO)
				|| !strnicmp(msg.subj,"NE:",3)) {   /* no echo */
				smb_unlockmsghdr(msg);
				smb_freemsgmem(msg);
				continue; }  /* From a Fido node, ignore it */

			if(msg.from_net.type && msg.from_net.type!=NET_FIDO
				&& !(sub[i]->misc&SUB_GATE)) {
				smb_unlockmsghdr(msg);
				smb_freemsgmem(msg);
				continue; }

			for(j=nextmsg;j;j++) {
				sprintf(fname,"%s%u.MSG",sub[i]->echopath,j);
				if(!fexist(fname))
					break; }
			if(!j) {
				lputs("\7EchoMail dir full!");
				smb_unlockmsghdr(msg);
				smb_freemsgmem(msg);
				continue; }
			nextmsg=j+1;
			strupr(fname);
			if((fmsg=nopen(fname,O_WRONLY|O_CREAT))==-1) {
				smb_unlockmsghdr(msg);
				smb_freemsgmem(msg);
				lprintf("\7ERROR creating %s\r\n",fname);
				continue; }
			if((fstream=fdopen(fmsg,"wb"))==NULL) {
				close(fmsg);
				smb_unlockmsghdr(msg);
                smb_freemsgmem(msg);
				lprintf("\7ERROR fdopen %s\r\n",fname);
				continue; }
			setvbuf(fstream,NULL,_IOFBF,2048);

			files++;

			memset(&hdr,0,sizeof(fmsghdr_t));	 /* Zero the header */
			hdr.origzone=sub[i]->faddr.zone;
			hdr.orignet=sub[i]->faddr.net;
			hdr.orignode=sub[i]->faddr.node;
			hdr.origpoint=sub[i]->faddr.point;

			hdr.attr=FIDO_LOCAL;
			if(misc&KILL_ECHOMAIL)
				hdr.attr|=FIDO_KILLSENT;
			if(msg.hdr.attr&MSG_PRIVATE)
				hdr.attr|=FIDO_PRIVATE;

			sprintf(hdr.from,"%.35s",msg.from);

			tm_p=gmtime((time_t *)&msg.hdr.when_written.time);
			sprintf(hdr.time,"%02u %3.3s %02u  %02u:%02u:%02u"
				,tm_p->tm_mday,mon[tm_p->tm_mon],tm_p->tm_year%100
				,tm_p->tm_hour,tm_p->tm_min,tm_p->tm_sec);

			sprintf(hdr.to,"%.35s",msg.to);

			sprintf(hdr.subj,"%.71s",msg.subj);

			fwrite(&hdr,sizeof(fmsghdr_t),1,fstream);

			for(j=0;j<msg.hdr.total_dfields;j++) {

				if(msg.dfield[j].type!=TEXT_BODY
					&& msg.dfield[j].type!=TEXT_TAIL)
					continue;					/* skip non-text data fields */

				if(msg.dfield[j].length<3)		/* need at least 3 bytes */
					continue;

				fseek(sdt_fp,msg.hdr.offset+msg.dfield[j].offset,SEEK_SET);

				lzh=0;
				fread(&xlat,2,1,sdt_fp);
				if(xlat==XLAT_LZH) {
					lzh=1;
					fread(&xlat,2,1,sdt_fp); }
				if(xlat!=XLAT_NONE) 	/* no other translations supported */
					continue;

				length=msg.dfield[j].length-2;
				if(lzh)
					length-=2;

				if((buf=LMALLOC(length))==NULL) {
					lprintf("Error allocating %lu bytes\r\n",length);
					continue; }

				fread(buf,length,1,sdt_fp);

				if(lzh) {
					l=*(long *)buf;
					if((outbuf=LMALLOC(l))==NULL) {
						lprintf("Error allocationg %lu for lzh\r\n",l);
						LFREE(buf);
						continue; }
					length=lzh_decode(buf,length,outbuf);
					LFREE(buf);
					buf=outbuf; }

				tear=0;
				for(l=0,cr=1;l<length;l++) {
					if(buf[l]==1) { /* Ctrl-A, so skip it and the next char */
                        l++;
						continue; }
					if(buf[l]==LF || buf[l]==0)  /* Ignore line feeds */
						continue;
					if(cr) {
						if(l+3<length && buf[l]=='-' && buf[l+1]=='-'
							&& buf[l+2]=='-'
							&& (buf[l+3]==SP || buf[l+3]==CR)) {
							if(misc&CONVERT_TEAR)	/* Convert to === */
								buf[l]=buf[l+1]=buf[l+2]='=';
							else
								tear=1; }
						else if(l+10<length
							&& !strncmp(buf+l," * Origin: ",11))
							buf[l+1]='#'; } /* Convert * Origin into # Origin */

					if(buf[l]==CR)
						cr=1;
					else
						cr=0;
					if(sub[i]->misc&SUB_ASCII || misc&ASCII_ONLY) {
						if(buf[l]<SP && buf[l]!=CR) /* Ctrl ascii */
							buf[l]='.';             /* converted to '.' */
						if((uchar)buf[l]>0x7f)		/* extended ASCII */
							buf[l]='*'; }           /* converted to '*' */
					fputc(buf[l],fstream); }
				fprintf(fstream,"\r\n");
				LFREE(buf); }

			if(!(sub[i]->misc&SUB_NOTAG)) {
				if(!tear)	/* No previous tear line */
					fprintf(fstream,"--- Synchronet+SBBSfido v%s\r\n"
						,VER);	/* so add ours */
				fprintf(fstream," * Origin: %s (%s)\r\n"
					,sub[i]->origline[0] ? sub[i]->origline : origline
					,faddrtoa(sub[i]->faddr)); }

			fputc(0,fstream);	/* Null terminator */
			fclose(fstream);
			exported++;
			exp++;
			printf("Exported: %lu of %lu",exp,exported);
			smb_unlockmsghdr(msg);
			smb_freemsgmem(msg); }

		smb_close();
		FREE(post);

		/***********************/
		/* Update FIDO_PTR.DAB */
		/***********************/
		if(!(misc&LEAVE_MSGPTRS) && lastmsg>ptr) {
			sprintf(str,"%s%s.SFP",sub[i]->data_dir,sub[i]->code);
			if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
				lprintf("\7ERROR opening/creating %s",str);
			else {
				write(file,&lastmsg,4);
				close(file); } } }

now=time(NULL);
if(now-start)
	lprintf("\r\nExported %lu EchoMail messages in %lu seconds "
		"(%lu messages/second).\r\n"
		,exported,now-start,exported/(now-start));

}

if(misc&UPDATE_MSGPTRS) {

lputs("\r\n\r\nUpdating Message Pointers to Last Posted Message...\r\n");

for(g=0;g<total_grps;g++)
for(i=0;i<total_subs;i++)
	if(sub[i]->misc&SUB_FIDO && sub[i]->grp==g) {
		lprintf("\r\n%-15.15s %s\r\n"
			,grp[sub[i]->grp]->sname,sub[i]->lname);
		getlastmsg(i,&l,0);
		sprintf(str,"%s%s.SFP",sub[i]->data_dir,sub[i]->code);
		if((file=nopen(str,O_WRONLY|O_CREAT))==-1)
			lprintf("\7ERROR opening/creating %s",str);
		else {
			write(file,&l,sizeof(time_t));
			close(file); } } }

if(misc&PURGE_ECHOMAIL) {

lputs("\r\n\r\nPurging EchoMail...\r\n");

for(g=0;g<total_grps;g++)
for(i=0;i<total_subs;i++)
	if(sub[i]->misc&SUB_FIDO && sub[i]->grp==g) {
		if(sub_code[0] && stricmp(sub_code,sub[i]->code))
            continue;
		if(!sub[i]->echopath[0])
            sprintf(sub[i]->echopath,"%s%s\\",echomail_dir,sub[i]->code);
		sprintf(str,"%s*.MSG",sub[i]->echopath);
		last=findfirst(str,&ff,0);
		while(!last) {
			sprintf(str,"%s%s",sub[i]->echopath,ff.name);
			if(startmsg!=2 || strcmp(ff.name,"1.MSG")) {
				lprintf("\r\nDeleting %s",str);
				remove(str); }
			last=findnext(&ff); } } }


if(misc&(IMPORT_NETMAIL|IMPORT_ECHOMAIL) && misc&REPORT) {
	sprintf(str,"%sSBBSFIDO.MSG",text_dir);
	if((file=nopen(str,O_WRONLY|O_CREAT|O_TRUNC))==-1) {
		lprintf("Error opening %s\r\n",str);
		exit(1); }
	sprintf(fname,"\1c\1h               "
		"���������������������������������������������������\r\n");
	sprintf(path,"\1c\1h               "
		"���������������������������������������������������\r\n");
	write(file,fname,strlen(fname));
	sprintf(str,"               \1n\1k\0016"
		" Last FidoNet Transfer on %.24s \1n\r\n",ctime(&start));
	write(file,str,strlen(str));
	write(file,path,strlen(path));
	write(file,fname,strlen(fname));
	sprintf(subj,"Imported %lu EchoMail and %lu NetMail Messages"
		,echomail,netmail);
	sprintf(str,"               \1n\1k\0016 %-50.50s\1n\r\n",subj);
	write(file,str,strlen(str));
	write(file,path,strlen(path));
	close(file); }

return(0);
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.