]> jfr.im git - irc/gameservirc.git/blobdiff - gameserv/tcpclient.cpp
Added ultimate2.8.x support
[irc/gameservirc.git] / gameserv / tcpclient.cpp
index 8add11214b07fa38fe2a7cfeb08361ff1ebf6564..72306500611708cd4e22188a9547a07ac865b772 100644 (file)
 #include "list.h"
 #include "aClient.h"
 #include "extern.h"
+#include "flags.h"
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <fstream>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+//#include <sys/types.h>
+//#include <sys/wait.h>
+//#include <errno.h>
 
 using std::ofstream;
 using std::ifstream;
+using std::cerr;
+using std::endl;
 
 char *PACKAGE = "GameServ";
-char *VERSION = "1.1.8";
+char *VERSION = "1.2.3 +devel";
 
 int sock;
-long timestamp;
+int day;
 
-List<aClient> clients;
+List<aClient> clients[U_TABLE_SIZE];
 
-void save_timestamp();
-void load_timestamp();
+void save_day();
+void load_day();
+void prettyIntro();
+void check_idles();
 
-int main()
+// Make this a daemon
+int daemon(int nochdir, int noclose);
+
+// Close all file descriptors from >= fd
+void closeall(int fd);
+
+int main(int argc, char *argv[])
 {
-  char buffer[1024], buf[1024];
-  int connected = 1;
-  char *cmd, *source = NULL;
-  srand(time(NULL));
-  
-
-  load_config_file();          // default = gameserv.conf
-
-  ignore_pipe();
-  sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
-  if (sock == -1) {
-    fprintf(stderr,"make_connection failed.\n");
+    char buffer[1024], buf[1024];
+    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");
+
+  /*
+   * 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;
+           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);
+    }
+
+  init_masters();
+  load_gs_dbase();
+  cout << "Loading news" << endl;
+  loadNews(newsdata, todaysnews);
+
+  if (load_monsters() == false)
+       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, " ");
+    }
+
+  strcpy(boss.name, "Red Dragon");
+  strcpy(boss.weapon, "Breath of Unholy Fire");
+  boss.strength = 2500;
+  boss.gold = 2000000000;
+  boss.exp = 2000000000;
+  boss.maxhp = 6667;
+  boss.hp = 6667;
+  strcpy(boss.death, "You finally snuff out the deadly murderous "\
+    "dragon's dark flames. You have freed the land of its terror "\
+    "filled reign from above!");
+
+
+ // This loop will retry the connection 3 times
+ for (int retry = 0; retry < 3 && !shuttingdown; retry++)
+ {
+    connected = 1;
+    load_day();
+
+
+    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 = 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("NICK %S 1 %d %S %s %s %d +w%s %s :%s v%s", time(NULL), gshost, 
+               servername, time(NULL), (isBOper() ? "o" : ""), gshost, PACKAGE, VERSION);
        raw(":%S JOIN %s", c_Forest);
-       raw(":%S MODE %s +mtn", 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("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(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 %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
-       raw(":%S MODE %s +o %S", c_Forest);
+
+#if defined(P10)
+       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
+    #endif
        raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
+#endif
 
   sock_gets(sock,buffer,sizeof(buffer)-1); /* -1 added thanks to
     David Duchene <dave@ltd.com> for pointing out the possible
@@ -82,23 +223,13 @@ int main()
       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, " ");
@@ -106,6 +237,10 @@ int main()
        }
        else
            cmd = strtok(buf, " ");
+      #else
+           source = strtok(buf, " ");
+           cmd = strtok(NULL, " ");
+      #endif
 
        #ifdef DEBUGMODE
            log("Server: %s", buffer);
@@ -115,7 +250,19 @@ int main()
         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;
+           }
        }
 
        // Save the player data every updateperiod seconds
@@ -123,18 +270,33 @@ int main()
        if (currentTime - oldTime >= updateperiod)
        {
            oldTime = currentTime;
+           log("Saving to %s", playerdata);
            save_gs_dbase();
+           saveNews(newsdata, todaysnews);
        }
 
+
+      #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);
+           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] == ':')
            {
@@ -142,59 +304,249 @@ int main()
                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].insertAtBack(tempPtr);
                }
            }
            else
            {
                char *nick;
-               aClient *newuser;
+      #else
+       } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
+           {   
+               char *nick, *realnick;
+               realnick = strtok(NULL, " ");
+
+               for (int x = 0; x < 5; x++)
+                     nick = strtok(NULL, " ");
+
+               if (nick[0] == '+')
+               {
+                   #ifdef DEBUGMODE
+                   log ("aClient has modes");
+                   #endif
+
+                   // Searching for the +r mode (extra parameter)
+                   for (unsigned int count = 1; count < strlen(nick); count++)
+                   {
+                       if (nick[count] == 'r')
+                       {
+                           nick = strtok(NULL, " ");
+                           break;
+                       }
+                   }
+                   nick = strtok(NULL, " ");
+               }
+      #endif
+               aClient *newuser, *temp;
+
                nick = strtok(NULL, " ");
-               newuser = new aClient(nick);
+
+               #ifdef P10
+                   newuser = new aClient(nick, realnick);
+               #else
+                   newuser = new aClient(nick);
+               #endif
+
+
                if (loaded)
-                   notice(s_GameServ, nick, welcomemsg, nick);
 
-               clients.insertAtBack(newuser);
+               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
+
+               temp = clients[hv].insertAtBack(newuser);
+
+               #if defined(HYBRID) || defined(BAHAMUT) || defined(ULTIMATE2)
+                   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(temp);
+                           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(temp);
+                           break;
+                       }
+                   }
+               #endif
                delete newuser;
            }
+      #if defined(P10)
+       } else if (stricmp(cmd, "Q") == 0) {
+//         unsigned long hv = sHASH((unsigned char *) source);
+      #else
        } else if (stricmp(cmd, "QUIT") == 0) {
+//         unsigned long hv = iHASH((unsigned char *) source);
+      #endif
            aClient *quitter;
-           if ((quitter = find(source + 1)))
-               clients.remove(quitter);
-           if ((quitter = findIRCplayer(source + 1)))
+           char z = source[0];
+
+           if (z == ':')
+               source++;
+
+           if (!(quitter = find(source)))
            {
-               quitter->setNick("!NULL!");
-               quitter->stats->user = NULL; // Unidentify them
+               log("Fatal Error: could not find %s in the "\
+                       "clients list", source);
+               goto end;
            }
 
+           logout(quitter);
+
+           if (z == ':')
+               source--;
+
+           /* Attempting to use the logout() function
+           if ((quitter = find(source)))
+               clients[hv].remove(quitter);
+           if ((quitter = findIRCplayer(source)))
+           {
+               if (player_fight(quitter))
+               {
+                   // Stop the fight on the other client
+                   aClient *otherplayer = quitter->stats->battle;
+                   otherplayer->stats->battle = NULL;
+                   notice(s_GameServ, otherplayer->getNick(), "%s "\
+                          "has quit IRC. The fight stops here.",
+                          quitter->stats->name);
+               }
+               quitter->stats->battle = NULL;
+               quitter->stats->fight = NULL;
+               quitter->stats->master = NULL;
+
+               quitter->setNick("Not Playing");
+               #ifdef P10
+                   quitter->setRealNick("Not Playing");
+               #endif
+               quitter->stats->client = NULL; // Unidentify them
+           }
+           */
+
+      #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)
+           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));
+
+            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->name, 
+                       #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
                log("Unrecognized Message: cmd = %s   source = %s", cmd, source);
