/*************************************************************************
NIXMAIL (Global routines)
--------------------------------------------------------------------------
general info and copyright
--------------------------------------------------------------------------
RCS Info

$Header: /home/smilie/emsi/RCS/global.c,v 1.15 1992/12/06 09:28:39 smilie Exp $

$Log: global.c,v $
 * Revision 1.15  1992/12/06  09:28:39  smilie
 * Run thru with Wall fixing up warnings
 *
 * Revision 1.14  1992/10/18  11:33:45  smilie
 * added SYSTEM_NODE to contain your node number
 *
 * Revision 1.13  1992/10/05  07:19:21  smilie
 * Fixed up logging
 * Fixed up a few problems with Configuration
 * added load_outbound
 *
 * Revision 1.12  1992/10/03  14:02:06  smilie
 * cleand up a bit
 * added load_outbound
 * added make_address function
 *
 * Revision 1.11  1992/10/03  08:03:38  smilie
 * added standard EXIT codes.
 *
 * Revision 1.10  1992/10/03  07:49:35  smilie
 * Forgot a pointer reference for the sscanf out data
 *
 * Revision 1.9  1992/10/03  07:40:58  smilie
 * Fixed up the CONFIG loading/parsing system
 * Now loads from a general config, and also System configs
 *
 * Revision 1.6  1992/09/01  13:31:21  smilie
 * updated
 *
 * Revision 1.4  1992/06/22  06:15:37  smilie
 * added config
 *
 * Revision 1.1  1992/06/14  16:17:52  smilie
 * Initial revision
 *

*************************************************************************/

/* Feature test switches */
#define _POSIX_SOURCE 1
#define _GLOBAL_C

/* System Headers */
#include <stdio.h>		/* STD I/O */
#include <stdarg.h>		/* STD Argument Parseing */
#include <time.h>		/* Time Functions */
#include <sys/types.h>		/* File Types */
#include <errno.h>		/* ERROR Reporting */
#include <unistd.h>		/* UNIX Standard Utils */
#include <termios.h>		/* TTY Definitions */
#include <stdlib.h>		/* STD library functions */
#include <string.h>		/* String/Memory Manipulation */

/* Local Headers */
#include "nixmail.h"		/* General NIXMAIL Header */

/* Macros */

/* File scope variables */

static char global_rcsid[] = "$Id: global.c,v 1.15 1992/12/06 09:28:39 smilie Exp $";
#define RCSID global_rcsid

nixmail_config CONFIG;		/* The Global NIXMAIL Config */
system_dat SYSTEM;		/* Remote System Information */

outbound_struct OBD[MAX_OBD];	/* outbound data */

/* External variables */

/* External Functions */

/* Structures and unions */

/* Functions */

/************************************************************************
			    MAKE_ADDRESS
-------------------------------------------------------------------------
*************************************************************************/
char *make_address(address_str *adr, int type)
{
static char adr_string[100];
/**/
if (type == ADR_FILE)
	{
	sprintf(adr_string, "%u.%u.%u.%u", adr->zone, adr->net, adr->node, adr->point);
	}
else	/* Default is ADR_NORM */
	{
	sprintf(adr_string, "%u:%u/%u.%u", adr->zone, adr->net, adr->node, adr->point);
	}
return adr_string;
}
/************************************************************************
			PARSE_CONFIG_STRING
-------------------------------------------------------------------------
Parses the Config Strings, setting the correct internal
configuration structures
*************************************************************************/
void parse_config_string(const char *tststring)
{
char tmps[100];
/**/
if (strncasecmp(tststring, "DIAL_PREFIX", 11) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.dialpre);
	}
else
if (strncasecmp(tststring, "DIAL_SUFFIX", 11) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.dialsuf);
	}
else
if (strncasecmp(tststring, "MODEM_INIT", 10) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.modeminit);
	}
else
if (strncasecmp(tststring, "LOGFILE", 7) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.logfile);
	CONFIG.logging = 1;
	}
else
if (strncasecmp(tststring, "MODEM", 5) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.port);
	CONFIG.logging = 1;
	}
else
if (strncasecmp(tststring, "NUMBER", 6) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.number);
	}
else
if (strncasecmp(tststring, "PASSWORD", 8) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.password);
	}
else
if (strncasecmp(tststring, "SYSTEM_NODE", 11) == 0)
	{
	sscanf(tststring, "%s %hu:%hu/%hu.%hu", tmps,
		&CONFIG.locaddress.zone,
		&CONFIG.locaddress.net,
		&CONFIG.locaddress.node,
		&CONFIG.locaddress.point);
	}
else
if (strncasecmp(tststring, "SYSTEM_NAME", 11) == 0)
	{
	fprintf(stderr, "sysname [%s]\n", tststring);
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.name);
	fprintf(stderr, "sysname [%s]\n", CONFIG.name);
	}
else
if (strncasecmp(tststring, "SYSTEM_LOCATION", 15) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.location);
	}
