Skip to content
Snippets Groups Projects
rechocfg.c 27.6 KiB
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)		*
 *																			*
rswindell's avatar
rswindell committed
 * 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>
rswindell's avatar
rswindell committed
#include <sys/stat.h>
rswindell's avatar
rswindell committed
#include "sbbs.h"
#include "sbbsecho.h"
#include "filewrap.h"	/* O_DENYNONE */

/****************************************************************************/
/* Returns the FidoNet address kept in str as ASCII.                        */
rswindell's avatar
rswindell committed
/* Supports wildcard of "ALL" in fields										*/
/****************************************************************************/
rswindell's avatar
rswindell committed
faddr_t atofaddr(const char *instr)
{
	char *p,str[51];
    faddr_t addr;

rswindell's avatar
rswindell committed
	SAFECOPY(str, instr);
	p=str;
	FIND_WHITESPACE(p);
	*p=0;
	if(!stricmp(str,"ALL")) {
		addr.zone=addr.net=addr.node=addr.point=0xffff;
rswindell's avatar
rswindell committed
		return(addr);
	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
rswindell's avatar
rswindell committed
			addr.net=atoi(p);
	}
rswindell's avatar
rswindell committed
		addr.zone=1;
rswindell's avatar
rswindell committed
		addr.net=atoi(str);
	}
	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
rswindell's avatar
rswindell committed
			addr.node=atoi(p);
	}
rswindell's avatar
rswindell committed
		if(!addr.net)
			addr.net=1;
rswindell's avatar
rswindell committed
		addr.node=atoi(str);
	}
	if((p=strchr(str,'.'))!=NULL) {
		p++;
		if(!strnicmp(p,"ALL",3))
			addr.point=0xffff;
		else
rswindell's avatar
rswindell committed
			addr.point=atoi(p);
	}
	return(addr);
rswindell's avatar
rswindell committed
/****************************************************************************/
/* 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);
rswindell's avatar
rswindell committed
					strcat(str,tmp);
				}
			}
		}
rswindell's avatar
rswindell committed
	}
	return(str);
}

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).
 ******************************************************************************/
rswindell's avatar
rswindell committed
int matchnode(sbbsecho_cfg_t* cfg, faddr_t addr, int exact)
	if(exact!=2) {
rswindell's avatar
rswindell committed
		for(i=0;i<cfg->nodecfgs;i++) 				/* Look for exact match */
			if(!memcmp(&cfg->nodecfg[i].addr,&addr,sizeof(faddr_t)))
rswindell's avatar
rswindell committed
		if(exact || i<cfg->nodecfgs)
rswindell's avatar
rswindell committed
			return(i);
	}
rswindell's avatar
rswindell committed
	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)
rswindell's avatar
rswindell committed
	if(i<cfg->nodecfgs)
rswindell's avatar
rswindell committed
	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)
rswindell's avatar
rswindell committed
	if(i<cfg->nodecfgs)
rswindell's avatar
rswindell committed
	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)
rswindell's avatar
rswindell committed
	if(i<cfg->nodecfgs)
		return(i);
rswindell's avatar
rswindell committed
	for(i=0;i<cfg->nodecfgs;i++) 					/* Look for total wild */
		if(cfg->nodecfg[i].addr.zone==0xffff)
			break;
	return(i);
rswindell's avatar
rswindell committed
nodecfg_t* findnodecfg(sbbsecho_cfg_t* cfg, faddr_t addr, int exact)
rswindell's avatar
rswindell committed
	uint node = matchnode(cfg, addr, exact);
rswindell's avatar
rswindell committed
	if(node < cfg->nodecfgs)
		return &cfg->nodecfg[node];
rswindell's avatar
rswindell committed
	return NULL;
}
rswindell's avatar
rswindell committed
void get_default_echocfg(sbbsecho_cfg_t* cfg)
{
	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->umask						= 077;
	cfg->areafile_backups			= 100;
rswindell's avatar
rswindell committed
	cfg->cfgfile_backups			= 100;
	cfg->auto_add_subs				= true;
	cfg->min_free_diskspace			= 10*1024*1024;
rswindell's avatar
rswindell committed
}
char* pktTypeStringList[] = {"2+", "2e", "2.2", "2", NULL};		// Must match enum pkt_type
rswindell's avatar
rswindell committed
char* mailStatusStringList[] = {"Normal", "Hold", "Crash", NULL};
rswindell's avatar
rswindell committed
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;
	}

rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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));
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed

	/* 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);
rswindell's avatar
rswindell committed

	/* NetMail options: */
	SAFECOPY(cfg->default_recipient, iniGetString(ini, ROOT_SECTION, "DefaultRecipient", "", value));
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	cfg->ignore_netmail_kill_attr	= iniGetBool(ini, ROOT_SECTION, "IgnoreNetmailKillAttr", cfg->ignore_netmail_kill_attr);
rswindell's avatar
rswindell committed
	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));

