]> jfr.im git - irc/gameservirc.git/blame - gameserv/tcpclient.cpp
Fixed some bugs
[irc/gameservirc.git] / gameserv / tcpclient.cpp
CommitLineData
85ce9d3e 1/*
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.
7 *
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.
10 *
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/.
13 */
14
15#include "sockhelp.h"
c7340cbd 16#include "options.h"
85ce9d3e 17#include "list.h"
18#include "aClient.h"
19#include "extern.h"
20#include <stdio.h>
21#include <unistd.h>
22#include <string.h>
fb37ecc7 23#include <fstream>
85ce9d3e 24#include <stdlib.h>
ce61cdfa 25#include <fcntl.h>
26#include <signal.h>
27//#include <sys/types.h>
28//#include <sys/wait.h>
29//#include <errno.h>
30
31
85ce9d3e 32
fb37ecc7 33using std::ofstream;
34using std::ifstream;
ce61cdfa 35using std::cerr;
36using std::endl;
fb37ecc7 37
91c0b563 38char *PACKAGE = "GameServ";
7f17db99 39char *VERSION = "1.2.0 +devel";
173302fe 40
85ce9d3e 41int sock;
abbfcdb9 42int day;
44ea29f7 43
85ce9d3e 44List<aClient> clients;
45
abbfcdb9 46void save_day();
47void load_day();
15838737 48void prettyIntro();
44ea29f7 49
ce61cdfa 50// Make this a daemon
51int daemon(int nochdir, int noclose);
52
53// Close all file descriptors from >= fd
54void closeall(int fd);
55
624c0352 56int main(int argc, char *argv[])
85ce9d3e 57{
28f552b8 58 char buffer[1024], buf[1024];
85ce9d3e 59 int connected = 1;
624c0352 60 char *cmd, *source = NULL, *conf = "gameserv.conf";
85ce9d3e 61 srand(time(NULL));
624c0352 62
1579dfa2 63 /*
64 * This needs to be fixed to work for any number of arguments in any
65 * order
66 *
67 */
624c0352 68 if (argc > 1)
69 {
70 if ( argc > 2 || stricmp(argv[1], "--help") == 0)
71 {
72 cout << "Usage: gameserv [options] [configfile]" << endl;
73 cout << "Options:" << endl;
74 cout << "--help Displays this help dialogue" << endl;
75 return 1;
76 }
77 conf = new char[strlen(argv[1])];
78 strcpy(conf, argv[1]);
79 }
80
15838737 81 prettyIntro();
624c0352 82
83 if (load_config_file(conf))
84 {
85 cout << "Config file loaded ok...\n"
86 << "Turning into a daemon" << endl;
87 }
88 else
89 exit(2);
324ab87f 90
ce61cdfa 91 // Turn into a daemon
92 if (daemon(1,0) < 0)
93 {
94 perror("Could not turn into a daemon");
95 exit(2);
96 }
97
85ce9d3e 98 ignore_pipe();
324ab87f 99 sock = make_connection(remoteport, SOCK_STREAM, remoteserver);
85ce9d3e 100 if (sock == -1) {
101 fprintf(stderr,"make_connection failed.\n");
102 unload_config_file();
103 return -1;
104 }
105
c7340cbd 106#ifdef UNREAL
85ce9d3e 107 raw("PROTOCTL NICKv2 VHP");
108 raw("PASS :%s", remotepass);
c7340cbd 109 raw("SERVER %s 1 :%s", servername, servername);
173302fe 110 raw("NICK %S 1 %d %S %s %s %d +owghraAxNt %s :%s v%s", time(NULL), gshost,
111 servername, time(NULL), gshost, PACKAGE, VERSION);
85ce9d3e 112 raw(":%S JOIN %s", c_Forest);
c7340cbd 113 raw(":%S MODE %s +mtn", c_Forest);
114#elif defined(BAHAMUT)
115 raw("PASS %s :TS", remotepass);
116 raw("SERVER %s 1 :%s", servername, servername);
117 raw("NICK %S 1 %d +o %s %s %s 0 :GameServ", time(NULL), gsident, gshost,
118 servername);
119 raw(":%s SJOIN %d %d %s +mnt :@%S", servername, time(NULL), time(NULL), c_Forest);
581ec09e 120#elif defined(HYBRID)
121 raw("PASS %s :TS", remotepass);
122 raw("SERVER %s 1 :%s", servername, servername);
123 raw("NICK %S 1 %d +o %s %s %s :GameServ", time(NULL), gsident, gshost,
124 servername);
125 // Sending a timestamp of 1 to force ops.
126 raw(":%s SJOIN 1 %s +ntm :@%S", servername, c_Forest);
e1c41a84 127#elif defined(P10)
128 // Server numeric is: [] <-- must be unique
129 raw("PASS :%s", remotepass);
130 raw("SERVER %s 1 %d %d P10 []AAF :%s", servername, time(NULL), time(NULL), servername);
131 raw("[] N %S 1 %d %s %s DAqAoB %s :%S", time(NULL), gsident, gshost, gsnum);
132 raw("[] B %s %d +tnm %s:o", c_Forest, time(NULL) - 864000, gsnum);
c7340cbd 133#endif
e1c41a84 134
135#if defined(P10)
136 raw("%s T %s :%s", gsnum, c_Forest, c_ForestTopic);
fc9d2643 137 raw("[] EB"); // End burst
581ec09e 138#else
139#ifndef HYBRID
85ce9d3e 140 raw(":%S MODE %s +o %S", c_Forest);
581ec09e 141#endif
c7340cbd 142 raw(":%S TOPIC %s :%s", c_Forest, c_ForestTopic);
e1c41a84 143#endif
85ce9d3e 144
145 sock_gets(sock,buffer,sizeof(buffer)-1); /* -1 added thanks to
146 David Duchene <dave@ltd.com> for pointing out the possible
147 buffer overflow resulting from the linefeed added below. */
148
149
9f8c2acc 150 #ifdef DEBUGMODE
151 log("Server: %s",buffer);
152 #endif
153
425d7369 154 strcpy(boss.name, "Red Dragon");
155 strcpy(boss.weapon, "Breath of Unholy Fire");
156 boss.strength = 6667;
157 boss.gold = 2000000000;
158 boss.exp = 2000000000;
159 strcpy(boss.death, "You finally snuff out the deadly murderous "\
160 "dragon's dark flames. You have freed the land of its terror "\
161 "filled reign from above!");
162
ab4f4ec0 163 init_masters();
ad7dfaa0 164 load_gs_dbase();
abbfcdb9 165 load_day();
922daad7 166 long int loadtime = time(NULL);
167 long int currentTime;
168 long int oldTime = loadtime;
5963944b 169 bool loaded = false;
44ea29f7 170
4dde2ed9 171 if (load_monsters() == false)
172 goto end;
173
85ce9d3e 174 while (connected) {
175 if (sock_gets(sock,buffer,sizeof(buffer)) == -1) {
176 connected = 0;
177 }
178 strcpy(buf, buffer);
179
e1c41a84 180 #if !defined(P10)
85ce9d3e 181 if (buffer[0] == ':')
182 {
183 source = strtok(buf, " ");
184 cmd = strtok(NULL, " ");
185 }
186 else
187 cmd = strtok(buf, " ");
e1c41a84 188 #else
189 source = strtok(buf, " ");
190 cmd = strtok(NULL, " ");
191 #endif
85ce9d3e 192
9f8c2acc 193 #ifdef DEBUGMODE
194 log("Server: %s", buffer);
195 #endif
5963944b 196
bf2cabcd 197 // Wait N seconds then we're loaded.
5963944b 198 if (!loaded)
199 {
922daad7 200 if (time(NULL) >= welcomedelay + loadtime)
5963944b 201 loaded = true;
202 }
203
922daad7 204 // Save the player data every updateperiod seconds
205 currentTime = time(NULL);
206 if (currentTime - oldTime >= updateperiod)
207 {
208 oldTime = currentTime;
209 save_gs_dbase();
210 }
211
e1c41a84 212
213 #if !defined(P10)
85ce9d3e 214 if (stricmp(cmd, "PING") == 0) {
0a1518fa 215 char *timestamp;
216 timestamp = strtok(NULL, "");
217 raw("PONG %s", timestamp);
e1c41a84 218 #else
219 if (stricmp(cmd, "G") == 0) {
220 char *timestamp;
221 timestamp = strtok(NULL, " ");
222 raw("[] Z [] %s 0 %s", timestamp + 1, timestamp);
223 #endif
fc9d2643 224 #ifdef P10
225 } else if (stricmp(cmd, "EB") == 0) {
226 raw("[] EA");
227 #endif
0501fe18 228 } else if (stricmp(cmd, "VERSION") == 0) {
229 char *server;
230 server = strtok(NULL, " ");
231 server++;
2e9db9c4 232 raw(":%s 351 %s %s_%s. %s", servername, source+1, PACKAGE, VERSION, servername);
ba2a880f 233 #if !defined(P10)
85ce9d3e 234 } else if (strncmp(cmd, "NICK", 4) == 0) {
235 if (buffer[0] == ':')
236 {
237 aClient *tempPtr;
28f552b8 238 if ((tempPtr = find((source + 1))))
85ce9d3e 239 {
240 char *nick;
241 nick = strtok(NULL, " ");
242 tempPtr->setNick(nick);
243 }
244 }
245 else
246 {
247 char *nick;
ba2a880f 248 #else
249 } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
250 {
ce61cdfa 251 char *nick, *realnick;
252 realnick = strtok(NULL, " ");
ba2a880f 253
ce61cdfa 254 for (int x = 0; x < 5; x++)
ba2a880f 255 nick = strtok(NULL, " ");
fc9d2643 256
ba2a880f 257 if (nick[0] == '+')
fc9d2643 258 {
259 #ifdef DEBUGMODE
260 log ("aClient has modes");
261 #endif
262
263 // Searching for the +r mode (extra parameter)
264 for (unsigned int count = 1; count < strlen(nick); count++)
265 {
266 if (nick[count] == 'r')
267 {
268 nick = strtok(NULL, " ");
269 break;
270 }
271 }
272 nick = strtok(NULL, " ");
273 }
ba2a880f 274 #endif
85ce9d3e 275 aClient *newuser;
ba2a880f 276
85ce9d3e 277 nick = strtok(NULL, " ");
ba2a880f 278
ce61cdfa 279 #ifdef P10
280 newuser = new aClient(nick, realnick);
281 #else
282 newuser = new aClient(nick);
283 #endif
284
285
5963944b 286 if (loaded)
ce61cdfa 287 #ifdef P10
288 notice(s_GameServ, nick, welcomemsg, realnick);
289 #else
bf2cabcd 290 notice(s_GameServ, nick, welcomemsg, nick);
ce61cdfa 291 #endif
b0a5c536 292
85ce9d3e 293 clients.insertAtBack(newuser);
294 delete newuser;
295 }
ba2a880f 296 #if defined(P10)
297 } else if (stricmp(cmd, "Q") == 0) {
298 #else
85ce9d3e 299 } else if (stricmp(cmd, "QUIT") == 0) {
ba2a880f 300 #endif
85ce9d3e 301 aClient *quitter;
fc9d2643 302 char z = source[0];
303
304 if (z == ':')
305 source++;
306
307 if ((quitter = find(source)))
85ce9d3e 308 clients.remove(quitter);
fc9d2643 309 if ((quitter = findIRCplayer(source)))
ee38284f 310 {
7f17db99 311 if (player_fight(quitter))
312 {
313 // Stop the fight on the other client
314 aClient *otherplayer = quitter->stats->battle;
315 otherplayer->stats->battle = NULL;
316 notice(s_GameServ, otherplayer->getNick(), "%s "\
317 "has quit IRC. The fight stops here.",
318 quitter->stats->name);
319 }
320 quitter->stats->battle = NULL;
321 quitter->stats->fight = NULL;
322 quitter->stats->master = NULL;
323
ee38284f 324 quitter->setNick("!NULL!");
a5316c52 325 #ifdef P10
326 quitter->setRealNick("!NULL!");
327 #endif
ee38284f 328 quitter->stats->user = NULL; // Unidentify them
329 }
fc9d2643 330
331 if (z == ':')
332 source--;
333
ba2a880f 334 #if defined(P10)
335 } else if (stricmp(cmd, "P") == 0) {
336 char *rest, *dest;
337 char *longname;
338 longname = new char[strlen(s_GameServ) + strlen(servername) + 2];
339
340 sprintf(longname, "%S@%s", servername);
85ce9d3e 341
ba2a880f 342 dest = strtok(NULL, " ");
343 rest = strtok(NULL, "");
344 if (stricmp(dest, gsnum) == 0 || stricmp(dest, longname) == 0)
345 {
346 delete [] longname;
347 gameserv(source, rest);
348 }
349 else if (stricmp(dest, c_Forest) == 0)
350 {
351 delete [] longname;
352 forest(source, rest);
353 }
354 #else
85ce9d3e 355 } else if (stricmp(cmd, "PRIVMSG") == 0) {
356 char *rest, *dest;
357 dest = strtok(NULL, " ");
358 rest = strtok(NULL, "");
ad7dfaa0 359 if (strnicmp(dest, s_GameServ, strlen(s_GameServ)) == 0)
85ce9d3e 360 gameserv(source, rest);
361 else if (stricmp(dest, c_Forest) == 0)
362 forest(source, rest);
ba2a880f 363 #endif
f2072f1a 364 #if defined(P10)
365 } else if (stricmp(cmd, "J") == 0) {
366 #else
85ce9d3e 367 } else if (stricmp(cmd, "JOIN") == 0) {
f2072f1a 368 #endif
85ce9d3e 369 char *channel;
f2072f1a 370 aClient *joiner;
85ce9d3e 371 channel = strtok(NULL, " ");
f2072f1a 372
373 char z = source[0];
374
375 if (z == ':')
376 source++;
377
378 joiner = find(source);
379
380 if (stricmp(channel, c_Forest) == 0 && is_playing(joiner))
381 {
382 #ifdef DEBUGMODE
383 log("Player %s (IRC: %s) joined %s",
384 joiner->stats->name,
385 #ifdef P10
386 joiner->getRealNick(),
387 #else
388 joiner->getNick(),
389 #endif
390 c_Forest);
391 #endif
392 raw(":%S MODE %s +v %s", c_Forest, (source));
393 }
394
395 if (z == ':')
396 source--;
c7340cbd 397
398 #if defined(BAHAMUT)
399 } else if (stricmp(cmd, "SJOIN") == 0) {
581ec09e 400 char *channel, *nick, *tmp, *rest;
c7340cbd 401 strtok(NULL, " "); // Ignore the TS
581ec09e 402#ifndef HYBRID
c7340cbd 403 strtok(NULL, " "); // Ignore the TS
581ec09e 404#endif
c7340cbd 405 channel = strtok(NULL, " ");
581ec09e 406 rest = strtok(NULL, "");
407 tmp = strchr(rest, ':');
408 tmp++;
409 nick = strtok(tmp, " ");
410 while (nick != NULL)
411 {
412 if (*nick == '@')
413 nick++;
414 if (*nick == '+')
415 nick++; // Assume for users set op and voice, they
416 // are never passed as +@nick
417 if (stricmp(channel, c_Forest) == 0 && is_playing(nick))
418 raw(":%S MODE %s +v %s", channel, nick);
419
420 nick = strtok(NULL, " ");
421 }
422#endif
85ce9d3e 423 } else {
9f8c2acc 424 #ifdef DEBUGMODE
425 log("Unrecognized Message: cmd = %s source = %s", cmd, source);
426 #endif
85ce9d3e 427 }
428 }
4dde2ed9 429
430 end:
431
c8ada07e 432 save_gs_dbase();
abbfcdb9 433 save_day();
4dde2ed9 434
c8ada07e 435 delete_monsters();
436 delete_masters();
437
9f8c2acc 438 #ifdef DEBUGMODE
439 log("<CLOSED>");
440 #endif
441
85ce9d3e 442 close(sock);
443 unload_config_file();
444 return 0;
445}
446
447aClient *find(char *nick)
448{
449 return findbynick(nick);
450}
451
452aClient *find(const char *nick)
453{
454 return findbynick(nick);
455}
456
ce61cdfa 457#ifdef P10
458
459aClient *findbyrealnick(char *realnick)
460{
461 ListNode <aClient> *newPtr;
462 newPtr = clients.First();
463
464 aClient *client = NULL;
465
466 while (newPtr)
467 {
468 client = newPtr->getData();
469 if (stricmp(client->getRealNick(), realnick) == 0)
470 return client;
471 client = NULL;
472 newPtr = newPtr->Next();
473 }
474 return client;
475}
4e5760fd 476
477#else
478
479aClient *findbyrealnick(char *realnick)
480{
481 return findbynick(realnick);
482}
483
ce61cdfa 484#endif
85ce9d3e 485
486aClient *findbynick(char *nick)
487{
488 ListNode <aClient> *newPtr;
489 newPtr = clients.First();
490
491 aClient *client = NULL;
492
493 while (newPtr)
494 {
495 client = newPtr->getData();
23ec3ff4 496 #ifdef P10
23ec3ff4 497 if (strcmp(client->getNick(), nick) == 0)
498 #else
499 if (stricmp(client->getNick(), nick) == 0)
500 #endif
85ce9d3e 501 return client;
502 client = NULL;
503 newPtr = newPtr->Next();
504 }
505 return client;
506}
507
ee38284f 508aClient *findIRCplayer(const char *nick)
509{
510 ListNode <aClient> *newPtr;
511 aClient *p = NULL;
512
513 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
514 {
515 p = newPtr->getData();
23ec3ff4 516 #ifdef P10
517 if (strcmp(p->getNick(), nick) == 0)
518 #else
519 if (stricmp(p->getNick(), nick) == 0)
520 #endif
ee38284f 521 return p;
522 p = NULL;
523 }
524 return NULL;
525}
0a1518fa 526aClient *findplayer(const char *name)
527{
528 ListNode <aClient> *newPtr;
529 Player *p = NULL;
530
531 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
532 {
533 p = newPtr->getData()->stats;
534 if (stricmp(p->name, name) == 0)
535 return newPtr->getData();
536 p = NULL;
537 }
538 return NULL;
539}
540
85ce9d3e 541aClient *findbynick(const char *nick)
542{
543 ListNode <aClient> *newPtr;
544 newPtr = clients.First();
545
546 aClient *client = NULL;
547
548 while (newPtr)
549 {
550 client = newPtr->getData();
23ec3ff4 551 #ifdef P10
552 if (strcmp(client->getNick(), nick) == 0)
553 #else
554 if (stricmp(client->getNick(), nick) == 0)
555 #endif
85ce9d3e 556 return client;
557 client = NULL;
558 newPtr = newPtr->Next();
559 }
560 return client;
561}
562
abbfcdb9 563void load_day()
44ea29f7 564{
565 ifstream infile;
566
abbfcdb9 567 infile.open(".gsday");
44ea29f7 568
569 if (infile.fail())
570 {
9f8c2acc 571 #ifdef DEBUGMODE
abbfcdb9 572 log("Error opening .gsday");
9f8c2acc 573 #endif
574
44ea29f7 575 generate:
9f8c2acc 576 #ifdef DEBUGMODE
abbfcdb9 577 log("Generating new day");
9f8c2acc 578 #endif
abbfcdb9 579 struct tm *tm;
580 time_t ti;
581 time(&ti);
582 tm = localtime(&ti);
583
584 day = tm->tm_mday;
585
586 save_day();
44ea29f7 587 return;
588 }
589
abbfcdb9 590 infile >> day;
44ea29f7 591 infile.close();
abbfcdb9 592 if (day < 1 || day > 31)
44ea29f7 593 goto generate;
594}
595
abbfcdb9 596void save_day()
44ea29f7 597{
598 ofstream outfile;
599
abbfcdb9 600 outfile.open(".gsday");
44ea29f7 601
602 if (outfile.fail())
603 {
abbfcdb9 604 log("Error creating new file .gsday");
44ea29f7 605 return;
606 }
607
abbfcdb9 608 outfile << day << endl;
44ea29f7 609
610 outfile.close();
611}
612
ce61cdfa 613/* daemon() - detach process from user and disappear into the background
614 * returns -1 on failure, but you can't do much except exit in that case
615 * since we may already have forked. This is based on the BSD version,
616 * so the caller is responsible for things like the umask, etc.
617 */
618
619/* believed to work on all Posix systems */
620
621int daemon(int nochdir, int noclose)
622{
623 pid_t pid;
624 switch (pid = fork())
625 {
626 case 0: break;
627 case -1: return -1;
628 default: _exit(0); /* exit the original process */
629 }
630
631 if (setsid() < 0) /* shoudn't fail */
632 return -1;
633
634 /* dyke out this switch if you want to acquire a control tty in */
635 /* the future -- not normally advisable for daemons */
636
637 switch (pid = fork())
638 {
639 case 0: break;
640 case -1: return -1;
641 default:
642 ofstream outfile;
69ae096c 643 outfile.open(pidfile);
ce61cdfa 644 if (outfile.fail())
69ae096c 645 cerr << "Unable to open " << pidfile << endl;
ce61cdfa 646 outfile << pid << endl;
647 outfile.close();
648
649 _exit(0);
650 }
651
652 if (!nochdir)
653 chdir("/");
654
655 if (!noclose)
656 {
657 closeall(0);
658 open("/dev/null",O_RDWR);
659 dup(0); dup(0);
660 }
661
662 return 0;
663}
664
665
666/* closeall() -- close all FDs >= a specified value */
667
668void closeall(int fd)
669{
670 int fdlimit = sysconf(_SC_OPEN_MAX);
671
672 while (fd < fdlimit)
673 close(fd++);
674}
675
15838737 676void prettyIntro()
677{
678cout << endl;
679cout << " GGGG AAA MM MM EEEEEEE SSSSS EEEEEEE RRRRRR VV VV " << endl;
680cout << " GG GG AAAAA MMM MMM EE SS EE RR RR VV VV " << endl;
681cout << "GG AA AA MM MM MM EEEEE SSSSS EEEEE RRRRRR VV VV " << endl;
682cout << "GG GGG AAAAAAA MM MM EE SS EE RR RR VV VV " << endl;
683cout << "G G AA AA MM MM EEEEEEE SSSSS EEEEEEE RR RR VVV" << endl;
684cout << " GGGGG V\n\n" << endl;
685cout << "Version: " << VERSION << endl;
686}