From b2601ca82c2ef5a0893a65e20ed4934a7eb7ebab Mon Sep 17 00:00:00 2001
From: "Rob Swindell (on Windows 11)" <rob@synchro.net>
Date: Tue, 15 Oct 2024 13:56:43 -0700
Subject: [PATCH] Add support for 31-line DOOR.SYS file format (alternative to
 52-line version)

Removed UTIDOOR.TXT file format: nobody uses this drop file format and we
removed the UTI driver long ago, so this was just an artifact.

If you previously had an external program (door) configured in SCFG to use
the "GAP DOOR.SYS" file format, SBBS will create the same (52 line) format
as before (no change).

But for doors that have compatibilty issues with the 52-line DOOR.SYS file
created by Synchronet (e.g. Thunder cat V3.30), a sysop can now choose "GAP
(original)" for the drop file type and Synchronet will create a 31-line
DOOR.SYS file instead.
---
 src/sbbs3/sbbsdefs.h      |   4 +-
 src/sbbs3/scfg/scfgxtrn.c |  94 +++++++++------------------
 src/sbbs3/xtrn_sec.cpp    | 132 ++++++++++++++++----------------------
 3 files changed, 88 insertions(+), 142 deletions(-)

diff --git a/src/sbbs3/sbbsdefs.h b/src/sbbs3/sbbsdefs.h
index 793b35d4cf..46752210c4 100644
--- a/src/sbbs3/sbbsdefs.h
+++ b/src/sbbs3/sbbsdefs.h
@@ -355,12 +355,12 @@ enum {								/* Values for xtrn_t.type				*/
 	 XTRN_NONE						/* No data file needed					*/
 	,XTRN_SBBS						/* Synchronet external					*/
 	,XTRN_WWIV						/* WWIV external						*/
-	,XTRN_GAP						/* Gap door 							*/
+	,XTRN_DOOR_SYS					/* 52-line door.sys file				*/
 	,XTRN_RBBS						/* RBBS, QBBS, or Remote Access 		*/
 	,XTRN_WILDCAT					/* Wildcat								*/
 	,XTRN_PCBOARD					/* PCBoard								*/
 	,XTRN_SPITFIRE					/* SpitFire 							*/
-	,XTRN_UTI						/* UTI Doors - MegaMail 				*/
+	,XTRN_GAP						/* 31-line doors.sys file				*/
 	,XTRN_SR						/* Solar Realms 						*/
 	,XTRN_RBBS1 					/* DORINFO1.DEF always					*/
 	,XTRN_TRIBBS					/* TRIBBS.SYS							*/
diff --git a/src/sbbs3/scfg/scfgxtrn.c b/src/sbbs3/scfg/scfgxtrn.c
index b6f4d2bf98..10e5125e58 100644
--- a/src/sbbs3/scfg/scfgxtrn.c
+++ b/src/sbbs3/scfg/scfgxtrn.c
@@ -216,92 +216,52 @@ static char* mdaystr(long mdays)
 static char* dropfile(int type, ulong misc)
 {
 	static char str[128];
-	char fname[64]="";
 
 	switch(type) {
 		case XTRN_SBBS:
-			strcpy(fname,"XTRN.DAT");
+			strcpy(str,"XTRN.DAT");
 			break;
 		case XTRN_WWIV:
-			strcpy(fname,"CHAIN.TXT");
+			strcpy(str,"CHAIN.TXT");
 			break;
 		case XTRN_GAP:
-			strcpy(fname,"DOOR.SYS");
+			strcpy(str,"DOOR.SYS (31 lines)");
 			break;
-		case XTRN_RBBS:
-			strcpy(fname,"DORINFO#.DEF");
-			break;
-		case XTRN_RBBS1:
-			strcpy(fname,"DORINFO1.DEF");
-            break;
-		case XTRN_WILDCAT:
-			strcpy(fname,"CALLINFO.BBS");
-			break;
-		case XTRN_PCBOARD:
-			strcpy(fname,"PCBOARD.SYS");
-			break;
-		case XTRN_SPITFIRE:
-			strcpy(fname,"SFDOORS.DAT");
-			break;
-		case XTRN_UTI:
-			strcpy(fname,"UTIDOOR.TXT");
-			break;
-		case XTRN_SR:
-			strcpy(fname,"DOORFILE.SR");
-			break;
-		case XTRN_TRIBBS:
-			strcpy(fname,"TRIBBS.SYS");
-			break;
-        case XTRN_DOOR32:
-            strcpy(fname,"DOOR32.SYS");
-            break;
-	}
-
-	if(misc&XTRN_LWRCASE)
-		strlwr(fname);
-
-	switch(type) {
-		case XTRN_SBBS:
-			sprintf(str,"%-15s %s","Synchronet",fname);
-			break;
-		case XTRN_WWIV:
-			sprintf(str,"%-15s %s","WWIV",fname);
-			break;
-		case XTRN_GAP:
-			sprintf(str,"%-15s %s","GAP",fname);
+		case XTRN_DOOR_SYS:
+			strcpy(str,"DOOR.SYS (52 lines)");
 			break;
 		case XTRN_RBBS:
-			sprintf(str,"%-15s %s","RBBS/QuickBBS",fname);
+			strcpy(str,"DORINFO#.DEF");
 			break;
 		case XTRN_RBBS1:
-			sprintf(str,"%-15s %s","RBBS/QuickBBS",fname);
+			strcpy(str,"DORINFO1.DEF");
             break;
 		case XTRN_WILDCAT:
-			sprintf(str,"%-15s %s","Wildcat",fname);
+			strcpy(str,"CALLINFO.BBS");
 			break;
 		case XTRN_PCBOARD:
-			sprintf(str,"%-15s %s","PCBoard",fname);
+			strcpy(str,"PCBOARD.SYS");
 			break;
 		case XTRN_SPITFIRE:
-			sprintf(str,"%-15s %s","SpitFire",fname);
-			break;
-		case XTRN_UTI:
-			sprintf(str,"%-15s %s","MegaMail",fname);
+			strcpy(str,"SFDOORS.DAT");
 			break;
 		case XTRN_SR:
-			sprintf(str,"%-15s %s","Solar Realms",fname);
+			strcpy(str,"DOORFILE.SR");
 			break;
 		case XTRN_TRIBBS:
-			sprintf(str,"%-15s %s","TriBBS",fname);
+			strcpy(str,"TRIBBS.SYS");
 			break;
         case XTRN_DOOR32:
-            sprintf(str,"%-15s %s","Mystic",fname);
+            strcpy(str,"DOOR32.SYS");
             break;
 		default:
 			strcpy(str,"None");
-			break;
+			return str;
 	}
-	return(str);
+
+	if(misc&XTRN_LWRCASE)
+		strlwr(str);
+	return str;
 }
 
 void xprogs_cfg()
@@ -1225,7 +1185,7 @@ void xtrn_cfg(int section)
 			snprintf(opt[k++],MAX_OPLN,"%-27.27s%s","Disable Local Display"
 				,cfg.xtrn[i]->misc&XTRN_NODISPLAY ? "Yes" : "No");
 			snprintf(opt[k++],MAX_OPLN,"%-23.23s%-4s%s","BBS Drop File Type"
-				,cfg.xtrn[i]->misc&REALNAME ? "(R)":nulstr
+				,(cfg.xtrn[i]->type != XTRN_NONE && (cfg.xtrn[i]->misc&REALNAME)) ? "(R)":nulstr
 				,dropfile(cfg.xtrn[i]->type,cfg.xtrn[i]->misc));
 			snprintf(opt[k++],MAX_OPLN,"%-27.27s%s","Place Drop File In"
 				,cfg.xtrn[i]->misc&STARTUPDIR ? "Start-Up Directory":cfg.xtrn[i]->misc&XTRN_TEMP_DIR ? "Temp Directory" : "Node Directory");
@@ -1518,12 +1478,12 @@ void xtrn_cfg(int section)
 					strcpy(opt[k++],"None");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Synchronet","XTRN.DAT");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","WWIV","CHAIN.TXT");
