From c9f6aaa541e7ef93052e730083eae3f200035ec2 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Thu, 21 Jul 2011 11:28:23 +0000
Subject: [PATCH] Complete QWKE support (using MultiMail for testing): Create
 and include in packet TOREADER.EXT if QWKEsupport is enabled (MultiMail keys
 of this file for QWKE support, so without, no QWKE features are enabled in
 MultiMail). Parse TODOOR.EXT if included in REP packets (for adding/dropping
 subs or setting/resetting pointers). Parse To:, From:, and Subject: QWKE
 kludge lines and use if/when appropriate (e.g. to defeat QWK 25-char header
 field limits). Create To:, From:, and Subject: QWKE kludge lines in QWK/REP
 packets when QWKE support is enabled and those fields exceed QWK limits (25
 chars). Also, legacy SyncQNET kludge lines (@VIA, @TZ, etc.) may now exist in
 the top of the message body in any order. Note: current versions of MultiMail
 do not support "To" fields > 25 chars, even in QWKE mode (though I have a
 patch pending) and do not (yet) support Synchronet HEADERS.DAT file
 (rendering QWKE kludges unnecessary). These are major changes in the QWK/REP
 creation/parsing code, so testing (especially with QWKE-compliant offline
 readers) and bug reports are welcome!

---
 src/sbbs3/msgtoqwk.cpp |  46 +++++----
 src/sbbs3/pack_qwk.cpp |  62 +++++++++++-
 src/sbbs3/qwk.h        |   3 +-
 src/sbbs3/qwktomsg.cpp | 218 ++++++++++++++++++-----------------------
 src/sbbs3/sbbs.h       |   3 +-
 src/sbbs3/un_rep.cpp   | 119 ++++++++++++++++------
 6 files changed, 274 insertions(+), 177 deletions(-)

diff --git a/src/sbbs3/msgtoqwk.cpp b/src/sbbs3/msgtoqwk.cpp
index 7c2dfac981..48a2d37238 100644
--- a/src/sbbs3/msgtoqwk.cpp
+++ b/src/sbbs3/msgtoqwk.cpp
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -167,27 +167,25 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, int subnum
 
 	fprintf(qwk_fp,"%*s",QWK_BLOCK_LEN,"");		/* Init header to space */
 
-	if(msg->from_net.addr && (uint)subnum==INVALID_SUB) {
-		if(mode&QM_TO_QNET)
-			sprintf(from,"%.128s",msg->from);
-		else if(msg->from_net.type==NET_FIDO)
+	/* 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(strlen(from)>25) {
-			size+=fprintf(qwk_fp,"From: %.128s%c%c",from,QWK_NEWLINE,QWK_NEWLINE);
-			sprintf(from,"%.128s",msg->from); 
-		} 
-	}
-	else {
-		sprintf(from,"%.128s",msg->from);
-		if(msg->hdr.attr&MSG_ANONYMOUS && !SYSOP)	   /* from user */
-			SAFECOPY(from,text[Anonymous]); 
 	}
-
+	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));
@@ -209,16 +207,16 @@ ulong sbbs_t::msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, int subnum
 		}
 		else
 			sprintf(to,"%.128s@%.128s",msg->to,(char*)msg->to_net.addr);
-		if(strlen(to)>25) {
-			size+=fprintf(qwk_fp,"To: %.128s%c%c",to,QWK_NEWLINE,QWK_NEWLINE);
-			if(msg->to_net.type==NET_QWK)
-				SAFECOPY(to,"NETMAIL");
-			else
-				sprintf(to,"%.128s",msg->to); 
-		} 
 	}
-	else
-		sprintf(to,"%.128s",msg->to);
+	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"
diff --git a/src/sbbs3/pack_qwk.cpp b/src/sbbs3/pack_qwk.cpp
index e0acc22567..826844b40f 100644
--- a/src/sbbs3/pack_qwk.cpp
+++ b/src/sbbs3/pack_qwk.cpp
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -205,6 +205,66 @@ bool sbbs_t::pack_qwk(char *packet, ulong *msgcnt, bool prepack)
 		}
 	}
 
