Пример #1
0
bool sbbs_t::pack_rep(uint hubnum)
{
	char		str[MAX_PATH+1];
	char 		tmp[MAX_PATH+1],tmp2[MAX_PATH+1];
	char		hubid_upper[LEN_QWKID+1];
	char		hubid_lower[LEN_QWKID+1];
	int 		file,mode;
	uint		i,j,k;
	long		msgcnt,submsgs,packedmail,netfiles=0,deleted;
	uint32_t	u;
	uint32_t	posts;
	uint32_t	mailmsgs;
	ulong		msgs;
	uint32_t	last;
	post_t*		post;
	mail_t*		mail;
	FILE*		rep;
	FILE*		hdrs=NULL;
	DIR*		dir;
	DIRENT*		dirent;
	smbmsg_t	msg;

	msgcnt=0L;
	delfiles(cfg.temp_dir,ALLFILES);

	SAFECOPY(hubid_upper,cfg.qhub[hubnum]->id);
	strupr(hubid_upper);
	SAFECOPY(hubid_lower,cfg.qhub[hubnum]->id);
	strlwr(hubid_lower);

	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
	if(fexistcase(str)) {
		eprintf(LOG_INFO,"Updating %s", str);
		external(cmdstr(cfg.qhub[hubnum]->unpack,str,ALLFILES,NULL),EX_OFFLINE);
	} else
		eprintf(LOG_INFO,"Creating %s", str);
	/*************************************************/
	/* Create SYSID.MSG, write header and leave open */
	/*************************************************/
	SAFEPRINTF2(str,"%s%s.MSG",cfg.temp_dir,hubid_upper);
	fexistcase(str);
	if((rep=fnopen(&file,str,O_CREAT|O_WRONLY|O_TRUNC))==NULL) {
		errormsg(WHERE,ERR_CREATE,str,O_CREAT|O_WRONLY|O_TRUNC);
		return(false);
	}
	if(filelength(file)<1) { 							/* New REP packet */
		SAFEPRINTF2(str,"%-*s"
			,QWK_BLOCK_LEN,hubid_upper);		/* So write header */
		fwrite(str,QWK_BLOCK_LEN,1,rep); 
	}
	fseek(rep,0L,SEEK_END);

	/* Always includes HEADERS.DAT in .REP packets which are only for QWKnet hubs */
	/* And *usually* a Synchronet system */
	SAFEPRINTF(str,"%sHEADERS.DAT",cfg.temp_dir);
	fexistcase(str);
	if((hdrs=fopen(str,"a"))==NULL)
		errormsg(WHERE,ERR_CREATE,str,0);

	/*********************/
	/* Pack new messages */
	/*********************/
	SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
	smb.retry_time=cfg.smb_retry_time;
	smb.subnum=INVALID_SUB;
	if((i=smb_open(&smb))!=0) {
		fclose(rep);
		if(hdrs!=NULL)
			fclose(hdrs);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
		return(false); 
	}

	/***********************/
	/* Pack E-mail, if any */
	/***********************/
	qwkmail_last=0;
	mail=loadmail(&smb,&mailmsgs,0,MAIL_YOUR,0);
	packedmail=0;
	if(mailmsgs) {
		eprintf(LOG_INFO,"Packing NetMail for %s", cfg.qhub[hubnum]->id);
		for(u=0;u<mailmsgs;u++) {
	//		bprintf("\b\b\b\b\b%-5lu",u+1);

			memset(&msg,0,sizeof(msg));
			msg.idx=mail[u];
			if(msg.idx.number>qwkmail_last)
				qwkmail_last=msg.idx.number;
			if(!loadmsg(&msg,mail[u].number))
				continue;

			SAFEPRINTF(str,"%s/",cfg.qhub[hubnum]->id);
			if(msg.to_net.type!=NET_QWK
				|| (strcmp((char *)msg.to_net.addr,cfg.qhub[hubnum]->id)
				&& strncmp((char *)msg.to_net.addr,str,strlen(str)))) {
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				continue; 
			}

			msgtoqwk(&msg,rep,QM_TO_QNET|QM_REP|A_LEAVE,INVALID_SUB,0,hdrs);
			packedmail++;
			smb_unlockmsghdr(&smb,&msg);
			smb_freemsgmem(&msg); 
			YIELD();	/* yield */
		}
		eprintf(LOG_INFO,"Packed %d NetMail messages",packedmail); 
	}
	smb_close(&smb);					/* Close the e-mail */
	if(mailmsgs)
		free(mail);

	for(i=0;i<cfg.qhub[hubnum]->subs;i++) {
		j=cfg.qhub[hubnum]->sub[i]; 			/* j now equals the real sub num */
		msgs=getlastmsg(j,&last,0);
		lncntr=0;						/* defeat pause */
		if(!msgs || last<=subscan[j].ptr) {
			if(subscan[j].ptr>last) {
				subscan[j].ptr=last;
				subscan[j].last=last; 
			}
			eprintf(LOG_INFO,remove_ctrl_a(text[NScanStatusFmt],tmp)
				,cfg.grp[cfg.sub[j]->grp]->sname
				,cfg.sub[j]->lname,0L,msgs);
			continue; 
		}

		SAFEPRINTF2(smb.file,"%s%s"
			,cfg.sub[j]->data_dir,cfg.sub[j]->code);
		smb.retry_time=cfg.smb_retry_time;
		smb.subnum=j;
		if((k=smb_open(&smb))!=0) {
			errormsg(WHERE,ERR_OPEN,smb.file,k,smb.last_error);
			continue; 
		}

		post=loadposts(&posts,j,subscan[j].ptr,LP_BYSELF|LP_OTHERS|LP_PRIVATE|LP_REP,NULL);
		eprintf(LOG_INFO,remove_ctrl_a(text[NScanStatusFmt],tmp)
			,cfg.grp[cfg.sub[j]->grp]->sname
			,cfg.sub[j]->lname,posts,msgs);
		if(!posts)	{ /* no new messages */
			smb_close(&smb);
			continue; 
		}

		subscan[j].ptr=last;                   /* set pointer */
		eprintf(LOG_INFO,"%s",remove_ctrl_a(text[QWKPackingSubboard],tmp));	/* ptr to last msg	*/
		submsgs=0;
		for(u=0;u<posts;u++) {
	//		bprintf("\b\b\b\b\b%-5lu",u+1);

			memset(&msg,0,sizeof(msg));
			msg.idx=post[u];
			if(!loadmsg(&msg,post[u].number))
				continue;

			if(msg.from_net.type && msg.from_net.type!=NET_QWK &&
				!(cfg.sub[j]->misc&SUB_GATE)) {
				smb_freemsgmem(&msg);
				smb_unlockmsghdr(&smb,&msg);
				continue; 
			}

			if(!strnicmp(msg.subj,"NE:",3) || (msg.from_net.type==NET_QWK &&
				route_circ((char *)msg.from_net.addr,cfg.qhub[hubnum]->id))) {
				smb_freemsgmem(&msg);
				smb_unlockmsghdr(&smb,&msg);
				continue; 
			}

			mode=cfg.qhub[hubnum]->mode[i]|QM_TO_QNET|QM_REP;
			if(mode&A_LEAVE) mode|=(QM_VIA|QM_TZ|QM_MSGID);
			if(msg.from_net.type!=NET_QWK)
				mode|=QM_TAGLINE;

			msgtoqwk(&msg,rep,mode,j,cfg.qhub[hubnum]->conf[i],hdrs);

			smb_freemsgmem(&msg);
			smb_unlockmsghdr(&smb,&msg);
			msgcnt++;
			submsgs++; 
			if(!(u%50))
				YIELD(); /* yield */
		}
		eprintf(LOG_INFO,remove_ctrl_a(text[QWKPackedSubboard],tmp),submsgs,msgcnt);
		free(post);
		smb_close(&smb); 
		YIELD();	/* yield */
	}

	if(hdrs!=NULL)
		fclose(hdrs);
	fclose(rep);			/* close HUB_ID.MSG */
	CRLF;
							/* Look for extra files to send out */
	SAFEPRINTF2(str,"%sqnet/%s.out",cfg.data_dir,hubid_lower);
	dir=opendir(str);
	while(dir!=NULL && (dirent=readdir(dir))!=NULL) {
		SAFEPRINTF3(str,"%sqnet/%s.out/%s",cfg.data_dir,hubid_lower,dirent->d_name);
		if(isdir(str))
			continue;
		SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,dirent->d_name);
		eprintf(LOG_INFO,remove_ctrl_a(text[RetrievingFile],tmp),str);
		if(!mv(str,tmp2,/* copy: */TRUE))
			netfiles++;
	}
	if(dir!=NULL)
		closedir(dir);
	if(netfiles)
		CRLF;

	if(!msgcnt && !netfiles && !packedmail) {
		eprintf(LOG_INFO,remove_ctrl_a(text[QWKNoNewMessages],tmp));
		return(true);	// Changed from false Mar-11-2005 (needs to be true to save updated ptrs)
	}

	/*******************/
	/* Compress Packet */
	/*******************/
	SAFEPRINTF2(str,"%s%s.REP",cfg.data_dir,hubid_upper);
	SAFEPRINTF2(tmp2,"%s%s",cfg.temp_dir,ALLFILES);
	i=external(cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL)
		,EX_OFFLINE|EX_WILDCARD);
	if(!fexistcase(str)) {
		eprintf(LOG_WARNING,"%s",remove_ctrl_a(text[QWKCompressionFailed],tmp));
		if(i)
			errormsg(WHERE,ERR_EXEC,cmdstr(cfg.qhub[hubnum]->pack,str,tmp2,NULL),i);
		else
			lprintf(LOG_ERR, "Couldn't compress REP packet");
		return(false); 
	}
	SAFEPRINTF2(str,"%sqnet/%s.out/",cfg.data_dir,hubid_lower);
	delfiles(str,ALLFILES);

	if(packedmail) {						/* Delete NetMail */
		SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
		smb.retry_time=cfg.smb_retry_time;
		smb.subnum=INVALID_SUB;
		if((i=smb_open(&smb))!=0) {
			errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
			return(true); 
		}

		mail=loadmail(&smb,&mailmsgs,0,MAIL_YOUR,0);

		if((i=smb_locksmbhdr(&smb))!=0) {			  /* Lock the base, so nobody */
			if(mailmsgs)
				free(mail);
			smb_close(&smb);
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
			return(true); 
		}

		if((i=smb_getstatus(&smb))!=0) {
			if(mailmsgs)
				free(mail);
			smb_close(&smb);
			errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
			return(true); 
		}

		deleted=0;
		/* Mark as READ and DELETE */
		for(u=0;u<mailmsgs;u++) {
			if(mail[u].number>qwkmail_last)
				continue;
			memset(&msg,0,sizeof(msg));
			/* !IMPORTANT: search by number (do not initialize msg.idx.offset) */
			if(!loadmsg(&msg,mail[u].number))
				continue;

			SAFEPRINTF(str,"%s/",cfg.qhub[hubnum]->id);
			if(msg.to_net.type!=NET_QWK
				|| (strcmp((char *)msg.to_net.addr,cfg.qhub[hubnum]->id)
				&& strncmp((char *)msg.to_net.addr,str,strlen(str)))) {
				smb_unlockmsghdr(&smb,&msg);
				smb_freemsgmem(&msg);
				continue; 
			}

			msg.hdr.attr|=MSG_DELETE;
			msg.idx.attr=msg.hdr.attr;
			if((i=smb_putmsg(&smb,&msg))!=0)
				errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
			else
				deleted++;
			smb_unlockmsghdr(&smb,&msg);
			smb_freemsgmem(&msg); 
		}

		if(deleted && cfg.sys_misc&SM_DELEMAIL)
			delmail(0,MAIL_YOUR);
		smb_close(&smb);
		if(mailmsgs)
			free(mail); 
		eprintf(LOG_INFO,"Deleted %d sent NetMail messages",deleted); 
	}

	return(true);
}
Пример #2
0
ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
	, int conf, FILE* hdrs)
{
	char	str[512],from[512],to[512],ch=0,tear=0,tearwatch=0,*buf,*p;
	char	asc;
	char	msgid[256];
	char 	tmp[512];
	long	l,size=0,offset;
	int 	i;
	ushort	hfield_type;
	struct	tm	tm;
	smbmsg_t	remsg;
	time_t	tt;

	offset=(long)ftell(qwk_fp);
	if(hdrs!=NULL) {
		fprintf(hdrs,"[%lx]\n",offset);

		/* Message-IDs */
		fprintf(hdrs,"Message-ID:  %s\n",get_msgid(&cfg,subnum,msg,msgid,sizeof(msgid)));
		if(msg->reply_id!=NULL)
			fprintf(hdrs,"In-Reply-To: %s\n",msg->reply_id);

		/* Time/Date/Zone info */
		fprintf(hdrs,"WhenWritten:  %-20s %04hx\n"
			,xpDateTime_to_isoDateTimeStr(
				time_to_xpDateTime(msg->hdr.when_written.time,smb_tzutc(msg->hdr.when_written.zone))
				,/* separators: */"","","", /* precision: */0
				,str,sizeof(str))
			,msg->hdr.when_written.zone
			);
		fprintf(hdrs,"WhenImported: %-20s %04hx\n"
			,xpDateTime_to_isoDateTimeStr(
				time_to_xpDateTime(msg->hdr.when_imported.time,smb_tzutc(msg->hdr.when_imported.zone))
				,/* separators: */"","","", /* precision: */0
				,str,sizeof(str))
			,msg->hdr.when_imported.zone
			);
		fprintf(hdrs,"WhenExported: %-20s %04hx\n"
			,xpDateTime_to_isoDateTimeStr(
				xpDateTime_now()
				,/* separators: */"","","", /* precision: */0
				,str,sizeof(str))
			,sys_timezone(&cfg)
			);
		fprintf(hdrs,"ExportedFrom: %s %s %"PRIu32"\n"
			,cfg.sys_id
			,subnum==INVALID_SUB ? "mail":cfg.sub[subnum]->code
			,msg->hdr.number
			);

		/* SENDER */
		fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SENDER),msg->from);
		if(msg->from_net.type)
			fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SENDERNETADDR),smb_netaddrstr(&msg->from_net,tmp));
		if((p=(char*)smb_get_hfield(msg,hfield_type=SENDERIPADDR,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n",smb_hfieldtype(hfield_type),p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=SENDERHOSTNAME,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n",smb_hfieldtype(hfield_type),p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=SENDERPROTOCOL,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n",smb_hfieldtype(hfield_type),p);
		if(msg->from_org!=NULL)
			fprintf(hdrs,"Organization: %s\n",msg->from_org);
		else if(msg->from_net.type==NET_NONE)
			fprintf(hdrs,"Organization: %s\n",cfg.sys_name);

		/* Reply-To */
		if((p=(char*)smb_get_hfield(msg,RFC822REPLYTO,NULL))==NULL) {
			if(msg->replyto_net.type==NET_INTERNET)
				p=(char*)msg->replyto_net.addr;
			else if(msg->replyto!=NULL)
				p=msg->replyto;
		}
		if(p!=NULL)
			fprintf(hdrs,"Reply-To: %s\n",p);	/* use original RFC822 header field */

		/* SUBJECT */
		fprintf(hdrs,"%s: %s\n",smb_hfieldtype(SUBJECT),msg->subj);

		/* RECIPIENT */
		fprintf(hdrs,"%s: %s\n",smb_hfieldtype(RECIPIENT),msg->to);
		if(msg->to_net.type)
			fprintf(hdrs,"%s: %s\n",smb_hfieldtype(RECIPIENTNETADDR),smb_netaddrstr(&msg->to_net,tmp));

		/* FidoNet */
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOAREA,NULL))!=NULL)	
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOSEENBY,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOPATH,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOMSGID,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOREPLYID,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOPID,NULL))!=NULL)	
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOFLAGS,NULL))!=NULL)	
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=FIDOTID,NULL))!=NULL)	
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);

		/* Synchronet */
		if((p=(char*)smb_get_hfield(msg,hfield_type=SMB_EDITOR,NULL))!=NULL)	
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);

		/* USENET */
		if((p=(char*)smb_get_hfield(msg,hfield_type=USENETPATH,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=USENETNEWSGROUPS,NULL))!=NULL)
			fprintf(hdrs,"%s: %s\n", smb_hfieldtype(hfield_type), p);

		/* RFC822 header fields: */
		for(i=0;i<msg->total_hfields;i++)
			if(msg->hfield[i].type==RFC822HEADER)
				fprintf(hdrs,"%s\n",truncsp_lines((char*)msg->hfield_dat[i]));

		/* Blank line: */
		fprintf(hdrs,"\n");
	}

	fprintf(qwk_fp,"%*s",QWK_BLOCK_LEN,"");		/* Init header to space */

	/* QWKE compatible kludges */
	SAFECOPY(from,msg->from);
	if(msg->from_net.addr && (uint)subnum==INVALID_SUB && !(mode&QM_TO_QNET)) {
		if(msg->from_net.type==NET_FIDO)
			sprintf(from,"%.128s@%.128s"
				,msg->from,smb_faddrtoa((faddr_t *)msg->from_net.addr,tmp));
		else if(msg->from_net.type==NET_INTERNET || strchr((char*)msg->from_net.addr,'@')!=NULL)
			sprintf(from,"%.128s",(char*)msg->from_net.addr);
		else
			sprintf(from,"%.128s@%.128s",msg->from,(char*)msg->from_net.addr);
	}
	if(msg->hdr.attr&MSG_ANONYMOUS && !SYSOP)
		SAFECOPY(from,text[Anonymous]); 
	else if((subnum==INVALID_SUB || (useron.qwk&QWK_EXT)) && strlen(from) > QWK_HFIELD_LEN) {
		size+=fprintf(qwk_fp,"From: %.128s%c", from, QWK_NEWLINE);
		SAFECOPY(from,msg->from); 
	} 

	SAFECOPY(to,msg->to);
	if(msg->to_net.addr && (uint)subnum==INVALID_SUB) {
		if(msg->to_net.type==NET_FIDO)
			sprintf(to,"%.128s@%s",msg->to,smb_faddrtoa((faddr_t *)msg->to_net.addr,tmp));
		else if(msg->to_net.type==NET_INTERNET)
			sprintf(to,"%.128s",(char*)msg->to_net.addr);
		else if(msg->to_net.type==NET_QWK) {
			if(mode&QM_TO_QNET) {
				p=strchr((char *)msg->to_net.addr,'/');
				if(p) { 	/* Another hop */
					p++;
					SAFECOPY(to,"NETMAIL");
					size+=fprintf(qwk_fp,"%.128s@%.128s%c",msg->to,p,QWK_NEWLINE);
				}
				else
					sprintf(to,"%.128s",msg->to); 
			}
			else
				sprintf(to,"%.128s@%.128s",msg->to,(char*)msg->to_net.addr); 
		}
		else
			sprintf(to,"%.128s@%.128s",msg->to,(char*)msg->to_net.addr);
	}
	if((subnum==INVALID_SUB || (useron.qwk&QWK_EXT)) && strlen(to) > QWK_HFIELD_LEN) {
		size+=fprintf(qwk_fp,"To: %.128s%c", to, QWK_NEWLINE);
		if(msg->to_net.type==NET_QWK)
			SAFECOPY(to,"NETMAIL");
		else
			SAFECOPY(to,msg->to); 
	}
	if((useron.qwk&QWK_EXT) && strlen(msg->subj) > QWK_HFIELD_LEN)
		size+=fprintf(qwk_fp,"Subject: %.128s%c", msg->subj, QWK_NEWLINE);

	if(msg->from_net.type==NET_QWK && mode&QM_VIA && !msg->forwarded)
		size+=fprintf(qwk_fp,"@VIA: %s%c"
			,(char*)msg->from_net.addr,QWK_NEWLINE);
	
	if(mode&QM_MSGID && (uint)subnum!=INVALID_SUB) {
		size+=fprintf(qwk_fp,"@MSGID: %s%c"
			,get_msgid(&cfg,subnum,msg,msgid,sizeof(msgid)),QWK_NEWLINE);

		if(msg->reply_id) {
			SAFECOPY(tmp,msg->reply_id);
			truncstr(tmp," ");
			size+=fprintf(qwk_fp,"@REPLY: %s%c"
				,tmp,QWK_NEWLINE);
		} else if(msg->hdr.thread_back) {
			memset(&remsg,0,sizeof(remsg));
			remsg.hdr.number=msg->hdr.thread_back;
			if(smb_getmsgidx(&smb, &remsg))
				size+=fprintf(qwk_fp,"@REPLY: <%s>%c",smb.last_error,QWK_NEWLINE);
			else
				size+=fprintf(qwk_fp,"@REPLY: %s%c"
					,get_msgid(&cfg,subnum,&remsg,msgid,sizeof(msgid))
					,QWK_NEWLINE);
		}
	}

	if(msg->hdr.when_written.zone && mode&QM_TZ)
		size+=fprintf(qwk_fp,"@TZ: %04hx%c",msg->hdr.when_written.zone,QWK_NEWLINE);

	if(msg->replyto!=NULL && mode&QM_REPLYTO)
		size+=fprintf(qwk_fp,"@REPLYTO: %s%c"
			,msg->replyto,QWK_NEWLINE);

	p=0;
	for(i=0;i<msg->total_hfields;i++) {
		if(msg->hfield[i].type==SENDER)
			p=(char *)msg->hfield_dat[i];
		if(msg->hfield[i].type==FORWARDED && p) {
			size+=fprintf(qwk_fp,"Forwarded from %s on %s%c",p
				,timestr(*(time32_t *)msg->hfield_dat[i])
				,QWK_NEWLINE);
		} 
	}

	buf=smb_getmsgtxt(&smb,msg,GETMSGTXT_ALL);
	if(!buf)
		return(0);

	for(l=0;buf[l];l++) {
		ch=buf[l];

		if(ch=='\n') {
			if(tear)
				tear++; 				/* Count LFs after tearline */
			if(tear>3)					/* more than two LFs after the tear */
				tear=0;
			if(tearwatch==4) {			/* watch for LF---LF */
				tear=1;
				tearwatch=0; 
			}
			else if(!tearwatch)
				tearwatch=1;
			else
				tearwatch=0;
			if(l && buf[l-1]=='\r')		/* Replace CRLF with funky char */
				ch=QWK_NEWLINE;			/* but leave sole LF (soft-NL) alone */
			fputc(ch,qwk_fp);		  
			size++;
			continue; 
		}

		if(ch=='\r') {					/* Ignore CRs */
			if(tearwatch<4) 			/* LF---CRLF is okay */
				tearwatch=0;			/* LF-CR- is not okay */
			continue; 
		}

		if(ch==' ' && tearwatch==4) {	/* watch for "LF--- " */
			tear=1;
			tearwatch=0; 
		}

		if(ch=='-') {                   /* watch for "LF---" */
			if(l==0 || (tearwatch && tearwatch<4))
				tearwatch++;
			else
				tearwatch=0; 
		}
		else
			tearwatch=0;

		if((uint)subnum!=INVALID_SUB && cfg.sub[subnum]->misc&SUB_ASCII) {
			if(ch<' ' && ch!=1)
				ch='.';
			else if((uchar)ch>0x7f)
				ch=exascii_to_ascii_char(ch); 
		}

		if(ch==QWK_NEWLINE)					/* funky char */
			ch='*';

		if(ch==CTRL_A) {
			ch=buf[++l];
			if(ch==0 || toupper(ch)=='Z')		/* EOF */
				break;
			if((asc=ctrl_a_to_ascii_char(ch)) != 0) {
				fputc(asc,qwk_fp);
				size++;
				continue;
			}
			if(mode&A_EXPAND) {
				str[0]=0;
				switch(toupper(ch)) {
					case 'W':
						SAFECOPY(str,ansi(LIGHTGRAY));
						break;
					case 'K':
						SAFECOPY(str,ansi(BLACK));
						break;
					case 'H':
						SAFECOPY(str,ansi(HIGH));
						break;
					case 'I':
						SAFECOPY(str,ansi(BLINK));
						break;
					case '-':
					case '_':
					case 'N':   /* Normal */
						SAFECOPY(str,ansi(ANSI_NORMAL));
						break;
					case 'R':
						SAFECOPY(str,ansi(RED));
						break;
					case 'G':
						SAFECOPY(str,ansi(GREEN));
						break;
					case 'B':
						SAFECOPY(str,ansi(BLUE));
						break;
					case 'C':
						SAFECOPY(str,ansi(CYAN));
						break;
					case 'M':
						SAFECOPY(str,ansi(MAGENTA));
						break;
					case 'Y':   /* Yellow */
						SAFECOPY(str,ansi(BROWN));
						break;
					case '0':
						SAFECOPY(str,ansi(BG_BLACK));
						break;
					case '1':
						SAFECOPY(str,ansi(BG_RED));
						break;
					case '2':
						SAFECOPY(str,ansi(BG_GREEN));
						break;
					case '3':
						SAFECOPY(str,ansi(BG_BROWN));
						break;
					case '4':
						SAFECOPY(str,ansi(BG_BLUE));
						break;
					case '5':
						SAFECOPY(str,ansi(BG_MAGENTA));
						break;
					case '6':
						SAFECOPY(str,ansi(BG_CYAN));
						break; 
					case '7':
						SAFECOPY(str,ansi(BG_LIGHTGRAY));
						break;
				}
				if(str[0])
					size+=fwrite(str,sizeof(char),strlen(str),qwk_fp);
				continue; 
			} 						/* End Expand */
			if(mode&A_LEAVE && valid_ctrl_a_code(ch)) {
				fputc(CTRL_A,qwk_fp);
				fputc(ch,qwk_fp);
				size+=2L; 
			}
			continue; 
		} 							/* End of Ctrl-A shit */
		fputc(ch,qwk_fp);
		size++; 
	}

	free(buf);
	if(ch!=QWK_NEWLINE) {
		fputc(QWK_NEWLINE,qwk_fp); 		/* make sure it ends in CRLF */
		size++; 
	}

	if(mode&QM_TAGLINE && !(cfg.sub[subnum]->misc&SUB_NOTAG)) {
		if(!tear)										/* no tear line */
			SAFEPRINTF(str,"\1n---%c",QWK_NEWLINE);        /* so add one */
		else
			SAFECOPY(str,"\1n");
		if(cfg.sub[subnum]->misc&SUB_ASCII) ch='*';
		else ch='þ';
		safe_snprintf(tmp,sizeof(tmp)," %c \1g%.10s\1n %c %.127s%c"
			,ch,VERSION_NOTICE,ch,cfg.sub[subnum]->tagline,QWK_NEWLINE);
		strcat(str,tmp);
		if(!(mode&A_LEAVE))
			remove_ctrl_a(str,str);
		size+=fwrite(str,sizeof(char),strlen(str),qwk_fp);
	}

	while(size%QWK_BLOCK_LEN) {				 /* Pad with spaces */
		size++;
		fputc(' ',qwk_fp); 
	}

	tt=msg->hdr.when_written.time;
	if(localtime_r(&tt,&tm)==NULL)
		memset(&tm,0,sizeof(tm));

	safe_snprintf(tmp,sizeof(tmp),"%02u-%02u-%02u%02u:%02u"
		,tm.tm_mon+1,tm.tm_mday,TM_YEAR(tm.tm_year)
		,tm.tm_hour,tm.tm_min);

	if(msg->hdr.attr&MSG_PRIVATE) {
		if(msg->hdr.attr&MSG_READ)
			ch='*'; /* private, read */
		else
			ch='+'; /* private, unread */ }
	else {
		if(msg->hdr.attr&MSG_READ)
			ch='-'; /* public, read */
		else
			ch=' '; /* public, unread */ }


	safe_snprintf(str,sizeof(str),"%c%-7lu%-13.13s%-25.25s"
		"%-25.25s%-25.25s%12s%-8lu%-6lu\xe1%c%c%c%c%c"
		,ch                     /* message status flag */
		,mode&QM_REP ? (ulong)conf /* conference or */
			: msg->hdr.number&MAX_MSGNUM	/* message number */
		,tmp					/* date and time */
		,to 					/* To: */
		,from					/* From: */
		,msg->subj              /* Subject */
		,nulstr                 /* Password */
		,msg->hdr.thread_back&MAX_MSGNUM   /* Message Re: Number */
		,(size/QWK_BLOCK_LEN)+1	/* Number of blocks */
		,(char)conf&0xff        /* Conference number lo byte */
		,(ushort)conf>>8		/*					 hi byte */
		,' '                     /* not used */
		,' '                     /* not used */
		,useron.rest&FLAG('Q') ? '*' : ' '     /* Net tag line */
		);

	fseek(qwk_fp,offset,SEEK_SET);
	fwrite(str,QWK_BLOCK_LEN,1,qwk_fp);
	fseek(qwk_fp,size,SEEK_CUR);

	return(size);
}