
/* This version adds the distribution list and cleans up the program's
    handling of messages (especially outgoing ones) by using the
    fidonet.h file for some fidonet-specific functions.            */

/*
This program scans the message files in the netmail directory looking
for messages addressed to it (BBSLIST as the 1st 7 chars.).  Any messages
which are null or of unrecognized format will engender a "help" message
which is sent to the originator of the message.  Messages which are requests
are processed immediately.  Messages which would update the bbs listing are
first checked for a valid password.

----- Make sure you compile this program from the command line (bcc)! -----
*/

#define MAX_MSGS_TO_SCAN 200  /* We scan messages from 1 to this */
                              /*  number for the name BBSLIST.   */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <dos.h>       /* Dos-specific functions are used to get date/time. */

#include "fidonet.h"
#include "i_f_eng.c"

#define ERRORLEVEL_SUCCESS       0
#define ERRORLEVEL_LIST_CHANGED  1
#define ERRORLEVEL_BAD_PARAMETER 2
#define ERRORLEVEL_CONFIGURATION 3
#define ERRORLEVEL_ENGINE        4
#define ERRORLEVEL_FATAL         5

char DEBUG_FLAG=0,                      /* These two fields are gotten from the "debug_string" */
     delete_received_messages_flag=0;   /*  line of the configuration file.                    */

struct data_record_type  {
  char unique_number_highorder;
  char unique_number_loworder;
  char name[30];
  char sysop[20];
  char sysopreal[20];
  char number[10];
  char addr1[20];
  char addr2[20];
  char addr3[20];
  char baud[20];
  char location[20];
  char hours[10];
  char software[10];
  }  data_record;

struct distribution_record_type  {
  unsigned char net_highorder;
  unsigned char net_loworder;
  unsigned char node_highorder;
  unsigned char node_loworder;
  }  distribution_record;

struct print_record_1_type  {
  char name[30],
       filler_1[2],
       number[10],
       filler_2[2],
       baud[20],
       filler_3[2],
       hours[10];
  }  print_record_1;

struct print_record_2_type  {
  char sysop[20],
	   filler_1[2],
	   sysopreal[20],
	   filler_2[2],
	   location[20],
	   filler_3[2],
       software[10];
  }  print_record_2;

struct print_record_3_type  {
  char addr1[20],
	   filler_1[2],
	   addr2[20],
	   filler_2[2],
	   addr3[20],
	   filler_3[2],
       unique_number[10];
  }  print_record_3;

char create_bbslist_flag=0; /* Set non-zero if new bbslist.txt should be written.*/

FILE *config_file,*incoming_file,*outgoing_file,*bbslist_file,*temp_file;
int message_number = 0;    /* The message number to open; we search  */
						   /*  the first MAX_MSGS_TO_SCAN messages.  */
int temp_int,
  data_file_handle, /* Holds the file handle for the file engine. */
  distribution_file_handle,
  errcode,          /* Used for holding results of indexed file engine calls. */
  result;           /* This is used to hold the result of memcmp() calls. */
char from_bbslist_program[]="BBSLIST -- the bbslist maintainer",
  temp_string[128],temp_string_2[128],
  CR_string[2],   /* This gets initialized to be a CR we can append to lines. */
  CRLF_string[3],debug_string[10],
  parsed_message_line[128],parsed_keyword[128],parsed_value[128],  /* These are used for parsing message lines. */
  message_file_suffix[]=".msg",
  config_file_name[64],help_file_name[64],info_file_name[64],
  data_file_name[64],distribution_file_name[64],
  bbslist_file_name[64],
  bbslist_header_spec[64],bbslist_trailer_spec[64],update_password[16],
  incoming_file_name[64],outgoing_file_name[64],netmail_directory_spec[64];
div_t results;  /* Used for splitting integers into separate bytes. */


/*----------------------- Program functions ------------------------*/
void send_attached_bbslist()
{
printf("Sending attached bbslist now.\n");
if ( fidonet_send_message(from_bbslist_program,
                          incoming_header.fromUserName,
                          "",
                          bbslist_file_name,
                          netmail_directory_spec,
                          incoming_header.destNode_loworder,
                          incoming_header.destNode_highorder,
                          incoming_header.origNode_loworder,
                          incoming_header.origNode_highorder,
                          incoming_header.origNet_loworder,
                          incoming_header.origNet_highorder,
                          incoming_header.destNet_loworder,
                          incoming_header.destNet_highorder,
                          DEBUG_FLAG) )
  exit(ERRORLEVEL_FATAL);
add_to_message_body_file("  The BBS listing you requested has been attached as BBSLIST.TXT.");
create_bbslist_flag = 1;
}

