Home | History | Annotate | Line # | Download | only in sail
sync.c revision 1.31
      1 /*	$NetBSD: sync.c,v 1.31 2009/03/14 22:54:05 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)sync.c	8.2 (Berkeley) 4/28/95";
     36 #else
     37 __RCSID("$NetBSD: sync.c,v 1.31 2009/03/14 22:54:05 dholland Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/stat.h>
     42 
     43 #include <fcntl.h>
     44 #include <errno.h>
     45 #include <signal.h>
     46 #include <stdarg.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <string.h>
     50 #include <time.h>
     51 #include <unistd.h>
     52 #include "extern.h"
     53 #include "pathnames.h"
     54 
     55 #define BUFSIZE 4096
     56 
     57 /* Message types */
     58 #define W_CAPTAIN	1
     59 #define W_CAPTURED	2
     60 #define W_CLASS		3
     61 #define W_CREW		4
     62 #define W_DBP		5
     63 #define W_DRIFT		6
     64 #define W_EXPLODE	7
     65 /*      W_FILE		8   not used */
     66 #define W_FOUL		9
     67 #define W_GUNL		10
     68 #define W_GUNR		11
     69 #define W_HULL		12
     70 #define W_MOVE		13
     71 #define W_OBP		14
     72 #define W_PCREW		15
     73 #define W_UNFOUL	16
     74 #define W_POINTS	17
     75 #define W_QUAL		18
     76 #define W_UNGRAP	19
     77 #define W_RIGG		20
     78 #define W_COL		21
     79 #define W_DIR		22
     80 #define W_ROW		23
     81 #define W_SIGNAL	24
     82 #define W_SINK		25
     83 #define W_STRUCK	26
     84 #define W_TA		27
     85 #define W_ALIVE		28
     86 #define W_TURN		29
     87 #define W_WIND		30
     88 #define W_FS		31
     89 #define W_GRAP		32
     90 #define W_RIG1		33
     91 #define W_RIG2		34
     92 #define W_RIG3		35
     93 #define W_RIG4		36
     94 #define W_BEGIN		37
     95 #define W_END		38
     96 #define W_DDEAD		39
     97 
     98 
     99 static void recv_captain(struct ship *ship, const char *astr);
    100 static void recv_captured(struct ship *ship, long a);
    101 static void recv_class(struct ship *ship, long a);
    102 static void recv_crew(struct ship *ship, long a, long b, long c);
    103 static void recv_dbp(struct ship *ship, long a, long b, long c, long d);
    104 static void recv_drift(struct ship *ship, long a);
    105 static void recv_explode(struct ship *ship, long a);
    106 static void recv_foul(struct ship *ship, long a);
    107 static void recv_gunl(struct ship *ship, long a, long b);
    108 static void recv_gunr(struct ship *ship, long a, long b);
    109 static void recv_hull(struct ship *ship, long a);
    110 static void recv_move(struct ship *ship, const char *astr);
    111 static void recv_obp(struct ship *ship, long a, long b, long c, long d);
    112 static void recv_pcrew(struct ship *ship, long a);
    113 static void recv_unfoul(struct ship *ship, long a, long b);
    114 static void recv_points(struct ship *ship, long a);
    115 static void recv_qual(struct ship *ship, long a);
    116 static void recv_ungrap(struct ship *ship, long a, long b);
    117 static void recv_rigg(struct ship *ship, long a, long b, long c, long d);
    118 static void recv_col(struct ship *ship, long a);
    119 static void recv_dir(struct ship *ship, long a);
    120 static void recv_row(struct ship *ship, long a);
    121 static void recv_signal(struct ship *ship, const char *astr);
    122 static void recv_sink(struct ship *ship, long a);
    123 static void recv_struck(struct ship *ship, long a);
    124 static void recv_ta(struct ship *ship, long a);
    125 static void recv_alive(void);
    126 static void recv_turn(long a);
    127 static void recv_wind(long a, long b);
    128 static void recv_fs(struct ship *ship, long a);
    129 static void recv_grap(struct ship *ship, long a);
    130 static void recv_rig1(struct ship *ship, long a);
    131 static void recv_rig2(struct ship *ship, long a);
    132 static void recv_rig3(struct ship *ship, long a);
    133 static void recv_rig4(struct ship *ship, long a);
    134 static void recv_begin(struct ship *ship);
    135 static void recv_end(struct ship *ship);
    136 static void recv_ddead(void);
    137 
    138 static void Write(int, struct ship *, long, long, long, long);
    139 static void Writestr(int, struct ship *, const char *);
    140 
    141 static int sync_update(int, struct ship *, const char *,
    142 		       long, long, long, long);
    143 
    144 static const char SF[] = _PATH_SYNC;
    145 static const char LF[] = _PATH_LOCK;
    146 static char sync_buf[BUFSIZE];
    147 static char *sync_bp = sync_buf;
    148 static char sync_lock[sizeof SF];
    149 static char sync_file[sizeof LF];
    150 static long sync_seek;
    151 static FILE *sync_fp;
    152 
    153 void
    154 fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
    155 {
    156 	while (*fmt) {
    157 		if (len-- == 0) {
    158 			*buf = '\0';
    159 			return;
    160 		}
    161 		if (*fmt == '$' && fmt[1] == '$') {
    162 			size_t l = snprintf(buf, len, "%s (%c%c)",
    163 			    ship->shipname, colours(ship), sterncolour(ship));
    164 			buf += l;
    165 			len -= l - 1;
    166 			fmt += 2;
    167 		}
    168 		else
    169 			*buf++ = *fmt++;
    170 	}
    171 
    172 	if (len > 0)
    173 		*buf = '\0';
    174 }
    175 
    176 
    177 /*VARARGS3*/
    178 void
    179 makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
    180 {
    181 	char message[BUFSIZ];
    182 	char format[BUFSIZ];
    183 	va_list ap;
    184 
    185 	va_start(ap, ship);
    186 	fmtship(format, sizeof(format), fmt, ship);
    187 	vsnprintf(message, sizeof(message), format, ap);
    188 	va_end(ap);
    189 	send_signal(from, message);
    190 }
    191 
    192 /*VARARGS2*/
    193 void
    194 makemsg(struct ship *from, const char *fmt, ...)
    195 {
    196 	char message[BUFSIZ];
    197 	va_list ap;
    198 
    199 	va_start(ap, fmt);
    200 	vsnprintf(message, sizeof(message), fmt, ap);
    201 	va_end(ap);
    202 	send_signal(from, message);
    203 }
    204 
    205 int
    206 sync_exists(int gamenum)
    207 {
    208 	char buf[sizeof sync_file];
    209 	struct stat s;
    210 	time_t t;
    211 
    212 	snprintf(buf, sizeof(buf), SF, gamenum);
    213 	time(&t);
    214 	setegid(egid);
    215 	if (stat(buf, &s) < 0) {
    216 		setegid(gid);
    217 		return 0;
    218 	}
    219 	if (s.st_mtime < t - 60*60*2) {		/* 2 hours */
    220 		unlink(buf);
    221 		snprintf(buf, sizeof(buf), LF, gamenum);
    222 		unlink(buf);
    223 		setegid(gid);
    224 		return 0;
    225 	} else {
    226 		setegid(gid);
    227 		return 1;
    228 	}
    229 }
    230 
    231 int
    232 sync_open(void)
    233 {
    234 	struct stat tmp;
    235 	if (sync_fp != NULL)
    236 		fclose(sync_fp);
    237 	snprintf(sync_lock, sizeof(sync_lock), LF, game);
    238 	snprintf(sync_file, sizeof(sync_file), SF, game);
    239 	setegid(egid);
    240 	if (stat(sync_file, &tmp) < 0) {
    241 		mode_t omask = umask(002);
    242 		sync_fp = fopen(sync_file, "w+");
    243 		umask(omask);
    244 	} else
    245 		sync_fp = fopen(sync_file, "r+");
    246 	setegid(gid);
    247 	if (sync_fp == NULL)
    248 		return -1;
    249 	sync_seek = 0;
    250 	return 0;
    251 }
    252 
    253 void
    254 sync_close(int doremove)
    255 {
    256 	if (sync_fp != 0)
    257 		fclose(sync_fp);
    258 	if (doremove) {
    259 		setegid(egid);
    260 		unlink(sync_file);
    261 		setegid(gid);
    262 	}
    263 }
    264 
    265 static void
    266 Write(int type, struct ship *ship, long a, long b, long c, long d)
    267 {
    268 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
    269 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
    270 
    271 	snprintf(sync_bp, max, "%d %d 0 %ld %ld %ld %ld\n",
    272 		       type, shipindex, a, b, c, d);
    273 	while (*sync_bp++)
    274 		;
    275 	sync_bp--;
    276 	if (sync_bp >= &sync_buf[sizeof sync_buf])
    277 		abort();
    278 	sync_update(type, ship, NULL, a, b, c, d);
    279 }
    280 
    281 static void
    282 Writestr(int type, struct ship *ship, const char *a)
    283 {
    284 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
    285 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
    286 
    287 	snprintf(sync_bp, max, "%d %d 1 %s\n", type, shipindex, a);
    288 	while (*sync_bp++)
    289 		;
    290 	sync_bp--;
    291 	if (sync_bp >= &sync_buf[sizeof sync_buf])
    292 		abort();
    293 	sync_update(type, ship, a, 0, 0, 0, 0);
    294 }
    295 
    296 int
    297 Sync(void)
    298 {
    299 	sig_t sighup, sigint;
    300 	int n;
    301 	int type, shipnum, isstr;
    302 	char *astr;
    303 	long a, b, c, d;
    304 	char buf[80];
    305 	char erred = 0;
    306 
    307 	sighup = signal(SIGHUP, SIG_IGN);
    308 	sigint = signal(SIGINT, SIG_IGN);
    309 	for (n = TIMEOUT; --n >= 0;) {
    310 #ifdef LOCK_EX
    311 		if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
    312 			break;
    313 		if (errno != EWOULDBLOCK)
    314 			return -1;
    315 #else
    316 		setegid(egid);
    317 		if (link(sync_file, sync_lock) >= 0) {
    318 			setegid(gid);
    319 			break;
    320 		}
    321 		setegid(gid);
    322 		if (errno != EEXIST)
    323 			return -1;
    324 #endif
    325 		sleep(1);
    326 	}
    327 	if (n <= 0)
    328 		return -1;
    329 	fseek(sync_fp, sync_seek, SEEK_SET);
    330 	for (;;) {
    331 		switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
    332 		case 3:
    333 			break;
    334 		case EOF:
    335 			goto out;
    336 		default:
    337 			goto bad;
    338 		}
    339 		if (shipnum < 0 || shipnum >= cc->vessels)
    340 			goto bad;
    341 		if (isstr != 0 && isstr != 1)
    342 			goto bad;
    343 		if (isstr) {
    344 			int ch;
    345 			char *p;
    346 
    347 			for (p = buf;;) {
    348 				ch = getc(sync_fp);
    349 				*p++ = ch;
    350 				switch (ch) {
    351 				case '\n':
    352 					p--;
    353 				case EOF:
    354 					break;
    355 				default:
    356 					if (p >= buf + sizeof buf)
    357 						p--;
    358 					continue;
    359 				}
    360 				break;
    361 			}
    362 			*p = 0;
    363 			for (p = buf; *p == ' '; p++)
    364 				;
    365 			astr = p;
    366 			a = b = c = d = 0;
    367 		} else {
    368 			if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d)
    369 			    != 4)
    370 				goto bad;
    371 			astr = NULL;
    372 		}
    373 		if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
    374 			goto bad;
    375 	}
    376 bad:
    377 	erred++;
    378 out:
    379 	if (!erred && sync_bp != sync_buf) {
    380 		fseek(sync_fp, 0L, SEEK_END);
    381 		fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
    382 			sync_fp);
    383 		fflush(sync_fp);
    384 		sync_bp = sync_buf;
    385 	}
    386 	sync_seek = ftell(sync_fp);
    387 #ifdef LOCK_EX
    388 	flock(fileno(sync_fp), LOCK_UN);
    389 #else
    390 	setegid(egid);
    391 	unlink(sync_lock);
    392 	setegid(gid);
    393 #endif
    394 	signal(SIGHUP, sighup);
    395 	signal(SIGINT, sigint);
    396 	return erred ? -1 : 0;
    397 }
    398 
    399 static int
    400 sync_update(int type, struct ship *ship, const char *astr,
    401 	    long a, long b, long c, long d)
    402 {
    403 	switch (type) {
    404 	case W_CAPTAIN:  recv_captain(ship, astr);    break;
    405 	case W_CAPTURED: recv_captured(ship, a);      break;
    406 	case W_CLASS:    recv_class(ship, a);         break;
    407 	case W_CREW:     recv_crew(ship, a, b, c);    break;
    408 	case W_DBP:      recv_dbp(ship, a, b, c, d);  break;
    409 	case W_DRIFT:    recv_drift(ship, a);         break;
    410 	case W_EXPLODE:  recv_explode(ship, a);       break;
    411 	case W_FOUL:     recv_foul(ship, a);          break;
    412 	case W_GUNL:     recv_gunl(ship, a, b);       break;
    413 	case W_GUNR:     recv_gunr(ship, a, b);       break;
    414 	case W_HULL:     recv_hull(ship, a);          break;
    415 	case W_MOVE:     recv_move(ship, astr);       break;
    416 	case W_OBP:      recv_obp(ship, a, b, c, d);  break;
    417 	case W_PCREW:    recv_pcrew(ship, a);         break;
    418 	case W_UNFOUL:   recv_unfoul(ship, a, b);     break;
    419 	case W_POINTS:   recv_points(ship, a);        break;
    420 	case W_QUAL:     recv_qual(ship, a);          break;
    421 	case W_UNGRAP:   recv_ungrap(ship, a, b);     break;
    422 	case W_RIGG:     recv_rigg(ship, a, b, c, d); break;
    423 	case W_COL:      recv_col(ship, a);           break;
    424 	case W_DIR:      recv_dir(ship, a);           break;
    425 	case W_ROW:      recv_row(ship, a);           break;
    426 	case W_SIGNAL:   recv_signal(ship, astr);     break;
    427 	case W_SINK:     recv_sink(ship, a);          break;
    428 	case W_STRUCK:   recv_struck(ship, a);        break;
    429 	case W_TA:       recv_ta(ship, a);            break;
    430 	case W_ALIVE:    recv_alive();                break;
    431 	case W_TURN:     recv_turn(a);                break;
    432 	case W_WIND:     recv_wind(a, b);             break;
    433 	case W_FS:       recv_fs(ship, a);            break;
    434 	case W_GRAP:     recv_grap(ship, a);          break;
    435 	case W_RIG1:     recv_rig1(ship, a);          break;
    436 	case W_RIG2:     recv_rig2(ship, a);          break;
    437 	case W_RIG3:     recv_rig3(ship, a);          break;
    438 	case W_RIG4:     recv_rig4(ship, a);          break;
    439 	case W_BEGIN:    recv_begin(ship);            break;
    440 	case W_END:      recv_end(ship);              break;
    441 	case W_DDEAD:    recv_ddead();                break;
    442 	default:
    443 		fprintf(stderr, "sync_update: unknown type %d\r\n", type);
    444 		return -1;
    445 	}
    446 	return 0;
    447 }
    448 
    449 /*
    450  * Messages to send
    451  */
    452 
    453 void
    454 send_captain(struct ship *ship, const char *astr)
    455 {
    456 	Writestr(W_CAPTAIN, ship, astr);
    457 }
    458 
    459 void
    460 send_captured(struct ship *ship, long a)
    461 {
    462 	Write(W_CAPTURED, ship, a, 0, 0, 0);
    463 }
    464 
    465 void
    466 send_class(struct ship *ship, long a)
    467 {
    468 	Write(W_CLASS, ship, a, 0, 0, 0);
    469 }
    470 
    471 void
    472 send_crew(struct ship *ship, long a, long b, long c)
    473 {
    474 	Write(W_CREW, ship, a, b, c, 0);
    475 }
    476 
    477 void
    478 send_dbp(struct ship *ship, long a, long b, long c, long d)
    479 {
    480 	Write(W_DBP, ship, a, b, c, d);
    481 }
    482 
    483 void
    484 send_drift(struct ship *ship, long a)
    485 {
    486 	Write(W_DRIFT, ship, a, 0, 0, 0);
    487 }
    488 
    489 void
    490 send_explode(struct ship *ship, long a)
    491 {
    492 	Write(W_EXPLODE, ship, a, 0, 0, 0);
    493 }
    494 
    495 void
    496 send_foul(struct ship *ship, long a)
    497 {
    498 	Write(W_FOUL, ship, a, 0, 0, 0);
    499 }
    500 
    501 void
    502 send_gunl(struct ship *ship, long a, long b)
    503 {
    504 	Write(W_GUNL, ship, a, b, 0, 0);
    505 }
    506 
    507 void
    508 send_gunr(struct ship *ship, long a, long b)
    509 {
    510 	Write(W_GUNR, ship, a, b, 0, 0);
    511 }
    512 
    513 void
    514 send_hull(struct ship *ship, long a)
    515 {
    516 	Write(W_HULL, ship, a, 0, 0, 0);
    517 }
    518 
    519 void
    520 send_move(struct ship *ship, const char *astr)
    521 {
    522 	Writestr(W_MOVE, ship, astr);
    523 }
    524 
    525 void
    526 send_obp(struct ship *ship, long a, long b, long c, long d)
    527 {
    528 	Write(W_OBP, ship, a, b, c, d);
    529 }
    530 
    531 void
    532 send_pcrew(struct ship *ship, long a)
    533 {
    534 	Write(W_PCREW, ship, a, 0, 0, 0);
    535 }
    536 
    537 void
    538 send_unfoul(struct ship *ship, long a, long b)
    539 {
    540 	Write(W_UNFOUL, ship, a, b, 0, 0);
    541 }
    542 
    543 void
    544 send_points(struct ship *ship, long a)
    545 {
    546 	Write(W_POINTS, ship, a, 0, 0, 0);
    547 }
    548 
    549 void
    550 send_qual(struct ship *ship, long a)
    551 {
    552 	Write(W_QUAL, ship, a, 0, 0, 0);
    553 }
    554 
    555 void
    556 send_ungrap(struct ship *ship, long a, long b)
    557 {
    558 	Write(W_UNGRAP, ship, a, b, 0, 0);
    559 }
    560 
    561 void
    562 send_rigg(struct ship *ship, long a, long b, long c, long d)
    563 {
    564 	Write(W_RIGG, ship, a, b, c, d);
    565 }
    566 
    567 void
    568 send_col(struct ship *ship, long a)
    569 {
    570 	Write(W_COL, ship, a, 0, 0, 0);
    571 }
    572 
    573 void
    574 send_dir(struct ship *ship, long a)
    575 {
    576 	Write(W_DIR, ship, a, 0, 0, 0);
    577 }
    578 
    579 void
    580 send_row(struct ship *ship, long a)
    581 {
    582 	Write(W_ROW, ship, a, 0, 0, 0);
    583 }
    584 
    585 void
    586 send_signal(struct ship *ship, const char *astr)
    587 {
    588 	Writestr(W_SIGNAL, ship, astr);
    589 }
    590 
    591 void
    592 send_sink(struct ship *ship, long a)
    593 {
    594 	Write(W_SINK, ship, a, 0, 0, 0);
    595 }
    596 
    597 void
    598 send_struck(struct ship *ship, long a)
    599 {
    600 	Write(W_STRUCK, ship, a, 0, 0, 0);
    601 }
    602 
    603 void
    604 send_ta(struct ship *ship, long a)
    605 {
    606 	Write(W_TA, ship, a, 0, 0, 0);
    607 }
    608 
    609 void
    610 send_alive(void)
    611 {
    612 	Write(W_ALIVE, NULL, 0, 0, 0, 0);
    613 }
    614 
    615 void
    616 send_turn(long a)
    617 {
    618 	Write(W_TURN, NULL, a, 0, 0, 0);
    619 }
    620 
    621 void
    622 send_wind(long a, long b)
    623 {
    624 	Write(W_WIND, NULL, a, b, 0, 0);
    625 }
    626 
    627 void
    628 send_fs(struct ship *ship, long a)
    629 {
    630 	Write(W_FS, ship, a, 0, 0, 0);
    631 }
    632 
    633 void
    634 send_grap(struct ship *ship, long a)
    635 {
    636 	Write(W_GRAP, ship, a, 0, 0, 0);
    637 }
    638 
    639 void
    640 send_rig1(struct ship *ship, long a)
    641 {
    642 	Write(W_RIG1, ship, a, 0, 0, 0);
    643 }
    644 
    645 void
    646 send_rig2(struct ship *ship, long a)
    647 {
    648 	Write(W_RIG2, ship, a, 0, 0, 0);
    649 }
    650 
    651 void
    652 send_rig3(struct ship *ship, long a)
    653 {
    654 	Write(W_RIG3, ship, a, 0, 0, 0);
    655 }
    656 
    657 void
    658 send_rig4(struct ship *ship, long a)
    659 {
    660 	Write(W_RIG4, ship, a, 0, 0, 0);
    661 }
    662 
    663 void
    664 send_begin(struct ship *ship)
    665 {
    666 	Write(W_BEGIN, ship, 0, 0, 0, 0);
    667 }
    668 
    669 void
    670 send_end(struct ship *ship)
    671 {
    672 	Write(W_END, ship, 0, 0, 0, 0);
    673 }
    674 
    675 void
    676 send_ddead(void)
    677 {
    678 	Write(W_DDEAD, NULL, 0, 0, 0, 0);
    679 }
    680 
    681 
    682 /*
    683  * Actions upon message receipt
    684  */
    685 
    686 static void
    687 recv_captain(struct ship *ship, const char *astr)
    688 {
    689 	strlcpy(ship->file->captain, astr, sizeof ship->file->captain);
    690 }
    691 
    692 static void
    693 recv_captured(struct ship *ship, long a)
    694 {
    695 	if (a < 0)
    696 		ship->file->captured = 0;
    697 	else
    698 		ship->file->captured = SHIP(a);
    699 }
    700 
    701 static void
    702 recv_class(struct ship *ship, long a)
    703 {
    704 	ship->specs->class = a;
    705 }
    706 
    707 static void
    708 recv_crew(struct ship *ship, long a, long b, long c)
    709 {
    710 	struct shipspecs *s = ship->specs;
    711 
    712 	s->crew1 = a;
    713 	s->crew2 = b;
    714 	s->crew3 = c;
    715 }
    716 
    717 static void
    718 recv_dbp(struct ship *ship, long a, long b, long c, long d)
    719 {
    720 	struct BP *p = &ship->file->DBP[a];
    721 
    722 	p->turnsent = b;
    723 	p->toship = SHIP(c);
    724 	p->mensent = d;
    725 }
    726 
    727 static void
    728 recv_drift(struct ship *ship, long a)
    729 {
    730 	ship->file->drift = a;
    731 }
    732 
    733 static void
    734 recv_explode(struct ship *ship, long a)
    735 {
    736 	if ((ship->file->explode = a) == 2)
    737 		ship->file->dir = 0;
    738 }
    739 
    740 static void
    741 recv_foul(struct ship *ship, long a)
    742 {
    743 	struct snag *p = &ship->file->foul[a];
    744 
    745 	if (SHIP(a)->file->dir == 0)
    746 		return;
    747 	if (p->sn_count++ == 0)
    748 		p->sn_turn = turn;
    749 	ship->file->nfoul++;
    750 }
    751 
    752 static void
    753 recv_gunl(struct ship *ship, long a, long b)
    754 {
    755 	struct shipspecs *s = ship->specs;
    756 
    757 	s->gunL = a;
    758 	s->carL = b;
    759 }
    760 
    761 static void
    762 recv_gunr(struct ship *ship, long a, long b)
    763 {
    764 	struct shipspecs *s = ship->specs;
    765 
    766 	s->gunR = a;
    767 	s->carR = b;
    768 }
    769 
    770 static void
    771 recv_hull(struct ship *ship, long a)
    772 {
    773 	ship->specs->hull = a;
    774 }
    775 
    776 static void
    777 recv_move(struct ship *ship, const char *astr)
    778 {
    779 	strlcpy(ship->file->movebuf, astr, sizeof ship->file->movebuf);
    780 }
    781 
    782 static void
    783 recv_obp(struct ship *ship, long a, long b, long c, long d)
    784 {
    785 	struct BP *p = &ship->file->OBP[a];
    786 
    787 	p->turnsent = b;
    788 	p->toship = SHIP(c);
    789 	p->mensent = d;
    790 }
    791 
    792 static void
    793 recv_pcrew(struct ship *ship, long a)
    794 {
    795 	ship->file->pcrew = a;
    796 }
    797 
    798 static void
    799 recv_unfoul(struct ship *ship, long a, long b)
    800 {
    801 	struct snag *p = &ship->file->foul[a];
    802 
    803 	if (p->sn_count > 0) {
    804 		if (b) {
    805 			ship->file->nfoul -= p->sn_count;
    806 			p->sn_count = 0;
    807 		} else {
    808 			ship->file->nfoul--;
    809 			p->sn_count--;
    810 		}
    811 	}
    812 }
    813 
    814 static void
    815 recv_points(struct ship *ship, long a)
    816 {
    817 	ship->file->points = a;
    818 }
    819 
    820 static void
    821 recv_qual(struct ship *ship, long a)
    822 {
    823 	ship->specs->qual = a;
    824 }
    825 
    826 static void
    827 recv_ungrap(struct ship *ship, long a, long b)
    828 {
    829 	struct snag *p = &ship->file->grap[a];
    830 
    831 	if (p->sn_count > 0) {
    832 		if (b) {
    833 			ship->file->ngrap -= p->sn_count;
    834 			p->sn_count = 0;
    835 		} else {
    836 			ship->file->ngrap--;
    837 			p->sn_count--;
    838 		}
    839 	}
    840 }
    841 
    842 static void
    843 recv_rigg(struct ship *ship, long a, long b, long c, long d)
    844 {
    845 	struct shipspecs *s = ship->specs;
    846 
    847 	s->rig1 = a;
    848 	s->rig2 = b;
    849 	s->rig3 = c;
    850 	s->rig4 = d;
    851 }
    852 
    853 static void
    854 recv_col(struct ship *ship, long a)
    855 {
    856 	ship->file->col = a;
    857 }
    858 
    859 static void
    860 recv_dir(struct ship *ship, long a)
    861 {
    862 	ship->file->dir = a;
    863 }
    864 
    865 static void
    866 recv_row(struct ship *ship, long a)
    867 {
    868 	ship->file->row = a;
    869 }
    870 
    871 static void
    872 recv_signal(struct ship *ship, const char *astr)
    873 {
    874 	if (mode == MODE_PLAYER) {
    875 		if (nobells)
    876 			Signal("$$: %s", ship, astr);
    877 		else
    878 			Signal("\a$$: %s", ship, astr);
    879 	}
    880 }
    881 
    882 static void
    883 recv_sink(struct ship *ship, long a)
    884 {
    885 	if ((ship->file->sink = a) == 2)
    886 		ship->file->dir = 0;
    887 }
    888 
    889 static void
    890 recv_struck(struct ship *ship, long a)
    891 {
    892 	ship->file->struck = a;
    893 }
    894 
    895 static void
    896 recv_ta(struct ship *ship, long a)
    897 {
    898 	ship->specs->ta = a;
    899 }
    900 
    901 static void
    902 recv_alive(void)
    903 {
    904 	alive = 1;
    905 }
    906 
    907 static void
    908 recv_turn(long a)
    909 {
    910 	turn = a;
    911 }
    912 
    913 static void
    914 recv_wind(long a, long b)
    915 {
    916 	winddir = a;
    917 	windspeed = b;
    918 }
    919 
    920 static void
    921 recv_fs(struct ship *ship, long a)
    922 {
    923 	ship->file->FS = a;
    924 }
    925 
    926 static void
    927 recv_grap(struct ship *ship, long a)
    928 {
    929 	struct snag *p = &ship->file->grap[a];
    930 
    931 	if (SHIP(a)->file->dir == 0)
    932 		return;
    933 	if (p->sn_count++ == 0)
    934 		p->sn_turn = turn;
    935 	ship->file->ngrap++;
    936 }
    937 
    938 static void
    939 recv_rig1(struct ship *ship, long a)
    940 {
    941 	ship->specs->rig1 = a;
    942 }
    943 
    944 static void
    945 recv_rig2(struct ship *ship, long a)
    946 {
    947 	ship->specs->rig2 = a;
    948 }
    949 
    950 static void
    951 recv_rig3(struct ship *ship, long a)
    952 {
    953 	ship->specs->rig3 = a;
    954 }
    955 
    956 static void
    957 recv_rig4(struct ship *ship, long a)
    958 {
    959 	ship->specs->rig4 = a;
    960 }
    961 
    962 static void
    963 recv_begin(struct ship *ship)
    964 {
    965 	strcpy(ship->file->captain, "begin");
    966 	people++;
    967 }
    968 
    969 static void
    970 recv_end(struct ship *ship)
    971 {
    972 	*ship->file->captain = 0;
    973 	ship->file->points = 0;
    974 	people--;
    975 }
    976 
    977 static void
    978 recv_ddead(void)
    979 {
    980 	hasdriver = 0;
    981 }
    982