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