/* $Id: loadconfig.c,v 1.41 2000/06/06 05:43:17 jared Exp $ */

#include "config.h"

struct set_type {
	char *name;
	char *value;
	struct set_type *next;
	} *set_head = NULL;

int match_facility(char *factomatch)
{
	if (strcmp(factomatch, "kern") == 0) 
		return LOG_KERN;
	if (strcmp(factomatch, "user") == 0) 
		return LOG_USER;
	if (strcmp(factomatch, "mail") == 0) 
		return LOG_MAIL;
	if (strcmp(factomatch, "daemon") == 0) 
		return LOG_DAEMON;
	if (strcmp(factomatch, "auth") == 0) 
		return LOG_AUTH;
	if (strcmp(factomatch, "syslog") == 0) 
		return LOG_SYSLOG;
	if (strcmp(factomatch, "lpr") == 0) 
		return LOG_LPR;
	if (strcmp(factomatch, "news") == 0) 
		return LOG_NEWS;
	if (strcmp(factomatch, "uucp") == 0) 
		return LOG_UUCP;
	if (strcmp(factomatch, "cron") == 0) 
		return LOG_CRON;
#ifdef LOG_AUTHPRIV
	if (strcmp(factomatch, "authpriv") == 0) 
		return LOG_AUTHPRIV;
#endif /* LOG_AUTHPRIV */
	if (strcmp(factomatch, "local0") == 0) 
		return LOG_LOCAL0;
	if (strcmp(factomatch, "local1") == 0) 
		return LOG_LOCAL1;
	if (strcmp(factomatch, "local2") == 0) 
		return LOG_LOCAL2;
	if (strcmp(factomatch, "local3") == 0) 
		return LOG_LOCAL3;
	if (strcmp(factomatch, "local4") == 0) 
		return LOG_LOCAL4;
	if (strcmp(factomatch, "local5") == 0) 
		return LOG_LOCAL5;
        if (strcmp(factomatch, "local6") == 0) 
		return LOG_LOCAL6;
        if (strcmp(factomatch, "local7") == 0) 
		return LOG_LOCAL7;
	if (strcmp(factomatch, "none") == 0) /* user requsted no syslogging */
		return -2;

	return -1; /* no facility matches */
}

void free_sets()
{
	struct set_type *here, *last = NULL;
	
	here = set_head;
	while (here != NULL)
	{
		if (last != NULL)
		{
			free(last->name);
			free(last->value);
			FREE(last);
			last = NULL;
		}
		last = here;
		here = here->next;
	}
	if (last != NULL)
	{
		free(last->name);
		free(last->value);
		FREE(last);
		last = NULL;
	}
	set_head = NULL;
}

/* We can now do generic variables in our sysmon.confs */
void do_set(char *var, char *value)
{
	struct set_type *setter;
	
	if (debug)
	{
		print_err(0, "set %s = %s", var, value);
	}
	setter = MALLOC(sizeof(struct set_type), "loadconfig:setter for do_set");
	setter->name = strdup(var);
	setter->value = strdup(value);
	setter->next = set_head;
	set_head = setter;
	return;
}

char *find_value(char *string)
{
	struct set_type *here;
	here = set_head;
	
	while (here != NULL)
	{
		if (strcmp(string,here->name) == 0)
		{
			return here->value;
		}
		here = here->next;
	}
	
	/* Not found */
	return NULL;
}

void do_set_replace(char *string)
{
	char new_string[MAX_STRLEN];
	char buff[MAX_STRLEN];
	char *repl = NULL;
	int x,y;

	memset(new_string, 0, MAX_STRLEN);
	for (x = 0;x < strlen(string) ;x++)
	{
		if (string[x] == '$')
		{
			for (y =x; y < strlen(string);y++)
			{
				if (isspace(string[y]))
					break;
				if (string[y] == ',')
					break;
			}
			memset(buff, 0, MAX_STRLEN);
			strncpy(buff, string+x+1, (y-x)-1);
			repl = find_value(buff);
			if (repl != NULL)
			{
				if (strncmp(repl, "spawn", 5) == 0)
				{
					strcat(new_string, "\"");
					strcat(new_string, repl);
					strcat(new_string, "\"");
				} else {
					strcat(new_string, repl);
				}
				x = (y-1);
			}
		} else {
			strncat(new_string, string+x, 1);
		}
	}
	strcpy(string, new_string);
}

/*
 * Begin function loadconfig
 */
