Newer
Older
break;
case 9:
uifc.helpbuf=
"~ Maximum Age of Imported NetMail ~\r\n\r\n"
"Maximum age (in days) of NetMail that may be imported. The age is based\r\n"
"on the date supplied in the message header and may be incorrect in some\r\n"
"conditions (e.g. erroneous software or incorrect system date).\r\n"
"Set this value to `0` to disable this feature (no maximum age imposed)."
;
if(cfg.max_netmail_age)
sprintf(str,"%1.0f", cfg.max_netmail_age / (24.0*60.0*60.0));
else
strcpy(str, "None");
if(uifc.input(WIN_MID|WIN_BOT|WIN_SAV,0,0,"Maximum NetMail Age (in Days)"
,str, 5, K_EDIT) >= 0)
cfg.max_netmail_age = (long) (strtod(str, NULL) * (24.0*60.0*60.0));
break;
}
}
case 5: /* EchoMail Settings */
"`Area Manager` is the BBS user name or alias to notify (via email) of\r\n"
" AreaFix activities and errors. This setting defaults to `SYSOP`.\r\n"
"`Maximum Packet Size` is the largest packet file size that SBBSecho will\r\n"
" normally create (in bytes).\r\n"
" This settings defaults to `250K` (250 Kilobytes, or 256,000 bytes).\r\n"
"`Maximum Bundle Size` is the largest bundle file size that SBBSecho will\r\n"
" normally create (in bytes).\r\n"
" This settings defaults to `250K` (250 Kilobytes, or 256,000 bytes).\r\n"
"\r\n"
"`Secure Operation` tells SBBSecho to check the Area File (e.g. areas.bbs)\r\n"
" to insure that the packet origin (FTN address) of EchoMail messages\r\n"
" is already linked to the EchoMail area where the message was posted.\r\n"
" This setting defaults to `No`.\r\n"
"`Notify Users of Received EchoMail` tells SBBSecho to send telegrams\r\n"
" (short messages) to BBS users when EchoMail addressed to their name\r\n"
" or alias has been imported into a message base that the user has\r\n"
" access to read.\r\n"
"\r\n"
"`Convert Existing Tear Lines` tells SBBSecho to convert any tear lines\r\n"
" (`---`) existing in the message text to `===`.\r\n"
" This setting defaults to `No`.\r\n"
"`Allow Nodes to Add Areas from Area File` when set to `Yes` allows linked\r\n"
" nodes to add areas listed in your Area File (e.g. `areas.bbs`).\r\n"
"\r\n"
"`Strip Line Feeds From Outgoing Messages` when set to `Yes` instructs\r\n"
" SBBSecho to remove any line-feed (ASCII 10) characters from the body\r\n"
" text of messages being exported to FidoNet EchoMail.\r\n"
"\r\n"
"`Circular Path Detection` when `Enabled` will cause SBBSecho, during\r\n"
" EchoMail import, to check the PATH kludge lines for any of the\r\n"
" system's AKAs and if found (indicating a message loop), not import\r\n"
" the message.\r\n"
"\r\n"
"`Outbound Bundle Attachments` may be either `Deleted` (killed) or `Truncated`\r\n"
" (changed to 0-bytes in length) after being sent by your mailer.\r\n"
"\r\n"
"`Zone Blind SEEN-BY and PATH Lines` when `Enabled` will cause SBBSecho\r\n"
" to assume that node numbers are not duplicated across zones and\r\n"
" that a net/node combination in either of these Kludge lines should\r\n"
" be used to identify a specific node regardless of which zone that\r\n"
" node is located (thus breaking the rules of FidoNet 3D addressing).\r\n"
"\r\n"
"`Maximum Age of Imported EchoMail` allows you to optionally set an age\r\n"
" limit (in days) of EchoMail messages that may be imported.\r\n"
" This setting defaults to `60` (60 days).\r\n"
;
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%s", "Area Manager",cfg.areamgr);
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%luK","Maximum Packet Size"
,cfg.maxpktsize/1024UL);
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%luK","Maximum Bundle Size"
,cfg.maxbdlsize/1024UL);
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%-3.3s","Secure Operation"
,cfg.secure_echomail ? "Yes":"No");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%-3.3s","Notify Users of Received EchoMail"
,cfg.echomail_notify ? "Yes":"No");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%-3.3s","Convert Existing Tear Lines"
,cfg.convert_tear ? "Yes":"No");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%-3.3s","Allow Nodes to Add Areas "
"from Area File",cfg.add_from_echolists_only ?"No":"Yes");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%-3.3s","Strip Line Feeds "
"from Outgoing Messages",cfg.strip_lf ? "Yes":"No");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%s","Circular Path Detection"
,cfg.check_path ? "Enabled" : "Disabled");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%s","Outbound Bundle Attachments"
,cfg.trunc_bundles ? "Truncate" : "Delete");
if(cfg.zone_blind)
sprintf(str,"Zones 1-%u", cfg.zone_blind_threshold);
else
strcpy(str,"Disabled");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%s","Zone Blind SEEN-BY and PATH Lines", str);
if(cfg.max_echomail_age)
sprintf(str,"%1.0f days", ((float)cfg.max_echomail_age) / (24.0*60.0*60.0));
else
strcpy(str, "None");
snprintf(opt[i++],MAX_OPLN-1,"%-45.45s%s","Maximum Age of Imported EchoMail", str);
j=uifc.list(WIN_ACT|WIN_RHT|WIN_BOT,0,0,64,&j,0,"EchoMail Settings",opt);
break;
case 0:
uifc.helpbuf=
"~ Area Manager ~\r\n\r\n"
"User to notify of AreaFix activity and errors.\r\n";
uifc.input(WIN_MID|WIN_BOT|WIN_SAV,0,0,"Area Manager (user name or alias)"
,cfg.areamgr
,LEN_ALIAS,K_EDIT);
break;
case 1:
uifc.helpbuf=
"~ Maximum Packet Size ~\r\n\r\n"
"This is the maximum file size that SBBSecho will create when placing\r\n"
"outgoing messages into packets. The default max size is 250 Kilobytes.\r\n";
sprintf(str,"%lu",cfg.maxpktsize);
uifc.input(WIN_MID|WIN_BOT|WIN_SAV,0,0,"Maximum Packet Size (in Bytes)",str
,9,K_EDIT|K_NUMBER);
cfg.maxpktsize=atol(str);
case 2:
uifc.helpbuf=
"~ Maximum Bundle Size ~\r\n\r\n"
"This is the maximum file size that SBBSecho will create when placing\r\n"
"outgoing packets into bundles. The default max size is 250 Kilobytes.\r\n";
sprintf(str,"%lu",cfg.maxbdlsize);
uifc.input(WIN_MID|WIN_BOT|WIN_SAV,0,0,"Maximum Bundle Size (in Bytes)",str
,9,K_EDIT|K_NUMBER);
cfg.maxbdlsize=atol(str);
break;
case 3:
k = !cfg.secure_echomail;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Secure Operation",uifcYesNoOpts)) {
case 0: cfg.secure_echomail = true; break;
case 1: cfg.secure_echomail = false; break;
}
case 4:
k = !cfg.echomail_notify;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Notify Users",uifcYesNoOpts)) {
case 0: cfg.echomail_notify = true; break;
case 1: cfg.echomail_notify = false; break;
}
break;
case 5:
k = !cfg.convert_tear;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Convert Tear Lines",uifcYesNoOpts)) {
case 0: cfg.convert_tear = true; break;
case 1: cfg.convert_tear = false; break;
}
case 6:
k = cfg.add_from_echolists_only;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Allow Add from Area File",uifcYesNoOpts)) {
case 0: cfg.add_from_echolists_only = false; break;
case 1: cfg.add_from_echolists_only = true; break;
}
case 7:
k = !cfg.strip_lf;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Strip Line Feeds",uifcYesNoOpts)) {
case 0: cfg.strip_lf = true; break;
case 1: cfg.strip_lf = false; break;
}
case 8:
k = !cfg.check_path;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Circular Path Detection",uifcYesNoOpts)) {
case 0: cfg.check_path = true; break;
case 1: cfg.check_path = false; break;
}
break;
case 9:
{
k = cfg.trunc_bundles;
char* opt[] = {"Delete after Sent", "Truncate after Sent", NULL };
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0
,"Outbound Bundles",opt)) {
case 0: cfg.trunc_bundles = false; break;
case 1: cfg.trunc_bundles = true; break;
}
break;
case 10:
k = !cfg.zone_blind;
switch(uifc.list(WIN_MID|WIN_SAV,0,0,0,&k,0,"Zone Blind",uifcYesNoOpts)) {
case 0:
cfg.zone_blind = true;
uifc.helpbuf=
"Zone Blind Threshold";
sprintf(str,"%u",cfg.zone_blind_threshold);
if(uifc.input(WIN_MID|WIN_SAV,0,0
,"Zone Blind Threshold (highest zone in the blind range)"
, str, 5, K_EDIT|K_NUMBER) >= 0)
cfg.zone_blind_threshold = (uint16_t)atol(str);
break;
case 1:
cfg.zone_blind = false;
break;
}
break;
case 11:
uifc.helpbuf=
"~ Maximum Age of Imported EchoMail ~\r\n\r\n"
"Maximum age (in days) of EchoMail that may be imported. The age is based\r\n"
"on the date supplied in the message header and may be incorrect in some\r\n"
"conditions (e.g. erroneous software or incorrect system date).\r\n"
"Set this value to `0` to disable this feature (no maximum age imposed)."
;
if(cfg.max_echomail_age)
sprintf(str,"%1.0f", cfg.max_echomail_age / (24.0*60.0*60.0));
else
strcpy(str, "None");
if(uifc.input(WIN_MID|WIN_BOT|WIN_SAV,0,0,"Maximum EchoMail Age (in Days)"
,str, 5, K_EDIT) >= 0)
cfg.max_echomail_age = (long) (strtod(str, NULL) * (24.0*60.0*60.0));
break;
}
}
uifc.helpbuf=
"~ Archive Types ~\r\n\r\n"
"These are the archive file types that have been configured along with\r\n"
"their corresponding archive programs and command-lines for the packing\r\n"
"and unpacking of EchoMail bundle files.\r\n"
"\r\n"
"The corresponding archive programs are sometimes referred to as `packers`."
;
for(u=0;u<cfg.arcdefs;u++)
int mode = WIN_SAV | WIN_INS | WIN_DEL | WIN_ACT | WIN_GET
| WIN_INSACT | WIN_DELACT | WIN_XTR;
if(savarcdef.name[0])
mode |= WIN_PUT;
i=uifc.list(mode,0,0,0,&i,0,"Archive Types",opt);
if(i==-1)
break;
if((i&MSK_ON)==MSK_INS) {
i&=MSK_OFF;
str[0]=0;
uifc.helpbuf=
"~ Archive Type ~\r\n\r\n"
"This is the identifying name of the archiving program (packer).\r\n";
if((cfg.arcdef=(arcdef_t *)realloc(cfg.arcdef
,sizeof(arcdef_t)*(cfg.arcdefs+1)))==NULL) {
printf("\nMemory Allocation Error\n");
exit(1);
}
for(j=cfg.arcdefs;j>i;j--)
memcpy(&cfg.arcdef[j],&cfg.arcdef[j-1]
,sizeof(arcdef_t));
strcpy(cfg.arcdef[j].name
,cfg.arcdef[j-1].name);
cfg.arcdefs++;
memset(&cfg.arcdef[i],0,sizeof(arcdef_t));
strcpy(cfg.arcdef[i].name,str);
continue;
}
if((i&MSK_ON)==MSK_DEL || (i&MSK_ON) == MSK_CUT) {
int msk = i&MSK_ON;
if(msk == MSK_CUT)
memcpy(&savarcdef, &cfg.arcdef[i], sizeof(arcdef_t));
cfg.arcdefs--;
if(cfg.arcdefs<=0) {
cfg.arcdefs=0;
continue;
}
for(u=i;u<cfg.arcdefs;u++)
memcpy(&cfg.arcdef[u],&cfg.arcdef[u+1]
if((cfg.arcdef=(arcdef_t *)realloc(cfg.arcdef
,sizeof(arcdef_t)*(cfg.arcdefs)))==NULL) {
printf("\nMemory Allocation Error\n");
exit(1);
}
continue;
}
if((i&MSK_ON)==MSK_GET) {
i&=MSK_OFF;
memcpy(&savarcdef,&cfg.arcdef[i],sizeof(arcdef_t));
continue;
}
if((i&MSK_ON)==MSK_PUT) {
i&=MSK_OFF;
memcpy(&cfg.arcdef[i],&savarcdef,sizeof(arcdef_t));
continue;
}
uifc.helpbuf=
"Archive Type and Program configuration";
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %u","Signature Offset"
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","Pack Command Line"
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","Unpack Command Line"
,cfg.arcdef[i].unpack);
opt[j][0]=0;
SAFEPRINTF(str,"Archive Type - %s", cfg.arcdef[i].name);
k=uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT,0,0,60,&packop,0,str,opt);
if(k==-1)
break;
switch(k) {
case 0:
uifc.helpbuf=
"~ Archive Type ~\r\n\r\n"
"This is the identifying name of the archive file type. Usually this name\r\n"
"corresponds with the common file extension or suffix denoting this type\r\n"
"of archive file (e.g. `zip`, `arc`, etc.)."
;
uifc.input(WIN_MID|WIN_SAV,0,0
,"Archive Type"
,cfg.arcdef[i].name,sizeof(cfg.arcdef[i].name)-1
,K_EDIT|K_UPPER);
break;
case 1:
uifc.helpbuf=
"~ Archive Signature ~\r\n\r\n"
"This is the identifying signature of the archive file format (in\r\n"
"hexadecimal notation). This signature is used in combination with the\r\n"
"Archive `Signature Offset` for the automatic detection of proper archive\r\n"
"program to extract (unarchive) inbound EchoMail bundle files."
;
uifc.input(WIN_MID|WIN_SAV,0,0
,"Archive Signature"
,cfg.arcdef[i].hexid,sizeof(cfg.arcdef[i].hexid)-1
,K_EDIT|K_UPPER);
break;
case 2:
uifc.helpbuf=
"~ Archive Signature Offset ~\r\n\r\n"
"This is the byte-offset of the identifying signature of the archive file\r\n"
"format. This offset is used in combination with the Archive `Signature`\r\n"
"for the automatic detection of proper archive program to extract\r\n"
"(unarchive) inbound EchoMail bundle files."
;
sprintf(str,"%u",cfg.arcdef[i].byteloc);
if(uifc.input(WIN_MID|WIN_SAV,0,0
,"Archive Signature Offset",str,5
,K_NUMBER|K_EDIT) > 0)
cfg.arcdef[i].byteloc=atoi(str);
uifc.helpbuf=
"~ Pack Command Line ~\r\n\r\n"
"This is the command-line to execute to create an archive file of the\r\n"
"selected type. The following command-line specifiers may be used for\r\n"
"dynamic variable replacement:\r\n"
"\r\n"
" `%f` The path/filename of the archive file to be created\r\n"
" `%s` The path/filename of the file(s) to be added to the archive\r\n"
" `%!` The Synchronet `exec` directory\r\n"
" `%@` The Synchronet `exec` directory only for non-Unix systems\r\n"
" `%.` Blank for Unix systems, '`.exe`' otherwise\r\n"
" `%?` The current platform description (e.g. 'linux', 'win32')\r\n"
" `%j` The Synchronet `data` directory\r\n"
" `%k` The Synchronet `ctrl` directory\r\n"
" `%o` The configured system operator name\r\n"
" `%q` The configured system QWK-ID\r\n"
" `%g` The configured temporary file directory\r\n"
;
uifc.input(WIN_MID|WIN_SAV,0,0
,"Pack Command Line"
,cfg.arcdef[i].pack,sizeof(cfg.arcdef[i].pack)-1
,K_EDIT);
break;
case 4:
uifc.helpbuf=
"~ Unpack Command Line ~\r\n\r\n"
"This is the command-line to execute to extract an archive file of the\r\n"
"selected type. The following command-line specifiers may be used for\r\n"
"dynamic variable replacement:\r\n"
"\r\n"
" `%f` The path/filename of the archive file to be extracted\r\n"
" `%s` The path/filename of the file(s) to extracted from the archive\r\n"
" `%!` The Synchronet `exec` directory\r\n"
" `%@` The Synchronet `exec` directory only for non-Unix systems\r\n"
" `%.` Blank for Unix systems, '`.exe`' otherwise\r\n"
" `%?` The current platform description (e.g. 'linux', 'win32')\r\n"
" `%j` The Synchronet `data` directory\r\n"
" `%k` The Synchronet `ctrl` directory\r\n"
" `%o` The configured system operator name\r\n"
" `%q` The configured system QWK-ID\r\n"
" `%g` The configured temporary file directory\r\n"
;
uifc.input(WIN_MID|WIN_SAV,0,0
,"Unpack Command Line"
,cfg.arcdef[i].unpack,sizeof(cfg.arcdef[i].unpack)-1
}
}
}
"This feature allows you to specify lists of echoes, in `BACKBONE.NA`\r\n"
"format, which are utilized in `addition` to your Area File (e.g. \r\n"
"`areas.bbs`) for advanced AreaFix (Area Management) operations.\r\n";
while(1) {
for(u=0;u<cfg.listcfgs;u++)
int mode = WIN_SAV | WIN_INS | WIN_DEL | WIN_ACT | WIN_GET
| WIN_INSACT | WIN_DELACT | WIN_XTR;
if(savlistcfg.listpath[0])
mode |= WIN_PUT;
i=uifc.list(mode,0,0,0,&i,0,"Additional EchoLists",opt);
break;
if((i&MSK_ON)==MSK_INS) {
i&=MSK_OFF;
str[0]=0;
uifc.helpbuf=
"~ EchoList ~\r\n\r\n"
"This is the path and filename of the echolist file you wish\r\n"
"to add.\r\n";
if(uifc.input(WIN_MID|WIN_SAV,0,0
if((cfg.listcfg=(echolist_t *)realloc(cfg.listcfg
,sizeof(echolist_t)*(cfg.listcfgs+1)))==NULL) {
printf("\nMemory Allocation Error\n");
exit(1);
}
for(j=cfg.listcfgs;j>i;j--)
memcpy(&cfg.listcfg[j],&cfg.listcfg[j-1]
,sizeof(echolist_t));
cfg.listcfgs++;
memset(&cfg.listcfg[i],0,sizeof(echolist_t));
strcpy(cfg.listcfg[i].listpath,str);
continue;
}
if((i&MSK_ON)==MSK_DEL || (i&MSK_ON) == MSK_CUT) {
int msk = i&MSK_ON;
if(msk == MSK_CUT)
memcpy(&savlistcfg, &cfg.listcfg[i], sizeof(echolist_t));
cfg.listcfgs--;
if(cfg.listcfgs<=0) {
cfg.listcfgs=0;
continue;
}
for(u=i;u<cfg.listcfgs;u++)
memcpy(&cfg.listcfg[u],&cfg.listcfg[u+1]
if((cfg.listcfg=(echolist_t *)realloc(cfg.listcfg
,sizeof(echolist_t)*(cfg.listcfgs)))==NULL) {
printf("\nMemory Allocation Error\n");
exit(1);
}
continue;
}
if((i&MSK_ON)==MSK_GET) {
i&=MSK_OFF;
memcpy(&savlistcfg,&cfg.listcfg[i],sizeof(echolist_t));
continue;
}
if((i&MSK_ON)==MSK_PUT) {
i&=MSK_OFF;
memcpy(&cfg.listcfg[i],&savlistcfg,sizeof(echolist_t));
continue;
}
uifc.helpbuf=
"Configuring an Additional EchoList"
;
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","EchoList Path/Name"
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","Hub Address"
,(cfg.listcfg[i].hub.zone) ?
faddrtoa(&cfg.listcfg[i].hub) : "None");
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","Forward Password"
,(cfg.listcfg[i].password[0]) ?
cfg.listcfg[i].password : "None");
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","Forward Requests"
,cfg.listcfg[i].forward ? "Yes" : "No");
snprintf(opt[j++],MAX_OPLN-1,"%-30.30s %s","AreaFix Keys"
,strListCombine(cfg.listcfg[i].keys, str, sizeof(str), ","));
SAFEPRINTF(str, "Additional EchoList - %s", getfname(cfg.listcfg[i].listpath));
k=uifc.list(WIN_ACT|WIN_SAV|WIN_RHT|WIN_BOT,0,0,60,&listop,0,str,opt);
break;
uifc.input(WIN_MID|WIN_SAV,0,0
,"EchoList Path/Name"
,cfg.listcfg[i].listpath,sizeof(cfg.listcfg[i].listpath)-1
,K_EDIT);
if(cfg.listcfg[i].hub.zone)
strcpy(str,faddrtoa(&cfg.listcfg[i].hub));
str[0]=0;
uifc.input(WIN_MID|WIN_SAV,0,0
,"Hub Address",str
,25,K_EDIT);
if(str[0])
,sizeof(faddr_t));
break;
case 2:
uifc.input(WIN_MID|WIN_SAV,0,0
,"Password to use when forwarding requests"
,cfg.listcfg[i].password,sizeof(cfg.listcfg[i].password)-1
,K_EDIT|K_UPPER);
uifc.helpbuf=
"~ AreaFix Keys ~\r\n\r\n"
"These keys determine which linked nodes have access to the current\r\n"
"echolist file via AreaFix requests (e.g. query, add, remove).\r\n";
for(u=0; cfg.listcfg[i].keys!=NULL && cfg.listcfg[i].keys[u] != NULL;u++)
strcpy(opt[u],cfg.listcfg[i].keys[u]);
x=uifc.list(WIN_SAV|WIN_INS|WIN_DEL|WIN_ACT|
WIN_XTR|WIN_INSACT|WIN_DELACT|WIN_RHT
if(x==-1)
break;
if((x&MSK_ON)==MSK_INS) {
x&=MSK_OFF;
str[0]=0;
if(uifc.input(WIN_MID|WIN_SAV,0,0
,K_EDIT|K_UPPER)<1)
continue;
continue;
}
if((x&MSK_ON)==MSK_DEL) {
x&=MSK_OFF;
continue;
}
uifc.input(WIN_MID|WIN_SAV,0,0,"AreaFix Keys"
,str,SBBSECHO_MAX_KEY_LEN,K_EDIT|K_UPPER);
strListReplace(cfg.listcfg[i].keys,x,str);
continue;
}
}
}
}
case 8:
if(!sbbsecho_write_ini(&cfg))
uifc.msg("Error saving configuration file");
else {
orig_cfg = cfg;
uifc.changes = FALSE;
}
break;
case -1:
if(uifc.changes) {
uifc.helpbuf=
"~ Save Configuration File ~\r\n\r\n"
"Select `Yes` to save the config file, `No` to quit without saving,\r\n"
"or hit ~ ESC ~ to go back to the menu.\r\n\r\n";
i=0;
strcpy(opt[0],"Yes");
strcpy(opt[1],"No");
opt[2][0]=0;
i=uifc.list(WIN_MID,0,0,0,&i,0,"Save Config File",opt);
if(i==-1) break;
if(i) {uifc.bail(); exit(0);}
if(!sbbsecho_write_ini(&cfg))
uifc.msg("Error saving configuration file");
}
uifc.bail();
exit(0);
}