+	if(useron.qwk&QWK_EXT) {
+		/****************************/
+		/* Create TOREADER.EXT file */
+		/****************************/
+		SAFEPRINTF(str,"%sTOREADER.EXT",cfg.temp_dir);
+		if((stream=fopen(str,"wb"))==NULL) {
+			errormsg(WHERE,ERR_OPEN,str,0);
+			return(false); 
+		}
+
+		fprintf(stream,"ALIAS %s\r\n", useron.alias);
+
+		/* Double-checked with multimail (qwk.cc): */
+		for(i=0;i<usrgrps;i++) 
+			for(j=0;j<usrsubs[i];j++) {
+				fprintf(stream,"AREA %u "
+					,cfg.sub[usrsub[i][j]]->qwkconf ? cfg.sub[usrsub[i][j]]->qwkconf : ((i+1)*1000)+j+1);
+				switch(subscan[usrsub[i][j]].cfg&(SUB_CFG_NSCAN|SUB_CFG_YSCAN)) {
+					case SUB_CFG_NSCAN|SUB_CFG_YSCAN:
+						fputc('p', stream);	// p   for personal messages
+						break;
+					case SUB_CFG_NSCAN:
+						fputc('a', stream); // a   for all messages
+						break;
+				}
+				switch(cfg.sub[usrsub[i][j]]->misc&(SUB_PRIV|SUB_PONLY)) {
+					case SUB_PRIV|SUB_PONLY:
+						fputc('P', stream);	// P   if the area is private mail only
+						break;
+					case SUB_PRIV:
+						fputc('X', stream); // X   if either private or public mail is allowed
+						break;
+					default:
+						fputc('O', stream);	// O   if the area is public mail only
+						break;
+				}
+				if(useron.qwk&QWK_BYSELF)
+					fputc('w', stream);		// w   if this area should include mail written by themselves
+				if(cfg.sub[usrsub[i][j]]->misc&SUB_FORCED)
+					fputc('F', stream);		// F   if this area is forced to be read
+				if(!chk_ar(cfg.sub[usrsub[i][j]]->post_ar,&useron,&client))
+					fputc('R', stream);		// R   if the area is read-only (no posting at all allowed)
+				if(cfg.sub[usrsub[i][j]]->misc&SUB_QNET)
+					fputc('Q', stream);		// I   if the area is an internet area
+				if(cfg.sub[usrsub[i][j]]->misc&SUB_INET)
+					fputc('I', stream);		// I   if the area is an internet area
+				if(cfg.sub[usrsub[i][j]]->misc&SUB_FIDO)
+					fputc('E', stream);		// E   if the area is an echomail area
+				if((cfg.sub[usrsub[i][j]]->misc&(SUB_FIDO|SUB_INET|SUB_QNET))==0)
+					fputc('L', stream);		// L   if the area is a local message area
+				if((cfg.sub[usrsub[i][j]]->misc&SUB_NAME)==0)
+					fputc('H', stream);		// H   if the area is an handles only message area
+				if(cfg.sub[usrsub[i][j]]->misc&SUB_ANON)
+					fputc('A', stream);		// A   if the area allows messages 'from' any name (pick-an-alias)
+				
+				fprintf(stream,"\r\n");
+			}
+		fclose(stream);
+	}
+
 	/****************************************************/
 	/* Create MESSAGES.DAT, write header and leave open */
 	/****************************************************/
diff --git a/src/sbbs3/qwk.h b/src/sbbs3/qwk.h
index be53a75213..2da1486a87 100644
--- a/src/sbbs3/qwk.h
+++ b/src/sbbs3/qwk.h
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -37,6 +37,7 @@
 
 #define QWK_NEWLINE		'\xe3'	/* QWK line terminator */
 #define QWK_BLOCK_LEN	128
+#define QWK_HFIELD_LEN	25		/* Header field (To/From/Subject) length */
 
 /* QWK mode bits */
 #define QM_TAGLINE 	(1<<5)	/* Place tagline at end of qwk message */