-					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP","DOOR.SYS");
+					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP (extended)","DOOR.SYS (52 lines)");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","RBBS/QuickBBS","DORINFO#.DEF");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Wildcat","CALLINFO.BBS");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","PCBoard","PCBOARD.SYS");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","SpitFire","SFDOORS.DAT");
-					snprintf(opt[k++], MAX_OPLN, "%-15s %s","MegaMail","UTIDOOR.TXT");
+					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP (original)","DOOR.SYS (31 lines)");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Solar Realms","DOORFILE.SR");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","RBBS/QuickBBS","DORINFO1.DEF");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","TriBBS","TRIBBS.SYS");
@@ -1547,9 +1507,15 @@ void xtrn_cfg(int section)
 						"  Wildcat! 2.x    CALLINFO.BBS\n"
 						"  SpitFire        SFDOORS.DAT\n"
 						"  TriBBS          TRIBBS.SYS\n"
-						"  MegaMail        UTIDOOR.TXT\n"
 						"  Solar Realms    DOORFILE.SR\n"
 						"  Synchronet      XTRN.DAT                      MODUSER.DAT\n"
+						"\n"
+						"The drop file format compatible with the largest number of online\n"
+						"programs (e.g. door games) written for MS-DOS based BBSes is the\n"
+						"`DOOR.SYS` file format.  Synchronet supports both the original (GAP)\n"
+						"31-line DOOR.SYS file format and the extended 52-line format.\n"
+						"If you encounter door compatibility issues with the original 32-line\n"
+						"format, try using the 52-line format (or vice versa).\n"
 					;
 					k=uifc.list(WIN_MID|WIN_ACT,0,0,0,&k,0
 						,"BBS Drop File Type",opt);
