]> jfr.im git - irc/gameservirc.git/blobdiff - gameserv/tcpclient.cpp
updated dependencies
[irc/gameservirc.git] / gameserv / tcpclient.cpp
index 64053d287c098c56c540efd710eb0c8f8e3b6682..df342342e73fe4620a8f6428bb57383f41577a7b 100644 (file)
 
 #include "sockhelp.h"
 #include "options.h"
-#include "list.h"
 #include "aClient.h"
 #include "extern.h"
+#include "flags.h"
+#include "toplist.h"
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <fstream>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <algorithm>
 
-using std::ofstream;
-using std::ifstream;
+//#include <sys/types.h>
+//#include <sys/wait.h>
+//#include <errno.h>
+
+using namespace std;
 
 char *PACKAGE = "GameServ";
-char *VERSION = "1.1.7";
+char *VERSION = "1.3.4 +devel";
 
 int sock;
-long timestamp;
+long lastrefresh;
+long lastrollover;
+
+list<aClient*> clients[U_TABLE_SIZE];
+
+void save_lastrefresh();
+void load_lastrefresh();
+void load_lastrollover();
+void save_lastrollover();
+void prettyIntro();
+void check_idles();
+void clearClients();
+void clearPlayers();
+void clearItems();
 
-List<aClient> clients;
+// Make this a daemon
+int daemon(int nochdir, int noclose);
 
-void save_timestamp();
-void load_timestamp();
+// Close all file descriptors from >= fd
+void closeall(int fd);
 
