1 /* $NetBSD: hunt.c,v 1.12 2001/02/05 00:40:45 christos Exp $ */ 2 /* 3 * Hunt 4 * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold 5 * San Francisco, California 6 */ 7 8 #include <sys/cdefs.h> 9 #ifndef lint 10 __RCSID("$NetBSD: hunt.c,v 1.12 2001/02/05 00:40:45 christos Exp $"); 11 #endif /* not lint */ 12 13 # include <sys/param.h> 14 # include <sys/stat.h> 15 # include <sys/time.h> 16 # include <ctype.h> 17 # include <err.h> 18 # include <errno.h> 19 # include <curses.h> 20 # include <signal.h> 21 # include <stdlib.h> 22 # include <string.h> 23 # if !defined(USE_CURSES) && defined(BSD_RELEASE) && BSD_RELEASE >= 44 24 # include <termios.h> 25 static struct termios saved_tty; 26 # endif 27 # include <unistd.h> 28 29 # include "hunt.h" 30 31 /* 32 * Some old versions of curses don't have these defined 33 */ 34 # if !defined(cbreak) && (!defined(BSD_RELEASE) || BSD_RELEASE < 44) 35 # define cbreak() crmode() 36 # endif 37 38 # if !defined(USE_CURSES) || !defined(TERMINFO) 39 # define beep() (void) putchar(CTRL('G')) 40 # endif 41 # if !defined(USE_CURSES) 42 # undef refresh 43 # define refresh() (void) fflush(stdout); 44 # endif 45 # ifdef USE_CURSES 46 # define clear_eol() clrtoeol() 47 # define put_ch addch 48 # define put_str addstr 49 # endif 50 51 #if !defined(BSD_RELEASE) || BSD_RELEASE < 44 52 extern int _putchar(); 53 #endif 54 55 FLAG Last_player = FALSE; 56 # ifdef MONITOR 57 FLAG Am_monitor = FALSE; 58 # endif 59 60 char Buf[BUFSIZ]; 61 62 int Socket; 63 # ifdef INTERNET 64 char *Sock_host; 65 char *use_port; 66 FLAG Query_driver = FALSE; 67 char *Send_message = NULL; 68 FLAG Show_scores = FALSE; 69 # endif 70 71 SOCKET Daemon; 72 # ifdef INTERNET 73 # define DAEMON_SIZE (sizeof Daemon) 74 # else 75 # define DAEMON_SIZE (sizeof Daemon - 1) 76 # endif 77 78 char map_key[256]; /* what to map keys to */ 79 FLAG no_beep; 80 81 static char name[NAMELEN]; 82 static char team = ' '; 83 84 static int in_visual; 85 86 extern int cur_row, cur_col; 87 88 void dump_scores __P((SOCKET)); 89 long env_init __P((long)); 90 void fill_in_blanks __P((void)); 91 void leave __P((int, char *)) __attribute__((__noreturn__)); 92 int main __P((int, char *[])); 93 # ifdef INTERNET 94 SOCKET *list_drivers __P((void)); 95 # endif 96 97 extern int Otto_mode; 98 /* 99 * main: 100 * Main program for local process 101 */ 102 int 103 main(ac, av) 104 int ac; 105 char **av; 106 { 107 char *term; 108 int c; 109 long enter_status; 110 111 enter_status = env_init((long) Q_CLOAK); 112 while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != -1) { 113 switch (c) { 114 case 'l': /* rsh compatibility */ 115 case 'n': 116 (void) strncpy(name, optarg, NAMELEN); 117 break; 118 case 't': 119 team = *optarg; 120 if (!isdigit(team)) { 121 warnx("Team names must be numeric"); 122 team = ' '; 123 } 124 break; 125 case 'o': 126 # ifndef OTTO 127 warnx("The -o flag is reserved for future use."); 128 goto usage; 129 # else 130 Otto_mode = TRUE; 131 break; 132 # endif 133 case 'm': 134 # ifdef MONITOR 135 Am_monitor = TRUE; 136 # else 137 warnx("The monitor was not compiled in."); 138 # endif 139 break; 140 # ifdef INTERNET 141 case 'S': 142 Show_scores = TRUE; 143 break; 144 case 'q': /* query whether hunt is running */ 145 Query_driver = TRUE; 146 break; 147 case 'w': 148 Send_message = optarg; 149 break; 150 case 'h': 151 Sock_host = optarg; 152 break; 153 case 'p': 154 use_port = optarg; 155 Test_port = atoi(use_port); 156 break; 157 # else 158 case 'S': 159 case 'q': 160 case 'w': 161 case 'h': 162 case 'p': 163 wanrx("Need TCP/IP for S, q, w, h, and p options."); 164 break; 165 # endif 166 case 'c': 167 enter_status = Q_CLOAK; 168 break; 169 case 'f': 170 # ifdef FLY 171 enter_status = Q_FLY; 172 # else 173 warnx("The flying code was not compiled in."); 174 # endif 175 break; 176 case 's': 177 enter_status = Q_SCAN; 178 break; 179 case 'b': 180 no_beep = !no_beep; 181 break; 182 default: 183 usage: 184 fputs( 185 "usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n", 186 stderr); 187 exit(1); 188 } 189 } 190 # ifdef INTERNET 191 if (optind + 1 < ac) 192 goto usage; 193 else if (optind + 1 == ac) 194 Sock_host = av[ac - 1]; 195 # else 196 if (optind > ac) 197 goto usage; 198 # endif 199 200 # ifdef INTERNET 201 if (Show_scores) { 202 SOCKET *hosts; 203 204 for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) 205 dump_scores(*hosts); 206 exit(0); 207 } 208 if (Query_driver) { 209 SOCKET *hosts; 210 211 for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) { 212 struct hostent *hp; 213 int num_players; 214 215 hp = gethostbyaddr((char *) &hosts->sin_addr, 216 sizeof hosts->sin_addr, AF_INET); 217 num_players = ntohs(hosts->sin_port); 218 printf("%d player%s hunting on %s!\n", 219 num_players, (num_players == 1) ? "" : "s", 220 hp != NULL ? hp->h_name : 221 inet_ntoa(hosts->sin_addr)); 222 } 223 exit(0); 224 } 225 # endif 226 # ifdef OTTO 227 if (Otto_mode) 228 (void) strncpy(name, "otto", NAMELEN); 229 else 230 # endif 231 fill_in_blanks(); 232 233 (void) fflush(stdout); 234 if (!isatty(0) || (term = getenv("TERM")) == NULL) 235 errx(1, "no terminal type"); 236 # ifdef USE_CURSES 237 initscr(); 238 (void) noecho(); 239 (void) cbreak(); 240 # else /* !USE_CURSES */ 241 # if !defined(BSD_RELEASE) || BSD_RELEASE < 44 242 _tty_ch = 0; 243 # endif 244 gettmode(); 245 (void) setterm(term); 246 (void) noecho(); 247 (void) cbreak(); 248 # if defined(BSD_RELEASE) && BSD_RELEASE >= 44 249 tcgetattr(0, &saved_tty); 250 # endif 251 _puts(TI); 252 _puts(VS); 253 # endif /* !USE_CURSES */ 254 in_visual = TRUE; 255 if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH) 256 leave(1, "Need a larger window"); 257 clear_the_screen(); 258 (void) signal(SIGINT, intr); 259 (void) signal(SIGTERM, sigterm); 260 (void) signal(SIGEMT, sigemt); 261 (void) signal(SIGPIPE, SIG_IGN); 262 #if !defined(USE_CURSES) && defined(SIGTSTP) 263 (void) signal(SIGTSTP, tstp); 264 #endif 265 266 for (;;) { 267 # ifdef INTERNET 268 find_driver(TRUE); 269 270 if (Daemon.sin_port == 0) 271 leave(1, "Game not found, try again"); 272 273 jump_in: 274 do { 275 int option; 276 277 Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); 278 if (Socket < 0) 279 err(1, "socket"); 280 option = 1; 281 if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, 282 &option, sizeof option) < 0) 283 warn("setsockopt loopback"); 284 errno = 0; 285 if (connect(Socket, (struct sockaddr *) &Daemon, 286 DAEMON_SIZE) < 0) { 287 if (errno != ECONNREFUSED) { 288 warn("connect"); 289 leave(1, "connect"); 290 } 291 } 292 else 293 break; 294 sleep(1); 295 } while (close(Socket) == 0); 296 # else /* !INTERNET */ 297 /* 298 * set up a socket 299 */ 300 301 if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) 302 err(1, "socket"); 303 304 /* 305 * attempt to connect the socket to a name; if it fails that 306 * usually means that the driver isn't running, so we start 307 * up the driver. 308 */ 309 310 Daemon.sun_family = SOCK_FAMILY; 311 (void) strcpy(Daemon.sun_path, Sock_name); 312 if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) { 313 if (errno != ENOENT) { 314 warn("connect"); 315 leave(1, "connect2"); 316 } 317 start_driver(); 318 319 do { 320 (void) close(Socket); 321 if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 322 0)) < 0) 323 err(1, "socket"); 324 sleep(2); 325 } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0); 326 } 327 # endif 328 329 do_connect(name, team, enter_status); 330 # ifdef INTERNET 331 if (Send_message != NULL) { 332 do_message(); 333 if (enter_status == Q_MESSAGE) 334 break; 335 Send_message = NULL; 336 /* don't continue as that will call find_driver */ 337 goto jump_in; 338 } 339 # endif 340 playit(); 341 if ((enter_status = quit(enter_status)) == Q_QUIT) 342 break; 343 } 344 leave(0, (char *) NULL); 345 /* NOTREACHED */ 346 return(0); 347 } 348 349 # ifdef INTERNET 350 # ifdef BROADCAST 351 int 352 broadcast_vec(s, vector) 353 int s; /* socket */ 354 struct sockaddr **vector; 355 { 356 char if_buf[BUFSIZ]; 357 struct ifconf ifc; 358 struct ifreq *ifr; 359 unsigned int n; 360 int vec_cnt; 361 362 *vector = NULL; 363 ifc.ifc_len = sizeof if_buf; 364 ifc.ifc_buf = if_buf; 365 if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) 366 return 0; 367 vec_cnt = 0; 368 n = ifc.ifc_len / sizeof (struct ifreq); 369 *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr)); 370 for (ifr = ifc.ifc_req; n != 0; n--, ifr++) 371 if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0) 372 memcpy(&(*vector)[vec_cnt++], &ifr->ifr_addr, 373 sizeof (struct sockaddr)); 374 return vec_cnt; 375 } 376 # endif 377 378 SOCKET * 379 list_drivers() 380 { 381 int option; 382 u_short msg; 383 u_short port_num; 384 static SOCKET test; 385 int test_socket; 386 int namelen; 387 char local_name[MAXHOSTNAMELEN + 1]; 388 static int initial = TRUE; 389 static struct in_addr local_address; 390 struct hostent *hp; 391 # ifdef BROADCAST 392 static int brdc; 393 static SOCKET *brdv; 394 # else 395 u_long local_net; 396 # endif 397 int i; 398 static SOCKET *listv; 399 static unsigned int listmax; 400 unsigned int listc; 401 fd_set mask; 402 struct timeval wait; 403 404 if (initial) { /* do one time initialization */ 405 # ifndef BROADCAST 406 sethostent(1); /* don't bother to close host file */ 407 # endif 408 if (gethostname(local_name, sizeof local_name) < 0) { 409 leave(1, "Sorry, I have no name."); 410 /* NOTREACHED */ 411 } 412 local_name[sizeof(local_name) - 1] = '\0'; 413 if ((hp = gethostbyname(local_name)) == NULL) { 414 leave(1, "Can't find myself."); 415 /* NOTREACHED */ 416 } 417 local_address = * ((struct in_addr *) hp->h_addr); 418 419 listmax = 20; 420 listv = (SOCKET *) malloc(listmax * sizeof (SOCKET)); 421 } else if (Sock_host != NULL) 422 return listv; /* address already valid */ 423 424 test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); 425 if (test_socket < 0) { 426 warn("socket"); 427 leave(1, "socket system call failed"); 428 /* NOTREACHED */ 429 } 430 test.sin_family = SOCK_FAMILY; 431 test.sin_port = htons(Test_port); 432 listc = 0; 433 434 if (Sock_host != NULL) { /* explicit host given */ 435 if ((hp = gethostbyname(Sock_host)) == NULL) { 436 leave(1, "Unknown host"); 437 /* NOTREACHED */ 438 } 439 test.sin_addr = *((struct in_addr *) hp->h_addr); 440 goto test_one_host; 441 } 442 443 if (!initial) { 444 /* favor host of previous session by broadcasting to it first */ 445 test.sin_addr = Daemon.sin_addr; 446 msg = htons(C_PLAYER); /* Must be playing! */ 447 (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, 448 (struct sockaddr *) &test, DAEMON_SIZE); 449 } 450 451 # ifdef BROADCAST 452 if (initial) 453 brdc = broadcast_vec(test_socket, (struct sockaddr **) &brdv); 454 455 if (brdc <= 0) { 456 initial = FALSE; 457 test.sin_addr = local_address; 458 goto test_one_host; 459 } 460 461 # ifdef SO_BROADCAST 462 /* Sun's will broadcast even though this option can't be set */ 463 option = 1; 464 if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST, 465 &option, sizeof option) < 0) { 466 warn("setsockopt broadcast"); 467 leave(1, "setsockopt broadcast"); 468 /* NOTREACHED */ 469 } 470 # endif 471 472 /* send broadcast packets on all interfaces */ 473 msg = htons(C_TESTMSG()); 474 for (i = 0; i < brdc; i++) { 475 test.sin_addr = brdv[i].sin_addr; 476 if (sendto(test_socket, (char *) &msg, sizeof msg, 0, 477 (struct sockaddr *) &test, DAEMON_SIZE) < 0) { 478 warn("sendto"); 479 leave(1, "sendto"); 480 /* NOTREACHED */ 481 } 482 } 483 # else /* !BROADCAST */ 484 /* loop thru all hosts on local net and send msg to them. */ 485 msg = htons(C_TESTMSG()); 486 local_net = inet_netof(local_address); 487 sethostent(0); /* rewind host file */ 488 while (hp = gethostent()) { 489 if (local_net == inet_netof(* ((struct in_addr *) hp->h_addr))){ 490 test.sin_addr = * ((struct in_addr *) hp->h_addr); 491 (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, 492 (struct sockaddr *) &test, DAEMON_SIZE); 493 } 494 } 495 # endif 496 497 get_response: 498 namelen = DAEMON_SIZE; 499 errno = 0; 500 wait.tv_sec = 1; 501 wait.tv_usec = 0; 502 for (;;) { 503 if (listc + 1 >= listmax) { 504 listmax += 20; 505 listv = (SOCKET *) realloc((char *) listv, 506 listmax * sizeof(SOCKET)); 507 } 508 509 FD_ZERO(&mask); 510 FD_SET(test_socket, &mask); 511 if (select(test_socket + 1, &mask, NULL, NULL, &wait) == 1 && 512 recvfrom(test_socket, (char *) &port_num, sizeof(port_num), 513 0, (struct sockaddr *) &listv[listc], &namelen) > 0) { 514 /* 515 * Note that we do *not* convert from network to host 516 * order since the port number *should* be in network 517 * order: 518 */ 519 for (i = 0; i < listc; i += 1) 520 if (listv[listc].sin_addr.s_addr 521 == listv[i].sin_addr.s_addr) 522 break; 523 if (i == listc) 524 listv[listc++].sin_port = port_num; 525 continue; 526 } 527 528 if (errno != 0 && errno != EINTR) { 529 warn("select/recvfrom"); 530 leave(1, "select/recvfrom"); 531 /* NOTREACHED */ 532 } 533 534 /* terminate list with local address */ 535 listv[listc].sin_family = SOCK_FAMILY; 536 listv[listc].sin_addr = local_address; 537 listv[listc].sin_port = htons(0); 538 539 (void) close(test_socket); 540 initial = FALSE; 541 return listv; 542 } 543 544 test_one_host: 545 msg = htons(C_TESTMSG()); 546 (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, 547 (struct sockaddr *) &test, DAEMON_SIZE); 548 goto get_response; 549 } 550 551 void 552 find_driver(do_startup) 553 FLAG do_startup; 554 { 555 SOCKET *hosts; 556 557 hosts = list_drivers(); 558 if (hosts[0].sin_port != htons(0)) { 559 int i, c; 560 561 if (hosts[1].sin_port == htons(0)) { 562 Daemon = hosts[0]; 563 return; 564 } 565 /* go thru list and return host that matches daemon */ 566 clear_the_screen(); 567 # ifdef USE_CURSES 568 move(1, 0); 569 # else 570 mvcur(cur_row, cur_col, 1, 0); 571 cur_row = 1; 572 cur_col = 0; 573 # endif 574 put_str("Pick one:"); 575 for (i = 0; i < HEIGHT - 4 && hosts[i].sin_port != htons(0); 576 i += 1) { 577 struct hostent *hp; 578 char buf[80]; 579 580 # ifdef USE_CURSES 581 move(3 + i, 0); 582 # else 583 mvcur(cur_row, cur_col, 3 + i, 0); 584 cur_row = 3 + i; 585 cur_col = 0; 586 # endif 587 hp = gethostbyaddr((char *) &hosts[i].sin_addr, 588 sizeof hosts[i].sin_addr, AF_INET); 589 (void) sprintf(buf, "%8c %.64s", 'a' + i, 590 hp != NULL ? hp->h_name 591 : inet_ntoa(hosts->sin_addr)); 592 put_str(buf); 593 } 594 # ifdef USE_CURSES 595 move(4 + i, 0); 596 # else 597 mvcur(cur_row, cur_col, 4 + i, 0); 598 cur_row = 4 + i; 599 cur_col = 0; 600 # endif 601 put_str("Enter letter: "); 602 refresh(); 603 while (!islower(c = getchar()) || (c -= 'a') >= i) { 604 beep(); 605 refresh(); 606 } 607 Daemon = hosts[c]; 608 clear_the_screen(); 609 return; 610 } 611 if (!do_startup) 612 return; 613 614 start_driver(); 615 sleep(2); 616 find_driver(FALSE); 617 } 618 619 void 620 dump_scores(host) 621 SOCKET host; 622 { 623 struct hostent *hp; 624 int s; 625 char buf[BUFSIZ]; 626 int cnt; 627 628 hp = gethostbyaddr((char *) &host.sin_addr, sizeof host.sin_addr, 629 AF_INET); 630 printf("\n%s:\n", hp != NULL ? hp->h_name : inet_ntoa(host.sin_addr)); 631 fflush(stdout); 632 633 s = socket(SOCK_FAMILY, SOCK_STREAM, 0); 634 if (s < 0) 635 err(1, "socket"); 636 if (connect(s, (struct sockaddr *) &host, sizeof host) < 0) 637 err(1, "connect"); 638 while ((cnt = read(s, buf, BUFSIZ)) > 0) 639 write(fileno(stdout), buf, cnt); 640 (void) close(s); 641 } 642 643 # endif 644 645 void 646 start_driver() 647 { 648 int procid; 649 650 # ifdef MONITOR 651 if (Am_monitor) { 652 leave(1, "No one playing."); 653 /* NOTREACHED */ 654 } 655 # endif 656 657 # ifdef INTERNET 658 if (Sock_host != NULL) { 659 sleep(3); 660 return; 661 } 662 # endif 663 664 # ifdef USE_CURSES 665 move(HEIGHT, 0); 666 # else 667 mvcur(cur_row, cur_col, HEIGHT, 0); 668 cur_row = HEIGHT; 669 cur_col = 0; 670 # endif 671 put_str("Starting..."); 672 refresh(); 673 procid = fork(); 674 if (procid == -1) { 675 warn("fork"); 676 leave(1, "fork failed."); 677 } 678 if (procid == 0) { 679 (void) signal(SIGINT, SIG_IGN); 680 # ifndef INTERNET 681 (void) close(Socket); 682 # else 683 if (use_port == NULL) 684 # endif 685 execl(Driver, "HUNT", (char *) NULL); 686 # ifdef INTERNET 687 else 688 execl(Driver, "HUNT", "-p", use_port, (char *) NULL); 689 # endif 690 /* only get here if exec failed */ 691 (void) kill(getppid(), SIGEMT); /* tell mom */ 692 _exit(1); 693 } 694 # ifdef USE_CURSES 695 move(HEIGHT, 0); 696 # else 697 mvcur(cur_row, cur_col, HEIGHT, 0); 698 cur_row = HEIGHT; 699 cur_col = 0; 700 # endif 701 put_str("Connecting..."); 702 refresh(); 703 } 704 705 /* 706 * bad_con: 707 * We had a bad connection. For the moment we assume that this 708 * means the game is full. 709 */ 710 void 711 bad_con() 712 { 713 leave(1, "The game is full. Sorry."); 714 /* NOTREACHED */ 715 } 716 717 /* 718 * bad_ver: 719 * version number mismatch. 720 */ 721 void 722 bad_ver() 723 { 724 leave(1, "Version number mismatch. No go."); 725 /* NOTREACHED */ 726 } 727 728 /* 729 * sigterm: 730 * Handle a terminate signal 731 */ 732 SIGNAL_TYPE 733 sigterm(dummy) 734 int dummy; 735 { 736 leave(0, (char *) NULL); 737 /* NOTREACHED */ 738 } 739 740 741 /* 742 * sigemt: 743 * Handle a emt signal - shouldn't happen on vaxes(?) 744 */ 745 SIGNAL_TYPE 746 sigemt(dummy) 747 int dummy; 748 { 749 leave(1, "Unable to start driver. Try again."); 750 /* NOTREACHED */ 751 } 752 753 # ifdef INTERNET 754 /* 755 * sigalrm: 756 * Handle an alarm signal 757 */ 758 SIGNAL_TYPE 759 sigalrm(dummy) 760 int dummy; 761 { 762 return; 763 } 764 # endif 765 766 /* 767 * rmnl: 768 * Remove a '\n' at the end of a string if there is one 769 */ 770 void 771 rmnl(s) 772 char *s; 773 { 774 char *cp; 775 776 cp = strrchr(s, '\n'); 777 if (cp != NULL) 778 *cp = '\0'; 779 } 780 781 /* 782 * intr: 783 * Handle a interrupt signal 784 */ 785 SIGNAL_TYPE 786 intr(dummy) 787 int dummy; 788 { 789 int ch; 790 int explained; 791 int y, x; 792 793 (void) signal(SIGINT, SIG_IGN); 794 # ifdef USE_CURSES 795 getyx(stdscr, y, x); 796 move(HEIGHT, 0); 797 # else 798 y = cur_row; 799 x = cur_col; 800 mvcur(cur_row, cur_col, HEIGHT, 0); 801 cur_row = HEIGHT; 802 cur_col = 0; 803 # endif 804 put_str("Really quit? "); 805 clear_eol(); 806 refresh(); 807 explained = FALSE; 808 for (;;) { 809 ch = getchar(); 810 if (isupper(ch)) 811 ch = tolower(ch); 812 if (ch == 'y') { 813 if (Socket != 0) { 814 (void) write(Socket, "q", 1); 815 (void) close(Socket); 816 } 817 leave(0, (char *) NULL); 818 } 819 else if (ch == 'n') { 820 (void) signal(SIGINT, intr); 821 # ifdef USE_CURSES 822 move(y, x); 823 # else 824 mvcur(cur_row, cur_col, y, x); 825 cur_row = y; 826 cur_col = x; 827 # endif 828 refresh(); 829 return; 830 } 831 if (!explained) { 832 put_str("(Yes or No) "); 833 refresh(); 834 explained = TRUE; 835 } 836 beep(); 837 refresh(); 838 } 839 } 840 841 /* 842 * leave: 843 * Leave the game somewhat gracefully, restoring all current 844 * tty stats. 845 */ 846 void 847 leave(eval, mesg) 848 int eval; 849 char *mesg; 850 { 851 if (in_visual) { 852 # ifdef USE_CURSES 853 move(HEIGHT, 0); 854 refresh(); 855 endwin(); 856 # else /* !USE_CURSES */ 857 mvcur(cur_row, cur_col, HEIGHT, 0); 858 (void) fflush(stdout); /* flush in case VE changes pages */ 859 # if defined(BSD_RELEASE) && BSD_RELEASE >= 44 860 tcsetattr(0, TCSADRAIN, &__orig_termios); 861 # else 862 resetty(); 863 # endif 864 _puts(VE); 865 _puts(TE); 866 # endif /* !USE_CURSES */ 867 } 868 if (mesg != NULL) 869 puts(mesg); 870 exit(eval); 871 } 872 873 #if !defined(USE_CURSES) && defined(SIGTSTP) 874 /* 875 * tstp: 876 * Handle stop and start signals 877 */ 878 SIGNAL_TYPE 879 tstp(dummy) 880 int dummy; 881 { 882 # if BSD_RELEASE < 44 883 static struct sgttyb tty; 884 # endif 885 int y, x; 886 887 y = cur_row; 888 x = cur_col; 889 mvcur(cur_row, cur_col, HEIGHT, 0); 890 cur_row = HEIGHT; 891 cur_col = 0; 892 # if !defined(BSD_RELEASE) || BSD_RELEASE < 44 893 tty = _tty; 894 # endif 895 _puts(VE); 896 _puts(TE); 897 (void) fflush(stdout); 898 # if defined(BSD_RELEASE) && BSD_RELEASE >= 44 899 tcsetattr(0, TCSADRAIN, &__orig_termios); 900 # else 901 resetty(); 902 # endif 903 (void) kill(getpid(), SIGSTOP); 904 (void) signal(SIGTSTP, tstp); 905 # if defined(BSD_RELEASE) && BSD_RELEASE >= 44 906 tcsetattr(0, TCSADRAIN, &saved_tty); 907 # else 908 _tty = tty; 909 ioctl(_tty_ch, TIOCSETP, &_tty); 910 # endif 911 _puts(TI); 912 _puts(VS); 913 cur_row = y; 914 cur_col = x; 915 _puts(tgoto(CM, cur_row, cur_col)); 916 redraw_screen(); 917 (void) fflush(stdout); 918 } 919 #endif /* !defined(USE_CURSES) && defined(SIGTSTP) */ 920 921 # if defined(BSD_RELEASE) && BSD_RELEASE < 43 922 char * 923 strpbrk(s, brk) 924 char *s, *brk; 925 { 926 char *p; 927 c; 928 929 while (c = *s) { 930 for (p = brk; *p; p++) 931 if (c == *p) 932 return (s); 933 s++; 934 } 935 return (0); 936 } 937 # endif 938 939 long 940 env_init(enter_status) 941 long enter_status; 942 { 943 int i; 944 char *envp, *envname, *s; 945 946 for (i = 0; i < 256; i++) 947 map_key[i] = (char) i; 948 949 envname = NULL; 950 if ((envp = getenv("HUNT")) != NULL) { 951 while ((s = strpbrk(envp, "=,")) != NULL) { 952 if (strncmp(envp, "cloak,", s - envp + 1) == 0) { 953 enter_status = Q_CLOAK; 954 envp = s + 1; 955 } 956 else if (strncmp(envp, "scan,", s - envp + 1) == 0) { 957 enter_status = Q_SCAN; 958 envp = s + 1; 959 } 960 else if (strncmp(envp, "fly,", s - envp + 1) == 0) { 961 enter_status = Q_FLY; 962 envp = s + 1; 963 } 964 else if (strncmp(envp, "nobeep,", s - envp + 1) == 0) { 965 no_beep = TRUE; 966 envp = s + 1; 967 } 968 else if (strncmp(envp, "name=", s - envp + 1) == 0) { 969 envname = s + 1; 970 if ((s = strchr(envp, ',')) == NULL) { 971 *envp = '\0'; 972 strncpy(name, envname, NAMELEN); 973 break; 974 } 975 *s = '\0'; 976 strncpy(name, envname, NAMELEN); 977 envp = s + 1; 978 } 979 # ifdef INTERNET 980 else if (strncmp(envp, "port=", s - envp + 1) == 0) { 981 use_port = s + 1; 982 Test_port = atoi(use_port); 983 if ((s = strchr(envp, ',')) == NULL) { 984 *envp = '\0'; 985 break; 986 } 987 *s = '\0'; 988 envp = s + 1; 989 } 990 else if (strncmp(envp, "host=", s - envp + 1) == 0) { 991 Sock_host = s + 1; 992 if ((s = strchr(envp, ',')) == NULL) { 993 *envp = '\0'; 994 break; 995 } 996 *s = '\0'; 997 envp = s + 1; 998 } 999 else if (strncmp(envp, "message=", s - envp + 1) == 0) { 1000 Send_message = s + 1; 1001 if ((s = strchr(envp, ',')) == NULL) { 1002 *envp = '\0'; 1003 break; 1004 } 1005 *s = '\0'; 1006 envp = s + 1; 1007 } 1008 # endif 1009 else if (strncmp(envp, "team=", s - envp + 1) == 0) { 1010 team = *(s + 1); 1011 if (!isdigit(team)) 1012 team = ' '; 1013 if ((s = strchr(envp, ',')) == NULL) { 1014 *envp = '\0'; 1015 break; 1016 } 1017 *s = '\0'; 1018 envp = s + 1; 1019 } /* must be last option */ 1020 else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) { 1021 for (s = s + 1; *s != '\0'; s += 2) { 1022 map_key[(unsigned int) *s] = *(s + 1); 1023 if (*(s + 1) == '\0') { 1024 break; 1025 } 1026 } 1027 *envp = '\0'; 1028 break; 1029 } else { 1030 *s = '\0'; 1031 printf("unknown option %s\n", envp); 1032 if ((s = strchr(envp, ',')) == NULL) { 1033 *envp = '\0'; 1034 break; 1035 } 1036 envp = s + 1; 1037 } 1038 } 1039 if (*envp != '\0') { 1040 if (envname == NULL) 1041 strncpy(name, envp, NAMELEN); 1042 else 1043 printf("unknown option %s\n", envp); 1044 } 1045 } 1046 return enter_status; 1047 } 1048 1049 void 1050 fill_in_blanks() 1051 { 1052 int i; 1053 char *cp; 1054 1055 again: 1056 if (name[0] != '\0') { 1057 printf("Entering as '%s'", name); 1058 if (team != ' ') 1059 printf(" on team %c.\n", team); 1060 else 1061 putchar('\n'); 1062 } else { 1063 printf("Enter your code name: "); 1064 if (fgets(name, NAMELEN, stdin) == NULL) 1065 exit(1); 1066 } 1067 rmnl(name); 1068 if (name[0] == '\0') { 1069 name[0] = '\0'; 1070 printf("You have to have a code name!\n"); 1071 goto again; 1072 } 1073 for (cp = name; *cp != '\0'; cp++) 1074 if (!isprint(*cp)) { 1075 name[0] = '\0'; 1076 printf("Illegal character in your code name.\n"); 1077 goto again; 1078 } 1079 if (team == ' ') { 1080 printf("Enter your team (0-9 or nothing): "); 1081 i = getchar(); 1082 if (isdigit(i)) 1083 team = i; 1084 while (i != '\n' && i != EOF) 1085 i = getchar(); 1086 } 1087 } 1088