Newer
Older
/* Synchronet FidoNet EchoMail Scanning/Tossing and NetMail Tossing Utility */
/* $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. *
****************************************************************************/
/* Portions written by Allen Christiansen 1994-1996 */
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
/****************************************************************************/
/* Returns the FidoNet address kept in str as ASCII. */
/****************************************************************************/
{
char *p,str[51];
faddr_t addr;
p=str;
FIND_WHITESPACE(p);
*p=0;
if(!stricmp(str,"ALL")) {
addr.zone=addr.net=addr.node=addr.point=0xffff;
addr.zone=addr.net=addr.node=addr.point=0;
if((p=strchr(str,':'))!=NULL) {
if(!strnicmp(str,"ALL:",4))
addr.zone=0xffff;
else
addr.zone=atoi(str);
p++;
if(!strnicmp(p,"ALL",3))
addr.net=0xffff;
else
if(!addr.zone) /* no such thing as zone 0 */
addr.zone=1;
if((p=strchr(str,'/'))!=NULL) {
p++;
if(!strnicmp(p,"ALL",3))
addr.node=0xffff;
else
if((p=strchr(str,'.'))!=NULL) {
p++;
if(!strnicmp(p,"ALL",3))
addr.point=0xffff;
else
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/****************************************************************************/
/* Returns an ASCII string for FidoNet address 'addr' */
/* Supports wildcard of "ALL" in fields */
/****************************************************************************/
const char *faddrtoa(const faddr_t* addr)
{
static char str[25];
char tmp[25];
str[0]=0;
if(addr->zone==0xffff)
strcpy(str,"ALL");
else if(addr->zone) {
sprintf(str,"%u:",addr->zone);
if(addr->net==0xffff)
strcat(str,"ALL");
else {
sprintf(tmp,"%u/",addr->net);
strcat(str,tmp);
if(addr->node==0xffff)
strcat(str,"ALL");
else {
sprintf(tmp,"%u",addr->node);
strcat(str,tmp);
if(addr->point==0xffff)
strcat(str,".ALL");
else if(addr->point) {
sprintf(tmp,".%u",addr->point);
bool faddr_contains_wildcard(const faddr_t* addr)
{
return addr->zone==0xffff || addr->net==0xffff || addr->node==0xffff || addr->point==0xffff;
}
/******************************************************************************
This function returns the number of the node in the SBBSECHO.CFG file which
matches the address passed to it (or cfg.nodecfgs if no match).
******************************************************************************/
for(i=0;i<cfg->nodecfgs;i++) /* Look for exact match */
if(!memcmp(&cfg->nodecfg[i].addr,&addr,sizeof(faddr_t)))
for(i=0;i<cfg->nodecfgs;i++) /* Look for point match */
if(cfg->nodecfg[i].addr.point==0xffff
&& addr.zone==cfg->nodecfg[i].addr.zone
&& addr.net==cfg->nodecfg[i].addr.net
&& addr.node==cfg->nodecfg[i].addr.node)
for(i=0;i<cfg->nodecfgs;i++) /* Look for node match */
if(cfg->nodecfg[i].addr.node==0xffff
&& addr.zone==cfg->nodecfg[i].addr.zone
&& addr.net==cfg->nodecfg[i].addr.net)
for(i=0;i<cfg->nodecfgs;i++) /* Look for net match */
if(cfg->nodecfg[i].addr.net==0xffff
&& addr.zone==cfg->nodecfg[i].addr.zone)
for(i=0;i<cfg->nodecfgs;i++) /* Look for total wild */
if(cfg->nodecfg[i].addr.zone==0xffff)
nodecfg_t* findnodecfg(sbbsecho_cfg_t* cfg, faddr_t addr, int exact)
cfg->maxpktsize = DFLT_PKT_SIZE;
cfg->maxbdlsize = DFLT_BDL_SIZE;
cfg->badecho = -1;
cfg->log_level = LOG_INFO;
cfg->check_path = true;
cfg->zone_blind = false;
cfg->zone_blind_threshold = 0xffff;
cfg->sysop_alias_list = strListSplitCopy(NULL, "SYSOP", ",");
cfg->max_echomail_age = 60*24*60*60;
cfg->bsy_timeout = 12*60*60;
cfg->bso_lock_attempts = 60;
cfg->bso_lock_delay = 10;
cfg->delete_packets = true;
cfg->delete_netmail = true;
cfg->echomail_notify = true;
cfg->kill_empty_netmail = true;
cfg->strict_packet_passwords = true;
cfg->relay_filtered_msgs = false;
cfg->min_free_diskspace = 10*1024*1024;
char* pktTypeStringList[] = {"2+", "2e", "2.2", "2", NULL}; // Must match enum pkt_type
char* mailStatusStringList[] = {"Normal", "Hold", "Crash", NULL};
bool sbbsecho_read_ini(sbbsecho_cfg_t* cfg)
{
FILE* fp;
str_list_t ini;
char value[INI_MAX_VALUE_LEN];
for(unsigned i = 0; i < cfg->domain_count; i++) {
FREE_AND_NULL(cfg->domain_list[i].zone_list);
cfg->domain_list[i].zone_count = 0;
}
get_default_echocfg(cfg);
if((fp=iniOpenFile(cfg->cfgfile, /* create: */false))==NULL)
return false;
ini = iniReadFile(fp);
iniCloseFile(fp);
/************************/
/* Global/root section: */
/************************/
iniFreeStringList(cfg->sysop_alias_list);
SAFECOPY(cfg->inbound , iniGetString(ini, ROOT_SECTION, "Inbound" ,DEFAULT_INBOUND , value));
SAFECOPY(cfg->secure_inbound, iniGetString(ini, ROOT_SECTION, "SecureInbound" ,DEFAULT_SECURE_INBOUND , value));
SAFECOPY(cfg->outbound , iniGetString(ini, ROOT_SECTION, "Outbound" ,DEFAULT_OUTBOUND , value));
SAFECOPY(cfg->areafile , iniGetString(ini, ROOT_SECTION, "AreaFile" ,DEFAULT_AREA_FILE , value));
SAFECOPY(cfg->badareafile , iniGetString(ini, ROOT_SECTION, "BadAreaFile" ,DEFAULT_BAD_AREA_FILE , value));
SAFECOPY(cfg->echostats , iniGetString(ini, ROOT_SECTION, "EchoStats" ,DEFAULT_ECHOSTATS_FILE , value));
SAFECOPY(cfg->logfile , iniGetString(ini, ROOT_SECTION, "LogFile" ,DEFAULT_LOG_FILE , value));
SAFECOPY(cfg->logtime , iniGetString(ini, ROOT_SECTION, "LogTimeFormat" ,DEFAULT_LOG_TIME_FMT , value));
SAFECOPY(cfg->temp_dir , iniGetString(ini, ROOT_SECTION, "TempDirectory" ,DEFAULT_TEMP_DIR , value));
SAFECOPY(cfg->outgoing_sem , iniGetString(ini, ROOT_SECTION, "OutgoingSemaphore", "", value));
cfg->log_level = iniGetLogLevel(ini, ROOT_SECTION, "LogLevel", cfg->log_level);
cfg->flo_mailer = iniGetBool(ini, ROOT_SECTION, "BinkleyStyleOutbound", cfg->flo_mailer);
cfg->bsy_timeout = (ulong)iniGetDuration(ini, ROOT_SECTION, "BsyTimeout", cfg->bsy_timeout);
cfg->bso_lock_attempts = iniGetLongInt(ini, ROOT_SECTION, "BsoLockAttempts", cfg->bso_lock_attempts);
cfg->bso_lock_delay = (ulong)iniGetDuration(ini, ROOT_SECTION, "BsoLockDelay", cfg->bso_lock_delay);
cfg->strict_packet_passwords= iniGetBool(ini, ROOT_SECTION, "StrictPacketPasswords", cfg->strict_packet_passwords);
cfg->relay_filtered_msgs = iniGetBool(ini, ROOT_SECTION, "RelayFilteredMsgs", cfg->relay_filtered_msgs);
cfg->umask = iniGetInteger(ini, ROOT_SECTION, "umask", cfg->umask);
cfg->areafile_backups = iniGetInteger(ini, ROOT_SECTION, "AreaFileBackups", cfg->areafile_backups);
cfg->cfgfile_backups = iniGetInteger(ini, ROOT_SECTION, "CfgFileBackups", cfg->cfgfile_backups);
cfg->min_free_diskspace = iniGetBytes(ini, ROOT_SECTION, "MinFreeDiskSpace", 1, cfg->min_free_diskspace);
cfg->strip_lf = iniGetBool(ini, ROOT_SECTION, "StripLineFeeds", cfg->strip_lf);
cfg->strip_soft_cr = iniGetBool(ini, ROOT_SECTION, "StripSoftCRs", cfg->strip_soft_cr);
/* EchoMail options: */
cfg->maxbdlsize = (ulong)iniGetBytes(ini, ROOT_SECTION, "BundleSize", 1, cfg->maxbdlsize);
cfg->maxpktsize = (ulong)iniGetBytes(ini, ROOT_SECTION, "PacketSize", 1, cfg->maxpktsize);
cfg->check_path = iniGetBool(ini, ROOT_SECTION, "CheckPathsForDupes", cfg->check_path);
cfg->secure_echomail = iniGetBool(ini, ROOT_SECTION, "SecureEchomail", cfg->secure_echomail);
cfg->echomail_notify = iniGetBool(ini, ROOT_SECTION, "EchomailNotify", cfg->echomail_notify);
cfg->convert_tear = iniGetBool(ini, ROOT_SECTION, "ConvertTearLines", cfg->convert_tear);
cfg->trunc_bundles = iniGetBool(ini, ROOT_SECTION, "TruncateBundles", cfg->trunc_bundles);
cfg->zone_blind = iniGetBool(ini, ROOT_SECTION, "ZoneBlind", cfg->zone_blind);
cfg->zone_blind_threshold = iniGetShortInt(ini, ROOT_SECTION, "ZoneBlindThreshold", cfg->zone_blind_threshold);
cfg->add_from_echolists_only= iniGetBool(ini, ROOT_SECTION, "AreaAddFromEcholistsOnly", cfg->add_from_echolists_only);
cfg->max_echomail_age = (ulong)iniGetDuration(ini, ROOT_SECTION, "MaxEchomailAge", cfg->max_echomail_age);
SAFECOPY(cfg->areamgr, iniGetString(ini, ROOT_SECTION, "AreaManager", "SYSOP", value));
cfg->auto_add_subs = iniGetBool(ini, ROOT_SECTION, "AutoAddSubs", cfg->auto_add_subs);
SAFECOPY(cfg->default_recipient, iniGetString(ini, ROOT_SECTION, "DefaultRecipient", "", value));
cfg->sysop_alias_list = iniGetStringList(ini, ROOT_SECTION, "SysopAliasList", ",", "SYSOP");
cfg->fuzzy_zone = iniGetBool(ini, ROOT_SECTION, "FuzzyNetmailZones", cfg->fuzzy_zone);
cfg->ignore_netmail_dest_addr = iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailDestAddr", cfg->ignore_netmail_dest_addr);
cfg->ignore_netmail_sent_attr = iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailSentAttr", cfg->ignore_netmail_sent_attr);
cfg->ignore_netmail_kill_attr = iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailKillAttr", cfg->ignore_netmail_kill_attr);
cfg->ignore_netmail_recv_attr = iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailRecvAttr", cfg->ignore_netmail_recv_attr);
cfg->ignore_netmail_local_attr = iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailLocalAttr", cfg->ignore_netmail_local_attr);
cfg->kill_empty_netmail = iniGetBool(ini, ROOT_SECTION, "KillEmptyNetmail", cfg->kill_empty_netmail);
cfg->delete_netmail = iniGetBool(ini, ROOT_SECTION, "DeleteNetmail", cfg->delete_netmail);
cfg->delete_packets = iniGetBool(ini, ROOT_SECTION, "DeletePackets", cfg->delete_packets);
cfg->max_netmail_age = (ulong)iniGetDuration(ini, ROOT_SECTION, "MaxNetmailAge", cfg->max_netmail_age);
/* BinkP options: */
SAFECOPY(cfg->binkp_caps, iniGetString(ini, "BinkP", "Capabilities", "", value));
SAFECOPY(cfg->binkp_sysop, iniGetString(ini, "BinkP", "Sysop", "", value));
/******************/
/* Archive Types: */
/******************/
str_list_t archivelist = iniGetSectionList(ini, "archive:");
cfg->arcdefs = strListCount(archivelist);
if((cfg->arcdef = realloc(cfg->arcdef, sizeof(arcdef_t)*cfg->arcdefs)) == NULL) {
strListFree(&archivelist);
while((archive=strListRemove(&archivelist, 0)) != NULL) {
arcdef_t* arc = &cfg->arcdef[cfg->arcdefs++];
memset(arc, 0, sizeof(arcdef_t));
SAFECOPY(arc->name, truncsp(archive+8));
arc->byteloc = iniGetInteger(ini, archive, "SigOffset", 0);
SAFECOPY(arc->hexid, truncsp(iniGetString(ini, archive, "Sig", "", value)));
SAFECOPY(arc->pack, truncsp(iniGetString(ini, archive, "Pack", "", value)));
SAFECOPY(arc->unpack, truncsp(iniGetString(ini, archive, "Unpack", "", value)));
}
strListFree(&archivelist);
/****************/
/* Links/Nodes: */
/****************/
str_list_t nodelist = iniGetSectionList(ini, "node:");
cfg->nodecfgs = strListCount(nodelist);
if((cfg->nodecfg = realloc(cfg->nodecfg, sizeof(nodecfg_t)*cfg->nodecfgs)) == NULL) {
strListFree(&nodelist);
while((node=strListRemove(&nodelist, 0)) != NULL) {
nodecfg_t* ncfg = &cfg->nodecfg[cfg->nodecfgs++];
memset(ncfg, 0, sizeof(nodecfg_t));
ncfg->addr = atofaddr(node+5);
char* domain = strchr(node+5, '@');
if(domain != NULL)
SAFECOPY(ncfg->domain, domain + 1);
if(iniGetString(ini, node, "route", NULL, value) != NULL && value[0]) {
fidoaddr_t addr = atofaddr(value);
if(addr.zone != 0 && memcmp(&addr, &ncfg->addr, sizeof(addr)) != 0)
ncfg->route = addr;
}
if(iniGetString(ini, node, "LocalAddress", NULL, value) != NULL && value[0]) {
fidoaddr_t addr = atofaddr(value);
if(addr.zone != 0 && memcmp(&addr, &ncfg->addr, sizeof(addr)) != 0)
ncfg->local_addr = addr;
}
SAFECOPY(ncfg->password , iniGetString(ini, node, "AreaFixPwd", "", value));
SAFECOPY(ncfg->pktpwd , iniGetString(ini, node, "PacketPwd", "", value));
SAFECOPY(ncfg->sesspwd , iniGetString(ini, node, "SessionPwd", "", value));
SAFECOPY(ncfg->ticpwd , iniGetString(ini, node, "TicFilePwd", "", value));
SAFECOPY(ncfg->name , iniGetString(ini, node, "Name", "", value));
SAFECOPY(ncfg->comment , iniGetString(ini, node, "Comment", "", value));
if(!faddr_contains_wildcard(&ncfg->addr)) {
SAFECOPY(ncfg->inbox , iniGetString(ini, node, "inbox", "", value));
SAFECOPY(ncfg->outbox , iniGetString(ini, node, "outbox", "", value));
char inbox[MAX_PATH + 1];
char insec[MAX_PATH + 1];
char inbound[MAX_PATH + 1];
char outbox[MAX_PATH + 1];
char outbound[MAX_PATH + 1];
FULLPATH(inbox, ncfg->inbox, sizeof(inbox)) , backslash(inbox);
FULLPATH(outbox, ncfg->outbox, sizeof(outbox)) , backslash(outbox);
FULLPATH(insec, cfg->secure_inbound, sizeof(insec)) , backslash(insec);
FULLPATH(inbound, cfg->inbound, sizeof(inbound)) , backslash(inbound);
FULLPATH(outbound, cfg->outbound, sizeof(outbound)) , backslash(outbound);
if (stricmp(inbound, inbox) == 0 || stricmp(insec, inbox) == 0)
ncfg->inbox[0] = 0;
if (stricmp(outbound, outbox) == 0)
ncfg->outbox[0] = 0;
}
ncfg->grphub = iniGetStringList(ini, node, "GroupHub", ",", "");
ncfg->keys = iniGetStringList(ini, node, "keys", ",", "");
ncfg->pkt_type = iniGetEnum(ini, node, "PacketType", pktTypeStringList, ncfg->pkt_type);
ncfg->areafix = iniGetBool(ini, node, "AreaFix", ncfg->password[0] ? true : false);
ncfg->send_notify = iniGetBool(ini, node, "notify", ncfg->send_notify);
ncfg->passive = iniGetBool(ini, node, "passive", ncfg->passive);
ncfg->direct = iniGetBool(ini, node, "direct", ncfg->direct);
ncfg->status = iniGetEnum(ini, node, "status", mailStatusStringList, ncfg->status);
char* archive = iniGetString(ini, node, "archive", "", value);
for(uint i=0; i<cfg->arcdefs; i++) {
if(stricmp(cfg->arcdef[i].name, archive) == 0) {
ncfg->archive = &cfg->arcdef[i];
break;
/* BinkP settings */
SAFECOPY(ncfg->binkp_src , iniGetString(ini, node, "BinkpSourceAddress", "", value));
SAFECOPY(ncfg->binkp_host , iniGetString(ini, node, "BinkpHost", "", value));
ncfg->binkp_port = iniGetShortInt(ini, node, "BinkpPort", 24554);
ncfg->binkp_poll = iniGetBool(ini, node, "BinkpPoll", FALSE);
ncfg->binkp_plainAuthOnly = iniGetBool(ini, node, "BinkpPlainAuthOnly", FALSE);
ncfg->binkp_allowPlainAuth = iniGetBool(ini, node, "BinkpAllowPlainAuth", FALSE);
ncfg->binkp_allowPlainText = iniGetBool(ini, node, "BinkpAllowPlainText", TRUE);
}
strListFree(&nodelist);
/**************/
/* EchoLists: */
/**************/
str_list_t echolists = iniGetSectionList(ini, "echolist:");
cfg->listcfgs = strListCount(echolists);
if((cfg->listcfg = realloc(cfg->listcfg, sizeof(echolist_t)*cfg->listcfgs)) == NULL) {
strListFree(&echolists);
while((echolist=strListRemove(&echolists, 0)) != NULL) {
echolist_t* elist = &cfg->listcfg[cfg->listcfgs++];
memset(elist, 0, sizeof(echolist_t));
SAFECOPY(elist->listpath, echolist + 9);
elist->keys = iniGetStringList(ini, echolist, "keys", ",", "");
if(iniGetString(ini, echolist, "hub", "", value) != NULL && value[0])
elist->hub = atofaddr(value);
elist->forward = iniGetBool(ini, echolist, "fwd", false);
SAFECOPY(elist->password, iniGetString(ini,echolist, "pwd", "", value));
SAFECOPY(elist->areamgr, iniGetString(ini, echolist, "AreaMgr", FIDO_AREAMGR_NAME, value));
/***********/
/* Domains */
/***********/
str_list_t domains = iniGetSectionList(ini, "domain:");
cfg->domain_count = strListCount(domains);
if((cfg->domain_list = realloc(cfg->domain_list, sizeof(struct fido_domain)*cfg->domain_count)) == NULL) {
strListFree(&domains);
return false;
}
cfg->domain_count = 0;
char* domain;
while((domain = strListRemove(&domains, 0)) != NULL) {
struct fido_domain* dom = &cfg->domain_list[cfg->domain_count++];
memset(dom, 0, sizeof(*dom));
dom->zone_list = iniGetIntList(ini, domain, "Zones", &dom->zone_count, ",", NULL);
SAFECOPY(dom->name, domain + 7);
SAFECOPY(dom->root, iniGetString(ini, domain, "OutboundRoot", cfg->outbound, value));
SAFECOPY(dom->nodelist, iniGetString(ini, domain, "NodeList", "", value));
SAFECOPY(dom->dns_suffix, iniGetString(ini, domain, "DNSSuffix", "", value));
}
strListFree(&domains);
/* make sure we have some sane "maximum" size values here: */
if(cfg->maxpktsize<1024)
cfg->maxpktsize=DFLT_PKT_SIZE;
if(cfg->maxbdlsize<1024)
cfg->maxbdlsize=DFLT_BDL_SIZE;
return true;
}
bool sbbsecho_write_ini(sbbsecho_cfg_t* cfg)
{
char section[128];
FILE* fp;
str_list_t ini;
if(cfg->cfgfile_backups)
backup(cfg->cfgfile, cfg->cfgfile_backups, /* ren: */false);
if((fp=iniOpenFile(cfg->cfgfile, /* create: */true))==NULL)
return false;
ini = iniReadFile(fp);
ini_style_t style = { .value_separator = " = " };
iniSetDefaultStyle(style);
/************************/
/* Global/root section: */
/************************/
iniSetString(&ini, ROOT_SECTION, "Inbound" ,cfg->inbound ,NULL);
iniSetString(&ini, ROOT_SECTION, "SecureInbound" ,cfg->secure_inbound ,NULL);
iniSetString(&ini, ROOT_SECTION, "Outbound" ,cfg->outbound ,NULL);
iniSetString(&ini, ROOT_SECTION, "AreaFile" ,cfg->areafile ,NULL);
iniSetInteger(&ini, ROOT_SECTION, "AreaFileBackups" ,cfg->areafile_backups ,NULL);
iniSetInteger(&ini, ROOT_SECTION, "CfgFileBackups" ,cfg->cfgfile_backups ,NULL);
iniSetBytes(&ini, ROOT_SECTION, "MinFreeDiskSpace" ,1,cfg->min_free_diskspace ,NULL);
iniSetString(&ini, ROOT_SECTION, "BadAreaFile" ,cfg->badareafile ,NULL);
iniSetString(&ini, ROOT_SECTION, "EchoStats" ,cfg->echostats ,NULL);
if(cfg->logfile[0])
iniSetString(&ini, ROOT_SECTION, "LogFile" ,cfg->logfile ,NULL);
if(cfg->logtime[0])
iniSetString(&ini, ROOT_SECTION, "LogTimeFormat" ,cfg->logtime ,NULL);
if(cfg->temp_dir[0])
iniSetString(&ini, ROOT_SECTION, "TempDirectory" ,cfg->temp_dir ,NULL);
iniSetString(&ini, ROOT_SECTION, "OutgoingSemaphore" ,cfg->outgoing_sem ,NULL);
iniSetBytes(&ini, ROOT_SECTION, "BundleSize" ,1,cfg->maxbdlsize ,NULL);
iniSetBytes(&ini, ROOT_SECTION, "PacketSize" ,1,cfg->maxpktsize ,NULL);
iniSetStringList(&ini, ROOT_SECTION, "SysopAliasList", "," ,cfg->sysop_alias_list ,NULL);
iniSetBool(&ini, ROOT_SECTION, "ZoneBlind" ,cfg->zone_blind ,NULL);
iniSetShortInt(&ini, ROOT_SECTION, "ZoneBlindThreshold" ,cfg->zone_blind_threshold ,NULL);
iniSetLogLevel(&ini, ROOT_SECTION, "LogLevel" ,cfg->log_level ,NULL);
iniSetBool(&ini, ROOT_SECTION, "CheckPathsForDupes" ,cfg->check_path ,NULL);
iniSetBool(&ini, ROOT_SECTION, "StrictPacketPasswords" ,cfg->strict_packet_passwords ,NULL);
iniSetBool(&ini, ROOT_SECTION, "SecureEchomail" ,cfg->secure_echomail ,NULL);
iniSetBool(&ini, ROOT_SECTION, "EchomailNotify" ,cfg->echomail_notify ,NULL);
iniSetBool(&ini, ROOT_SECTION, "StripLineFeeds" ,cfg->strip_lf ,NULL);
iniSetBool(&ini, ROOT_SECTION, "StripLineSoftCRs" ,cfg->strip_soft_cr ,NULL);
iniSetBool(&ini, ROOT_SECTION, "ConvertTearLines" ,cfg->convert_tear ,NULL);
iniSetBool(&ini, ROOT_SECTION, "FuzzyNetmailZones" ,cfg->fuzzy_zone ,NULL);
iniSetBool(&ini, ROOT_SECTION, "BinkleyStyleOutbound" ,cfg->flo_mailer ,NULL);
iniSetBool(&ini, ROOT_SECTION, "TruncateBundles" ,cfg->trunc_bundles ,NULL);
iniSetBool(&ini, ROOT_SECTION, "AreaAddFromEcholistsOnly",cfg->add_from_echolists_only ,NULL);
iniSetBool(&ini, ROOT_SECTION, "AutoAddSubs" ,cfg->auto_add_subs ,NULL);
iniSetDuration(&ini, ROOT_SECTION, "BsyTimeout" ,cfg->bsy_timeout ,NULL);
iniSetDuration(&ini, ROOT_SECTION, "BsoLockDelay" ,cfg->bso_lock_delay ,NULL);
iniSetLongInt(&ini, ROOT_SECTION, "BsoLockAttempts" ,cfg->bso_lock_attempts ,NULL);
iniSetDuration(&ini, ROOT_SECTION, "MaxEchomailAge" ,cfg->max_echomail_age ,NULL);
iniSetDuration(&ini, ROOT_SECTION, "MaxNetmailAge" ,cfg->max_netmail_age ,NULL);
iniSetBool(&ini, ROOT_SECTION, "RelayFilteredMsgs" ,cfg->relay_filtered_msgs ,NULL);
iniSetBool(&ini, ROOT_SECTION, "KillEmptyNetmail", cfg->kill_empty_netmail ,NULL);
iniSetBool(&ini, ROOT_SECTION, "DeleteNetmail", cfg->delete_netmail ,NULL);
iniSetBool(&ini, ROOT_SECTION, "DeletePackets", cfg->delete_packets ,NULL);
iniSetBool(&ini, ROOT_SECTION, "IgnoreNetmailDestAddr" ,cfg->ignore_netmail_dest_addr ,NULL);
iniSetBool(&ini, ROOT_SECTION, "IgnoreNetmailSentAttr" ,cfg->ignore_netmail_sent_attr ,NULL);
iniSetBool(&ini, ROOT_SECTION, "IgnoreNetmailKillAttr" ,cfg->ignore_netmail_kill_attr ,NULL);
iniSetBool(&ini, ROOT_SECTION, "IgnoreNetmailRecvAttr" ,cfg->ignore_netmail_recv_attr ,NULL);
iniSetBool(&ini, ROOT_SECTION, "IgnoreNetmailLocalAttr" ,cfg->ignore_netmail_local_attr ,NULL);
iniSetString(&ini, ROOT_SECTION, "DefaultRecipient" ,cfg->default_recipient ,NULL);
/******************/
/* BinkP Settings */
/******************/
iniSetString(&ini, "BinkP" , "Capabilities" ,cfg->binkp_caps ,&style);
iniSetString(&ini, "BinkP" , "Sysop" ,cfg->binkp_sysop ,&style);
/******************/
/* Archive Types: */
/******************/
iniRemoveSections(&ini, "archive:");
for(uint i=0; i<cfg->arcdefs; i++) {
arcdef_t* arc = &cfg->arcdef[i];
if(arc->name[0] == 0)
continue;
SAFEPRINTF(section,"archive:%s", arc->name);
iniSetString(&ini, section, "Sig" ,arc->hexid ,&style);
iniSetInteger(&ini, section, "SigOffset" ,arc->byteloc ,&style);
iniSetString(&ini, section, "Pack" ,arc->pack ,&style);
iniSetString(&ini, section, "Unpack" ,arc->unpack ,&style);
}
/****************/
/* Links/Nodes: */
/****************/
iniRemoveSections(&ini, "node:");
for(uint i=0; i<cfg->nodecfgs; i++) {
nodecfg_t* node = &cfg->nodecfg[i];
SAFEPRINTF(section,"node:%s", faddrtoa(&node->addr));
if(node->domain[0])
sprintf(section + strlen(section), "@%s", node->domain);
iniSetString(&ini ,section, "Comment" ,node->comment ,&style);
iniSetString(&ini ,section, "Archive" ,node->archive == SBBSECHO_ARCHIVE_NONE ? "None" : node->archive->name, &style);
iniSetEnum(&ini ,section, "PacketType" ,pktTypeStringList, node->pkt_type, &style);
iniSetString(&ini ,section, "PacketPwd" ,node->pktpwd ,&style);
iniSetString(&ini ,section, "AreaFixPwd" ,node->password ,&style);
iniSetString(&ini ,section, "SessionPwd" ,node->sesspwd ,&style);
iniSetString(&ini ,section, "TicFilePwd" ,node->ticpwd ,&style);
iniSetString(&ini ,section, "Inbox" ,node->inbox ,&style);
iniSetString(&ini ,section, "Outbox" ,node->outbox ,&style);
iniSetBool(&ini ,section, "Passive" ,node->passive ,&style);
iniSetBool(&ini ,section, "Direct" ,node->direct ,&style);
iniSetBool(&ini ,section, "Notify" ,node->send_notify ,&style);
iniSetStringList(&ini,section, "Keys", "," ,node->keys ,&style);
iniSetEnum(&ini ,section, "Status" ,mailStatusStringList, node->status, &style);
if(node->route.zone)
iniSetString(&ini,section, "Route" ,faddrtoa(&node->route), &style);
else
iniRemoveKey(&ini,section, "Route");
if(node->local_addr.zone)
iniSetString(&ini,section, "LocalAddress" ,faddrtoa(&node->local_addr), &style);
else
iniRemoveKey(&ini,section, "LocalAddress");
iniSetStringList(&ini, section, "GroupHub", "," ,node->grphub ,&style);
/* BinkP-related */
iniSetString(&ini ,section, "BinkpHost" ,node->binkp_host ,&style);
iniSetShortInt(&ini ,section, "BinkpPort" ,node->binkp_port ,&style);
iniSetBool(&ini ,section, "BinkpPoll" ,node->binkp_poll ,&style);
iniSetBool(&ini ,section, "BinkpPlainAuthOnly",node->binkp_plainAuthOnly, &style);
iniSetBool(&ini ,section, "BinkpAllowPlainAuth",node->binkp_allowPlainAuth, &style);
iniSetBool(&ini ,section, "BinkpAllowPlainText",node->binkp_allowPlainText, &style);
iniSetString(&ini ,section, "BinkpSourceAddress",node->binkp_src, &style);
/**************/
/* EchoLists: */
/**************/
iniRemoveSections(&ini, "echolist:");
for(uint i=0; i<cfg->listcfgs; i++) {
echolist_t* elist = &cfg->listcfg[i];
if(elist->listpath[0] == 0)
continue;
SAFEPRINTF(section,"echolist:%s", elist->listpath);
iniSetString(&ini ,section, "Hub" ,faddrtoa(&elist->hub) ,&style);
iniSetString(&ini ,section, "Pwd" ,elist->password ,&style);
iniSetBool(&ini ,section, "Fwd" ,elist->forward ,&style);
iniSetStringList(&ini,section, "Keys", "," ,elist->keys ,&style);
/* Domains */
iniRemoveSections(&ini, "domain:");
for(unsigned i=0; i < cfg->domain_count; i++) {
struct fido_domain* dom = &cfg->domain_list[i];
if(dom->name[0] == 0)
continue;
SAFEPRINTF(section, "domain:%s", dom->name);
iniSetIntList(&ini, section, "Zones", ",", dom->zone_list, dom->zone_count, &style);
iniSetString(&ini, section, "DNSSuffix", dom->dns_suffix, &style);
if(strcmp(cfg->outbound, dom->root) != 0)
iniSetString(&ini, section, "OutboundRoot", dom->root, &style);
iniSetString(&ini, section, "NodeList", dom->nodelist, &style);
}