-int main()
+int main(int argc, char *argv[])
 {
   char buffer[1024], buf[1024];
-  int connected = 1;
-  char *cmd, *source = NULL;
+  memset(buffer, 0, 1024);
+  memset(buf, 0, 1024);
+  int connected;
+  long lastidlecheck;
+  char *cmd, *source = NULL, *conf;
   srand(time(NULL));
+  conf = new char[16];
+  strcpy(conf, "gameserv.conf");
   
-
-  load_config_file();          // default = gameserv.conf
-
-  ignore_pipe();
-  sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
-  if (sock == -1) {
-    fprintf(stderr,"make_connection failed.\n");
-    unload_config_file();
-    return -1;
-  }
-
+  /*
+   * This needs to be fixed to work for any number of arguments in any
+   * order
+   *
+   */
+  if (argc > 1)
+       {
+         if ( argc > 2 || stricmp(argv[1], "--help") == 0)
+               {
+                 cout << "Usage: gameserv [options] [configfile]" << endl;
+                 cout << "Options:" << endl;
+                 cout << "--help                        Displays this help dialogue" << endl;
+                 delete []conf;
+                 return 1;
+               }
+         delete []conf;
+         conf = argv[1];
+       }
+  
+  prettyIntro();
+  
+  if (load_config_file(conf))
+       {
+         cout << "Config file loaded ok...\n"
+                  << "Turning into a daemon" << endl;
+       }
+  else
+       exit(2);
+  
+  if (argc <= 1)
+       delete []conf;
+  
+  // Turn into a daemon
+  if (daemon(1,0) < 0)
+    {
+         perror("Could not turn into a daemon");
+         exit(3);
+    }
+  if (load_items() == 0)
+    {
+      log("Error loading items");
+      goto end;
+    }
+  
+  if (load_store() == 0)
+    {
+      log("Error loading store");
+      goto end;
+    }
+  if (load_tavern() == 0)
+    {
+      log("Error loading tavern");
+      goto end;
+    }
+  
+  load_gs_dbase();
+  loadNews(newsdata, todaysnews);
+  
+  
+  if (load_masters() == false)
+    {
+      log("Error loading masters");
+      goto end;
+    }
+  
+  if (load_monsters() == false)
+    {
+      log("Error loading monsters");
+      goto end;
+    }
+  
+  if (!load_dragon())
+    {
+      log("Error loading dragon");
+      goto end;
+    }
+  
+  if (load_levels() == false)
+    {
+      log("Error loading levels");
+      goto end;
+    }
+  
+  shuttingdown = false;
+  
+  char ignoreservers[32][256];
+  char *currentserver;
+  currentserver = strtok(ignoreserverslist, " ");
+  for (int server = 0; server < 32 && currentserver != NULL; server++)
+    {
+         strncpy(ignoreservers[server], currentserver, 255);
+         log("Placing %s on the server ignore list", currentserver);
+         currentserver = strtok(NULL, " ");
+    }
+  
+  // This loop will retry the connection 3 times
+  for (int retry = 0; retry < 3 && !shuttingdown; retry++)
+       {
+         connected = 1;
+         load_lastrefresh();
+         load_lastrollover();
+         
+         long int loadtime = time(NULL);
+         long int currentTime;
+         long int oldTime = loadtime;
+         
+         lastidlecheck = loadtime;
+         
+#ifdef DEBUGMODE
+         log("Setting primary Idle Check timestamp: %ld", lastidlecheck);
+#endif
+         bool loaded = false;
+         
+         ignore_pipe();
+         sock = conn(remoteserver, remoteport, localhost, 0);
+         //    sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
+         if (sock == -1)
+               {
+                 fprintf(stderr,"make_connection failed.\n");
+                 unload_config_file();
+                 return -1;
+               }
+         log("%S socket connected.");
+         
 #ifdef UNREAL
-       raw("PROTOCTL NICKv2 VHP");
-       raw("PASS :%s", remotepass);
-       raw("SERVER %s 1 :%s", servername, servername);
-       raw("NICK %S 1 %d %S %s %s %d +owghraAxNt %s :%s v%s", time(NULL), gshost, 
-               servername, time(NULL), gshost, PACKAGE, VERSION);
-       raw(":%S JOIN %s", c_Forest);
-       raw(":%S MODE %s +mtn", c_Forest);
+         raw("PASS :%s", remotepass);
+         raw("SERVER %s 1 :%s", servername, servername);
+         raw("NICK %S 1 %d %s %s %s %d :%s v%s", time(NULL), gsident, gshost, 
+                 servername, time(NULL), PACKAGE, VERSION);
+         raw(":%S JOIN %s", c_Forest);
+         raw(":%S MODE %s +tn", c_Forest);
 #elif defined(BAHAMUT)
-       raw("PASS %s :TS", remotepass);
-       raw("SERVER %s 1 :%s", servername, servername);
-        raw("NICK %S 1 %d +o %s %s %s 0 :GameServ", time(NULL), gsident, gshost, 
-               servername);
-       raw(":%s SJOIN %d %d %s +mnt :@%S", servername, time(NULL), time(NULL), c_Forest);
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s 1 :%s", servername, servername);
+         raw("NICK %S 1 %d +w%s %s %s %s 0 :GameServ", time(NULL), (isBOper() ? "o" : ""), 
+                 gsident, gshost, servername);
+         raw(":%s SJOIN %d %d %s +nt :@%S", servername, time(NULL), time(NULL), c_Forest);
+#elif defined(HYBRID)
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s 1 :%s", servername, servername);
+         raw("NICK %S 1 %d +w%s %s %s %s :GameServ", time(NULL), (isBOper() ? "o" : ""), 
+                 gsident, gshost, servername);
+         raw(":%s SJOIN %ld %s +nt :@%S", servername, time(NULL), c_Forest);
+#elif defined(ULTIMATE2)
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s 1 :%s", servername, servername);
+         raw("NICK %S 1 %d %s %s %s 0 :GameServ", 
+                 time(NULL), gsident, gshost, servername);
+         if (isBOper())
+           raw(":%S mode %S +o");
+         raw(":%S JOIN %s", c_Forest);
+#elif defined(PTLINK)
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s 1 :%s", servername, servername);
+         raw("NICK %S 1 %d %s%s %s %s %s :GameServ", time(NULL), (isBOper() ? "+iow " : ""), gsident, gshost, gshost, servername);
+         raw(":%s SJOIN %d %s +nt :@%S", servername, time(NULL), c_Forest);
+#elif defined(VLIFE)
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s 1 %d :%s", servername, time(NULL), servername);
+         raw("NNICK %S 1 %d +w%s %s %s %s %s :GameServ", time(NULL),(isBOper() ? "o" : ""), gsident, gshost, gshost, servername);
+         raw(":%s SJOIN %d %s +nt :@%S", servername, time(NULL), c_Forest);
+#elif defined(BAHAMUT8)
+         raw("PASS %s :TS", remotepass);
+         raw("SERVER %s %d :%s", servername, time(NULL), servername);
+         raw("NICK %S 1 %d +w%s %s %s %s 0 %d :GameServ", time(NULL), (isBOper() ? "o" : ""), gsident, gshost, servername, time(NULL));
+         raw(":%s SJOIN %d %d %s +nt :@%S", servername, time(NULL), time(NULL), c_Forest);
 #elif defined(P10)
-       // Server numeric is: []  <-- must be unique
-       raw("PASS :%s", remotepass);
-       raw("SERVER %s 1 %d %d P10 []AAF :%s", servername, time(NULL), time(NULL), servername);
-       raw("[] N %S 1 %d %s %s DAqAoB %s :%S", time(NULL), gsident, gshost, gsnum);
-       raw("[] B %s %d +tnm %s:o", c_Forest, time(NULL) - 864000, gsnum);
+         // Server numeric is: []  <-- must be unique
+         raw("PASS :%s", remotepass);
+         raw("SERVER %s 1 %d %d P10 []AAF :%s", servername, time(NULL), time(NULL), servername);
+         raw("[] N %S 1 %d %s %s %s DAqAoB %s :%S", time(NULL), gsident, gshost,
+                 (isBOper() ? "+o" : ""), gsnum);
+         raw("[] B %s %d +tn %s:o", c_Forest, time(NULL) - 864000, gsnum);
 #endif
-
+         
 #if defined(P10)
-       raw("%s T %s :%s", gsnum, c_Forest, c_ForestTopic);
-       raw("[] EB");  // End burst
-#else   
-       raw(":%S MODE %s +o %S", c_Forest);
-       raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
+         raw("%s T %s :%s", gsnum, c_Forest, c_ForestTopic);
+         raw("[] EB");  // End burst
+#else 
+#ifndef HYBRID
+#if defined(ULTIMATE2)
+         raw(":%s MODE %s +o %S %ld", servername, c_Forest, 
+                 time(NULL));
+#else
+         raw(":%S MODE %s +o %S", c_Forest);
 #endif
-
-  sock_gets(sock,buffer,sizeof(buffer)-1); /* -1 added thanks to
-    David Duchene <dave@ltd.com> for pointing out the possible
-    buffer overflow resulting from the linefeed added below. */
-
-
-  #ifdef DEBUGMODE
+#endif
+         raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
+#endif
+         
+#ifndef P10
+         if (isUseNickServ())
+               {
+                 raw(":%S PRIVMSG %s :IDENTIFY %s", nsname, nspass);
+               }
+#endif
+         sock_gets(sock,buffer,sizeof(buffer)-1); /* -1 added thanks to
+                                                                                                 David Duchene <dave@ltd.com> for pointing out the possible
+                                                                                                 buffer overflow resulting from the linefeed added below. */
+         
+         
+#ifdef DEBUGMODE
       log("Server: %s",buffer);
-  #endif
-
-  init_masters();
-  load_gs_dbase();
-  load_timestamp();
-  long int loadtime = time(NULL);
-  long int currentTime;
-  long int oldTime = loadtime;
-  bool loaded = false;
-
-  if (load_monsters() == false)
-       goto end;
-
-  while (connected) {
-      if (sock_gets(sock,buffer,sizeof(buffer)) == -1) {
-        connected = 0;
-      }
-       strcpy(buf, buffer);
-
-      #if !defined(P10)
-        if (buffer[0] == ':')
-       {
-           source = strtok(buf, " ");
-           cmd = strtok(NULL, " ");
-       }
-       else
-           cmd = strtok(buf, " ");
-      #else
-           source = strtok(buf, " ");
-           cmd = strtok(NULL, " ");
-      #endif
-
-       #ifdef DEBUGMODE
-           log("Server: %s", buffer);
-       #endif
-
-       // Wait N seconds then we're loaded.
-        if (!loaded)
-       {
-           if (time(NULL) >= welcomedelay + loadtime)
-               loaded = true;
-       }
-
-       // Save the player data every updateperiod seconds
-       currentTime = time(NULL);
-       if (currentTime - oldTime >= updateperiod)
-       {
-           oldTime = currentTime;
-           save_gs_dbase();
-       }
+#endif
+         
+         while (connected)
+               {
+                 if (sock_gets(sock,buffer,sizeof(buffer)) == -1)
+                       {
+                         connected = 0;
+                       }
+                 strcpy(buf, buffer);
+                 
+#if !defined(P10)
+                 if (buffer[0] == ':')
+                       {
+                         source = strtok(buf, " ");
+                         cmd = strtok(NULL, " ");
+                       }
+                 else
+                       {
+                         cmd = strtok(buf, " ");
+                       }
+#else
+                 source = strtok(buf, " ");
+                 cmd = strtok(NULL, " ");
+#endif
+                 
+#ifdef DEBUGMODE
+                 log("Server: %s", buffer);
+#endif
+                 
+                 // Wait N seconds then we're loaded.
+                 if (!loaded)
+                       {
+                         if (time(NULL) >= welcomedelay + loadtime)
+                               {
+                                 loaded = true;
+                                 retry = 0; // Start the reconnection cycle over
+                               }
+                       }
+                 else
+                       {
+                         long TIME = time(NULL);
+                         if (TIME - lastidlecheck >= idlecheckperiod)
+                               {
+                                 check_idles();
+                                 lastidlecheck = TIME;
+                               }
+                       }
 
+                 // Refresh players and clear news if the time is up
+                 currentTime = time(NULL);
+                 
+                 if (isRolloverForestFights())
+                       {
+                         if (currentTime - lastrollover >= rolloverperiod)
+                               {
+                                 rolloverall();
+                                 lastrollover = currentTime;
+                                 save_lastrollover();
+                                 notice(s_GameServ, c_Forest, "Adding %d forest fights to all players!", numrolloverfights);
+                               }
+                       }
+                 
+                 if (currentTime - lastrefresh >= refreshperiod)
+                       {
+                         refreshall();
+                         clearNews(todaysnews);
+                         saveNews(newsdata, todaysnews);
+                         lastrefresh = currentTime;
+                         save_lastrefresh();
+                         notice(s_GameServ, c_Forest, "Refreshing all players "\
+                                        "and resetting news!");
+                       }
 
-      #if !defined(P10)
-       if (stricmp(cmd, "PING") == 0) {
-           char *timestamp;
-           timestamp = strtok(NULL, "");
-           raw("PONG %s", timestamp);
-      #else
-       if (stricmp(cmd, "G") == 0) {
-           char *timestamp;
-           timestamp = strtok(NULL, " ");
-           raw("[] Z [] %s 0 %s", timestamp + 1, timestamp);
-      #endif
-       #ifdef P10
-       } else if (stricmp(cmd, "EB") == 0) {
-           raw("[] EA");
-       #endif
-       } else if (stricmp(cmd, "VERSION") == 0) {
-           char *server;
-           server = strtok(NULL, " ");
-           server++;
-           raw(":%s 351 %s  %s %s. %s", servername, source+1, PACKAGE, VERSION, servername);
-      #if !defined(P10)
-       } else if (strncmp(cmd, "NICK", 4) == 0) {
-           if (buffer[0] == ':')
-           {
-               aClient *tempPtr;
-               if ((tempPtr = find((source + 1))))
-               {
-                   char *nick;
-                   nick = strtok(NULL, " ");
-                   tempPtr->setNick(nick);
-               }
-           }
-           else
-           {
-               char *nick;
-      #else
+                 // Save the player data every updateperiod seconds
+                 if (currentTime - oldTime >= updateperiod)
+                       {
+                         oldTime = currentTime;
+                         log("Saving to %s", playerdata);
+                         
+                         save_gs_dbase();
+                         saveNews(newsdata, todaysnews);
+                         if (isSavedNotice())
+                               {
+                                 // Send notice to the channel of the update
+                                 notice(s_GameServ, c_Forest, "%S player data saved");
+                               }
+                       }
+                 
+                 
+#if !defined(P10)
+                 if (stricmp(cmd, "PING") == 0)
+                       {
+                         char *timestamp;
+                         timestamp = strtok(NULL, "");
+                         raw("PONG %s", timestamp);
+                       }
+#else
+                 // P10 Ping
+                 if (stricmp(cmd, "G") == 0)
+                       {
+                         char *timestamp;
+                         timestamp = strtok(NULL, " ");
+                         raw("[] Z [] %s 0 %s", timestamp + 1, timestamp);
+                       }
+#endif
+#ifdef P10
+                 else if (stricmp(cmd, "EB") == 0)
+                       {
+                         raw("[] EA");
+                       }
+#endif
+                 else if (stricmp(cmd, "VERSION") == 0)
+                       {
+                         char *server;
+                         server = strtok(NULL, " ");
+                         server++;
+                         raw(":%s 351 %s %s_%s. %s", servername, source+1, PACKAGE, VERSION, servername);
+                       }
+                 // Code indenting is clean up until here!
+#if !defined(P10)
+                 else if (strncmp(cmd, "NICK", 4) == 0
+                                  #ifdef VLIFE
+                                  || strncmp(cmd, "NNICK", 5) == 0
+                                  #endif
+                                  )
+                       {
+                         if (buffer[0] == ':')
+                               {
+                                 aClient *tempPtr;
+                                 if ((tempPtr = find((source + 1))))
+                                       {
+                                         char *nick;
+                                         unsigned long oldhv, newhv;
+                                         nick = strtok(NULL, " ");
+                                         oldhv = iHASH((unsigned char *) tempPtr->getNick());
+                                         newhv = iHASH((unsigned char *) nick);
+                                         tempPtr->setNick(nick);
+                                         clients[oldhv].remove(tempPtr);
+                                         clients[newhv].push_back(tempPtr);
+                                       }
+                               }
+                         else
+                               {
+                                 char *nick;
+#else
        } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
            {   
-               char *nick;
+               char *nick, *realnick;
+               realnick = strtok(NULL, " ");
 
-               for (int x = 0; x < 6; x++)
+               for (int x = 0; x < 5; x++)
                      nick = strtok(NULL, " ");
 
                if (nick[0] == '+')
                {
-                   #ifdef DEBUGMODE
+#ifdef DEBUGMODE
                    log ("aClient has modes");
-                   #endif
-
+#endif
                    // Searching for the +r mode (extra parameter)
                    for (unsigned int count = 1; count < strlen(nick); count++)
                    {
@@ -204,107 +442,213 @@ int main()
                    }
                    nick = strtok(NULL, " ");
                }
-      #endif
+#endif
                aClient *newuser;
 
                nick = strtok(NULL, " ");
 
-               newuser = new aClient(nick);
-               if (loaded)
-                   notice(s_GameServ, nick, welcomemsg, nick);
+#ifdef P10
+                   newuser = new aClient(nick, realnick);
+#else
+                   newuser = new aClient(nick);
+#endif
+
 
-               clients.insertAtBack(newuser);
-               delete newuser;
+                       if (loaded)
+                         if (isWelcome())
+                               {
+#ifdef P10
+                                 notice(s_GameServ, nick, welcomemsg, realnick);
+#else
+                                 notice(s_GameServ, nick, welcomemsg, nick);
+#endif
+                               }
+#ifdef P10
+                   unsigned long hv = sHASH((unsigned char *) nick);
+#else
+                   unsigned long hv = iHASH((unsigned char *) nick);
+#endif
+                       
+#if defined(HYBRID) || defined(BAHAMUT) || defined(ULTIMATE2) || defined(PTLINK)
+               char *nickserver;
+               strtok(NULL, " ");
+               strtok(NULL, " ");
+               nickserver = strtok(NULL, " ");
+               if (nickserver[0] == '+')
+                 strtok(NULL, " ");
+               strtok(NULL, " ");
+               nickserver = strtok(NULL, " ");
+               for (int x = 0; x < 32; x++)
+                 {
+                       if (stricmp(ignoreservers[x], nickserver) == 0)
+                         {
+                           setIgnore(newuser);
+                           break;
+                         }
+                 }
+#elif defined(UNREAL)
+               char *nickserver;
+               strtok(NULL, " ");
+               strtok(NULL, " ");
+               strtok(NULL, " ");
+               strtok(NULL, " ");
+               nickserver = strtok(NULL, " ");
+               for (int x = 0; x < 32; x++)
+                 {
+                       if (stricmp(ignoreservers[x], nickserver) == 0)
+                         {
+                           setIgnore(newuser);
+                           break;
+                         }
+                 }
+#endif
+               clients[hv].push_back(newuser);
            }
-      #if defined(P10)
+#if defined(P10)
        } else if (stricmp(cmd, "Q") == 0) {
-      #else
-       } else if (stricmp(cmd, "QUIT") == 0) {
-      #endif
-           aClient *quitter;
-           char z = source[0];
-
-           if (z == ':')
-               source++;
+//         unsigned long hv = sHASH((unsigned char *) source);
+#else
+       } else if (stricmp(cmd, "QUIT") == 0)
+         {
 
-           if ((quitter = find(source)))
-               clients.remove(quitter);
-           if ((quitter = findIRCplayer(source)))
-           {
-               quitter->setNick("!NULL!");
-               quitter->stats->user = NULL; // Unidentify them
-           }
+#endif
+               aClient *quitter;
+               char z = source[0];
 
            if (z == ':')
-               source--;
+                 source++;
 
-      #if defined(P10)
-       } else if (stricmp(cmd, "P") == 0) {
-           char *rest, *dest;
-           char *longname;
-           longname = new char[strlen(s_GameServ) + strlen(servername) + 2];
+               unsigned long hv = iHASH((unsigned char *) source);             
+           if (!(quitter = find(source)))
+                 {
+                       log("Fatal Error: could not find %s in the "\
+                               "clients list", source);
+                       goto end;
+                 }
 
-           sprintf(longname, "%S@%s", servername);
+               clients[hv].remove(quitter);
+               logout(quitter);
 
-           dest = strtok(NULL, " ");
-           rest = strtok(NULL, "");
-           if (stricmp(dest, gsnum) == 0 || stricmp(dest, longname) == 0)
-           {
-               delete [] longname;
-               gameserv(source, rest);
-           }
-           else if (stricmp(dest, c_Forest) == 0)
-           {
-               delete [] longname;
-               forest(source, rest);
-           }
-      #else
-       } else if (stricmp(cmd, "PRIVMSG") == 0) {
+               delete quitter;
+               
+           if (z == ':')
+                 source--;
+
+#if defined(P10)
+         }
+       else if (stricmp(cmd, "P") == 0)
+         {
+               char *rest, *dest;
+               char *longname;
+               longname = new char[strlen(s_GameServ) + strlen(servername) + 2];
+               
+               sprintf(longname, "%S@%s", servername);
+               
+               dest = strtok(NULL, " ");
+               rest = strtok(NULL, "");
+               if (stricmp(dest, gsnum) == 0 || stricmp(dest, longname) == 0)
+                 {
+                       delete [] longname;
+                       gameserv(source, rest);
+                 }
+               else if (stricmp(dest, c_Forest) == 0 && isListenOnCF())
+                 {
+                       delete [] longname;
+                       forest(source, rest);
+                 }
+#else
+         }
+       else if (stricmp(cmd, "PRIVMSG") == 0)
+         {
            char *rest, *dest;
            dest = strtok(NULL, " ");
            rest = strtok(NULL, "");
            if (strnicmp(dest, s_GameServ, strlen(s_GameServ)) == 0)
-               gameserv(source, rest);
-           else if (stricmp(dest, c_Forest) == 0)
-               forest(source, rest);
-      #endif
+                 gameserv(source, rest);
+           else if (stricmp(dest, c_Forest) == 0 && isListenOnCF())
+                 forest(source, rest);
+#endif
+#if defined(P10)
+       } else if (stricmp(cmd, "J") == 0) {
+#else
        } else if (stricmp(cmd, "JOIN") == 0) {
+#endif
            char *channel;
+           aClient *joiner;
            channel = strtok(NULL, " ");
-           if (stricmp(channel, c_Forest) == 0 && is_playing(source + 1))
-               raw(":%S MODE %s +v %s", c_Forest, (source + 1));
 
-       #if defined(BAHAMUT)
+            char z = source[0];
+
+            if (z == ':')
+                source++;
+
+               joiner = find(source);
+
+           if (stricmp(channel, c_Forest) == 0 && is_playing(joiner))
+           {
+#ifdef DEBUGMODE
+                 log("Player %s (IRC: %s) joined %s", 
+                         joiner->stats->getName().c_str(), 
+#ifdef P10
+                         joiner->getRealNick(),
+#else
+                         joiner->getNick(),
+#endif
+                         c_Forest);
+#endif
+                 raw(":%S MODE %s +v %s", c_Forest, (source));
+           }
+
+           if (z == ':')
+               source--;
+
+#if defined(BAHAMUT)
        } else if (stricmp(cmd, "SJOIN") == 0) {
-           char *channel, *nick;
+           char *channel, *nick, *tmp, *rest;
            strtok(NULL, " "); // Ignore the TS
+#ifndef HYBRID
            strtok(NULL, " "); // Ignore the TS
+#endif
            channel = strtok(NULL, " ");
-           strtok(NULL, " ");
-           nick = strtok(NULL, " ");
-           nick++; // Get rid of the :
-           if (stricmp(channel, c_Forest) == 0 && is_playing(nick))
-               raw(":%S MODE %s +v %s", channel, nick);
-       #endif
-
+           rest = strtok(NULL, "");
+           tmp = strchr(rest, ':');
+           tmp++;
+           nick = strtok(tmp, " ");
+           while (nick != NULL)
+           {
+               if (*nick == '@')
+                   nick++;
+               if (*nick == '+')
+                   nick++; // Assume for users set op and voice, they
+                            // are never passed as +@nick
+               if (stricmp(channel, c_Forest) == 0 && is_playing(nick))
+                   raw(":%S MODE %s +v %s", channel, nick);
+
+               nick = strtok(NULL, " ");
+           }
+#endif
        } else {
-           #ifdef DEBUGMODE
+#ifdef DEBUGMODE
                log("Unrecognized Message: cmd = %s   source = %s", cmd, source);
-           #endif
+#endif
        }
   }
 
+ } // for loop for connection retry
+
   end:
 
   save_gs_dbase();
-  save_timestamp();
-
+  save_dragon();
+  saveNews(newsdata, todaysnews);
+  clearClients();
+  clearPlayers();
+  clearItems();
   delete_monsters();
-  delete_masters();
 
-  #ifdef DEBUGMODE
+#ifdef DEBUGMODE
       log("<CLOSED>");
-  #endif
+#endif
 
   close(sock);
   unload_config_file();
@@ -321,23 +665,20 @@ aClient *find(const char *nick)
        return findbynick(nick);
 }
 
+#ifdef P10
 
-aClient *findbynick(char *nick)
+aClient *findbyrealnick(char *realnick)
 {
-    ListNode <aClient> *newPtr;
-    newPtr = clients.First();
+   ListNode <aClient> *newPtr;
+   unsigned long hv = sHASH((unsigned char *) realnick);
+    newPtr = clients[hv].First();
 
     aClient *client = NULL;
 
     while (newPtr)
     {
        client = newPtr->getData();
-       #ifdef P10
-           log("Comparing %s with %s", client->getNick(), nick);
-           if (strcmp(client->getNick(), nick) == 0)
-       #else
-           if (stricmp(client->getNick(), nick) == 0)
-       #endif
+           if (stricmp(client->getRealNick(), realnick) == 0)
            return client;
        client = NULL;
        newPtr = newPtr->Next();
@@ -345,106 +686,319 @@ aClient *findbynick(char *nick)
     return client;    
 }
 
-aClient *findIRCplayer(const char *nick)
+#else
+
+aClient *findbyrealnick(char *realnick)
 {
-    ListNode <aClient> *newPtr;
-    aClient *p = NULL;
+  return findbynick(realnick);
+}
+
+#endif
 
-    for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
+aClient *findbynick(char *nick)
+{
+  list<aClient*>::iterator iter;
+#ifdef P10
+  unsigned long hv = sHASH((unsigned char *) nick);
+#else
+  unsigned long hv = iHASH((unsigned char *) nick);
+#endif
+
+  aClient *client = NULL;
+  
+  for(iter = clients[hv].begin(); iter != clients[hv].end(); iter++)
     {
-       p = newPtr->getData();
-       #ifdef P10
-           if (strcmp(p->getNick(), nick) == 0)
-       #else
-           if (stricmp(p->getNick(), nick) == 0)
-       #endif
-           return p;
-       p = NULL;
+         client = (*iter);
+#ifdef P10
+         if (strcmp(client->getNick(), nick) == 0)
+               {
+#else
+         if (stricmp(client->getNick(), nick) == 0)
+               {
+#endif
+                 return client;
+               }
+         client = NULL;
     }
-    return NULL;
+       return client;
 }
-aClient *findplayer(const char *name)
+
+Player *findplayer(const char *name)
 {
-    ListNode <aClient> *newPtr;
-    Player *p = NULL;
+  list<Player*>::iterator iter;
+  Player *p;
+  unsigned long hv = iHASH((unsigned char *) name);
+  for (iter = players[hv].begin(); iter != players[hv].end(); iter++)
+    {
+         p = (*iter);
+         if (stricmp(p->getName().c_str(), name) == 0)
+           return p;
+         p = NULL;
+    }
+  return NULL;
+}
 
-    for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
+void check_idles()
+{
+  list<Player*>::iterator iter;
+  Player *p;
+  
+  for (int x = 0; x < U_TABLE_SIZE; x++)
     {
-       p = newPtr->getData()->stats;
-       if (stricmp(p->name, name) == 0)
-           return newPtr->getData();
-       p = NULL;
+         for (iter = players[x].begin(); iter != players[x].end(); iter++)
+               {
+                 p = (*iter);
+
+                 switch(p->getLevel())
+                       {
+                       case 1:
+                         if ((time(NULL) - p->lastlogin) / 86400 >= level1expire)
+                               {
+                                 logout(p->getClient());
+                                 return;
+                               }
+                         break;
+                         
+                       default:
+                         if ((time(NULL) - p->lastlogin) / 86400 >= defaultexpire)
+                               {
+                                 logout(p->getClient());
+                                 return;
+                               }
+                         break;
+                       }
+                 if (timedOut(p))
+                       {
+                         timeOutEvent(p);
+                       }
+               }
     }
-    return NULL;
 }
 
 aClient *findbynick(const char *nick)
 {
-    ListNode <aClient> *newPtr;
-    newPtr = clients.First();
+  list<aClient*>::iterator iter;
+#ifdef P10
+  unsigned long hv = sHASH((unsigned char *) nick);
+#else
+  unsigned long hv = iHASH((unsigned char *) nick);
+#endif
+  
+  aClient *client = NULL;
+  
+  for (iter = clients[hv].begin(); iter != clients[hv].end(); iter++)
+    {
+         client = (*iter);
+#ifdef P10
+         if (strcmp(client->getNick(), nick) == 0)
+#else
+           if (stricmp(client->getNick(), nick) == 0)
+#endif
+                 return client;
+         client = NULL;
+    }
+  return client;    
+}
+
+/* daemon() - detach process from user and disappear into the background
+ * returns -1 on failure, but you can't do much except exit in that case
+ * since we may already have forked. This is based on the BSD version,
+ * so the caller is responsible for things like the umask, etc.
+ */
+
+/* believed to work on all Posix systems */
+
+int daemon(int nochdir, int noclose)
+{
+    pid_t pid;
+    switch (pid = fork())
+    {
+        case 0:  break;
+        case -1: return -1;
+        default: _exit(0);          /* exit the original process */
+    }
 
-    aClient *client = NULL;
+    if (setsid() < 0)               /* shoudn't fail */
+      return -1;
 
-    while (newPtr)
+    /* dyke out this switch if you want to acquire a control tty in */
+    /* the future -- not normally advisable for daemons */
+
+    switch (pid = fork())
     {
-       client = newPtr->getData();
-       #ifdef P10
-           if (strcmp(client->getNick(), nick) == 0)
-       #else
-           if (stricmp(client->getNick(), nick) == 0)
-       #endif
-           return client;
-       client = NULL;
-       newPtr = newPtr->Next();
+        case 0:  break;
+        case -1: return -1;
+        default: 
+               ofstream outfile;
+               outfile.open(pidfile);
+               if (outfile.fail())
+                   cerr << "Unable to open " << pidfile << endl;
+               outfile << pid << endl;
+               outfile.close();
+
+       _exit(0);
     }
-    return client;    
+
+    if (!nochdir)
+      chdir("/");
+
+    if (!noclose)
+    {
+        closeall(0);
+        open("/dev/null",O_RDWR);
+        dup(0); dup(0);
+    }
+
+    return 0;
 }
 
-void load_timestamp()
+
+/* closeall() -- close all FDs >= a specified value */
+
+void closeall(int fd)
 {
-    ifstream infile;
+    int fdlimit = sysconf(_SC_OPEN_MAX);
+
+    while (fd < fdlimit)
+      close(fd++);
+}
 
-    infile.open(".gstimestamp");
+void prettyIntro()
+{
+  cout << endl;
+  cout << "  GGGG     AAA   MM    MM EEEEEEE  SSSSS  EEEEEEE RRRRRR  VV     VV " << endl;
+  cout << " GG  GG   AAAAA  MMM  MMM EE      SS      EE      RR   RR VV     VV " << endl;
+  cout << "GG       AA   AA MM MM MM EEEEE    SSSSS  EEEEE   RRRRRR   VV   VV  " << endl;
+  cout << "GG   GGG AAAAAAA MM    MM EE           SS EE      RR  RR    VV VV   " << endl;
+  cout << "G     G  AA   AA MM    MM EEEEEEE  SSSSS  EEEEEEE RR   RR    VVV" << endl;
+  cout << " GGGGG                                                        V\n\n" << endl;
+  cout << "Version: " << VERSION << endl;
+  cout << "http://www.gameserv.us - http://www.sourceforge.net/projects/gameservirc" << endl;
+}
 
+void load_lastrefresh()
+{
+    ifstream infile;
+    infile.open(".gsrefresh");
     if (infile.fail())
     {
-       #ifdef DEBUGMODE
-           log("Error opening .gstimestamp");
-       #endif
+#ifdef DEBUGMODE
+           log("Error opening .gsrefresh");
+#endif
 
        generate:
-        #ifdef DEBUGMODE
-           log("Generating new timestamp");
-       #endif
-       timestamp = midnight();
-        save_timestamp();
+       long mytime = time(NULL);
+#ifdef DEBUGMODE
+           log("Generating new refresh time");
+#endif
+
+       // Just a safety measure... tho no one should
+       // get anywhere near the actual time as their refreshperiod
+       if (refreshperiod >= mytime)
+         {
+           log("Refresh period is greater than or equal to the actual time... setting it to 86400");
+           refreshperiod = 86400;
+         }
+       
+       lastrefresh = mytime - (mytime % refreshperiod);
+
+       refreshall();
+       save_lastrefresh();
        return;
     }
+    infile >> lastrefresh;
 
-    infile >> timestamp;
     infile.close();
-    if (timestamp < 1000000)
+    if (lastrefresh < 0)
        goto generate;
 }
 
-void save_timestamp()
+void load_lastrollover()
+{
+  ifstream infile;
+  infile.open(".gsrollover");
+  if (infile.fail())
+    {
+#ifdef DEBUGMODE
+      log("Error opening .gsrollover");
+#endif
+      
+    generate:
+      long mytime = time(NULL);
+#ifdef DEBUGMODE
+      log("Generating new rollover time");
+#endif
+      lastrollover = mytime;
+      return;
+    }
+  infile >> lastrollover;
+  
+  infile.close();
+  if (lastrollover < 0)
+    goto generate;
+}
+
+void save_lastrefresh()
 {
     ofstream outfile;
 
-    outfile.open(".gstimestamp");
+    outfile.open(".gsrefresh");
 
     if (outfile.fail())
     {
-       log("Error creating new file .gstimestamp");
+       log("Error creating new file .gsrefresh");
        return;
     }
+    outfile << lastrefresh << endl << lastrollover;
 
-    outfile << timestamp << endl;
+    outfile.close();
+}
+
+void save_lastrollover()
+{
+    ofstream outfile;
+
+    outfile.open(".gsrollover");
 
+    if (outfile.fail())
+    {
+       log("Error creating new file .gsrollover");
+       return;
+    }
+    outfile << lastrollover << endl;
     outfile.close();
 }
+void clearItems()
+{
+  list<item*>::iterator iter;
+  for (iter = Items.begin(); iter != Items.end(); iter++)
+       {
+         delete (*iter);
+         Items.erase(iter);
+       }
+}
+void clearClients()
+{
+  list<aClient*>::iterator iter;
+  for (unsigned long x = 0; x < U_TABLE_SIZE; x++)
+       {
+         for (iter = clients[x].begin(); iter != clients[x].end(); iter++)
+               {
+                 delete (*iter);
+                 clients[x].erase(iter);
+               }
+       }
+}
 
-long int midnight(long int offset)
+void clearPlayers()
 {
-    return (time(NULL) - (time(NULL) % 86400)) + (offset * 3600);
+  list<Player*>::iterator iter;
+  for (unsigned long x = 0; x < U_TABLE_SIZE; x++)
+       {
+         for (iter = players[x].begin(); iter != players[x].end(); iter++)
+               {
+                 delete (*iter);
+                 players[x].erase(iter);
+               }
+       }
 }