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 *
get_sync_file(int scenario_number)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 *
get_lock_file(int scenario_number)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
fmtship(char * buf,size_t len,const char * fmt,struct ship * ship)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
makesignal(struct ship * from,const char * fmt,struct ship * ship,...)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
makemsg(struct ship * from,const char * fmt,...)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
sync_exists(int gamenum)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
sync_open(void)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
sync_close(int doremove)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
Write(int type,struct ship * ship,long a,long b,long c,long d)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
Writestr(int type,struct ship * ship,const char * a)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
Sync(void)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
sync_update(int type,struct ship * ship,const char * astr,long a,long b,long c,long d)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
send_captain(struct ship * ship,const char * astr)480 send_captain(struct ship *ship, const char *astr)
481 {
482           Writestr(W_CAPTAIN, ship, astr);
483 }
484 
485 void
send_captured(struct ship * ship,long a)486 send_captured(struct ship *ship, long a)
487 {
488           Write(W_CAPTURED, ship, a, 0, 0, 0);
489 }
490 
491 void
send_class(struct ship * ship,long a)492 send_class(struct ship *ship, long a)
493 {
494           Write(W_CLASS, ship, a, 0, 0, 0);
495 }
496 
497 void
send_crew(struct ship * ship,long a,long b,long c)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
send_dbp(struct ship * ship,long a,long b,long c,long d)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
send_drift(struct ship * ship,long a)510 send_drift(struct ship *ship, long a)
511 {
512           Write(W_DRIFT, ship, a, 0, 0, 0);
513 }
514 
515 void
send_explode(struct ship * ship,long a)516 send_explode(struct ship *ship, long a)
517 {
518           Write(W_EXPLODE, ship, a, 0, 0, 0);
519 }
520 
521 void
send_foul(struct ship * ship,long a)522 send_foul(struct ship *ship, long a)
523 {
524           Write(W_FOUL, ship, a, 0, 0, 0);
525 }
526 
527 void
send_gunl(struct ship * ship,long a,long b)528 send_gunl(struct ship *ship, long a, long b)
529 {
530           Write(W_GUNL, ship, a, b, 0, 0);
531 }
532 
533 void
send_gunr(struct ship * ship,long a,long b)534 send_gunr(struct ship *ship, long a, long b)
535 {
536           Write(W_GUNR, ship, a, b, 0, 0);
537 }
538 
539 void
send_hull(struct ship * ship,long a)540 send_hull(struct ship *ship, long a)
541 {
542           Write(W_HULL, ship, a, 0, 0, 0);
543 }
544 
545 void
send_move(struct ship * ship,const char * astr)546 send_move(struct ship *ship, const char *astr)
547 {
548           Writestr(W_MOVE, ship, astr);
549 }
550 
551 void
send_obp(struct ship * ship,long a,long b,long c,long d)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
send_pcrew(struct ship * ship,long a)558 send_pcrew(struct ship *ship, long a)
559 {
560           Write(W_PCREW, ship, a, 0, 0, 0);
561 }
562 
563 void
send_unfoul(struct ship * ship,long a,long b)564 send_unfoul(struct ship *ship, long a, long b)
565 {
566           Write(W_UNFOUL, ship, a, b, 0, 0);
567 }
568 
569 void
send_points(struct ship * ship,long a)570 send_points(struct ship *ship, long a)
571 {
572           Write(W_POINTS, ship, a, 0, 0, 0);
573 }
574 
575 void
send_qual(struct ship * ship,long a)576 send_qual(struct ship *ship, long a)
577 {
578           Write(W_QUAL, ship, a, 0, 0, 0);
579 }
580 
581 void
send_ungrap(struct ship * ship,long a,long b)582 send_ungrap(struct ship *ship, long a, long b)
583 {
584           Write(W_UNGRAP, ship, a, b, 0, 0);
585 }
586 
587 void
send_rigg(struct ship * ship,long a,long b,long c,long d)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
send_col(struct ship * ship,long a)594 send_col(struct ship *ship, long a)
595 {
596           Write(W_COL, ship, a, 0, 0, 0);
597 }
598 
599 void
send_dir(struct ship * ship,long a)600 send_dir(struct ship *ship, long a)
601 {
602           Write(W_DIR, ship, a, 0, 0, 0);
603 }
604 
605 void
send_row(struct ship * ship,long a)606 send_row(struct ship *ship, long a)
607 {
608           Write(W_ROW, ship, a, 0, 0, 0);
609 }
610 
611 void
send_signal(struct ship * ship,const char * astr)612 send_signal(struct ship *ship, const char *astr)
613 {
614           Writestr(W_SIGNAL, ship, astr);
615 }
616 
617 void
send_sink(struct ship * ship,long a)618 send_sink(struct ship *ship, long a)
619 {
620           Write(W_SINK, ship, a, 0, 0, 0);
621 }
622 
623 void
send_struck(struct ship * ship,long a)624 send_struck(struct ship *ship, long a)
625 {
626           Write(W_STRUCK, ship, a, 0, 0, 0);
627 }
628 
629 void
send_ta(struct ship * ship,long a)630 send_ta(struct ship *ship, long a)
631 {
632           Write(W_TA, ship, a, 0, 0, 0);
633 }
634 
635 void
send_alive(void)636 send_alive(void)
637 {
638           Write(W_ALIVE, NULL, 0, 0, 0, 0);
639 }
640 
641 void
send_turn(long a)642 send_turn(long a)
643 {
644           Write(W_TURN, NULL, a, 0, 0, 0);
645 }
646 
647 void
send_wind(long a,long b)648 send_wind(long a, long b)
649 {
650           Write(W_WIND, NULL, a, b, 0, 0);
651 }
652 
653 void
send_fs(struct ship * ship,long a)654 send_fs(struct ship *ship, long a)
655 {
656           Write(W_FS, ship, a, 0, 0, 0);
657 }
658 
659 void
send_grap(struct ship * ship,long a)660 send_grap(struct ship *ship, long a)
661 {
662           Write(W_GRAP, ship, a, 0, 0, 0);
663 }
664 
665 void
send_rig1(struct ship * ship,long a)666 send_rig1(struct ship *ship, long a)
667 {
668           Write(W_RIG1, ship, a, 0, 0, 0);
669 }
670 
671 void
send_rig2(struct ship * ship,long a)672 send_rig2(struct ship *ship, long a)
673 {
674           Write(W_RIG2, ship, a, 0, 0, 0);
675 }
676 
677 void
send_rig3(struct ship * ship,long a)678 send_rig3(struct ship *ship, long a)
679 {
680           Write(W_RIG3, ship, a, 0, 0, 0);
681 }
682 
683 void
send_rig4(struct ship * ship,long a)684 send_rig4(struct ship *ship, long a)
685 {
686           Write(W_RIG4, ship, a, 0, 0, 0);
687 }
688 
689 void
send_begin(struct ship * ship)690 send_begin(struct ship *ship)
691 {
692           Write(W_BEGIN, ship, 0, 0, 0, 0);
693 }
694 
695 void
send_end(struct ship * ship)696 send_end(struct ship *ship)
697 {
698           Write(W_END, ship, 0, 0, 0, 0);
699 }
700 
701 void
send_ddead(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
recv_captain(struct ship * ship,const char * astr)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
recv_captured(struct ship * ship,long a)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
recv_class(struct ship * ship,long a)728 recv_class(struct ship *ship, long a)
729 {
730           ship->specs->class = a;
731 }
732 
733 static void
recv_crew(struct ship * ship,long a,long b,long c)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
recv_dbp(struct ship * ship,long a,long b,long c,long d)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
recv_drift(struct ship * ship,long a)754 recv_drift(struct ship *ship, long a)
755 {
756           ship->file->drift = a;
757 }
758 
759 static void
recv_explode(struct ship * ship,long a)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
recv_foul(struct ship * ship,long a)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
recv_gunl(struct ship * ship,long a,long b)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
recv_gunr(struct ship * ship,long a,long b)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
recv_hull(struct ship * ship,long a)797 recv_hull(struct ship *ship, long a)
798 {
799           ship->specs->hull = a;
800 }
801 
802 static void
recv_move(struct ship * ship,const char * astr)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
recv_obp(struct ship * ship,long a,long b,long c,long d)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
recv_pcrew(struct ship * ship,long a)819 recv_pcrew(struct ship *ship, long a)
820 {
821           ship->file->pcrew = a;
822 }
823 
824 static void
recv_unfoul(struct ship * ship,long a,long b)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
recv_points(struct ship * ship,long a)841 recv_points(struct ship *ship, long a)
842 {
843           ship->file->points = a;
844 }
845 
846 static void
recv_qual(struct ship * ship,long a)847 recv_qual(struct ship *ship, long a)
848 {
849           ship->specs->qual = a;
850 }
851 
852 static void
recv_ungrap(struct ship * ship,long a,long b)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
recv_rigg(struct ship * ship,long a,long b,long c,long d)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
recv_col(struct ship * ship,long a)880 recv_col(struct ship *ship, long a)
881 {
882           ship->file->col = a;
883 }
884 
885 static void
recv_dir(struct ship * ship,long a)886 recv_dir(struct ship *ship, long a)
887 {
888           ship->file->dir = a;
889 }
890 
891 static void
recv_row(struct ship * ship,long a)892 recv_row(struct ship *ship, long a)
893 {
894           ship->file->row = a;
895 }
896 
897 static void
recv_signal(struct ship * ship,const char * astr)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
recv_sink(struct ship * ship,long a)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
recv_struck(struct ship * ship,long a)916 recv_struck(struct ship *ship, long a)
917 {
918           ship->file->struck = a;
919 }
920 
921 static void
recv_ta(struct ship * ship,long a)922 recv_ta(struct ship *ship, long a)
923 {
924           ship->specs->ta = a;
925 }
926 
927 static void
recv_alive(void)928 recv_alive(void)
929 {
930           alive = 1;
931 }
932 
933 static void
recv_turn(long a)934 recv_turn(long a)
935 {
936           turn = a;
937 }
938 
939 static void
recv_wind(long a,long b)940 recv_wind(long a, long b)
941 {
942           winddir = a;
943           windspeed = b;
944 }
945 
946 static void
recv_fs(struct ship * ship,long a)947 recv_fs(struct ship *ship, long a)
948 {
949           ship->file->FS = a;
950 }
951 
952 static void
recv_grap(struct ship * ship,long a)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
recv_rig1(struct ship * ship,long a)965 recv_rig1(struct ship *ship, long a)
966 {
967           ship->specs->rig1 = a;
968 }
969 
970 static void
recv_rig2(struct ship * ship,long a)971 recv_rig2(struct ship *ship, long a)
972 {
973           ship->specs->rig2 = a;
974 }
975 
976 static void
recv_rig3(struct ship * ship,long a)977 recv_rig3(struct ship *ship, long a)
978 {
979           ship->specs->rig3 = a;
980 }
981 
982 static void
recv_rig4(struct ship * ship,long a)983 recv_rig4(struct ship *ship, long a)
984 {
985           ship->specs->rig4 = a;
986 }
987 
988 static void
recv_begin(struct ship * ship)989 recv_begin(struct ship *ship)
990 {
991           strcpy(ship->file->captain, "begin");
992           people++;
993 }
994 
995 static void
recv_end(struct ship * ship)996 recv_end(struct ship *ship)
997 {
998           *ship->file->captain = 0;
999           ship->file->points = 0;
1000           people--;
1001 }
1002 
1003 static void
recv_ddead(void)1004 recv_ddead(void)
1005 {
1006           hasdriver = 0;
1007 }
1008