rswindell's avatar
rswindell committed
	/******************/
	/* 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);
rswindell's avatar
rswindell committed
		return false;
rswindell's avatar
rswindell committed
	cfg->arcdefs = 0;
	char* archive;
	while((archive=strListRemove(&archivelist, 0)) != NULL) {
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
		return false;
rswindell's avatar
rswindell committed
	cfg->nodecfgs = 0;
	char* node;
	while((node=strListRemove(&nodelist, 0)) != NULL) {
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
		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));
rswindell's avatar
rswindell committed
		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));
rswindell's avatar
rswindell committed
		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", ",", "");
rswindell's avatar
rswindell committed
		ncfg->keys				= iniGetStringList(ini, node, "keys", ",", "");
		ncfg->pkt_type			= iniGetEnum(ini, node, "PacketType", pktTypeStringList, ncfg->pkt_type);
rswindell's avatar
rswindell committed
		ncfg->areafix			= iniGetBool(ini, node, "AreaFix", ncfg->password[0] ? true : false);
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
	}
	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);
rswindell's avatar
rswindell committed
		return false;
rswindell's avatar
rswindell committed
	cfg->listcfgs = 0;
	char* echolist;
	while((echolist=strListRemove(&echolists, 0)) != NULL) {
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
		elist->forward = iniGetBool(ini, echolist, "fwd", false);
		SAFECOPY(elist->password, iniGetString(ini,echolist, "pwd", "", value));
rswindell's avatar
rswindell committed
		SAFECOPY(elist->areamgr, iniGetString(ini, echolist, "AreaMgr", FIDO_AREAMGR_NAME, value));
rswindell's avatar
rswindell committed
	}
	strListFree(&echolists);
	/***********/
	/* 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);

rswindell's avatar
rswindell committed
	/* 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;
rswindell's avatar
rswindell committed
	strListFree(&ini);
rswindell's avatar
rswindell committed
bool sbbsecho_write_ini(sbbsecho_cfg_t* cfg)
{
	char section[128];
	FILE* fp;
	str_list_t	ini;

rswindell's avatar
rswindell committed
	if(cfg->cfgfile_backups)
		backup(cfg->cfgfile, cfg->cfgfile_backups, /* ren: */false);

rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	if(cfg->logfile[0])
	iniSetString(&ini,		ROOT_SECTION, "LogFile"					,cfg->logfile					,NULL);
	if(cfg->logtime[0])
	iniSetString(&ini,		ROOT_SECTION, "LogTimeFormat"			,cfg->logtime					,NULL);
rswindell's avatar
rswindell committed
	if(cfg->temp_dir[0])
	iniSetString(&ini,		ROOT_SECTION, "TempDirectory"			,cfg->temp_dir					,NULL);
	iniSetString(&ini,		ROOT_SECTION, "OutgoingSemaphore"		,cfg->outgoing_sem				,NULL);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed
	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);
rswindell's avatar
rswindell committed

	iniSetBool(&ini,		ROOT_SECTION, "IgnoreNetmailDestAddr"	,cfg->ignore_netmail_dest_addr	,NULL);
	iniSetBool(&ini,		ROOT_SECTION, "IgnoreNetmailSentAttr"	,cfg->ignore_netmail_sent_attr	,NULL);
rswindell's avatar
rswindell committed
	iniSetBool(&ini,		ROOT_SECTION, "IgnoreNetmailKillAttr"	,cfg->ignore_netmail_kill_attr	,NULL);
rswindell's avatar
rswindell committed
	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);

rswindell's avatar
rswindell committed
	style.key_prefix = "\t";

	/******************/
	/* BinkP Settings */
	/******************/
	iniSetString(&ini,		"BinkP"	,	"Capabilities"				,cfg->binkp_caps				,&style);
	iniSetString(&ini,		"BinkP"	,	"Sysop"						,cfg->binkp_sysop				,&style);

rswindell's avatar
rswindell committed
	/******************/
	/* Archive Types: */
	/******************/
	iniRemoveSections(&ini, "archive:");
	for(uint i=0; i<cfg->arcdefs; i++) {
		arcdef_t* arc = &cfg->arcdef[i];
rswindell's avatar
rswindell committed
		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);
	}
rswindell's avatar
rswindell committed
	/****************/
	/* 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);
rswindell's avatar
rswindell committed
		iniSetString(&ini	,section,	"Name"			,node->name			,&style);
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
		iniSetBool(&ini		,section,	"AreaFix"		,node->areafix		,&style);
		iniSetString(&ini	,section,	"AreaFixPwd"	,node->password		,&style);
		iniSetString(&ini	,section,	"SessionPwd"	,node->sesspwd		,&style);
		iniSetString(&ini	,section,	"TicFilePwd"	,node->ticpwd		,&style);
rswindell's avatar
rswindell committed
		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");
rswindell's avatar
rswindell committed
		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);
rswindell's avatar
rswindell committed
	}
rswindell's avatar
rswindell committed
	/**************/
	/* EchoLists: */
	/**************/
	iniRemoveSections(&ini, "echolist:");
	for(uint i=0; i<cfg->listcfgs; i++) {
		echolist_t* elist = &cfg->listcfg[i];
rswindell's avatar
rswindell committed
		SAFEPRINTF(section,"echolist:%s", elist->listpath);
		iniSetString(&ini	,section,	"Hub"		,faddrtoa(&elist->hub)				,&style);
rswindell's avatar
rswindell committed
		iniSetString(&ini	,section,	"AreaMgr"	,elist->areamgr						,&style);
rswindell's avatar
rswindell committed
		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);
	}

rswindell's avatar
rswindell committed
	iniWriteFile(fp, ini);
	iniCloseFile(fp);
rswindell's avatar
rswindell committed
	iniFreeStringList(ini);
	return true;
}