diff --git a/src/sbbs3/qwktomsg.cpp b/src/sbbs3/qwktomsg.cpp
index 255c43973b..e18a1118bb 100644
--- a/src/sbbs3/qwktomsg.cpp
+++ b/src/sbbs3/qwktomsg.cpp
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -214,18 +214,18 @@ bool sbbs_t::qwk_import_msg(FILE *qwk_fp, char *hdrblk, ulong blocks
 {
 	char*		body;
 	char*		tail;
-	char*		header;
-	char		str[256],col=0,lastch=0,*p,qwkbuf[QWK_BLOCK_LEN+1];
+	char*		qwkbuf;
+	char		str[256],col=0,lastch=0,*p;
 	char		from[128];
-	uint 		i,k,lzh=0,skip=0;
+	uint 		i,k,lzh=0;
 	long		bodylen,taillen;
 	bool		header_cont=false;
 	bool		success=false;
-	ulong		block;
 	uint16_t	net_type;
 	ushort		xlat=XLAT_NONE;
 	int			storage=SMB_SELFPACK;
 	long		dupechk_hashes=SMB_HASH_SOURCE_DUPE;
+	str_list_t	kludges;
 
 	if(subnum!=INVALID_SUB
 		&& (hdrblk[0]=='*' || hdrblk[0]=='+' || cfg.sub[subnum]->misc&SUB_PONLY))
@@ -278,96 +278,102 @@ bool sbbs_t::qwk_import_msg(FILE *qwk_fp, char *hdrblk, ulong blocks
 	/* Convert the QWK message text */
 	/********************************/
 
-	if((header=(char *)calloc((blocks-1L)*QWK_BLOCK_LEN*2L,sizeof(char)))==NULL) {
-		errormsg(WHERE,ERR_ALLOC,"QWK msg header",(blocks-1L)*QWK_BLOCK_LEN*2L);
+	if((qwkbuf=(char *)malloc((blocks-1)*QWK_BLOCK_LEN))==NULL) {
+		errormsg(WHERE,ERR_ALLOC,"QWK msg buf",(blocks-1)*QWK_BLOCK_LEN);
 		return(false); 
 	}
 
+	if(fread(qwkbuf,QWK_BLOCK_LEN,blocks-1,qwk_fp) != blocks-1) {
+		free(qwkbuf);
+		errormsg(WHERE,ERR_READ,"QWK msg blocks",(blocks-1)*QWK_BLOCK_LEN);
+	}
+
 	bodylen=0;
 	if((body=(char *)malloc((blocks-1L)*QWK_BLOCK_LEN*2L))==NULL) {
-		free(header);
+		free(qwkbuf);
 		errormsg(WHERE,ERR_ALLOC,"QWK msg body",(blocks-1L)*QWK_BLOCK_LEN*2L);
 		return(false); 
 	}
 
 	taillen=0;
 	if((tail=(char *)malloc((blocks-1L)*QWK_BLOCK_LEN*2L))==NULL) {
-		free(header);
+		free(qwkbuf);
 		free(body);
 		errormsg(WHERE,ERR_ALLOC,"QWK msg tail",(blocks-1L)*QWK_BLOCK_LEN*2L);
 		return(false); 
 	}
 
-	memset(qwkbuf,0,sizeof(qwkbuf));
-
-	for(block=1;block<blocks;block++) {
-		if(!fread(qwkbuf,1,QWK_BLOCK_LEN,qwk_fp))
-			break;
-		for(k=0;k<QWK_BLOCK_LEN;k++) {
-			if(qwkbuf[k]==0)
-				continue;
-			if(bodylen==0 && (qwkbuf[k]=='@' || header_cont)) {
-				if((p=strchr(qwkbuf+k, QWK_NEWLINE))!=NULL)
-					*p=0;
-				strcat(header, qwkbuf+k);
-				strcat(header, "\n");
-				if(p==NULL) {
-					header_cont=true;
-					break;
-				}
-				k+=strlen(qwkbuf+k);
-				header_cont=false;
+	kludges=strListInit();
+
+	for(k=0;k<(blocks-1)*QWK_BLOCK_LEN;k++) {
+		if(qwkbuf[k]==0)
+			continue;
+		if(bodylen==0 
+			&& (qwkbuf[k]=='@' 
+				|| (((useron.qwk&QWK_EXT) || subnum==INVALID_SUB)
+					&& (strnicmp(qwkbuf+k,"To:",3)==0 
+					||  strnicmp(qwkbuf+k,"From:",5)==0 
+					||  strnicmp(qwkbuf+k,"Subject:",8)==0)))) {
+			if((p=strchr(qwkbuf+k, QWK_NEWLINE))==NULL) {
+				body[bodylen++]=qwkbuf[k];
 				continue;
 			}
-			if(!taillen && qwkbuf[k]==' ' && col==3 && bodylen>=3
-				&& body[bodylen-3]=='-' && body[bodylen-2]=='-'
-				&& body[bodylen-1]=='-') {
+			*p=0;	/* Converts QWK_NEWLINE to NUL */
+			strListPush(&kludges, qwkbuf+k);
+			k+=strlen(qwkbuf+k);
+			continue;
+		}
+		if(!taillen && qwkbuf[k]==' ' && col==3 && bodylen>=3
+			&& body[bodylen-3]=='-' && body[bodylen-2]=='-'
+			&& body[bodylen-1]=='-') {
+			bodylen-=3;
+			strcpy(tail,"--- ");	/* DO NOT USE SAFECOPY */
+			taillen=4;
+			col++;
+			continue; 
+		}
+		if(qwkbuf[k]==QWK_NEWLINE) {		/* expand QWK_NEWLINE to crlf */
+			if(!bodylen && !taillen)		/* Ignore blank lines at top of message */
+				continue;
+			if(!taillen && col==3 && bodylen>=3 && body[bodylen-3]=='-'
+				&& body[bodylen-2]=='-' && body[bodylen-1]=='-') {
 				bodylen-=3;
-				strcpy(tail,"--- ");	/* DO NOT USE SAFECOPY */
-				taillen=4;
-				col++;
-				continue; 
+				strcpy(tail,"---");	/* DO NOT USE SAFECOPY */
+				taillen=3; 
 			}
-			if(qwkbuf[k]==QWK_NEWLINE) {		/* expand QWK_NEWLINE to crlf */
-				if(!taillen && col==3 && bodylen>=3 && body[bodylen-3]=='-'
-					&& body[bodylen-2]=='-' && body[bodylen-1]=='-') {
-					bodylen-=3;
-					strcpy(tail,"---");	/* DO NOT USE SAFECOPY */
-					taillen=3; 
-				}
-				col=0;
-				if(taillen) {
-					tail[taillen++]=CR;
-					tail[taillen++]=LF; 
-				}
-				else {
-					body[bodylen++]=CR;
-					body[bodylen++]=LF; 
-				}
-				continue; 
+			col=0;
+			if(taillen) {
+				tail[taillen++]=CR;
+				tail[taillen++]=LF; 
 			}
-			/* beep restrict */
-			if(!fromhub && qwkbuf[k]==BEL && useron.rest&FLAG('B'))   
-				continue;
-			/* ANSI restriction */
-			if(!fromhub && (qwkbuf[k]==CTRL_A || qwkbuf[k]==ESC)
-				&& useron.rest&FLAG('A'))
-				continue;
-			if(qwkbuf[k]!=1 && lastch!=1)
-				col++;
-			if(lastch==CTRL_A && !valid_ctrl_a_code(qwkbuf[k])) {
-				if(taillen) taillen--;
-				else		bodylen--;
-				lastch=0;
-				continue; 
+			else {
+				body[bodylen++]=CR;
+				body[bodylen++]=LF; 
 			}
-			lastch=qwkbuf[k];
-			if(taillen)
-				tail[taillen++]=qwkbuf[k];
-			else
-				body[bodylen++]=qwkbuf[k]; 
-		} 
-	}
+			continue; 
+		}
+		/* beep restrict */
+		if(!fromhub && qwkbuf[k]==BEL && useron.rest&FLAG('B'))   
+			continue;
+		/* ANSI restriction */
+		if(!fromhub && (qwkbuf[k]==CTRL_A || qwkbuf[k]==ESC)
+			&& useron.rest&FLAG('A'))
+			continue;
+		if(qwkbuf[k]!=1 && lastch!=1)
+			col++;
+		if(lastch==CTRL_A && !valid_ctrl_a_code(qwkbuf[k])) {
+			if(taillen) taillen--;
+			else		bodylen--;
+			lastch=0;
+			continue; 
+		}
+		lastch=qwkbuf[k];
+		if(taillen)
+			tail[taillen++]=qwkbuf[k];
+		else
+			body[bodylen++]=qwkbuf[k]; 
+	} 
+	free(qwkbuf);
 
 	while(bodylen && body[bodylen-1]==' ') bodylen--; /* remove trailing spaces */
 	if(bodylen>=2 && body[bodylen-2]==CR && body[bodylen-1]==LF)
@@ -375,25 +381,17 @@ bool sbbs_t::qwk_import_msg(FILE *qwk_fp, char *hdrblk, ulong blocks
 
 	while(taillen && tail[taillen-1]<=' ') taillen--; /* remove trailing garbage */
 
-	skip=0;
+	/* Parse QWK Kludges (QWKE standard and SyncQNET legacy) here: */
 	if(useron.rest&FLAG('Q') || fromhub) {      /* QWK Net */
-		if(!strnicmp(header,"@VIA:",5)) {
+		if((p=iniGetString(kludges,ROOT_SECTION,"@VIA",NULL,NULL)) != NULL) {
 			if(!fromhub)
 				set_qwk_flag(QWK_VIA);
-			p=strchr(header, '\n');
-			if(p) {
-				*p=0;
-				skip=strlen(header)+1; 
-			}
-			truncsp(header);
-			p=header+5; 					/* Skip "@VIA:" */
-			while(*p && *p<=' ') p++;		/* Skip any spaces */
 			if(route_circ(p,cfg.sys_id)) {
 				bprintf("\r\nCircular message path: %s\r\n",p);
 				SAFEPRINTF2(str,"Circular message path: %s from %s"
 					,p,fromhub ? cfg.qhub[fromhub-1]->id:useron.alias);
 				errorlog(str);
-				free(header);
+				strListFree(&kludges);
 				free(body);
 				free(tail);
 				return(false); 
@@ -424,63 +422,39 @@ bool sbbs_t::qwk_import_msg(FILE *qwk_fp, char *hdrblk, ulong blocks
 			SAFECOPY(from,useron.alias);
 		smb_hfield_str(msg,SENDER,from);
 	}
-
-	if(!strnicmp(header+skip,"@MSGID:",7)) {
+	if((p=iniGetString(kludges,ROOT_SECTION,"@MSGID",NULL,NULL)) != NULL) {
 		if(!fromhub)
 			set_qwk_flag(QWK_MSGID);
-		p=strchr(header+skip, '\n');
-		i=skip;
-		if(p) {
-			*p=0;
-			skip+=strlen(header+i)+1; 
-		}
-		p=header+i+7;					/* Skip "@MSGID:" */
-		while(*p && *p<=' ') p++;		/* Skip any spaces */
 		truncstr(p," ");				/* Truncate at first space char */
 		if(msg->id==NULL)
 			smb_hfield_str(msg,RFC822MSGID,p);
 	}
-	if(!strnicmp(header+skip,"@REPLY:",7)) {
+	if((p=iniGetString(kludges,ROOT_SECTION,"@REPLY",NULL,NULL)) != NULL) {
 		if(!fromhub)
 			set_qwk_flag(QWK_MSGID);
-		p=strchr(header+skip, '\n');
-		i=skip;
-		if(p) {
-			*p=0;
-			skip+=strlen(header+i)+1; 
-		}
-		p=header+i+7;					/* Skip "@REPLY:" */
-		while(*p && *p<=' ') p++;		/* Skip any spaces */
 		truncstr(p," ");				/* Truncate at first space char */
 		if(msg->reply_id==NULL)
 			smb_hfield_str(msg,RFC822REPLYID,p);
 	}
-	if(!strnicmp(header+skip,"@TZ:",4)) {
+	if((p=iniGetString(kludges,ROOT_SECTION,"@TZ",NULL,NULL)) != NULL) {
 		if(!fromhub)
 			set_qwk_flag(QWK_TZ);
-		p=strchr(header+skip, '\n');
-		i=skip;
-		if(p) {
-			*p=0;
-			skip+=strlen(header+i)+1; 
-		}
-		p=header+i+4;					/* Skip "@TZ:" */
-		while(*p && *p<=' ') p++;		/* Skip any spaces */
 		msg->hdr.when_written.zone=(short)ahtoul(p); 
 	}
-	if(!strnicmp(header+skip,"@REPLYTO:",9)) {
-		p=strchr(header+skip, '\n');
-		i=skip;
-		if(p) {
-			*p=0;
-			skip+=strlen(header+i)+1; 
-		}
-		p=header+i+9;					/* Skip "@REPLYTO:" */
-		while(*p && *p<=' ') p++;		/* Skip any spaces */
+	if((p=iniGetString(kludges,ROOT_SECTION,"@REPLYTO",NULL,NULL)) != NULL) {
 		if(msg->replyto==NULL)
 			smb_hfield_str(msg,REPLYTO,p);
 	}
-	free(header);
+	/* QWKE standard: */
+	if((p=iniGetString(kludges,ROOT_SECTION,"Subject",NULL,NULL)) != NULL)
+		smb_hfield_replace_str(msg,SUBJECT,p);
+	if((p=iniGetString(kludges,ROOT_SECTION,"To",NULL,NULL)) != NULL)
+		smb_hfield_replace_str(msg,RECIPIENT,p);
+	if((useron.rest&FLAG('Q'))
+		&& (p=iniGetString(kludges,ROOT_SECTION,"From",NULL,NULL)) != NULL)
+		smb_hfield_replace_str(msg,SENDER,p);
+
+	strListFree(&kludges);
 
 	/* smb_addmsg requires ASCIIZ strings */
 	body[bodylen]=0;
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index abb50f2196..1d5a92ee73 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -334,7 +334,7 @@ public:
 	char 	temp_uler[31];  /* User who uploaded the files to temp dir */
 	char 	temp_file[41];	/* Origin of extracted temp files */
 	long 	temp_cdt;		/* Credit value of file that was extracted */
-	char 	autohang;		/* Used for auto-hangup after transfer */
+	bool 	autohang;		/* Used for auto-hangup after transfer */
 	size_t 	logcol; 		/* Current column of log file */
 	uint 	criterrs; 		/* Critical error counter */
 
@@ -741,6 +741,7 @@ public:
 
 	/* un_rep.cpp */
 	bool	unpack_rep(char* repfile=NULL);
+	uint	resolve_qwkconf(uint n);
 
 	/* msgtoqwk.cpp */
 	ulong	msgtoqwk(smbmsg_t* msg, FILE *qwk_fp, long mode, int subnum, int conf, FILE* hdrs_dat);
diff --git a/src/sbbs3/un_rep.cpp b/src/sbbs3/un_rep.cpp
index e5fb8accc7..242f960792 100644
--- a/src/sbbs3/un_rep.cpp
+++ b/src/sbbs3/un_rep.cpp
@@ -8,7 +8,7 @@
  * @format.tab-size 4		(Plain Text/Source Code File Header)			*
  * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
  *																			*
- * Copyright 2010 Rob Swindell - http://www.synchro.net/copyright.html		*
+ * Copyright 2011 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				*
@@ -38,6 +38,40 @@
 #include "sbbs.h"
 #include "qwk.h"
 
+/****************************************************************************/
+/* Convert a QWK conference number into a sub-board offset					*/
+/* Return INVALID_SUB upon failure to convert								*/
+/****************************************************************************/
+uint sbbs_t::resolve_qwkconf(uint n)
+{
+	uint	j,k;
+
+	for	(j=0;j<usrgrps;j++) {
+		for(k=0;k<usrsubs[j];k++)
+			if(cfg.sub[usrsub[j][k]]->qwkconf==n)
+				break;
+		if(k<usrsubs[j])
+			break; 
+	}
+
+	if(j>=usrgrps) {
+		if(n<1000) {			 /* version 1 method, start at 101 */
+			j=n/100;
+			k=n-(j*100); 
+		}
+		else {					 /* version 2 method, start at 1001 */
+			j=n/1000;
+			k=n-(j*1000); 
+		}
+		j--;	/* j is group */
+		k--;	/* k is sub */
+		if(j>=usrgrps || k>=usrsubs[j] || cfg.sub[usrsub[j][k]]->qwkconf)
+			return INVALID_SUB;
+	}
+
+	return usrsub[j][k];
+}
+
 /****************************************************************************/
 /* Unpacks .REP packet, 'repname' is the path and filename of the packet    */
 /****************************************************************************/
@@ -347,36 +381,15 @@ bool sbbs_t::unpack_rep(char* repfile)
 				/**************************/
 		else {	/* message on a sub-board */
 				/**************************/
-			n=atol((char *)block+1); /* conference number */
-			for(j=0;j<usrgrps;j++) {
-				for(k=0;k<usrsubs[j];k++)
-					if(cfg.sub[usrsub[j][k]]->qwkconf==n)
-						break;
-				if(k<usrsubs[j])
-					break; 
-			}
+			n=resolve_qwkconf(atol((char *)block+1)); /* conference number */
 
-			if(j>=usrgrps) {
-				if(n<1000) {			 /* version 1 method, start at 101 */
-					j=n/100;
-					k=n-(j*100); 
-				}
-				else {					 /* version 2 method, start at 1001 */
-					j=n/1000;
-					k=n-(j*1000); 
-				}
-				j--;	/* j is group */
-				k--;	/* k is sub */
-				if(j>=usrgrps || k>=usrsubs[j] || cfg.sub[usrsub[j][k]]->qwkconf) {
-					bprintf(text[QWKInvalidConferenceN],n);
-					SAFEPRINTF2(str,"%s: Invalid QWK conference number %lu",useron.alias,n);
-					logline(LOG_NOTICE,"P!",str);
-					continue; 
-				} 
+			if(n==INVALID_SUB) {
+				bprintf(text[QWKInvalidConferenceN],n);
+				SAFEPRINTF2(str,"%s: Invalid QWK conference number %lu",useron.alias,n);
+				logline(LOG_NOTICE,"P!",str);
+				continue; 
 			}
 
-			n=usrsub[j][k];
-
 			/* if posting, add to new-scan config for QWKnet nodes automatically */
 			if(useron.rest&FLAG('Q'))
 				subscan[n].cfg|=SUB_CFG_NSCAN;
@@ -536,6 +549,56 @@ bool sbbs_t::unpack_rep(char* repfile)
 		smb_close(&smb);
 	fclose(rep);
 
+	/* QWKE support */
+	SAFEPRINTF(fname,"%sTODOOR.EXT",cfg.temp_dir);
+	if(fexistcase(fname)) {
+		useron.qwk|=QWK_EXT;
+		FILE* fp=fopen(fname,"r");
+		char* p;
+		if(fp!=NULL) {
+			while(!feof(fp)) {
+				if(!fgets(str,sizeof(str)-1,fp))
+					break;
+				if(strnicmp(str,"AREA ",5)==0) {
+					p=str+5;
+					SKIP_WHITESPACE(p);
+					if((n=resolve_qwkconf(atoi(p))) != INVALID_SUB) {
+						FIND_WHITESPACE(p);
+						SKIP_WHITESPACE(p);
+						if(strchr(p,'D'))
+							subscan[n].cfg&=~SUB_CFG_NSCAN;
+						else if(strchr(p,'a') || strchr(p,'g'))
+							subscan[n].cfg|=SUB_CFG_NSCAN;
+						else if(strchr(p,'p'))
+							subscan[n].cfg|=SUB_CFG_NSCAN|SUB_CFG_YSCAN;
+					}
+					continue;
+				}
+				if(strnicmp(str,"RESET ",6)==0) {
+					p=str+6;
+					SKIP_WHITESPACE(p);
+					if((n=resolve_qwkconf(atoi(p))) != INVALID_SUB) {
+						FIND_WHITESPACE(p);
+						SKIP_WHITESPACE(p);
+						/* If the [#ofmessages] is blank then the pointer should be set back to the start of the message base */
+						if(*p==0)
+							subscan[n].ptr=0;
+						else {
+							/* otherwise it should be set back [#ofmessages] back from the end of the message base. */
+							uint32_t last=0;
+							getlastmsg(n,&last,/* time_t* */NULL);
+							l=last-atol(p);
+							if(l<0)
+								l=0;
+							subscan[n].ptr=l;
+						}
+					}
+				}
+			}
+			fclose(fp);
+		}
+	}
+
 	if(useron.rest&FLAG('Q')) {             /* QWK Net Node */
 		if(fexistcase(msg_fname))
 			remove(msg_fname);
-- 
GitLab