]> jfr.im git - irc/gameservirc.git/blame - gameserv/tcpclient.cpp
Made it so missing directives are found on a config file load.
[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";
ce61cdfa 39char *VERSION = "1.1.8";
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
ab4f4ec0 149 init_masters();
ad7dfaa0 150 load_gs_dbase();
abbfcdb9 151 load_day();
922daad7 152 long int loadtime = time(NULL);
153 long int currentTime;
154 long int oldTime = loadtime;
5963944b 155 bool loaded = false;
44ea29f7 156
4dde2ed9 157 if (load_monsters() == false)
158 goto end;
159
85ce9d3e 160 while (connected) {
161 if (sock_gets(sock,buffer,sizeof(buffer)) == -1) {
162 connected = 0;
163 }
164 strcpy(buf, buffer);
165
e1c41a84 166 #if !defined(P10)
85ce9d3e 167 if (buffer[0] == ':')
168 {
169 source = strtok(buf, " ");
170 cmd = strtok(NULL, " ");
171 }
172 else
173 cmd = strtok(buf, " ");
e1c41a84 174 #else
175 source = strtok(buf, " ");
176 cmd = strtok(NULL, " ");
177 #endif
85ce9d3e 178
9f8c2acc 179 #ifdef DEBUGMODE
180 log("Server: %s", buffer);
181 #endif
5963944b 182
bf2cabcd 183 // Wait N seconds then we're loaded.
5963944b 184 if (!loaded)
185 {
922daad7 186 if (time(NULL) >= welcomedelay + loadtime)
5963944b 187 loaded = true;
188 }
189
922daad7 190 // Save the player data every updateperiod seconds
191 currentTime = time(NULL);
192 if (currentTime - oldTime >= updateperiod)
193 {
194 oldTime = currentTime;
195 save_gs_dbase();
196 }
197
e1c41a84 198
199 #if !defined(P10)
85ce9d3e 200 if (stricmp(cmd, "PING") == 0) {
0a1518fa 201 char *timestamp;
202 timestamp = strtok(NULL, "");
203 raw("PONG %s", timestamp);
e1c41a84 204 #else
205 if (stricmp(cmd, "G") == 0) {
206 char *timestamp;
207 timestamp = strtok(NULL, " ");
208 raw("[] Z [] %s 0 %s", timestamp + 1, timestamp);
209 #endif
fc9d2643 210 #ifdef P10
211 } else if (stricmp(cmd, "EB") == 0) {
212 raw("[] EA");
213 #endif
0501fe18 214 } else if (stricmp(cmd, "VERSION") == 0) {
215 char *server;
216 server = strtok(NULL, " ");
217 server++;
2e9db9c4 218 raw(":%s 351 %s %s_%s. %s", servername, source+1, PACKAGE, VERSION, servername);
ba2a880f 219 #if !defined(P10)
85ce9d3e 220 } else if (strncmp(cmd, "NICK", 4) == 0) {
221 if (buffer[0] == ':')
222 {
223 aClient *tempPtr;
28f552b8 224 if ((tempPtr = find((source + 1))))
85ce9d3e 225 {
226 char *nick;
227 nick = strtok(NULL, " ");
228 tempPtr->setNick(nick);
229 }
230 }
231 else
232 {
233 char *nick;
ba2a880f 234 #else
235 } else if (stricmp(cmd, "N") == 0 && strlen(source) == 2) {
236 {
ce61cdfa 237 char *nick, *realnick;
238 realnick = strtok(NULL, " ");
ba2a880f 239
ce61cdfa 240 for (int x = 0; x < 5; x++)
ba2a880f 241 nick = strtok(NULL, " ");
fc9d2643 242
ba2a880f 243 if (nick[0] == '+')
fc9d2643 244 {
245 #ifdef DEBUGMODE
246 log ("aClient has modes");
247 #endif
248
249 // Searching for the +r mode (extra parameter)
250 for (unsigned int count = 1; count < strlen(nick); count++)
251 {
252 if (nick[count] == 'r')
253 {
254 nick = strtok(NULL, " ");
255 break;
256 }
257 }
258 nick = strtok(NULL, " ");
259 }
ba2a880f 260 #endif
85ce9d3e 261 aClient *newuser;
ba2a880f 262
85ce9d3e 263 nick = strtok(NULL, " ");
ba2a880f 264
ce61cdfa 265 #ifdef P10
266 newuser = new aClient(nick, realnick);
267 #else
268 newuser = new aClient(nick);
269 #endif
270
271
5963944b 272 if (loaded)
ce61cdfa 273 #ifdef P10
274 notice(s_GameServ, nick, welcomemsg, realnick);
275 #else
bf2cabcd 276 notice(s_GameServ, nick, welcomemsg, nick);
ce61cdfa 277 #endif
b0a5c536 278
85ce9d3e 279 clients.insertAtBack(newuser);
280 delete newuser;
281 }
ba2a880f 282 #if defined(P10)
283 } else if (stricmp(cmd, "Q") == 0) {
284 #else
85ce9d3e 285 } else if (stricmp(cmd, "QUIT") == 0) {
ba2a880f 286 #endif
85ce9d3e 287 aClient *quitter;
fc9d2643 288 char z = source[0];
289
290 if (z == ':')
291 source++;
292
293 if ((quitter = find(source)))
85ce9d3e 294 clients.remove(quitter);
fc9d2643 295 if ((quitter = findIRCplayer(source)))
ee38284f 296 {
297 quitter->setNick("!NULL!");
298 quitter->stats->user = NULL; // Unidentify them
299 }
fc9d2643 300
301 if (z == ':')
302 source--;
303
ba2a880f 304 #if defined(P10)
305 } else if (stricmp(cmd, "P") == 0) {
306 char *rest, *dest;
307 char *longname;
308 longname = new char[strlen(s_GameServ) + strlen(servername) + 2];
309
310 sprintf(longname, "%S@%s", servername);
85ce9d3e 311
ba2a880f 312 dest = strtok(NULL, " ");
313 rest = strtok(NULL, "");
314 if (stricmp(dest, gsnum) == 0 || stricmp(dest, longname) == 0)
315 {
316 delete [] longname;
317 gameserv(source, rest);
318 }
319 else if (stricmp(dest, c_Forest) == 0)
320 {
321 delete [] longname;
322 forest(source, rest);
323 }
324 #else
85ce9d3e 325 } else if (stricmp(cmd, "PRIVMSG") == 0) {
326 char *rest, *dest;
327 dest = strtok(NULL, " ");
328 rest = strtok(NULL, "");
ad7dfaa0 329 if (strnicmp(dest, s_GameServ, strlen(s_GameServ)) == 0)
85ce9d3e 330 gameserv(source, rest);
331 else if (stricmp(dest, c_Forest) == 0)
332 forest(source, rest);
ba2a880f 333 #endif
85ce9d3e 334 } else if (stricmp(cmd, "JOIN") == 0) {
335 char *channel;
336 channel = strtok(NULL, " ");
337 if (stricmp(channel, c_Forest) == 0 && is_playing(source + 1))
338 raw(":%S MODE %s +v %s", c_Forest, (source + 1));
c7340cbd 339
340 #if defined(BAHAMUT)
341 } else if (stricmp(cmd, "SJOIN") == 0) {
581ec09e 342 char *channel, *nick, *tmp, *rest;
c7340cbd 343 strtok(NULL, " "); // Ignore the TS
581ec09e 344#ifndef HYBRID
c7340cbd 345 strtok(NULL, " "); // Ignore the TS
581ec09e 346#endif
c7340cbd 347 channel = strtok(NULL, " ");
581ec09e 348 rest = strtok(NULL, "");
349 tmp = strchr(rest, ':');
350 tmp++;
351 nick = strtok(tmp, " ");
352 while (nick != NULL)
353 {
354 if (*nick == '@')
355 nick++;
356 if (*nick == '+')
357 nick++; // Assume for users set op and voice, they
358 // are never passed as +@nick
359 if (stricmp(channel, c_Forest) == 0 && is_playing(nick))
360 raw(":%S MODE %s +v %s", channel, nick);
361
362 nick = strtok(NULL, " ");
363 }
364#endif
85ce9d3e 365 } else {
9f8c2acc 366 #ifdef DEBUGMODE
367 log("Unrecognized Message: cmd = %s source = %s", cmd, source);
368 #endif
85ce9d3e 369 }
370 }
4dde2ed9 371
372 end:
373
c8ada07e 374 save_gs_dbase();
abbfcdb9 375 save_day();
4dde2ed9 376
c8ada07e 377 delete_monsters();
378 delete_masters();
379
9f8c2acc 380 #ifdef DEBUGMODE
381 log("<CLOSED>");
382 #endif
383
85ce9d3e 384 close(sock);
385 unload_config_file();
386 return 0;
387}
388
389aClient *find(char *nick)
390{
391 return findbynick(nick);
392}
393
394aClient *find(const char *nick)
395{
396 return findbynick(nick);
397}
398
ce61cdfa 399#ifdef P10
400
401aClient *findbyrealnick(char *realnick)
402{
403 ListNode <aClient> *newPtr;
404 newPtr = clients.First();
405
406 aClient *client = NULL;
407
408 while (newPtr)
409 {
410 client = newPtr->getData();
411 if (stricmp(client->getRealNick(), realnick) == 0)
412 return client;
413 client = NULL;
414 newPtr = newPtr->Next();
415 }
416 return client;
417}
4e5760fd 418
419#else
420
421aClient *findbyrealnick(char *realnick)
422{
423 return findbynick(realnick);
424}
425
ce61cdfa 426#endif
85ce9d3e 427
428aClient *findbynick(char *nick)
429{
430 ListNode <aClient> *newPtr;
431 newPtr = clients.First();
432
433 aClient *client = NULL;
434
435 while (newPtr)
436 {
437 client = newPtr->getData();
23ec3ff4 438 #ifdef P10
23ec3ff4 439 if (strcmp(client->getNick(), nick) == 0)
440 #else
441 if (stricmp(client->getNick(), nick) == 0)
442 #endif
85ce9d3e 443 return client;
444 client = NULL;
445 newPtr = newPtr->Next();
446 }
447 return client;
448}
449
ee38284f 450aClient *findIRCplayer(const char *nick)
451{
452 ListNode <aClient> *newPtr;
453 aClient *p = NULL;
454
455 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
456 {
457 p = newPtr->getData();
23ec3ff4 458 #ifdef P10
459 if (strcmp(p->getNick(), nick) == 0)
460 #else
461 if (stricmp(p->getNick(), nick) == 0)
462 #endif
ee38284f 463 return p;
464 p = NULL;
465 }
466 return NULL;
467}
0a1518fa 468aClient *findplayer(const char *name)
469{
470 ListNode <aClient> *newPtr;
471 Player *p = NULL;
472
473 for (newPtr = players.First(); newPtr; newPtr = newPtr->Next())
474 {
475 p = newPtr->getData()->stats;
476 if (stricmp(p->name, name) == 0)
477 return newPtr->getData();
478 p = NULL;
479 }
480 return NULL;
481}
482
85ce9d3e 483aClient *findbynick(const char *nick)
484{
485 ListNode <aClient> *newPtr;
486 newPtr = clients.First();
487
488 aClient *client = NULL;
489
490 while (newPtr)
491 {
492 client = newPtr->getData();
23ec3ff4 493 #ifdef P10
494 if (strcmp(client->getNick(), nick) == 0)
495 #else
496 if (stricmp(client->getNick(), nick) == 0)
497 #endif
85ce9d3e 498 return client;
499 client = NULL;
500 newPtr = newPtr->Next();
501 }
502 return client;
503}
504
abbfcdb9 505void load_day()
44ea29f7 506{
507 ifstream infile;
508
abbfcdb9 509 infile.open(".gsday");
44ea29f7 510
511 if (infile.fail())
512 {
9f8c2acc 513 #ifdef DEBUGMODE
abbfcdb9 514 log("Error opening .gsday");
9f8c2acc 515 #endif
516
44ea29f7 517 generate:
9f8c2acc 518 #ifdef DEBUGMODE
abbfcdb9 519 log("Generating new day");
9f8c2acc 520 #endif
abbfcdb9 521 struct tm *tm;
522 time_t ti;
523 time(&ti);
524 tm = localtime(&ti);
525
526 day = tm->tm_mday;
527
528 save_day();
44ea29f7 529 return;
530 }
531
abbfcdb9 532 infile >> day;
44ea29f7 533 infile.close();
abbfcdb9 534 if (day < 1 || day > 31)
44ea29f7 535 goto generate;
536}
537
abbfcdb9 538void save_day()
44ea29f7 539{
540 ofstream outfile;
541
abbfcdb9 542 outfile.open(".gsday");
44ea29f7 543
544 if (outfile.fail())
545 {
abbfcdb9 546 log("Error creating new file .gsday");
44ea29f7 547 return;
548 }
549
abbfcdb9 550 outfile << day << endl;
44ea29f7 551
552 outfile.close();
553}
554
ce61cdfa 555/* daemon() - detach process from user and disappear into the background
556 * returns -1 on failure, but you can't do much except exit in that case
557 * since we may already have forked. This is based on the BSD version,
558 * so the caller is responsible for things like the umask, etc.
559 */
560
561/* believed to work on all Posix systems */
562
563int daemon(int nochdir, int noclose)
564{
565 pid_t pid;
566 switch (pid = fork())
567 {
568 case 0: break;
569 case -1: return -1;
570 default: _exit(0); /* exit the original process */
571 }
572
573 if (setsid() < 0) /* shoudn't fail */
574 return -1;
575
576 /* dyke out this switch if you want to acquire a control tty in */
577 /* the future -- not normally advisable for daemons */
578
579 switch (pid = fork())
580 {
581 case 0: break;
582 case -1: return -1;
583 default:
584 ofstream outfile;
585 outfile.open("gameserv.pid");
586 if (outfile.fail())
587 cerr << "Unable to open gameserv.pid" << endl;
588 outfile << pid << endl;
589 outfile.close();
590
591 _exit(0);
592 }
593
594 if (!nochdir)
595 chdir("/");
596
597 if (!noclose)
598 {
599 closeall(0);
600 open("/dev/null",O_RDWR);
601 dup(0); dup(0);
602 }
603
604 return 0;
605}
606
607
608/* closeall() -- close all FDs >= a specified value */
609
610void closeall(int fd)
611{
612 int fdlimit = sysconf(_SC_OPEN_MAX);
613
614 while (fd < fdlimit)
615 close(fd++);
616}
617
15838737 618void prettyIntro()
619{
620cout << endl;
621cout << " GGGG AAA MM MM EEEEEEE SSSSS EEEEEEE RRRRRR VV VV " << endl;
622cout << " GG GG AAAAA MMM MMM EE SS EE RR RR VV VV " << endl;
623cout << "GG AA AA MM MM MM EEEEE SSSSS EEEEE RRRRRR VV VV " << endl;
624cout << "GG GGG AAAAAAA MM MM EE SS EE RR RR VV VV " << endl;
625cout << "G G AA AA MM MM EEEEEEE SSSSS EEEEEEE RR RR VVV" << endl;
626cout << " GGGGG V\n\n" << endl;
627cout << "Version: " << VERSION << endl;
628}