@@ -202,10 +554,13 @@ int main()
        }
   }
 
+ } // for loop for connection retry
+
   end:
 
   save_gs_dbase();
-  save_timestamp();
+  saveNews(newsdata, todaysnews);
+  save_day();
 
   delete_monsters();
   delete_masters();
@@ -229,18 +584,57 @@ aClient *find(const char *nick)
        return findbynick(nick);
 }
 
+#ifdef P10
+
+aClient *findbyrealnick(char *realnick)
+{
+   ListNode <aClient> *newPtr;
+   unsigned long hv = sHASH((unsigned char *) realnick);
+    newPtr = clients[hv].First();
+
+    aClient *client = NULL;
+
+    while (newPtr)
+    {
+       client = newPtr->getData();
+           if (stricmp(client->getRealNick(), realnick) == 0)
+           return client;
+       client = NULL;
+       newPtr = newPtr->Next();
+    }
+    return client;    
+}
+
+#else
+
+aClient *findbyrealnick(char *realnick)
+{
+  return findbynick(realnick);
+}
+
+#endif
 
 aClient *findbynick(char *nick)
 {
     ListNode <aClient> *newPtr;
-    newPtr = clients.First();
+    #ifdef P10
+       unsigned long hv = sHASH((unsigned char *) nick);
+    #else
+       unsigned long hv = iHASH((unsigned char *) nick);
+    #endif
+
+    newPtr = clients[hv].First();
 
     aClient *client = NULL;
 
     while (newPtr)
     {
        client = newPtr->getData();
-       if (stricmp(client->getNick(), nick) == 0)
+       #ifdef P10
+           if (strcmp(client->getNick(), nick) == 0)
+       #else
+           if (stricmp(client->getNick(), nick) == 0)
+       #endif
            return client;
        client = NULL;
        newPtr = newPtr->Next();
@@ -253,21 +647,33 @@ aClient *findIRCplayer(const char *nick)
     ListNode <aClient> *newPtr;
     aClient *p = NULL;
 
-    for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
+    p = find(nick);
+
+    if (!is_playing(p))
+       return NULL;
+
+    unsigned long hv = iHASH((unsigned char *) p->stats->name);
+
+    for (newPtr = players[hv].First(); newPtr; newPtr = newPtr->Next())
     {
        p = newPtr->getData();
-       if (stricmp(p->getNick(), nick) == 0)
+       #ifdef P10
+           if (strcmp(p->getNick(), nick) == 0)
+       #else
+           if (stricmp(p->getNick(), nick) == 0)
+       #endif
            return p;
        p = NULL;
     }
     return NULL;
 }
+
 aClient *findplayer(const char *name)
 {
     ListNode <aClient> *newPtr;
     Player *p = NULL;
-
-    for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
+    unsigned long hv = iHASH((unsigned char *) name);
+    for (newPtr = players[hv].First(); newPtr; newPtr = newPtr->Next())
     {
        p = newPtr->getData()->stats;
        if (stricmp(p->name, name) == 0)
@@ -277,17 +683,45 @@ aClient *findplayer(const char *name)
     return NULL;
 }
 
+void check_idles()
+{
+    ListNode <aClient> *newPtr;
+    Player *p = NULL;
+
+    for (int x = 0; x < U_TABLE_SIZE; x++)
+    {
+       for (newPtr = players[x].First(); newPtr; newPtr = newPtr->Next())
+       {
+           p = newPtr->getData()->stats;
+           if (timedOut(p))
+           {
+               timeOutEvent(p);
+           }
+       }
+    }
+}
+
 aClient *findbynick(const char *nick)
 {
     ListNode <aClient> *newPtr;
-    newPtr = clients.First();
+    #ifdef P10
+       unsigned long hv = sHASH((unsigned char *) nick);
+    #else
+       unsigned long hv = iHASH((unsigned char *) nick);
+    #endif
+
+    newPtr = clients[hv].First();
 
     aClient *client = NULL;
 
     while (newPtr)
     {
        client = newPtr->getData();
-       if (stricmp(client->getNick(), nick) == 0)
+       #ifdef P10
+           if (strcmp(client->getNick(), nick) == 0)
+       #else
+           if (stricmp(client->getNick(), nick) == 0)
+       #endif
            return client;
        client = NULL;
        newPtr = newPtr->Next();
@@ -295,51 +729,127 @@ aClient *findbynick(const char *nick)
     return client;    
 }
 
-void load_timestamp()
+void load_day()
 {
     ifstream infile;
 
-    infile.open(".gstimestamp");
+    infile.open(".gsday");
 
     if (infile.fail())
     {
        #ifdef DEBUGMODE
-           log("Error opening .gstimestamp");
+           log("Error opening .gsday");
        #endif
 
        generate:
         #ifdef DEBUGMODE
-           log("Generating new timestamp");
+           log("Generating new day");
        #endif
-       timestamp = midnight();
-        save_timestamp();
+       struct tm *tm;
+       time_t ti;
+       time(&ti);
+       tm = localtime(&ti);
+
+       day = tm->tm_mday;
+
+        save_day();
        return;
     }
 
-    infile >> timestamp;
+    infile >> day;
     infile.close();
-    if (timestamp < 1000000)
+    if (day < 1 || day > 31)
        goto generate;
 }
 
-void save_timestamp()
+void save_day()
 {
     ofstream outfile;
 
-    outfile.open(".gstimestamp");
+    outfile.open(".gsday");
 
     if (outfile.fail())
     {
-       log("Error creating new file .gstimestamp");
+       log("Error creating new file .gsday");
        return;
     }
 
-    outfile << timestamp << endl;
+    outfile << day << endl;
 
     outfile.close();
 }
 
-long int midnight(long int offset)
+/* 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 */
+    }
+
+    if (setsid() < 0)               /* shoudn't fail */
+      return -1;
+
+    /* dyke out this switch if you want to acquire a control tty in */
+    /* the future -- not normally advisable for daemons */
+
+    switch (pid = fork())
+    {
+        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);
+    }
+
+    if (!nochdir)
+      chdir("/");
+
+    if (!noclose)
+    {
+        closeall(0);
+        open("/dev/null",O_RDWR);
+        dup(0); dup(0);
+    }
+
+    return 0;
+}
+
+
+/* closeall() -- close all FDs >= a specified value */
+
+void closeall(int fd)
+{
+    int fdlimit = sysconf(_SC_OPEN_MAX);
+
+    while (fd < fdlimit)
+      close(fd++);
+}
+
+void prettyIntro()
 {
-    return (time(NULL) - (time(NULL) % 86400)) + (offset * 3600);
+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;
 }