@@ -2263,12 +2229,12 @@ void xedit_cfg()
 					strcpy(opt[k++],"None");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Synchronet","XTRN.DAT");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","WWIV","CHAIN.TXT");
-					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP","DOOR.SYS");
+					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP (extended)","DOOR.SYS (52 lines)");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","RBBS/QuickBBS","DORINFO#.DEF");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Wildcat","CALLINFO.BBS");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","PCBoard","PCBOARD.SYS");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","SpitFire","SFDOORS.DAT");
-					snprintf(opt[k++], MAX_OPLN, "%-15s %s","MegaMail","UTIDOOR.TXT");
+					snprintf(opt[k++], MAX_OPLN, "%-15s %s","GAP (original)","DOOR.SYS (31 lines)");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","Solar Realms","DOORFILE.SR");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","RBBS/QuickBBS","DORINFO1.DEF");
 					snprintf(opt[k++], MAX_OPLN, "%-15s %s","TriBBS","TRIBBS.SYS");
diff --git a/src/sbbs3/xtrn_sec.cpp b/src/sbbs3/xtrn_sec.cpp
index 7d9883fc32..74dc757a1b 100644
--- a/src/sbbs3/xtrn_sec.cpp
+++ b/src/sbbs3/xtrn_sec.cpp
@@ -352,7 +352,7 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, uint tle
 		fclose(fp); 
 	}
 
