/*
 * Configuration module
 * by Ken Hollis (take from some old Atari ST code I wrote a while ago)
 *
 * Note: This is quite complex, and it works quite well.  I have not
 * found any bugs except for the fact that you need to configure the
 * options in an exact way or it will break on you.  :-D  This was the
 * most efficient piece of configuration code I've ever written.  It's
 * quite nice, actually.  :-)
 *
 * Copyright (C) 1994 - 1995, Ken Hollis (khollis@bitgate.chatlink.com)
 */

#include "cfingerd.h"

int trusted_host_num;
int rejected_host_num;
int fakeuser_num;
int num_headers;

typedef struct {
    char *option;
    int level;
    BOOL is_boolean;
    BOOL is_extended_list;
    BOOL is_text;
    BOOL is_userlist;
    BOOL is_single_boolean;
    BOOL is_numeric;
    int value;
} CONFIG_STRUCT;

#define CONFIG_OPTIONS	62

CONFIG_STRUCT configure_strings[] = {
    {"plan_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"project_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"nofinger_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"top_display_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"bottom_display_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"no_name_banner_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"no_user_banner_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"rejected_banner_file", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"finger_program", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"trusted_hosts", 0, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 0},
    {"rejected_hosts", 0, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 0},
    {"show_top_file", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_TOP},
    {"show_bottom_file", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_BOTTOM},
    {"show_login_id", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_UNAME},
    {"show_realname", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_REALNAME},
    {"show_directory", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_DIR},
    {"show_shell", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_SHELL},
    {"show_room_number", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_ROOM},
    {"show_work_phone", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_WPHONE},
    {"show_home_phone", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_HPHONE},
    {"show_other", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_OTHER},
    {"show_last_time_on", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_LTON},
    {"show_if_online", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_IFON},
    {"show_last_time_mail_read", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_LRMAIL},
    {"show_last_day_mail_read", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_MRDATE},
    {"show_last_origination", 1, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_FROM},
    {"show_planfile", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_PLAN},
    {"show_projectfile", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_PROJECT},
    {"show_no_name_banner", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_NN_BANNER},
    {"show_rejected_banner", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_REJECTED},
    {"show_system_list", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_SYSTEMLIST},
    {"show_nouser", 2, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, SHOW_NOUSER},

    {"show_system_wildcard", 2, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, SHOW_WILDCARD},
    {"show_no_ip_match", 2, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, SHOW_IP_MATCH},

    {"username_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_USERNAME},
    {"realname_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_REALNAME},
    {"directory_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_DIRECTORY},
    {"shell_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_SHELL},
    {"room_number_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_ROOM},
    {"work_phone_number_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_WORK_PHONE},
    {"home_phone_number_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_HOME_PHONE},
    {"other_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_OTHER},
    {"ip_no_hostmatch", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_IP_NO_MATCH},
    {"nice_fatal", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_NICE_FATAL},
    {"stdin_empty", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_STDIN_EMPTY},
    {"trusted_host_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_TRUST_HOST},
    {"rejected_host_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_REJECT_HOST},
    {"root_finger_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_ROOT_FINGER},
    {"service_finger_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_SVC_FINGER},
    {"userlist_finger_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_ULIST_FINGER},
    {"fake_user_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_FAKE_USER},
    {"whois_user_text", 0, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, D_WHOIS_USER},

    {"services_header_1", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_header_2", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_header_3", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_header_4", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_header_5", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_string", 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0},
    {"services_userpos", 0, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, 0},
    {"services_servpos", 0, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, 0},
    {"services_srchpos", 0, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, 0},
    {"fakeuser", 0, FALSE, FALSE, FALSE, TRUE, FALSE, 0}
};

/* This is for debugging information.  DON'T TOUCH!  :-) */
void show_configuration(void)
{
    int i;

    printf("System configuration for finger:\n\n");
    printf("TOP: %s || BOTTOM: %s\n", prog_config.top_display_file,
	   prog_config.bottom_display_file);
    printf("PLAN: %s || PROJECT %s\nNO_NAME_BANNER: %s",
	   prog_config.plan_file, prog_config.project_file,
	   prog_config.no_name_banner_file);
    printf(" || NO_FINGER: %s\n", prog_config.no_finger_file);
    printf("REJECTED_BANNER: %s\n", prog_config.rejected_file);
    printf("%s", (prog_config.config_bits1 & 0x0001) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0002) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0004) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0008) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0010) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0020) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0040) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0080) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0100) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0200) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0400) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x0800) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x1000) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x2000) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x4000) ? "T" : "F");
    printf("%s", (prog_config.config_bits1 & 0x8000) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0001) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0002) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0004) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0008) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0010) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0020) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0040) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0080) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0100) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0200) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0400) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x0800) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x1000) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x2000) ? "T" : "F");
    printf("%s", (prog_config.config_bits2 & 0x4000) ? "T" : "F");
    printf("%s\n", (prog_config.config_bits2 & 0x8000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0001) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0002) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0004) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0008) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0010) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0020) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0040) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0080) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0100) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0200) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0400) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x0800) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x1000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x2000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x4000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits1 & 0x8000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0001) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0002) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0004) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0008) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0010) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0020) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0040) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0080) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0100) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0200) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0400) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x0800) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x1000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x2000) ? "T" : "F");
    printf("%s", (prog_config.local_config_bits2 & 0x4000) ? "T" : "F");
    printf("%s\n", (prog_config.local_config_bits2 & 0x8000) ? "T" : "F");
    printf("TRUSTED_HOSTS: %d\n", trusted_host_num);
    for (i = 0; i < trusted_host_num; i++)
	printf("%s ", prog_config.trusted[i]);
    printf("\n");
    printf("REJECTED_HOSTS: %d\n", rejected_host_num);
    for (i = 0; i < rejected_host_num; i++)
	printf("%s ", prog_config.rejected[i]);
    printf("\n");
}