struct hostinfo *loadconfig(char *cfname)
{
	struct hostinfo *head = NULL;
	FILE *cnf; /* file handle to take care of the config file loading */

	/* reset it */
	int ln = 0;
	int lvl = 0;

	cnf = fopen(cfname, "r"); /* open the file */

	if (cnf == NULL)
	{
		perror(cfname);
		return NULL;
	}

	fprintf(stdout, "Loading config file..\n"); /* log what's going on */
	set_defaults();

	head = parseline(&ln, &lvl, cfname, cnf); /* actually load it */
	free_sets();
	if (lvl != 0)
	{
		print_err(1, "Parse error in config file, misbalanced braces");
		badconfig = TRUE;
		if (lvl > 0)
		{
			print_err(1, "Too many {'s in config file");
		} else {
			print_err(1, "Too many }'s in config file");
		}
	}

	if (head == NULL) /* check for weird errors */
	{
		print_err(1, "loading of config file returned NULL (empty cnfg?)");
		badconfig = TRUE;
	}

	fclose(cnf); /* leaking a fd here aren't we */

	fprintf(stdout, "Done loading config file..\n");

	syslogmsg("done loading config file");

	return head;
}

/* Free the n-ary linked list */
void	free_it(struct hostinfo *doit)
{

	if (doit == NULL)
		return;
	
	if (doit->hdr != NULL)
		free(doit->hdr);
	if (doit->hdrval != NULL)
		free(doit->hdrval);

	if (doit->contact != NULL)
	{
		free(doit->contact);
	}
	if (doit->child != NULL)
	{
		free_it(doit->child);
	}

	if (doit->sibling != NULL)
		free_it(doit->sibling);

	if (doit->sibling != NULL)
	{
		if ((doit->sibling->sibling == NULL) &&
			(doit->sibling->child == NULL))
		{
			FREE(doit->sibling);	
			doit->sibling = NULL;
		}
	}

	if (doit->child != NULL)
	{
		if (doit->child->sibling == NULL && doit->child->child == NULL)
		{
			FREE(doit->child);	
			doit->child = NULL;
		}
	}

	return;
}

void free_tree(struct hostinfo *freemebaby)
{
	if (freemebaby == NULL)
		return;

	free_it(freemebaby);
	if (freemebaby->sibling == NULL && freemebaby->child == NULL)
	{
		FREE(freemebaby);
	} else {
		syslogmsg("bug in freeing memory\n");
	}
	
	/* free the binary tree freemebaby */
}

void reload_config()
{
	/* log a message */
	syslogmsg("caught SIGHUP preparing to reload config");
	signal(SIGHUP, reload_config);
	
	gotsighup = TRUE; /* we need to watch for this, and when 
		it gets set, bail out of checks and do some cleanup, then
		copy alerts over, then free old tree */

	return;
}

void find_match(struct hostinfo *matchme,struct hostinfo *righthere)
{
	if (righthere == NULL)
		return;

	if ((strcmp(matchme->hostname, righthere->hostname) == 0) &&
		(matchme->type == righthere->type) && 
		(matchme->port == righthere->port))
	{

		hard_copy(matchme, righthere);
		return;
	}

	find_match(matchme, righthere->child); /* check the kids */
	find_match(matchme, righthere->sibling); /* check the siblings */
}

void	hard_copy(struct hostinfo *old, struct hostinfo *new)
{
	struct hostinfo *tmp1, *tmp2;

	tmp1 = new->child;
	tmp2 = new->sibling;

	if (debug)
	{
		print_err(0, "copying %s %d %d over %s %d %d", old->hostname, 
			old->port, old->lastcheck, new->hostname, 
			new->port, new->lastcheck);
	}
	memcpy(new->unique_id, old->unique_id, 128);
	new->lastcheck = old->lastcheck;
	new->downct = old->downct;
	new->contacted = old->contacted;
	new->lastcontacted = old->lastcontacted;
	new->lchecktime = old->lchecktime;
	new->deathtime = old->deathtime;
	new->totalchecked = old->totalchecked;
	new->last_up = old->last_up;
}

void copy_alerts(struct hostinfo *old, struct hostinfo *new)
{
	if (old == NULL)
		return;

	find_match(old, new);

	copy_alerts(old->child, new);
	copy_alerts(old->sibling, new);
}

struct hostinfo *sync_after_sighup(struct hostinfo *oldhead, char *cnffile)
{
	struct hostinfo *newhead = NULL;
	