void process_bbslist_change(unique_number)
{
printf("Processing bbslist change for number %d.\n",unique_number);
if (strcmp(incoming_header.subject,update_password)) /* Password not correct? */
  {
  add_to_message_body_file("  Invalid update password; please send update password as subject of message.");
  add_to_message_body_file("  Skipping keywords up to blank (separator) line or end of message.");
  while (parsed_keyword[0])
    parse_message_line();
  return;
  }
errcode = indexed_file(&data_file_handle,I_F_OPEN_IO,data_file_name,0);
if (errcode)  {
  printf("?Error opening data file to change record; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);    }
results = div(unique_number,256);    /* Try to read key. */
data_record.unique_number_highorder = results.quot;
data_record.unique_number_loworder  = results.rem;
errcode = indexed_file(&data_file_handle,I_F_READ,&data_record,0);
if (errcode == I_F_ERROR_KEYNOTFOUND)
  {
  strcpy(temp_string,"  ?Can't read unique number to change: ");
  itoa(unique_number,temp_string_2,10);
  strcat(temp_string,temp_string_2);
  add_to_message_body_file(temp_string);
  indexed_file(&data_file_handle,I_F_CLOSE,"",0);
  while (parsed_keyword[0])  /* Skip through the change field names */
	parse_message_line();    /*  until we get to a blank or end.    */
  return;
  }
/* We have read the record.  Modify the fields listed in the message. */
while (!parse_message_line())  /* Quit if EOF reached. */
  {
  /* printf("Parsed keyword: %s   Parsed value: %s\n",parsed_keyword,parsed_value); */
  if (!parsed_keyword[0])   /* Blank line in message? */
	break;                  /*  End of this particular function. */
  if       (!strcmp(parsed_keyword,"name"))      strncpy(data_record.name,parsed_value,sizeof(data_record.name));
   else if (!strcmp(parsed_keyword,"sysop"))     strncpy(data_record.sysop,parsed_value,sizeof(data_record.sysop));
   else if (!strcmp(parsed_keyword,"sysopreal")) strncpy(data_record.sysopreal,parsed_value,sizeof(data_record.sysopreal));
   else if (!strcmp(parsed_keyword,"number"))    strncpy(data_record.number,parsed_value,sizeof(data_record.number));
   else if (!strcmp(parsed_keyword,"addr1"))     strncpy(data_record.addr1,parsed_value,sizeof(data_record.addr1));
   else if (!strcmp(parsed_keyword,"addr2"))     strncpy(data_record.addr2,parsed_value,sizeof(data_record.addr2));
   else if (!strcmp(parsed_keyword,"addr3"))     strncpy(data_record.addr3,parsed_value,sizeof(data_record.addr3));
   else if (!strcmp(parsed_keyword,"baud"))      strncpy(data_record.baud,parsed_value,sizeof(data_record.baud));
   else if (!strcmp(parsed_keyword,"location"))  strncpy(data_record.location,parsed_value,sizeof(data_record.location));
   else if (!strcmp(parsed_keyword,"hours"))     strncpy(data_record.hours,parsed_value,sizeof(data_record.hours));
   else if (!strcmp(parsed_keyword,"software"))  strncpy(data_record.software,parsed_value,sizeof(data_record.software));
   else                                          {
                                                 strcpy(temp_string,"  ?Unknown keyword skipped: ");
												 strcat(temp_string,parsed_keyword);
                                                 add_to_message_body_file(temp_string);
                                                 }
  }
/* We have modified the data in the record. */
errcode = indexed_file(&data_file_handle,I_F_REWRITE,&data_record,0);
if (errcode) { /* The record was successfully added? */
  printf("?Unexpected error rewriting record; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);   }
indexed_file(&data_file_handle,I_F_CLOSE,data_file_name,0);
strcpy(temp_string,"  Changes made to listing for BBS with unique number ");
itoa(unique_number,temp_string_2,10);
strcat(temp_string,temp_string_2);
add_to_message_body_file(temp_string);
create_bbslist_flag = 1;
}

void process_bbslist_addition()
{
short unique_number=0;  /* Holds the unique number of the created message. */
printf("Processing bbslist addition.\n");
if (strcmp(incoming_header.subject,update_password)) /* Password not correct? */
  {
  add_to_message_body_file("  Invalid update password; please send update password as subject of message.");
  add_to_message_body_file("  Skipping keywords up to blank (separator) line or end of message.");
  while (parsed_keyword[0])
    parse_message_line();
  return;
  }
memset(&data_record,0,sizeof(struct data_record_type));
while (!parse_message_line())  /* Quit if EOF reached. */
  {
  if (!parsed_keyword[0])   /* Blank line in message? */
    {
    printf("Blank keyword encountered; end of ADD function.\n");
	break;                  /*  End of this particular function. */
    }
  if       (!strcmp(parsed_keyword,"name"))      strncpy(data_record.name,parsed_value,sizeof(data_record.name));
   else if (!strcmp(parsed_keyword,"sysop"))     strncpy(data_record.sysop,parsed_value,sizeof(data_record.sysop));
   else if (!strcmp(parsed_keyword,"sysopreal")) strncpy(data_record.sysopreal,parsed_value,sizeof(data_record.sysopreal));
   else if (!strcmp(parsed_keyword,"number"))    strncpy(data_record.number,parsed_value,sizeof(data_record.number));
   else if (!strcmp(parsed_keyword,"addr1"))     strncpy(data_record.addr1,parsed_value,sizeof(data_record.addr1));
   else if (!strcmp(parsed_keyword,"addr2"))     strncpy(data_record.addr2,parsed_value,sizeof(data_record.addr2));
   else if (!strcmp(parsed_keyword,"addr3"))     strncpy(data_record.addr3,parsed_value,sizeof(data_record.addr3));
   else if (!strcmp(parsed_keyword,"baud"))      strncpy(data_record.baud,parsed_value,sizeof(data_record.baud));
   else if (!strcmp(parsed_keyword,"location"))  strncpy(data_record.location,parsed_value,sizeof(data_record.location));
   else if (!strcmp(parsed_keyword,"hours"))     strncpy(data_record.hours,parsed_value,sizeof(data_record.hours));
   else if (!strcmp(parsed_keyword,"software"))  strncpy(data_record.software,parsed_value,sizeof(data_record.software));
   else                                          {
                                                 strcpy(temp_string,"  ?Unknown keyword skipped: ");
												 strcat(temp_string,parsed_keyword);
                                                 add_to_message_body_file(temp_string);
                                                 }
  }
if (DEBUG_FLAG)
  printf("Opening indexed file for I/O now.\n");
errcode = indexed_file(&data_file_handle,I_F_OPEN_IO,data_file_name,0);
if (errcode)
  {
  printf("?Error opening data file to add record; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);
  }
while (1)
  {
  results = div(unique_number,256);    /* Try to write with key; might exist already! */
  data_record.unique_number_highorder = results.quot;
  data_record.unique_number_loworder  = results.rem;
  printf("Trying to write record with loworder %d and highorder %d now.\n",data_record.unique_number_loworder,data_record.unique_number_highorder);
  errcode = indexed_file(&data_file_handle,I_F_WRITE,&data_record,0);
  if (errcode == I_F_ERROR_KEYEXISTS)  /* Go try the next unique number. */
    {
    if (DEBUG_FLAG)
      printf("Unique number %d already in file; trying next number.\n",unique_number);
    unique_number++;
    continue;
    }
  if (!errcode)  /* The record was successfully added? */
	break;
  printf("?Unexpected error adding record; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);
  }
if (DEBUG_FLAG)
  printf("Record was added ok.\n");
indexed_file(&data_file_handle,I_F_CLOSE,data_file_name,0);
strcpy(temp_string,"  BBS added to list and given unique number ");
itoa(unique_number,temp_string_2,10);
strcat(temp_string,temp_string_2);
add_to_message_body_file(temp_string);
create_bbslist_flag = 1;
}

void process_bbslist_deletion(short unique_number)
{
printf("Processing bbslist deletion of number %d.\n",unique_number);
if (strcmp(incoming_header.subject,update_password)) /* Password not correct? */
  {
  add_to_message_body_file("  Invalid update password; please send update password as subject of message.");
  add_to_message_body_file("  Skipping keywords up to blank (separator) line or end of message.");
  while (parsed_keyword[0])
    parse_message_line();
  return;
  }
/* Try to delete the BBS list entry with that unique number from the data file.*/
errcode = indexed_file(&data_file_handle,I_F_OPEN_IO,data_file_name,0);
if (errcode)  {
  printf("?Error opening data file; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);    }
results = div(unique_number,256);    /* Figure out the key. */
data_record.unique_number_highorder = results.quot;
data_record.unique_number_loworder  = results.rem;
errcode = indexed_file(&data_file_handle,I_F_READ,&data_record,0);
if (!errcode)
  errcode = indexed_file(&data_file_handle,I_F_DELETE,&data_record,0);
if (errcode == I_F_ERROR_KEYNOTFOUND)
  {
  strcpy(temp_string,"  ?Unable to delete BBS with unique number ");
  itoa(unique_number,temp_string_2,10);
  strcat(temp_string,temp_string_2);
  strcat(temp_string,"; doesn't exist!");
  add_to_message_body_file(temp_string);
  }
else
if (errcode)
  {
  printf("?Error deleting unique number %d; error code: %d\n",unique_number,errcode);
  exit(ERRORLEVEL_ENGINE);
  }
else
  {
  strcpy(temp_string,"  BBS with unique number ");
  itoa(unique_number,temp_string_2,10);
  strcat(temp_string,temp_string_2);
  strcat(temp_string," deleted!");
  add_to_message_body_file(temp_string);
  }
indexed_file(&data_file_handle,I_F_CLOSE,"",0);  /* Close the data file. */
create_bbslist_flag = 1;
}

void send_info_message()
{
printf("Sending info. message.\n");
if ( fidonet_send_message(from_bbslist_program,
                          incoming_header.fromUserName,
                          "",
                          info_file_name,
                          netmail_directory_spec,
                          incoming_header.destNode_loworder,
                          incoming_header.destNode_highorder,
                          incoming_header.origNode_loworder,
                          incoming_header.origNode_highorder,
                          incoming_header.origNet_loworder,
                          incoming_header.origNet_highorder,
                          incoming_header.destNet_loworder,
                          incoming_header.destNet_highorder,
                          DEBUG_FLAG) )
  exit(ERRORLEVEL_FATAL);
add_to_message_body_file("  The info file BBSLIST.INF has been attached to you.");
}

void process_distribution_list_update(char update_mode,char net_and_node[])  /* Update mode is 'a'dd or 'd'elete; net_and_node is "xxx/xxx". */
{
char the_net[8]="",the_node[8]="",*temp_char_ptr;
unsigned short net_number,node_number;
printf("Processing distribution list update; mode %c, net/node %s.\n",update_mode,net_and_node);
if (strcmp(incoming_header.subject,update_password)) /* Password not correct? */
  {
  add_to_message_body_file("  Invalid update password; please send update password as subject of message.");
  add_to_message_body_file("  Skipping keywords up to blank (separator) line or end of message.");
  while (parsed_keyword[0])
    parse_message_line();
  return;
  }
errcode = indexed_file(&distribution_file_handle,I_F_OPEN_READ,distribution_file_name,0);
if (errcode)  {
  printf("!Couldn't open distribution file; attempting to create new one\n");
  strcpy(I_F_FILE_ATTRIBUTES,"4 1 0 4 0");
  errcode = indexed_file(&distribution_file_handle,I_F_OPEN_WRITE,distribution_file_name,0);  }
if (errcode)  {
  printf("?Error checking/creating distribution file; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);    }
indexed_file(&distribution_file_handle,I_F_CLOSE,"",0);
if (strstr(net_and_node,"/")==NULL)       /* Bad format (slash missing)?      */
  {
  add_to_message_body_file("  ?Bad format; slash missing from net/node.  Specify as xxx/xxx.");
  return;
  }
temp_char_ptr = strtok(net_and_node,"/"); /* Now parse the net/node supplied. */
if (temp_char_ptr)
	strcpy(the_net,temp_char_ptr);
temp_char_ptr = strtok(NULL,"/");
if (temp_char_ptr)
strcpy(the_node,temp_char_ptr);
net_number  = (unsigned short)atol(the_net);
node_number = (unsigned short)atol(the_node);
if (!net_number)
  {
  add_to_message_body_file("  ?Net number invalid or zero -or- net/node format wrong (use xxx/xxx).");
  return;
  }
distribution_record.net_highorder  = (net_number >> 8)  & 255;
distribution_record.net_loworder   =  net_number        & 255;
distribution_record.node_highorder = (node_number >> 8) & 255;
distribution_record.node_loworder  =  node_number       & 255;
if (DEBUG_FLAG)
  printf("\n%d  %d  %d  %d  ----- TEST\n",distribution_record.net_highorder,
   distribution_record.net_loworder,distribution_record.node_highorder,
   distribution_record.node_loworder);
errcode = indexed_file(&distribution_file_handle,I_F_OPEN_IO,distribution_file_name,0);
if (errcode)                {
  printf("!Couldn't reopen distribution file; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);  }
errcode = indexed_file(&distribution_file_handle,I_F_READ,&distribution_record,0);
if (errcode)
  {
  if (update_mode == 'a')
    goto add_to_list;
  add_to_message_body_file("  ?Couldn't find net/node in the distribution list.");
  goto update_done;
  }
if (update_mode == 'a')
  {
  add_to_message_body_file("  ?Net/node already in the distribution list.");
  goto update_done;
  }
errcode = indexed_file(&distribution_file_handle,I_F_DELETE,&distribution_record,0);
if (errcode)
  {
  printf("?Invalid delete after good read in process_distribution_list_update()\n");
  printf(" Engine error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);
  }
goto send_verification;
add_to_list:
errcode = indexed_file(&distribution_file_handle,I_F_WRITE,&distribution_record,0);
if (errcode)
  {
  printf("?Invalid write in process_distribution_list_update(); error: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);
  }
if ( fidonet_send_message(from_bbslist_program,
                          "Sysop",
                          ";Your system has been added to the BBSLIST distribution list.",
                          bbslist_file_name,
                          netmail_directory_spec,
                          incoming_header.destNode_loworder,
                          incoming_header.destNode_highorder,
                          distribution_record.node_loworder,
                          distribution_record.node_highorder,
                          distribution_record.net_loworder,
                          distribution_record.net_highorder,
                          incoming_header.destNet_loworder,
                          incoming_header.destNet_highorder,
                          DEBUG_FLAG) )
  exit(ERRORLEVEL_FATAL);
if ( fidonet_send_message(from_bbslist_program,
                          "Sysop",
                          ";Attached is the help file for the BBSLIST message processor.",
                          help_file_name,
                          netmail_directory_spec,
                          incoming_header.destNode_loworder,
                          incoming_header.destNode_highorder,
                          distribution_record.node_loworder,
                          distribution_record.node_highorder,
                          distribution_record.net_loworder,
                          distribution_record.net_highorder,
                          incoming_header.destNet_loworder,
                          incoming_header.destNet_highorder,
                          DEBUG_FLAG) )
  exit(ERRORLEVEL_FATAL);
add_to_message_body_file("  New node notified and sent latest list and help file.");
/* Now send the distribution list along in the response message. */
send_verification:
memset(&distribution_record,0,sizeof(struct distribution_record_type));
errcode = indexed_file(&distribution_file_handle,I_F_START,&distribution_record,0);
add_to_message_body_file("  This is a list of the nodes currently on the distribution list:");
while (!indexed_file(&distribution_file_handle,I_F_READNEXT,&distribution_record,0))
  {
  net_number  = (distribution_record.net_highorder  << 8) + distribution_record.net_loworder;
  ltoa((long)net_number,the_net,10);
  node_number = (distribution_record.node_highorder << 8) + distribution_record.node_loworder;
  ltoa((long)node_number,the_node,10);
  strcpy(temp_string,"    ");
  strcat(temp_string,the_net);
  strcat(temp_string,"/");
  strcat(temp_string,the_node);
  add_to_message_body_file(temp_string);
  }
add_to_message_body_file("    (end of distribution list)");
update_done:
indexed_file(&distribution_file_handle,I_F_CLOSE,"",0);
}

/*--------------- Message character/line subroutines ---------------*/

int read_character_from_message()  /* Returns character or -1 for EOF. */
{                                  /*  Also return EOF if NULL found.  */
char input_char;
int result;
read_character:
result = fread(&input_char,1,1,incoming_file);
if (!result)            /* End of file?  Return EOF.           */
  return(-1);
if (input_char == 00)   /* End of message found; return EOF.   */
  return(-1);
if (input_char == 10)   /* Skip linefeeds in the message body. */
  goto read_character;
return(input_char);
}

int parse_message_line()  /* Sets global variables parsed_keyword and    */
{                         /* and parsed_value.  Returns non-zero if EOF. */
int parsed_keyword_pointer=0,parsed_value_pointer=0,char_from_file,
    parsed_message_line_pointer=0;

if (DEBUG_FLAG)
  printf("\nThis is parse_message_line().\n");
parsed_keyword[0] = 0;  /* Initialize to null strings. */
parsed_value[0]   = 0;
parsed_message_line[0] = 0;
char_from_file = read_character_from_message(); /* Read 1st char from message.*/
if (char_from_file == -1)   /* EOF? */
  {
  if (DEBUG_FLAG)
    printf("The first character read was EOF.\n");
  return(1);
  }
while (1)     /* Process/read characters until we break out. */
  {
  printf("Keyword character read; value: %d; character: %c\n",char_from_file,char_from_file);
  if (char_from_file == 13)
    {
    if (DEBUG_FLAG)
      printf("CR found while parsing keyword.\n");
    parsed_keyword[parsed_keyword_pointer] = 0;
    parsed_message_line[parsed_message_line_pointer] = 0;
    return(0);
    }
  parsed_keyword[parsed_keyword_pointer++] = char_from_file;
  parsed_message_line[parsed_message_line_pointer++] = char_from_file;
  if (parsed_keyword_pointer == sizeof(parsed_keyword))
    return(0);   /* Before it overflows! */
  if (parsed_message_line_pointer == sizeof(parsed_message_line))
    return(0);
  char_from_file = read_character_from_message();
  if (char_from_file == -1)
    {
    parsed_keyword[parsed_keyword_pointer] = 0;  /* Terminate string. */
    parsed_message_line[parsed_message_line_pointer] = 0;
    if (DEBUG_FLAG)
      printf("EOF char found while parsing keyword.\n");
    return(0);
    }
  if (char_from_file == '=')
    {
    parsed_keyword[parsed_keyword_pointer] = 0;
    parsed_message_line[parsed_message_line_pointer++] = '=';
    break;
    }              /* Go and read characters after '=' sign. */
  /* Go and read next character of keyword. */
  }
char_from_file = read_character_from_message();
if (char_from_file == -1)
  {
  parsed_message_line[parsed_message_line_pointer] = 0;
  if (DEBUG_FLAG)
    printf("EOF char found while reading char after =.\n");
  return(0);
  }
while (1)
  {
  printf("Value character read; value: %d; character: %c\n",char_from_file,char_from_file);
  if (char_from_file == 13)
    {
    parsed_value[parsed_value_pointer] = 0;
    parsed_message_line[parsed_message_line_pointer] = 0;
    if (DEBUG_FLAG)
      printf("CR found while reading value.\n");
    break;
    }
  parsed_value[parsed_value_pointer++] = char_from_file;
  parsed_message_line[parsed_message_line_pointer++] = char_from_file;
  if (parsed_value_pointer == sizeof(parsed_value))
    break;  /* Prevent overflow! */
  if (parsed_message_line_pointer == sizeof(parsed_message_line))
    break;
  char_from_file = read_character_from_message();
  if (char_from_file == -1)
    {
    parsed_value[parsed_value_pointer] = 0;
    parsed_message_line[parsed_message_line_pointer] = 0;
    if (DEBUG_FLAG)
      printf("EOF char found while reading value.\n");
    break;
    }
  }
return(0);
}

void process_this_message()
{
char temp_string[80],file_to_attach[80]="";
printf("Processing message %d....\n",message_number);
decode_attribute_word((incoming_header.AttributeWord_highorder*256)+incoming_header.AttributeWord_loworder);
if (flag_recd)  /* This message already received? */
  return;
if (init_message_body_file())  /* Where we echo incoming and write reply lines to.*/
  {
  printf("?Error initializing message body file\n");
  exit(ERRORLEVEL_FATAL);
  }
while (!parse_message_line())    /* Read lines of incoming message until EOF. */
  {
  if (!parsed_message_line[0])   /* Blank line? */
    continue;                    /*   Ignore blanks at this point. */
  if (parsed_message_line[0] != 1)  /* Don't echo kludge lines to requester. */
    {
    if (add_to_message_body_file(parsed_message_line))
      {
      printf("?Error adding to message body file.\n");
      exit(ERRORLEVEL_FATAL);
      }
    }
    if (DEBUG_FLAG)
      {
      printf("Just wrote parsed_message_line to message_body_file.\n");
      printf("Keyword: %s    Value: %s\n",parsed_keyword,parsed_value);
      }
  if       (!strcmp(parsed_keyword,"DELETE"))  process_bbslist_deletion(atoi(parsed_value));
   else if (!strcmp(parsed_keyword,"ADD")   )  process_bbslist_addition();
   else if (!strcmp(parsed_keyword,"CHANGE"))  process_bbslist_change(atoi(parsed_value));
   else if (!strcmp(parsed_keyword,"LIST")  )  send_attached_bbslist();
   else if (!strcmp(parsed_keyword,"HELP")  )  {
                                               strcpy(file_to_attach,help_file_name);
                                               add_to_message_body_file("  The help file is attached, per your request.");
                                               }
   else if (!strcmp(parsed_keyword,"INFO")  )  send_info_message();
   else if (!strcmp(parsed_keyword,"DIST-A"))  process_distribution_list_update('a',parsed_value);
   else if (!strcmp(parsed_keyword,"DIST-D"))  process_distribution_list_update('d',parsed_value);
   else if (parsed_keyword[0] == 1          )  {
                                               /* printf("Skipping kludge line.\n"); */
                                               continue;
                                               }
   else                                        {
                                               strcpy(file_to_attach,help_file_name);
                                               add_to_message_body_file("  ?Keyword unrecognized at this point; see attached help file.");
                                               }
  }
if (DEBUG_FLAG)
  printf("Getting ready to send back message body file %s\n",message_body_filename);
if ( fidonet_send_message(from_bbslist_program,
                          incoming_header.fromUserName,
                          message_body_filename,
                          file_to_attach,
                          netmail_directory_spec,
                          incoming_header.destNode_loworder,
                          incoming_header.destNode_highorder,
                          incoming_header.origNode_loworder,
                          incoming_header.origNode_highorder,
                          incoming_header.origNet_loworder,
                          incoming_header.origNet_highorder,
                          incoming_header.destNet_loworder,
                          incoming_header.destNet_highorder,
                          DEBUG_FLAG) )
  exit(ERRORLEVEL_FATAL);
incoming_header.AttributeWord_loworder |= 4;  /* Mark this message received. */
fseek(incoming_file,0,SEEK_SET);
result = fwrite(&incoming_header,sizeof(struct message_header_type),1,incoming_file);
if (!result)               {
  printf("?Error rewriting message header of incoming file\n");
  exit(ERRORLEVEL_FATAL);  }
}

void init_print_records()
{
memset(&print_record_1,32,sizeof(struct print_record_1_type));
memset(&print_record_2,32,sizeof(struct print_record_2_type));
memset(&print_record_3,32,sizeof(struct print_record_3_type));
}

void move_to_print_field(char output_field[],char input_field[],char field_size)
{
char offset_counter=0;
while (offset_counter < field_size)
  {
  if (!input_field[offset_counter])
	break;
  output_field[offset_counter] = input_field[offset_counter];
  offset_counter++;
  }
}

/*--------------------------- The Code -------------------------------------*/
int main(int argc, char *argv[])
{
struct date current_date;
struct time current_time;

printf("----Begin program execution\n");
if (argc != 2)
  {
  printf("?Illegal number of arguments; command line syntax: \n");
  printf("    BBSLIST BBSLIST.CFG                            \n");
  printf("  where BBSLIST.CFG is the path to the config file.\n");
  return(ERRORLEVEL_BAD_PARAMETER);
  }
strcpy(config_file_name,argv[1]);
config_file = fopen(config_file_name,"rt");
if (config_file == NULL)
  {
  printf("?Can't open config file %s\n",config_file_name);
  return(ERRORLEVEL_BAD_PARAMETER);
  }
fgets(help_file_name,sizeof(help_file_name),config_file);
help_file_name[strlen(help_file_name)-1] = 0;  /* Cut off LF. */
fgets(info_file_name,sizeof(info_file_name),config_file);
info_file_name[strlen(info_file_name)-1] = 0;  /* Cut off LF. */
fgets(data_file_name,sizeof(data_file_name),config_file);
data_file_name[strlen(data_file_name)-1] = 0;
fgets(distribution_file_name,sizeof(distribution_file_name),config_file);
distribution_file_name[strlen(distribution_file_name)-1] = 0;
fgets(bbslist_file_name,sizeof(bbslist_file_name),config_file);
bbslist_file_name[strlen(bbslist_file_name)-1] = 0;
fgets(netmail_directory_spec,sizeof(netmail_directory_spec),config_file);
netmail_directory_spec[strlen(netmail_directory_spec)-1] = 0;
if (netmail_directory_spec[strlen(netmail_directory_spec)-1] != '\\')  {
  netmail_directory_spec[strlen(netmail_directory_spec)+1] = 0;
  netmail_directory_spec[strlen(netmail_directory_spec)]   = '\\';     }
fgets(bbslist_header_spec,sizeof(bbslist_header_spec),config_file);
bbslist_header_spec[strlen(bbslist_header_spec)-1] = 0;
fgets(bbslist_trailer_spec,sizeof(bbslist_trailer_spec),config_file);
bbslist_trailer_spec[strlen(bbslist_trailer_spec)-1] = 0;
fgets(update_password,sizeof(update_password),config_file);
update_password[strlen(update_password)-1] = 0;
fgets(debug_string,sizeof(debug_string),config_file);
debug_string[strlen(debug_string)-1] = 0;
fclose(config_file);

if (debug_string[0] == 'Y')   /* Turn debug mode on? */
  DEBUG_FLAG = 1;
if (debug_string[1] == 'Y')
  delete_received_messages_flag = 1;

if (DEBUG_FLAG)
  {
  printf("Help file spec:            %s\n",help_file_name);
  printf("Info file spec:            %s\n",info_file_name);
  printf("Data file spec:            %s\n",data_file_name);
  printf("Distribution file name:    %s\n",distribution_file_name);
  printf("BBSLIST (text) file spec:  %s\n",bbslist_file_name);
  printf("Netmail directory spec:    %s\n",netmail_directory_spec);
  printf("BBSLIST header file spec:  %s\n",bbslist_header_spec);
  printf("BBSLIST trailer file spec: %s\n",bbslist_trailer_spec);
  printf("Update password:           %s\n",update_password);
  }
errcode = indexed_file(&data_file_handle,I_F_OPEN_READ,data_file_name,0);
if (errcode)  {
  printf("!Couldn't open data file; attempting to create new one\n");
  strcpy(I_F_FILE_ATTRIBUTES,"202 2 0 2 0 2 30 0");
  errcode = indexed_file(&data_file_handle,I_F_OPEN_WRITE,data_file_name,0);  }
if (errcode)  {
  printf("?Error checking/creating data file; error code: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);    }
indexed_file(&data_file_handle,I_F_CLOSE,"",0);

CR_string[0] = 13;  /* We'll use this for stuff. */
CR_string[1] = 0;
CRLF_string[0] = 13;
CRLF_string[1] = 10;
CRLF_string[2] = 0;

message_number = 0;        /* Start looking for messages addressed to us. */
while (1)   /* Do this until we break out. */
  {
  if (message_number++ > MAX_MSGS_TO_SCAN)    /* Check, then increment. */
	break;
  strcpy(incoming_file_name,netmail_directory_spec);
  itoa(message_number,temp_string,10);
  strcat(incoming_file_name,temp_string);
  strcat(incoming_file_name,message_file_suffix);
  incoming_file = fopen(incoming_file_name,"rb+");
  if (incoming_file != NULL)   /* Found a message file?     */
	{
    fread(&incoming_header,sizeof(struct message_header_type),1,incoming_file);
    temp_string[0] = 0;
    strncat(temp_string,incoming_header.toUserName,sizeof(incoming_header.toUserName));
    strupr(temp_string);
    result = memcmp(temp_string,"BBSLIST",8);
    if (!result)
      {
      process_this_message(); /* We found a message addressed to BBSLIST. */
      if (delete_received_messages_flag)
        {
        if (unlink(incoming_file_name))
          {
          printf("?Error deleting the incoming message we just processed.\n");
          printf(" The filename was %s.\n",incoming_file_name);
          exit(ERRORLEVEL_FATAL);
          }
        }
      }
    fclose(incoming_file);
    }
  }

if (!create_bbslist_flag)   /* Anything else to do? */
  exit(ERRORLEVEL_SUCCESS);  /*  Guess not!          */

/* First, write out the new bbslist text file from the data file. */
bbslist_file = fopen(bbslist_file_name,"wb");
if (bbslist_file == NULL)          {
  printf("?Error opening bbslist file for output\n");
  exit(ERRORLEVEL_CONFIGURATION);  }
temp_file = fopen(bbslist_header_spec,"rt");
if (temp_file == NULL)             {
  printf("?Error opening header file for bbs list\n");
  exit(ERRORLEVEL_CONFIGURATION);  }
while (!feof(temp_file))                                   {
  fgets(temp_string,sizeof(temp_string),temp_file);
  if (strlen(temp_string))
    temp_string[strlen(temp_string)-1] = 0;  /* Strip off CR. */
  fwrite(temp_string,strlen(temp_string),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);  }
fclose(temp_file);
/* Now print out each record in the indexed file. */
errcode = indexed_file(&data_file_handle,I_F_OPEN_READ,data_file_name,0);
if (errcode)
  {
  printf("?Error opening indexed file to write out new bbs list: %d\n",errcode);
  exit(ERRORLEVEL_ENGINE);
  }
memset(&data_record,0,sizeof(struct data_record_type));
errcode = indexed_file(&data_file_handle,I_F_START,&data_record,1);  /* Start by name. */
if (!errcode)
  errcode = indexed_file(&data_file_handle,I_F_READNEXT,&data_record,0);
while (!errcode)
  {               /* Copy the data fields to the print fields and print. */
  init_print_records();
  move_to_print_field(print_record_1.name,     data_record.name,     sizeof(print_record_1.name));
  move_to_print_field(print_record_1.number,   data_record.number,   sizeof(print_record_1.number));
  move_to_print_field(print_record_1.baud,     data_record.baud,     sizeof(print_record_1.baud));
  move_to_print_field(print_record_1.hours,    data_record.hours,    sizeof(print_record_1.hours));
  move_to_print_field(print_record_2.sysop,    data_record.sysop,    sizeof(print_record_2.sysop));
  move_to_print_field(print_record_2.sysopreal,data_record.sysopreal,sizeof(print_record_2.sysopreal));
  move_to_print_field(print_record_2.location, data_record.location, sizeof(print_record_2.location));
  move_to_print_field(print_record_2.software, data_record.software, sizeof(print_record_2.software));
  move_to_print_field(print_record_3.addr1,    data_record.addr1,    sizeof(print_record_3.addr1));
  move_to_print_field(print_record_3.addr2,    data_record.addr2,    sizeof(print_record_3.addr2));
  move_to_print_field(print_record_3.addr3,    data_record.addr3,    sizeof(print_record_3.addr3));
  itoa((data_record.unique_number_highorder*256)+data_record.unique_number_loworder,temp_string,10);
  move_to_print_field(print_record_3.unique_number,temp_string,sizeof(print_record_3.unique_number));
  fwrite(&print_record_1,sizeof(struct print_record_1_type),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
  fwrite(&print_record_2,sizeof(struct print_record_2_type),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
  fwrite(&print_record_3,sizeof(struct print_record_3_type),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
  errcode = indexed_file(&data_file_handle,I_F_READNEXT,&data_record,0);
  }
indexed_file(&data_file_handle,I_F_CLOSE,"",0);
temp_file = fopen(bbslist_trailer_spec,"rt");
if (temp_file == NULL)  {
  printf("?Error opening trailer file for bbs list\n");
  exit(ERRORLEVEL_CONFIGURATION);              }
while (!feof(temp_file))                     {
  fgets(temp_string,sizeof(temp_string),temp_file);
  if (strlen(temp_string))
    temp_string[strlen(temp_string)-1] = 0;
  fwrite(temp_string,strlen(temp_string),1,bbslist_file);
  fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);  }
fclose(temp_file);
fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
strcpy(temp_string,"This listing was last updated ");
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
getdate(&current_date);
itoa(current_date.da_mon,temp_string,10);
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
fwrite("/",1,1,bbslist_file);
itoa(current_date.da_day,temp_string,10);
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
fwrite("/",1,1,bbslist_file);
itoa(current_date.da_year,temp_string,10);
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
fwrite(" at ",4,1,bbslist_file);
gettime(&current_time);
itoa(current_time.ti_hour,temp_string,10);
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
fwrite(":",1,1,bbslist_file);
itoa(current_time.ti_min,temp_string,10);
fwrite(temp_string,strlen(temp_string),1,bbslist_file);
fwrite(CRLF_string,strlen(CRLF_string),1,bbslist_file);
fclose(bbslist_file);

/* Now send to the distribution list, if any. */
if (!indexed_file(&distribution_file_handle,I_F_OPEN_READ,distribution_file_name,0))  /* Does file exist at all? */
  {
  memset(&distribution_record,0,sizeof(struct distribution_record_type));
  indexed_file(&distribution_file_handle,I_F_START,&distribution_record,0);
  while (!indexed_file(&distribution_file_handle,I_F_READNEXT,&distribution_record,0))
    {
    if ( fidonet_send_message(from_bbslist_program,
                              "Sysop",
                              "",
                              bbslist_file_name,
                              netmail_directory_spec,
                              incoming_header.destNode_loworder,
                              incoming_header.destNode_highorder,
                              distribution_record.node_loworder,
                              distribution_record.node_highorder,
                              distribution_record.net_loworder,
                              distribution_record.net_highorder,
                              incoming_header.destNet_loworder,
                              incoming_header.destNet_highorder,
                              DEBUG_FLAG) )
      exit(ERRORLEVEL_FATAL);
    }
  indexed_file(&distribution_file_handle,I_F_CLOSE,"",0);
  }

return(ERRORLEVEL_LIST_CHANGED);
}