else
if (strncasecmp(tststring, "SYSTEM_SYSOP", 12) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.sysop);
	}
else
if (strncasecmp(tststring, "SYSTEM_NUMBER", 13) == 0)
	{
	sscanf(tststring, "%s %[^_]", tmps, CONFIG.phone);
	}
else
if (strncasecmp(tststring, "SPEED", 5) == 0)
	{
	sscanf(tststring, "%s %u", tmps, &CONFIG.speed);
	}
else
if (strncasecmp(tststring, "LOCKED", 6) == 0)
	{
	CONFIG.locked = 1;	
	}
else
if (strncasecmp(tststring, "RETRY", 5) == 0)
	{
	sscanf(tststring, "%s %u", tmps, &CONFIG.maxdial);
	}
}
/************************************************************************
			LOAD_ACONFIG
-------------------------------------------------------------------------
Loads a Config given the file name
*************************************************************************/
int load_aconfig(const char *filenam)
{
FILE *fh;
char tmpstr[100];
/**/

if ((fh = fopen(filenam, "rt")) == NULL)
	{
	perror(filenam);
	return FALSE;
	}
while(!feof(fh))
	{
	fgetstr(tmpstr, sizeof(tmpstr), fh);
	if ((tmpstr[0] != 0) && (tmpstr[0] != '#'))
		{
		parse_config_string(tmpstr);
		}
	}
fclose(fh);
return TRUE;
}
/************************************************************************
			CHECK_CONFIG
-------------------------------------------------------------------------
Checks the config to make sure that there are no critical configuration
items were left out.
*************************************************************************/
int check_config(void)
{
int config_error = 0;
/**/

#ifdef DEBUG
flog("Logging : %s\n", CONFIG.logging ? "Y" : "N");
if (CONFIG.logging)
	flog("Log file = '%s'\n", CONFIG.logfile);
#endif

if (!CONFIG.dialpre[0])
	{
	config_error++;	
	flog("CONFIG: No Dialing Prefix Set eg:[DIAL_PREFIX ATDT]\n");
	}
if (!CONFIG.dialsuf[0])
	{
	config_error++;	
	flog("CONFIG: No Dialing Suffix Set eg:[DIAL_SUFFIX |]\n");
	}
if (!CONFIG.locaddress.zone)
	{
	config_error++;	
	flog("CONFIG: No System node Number eg:[SYSTEM_NODE 58:2200/164.0]\n");
	}
if (!CONFIG.port[0])
	{
	config_error++;	
	flog("CONFIG: The modem port has not been set [MODEM /dev/ttys1]\n");
	}
if (!CONFIG.number[0])
	{
	config_error++;	
	flog("CONFIG: No number to dial eg:[NUMBER 123-4567]\n");
	}
if (!CONFIG.name[0])
	{
	config_error++;	
	flog("CONFIG: No system name set eg:[SYSTEM_NAME Linux Support OZ]\n");
	}
if (!CONFIG.location[0])
	{
	config_error++;	
	flog("CONFIG: No location set eg:[SYSTEM_LOCATION Lane Cove, NSW]\n");
	}
if (!CONFIG.sysop[0])
	{
	config_error++;	
	flog("CONFIG: No sysop set eg:[SYSTEM_SYSOP Anthony Rumble]\n");
	}
if (!CONFIG.phone[0])
	{
	config_error++;	
	flog("CONFIG: No system phone number set eg:[SYSTEM_NUMBER +61-2-418-8750]\n");
	}
if (!CONFIG.speed)
	{
	config_error++;	
	flog("CONFIG: No modem speed eg:[SPEED 2400]\n");
	}
if (!CONFIG.maxdial)
	{
	config_error++;	
	flog("CONFIG: No Maximum Dial Retries set eg:[RETRY 5]\n");
	}
if (config_error)
	return FALSE;
return TRUE;
}
/************************************************************************
			LOAD_CONFIG
-------------------------------------------------------------------------
		Load the Various General Configuration Files

/usr/lib/nixmail/config - For main general config
/usr/lib/nixmail/zone.net.node.point - For system config

/usr/lib/nixmail is #define'd as NIX_CONFIG_AREA
*************************************************************************/
int load_config()
{
char filenam[256];
/**/
CONFIG.logging = 0;
CONFIG.locked = 0;
#ifdef DEBUG
flog("Loading Config\n");
#endif
sprintf(filenam, "%s/config", NIX_CONFIG_AREA);
load_aconfig(filenam);
sprintf(filenam, "%s/%s", NIX_CONFIG_AREA, make_address(&CONFIG.address, ADR_FILE));
load_aconfig(filenam);

if (!check_config())
	{
	flog("load_config: Something missing in config files\n");
	exit(ERRET_FATAL);
	}

#ifdef DEBUG
flog("Calling node [%s]\n",
	make_address(&CONFIG.address, ADR_NORM));
flog("Using [%s] pass [%s]\n",
	make_address(&CONFIG.locaddress, ADR_NORM), CONFIG.password);
flog("SYS='%s' Loc='%s' SysOpname='%s' PH='%s'\n", CONFIG.name, CONFIG.location, CONFIG.sysop, CONFIG.phone);
#endif
return TRUE;
}
/************************************************************************
			LOAD_OUTBOUND
-------------------------------------------------------------------------
Loads the outbound file list
*************************************************************************/
int load_outbound(void)
{
FILE *fh, *fhd;
char tmpf[256];
char tnam[256];
char tnamdat[256];
char tmps1[256], tmps2[256];
int cur_tok = 0;
int que = 0;
/**/
/* Generate a Temp file name */
sprintf(tmpf, "%s/control/%u.%u.%u.%u", NIX_FILE_AREA, CONFIG.address.zone, CONFIG.address.net, CONFIG.address.node, CONFIG.address.point);
sprintf(tnam, "%s~", tmpf);
sprintf(tnamdat, "%sd", tmpf);

/* Rename control file to temp */
if (rename(tmpf, tnam) == -1)
	{
	if (errno != ENOENT)
		{
		flog("load_outbound: Can't rename '%s' to '%s' : %s\n", tmpf, tnam ,strerror(errno));
		exit(ERRET_FATAL);
		}	
	}
	
if ((fh = fopen(tnam, "rt")) != NULL)
	{
	if ((fhd = fopen(tnamdat, "a+t")) == NULL)
		{
		flog("load_outbound: Can't open '%s' : %s\n", tnamdat, strerror(errno));
		exit(ERRET_FATAL);
		}

	/* Append New Control file to previous control file */

	while(!feof(fh))
		{
		fgetstr(tmpf, sizeof(tmpf), fh);
		fprintf(fhd, "%s\n", tmpf);
		}

	/* Close and delete temp file */
	
	fclose(fh);
	fclose(fhd);
	unlink(tnam);
	}
else
	{
	if (errno != ENOENT)
		{
		flog("load_outbound: Can't open '%s' : %s\n", tnam, strerror(errno));
		exit(ERRET_FATAL);
		}
	}
	
/* open new control file */

if ((fhd = fopen(tnamdat, "a+t")) == NULL)
	{
	if (errno != ENOENT)
		{
		flog("load_outbound: Can't open '%s' : %s\n", tnamdat, strerror(errno));
		exit(ERRET_FATAL);
		}
	return FALSE;
	}

/* Load in Control file */
	
while (!feof(fhd))
	{
	fgetstr(tmpf, sizeof(tmpf), fhd);
	#ifdef DEBUG
	flog("load_outbound: [%s]\n", tmpf);
	#endif
	if ((tmpf[0]) && (tmpf[0] != '#'))
		{
		sscanf(tmpf, "%s %s", tmps1, tmps2);
		if (strcasecmp(tmps1, "SEND") == 0)
			OBD[cur_tok].token = OBD_SEND;
		else
		if (strcasecmp(tmps1, "COPY") == 0)
			OBD[cur_tok].token = OBD_SEND;
		else
		if (strcasecmp(tmps1, "MOVE") == 0)
			OBD[cur_tok].token = OBD_MOVE;
		else
		if (strcasecmp(tmps1, "REQ") == 0)
			OBD[cur_tok].token = OBD_REQ;
		else
			OBD[cur_tok].token = OBD_NULL;
		OBD[cur_tok].string = malloc(strlen(tmps2)+1);
		if (OBD[cur_tok].string == NULL)
			{
			flog("load_outbound: malloc returned NULL\n");
			exit(ERRET_FATAL);
			}
		memcpy(OBD[cur_tok].string, tmps2, strlen(tmps2)+1);
		#ifdef DEBUG
		flog("load_outbound: t[%u] = '%u', '%s'\n", cur_tok, OBD[cur_tok].token, OBD[cur_tok].string);
		#endif
		cur_tok++; que++;
		}
	}
fclose(fhd);
return que;
}
/*************************************************************************
				FLOG
*************************************************************************/
void flog(char *fmt, ...)
{
va_list	ap;
FILE *fh;
time_t t;
char tmps[256];
/**/

va_start(ap, fmt);

vfprintf(stderr, fmt, ap);

va_end(ap);

if (CONFIG.logging)
	{
	if ((fh = fopen(CONFIG.logfile, "at")) ==  NULL)
		{
		fprintf(stderr, "Can't open logfile '%s'\n", CONFIG.logfile);
		perror("logfile");
		exit(ERRET_FATAL);
		}
	time(&t);
	sprintf(tmps, "%s", ctime(&t));
	tmps[strlen(tmps)-1] = 0;
	strcat(tmps, " ");
	fprintf(fh, "%s", tmps);
	va_start(ap, fmt);
	vfprintf(fh, fmt, ap);
	va_end(ap);
	fclose(fh);
	}

}