	if (debug)
	{
		print_err(0, "entering sync_after_sighup");
	}

	/* load the config file */
	newhead = loadconfig(cnffile);
	if (badconfig)
	{
		print_err(1, "New configuration file is invalid.  Will not use it");
		free_tree(newhead);
		return currenthead;
	}

	if (debug)
	{
		print_err(0, "calling copy_alerts");
	}

	/* copy the alerts */
	copy_alerts(oldhead, newhead);

	if (debug)
	{
		print_err(0, "exiting sync_after_sighup");
	}

	/* free the old tree */
	free_tree(oldhead);

	oldhead = NULL;

	return newhead;
}

/*
 *
 */
void gen_unique_id (unsigned char *id_here)
{
	/* Generate a unique ascii id */

	/* length ~ 20 chars or so */

	gen_rand_ascii(id_here, 20);

	return;
}

/*
 * Parse a line 
 */
struct hostinfo	*parseline(int *ln, int *lvl, char *cfname, FILE *fh)
{
        char buf[MAX_STRLEN];
        struct my_hostent *hp = NULL;
	struct parsed mydata;
	int buflen = 0;
	char *temp;

        struct hostinfo data, *xtra = NULL, *myfst = NULL, *current = NULL;

	while (fgets(buf, 16000, fh) != NULL)
	{
	        *ln = *ln+1;
		buflen = strlen(buf);

		/* Zero out that memory */
		memset(&data, 0, sizeof(struct hostinfo));

	        data.child = NULL; /* nothing linked in yet... */
	        data.sibling = NULL; /* My next brother/sister */
	        data.contact = NULL; /* init it */
	        data.message[0] = '\0'; /* init it */
	        data.port = 0; /* init it */
	        data.lastcheck = 0; /* init it */
		data.contacted = FALSE; /* init it */
		data.queued = 0; /* initalize it */
		data.reverse = 0; /* reverse test down=up,up=down */
		data.downct = 0; /* init it */
		data.max_down =  numfailures; /* init it */
		data.lchecktime = 0;
		data.last_up = 0;
		data.deathtime = 0;
		gen_unique_id(data.unique_id);

		/* If a blank line */
		if (buflen == 1)
			continue;

		do_set_replace(buf);
		if (parse(buf, &mydata) == -1)
		{
			print_err(1, "loadconfig.c:parseline: Invalid line %s:%d", cfname, *ln);
			continue;
		}

		if ((buf[buflen-2] == '{') && !(isspace(buf[buflen-3])))
		{
			print_err(1, "WARNING: possible missing space before { on line %d of %s", *ln, cfname);
		}

		if (debug)
		{
			print_err(0, "%s:line #%d - strlen() = %d", 
				cfname, *ln, buflen);
		}

		if (((buflen) == 1) || (mydata.count == 0))       
		{
			free_parsed(&mydata);
			continue; /* if a blank line */
		}

	        if ((*mydata.data[0]==';') || (*mydata.data[0]=='#')) 
		{
			free_parsed(&mydata);
			continue; /* comment */
		}

	        if (*mydata.data[0] == '}')
		{
			if (*lvl == 0)
			{
				print_err(1, "%s: line %d - attempting to close dependency where we can't.  Too many }'s", cfname, *ln);
			}
	                *lvl = (*lvl) - 1;
			/* Free the structure */
			free_parsed(&mydata);
			if (*lvl < 0)
			{
				print_err(1, "%s: line #%d - begin of missing brace?", cfname, *ln);
			}
	                return myfst;
	        } else {
	                if (mydata.count < 2)
	                {
	                        print_err(1, "%s:%d: Not enough arguments to check",
					cfname, *ln);
				free_parsed(&mydata);
	                        continue;
	                }
		}

	if (strncmp(mydata.data[0], "set", 3) == 0)
	{
		/* Four args.. no more, no less */
		if (mydata.count != 4)
		{
			print_err(1, "%s:%d: Not enough arguments to host %s",
				cfname, *ln, mydata.data[0]);
			free_parsed(&mydata);
			continue;
		}
                /* set pmesg = "new-string" */
		if (strncmp(mydata.data[1], "pmesg", 4) == 0)
		{
			pmesg = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "sender", 6) == 0)
		{
			sender = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "from", 4) == 0)
		{
			sender = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "subject", 7) == 0)
		{
			subject = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "upcolor", 7) == 0)
		{
			upcolor = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "downcolor", 9) == 0)
		{
			downcolor = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "recentcolor", 11) == 0)
		{
			recentcolor = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		}
		do_set(mydata.data[1], mydata.data[3]);
		free_parsed(&mydata);
		continue;

		/* others will set potential args to be used
		   in config file */
	}
	if (strncmp(mydata.data[0], "config", 6) == 0)
	{
		if (strncmp(mydata.data[1], "queuetime", 9) == 0)
		{
			queuetime = atoi(mydata.data[2]);
			free_parsed(&mydata);
			continue;
		}
		if (strncmp(mydata.data[1], "include", 7) == 0)
		{
			int subln = 0;
			FILE *subfh = NULL;
			struct hostinfo *subf = NULL;
			int tlvl;

			if (mydata.count != 3)
			{
				continue;
			}

			if (debug)
			{
				print_err(0, "about to open sub file %s", 
					mydata.data[2]);
			}
			subfh = fopen(mydata.data[2], "r");
			if (subfh == NULL)
			{
				perror(mydata.data[2]);
				continue;
			}
			/* parse the subfile */
			tlvl = *lvl;
			subf = parseline(&subln, lvl, mydata.data[2], subfh);
			if (tlvl != *lvl)
			{
				print_err(1, "WARNING: subfile %s has misbalanced braces!", mydata.data[2]);
			}
			/* subf now equal to the tree generated from
			 * that other file */

			xtra = subf;
			/* close the fd */
			fclose(subfh);
			goto setup_data;
			
		}
		if (strncmp(mydata.data[1], "showupalso", 10) == 0)
		{
			/* Show hosts that are up also in text file */
			showupalso = 1;
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "errorsto", 8) == 0)
		{
			if (debug)
			{
				print_err(0, "Setting errorsto == %s", 
					mydata.data[2]);
			}
			errorsto = strdup(mydata.data[2]);
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "header", 6) == 0)
		{
			if (mydata.count != 4)
			{
	                        print_err(1, "%s:%d: Not enough arguments to option header",
	                                cfname, *ln);
				free_parsed(&mydata);
                        	continue;
			}
			if (globhdr != NULL)
			{
				free(globhdr);
				globhdr = NULL;
			}
			if (globhdrval != NULL)
			{
				free(globhdrval);
				globhdrval = NULL;
			}
			if ((strcmp(mydata.data[2], "null") == 0) ||
				(strcmp(mydata.data[2], "NULL") == 0))
			{
				globhdr = NULL;
			} else {
				globhdr = strdup(mydata.data[2]);
			}

                        if ((strcmp(mydata.data[3], "null") == 0) ||
                                (strcmp(mydata.data[3], "NULL") == 0))
			{
				globhdrval = NULL;
			} else {
				globhdrval = strdup(mydata.data[3]);
			}
		} else if (strncmp(mydata.data[1], "maxqueued", 9) == 0)
		{
			if (debug)
			{
				print_err(0, "Setting maxqueued == %s",
					mydata.data[2]);
			}
			maxqueued = atoi(mydata.data[2]);
			if (maxqueued == 0)
			{
				print_err(1, "maxqueued can not be zero, using 100");
				maxqueued = 100;
			}
		} else if (strncmp(mydata.data[1], "replyto", 7) == 0)
		{
			if (debug)
			{
				print_err(0, "setting reply-to == %s",
					mydata.data[2]);
			}
			replyto = strdup(mydata.data[2]);
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "noheartbeat", 11) == 0)
		{
			heartbeat = 0; /* for me */
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "pageinterval", 12) == 0)
		{
			pageinterval = atoi(mydata.data[2]); /* in minutes */
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "logging", 7) == 0)
		{
			facility = match_facility(mydata.data[2]);
			if (facility == -1)
			{
				print_err(1, "logging facility of %s invalid, using daemon instead", mydata.data[2]);
				facility = LOG_DAEMON;
			}
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "dnslog", 6) == 0)
		{
			dnslog = atoi(mydata.data[2]);
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "dnsexpire", 9) == 0)
		{
			dnsexpire = atoi(mydata.data[2]);
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "statusfile", 10) == 0)
		{
			if (mydata.count != 4)
			{
				print_err(1, "invalid number of args for configuration option %s", mydata.data[1]);
				continue;
			}
			/* Determine the file type */
			if (strncmp(mydata.data[2], "html", 4) == 0) html = 1;
			if (strncmp(mydata.data[2], "text", 4) == 0) html = 0;
			if (html == -1)
			{
				print_err(1, "statusfile type of %s is invalid, try either html or text", mydata.data[2]);
				continue;
			}
			statusfilename = strdup(mydata.data[3]);
			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "nosubject", 9) == 0) {
			subject = NULL;
		} else if (strncmp(mydata.data[1], "authkey", 7) == 0) {
			if (authkey != NULL)
			{
				free(authkey);
				authkey = NULL;
			}
			authkey = strdup(mydata.data[2]);
		} else if (strncmp(mydata.data[1], "statefile", 9) == 0) {
			if (statefile != NULL)
			{
				free(statefile);
				statefile = NULL;
			}
			statefile = strdup(mydata.data[2]);
		} else if (strncmp(mydata.data[1], "numfailures", 11) == 0) {
			numfailures = atoi(mydata.data[2]);
	
			if (debug)
			{
				print_err(0, "%s:%d:changing numfailures to %d",cfname,*ln, numfailures);
			}

			free_parsed(&mydata);
			continue;
		} else if (strncmp(mydata.data[1], "sleeptime", 9) == 0)
		{
			print_err(1, "%s:%d:Ignoring legacy configuration option", cfname, *ln);
		} else {
			print_err(1, "%s:%d:Unknown configuration option %s",
				cfname, *ln, mydata.data[1]);
		}
		free_parsed(&mydata);
		continue;
	} 

	/* end if config block */
	/* must be a test type or something */
	if (mydata.data[1][0] == '-')
	{
		if (debug) print_err(0, "Turning on invert test option");
		data.reverse = 1;
		data.type = name_to_type(mydata.data[1]+1);
	} else {
		data.type = name_to_type(mydata.data[1]);
	}
	
	if (data.type == -1) 
	{
                print_err(1, "line %s:%d: Invalid test type", 
			cfname, *ln);
		free_parsed(&mydata);
                continue;
        }

	strcpy(data.hostname, mydata.data[0]); /* save hostname */

	/* In this switch, we group similar test types together
	   that can go through the same parser routines.  Some of
	   these features do not require any difference in handling
	   of arguments, as we've already gotten the type above.

	   We need to get rid of those abort()'s that are here, but
	   that awaits my coding a few more check types.  Most
	   important are the radius and dns checks */
	switch (data.type)
	{
		case SYSM_TYPE_TCP:
		/* ex: hostname tcp # desc "spawn" email {  */
		case SYSM_TYPE_UDP:
		/* ex: hostname udp # desc "spawn" email { */
			if (mydata.count > 7 || mydata.count < 4)
			{
				print_err(1, "insufficent arguments to test on line %d of %s", *ln, cfname);
				free_parsed(&mydata);
				continue;
			}
			data.port = atoi(mydata.data[2]);
			if (data.port == 0)
			{
				print_err(1, "invalid port number to test on line %d of %s", *ln, cfname);
				free_parsed(&mydata);
				continue;
			}

			/* Store the message */
			strcpy(data.message, mydata.data[3]);

			/* If we've reached our max arg count for this
			   line, get out of the case, and go along with
			   setting this all up.
			 */
			if (mydata.count == 4)
			{
				free_parsed(&mydata);
				break;
			}

			if (strncmp(mydata.data[4], "spawn", 5) == 0)
			{
				/* arg4 = spawn */
				data.command = strdup(mydata.data[4]);
			} else if (mydata.data[4][0] == '{') {
				/* arg4 = open curly brace */
                                *lvl = (*lvl) + 1;
                                data.child =  parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[4]);
				/* arg4 = contact */
			}
			if (mydata.count == 5) 
				break;
			if (mydata.data[5][0] == '{')
			{
				/* we have a curly brace */
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[5]);
			}
			if (mydata.count == 6)
				break;

			/* Must be a curly brace, otherwise line is bogus */
			if (mydata.data[6][0] == '{')
			{
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				print_err(1, "error in line %d of file %s", *ln, cfname);
			}

			/* end of parser for tcp/udp */
			break;

		case SYSM_TYPE_PING:
		/* ex: hostname ping desc "spawn" email { */
		case SYSM_TYPE_NNTP:
		/* ex: hostname nntp desc "spawn" email { */
		case SYSM_TYPE_SMTP:
		/* ex: hostname smtp desc "spawn" email { */
		case SYSM_TYPE_SYSM:
		/* ex: hostname sysmon desc "spawn" email { */
		case SYSM_TYPE_SSHD:
		/* ex: hostname ssh desc "spawn" email { */
		case SYSM_TYPE_X500:
		/* ex: hostname x500 desc "spawn" email { */
		/* Generic parser portion.  min args = 3, max args = 6 */
			if (mydata.count > 6 || mydata.count < 3)
			{
				print_err(1, "error on line %d of %s, args mismatch", *ln, cfname);
				free_parsed(&mydata);
				continue;
			}
			/* Required argument */
			strcpy(data.message, mydata.data[2]);
	
			/* If we've reached our max arg count for this
			   line, get out of the case, and go along with
			   setting this all up.
			 */
			if (mydata.count == 3)
			{
				break;
			}

			if (strncmp(mydata.data[3], "spawn", 5) == 0)
			{
				/* arg3 = spawn */
				data.command = strdup(mydata.data[3]);
			} else if (mydata.data[3][0] == '{') {
				/* arg3 = open curly brace */
                                *lvl = (*lvl) + 1;
                                data.child =  parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[3]);
				/* arg3 = contact */
			}
			if (mydata.count == 4) 
				break;
			if (mydata.data[4][0] == '{')
			{
				/* we have a curly brace */
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				data.contact =  strdup(mydata.data[4]);
			}
			if (mydata.count == 5)
				break;

			/* Must be a curly brace, otherwise line is bogus */
			if (mydata.data[5][0] == '{')
			{
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				print_err(1, "error in line %d in %s", *ln, cfname);
			}	
			break;

		case SYSM_TYPE_IMAP:
		/* ex: hostname imap user pw desc "spawn" email { */
		case SYSM_TYPE_POP3:
		/* ex: hostname pop3 user pw desc "spawn" email { */
		case SYSM_TYPE_POP2:
		/* ex: hostname pop2 user pw desc "spawn" email { */
		/* Generic parser portion.  min args = 6, max args = 8 */

			if (mydata.count > 8 || mydata.count < 6)
			{
				print_err(1, "error on line %d of %s, args mismatch", *ln, cfname);
				free_parsed(&mydata);
				continue;
			}
			/* the required arguments */
			strcpy(data.username, mydata.data[2]);
			strcpy(data.password, mydata.data[3]);
			strcpy(data.message, mydata.data[4]);


			/* If we've reached our max arg count for this
			   line, get out of the case, and go along with
			   setting this all up.
			 */
			if (mydata.count == 5)
			{
				break;
			}

			if (strncmp(mydata.data[5], "spawn", 5) == 0)
			{
				/* arg5 = spawn */
				data.command = strdup(mydata.data[5]);
			} else if (mydata.data[5][0] == '{') {
				/* arg5 = open curly brace */
                                *lvl = (*lvl) + 1;
                                data.child =  parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[5]);
				/* arg5 = contact */
			}
			if (mydata.count == 6) 
				break;
			if (mydata.data[6][0] == '{')
			{
				/* we have a curly brace */
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[6]);
			}
			if (mydata.count == 7)
				break;

			/* Must be a curly brace, otherwise line is bogus */
			if (mydata.data[7][0] == '{')
			{
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				print_err(1, "error in line %d in %s", *ln, cfname);
			}
			break;

		case SYSM_TYPE_WWW:
		/* ex: hostname http /file text desc "spawn" email { */
		/* non-generic parser portion.  min args = 5, max = 8 */
			if (mydata.count > 8 || mydata.count < 5)
			{
				print_err(1, "error on line %d of %s, args mismatch", *ln, cfname);
				free_parsed(&mydata);
				continue;
			}
			strcpy(data.url, mydata.data[2]);
			strcpy(data.url_text, mydata.data[3]);
			strcpy(data.message, mydata.data[4]);
			data.port = HTTP_PORTNUM;
			temp = index(mydata.data[1], ':');
			if (temp != NULL)
			{
				data.port = atoi(temp+1);
				if (debug)
					print_err(1, "resetting http_port to %d\n", data.port);
			}
		
			/* If we've reached our max arg count for this
			   line, get out of the case, and go along with
			   setting this all up.
			 */
			if (mydata.count == 5)
			{
				break;
			}

			if (strncmp(mydata.data[5], "spawn", 5) == 0)
			{
				/* arg5 = spawn */
				data.command = strdup(mydata.data[5]);
			} else if (mydata.data[5][0] == '{') {
				/* arg5 = open curly brace */
                                *lvl = (*lvl) + 1;
                                data.child =  parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[5]);
				/* arg5 = contact */
			}
			if (mydata.count == 6) 
				break;
			if (mydata.data[6][0] == '{')
			{
				/* we have a curly brace */
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[6]);
			}
			if (mydata.count == 7)
				break;

			/* Must be a curly brace, otherwise line is bogus */
			if (mydata.data[7][0] == '{')
			{
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				print_err(1, "error in line %d in %s", *ln, cfname);
			}
			break;	

		case SYSM_TYPE_RADIUS:
		/* ex: hostname radius user@x password secret desc [spawn] [email] [{] */
                        if (mydata.count > 9 || mydata.count < 6)
                        {
                                print_err(1, "error on line %d of %s, args mismatch", *ln, cfname);
				free_parsed(&mydata);
                                continue;
                        }
			strcpy(data.username, mydata.data[2]);
			strcpy(data.password, mydata.data[3]);
			data.port = 1645;
			data.secret = strdup(mydata.data[4]);
			strcpy(data.message, mydata.data[5]);
	
			/* If we've reached our max arg count for this
			   line, get out of the case, and go along with
			   setting this all up.
			 */
			if (mydata.count == 6)
			{
				break;
			}

			if (strncmp(mydata.data[6], "spawn", 5) == 0)
			{
				/* arg5 = spawn */
				data.command = strdup(mydata.data[5]);
			} else if (mydata.data[6][0] == '{') {
				/* arg6 = open curly brace */
                                *lvl = (*lvl) + 1;
                                data.child =  parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[6]);
				/* arg6 = contact */
			}
			if (mydata.count == 7) 
				break;
			if (mydata.data[7][0] == '{')
			{
				/* we have a curly brace */
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				data.contact = strdup(mydata.data[7]);
			}
			if (mydata.count == 8)
				break;

			/* Must be a curly brace, otherwise line is bogus */
			if (mydata.data[8][0] == '{')
			{
				*lvl = (*lvl) + 1;
				data.child = parseline(ln, lvl, cfname, fh);
			} else {
				print_err(1, "error in line %d in %s - should have found {, but we found %s", *ln, cfname, mydata.data[8]);
			}
			break;
