Home | History | Annotate | Line # | Download | only in sail
sync.c revision 1.25.12.1
      1 /*	$NetBSD: sync.c,v 1.25.12.1 2009/05/13 19:18:06 jym 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.25.12.1 2009/05/13 19:18:06 jym 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 	const char *sync_lock;
    251 	struct stat tmp;
    252 
    253 	if (sync_fp != NULL)
    254 		fclose(sync_fp);
    255 	sync_file = get_sync_file(game);
    256 	sync_lock = get_lock_file(game);
    257 	setegid(egid);
    258 	if (stat(sync_file, &tmp) < 0) {
    259 		mode_t omask = umask(002);
    260 		sync_fp = fopen(sync_file, "w+");
    261 		umask(omask);
    262 	} else
    263 		sync_fp = fopen(sync_file, "r+");
    264 	setegid(gid);
    265 	if (sync_fp == NULL)
    266 		return -1;
    267 	sync_seek = 0;
    268 	return 0;
    269 }
    270 
    271 void
    272 sync_close(int doremove)
    273 {
    274 	const char *sync_file;
    275 
    276 	if (sync_fp != 0)
    277 		fclose(sync_fp);
    278 	if (doremove) {
    279 		sync_file = get_sync_file(game);
    280 		setegid(egid);
    281 		unlink(sync_file);
    282 		setegid(gid);
    283 	}
    284 }
    285 
    286 static void
    287 Write(int type, struct ship *ship, long a, long b, long c, long d)
    288 {
    289 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
    290 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
    291 
    292 	snprintf(sync_bp, max, "%d %d 0 %ld %ld %ld %ld\n",
    293 		       type, shipindex, a, b, c, d);
    294 	while (*sync_bp++)
    295 		;
    296 	sync_bp--;
    297 	if (sync_bp >= &sync_buf[sizeof sync_buf])
    298 		abort();
    299 	sync_update(type, ship, NULL, a, b, c, d);
    300 }
    301 
    302 static void
    303 Writestr(int type, struct ship *ship, const char *a)
    304 {
    305 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
    306 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
    307 
    308 	snprintf(sync_bp, max, "%d %d 1 %s\n", type, shipindex, a);
    309 	while (*sync_bp++)
    310 		;
    311 	sync_bp--;
    312 	if (sync_bp >= &sync_buf[sizeof sync_buf])
    313 		abort();
    314 	sync_update(type, ship, a, 0, 0, 0, 0);
    315 }
    316 
    317 int
    318 Sync(void)
    319 {
    320 	sig_t sighup, sigint;
    321 	int n;
    322 	int type, shipnum, isstr;
    323 	char *astr;
    324 	long a, b, c, d;
    325 	char buf[80];
    326 	char erred = 0;
    327 #ifndef LOCK_EX
    328 	const char *sync_file;
    329 	const char *sync_lock;
    330 #endif
    331 
    332 	sighup = signal(SIGHUP, SIG_IGN);
    333 	sigint = signal(SIGINT, SIG_IGN);
    334 	for (n = TIMEOUT; --n >= 0;) {
    335 #ifdef LOCK_EX
    336 		if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
    337 			break;
    338 		if (errno != EWOULDBLOCK)
    339 			return -1;
    340 #else
    341 		sync_file = get_sync_file(game);
    342 		sync_lock = get_lock_file(game);
    343 		setegid(egid);
    344 		if (link(sync_file, sync_lock) >= 0) {
    345 			setegid(gid);
    346 			break;
    347 		}
    348 		setegid(gid);
    349 		if (errno != EEXIST)
    350 			return -1;
    351 #endif
    352 		sleep(1);
    353 	}
    354 	if (n <= 0)
    355 		return -1;
    356 	fseek(sync_fp, sync_seek, SEEK_SET);
    357 	for (;;) {
    358 		switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
    359 		case 3:
    360 			break;
    361 		case EOF:
    362 			goto out;
    363 		default:
    364 			goto bad;
    365 		}
    366 		if (shipnum < 0 || shipnum >= cc->vessels)
    367 			goto bad;
    368 		if (isstr != 0 && isstr != 1)
    369 			goto bad;
    370 		if (isstr) {
    371 			int ch;
    372 			char *p;
    373 
    374 			for (p = buf;;) {
    375 				ch = getc(sync_fp);
    376 				*p++ = ch;
    377 				switch (ch) {
    378 				case '\n':
    379 					p--;
    380 				case EOF:
    381 					break;
    382 				default:
    383 					if (p >= buf + sizeof buf)
    384 						p--;
    385 					continue;
    386 				}
    387 				break;
    388 			}
    389 			*p = 0;
    390 			for (p = buf; *p == ' '; p++)
    391 				;
    392 			astr = p;
    393 			a = b = c = d = 0;
    394 		} else {
    395 			if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d)
    396 			    != 4)
    397 				goto bad;
    398 			astr = NULL;
    399 		}
    400 		if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
    401 			goto bad;
    402 	}
    403 bad:
    404 	erred++;
    405 out:
    406 	if (!erred && sync_bp != sync_buf) {
    407 		fseek(sync_fp, 0L, SEEK_END);
    408 		fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
    409 			sync_fp);
    410 		fflush(sync_fp);
    411 		sync_bp = sync_buf;
    412 	}
    413 	sync_seek = ftell(sync_fp);
    414 #ifdef LOCK_EX
    415 	flock(fileno(sync_fp), LOCK_UN);
    416 #else
    417 	setegid(egid);
    418 	unlink(sync_lock);
    419 	setegid(gid);
    420 #endif
    421 	signal(SIGHUP, sighup);
    422 	signal(SIGINT, sigint);
    423 	return erred ? -1 : 0;
    424 }
    425 
    426 static int
    427 sync_update(int type, struct ship *ship, const char *astr,
    428 	    long a, long b, long c, long d)
    429 {
    430 	switch (type) {
    431 	case W_CAPTAIN:  recv_captain(ship, astr);    break;
    432 	case W_CAPTURED: recv_captured(ship, a);      break;
    433 	case W_CLASS:    recv_class(ship, a);         break;
    434 	case W_CREW:     recv_crew(ship, a, b, c);    break;
    435 	case W_DBP:      recv_dbp(ship, a, b, c, d);  break;
    436 	case W_DRIFT:    recv_drift(ship, a);         break;
    437 	case W_EXPLODE:  recv_explode(ship, a);       break;
    438 	case W_FOUL:     recv_foul(ship, a);          break;
    439 	case W_GUNL:     recv_gunl(ship, a, b);       break;
    440 	case W_GUNR:     recv_gunr(ship, a, b);       break;
    441 	case W_HULL:     recv_hull(ship, a);          break;
    442 	case W_MOVE:     recv_move(ship, astr);       break;
    443 	case W_OBP:      recv_obp(ship, a, b, c, d);  break;
    444 	case W_PCREW:    recv_pcrew(ship, a);         break;
    445 	case W_UNFOUL:   recv_unfoul(ship, a, b);     break;
    446 	case W_POINTS:   recv_points(ship, a);        break;
    447 	case W_QUAL:     recv_qual(ship, a);          break;
    448 	case W_UNGRAP:   recv_ungrap(ship, a, b);     break;
    449 	case W_RIGG:     recv_rigg(ship, a, b, c, d); break;
    450 	case W_COL:      recv_col(ship, a);           break;
    451 	case W_DIR:      recv_dir(ship, a);           break;
    452 	case W_ROW:      recv_row(ship, a);           break;
    453 	case W_SIGNAL:   recv_signal(ship, astr);     break;
    454 	case W_SINK:     recv_sink(ship, a);          break;
    455 	case W_STRUCK:   recv_struck(ship, a);        break;
    456 	case W_TA:       recv_ta(ship, a);            break;
    457 	case W_ALIVE:    recv_alive();                break;
    458 	case W_TURN:     recv_turn(a);                break;
    459 	case W_WIND:     recv_wind(a, b);             break;
    460 	case W_FS:       recv_fs(ship, a);            break;
    461 	case W_GRAP:     recv_grap(ship, a);          break;
    462 	case W_RIG1:     recv_rig1(ship, a);          break;
    463 	case W_RIG2:     recv_rig2(ship, a);          break;
    464 	case W_RIG3:     recv_rig3(ship, a);          break;
    465 	case W_RIG4:     recv_rig4(ship, a);          break;
    466 	case W_BEGIN:    recv_begin(ship);            break;
    467 	case W_END:      recv_end(ship);              break;
    468 	case W_DDEAD:    recv_ddead();                break;
    469 	default:
    470 		fprintf(stderr, "sync_update: unknown type %d\r\n", type);
    471 		return -1;
    472 	}
    473 	return 0;
    474 }
    475 
    476 /*
    477  * Messages to send
    478  */
    479 
    480 void
    481 send_captain(struct ship *ship, const char *astr)
    482 {
    483 	Writestr(W_CAPTAIN, ship, astr);
    484 }
    485 
    486 void
    487 send_captured(struct ship *ship, long a)
    488 {
    489 	Write(W_CAPTURED, ship, a, 0, 0, 0);
    490 }
    491 
    492 void
    493 send_class(struct ship *ship, long a)
    494 {
    495 	Write(W_CLASS, ship, a, 0, 0, 0);
    496 }
    497 
    498 void
    499 send_crew(struct ship *ship, long a, long b, long c)
    500 {
    501 	Write(W_CREW, ship, a, b, c, 0);
    502 }
    503 
    504 void
    505 send_dbp(struct ship *ship, long a, long b, long c, long d)
    506 {
    507 	Write(W_DBP, ship, a, b, c, d);
    508 }
    509 
    510 void
    511 send_drift(struct ship *ship, long a)
    512 {
    513 	Write(W_DRIFT, ship, a, 0, 0, 0);
    514 }
    515 
    516 void
    517 send_explode(struct ship *ship, long a)
    518 {
    519 	Write(W_EXPLODE, ship, a, 0, 0, 0);
    520 }
    521 
    522 void
    523 send_foul(struct ship *ship, long a)
    524 {
    525 	Write(W_FOUL, ship, a, 0, 0, 0);
    526 }
    527 
    528 void
    529 send_gunl(struct ship *ship, long a, long b)
    530 {
    531 	Write(W_GUNL, ship, a, b, 0, 0);
    532 }
    533 
    534 void
    535 send_gunr(struct ship *ship, long a, long b)
    536 {
    537 	Write(W_GUNR, ship, a, b, 0, 0);
    538 }
    539 
    540 void
    541 send_hull(struct ship *ship, long a)
    542 {
    543 	Write(W_HULL, ship, a, 0, 0, 0);
    544 }
    545 
    546 void
    547 send_move(struct ship *ship, const char *astr)
    548 {
    549 	Writestr(W_MOVE, ship, astr);
    550 }
    551 
    552 void
    553 send_obp(struct ship *ship, long a, long b, long c, long d)
    554 {
    555 	Write(W_OBP, ship, a, b, c, d);
    556 }
    557 
    558 void
    559 send_pcrew(struct ship *ship, long a)
    560 {
    561 	Write(W_PCREW, ship, a, 0, 0, 0);
    562 }
    563 
    564 void
    565 send_unfoul(struct ship *ship, long a, long b)
    566 {
    567 	Write(W_UNFOUL, ship, a, b, 0, 0);
    568 }
    569 
    570 void
    571 send_points(struct ship *ship, long a)
    572 {
    573 	Write(W_POINTS, ship, a, 0, 0, 0);
    574 }
    575 
    576 void
    577 send_qual(struct ship *ship, long a)
    578 {
    579 	Write(W_QUAL, ship, a, 0, 0, 0);
    580 }
    581 
    582 void
    583 send_ungrap(struct ship *ship, long a, long b)
    584 {
    585 	Write(W_UNGRAP, ship, a, b, 0, 0);
    586 }
    587 
    588 void
    589 send_rigg(struct ship *ship, long a, long b, long c, long d)
    590 {
    591 	Write(W_RIGG, ship, a, b, c, d);
    592 }
    593 
    594 void
    595 send_col(struct ship *ship, long a)
    596 {
    597 	Write(W_COL, ship, a, 0, 0, 0);
    598 }
    599 
    600 void
    601 send_dir(struct ship *ship, long a)
    602 {
    603 	Write(W_DIR, ship, a, 0, 0, 0);
    604 }
    605 
    606 void
    607 send_row(struct ship *ship, long a)
    608 {
    609 	Write(W_ROW, ship, a, 0, 0, 0);
    610 }
    611 
    612 void
    613 send_signal(struct ship *ship, const char *astr)
    614 {
    615 	Writestr(W_SIGNAL, ship, astr);
    616 }
    617 
    618 void
    619 send_sink(struct ship *ship, long a)
    620 {
    621 	Write(W_SINK, ship, a, 0, 0, 0);
    622 }
    623 
    624 void
    625 send_struck(struct ship *ship, long a)
    626 {
    627 	Write(W_STRUCK, ship, a, 0, 0, 0);
    628 }
    629 
    630 void
    631 send_ta(struct ship *ship, long a)
    632 {
    633 	Write(W_TA, ship, a, 0, 0, 0);
    634 }
    635 
    636 void
    637 send_alive(void)
    638 {
    639 	Write(W_ALIVE, NULL, 0, 0, 0, 0);
    640 }
    641 
    642 void
    643 send_turn(long a)
    644 {
    645 	Write(W_TURN, NULL, a, 0, 0, 0);
    646 }
    647 
    648 void
    649 send_wind(long a, long b)
    650 {
    651 	Write(W_WIND, NULL, a, b, 0, 0);
    652 }
    653 
    654 void
    655 send_fs(struct ship *ship, long a)
    656 {
    657 	Write(W_FS, ship, a, 0, 0, 0);
    658 }
    659 
    660 void
    661 send_grap(struct ship *ship, long a)
    662 {
    663 	Write(W_GRAP, ship, a, 0, 0, 0);
    664 }
    665 
    666 void
    667 send_rig1(struct ship *ship, long a)
    668 {
    669 	Write(W_RIG1, ship, a, 0, 0, 0);
    670 }
    671 
    672 void
    673 send_rig2(struct ship *ship, long a)
    674 {
    675 	Write(W_RIG2, ship, a, 0, 0, 0);
    676 }
    677 
    678 void
    679 send_rig3(struct ship *ship, long a)
    680 {
    681 	Write(W_RIG3, ship, a, 0, 0, 0);
    682 }
    683 
    684 void
    685 send_rig4(struct ship *ship, long a)
    686 {
    687 	Write(W_RIG4, ship, a, 0, 0, 0);
    688 }
    689 
    690 void
    691 send_begin(struct ship *ship)
    692 {
    693 	Write(W_BEGIN, ship, 0, 0, 0, 0);
    694 }
    695 
    696 void
    697 send_end(struct ship *ship)
    698 {
    699 	Write(W_END, ship, 0, 0, 0, 0);
    700 }
    701 
    702 void
    703 send_ddead(void)
    704 {
    705 	Write(W_DDEAD, NULL, 0, 0, 0, 0);
    706 }
    707 
    708 
    709 /*
    710  * Actions upon message receipt
    711  */
    712 
    713 static void
    714 recv_captain(struct ship *ship, const char *astr)
    715 {
    716 	strlcpy(ship->file->captain, astr, sizeof ship->file->captain);
    717 }
    718 
    719 static void
    720 recv_captured(struct ship *ship, long a)
    721 {
    722 	if (a < 0)
    723 		ship->file->captured = 0;
    724 	else
    725 		ship->file->captured = SHIP(a);
    726 }
    727 
    728 static void
    729 recv_class(struct ship *ship, long a)
    730 {
    731 	ship->specs->class = a;
    732 }
    733 
    734 static void
    735 recv_crew(struct ship *ship, long a, long b, long c)
    736 {
    737 	struct shipspecs *s = ship->specs;
    738 
    739 	s->crew1 = a;
    740 	s->crew2 = b;
    741 	s->crew3 = c;
    742 }
    743 
    744 static void
    745 recv_dbp(struct ship *ship, long a, long b, long c, long d)
    746 {
    747 	struct BP *p = &ship->file->DBP[a];
    748 
    749 	p->turnsent = b;
    750 	p->toship = SHIP(c);
    751 	p->mensent = d;
    752 }
    753 
    754 static void
    755 recv_drift(struct ship *ship, long a)
    756 {
    757 	ship->file->drift = a;
    758 }
    759 
    760 static void
    761 recv_explode(struct ship *ship, long a)
    762 {
    763 	if ((ship->file->explode = a) == 2)
    764 		ship->file->dir = 0;
    765 }
    766 
    767 static void
    768 recv_foul(struct ship *ship, long a)
    769 {
    770 	struct snag *p = &ship->file->foul[a];
    771 
    772 	if (SHIP(a)->file->dir == 0)
    773 		return;
    774 	if (p->sn_count++ == 0)
    775 		p->sn_turn = turn;
    776 	ship->file->nfoul++;
    777 }
    778 
    779 static void
    780 recv_gunl(struct ship *ship, long a, long b)
    781 {
    782 	struct shipspecs *s = ship->specs;
    783 
    784 	s->gunL = a;
    785 	s->carL = b;
    786 }
    787 
    788 static void
    789 recv_gunr(struct ship *ship, long a, long b)
    790 {
    791 	struct shipspecs *s = ship->specs;
    792 
    793 	s->gunR = a;
    794 	s->carR = b;
    795 }
    796 
    797 static void
    798 recv_hull(struct ship *ship, long a)
    799 {
    800 	ship->specs->hull = a;
    801 }
    802 
    803 static void
    804 recv_move(struct ship *ship, const char *astr)
    805 {
    806 	strlcpy(ship->file->movebuf, astr, sizeof ship->file->movebuf);
    807 }
    808 
    809 static void
    810 recv_obp(struct ship *ship, long a, long b, long c, long d)
    811 {
    812 	struct BP *p = &ship->file->OBP[a];
    813 
    814 	p->turnsent = b;
    815 	p->toship = SHIP(c);
    816 	p->mensent = d;
    817 }
    818 
    819 static void
    820 recv_pcrew(struct ship *ship, long a)
    821 {
    822 	ship->file->pcrew = a;
    823 }
    824 
    825 static void
    826 recv_unfoul(struct ship *ship, long a, long b)
    827 {
    828 	struct snag *p = &ship->file->foul[a];
    829 
    830 	if (p->sn_count > 0) {
    831 		if (b) {
    832 			ship->file->nfoul -= p->sn_count;
    833 			p->sn_count = 0;
    834 		} else {
    835 			ship->file->nfoul--;
    836 			p->sn_count--;
    837 		}
    838 	}
    839 }
    840 
    841 static void
    842 recv_points(struct ship *ship, long a)
    843 {
    844 	ship->file->points = a;
    845 }
    846 
    847 static void
    848 recv_qual(struct ship *ship, long a)
    849 {
    850 	ship->specs->qual = a;
    851 }
    852 
    853 static void
    854 recv_ungrap(struct ship *ship, long a, long b)
    855 {
    856 	struct snag *p = &ship->file->grap[a];
    857 
    858 	if (p->sn_count > 0) {
    859 		if (b) {
    860 			ship->file->ngrap -= p->sn_count;
    861 			p->sn_count = 0;
    862 		} else {
    863 			ship->file->ngrap--;
    864 			p->sn_count--;
    865 		}
    866 	}
    867 }
    868 
    869 static void
    870 recv_rigg(struct ship *ship, long a, long b, long c, long d)
    871 {
    872 	struct shipspecs *s = ship->specs;
    873 
    874 	s->rig1 = a;
    875 	s->rig2 = b;
    876 	s->rig3 = c;
    877 	s->rig4 = d;
    878 }
    879 
    880 static void
    881 recv_col(struct ship *ship, long a)
    882 {
    883 	ship->file->col = a;
    884 }
    885 
    886 static void
    887 recv_dir(struct ship *ship, long a)
    888 {
    889 	ship->file->dir = a;
    890 }
    891 
    892 static void
    893 recv_row(struct ship *ship, long a)
    894 {
    895 	ship->file->row = a;
    896 }
    897 
    898 static void
    899 recv_signal(struct ship *ship, const char *astr)
    900 {
    901 	if (mode == MODE_PLAYER) {
    902 		if (nobells)
    903 			Signal("$$: %s", ship, astr);
    904 		else
    905 			Signal("\a$$: %s", ship, astr);
    906 	}
    907 }
    908 
    909 static void
    910 recv_sink(struct ship *ship, long a)
    911 {
    912 	if ((ship->file->sink = a) == 2)
    913 		ship->file->dir = 0;
    914 }
    915 
    916 static void
    917 recv_struck(struct ship *ship, long a)
    918 {
    919 	ship->file->struck = a;
    920 }
    921 
    922 static void
    923 recv_ta(struct ship *ship, long a)
    924 {
    925 	ship->specs->ta = a;
    926 }
    927 
    928 static void
    929 recv_alive(void)
    930 {
    931 	alive = 1;
    932 }
    933 
    934 static void
    935 recv_turn(long a)
    936 {
    937 	turn = a;
    938 }
    939 
    940 static void
    941 recv_wind(long a, long b)
    942 {
    943 	winddir = a;
    944 	windspeed = b;
    945 }
    946 
    947 static void
    948 recv_fs(struct ship *ship, long a)
    949 {
    950 	ship->file->FS = a;
    951 }
    952 
    953 static void
    954 recv_grap(struct ship *ship, long a)
    955 {
    956 	struct snag *p = &ship->file->grap[a];
    957 
    958 	if (SHIP(a)->file->dir == 0)
    959 		return;
    960 	if (p->sn_count++ == 0)
    961 		p->sn_turn = turn;
    962 	ship->file->ngrap++;
    963 }
    964 
    965 static void
    966 recv_rig1(struct ship *ship, long a)
    967 {
    968 	ship->specs->rig1 = a;
    969 }
    970 
    971 static void
    972 recv_rig2(struct ship *ship, long a)
    973 {
    974 	ship->specs->rig2 = a;
    975 }
    976 
    977 static void
    978 recv_rig3(struct ship *ship, long a)
    979 {
    980 	ship->specs->rig3 = a;
    981 }
    982 
    983 static void
    984 recv_rig4(struct ship *ship, long a)
    985 {
    986 	ship->specs->rig4 = a;
    987 }
    988 
    989 static void
    990 recv_begin(struct ship *ship)
    991 {
    992 	strcpy(ship->file->captain, "begin");
    993 	people++;
    994 }
    995 
    996 static void
    997 recv_end(struct ship *ship)
    998 {
    999 	*ship->file->captain = 0;
   1000 	ship->file->points = 0;
   1001 	people--;
   1002 }
   1003 
   1004 static void
   1005 recv_ddead(void)
   1006 {
   1007 	hasdriver = 0;
   1008 }
   1009