diff --git a/src/sbbs3/msgtoqwk.cpp b/src/sbbs3/msgtoqwk.cpp
index 7c2dfac981b4c2be54f570982ae8c7b7ccefe663..48a2d3723838371fe171f4222f33f134bd7a7b50 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 e0acc22567be21f06113b644be9861d1e061fc1c..826844b40f72c02faea8fdfa454e61a21b7846ca 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 be53a75213330fbc56983a83a06e1866047a17f5..2da1486a875a41b748695b3b1b4a4d6c6b122d83 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 255c43973be77237d6a63f6c4c6656cde634e0f7..e18a1118bb259c7ef7358cddaf88436440c8179a 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 abb50f2196a8c6b2a5c2f34ea1cfdbd76bc26948..1d5a92ee733fc293e5baf7917f4bbcce7efc6894 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 e5fb8accc7e609668b89b8fa8e238912336991b3..242f96079260e428979eb241ea7747e95eae4e25 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);