/*
 *========================================================================
 * $Id: wulfhosts_util.c 96 2006-07-20 17:56:16Z rgb $
 *
 * See copyright in copyright.h and the accompanying file COPYING
 *========================================================================
 */

#include <wulfware/libwulf.h>
static char f0[K];
static char f1[K];
static char f2[K];
static char f3[K];
static char *fields[] = {f0, f1, f2, f3};

/*
 *========================================================================
 * A collection of routines split off from read_wulfhosts to make it
 * a bit more modular.
 *========================================================================
 */

void parse_hostrange(xmlXPathContextPtr xp_hostdoc)
{

 /* Generic loop indices, and node limit */
 int i,numnodes;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 /* To facilitate addition of hosts */
 Host newhost;
 Hostrange newhostrange;
 Host *hostptr;
 Hostrange *hostrangeptr;

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting parse_hostrange().\n");
 }

 /*
  * Process the <hostrange> tag.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval all paths to /wulfstat/hostrange.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/hostrange",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.\n");
   return;
 }

 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/hostrange
  * list in no particular order.
  *
  * Time to walk the dog-ument and pull out the hosts.
  * This sets cur to point to each <wulfstat><hostrange> in turn:
  * This loop puts the results into a linked list that can be used
  * to reconstruct the wulfhosts file including this range.
  */
 numnodes = xp_op->nodesetval->nodeNr;
 for(i = 0 ; i < numnodes; i++){
   cur = xp_op->nodesetval->nodeTab[i]->xmlChildrenNode;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Ready to walk document from point = %x\n",cur);
   }
   while (cur != NULL) {
     /*
      * Clear/set default values (if any).
      */
     newhostrange.port = XMLSYSD_PORT;
     /*
      * Extract the "hostfmt" tag contents.
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "hostfmt") == 0) {
       snprintf(newhostrange.hostfmt,128,"%s",(char *)cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: hostfmt = %s\n",newhostrange.hostfmt);
       }
     }

     /*
      * Extract the "imin" tag contents (required)
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "imin") == 0) {
       newhostrange.imin = atoi((char *)cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: imin = %d\n",newhostrange.imin);
       }
     }

     /*
      * Extract the "imax" tag contents (required)
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "imax") == 0) {
       newhostrange.imax = atoi((char *)cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: imax = %d\n",newhostrange.imax);
       }
     }

     /*
      * Extract the "port" tag contents (if any).  This overrides the
      * default (set above).
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "port") == 0) {
       newhostrange.port = atoi((char *)cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: Found port = %d\n",newhostrange.port);
       }
     }

     cur = cur->next;

   }

   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: hostfmt = %s, imin = %d, imax = %d, port = %d\n",
       newhostrange.hostfmt,newhostrange.imin,newhostrange.imax,
       newhostrange.port);
   }
   add_list(hostrangelist,&newhostrange,sizeof(Hostrange));

 }

}

int validate_hostrange(List *hostrangelistptr)
{

 int i;
 int numhosts;

 Host newhost;
 Hostrange *hostrangeptr;
 ListElement *element;

 element = hostrangelist->head;
 while(element != NULL){
   hostrangeptr = element->data;

   /*
    * We have to set the port for each new host explicitly.  It
    * should either be the default or an override from the
    * parse_hostrange() code above.
    */
   newhost.port = hostrangeptr->port;

   /*
    * We
    * Now we do a single loop to build the hostnames according to
    * the hostfmt specified.  Note that by entering a printf format
    * string one has a LOT of flexibility
    */
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Entering hostrange loop\n");
   }
   for(i=hostrangeptr->imin;i<=hostrangeptr->imax;i++){
     strncpy(newhost.hostip,"",K);
     snprintf(newhost.hostname,K,hostrangeptr->hostfmt,i);
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"Validating hostname = %s, port = %d\n",newhost.hostname,newhost.port);
     }
     /*
      * At this particular instant, newhost.hostname, newhost.hostip,
      * and newhost.port are set with the settings for THIS host (if any).
      * Time to validate them.  The following routine makes them consistent
      * (if possible) or nulls them if not.
      */
     validate_host(&newhost);
     /*
      * newhost is now validated -- or not.  If not, we just skip to the
      * next host.  Otherwise we add it and clear it.  If the host is NOT
      * valid, we've set its name to "".
      */
     if(strlen(newhost.hostname) > 0){
       memset( &newhost.val,0,sizeof(Value) );
       /*
        * create a linked list for the host's pids.  We get the warm
        * and fuzzy feeling that this is about to be split off into
        * its own subroutine as we crank on up.
        */
       newhost.pidlist = newlist();
       add_list(hostlist,&newhost,sizeof(Host));
       numhosts++;
     }
   }
   element = element->next;
 }

 return(numhosts);
 
}

