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: answer.c,v 1.11 2007/11/06 10:22:29 chl Exp $
3282a5c12eSMatthew Dillon * $NetBSD: answer.c,v 1.3 1997/10/10 16:32:50 lukem Exp $
3382a5c12eSMatthew Dillon */
3482a5c12eSMatthew Dillon
3582a5c12eSMatthew Dillon #include <sys/socket.h>
3682a5c12eSMatthew Dillon #include <netinet/in.h>
3782a5c12eSMatthew Dillon #include <arpa/inet.h>
3882a5c12eSMatthew Dillon
3982a5c12eSMatthew Dillon #include <ctype.h>
4082a5c12eSMatthew Dillon #include <errno.h>
4182a5c12eSMatthew Dillon #include <fcntl.h>
4282a5c12eSMatthew Dillon #include <stdlib.h>
4382a5c12eSMatthew Dillon #include <unistd.h>
4482a5c12eSMatthew Dillon #include <stdio.h>
4582a5c12eSMatthew Dillon #include <syslog.h>
4682a5c12eSMatthew Dillon #include <string.h>
4782a5c12eSMatthew Dillon #include <tcpd.h>
4882a5c12eSMatthew Dillon
4982a5c12eSMatthew Dillon #include "hunt.h"
5082a5c12eSMatthew Dillon #include "server.h"
5182a5c12eSMatthew Dillon #include "conf.h"
5282a5c12eSMatthew Dillon
5382a5c12eSMatthew Dillon /* Exported symbols for hosts_access(): */
5482a5c12eSMatthew Dillon int allow_severity = LOG_INFO;
5582a5c12eSMatthew Dillon int deny_severity = LOG_WARNING;
5682a5c12eSMatthew Dillon
5782a5c12eSMatthew Dillon
5882a5c12eSMatthew Dillon /* List of spawning connections: */
5982a5c12eSMatthew Dillon struct spawn *Spawn = NULL;
6082a5c12eSMatthew Dillon
6182a5c12eSMatthew Dillon static void stplayer(PLAYER *, int);
6282a5c12eSMatthew Dillon static void stmonitor(PLAYER *);
6382a5c12eSMatthew Dillon static IDENT * get_ident(struct sockaddr *, int, uid_t, char *, char);
6482a5c12eSMatthew Dillon
6582a5c12eSMatthew Dillon void
answer_first(void)666beb426bSSascha Wildner answer_first(void)
6782a5c12eSMatthew Dillon {
6882a5c12eSMatthew Dillon struct sockaddr sockstruct;
6982a5c12eSMatthew Dillon int newsock;
7082a5c12eSMatthew Dillon socklen_t socklen;
7182a5c12eSMatthew Dillon int flags;
7282a5c12eSMatthew Dillon struct request_info ri;
7382a5c12eSMatthew Dillon struct spawn *sp;
7482a5c12eSMatthew Dillon
7582a5c12eSMatthew Dillon /* Answer the call to hunt: */
7682a5c12eSMatthew Dillon socklen = sizeof sockstruct;
7782a5c12eSMatthew Dillon newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen);
7882a5c12eSMatthew Dillon if (newsock < 0) {
7982a5c12eSMatthew Dillon logit(LOG_ERR, "accept");
8082a5c12eSMatthew Dillon return;
8182a5c12eSMatthew Dillon }
8282a5c12eSMatthew Dillon
8382a5c12eSMatthew Dillon /* Check for access permissions: */
8482a5c12eSMatthew Dillon request_init(&ri, RQ_DAEMON, "huntd", RQ_FILE, newsock, 0);
8582a5c12eSMatthew Dillon fromhost(&ri);
8682a5c12eSMatthew Dillon if (hosts_access(&ri) == 0) {
8782a5c12eSMatthew Dillon logx(LOG_INFO, "rejected connection from %s", eval_client(&ri));
8882a5c12eSMatthew Dillon close(newsock);
8982a5c12eSMatthew Dillon return;
9082a5c12eSMatthew Dillon }
9182a5c12eSMatthew Dillon
9282a5c12eSMatthew Dillon /* Remember this spawning connection: */
9382a5c12eSMatthew Dillon sp = (struct spawn *)malloc(sizeof *sp);
9482a5c12eSMatthew Dillon if (sp == NULL) {
9582a5c12eSMatthew Dillon logit(LOG_ERR, "malloc");
9682a5c12eSMatthew Dillon close(newsock);
9782a5c12eSMatthew Dillon return;
9882a5c12eSMatthew Dillon }
9982a5c12eSMatthew Dillon memset(sp, '\0', sizeof *sp);
10082a5c12eSMatthew Dillon
10182a5c12eSMatthew Dillon /* Keep the calling machine's source addr for ident purposes: */
10282a5c12eSMatthew Dillon memcpy(&sp->source, &sockstruct, sizeof sp->source);
10382a5c12eSMatthew Dillon sp->sourcelen = socklen;
10482a5c12eSMatthew Dillon
10582a5c12eSMatthew Dillon /* Warn if we lose connection info: */
10682a5c12eSMatthew Dillon if (socklen > sizeof Spawn->source)
10782a5c12eSMatthew Dillon logx(LOG_WARNING,
10882a5c12eSMatthew Dillon "struct sockaddr is not big enough! (%d > %zu)",
10982a5c12eSMatthew Dillon socklen, sizeof Spawn->source);
11082a5c12eSMatthew Dillon
11182a5c12eSMatthew Dillon /*
11282a5c12eSMatthew Dillon * Turn off blocking I/O, so a slow or dead terminal won't stop
11382a5c12eSMatthew Dillon * the game. All subsequent reads check how many bytes they read.
11482a5c12eSMatthew Dillon */
11582a5c12eSMatthew Dillon flags = fcntl(newsock, F_GETFL, 0);
11682a5c12eSMatthew Dillon flags |= O_NDELAY;
117*d9f85b33Szrj fcntl(newsock, F_SETFL, flags);
11882a5c12eSMatthew Dillon
11982a5c12eSMatthew Dillon /* Start listening to the spawning connection */
12082a5c12eSMatthew Dillon sp->fd = newsock;
12182a5c12eSMatthew Dillon FD_SET(sp->fd, &Fds_mask);
12282a5c12eSMatthew Dillon if (sp->fd >= Num_fds)
12382a5c12eSMatthew Dillon Num_fds = sp->fd + 1;
12482a5c12eSMatthew Dillon
12582a5c12eSMatthew Dillon sp->reading_msg = 0;
12682a5c12eSMatthew Dillon sp->inlen = 0;
12782a5c12eSMatthew Dillon
12882a5c12eSMatthew Dillon /* Add to the spawning list */
12982a5c12eSMatthew Dillon if ((sp->next = Spawn) != NULL)
13082a5c12eSMatthew Dillon Spawn->prevnext = &sp->next;
13182a5c12eSMatthew Dillon sp->prevnext = &Spawn;
13282a5c12eSMatthew Dillon Spawn = sp;
13382a5c12eSMatthew Dillon }
13482a5c12eSMatthew Dillon
13582a5c12eSMatthew Dillon int
answer_next(struct spawn * sp)1366beb426bSSascha Wildner answer_next(struct spawn *sp)
13782a5c12eSMatthew Dillon {
13882a5c12eSMatthew Dillon PLAYER *pp;
13982a5c12eSMatthew Dillon char *cp1, *cp2;
14082a5c12eSMatthew Dillon u_int32_t version;
14182a5c12eSMatthew Dillon FILE *conn;
14282a5c12eSMatthew Dillon int len;
14382a5c12eSMatthew Dillon char teamstr[] = "[x]";
14482a5c12eSMatthew Dillon
14582a5c12eSMatthew Dillon if (sp->reading_msg) {
14682a5c12eSMatthew Dillon /* Receive a message from a player */
14782a5c12eSMatthew Dillon len = read(sp->fd, sp->msg + sp->msglen,
14882a5c12eSMatthew Dillon sizeof sp->msg - sp->msglen);
14982a5c12eSMatthew Dillon if (len < 0)
15082a5c12eSMatthew Dillon goto error;
15182a5c12eSMatthew Dillon sp->msglen += len;
15282a5c12eSMatthew Dillon if (len && sp->msglen < (int)(sizeof sp->msg))
15382a5c12eSMatthew Dillon return FALSE;
15482a5c12eSMatthew Dillon
15582a5c12eSMatthew Dillon teamstr[1] = sp->team;
15682a5c12eSMatthew Dillon outyx(ALL_PLAYERS, HEIGHT, 0, "%s%s: %.*s",
15782a5c12eSMatthew Dillon sp->name,
15882a5c12eSMatthew Dillon sp->team == ' ' ? "": teamstr,
15982a5c12eSMatthew Dillon sp->msglen,
16082a5c12eSMatthew Dillon sp->msg);
16182a5c12eSMatthew Dillon ce(ALL_PLAYERS);
16282a5c12eSMatthew Dillon sendcom(ALL_PLAYERS, REFRESH);
16382a5c12eSMatthew Dillon sendcom(ALL_PLAYERS, READY, 0);
16482a5c12eSMatthew Dillon flush(ALL_PLAYERS);
16582a5c12eSMatthew Dillon goto close_it;
16682a5c12eSMatthew Dillon }
16782a5c12eSMatthew Dillon
16882a5c12eSMatthew Dillon /* Fill the buffer */
16982a5c12eSMatthew Dillon len = read(sp->fd, sp->inbuf + sp->inlen,
17082a5c12eSMatthew Dillon sizeof sp->inbuf - sp->inlen);
17182a5c12eSMatthew Dillon if (len <= 0)
17282a5c12eSMatthew Dillon goto error;
17382a5c12eSMatthew Dillon sp->inlen += len;
17482a5c12eSMatthew Dillon if (sp->inlen < (int)(sizeof sp->inbuf))
17582a5c12eSMatthew Dillon return FALSE;
17682a5c12eSMatthew Dillon
17782a5c12eSMatthew Dillon /* Extract values from the buffer */
17882a5c12eSMatthew Dillon cp1 = sp->inbuf;
17982a5c12eSMatthew Dillon memcpy(&sp->uid, cp1, sizeof (u_int32_t));
18082a5c12eSMatthew Dillon cp1+= sizeof(u_int32_t);
18182a5c12eSMatthew Dillon memcpy(sp->name, cp1, NAMELEN);
18282a5c12eSMatthew Dillon cp1+= NAMELEN;
18382a5c12eSMatthew Dillon memcpy(&sp->team, cp1, sizeof (u_int8_t));
18482a5c12eSMatthew Dillon cp1+= sizeof(u_int8_t);
18582a5c12eSMatthew Dillon memcpy(&sp->enter_status, cp1, sizeof (u_int32_t));
18682a5c12eSMatthew Dillon cp1+= sizeof(u_int32_t);
18782a5c12eSMatthew Dillon memcpy(sp->ttyname, cp1, NAMELEN);
18882a5c12eSMatthew Dillon cp1+= NAMELEN;
18982a5c12eSMatthew Dillon memcpy(&sp->mode, cp1, sizeof (u_int32_t));
19082a5c12eSMatthew Dillon cp1+= sizeof(u_int32_t);
19182a5c12eSMatthew Dillon
19282a5c12eSMatthew Dillon /* Convert data from network byte order: */
19382a5c12eSMatthew Dillon sp->uid = ntohl(sp->uid);
19482a5c12eSMatthew Dillon sp->enter_status = ntohl(sp->enter_status);
19582a5c12eSMatthew Dillon sp->mode = ntohl(sp->mode);
19682a5c12eSMatthew Dillon
19782a5c12eSMatthew Dillon /*
19882a5c12eSMatthew Dillon * Make sure the name contains only printable characters
19982a5c12eSMatthew Dillon * since we use control characters for cursor control
20082a5c12eSMatthew Dillon * between driver and player processes
20182a5c12eSMatthew Dillon */
20282a5c12eSMatthew Dillon sp->name[NAMELEN] = '\0';
20382a5c12eSMatthew Dillon for (cp1 = cp2 = sp->name; *cp1 != '\0'; cp1++)
20482a5c12eSMatthew Dillon if (isprint(*cp1) || *cp1 == ' ')
20582a5c12eSMatthew Dillon *cp2++ = *cp1;
20682a5c12eSMatthew Dillon *cp2 = '\0';
20782a5c12eSMatthew Dillon
20882a5c12eSMatthew Dillon /* Make sure team name is valid */
20982a5c12eSMatthew Dillon if (sp->team < '1' || sp->team > '9')
21082a5c12eSMatthew Dillon sp->team = ' ';
21182a5c12eSMatthew Dillon
21282a5c12eSMatthew Dillon /* Tell the other end this server's hunt driver version: */
21382a5c12eSMatthew Dillon version = htonl((u_int32_t) HUNT_VERSION);
214*d9f85b33Szrj write(sp->fd, &version, sizeof version);
21582a5c12eSMatthew Dillon
21682a5c12eSMatthew Dillon if (sp->mode == C_MESSAGE) {
21782a5c12eSMatthew Dillon /* The clients only wants to send a message: */
21882a5c12eSMatthew Dillon sp->msglen = 0;
21982a5c12eSMatthew Dillon sp->reading_msg = 1;
22082a5c12eSMatthew Dillon return FALSE;
22182a5c12eSMatthew Dillon }
22282a5c12eSMatthew Dillon
22382a5c12eSMatthew Dillon /* Use a stdio file descriptor from now on: */
22482a5c12eSMatthew Dillon conn = fdopen(sp->fd, "w");
22582a5c12eSMatthew Dillon
22682a5c12eSMatthew Dillon /* The player is a monitor: */
22782a5c12eSMatthew Dillon if (sp->mode == C_MONITOR) {
22882a5c12eSMatthew Dillon if (conf_monitor && End_monitor < &Monitor[MAXMON]) {
22982a5c12eSMatthew Dillon pp = End_monitor++;
23082a5c12eSMatthew Dillon if (sp->team == ' ')
23182a5c12eSMatthew Dillon sp->team = '*';
23282a5c12eSMatthew Dillon } else {
23382a5c12eSMatthew Dillon /* Too many monitors */
23482a5c12eSMatthew Dillon fprintf(conn, "Too many monitors\n");
23582a5c12eSMatthew Dillon fflush(conn);
23682a5c12eSMatthew Dillon logx(LOG_NOTICE, "too many monitors");
23782a5c12eSMatthew Dillon goto close_it;
23882a5c12eSMatthew Dillon }
23982a5c12eSMatthew Dillon
24082a5c12eSMatthew Dillon /* The player is a normal hunter: */
24182a5c12eSMatthew Dillon } else {
24282a5c12eSMatthew Dillon if (End_player < &Player[MAXPL])
24382a5c12eSMatthew Dillon pp = End_player++;
24482a5c12eSMatthew Dillon else {
24582a5c12eSMatthew Dillon fprintf(conn, "Too many players\n");
24682a5c12eSMatthew Dillon fflush(conn);
24782a5c12eSMatthew Dillon /* Too many players */
24882a5c12eSMatthew Dillon logx(LOG_NOTICE, "too many players");
24982a5c12eSMatthew Dillon goto close_it;
25082a5c12eSMatthew Dillon }
25182a5c12eSMatthew Dillon }
25282a5c12eSMatthew Dillon
25382a5c12eSMatthew Dillon /* Find the player's running scorecard */
25482a5c12eSMatthew Dillon pp->p_ident = get_ident(&sp->source, sp->sourcelen, sp->uid,
25582a5c12eSMatthew Dillon sp->name, sp->team);
25682a5c12eSMatthew Dillon pp->p_output = conn;
25782a5c12eSMatthew Dillon pp->p_death[0] = '\0';
25882a5c12eSMatthew Dillon pp->p_fd = sp->fd;
25982a5c12eSMatthew Dillon
26082a5c12eSMatthew Dillon /* No idea where the player starts: */
26182a5c12eSMatthew Dillon pp->p_y = 0;
26282a5c12eSMatthew Dillon pp->p_x = 0;
26382a5c12eSMatthew Dillon
26482a5c12eSMatthew Dillon /* Mode-specific initialisation: */
26582a5c12eSMatthew Dillon if (sp->mode == C_MONITOR)
26682a5c12eSMatthew Dillon stmonitor(pp);
26782a5c12eSMatthew Dillon else
26882a5c12eSMatthew Dillon stplayer(pp, sp->enter_status);
26982a5c12eSMatthew Dillon
27082a5c12eSMatthew Dillon /* And, they're off! Caller should remove and free sp. */
27182a5c12eSMatthew Dillon return TRUE;
27282a5c12eSMatthew Dillon
27382a5c12eSMatthew Dillon error:
27482a5c12eSMatthew Dillon if (len < 0)
27582a5c12eSMatthew Dillon logit(LOG_WARNING, "read");
27682a5c12eSMatthew Dillon else
27782a5c12eSMatthew Dillon logx(LOG_WARNING, "lost connection to new client");
27882a5c12eSMatthew Dillon
27982a5c12eSMatthew Dillon close_it:
28082a5c12eSMatthew Dillon /* Destroy the spawn */
28182a5c12eSMatthew Dillon *sp->prevnext = sp->next;
28282a5c12eSMatthew Dillon if (sp->next) sp->next->prevnext = sp->prevnext;
28382a5c12eSMatthew Dillon FD_CLR(sp->fd, &Fds_mask);
28482a5c12eSMatthew Dillon close(sp->fd);
28582a5c12eSMatthew Dillon free(sp);
28682a5c12eSMatthew Dillon return FALSE;
28782a5c12eSMatthew Dillon }
28882a5c12eSMatthew Dillon
28982a5c12eSMatthew Dillon /* Start a monitor: */
29082a5c12eSMatthew Dillon static void
stmonitor(PLAYER * pp)2916beb426bSSascha Wildner stmonitor(PLAYER *pp)
29282a5c12eSMatthew Dillon {
29382a5c12eSMatthew Dillon
29482a5c12eSMatthew Dillon /* Monitors get to see the entire maze: */
29582a5c12eSMatthew Dillon memcpy(pp->p_maze, Maze, sizeof pp->p_maze);
29682a5c12eSMatthew Dillon drawmaze(pp);
29782a5c12eSMatthew Dillon
29882a5c12eSMatthew Dillon /* Put the monitor's name near the bottom right on all screens: */
29982a5c12eSMatthew Dillon outyx(ALL_PLAYERS,
30082a5c12eSMatthew Dillon STAT_MON_ROW + 1 + (pp - Monitor), STAT_NAME_COL,
30182a5c12eSMatthew Dillon "%5.5s%c%-10.10s %c", " ",
30282a5c12eSMatthew Dillon stat_char(pp), pp->p_ident->i_name, pp->p_ident->i_team);
30382a5c12eSMatthew Dillon
30482a5c12eSMatthew Dillon /* Ready the monitor: */
30582a5c12eSMatthew Dillon sendcom(pp, REFRESH);
30682a5c12eSMatthew Dillon sendcom(pp, READY, 0);
30782a5c12eSMatthew Dillon flush(pp);
30882a5c12eSMatthew Dillon }
30982a5c12eSMatthew Dillon
31082a5c12eSMatthew Dillon /* Start a player: */
31182a5c12eSMatthew Dillon static void
stplayer(PLAYER * newpp,int enter_status)3126beb426bSSascha Wildner stplayer(PLAYER *newpp, int enter_status)
31382a5c12eSMatthew Dillon {
31482a5c12eSMatthew Dillon int x, y;
31582a5c12eSMatthew Dillon PLAYER *pp;
31682a5c12eSMatthew Dillon int len;
31782a5c12eSMatthew Dillon
31882a5c12eSMatthew Dillon Nplayer++;
31982a5c12eSMatthew Dillon
32082a5c12eSMatthew Dillon for (y = 0; y < UBOUND; y++)
32182a5c12eSMatthew Dillon for (x = 0; x < WIDTH; x++)
32282a5c12eSMatthew Dillon newpp->p_maze[y][x] = Maze[y][x];
32382a5c12eSMatthew Dillon for ( ; y < DBOUND; y++) {
32482a5c12eSMatthew Dillon for (x = 0; x < LBOUND; x++)
32582a5c12eSMatthew Dillon newpp->p_maze[y][x] = Maze[y][x];
32682a5c12eSMatthew Dillon for ( ; x < RBOUND; x++)
32782a5c12eSMatthew Dillon newpp->p_maze[y][x] = SPACE;
32882a5c12eSMatthew Dillon for ( ; x < WIDTH; x++)
32982a5c12eSMatthew Dillon newpp->p_maze[y][x] = Maze[y][x];
33082a5c12eSMatthew Dillon }
33182a5c12eSMatthew Dillon for ( ; y < HEIGHT; y++)
33282a5c12eSMatthew Dillon for (x = 0; x < WIDTH; x++)
33382a5c12eSMatthew Dillon newpp->p_maze[y][x] = Maze[y][x];
33482a5c12eSMatthew Dillon
33582a5c12eSMatthew Dillon /* Drop the new player somewhere in the maze: */
33682a5c12eSMatthew Dillon do {
33782a5c12eSMatthew Dillon x = rand_num(WIDTH - 1) + 1;
33882a5c12eSMatthew Dillon y = rand_num(HEIGHT - 1) + 1;
33982a5c12eSMatthew Dillon } while (Maze[y][x] != SPACE);
34082a5c12eSMatthew Dillon newpp->p_over = SPACE;
34182a5c12eSMatthew Dillon newpp->p_x = x;
34282a5c12eSMatthew Dillon newpp->p_y = y;
34382a5c12eSMatthew Dillon newpp->p_undershot = FALSE;
34482a5c12eSMatthew Dillon
34582a5c12eSMatthew Dillon /* Send them flying if needed */
34682a5c12eSMatthew Dillon if (enter_status == Q_FLY && conf_fly) {
34782a5c12eSMatthew Dillon newpp->p_flying = rand_num(conf_flytime);
34882a5c12eSMatthew Dillon newpp->p_flyx = 2 * rand_num(conf_flystep + 1) - conf_flystep;
34982a5c12eSMatthew Dillon newpp->p_flyy = 2 * rand_num(conf_flystep + 1) - conf_flystep;
35082a5c12eSMatthew Dillon newpp->p_face = FLYER;
35182a5c12eSMatthew Dillon } else {
35282a5c12eSMatthew Dillon newpp->p_flying = -1;
35382a5c12eSMatthew Dillon newpp->p_face = rand_dir();
35482a5c12eSMatthew Dillon }
35582a5c12eSMatthew Dillon
35682a5c12eSMatthew Dillon /* Initialize the new player's attributes: */
35782a5c12eSMatthew Dillon newpp->p_damage = 0;
35882a5c12eSMatthew Dillon newpp->p_damcap = conf_maxdam;
35982a5c12eSMatthew Dillon newpp->p_nchar = 0;
36082a5c12eSMatthew Dillon newpp->p_ncount = 0;
36182a5c12eSMatthew Dillon newpp->p_nexec = 0;
36282a5c12eSMatthew Dillon newpp->p_ammo = conf_ishots;
36382a5c12eSMatthew Dillon newpp->p_nboots = 0;
36482a5c12eSMatthew Dillon
36582a5c12eSMatthew Dillon /* Decide on what cloak/scan status to enter with */
36682a5c12eSMatthew Dillon if (enter_status == Q_SCAN && conf_scan) {
36782a5c12eSMatthew Dillon newpp->p_scan = conf_scanlen * Nplayer;
36882a5c12eSMatthew Dillon newpp->p_cloak = 0;
36982a5c12eSMatthew Dillon } else if (conf_cloak) {
37082a5c12eSMatthew Dillon newpp->p_scan = 0;
37182a5c12eSMatthew Dillon newpp->p_cloak = conf_cloaklen;
37282a5c12eSMatthew Dillon } else {
37382a5c12eSMatthew Dillon newpp->p_scan = 0;
37482a5c12eSMatthew Dillon newpp->p_cloak = 0;
37582a5c12eSMatthew Dillon }
37682a5c12eSMatthew Dillon newpp->p_ncshot = 0;
37782a5c12eSMatthew Dillon
37882a5c12eSMatthew Dillon /*
37982a5c12eSMatthew Dillon * For each new player, place a large mine and
38082a5c12eSMatthew Dillon * a small mine somewhere in the maze:
38182a5c12eSMatthew Dillon */
38282a5c12eSMatthew Dillon do {
38382a5c12eSMatthew Dillon x = rand_num(WIDTH - 1) + 1;
38482a5c12eSMatthew Dillon y = rand_num(HEIGHT - 1) + 1;
38582a5c12eSMatthew Dillon } while (Maze[y][x] != SPACE);
38682a5c12eSMatthew Dillon Maze[y][x] = GMINE;
38782a5c12eSMatthew Dillon for (pp = Monitor; pp < End_monitor; pp++)
38882a5c12eSMatthew Dillon check(pp, y, x);
38982a5c12eSMatthew Dillon
39082a5c12eSMatthew Dillon do {
39182a5c12eSMatthew Dillon x = rand_num(WIDTH - 1) + 1;
39282a5c12eSMatthew Dillon y = rand_num(HEIGHT - 1) + 1;
39382a5c12eSMatthew Dillon } while (Maze[y][x] != SPACE);
39482a5c12eSMatthew Dillon Maze[y][x] = MINE;
39582a5c12eSMatthew Dillon for (pp = Monitor; pp < End_monitor; pp++)
39682a5c12eSMatthew Dillon check(pp, y, x);
39782a5c12eSMatthew Dillon
39882a5c12eSMatthew Dillon /* Create a score line for the new player: */
399*d9f85b33Szrj snprintf(Buf, sizeof Buf, "%5.2f%c%-10.10s %c",
40082a5c12eSMatthew Dillon newpp->p_ident->i_score, stat_char(newpp),
40182a5c12eSMatthew Dillon newpp->p_ident->i_name, newpp->p_ident->i_team);
40282a5c12eSMatthew Dillon len = strlen(Buf);
40382a5c12eSMatthew Dillon y = STAT_PLAY_ROW + 1 + (newpp - Player);
40482a5c12eSMatthew Dillon for (pp = Player; pp < End_player; pp++) {
40582a5c12eSMatthew Dillon if (pp != newpp) {
40682a5c12eSMatthew Dillon /* Give everyone a few more shots: */
40782a5c12eSMatthew Dillon pp->p_ammo += conf_nshots;
40882a5c12eSMatthew Dillon newpp->p_ammo += conf_nshots;
40982a5c12eSMatthew Dillon outyx(pp, y, STAT_NAME_COL, Buf, len);
41082a5c12eSMatthew Dillon ammo_update(pp);
41182a5c12eSMatthew Dillon }
41282a5c12eSMatthew Dillon }
41382a5c12eSMatthew Dillon for (pp = Monitor; pp < End_monitor; pp++)
41482a5c12eSMatthew Dillon outyx(pp, y, STAT_NAME_COL, Buf, len);
41582a5c12eSMatthew Dillon
41682a5c12eSMatthew Dillon /* Show the new player what they can see and where they are: */
41782a5c12eSMatthew Dillon drawmaze(newpp);
41882a5c12eSMatthew Dillon drawplayer(newpp, TRUE);
41982a5c12eSMatthew Dillon look(newpp);
42082a5c12eSMatthew Dillon
42182a5c12eSMatthew Dillon /* Make sure that the position they enter in will be erased: */
42282a5c12eSMatthew Dillon if (enter_status == Q_FLY && conf_fly)
42382a5c12eSMatthew Dillon showexpl(newpp->p_y, newpp->p_x, FLYER);
42482a5c12eSMatthew Dillon
42582a5c12eSMatthew Dillon /* Ready the new player: */
42682a5c12eSMatthew Dillon sendcom(newpp, REFRESH);
42782a5c12eSMatthew Dillon sendcom(newpp, READY, 0);
42882a5c12eSMatthew Dillon flush(newpp);
42982a5c12eSMatthew Dillon }
43082a5c12eSMatthew Dillon
43182a5c12eSMatthew Dillon /*
43282a5c12eSMatthew Dillon * rand_dir:
43382a5c12eSMatthew Dillon * Return a random direction
43482a5c12eSMatthew Dillon */
43582a5c12eSMatthew Dillon int
rand_dir(void)4366beb426bSSascha Wildner rand_dir(void)
43782a5c12eSMatthew Dillon {
43882a5c12eSMatthew Dillon switch (rand_num(4)) {
43982a5c12eSMatthew Dillon case 0:
44082a5c12eSMatthew Dillon return LEFTS;
44182a5c12eSMatthew Dillon case 1:
44282a5c12eSMatthew Dillon return RIGHT;
44382a5c12eSMatthew Dillon case 2:
44482a5c12eSMatthew Dillon return BELOW;
44582a5c12eSMatthew Dillon case 3:
44682a5c12eSMatthew Dillon return ABOVE;
44782a5c12eSMatthew Dillon }
44882a5c12eSMatthew Dillon /* NOTREACHED */
44982a5c12eSMatthew Dillon return(-1);
45082a5c12eSMatthew Dillon }
45182a5c12eSMatthew Dillon
45282a5c12eSMatthew Dillon /*
45382a5c12eSMatthew Dillon * get_ident:
45482a5c12eSMatthew Dillon * Get the score structure of a player
45582a5c12eSMatthew Dillon */
45682a5c12eSMatthew Dillon static IDENT *
get_ident(struct sockaddr * sa,int salen __unused,uid_t uid,char * name,char team)4576beb426bSSascha Wildner get_ident(struct sockaddr *sa, int salen __unused, uid_t uid, char *name,
4586beb426bSSascha Wildner char team)
45982a5c12eSMatthew Dillon {
46082a5c12eSMatthew Dillon IDENT *ip;
46182a5c12eSMatthew Dillon static IDENT punt;
46282a5c12eSMatthew Dillon u_int32_t machine;
46382a5c12eSMatthew Dillon
46482a5c12eSMatthew Dillon if (sa->sa_family == AF_INET)
46582a5c12eSMatthew Dillon machine = ntohl((u_long)((struct sockaddr_in *)sa)->sin_addr.s_addr);
46682a5c12eSMatthew Dillon else
46782a5c12eSMatthew Dillon machine = 0;
46882a5c12eSMatthew Dillon
46982a5c12eSMatthew Dillon for (ip = Scores; ip != NULL; ip = ip->i_next)
47082a5c12eSMatthew Dillon if (ip->i_machine == machine
47182a5c12eSMatthew Dillon && ip->i_uid == uid
47282a5c12eSMatthew Dillon /* && ip->i_team == team */
47382a5c12eSMatthew Dillon && strncmp(ip->i_name, name, NAMELEN) == 0)
47482a5c12eSMatthew Dillon break;
47582a5c12eSMatthew Dillon
47682a5c12eSMatthew Dillon if (ip != NULL) {
47782a5c12eSMatthew Dillon if (ip->i_team != team) {
47882a5c12eSMatthew Dillon logx(LOG_INFO, "player %s %s team %c",
47982a5c12eSMatthew Dillon name,
48082a5c12eSMatthew Dillon team == ' ' ? "left" : ip->i_team == ' ' ?
48182a5c12eSMatthew Dillon "joined" : "changed to",
48282a5c12eSMatthew Dillon team == ' ' ? ip->i_team : team);
48382a5c12eSMatthew Dillon ip->i_team = team;
48482a5c12eSMatthew Dillon }
48582a5c12eSMatthew Dillon if (ip->i_entries < conf_scoredecay)
48682a5c12eSMatthew Dillon ip->i_entries++;
48782a5c12eSMatthew Dillon else
48882a5c12eSMatthew Dillon ip->i_kills = (ip->i_kills * (conf_scoredecay - 1))
48982a5c12eSMatthew Dillon / conf_scoredecay;
49082a5c12eSMatthew Dillon ip->i_score = ip->i_kills / (double) ip->i_entries;
49182a5c12eSMatthew Dillon }
49282a5c12eSMatthew Dillon else {
49382a5c12eSMatthew Dillon /* Alloc new entry -- it is released in clear_scores() */
49482a5c12eSMatthew Dillon ip = (IDENT *) malloc(sizeof (IDENT));
49582a5c12eSMatthew Dillon if (ip == NULL) {
49682a5c12eSMatthew Dillon logit(LOG_ERR, "malloc");
49782a5c12eSMatthew Dillon /* Fourth down, time to punt */
49882a5c12eSMatthew Dillon ip = &punt;
49982a5c12eSMatthew Dillon }
50082a5c12eSMatthew Dillon ip->i_machine = machine;
50182a5c12eSMatthew Dillon ip->i_team = team;
50282a5c12eSMatthew Dillon ip->i_uid = uid;
50382a5c12eSMatthew Dillon strlcpy(ip->i_name, name, sizeof ip->i_name);
50482a5c12eSMatthew Dillon ip->i_kills = 0;
50582a5c12eSMatthew Dillon ip->i_entries = 1;
50682a5c12eSMatthew Dillon ip->i_score = 0;
50782a5c12eSMatthew Dillon ip->i_absorbed = 0;
50882a5c12eSMatthew Dillon ip->i_faced = 0;
50982a5c12eSMatthew Dillon ip->i_shot = 0;
51082a5c12eSMatthew Dillon ip->i_robbed = 0;
51182a5c12eSMatthew Dillon ip->i_slime = 0;
51282a5c12eSMatthew Dillon ip->i_missed = 0;
51382a5c12eSMatthew Dillon ip->i_ducked = 0;
51482a5c12eSMatthew Dillon ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
51582a5c12eSMatthew Dillon ip->i_stillb = ip->i_saved = 0;
51682a5c12eSMatthew Dillon ip->i_next = Scores;
51782a5c12eSMatthew Dillon Scores = ip;
51882a5c12eSMatthew Dillon
51982a5c12eSMatthew Dillon logx(LOG_INFO, "new player: %s%s%c%s",
52082a5c12eSMatthew Dillon name,
52182a5c12eSMatthew Dillon team == ' ' ? "" : " (team ",
52282a5c12eSMatthew Dillon team,
52382a5c12eSMatthew Dillon team == ' ' ? "" : ")");
52482a5c12eSMatthew Dillon }
52582a5c12eSMatthew Dillon
52682a5c12eSMatthew Dillon return ip;
52782a5c12eSMatthew Dillon }
52882a5c12eSMatthew Dillon
52982a5c12eSMatthew Dillon void
answer_info(FILE * fp)5306beb426bSSascha Wildner answer_info(FILE *fp)
53182a5c12eSMatthew Dillon {
53282a5c12eSMatthew Dillon struct spawn *sp;
53382a5c12eSMatthew Dillon char buf[128];
53482a5c12eSMatthew Dillon const char *bf;
53582a5c12eSMatthew Dillon struct sockaddr_in *sa;
53682a5c12eSMatthew Dillon
53782a5c12eSMatthew Dillon if (Spawn == NULL)
53882a5c12eSMatthew Dillon return;
53982a5c12eSMatthew Dillon fprintf(fp, "\nSpawning connections:\n");
54082a5c12eSMatthew Dillon for (sp = Spawn; sp; sp = sp->next) {
54182a5c12eSMatthew Dillon sa = (struct sockaddr_in *)&sp->source;
54282a5c12eSMatthew Dillon bf = inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof buf);
54382a5c12eSMatthew Dillon if (!bf) {
54482a5c12eSMatthew Dillon logit(LOG_WARNING, "inet_ntop");
54582a5c12eSMatthew Dillon bf = "?";
54682a5c12eSMatthew Dillon }
54782a5c12eSMatthew Dillon fprintf(fp, "fd %d: state %d, from %s:%d\n",
54882a5c12eSMatthew Dillon sp->fd, sp->inlen + (sp->reading_msg ? sp->msglen : 0),
54982a5c12eSMatthew Dillon bf, sa->sin_port);
55082a5c12eSMatthew Dillon }
55182a5c12eSMatthew Dillon }
552