pdirt/data/
pdirt/data/HELP/
pdirt/data/HELP/0/
pdirt/data/HELP/F/
pdirt/data/HELP/G/
pdirt/data/HELP/H/
pdirt/data/HELP/J/
pdirt/data/HELP/K/
pdirt/data/HELP/O/
pdirt/data/HELP/Q/
pdirt/data/HELP/R/
pdirt/data/HELP/U/
pdirt/data/HELP/V/
pdirt/data/HELP/Y/
pdirt/data/HELP/Z/
pdirt/data/MESSAGES/
pdirt/data/POWERINFO/
pdirt/data/WIZ_ZONES/
pdirt/drv/
pdirt/drv/bin/
pdirt/drv/compiler/converter/
pdirt/drv/compiler/libs/
pdirt/drv/compiler/scripts/
pdirt/drv/include/AberChat/
pdirt/drv/include/InterMud/
pdirt/drv/include/machine/
pdirt/drv/src/InterMud/
pdirt/drv/src/Players/
pdirt/drv/utils/UAFPort/
pdirt/drv/utils/dnsresolv/
pdirt/drv/utils/gdbm/
/***************************************************************************
 ** Eradicated Worlds Mud Polling program
 ** Author: Peter Eussen 1997
 ** Polls muds, writes an mudlist for inside the mud and
 ** a homepage.
 **************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>


/**************************************************************************
 ** File name and locations
 ** MUDLIST    : mudlist inside the mud
 ** CONFIG_FILE: List with all muds that need to be checked.
 ** WWWMUDLIST : HTML Page
 *******************************************************/
#define MUDLIST                 ROOTDIR"/data/INFO/mudlist.i"
#define CONFIG_FILE             ROOTDIR"/data/mudlist"
#define DUMPFILE                ROOTDIR"/data/CONFIG/mudlist.stat"
#define WWWMUDLIST              "/home/www/htdocs/sites.html"
#define HTML_HEADER             \
"<HTML>\n<BODY bgcolor=\"#BBBBBB\" text=\"#000000\" link=\"#0000ff\" vlink=\"#ff0000\" alink=\"#00a000\"><CENTER><H1>Eradicated Worlds Mudlist</H1></CENTER>\n<HR>\n"
#define HTML_FOOTER             "</BODY>\n</HTML>\n"

#define MAX_MUDNAME             80         /* Size reserved for mud names */
#define MAX_HOSTLEN             125        /* Size reserved for hostname */
#define MAX_IPLEN               15         /* Size reserved for ip number */
#define MAX_URLLEN              255        /* Size reserved for URL */
#define POLL_INTERVAL           4*60*60    /* Time between checks in secs */
#define HOSTLOOKUPFAILURE	4
#define NEWIP			3	   /* Internal Usage */
#define UNREACHABLE		2	   /* Internal Usage */
#define REACHABLE               1          /* Internal Usage */
#define DOWN                    0          /* Internal Usage */
#define MUD_SEND                "\n"       /* What to send to leave the mud */
#define MUD_OPEN                "Opened"   /* For HTML */
#define HOST_DOWN		"Host Down or non-exsistant"

typedef struct _MudStat {
	char    mudname[MAX_MUDNAME+1];    
	char    hostname[MAX_HOSTLEN+1];
	char    ipnumber[MAX_IPLEN+1];
	char    homepage[MAX_URLLEN];
	int     port;

	time_t  last_succes;               /* Time of last connect */
	time_t  last_checked;              /* Time of last Poll */
	char    *status;                   /* Error message pointer */
	int     short_stat;                /* Up or Down? */

	struct  _MudStat *next;
} MudStat;

MudStat         *MudList = NULL;
extern char *sys_errlist[];

void addto(MudStat *p, MudStat *list);
void do_poll(void);
void write_stats(void);
void write_info();
void write_html();
void try_connect(MudStat *l);
void read_file(void);
void update_mudlist(int sig);
int  read_dumpfile(void);
void dump_mudlist(int sig);

int main(void)
{    int pid;

     if (!read_dumpfile())
        read_file();

     /* Go Background and forget */
     switch ((pid = fork())) {
     case -1: printf("Fork Failed!\n");
	      return 2;
     case  0: break;              
     default: printf("Mud Poller Started (pid %d)\n",pid);
	      return 0;
     }

     fclose(stdin);
     fclose(stdout);
     fclose(stderr);
     signal(SIGUSR1,update_mudlist);
     signal(SIGTERM,dump_mudlist);

     while (1)
     {   do_poll();              /* Do your job */
	 sleep(POLL_INTERVAL);   /* And sleep till next job */
     }
     return 0;
}

void addMudList(MudStat *p)
{  MudStat *l = MudList;

   if (MudList == NULL)
   {  p->next = MudList;
      MudList = p;
      return;
   }

   while (l->next != NULL)
	l = l->next;

   p->next = l->next;
   l->next = p;
}

void addto(MudStat *p, MudStat *list)
{  MudStat *l = list;

   if (list == NULL)
   {  p->next = list;
      list = p;
      return;
   }

   while (l->next != NULL)
	l = l->next;

   p->next = l->next;
   l->next = p;
}


