/*
 *========================================================================
 * $Id: xmlsysd_work.c 139 2004-07-06 14:01:42Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */


#include "xmlsysd.h"

/*
 * This is the main message handling loop.
 * Basically, it processes commands listed in commands.h and
 * documented therein.
 */

void xmlsysd_work_loop()
{

 int i,n,numfields,ifld,icmd,quitflag;
 char inbuf[K],valuename[K],useruid[16],*nextval;
 ListElement *element;
 char *listdata;
 struct passwd *pw;

 if((verbose == D_ALL) || (verbose == D_WORK)){
   printf("D_WORK: Starting xmlsysd_work().  Use -v %d to focus.\n",D_WORK);
 }


 /*
  * Command parser.  Very simple.  Read a line.  Parse it.  Do what
  * it says.  Commands are either one word (the first) or one word
  * and a second word that is its argument.
  */
 bzero(inbuf,K);
 if((verbose == D_ALL) || (verbose == D_WORK)){
   printf("D_WORK: Entering main command loop.\n");
 }
 /* Loop "forever" (break on the "quit" command only) */
 quitflag = 0;
 while( quitflag == 0 ){


   /*
    * read a LF-null-terminated line.
    */
   if((verbose == D_ALL) || (verbose == D_WORK)){
     printf("D_WORK: Reading a line from fd (socket) %d.\n",client_fd);
   }
   n = readline(client_fd,inbuf,K);
   if(n < 0) break;
   if((verbose == D_ALL) || (verbose == D_WORK)){
     printf("D_WORK: Received and Parsing (command) line: %s\n",inbuf);
   }

   /* 
    * parse chops inbuf into numfields fields[].
    */
   numfields = parse(inbuf,fields,MAXFIELDNUMBER,K);
   if((verbose == D_ALL) || (verbose == D_WORK)){
     printf("D_WORK: Parse returned:|");
     for(i=0;i<numfields;i++){
       printf(" %s |",fields[i]);
     }
     printf("\nD_WORK:==================================================\n");
   }

   /* fields[0] is the command */
   if((verbose == D_ALL) || (verbose == D_WORK)){
     printf("D_WORK: Found command: %s\n",fields[0]);
   }

   /*
    * To make things relatively simple, we will do this with a
    * matchup loop.  All known commands are in commands[].  We simply
    * loop until we get a match to set the index in the associated
    * enumerated list.  Then we do a simple case switch to execute
    * the appropriate code.
    */
   for(icmd = 0;icmd < N_COMMANDS;icmd++){
     if(strncmp(fields[0],commands[icmd],strlen(commands[icmd])) == 0) break;
   }

   /* 
    * icmd should now index the command parsed OR equal N_COMMANDS,
    * which is the "unknown command"/default error.  We now just
    * pipe this into a case switch and execute each command as necessary.
    */
   switch(icmd){
     case INIT:
       if((verbose == D_ALL) || (verbose == D_WORK)){
         printf("D_WORK: Executing command %s\n",commands[INIT]);
       }
       /* Open all /proc paths, set initialized. */
       init_stats();

       /* done */
       break;
     case SENDALL:
       if((verbose == D_ALL) || (verbose == D_WORK)){
         printf("D_WORK: Executing command %s\n",commands[SENDALL]);
       }

       /* Save current dctl flags, set for sending all */
       save_dctl();

       /* extract the selected statistics and xmlify them */
       get_stats();

       /* send the xmlified stats. */
       send_stats();

       /* restore saved dctl flags */
       restore_dctl();

       /* done */
       break;

     case SEND:
       if((verbose == D_ALL) || (verbose == D_WORK)){
         printf("D_WORK: Executing command %s\n",commands[SEND]);
       }
       /* extract the selected statistics and xmlify them */
       get_stats();

       /* send the xmlified stats. */
       send_stats();

       /* done */
       break;

     case ON:
       /*
        * This one is moderately complicated.  We loop over all fields[]
        * until a NULL is encountered (so parse() must terminate what
        * it finds with a NULL field[]).
        * Each non-null field is compared to a field control variable
        * name and turned on if matched.
	*
	* NOTE WELL!  One has to be very careful about embedded names
	* and strncmp.  For example, pids and pidstats, where the former
	* can easily block the latter.  Note "fix" -- strncmp on the
	* length of the longer string for the shorter one, so that we
	* just use an arbtrarily longer length (but less than K, the
	* size of fields[]) for all strncmps.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s",commands[ON]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf(" %s",fields[ifld]);
         }
         if(strncmp("compress",fields[ifld],32) == 0){
           dctl.compress = 1;
	 } else
         if(strncmp("whitespace",fields[ifld],32) == 0){
           dctl.whitespace = 1;
	 } else
         if(strncmp("identity",fields[ifld],32) == 0){
           dctl.identity = 1;
	 } else
         if(strncmp("time",fields[ifld],32) == 0){
           dctl.time = 1;
	 } else
         if(strncmp("users",fields[ifld],32) == 0){
           dctl.users = 1;
	 } else
         if(strncmp("cpuinfo",fields[ifld],32) == 0){
           dctl.cpuinfo = 1;
	 } else
         if(strncmp("loadavg",fields[ifld],32) == 0){
           dctl.loadavg = 1;
	 } else
         if(strncmp("meminfo",fields[ifld],32) == 0){
           dctl.meminfo = 1;
	 } else
         if(strncmp("net",fields[ifld],32) == 0){
           dctl.net = 1;
	 } else
         if(strncmp("stat",fields[ifld],32) == 0){
           dctl.stat = 1;
	 } else
         if(strncmp("sysvipc",fields[ifld],32) == 0){
           dctl.sysvipc = 1;
	 } else
         if(strncmp("uptime",fields[ifld],32) == 0){
           dctl.uptime = 1;
	 } else
         if(strncmp("version",fields[ifld],32) == 0){
           dctl.version = 1;
	 } else
         if(strncmp("pids",fields[ifld],32) == 0){
           dctl.pids = 1;
	 } else
         if(strncmp("running",fields[ifld],32) == 0){
           dctl.running = 1;
	 } else
         if(strncmp("root",fields[ifld],32) == 0){
           dctl.root = 1;
	 } else
         if(strncmp("pidstats",fields[ifld],32) == 0){
           dctl.pidstats = 1;
	 } else
         if(strncmp("cmdline",fields[ifld],32) == 0){
           dctl.cmdline = 1;
	 } else
         if(strncmp("all",fields[ifld],32) == 0){
           dctl.identity = 1;	/* send identity */
           dctl.time = 1;		/* send time */
           dctl.users = 1;	/* send users */
           dctl.cpuinfo = 1;	/* send cpuinfo */
           dctl.loadavg = 1;	/* send loadavg */
           dctl.meminfo = 1;	/* send meminfo */
           dctl.net = 1;		/* send net */
           dctl.stat = 1;		/* send stat */
           dctl.sysvipc = 1;	/* send sysvipc */
           dctl.uptime = 1;	/* send uptime */
           dctl.version = 1;	/* send version */
	 }

         ifld++;
       }

       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("\n");
       }
       break;       

     case OFF:
       /*
        * This one precisely mirrors ON: above, but turns the matched
        * fields off instead of on.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s",commands[OFF]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf(" %s",fields[ifld]);
         }
         if(strncmp("compress",fields[ifld],32) == 0){
           dctl.compress = 0;
	 } else
         if(strncmp("whitespace",fields[ifld],32) == 0){
           dctl.whitespace = 0;
	 } else
         if(strncmp("identity",fields[ifld],32) == 0){
           dctl.identity = 0;
	 } else
         if(strncmp("time",fields[ifld],32) == 0){
           dctl.time = 0;
	 } else
         if(strncmp("users",fields[ifld],32) == 0){
           dctl.users = 0;
	 } else
         if(strncmp("cpuinfo",fields[ifld],32) == 0){
           dctl.cpuinfo = 0;
	 } else
         if(strncmp("loadavg",fields[ifld],32) == 0){
           dctl.loadavg = 0;
	 } else
         if(strncmp("meminfo",fields[ifld],32) == 0){
           dctl.meminfo = 0;
	 } else
         if(strncmp("net",fields[ifld],32) == 0){
           dctl.net = 0;
	 } else
         if(strncmp("stat",fields[ifld],32) == 0){
           dctl.stat = 0;
	 } else
         if(strncmp("sysvipc",fields[ifld],32) == 0){
           dctl.sysvipc = 0;
	 } else
         if(strncmp("uptime",fields[ifld],32) == 0){
           dctl.uptime = 0;
	 } else
         if(strncmp("version",fields[ifld],32) == 0){
           dctl.version = 0;
	 } else 
         if(strncmp("pids",fields[ifld],32) == 0){
           dctl.pids = 0;
	 } else
         if(strncmp("running",fields[ifld],32) == 0){
           dctl.running = 0;
	 } else
         if(strncmp("root",fields[ifld],32) == 0){
           dctl.root = 0;
	 } else
         if(strncmp("pidstats",fields[ifld],32) == 0){
           dctl.pidstats = 0;
	 } else
         if(strncmp("cmdline",fields[ifld],32) == 0){
           dctl.cmdline = 0;
	 } else
         if(strncmp("all",fields[ifld],32) == 0){
           dctl.identity = 0;	/* send identity */
           dctl.time = 0;		/* send time */
           dctl.users = 0;	/* send users */
           dctl.cpuinfo = 0;	/* send cpuinfo */
           dctl.loadavg = 0;	/* send loadavg */
           dctl.meminfo = 0;	/* send meminfo */
           dctl.net = 0;		/* send net */
           dctl.stat = 0;		/* send stat */
           dctl.sysvipc = 0;	/* send sysvipc */
           dctl.uptime = 0;	/* send uptime */
           dctl.version = 0;	/* send version */
	 }

         ifld++;
       }

       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("\n");
       }
       break;

     case ADDUSER:
       /*
        * We cycle through the list of user names and add them to the
        * linked list of users whose PIDs are to be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[ADDUSER]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf("     %s\n",fields[ifld]);
         }
         /* 
          * Add the elements one after another.  We have to add each
          * user twice -- once to userlist and their uid to uidlist.
          * only uidlist can be easily used to check ownership.  Note
          * that we ONLY add usernames if they match passwd entries.
          */
         if((pw = getpwnam(fields[ifld])) != NULL){
            sprintf(useruid,"%d",pw->pw_uid);
            add_list(dctl.uidlist,useruid,strlen(useruid)+1);
            add_list(dctl.userlist,fields[ifld],strlen(fields[ifld])+1);
	 }
         ifld++;
       }
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the userlist afterward to be sure */
         printf("DWORK: Dumping userlist and uidlist to check\n");
         ifld = 0;
         element = dctl.userlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.userlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
         /* Dump the uidlist afterward to be sure */
         printf("DWORK: Dumping uidlist to check\n");
         ifld = 0;
         element = dctl.uidlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.uidlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;

     case RMUSER:
       /*
        * We cycle through the list of user names and remove them from the
        * linked list of users whose PIDs are to be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[RMUSER]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf("     %s\n",fields[ifld]);
         }
         /* 
          * Remove the elements one after another.
          */
         if((pw = getpwnam(fields[ifld])) != NULL){
            sprintf(useruid,"%d",pw->pw_uid);
            rm_list(dctl.uidlist,useruid,strlen(useruid)+1);
            rm_list(dctl.userlist,fields[ifld],strlen(fields[ifld])+1);
	 }
         ifld++;
       }
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the userlist afterward to be sure */
         printf("DWORK: Dumping userlist to check\n");
         ifld = 0;
         element = dctl.userlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.userlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
         /* Dump the uidlist afterward to be sure */
         printf("DWORK: Dumping uidlist to check\n");
         ifld = 0;
         element = dctl.uidlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.uidlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;

     case CLRUSER:
       /*
        * Clear lists of usernames (really uids) whose PIDS are to
        * be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[CLRUSER]);
       }
       delete_list(dctl.userlist);
       delete_list(dctl.uidlist);
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the userist afterward to be sure */
         printf("DWORK: Dumping userlist to check\n");
         ifld = 0;
         element = dctl.userlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.userlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
         /* Dump the uidlist afterward to be sure */
         printf("DWORK: Dumping uidlist to check\n");
         ifld = 0;
         element = dctl.uidlist->head;
         while (element != NULL) {
           printf("DWORK: dctl.uidlist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;




     case ADDTASK:
       /*
        * We cycle through the list of task names and add them to the
        * linked list of tasks whose PIDs are to be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[ADDTASK]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf("     %s\n",fields[ifld]);
         }
         /* 
          * Add the elements one after another.
          */
         add_list(dctl.tasklist,fields[ifld],strlen(fields[ifld])+1);
         ifld++;
       }
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the list afterward to be sure */
         printf("DWORK: Dumping tasklist to check\n");
         ifld = 0;
         element = dctl.tasklist->head;
         while (element != NULL) {
           printf("DWORK: dctl.tasklist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;

     case RMTASK:
       /*
        * We cycle through the list of task names and add them to the
        * linked list of tasks whose PIDs are to be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[RMTASK]);
       }
       ifld = 1;
       while(strlen(fields[ifld]) != 0){
         if((verbose == D_ALL) || (verbose == D_WORK)) {
           printf("     %s\n",fields[ifld]);
         }
         /* 
          * Add the elements one after another.
          */
         rm_list(dctl.tasklist,fields[ifld],strlen(fields[ifld])+1);
         ifld++;
       }
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the list afterward to be sure */
         printf("DWORK: Dumping tasklist to check\n");
         ifld = 0;
         element = dctl.tasklist->head;
         while (element != NULL) {
           printf("DWORK: dctl.tasklist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;

     case CLRTASK:
       /*
        * We cycle through the list of task names and add them to the
        * linked list of tasks whose PIDs are to be monitored.
        */
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s:\n",commands[CLRTASK]);
       }
       delete_list(dctl.tasklist);
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         /* Dump the list afterward to be sure */
         printf("DWORK: Dumping tasklist to check\n");
         ifld = 0;
         element = dctl.tasklist->head;
         while (element != NULL) {
           printf("DWORK: dctl.tasklist[%d]=%s\n", ifld++, element->data);
           element = element->next;
         }
       }

       break;

     case RUNTIME:
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s\n",commands[RUNTIME]);
       }
       /* 
        * set the minimum runtime that must be accumulated before
        * a pid will display.
        */
       if(numfields == 2){
         dctl.min_runtime = atoi(fields[1]);
       } else {
         dctl.min_runtime = 0;	/* back to default on anything else */
       }
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Setting minimum runtime for pid display to %d\n",dctl.min_runtime);
       }
       break;

     case VERBOSE:
       if((verbose == D_ALL) || (verbose == D_WORK)) {
         printf("D_WORK: Executing command %s\n",commands[VERBOSE]);
       }
       /* 
        * set the verbosity.  Note that if this is done in inetd
        * mode, the output will be BROKEN!  Use this only for
        * easy debugging.
        */
       if(numfields == 2){
         verbose = atoi(fields[1]);
       } else {
         verbose = !verbose; /* toggle verbosity */
       }
       /* If we turned verbosity ON, announce that fact */
       if(verbose){
         printf("D_WORK: Resetting the verbosity to %d\n",verbose);
       }

       break;

     case QUIT:
       if((verbose == D_ALL) || (verbose == D_WORK)){
         printf("D_WORK: Executing command %s\n",commands[QUIT]);
       }
       quitflag = 1;
       break;

     case N_COMMANDS:
     default:
       /* Do nothing -- ignore bad commands */
       break;
   }

 }

 xmlsysd_quit();

}	/* End of handlemessage() */
