1 /*
2  * Support for the "remote console".  It lets the server admin
3  * perform server maintenance without requiring that the server
4  * have a devoted tty.
5  */
6 
7 /* added this for consistency in some (unrelated) header-inclusion,
8    it IS a server file, isn't it? */
9 #define SERVER
10 
11 #include <stdarg.h>
12 #include "angband.h"
13 #include "control.h"
14 
15 #ifdef MINGW
16 #define EWOULDBLOCK WSAEWOULDBLOCK
17 #endif
18 
19 #ifdef SERVER_GWPORT
20 #if 0
21 /* Server gateway stuff */
22 void SGWHit(int read_fd, int arg){
23 	int newsock = 0;
24 	char *sdb;
25 	int size = 0;
26 	time_t now;
27 
28 	/* read_fd always the main socket, because we
29 	   never install_input on any others. */
30 	/* Order: connection, s->send, s->shutdown socket */
31 
32 	if ((newsock = SocketAccept(read_fd)) != -1) {
33 		/* Send some crap here */
34 		sdb = C_NEW(4096, char);
35 		if (sdb != (char*)NULL) {
36 			int i;
37 			time(&now);
38 			size += sprintf(sdb, "runtime=%d\n", (int)(now - cfg.runtime));
39 			size += sprintf(&sdb[size], "turn=%d\n", turn);
40 			size += sprintf(&sdb[size], "day=%d\n", DAY); /* day const */
41 			size += sprintf(&sdb[size], "year=%d\n", bst(YEAR, turn)); /* starting year const */
42 			/* let the script count or we'll give away
43 			   the dungeon masters. */
44 			/* size+=sprintf(&sdb[size],"num=%d\n", NumPlayers);*/
45 			for (i = 1; i <= NumPlayers; i++) {
46 				if (Players[i]->admin_dm && cfg.secret_dungeon_master) continue;
47 				size += sprintf(&sdb[size], "player=%s\n", Players[i]->name);
48 				size += sprintf(&sdb[size], "level=%d\n", Players[i]->lev);
49 				size += sprintf(&sdb[size], "race=%s\n", race_info[Players[i]->prace].title);
50 				size += sprintf(&sdb[size], "born=%d\n", Players[i]->turn);
51 			}
52 			size += highscore_send(&sdb[size], 4096 - size);
53 			DgramWrite(newsock, sdb, size);
54 			C_FREE(sdb, 4096, char);
55 		}
56 		close(newsock);	/* oops */
57 	}
58 	else
59 		s_printf("Web server request failed: %d\n", errno);
60 }
61 #else
62 /* Server gateway stuff */
63 
64 gw_connection_t gw_conns[MAX_GW_CONNS];
65 int gw_conns_num;
66 
67 /* Copy the first line from the socket buffer into buf */
Packet_getln(sockbuf_t * s,char * buf)68 static int Packet_getln(sockbuf_t *s, char *buf) {
69 	char *scan;
70 	int len;
71 
72 	for (scan = s->ptr; scan < s->buf + s->len; scan++) {
73 		if (*scan == '\n') {
74 			/* Calculate the length and limit to MSG_LEN - 1 */
75 			len = MIN(scan - s->ptr, MSG_LEN - 1);
76 
77 			/* Copy the line */
78 			memcpy(buf, s->ptr, len);
79 
80 			/* Terminate */
81 			buf[len] = '\0';
82 
83 			/* Move the socket buffer pointer forward */
84 			s->ptr = scan + 1;
85 
86 			return len;
87 		}
88 	}
89 
90 	return 0;
91 }
92 
93 /* Write formatted ouput terminated with a newline into a socket buffer */
Packet_println(sockbuf_t * s,cptr fmt,...)94 static int Packet_println(sockbuf_t *s, cptr fmt, ...) {
95 	va_list ap;
96 	char buf[4096];
97 	int n;
98 	int rval;
99 
100 	va_start(ap, fmt);
101 
102 	/* Use vsnprintf to do the formatting */
103 	n = vsnprintf(buf, 4095, fmt, ap);
104 
105 	if (n >= 0) {
106 		/* Write the output to the socket buffer */
107 		buf[n++] = '\n';
108 		rval = Sockbuf_write(s, buf, n);
109 	} else {
110 		/* Some error */
111 		rval = 0;
112 	}
113 
114 	va_end(ap);
115 
116 	return rval;
117 }
118 
119 /* GW connection handler */
SGWHit(int read_fd,int arg)120 void SGWHit(int read_fd, int arg) {
121 	int i, sock, bytes;
122 	gw_connection_t *gw_conn = NULL;
123 	char buf[MSG_LEN];
124 
125 	/* Check if it's a new client */
126 	if (read_fd == SGWSocket) {
127 		/* Accept it */
128 		sock = SocketAccept(read_fd);
129 
130 		if (sock == -1) {
131 			s_printf("Failed to accept GW port connection (errno=%d)\n", errno);
132 			return;
133 		}
134 
135 		/* Check if we have room for it */
136 		if (gw_conns_num < MAX_GW_CONNS) {
137 
138 			/* Find a free connection */
139 			for (i = 0; i < MAX_GW_CONNS; i++) {
140 				gw_conn = &gw_conns[i];
141 
142 				if (gw_conn->state == CONN_FREE)
143 					break;
144 			}
145 
146 			gw_conn->sock = sock;
147 			gw_conn->state = CONN_CONNECTED;
148 			gw_conn->last_activity = time(NULL);
149 
150 #if 0 /* prevents sending lots of data */
151 			if (SetSocketNonBlocking(sock, 1) == -1) {
152 				plog("Cannot make GW client socket non-blocking");
153 			}
154 #endif
155 
156 			/* Initialize socket buffers */
157 			Sockbuf_init(&gw_conn->r, sock, 8192, SOCKBUF_READ);
158 			Sockbuf_init(&gw_conn->w, sock, 8192, SOCKBUF_WRITE);
159 
160 			install_input(SGWHit, sock, 2);
161 
162 			gw_conns_num++;
163 		} else {
164 			/* No room, close the connection */
165 			DgramClose(sock);
166 		}
167 
168 		/* The connection has either been accepted or not, we're done */
169 		return;
170 	}
171 
172 	/* Find the matching connection */
173 	for (i = 0; i < MAX_GW_CONNS; i++) {
174 		gw_connection_t *gw_conn2 = &gw_conns[i];
175 
176 		if (gw_conn2->state == CONN_CONNECTED && gw_conn2->sock == read_fd) {
177 			gw_conn = gw_conn2;
178 			break;
179 		}
180 	}
181 
182 	if (!gw_conn) {
183 		s_printf("No GW connection found for socket number %d\n", read_fd);
184 		DgramClose(read_fd);
185 		return;
186 	}
187 
188 	/* Read the message */
189 	bytes = DgramReceiveAny(read_fd, gw_conn->r.buf + gw_conn->r.len, gw_conn->r.size - gw_conn->r.len);
190 
191 	/* Check for errors or our TCP connection closing */
192 	if (bytes <= 0) {
193 		/* If 0 bytes have been sent than the client has probably closed
194 		 * the connection
195 		 */
196 		if (bytes == 0) {
197 			gw_conn->state = CONN_FREE;
198 			Sockbuf_cleanup(&gw_conn->r);
199 			Sockbuf_cleanup(&gw_conn->w);
200 			DgramClose(read_fd);
201 			remove_input(read_fd);
202 			gw_conns_num--;
203 		}
204 		else if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
205 			errno != EINTR)
206 		{
207 			/* Clear the error condition for the contact socket */
208 			GetSocketError(read_fd);
209 
210 			s_printf("Failed to read from GW client!\n");
211 		}
212 		return;
213 	}
214 
215 	/* Set length */
216 	gw_conn->r.len = bytes;
217 
218 	gw_conn->last_activity = time(NULL);
219 
220 	/* Prepare to send a new reply */
221 	Sockbuf_clear(&gw_conn->w);
222 
223 	/* Try to read the request */
224 	while (Packet_getln(&gw_conn->r, buf) > 0) {
225 		/* Basic server info */
226 		if (!strcmp(buf, "INFO")) {
227 			time_t now;
228 			player_type *p_ptr;
229 			int players = 0;
230 			int day = bst(DAY, turn);
231 			now = time(NULL);
232 
233 			/* Count players */
234 			for (i = 1; i <= NumPlayers; i++) {
235 				p_ptr = Players[i];
236 				if (p_ptr->admin_dm && cfg.secret_dungeon_master) continue;
237 				players++;
238 			}
239 
240 			Packet_println(&gw_conn->w, "INFO REPLY");
241 			Packet_println(&gw_conn->w, "uptime=%d", now - cfg.runtime);
242 			Packet_println(&gw_conn->w, "turn=%d", turn);
243 			Packet_println(&gw_conn->w, "ingameday=%s of the %s year", get_month_name(day, FALSE, FALSE), get_day(bst(YEAR, turn)));
244 			Packet_println(&gw_conn->w, "fps=%d", cfg.fps);
245 			Packet_println(&gw_conn->w, "players=%d", players);
246 			Packet_println(&gw_conn->w, "INFO REPLY END");
247 		}
248 
249 		/* List of players */
250 		else if (!strcmp(buf, "PLAYERS")) {
251 			player_type *p_ptr;
252 			Packet_println(&gw_conn->w, "PLAYERS REPLY");
253 			for (i = 1; i <= NumPlayers; i++) {
254 				p_ptr = Players[i];
255 				if (p_ptr->admin_dm && cfg.secret_dungeon_master) continue;
256 				Packet_println(&gw_conn->w, "name=%s", p_ptr->name);
257 				Packet_println(&gw_conn->w, "account=%s", p_ptr->accountname);
258 				Packet_println(&gw_conn->w, "host=%s", p_ptr->hostname);
259 				Packet_println(&gw_conn->w, "level=%d", p_ptr->lev);
260 				Packet_println(&gw_conn->w, "race=%s", race_info[p_ptr->prace].title);
261 				Packet_println(&gw_conn->w, "class=%s", class_info[p_ptr->pclass].title);
262 				Packet_println(&gw_conn->w, "gender=%s", (p_ptr->male) ? "male" : "female");
263 			}
264 			Packet_println(&gw_conn->w, "PLAYERS REPLY END");
265 		}
266 
267 		/* Highscore list */
268 		else if (!strcmp(buf, "SCORES")) {
269 			char *buf2;
270 			int len;
271 			int amount, sent = 0, rval, fail = 0;
272 
273 			Packet_println(&gw_conn->w, "SCORES REPLY");
274 
275 			/* Send the contents of the socket buffer before sending buf2 */
276 			Sockbuf_flush(&gw_conn->w);
277 			Sockbuf_clear(&gw_conn->w);
278 
279 			C_MAKE(buf2, 81920, char);
280 			len = highscore_send(buf2, 81920);
281 
282 			/* Send buf2 in pieces */
283 			/* XXX - Blocking send loop */
284 			while (sent < len) {
285 				/* Try to send a full socket buffer */
286 				amount = MIN(8192, len - sent);
287 				Sockbuf_write(&gw_conn->w, &buf2[sent], amount);
288 				rval = Sockbuf_flush(&gw_conn->w);
289 
290 				if (rval <= 0) {
291 					/* Failure */
292 					if (++fail >= 3) {
293 						/* Give up */
294 						break;
295 					}
296 				}
297 				else {
298 					sent += rval;
299 				}
300 
301 				Sockbuf_clear(&gw_conn->w);
302 			}
303 
304 			C_KILL(buf2, 81920, char);
305 			Packet_println(&gw_conn->w, "SCORES REPLY END");
306 		}
307 
308 		/* House list */
309 		else if (!strcmp(buf, "HOUSES")) {
310 			char *buf2;
311 			int len, alloc = 128 * num_houses;
312 			int amount, sent = 0, rval, fail = 0;
313 
314 			C_MAKE(buf2, alloc, char);
315 			Packet_println(&gw_conn->w, "HOUSES REPLY");
316 
317 			len = houses_send(buf2, alloc);
318 
319 			/* Send the contents of the socket buffer before sending buf2 */
320 			Sockbuf_flush(&gw_conn->w);
321 			Sockbuf_clear(&gw_conn->w);
322 
323 			/* Send buf2 in pieces */
324 			/* XXX - Blocking send loop */
325 			while (sent < len) {
326 				/* Try to send a full socket buffer */
327 				amount = MIN(8192, len - sent);
328 				Sockbuf_write(&gw_conn->w, &buf2[sent], amount);
329 				rval = Sockbuf_flush(&gw_conn->w);
330 
331 				if (rval <= 0) {
332 					/* Failure */
333 					if (++fail >= 3) {
334 						/* Give up */
335 						break;
336 					}
337 				}
338 				else {
339 					sent += rval;
340 				}
341 
342 				Sockbuf_clear(&gw_conn->w);
343 			}
344 
345 			Packet_println(&gw_conn->w, "HOUSES REPLY END");
346 			C_KILL(buf2, alloc, char);
347 		}
348 
349 		/* Player stores list */
350 		else if (!strcmp(buf, "PSTORES")) {
351 			//MAX_HOUSES (65536), STORE_INVEN_MAX (120)
352 #if 0 /* todo: implement (this is a copy/paste of above 'HOUSES') */
353 			char *buf2;
354 			int len, alloc = 128 * num_houses;
355 			int amount, sent = 0, rval, fail = 0;
356 
357 			C_MAKE(buf2, alloc, char);
358 			Packet_println(&gw_conn->w, "PSTORES REPLY");
359 
360 			len = pstores_send(buf2, alloc);
361 
362 			/* Send the contents of the socket buffer before sending buf2 */
363 			Sockbuf_flush(&gw_conn->w);
364 			Sockbuf_clear(&gw_conn->w);
365 
366 			/* Send buf2 in pieces */
367 			/* XXX - Blocking send loop */
368 			while (sent < len) {
369 				/* Try to send a full socket buffer */
370 				amount = MIN(8192, len - sent);
371 				Sockbuf_write(&gw_conn->w, &buf2[sent], amount);
372 				rval = Sockbuf_flush(&gw_conn->w);
373 
374 				if (rval <= 0) {
375 					/* Failure */
376 					if (++fail >= 3) {
377 						/* Give up */
378 						break;
379 					}
380 				}
381 				else {
382 					sent += rval;
383 				}
384 
385 				Sockbuf_clear(&gw_conn->w);
386 			}
387 
388 			Packet_println(&gw_conn->w, "PSTORES REPLY END");
389 			C_KILL(buf2, alloc, char);
390 #endif
391 		}
392 
393 		/* Default reply */
394 		else {
395 			Packet_println(&gw_conn->w, "ERROR UNKNOWN REQUEST");
396 		}
397 
398 		if (gw_conn->w.len) {
399 			/* Send our reply */
400 			Sockbuf_flush(&gw_conn->w);
401 
402 			/* Make room for more */
403 			Sockbuf_clear(&gw_conn->w);
404 		}
405 	}
406 
407 	/* Advance the read buffer */
408 	Sockbuf_advance(&gw_conn->r, gw_conn->r.ptr - gw_conn->r.buf);
409 }
410 
411 /* Checks whether GW connections should timeout */
SGWTimeout()412 void SGWTimeout() {
413 	int i;
414 	gw_connection_t *gw_conn;
415 	time_t now;
416 
417 	now = time(NULL);
418 
419 	/* Go through all gateway connections */
420 	for (i = 0; i < MAX_GW_CONNS; i++) {
421 		gw_conn = &gw_conns[i];
422 		if (gw_conn->state == CONN_CONNECTED) {
423 			/* Check for timeout */
424 			if (gw_conn->last_activity + GW_CONN_TIMEOUT < now) {
425 				s_printf("GW client timeout\n");
426 
427 				/* Close the connection */
428 				gw_conn->state = CONN_FREE;
429 				Sockbuf_cleanup(&gw_conn->r);
430 				Sockbuf_cleanup(&gw_conn->w);
431 				DgramClose(gw_conn->sock);
432 				remove_input(gw_conn->sock);
433 				gw_conns_num--;
434 			}
435 		}
436 	}
437 }
438 #endif
439 #endif
440 
441 #ifdef NEW_SERVER_CONSOLE
442 
443 static sockbuf_t console_buf;
444 
445 /*
446  * Return the list of players
447  */
console_status()448 static void console_status()
449 {
450 	int k;
451 
452 	/* Packet header */
453 	Packet_printf(&console_buf, "%c%d", CONSOLE_STATUS, NumPlayers);
454 
455 	/* Scan the player list */
456 	for (k = 1; k <= NumPlayers; k++)
457 	{
458 		player_type *p_ptr = Players[k];
459 
460 		/* Skip disconnected players */
461 		if (p_ptr->conn == NOT_CONNECTED) continue;
462 
463 		/* Add an entry */
464 		Packet_printf(&console_buf, "%s%s%s%d%d%d%d",
465 			p_ptr->name, race_info[p_ptr->prace].title,
466 			class_info[p_ptr->pclass].title, p_ptr->lev,
467 			p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
468 	}
469 }
470 
console_player_info(int player)471 static void console_player_info(int player)
472 {
473 }
474 
console_artifacts()475 static void console_artifacts()
476 {
477 	int i, count = 0, z;
478 	bool okay[MAX_A_IDX];
479 	char base_name[ONAME_LEN];
480 
481 	/* Packet header */
482 	Packet_printf(&console_buf, "%c", CONSOLE_ARTIFACT_LIST);
483 
484 	/* Scan the artifacts */
485 	for (i = 0; i < MAX_A_IDX; i++) {
486 		artifact_type *a_ptr = &a_info[i];
487 
488 		/* Default */
489 		okay[i] = FALSE;
490 
491 		/* Skip "empty" artifacts */
492 		if (!a_ptr->name) continue;
493 
494 		/* Skip "uncreated" artifacts */
495 		if (!a_ptr->cur_num) continue;
496 
497 		/* Assume OK */
498 		okay[i] = TRUE;
499 
500 		/* One more artifact */
501 		count++;
502 	}
503 
504 	/* Write the number */
505 	Packet_printf(&console_buf, "%d", count);
506 
507 	/* Write each artifact info */
508 	for (i = 0; i < MAX_A_IDX; i++) {
509 		artifact_type *a_ptr = &a_info[i];
510 
511 		/* List "dead" ones */
512 		if (!okay[i]) continue;
513 
514 		/* Paranoia */
515 		strcpy(base_name, "Unknown Artifact");
516 
517 		/* Obtain the base object type */
518 		z = lookup_kind(a_ptr->tval, a_ptr->sval);
519 
520 		/* Real object */
521 		if (z) {
522 			object_type forge;
523 
524 			/* Create the object */
525 			invcopy(&forge, z);
526 
527 			/* Create the artifact */
528 			forge.name1 = i;
529 
530 			/* Describe the artifact */
531 			object_desc_store(0, base_name, &forge, FALSE, 0);
532 		}
533 
534 		/* Output this artifact's number and name */
535 		Packet_printf(&console_buf, "%d%s", i, base_name);
536 	}
537 }
538 
console_uniques()539 static void console_uniques()
540 {
541 	int k, count = 0;
542 	char buf[1024];
543 
544 	/* Packet header */
545 	Packet_printf(&console_buf, "%c", CONSOLE_UNIQUE_LIST);
546 
547 	/* Scan the monster races */
548 	for (k = 1; k < MAX_R_IDX - 1; k++) {
549 		monster_race *r_ptr = &r_info[k];
550 
551 		/* Only process uniques */
552 		if (r_ptr->flags1 & RF1_UNIQUE) {
553 			bool dead = (r_ptr->max_num == 0);
554 
555 			/* Only count known uniques */
556 			if (dead || r_ptr->r_sights) {
557 				/* One more */
558 				count++;
559 			}
560 		}
561 	}
562 
563 	/* Write the number of uniques */
564 	Packet_printf(&console_buf, "%d", count);
565 
566 	/* Scan the monster races */
567 	for (k = 1; k < MAX_R_IDX - 1; k++) {
568 		monster_race *r_ptr = &r_info[k];
569 
570 		/* Only process uniques */
571 		if (r_ptr->flags1 & RF1_UNIQUE) {
572 			/* Only display known uniques */
573 			if (r_ptr->r_sights) {
574 				int i;
575 				byte ok = FALSE;
576 
577 				/* Format message */
578 				sprintf(buf, "%s has been killed by:\n", r_name + r_ptr->name);
579 
580 				for (i = 1; i <= NumPlayers; i++) {
581 					player_type *q_ptr = Players[i];
582 
583 					if (q_ptr->r_killed[k] == 1) {
584 						sprintf(buf, "        %s\n", q_ptr->name);
585 						ok = TRUE;
586 					}
587 				}
588 				if (!ok) sprintf(buf, "       Nobody\n");
589 
590 
591 				/* Add info */
592 				Packet_printf(&console_buf, "%d%s", k, buf);
593 			}
594 		}
595 	}
596 }
597 
console_change_artifact(int artifact,int status)598 static void console_change_artifact(int artifact, int status) {
599 	/* Check bounds */
600 	if (artifact <= 0 || artifact > MAX_A_IDX) {
601 		/* Failed */
602 		Packet_printf(&console_buf, "%c%c", CONSOLE_CHANGE_ARTIFACT, 0);
603 		return;
604 	}
605 
606 	/* Set the artifact's status */
607 	if (status) {
608 		/* Make found */
609 		handle_art_inum(artifact);
610 	} else {
611 		/* Make unfound */
612 		handle_art_dnum(artifact);
613 	}
614 
615 	/* Succeeded */
616 	Packet_printf(&console_buf, "%c%c", CONSOLE_CHANGE_ARTIFACT, 1);
617 }
618 
console_change_unique(int unique,cptr killer)619 static void console_change_unique(int unique, cptr killer)
620 {
621 	monster_race *r_ptr;
622 	int kill_idx;
623 	char buf[80];
624 
625 	/* Check bounds */
626 	if (unique <= 0 || unique > MAX_R_IDX - 1) {
627 		/* Failed */
628 		Packet_printf(&console_buf, "%c%c", CONSOLE_CHANGE_UNIQUE, 0);
629 
630 		return;
631 	}
632 
633 	/* Get killer index */
634 	if (killer) {
635 		/* Lookup player by name */
636 		kill_idx = lookup_player_id(killer);
637 	} else {
638 		/* No killer */
639 		kill_idx = 0;
640 	}
641 
642 	/* Set pointer */
643 	r_ptr = &r_info[unique];
644 
645 	/* Check for uniqueness */
646 	if (!r_ptr->flags1 & RF1_UNIQUE) {
647 		/* Failed */
648 		Packet_printf(&console_buf, "%c%c", CONSOLE_CHANGE_UNIQUE, 0);
649 
650 		return;
651 	}
652 
653 	/* Set death flag */
654 	if (kill_idx) {
655 		/* Dead */
656 		r_ptr->max_num = 0;
657 	} else {
658 		/* Alive */
659 
660 		/* Tell people if the monster is respawning */
661 		if (!r_ptr->max_num)
662 		{	/* the_sandman: added colour */
663 			snprintf(buf, 80, "\377v%s rises from the dead!",(r_name + r_ptr->name));
664 
665 			/* Tell every player */
666 			msg_broadcast(0,buf);
667 		}
668 		r_ptr->max_num = 1;
669 	}
670 
671 	/* Succeeded */
672 	Packet_printf(&console_buf, "%c%c", CONSOLE_CHANGE_UNIQUE, 1);
673 }
674 
console_message(char * buf)675 static void console_message(char *buf)
676 {
677 	/* Send the message */
678 	player_talk(0, buf);
679 
680 	/* Reply */
681 	Packet_printf(&console_buf, "%c", CONSOLE_MESSAGE);
682 }
683 
console_kick_player(char * name)684 static void console_kick_player(char *name)
685 {
686 	int i;
687 
688 	/* Check the players in the game */
689 	for (i = 1; i <= NumPlayers; i++) {
690 		/* Check name */
691 		if (!strcmp(name, Players[i]->name)) {
692 			/* Kick him */
693 			Destroy_connection(Players[i]->conn, "Kicked out");
694 
695 			/* Success */
696 			Packet_printf(&console_buf, "%c%c", CONSOLE_KICK_PLAYER, 1);
697 
698 			return;
699 		}
700 	}
701 
702 	/* Failure */
703 	Packet_printf(&console_buf, "%c%c", CONSOLE_KICK_PLAYER, 0);
704 }
705 
console_reload_server_preferences(void)706 static void console_reload_server_preferences(void)
707 {
708 	/* Reload the server preferences */
709 	load_server_cfg();
710 
711 	/* Let mangconsole know that the command was a success */
712 	/* Packet header */
713 	Packet_printf(&console_buf, "%c", CONSOLE_RELOAD_SERVER_PREFERENCES);
714 
715 	/* Write the output */
716 	DgramReply(console_buf.sock, console_buf.ptr, console_buf.len);
717 }
console_shutdown(void)718 static void console_shutdown(void)
719 {
720 	/* Packet header */
721 	Packet_printf(&console_buf, "%c", CONSOLE_SHUTDOWN);
722 
723 	/* Write the output */
724 	DgramReply(console_buf.sock, console_buf.ptr, console_buf.len);
725 
726 	/* Shutdown */
727 	shutdown_server();
728 }
729 
730 /*
731  * This is the response function when incoming data is received on the
732  * control pipe.
733  */
NewConsole(int read_fd,int arg)734 void NewConsole(int read_fd, int arg)
735 {
736 	char ch, passwd[80], buf[1024];
737 	int i, j, bytes;
738 	static int newsock = 0;
739 
740 	/* Make a TCP connection */
741 	/* Hack -- check if this data has arrived on the contact socket or not.
742 	 * If it has, then we have not created a connection with the client yet,
743 	 * and so we must do so.
744 	 */
745 	if (read_fd == ConsoleSocket)
746 	{
747 		/* Hack -- make sure that two people haven't tried to use mangconsole
748 		 * at the same time.  Since I am currently too lazy to support this,
749 		 * we will remove the input of the first person when the second person
750 		 * connects.
751 		 */
752 		if (newsock) remove_input(newsock);
753 		if ((newsock = SocketAccept(read_fd)) == -1)
754 		{
755 			/* Clear socket if it failed */
756 			newsock = 0;
757 			quit("Couldn't accept console TCP connection.\n");
758 		}
759 		console_buf.sock = newsock;
760 		install_input(NewConsole, newsock, 2);
761 		return;
762 	}
763 
764 
765 	/* Clear the buffer */
766 	Sockbuf_clear(&console_buf);
767 	/* Read the message */
768 	bytes = DgramReceiveAny(read_fd, console_buf.buf, console_buf.size);
769 
770 	/* Check for errors or our TCP connection closing */
771 	if (bytes <= 0)
772 	{
773 		/* If this happens our TCP connection has probably been severed.
774 		 * Remove the input.
775 		 */
776 		close(newsock);
777 		remove_input(newsock);
778 		newsock = 0;
779 
780 		return;
781 	}
782 
783 	/* Set length */
784 	console_buf.len = bytes;
785 
786 	/* Get the password */
787 	Packet_scanf(&console_buf, "%s",passwd);
788 
789 	if (strcmp(passwd, cfg.console_password))
790 	{
791 		/* Clear buffer */
792 		Sockbuf_clear(&console_buf);
793 
794 		/* Put an "illegal access" reply in the buffer */
795 		Packet_printf(&console_buf, "%c", CONSOLE_DENIED);
796 
797 		/* Send it */
798 		DgramWrite(read_fd, console_buf.buf, console_buf.len);
799 
800 		/* Log this to the local console */
801 		s_printf("Illegal console command from %s.\n", DgramLastname(read_fd));
802 
803 		return;
804 	}
805 	else s_printf("Valid console command from %s.\n", DgramLastname(read_fd));
806 
807 	/* Acquire command */
808 	Packet_scanf(&console_buf, "%c", &ch);
809 
810 	/* Determine what the command is */
811 	switch(ch)
812 	{
813 		/* Wants to see the player list */
814 		case CONSOLE_STATUS:
815 			console_status();
816 			break;
817 
818 		/* Wants to see detailed player info */
819 		case CONSOLE_PLAYER_INFO:
820 			Packet_scanf(&console_buf, "%d", &i);
821 			console_player_info(i);
822 			break;
823 
824 		/* Wants to see the artifact list */
825 		case CONSOLE_ARTIFACT_LIST:
826 			console_artifacts();
827 			break;
828 
829 		/* Wants to see the unique list */
830 		case CONSOLE_UNIQUE_LIST:
831 			console_uniques();
832 			break;
833 
834 		/* Wants to change artifact status */
835 		case CONSOLE_CHANGE_ARTIFACT:
836 			Packet_scanf(&console_buf, "%d%d", &i, &j);
837 			console_change_artifact(i, j);
838 			break;
839 
840 		/* Wants to change unique status */
841 		case CONSOLE_CHANGE_UNIQUE:
842 			Packet_scanf(&console_buf, "%d%s", &i, buf);
843 			console_change_unique(i, buf);
844 			break;
845 
846 		/* Wants to send a message */
847 		case CONSOLE_MESSAGE:
848 			Packet_scanf(&console_buf, "%s", buf);
849 			console_message(buf);
850 			break;
851 
852 		/* Wants to kick a player */
853 		case CONSOLE_KICK_PLAYER:
854 			Packet_scanf(&console_buf, "%s", buf);
855 			console_kick_player(buf);
856 			break;
857 
858 		/* Wants to reload the server preferences */
859 		case CONSOLE_RELOAD_SERVER_PREFERENCES:
860 			console_reload_server_preferences();
861 			break;
862 
863 		/* Wants to shut the server down */
864 		case CONSOLE_SHUTDOWN:
865 			console_shutdown();
866 			break;
867 
868 		/* Strangeness */
869 		default:
870 			s_printf("Bizarre input on server console; ignoring.\n");
871 			return;
872 	}
873 
874 	/* Write the response */
875 	DgramWrite(console_buf.sock, console_buf.ptr, console_buf.len);
876 }
877 
878 /*
879  * Initialize the stuff for the new console
880  */
InitNewConsole(int write_fd)881 bool InitNewConsole(int write_fd)
882 {
883 	/* Initialize buffer */
884 	if (Sockbuf_init(&console_buf, write_fd, 8192, SOCKBUF_READ | SOCKBUF_WRITE))
885 	{
886 		/* Failed */
887 		s_printf("No memory for console buffer.\n");
888 
889 		return FALSE;
890 	}
891 
892 	return TRUE;
893 }
894 
895 #endif
896