void validate_host(Host *hostptr)
{

 /* hostname/hostip resolution objects */
 struct hostent* host_id;
 struct in_addr* host_in_addr;
 struct sockaddr_in host_sockaddr_in;

 char ip_tmp[32],name_tmp[32];

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Validating host:\n");
   fprintf(OUTFP,"D_READHOST: Starting  name = |%s|  hostip = |%s| inetaddress = |%x|  port = |%d|\n",
       hostptr->hostname,hostptr->hostip,hostptr->inetaddress,hostptr->port);
 }

 /*
  * In addition to just validating the host, we take advantage of this
  * call to initialize certain pointers to zero.  This less us avoid
  * leaking memory later, we hope.
  */
 hostptr->val.interface = 0;
 hostptr->val.cpu = 0;
 hostptr->connected = 0;
 

 memset(ip_tmp,0,32);	/* MUST clear ip_tmp to start */

 /* 
  * To validate the triplet of values, we have to decide which one "wins"
  * a conflict.  We will assume that if the hostname is nonblank AND resolves
  * to an IP address, it wins.  If the hostname is blank AND there is a name
  * that corresponds to the nonblank ip address, we fill in the name.  If
  * there is NO name that resolves we fill in the IP number for the name.
  */
 if( strlen(hostptr->hostname) > 0){
   /*
    * In this code block, the hostname is not blank, so we use it
    * to try to determine an associated ip (ip_tmp).  That's all --
    * we deal with the outcomes later.
    */
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Looking up ip number for host %s.\n",hostptr->hostname);
   }
   /*
    * Lookup the host by name.  This fills in an entire host struct.
    */
   host_id = gethostbyname(hostptr->hostname);
   if(host_id){
     /* 
      * We got a valid ip number for this hostname.  We'll save it
      * and check it against the tag value ip number later.
      */
     host_in_addr = (struct in_addr*) host_id->h_addr_list[0];
     snprintf(ip_tmp,32,"%s",inet_ntoa(*host_in_addr));
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"D_READHOST: Got host_id = %x.\n",host_id);
       fprintf(OUTFP,"D_READHOST: Setting ip_tmp to %s\n",ip_tmp);
     }
   } else {
     /* 
      * We didn't.  This means that the host name is NOT BLANK
      * and that the named host DOES NOT RESOLVE, a Bad Thing_tm.
      * We'll deal with it later.
      */
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"D_READHOST: host %s does not resolve\n",hostptr->hostname);
     }
     memset(ip_tmp,0,32);
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"D_READHOST: Setting ip_tmp to %s(empty)\n",ip_tmp);
     }
   }

 } else {
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Looking up hostname for ip number %s.\n",hostptr->hostip);
   }
   /*
    * This code block is executed if the hostname is blank.  If the hostip
    * is ALSO blank, we have null entry and we just return -- the host is
    * NOT valid (and we really shouldn't be able to be here.  Otherwise we
    * try to resolve the host name from the ip number, instead.
    */
   if( strlen(hostptr->hostip) == 0 ) {
     fprintf(stderr,"Error: No hostname and no IP number.  This cannot happen.\n");
     exit(0);
   }

   hostptr->inetaddress = inet_addr(hostptr->hostip);
   host_id = gethostbyaddr(&hostptr->inetaddress,4,AF_INET);
   if(!host_id){
     /*
      * No name returned, but ip number could still be good.
      * we set hostname to hostip.
      */
     strncpy(hostptr->hostname,hostptr->hostip,32);
   } else {
     /*
      * We got a name, so we use it.
      */
     strncpy(hostptr->hostname,host_id->h_name,32);
   }
 }

 /*
  * At this point we have
  *   a) returned if hostname and hostip both blank (???)
  *   b) set hostname if blank but hostip was not
  *   c) found an ip number if the hostname was not blank, maybe.
  *
  * The only tricky decision remaining is what to do if hostname and hostip
  * are both not blank AND do not correspond to one another.  We fix this
  * by (arbitrarily) using the hostname ip number (in ip_tmp) if it is
  * different.
  */
 if( strlen(ip_tmp) > 0){
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Reset hostip from %s\n",hostptr->hostip);
   }
   snprintf(hostptr->hostip,32,"%s",ip_tmp);
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: hostip is now %s\n",hostptr->hostip);
   }
 }

 /*
  * If hostptr->hostip is still blank, it probably means that we should
  * just return and quit.
 if( strlen(hostptr->hostip) == 0){
   fprintf(OUTFP,"Warning: Host %s not recognized (does not resolve). Skipping.\n",hostptr->hostname);
 }
  */
 if( strlen(hostptr->hostip) == 0){
   snprintf(hostptr->hostip,32,"0.0.0.0");
 }

 /*
  * At this point this should be safe.  hostip is set correctly
  * according to our rules, even though the host may not exist.  We
  * might warn a body if their hostname and hostip don't correspond,
  * when both are specified.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Setting inetaddr from hostip %s\n",hostptr->hostip);
 }
 hostptr->inetaddress = inet_addr(hostptr->hostip);

 /* 
  * No port number.  Fill in default of XMLSYSD_PORT 
  */
 if( hostptr->port == 0 ) {
   hostptr->port = XMLSYSD_PORT;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Setting host %s's port = %d\n",hostptr->hostname,hostptr->port);
   }
 }

 /*
  * Did it all work correctly?  Whether or not it did, we need to increment
  * numhosts, since things that make it through here SHOULD generate a
  * table entry to loop over, even if that entry is null.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Cleaned up host %s (we hope).\n",hostptr->hostname);
   fprintf(OUTFP,"D_READHOST: Ending name = %s  hostip = %s inetaddress = %x  port = %d\n",
       hostptr->hostname,hostptr->hostip,hostptr->inetaddress,hostptr->port);
 }

}

void parse_iprange(xmlXPathContextPtr xp_hostdoc)
{

 IPrange newiprange;

 /* Generic loop indices, and node limit */
 int i,j,numnodes;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 /*
  * Process the <iprange> tag.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval all paths to /wulfstat/iprange.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/iprange",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.\n");
   return;
 }
 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/iprange
  * list in no particular order.
  *
  * Time to walk the dog-ument and pull out the hosts.
  * This sets cur to point to each <wulfstat><iprange> in turn:
  */
 numnodes = xp_op->nodesetval->nodeNr;
 for(i = 0 ; i < numnodes; i++){
   cur = xp_op->nodesetval->nodeTab[i]->xmlChildrenNode;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Ready to walk document from point = %x\n",cur);
   }
   while (cur != NULL) {
     /*
      * Clear the old values (if any).
      */
     newiprange.port = XMLSYSD_PORT;
     /*
      * Extract the "ipmin" tag contents (required)
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "ipmin") == 0) {
       split((char *)cur->xmlChildrenNode->content,(char **)fields,".",4,K);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: ipmin = %s",fields[0]);
         for(j=1;j<4;j++){
           fprintf(OUTFP,".%s",fields[j]);
	 }
         fprintf(OUTFP,"\n");
       }
       /*
        * Now put the fields where we can use them as loop boundaries
        */
       for(j=0;j<4;j++) newiprange.ipmin[j] = atoi(fields[j]);
       

     }
     /*
      * Extract the "ipmax" tag contents (required)
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "ipmax") == 0) {
       split((char *)cur->xmlChildrenNode->content,(char **)fields,".",4,K);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: ipmax = %s",fields[0]);
         for(j=1;j<4;j++){
           fprintf(OUTFP,".%s",fields[j]);
	 }
         fprintf(OUTFP,"\n");
       }
       /*
        * Now put the fields where we can use them as loop boundaries
        */
       for(j=0;j<4;j++) newiprange.ipmax[j] = atoi(fields[j]);

     }
     /*
      * Extract the "port" tag contents (if any).  This overrides the
      * default (set above).
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "port") == 0) {
       newiprange.port = atoi((char*) cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: Found port = %d\n",newiprange.port);
       }
     }
     cur = cur->next;
   }

   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: iprange ipmin = %d.%d.%d.%d\n",
       newiprange.ipmin[0],newiprange.ipmin[1],newiprange.ipmin[2],
       newiprange.ipmin[3]);
     fprintf(OUTFP,"D_READHOST: iprange ipmax = %d.%d.%d.%d\n",
       newiprange.ipmax[0],newiprange.ipmax[1],newiprange.ipmax[2],
       newiprange.ipmax[3]);
     fprintf(OUTFP,"D_READHOST: iprange port = %d\n",newiprange.port);
   }
   add_list(iprangelist,&newiprange,sizeof(IPrange));

 }

}


int validate_iprange(List *iprangelistptr)
{

 int i0,i1,i2,i3;
 int numhosts;

 Host newhost;
 IPrange *iprangeptr;
 ListElement *element;
 char ipbyte[8][8];

 element = iprangelistptr->head;
 numhosts = 0;
 while(element != NULL){
   iprangeptr = element->data;

   /*
    * We have to set the port for each new host explicitly.  It
    * should either be the default or an override from the
    * parse_iprange() code above.
    */
   newhost.port = iprangeptr->port;

   /*
    * Now we do a four-way loop to generate all the ipnumbers in
    * the range specified above.  Be wary!  There can be a LOT
    * of them if the second byte or more vary!
    */
   for(i0=iprangeptr->ipmin[0];i0<=iprangeptr->ipmax[0];i0++){
     snprintf(ipbyte[0],5,"%d.",i0);
     for(i1=iprangeptr->ipmin[1];i1<=iprangeptr->ipmax[1];i1++){
       snprintf(ipbyte[1],5,"%d.",i1);
       for(i2=iprangeptr->ipmin[2];i2<=iprangeptr->ipmax[2];i2++){
         snprintf(ipbyte[2],5,"%d.",i2);
         for(i3=iprangeptr->ipmin[3];i3<=iprangeptr->ipmax[3];i3++){
           snprintf(ipbyte[3],5,"%d",i3);
           /* Now we build the host addresses and validate them */
           strcpy(newhost.hostname,"");
           strcpy(newhost.hostip,"");
           newhost.inetaddress = 0;
           strncat(newhost.hostip,ipbyte[0],K);
           strncat(newhost.hostip,ipbyte[1],K);
           strncat(newhost.hostip,ipbyte[2],K);
           strncat(newhost.hostip,ipbyte[3],K);
           if((verbose == D_ALL) || (verbose == D_READHOST)){
             fprintf(OUTFP,"Validating hostip = %s, port = %d\n",newhost.hostip,newhost.port);
	   }
           /*
            * At this particular instant, newhost.hostname, newhost.hostip,
            * and newhost.port are set with the settings for THIS host (if any).
            * Time to validate them.  The following routine makes them consistent
            * (if possible) or nulls them if not.
            */
           validate_host(&newhost);
           /*
            * newhost is now validated -- or not.  If not, we just skip to the
            * next host.  Otherwise we add it and clear it.  If the host is NOT
            * valid, we've set its name to "".
            */
           if(strlen(newhost.hostname) > 0){
             memset( &newhost.val,0,sizeof(Value) );
             /*
              * create a linked list for the host's pids.  We get the warm
              * and fuzzy feeling that this is about to be split off into
              * its own subroutine as we crank on up.
              */
             newhost.pidlist = newlist();
             add_list(hostlist,&newhost,sizeof(Host));
             numhosts++;
           }
	 }
       }
     }
     element = element->next;
   }
 }

 return(numhosts);

}


