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