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