void parse_hosttag(xmlXPathContextPtr xp_hostdoc)
{

 /* Generic loop indices, and node limit */
 int i,numnodes;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 /* To facilitate addition of hosts */
 Host newhost;
 Hosttag newhosttag;

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting parse_hosttag().\n");
 }

 /*
  * We now need to extract the contents of each of the tags
  * above.  Let's start with the host tags, which we will actually
  * have to walk.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval a path to /wulfstat/host.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/host",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.  Using localhost.\n");
   return;
 }

 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/hosts
  * hostdoc node list in no particular order.  We now have to resort
  * to a loop through each host, extracting the content of their
  * appropriately named children.  The easiest way to do this is
  * probably to go ahead and set the xmlNodePtr cur to point to each
  * xmlNode that matches /wulfstat/host in turn.  This is very similar
  * to the standard libxml tree way, except that I skip the horror
  * of xmlNodeListGetString by just directly grabbing the content,
  * and of course I don't have to walk the tree to find the top of
  * the list of matching nodes.
  *
  * Time to walk the dog-ument and pull out the hosts.
  * This sets cur to point to each <wulfstat><host> in turn:
  */
 numnodes = xp_op->nodesetval->nodeNr;
 for(i = 0 ; i < numnodes; i++){
   cur = xp_op->nodesetval->nodeTab[i]->xmlChildrenNode;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Ready to walk document from point = %x\n",cur);
   }
   newhosttag.port = XMLSYSD_PORT;
   while (cur != NULL) {
     /*
      * Extract the "name" tag contents (if any)
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "name") == 0) {
       strncpy(newhosttag.hostname,(char *)cur->xmlChildrenNode->content,K);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: Found hostname = %s\n",newhosttag.hostname);
       }
     }
     /*
      * Extract the "ip" tag contents (if any).  Also set the (binary)
      * actual internet address.
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "ip") == 0) {
       strncpy(newhosttag.hostip,(char *)cur->xmlChildrenNode->content,K);
       newhosttag.inetaddress = inet_addr(newhosttag.hostip);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: Found hostip = %s\n",newhosttag.hostip);
       }
     }
     /*
      * Extract the "port" tag contents (if any) or use the default.
      */
     if( xmlStrcmp(cur->name, (const xmlChar *) "port") == 0) {
       newhosttag.port = atoi((char*) cur->xmlChildrenNode->content);
       if((verbose == D_ALL) || (verbose == D_READHOST)){
         fprintf(OUTFP,"D_READHOST: Found port = %d\n",newhosttag.port);
       }
     }
     cur = cur->next;
   }

   add_list(hosttaglist,&newhosttag,sizeof(Hosttag));

 }

}

