1/* $NetBSD: hunt.c,v 1.40 2011/08/31 16:24:56 plunky Exp $ */ 2/* 3 * Copyright (c) 1983-2003, Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * + Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * + 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 * + Neither the name of the University of California, San Francisco nor 16 * the names of its contributors may be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34#ifndef lint 35__RCSID("$NetBSD: hunt.c,v 1.40 2011/08/31 16:24:56 plunky Exp $"); 36#endif /* not lint */ 37 38#include <sys/param.h> 39#include <sys/stat.h> 40#include <sys/time.h> 41#include <sys/poll.h> 42#include <ctype.h> 43#include <err.h> 44#include <errno.h> 45#include <curses.h> 46#include <signal.h> 47#include <stdlib.h> 48#include <string.h> 49#include <unistd.h> 50#include <ifaddrs.h> 51 52#include "hunt.h" 53 54#define clear_eol() clrtoeol() 55#define put_ch addch 56#define put_str addstr 57 58FLAG Last_player = FALSE; 59#ifdef MONITOR 60FLAG Am_monitor = FALSE; 61#endif 62 63char Buf[BUFSIZ]; 64 65/*static*/ int Socket; 66#ifdef INTERNET 67static char *Sock_host; 68static char *use_port; 69static FLAG Query_driver = FALSE; 70char *Send_message = NULL; 71static FLAG Show_scores = FALSE; 72#endif 73 74static SOCKET Daemon; 75#ifdef INTERNET 76#define DAEMON_SIZE (sizeof Daemon) 77#else 78#define DAEMON_SIZE (sizeof Daemon - 1) 79#endif 80 81char map_key[256]; /* what to map keys to */ 82FLAG no_beep; 83 84static char name[NAMELEN]; 85static char team = ' '; 86 87static int in_visual; 88 89extern int cur_row, cur_col; 90 91static void dump_scores(SOCKET); 92static long env_init(long); 93static void fill_in_blanks(void); 94static void leave(int, const char *) __dead; 95static void leavex(int, const char *) __dead; 96static void fincurs(void); 97static void rmnl(char *); 98static void sigterm(int) __dead; 99static void sigusr1(int) __dead; 100static void find_driver(FLAG); 101static void start_driver(void); 102static int broadcast_vec(int, struct sockaddr **); 103#ifdef INTERNET 104static SOCKET *list_drivers(void); 105#endif 106 107extern int Otto_mode; 108/* 109 * main: 110 * Main program for local process 111 */ 112int 113main(int ac, char **av) 114{ 115 char *term; 116 int c; 117 long enter_status; 118 119 enter_status = env_init((long) Q_CLOAK); 120 while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != -1) { 121 switch (c) { 122 case 'l': /* rsh compatibility */ 123 case 'n': 124 (void) strncpy(name, optarg, NAMELEN); 125 break; 126 case 't': 127 team = *optarg; 128 if (!isdigit((unsigned char)team)) { 129 warnx("Team names must be numeric"); 130 team = ' '; 131 } 132 break; 133 case 'o': 134#ifndef OTTO 135 warnx("The -o flag is reserved for future use."); 136 goto usage; 137#else 138 Otto_mode = TRUE; 139 break; 140#endif 141 case 'm': 142#ifdef MONITOR 143 Am_monitor = TRUE; 144#else 145 warnx("The monitor was not compiled in."); 146#endif 147 break; 148#ifdef INTERNET 149 case 'S': 150 Show_scores = TRUE; 151 break; 152 case 'q': /* query whether hunt is running */ 153 Query_driver = TRUE; 154 break; 155 case 'w': 156 Send_message = optarg; 157 break; 158 case 'h': 159 Sock_host = optarg; 160 break; 161 case 'p': 162 use_port = optarg; 163 Test_port = atoi(use_port); 164 break; 165#else 166 case 'S': 167 case 'q': 168 case 'w': 169 case 'h': 170 case 'p': 171 wanrx("Need TCP/IP for S, q, w, h, and p options."); 172 break; 173#endif 174 case 'c': 175 enter_status = Q_CLOAK; 176 break; 177 case 'f': 178#ifdef FLY 179 enter_status = Q_FLY; 180#else 181 warnx("The flying code was not compiled in."); 182#endif 183 break; 184 case 's': 185 enter_status = Q_SCAN; 186 break; 187 case 'b': 188 no_beep = !no_beep; 189 break; 190 default: 191 usage: 192 fputs( 193"usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n", 194 stderr); 195 exit(1); 196 } 197 } 198#ifdef INTERNET 199 if (optind + 1 < ac) 200 goto usage; 201 else if (optind + 1 == ac) 202 Sock_host = av[ac - 1]; 203#else 204 if (optind > ac) 205 goto usage; 206#endif 207 208#ifdef INTERNET 209 if (Show_scores) { 210 SOCKET *hosts; 211 212 for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) 213 dump_scores(*hosts); 214 exit(0); 215 } 216 if (Query_driver) { 217 SOCKET *hosts; 218 219 for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) { 220 struct hostent *hp; 221 int num_players; 222 223 hp = gethostbyaddr((char *) &hosts->sin_addr, 224 sizeof hosts->sin_addr, AF_INET); 225 num_players = ntohs(hosts->sin_port); 226 printf("%d player%s hunting on %s!\n", 227 num_players, (num_players == 1) ? "" : "s", 228 hp != NULL ? hp->h_name : 229 inet_ntoa(hosts->sin_addr)); 230 } 231 exit(0); 232 } 233#endif 234#ifdef OTTO 235 if (Otto_mode) 236 (void) strncpy(name, "otto", NAMELEN); 237 else 238#endif 239 fill_in_blanks(); 240 241 (void) fflush(stdout); 242 if (!isatty(0) || (term = getenv("TERM")) == NULL) 243 errx(1, "no terminal type"); 244 if (!initscr()) 245 errx(0, "couldn't initialize screen"); 246 (void) noecho(); 247 (void) cbreak(); 248 in_visual = TRUE; 249 if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH) 250 leavex(1, "Need a larger window"); 251 clear_the_screen(); 252 (void) signal(SIGINT, intr); 253 (void) signal(SIGTERM, sigterm); 254 (void) signal(SIGUSR1, sigusr1); 255 (void) signal(SIGPIPE, SIG_IGN); 256 257 for (;;) { 258#ifdef INTERNET 259 find_driver(TRUE); 260 261 if (Daemon.sin_port == 0) 262 leavex(1, "Game not found, try again"); 263 264 jump_in: 265 do { 266 int option; 267 268 Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); 269 if (Socket < 0) 270 err(1, "socket"); 271 option = 1; 272 if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, 273 &option, sizeof option) < 0) 274 warn("setsockopt loopback"); 275 errno = 0; 276 if (connect(Socket, (struct sockaddr *) &Daemon, 277 DAEMON_SIZE) < 0) { 278 if (errno != ECONNREFUSED) { 279 leave(1, "connect"); 280 } 281 } 282 else 283 break; 284 sleep(1); 285 } while (close(Socket) == 0); 286#else /* !INTERNET */ 287 /* 288 * set up a socket 289 */ 290 291 if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) 292 err(1, "socket"); 293 294 /* 295 * attempt to connect the socket to a name; if it fails that 296 * usually means that the driver isn't running, so we start 297 * up the driver. 298 */ 299 300 Daemon.sun_family = SOCK_FAMILY; 301 (void) strcpy(Daemon.sun_path, Sock_name); 302 if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) { 303 if (errno != ENOENT) { 304 leavex(1, "connect2"); 305 } 306 start_driver(); 307 308 do { 309 (void) close(Socket); 310 if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 311 0)) < 0) 312 err(1, "socket"); 313 sleep(2); 314 } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0); 315 } 316#endif 317 318 do_connect(name, team, enter_status); 319#ifdef INTERNET 320 if (Send_message != NULL) { 321 do_message(); 322 if (enter_status == Q_MESSAGE) 323 break; 324 Send_message = NULL; 325 /* don't continue as that will call find_driver */ 326 goto jump_in; 327 } 328#endif 329 playit(); 330 if ((enter_status = quit(enter_status)) == Q_QUIT) 331 break; 332 } 333 leavex(0, NULL); 334 /* NOTREACHED */ 335 return(0); 336} 337 338#ifdef INTERNET 339static int 340broadcast_vec(int s /*socket*/, struct sockaddr **vector) 341{ 342 int vec_cnt; 343 struct ifaddrs *ifp, *ip; 344 345 *vector = NULL; 346 if (getifaddrs(&ifp) < 0) 347 return 0; 348 349 vec_cnt = 0; 350 for (ip = ifp; ip; ip = ip->ifa_next) 351 if ((ip->ifa_addr->sa_family == AF_INET) && 352 (ip->ifa_flags & IFF_BROADCAST)) 353 vec_cnt++; 354 355 *vector = (struct sockaddr *) 356 malloc(vec_cnt * sizeof(struct sockaddr_in)); 357 358 vec_cnt = 0; 359 for (ip = ifp; ip; ip = ip->ifa_next) 360 if ((ip->ifa_addr->sa_family == AF_INET) && 361 (ip->ifa_flags & IFF_BROADCAST)) 362 memcpy(&(*vector)[vec_cnt++], ip->ifa_broadaddr, 363 sizeof(struct sockaddr_in)); 364 365 freeifaddrs(ifp); 366 return vec_cnt; 367} 368 369SOCKET * 370list_drivers(void) 371{ 372 int option; 373 u_short msg; 374 u_short port_num; 375 static SOCKET test; 376 int test_socket; 377 socklen_t namelen; 378 char local_name[MAXHOSTNAMELEN + 1]; 379 static int initial = TRUE; 380 static struct in_addr local_address; 381 struct hostent *hp; 382 static int brdc; 383 static SOCKET *brdv; 384 int i; 385 unsigned j; 386 static SOCKET *listv; 387 static unsigned int listmax; 388 unsigned int listc; 389 struct pollfd set[1]; 390 391 if (initial) { /* do one time initialization */ 392 if (gethostname(local_name, sizeof local_name) < 0) { 393 leavex(1, "Sorry, I have no name."); 394 /* NOTREACHED */ 395 } 396 local_name[sizeof(local_name) - 1] = '\0'; 397 if ((hp = gethostbyname(local_name)) == NULL) { 398 leavex(1, "Can't find myself."); 399 /* NOTREACHED */ 400 } 401 local_address = * ((struct in_addr *) hp->h_addr); 402 403 listmax = 20; 404 listv = (SOCKET *) malloc(listmax * sizeof (SOCKET)); 405 } else if (Sock_host != NULL) 406 return listv; /* address already valid */ 407 408 test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); 409 if (test_socket < 0) { 410 leave(1, "socket system call failed"); 411 /* NOTREACHED */ 412 } 413 test.sin_family = SOCK_FAMILY; 414 test.sin_port = htons(Test_port); 415 listc = 0; 416 417 if (Sock_host != NULL) { /* explicit host given */ 418 if ((hp = gethostbyname(Sock_host)) == NULL) { 419 leavex(1, "Unknown host"); 420 /* NOTREACHED */ 421 } 422 test.sin_addr = *((struct in_addr *) hp->h_addr); 423 goto test_one_host; 424 } 425 426 if (!initial) { 427 /* favor host of previous session by broadcasting to it first */ 428 test.sin_addr = Daemon.sin_addr; 429 msg = htons(C_PLAYER); /* Must be playing! */ 430 (void) sendto(test_socket, &msg, sizeof msg, 0, 431 (struct sockaddr *) &test, DAEMON_SIZE); 432 } 433 434 if (initial) 435 brdc = broadcast_vec(test_socket, (void *) &brdv); 436 437#ifdef SO_BROADCAST 438 /* Sun's will broadcast even though this option can't be set */ 439 option = 1; 440 if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST, 441 &option, sizeof option) < 0) { 442 leave(1, "setsockopt broadcast"); 443 /* NOTREACHED */ 444 } 445#endif 446 447 /* send broadcast packets on all interfaces */ 448 msg = htons(C_TESTMSG()); 449 for (i = 0; i < brdc; i++) { 450 test.sin_addr = brdv[i].sin_addr; 451 if (sendto(test_socket, &msg, sizeof msg, 0, 452 (struct sockaddr *) &test, DAEMON_SIZE) < 0) { 453 leave(1, "sendto"); 454 /* NOTREACHED */ 455 } 456 } 457 test.sin_addr = local_address; 458 if (sendto(test_socket, &msg, sizeof msg, 0, 459 (struct sockaddr *) &test, DAEMON_SIZE) < 0) { 460 leave(1, "sendto"); 461 /* NOTREACHED */ 462 } 463 464get_response: 465 namelen = DAEMON_SIZE; 466 errno = 0; 467 set[0].fd = test_socket; 468 set[0].events = POLLIN; 469 for (;;) { 470 if (listc + 1 >= listmax) { 471 SOCKET *newlistv; 472 473 listmax += 20; 474 newlistv = realloc(listv, listmax * sizeof(*listv)); 475 if (newlistv == NULL) 476 leave(1, "realloc"); 477 listv = newlistv; 478 } 479 480 if (poll(set, 1, 1000) == 1 && 481 recvfrom(test_socket, &port_num, sizeof(port_num), 482 0, (struct sockaddr *) &listv[listc], &namelen) > 0) { 483 /* 484 * Note that we do *not* convert from network to host 485 * order since the port number *should* be in network 486 * order: 487 */ 488 for (j = 0; j < listc; j += 1) 489 if (listv[listc].sin_addr.s_addr 490 == listv[j].sin_addr.s_addr) 491 break; 492 if (j == listc) 493 listv[listc++].sin_port = port_num; 494 continue; 495 } 496 497 if (errno != 0 && errno != EINTR) { 498 leave(1, "poll/recvfrom"); 499 /* NOTREACHED */ 500 } 501 502 /* terminate list with local address */ 503 listv[listc].sin_family = SOCK_FAMILY; 504 listv[listc].sin_addr = local_address; 505 listv[listc].sin_port = htons(0); 506 507 (void) close(test_socket); 508 initial = FALSE; 509 return listv; 510 } 511 512test_one_host: 513 msg = htons(C_TESTMSG()); 514 (void) sendto(test_socket, &msg, sizeof msg, 0, 515 (struct sockaddr *) &test, DAEMON_SIZE); 516 goto get_response; 517} 518 519static void 520find_driver(FLAG do_startup) 521{ 522 SOCKET *hosts; 523 524 hosts = list_drivers(); 525 if (hosts[0].sin_port != htons(0)) { 526 int i, c; 527 528 if (hosts[1].sin_port == htons(0)) { 529 Daemon = hosts[0]; 530 return; 531 } 532 /* go thru list and return host that matches daemon */ 533 clear_the_screen(); 534 move(1, 0); 535 put_str("Pick one:"); 536 for (i = 0; i < HEIGHT - 4 && hosts[i].sin_port != htons(0); 537 i += 1) { 538 struct hostent *hp; 539 char buf[80]; 540 541 move(3 + i, 0); 542 hp = gethostbyaddr((char *) &hosts[i].sin_addr, 543 sizeof hosts[i].sin_addr, AF_INET); 544 (void) snprintf(buf, sizeof(buf), 545 "%8c %.64s", 'a' + i, 546 hp != NULL ? hp->h_name 547 : inet_ntoa(hosts->sin_addr)); 548 put_str(buf); 549 } 550 move(4 + i, 0); 551 put_str("Enter letter: "); 552 refresh(); 553 while (!islower(c = getchar()) || (c -= 'a') >= i) { 554 beep(); 555 refresh(); 556 } 557 Daemon = hosts[c]; 558 clear_the_screen(); 559 return; 560 } 561 if (!do_startup) 562 return; 563 564 start_driver(); 565 sleep(2); 566 find_driver(FALSE); 567} 568 569static void 570dump_scores(SOCKET host) 571{ 572 struct hostent *hp; 573 int s; 574 char buf[BUFSIZ]; 575 int cnt; 576 577 hp = gethostbyaddr((char *) &host.sin_addr, sizeof host.sin_addr, 578 AF_INET); 579 printf("\n%s:\n", hp != NULL ? hp->h_name : inet_ntoa(host.sin_addr)); 580 fflush(stdout); 581 582 s = socket(SOCK_FAMILY, SOCK_STREAM, 0); 583 if (s < 0) 584 err(1, "socket"); 585 if (connect(s, (struct sockaddr *) &host, sizeof host) < 0) 586 err(1, "connect"); 587 while ((cnt = read(s, buf, BUFSIZ)) > 0) 588 write(fileno(stdout), buf, cnt); 589 (void) close(s); 590} 591 592#endif 593 594static void 595start_driver(void) 596{ 597 int procid; 598 599#ifdef MONITOR 600 if (Am_monitor) { 601 leavex(1, "No one playing."); 602 /* NOTREACHED */ 603 } 604#endif 605 606#ifdef INTERNET 607 if (Sock_host != NULL) { 608 sleep(3); 609 return; 610 } 611#endif 612 613 move(HEIGHT, 0); 614 put_str("Starting..."); 615 refresh(); 616 procid = fork(); 617 if (procid == -1) { 618 leave(1, "fork failed."); 619 } 620 if (procid == 0) { 621 (void) signal(SIGINT, SIG_IGN); 622#ifndef INTERNET 623 (void) close(Socket); 624#else 625 if (use_port == NULL) 626#endif 627 execl(Driver, "HUNT", (char *) NULL); 628#ifdef INTERNET 629 else 630 execl(Driver, "HUNT", "-p", use_port, (char *) NULL); 631#endif 632 /* only get here if exec failed */ 633 (void) kill(getppid(), SIGUSR1); /* tell mom */ 634 _exit(1); 635 } 636 move(HEIGHT, 0); 637 put_str("Connecting..."); 638 refresh(); 639} 640 641/* 642 * bad_con: 643 * We had a bad connection. For the moment we assume that this 644 * means the game is full. 645 */ 646void 647bad_con(void) 648{ 649 leavex(1, "The game is full. Sorry."); 650 /* NOTREACHED */ 651} 652 653/* 654 * bad_ver: 655 * version number mismatch. 656 */ 657void 658bad_ver(void) 659{ 660 leavex(1, "Version number mismatch. No go."); 661 /* NOTREACHED */ 662} 663 664/* 665 * sigterm: 666 * Handle a terminate signal 667 */ 668static void 669sigterm(int dummy __unused) 670{ 671 leavex(0, NULL); 672 /* NOTREACHED */ 673} 674 675 676/* 677 * sigusr1: 678 * Handle a usr1 signal 679 */ 680static void 681sigusr1(int dummy __unused) 682{ 683 leavex(1, "Unable to start driver. Try again."); 684 /* NOTREACHED */ 685} 686 687/* 688 * rmnl: 689 * Remove a '\n' at the end of a string if there is one 690 */ 691static void 692rmnl(char *s) 693{ 694 char *cp; 695 696 cp = strrchr(s, '\n'); 697 if (cp != NULL) 698 *cp = '\0'; 699} 700 701/* 702 * intr: 703 * Handle a interrupt signal 704 */ 705void 706intr(int dummy __unused) 707{ 708 int ch; 709 int explained; 710 int y, x; 711 712 (void) signal(SIGINT, SIG_IGN); 713 getyx(stdscr, y, x); 714 move(HEIGHT, 0); 715 put_str("Really quit? "); 716 clear_eol(); 717 refresh(); 718 explained = FALSE; 719 for (;;) { 720 ch = getchar(); 721 if (isupper(ch)) 722 ch = tolower(ch); 723 if (ch == 'y') { 724 if (Socket != 0) { 725 (void) write(Socket, "q", 1); 726 (void) close(Socket); 727 } 728 leavex(0, NULL); 729 } 730 else if (ch == 'n') { 731 (void) signal(SIGINT, intr); 732 move(y, x); 733 refresh(); 734 return; 735 } 736 if (!explained) { 737 put_str("(Yes or No) "); 738 refresh(); 739 explained = TRUE; 740 } 741 beep(); 742 refresh(); 743 } 744} 745 746static void 747fincurs(void) 748{ 749 if (in_visual) { 750 move(HEIGHT, 0); 751 refresh(); 752 endwin(); 753 } 754} 755 756/* 757 * leave: 758 * Leave the game somewhat gracefully, restoring all current 759 * tty stats, and print errno. 760 */ 761void 762leave(int eval, const char *mesg) 763{ 764 int serrno = errno; 765 fincurs(); 766 errno = serrno; 767 err(eval, "%s", mesg ? mesg : ""); 768} 769 770/* 771 * leavex: 772 * Leave the game somewhat gracefully, restoring all current 773 * tty stats. 774 */ 775void 776leavex(int eval, const char *mesg) 777{ 778 fincurs(); 779 errx(eval, "%s", mesg ? mesg : ""); 780} 781 782static long 783env_init(long enter_status) 784{ 785 int i; 786 char *envp, *envname, *s; 787 788 for (i = 0; i < 256; i++) 789 map_key[i] = (char) i; 790 791 envname = NULL; 792 if ((envp = getenv("HUNT")) != NULL) { 793 while ((s = strpbrk(envp, "=,")) != NULL) { 794 if (strncmp(envp, "cloak,", s - envp + 1) == 0) { 795 enter_status = Q_CLOAK; 796 envp = s + 1; 797 } 798 else if (strncmp(envp, "scan,", s - envp + 1) == 0) { 799 enter_status = Q_SCAN; 800 envp = s + 1; 801 } 802 else if (strncmp(envp, "fly,", s - envp + 1) == 0) { 803 enter_status = Q_FLY; 804 envp = s + 1; 805 } 806 else if (strncmp(envp, "nobeep,", s - envp + 1) == 0) { 807 no_beep = TRUE; 808 envp = s + 1; 809 } 810 else if (strncmp(envp, "name=", s - envp + 1) == 0) { 811 envname = s + 1; 812 if ((s = strchr(envp, ',')) == NULL) { 813 *envp = '\0'; 814 strncpy(name, envname, NAMELEN); 815 break; 816 } 817 *s = '\0'; 818 strncpy(name, envname, NAMELEN); 819 envp = s + 1; 820 } 821#ifdef INTERNET 822 else if (strncmp(envp, "port=", s - envp + 1) == 0) { 823 use_port = s + 1; 824 Test_port = atoi(use_port); 825 if ((s = strchr(envp, ',')) == NULL) { 826 *envp = '\0'; 827 break; 828 } 829 *s = '\0'; 830 envp = s + 1; 831 } 832 else if (strncmp(envp, "host=", s - envp + 1) == 0) { 833 Sock_host = s + 1; 834 if ((s = strchr(envp, ',')) == NULL) { 835 *envp = '\0'; 836 break; 837 } 838 *s = '\0'; 839 envp = s + 1; 840 } 841 else if (strncmp(envp, "message=", s - envp + 1) == 0) { 842 Send_message = s + 1; 843 if ((s = strchr(envp, ',')) == NULL) { 844 *envp = '\0'; 845 break; 846 } 847 *s = '\0'; 848 envp = s + 1; 849 } 850#endif 851 else if (strncmp(envp, "team=", s - envp + 1) == 0) { 852 team = *(s + 1); 853 if (!isdigit((unsigned char)team)) 854 team = ' '; 855 if ((s = strchr(envp, ',')) == NULL) { 856 *envp = '\0'; 857 break; 858 } 859 *s = '\0'; 860 envp = s + 1; 861 } /* must be last option */ 862 else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) { 863 for (s = s + 1; *s != '\0'; s += 2) { 864 map_key[(unsigned int) *s] = *(s + 1); 865 if (*(s + 1) == '\0') { 866 break; 867 } 868 } 869 *envp = '\0'; 870 break; 871 } else { 872 *s = '\0'; 873 printf("unknown option %s\n", envp); 874 if ((s = strchr(envp, ',')) == NULL) { 875 *envp = '\0'; 876 break; 877 } 878 envp = s + 1; 879 } 880 } 881 if (*envp != '\0') { 882 if (envname == NULL) 883 strncpy(name, envp, NAMELEN); 884 else 885 printf("unknown option %s\n", envp); 886 } 887 } 888 return enter_status; 889} 890 891static void 892fill_in_blanks(void) 893{ 894 int i; 895 char *cp; 896 897again: 898 if (name[0] != '\0') { 899 printf("Entering as '%s'", name); 900 if (team != ' ') 901 printf(" on team %c.\n", team); 902 else 903 putchar('\n'); 904 } else { 905 printf("Enter your code name: "); 906 if (fgets(name, NAMELEN, stdin) == NULL) 907 exit(1); 908 } 909 rmnl(name); 910 if (name[0] == '\0') { 911 name[0] = '\0'; 912 printf("You have to have a code name!\n"); 913 goto again; 914 } 915 for (cp = name; *cp != '\0'; cp++) 916 if (!isprint((unsigned char)*cp)) { 917 name[0] = '\0'; 918 printf("Illegal character in your code name.\n"); 919 goto again; 920 } 921 if (team == ' ') { 922 printf("Enter your team (0-9 or nothing): "); 923 i = getchar(); 924 if (isdigit(i)) 925 team = i; 926 while (i != '\n' && i != EOF) 927 i = getchar(); 928 } 929} 930