/* UNIMPLEMENTED CHECKS FOLLOW HERE */
		case SYSM_TYPE_BOOTP:
		/* ex: hostname bootp desc "spawn" email { */
			break;
		case SYSM_TYPE_DNS:
		/* ex: hostname dns domain desc "spawn" email { */
			break;
		case SYSM_TYPE_HTTPS:
			break;
		case SYSM_TYPE_SNMP:
			break;
		default:
			print_err(1, "loadconfig.c: How did we get here?");
	}

	        /* Ok, time to allocate some memory */
	        hp = my_gethostbyname(data.hostname); /* do dns query */
	        if (!hp) 
	        {
	                print_err(1, "%s:%d - %s: unknown host, ignoring line",
				cfname, *ln, data.hostname);
			data.lastcheck = SYSM_NODNS;
			free_parsed(&mydata);
			continue;
	        } else  {
			data.inaddr = inet_addr(data.hostname);   /* do conversion */
		}
		if (hp->h_length > 4)
		{
			print_err(1, "warning: hostname %s returned multiple A records", data.hostname);
		}

	        xtra = MALLOC(sizeof(struct hostinfo), "hostinfo struct");

		if (globhdr != NULL)
			data.hdr = strdup(globhdr);
		if (globhdrval != NULL)
			data.hdrval = strdup(globhdrval);

	        /* copy the data structure into the xtra pointer we allocated */
	        memcpy(xtra, &data, sizeof(struct hostinfo));

setup_data:
		free_parsed(&mydata);

		/* if the first entry is null */
	        if (myfst == NULL)
	        {
	                current = xtra;
	                myfst = xtra; /* my first entry is now equal to the
	                                one that we just made -- same w/ current */
	        } 
		else 
		{
			if (current != NULL)
			{
		                current->sibling = xtra;
			}
	     	        current = xtra;
	     	 }

	} /* end of while */

	/*
	 *
	 */
	if (*lvl < 0)
	{
		print_err(1, "%s: line #%d - begin of missing brace?", cfname, *ln);
	}
	return myfst;
}