void add_localhost()
{

 /* To facilitate addition of hosts */
 Hosttag newhosttag;

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting add_localhost().\n");
 }

 strncpy(newhosttag.hostname,"localhost",K);
 strncpy(newhosttag.hostip,"127.0.0.1",K);
 newhosttag.inetaddress = inet_addr(newhosttag.hostip);
 newhosttag.port = XMLSYSD_PORT;
 add_list(hosttaglist,&newhosttag,sizeof(Hosttag));

}

int validate_hosttag(List *hosttaglistptr)
{

 int i;
 int numhosts;

 Host newhost;
 Hosttag *hosttagptr;
 ListElement *element;

 element = hosttaglistptr->head;
 numhosts = 0;
 while(element != NULL){
   hosttagptr = element->data;

   /*
    * At this particular instant, hosttagptr->hostname, hosttagptr->hostip,
    * and hosttagptr->port are set with the settings for THIS host (if any).
    * Time to validate them.  The following routine makes them consistent
    * (if possible) or nulls them if not.
    */
   strncpy(newhost.hostname,hosttagptr->hostname,K);
   strncpy(newhost.hostip,hosttagptr->hostip,K);
   newhost.port = hosttagptr->port;
   validate_host(&newhost);
   /*
    * newhost is now validated -- or not.  If not, we just skip to the
    * next host.  Otherwise we add it and clear it.  If the host is NOT
    * valid, we've set its name to "".
    */
   if(strlen(newhost.hostname) > 0){
     memset( &newhost.val,0,sizeof(Value) );
     /*
      * create a linked list for the host's pids.  We get the warm
      * and fuzzy feeling that this is about to be split off into
      * its own subroutine as we crank on up.
      */
     newhost.pidlist = newlist();
     add_list(hostlist,&newhost,sizeof(Host));
     numhosts++;
   } else {
     /* REMOVE bad entries from the hosttag list! */
     rm_list(hosttaglist,hosttagptr,sizeof(Hosttag));
   }
   element = element->next;
 }

 return(numhosts);

}

