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