void do_poll(void)
{   MudStat *l = MudList;

    while (l != NULL)
    {   try_connect(l);         /* Try to connect to this mud */
	l = l->next;            /* Untill all muds are checked */
    }
    write_stats();              /* Then write new files */
}

void try_connect(MudStat *l)
{   int s,ret;
    char buffer[100];
    struct sockaddr_in client;
    struct hostent *host;
   
    host = gethostbyname(l->hostname); 

    if (host == NULL)
    {  l->last_checked = time(0);
       l->short_stat = HOSTLOOKUPFAILURE;
       l->status = HOST_DOWN;
       return;
    }
   
    bzero((char *)&client,sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port   = htons(l->port);
    client.sin_addr   = (*(struct in_addr*)host->h_addr_list[0]);

    s = socket(AF_INET,SOCK_STREAM,0);

    ret = connect(s,(struct sockaddr *)&client,sizeof(client));

    l->last_checked = time(0);
    
    if (ret == -1)
    {  l->status = sys_errlist[errno];
       l->short_stat = DOWN;
       close(s);
       return;
    }

    fcntl(s,F_SETFL,O_NONBLOCK);

    while (read(s,buffer,100) >= 0);
     
    write(s,MUD_SEND,2);
    close(s);

    l->last_succes  = l->last_checked;
    l->status       = MUD_OPEN;
    l->short_stat   = REACHABLE;
/*
    if (strcmp(host->h_addr_list[0],l->ipnumber) != 0)
    {  l->short_stat = NEWIP;
       strcpy(l->ipnumber,host->h_addr);
    }
*/
} 

void write_stats(void)
{   write_info();       /* Write intermal mudlist */
    write_html();       /* Write HTML page */
}

void write_html()
{   FILE *fp;
    MudStat *l = MudList;
    time_t t=time(NULL);
    int    hadbad = 0,hadgood=0;

    fp = fopen(WWWMUDLIST,"w");

    if (fp == NULL)
       return;


    fprintf(fp,HTML_HEADER);
    fprintf(fp,"<CENTER>Last update of this page was: %s</CENTER><BR>\n",ctime(&t));

    while (l != NULL)
    {   if (l->short_stat == REACHABLE)
	{  if (!hadgood)
           {   
              fprintf(fp,"<CENTER><H2>Reachable Muds</H2></CENTER><P>\n");
              hadgood = 1;
           }

           fprintf(fp,"<TABLE Width=\"100%%\" Align=left Border=1>\n");
	   if (l->homepage[0] != '-')
	      fprintf(fp,"<TR>\n"
                         "   <TD colspan=4 align=center width=\"100%%\">"
                         "<A HREF=\"%s\">%s Homepage</A>\n</TR>\n",
		   l->homepage,l->mudname);
           fprintf(fp,"<TR>\n"
                      "     <TD width=\"30%%\"><A HREF=\"telnet://%s:%d\">%s</A></TD>\n"
                      "     <TD width=\"20%%\">%s</TD>\n"
                      "     <TD width=\"40%%\">%s</TD>\n"
                      "     <TD width=\"10%%\">%d</TD>\n"
                      "</TR>\n",
	       l->ipnumber,l->port,l->mudname,l->ipnumber,l->hostname,l->port);
	   fprintf(fp,"</TABLE><BR clear=left><BR>\n");
	}
	l = l->next;
    }

    l = MudList;
    while (l != NULL)
    {   if (l->short_stat == DOWN || l->short_stat == HOSTLOOKUPFAILURE)
	{  if (!hadbad)
	   {   fprintf(fp,"<P><CENTER><H2>Unreachable Muds</H2></CENTER></P>\n");
	       hadbad = 1;
	   }

	   fprintf(fp,"<TABLE Width=\"100%%\" Align=left Border=1>\n");
	   if (l->homepage[0] != '-')
	      fprintf(fp,"<TR>\n"
                         "   <TD colspan=4 align=center width=\"100%%\">"
                         "<A HREF=\"%s\">%s Homepage</A>\n</TR>\n",
		   l->homepage,l->mudname);
           fprintf(fp,"<TR>\n"
                      "     <TD width=\"30%%\"><A HREF=\"telnet://%s:%d\">%s</A></TD>\n"
                      "     <TD width=\"20%%\">%s</TD>\n"
                      "     <TD width=\"40%%\">%s</TD>\n"
                      "     <TD width=\"10%%\">%d</TD>\n"
                      "</TR>\n",
	       l->ipnumber,l->port,l->mudname,l->ipnumber,l->hostname,l->port);
	   fprintf(fp,"<TR>\n"
                      "   <TD BGCOLOR=\"#FFFFAA\" colspan=2 width=\"50%%\"><B>Last Connect:</B> %s</TD>\n"
                      "   <TD BGCOLOR=\"#999999\" colspan=2 width=\"50%%\"><B>Reason:</B> %s</TD>\n"
                      "</TR>\n",
		l->last_succes == 0 ? "Never" : ctime(&l->last_succes),l->status);
	   fprintf(fp,"</TABLE><BR clear=left><BR>\n");
	}
	l = l->next;
    }
    fprintf(fp,HTML_FOOTER);
    fclose(fp);
}

void write_info()
{   FILE *fp;
    MudStat *l = MudList;
    time_t t = time(NULL);
    char   *stat = NULL;

    fp = fopen(MUDLIST,"w");

    if (fp == NULL)
      return;

    fprintf(fp,"&+b=&+B[&+WMud Name&+B]&+b===========&+B[&+WIP&+B]&+b============&+B[&+WHostname&+B]&+b==================&+B[&+WPort&+B]&+b=&+B[&+WSt&+B]&+b=&*\n");
    while (l != NULL)
    {   fprintf(fp,"%-20.20s %-14.14s  %-29.29s %.4d   ",
		l->mudname,l->ipnumber,l->hostname,l->port);
        switch (l->short_stat) {
        case DOWN: stat = "Dn"; break;
        case REACHABLE: stat = "Up"; break;
        case UNREACHABLE: stat = "ND"; break;
        case NEWIP: stat = "IP"; break;
        case HOSTLOOKUPFAILURE: stat = "HF"; break;
        default: stat = "Dn";
        }
        fprintf(fp,"%s\n",stat);
	l = l->next;
    }
    fprintf(fp,"&+b==============================================================================&*\n"
               " Dn = Down   Up = Up   ND = Network Down   IP = New IP   HF = Hostname failure\n");

    fprintf(fp,"Last poll: %s\n",ctime(&t));
    fclose(fp);
}

void read_file(void)
{  FILE *fp;
   MudStat *l;
   char line[255+1];

   fp = fopen(CONFIG_FILE,"r");

   if (fp == NULL)
   {   printf("Can't find config file.\n");
       exit(1);
   }

   fgets(line,255,fp);

   while (!feof(fp))
   {   
       l = (MudStat *)malloc(sizeof(MudStat));
       line[strlen(line)-1] = '\0';
       strcpy(l->mudname,line);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->hostname,line);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->ipnumber,line);
       fgets(line,255,fp);
       sscanf(line,"%d ",&l->port);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->homepage,line);
       
       l->next = NULL;
       l->last_succes = l->last_checked = 0;
       l->short_stat = DOWN;
       addMudList(l);
       fgets(line,255,fp);
   }
   fclose(fp);
}