void parse_tasktag(xmlXPathContextPtr xp_hostdoc)
{

 /* Generic loop indices, and node limit */
 int i,numnodes;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 /* To facilitate addition of tasks */
 char newtask[128];

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting parse_tasktag().\n");
 }

 /*
  * Process the <task> tag.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval all paths to /wulfstat/task.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/task",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.\n");
   return;
 }

 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/pids
  * list in no particular order.
  *
  * Time to walk the dog-ument and pull out the tasks, users, and
  * desired runstatus.  numnodes is the number of <pids></pids>
  * we find (probably just one).
  */
 numnodes = xp_op->nodesetval->nodeNr;
 for(i = 0 ; i < numnodes; i++){
   cur = xp_op->nodesetval->nodeTab[i]->xmlChildrenNode;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Ready to walk document from point = %x\n",cur);
   }
   while (cur != NULL) {
     strncpy(newtask,(char *)cur->content,128);
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"D_READHOST: Found task = %s\n",newtask);
     }
     cur = cur->next;
   }

   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: adding to list.\n");
   }
   add_list(tasklist,&newtask,sizeof(newtask));

 }

}

void parse_usertag(xmlXPathContextPtr xp_hostdoc)
{

 /* Generic loop indices, and node limit */
 int i,numnodes;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 /* To facilitate addition of users */
 char newuser[128];

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting parse_usertag().\n");
 }

 /*
  * Process the <user> tag.
  */
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval all paths to /wulfstat/user.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/user",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.\n");
   return;
 }

 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/pids
  * list in no particular order.
  *
  * Time to walk the dog-ument and pull out the users, users, and
  * desired runstatus.  numnodes is the number of <pids></pids>
  * we find (probably just one).
  */
 numnodes = xp_op->nodesetval->nodeNr;
 for(i = 0 ; i < numnodes; i++){
   cur = xp_op->nodesetval->nodeTab[i]->xmlChildrenNode;
   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: Ready to walk document from point = %x\n",cur);
   }
   while (cur != NULL) {
     strncpy(newuser,(char *)cur->content,128);
     if((verbose == D_ALL) || (verbose == D_READHOST)){
       fprintf(OUTFP,"D_READHOST: Found user = %s\n",newuser);
     }
     cur = cur->next;
   }

   if((verbose == D_ALL) || (verbose == D_READHOST)){
     fprintf(OUTFP,"D_READHOST: adding to list.\n");
   }
   add_list(userlist,&newuser,sizeof(newuser));

 }

}

