]>
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/.
28 //#include <sys/types.h>
29 //#include <sys/wait.h>
39 char *PACKAGE
= "GameServ";
40 char *VERSION
= "1.2.1 +devel";
45 List
<aClient
> clients
[U_TABLE_SIZE
];
53 int daemon(int nochdir
, int noclose
);
55 // Close all file descriptors from >= fd
56 void closeall(int fd
);
58 int main(int argc
, char *argv
[])
60 char buffer
[1024], buf
[1024];
63 char *cmd
, *source
= NULL
, *conf
= "gameserv.conf";
67 * This needs to be fixed to work for any number of arguments in any
73 if ( argc
> 2 || stricmp(argv
[1], "--help") == 0)
75 cout
<< "Usage: gameserv [options] [configfile]" << endl
;
76 cout
<< "Options:" << endl
;
77 cout
<< "--help Displays this help dialogue" << endl
;
80 conf
= new char[strlen(argv
[1])];
81 strcpy(conf
, argv
[1]);
86 if (load_config_file(conf
))
88 cout
<< "Config file loaded ok...\n"
89 << "Turning into a daemon" << endl
;
97 perror("Could not turn into a daemon");
103 if (load_monsters() == false)
106 shuttingdown
= false;
108 char ignoreservers
[32][256];
110 currentserver
= strtok(ignoreserverslist
, " ");
111 for (int server
= 0; server
< 32 && currentserver
!= NULL
; server
++)
113 strncpy(ignoreservers
[server
], currentserver
, 255);
114 log("Placing %s on the server ignore list", currentserver
);
115 currentserver
= strtok(NULL
, " ");
118 strcpy(boss
.name
, "Red Dragon");
119 strcpy(boss
.weapon
, "Breath of Unholy Fire");
120 boss
.strength
= 6667;
121 boss
.gold
= 2000000000;
122 boss
.exp
= 2000000000;
123 strcpy(boss
.death
, "You finally snuff out the deadly murderous "\
124 "dragon's dark flames. You have freed the land of its terror "\
125 "filled reign from above!");
128 // This loop will retry the connection 3 times
129 for (int retry
= 0; retry
< 3 && !shuttingdown
; retry
++)
135 long int loadtime
= time(NULL
);
136 long int currentTime
;
137 long int oldTime
= loadtime
;
139 lastidlecheck
= loadtime
;
142 log("Setting primary Idle Check timestamp: %ld", lastidlecheck
);
147 sock
= make_connection(remoteport
, SOCK_STREAM
, remoteserver
);
149 fprintf(stderr
,"make_connection failed.\n");
150 unload_config_file();
153 log("%S socket connected.");
156 raw("PROTOCTL NICKv2 VHP");
157 raw("PASS :%s", remotepass
);
158 raw("SERVER %s 1 :%s", servername
, servername
);
159 raw("NICK %S 1 %d %S %s %s %d +wghraAxNt %s :%s v%s", time(NULL
), gshost
,
160 servername
, time(NULL
), gshost
, PACKAGE
, VERSION
);
161 raw(":%S JOIN %s", c_Forest
);
162 raw(":%S MODE %s +tn", c_Forest
);
163 #elif defined(BAHAMUT)
164 raw("PASS %s :TS", remotepass
);
165 raw("SERVER %s 1 :%s", servername
, servername
);
166 raw("NICK %S 1 %d +w %s %s %s 0 :GameServ", time(NULL
), gsident
, gshost
,
168 raw(":%s SJOIN %d %d %s +nt :@%S", servername
, time(NULL
), time(NULL
), c_Forest
);
169 #elif defined(HYBRID)
170 raw("PASS %s :TS", remotepass
);
171 raw("SERVER %s 1 :%s", servername
, servername
);
172 raw("NICK %S 1 %d +w %s %s %s :GameServ", time(NULL
), gsident
, gshost
,
174 raw(":%s SJOIN %ld %s +nt :@%S", servername
, time(NULL
), c_Forest
);
176 // Server numeric is: [] <-- must be unique
177 raw("PASS :%s", remotepass
);
178 raw("SERVER %s 1 %d %d P10 []AAF :%s", servername
, time(NULL
), time(NULL
), servername
);
179 raw("[] N %S 1 %d %s %s DAqAoB %s :%S", time(NULL
), gsident
, gshost
, gsnum
);
180 raw("[] B %s %d +tn %s:o", c_Forest
, time(NULL
) - 864000, gsnum
);
184 raw("%s T %s :%s", gsnum
, c_Forest
, c_ForestTopic
);
185 raw("[] EB"); // End burst
188 raw(":%S MODE %s +o %S", c_Forest
);
190 raw(":%S TOPIC %s :%s", c_Forest
, c_ForestTopic
);
193 sock_gets(sock
,buffer
,sizeof(buffer
)-1); /* -1 added thanks to
194 David Duchene <dave@ltd.com> for pointing out the possible
195 buffer overflow resulting from the linefeed added below. */
199 log("Server: %s",buffer
);
203 if (sock_gets(sock
,buffer
,sizeof(buffer
)) == -1) {
209 if (buffer
[0] == ':')
211 source
= strtok(buf
, " ");
212 cmd
= strtok(NULL
, " ");
215 cmd
= strtok(buf
, " ");
217 source
= strtok(buf
, " ");
218 cmd
= strtok(NULL
, " ");
222 log("Server: %s", buffer
);
225 // Wait N seconds then we're loaded.
228 if (time(NULL
) >= welcomedelay
+ loadtime
)
231 retry
= 0; // Start the reconnection cycle over
236 long TIME
= time(NULL
);
237 if (TIME
- lastidlecheck
>= idlecheckperiod
)
240 lastidlecheck
= TIME
;
244 // Save the player data every updateperiod seconds
245 currentTime
= time(NULL
);
246 if (currentTime
- oldTime
>= updateperiod
)
248 oldTime
= currentTime
;
249 log("Saving to %s", playerdata
);
255 if (stricmp(cmd
, "PING") == 0) {
257 timestamp
= strtok(NULL
, "");
258 raw("PONG %s", timestamp
);
260 if (stricmp(cmd
, "G") == 0) {
262 timestamp
= strtok(NULL
, " ");
263 raw("[] Z [] %s 0 %s", timestamp
+ 1, timestamp
);
266 } else if (stricmp(cmd
, "EB") == 0) {
269 } else if (stricmp(cmd
, "VERSION") == 0) {
271 server
= strtok(NULL
, " ");
273 raw(":%s 351 %s %s_%s. %s", servername
, source
+1, PACKAGE
, VERSION
, servername
);
275 } else if (strncmp(cmd
, "NICK", 4) == 0) {
276 if (buffer
[0] == ':')
279 if ((tempPtr
= find((source
+ 1))))
282 unsigned long oldhv
, newhv
;
283 nick
= strtok(NULL
, " ");
284 oldhv
= iHASH((unsigned char *) tempPtr
->getNick());
285 newhv
= iHASH((unsigned char *) nick
);
286 tempPtr
->setNick(nick
);
287 clients
[oldhv
].remove(tempPtr
);
288 clients
[newhv
].insertAtBack(tempPtr
);
295 } else if (stricmp(cmd
, "N") == 0 && strlen(source
) == 2) {
297 char *nick
, *realnick
;
298 realnick
= strtok(NULL
, " ");
300 for (int x
= 0; x
< 5; x
++)
301 nick
= strtok(NULL
, " ");
306 log ("aClient has modes");
309 // Searching for the +r mode (extra parameter)
310 for (unsigned int count
= 1; count
< strlen(nick
); count
++)
312 if (nick
[count
] == 'r')
314 nick
= strtok(NULL
, " ");
318 nick
= strtok(NULL
, " ");
321 aClient
*newuser
, *temp
;
323 nick
= strtok(NULL
, " ");
326 newuser
= new aClient(nick
, realnick
);
328 newuser
= new aClient(nick
);
334 notice(s_GameServ
, nick
, welcomemsg
, realnick
);
336 notice(s_GameServ
, nick
, welcomemsg
, nick
);
339 unsigned long hv
= sHASH((unsigned char *) nick
)
341 unsigned long hv
= iHASH((unsigned char *) nick
);
344 temp
= clients
[hv
].insertAtBack(newuser
);
350 nickserver
= strtok(NULL
, " ");
351 if (nickserver
[0] == '+')
355 nickserver
= strtok(NULL
, " ");
356 for (int x
= 0; x
< 32; x
++)
358 if (stricmp(ignoreservers
[x
], nickserver
) == 0)
368 } else if (stricmp(cmd
, "Q") == 0) {
369 // unsigned long hv = sHASH((unsigned char *) source);
371 } else if (stricmp(cmd
, "QUIT") == 0) {
372 // unsigned long hv = iHASH((unsigned char *) source);
380 if (!(quitter
= find(source
)))
382 log("Fatal Error: could not find %s in the "\
383 "clients list", source
);
392 /* Attempting to use the logout() function
393 if ((quitter = find(source)))
394 clients[hv].remove(quitter);
395 if ((quitter = findIRCplayer(source)))
397 if (player_fight(quitter))
399 // Stop the fight on the other client
400 aClient *otherplayer = quitter->stats->battle;
401 otherplayer->stats->battle = NULL;
402 notice(s_GameServ, otherplayer->getNick(), "%s "\
403 "has quit IRC. The fight stops here.",
404 quitter->stats->name);
406 quitter->stats->battle = NULL;
407 quitter->stats->fight = NULL;
408 quitter->stats->master = NULL;
410 quitter->setNick("Not Playing");
412 quitter->setRealNick("Not Playing");
414 quitter->stats->client = NULL; // Unidentify them
419 } else if (stricmp(cmd
, "P") == 0) {
422 longname
= new char[strlen(s_GameServ
) + strlen(servername
) + 2];
424 sprintf(longname
, "%S@%s", servername
);
426 dest
= strtok(NULL
, " ");
427 rest
= strtok(NULL
, "");
428 if (stricmp(dest
, gsnum
) == 0 || stricmp(dest
, longname
) == 0)
431 gameserv(source
, rest
);
433 else if (stricmp(dest
, c_Forest
) == 0 && listenonc_forest
)
436 forest(source
, rest
);
439 } else if (stricmp(cmd
, "PRIVMSG") == 0) {
441 dest
= strtok(NULL
, " ");
442 rest
= strtok(NULL
, "");
443 if (strnicmp(dest
, s_GameServ
, strlen(s_GameServ
)) == 0)
444 gameserv(source
, rest
);
445 else if (stricmp(dest
, c_Forest
) == 0)
446 forest(source
, rest
);
449 } else if (stricmp(cmd
, "J") == 0) {
451 } else if (stricmp(cmd
, "JOIN") == 0) {
455 channel
= strtok(NULL
, " ");
462 joiner
= find(source
);
464 if (stricmp(channel
, c_Forest
) == 0 && is_playing(joiner
))
467 log("Player %s (IRC: %s) joined %s",
470 joiner
->getRealNick(),
476 raw(":%S MODE %s +v %s", c_Forest
, (source
));
483 } else if (stricmp(cmd
, "SJOIN") == 0) {
484 char *channel
, *nick
, *tmp
, *rest
;
485 strtok(NULL
, " "); // Ignore the TS
487 strtok(NULL
, " "); // Ignore the TS
489 channel
= strtok(NULL
, " ");
490 rest
= strtok(NULL
, "");
491 tmp
= strchr(rest
, ':');
493 nick
= strtok(tmp
, " ");
499 nick
++; // Assume for users set op and voice, they
500 // are never passed as +@nick
501 if (stricmp(channel
, c_Forest
) == 0 && is_playing(nick
))
502 raw(":%S MODE %s +v %s", channel
, nick
);
504 nick
= strtok(NULL
, " ");
509 log("Unrecognized Message: cmd = %s source = %s", cmd
, source
);
514 } // for loop for connection retry
529 unload_config_file();
533 aClient
*find(char *nick
)
535 return findbynick(nick
);
538 aClient
*find(const char *nick
)
540 return findbynick(nick
);
545 aClient
*findbyrealnick(char *realnick
)
547 ListNode
<aClient
> *newPtr
;
548 unsigned long hv
= sHASH((unsigned char *) realnick
);
549 newPtr
= clients
[hv
].First();
551 aClient
*client
= NULL
;
555 client
= newPtr
->getData();
556 if (stricmp(client
->getRealNick(), realnick
) == 0)
559 newPtr
= newPtr
->Next();
566 aClient
*findbyrealnick(char *realnick
)
568 return findbynick(realnick
);
573 aClient
*findbynick(char *nick
)
575 ListNode
<aClient
> *newPtr
;
577 unsigned long hv
= sHASH((unsigned char *) nick
);
579 unsigned long hv
= iHASH((unsigned char *) nick
);
582 newPtr
= clients
[hv
].First();
584 aClient
*client
= NULL
;
588 client
= newPtr
->getData();
590 if (strcmp(client
->getNick(), nick
) == 0)
592 if (stricmp(client
->getNick(), nick
) == 0)
596 newPtr
= newPtr
->Next();
601 aClient
*findIRCplayer(const char *nick
)
603 ListNode
<aClient
> *newPtr
;
611 unsigned long hv
= iHASH((unsigned char *) p
->stats
->name
);
613 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
615 p
= newPtr
->getData();
617 if (strcmp(p
->getNick(), nick
) == 0)
619 if (stricmp(p
->getNick(), nick
) == 0)
627 aClient
*findplayer(const char *name
)
629 ListNode
<aClient
> *newPtr
;
631 unsigned long hv
= iHASH((unsigned char *) name
);
632 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
634 p
= newPtr
->getData()->stats
;
635 if (stricmp(p
->name
, name
) == 0)
636 return newPtr
->getData();
644 ListNode
<aClient
> *newPtr
;
647 for (int x
= 0; x
< U_TABLE_SIZE
; x
++)
649 for (newPtr
= players
[x
].First(); newPtr
; newPtr
= newPtr
->Next())
651 p
= newPtr
->getData()->stats
;
660 aClient
*findbynick(const char *nick
)
662 ListNode
<aClient
> *newPtr
;
664 unsigned long hv
= sHASH((unsigned char *) nick
);
666 unsigned long hv
= iHASH((unsigned char *) nick
);
669 newPtr
= clients
[hv
].First();
671 aClient
*client
= NULL
;
675 client
= newPtr
->getData();
677 if (strcmp(client
->getNick(), nick
) == 0)
679 if (stricmp(client
->getNick(), nick
) == 0)
683 newPtr
= newPtr
->Next();
692 infile
.open(".gsday");
697 log("Error opening .gsday");
702 log("Generating new day");
717 if (day
< 1 || day
> 31)
725 outfile
.open(".gsday");
729 log("Error creating new file .gsday");
733 outfile
<< day
<< endl
;
738 /* daemon() - detach process from user and disappear into the background
739 * returns -1 on failure, but you can't do much except exit in that case
740 * since we may already have forked. This is based on the BSD version,
741 * so the caller is responsible for things like the umask, etc.
744 /* believed to work on all Posix systems */
746 int daemon(int nochdir
, int noclose
)
749 switch (pid
= fork())
753 default: _exit(0); /* exit the original process */
756 if (setsid() < 0) /* shoudn't fail */
759 /* dyke out this switch if you want to acquire a control tty in */
760 /* the future -- not normally advisable for daemons */
762 switch (pid
= fork())
768 outfile
.open(pidfile
);
770 cerr
<< "Unable to open " << pidfile
<< endl
;
771 outfile
<< pid
<< endl
;
783 open("/dev/null",O_RDWR
);
791 /* closeall() -- close all FDs >= a specified value */
793 void closeall(int fd
)
795 int fdlimit
= sysconf(_SC_OPEN_MAX
);
804 cout
<< " GGGG AAA MM MM EEEEEEE SSSSS EEEEEEE RRRRRR VV VV " << endl
;
805 cout
<< " GG GG AAAAA MMM MMM EE SS EE RR RR VV VV " << endl
;
806 cout
<< "GG AA AA MM MM MM EEEEE SSSSS EEEEE RRRRRR VV VV " << endl
;
807 cout
<< "GG GGG AAAAAAA MM MM EE SS EE RR RR VV VV " << endl
;
808 cout
<< "G G AA AA MM MM EEEEEEE SSSSS EEEEEEE RR RR VVV" << endl
;
809 cout
<< " GGGGG V\n\n" << endl
;
810 cout
<< "Version: " << VERSION
<< endl
;