xref: /dragonfly/games/hunt/hunt/hunt.c (revision d9f85b33)
16693db17SSascha Wildner /*-
282a5c12eSMatthew Dillon  * Copyright (c) 1983-2003, Regents of the University of California.
382a5c12eSMatthew Dillon  * All rights reserved.
482a5c12eSMatthew Dillon  *
582a5c12eSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
682a5c12eSMatthew Dillon  * modification, are permitted provided that the following conditions are
782a5c12eSMatthew Dillon  * met:
882a5c12eSMatthew Dillon  *
96693db17SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
1082a5c12eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
116693db17SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1282a5c12eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
1382a5c12eSMatthew Dillon  *    documentation and/or other materials provided with the distribution.
146693db17SSascha Wildner  * 3. Neither the name of the University of California, San Francisco nor
1582a5c12eSMatthew Dillon  *    the names of its contributors may be used to endorse or promote
1682a5c12eSMatthew Dillon  *    products derived from this software without specific prior written
1782a5c12eSMatthew Dillon  *    permission.
1882a5c12eSMatthew Dillon  *
1982a5c12eSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2082a5c12eSMatthew Dillon  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2182a5c12eSMatthew Dillon  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2282a5c12eSMatthew Dillon  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2382a5c12eSMatthew Dillon  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2482a5c12eSMatthew Dillon  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2582a5c12eSMatthew Dillon  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2682a5c12eSMatthew Dillon  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2782a5c12eSMatthew Dillon  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2882a5c12eSMatthew Dillon  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2982a5c12eSMatthew Dillon  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3082a5c12eSMatthew Dillon  *
3182a5c12eSMatthew Dillon  * $OpenBSD: hunt.c,v 1.13 2008/03/17 09:17:56 sobrado Exp $
3282a5c12eSMatthew Dillon  * $NetBSD: hunt.c,v 1.8 1998/09/13 15:27:28 hubertf Exp $
3382a5c12eSMatthew Dillon  */
3482a5c12eSMatthew Dillon 
3582a5c12eSMatthew Dillon #include <ctype.h>
3682a5c12eSMatthew Dillon #include <err.h>
3782a5c12eSMatthew Dillon #include <errno.h>
3882a5c12eSMatthew Dillon #include <curses.h>
3982a5c12eSMatthew Dillon #include <signal.h>
4082a5c12eSMatthew Dillon #include <stdlib.h>
4182a5c12eSMatthew Dillon #include <string.h>
4282a5c12eSMatthew Dillon #include <unistd.h>
4382a5c12eSMatthew Dillon #include <netdb.h>
4482a5c12eSMatthew Dillon 
4582a5c12eSMatthew Dillon #include <sys/stat.h>
4682a5c12eSMatthew Dillon #include <sys/time.h>
4782a5c12eSMatthew Dillon #include <sys/types.h>
4882a5c12eSMatthew Dillon #include <sys/socket.h>
4982a5c12eSMatthew Dillon #include <sys/ioctl.h>
5082a5c12eSMatthew Dillon #include <sys/sockio.h>
5182a5c12eSMatthew Dillon 
5282a5c12eSMatthew Dillon #include <netinet/in.h>
5382a5c12eSMatthew Dillon #include <net/if.h>
5482a5c12eSMatthew Dillon 
5582a5c12eSMatthew Dillon #include <arpa/inet.h>
5682a5c12eSMatthew Dillon 
5782a5c12eSMatthew Dillon #include "hunt.h"
5882a5c12eSMatthew Dillon #include "display.h"
5982a5c12eSMatthew Dillon #include "client.h"
6082a5c12eSMatthew Dillon #include "list.h"
6182a5c12eSMatthew Dillon 
6282a5c12eSMatthew Dillon #ifndef __GNUC__
6382a5c12eSMatthew Dillon #define __attribute__(x)
6482a5c12eSMatthew Dillon #endif
6582a5c12eSMatthew Dillon 
6682a5c12eSMatthew Dillon FLAG	Am_monitor = FALSE;
6782a5c12eSMatthew Dillon int	Socket;
6882a5c12eSMatthew Dillon char	map_key[256];			/* what to map keys to */
6982a5c12eSMatthew Dillon FLAG	no_beep = FALSE;
7082a5c12eSMatthew Dillon char	*Send_message = NULL;
7182a5c12eSMatthew Dillon 
7282a5c12eSMatthew Dillon static char	*Sock_host;
7382a5c12eSMatthew Dillon static char	*use_port;
7482a5c12eSMatthew Dillon static FLAG	Query_driver = FALSE;
7582a5c12eSMatthew Dillon static FLAG	Show_scores = FALSE;
7682a5c12eSMatthew Dillon static struct sockaddr	Daemon;
7782a5c12eSMatthew Dillon 
7882a5c12eSMatthew Dillon 
7982a5c12eSMatthew Dillon static char	name[NAMELEN];
8082a5c12eSMatthew Dillon static char	team = '-';
8182a5c12eSMatthew Dillon 
8282a5c12eSMatthew Dillon static int	in_visual;
8382a5c12eSMatthew Dillon 
8482a5c12eSMatthew Dillon static void	dump_scores(void);
8582a5c12eSMatthew Dillon static long	env_init(long);
8682a5c12eSMatthew Dillon static void	fill_in_blanks(void);
8782a5c12eSMatthew Dillon static void	leave(int, const char *) __attribute__((__noreturn__));
8882a5c12eSMatthew Dillon static void	sigterm(int);
8982a5c12eSMatthew Dillon static int	find_driver(void);
9082a5c12eSMatthew Dillon 
9182a5c12eSMatthew Dillon /*
9282a5c12eSMatthew Dillon  * main:
9382a5c12eSMatthew Dillon  *	Main program for local process
9482a5c12eSMatthew Dillon  */
9582a5c12eSMatthew Dillon int
main(int ac,char ** av)9682a5c12eSMatthew Dillon main(int ac, char **av)
9782a5c12eSMatthew Dillon {
9882a5c12eSMatthew Dillon 	int		c;
9982a5c12eSMatthew Dillon 	long		enter_status;
10082a5c12eSMatthew Dillon 	int		option;
10182a5c12eSMatthew Dillon 	struct servent	*se;
10282a5c12eSMatthew Dillon 
10382a5c12eSMatthew Dillon 	enter_status = env_init((long) Q_CLOAK);
10482a5c12eSMatthew Dillon 	while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != -1) {
10582a5c12eSMatthew Dillon 		switch (c) {
10682a5c12eSMatthew Dillon 		case 'l':	/* rsh compatibility */
10782a5c12eSMatthew Dillon 		case 'n':
108*d9f85b33Szrj 			strlcpy(name, optarg, sizeof name);
10982a5c12eSMatthew Dillon 			break;
11082a5c12eSMatthew Dillon 		case 't':
11182a5c12eSMatthew Dillon 			team = *optarg;
11282a5c12eSMatthew Dillon 			if (!isdigit(team) && team != ' ') {
11382a5c12eSMatthew Dillon 				warnx("Team names must be numeric or space");
11482a5c12eSMatthew Dillon 				team = '-';
11582a5c12eSMatthew Dillon 			}
11682a5c12eSMatthew Dillon 			break;
11782a5c12eSMatthew Dillon 		case 'o':
11882a5c12eSMatthew Dillon 			Otto_mode = TRUE;
11982a5c12eSMatthew Dillon 			break;
12082a5c12eSMatthew Dillon 		case 'm':
12182a5c12eSMatthew Dillon 			Am_monitor = TRUE;
12282a5c12eSMatthew Dillon 			break;
12382a5c12eSMatthew Dillon 		case 'S':
12482a5c12eSMatthew Dillon 			Show_scores = TRUE;
12582a5c12eSMatthew Dillon 			break;
12682a5c12eSMatthew Dillon 		case 'q':	/* query whether hunt is running */
12782a5c12eSMatthew Dillon 			Query_driver = TRUE;
12882a5c12eSMatthew Dillon 			break;
12982a5c12eSMatthew Dillon 		case 'w':
13082a5c12eSMatthew Dillon 			Send_message = optarg;
13182a5c12eSMatthew Dillon 			break;
13282a5c12eSMatthew Dillon 		case 'h':
13382a5c12eSMatthew Dillon 			Sock_host = optarg;
13482a5c12eSMatthew Dillon 			break;
13582a5c12eSMatthew Dillon 		case 'p':
13682a5c12eSMatthew Dillon 			use_port = optarg;
13782a5c12eSMatthew Dillon 			Server_port = atoi(use_port);
13882a5c12eSMatthew Dillon 			break;
13982a5c12eSMatthew Dillon 		case 'c':
14082a5c12eSMatthew Dillon 			enter_status = Q_CLOAK;
14182a5c12eSMatthew Dillon 			break;
14282a5c12eSMatthew Dillon 		case 'f':
14382a5c12eSMatthew Dillon 			enter_status = Q_FLY;
14482a5c12eSMatthew Dillon 			break;
14582a5c12eSMatthew Dillon 		case 's':
14682a5c12eSMatthew Dillon 			enter_status = Q_SCAN;
14782a5c12eSMatthew Dillon 			break;
14882a5c12eSMatthew Dillon 		case 'b':
14982a5c12eSMatthew Dillon 			no_beep = !no_beep;
15082a5c12eSMatthew Dillon 			break;
15182a5c12eSMatthew Dillon 		default:
15282a5c12eSMatthew Dillon 		usage:
15382a5c12eSMatthew Dillon 			fputs("usage: hunt [-bcfmqSs] [-n name] [-p port] "
15482a5c12eSMatthew Dillon 			    "[-t team] [-w message] [[-h] host]\n",
15582a5c12eSMatthew Dillon 			    stderr);
15682a5c12eSMatthew Dillon 			exit(1);
15782a5c12eSMatthew Dillon 		}
15882a5c12eSMatthew Dillon 	}
15982a5c12eSMatthew Dillon 	if (optind + 1 < ac)
16082a5c12eSMatthew Dillon 		goto usage;
16182a5c12eSMatthew Dillon 	else if (optind + 1 == ac)
16282a5c12eSMatthew Dillon 		Sock_host = av[ac - 1];
16382a5c12eSMatthew Dillon 
16482a5c12eSMatthew Dillon 	if (Server_port == 0) {
16582a5c12eSMatthew Dillon 		se = getservbyname("hunt", "udp");
16682a5c12eSMatthew Dillon 		if (se != NULL)
16782a5c12eSMatthew Dillon 			Server_port = ntohs(se->s_port);
16882a5c12eSMatthew Dillon 		else
16982a5c12eSMatthew Dillon 			Server_port = HUNT_PORT;
17082a5c12eSMatthew Dillon 	}
17182a5c12eSMatthew Dillon 
17282a5c12eSMatthew Dillon 	if (Show_scores) {
17382a5c12eSMatthew Dillon 		dump_scores();
17482a5c12eSMatthew Dillon 		exit(0);
17582a5c12eSMatthew Dillon 	}
17682a5c12eSMatthew Dillon 
17782a5c12eSMatthew Dillon 	if (Query_driver) {
17882a5c12eSMatthew Dillon 		struct driver		*driver;
17982a5c12eSMatthew Dillon 
18082a5c12eSMatthew Dillon 		probe_drivers(C_MESSAGE, Sock_host);
18182a5c12eSMatthew Dillon 		while ((driver = next_driver()) != NULL) {
18282a5c12eSMatthew Dillon 			printf("%d player%s hunting on %s!\n",
18382a5c12eSMatthew Dillon 			    driver->response,
18482a5c12eSMatthew Dillon 			    (driver->response == 1) ? "" : "s",
18582a5c12eSMatthew Dillon 			    driver_name(driver));
18682a5c12eSMatthew Dillon 			if (Sock_host)
18782a5c12eSMatthew Dillon 				break;
18882a5c12eSMatthew Dillon 		}
18982a5c12eSMatthew Dillon 		exit(0);
19082a5c12eSMatthew Dillon 	}
19182a5c12eSMatthew Dillon 	if (Otto_mode) {
19282a5c12eSMatthew Dillon 		if (Am_monitor)
19382a5c12eSMatthew Dillon 			errx(1, "otto mode incompatible with monitor mode");
194*d9f85b33Szrj 		strlcpy(name, "otto", sizeof name);
19582a5c12eSMatthew Dillon 		team = ' ';
19682a5c12eSMatthew Dillon 	} else
19782a5c12eSMatthew Dillon 		fill_in_blanks();
19882a5c12eSMatthew Dillon 
199*d9f85b33Szrj 	fflush(stdout);
20082a5c12eSMatthew Dillon 	display_open();
20182a5c12eSMatthew Dillon 	in_visual = TRUE;
20282a5c12eSMatthew Dillon 	if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH) {
20382a5c12eSMatthew Dillon 		errno = 0;
20482a5c12eSMatthew Dillon 		leave(1, "Need a larger window");
20582a5c12eSMatthew Dillon 	}
20682a5c12eSMatthew Dillon 	display_clear_the_screen();
207*d9f85b33Szrj 	signal(SIGINT, intr);
208*d9f85b33Szrj 	signal(SIGTERM, sigterm);
209*d9f85b33Szrj 	/* signal(SIGPIPE, SIG_IGN); */
21082a5c12eSMatthew Dillon 
21182a5c12eSMatthew Dillon 	Daemon.sa_len = 0;
21282a5c12eSMatthew Dillon     ask_driver:
21382a5c12eSMatthew Dillon 	while (!find_driver()) {
21482a5c12eSMatthew Dillon 		if (Am_monitor) {
21582a5c12eSMatthew Dillon 			errno = 0;
21682a5c12eSMatthew Dillon 			leave(1, "No one playing");
21782a5c12eSMatthew Dillon 		}
21882a5c12eSMatthew Dillon 
21982a5c12eSMatthew Dillon 		if (Sock_host == NULL) {
22082a5c12eSMatthew Dillon 			errno = 0;
22182a5c12eSMatthew Dillon 			leave(1, "huntd not running");
22282a5c12eSMatthew Dillon 		}
22382a5c12eSMatthew Dillon 
22482a5c12eSMatthew Dillon 		sleep(3);
22582a5c12eSMatthew Dillon 	}
22682a5c12eSMatthew Dillon 	Socket = -1;
22782a5c12eSMatthew Dillon 
22882a5c12eSMatthew Dillon 	for (;;) {
22982a5c12eSMatthew Dillon 		if (Socket != -1)
23082a5c12eSMatthew Dillon 			close(Socket);
23182a5c12eSMatthew Dillon 
23282a5c12eSMatthew Dillon 		Socket = socket(Daemon.sa_family, SOCK_STREAM, 0);
23382a5c12eSMatthew Dillon 		if (Socket < 0)
23482a5c12eSMatthew Dillon 			leave(1, "socket");
23582a5c12eSMatthew Dillon 
23682a5c12eSMatthew Dillon 		option = 1;
23782a5c12eSMatthew Dillon 		if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
23882a5c12eSMatthew Dillon 		    &option, sizeof option) < 0)
23982a5c12eSMatthew Dillon 			warn("setsockopt loopback");
24082a5c12eSMatthew Dillon 
24182a5c12eSMatthew Dillon 		errno = 0;
24282a5c12eSMatthew Dillon 		if (connect(Socket, &Daemon, Daemon.sa_len) == -1)  {
24382a5c12eSMatthew Dillon 			if (errno == ECONNREFUSED)
24482a5c12eSMatthew Dillon 				goto ask_driver;
24582a5c12eSMatthew Dillon 			leave(1, "connect");
24682a5c12eSMatthew Dillon 		}
24782a5c12eSMatthew Dillon 
24882a5c12eSMatthew Dillon 		do_connect(name, team, enter_status);
24982a5c12eSMatthew Dillon 		if (Send_message != NULL) {
25082a5c12eSMatthew Dillon 			do_message();
25182a5c12eSMatthew Dillon 			if (enter_status == Q_MESSAGE)
25282a5c12eSMatthew Dillon 				break;
25382a5c12eSMatthew Dillon 			Send_message = NULL;
25482a5c12eSMatthew Dillon 			continue;
25582a5c12eSMatthew Dillon 		}
25682a5c12eSMatthew Dillon 		playit();
25782a5c12eSMatthew Dillon 		if ((enter_status = quit(enter_status)) == Q_QUIT)
25882a5c12eSMatthew Dillon 			break;
25982a5c12eSMatthew Dillon 	}
2602038fb68SSascha Wildner 	leave(0, NULL);
26182a5c12eSMatthew Dillon 	/* NOTREACHED */
26282a5c12eSMatthew Dillon 	return(0);
26382a5c12eSMatthew Dillon }
26482a5c12eSMatthew Dillon 
26582a5c12eSMatthew Dillon /*
26682a5c12eSMatthew Dillon  * Set Daemon to be the address of a hunt driver, or return 0 on failure.
26782a5c12eSMatthew Dillon  *
26882a5c12eSMatthew Dillon  * We start quietly probing for drivers. As soon as one driver is found
26982a5c12eSMatthew Dillon  * we show it in the list. If we run out of drivers and we only have one
27082a5c12eSMatthew Dillon  * then we choose it. Otherwise we present a list of the found drivers.
27182a5c12eSMatthew Dillon  */
27282a5c12eSMatthew Dillon static int
find_driver(void)2736beb426bSSascha Wildner find_driver(void)
27482a5c12eSMatthew Dillon {
27582a5c12eSMatthew Dillon 	int last_driver, numdrivers, waiting, is_current;
27682a5c12eSMatthew Dillon 	struct driver *driver;
27782a5c12eSMatthew Dillon 	int c;
27882a5c12eSMatthew Dillon 	char buf[80];
27982a5c12eSMatthew Dillon 	const char *xname;
28082a5c12eSMatthew Dillon 
28182a5c12eSMatthew Dillon 	probe_drivers(Am_monitor ? C_MONITOR : C_PLAYER, Sock_host);
28282a5c12eSMatthew Dillon 
28382a5c12eSMatthew Dillon 	last_driver = -1;
28482a5c12eSMatthew Dillon 	numdrivers = 0;
28582a5c12eSMatthew Dillon 	waiting = 1;
28682a5c12eSMatthew Dillon 	for (;;) {
28782a5c12eSMatthew Dillon 		if (numdrivers == 0) {
28882a5c12eSMatthew Dillon 			/* Silently wait for at least one driver */
28982a5c12eSMatthew Dillon 			driver = next_driver();
29082a5c12eSMatthew Dillon 		} else if (!waiting || (driver =
29182a5c12eSMatthew Dillon 		    next_driver_fd(STDIN_FILENO)) == (struct driver *)-1) {
29282a5c12eSMatthew Dillon 			/* We have a key waiting, or no drivers left */
29382a5c12eSMatthew Dillon 			c = getchar();
29482a5c12eSMatthew Dillon 			if (c == '\r' || c == '\n' || c == ' ') {
29582a5c12eSMatthew Dillon 				if (numdrivers == 1)
29682a5c12eSMatthew Dillon 					c = 'a';
29782a5c12eSMatthew Dillon 				else if (last_driver != -1)
29882a5c12eSMatthew Dillon 					c = 'a' + last_driver;
29982a5c12eSMatthew Dillon 			}
30082a5c12eSMatthew Dillon 			if (c < 'a' || c >= numdrivers + 'a') {
30182a5c12eSMatthew Dillon 				display_beep();
30282a5c12eSMatthew Dillon 				continue;
30382a5c12eSMatthew Dillon 			}
30482a5c12eSMatthew Dillon 			driver = &drivers[c - 'a'];
30582a5c12eSMatthew Dillon 			break;
30682a5c12eSMatthew Dillon 		}
30782a5c12eSMatthew Dillon 
30882a5c12eSMatthew Dillon 		if (driver == NULL) {
30982a5c12eSMatthew Dillon 			waiting = 0;
31082a5c12eSMatthew Dillon 			if (numdrivers == 0) {
31182a5c12eSMatthew Dillon 				probe_cleanup();
31282a5c12eSMatthew Dillon 				return 0;	/* Failure */
31382a5c12eSMatthew Dillon 			}
31482a5c12eSMatthew Dillon 			if (numdrivers == 1) {
31582a5c12eSMatthew Dillon 				driver = &drivers[0];
31682a5c12eSMatthew Dillon 				break;
31782a5c12eSMatthew Dillon 			}
31882a5c12eSMatthew Dillon 			continue;
31982a5c12eSMatthew Dillon 		}
32082a5c12eSMatthew Dillon 
32182a5c12eSMatthew Dillon 		/* Use the preferred host straight away. */
32282a5c12eSMatthew Dillon 		if (Sock_host)
32382a5c12eSMatthew Dillon 			break;
32482a5c12eSMatthew Dillon 
32582a5c12eSMatthew Dillon 		if (numdrivers == 0) {
32682a5c12eSMatthew Dillon 			display_clear_the_screen();
32782a5c12eSMatthew Dillon 			display_move(1, 0);
32882a5c12eSMatthew Dillon 			display_put_str("Pick one:");
32982a5c12eSMatthew Dillon 		}
33082a5c12eSMatthew Dillon 
33182a5c12eSMatthew Dillon 		/* Mark the last driver we used with an asterisk */
33282a5c12eSMatthew Dillon 		is_current = (last_driver == -1 && Daemon.sa_len != 0 &&
33382a5c12eSMatthew Dillon 		    memcmp(&Daemon, &driver->addr, Daemon.sa_len) == 0);
33482a5c12eSMatthew Dillon 		if (is_current)
33582a5c12eSMatthew Dillon 			last_driver = numdrivers;
33682a5c12eSMatthew Dillon 
33782a5c12eSMatthew Dillon 		/* Display it in the list if there is room */
33882a5c12eSMatthew Dillon 		if (numdrivers < HEIGHT - 3) {
33982a5c12eSMatthew Dillon 			xname = driver_name(driver);
34082a5c12eSMatthew Dillon 			display_move(3 + numdrivers, 0);
34182a5c12eSMatthew Dillon 			snprintf(buf, sizeof buf, "%6c %c    %s",
34282a5c12eSMatthew Dillon 			    is_current ? '*' : ' ', 'a' + numdrivers, xname);
34382a5c12eSMatthew Dillon 			display_put_str(buf);
34482a5c12eSMatthew Dillon 		}
34582a5c12eSMatthew Dillon 
34682a5c12eSMatthew Dillon 		/* Clear the last 'Enter letter' line if any */
34782a5c12eSMatthew Dillon 		display_move(4 + numdrivers, 0);
34882a5c12eSMatthew Dillon 		display_clear_eol();
34982a5c12eSMatthew Dillon 
35082a5c12eSMatthew Dillon 		if (last_driver != -1)
35182a5c12eSMatthew Dillon 			snprintf(buf, sizeof buf, "Enter letter [%c]: ",
35282a5c12eSMatthew Dillon 			    'a' + last_driver);
35382a5c12eSMatthew Dillon 		else
35482a5c12eSMatthew Dillon 			snprintf(buf, sizeof buf, "Enter letter: ");
35582a5c12eSMatthew Dillon 
35682a5c12eSMatthew Dillon 		display_move(5 + numdrivers, 0);
35782a5c12eSMatthew Dillon 		display_put_str(buf);
35882a5c12eSMatthew Dillon 		display_refresh();
35982a5c12eSMatthew Dillon 
36082a5c12eSMatthew Dillon 		numdrivers++;
36182a5c12eSMatthew Dillon 	}
36282a5c12eSMatthew Dillon 
36382a5c12eSMatthew Dillon 	display_clear_the_screen();
36482a5c12eSMatthew Dillon 	Daemon = driver->addr;
36582a5c12eSMatthew Dillon 
36682a5c12eSMatthew Dillon 	probe_cleanup();
36782a5c12eSMatthew Dillon 	return 1;		/* Success */
36882a5c12eSMatthew Dillon }
36982a5c12eSMatthew Dillon 
37082a5c12eSMatthew Dillon static void
dump_scores(void)3716beb426bSSascha Wildner dump_scores(void)
37282a5c12eSMatthew Dillon {
37382a5c12eSMatthew Dillon 	struct	driver *driver;
37482a5c12eSMatthew Dillon 	int	s, cnt, i;
37582a5c12eSMatthew Dillon 	char	buf[1024];
37682a5c12eSMatthew Dillon 
37782a5c12eSMatthew Dillon 	probe_drivers(C_SCORES, Sock_host);
37882a5c12eSMatthew Dillon 	while ((driver = next_driver()) != NULL) {
37982a5c12eSMatthew Dillon 		printf("\n%s:\n", driver_name(driver));
38082a5c12eSMatthew Dillon 		fflush(stdout);
38182a5c12eSMatthew Dillon 
38282a5c12eSMatthew Dillon 		if ((s = socket(driver->addr.sa_family, SOCK_STREAM, 0)) < 0) {
38382a5c12eSMatthew Dillon 			warn("socket");
38482a5c12eSMatthew Dillon 			continue;
38582a5c12eSMatthew Dillon 		}
38682a5c12eSMatthew Dillon 		if (connect(s, &driver->addr, driver->addr.sa_len) < 0) {
38782a5c12eSMatthew Dillon 			warn("connect");
38882a5c12eSMatthew Dillon 			close(s);
38982a5c12eSMatthew Dillon 			continue;
39082a5c12eSMatthew Dillon 		}
39182a5c12eSMatthew Dillon 		while ((cnt = read(s, buf, sizeof buf)) > 0) {
39282a5c12eSMatthew Dillon 			/* Whittle out bad characters */
39382a5c12eSMatthew Dillon 			for (i = 0; i < cnt; i++)
39482a5c12eSMatthew Dillon 				if ((buf[i] < ' ' || buf[i] > '~') &&
39582a5c12eSMatthew Dillon 				    buf[i] != '\n' && buf[i] != '\t')
39682a5c12eSMatthew Dillon 					buf[i] = '?';
39782a5c12eSMatthew Dillon 			fwrite(buf, cnt, 1, stdout);
39882a5c12eSMatthew Dillon 		}
39982a5c12eSMatthew Dillon 		if (cnt < 0)
40082a5c12eSMatthew Dillon 			warn("read");
401*d9f85b33Szrj 		close(s);
40282a5c12eSMatthew Dillon 		if (Sock_host)
40382a5c12eSMatthew Dillon 			break;
40482a5c12eSMatthew Dillon 	}
40582a5c12eSMatthew Dillon 	probe_cleanup();
40682a5c12eSMatthew Dillon }
40782a5c12eSMatthew Dillon 
40882a5c12eSMatthew Dillon 
40982a5c12eSMatthew Dillon /*
41082a5c12eSMatthew Dillon  * bad_con:
41182a5c12eSMatthew Dillon  *	We had a bad connection.  For the moment we assume that this
41282a5c12eSMatthew Dillon  *	means the game is full.
41382a5c12eSMatthew Dillon  */
41482a5c12eSMatthew Dillon void
bad_con(void)4156beb426bSSascha Wildner bad_con(void)
41682a5c12eSMatthew Dillon {
41782a5c12eSMatthew Dillon 	leave(1, "lost connection to huntd");
41882a5c12eSMatthew Dillon }
41982a5c12eSMatthew Dillon 
42082a5c12eSMatthew Dillon /*
42182a5c12eSMatthew Dillon  * bad_ver:
42282a5c12eSMatthew Dillon  *	version number mismatch.
42382a5c12eSMatthew Dillon  */
42482a5c12eSMatthew Dillon void
bad_ver(void)4256beb426bSSascha Wildner bad_ver(void)
42682a5c12eSMatthew Dillon {
42782a5c12eSMatthew Dillon 	errno = 0;
42882a5c12eSMatthew Dillon 	leave(1, "Version number mismatch. No go.");
42982a5c12eSMatthew Dillon }
43082a5c12eSMatthew Dillon 
43182a5c12eSMatthew Dillon /*
43282a5c12eSMatthew Dillon  * sigterm:
43382a5c12eSMatthew Dillon  *	Handle a terminate signal
43482a5c12eSMatthew Dillon  */
43582a5c12eSMatthew Dillon static void
sigterm(int signo __unused)43682a5c12eSMatthew Dillon sigterm(int signo __unused)
43782a5c12eSMatthew Dillon {
4382038fb68SSascha Wildner 	leave(0, NULL);
43982a5c12eSMatthew Dillon }
44082a5c12eSMatthew Dillon 
44182a5c12eSMatthew Dillon /*
44282a5c12eSMatthew Dillon  * rmnl:
44382a5c12eSMatthew Dillon  *	Remove a '\n' at the end of a string if there is one
44482a5c12eSMatthew Dillon  */
44582a5c12eSMatthew Dillon static void
rmnl(char * s)44682a5c12eSMatthew Dillon rmnl(char *s)
44782a5c12eSMatthew Dillon {
44882a5c12eSMatthew Dillon 	char	*cp;
44982a5c12eSMatthew Dillon 
45082a5c12eSMatthew Dillon 	cp = strrchr(s, '\n');
45182a5c12eSMatthew Dillon 	if (cp != NULL)
45282a5c12eSMatthew Dillon 		*cp = '\0';
45382a5c12eSMatthew Dillon }
45482a5c12eSMatthew Dillon 
45582a5c12eSMatthew Dillon /*
45682a5c12eSMatthew Dillon  * intr:
45782a5c12eSMatthew Dillon  *	Handle a interrupt signal
45882a5c12eSMatthew Dillon  */
45982a5c12eSMatthew Dillon void
intr(int dummy __unused)46082a5c12eSMatthew Dillon intr(int dummy __unused)
46182a5c12eSMatthew Dillon {
46282a5c12eSMatthew Dillon 	int	ch;
46382a5c12eSMatthew Dillon 	int	explained;
46482a5c12eSMatthew Dillon 	int	y, x;
46582a5c12eSMatthew Dillon 
466*d9f85b33Szrj 	signal(SIGINT, SIG_IGN);
46782a5c12eSMatthew Dillon 	display_getyx(&y, &x);
46882a5c12eSMatthew Dillon 	display_move(HEIGHT, 0);
46982a5c12eSMatthew Dillon 	display_put_str("Really quit? ");
47082a5c12eSMatthew Dillon 	display_clear_eol();
47182a5c12eSMatthew Dillon 	display_refresh();
47282a5c12eSMatthew Dillon 	explained = FALSE;
47382a5c12eSMatthew Dillon 	for (;;) {
47482a5c12eSMatthew Dillon 		ch = getchar();
47582a5c12eSMatthew Dillon 		if (isupper(ch))
47682a5c12eSMatthew Dillon 			ch = tolower(ch);
47782a5c12eSMatthew Dillon 		if (ch == 'y') {
47882a5c12eSMatthew Dillon 			if (Socket != 0) {
479*d9f85b33Szrj 				write(Socket, "q", 1);
480*d9f85b33Szrj 				close(Socket);
48182a5c12eSMatthew Dillon 			}
4822038fb68SSascha Wildner 			leave(0, NULL);
48382a5c12eSMatthew Dillon 		}
48482a5c12eSMatthew Dillon 		else if (ch == 'n') {
485*d9f85b33Szrj 			signal(SIGINT, intr);
48682a5c12eSMatthew Dillon 			display_move(y, x);
48782a5c12eSMatthew Dillon 			display_refresh();
48882a5c12eSMatthew Dillon 			return;
48982a5c12eSMatthew Dillon 		}
49082a5c12eSMatthew Dillon 		if (!explained) {
49182a5c12eSMatthew Dillon 			display_put_str("(Yes or No) ");
49282a5c12eSMatthew Dillon 			display_refresh();
49382a5c12eSMatthew Dillon 			explained = TRUE;
49482a5c12eSMatthew Dillon 		}
49582a5c12eSMatthew Dillon 		display_beep();
49682a5c12eSMatthew Dillon 		display_refresh();
49782a5c12eSMatthew Dillon 	}
49882a5c12eSMatthew Dillon }
49982a5c12eSMatthew Dillon 
50082a5c12eSMatthew Dillon /*
50182a5c12eSMatthew Dillon  * leave:
50282a5c12eSMatthew Dillon  *	Leave the game somewhat gracefully, restoring all current
50382a5c12eSMatthew Dillon  *	tty stats.
50482a5c12eSMatthew Dillon  */
50582a5c12eSMatthew Dillon static void
leave(int eval,const char * mesg)50682a5c12eSMatthew Dillon leave(int eval, const char *mesg)
50782a5c12eSMatthew Dillon {
50882a5c12eSMatthew Dillon 	int saved_errno;
50982a5c12eSMatthew Dillon 
51082a5c12eSMatthew Dillon 	saved_errno = errno;
51182a5c12eSMatthew Dillon 	if (in_visual) {
51282a5c12eSMatthew Dillon 		display_move(HEIGHT, 0);
51382a5c12eSMatthew Dillon 		display_refresh();
51482a5c12eSMatthew Dillon 		display_end();
51582a5c12eSMatthew Dillon 	}
51682a5c12eSMatthew Dillon 	errno = saved_errno;
51782a5c12eSMatthew Dillon 
51882a5c12eSMatthew Dillon 	if (errno == 0 && mesg != NULL)
5199462167aSSascha Wildner 		errx(eval, "%s", mesg);
52082a5c12eSMatthew Dillon 	else if (mesg != NULL)
5219462167aSSascha Wildner 		err(eval, "%s", mesg);
52282a5c12eSMatthew Dillon 	exit(eval);
52382a5c12eSMatthew Dillon }
52482a5c12eSMatthew Dillon 
52582a5c12eSMatthew Dillon /*
52682a5c12eSMatthew Dillon  * env_init:
52782a5c12eSMatthew Dillon  *	initialise game parameters from the HUNT envvar
52882a5c12eSMatthew Dillon  */
52982a5c12eSMatthew Dillon static long
env_init(long enter_status)5306beb426bSSascha Wildner env_init(long enter_status)
53182a5c12eSMatthew Dillon {
53282a5c12eSMatthew Dillon 	int	i;
53382a5c12eSMatthew Dillon 	char	*envp, *envname, *s;
53482a5c12eSMatthew Dillon 
53582a5c12eSMatthew Dillon 	/* Map all keys to themselves: */
53682a5c12eSMatthew Dillon 	for (i = 0; i < 256; i++)
53782a5c12eSMatthew Dillon 		map_key[i] = (char) i;
53882a5c12eSMatthew Dillon 
53982a5c12eSMatthew Dillon 	envname = NULL;
54082a5c12eSMatthew Dillon 	if ((envp = getenv("HUNT")) != NULL) {
54182a5c12eSMatthew Dillon 		while ((s = strpbrk(envp, "=,")) != NULL) {
54282a5c12eSMatthew Dillon 			if (strncmp(envp, "cloak,", s - envp + 1) == 0) {
54382a5c12eSMatthew Dillon 				enter_status = Q_CLOAK;
54482a5c12eSMatthew Dillon 				envp = s + 1;
54582a5c12eSMatthew Dillon 			}
54682a5c12eSMatthew Dillon 			else if (strncmp(envp, "scan,", s - envp + 1) == 0) {
54782a5c12eSMatthew Dillon 				enter_status = Q_SCAN;
54882a5c12eSMatthew Dillon 				envp = s + 1;
54982a5c12eSMatthew Dillon 			}
55082a5c12eSMatthew Dillon 			else if (strncmp(envp, "fly,", s - envp + 1) == 0) {
55182a5c12eSMatthew Dillon 				enter_status = Q_FLY;
55282a5c12eSMatthew Dillon 				envp = s + 1;
55382a5c12eSMatthew Dillon 			}
55482a5c12eSMatthew Dillon 			else if (strncmp(envp, "nobeep,", s - envp + 1) == 0) {
55582a5c12eSMatthew Dillon 				no_beep = TRUE;
55682a5c12eSMatthew Dillon 				envp = s + 1;
55782a5c12eSMatthew Dillon 			}
55882a5c12eSMatthew Dillon 			else if (strncmp(envp, "name=", s - envp + 1) == 0) {
55982a5c12eSMatthew Dillon 				envname = s + 1;
56082a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
56182a5c12eSMatthew Dillon 					*envp = '\0';
56282a5c12eSMatthew Dillon 					strlcpy(name, envname, sizeof name);
56382a5c12eSMatthew Dillon 					break;
56482a5c12eSMatthew Dillon 				}
56582a5c12eSMatthew Dillon 				*s = '\0';
56682a5c12eSMatthew Dillon 				strlcpy(name, envname, sizeof name);
56782a5c12eSMatthew Dillon 				envp = s + 1;
56882a5c12eSMatthew Dillon 			}
56982a5c12eSMatthew Dillon 			else if (strncmp(envp, "port=", s - envp + 1) == 0) {
57082a5c12eSMatthew Dillon 				use_port = s + 1;
57182a5c12eSMatthew Dillon 				Server_port = atoi(use_port);
57282a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
57382a5c12eSMatthew Dillon 					*envp = '\0';
57482a5c12eSMatthew Dillon 					break;
57582a5c12eSMatthew Dillon 				}
57682a5c12eSMatthew Dillon 				*s = '\0';
57782a5c12eSMatthew Dillon 				envp = s + 1;
57882a5c12eSMatthew Dillon 			}
57982a5c12eSMatthew Dillon 			else if (strncmp(envp, "host=", s - envp + 1) == 0) {
58082a5c12eSMatthew Dillon 				Sock_host = s + 1;
58182a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
58282a5c12eSMatthew Dillon 					*envp = '\0';
58382a5c12eSMatthew Dillon 					break;
58482a5c12eSMatthew Dillon 				}
58582a5c12eSMatthew Dillon 				*s = '\0';
58682a5c12eSMatthew Dillon 				envp = s + 1;
58782a5c12eSMatthew Dillon 			}
58882a5c12eSMatthew Dillon 			else if (strncmp(envp, "message=", s - envp + 1) == 0) {
58982a5c12eSMatthew Dillon 				Send_message = s + 1;
59082a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
59182a5c12eSMatthew Dillon 					*envp = '\0';
59282a5c12eSMatthew Dillon 					break;
59382a5c12eSMatthew Dillon 				}
59482a5c12eSMatthew Dillon 				*s = '\0';
59582a5c12eSMatthew Dillon 				envp = s + 1;
59682a5c12eSMatthew Dillon 			}
59782a5c12eSMatthew Dillon 			else if (strncmp(envp, "team=", s - envp + 1) == 0) {
59882a5c12eSMatthew Dillon 				team = *(s + 1);
59982a5c12eSMatthew Dillon 				if (!isdigit(team))
60082a5c12eSMatthew Dillon 					team = ' ';
60182a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
60282a5c12eSMatthew Dillon 					*envp = '\0';
60382a5c12eSMatthew Dillon 					break;
60482a5c12eSMatthew Dillon 				}
60582a5c12eSMatthew Dillon 				*s = '\0';
60682a5c12eSMatthew Dillon 				envp = s + 1;
60782a5c12eSMatthew Dillon 			}			/* must be last option */
60882a5c12eSMatthew Dillon 			else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
60982a5c12eSMatthew Dillon 				for (s = s + 1; *s != '\0'; s += 2) {
61082a5c12eSMatthew Dillon 					map_key[(unsigned int) *s] = *(s + 1);
61182a5c12eSMatthew Dillon 					if (*(s + 1) == '\0') {
61282a5c12eSMatthew Dillon 						break;
61382a5c12eSMatthew Dillon 					}
61482a5c12eSMatthew Dillon 				}
61582a5c12eSMatthew Dillon 				*envp = '\0';
61682a5c12eSMatthew Dillon 				break;
61782a5c12eSMatthew Dillon 			} else {
61882a5c12eSMatthew Dillon 				*s = '\0';
61982a5c12eSMatthew Dillon 				printf("unknown option %s\n", envp);
62082a5c12eSMatthew Dillon 				if ((s = strchr(envp, ',')) == NULL) {
62182a5c12eSMatthew Dillon 					*envp = '\0';
62282a5c12eSMatthew Dillon 					break;
62382a5c12eSMatthew Dillon 				}
62482a5c12eSMatthew Dillon 				envp = s + 1;
62582a5c12eSMatthew Dillon 			}
62682a5c12eSMatthew Dillon 		}
62782a5c12eSMatthew Dillon 		if (*envp != '\0') {
62882a5c12eSMatthew Dillon 			if (envname == NULL)
62982a5c12eSMatthew Dillon 				strlcpy(name, envp, sizeof name);
63082a5c12eSMatthew Dillon 			else
63182a5c12eSMatthew Dillon 				printf("unknown option %s\n", envp);
63282a5c12eSMatthew Dillon 		}
63382a5c12eSMatthew Dillon 	}
63482a5c12eSMatthew Dillon 	return enter_status;
63582a5c12eSMatthew Dillon }
63682a5c12eSMatthew Dillon 
63782a5c12eSMatthew Dillon /*
63882a5c12eSMatthew Dillon  * fill_in_blanks:
63982a5c12eSMatthew Dillon  *	quiz the user for the information they didn't provide earlier
64082a5c12eSMatthew Dillon  */
64182a5c12eSMatthew Dillon static void
fill_in_blanks(void)6426beb426bSSascha Wildner fill_in_blanks(void)
64382a5c12eSMatthew Dillon {
64482a5c12eSMatthew Dillon 	int	i;
64582a5c12eSMatthew Dillon 	char	*cp;
64682a5c12eSMatthew Dillon 
64782a5c12eSMatthew Dillon again:
64882a5c12eSMatthew Dillon 	if (name[0] != '\0') {
64982a5c12eSMatthew Dillon 		printf("Entering as '%s'", name);
65082a5c12eSMatthew Dillon 		if (team != ' ' && team != '-')
65182a5c12eSMatthew Dillon 			printf(" on team %c.\n", team);
65282a5c12eSMatthew Dillon 		else
65382a5c12eSMatthew Dillon 			putchar('\n');
65482a5c12eSMatthew Dillon 	} else {
65582a5c12eSMatthew Dillon 		printf("Enter your code name: ");
65682a5c12eSMatthew Dillon 		if (fgets(name, sizeof name, stdin) == NULL)
65782a5c12eSMatthew Dillon 			exit(1);
65882a5c12eSMatthew Dillon 	}
65982a5c12eSMatthew Dillon 	rmnl(name);
66082a5c12eSMatthew Dillon 	if (name[0] == '\0') {
66182a5c12eSMatthew Dillon 		printf("You have to have a code name!\n");
66282a5c12eSMatthew Dillon 		goto again;
66382a5c12eSMatthew Dillon 	}
66482a5c12eSMatthew Dillon 	for (cp = name; *cp != '\0'; cp++)
66582a5c12eSMatthew Dillon 		if (!isprint(*cp)) {
66682a5c12eSMatthew Dillon 			name[0] = '\0';
66782a5c12eSMatthew Dillon 			printf("Illegal character in your code name.\n");
66882a5c12eSMatthew Dillon 			goto again;
66982a5c12eSMatthew Dillon 		}
67082a5c12eSMatthew Dillon 	if (team == '-') {
67182a5c12eSMatthew Dillon 		printf("Enter your team (0-9 or nothing): ");
67282a5c12eSMatthew Dillon 		i = getchar();
67382a5c12eSMatthew Dillon 		if (isdigit(i))
67482a5c12eSMatthew Dillon 			team = i;
67582a5c12eSMatthew Dillon 		else if (i == '\n' || i == EOF || i == ' ')
67682a5c12eSMatthew Dillon 			team = ' ';
67782a5c12eSMatthew Dillon 		/* ignore trailing chars */
67882a5c12eSMatthew Dillon 		while (i != '\n' && i != EOF)
67982a5c12eSMatthew Dillon 			i = getchar();
68082a5c12eSMatthew Dillon 		if (team == '-') {
68182a5c12eSMatthew Dillon 			printf("Teams must be numeric.\n");
68282a5c12eSMatthew Dillon 			goto again;
68382a5c12eSMatthew Dillon 		}
68482a5c12eSMatthew Dillon 	}
68582a5c12eSMatthew Dillon }
686