/*
 * I don't remember what this does -- looks sort of like nothing!
 */
void parse_roottag(xmlXPathContextPtr xp_hostdoc)
{

 /* Generic loop indices, and node limit */
 int i,numnodes,root_flag;

 xmlNodePtr cur = NULL;
 /* xml (path) objects) */
 xmlXPathObjectPtr xp_op = NULL;

 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: Starting parse_roottag().\n");
 }

 /*
  * Process the <root/> tag.  Start by setting it to the
  * default -- off.
  */
 root_flag = 0;
 if((verbose == D_ALL) || (verbose == D_READHOST)){
   fprintf(OUTFP,"D_READHOST: xp_hostdoc (ContextPtr) = %x\n",xp_hostdoc);
   fprintf(OUTFP,"D_READHOST: Now to eval all paths to /wulfstat/root.\n");
 }
 xp_op = xmlXPathEval((const xmlChar *)"/wulfstat/root",xp_hostdoc);

 /* Did we get an xpath object at all for this path? */
 if( xp_op == NULL ) {
   fprintf(OUTFP,"xpath cannot parse hostfile.\n");
   return;
 }

 /* If we did, is it a nodeset? */
 if( xp_op->type != XPATH_NODESET ){
   fprintf(OUTFP,"No nodes found by xpath in hostfile.\n");
   return;
 }

 /*
  * xp_op now contains an xpath object pointer to the /wulfstat/root
  * tag.  Ordinarily we'd parse out contents, but here the presence
  * of the tag is enough.  If numnodes != 0, we're done.
  */
 numnodes = xp_op->nodesetval->nodeNr;
 if(numnodes > 0) root_flag = 1;

}