void update_mudlist(int sig)
{  MudStat *l, *n;
   FILE    *fp;
   int     r;
   char    line[255+1];

   n = MudList;

   fp = fopen(CONFIG_FILE,"r");

   if (fp == NULL)
   {   printf("Can't find config file.\n");
       exit(1);
   }

   fgets(line,255,fp);

   while (!feof(fp))
   {   line[strlen(line)-1] = '\0';
       if ((r = strcasecmp(n->mudname,line)) == 0)
       {  l = n;
	  n = n->next;
       }
       else if (r < 0)
       {  l = (MudStat *)malloc(sizeof(MudStat));
	  l->next = NULL;
	  l->last_succes = l->last_checked = 0;
	  l->short_stat = DOWN;
       }
       else
       {  l = MudList;            /* No longer in list so delete it */
	  if (l != n)
	  {
	    while (l->next != n)
	       l = l->next;
	  }
	  l->next = n->next;
	  free(n);
	  n = l->next;
	  l = (MudStat *)malloc(sizeof(MudStat));
	  l->next = NULL;
	  l->last_succes = l->last_checked = 0;
	  l->short_stat = DOWN;
       }

       strcpy(l->mudname,line);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->hostname,line);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->ipnumber,line);
       fgets(line,255,fp);
       sscanf(line,"%d ",&l->port);
       fgets(line,255,fp);
       line[strlen(line)-1] = '\0';
       strcpy(l->homepage,line);
       
       addMudList(l);
       fgets(line,255,fp);
   }
   fclose(fp);

   signal(SIGUSR1,update_mudlist);
}

int read_dumpfile(void)
{   FILE *fp;
    MudStat l, *p;

    fp = fopen(DUMPFILE,"r");
    if (fp == NULL)
       return 0;

    printf("Reading data from history logfile.\n");
    while (!feof(fp) && fread(&l,sizeof(MudStat),1,fp) == 1)
    {  p = (MudStat *)malloc(sizeof(MudStat));
       bcopy((char *)p,(char *)&l,sizeof(MudStat));
       p->next   = NULL;
       p->status = NULL;
       addMudList(p);
    }
    fclose(fp);
    remove(DUMPFILE);
    return 1;
}

void dump_mudlist(int sig)
{   FILE    *fp;
    MudStat *l = MudList;

    printf("Dump to: "DUMPFILE"\n");
    fp = fopen(DUMPFILE,"w");

    if (fp == NULL)
       return;

    printf("Dumping file.\n");
    for (; l != NULL; l = l->next)
    {  fwrite((char *)l,sizeof(MudStat), 1, fp);
    }
    fclose(fp);       
    exit(0); 
}