]>
jfr.im git - irc/gameservirc.git/blob - gameserv/tcpclient.cpp
e421b2c31331d379a3d82d9b59acb91e19f286f2
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>
37 char *PACKAGE
= "GameServ";
38 char *VERSION
= "1.2.4 +devel";
43 List
<aClient
> clients
[U_TABLE_SIZE
];
45 void save_lastrefresh();
46 void load_lastrefresh();
51 int daemon(int nochdir
, int noclose
);
53 // Close all file descriptors from >= fd
54 void closeall(int fd
);
56 int main(int argc
, char *argv
[])
58 char buffer
[1024], buf
[1024];
59 memset(buffer
, 0, 1024);
63 char *cmd
, *source
= NULL
, *conf
;
66 strcpy(conf
, "gameserv.conf");
69 * This needs to be fixed to work for any number of arguments in any
75 if ( argc
> 2 || stricmp(argv
[1], "--help") == 0)
77 cout
<< "Usage: gameserv [options] [configfile]" << endl
;
78 cout
<< "Options:" << endl
;
79 cout
<< "--help Displays this help dialogue" << endl
;
88 if (load_config_file(conf
))
90 cout
<< "Config file loaded ok...\n"
91 << "Turning into a daemon" << endl
;
102 perror("Could not turn into a daemon");
108 loadNews(newsdata
, todaysnews
);
110 if (load_monsters() == false)
112 log("Error loading monsters");
116 if (load_levels() == false)
118 log("Error loading levels");
122 shuttingdown
= false;
124 char ignoreservers
[32][256];
126 currentserver
= strtok(ignoreserverslist
, " ");
127 for (int server
= 0; server
< 32 && currentserver
!= NULL
; server
++)
129 strncpy(ignoreservers
[server
], currentserver
, 255);
130 log("Placing %s on the server ignore list", currentserver
);
131 currentserver
= strtok(NULL
, " ");
134 strcpy(boss
.name
, "Red Dragon");
135 strcpy(boss
.weapon
, "Breath of Unholy Fire");
136 boss
.strength
= 2500;
137 boss
.gold
= 2000000000;
138 boss
.exp
= 2000000000;
141 strcpy(boss
.death
, "You finally snuff out the deadly murderous "\
142 "dragon's dark flames. You have freed the land of its terror "\
143 "filled reign from above!");
146 // This loop will retry the connection 3 times
147 for (int retry
= 0; retry
< 3 && !shuttingdown
; retry
++)
153 long int loadtime
= time(NULL
);
154 long int currentTime
;
155 long int oldTime
= loadtime
;
157 lastidlecheck
= loadtime
;
160 log("Setting primary Idle Check timestamp: %ld", lastidlecheck
);
165 sock
= make_connection(remoteport
, SOCK_STREAM
, remoteserver
);
167 fprintf(stderr
,"make_connection failed.\n");
168 unload_config_file();
171 log("%S socket connected.");
174 raw("PROTOCTL NICKv2 VHP");
175 raw("PASS :%s", remotepass
);
176 raw("SERVER %s 1 :%s", servername
, servername
);
177 raw("NICK %S 1 %d %S %s %s %d +w%s %s :%s v%s", time(NULL
), gshost
,
178 servername
, time(NULL
), (isBOper() ? "o" : ""), gshost
, PACKAGE
, VERSION
);
179 raw(":%S JOIN %s", c_Forest
);
180 raw(":%S MODE %s +tn", c_Forest
);
181 #elif defined(BAHAMUT)
182 raw("PASS %s :TS", remotepass
);
183 raw("SERVER %s 1 :%s", servername
, servername
);
184 raw("NICK %S 1 %d +w%s %s %s %s 0 :GameServ", time(NULL
), (isBOper() ? "o" : ""),
185 gsident
, gshost
, servername
);
186 raw(":%s SJOIN %d %d %s +nt :@%S", servername
, time(NULL
), time(NULL
), c_Forest
);
187 #elif defined(HYBRID)
188 raw("PASS %s :TS", remotepass
);
189 raw("SERVER %s 1 :%s", servername
, servername
);
190 raw("NICK %S 1 %d +w%s %s %s %s :GameServ", time(NULL
), (isBOper() ? "o" : ""),
191 gsident
, gshost
, servername
);
192 raw(":%s SJOIN %ld %s +nt :@%S", servername
, time(NULL
), c_Forest
);
193 #elif defined(ULTIMATE2)
194 raw("PASS %s :TS", remotepass
);
195 raw("SERVER %s 1 :%s", servername
, servername
);
196 raw("NICK %S 1 %d %s %s %s 0 :GameServ",
197 time(NULL
), gsident
, gshost
, servername
);
199 raw(":%S mode %S +o");
200 raw(":%S JOIN %s", c_Forest
);
202 // Server numeric is: [] <-- must be unique
203 raw("PASS :%s", remotepass
);
204 raw("SERVER %s 1 %d %d P10 []AAF :%s", servername
, time(NULL
), time(NULL
), servername
);
205 raw("[] N %S 1 %d %s %s %s DAqAoB %s :%S", time(NULL
), gsident
, gshost
,
206 (isBOper() ? "+o" : ""), gsnum
);
207 raw("[] B %s %d +tn %s:o", c_Forest
, time(NULL
) - 864000, gsnum
);
211 raw("%s T %s :%s", gsnum
, c_Forest
, c_ForestTopic
);
212 raw("[] EB"); // End burst
215 #if defined(ULTIMATE2)
216 raw(":%s MODE %s +o %S %ld", servername
, c_Forest
,
219 raw(":%S MODE %s +o %S", c_Forest
);
222 raw(":%S TOPIC %s :%s", c_Forest
, c_ForestTopic
);
225 sock_gets(sock
,buffer
,sizeof(buffer
)-1); /* -1 added thanks to
226 David Duchene <dave@ltd.com> for pointing out the possible
227 buffer overflow resulting from the linefeed added below. */
231 log("Server: %s",buffer
);
235 if (sock_gets(sock
,buffer
,sizeof(buffer
)) == -1) {
241 if (buffer
[0] == ':')
243 source
= strtok(buf
, " ");
244 cmd
= strtok(NULL
, " ");
247 cmd
= strtok(buf
, " ");
249 source
= strtok(buf
, " ");
250 cmd
= strtok(NULL
, " ");
254 log("Server: %s", buffer
);
257 // Wait N seconds then we're loaded.
260 if (time(NULL
) >= welcomedelay
+ loadtime
)
263 retry
= 0; // Start the reconnection cycle over
268 long TIME
= time(NULL
);
269 if (TIME
- lastidlecheck
>= idlecheckperiod
)
272 lastidlecheck
= TIME
;
276 // Refresh players and clear news if the time is up
277 currentTime
= time(NULL
);
278 if (currentTime
- lastrefresh
>= refreshperiod
)
281 clearNews(todaysnews
);
282 saveNews(newsdata
, todaysnews
);
283 lastrefresh
= currentTime
;
285 notice(s_GameServ
, c_Forest
, "Refreshing all players "\
286 "and resetting news!");
289 // Save the player data every updateperiod seconds
290 currentTime
= time(NULL
);
291 if (currentTime
- oldTime
>= updateperiod
)
293 oldTime
= currentTime
;
294 log("Saving to %s", playerdata
);
297 saveNews(newsdata
, todaysnews
);
298 // Send notice to the channel of the update
299 notice(s_GameServ
, c_Forest
, "%S player data saved");
304 if (stricmp(cmd
, "PING") == 0) {
306 timestamp
= strtok(NULL
, "");
307 raw("PONG %s", timestamp
);
309 if (stricmp(cmd
, "G") == 0) {
311 timestamp
= strtok(NULL
, " ");
312 raw("[] Z [] %s 0 %s", timestamp
+ 1, timestamp
);
315 } else if (stricmp(cmd
, "EB") == 0) {
318 } else if (stricmp(cmd
, "VERSION") == 0) {
320 server
= strtok(NULL
, " ");
322 raw(":%s 351 %s %s_%s. %s", servername
, source
+1, PACKAGE
, VERSION
, servername
);
324 } else if (strncmp(cmd
, "NICK", 4) == 0) {
325 if (buffer
[0] == ':')
328 if ((tempPtr
= find((source
+ 1))))
331 unsigned long oldhv
, newhv
;
332 nick
= strtok(NULL
, " ");
333 oldhv
= iHASH((unsigned char *) tempPtr
->getNick());
334 newhv
= iHASH((unsigned char *) nick
);
335 tempPtr
->setNick(nick
);
336 clients
[oldhv
].remove(tempPtr
);
337 clients
[newhv
].insertAtBack(tempPtr
);
344 } else if (stricmp(cmd
, "N") == 0 && strlen(source
) == 2) {
346 char *nick
, *realnick
;
347 realnick
= strtok(NULL
, " ");
349 for (int x
= 0; x
< 5; x
++)
350 nick
= strtok(NULL
, " ");
355 log ("aClient has modes");
358 // Searching for the +r mode (extra parameter)
359 for (unsigned int count
= 1; count
< strlen(nick
); count
++)
361 if (nick
[count
] == 'r')
363 nick
= strtok(NULL
, " ");
367 nick
= strtok(NULL
, " ");
370 aClient
*newuser
, *temp
;
372 nick
= strtok(NULL
, " ");
375 newuser
= new aClient(nick
, realnick
);
377 newuser
= new aClient(nick
);
386 notice(s_GameServ
, nick
, welcomemsg
, realnick
);
388 notice(s_GameServ
, nick
, welcomemsg
, nick
);
392 unsigned long hv
= sHASH((unsigned char *) nick
);
394 unsigned long hv
= iHASH((unsigned char *) nick
);
397 temp
= clients
[hv
].insertAtBack(newuser
);
399 #if defined(HYBRID) || defined(BAHAMUT) || defined(ULTIMATE2)
403 nickserver
= strtok(NULL
, " ");
404 if (nickserver
[0] == '+')
407 nickserver
= strtok(NULL
, " ");
408 for (int x
= 0; x
< 32; x
++)
410 if (stricmp(ignoreservers
[x
], nickserver
) == 0)
416 #elif defined(UNREAL)
422 nickserver
= strtok(NULL
, " ");
423 for (int x
= 0; x
< 32; x
++)
425 if (stricmp(ignoreservers
[x
], nickserver
) == 0)
435 } else if (stricmp(cmd
, "Q") == 0) {
436 // unsigned long hv = sHASH((unsigned char *) source);
438 } else if (stricmp(cmd
, "QUIT") == 0) {
439 // unsigned long hv = iHASH((unsigned char *) source);
447 if (!(quitter
= find(source
)))
449 log("Fatal Error: could not find %s in the "\
450 "clients list", source
);
459 /* Attempting to use the logout() function
460 if ((quitter = find(source)))
461 clients[hv].remove(quitter);
462 if ((quitter = findIRCplayer(source)))
464 if (player_fight(quitter))
466 // Stop the fight on the other client
467 aClient *otherplayer = quitter->stats->battle;
468 otherplayer->stats->battle = NULL;
469 notice(s_GameServ, otherplayer->getNick(), "%s "\
470 "has quit IRC. The fight stops here.",
471 quitter->stats->name);
473 quitter->stats->battle = NULL;
474 quitter->stats->fight = NULL;
475 quitter->stats->master = NULL;
477 quitter->setNick("Not Playing");
479 quitter->setRealNick("Not Playing");
481 quitter->stats->client = NULL; // Unidentify them
486 } else if (stricmp(cmd
, "P") == 0) {
489 longname
= new char[strlen(s_GameServ
) + strlen(servername
) + 2];
491 sprintf(longname
, "%S@%s", servername
);
493 dest
= strtok(NULL
, " ");
494 rest
= strtok(NULL
, "");
495 if (stricmp(dest
, gsnum
) == 0 || stricmp(dest
, longname
) == 0)
498 gameserv(source
, rest
);
500 else if (stricmp(dest
, c_Forest
) == 0 && isListenOnCF())
503 forest(source
, rest
);
506 } else if (stricmp(cmd
, "PRIVMSG") == 0) {
508 dest
= strtok(NULL
, " ");
509 rest
= strtok(NULL
, "");
510 if (strnicmp(dest
, s_GameServ
, strlen(s_GameServ
)) == 0)
511 gameserv(source
, rest
);
512 else if (stricmp(dest
, c_Forest
) == 0 && isListenOnCF())
513 forest(source
, rest
);
516 } else if (stricmp(cmd
, "J") == 0) {
518 } else if (stricmp(cmd
, "JOIN") == 0) {
522 channel
= strtok(NULL
, " ");
529 joiner
= find(source
);
531 if (stricmp(channel
, c_Forest
) == 0 && is_playing(joiner
))
534 log("Player %s (IRC: %s) joined %s",
537 joiner
->getRealNick(),
543 raw(":%S MODE %s +v %s", c_Forest
, (source
));
550 } else if (stricmp(cmd
, "SJOIN") == 0) {
551 char *channel
, *nick
, *tmp
, *rest
;
552 strtok(NULL
, " "); // Ignore the TS
554 strtok(NULL
, " "); // Ignore the TS
556 channel
= strtok(NULL
, " ");
557 rest
= strtok(NULL
, "");
558 tmp
= strchr(rest
, ':');
560 nick
= strtok(tmp
, " ");
566 nick
++; // Assume for users set op and voice, they
567 // are never passed as +@nick
568 if (stricmp(channel
, c_Forest
) == 0 && is_playing(nick
))
569 raw(":%S MODE %s +v %s", channel
, nick
);
571 nick
= strtok(NULL
, " ");
576 log("Unrecognized Message: cmd = %s source = %s", cmd
, source
);
581 } // for loop for connection retry
586 saveNews(newsdata
, todaysnews
);
596 unload_config_file();
600 aClient
*find(char *nick
)
602 return findbynick(nick
);
605 aClient
*find(const char *nick
)
607 return findbynick(nick
);
612 aClient
*findbyrealnick(char *realnick
)
614 ListNode
<aClient
> *newPtr
;
615 unsigned long hv
= sHASH((unsigned char *) realnick
);
616 newPtr
= clients
[hv
].First();
618 aClient
*client
= NULL
;
622 client
= newPtr
->getData();
623 if (stricmp(client
->getRealNick(), realnick
) == 0)
626 newPtr
= newPtr
->Next();
633 aClient
*findbyrealnick(char *realnick
)
635 return findbynick(realnick
);
640 aClient
*findbynick(char *nick
)
642 ListNode
<aClient
> *newPtr
;
644 unsigned long hv
= sHASH((unsigned char *) nick
);
646 unsigned long hv
= iHASH((unsigned char *) nick
);
649 newPtr
= clients
[hv
].First();
651 aClient
*client
= NULL
;
655 client
= newPtr
->getData();
657 if (strcmp(client
->getNick(), nick
) == 0)
659 if (stricmp(client
->getNick(), nick
) == 0)
663 newPtr
= newPtr
->Next();
668 aClient
*findIRCplayer(const char *nick
)
670 ListNode
<aClient
> *newPtr
;
678 unsigned long hv
= iHASH((unsigned char *) p
->stats
->name
);
680 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
682 p
= newPtr
->getData();
684 if (strcmp(p
->getNick(), nick
) == 0)
686 if (stricmp(p
->getNick(), nick
) == 0)
694 aClient
*findplayer(const char *name
)
696 ListNode
<aClient
> *newPtr
;
698 unsigned long hv
= iHASH((unsigned char *) name
);
699 for (newPtr
= players
[hv
].First(); newPtr
; newPtr
= newPtr
->Next())
701 p
= newPtr
->getData()->stats
;
702 if (stricmp(p
->name
, name
) == 0)
703 return newPtr
->getData();
711 ListNode
<aClient
> *newPtr
;
714 for (int x
= 0; x
< U_TABLE_SIZE
; x
++)
716 for (newPtr
= players
[x
].First(); newPtr
; newPtr
= newPtr
->Next())
718 p
= newPtr
->getData()->stats
;
722 if ((time(NULL
) - p
->lastlogin
) / 86400 >= level1expire
)
724 logout(newPtr
->getData());
725 players
[x
].remove(newPtr
->getData());
731 if ((time(NULL
) - p
->lastlogin
) / 86400 >= defaultexpire
)
733 logout(newPtr
->getData());
734 players
[x
].remove(newPtr
->getData());
747 aClient
*findbynick(const char *nick
)
749 ListNode
<aClient
> *newPtr
;
751 unsigned long hv
= sHASH((unsigned char *) nick
);
753 unsigned long hv
= iHASH((unsigned char *) nick
);
756 newPtr
= clients
[hv
].First();
758 aClient
*client
= NULL
;
762 client
= newPtr
->getData();
764 if (strcmp(client
->getNick(), nick
) == 0)
766 if (stricmp(client
->getNick(), nick
) == 0)
770 newPtr
= newPtr
->Next();
775 /* daemon() - detach process from user and disappear into the background
776 * returns -1 on failure, but you can't do much except exit in that case
777 * since we may already have forked. This is based on the BSD version,
778 * so the caller is responsible for things like the umask, etc.
781 /* believed to work on all Posix systems */
783 int daemon(int nochdir
, int noclose
)
786 switch (pid
= fork())
790 default: _exit(0); /* exit the original process */
793 if (setsid() < 0) /* shoudn't fail */
796 /* dyke out this switch if you want to acquire a control tty in */
797 /* the future -- not normally advisable for daemons */
799 switch (pid
= fork())
805 outfile
.open(pidfile
);
807 cerr
<< "Unable to open " << pidfile
<< endl
;
808 outfile
<< pid
<< endl
;
820 open("/dev/null",O_RDWR
);
828 /* closeall() -- close all FDs >= a specified value */
830 void closeall(int fd
)
832 int fdlimit
= sysconf(_SC_OPEN_MAX
);
841 cout
<< " GGGG AAA MM MM EEEEEEE SSSSS EEEEEEE RRRRRR VV VV " << endl
;
842 cout
<< " GG GG AAAAA MMM MMM EE SS EE RR RR VV VV " << endl
;
843 cout
<< "GG AA AA MM MM MM EEEEE SSSSS EEEEE RRRRRR VV VV " << endl
;
844 cout
<< "GG GGG AAAAAAA MM MM EE SS EE RR RR VV VV " << endl
;
845 cout
<< "G G AA AA MM MM EEEEEEE SSSSS EEEEEEE RR RR VVV" << endl
;
846 cout
<< " GGGGG V\n\n" << endl
;
847 cout
<< "Version: " << VERSION
<< endl
;
850 void load_lastrefresh()
853 infile
.open(".gsrefresh");
857 log("Error opening .gsrefresh");
861 long mytime
= time(NULL
);
863 log("Generating new refresh time");
866 // Just a safety measure... tho no one should
867 // get anywhere near the time as their refreshperiod
868 if (refreshperiod
>= mytime
)
869 refreshperiod
= 86400;
871 lastrefresh
= mytime
- (mytime
% refreshperiod
);
876 infile
>> lastrefresh
;
882 void save_lastrefresh()
886 outfile
.open(".gsrefresh");
890 log("Error creating new file .gsrefresh");
893 outfile
<< lastrefresh
<< endl
;