-	else if(type==XTRN_GAP) {	/* Gap DOOR.SYS File */
+	else if(type==XTRN_GAP || type==XTRN_DOOR_SYS) {	/* Gap DOOR.SYS File */
 		SAFECOPY(tmp,"DOOR.SYS");
 		if(misc&XTRN_LWRCASE)
 			strlwr(tmp);
@@ -429,52 +429,58 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, uint tle
 
 		t = getnextevent(&cfg, NULL);
 		localtime_r(&t, &tm);
-		safe_snprintf(str, sizeof(str), "%u\n%" PRIu64 "\n%s\n%s\n%s\n%s"
-			"\n%s\n%02d:%02d\n%c\n"
+		safe_snprintf(str, sizeof(str), "%u\n%" PRIu64 "\n"
 			,0									/* 30: Kbytes downloaded today */
 			,user_available_credits(&useron)/1024UL /* 31: Max Kbytes to download today */
-			,getbirthmmddyy(&cfg, '/', useron.birth, tmp, sizeof(tmp))	/* 32: User birthday (MM/DD/YY) */
-			,node_dir							/* 33: Path to MAIN directory */
-			,data_dir							/* 34: Path to GEN directory */
-			,cfg.sys_op 						/* 35: Sysop name */
-			,useron.handle						/* 36: Alias name */
-			,tm.tm_hour							/* 37: Event time HH:MM */
-			,tm.tm_min
-			,'Y');                              /* 38: Error correcting connection */
+			);
 		lfexpand(str,misc);
 		fwrite(str,strlen(str),1,fp);
 
-		localtime_r(&ns_time,&tm);
-		safe_snprintf(str, sizeof(str), "%c\n%c\n%u\n%" PRIu32 "\n%02d/%02d/%02d\n"
-			,(term & (NO_EXASCII|ANSI|COLOR)) == ANSI
-				? 'Y':'N'                       /* 39: ANSI supported but NG mode */
-			,'Y'                                /* 40: Use record locking */
-			,cfg.color[clr_external]			/* 41: BBS default color */
-			,MIN(useron.min, INT16_MAX)			/* 42: Time credits in minutes */
-			,TM_MONTH(tm.tm_mon)				/* 43: File new-scan date */
-			,tm.tm_mday
-			,TM_YEAR(tm.tm_year));
-		lfexpand(str,misc);
-		fwrite(str,strlen(str),1,fp);
+		if(type == XTRN_DOOR_SYS) { // 52-line variant
+			safe_snprintf(str, sizeof(str), "%s\n%s\n%s\n%s"
+				"\n%s\n%02d:%02d\n%c\n"
+				,getbirthmmddyy(&cfg, '/', useron.birth, tmp, sizeof(tmp))	/* 32: User birthday (MM/DD/YY) */
+				,node_dir							/* 33: Path to MAIN directory */
+				,data_dir							/* 34: Path to GEN directory */
+				,cfg.sys_op 						/* 35: Sysop name */
+				,useron.handle						/* 36: Alias name */
+				,tm.tm_hour							/* 37: Event time HH:MM */
+				,tm.tm_min
+				,'Y');                              /* 38: Error correcting connection */
+			lfexpand(str,misc);
+			fwrite(str,strlen(str),1,fp);
 
-		localtime_r(&logontime,&tm);
-		localtime32(&useron.laston,&tl);
-		safe_snprintf(str, sizeof(str), "%02d:%02d\n%02d:%02d\n%u\n%u\n%" PRIu64 "\n"
-			"%"  PRIu64 "\n%s\n%u\n%u\n"
-			,tm.tm_hour							/* 44: Time of this call */
-			,tm.tm_min
-			,tl.tm_hour							/* 45: Time of last call */
-			,tl.tm_min
-			,999								/* 46: Max daily files available */
-			,0									/* 47: Files downloaded so far today */
-			,useron.ulb/1024UL					/* 48: Total Kbytes uploaded */
-			,useron.dlb/1024UL					/* 49: Total Kbytes downloaded */
-			,useron.comment 					/* 50: User comment */
-			,0									/* 51: Total doors opened */
-			,MIN(useron.posts, INT16_MAX));		/* 52: User message left */
-		lfexpand(str,misc);
-		fwrite(str,strlen(str),1,fp);
+			localtime_r(&ns_time,&tm);
+			safe_snprintf(str, sizeof(str), "%c\n%c\n%u\n%" PRIu32 "\n%02d/%02d/%02d\n"
+				,(term & (NO_EXASCII|ANSI|COLOR)) == ANSI
+					? 'Y':'N'                       /* 39: ANSI supported but NG mode */
+				,'Y'                                /* 40: Use record locking */
+				,cfg.color[clr_external]			/* 41: BBS default color */
+				,MIN(useron.min, INT16_MAX)			/* 42: Time credits in minutes */
+				,TM_MONTH(tm.tm_mon)				/* 43: File new-scan date */
+				,tm.tm_mday
+				,TM_YEAR(tm.tm_year));
+			lfexpand(str,misc);
+			fwrite(str,strlen(str),1,fp);
 
+			localtime_r(&logontime,&tm);
+			localtime32(&useron.laston,&tl);
+			safe_snprintf(str, sizeof(str), "%02d:%02d\n%02d:%02d\n%u\n%u\n%" PRIu64 "\n"
+				"%"  PRIu64 "\n%s\n%u\n%u\n"
+				,tm.tm_hour							/* 44: Time of this call */
+				,tm.tm_min
+				,tl.tm_hour							/* 45: Time of last call */
+				,tl.tm_min
+				,999								/* 46: Max daily files available */
+				,0									/* 47: Files downloaded so far today */
+				,useron.ulb/1024UL					/* 48: Total Kbytes uploaded */
+				,useron.dlb/1024UL					/* 49: Total Kbytes downloaded */
+				,useron.comment 					/* 50: User comment */
+				,0									/* 51: Total doors opened */
+				,MIN(useron.posts, INT16_MAX));		/* 52: User message left */
+			lfexpand(str,misc);
+			fwrite(str,strlen(str),1,fp);
+		}
 		fclose(fp);
 	}
 
@@ -862,31 +868,6 @@ void sbbs_t::xtrndat(const char *name, const char *dropdir, uchar type, uint tle
 		fclose(fp);
 	}
 
-	else if(type==XTRN_UTI) { /* UTI v2.1 - UTIDOOR.TXT */
-		SAFECOPY(tmp,"UTIDOOR.TXT");
-		if(misc&XTRN_LWRCASE)
-			strlwr(tmp);
-		SAFEPRINTF2(str,"%s%s",dropdir,tmp);
-		(void)removecase(str);
-		if((fp = fnopen(NULL,str,O_WRONLY|O_CREAT|O_TRUNC|O_TEXT)) == NULL) {
-			errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_TRUNC|O_TEXT);
-			return; 
-		}
-
-		SAFECOPY(tmp,name);
-		strupr(tmp);
-		safe_snprintf(str, sizeof(str), "%s\n%u\n%u\n%u\n%u\n"
-			,tmp								/* User name */
-			,cur_rate							/* Actual BPS rate */
-			,online==ON_LOCAL ? 0: cfg.com_port /* COM Port */
-			,dte_rate							/* DTE rate */
-			,tleft);							/* Time left in sec */
-		lfexpand(str,misc);
-		fwrite(str, strlen(str), 1, fp);
-
-		fclose(fp);
-	}
-
 	else if(type==XTRN_SR) { /* Solar Realms DOORFILE.SR */
 		SAFECOPY(tmp,"DOORFILE.SR");
 		if(misc&XTRN_LWRCASE)
@@ -1029,7 +1010,7 @@ void sbbs_t::moduserdat(uint xtrnnum)
 		}
 		return; 
 	}
