1 /* experimental code - evileye */
2 /* this does not necessarily follow any sensible design */
3
4 /* added this for consistency in some (unrelated) header-inclusion,
5 it IS a server file, isn't it? */
6 #define SERVER
7 #include "angband.h"
8
9 #ifdef TOMENET_WORLDS
10
11 #include <sys/types.h>
12 #include <sys/socket.h>
13
14 #include "../world/world.h"
15
16 /* pfft. i'll use generic lists when i get around to it */
17 struct svlist{
18 struct svlist *next;
19 uint16_t sid;
20 char name[30];
21 };
22
23 struct list *rpmlist = NULL;
24 struct list *svlist = NULL;
25
26 struct wpacket spk;
27
28 uint32_t chk(char *s1, char *s2);
29 void rem_server(int16_t id);
30 void add_rplayer(struct wpacket *wpk);
31 void add_server(struct sinfo *sinfo);
32 bool world_check_ignore(int Ind, uint32_t id, int16_t server);
33 void world_update_players(void);
34 int world_find_server(char *pname);
35 void world_msg(char *text);
36 struct list *addlist(struct list **head, int dsize);
37 struct list *remlist(struct list **head, struct list *dlp);
38 void world_reboot();
39
40 /* Generic list handling function */
addlist(struct list ** head,int dsize)41 struct list *addlist(struct list **head, int dsize) {
42 struct list *newlp;
43 newlp = malloc(sizeof(struct list));
44 if (newlp) {
45 newlp->data = malloc(dsize);
46 if (newlp->data != NULL) {
47 newlp->next = *head;
48 *head = newlp;
49 return(newlp);
50 }
51 free(newlp);
52 }
53 return(NULL);
54 }
55
56 /* Generic list handling function */
remlist(struct list ** head,struct list * dlp)57 struct list *remlist(struct list **head, struct list *dlp){
58 struct list *lp;
59 lp = *head;
60 if (!lp || !dlp) return(NULL);
61 if (dlp == *head) {
62 *head = lp->next;
63 free(dlp->data);
64 free(dlp);
65 return(*head);
66 }
67 while (lp) {
68 if (lp->next == dlp) {
69 lp->next = dlp->next;
70 free(dlp->data);
71 free(dlp);
72 return(lp->next);
73 }
74 lp = lp->next;
75 }
76 return(dlp->next);
77 }
78
world_update_players()79 void world_update_players(){
80 int i;
81 for (i = 1; i <= NumPlayers; i++) {
82 if(Players[i]->conn != NOT_CONNECTED){
83 if (!Players[i]->admin_dm)
84 world_player(Players[i]->id, Players[i]->name, 1, 0);
85 }
86 }
87 }
88
world_check_ignore(int Ind,uint32_t id,int16_t server)89 bool world_check_ignore(int Ind, uint32_t id, int16_t server) {
90 struct remote_ignore *curr;
91 curr = Players[Ind]->w_ignore;
92 while (curr) {
93 if (curr->serverid == server && curr->id == id)
94 return(TRUE);
95 curr = curr->next;
96 }
97 return(FALSE);
98 }
99
world_comm(int fd,int arg)100 void world_comm(int fd, int arg) {
101 static char buffer[1024], msg[MSG_LEN], *msg_ptr, *wmsg_ptr, *wmsg_ptr2;
102 char cbuf[sizeof(struct wpacket)], *p;
103 static short bpos = 0;
104 static short blen = 0;
105 int x, i;
106 struct wpacket *wpk;
107 x = recv(fd, buffer + (bpos + blen), 1024 - (bpos + blen), 0);
108 if (x == 0) {
109 //struct rplist *c_pl, *n_pl;
110 /* This happens... we are screwed (fortunately SIGPIPE isnt handled) */
111 s_printf("pfft. world server closed\n");
112 remove_input(WorldSocket);
113 close(WorldSocket); /* ;) this'll fix it... */
114 /* Clear all the world players quietly */
115 while(remlist(&rpmlist, rpmlist));
116 #if 0
117 c_pl = rpmlist;
118 while (c_pl) {
119 n_pl = c_pl->next;
120 free(c_pl);
121 c_pl = n_pl;
122 }
123 rpmlist = NULL;
124 #endif
125 WorldSocket = -1;
126 }
127 blen += x;
128 while (blen >= sizeof(struct wpacket)) {
129 wpk = (struct wpacket*)(buffer + bpos);
130 switch (wpk->type) {
131 case WP_SINFO:
132 /* Server login information */
133 add_server(&wpk->d.sinfo);
134 break;
135 case WP_CHAT:
136 /* TEMPORARY chat broadcast method */
137 /* strip special chat codes \374/5/6 before testing prefix() */
138 p = wpk->d.chat.ctxt;
139 if (*p == '\374') p++;
140 else if (*p == '\375') p++;
141 if (*p == '\376') p++;
142
143 #if 0 /* see #else below */
144 if (!(cfg.worldd_pubchat || (cfg.worldd_broadcast && prefix(p, "\377r[\377"))))
145 break; /* Filter incoming public chat and broadcasts here now - mikaelh */
146 #else /* Consistency: Let world's 'server' flags decide about filtering our incoming messages */
147 #endif
148
149 for (i = 1; i <= NumPlayers; i++) {
150 if (Players[i]->conn != NOT_CONNECTED) {
151 /* lame method just now */
152 if (world_check_ignore(i, wpk->d.chat.id, wpk->serverid))
153 continue;
154 msg_print(i, wpk->d.chat.ctxt);
155 }
156 }
157
158 #if 1
159 /* log */
160 wmsg_ptr = wpk->d.chat.ctxt;
161 /* strip \374,\375,\376 */
162 while (*wmsg_ptr >= '\374' && *wmsg_ptr < '\377') wmsg_ptr++;
163 strcpy(msg, wmsg_ptr);
164 /* strip next colour code */
165 wmsg_ptr = strchr(wmsg_ptr, '\377') + 2;
166 msg_ptr = strchr(msg, '\377');
167 strcpy(msg_ptr, wmsg_ptr);
168 /* strip next colour code */
169 wmsg_ptr = strchr(wmsg_ptr, '\377') + 2;
170 msg_ptr = strchr(msg, '\377');
171 strcpy(msg_ptr, wmsg_ptr);
172 /* strip next colour code if at the beginning of the actual message line */
173 if (*(wmsg_ptr + 1) == '\377') {
174 strcpy(msg_ptr + 1, wmsg_ptr + 3);
175 /* strip next colour code if existing */
176 if ((wmsg_ptr = strchr(wmsg_ptr + 3, '\377'))
177 /* not in /me though: ']' check */
178 && (wmsg_ptr2 = strchr(wpk->d.chat.ctxt + 9, ']')) && wmsg_ptr2 < wmsg_ptr) {
179 msg_ptr = strchr(msg + 1, '\377');
180 strcpy(msg_ptr, wmsg_ptr + 2);
181 }
182 }
183 s_printf("%s\n", msg);
184 #endif
185 break;
186 case WP_PMSG:
187 /* private message from afar -authed */
188 for (i = 1; i <= NumPlayers; i++) {
189 if (!strcmp(Players[i]->name, wpk->d.pmsg.victim)) {
190 if (!world_check_ignore(i, wpk->d.pmsg.id, wpk->serverid)) {
191 msg_format(i, "\375\377s[%s:%s] %s", wpk->d.pmsg.player, Players[i]->name, wpk->d.pmsg.ctxt);
192 /* Remember sender for quick replying */
193 strcpy(Players[i]->reply_name, wpk->d.pmsg.player);
194 }
195 }
196 }
197 break;
198 case WP_MESSAGE:
199 /* A raw message - no data */
200 msg_broadcast_format(0, "%s", wpk->d.smsg.stxt);
201
202 #if 1
203 /* log */
204 wmsg_ptr = wpk->d.smsg.stxt;
205 /* strip \374,\375,\376 */
206 while (*wmsg_ptr >= '\374' && *wmsg_ptr < '\377') wmsg_ptr++;
207 strcpy(msg, wmsg_ptr);
208 /* strip next colour code */
209 wmsg_ptr = strchr(wmsg_ptr, '\377') + 2;
210 msg_ptr = strchr(msg, '\377');
211 strcpy(msg_ptr, wmsg_ptr);
212 /* strip next colour code */
213 wmsg_ptr = strchr(wmsg_ptr, '\377') + 2;
214 msg_ptr = strchr(msg, '\377');
215 strcpy(msg_ptr, wmsg_ptr);
216 /* strip next colour code if at the beginning of the actual message line */
217 if (*(wmsg_ptr + 1) == '\377')
218 strcpy(msg_ptr + 1, wmsg_ptr + 3);
219 s_printf("%s\n", msg);
220 #endif
221 break;
222 case WP_NPLAYER:
223 case WP_QPLAYER:
224 /* we need to handle a list */
225 /* full death must count! */
226 add_rplayer(wpk);
227 break;
228 case WP_AUTH:
229 /* Authentication request */
230 wpk->d.auth.val = chk(cfg.pass, wpk->d.auth.pass);
231 x = sizeof(struct wpacket);
232 x = send(WorldSocket, wpk, x, 0);
233 world_update_players();
234 break;
235 case WP_SQUIT:
236 /* Remove players */
237 rem_server(wpk->d.sid);
238 break;
239 case WP_RESTART:
240 set_runlevel(0);
241 break;
242 case WP_IRCCHAT:
243 #if 1
244 /* Allow certain status commands from IRC to TomeNET server */
245 if ((p = strchr(wpk->d.chat.ctxt, ']')) && *(p += 2) == '?') {
246 /* list number + character names of players online */
247 if (!strncmp(p, "?players", 8)) {
248 char buf[MSG_LEN];
249 strcpy(buf, " 0 Players: ");
250 x = 0;
251 for (i = 1; i <= NumPlayers; i++) {
252 if (Players[i]->conn == NOT_CONNECTED) continue;
253 if (Players[i]->admin_dm && cfg.secret_dungeon_master) continue;
254
255 x++;
256 if (strlen(buf) + strlen(Players[i]->name) + 2 >= MSG_LEN - 20) continue; /* paranoia reserved */
257 if (x != 1) strcat(buf, ", ");
258 strcat(buf, Players[i]->name);
259 strcat(buf, " (");
260 strcat(buf, Players[i]->accountname);
261 strcat(buf, ")");
262 }
263 if (!x) strcpy(buf, "No players online");
264 else {
265 if (x >= 10) buf[0] = '0' + x / 10;
266 buf[1] = '0' + x % 10;
267 }
268 if (x == 1) buf[9] = ' '; /* Player_s_ */
269 msg_to_irc(buf);
270 break;
271 }
272 else if (!strncmp(p, "?seen", 5)) {
273 char buf[MSG_LEN];
274 get_laston(p + 5 + 1, buf, FALSE);
275 msg_to_irc(buf);
276 break;
277 }
278 }
279 #endif
280
281 #if 0 /* 0ed for consistency: Let world's 'server' flags decide about filtering our incoming messages */
282 if (!cfg.worldd_ircchat) break;
283 #endif
284
285 for (i = 1; i <= NumPlayers; i++) {
286 if (Players[i]->conn == NOT_CONNECTED) continue;
287 if (Players[i]->ignoring_chat) continue;
288 msg_print(i, wpk->d.chat.ctxt);
289 }
290
291 #if 1
292 /* log */
293 strcpy(msg, "[IRC]");
294 wmsg_ptr = wpk->d.chat.ctxt;
295 /* strip \374,\375,\376 */
296 while (*wmsg_ptr >= '\374' && *wmsg_ptr < '\377') wmsg_ptr++;
297 wmsg_ptr += 10;
298 strcat(msg, wmsg_ptr);
299 /* strip next colour code */
300 wmsg_ptr = strchr(wmsg_ptr, '\377') + 2;
301 msg_ptr = strchr(msg, '\377');
302 strcpy(msg_ptr, wmsg_ptr);
303 /* done */
304 s_printf("%s\n", msg);
305 #endif
306 break;
307 default:
308 s_printf("unknown packet from world: %d\n", wpk->type);
309 }
310 /* update buffer position and remaining data size */
311 bpos += sizeof(struct wpacket);
312 blen -= sizeof(struct wpacket);
313 }
314 if (blen) {
315 /* copy it back */
316 memcpy(cbuf, buffer + bpos, blen);
317 memcpy(buffer, cbuf, blen);
318 }
319 bpos = 0;
320 }
321
322 /* returns authed server id or 0 */
world_find_server(char * pname)323 int world_find_server(char *pname) {
324 struct list *lp;
325 struct rplist *c_pl;
326 lp = rpmlist;
327
328 while (lp) {
329 c_pl = (struct rplist*)lp->data;
330 if (!strcmp(c_pl->name, pname)) {
331 return(c_pl->server);
332 }
333 lp = lp->next;
334 }
335 return(0);
336 }
337
338 /* returns list entry, or NULL */
world_find_player(char * pname,int16_t server)339 struct rplist *world_find_player(char *pname, int16_t server) {
340 struct list *lp;
341 struct rplist *c_pl;
342 lp = rpmlist;
343
344 while (lp) {
345 c_pl = (struct rplist*)lp->data;
346 if (!stricmp(c_pl->name, pname) && (!server || server == c_pl->server)) {
347 return(c_pl);
348 }
349 lp = lp->next;
350 }
351 return(NULL);
352 }
353
354 /* proper data will come with merge.
355 Returns number of remote players. */
world_remote_players(FILE * fff)356 int world_remote_players(FILE *fff) {
357 int num = 0;
358 struct list *lp, *slp;
359 struct rplist *c_pl;
360 struct svlist *c_sv;
361 char servername[30];
362 lp = rpmlist;
363 if (lp) {
364 fprintf(fff, "\n\377y Remote players on different servers:\n\n");
365 }
366 while (lp) {
367 c_pl = (struct rplist*)lp->data;
368 slp = svlist;
369 sprintf(servername, "%d", c_pl->server);
370 while (slp) {
371 c_sv = (struct svlist*)slp->data;
372 if (c_sv->sid == c_pl->server) {
373 strncpy(servername, c_sv->name, 30);
374 break;
375 }
376 slp = slp->next;
377 }
378
379 // fprintf(fff, "\377%c %s\377s on '%s'\n", c_pl->server ? 'w' : 'W', c_pl->name, servername);
380 fprintf(fff, "\377s %s\377%c %s\n", servername, c_pl->server ? 'w' : 'W', c_pl->name);
381 num++;
382 lp = lp->next;
383 }
384 return (num);
385 }
386
387 /* When a server logs in, we get information about it */
add_server(struct sinfo * sinfo)388 void add_server(struct sinfo *sinfo) {
389 struct list *lp;
390 struct svlist *c_sr;
391 /*
392 c_sr = malloc(sizeof(struct svlist));
393 */
394 lp = addlist(&svlist, sizeof(struct svlist));
395 if (lp) {
396 c_sr = (struct svlist*)lp->data;
397 strncpy(c_sr->name, sinfo->name, 30);
398 c_sr->sid = sinfo->sid;
399 }
400 }
401
402 /* This is called when a remote server disconnects */
rem_server(int16_t id)403 void rem_server(int16_t id) {
404 struct rplist *c_pl;
405 struct svlist *c_sr;
406
407 struct list *lp;
408
409 /* remove all the old players */
410 lp = rpmlist;
411 while (lp) {
412 c_pl = (struct rplist*)lp->data;
413 if (c_pl->server == id) {
414 lp = remlist(&rpmlist, lp);
415 }
416 else lp = lp->next;
417 }
418
419 /* Delete the server info */
420 lp = svlist;
421 while (lp) {
422 c_sr = (struct svlist*)lp->data;
423 if (c_sr->sid == id) {
424 lp = remlist(&svlist, lp);
425 }
426 else lp = lp->next;
427 }
428 }
429
add_rplayer(struct wpacket * wpk)430 void add_rplayer(struct wpacket *wpk) {
431 struct list *lp;
432 struct rplist *n_pl, *c_pl;
433 unsigned char found = 0;
434 if (!wpk->d.play.silent)
435 msg_broadcast_format(0, "\374\377s%s has %s the game on another server.", wpk->d.play.name, (wpk->type == WP_NPLAYER ? "entered" : "left"));
436
437 if (wpk->type == WP_NPLAYER && !wpk->d.play.server) return;
438 lp = rpmlist;
439 while (lp) {
440 c_pl = (struct rplist*)lp->data;
441 // if (/* c_pl->id == wpk->d.play.id && */ !(strcmp(c_pl->name, wpk->d.play.name))) {
442 if (c_pl->server == wpk->d.play.server && !(strcmp(c_pl->name, wpk->d.play.name))) {
443 found = 1;
444 break;
445 }
446 lp = lp->next;
447 }
448 if (wpk->type == WP_NPLAYER && !found) {
449 lp = addlist(&rpmlist, sizeof(struct rplist));
450 if (lp) {
451 n_pl = (struct rplist*)lp->data;
452 n_pl->id = wpk->d.play.id;
453 n_pl->server = wpk->d.play.server;
454 strncpy(n_pl->name, wpk->d.play.name, 30);
455 }
456 }
457 else if (wpk->type == WP_QPLAYER && found)
458 remlist(&rpmlist, lp);
459 }
460
world_pmsg_send(uint32_t id,char * name,char * pname,char * text)461 void world_pmsg_send(uint32_t id, char *name, char *pname, char *text) {
462 int len;
463 if (WorldSocket == -1) return;
464 spk.type = WP_PMSG;
465 len = sizeof(struct wpacket);
466 snprintf(spk.d.pmsg.ctxt, MSG_LEN, "%s", text);
467 spk.d.pmsg.id = id;
468 spk.d.pmsg.sid = world_find_server(pname);
469 snprintf(spk.d.pmsg.player, 80, "%s", name);
470 snprintf(spk.d.pmsg.victim, 80, "%s", pname);
471 send(WorldSocket, &spk, len, 0);
472 }
473
world_chat(uint32_t id,char * text)474 void world_chat(uint32_t id, char *text) {
475 int len;
476 if (WorldSocket == -1) return;
477 spk.type = WP_CHAT;
478 len = sizeof(struct wpacket);
479 snprintf(spk.d.chat.ctxt, MSG_LEN, "%s", text);
480 spk.d.chat.id = id;
481 send(WorldSocket, &spk, len, 0);
482 }
483
world_reboot()484 void world_reboot() {
485 int len;
486 if (WorldSocket == -1) return;
487 spk.type = WP_RESTART;
488 len = sizeof(struct wpacket);
489 send(WorldSocket, &spk, len, 0);
490 }
491
world_msg(char * text)492 void world_msg(char *text) {
493 int len;
494 if (WorldSocket == -1) return;
495 spk.type = WP_MESSAGE;
496 len = sizeof(struct wpacket);
497 snprintf(spk.d.smsg.stxt, MSG_LEN, "%s", text);
498 send(WorldSocket, &spk, len, 0);
499 }
500
msg_to_irc(char * text)501 void msg_to_irc(char *text) {
502 int len;
503 if (WorldSocket == -1) return;
504 spk.type = WP_MSG_TO_IRC;
505 len = sizeof(struct wpacket);
506 snprintf(spk.d.smsg.stxt, MSG_LEN, "%s", text);
507 send(WorldSocket, &spk, len, 0);
508 }
509
510 /* we can rely on ID alone when we merge data */
world_player(uint32_t id,char * name,uint16_t enter,byte quiet)511 void world_player(uint32_t id, char *name, uint16_t enter, byte quiet) {
512 int len;
513 if (WorldSocket == -1) return;
514 spk.type = (enter ? WP_NPLAYER : WP_QPLAYER);
515 len = sizeof(struct wpacket);
516 strncpy(spk.d.play.name, name, 30);
517 spk.d.play.id = id;
518 spk.d.play.silent = quiet;
519 send(WorldSocket, &spk, len, 0);
520 }
521
522 /* unified, hopefully unique password check function */
chk(char * s1,char * s2)523 uint32_t chk(char *s1, char *s2) {
524 unsigned int i, j = 0;
525 int m1, m2;
526 static uint32_t rval[2] = {0, 0};
527 rval[0] = 0L;
528 rval[1] = 0L;
529 m1 = strlen(s1);
530 m2 = strlen(s2);
531 for (i = 0; i < m1; i++) {
532 rval[0] += s1[i];
533 rval[0] <<= 5;
534 }
535 for (j = 0; j < m2; j++) {
536 rval[1] += s2[j];
537 rval[1] <<= 3;
538 }
539 for (i = 0; i < m1; i++) {
540 rval[1] += s1[i];
541 rval[1] <<= (3 + rval[0] % 5);
542 rval[0] += s2[j];
543 j = rval[0] % m2;
544 rval[0] <<= (3 + rval[1] % 3);
545 }
546 return(rval[0] + rval[1]);
547 }
548 #endif
549