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