-	else if(cfg.xtrn[xtrnnum]->type==XTRN_GAP) {
+	else if(cfg.xtrn[xtrnnum]->type == XTRN_GAP || cfg.xtrn[xtrnnum]->type == XTRN_DOOR_SYS) {
 		SAFEPRINTF(path,"%sDOOR.SYS", xtrn_dropdir(cfg.xtrn[xtrnnum], startup, sizeof(startup)));
 		fexistcase(path);
 		if((stream=fopen(path,"rb"))!=NULL) {
@@ -1083,12 +1064,14 @@ void sbbs_t::moduserdat(uint xtrnnum)
 				}
 			}
 
-			for(;i<42;i++)
-				if(!fgets(str,128,stream))
-					break;
-			if(i==42 && IS_DIGIT(str[0])) {	/* Time Credits in Minutes */
-				useron.min=atol(str);
-				putuserdec32(useron.number, USER_MIN, useron.min); 
+			if(cfg.xtrn[xtrnnum]->type == XTRN_DOOR_SYS) {
+				for(;i<42;i++)
+					if(!fgets(str,128,stream))
+						break;
+				if(i==42 && IS_DIGIT(str[0])) {	/* Time Credits in Minutes */
+					useron.min=atol(str);
+					putuserdec32(useron.number, USER_MIN, useron.min); 
+				}
 			}
 
 			fclose(stream); 
@@ -1328,7 +1311,7 @@ bool sbbs_t::exec_xtrn(uint xtrnnum, bool user_event)
 		case XTRN_WWIV:
 			SAFECOPY(name,"CHAIN.TXT");
 			break;
-		case XTRN_GAP:
+		case XTRN_DOOR_SYS:
 			SAFECOPY(name,"DOOR.SYS");
 			break;
 		case XTRN_RBBS:
@@ -1343,9 +1326,6 @@ bool sbbs_t::exec_xtrn(uint xtrnnum, bool user_event)
 		case XTRN_PCBOARD:
 			SAFECOPY(name,"PCBOARD.SYS");
 			break;
-		case XTRN_UTI:
-			SAFECOPY(name,"UTIDOOR.TXT");
-			break;
 		case XTRN_SR:
 			SAFECOPY(name,"DOORFILE.SR");
 			break;
-- 
GitLab