Skip to content
Snippets Groups Projects
msgtoqwk.cpp 17.73 KiB
/* Synchronet message to QWK format conversion routine */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
#include "qwk.h"

#define MAX_MSGNUM	0x7FFFFFUL	// only 7 (decimal) digits allowed for msg num 

/****************************************************************************/
/* Converts message 'msg' to QWK format, writing to file 'qwk_fp'.          */
/* mode determines how to handle Ctrl-A codes								*/
/* Returns the number of bytes used for the body-text (multiple of 128)		*/
/****************************************************************************/
ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, uint subnum
	, int conf, FILE* hdrs, FILE* voting)
{
	char	str[512],from[512],to[512],ch=0,tear=0,tearwatch=0,*buf,*p;
	char	asc;
	char	msgid[256];
	char	reply_id[256];
	char 	tmp[512];
	long	l,size=0,offset;
	int 	i;
	ushort	hfield_type;
	struct	tm	tm;
	smbmsg_t	remsg;
	time_t	tt;

	get_msgid(&cfg, subnum, msg, msgid, sizeof(msgid));
	offset=(long)ftell(qwk_fp);

	if(msg->hdr.type != SMB_MSG_TYPE_NORMAL) {
		if(voting == NULL)
			return 0;
		fprintf(voting,"[%lx]\n",offset);
		switch(msg->hdr.type) {
		case SMB_MSG_TYPE_BALLOT:
			fprintf(voting, "[vote:%s]\n", msgid);
			if((msg->hdr.attr&MSG_VOTE) == MSG_VOTE)
				fprintf(voting, "Votes = 0x%hx\n", msg->hdr.votes);
			else
				fprintf(voting, "%sVote = true\n", msg->hdr.attr&MSG_UPVOTE ? "Up" : "Down");
			break;
		case SMB_MSG_TYPE_POLL:
		{
			unsigned comments = 0;
			unsigned answers = 0;
			fprintf(voting, "[poll:%s]\n", msgid);
			if(msg->hdr.votes)
				fprintf(voting, "MaxVotes = %hd\n", msg->hdr.votes);
			if(msg->hdr.auxattr&POLL_RESULTS_MASK)
				fprintf(voting , "Results = %u\n", (msg->hdr.auxattr&POLL_RESULTS_MASK) >> POLL_RESULTS_SHIFT);
			for(i=0; i < msg->total_hfields; i++) {
				if(msg->hfield[i].type == SMB_COMMENT)
					fprintf(voting, "%s%u = %s\n", smb_hfieldtype(msg->hfield[i].type), comments++, (char*)msg->hfield_dat[i]);
				else if(msg->hfield[i].type == SMB_POLL_ANSWER)
					fprintf(voting, "%s%u = %s\n", smb_hfieldtype(msg->hfield[i].type), answers++, (char*)msg->hfield_dat[i]);
			}
			break;
		}
		case SMB_MSG_TYPE_POLL_CLOSURE:
			fprintf(voting, "[close:%s]\n", msgid);
			break;
		}
		if(msg->subj && *msg->subj)
			fprintf(voting, "%s: %s\n",smb_hfieldtype(SUBJECT), msg->subj);
		if((p = get_replyid(&cfg, &smb, msg, reply_id, sizeof(reply_id))) != NULL)
			fprintf(voting, "%s: %s\n", smb_hfieldtype(RFC822REPLYID), p);
		/* Time/Date/Zone info */
		fprintf(voting,"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
			);

		/* SENDER */
		fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDER), msg->from);
		if(msg->from_net.type)
			fprintf(voting, "%s: %s\n", smb_hfieldtype(SENDERNETADDR), smb_netaddrstr(&msg->from_net, tmp));
		fprintf(voting, "Conference: %u\n", conf);
		fputc('\n', voting);
	}
	else if(hdrs!=NULL) {
		fprintf(hdrs,"[%lx]\n",offset);

		/* Message-IDs */
		fprintf(hdrs,"%s: %s\n", smb_hfieldtype(RFC822MSGID), msgid);
		if((p = get_replyid(&cfg, &smb, msg, reply_id, sizeof(reply_id))) != NULL)
			fprintf(hdrs, "%s: %s\n", smb_hfieldtype(RFC822REPLYID), p);

		/* 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!=NET_NONE && subnum==INVALID_SUB)
			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);
		if((p=(char*)smb_get_hfield(msg,hfield_type=SMB_COLUMNS,NULL))!=NULL)	
			fprintf(hdrs,"%s: %u\n", smb_hfieldtype(hfield_type), *(uint8_t*)p);
		if((p=(char*)smb_get_hfield(msg,hfield_type=SMB_TAGS,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 */

	SAFECOPY(from,msg->from);
	SAFECOPY(to,msg->to);

	if(msg->hdr.type == SMB_MSG_TYPE_NORMAL) {
		/* QWKE compatible kludges */
		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((mode&QM_EXT) && strlen(from) > QWK_HFIELD_LEN) {
			size+=fprintf(qwk_fp,"From: %.128s%c", from, QWK_NEWLINE);
			SAFECOPY(from,msg->from); 
		} 

		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((mode&QM_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((mode&QM_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"
				,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);
			} 
		}

		ulong getmsgtxt_mode = GETMSGTXT_ALL;
		if(!(mode&QM_TO_QNET))	// Get just the plain-text portion of MIME-encoded messages
			getmsgtxt_mode |= GETMSGTXT_PLAIN;
		buf=smb_getmsgtxt(&smb, msg, getmsgtxt_mode);
		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 || ch=='Z')	/* EOF */
					break;
				if((asc=ctrl_a_to_ascii_char(ch)) != 0) {
					fputc(asc,qwk_fp);
					size++;
					continue;
				}
				if(mode&QM_EXPCTLA) {
					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&QM_RETCTLA && 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&QM_RETCTLA))
				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_POLL_VOTE_MASK)
		ch = 'V';	/* Vote/poll message */
	else 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 */
		,(mode&QM_TO_QNET) ? '*' : ' '     /* 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);
}