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

/* this file has various functions to get/process data from client */

/* process the data from the client */
/* this is the main processing function.. it processes */
/* data and calls the appropriate functions            */
void procData(int stopit)
{
   int res;
   int stop = 0;
   char readbuf[MAXREADSIZE];

   errors = 0;

   /* make sure pids and structs are right */
   if (stopit != 1) checkValid1();
   else
   {
      timeout = 0, errors = 0;

      signal(SIGALRM, IDtimeout);
      (void)alarm((MAXPAUSE * 3) * 2);

      /* first thing the client sends (this should be ID) */

      memset(readbuf, 0, sizeof(readbuf)); /* [re]clear buffer */
      recv_data(clients[curClient].sockfd, readbuf, sizeof(readbuf)-1, 0);

      if ((timeout == 1) || (errors == 1))
      {
         (void)alarm(0);

         errors = 1;
         return;
      }

      debug("(in procData) ID part.. data is: %s\n", readbuf);

      if (strncmp(readbuf, "ID ", 3) == 0) 
      {
         (void)alarm(0);
         authClient(readbuf, strlen(readbuf)); 

         if ((timeout == 1) || (errors == 1))
         {
            errors = 1;
            return;
         }
      }

      else
      {
         alarm(0);

         error("client did not send \"ID\"\n\n");
         send_data(clients[curClient].sockfd, "ERROR: %s\n", IDERROR);
         
         errors = 1;
         return;
      }

      return;
   }

   res = seteuid(0);
   if (res == ERROR)
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }

   /* we now have the client's ID.. parsed while inside authClient() */
   /* create directories for clients.. in CLIENTDIRS */
   createDirs(1); /* 1 == we have a client */

   res = seteuid(pwd->pw_uid);
   if (res == ERROR)
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }

   /* loop until we get a command we understand */
   /* next command will be VERS & SERVLIST, or SUBID...     */
   /* depending on whether we're an info or a stream server */   

   signal(SIGALRM, InsTimeout);
   (void)alarm(MAXTIMEOUT); /* give them a minute to send command */

   while(1)
   {
      debug("(in procData) waiting for next instruction\n\n");

      memset(readbuf, 0, sizeof(readbuf)); /* [re]clear buffer */
 
      recv_data(clients[curClient].sockfd, readbuf, sizeof(readbuf)-1,
                ((child == 1) ? 1 : 0));

      if ((timeout == 1) || (errors == 1))
      {
         (void)alarm(0);
         errors = 1;
         return;
      }

      /* we use if and not else if for the next few instructions, */
      /* in case they send several instructions at the same time  */

      /* client wants current client & server version */
      if (strncmp(readbuf, "VERS", 4) == 0) 
      {
         if (!stop) (void)alarm(0);

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

         debug("sending the client the current versions...\n");
         sendVers(); /* send current server and client version */
      }

      else if (strncmp(readbuf, "SERVLIST", 8) == 0)
      {
         if (!stop) (void)alarm(0);

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

         debug("sending client the streaming server list...\n");
         sendServList();
      }


      /* client wants its sub-ID */
      else if (strncmp(readbuf, "SUBID", 5) == 0)
      {
         if (!stop) (void)alarm(0);

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

         debug("sending client its sub-ID...\n");
         sendSubID();
      }

      /* client is going to start streaming */
      else if (strncmp(readbuf, "START SYSLOG.CONF", 17) == 0)
      {
         if (!stop) (void)alarm(0);

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

         debug("now getting syslog.conf from client...\n");
         readSysConf();
         debug("now finished with syslog.conf...\n");
      }

      /* client is going to start streaming */
      else if (strncmp(readbuf, "START STREAM", 12) == 0)
      {
         if (!stop) (void)alarm(0);

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

         debug("received request to start streaming...\n");

         readStream();
      }


      else if (strncmp(readbuf, "START PINGS", 11) == 0)
      {
         if (!stop) (void)alarm(0);

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

         if (clients[curClient].pinging != NOPING)
         {
            send_data(clients[curClient].sockfd, "YES PINGING\n");
            startPings();
         }

         else send_data(clients[curClient].sockfd, "NO PINGING\n");
      }

      /* client's way of checking of ensuring it's okay */
      else if (strncmp(readbuf, "PING CHECK", 10) == 0)
      { 
         /* do nothing */
         continue;
      }

      else 
      {
         error("command from client not understood.. ignoring\n\n");
         continue;
      }

      /* we had a timeout waiting for a valid instruction */
      if (stop) break;
   }
}


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


/* send client the current server/client versions */
void sendVers()
{
   send_data((clients[curClient]).sockfd, "CVER %s, SVER %s\n", 
             CVER, SVER);
}


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


/* send client the current stream server list */
void sendServList()
{
   FILE *file;

   int res1;
   char *res; /* has results from various functions */

   char buf[MAXWRITESIZE];
   char servFile[MAXFNAMESIZE];

   memset(buf, 0, sizeof(buf));
   memset(servFile, 0, sizeof(servFile));

   if (servListFile == NULL)
      sprintf(servFile, "%s", SERVFILE);

   else
      sprintf(servFile, "%s", servListFile);

   res1 = seteuid(0);
   if (res1 == ERROR)
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }

   file = fopen(servFile, "r");
   if (file == NULL)
   {
      error("error opening %s: %s..\n"
            "put the server list into it to fix\n\n", SERVFILE, 
             strerror(errno));

      quit(ERROR);
   }
   
   res1 = seteuid(pwd->pw_uid);
   if (res1 == ERROR)
   {
      error("error with seteuid: %s\n\n", strerror(errno));
      quit(ERROR);
   }

   while(1)
   {
      errno = 0;
      memset(buf, 0, sizeof(buf));

      res = fgets(buf, sizeof(buf)-2, file);
      buf[sizeof(buf)-1] = '\0';

      errors = 0;
      if (res == NULL)
      {
         if (errno == EINTR) continue;
         else if ((!feof(file)) && (errno > 0))
         {
            error("error reading from server list file:\n%s\n\n", 
                  strerror(errno));

            quit(ERROR);
         }

         else
         {
            (void)fclose(file);
            break;
         }
      }

      if ((buf == NULL) || (buf[0] == '\0') || (isprint(buf[0]) == 0))
         continue;

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

      send_data((clients[curClient]).sockfd, "SERV %s%c", 
                buf, (strchr(buf, '\n') == NULL ? '\n' : '\0'));
   }

   send_data((clients[curClient]).sockfd, "DONE\n");
}


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


/* send sub-ID to the client */
void sendSubID()
{
   send_data((clients[curClient]).sockfd, "SUBID %04d\n", 
             (clients[curClient]).numSubIDs);
}


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


/* make sure the structs and pids are valid */
void checkValid1()
{
   if (getpid() != (clients[curClient]).pidstats[curPid].pid) 
   {
      error("my pid [pid %d] != pidstats[%d].pid (pid %d)\n\n",
            getpid(), curPid, clients[curClient].pidstats[curPid].pid);

      quit(ERROR);
   }
}
