Exemple #1
0
/* length=0 specifies ASCIIZ data											*/
int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
								 ,unsigned flags, const void* data, size_t length)
{
	int			retval;
	size_t		n;
	hash_t**	hashes;
	hash_t		found;

	if((hashes=(hash_t**)malloc(sizeof(hash_t*)*2))==NULL)
		return(SMB_ERR_MEM);

	if(length==0)
		hashes[0]=smb_hashstr(0,0,source,flags,data);
	else
		hashes[0]=smb_hash(0,0,source,flags,data,length);
	if(hashes[0]==NULL)
		return(SMB_ERR_MEM);

	hashes[1]=NULL;	/* terminate list */

	if((retval=smb_findhash(smb, hashes, &found, 1<<source, FALSE))==SMB_SUCCESS) {
		if(found.number==0)
			retval=SMB_FAILURE;	/* use better error value here? */
		else {
			msg->hdr.number=found.number;
			retval=smb_getmsgidx(smb, msg);
		}
	}

	FREE_LIST(hashes,n);

	return(retval);
}
Exemple #2
0
ulong first_msg()
{
	smbmsg_t msg;

	msg.offset=0;
	msg.hdr.number=0;
	if(smb_getmsgidx(&smb,&msg))			/* Get first message index */
		return(0);
	return(msg.idx.number);
}
Exemple #3
0
int sbbs_t::loadmsg(smbmsg_t *msg, ulong number)
{
	char str[128];
	int i;

	if(msg->idx.offset) {				/* Load by offset if specified */

		if((i=smb_lockmsghdr(&smb,msg))!=0) {
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
			return(0); 
		}

		i=smb_getmsghdr(&smb,msg);
		if(i==SMB_SUCCESS) {
			if(msg->hdr.number==number)
				return(1);
			/* Wrong offset  */
			smb_freemsgmem(msg);
		}

		smb_unlockmsghdr(&smb,msg); 
	}

	msg->hdr.number=number;
	if((i=smb_getmsgidx(&smb,msg))!=SMB_SUCCESS)				 /* Message is deleted */
		return(0);
	if((i=smb_lockmsghdr(&smb,msg))!=SMB_SUCCESS) {
		errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
		return(0); 
	}
	if((i=smb_getmsghdr(&smb,msg))!=SMB_SUCCESS) {
		sprintf(str,"(%06"PRIX32") #%"PRIu32"/%lu %s",msg->idx.offset,msg->idx.number
			,number,smb.file);
		smb_unlockmsghdr(&smb,msg);
		errormsg(WHERE,ERR_READ,str,i,smb.last_error);
		return(0); 
	}
	return(msg->total_hfields);
}
Exemple #4
0
time_t sbbs_t::getmsgtime(uint subnum, ulong ptr)
{
	int 	i;
	smbmsg_t msg;
	idxrec_t lastidx;

	sprintf(smb.file,"%s%s",cfg.sub[subnum]->data_dir,cfg.sub[subnum]->code);
	smb.retry_time=cfg.smb_retry_time;
	smb.subnum=subnum;
	if((i=smb_open(&smb))!=0) {
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
		return(0); 
	}
	if(!filelength(fileno(smb.sid_fp))) {			/* Empty base */
		smb_close(&smb);
		return(0); 
	}
	msg.offset=0;
	msg.hdr.number=0;
	if(smb_getmsgidx(&smb,&msg)) {				/* Get first message index */
		smb_close(&smb);
		return(0); 
	}
	if(!ptr || msg.idx.number>=ptr) {			/* ptr is before first message */
		smb_close(&smb);
		return(msg.idx.time);   				/* so return time of first msg */
	}

	if(smb_getlastidx(&smb,&lastidx)) { 			 /* Get last message index */
		smb_close(&smb);
		return(0); 
	}
	if(lastidx.number<ptr) {					/* ptr is after last message */
		smb_close(&smb);
		return(lastidx.time);	 				/* so return time of last msg */
	}

	msg.idx.time=0;
	msg.hdr.number=ptr;
	if(!smb_getmsgidx(&smb,&msg)) {
		smb_close(&smb);
		return(msg.idx.time); 
	}

	if(ptr-msg.idx.number < lastidx.number-ptr) {
		msg.offset=0;
		msg.idx.number=0;
		while(msg.idx.number<ptr) {
			msg.hdr.number=0;
			if(smb_getmsgidx(&smb,&msg) || msg.idx.number>=ptr)
				break;
			msg.offset++; 
		}
		smb_close(&smb);
		return(msg.idx.time); 
	}

	ptr--;
	while(ptr) {
		msg.hdr.number=ptr;
		if(!smb_getmsgidx(&smb,&msg))
			break;
		ptr--; 
	}
	smb_close(&smb);
	return(msg.idx.time);
}
Exemple #5
0
void sbbs_t::readmail(uint usernumber, int which)
{
	char	str[256],str2[256],str3[256],done=0,domsg=1
			,*p,*tp,*sp,ch;
	char 	tmp[512];
	int		i,j;
	int		error;
	int		mismatches=0,act;
    long    length,l,lm_mode;
	ulong	last;
	bool	replied;
	file_t	fd;
	mail_t	*mail;
	smbmsg_t msg;

	if(which==MAIL_SENT && useron.rest&FLAG('K')) {
		bputs(text[R_ReadSentMail]);
		return;
	}

	msg.total_hfields=0;			/* init to NULL, cause not allocated yet */

	fd.dir=cfg.total_dirs+1;			/* temp dir for file attachments */

	if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
		errormsg(WHERE,ERR_OPEN,"MAIL",i);
		return; }
	sprintf(smb.file,"%smail",cfg.data_dir);
	smb.retry_time=cfg.smb_retry_time;
	smb.subnum=INVALID_SUB;
	if((i=smb_open(&smb))!=0) {
		smb_stack(&smb,SMB_STACK_POP);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
		return; }

	if(cfg.sys_misc&SM_SYSVDELM && (SYSOP || cfg.sys_misc&SM_USRVDELM))
		lm_mode=LM_INCDEL;
	else
		lm_mode=0;
	mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
	if(!smb.msgs) {
		if(which==MAIL_SENT)
			bputs(text[NoMailSent]);
		else if(which==MAIL_ALL)
			bputs(text[NoMailOnSystem]);
		else
			bputs(text[NoMailWaiting]);
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);
		return; }

	last=smb.status.last_msg;

	if(which==MAIL_SENT)
		act=NODE_RSML;
	else if(which==MAIL_ALL)
		act=NODE_SYSP;
	else
		act=NODE_RMAL;
	action=act;
	if(smb.msgs>1 && which!=MAIL_ALL) {
		if(which==MAIL_SENT)
			bputs(text[MailSentLstHdr]);
		else
			bputs(text[MailWaitingLstHdr]);

		for(smb.curmsg=0;smb.curmsg<smb.msgs && !msgabort();smb.curmsg++) {
			if(msg.total_hfields)
				smb_freemsgmem(&msg);
			msg.total_hfields=0;
			msg.idx.offset=mail[smb.curmsg].offset;
			if(!loadmsg(&msg,mail[smb.curmsg].number))
				continue;
			smb_unlockmsghdr(&smb,&msg);
			bprintf(text[MailWaitingLstFmt],smb.curmsg+1
				,which==MAIL_SENT ? msg.to
				: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP ? text[Anonymous]
				: msg.from
				,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_REPLIED ? 'R'
					: msg.hdr.attr&MSG_READ ? ' '
					: msg.from_net.type || msg.to_net.type ? 'N':'*'
				,msg.subj);
			smb_freemsgmem(&msg);
			msg.total_hfields=0; }

		ASYNC;
		if(!(sys_status&SS_ABORT)) {
			bprintf(text[StartWithN],1L);
			if((long)(smb.curmsg=getnum(smb.msgs))>0)
				smb.curmsg--;
			else if((long)smb.curmsg==-1) {
				free(mail);
				smb_close(&smb);
				smb_stack(&smb,SMB_STACK_POP);
				return; } }
		sys_status&=~SS_ABORT; }
	else {
		smb.curmsg=0;
		if(which==MAIL_ALL)
			domsg=0; }
	if(which==MAIL_SENT) {
		sprintf(str,"%s read sent mail",useron.alias);
		logline("E",str);
	} else if(which==MAIL_ALL) {
		sprintf(str,"%s read all mail",useron.alias);
		logline("S+",str);
	} else {
		sprintf(str,"%s read mail",useron.alias);
		logline("E",str);
	}
	if(useron.misc&RIP) {
		strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
			"allmail" : "sentmail");
		menu(str); }
	while(online && !done) {
		action=act;

		if(msg.total_hfields)
			smb_freemsgmem(&msg);
		msg.total_hfields=0;

		msg.idx.offset=mail[smb.curmsg].offset;
		msg.idx.number=mail[smb.curmsg].number;
		msg.idx.to=mail[smb.curmsg].to;
		msg.idx.from=mail[smb.curmsg].from;
		msg.idx.subj=mail[smb.curmsg].subj;

		if((i=smb_locksmbhdr(&smb))!=0) {
			errormsg(WHERE,ERR_LOCK,smb.file,i);
			break; }

		if((i=smb_getstatus(&smb))!=0) {
			smb_unlocksmbhdr(&smb);
			errormsg(WHERE,ERR_READ,smb.file,i);
			break; }
		smb_unlocksmbhdr(&smb);

		if(smb.status.last_msg!=last) { 	/* New messages */
			last=smb.status.last_msg;
			free(mail);
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);   /* So re-load */
			if(!smb.msgs)
				break;
			for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
				if(mail[smb.curmsg].number==msg.idx.number)
					break;
			if(smb.curmsg>=smb.msgs)
				smb.curmsg=(smb.msgs-1);
			continue; }

		if(!loadmsg(&msg,mail[smb.curmsg].number)) {	/* Message header gone */
			if(mismatches>5) {	/* We can't do this too many times in a row */
				errormsg(WHERE,ERR_CHK,"message number",mail[smb.curmsg].number);
				break; }
			free(mail);
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
			if(!smb.msgs)
				break;
			if(smb.curmsg>(smb.msgs-1))
				smb.curmsg=(smb.msgs-1);
			mismatches++;
			continue; }
		smb_unlockmsghdr(&smb,&msg);
		msg.idx.attr=msg.hdr.attr;

		mismatches=0;

		if(domsg && !(sys_status&SS_ABORT)) {

			show_msg(&msg
				,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
					? 0:P_NOATCODES);

			if(msg.hdr.auxattr&MSG_FILEATTACH) {  /* Attached file */
				smb_getmsgidx(&smb,&msg);
				strcpy(str,msg.subj);					/* filenames in title */
//				strupr(str);
				tp=str;
				while(online) {
					p=strchr(tp,' ');
					if(p) *p=0;
					sp=strrchr(tp,'/');              /* sp is slash pointer */
					if(!sp) sp=strrchr(tp,'\\');
					if(sp) tp=sp+1;
					padfname(tp,fd.name);
					sprintf(str2,"%sfile/%04u.in/%s"  /* str2 is path/fname */
						,cfg.data_dir,msg.idx.to,tp);
					length=flength(str2);
					if(length<1)
						bputs(text[FileNotFound]);
					else if(!(useron.exempt&FLAG('T')) && cur_cps && !SYSOP
						&& length/(long)cur_cps>(time_t)timeleft)
						bputs(text[NotEnoughTimeToDl]);
					else {
						sprintf(str3,text[DownloadAttachedFileQ]
							,tp,ultoac(length,tmp));
						if(length>0L && yesno(str3)) {
#if 0	/* no such thing as local logon */
							if(online==ON_LOCAL) {
								bputs(text[EnterPath]);
								if(getstr(str3,60,K_LINE)) {
									backslashcolon(str3);
									sprintf(tmp,"%s%s",str3,tp);
									if(!mv(str2,tmp,which!=MAIL_YOUR)) {
										logon_dlb+=length;
										logon_dls++;
										useron.dls=(ushort)adjustuserrec(&cfg,useron.number
											,U_DLS,5,1);
										useron.dlb=adjustuserrec(&cfg,useron.number
											,U_DLB,10,length);
										bprintf(text[FileNBytesSent]
											,fd.name,ultoac(length,tmp)); } } }

							else 
#endif
							{	/* Remote User */
								xfer_prot_menu(XFER_DOWNLOAD);
								mnemonics(text[ProtocolOrQuit]);
								strcpy(str3,"Q");
								for(i=0;i<cfg.total_prots;i++)
									if(cfg.prot[i]->dlcmd[0]
										&& chk_ar(cfg.prot[i]->ar,&useron)) {
										sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
										strcat(str3,tmp); }
								ch=(char)getkeys(str3,0);
								for(i=0;i<cfg.total_prots;i++)
									if(cfg.prot[i]->dlcmd[0] && ch==cfg.prot[i]->mnemonic
										&& chk_ar(cfg.prot[i]->ar,&useron))
										break;
								if(i<cfg.total_prots) {
									error=protocol(cfg.prot[i],XFER_DOWNLOAD,str2,nulstr,false);
									if(checkprotresult(cfg.prot[i],error,&fd)) {
										if(which==MAIL_YOUR)
											remove(str2);
										logon_dlb+=length;	/* Update stats */
										logon_dls++;
										useron.dls=(ushort)adjustuserrec(&cfg,useron.number
											,U_DLS,5,1);
										useron.dlb=adjustuserrec(&cfg,useron.number
											,U_DLB,10,length);
										bprintf(text[FileNBytesSent]
											,fd.name,ultoac(length,tmp));
										sprintf(str3
											,"%s downloaded attached file: %s"
											,useron.alias
											,fd.name);
										logline("D-",str3); 
									}
									autohangup(); 
								} 
							} 
						} 
					}
					if(!p)
						break;
					tp=p+1;
					while(*tp==' ') tp++; 
				}
				sprintf(str,"%sfile/%04u.in",cfg.data_dir,usernumber);
				rmdir(str); }
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
				mail[smb.curmsg].attr|=MSG_READ;
				if(thisnode.status==NODE_INUSE)
					telluser(&msg);
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;						/* Search by number */
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
					if(loadmsg(&msg,msg.idx.number)) {
						msg.hdr.attr|=MSG_READ;
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
							errormsg(WHERE,ERR_WRITE,smb.file,i);
						smb_unlockmsghdr(&smb,&msg); }
					smb_unlocksmbhdr(&smb); }
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
					continue; } }
			}
		else domsg=1;

		if(useron.misc&WIP) {
			strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
				"allmail" : "sentmail");
			menu(str); }

		ASYNC;
		if(which==MAIL_SENT)
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
		else if(which==MAIL_ALL)
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
		else
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
		sprintf(str,"ADFLNQRT?<>[]{}-+");
		if(SYSOP)
			strcat(str,"CUSPH");
		if(which!=MAIL_YOUR)
			strcat(str,"E");
		l=getkeys(str,smb.msgs);
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
			smb.curmsg=(l&~0x80000000L)-1;
			continue; }
		switch(l) {
			case 'A':   /* Auto-reply to last piece */
			case 'R':
				if(l==(cfg.sys_misc&SM_RA_EMU ? 'A' : 'R'))  /* re-read last message */
					break;

				if(which==MAIL_SENT)
					break;
				if((msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP) {
					bputs(text[CantReplyToAnonMsg]);
					break; }

				quotemsg(&msg,1);

				if(msg.from_net.addr==NULL)
					SAFECOPY(str,msg.from);
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
					SAFEPRINTF2(str,"%s@%s",msg.from
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
				else if(msg.from_net.type==NET_INTERNET) {
					if(msg.replyto_net.type==NET_INTERNET)
						SAFECOPY(str,(char *)msg.replyto_net.addr);
					else
						SAFECOPY(str,(char *)msg.from_net.addr);
				} else
					SAFEPRINTF2(str,"%s@%s",msg.from,(char*)msg.from_net.addr);

				SAFECOPY(str2,str);

				bputs(text[Email]);
				if(!getstr(str,64,K_EDIT|K_AUTODEL))
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);

				if(!stricmp(str2,str))		/* Reply to sender */
					sprintf(str2,text[Regarding],msg.subj);
				else						/* Reply to other */
					sprintf(str2,text[RegardingByOn],msg.subj,msg.from
						,timestr((time_t *)&msg.hdr.when_written.time));

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
					sprintf(str2,text[DeleteMailQ],msg.from); }
				else {
					if(!msg.from_net.type && !stricmp(str,msg.from))
						replied=email(msg.idx.from,str2,msg.subj,WM_EMAIL|WM_QUOTE);
					else if(!stricmp(str,"SYSOP"))
						replied=email(1,str2,msg.subj,WM_EMAIL|WM_QUOTE);
					else if((i=finduser(str))!=0)
						replied=email(i,str2,msg.subj,WM_EMAIL|WM_QUOTE);
					else
						replied=false;
					sprintf(str2,text[DeleteMailQ],msg.from); }

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
						if(loadmsg(&msg,msg.idx.number)) {
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
								errormsg(WHERE,ERR_WRITE,smb.file,i);
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
				}

				if(msg.hdr.attr&MSG_DELETE || !yesno(str2)) {
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
					else done=1;
					break;	}
				/* Case 'D': must follow! */
			case 'D':   /* Delete last piece (toggle) */
				if(msg.hdr.attr&MSG_PERMANENT) {
					bputs("\r\nPermanent message.\r\n");
					domsg=0;
					break; }
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
					if(loadmsg(&msg,msg.idx.number)) {
						msg.hdr.attr^=MSG_DELETE;
						msg.idx.attr=msg.hdr.attr;
		//				  mail[smb.curmsg].attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
							errormsg(WHERE,ERR_WRITE,smb.file,i);
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				else done=1;
				break;
			case 'F':  /* Forward last piece */
				domsg=0;
				bputs(text[ForwardMailTo]);
				if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
					break;
				i=finduser(str);
				if(!i)
					break;
				domsg=1;
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				else done=1;
				smb_getmsgidx(&smb,&msg);
				forwardmail(&msg,i);
				if(msg.hdr.attr&MSG_PERMANENT)
					break;
				sprintf(str2,text[DeleteMailQ],msg.from);
				if(!yesno(str2))
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
					if(loadmsg(&msg,msg.idx.number)) {
						msg.hdr.attr|=MSG_DELETE;
						msg.idx.attr=msg.hdr.attr;
		//				  mail[smb.curmsg].attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
							errormsg(WHERE,ERR_WRITE,smb.file,i);
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}

				break;
			case 'H':
				domsg=0;
				msghdr(&msg);
				break;
			case 'L':     /* List mail */
				domsg=0;
				bprintf(text[StartWithN],(long)smb.curmsg+1);
				if((i=getnum(smb.msgs))>0)
					i--;
				else if(i==-1)
					break;
				else
					i=smb.curmsg;
				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
				for(;i<smb.msgs && !msgabort();i++) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=mail[i].offset;
					if(!loadmsg(&msg,mail[i].number))
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
							,i+1,msg.from,msg.to
							,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_REPLIED ? 'R'
								: msg.hdr.attr&MSG_READ ? ' '
								: msg.from_net.type || msg.to_net.type ? 'N':'*'
							,msg.subj);
					else
						bprintf(text[MailWaitingLstFmt],i+1
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
							,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_REPLIED ? 'R'
								: msg.hdr.attr&MSG_READ ? ' '
								: msg.from_net.type || msg.to_net.type ? 'N':'*'
							,msg.subj);
					smb_freemsgmem(&msg);
					msg.total_hfields=0; }
				break;
			case 'Q':
				done=1;
				break;
			case 'C':   /* Change attributes of last piece */
				i=chmsgattr(msg.hdr.attr);
				if(msg.hdr.attr==i)
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
					if(loadmsg(&msg,msg.idx.number)) {
						msg.hdr.attr=msg.idx.attr=(ushort)i;
						if((i=smb_putmsg(&smb,&msg))!=0)
							errormsg(WHERE,ERR_WRITE,smb.file,i);
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
				break;
			case '>':
				for(i=smb.curmsg+1;i<smb.msgs;i++)
					if(mail[i].subj==msg.idx.subj)
						break;
				if(i<smb.msgs)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case '<':   /* Search Title backward */
				for(i=smb.curmsg-1;i>-1;i--)
					if(mail[i].subj==msg.idx.subj)
						break;
				if(i>-1)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
				for(i=smb.curmsg+1;i<smb.msgs;i++)
					if(mail[i].from==msg.idx.from)
						break;
				if(i<smb.msgs)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case 'N':   /* Got to next un-read message */
				for(i=smb.curmsg+1;i<smb.msgs;i++)
					if(!(mail[i].attr&MSG_READ))
						break;
				if(i<smb.msgs)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
				for(i=smb.curmsg-1;i>-1;i--)
					if(mail[i].from==msg.idx.from)
						break;
				if(i>-1)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
				for(i=smb.curmsg+1;i<smb.msgs;i++)
					if(mail[i].to==msg.idx.to)
						break;
				if(i<smb.msgs)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
				for(i=smb.curmsg-1;i>-1;i--)
					if(mail[i].to==msg.idx.to)
						break;
				if(i>-1)
					smb.curmsg=i;
				else
					domsg=0;
				break;
			case 0:
			case '+':
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				else done=1;
				break;
			case '-':
				if(smb.curmsg>0) smb.curmsg--;
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
				if(getstr(str,40,K_LINE))
					msgtotxt(&msg,str,1,1);
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
				i=smb.curmsg;
				if(i) i++;
				j=i+10;
				if(j>smb.msgs)
					j=smb.msgs;

				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
				for(;i<j;i++) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=mail[i].offset;
					if(!loadmsg(&msg,mail[i].number))
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
							,i+1,msg.from,msg.to
							,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_REPLIED ? 'R'
								: msg.hdr.attr&MSG_READ ? ' ' 
								: msg.from_net.type || msg.to_net.type ? 'N':'*'
							,msg.subj);
					else
						bprintf(text[MailWaitingLstFmt],i+1
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
							,msg.hdr.attr&MSG_DELETE ? '-' : msg.hdr.attr&MSG_REPLIED ? 'R'
								: msg.hdr.attr&MSG_READ ? ' '
								: msg.from_net.type || msg.to_net.type ? 'N':'*'
							,msg.subj);
					smb_freemsgmem(&msg);
					msg.total_hfields=0; }
				smb.curmsg=(i-1);
				break;
			case 'U':   /* user edit */
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
				useredit(which==MAIL_SENT ? msg.idx.to : msg.idx.from);
				break;
			case 'P':   /* Purge author and all mail to/from */
				if(noyes(text[AreYouSureQ]))
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
				purgeuser(msg.idx.from);
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				break;
			case '?':
				strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL
						? "allmail" : "sentmail");
				menu(str);
				if(SYSOP && which==MAIL_SENT)
					menu("syssmail");
				else if(SYSOP && which==MAIL_YOUR)
					menu("sysmailr");   /* Sysop Mail Read */
				domsg=0;
				break;
				} }

	if(msg.total_hfields)
		smb_freemsgmem(&msg);

	if(smb.msgs)
		free(mail);

	/***************************************/
	/* Delete messages marked for deletion */
	/***************************************/

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
			errormsg(WHERE,ERR_LOCK,smb.file,i);	/* messes with the index */
		else
			delmail(usernumber,which); }

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
}
Exemple #6
0
void maint(void)
{
	int i;
	ulong l,m,n,f,flagged=0;
	time_t now;
	smbmsg_t msg;
	idxrec_t *idx;

	printf("Maintaining %s\r\n",smb.file);
	now=time(NULL);
	i=smb_locksmbhdr(&smb);
	if(i) {
		fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
			,beep,i,smb.last_error);
		return; 
	}
	i=smb_getstatus(&smb);
	if(i) {
		smb_unlocksmbhdr(&smb);
		fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
			,beep,i,smb.last_error);
		return; 
	}
	if(smb_open_hash(&smb) == SMB_SUCCESS)
	{
		ulong max_hashes=0;

		printf("Maintaining %s hash file\r\n", smb.file);

		if((smb.status.attr&(SMB_EMAIL|SMB_NOHASH)) == 0) {
			max_hashes = smb.status.max_msgs;
			if(smb.status.max_crcs > max_hashes)
				max_hashes = smb.status.max_crcs;
		}
		if(!max_hashes) {
			CHSIZE_FP(smb.hash_fp,0);
		} else if(filelength(fileno(smb.hash_fp)) > (long)(max_hashes * SMB_HASH_SOURCE_TYPES * sizeof(hash_t))) {
			if(fseek(smb.hash_fp, -((long)(max_hashes * SMB_HASH_SOURCE_TYPES * sizeof(hash_t))), SEEK_END) == 0) {
				hash_t*	hashes = malloc(max_hashes * SMB_HASH_SOURCE_TYPES * sizeof(hash_t));
				if(hashes != NULL) {
					if(fread(hashes, sizeof(hash_t), max_hashes * SMB_HASH_SOURCE_TYPES, smb.hash_fp) == max_hashes * SMB_HASH_SOURCE_TYPES) {
						CHSIZE_FP(smb.hash_fp,0);
						rewind(smb.hash_fp);
						fwrite(hashes, sizeof(hash_t), max_hashes * SMB_HASH_SOURCE_TYPES, smb.hash_fp);
					}
					free(hashes);
				}
			}
		}
		smb_close_hash(&smb);
	}
	if(!smb.status.total_msgs) {
		smb_unlocksmbhdr(&smb);
		printf("Empty\n");
		return; 
	}
	printf("Loading index...\n");
	if((idx=(idxrec_t *)malloc(sizeof(idxrec_t)*smb.status.total_msgs))
		==NULL) {
		smb_unlocksmbhdr(&smb);
		fprintf(errfp,"\n%s!Error allocating %u bytes of memory\n"
			,beep,sizeof(idxrec_t)*smb.status.total_msgs);
		return; 
	}
	fseek(smb.sid_fp,0L,SEEK_SET);
	for(l=0;l<smb.status.total_msgs;l++) {
		printf("%lu of %"PRIu32"\r"
			,l+1,smb.status.total_msgs);
		if(!fread(&idx[l],1,sizeof(idxrec_t),smb.sid_fp))
			break; 
	}
	printf("\nDone.\n\n");

	printf("Scanning for pre-flagged messages...\n");
	for(m=0;m<l;m++) {
		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
		if(idx[m].attr&MSG_DELETE)
			flagged++; 
	}
	printf("\r100%% (%lu pre-flagged for deletion)\n",flagged);

	if(smb.status.max_age) {
		printf("Scanning for messages more than %u days old...\n"
			,smb.status.max_age);
		for(m=f=0;m<l;m++) {
			printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
				continue;
			if((ulong)now>idx[m].time && (now-idx[m].time)/(24L*60L*60L)
				>smb.status.max_age) {
				f++;
				flagged++;
				idx[m].attr|=MSG_DELETE; 
			} 
		}  /* mark for deletion */
		printf("\r100%% (%lu flagged for deletion due to age)\n",f); 
	}

	printf("Scanning for read messages to be killed...\n");
	for(m=f=0;m<l;m++) {
		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
		if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
			continue;
		if((idx[m].attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
			f++;
			flagged++;
			idx[m].attr|=MSG_DELETE; 
		} 
	}
	printf("\r100%% (%lu flagged for deletion due to read status)\n",f);

	if(smb.status.max_msgs && l-flagged>smb.status.max_msgs) {
		printf("Flagging excess messages for deletion...\n");
		for(m=n=0,f=flagged;l-flagged>smb.status.max_msgs && m<l;m++) {
			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
				continue;
			printf("%lu of %lu\r",++n,(l-f)-smb.status.max_msgs);
			flagged++;
			idx[m].attr|=MSG_DELETE; 
		}			/* mark for deletion */
		printf("\nDone.\n\n"); 
	}

	if(!flagged) {				/* No messages to delete */
		free(idx);
		smb_unlocksmbhdr(&smb);
		return; 
	}

	if(!(mode&NOANALYSIS)) {

		printf("Freeing allocated header and data blocks for deleted messages...\n");
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			i=smb_open_da(&smb);
			if(i) {
				smb_unlocksmbhdr(&smb);
				fprintf(errfp,"\n%s!smb_open_da returned %d: %s\n"
					,beep,i,smb.last_error);
				bail(1); 
			}
			i=smb_open_ha(&smb);
			if(i) {
				smb_unlocksmbhdr(&smb);
				fprintf(errfp,"\n%s!smb_open_ha returned %d: %s\n"
					,beep,i,smb.last_error);
				bail(1); 
			} 
		}

		for(m=n=0;m<l;m++) {
			if(idx[m].attr&MSG_DELETE) {
				printf("%lu of %lu\r",++n,flagged);
				msg.idx=idx[m];
				msg.hdr.number=msg.idx.number;
				if((i=smb_getmsgidx(&smb,&msg))!=0) {
					fprintf(errfp,"\n%s!smb_getmsgidx returned %d: %s\n"
						,beep,i,smb.last_error);
					continue; 
				}
				i=smb_lockmsghdr(&smb,&msg);
				if(i) {
					fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
						,beep,i,smb.last_error);
					break; 
				}
				if((i=smb_getmsghdr(&smb,&msg))!=0) {
					smb_unlockmsghdr(&smb,&msg);
					fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
						,beep,i,smb.last_error);
					break; 
				}
				msg.hdr.attr|=MSG_DELETE;			/* mark header as deleted */
				if((i=smb_putmsg(&smb,&msg))!=0) {
					smb_freemsgmem(&msg);
					smb_unlockmsghdr(&smb,&msg);
					fprintf(errfp,"\n%s!smb_putmsg returned %d: %s\n"
						,beep,i,smb.last_error);
					break; 
				}
				smb_unlockmsghdr(&smb,&msg);
				if((i=smb_freemsg(&smb,&msg))!=0) {
					smb_freemsgmem(&msg);
					fprintf(errfp,"\n%s!smb_freemsg returned %d: %s\n"
						,beep,i,smb.last_error);
					break; 
				}
				smb_freemsgmem(&msg); 
			} 
		}
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			smb_close_ha(&smb);
			smb_close_da(&smb); 
		}
		printf("\nDone.\n\n"); 
	}

	printf("Re-writing index...\n");
	rewind(smb.sid_fp);
	CHSIZE_FP(smb.sid_fp,0);
	for(m=n=0;m<l;m++) {
		if(idx[m].attr&MSG_DELETE)
			continue;
		printf("%lu of %lu\r",++n,l-flagged);
		fwrite(&idx[m],sizeof(idxrec_t),1,smb.sid_fp); 
	}
	printf("\nDone.\n\n");
	fflush(smb.sid_fp);

	free(idx);
	smb.status.total_msgs-=flagged;
	smb_putstatus(&smb);
	smb_unlocksmbhdr(&smb);
}
Exemple #7
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);
}