]>
jfr.im git - irc/gameservirc.git/blob - gameserv/tcpclient.cpp
2 * This file is provided for use with the unix-socket-faq. It is public
3 * domain, and may be copied freely. There is no copyright on it. The
4 * original work was by Vic Metcalfe (vic@brutus.tlug.org), and any
5 * modifications made to that work were made with the understanding that
6 * the finished work would be in the public domain.
8 * If you have found a bug, please pass it on to me at the above address
9 * acknowledging that there will be no copyright on your work.
11 * The most recent version of this file, and the unix-socket-faq can be
12 * found at http://www.interlog.com/~vic/sock-faq/.
29 //#include <sys/types.h>
30 //#include <sys/wait.h>
35 char *PACKAGE
= "GameServ";
36 char *VERSION
= "1.3.2 +devel";
42 List
<aClient
> clients
[U_TABLE_SIZE
];
44 void save_lastrefresh();
45 void load_lastrefresh();
46 void load_lastrollover();
47 void save_lastrollover();
52 int daemon(int nochdir
, int noclose
);
54 // Close all file descriptors from >= fd
55 void closeall(int fd
);
57 int main(int argc
, char *argv
[])
59 char buffer
[1024], buf
[1024];
60 memset(buffer
, 0, 1024);
64 char *cmd
, *source
= NULL
, *conf
;
67 strcpy(conf
, "gameserv.conf");
70 * This needs to be fixed to work for any number of arguments in any
76 if ( argc
> 2 || stricmp(argv
[1], "--help") == 0)
78 cout
<< "Usage: gameserv [options] [configfile]" << endl
;
79 cout
<< "Options:" << endl
;
80 cout
<< "--help Displays this help dialogue" << endl
;
89 if (load_config_file(conf
))
91 cout
<< "Config file loaded ok...\n"
92 << "Turning into a daemon" << endl
;
100 // Turn into a daemon
103 perror("Could not turn into a daemon");
106 if (load_items() == 0)
108 log("Error loading items");
112 if (load_store() == 0)
114 log("Error loading store");
117 if (load_tavern() == 0)
119 log("Error loading tavern");
124 loadNews(newsdata
, todaysnews
);
127 if (load_masters() == false)
129 log("Error loading masters");
133 if (load_monsters() == false)
135 log("Error loading monsters");
141 log("Error loading dragon");
145 if (load_levels() == false)
147 log("Error loading levels");
151 shuttingdown
= false;
153 char ignoreservers
[32][256];
155 currentserver
= strtok(ignoreserverslist
, " ");
156 for (int server
= 0; server
< 32 && currentserver
!= NULL
; server
++)
158 strncpy(ignoreservers
[server
], currentserver
, 255);
159 log("Placing %s on the server ignore list", currentserver
);
160 currentserver
= strtok(NULL
, " ");
163 // This loop will retry the connection 3 times
164 for (int retry
= 0; retry
< 3 && !shuttingdown
; retry
++)
170 long int loadtime
= time(NULL
);
171 long int currentTime
;
172 long int oldTime
= loadtime
;
174 lastidlecheck
= loadtime
;
177 log("Setting primary Idle Check timestamp: %ld", lastidlecheck
);
182 sock
= conn(remoteserver
, remoteport
, localhost
, 0);
183 // sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
185 fprintf(stderr
,"make_connection failed.\n");
186 unload_config_file();
189 log("%S socket connected.");
192 raw("PASS :%s", remotepass
);
193 raw("SERVER %s 1 :%s", servername
, servername
);
194 raw("NICK %S 1 %d %s %s %s %d :%s v%s", time(NULL
), gsident
, gshost
,
195 servername
, time(NULL
), PACKAGE
, VERSION
);
196 raw(":%S JOIN %s", c_Forest
);
197 raw(":%S MODE %s +tn", c_Forest
);
198 #elif defined(BAHAMUT)
199 raw("PASS %s :TS", remotepass
);
200 raw("SERVER %s 1 :%s", servername
, servername
);
201 raw("NICK %S 1 %d +w%s %s %s %s 0 :GameServ", time(NULL
), (isBOper() ? "o" : ""),
202 gsident
, gshost
, servername
);
203 raw(":%s SJOIN %d %d %s +nt :@%S", servername
, time(NULL
), time(NULL
), c_Forest
);
204 #elif defined(HYBRID)
205 raw("PASS %s :TS", remotepass
);
206 raw("SERVER %s 1 :%s", servername
, servername
);
207 raw("NICK %S 1 %d +w%s %s %s %s :GameServ", time(NULL
), (isBOper() ? "o" : ""),
208 gsident
, gshost
, servername
);
209 raw(":%s SJOIN %ld %s +nt :@%S", servername
, time(NULL
), c_Forest
);
210 #elif defined(ULTIMATE2)
211 raw("PASS %s :TS", remotepass
);
212 raw("SERVER %s 1 :%s", servername
, servername
);
213 raw("NICK %S 1 %d %s %s %s 0 :GameServ",
214 time(NULL
), gsident
, gshost
, servername
);
216 raw(":%S mode %S +o");
217 raw(":%S JOIN %s", c_Forest
);
219 // Server numeric is: [] <-- must be unique
220 raw("PASS :%s", remotepass
);
221 raw("SERVER %s 1 %d %d P10 []AAF :%s", servername
, time(NULL
), time(NULL
), servername
);
222 raw("[] N %S 1 %d %s %s %s DAqAoB %s :%S", time(NULL
), gsident
, gshost
,
223 (isBOper() ? "+o" : ""), gsnum
);
224 raw("[] B %s %d +tn %s:o", c_Forest
, time(NULL
) - 864000, gsnum
);
228 raw("%s T %s :%s", gsnum
, c_Forest
, c_ForestTopic
);
229 raw("[] EB"); // End burst
232 #if defined(ULTIMATE2)
233 raw(":%s MODE %s +o %S %ld", servername
, c_Forest
,
236 raw(":%S MODE %s +o %S", c_Forest
);
239 raw(":%S TOPIC %s :%s", c_Forest
, c_ForestTopic
);
245 raw(":%S PRIVMSG %s :IDENTIFY %s", nsname
, nspass
);
248 sock_gets(sock
,buffer
,sizeof(buffer
)-1); /* -1 added thanks to
249 David Duchene <dave@ltd.com> for pointing out the possible
250 buffer overflow resulting from the linefeed added below. */
254 log("Server: %s",buffer
);
259 if (sock_gets(sock
,buffer
,sizeof(buffer
)) == -1)
266 if (buffer
[0] == ':')
268 source
= strtok(buf
, " ");
269 cmd
= strtok(NULL
, " ");
272 cmd
= strtok(buf
, " ");
274 source
= strtok(buf
, " ");
275 cmd
= strtok(NULL
, " ");
279 log("Server: %s", buffer
);
282 // Wait N seconds then we're loaded.
285 if (time(NULL
) >= welcomedelay
+ loadtime
)
288 retry
= 0; // Start the reconnection cycle over
293 long TIME
= time(NULL
);
294 if (TIME
- lastidlecheck
>= idlecheckperiod
)
297 lastidlecheck
= TIME
;
301 // Refresh players and clear news if the time is up
302 currentTime
= time(NULL
);
304 if (isRolloverForestFights())
306 if (currentTime
- lastrollover
>= rolloverperiod
)
309 lastrollover
= currentTime
;
311 notice(s_GameServ
, c_Forest
, "Adding %d forest fights to all players!", numrolloverfights
);
315 if (currentTime
- lastrefresh
>= refreshperiod
)
318 clearNews(todaysnews
);
319 saveNews(newsdata
, todaysnews
);
320 lastrefresh
= currentTime
;
322 notice(s_GameServ
, c_Forest
, "Refreshing all players "\
323 "and resetting news!");
326 // Save the player data every updateperiod seconds
327 if (currentTime
- oldTime
>= updateperiod
)
329 oldTime
= currentTime
;
330 log("Saving to %s", playerdata
);
333 saveNews(newsdata
, todaysnews
);
336 // Send notice to the channel of the update
337 notice(s_GameServ
, c_Forest
, "%S player data saved");
343 if (stricmp(cmd
, "PING") == 0) {
345 timestamp
= strtok(NULL
, "");
346 raw("PONG %s", timestamp
);
348 if (stricmp(cmd
, "G") == 0) {
350 timestamp
= strtok(NULL
, " ");
351 raw("[] Z [] %s 0 %s", timestamp
+ 1, timestamp
);
354 } else if (stricmp(cmd
, "EB") == 0) {
357 } else if (stricmp(cmd
, "VERSION") == 0) {
359 server
= strtok(NULL
, " ");
361 raw(":%s 351 %s %s_%s. %s", servername
, source
+1, PACKAGE
, VERSION
, servername
);
363 } else if (strncmp(cmd
, "NICK", 4) == 0) {
364 if (buffer
[0] == ':')
367 if ((tempPtr
= find((source
+ 1))))
370 unsigned long oldhv
, newhv
;
371 nick
= strtok(NULL
, " ");
372 oldhv
= iHASH((unsigned char *) tempPtr
->getNick());
373 newhv
= iHASH((unsigned char *) nick
);
374 tempPtr
->setNick(nick
);
375 clients
[oldhv
].remove(tempPtr
);
376 clients
[newhv
].insertAtBack(tempPtr
);
383 } else if (stricmp(cmd
, "N") == 0 && strlen(source
) == 2) {
385 char *nick
, *realnick
;
386 realnick
= strtok(NULL
, " ");
388 for (int x
= 0; x
< 5; x
++)
389 nick
= strtok(NULL
, " ");
394 log ("aClient has modes");
397 // Searching for the +r mode (extra parameter)
398 for (unsigned int count
= 1; count
< strlen(nick
); count
++)
400 if (nick
[count
] == 'r')
402 nick
= strtok(NULL
, " ");
406 nick
= strtok(NULL
, " ");
409 aClient
*newuser
, *temp
;
411 nick
= strtok(NULL
, " ");
414 newuser
= new aClient(nick
, realnick
);
416 newuser
= new aClient(nick
);
425 notice(s_GameServ
, nick
, welcomemsg
, realnick
);
427 notice(s_GameServ
, nick
, welcomemsg
, nick
);
431 unsigned long hv
= sHASH((unsigned char *) nick
);
433 unsigned long hv
= iHASH((unsigned char *) nick
);
436 temp
= clients
[hv
].insertAtBack(newuser
);
438 #if defined(HYBRID) || defined(BAHAMUT) || defined(ULTIMATE2)
442 nickserver
= strtok(NULL
, " ");
443 if (nickserver
[0] == '+')
446 nickserver
= strtok(NULL
, " ");
447 for (int x
= 0; x
< 32; x
++)
449 if (stricmp(ignoreservers
[x
], nickserver
) == 0)
455 #elif defined(UNREAL)
461 nickserver
= strtok(NULL
, " ");
462 for (int x
= 0; x
< 32; x
++)
464 if (stricmp(ignoreservers
[x
], nickserver
) == 0)
474 } else if (stricmp(cmd
, "Q") == 0) {
475 // unsigned long hv = sHASH((unsigned char *) source);
477 } else if (stricmp(cmd
, "QUIT") == 0) {
478 // unsigned long hv = iHASH((unsigned char *) source);
486 if (!(quitter
= find(source
)))
488 log("Fatal Error: could not find %s in the "\
489 "clients list", source
);
499 /* Attempting to use the logout() function
500 if ((quitter = find(source)))
501 clients[hv].remove(quitter);
502 if ((quitter = findIRCplayer(source)))
504 if (player_fight(quitter))
506 // Stop the fight on the other client
507 aClient *otherplayer = quitter->stats->battle;
508 otherplayer->stats->battle = NULL;
509 notice(s_GameServ, otherplayer->getNick(), "%s "\
510 "has quit IRC. The fight stops here.",
511 quitter->stats->name);
513 quitter->stats->battle = NULL;
514 quitter->stats->fight = NULL;
515 quitter->stats->master = NULL;
517 quitter->setNick("Not Playing");
519 quitter->setRealNick("Not Playing");
521 quitter->stats->client = NULL; // Unidentify them
526 } else if (stricmp(cmd
, "P") == 0) {
529 longname
= new char[strlen(s_GameServ
) + strlen(servername
) + 2];
531 sprintf(longname
, "%S@%s", servername
);
533 dest
= strtok(NULL
, " ");
534 rest
= strtok(NULL
, "");
535 if (stricmp(dest
, gsnum
) == 0 || stricmp(dest
, longname
) == 0)
538 gameserv(source
, rest
);
540 else if (stricmp(dest
, c_Forest
) == 0 && isListenOnCF())
543 forest(source
, rest
);
546 } else if (stricmp(cmd
, "PRIVMSG") == 0) {
548 dest
= strtok(NULL
, " ");
549 rest
= strtok(NULL
, "");
550 if (strnicmp(dest
, s_GameServ
, strlen(s_GameServ
)) == 0)
551 gameserv(source
, rest
);
552 else if (stricmp(dest
, c_Forest
) == 0 && isListenOnCF())
553 forest(source
, rest
);
556 } else if (stricmp(cmd
, "J") == 0) {
558 } else if (stricmp(cmd
, "JOIN") == 0) {
562 channel
= strtok(NULL
, " ");
569 joiner
= find(source
);
571 if (stricmp(channel
, c_Forest
) == 0 && is_playing(joiner
))
574 log("Player %s (IRC: %s) joined %s",
575 joiner
->stats
->getName().c_str(),
577 joiner
->getRealNick(),
583 raw(":%S MODE %s +v %s", c_Forest
, (source
));
590 } else if (stricmp(cmd
, "SJOIN") == 0) {
591 char *channel
, *nick
, *tmp
, *rest
;
592 strtok(NULL
, " "); // Ignore the TS
594 strtok(NULL
, " "); // Ignore the TS
596 channel
= strtok(NULL
, " ");
597 rest
= strtok(NULL
, "");
598 tmp
= strchr(rest
, ':');
600 nick
= strtok(tmp
, " ");
606 nick
++; // Assume for users set op and voice, they
607 // are never passed as +@nick
608 if (stricmp(channel
, c_Forest
) == 0 && is_playing(nick
))
609 raw(":%S MODE %s +v %s", channel
, nick
);
611 nick
= strtok(NULL
, " ");
616 log("Unrecognized Message: cmd = %s source = %s", cmd
, source
);
621 } // for loop for connection retry
627 saveNews(newsdata
, todaysnews
);
636 unload_config_file();
640 aClient
*find(char *nick
)
642 return findbynick(nick
);
645 aClient
*find(const char *nick
)
647 return findbynick(nick
);
652 aClient
*findbyrealnick(char *realnick
)
654 ListNode
<aClient
> *newPtr
;
655 unsigned long hv
= sHASH((unsigned char *) realnick
);
656 newPtr
= clients
[hv
].First();
658 aClient
*client
= NULL
;
662 client
= newPtr
->getData();
663 if (stricmp(client
->getRealNick(), realnick
) == 0)
666 newPtr
= newPtr
->Next();
673 aClient
*findbyrealnick(char *realnick
)
675 return findbynick(realnick
);
680 aClient
*findbynick(char *nick
)
682 ListNode
<aClient
> *newPtr
;
684 unsigned long hv
= sHASH((unsigned char *) nick
);
686 unsigned long hv
= iHASH((unsigned char *) nick
);
689 newPtr
= clients
[hv
].First();
691 aClient
*client
= NULL
;
695 client
= newPtr
->getData();
697 if (strcmp(client
->getNick(), nick
) == 0)
699 if (stricmp(client
->getNick(), nick
) == 0)
703 newPtr
= newPtr
->Next();
708 aClient
*findIRCplayer(const char *nick
)
710 ListNode
<aClient
> *newPtr
;
718 unsigned long hv
= iHASH((unsigned char *) p
->stats
->getName().c_str());
720 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
722 p
= newPtr
->getData();
724 if (strcmp(p
->getNick(), nick
) == 0)
726 if (stricmp(p
->getNick(), nick
) == 0)
734 aClient
*findplayer(const char *name
)
736 ListNode
<aClient
> *newPtr
;
738 unsigned long hv
= iHASH((unsigned char *) name
);
739 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
741 p
= newPtr
->getData()->stats
;
742 if (stricmp(p
->getName().c_str(), name
) == 0)
743 return newPtr
->getData();
751 ListNode
<aClient
> *newPtr
;
754 for (int x
= 0; x
< U_TABLE_SIZE
; x
++)
756 for (newPtr
= players
[x
].First(); newPtr
; newPtr
= newPtr
->Next())
758 p
= newPtr
->getData()->stats
;
759 switch(p
->getLevel())
762 if ((time(NULL
) - p
->lastlogin
) / 86400 >= level1expire
)
764 logout(newPtr
->getData());
765 players
[x
].remove(newPtr
->getData());
771 if ((time(NULL
) - p
->lastlogin
) / 86400 >= defaultexpire
)
773 logout(newPtr
->getData());
774 players
[x
].remove(newPtr
->getData());
787 aClient
*findbynick(const char *nick
)
789 ListNode
<aClient
> *newPtr
;
791 unsigned long hv
= sHASH((unsigned char *) nick
);
793 unsigned long hv
= iHASH((unsigned char *) nick
);
796 newPtr
= clients
[hv
].First();
798 aClient
*client
= NULL
;
802 client
= newPtr
->getData();
804 if (strcmp(client
->getNick(), nick
) == 0)
806 if (stricmp(client
->getNick(), nick
) == 0)
810 newPtr
= newPtr
->Next();
815 /* daemon() - detach process from user and disappear into the background
816 * returns -1 on failure, but you can't do much except exit in that case
817 * since we may already have forked. This is based on the BSD version,
818 * so the caller is responsible for things like the umask, etc.
821 /* believed to work on all Posix systems */
823 int daemon(int nochdir
, int noclose
)
826 switch (pid
= fork())
830 default: _exit(0); /* exit the original process */
833 if (setsid() < 0) /* shoudn't fail */
836 /* dyke out this switch if you want to acquire a control tty in */
837 /* the future -- not normally advisable for daemons */
839 switch (pid
= fork())
845 outfile
.open(pidfile
);
847 cerr
<< "Unable to open " << pidfile
<< endl
;
848 outfile
<< pid
<< endl
;
860 open("/dev/null",O_RDWR
);
868 /* closeall() -- close all FDs >= a specified value */
870 void closeall(int fd
)
872 int fdlimit
= sysconf(_SC_OPEN_MAX
);
881 cout
<< " GGGG AAA MM MM EEEEEEE SSSSS EEEEEEE RRRRRR VV VV " << endl
;
882 cout
<< " GG GG AAAAA MMM MMM EE SS EE RR RR VV VV " << endl
;
883 cout
<< "GG AA AA MM MM MM EEEEE SSSSS EEEEE RRRRRR VV VV " << endl
;
884 cout
<< "GG GGG AAAAAAA MM MM EE SS EE RR RR VV VV " << endl
;
885 cout
<< "G G AA AA MM MM EEEEEEE SSSSS EEEEEEE RR RR VVV" << endl
;
886 cout
<< " GGGGG V\n\n" << endl
;
887 cout
<< "Version: " << VERSION
<< endl
;
888 cout
<< "http://www.gameserv.us - http://www.sourceforge.net/projects/gameservirc" << endl
;
891 void load_lastrefresh()
894 infile
.open(".gsrefresh");
898 log("Error opening .gsrefresh");
902 long mytime
= time(NULL
);
904 log("Generating new refresh time");
907 // Just a safety measure... tho no one should
908 // get anywhere near the actual time as their refreshperiod
909 if (refreshperiod
>= mytime
)
911 log("Refresh period is greater than or equal to the actual time... setting it to 86400");
912 refreshperiod
= 86400;
915 lastrefresh
= mytime
- (mytime
% refreshperiod
);
921 infile
>> lastrefresh
;
928 void load_lastrollover()
931 infile
.open(".gsrollover");
935 log("Error opening .gsrollover");
939 long mytime
= time(NULL
);
941 log("Generating new rollover time");
943 lastrollover
= mytime
;
946 infile
>> lastrollover
;
949 if (lastrollover
< 0)
953 void save_lastrefresh()
957 outfile
.open(".gsrefresh");
961 log("Error creating new file .gsrefresh");
964 outfile
<< lastrefresh
<< endl
<< lastrollover
;
969 void save_lastrollover()
973 outfile
.open(".gsrollover");
977 log("Error creating new file .gsrollover");
980 outfile
<< lastrollover
<< endl
;