void read_configuration(void)
{
    FILE *file = fopen(CFINGER_CONF, "r");

    if (file) {
	while (!feof(file)) {
	    char *element = NULL;
	    char first = fgetc(file);

	    ungetc(first, file);

	    element = (char *) malloc(80);

	    if ((first == '#') || (first == ';') || (first == '*') ||
		(first == '\'') || (first == '!') || (first == '\n')) {
		/* Get the entire line until we hit a return, and remove
		   the return at the end.  (I don't need to, but it looks
		   nice if you want to display the option.  :-P */
		fscanf(file, "%[^\n]\n", element);
	    } else {
		char *option = NULL;
		int i;
		BOOL found = FALSE;

		option = (char *) malloc(80);

		/* Cut off the equal after it reaches the equal; we don't
		   want it in the configuration option!  That would be
		   very bad, Jim. */
		fscanf(file, "%[^=]=", option);

		option = lowercase(option);

		for (i = 0; i < CONFIG_OPTIONS; i++)
		    if (!strcmp(option, configure_strings[i].option)) {
			found++;
			break;
		    }

		if ((!strcmp(option, configure_strings[i].option)) &&
		    (!configure_strings[i].is_text) &&
		    (!configure_strings[i].is_numeric)) {
		    int level;

		    level = configure_strings[i].level;
		    if (level == 0 && !configure_strings[i].is_extended_list &&
			!configure_strings[i].is_userlist) {
			char *filename = NULL;

			filename = (char *) malloc(80);

			/* Get the filename, and consider everything after
			   the filename (a tab or return) a comment. */
			fscanf(file, "%[^\t\n]\t\n", filename);

			/* I could not think of an easier way to do this,
			   so there are copies and recopies of it...  :( */
			if (!strcmp(option, "plan_file")) {
			    strmcpy(&prog_config.plan_file, filename);
			}

			if (!strcmp(option, "project_file")) {
			    strmcpy(&prog_config.project_file, filename);
			}

			if (!strcmp(option, "nofinger_file")) {
			    strmcpy(&prog_config.no_finger_file, filename);
			}

			if (!strcmp(option, "top_display_file")) {
			    strmcpy(&prog_config.top_display_file, filename);
			}

			if (!strcmp(option, "bottom_display_file")) {
			    strmcpy(&prog_config.bottom_display_file, filename);
			}

			if (!strcmp(option, "no_name_banner_file")) {
			    strmcpy(&prog_config.no_name_banner_file, filename);
			}

			if (!strcmp(option, "no_user_banner_file")) {
			    strmcpy(&prog_config.no_user_banner_file, filename);
			}

			if (!strcmp(option, "rejected_banner_file")) {
			    strmcpy(&prog_config.rejected_file, filename);
			}

			if (!strcmp(option, "finger_program")) {
			    strmcpy(&prog_config.finger_program, filename);
			}

			if (!strcmp(option, "services_header_1")) {
			    strmcpy(&prog_config.services.header[1], filename);
			    num_headers = 1;
			}

			if (!strcmp(option, "services_header_2")) {
			    strmcpy(&prog_config.services.header[2], filename);
			    num_headers = 2;
			}

			if (!strcmp(option, "services_header_3")) {
			    strmcpy(&prog_config.services.header[3], filename);
			    num_headers = 3;
			}

			if (!strcmp(option, "services_header_4")) {
			    strmcpy(&prog_config.services.header[4], filename);
			    num_headers = 4;
			}

			if (!strcmp(option, "services_header_5")) {
			    strmcpy(&prog_config.services.header[5], filename);
			    num_headers = 5;
			}

			if (!strcmp(option, "services_string")) {
			    strmcpy(&prog_config.services.display_string, filename);
			}

			free(filename);
		    }

		    if (configure_strings[i].is_userlist) {
			char *option1 = NULL, *option2 = NULL,
			     *option3 = NULL, *option4 = NULL;

			option1 = (char *) malloc(80);
			option2 = (char *) malloc(80);
			option3 = (char *) malloc(80);
			option4 = (char *) malloc(80);

			fscanf(file, "%[^,\n],%[^,\n],%[^,\n],%[^\t\n]\t\n",
				option1, option2, option3, option4);

			option3 = lowercase(option3);

			strmcpy(&prog_config.fusers[fakeuser_num].user, option1);
			strmcpy(&prog_config.fusers[fakeuser_num].description, option2);
			prog_config.fusers[fakeuser_num].searchable =
				(!strcmp(option3, "true")) ? TRUE : FALSE;
			strmcpy(&prog_config.fusers[fakeuser_num].script, option4);

			fakeuser_num++;

			free(option1);
			free(option2);
			free(option3);
			free(option4);
		    }

		    if (configure_strings[i].is_extended_list) {
			char *option = (char *) malloc(80);

			fscanf(file, "%[^\n\t]\n\t", option);
			option[strlen(option) + 1] = '\0';

			if (!strcmp("trusted_hosts", configure_strings[i].option)) {
			    for (;;) {
				strmcpy(&prog_config.trusted[trusted_host_num], strsep(&option, ","));

				if (!strcmp(local_host, prog_config.trusted[trusted_host_num]) ||
				    (!strcmp("localhost", prog_config.trusted[trusted_host_num]) &&
				    !prog_config.config_bits2 & SHOW_WILDCARD)) {
				    printf("Cannot have your local host in the TRUSTED_HOST list!  Re-configure!\n");
#ifdef	SYSLOG
				    syslog(LOG_ERR, "TRUSTED_HOST list contains LOCAL HOST!");
#endif
				    exit(PROGRAM_SYSLOG);
				}

				if (option == NULL)
				    break;
				else
				    trusted_host_num++;
			    }

			    trusted_host_num++;
			}

			if (!strcmp("rejected_hosts", configure_strings[i].option)) {
			    for (;;) {
				strmcpy(&prog_config.rejected[rejected_host_num], strsep(&option, ","));

				if (!strcmp(local_host, prog_config.rejected[rejected_host_num]) ||
				    (!strcmp("localhost", prog_config.rejected[rejected_host_num]) &&
				    !prog_config.config_bits2 & SHOW_WILDCARD)) {
				    printf("Cannot have your local host in the REJECTED_HOST list!  Re-configure!\n");
#ifdef	SYSLOG
				    syslog(LOG_ERR, "REJECTED_HOST list contains LOCAL HOST!");
#endif
				    exit(PROGRAM_SYSLOG);
				}

				if (option == NULL)
				    break;
				else
				    rejected_host_num++;
			    }

			    rejected_host_num++;
			}

			free(option);
		    }

		    if ((level == 1) || (level == 2)) {
			if (configure_strings[i].is_boolean) {
			    char *option1 = NULL, *option2 = NULL;

			    option1 = (char *) malloc(80);
			    option2 = (char *) malloc(80);

			/* Get the "firstoption,secondoption" (NO spaces),
			   and consider that everything else after the
			   secondoption a comment. */
			    fscanf(file, "%[^,],%[^\t\n]\t\n",
				   option1, option2);

			    option1 = lowercase(option1);
			    option2 = lowercase(option2);

			    if (level == 1) {
				prog_config.config_bits1 |=
				    (!strcmp(option1, "true")) ?
				    configure_strings[i].value : 0;
				prog_config.local_config_bits1 |=
				    (!strcmp(option2, "true")) ?
				    configure_strings[i].value : 0;
			    } else if (level == 2) {
				prog_config.config_bits2 |=
				    (!strcmp(option1, "true")) ?
				    configure_strings[i].value : 0;
				prog_config.local_config_bits2 |=
				    (!strcmp(option2, "true")) ?
				    configure_strings[i].value : 0;
			    }

			    free(option1);
			    free(option2);
			} else if (configure_strings[i].is_single_boolean) {
			    char *option = NULL;

			    option = (char *) malloc(80);
			    fscanf(file, "%[^\t\n]\t\n", option);

			    option = lowercase(option);

			    if (level == 1) {
				prog_config.config_bits1 |=
				    (!strcmp(option, "true")) ?
				    configure_strings[i].value : 0;
			    } else if (level == 2) {
				prog_config.config_bits2 |=
				    (!strcmp(option, "true")) ?
				    configure_strings[i].value : 0;
			    }

			    free(option);
			}
		    }
		} else if ((!strcmp(option, configure_strings[i].option)) &&
					configure_strings[i].is_text) {
		    char *option = (char *) malloc(80);
		    char *dummy = (char *) malloc(80);

		    fscanf(file, "\"%[^\t\"]\t\"%[^\n]\n", option, dummy);

		    strmcpy(&prog_config.p_strings[configure_strings[i].value],
			    option);
		} else if ((!strcmp(option, configure_strings[i].option)) &&
					configure_strings[i].is_numeric) {
		    char *opt = (char *) malloc(80);

		    fscanf(file, "%[^\t\n]\t\n", opt);

		    if (!strcmp(option, "services_userpos"))
			prog_config.services.name_pos = atoi(opt);

		    if (!strcmp(option, "services_servpos"))
			prog_config.services.service_pos = atoi(opt);

		    if (!strcmp(option, "services_srchpos"))
			prog_config.services.search_pos = atoi(opt);
		} else {
		    /* Hey, what you trying to do, bomb cfingerd? >B] */
		    if ((!strstr(option, "true")) && (!strstr(option, "false"))) {
#ifdef	SYSLOG
			syslog(LOG_WARNING, "Option %s non-existent", option);
#endif

#ifdef	DEBUG
			printf("%s\n", option);
#endif
		    }
		}

		free(option);
	    }

	    free(element);
	}

        fclose(file);
    } else {
#ifdef	SYSLOG
	syslog(LOG_ERR, "%s not found", CFINGER_CONF);
#endif
	printf("The configuration file, %s, was not found.  This file *MUST*\n", CFINGER_CONF);
	printf("be present in order for cfingerd to operate correctly.\n\n");
	exit(PROGRAM_SYSLOG);
    }
}
