/*  READ ME READ ME READ ME READ ME READ ME READ ME READ ME READ ME  */
/*    This file is _horrendous_! Do not even attempt to follow it.   */
/*    I'm going to have to wait til SRSv2 to clean it up. There is   */
/*    just not enough time.                                          */
/*                                                                   */
/*    There is a lot of repetitious and redundant code.. and huge    */
/*    function sizes. Once we clean up it will be a lot smaller      */
/*  READ ME READ ME READ ME READ ME READ ME READ ME READ ME READ ME  */

/* This has functions to parse various data from server */
/* ---------------------------------------------------- */

#include "headers.h" /* has all important stuff */

/* parse options from config file */
void parseSysConf(char *str)
{   
   register int i, j;

   int count = 0;      /* prevent overflows */

   int didfacs = 0, numfacs = 0; 

   char filename[MAXFNAMESIZE];
   char facility[16], priority[16];

   char *dataptr, *facptr, *priptr, *fnameptr;

   memset(filename, 0, sizeof(filename));
   memset(facility, 0, sizeof(facility));
   memset(priority, 0, sizeof(priority));

   dataptr = str;
   facptr = facility, priptr = priority, fnameptr = filename;

   if ((str[0] == '\0') || (str[0] == '\n') || (isprint((int)str[0]) == 0)) 
      return;

   else if (strchr(str, '#') != NULL)
   {
      if (str[0] == '#') return;
      else
      {
         char *ptr = strchr(str, '#');
         if (ptr != NULL) *ptr = '\0'; 
      }   
   }

   else if ((strstr(str, "ifdef(") != NULL)  || 
       (strstr(str, "ifndef(") != NULL) || 
       (strstr(str, "elif(") != NULL)   ||
       (strstr(str, "else(") != NULL))
   {
      /* FIX - do we need to set any values to ERROR? */
      error("ifdef(), ifndef(), elif(), and else() "
            "aren't supported at this time\n\n");

      return;
   }

   else if (strchr(str, ')') != NULL)
   {
      debug("possibly the end of an ifdef(), ignoring\n");
      return;
   }

   /* --------------------- facility stuff ---------------------- */

   curlogfd++;
   debug("(in parseSysConf) curlogfd = %d\n", curlogfd);

   if (curlogfd >= MAXLOGTYPES)
   {
      error("error parsing /etc/syslog.conf.. overflowed logs[]\n\n");
      quit(ERROR);
   }

   if (str[0] == '*') 
   {
      logs[curlogfd].facility = ALL;

      memset(facility, 0, sizeof(facility));
      strcpy(facility, "*");

      debug("facility = * (all facilities)\n\n");
   }

   else if (str[0] == '-')
      logs[curlogfd].nsync = 1; /* don't sync/flush data */

   /* parse facility.* */
   else /* no tricks for us.. just do it normally */
   {
      facptr = facility;
      memset(facility, 0, sizeof(facility));

      /* do manual parsing */
      count = 0;
      while ((*dataptr) && (*dataptr != ' ') &&
             (*dataptr != '.') && (*dataptr != ',') && 
             (isprint((int)*dataptr) != 0) && 
             (count < (int)sizeof(facility)-1))
      {
         *facptr++ = *dataptr++;
         count++;
      }

      debug("facility = %s\n", facility);

      if (isprint((int)*dataptr) != 0)
         debug("current seperator = %c\n", *dataptr);

      else
         debug("current seperator = 0x%x (in hex)\n", *dataptr);

      if (debugging == 1)
      {
         (void)putchar('\n');
         (void)write(dblogfd, "\n", 1);
      }

      logs[curlogfd].facility = facNameToVal(facility);

      if (logs[curlogfd].facility == ERROR)
      {
         error("(in parseSysConf) error parsing line:\n%s"
               "unknown facility type..\n\n", str);

         quit(ERROR);
      }

      logs[curlogfd].facility = facNameToVal(facility);

      if (*dataptr == ',')
      {
         parsePri(str); /* parse the previous one */
         dataptr += 1; 

         curlogfd++, numfacs = 0;
         if (curlogfd >= MAXLOGTYPES)
         {
            error("error parsing /etc/syslog.conf.. overflowed logs[]\n\n");
            quit(ERROR);
         }

/*
         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
*/

         debug("curlogfd = %d\n", curlogfd);

         debug("---before parseFac---\n");
         numfacs = parseFac(dataptr, numfacs);
         debug("---after parseFac---\n");

         debug("curlogfd = %d\n", curlogfd);
/*
         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
*/
         didfacs = 1;
      }
   }

   /* --------------------- priority stuff ---------------------- */

   /* "*.*" probably -- try a shortcut/hack */
   if (str[3] == '*') /* do we have a shortcut? */
   {
      logs[curlogfd].priority.priority = ALL;

      memset(priority, 0, sizeof(priority));
      strcpy(priority, "*");

      debug("priority = * (all priorities)\n");
   }

   /* parse *.priority */
   else if (didfacs != 1) /* no tricks for us.. just do it normally */
   {
      dataptr = strchr(str, '.');
      if (dataptr == NULL)
      {
         error("(in sysLogConf) unable to parse:\n%s\n", str);
         quit(ERROR);
      }

      dataptr += 1; /* skip '.' */

      /* can be "*.!=*" or "*.=*" */
      if (*dataptr == '!') 
      {
         /* check for possible bugs */
         if ((*(dataptr + 1)) == '*')
         {
            error("error parsing line (no '*' allowed after '!'): %s\n", str);
            quit(ERROR);
         }

         debug("exclude ('!') on\n");
         logs[curlogfd].priority.exclude = 1;
      }

      if ((*dataptr == '=') || ((*(dataptr+1)) == '=')) 
      {
         /* check for possible bugs */
         if (((*(dataptr + 1)) == '*') || ((*(dataptr + 2)) == '*'))
         {
            error("error parsing line (no '*' allowed after '='):\n%s\n", str);
            quit(ERROR);
         }

         debug("single ('=') on\n");
         logs[curlogfd].priority.single = 1;
      }

      /* skip to next valid data to parse */
      if (logs[curlogfd].priority.single == 1)
      {
         if (logs[curlogfd].priority.exclude == 1)
            dataptr += 2; /* skip both '!' and '=' */

         else
            dataptr += 1;
      }

      else if (logs[curlogfd].priority.exclude == 1)
         dataptr += 1;
         
      priptr = priority;
      memset(priority, 0, sizeof(priority));
      
      count = 0;
      while ((*dataptr) && (*dataptr != ' ') &&
             (*dataptr != ';') && (isprint((int)*dataptr) != 0) && 
             (count < (int)sizeof(priority)-1))
      {
         *priptr++ = *dataptr++;
         count++;
      }

      if (strchr(priority, '*') != NULL)
      {
         if (logs[curlogfd].priority.exclude == 1)
         {
            (void)strcpy(priority, "none");
            logs[curlogfd].priority.priority = NONE;
            debug("priority = %s (no priorities)\n", priority);
         }

         else
         {
            logs[curlogfd].priority.priority = ALL;
            debug("priority = %s (all priorities)\n", priority);
         }
      }

      else if (strncmp(priority, "none", 4) == 0)
      {
         if (logs[curlogfd].priority.exclude == 1)
         {
            (void)strcpy(priority, "all");
            logs[curlogfd].priority.priority = ALL;
            debug("priority = !none (all priorities)\n");
         }

         else
         {
            (void)strcpy(priority, "none");
            logs[curlogfd].priority.priority = NONE;
            debug("priority = %s (no priorities)\n", priority);
         }
      }

      else 
      {
         if (logs[curlogfd].priority.exclude == 1)
         {
            if (logs[curlogfd].priority.single == 1)
            {
               logs[curlogfd].priority.ignpri = priNameToVal(priority);
               logs[curlogfd].priority.priority = ERROR;
            }
         }

         else
            logs[curlogfd].priority.priority = priNameToVal(priority);

         debug("priority = %s\n", priority);
      }

      if (isprint((int)*dataptr) != 0)
         debug("current seperator = '%c'\n", *dataptr);

      else
         debug("current seperator = 0x%x (in hex)\n", *dataptr);

      if (*dataptr == ';')
      {
         errors = 0, dataptr += 1;
         parseFile(dataptr, didfacs, numfacs, facility, priority);

         if (errors == 1)
         {
            errors = 0;
            return;
         }

         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }

         debug("---before parseSysConf---\n");
         parseSysConf(dataptr);
/*
         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
*/
         return;
      }
   }
   
   /* -------------- little error checking -------------- */

   if (didfacs == 1)
      while ((isprint((int)*dataptr) != 0) && (*dataptr != ' ')) 
         dataptr += 1;

   /* get to file name */
   while ((isprint((int)*dataptr) == 0) || (*dataptr == ' '))
   dataptr += 1;

   if (*dataptr == '\0')
   {
      error("error parsing line:\n%s"
            "found an unexpected null..\n\n", str);

      quit(ERROR);
   }

   else if (*dataptr == '\n')
   {
      error("error parsing line:\n%s"
            "found an unexpected newline..\n\n", str);

      quit(ERROR);
   }

   /* -------------- file/device/user output ------------- */
  
   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   debug("dataptr = %c\n", (*dataptr));
   if (*dataptr == '/')
   {
      count = 0;
      memset(filename, 0, sizeof(filename));

      while ((*dataptr) && (isprint((int)*dataptr) != 0) && 
            (count < (int)sizeof(filename)-1))
      {
         *fnameptr++ = *dataptr++;
         count++;
      }    

      if (didfacs != 1)
         debug("logging %s.%s to: %s\n", facility, priority, filename);

      else
      {
         for (i = curlogfd - numfacs; i <= curlogfd; i++)
         {
            strcpy(facility, facValToName(logs[i].facility));

            if (logs[i].priority.priority == ALL)
               strcpy(priority, "*");

            else if (logs[i].priority.priority == NONE)
               strcpy(priority, "none");

            else
               strcpy(priority, 
                      priValToName(logs[i].priority.priority));

            debug("logging %s.%s to: %s\n", facility, priority,
                  filename);
         }
      }

      /* malloc filenames and open fd's */
      if (didfacs != 1)
      {
         logs[curlogfd].filename = (char *)malloc(strlen(filename)+1);
         if (logs[curlogfd].filename == NULL)
         {
            error("error with malloc(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         memset(logs[curlogfd].filename, 0, strlen(filename)+1);
         strcpy(logs[curlogfd].filename, filename);
 
         for (i = 0; i <= curlogfd; i++)
         {
            if ((logs[i].filename == NULL) || (logs[i].fd <= 0))
               continue;

            if (strcmp(logs[curlogfd].filename, logs[i].filename) == 0)
            {
               logs[curlogfd].fd = logs[i].fd;
               break;
            }
         }

         if (logs[curlogfd].fd <= 0)
         {
            logs[curlogfd].fd = 
		open(logs[curlogfd].filename, 
                     O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

            if (logs[curlogfd].fd == ERROR)
            {
               error("error opening %s: %s\n\n", logs[curlogfd].filename, 
                     strerror(errno));

               quit(ERROR);
            }
         }

         if (isatty(logs[curlogfd].fd) == 1) 
            debug("%s is a tty (device)\n", logs[curlogfd].filename);
      }

      /* either a facility or colon was parsed */
      else
      {
         for (i = curlogfd - numfacs; i <= curlogfd; i++)
         {
            logs[i].filename = (char *)malloc(strlen(filename)+1);
            if (logs[i].filename == NULL)
            {
               error("error with malloc(): %s\n\n", strerror(errno));
               quit(ERROR);
            }

            memset(logs[i].filename, 0, strlen(filename)+1);
            strcpy(logs[i].filename, filename);
 
            for (j = 0; j <= curlogfd; j++)
            {
               if ((logs[j].filename == NULL) || (logs[j].fd <= 0))
                  continue;

               if (strcmp(logs[i].filename, logs[j].filename) == 0)
               {
                  logs[i].fd = logs[j].fd;
                  break;
               }
            }

            if (logs[i].fd <= 0)
            {
               logs[i].fd = 
		   open(logs[i].filename, 
                        O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

               if (logs[i].fd == ERROR)
               {
                  error("error opening %s: %s\n\n", logs[i].filename, 
                        strerror(errno));

                  quit(ERROR);
               }
            }

            if (isatty(logs[i].fd) == 1) 
               debug("%s is a tty (device)\n", logs[i].filename);
         }

         if (debugging == 1)
         {
            (void)putchar('\n');
            (void)write(dblogfd, "\n", 1);
         }
      }
   }

   /* determine the device, file, or host to log to */
   else if (*dataptr == '@') /* '@' == remote host logging  */
      parseRemHost(str);

   else if (*dataptr == '|') /* '|' == output to named pipe */
      parseNamedPipe(str);

   else if (*dataptr == '*')
   {
      char filename[MAXFNAMESIZE];

      /* 'wall' everyone online... */

      memset(filename, 0, sizeof(filename));
      if (getcwd(filename, (sizeof(filename) - 11)) == NULL)
      {
         error("error with getcwd(): %s\n\n", strerror(errno));
         quit(ERROR);
      }

      strcat(filename, "/wall.log");

      logs[curlogfd].filename = malloc(strlen(filename) + 1);
      if (logs[curlogfd].filename == NULL)
      {
         error("error with malloc(): %s\n\n", strerror(errno));
         quit(ERROR);
      }

      memset(logs[curlogfd].filename, 0, strlen(filename) + 1);
      strcpy(logs[curlogfd].filename, filename);

      error("wall'ing is not supported at this time..\n" 
            "outputting %s.%s to %s instead\n\n", facility, priority, 
            logs[curlogfd].filename);

      logs[curlogfd].fd = open(logs[curlogfd].filename, 
                               O_CREAT | O_WRONLY | O_APPEND, 0600);

      if (logs[curlogfd].fd == ERROR)
      {
         error("error opening %s: %s\n\n", logs[curlogfd].filename,
               strerror(errno));

         quit(ERROR);
      }
   }

   /* check if they are users in /etc/passwd.. and if they're online */
   else if (isalpha((int)*dataptr) != 0)
   {
      int new1 = 1;

      char *userptr;
      char filename[MAXFNAMESIZE];

      /* just some more error checking */
      if (strchr(dataptr, '/') != NULL)
      {
         error("file names must begin with '/':\n%s\n", str);
         quit(ERROR);
      }

      if (debugging == 1)
      {
         (void)putchar('\n');
         (void)write(dblogfd, "\n", 1);
      }

      error("logging msgs to users is not supported yet..\n"
            "outputting to the following instead:\n\n");

      while(1)
      {
         if (new1 == 1) new1 = 0;
         else /* we've already been in this loop once before */
         {
            if (curlogfd+1 >= MAXLOGTYPES)
            {
               error("overflowed logs[]\n\n"); 
               quit(ERROR);
            }

            else 
            {
               copyLogStruct(curlogfd, curlogfd+1);
               curlogfd++;
            }
         }

         memset(filename, 0, sizeof(filename));
         if (getcwd(filename, ((sizeof(filename) / 2) - 11)) == NULL)
         {
            error("error with getcwd(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         logs[curlogfd].filename = (char *)malloc(sizeof(filename) + 1);
         if (logs[curlogfd].filename == NULL)
         {
            error("error with malloc(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         memset(logs[curlogfd].filename, 0, sizeof(filename) + 1);
         strcpy(logs[curlogfd].filename, filename);
         strcat(logs[curlogfd].filename, "/");

         userptr = logs[curlogfd].filename + strlen(logs[curlogfd].filename);

         /* now parsing the user names.. check for ','s */
         count = 0;
         while ((*dataptr) && (isprint((int)*dataptr) != 0) &&
                (*dataptr != ',') && (count < MAXUSERNAME))
         {
            *userptr++ = *dataptr++;
            count++;
         }

         strcat(logs[curlogfd].filename, "-user.log");
         error("%s.%s to %s\n", facility, priority, logs[curlogfd].filename);
         (void)write(errlogfd, "\n", 1);

         logs[curlogfd].fd = open(logs[curlogfd].filename,
                                  O_CREAT | O_APPEND | O_WRONLY, 0600);

         if (logs[curlogfd].fd == ERROR)
         { 
            error("error opening %s: %s\n\n", logs[curlogfd].filename);
            quit(ERROR);
         }

         if (*dataptr == ',') dataptr += 1;
         else break;
      }

      if (debugging == 1)
      {
         (void)putchar('\n');
         (void)write(dblogfd, "\n", 1);
      }

      (void)write(errlogfd, "\n", 1);
   }

   /* ---------------------------------------------------- */

   return;
}


/* ----------------------- */


/* functions to parse specific log types ('@', '|', etc.) */ 
/* ------------------------------------------------------ */

/* parse '@' from syslog.conf */
void parseRemHost(char *str)
{
   register int i;

   int count = 0; /* prevent overflows */

   char *dataptr, *fnameptr;
   char filename[MAXFNAMESIZE];

   dataptr = str, fnameptr = filename;
   memset(filename, 0, sizeof(filename));

   if (getcwd(filename, (sizeof(filename) / 2) - 11) == NULL)
   {
      error("error with getcwd(): %s\n\n", strerror(errno));
      quit(ERROR);
   }

   strcat(filename, "/");
   fnameptr += strlen(filename);

   dataptr = strchr(str, '@');
   dataptr += 1;

   count = 0;
   while ((*dataptr) && (*dataptr != ' ') && 
          (isprint((int)*dataptr) != 0) && 
          (count < (((int)sizeof(filename) / 2) - (int)strlen(filename) - 1)))
   {
         *fnameptr++ = *dataptr++;
         count++;
   }

   (void)strcat(filename, "-host.log");
   
   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   if (debugging == 1) (void)write(dblogfd, "\n", 1);
   error("remote logging ('@') is not supported at this time\n"
         "outputting to the following file instead:\n%s\n\n", filename);

   /* curlogfd++; */

   logs[curlogfd].filename = (char *)malloc(strlen(filename)+1);
   if (logs[curlogfd].filename == NULL)
   {
      error("error with malloc(): %s\n\n", strerror(errno));
      quit(ERROR);
   }

   memset(logs[curlogfd].filename, 0, strlen(filename)+1);
   strcpy(logs[curlogfd].filename, filename);
 
   for (i = 0; i <= curlogfd; i++)
   {
      if ((logs[i].filename == NULL) || (logs[i].fd <= 0)) continue;
      if (strcmp(logs[curlogfd].filename, logs[i].filename) == 0)
      {
         logs[curlogfd].fd = logs[i].fd;
         break;
      }
   }

   if (logs[curlogfd].fd <= 0)
   {
      logs[curlogfd].fd = 
		open(logs[curlogfd].filename, 
                     O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

      if (logs[curlogfd].fd == ERROR)
      {
         error("error opening %s: %s\n\n", logs[curlogfd].filename, 
               strerror(errno));

         quit(ERROR);
      }
   }

   return;
}


/* -------------------------- */


/* parse '|' from syslog.conf */
void parseNamedPipe(char *str)
{
   register int i;

   int count = 0; /* prevent overflows */

   char filename[MAXFNAMESIZE];
   char *dataptr, *fnameptr;

   fnameptr = filename;
   memset(filename, 0, sizeof(filename));

   dataptr = strrchr(str, '/');

   if (dataptr != NULL) dataptr += 1;
   else
   {
      error("error parsing:\n%s"
            "filenames must begin with '/'\n\n", str);

      quit(ERROR);
   }

   if (getcwd(filename, (sizeof(filename) / 2) - 11) == NULL)
   {
      error("error with getcwd(): %s\n\n", strerror(errno));
      quit(ERROR);
   }

   (void)strcat(filename, "/");
   fnameptr += strlen(filename);

   count = 0;
   while ((*dataptr) && (isprint((int)*dataptr) != 0) &&
          (count < (((int)sizeof(filename) / 2) - (int)strlen(filename) - 1)))
   {
      *fnameptr++ = *dataptr++;
      count++;
   }

   (void)strcat(filename, "-pipe.log");

   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   if (debugging == 1) (void)write(dblogfd, "\n", 1);
   error("named pipes ('|') aren't supported at this time\n"
         "outputting to the following file instead:\n%s\n\n", filename);

   /* open the parsed file */
   /* -------------------- */
   logs[curlogfd].filename = (char *)malloc(strlen(filename)+1);
   if (logs[curlogfd].filename == NULL)
   {
      error("error with malloc(): %s\n\n", strerror(errno));
      quit(ERROR);
   }

   memset(logs[curlogfd].filename, 0, strlen(filename)+1);
   strcpy(logs[curlogfd].filename, filename);

   for (i = 0; i <= curlogfd; i++)
   {
      if ((logs[i].filename == NULL) || (logs[i].fd <= 0)) continue;
      if (strcmp(logs[curlogfd].filename, logs[i].filename) == 0)
      {
         logs[curlogfd].fd = logs[i].fd;
         break;
      }
   }

   if (logs[curlogfd].fd <= 0)
   {
      logs[curlogfd].fd = 
		open(logs[curlogfd].filename, 
                     O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

      if (logs[curlogfd].fd == ERROR)
      {
         error("error opening %s: %s\n\n", logs[curlogfd].filename, 
               strerror(errno));

         quit(ERROR);
      }
   }

   return;
}


/* ------------------------------------------------------ */


/* parse next facility.. called when there are multi-facilities */
int parseFac(char *str, int numfacs)
{
   int count;

   char *facptr;
   char *dataptr = str;

   char facility[16];

   facptr = facility;
   memset(facility, 0, sizeof(facility));

   /* do manual parsing */
   count = 0;

   while ((*dataptr) && (*dataptr != ' ') &&
          (*dataptr != '.') && (*dataptr != ',') && 
          (*dataptr != ';') && (isprint((int)*dataptr) != 0) && 
          (count < (int)sizeof(facility)-1))
   {
      *facptr++ = *dataptr++;
      count++;
   }

   if (isprint((int)*dataptr) != 0)
      debug("current seperator = %c\n", *dataptr);

   else
      debug("current seperator = 0x%x (in hex)\n", *dataptr);

   logs[curlogfd].facility = facNameToVal(facility);

   if (logs[curlogfd].facility == ERROR)
   {
      error("(in parseSysConf) error parsing line:\n%s"
            "unknown facility type..\n\n", str);

      quit(ERROR);
   }

   /* logs[curlogfd].facility = LOG_FAC(facNameToVal(facility)); */

   debug("(in parseFac) curlogfd = %d, facility = %s (in str = %s)\n",
         numfacs, facility, facValToName(logs[curlogfd].facility));

   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   parsePri(str); /* parse the current priority */

   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   numfacs++;

   if (*dataptr == ',') 
   {
      dataptr += 1;

      curlogfd++;
      if (curlogfd >= MAXLOGTYPES)
      {
         error("error parsing /etc/syslog.conf.. overflowed logs[]\n\n");
         quit(ERROR);
      }

      numfacs = parseFac(dataptr, numfacs);
   }

   return numfacs;
}


/* ------------------------------------------------------ */


/* parse the priority */
void parsePri(char *str)
{
   int count = 0;

   char priority[16];
   char *priptr, *dataptr;

   dataptr = strchr(str, '.');
   if (dataptr == NULL)
   {
      error("(in sysLogConf) unable to parse:\n%s\n", str);
      quit(ERROR);
   }

   dataptr += 1; /* skip '.' */

   /* can be "*.!=*" or "*.=*" */
   if (*dataptr == '!') 
   {
      /* check for possible bugs */
      if ((*(dataptr + 1)) == '*')
      {
         error("error parsing line (no '*' allowed after '!'): %s\n", str);
         quit(ERROR);
      }

      debug("exclude ('!') on\n");
      logs[curlogfd].priority.exclude = 1;
   }

   if ((*dataptr == '=') || ((*(dataptr+1)) == '=')) 
   {
      /* check for possible bugs */
      if (((*(dataptr + 1)) == '*') || ((*(dataptr + 2)) == '*'))
      {
         error("error parsing line (no '*' allowed after '='):\n%s\n", str);
         quit(ERROR);
      }

      debug("single ('!') on\n");
      logs[curlogfd].priority.single = 1;
   }

   /* skip to next valid data to parse */
   if (logs[curlogfd].priority.single == 1)
      dataptr += 1;

   if (logs[curlogfd].priority.exclude == 1)
      dataptr += 1;
         
   priptr = priority;
   memset(priority, 0, sizeof(priority));
      
   count = 0;
   while ((*dataptr) && (*dataptr != ' ') &&
          (*dataptr != ';') && (isprint((int)*dataptr) != 0) && 
          (count < (int)sizeof(priority)-1))
   {
      *priptr++ = *dataptr++;
      count++;
   }


   if (strchr(priority, '*') != NULL)
   {
      if (logs[curlogfd].priority.exclude == 1)
      {
         (void)strcpy(priority, "none");
         logs[curlogfd].priority.priority = NONE;
         debug("priority = %s (no priorities)\n", priority);
      }

      else
      {
         logs[curlogfd].priority.priority = ALL;
         debug("priority = %s (all priorities)\n", priority);
      }
   }

   else if (strncmp(priority, "none", 4) == 0)
   {
      if (logs[curlogfd].priority.exclude == 1)
      {
         /* !none == ALL.. double negatives.. */

         (void)strcpy(priority, "all");
         logs[curlogfd].priority.priority = ALL;
         debug("priority = !none (all priorities)\n");
      }

      else
      {
         (void)strcpy(priority, "none");
         logs[curlogfd].priority.priority = NONE;
         debug("priority = %s (no priorities)\n", priority);
      }
   }

   else 
   {
      if (logs[curlogfd].priority.exclude == 1)
      {
         if (logs[curlogfd].priority.single == 1)
         {
            logs[curlogfd].priority.ignpri = priNameToVal(priority);

            if (logs[curlogfd].priority.ignpri == ERROR)
            {
               error("(in parseSysConf) error parsing line:\n%s"
                     "unknown priority..\n\n", str);

               quit(ERROR);
            }

            logs[curlogfd].priority.priority = ERROR;
         }
      }    
     
      logs[curlogfd].priority.priority = priNameToVal(priority);
      debug("priority = %s\n", priority);
   }


   if (isprint((int)*dataptr) != 0)
      debug("current seperator = '%c'\n", *dataptr);

   else
      debug("current seperator = 0x%x (in hex)\n", *dataptr);
}


/* ------------------------------------------------------ */


/* parse the file name and things */
void parseFile(char *str, int didfacs, int numfacs, char *fac, char *pri)
{
   int count;
   register int i, j;

   char *fnameptr;
   char *dataptr = str;

   char filename[MAXFNAMESIZE];
   char facility[16], priority[16];

   fnameptr = filename;

   memset(facility, 0, sizeof(facility));
   memset(priority, 0, sizeof(priority));
   memset(filename, 0, sizeof(filename));

   (void)strcpy(facility, fac), (void)strcpy(priority, pri);

   /* -------------- little error checking -------------- */

   while ((isprint((int)*dataptr) != 0) && (*dataptr != ' ')) 
      dataptr += 1;

   /* get to file name */
   while ((isprint((int)*dataptr) == 0) || (*dataptr == ' '))
      dataptr += 1;

   if (*dataptr == '\0')
   {
      error("error parsing line:\n%s"
            "found an unexpected null..\n\n", str);

      quit(ERROR);
   }
   else if (*dataptr == '\n')
   {
      error("error parsing line:\n%s"
            "found an unexpected newline..\n\n", str);

      quit(ERROR);
   }

   /* -------------- file/device/user output ------------- */
  
   if (debugging == 1)
   {
      (void)putchar('\n');
      (void)write(dblogfd, "\n", 1);
   }

   debug("dataptr = %c\n", (*dataptr));
   if (*dataptr == '/')
   {
      memset(filename, 0, sizeof(filename));

      count = 0;
      while ((*dataptr) && (isprint((int)*dataptr) != 0) && 
            (count < (int)sizeof(filename)-1))
      {
         *fnameptr++ = *dataptr++;
         count++;
      }    

      if (didfacs != 1)
         debug("logging %s.%s to: %s\n", facility, priority, filename);

      else
      {
         for (i = curlogfd - numfacs; i <= curlogfd; i++)
         {
            strcpy(facility, facValToName(logs[i].facility));
            /* strcpy(facility, LOG_FAC(facValToName(logs[i].facility))); */

            if (logs[i].priority.priority == ALL)
               strcpy(priority, "*");


            else if (logs[i].priority.priority == NONE)
               strcpy(priority, "none");

            else
               strcpy(priority, 
                      priValToName(logs[i].priority.priority));

            debug("logging %s.%s to: %s\n", facility, priority, filename);
         }
      }

      /* malloc filenames and open fd's */
      if (didfacs != 1)
      {
         logs[curlogfd].filename = (char *)malloc(strlen(filename)+1);
         if (logs[curlogfd].filename == NULL)
         {
            error("error with malloc(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         memset(logs[curlogfd].filename, 0, strlen(filename)+1);
         strcpy(logs[curlogfd].filename, filename);
 
         for (i = 0; i <= curlogfd; i++)
         {
            if ((logs[i].filename == NULL) || (logs[i].fd <= 0)) continue;

            if (strcmp(logs[curlogfd].filename, logs[i].filename) == 0)
            {
               logs[curlogfd].fd = logs[i].fd;
               break;
            }
         }

         if (logs[curlogfd].fd <= 0)
         {
            logs[curlogfd].fd = 
		open(logs[curlogfd].filename, 
                     O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

            if (logs[curlogfd].fd == ERROR)
            {
               error("error opening %s: %s\n\n", logs[curlogfd].filename, 
                     strerror(errno));

               quit(ERROR);
            }
         }

         if (isatty(logs[curlogfd].fd) == 1) 
            debug("%s is a tty (device)\n", logs[curlogfd].filename);
      }

      /* either a facility or colon was parsed */
      else
      {
         for (i = curlogfd - numfacs; i <= curlogfd; i++)
         {
            logs[i].filename = (char *)malloc(strlen(filename)+1);
            if (logs[i].filename == NULL)
            {
               error("error with malloc(): %s\n\n", strerror(errno));
               quit(ERROR);
            }

            memset(logs[i].filename, 0, strlen(filename)+1);
            strcpy(logs[i].filename, filename);
 
            for (j = 0; j <= curlogfd; j++)
            {
               if ((logs[j].filename == NULL) || (logs[j].fd <= 0))
                  continue;

               if (strcmp(logs[i].filename, logs[j].filename) == 0)
               {
                  logs[i].fd = logs[j].fd;
                  break;
               }
            }

            if (logs[i].fd <= 0)
            {
               logs[i].fd = 
			open(logs[i].filename, 
                             O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600);

               if (logs[i].fd == ERROR)
               {
                  error("error opening %s: %s\n\n", logs[i].filename, 
                        strerror(errno));

                  quit(ERROR);
               }
            }

            if (isatty(logs[i].fd) == 1) 
               debug("%s is a tty (device)\n", logs[i].filename);
         }
      }
   }

   /* determine the device, file, or host to log to */
   else if (*dataptr == '@') /* '@' == remote host logging  */
      parseRemHost(str);

   else if (*dataptr == '|') /* '|' == output to named pipe */
      parseNamedPipe(str);

   else if (*dataptr == '*')
   {
      char filename[MAXFNAMESIZE];

      /* 'wall' everyone online... */

      memset(filename, 0, sizeof(filename));
      if (getcwd(filename, (sizeof(filename) - 11)) == NULL)
      {
         error("error with getcwd(): %s\n\n", strerror(errno));
         quit(ERROR);
      }

      strcat(filename, "/wall.log");

      logs[curlogfd].filename = malloc(strlen(filename) + 1);
      if (logs[curlogfd].filename == NULL)
      {
         error("error with malloc(): %s\n\n", strerror(errno));
         quit(ERROR);
      }

      memset(logs[curlogfd].filename, 0, strlen(filename) + 1);
      strcpy(logs[curlogfd].filename, filename);

      error("wall'ing is not supported at this time..\n" 
            "outputting %s.%s to %s instead\n\n", facility, priority, 
            logs[curlogfd].filename);

      logs[curlogfd].fd = open(logs[curlogfd].filename, 
                               O_CREAT | O_WRONLY | O_APPEND, 0600);

      if (logs[curlogfd].fd == ERROR)
      {
         error("error opening %s: %s\n\n", logs[curlogfd].filename,
               strerror(errno));

         quit(ERROR);
      }
   }

   /* check if they are users in /etc/passwd.. and if they're online */
   else if (isalpha((int)*dataptr) != 0)
   {
      int new1 = 1;

      char *userptr;
      char filename[MAXFNAMESIZE];

      /* just some more error checking */
      if (strchr(dataptr, '/') != NULL)
      {
         error("file names must begin with '/':\n%s\n", str);
         quit(ERROR);
      }

      error("logging msgs to users is not supported yet..\n"
            "outputting to the following instead:\n\n");

      while(1)
      {
         if (new1 == 1) new1 = 0;
         else /* we've already been in this loop once before */
         {
            if (curlogfd+1 >= MAXLOGTYPES)
            {
               error("overflowed logs[]\n\n"); 
               quit(ERROR);
            }

            else 
            {
               copyLogStruct(curlogfd, curlogfd+1);
               curlogfd++;
            }
         }

         memset(filename, 0, sizeof(filename));
         if (getcwd(filename, ((sizeof(filename) / 2) - 11)) == NULL)
         {
            error("error with getcwd(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         logs[curlogfd].filename = (char *)malloc(sizeof(filename) + 1);
         if (logs[curlogfd].filename == NULL)
         {
            error("error with malloc(): %s\n\n", strerror(errno));
            quit(ERROR);
         }

         memset(logs[curlogfd].filename, 0, sizeof(filename) + 1);
         strcpy(logs[curlogfd].filename, filename);
         strcat(logs[curlogfd].filename, "/");

         userptr = logs[curlogfd].filename + strlen(logs[curlogfd].filename);

         /* now parsing the user names.. check for ','s */
         count = 0;
         while ((*dataptr) && (isprint((int)*dataptr) != 0) &&
                (*dataptr != ',') && (count < MAXUSERNAME))
         {
            *userptr++ = *dataptr++;
            count++;
         }

         strcat(logs[curlogfd].filename, "-user.log");
         error("%s.%s to %s\n\n", facility, priority, logs[curlogfd].filename);

         logs[curlogfd].fd = open(logs[curlogfd].filename,
                                  O_CREAT | O_APPEND | O_WRONLY, 0600);

         if (logs[curlogfd].fd == ERROR)
         { 
            error("error opening %s: %s\n\n", logs[curlogfd].filename);
            quit(ERROR);
         }

         if (*dataptr == ',') dataptr += 1;
         else break;
      }

      if (debugging == 1)
      {
         (void)putchar('\n');
         (void)write(dblogfd, "\n", 1);
      }

      (void)write(errlogfd, "\n", 1);
   }

   return;
}


/* ------------------------------------------------------ */


/* parse priority/facility of log message client */
void doLogging(char *str)
{
   register int i, j;

   int res;
   int count = 0;

   int restart;
   int fds[MAXLOGTYPES];

   int glued = 0;   /* part of a glued message */

   int data;        /* the priority/facility OR'd together  */
   int fac, pri;    /* facility and priority of the message */

   char pristr[16]; /* priority as a string */
   char writebuf[MAXWRITESIZE];

   char *priptr, *dataptr, *writeptr;

   memset(pristr, 0, sizeof(pristr));
   memset(writebuf, 0, sizeof(writebuf));

   priptr = pristr, writeptr = writebuf;
   dataptr = str;

   if (*dataptr != '<')
   {
      /* it's part of a truncated message */

      if (debugging == 1)
      {
         (void)putchar('\n');
         (void)write(dblogfd, "\n", 1);
      }

#     ifndef SUN
      debug("received next part of log\n");
      glued = 1, data = prevmsg;
#     else
      glued = ERROR;
#     endif

      goto Domsg;
   }

   dataptr += 1; /* skip "<" */

   while (isdigit((int)*dataptr) != 0) *priptr++ = *dataptr++; 

   if (*dataptr != '>')
   {
      error("error parsing message ('>' was expected):\n%s\n", str);
      quit(ERROR);
   }

   data = atoi(pristr);
   dataptr += 1; /* skip ">" */

Domsg:
   count = 0;
   while ((*dataptr) && (count < (int)sizeof(writebuf)))
   {
      *writeptr++ = *dataptr++;
      count++;
   }
   
   if (glued != 1)
   {
      if ((data <= 0) || (data >= (LOG_NFACILITIES << 3)))
         data = DEFUPRI;

      else if (data &~ (LOG_FACMASK | LOG_PRIMASK))
         data = DEFUPRI;

      if (LOG_PRI(data) == LOG_KERN)
         data |= LOG_USER;

      prevmsg = data;
   }

   fac = LOG_FAC(data), pri = LOG_PRI(data);

   if ((glued != 1) && (glued != ERROR))
   {
      debug("facility = %d, priority = %d\n", fac, pri);
      debug("facility = %s, priority = %s\n\n", facValToName(fac),
            priValToName(pri));
   }

   for (i = 0; i <= curlogfd; i++)
   {
      if ((logs[i].fd <= 0) || (logs[i].filename == NULL)) break;

      else if ((logs[i].facility == ALL) || 
               (logs[i].facility == (fac << 3)) || 
               (fac == LOG_DAEMON))
      {
         if (logs[i].priority.priority == NONE) continue;
         else if (logs[i].priority.priority == ALL)
         {
            if (strcmp(logs[i].filename, "/dev/tty") == 0)
            {
               (void)close(logs[i].fd);

               /* re-open /dev/tty to the current tty */
               logs[i].fd = open("/dev/tty", O_WRONLY | O_NOCTTY);
               if (logs[i].fd == ERROR)
               {
                  error("error opening /dev/tty: %s\n\n", strerror(errno));
                  quit(ERROR);
               }
            }

            for (j = 0; j < MAXLOGTYPES; j++)
            {
                if (fds[j] <= 0) continue;
                else if (fds[j] == logs[i].fd)
                {
                   restart = 1; 
                   break;
                }
            }

            if (restart == 1)
            {
               restart = 0;
               continue;
            }

            else
               for (j = 0; j < MAXLOGTYPES; j++)
                   if (fds[j] <= 0) 
                   {
                      fds[j] = logs[i].fd;
                      break;
                   }

            debug("writing the following to %s:\n%s\n%c",
                  logs[i].filename, writebuf,
                  (strchr(writebuf, '\n') == NULL ? '\n' : '\0'));

            res = write(logs[i].fd, writebuf, strlen(writebuf));
            if ((res == 0) || ((res == ERROR) && (errno > 0)))
            {
               error("error writing to %s: %s\n\n", logs[i].filename,
                     strerror(errno));

               quit(ERROR); 
            }
 
            if (strchr(writebuf, '\n') == NULL) 
               (void)write(logs[i].fd, "\n", 1);
         }

         else if (logs[i].priority.priority <= pri) 
         {
            if (logs[i].priority.exclude == 1) 
               if (logs[i].priority.ignpri <= pri) 
               {
                  if (logs[i].priority.single != 1) continue;
                  else if (logs[i].priority.ignpri == pri) continue;
               }

            if (logs[i].priority.single == 1)
               if (logs[i].priority.priority != pri) continue;


            if (strcmp(logs[i].filename, "/dev/tty") == 0)
            {
               (void)close(logs[i].fd);

               /* re-open /dev/tty to the current tty */
               logs[i].fd = open("/dev/tty", O_WRONLY | O_NOCTTY);
               if (logs[i].fd == ERROR)
               {
                  error("error opening /dev/tty: %s\n\n", strerror(errno));
                  quit(ERROR);
               }
            }

            for (j = 0; j < MAXLOGTYPES; j++)
            {
                if (fds[j] <= 0) continue;
                else if (fds[j] == logs[i].fd)
                {
                   restart = 1; 
                   break;
                }
            }

            if (restart == 1)
            {
               restart = 0;
               continue;
            }

            else
               for (j = 0; j < MAXLOGTYPES; j++)
                   if (fds[j] <= 0) 
                   {
                      fds[j] = logs[i].fd;
                      break;
                   }

            debug("writing the following to %s:\n%s\n%c",
                  logs[i].filename, writebuf,
                  (strchr(writebuf, '\n') == NULL ? '\n' : '\0'));

            if ((isprint((int)writebuf[0]) == 0) && 
                (isprint((int)writebuf[1])))
               continue;

            res = write(logs[i].fd, writebuf, strlen(writebuf));
            if ((res == 0) || ((res == ERROR) && (errno > 0)))
            {
               error("error writing to %s: %s\n\n", logs[i].filename,
                     strerror(errno));

               quit(ERROR); 
            }
 
            if (strchr(writebuf, '\n') == NULL) 
               (void)write(logs[i].fd, "\n", 1);
         }
      }
   }
}
