1 /* 2 Copyright (c) 1990-2001 Info-ZIP. All rights reserved. 3 4 See the accompanying file LICENSE, version 2000-Apr-09 or later 5 (the contents of which are also included in zip.h) for terms of use. 6 If, for some reason, all these files are missing, the Info-ZIP license 7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html 8 */ 9 /*--------------------------------------------------------------------------- 10 11 ttyio.c 12 13 This file contains routines for doing console input/output, including code 14 for non-echoing input. It is used by the encryption/decryption code but 15 does not contain any restricted code itself. This file is shared between 16 Info-ZIP's Zip and UnZip. 17 18 Contains: echo() (VMS only) 19 Echon() (Unix only) 20 Echoff() (Unix only) 21 screensize() (Unix only) 22 zgetch() (Unix, VMS, and non-Unix/VMS versions) 23 getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS) 24 25 ---------------------------------------------------------------------------*/ 26 27 #define __TTYIO_C /* identifies this source module */ 28 29 #include "zip.h" 30 #include "crypt.h" 31 32 #if (CRYPT || (defined(UNZIP) && !defined(FUNZIP))) 33 /* Non-echo console/keyboard input is needed for (en/de)cryption's password 34 * entry, and for UnZip(SFX)'s MORE and Pause features. 35 * (The corresponding #endif is found at the end of this module.) 36 */ 37 38 #include "ttyio.h" 39 40 #ifndef PUTC 41 # define PUTC putc 42 #endif 43 44 #ifdef ZIP 45 # ifdef GLOBAL /* used in Amiga system headers, maybe others too */ 46 # undef GLOBAL 47 # endif 48 # define GLOBAL(g) g 49 #else 50 # define GLOBAL(g) G.g 51 #endif 52 53 #ifdef __BEOS__ /* why yes, we do */ 54 # define HAVE_TERMIOS_H 55 #endif 56 57 #ifdef _POSIX_VERSION 58 # ifndef USE_POSIX_TERMIOS 59 # define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */ 60 # endif 61 # ifndef HAVE_TERMIOS_H 62 # define HAVE_TERMIOS_H /* POSIX termios.h */ 63 # endif 64 #endif /* _POSIX_VERSION */ 65 66 #ifdef UNZIP /* Zip handles this with the unix/configure script */ 67 # ifndef _POSIX_VERSION 68 # if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__) 69 # ifndef USE_SYSV_TERMIO 70 # define USE_SYSV_TERMIO 71 # endif 72 # ifdef COHERENT 73 # ifndef HAVE_TERMIO_H 74 # define HAVE_TERMIO_H 75 # endif 76 # ifdef HAVE_SYS_TERMIO_H 77 # undef HAVE_SYS_TERMIO_H 78 # endif 79 # else /* !COHERENT */ 80 # ifdef HAVE_TERMIO_H 81 # undef HAVE_TERMIO_H 82 # endif 83 # ifndef HAVE_SYS_TERMIO_H 84 # define HAVE_SYS_TERMIO_H 85 # endif 86 # endif /* ?COHERENT */ 87 # endif /* (SYSV || CRAY) && !__MINT__ */ 88 # endif /* !_POSIX_VERSION */ 89 # if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__)) 90 # ifndef NO_FCNTL_H 91 # define NO_FCNTL_H 92 # endif 93 # endif /* !(BSD4_4 || SYSV || __convexc__) */ 94 #endif /* UNZIP */ 95 96 #ifdef HAVE_TERMIOS_H 97 # ifndef USE_POSIX_TERMIOS 98 # define USE_POSIX_TERMIOS 99 # endif 100 #endif 101 102 #if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H)) 103 # ifndef USE_SYSV_TERMIO 104 # define USE_SYSV_TERMIO 105 # endif 106 #endif 107 108 #if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE)) 109 # include <sys/ioctl.h> 110 # define GOT_IOCTL_H 111 /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */ 112 #endif 113 114 #ifndef HAVE_WORKING_GETCH 115 /* include system support for switching of console echo */ 116 # ifdef VMS 117 # include <descrip.h> 118 # include <iodef.h> 119 # include <ttdef.h> 120 # include <starlet.h> 121 # include <ssdef.h> 122 # else /* !VMS */ 123 # ifdef HAVE_TERMIOS_H 124 # include <termios.h> 125 # define sgttyb termios 126 # define sg_flags c_lflag 127 # define GTTY(f, s) tcgetattr(f, (zvoid *) s) 128 # define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s) 129 # else /* !HAVE_TERMIOS_H */ 130 # ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */ 131 # ifdef HAVE_TERMIO_H 132 # include <termio.h> 133 # endif 134 # ifdef HAVE_SYS_TERMIO_H 135 # include <sys/termio.h> 136 # endif 137 # ifdef NEED_PTEM 138 # include <sys/stream.h> 139 # include <sys/ptem.h> 140 # endif 141 # define sgttyb termio 142 # define sg_flags c_lflag 143 # define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s) 144 # define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s) 145 # else /* !USE_SYSV_TERMIO */ 146 # ifndef CMS_MVS 147 # if (!defined(MINIX) && !defined(GOT_IOCTL_H)) 148 # include <sys/ioctl.h> 149 # endif 150 # include <sgtty.h> 151 # define GTTY gtty 152 # define STTY stty 153 # ifdef UNZIP 154 /* 155 * XXX : Are these declarations needed at all ???? 156 */ 157 /* 158 * GRR: let's find out... Hmmm, appears not... 159 int gtty OF((int, struct sgttyb *)); 160 int stty OF((int, struct sgttyb *)); 161 */ 162 # endif 163 # endif /* !CMS_MVS */ 164 # endif /* ?USE_SYSV_TERMIO */ 165 # endif /* ?HAVE_TERMIOS_H */ 166 # ifndef NO_FCNTL_H 167 # ifndef UNZIP 168 # include <fcntl.h> 169 # endif 170 # else 171 char *ttyname OF((int)); 172 # endif 173 # endif /* ?VMS */ 174 #endif /* !HAVE_WORKING_GETCH */ 175 176 177 178 #ifndef HAVE_WORKING_GETCH 179 #ifdef VMS 180 181 static struct dsc$descriptor_s DevDesc = 182 {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"}; 183 /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */ 184 185 /* 186 * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c 187 * and hence on Joe Meadows' file.c code. 188 */ 189 int echo(opt) 190 int opt; 191 { 192 /* 193 * For VMS v5.x: 194 * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming, 195 * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6 196 * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services, 197 * System Services Reference Manual, pp. sys-23, sys-379 198 * fixed-length descriptor info: Programming, Vol. 3, System Services, 199 * Intro to System Routines, sec. 2.9.2 200 * Greg Roelofs, 15 Aug 91 201 */ 202 203 short DevChan, iosb[4]; 204 long status; 205 unsigned long ttmode[2]; /* space for 8 bytes */ 206 207 208 /* assign a channel to standard input */ 209 status = sys$assign(&DevDesc, &DevChan, 0, 0); 210 if (!(status & 1)) 211 return status; 212 213 /* use sys$qio and the IO$_SENSEMODE function to determine the current 214 * tty status (for password reading, could use IO$_READVBLK function 215 * instead, but echo on/off will be more general) 216 */ 217 status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0, 218 ttmode, 8, 0, 0, 0, 0); 219 if (!(status & 1)) 220 return status; 221 status = iosb[0]; 222 if (!(status & 1)) 223 return status; 224 225 /* modify mode buffer to be either NOECHO or ECHO 226 * (depending on function argument opt) 227 */ 228 if (opt == 0) /* off */ 229 ttmode[1] |= TT$M_NOECHO; /* set NOECHO bit */ 230 else 231 ttmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */ 232 233 /* use the IO$_SETMODE function to change the tty status */ 234 status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0, 235 ttmode, 8, 0, 0, 0, 0); 236 if (!(status & 1)) 237 return status; 238 status = iosb[0]; 239 if (!(status & 1)) 240 return status; 241 242 /* deassign the sys$input channel by way of clean-up */ 243 status = sys$dassgn(DevChan); 244 if (!(status & 1)) 245 return status; 246 247 return SS$_NORMAL; /* we be happy */ 248 249 } /* end function echo() */ 250 251 252 /* 253 * Read a single character from keyboard in non-echoing mode (VMS). 254 * (returns EOF in case of errors) 255 */ 256 int tt_getch() 257 { 258 short DevChan, iosb[4]; 259 long status; 260 char kbbuf[16]; /* input buffer with - some - excess length */ 261 262 /* assign a channel to standard input */ 263 status = sys$assign(&DevDesc, &DevChan, 0, 0); 264 if (!(status & 1)) 265 return EOF; 266 267 /* read a single character from SYS$COMMAND (no-echo) and 268 * wait for completion 269 */ 270 status = sys$qiow(0,DevChan, 271 IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR, 272 &iosb, 0, 0, 273 &kbbuf, 1, 0, 0, 0, 0); 274 if ((status&1) == 1) 275 status = iosb[0]; 276 277 /* deassign the sys$input channel by way of clean-up 278 * (for this step, we do not need to check the completion status) 279 */ 280 sys$dassgn(DevChan); 281 282 /* return the first char read, or EOF in case the read request failed */ 283 return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF); 284 285 } /* end function tt_getch() */ 286 287 288 #else /* !VMS: basically Unix */ 289 290 291 /* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */ 292 #ifndef CMS_MVS 293 294 #ifdef ZIP /* moved to globals.h for UnZip */ 295 static int echofd=(-1); /* file descriptor whose echo is off */ 296 #endif 297 298 /* 299 * Turn echo off for file descriptor f. Assumes that f is a tty device. 300 */ 301 void Echoff(__G__ f) 302 __GDEF 303 int f; /* file descriptor for which to turn echo off */ 304 { 305 struct sgttyb sg; /* tty device structure */ 306 307 GLOBAL(echofd) = f; 308 GTTY(f, &sg); /* get settings */ 309 sg.sg_flags &= ~ECHO; /* turn echo off */ 310 STTY(f, &sg); 311 } 312 313 /* 314 * Turn echo back on for file descriptor echofd. 315 */ 316 void Echon(__G) 317 __GDEF 318 { 319 struct sgttyb sg; /* tty device structure */ 320 321 if (GLOBAL(echofd) != -1) { 322 GTTY(GLOBAL(echofd), &sg); /* get settings */ 323 sg.sg_flags |= ECHO; /* turn echo on */ 324 STTY(GLOBAL(echofd), &sg); 325 GLOBAL(echofd) = -1; 326 } 327 } 328 329 #endif /* !CMS_MVS */ 330 #endif /* ?VMS */ 331 332 333 #if (defined(UNZIP) && !defined(FUNZIP)) 334 335 #if (defined(UNIX) || defined(__BEOS__)) 336 #ifdef MORE 337 338 /* 339 * Get the number of lines on the output terminal. SCO Unix apparently 340 * defines TIOCGWINSZ but doesn't support it (!M_UNIX). 341 * 342 * GRR: will need to know width of terminal someday, too, to account for 343 * line-wrapping. 344 */ 345 346 #if (defined(TIOCGWINSZ) && !defined(M_UNIX)) 347 348 int screensize(tt_rows, tt_cols) 349 int *tt_rows; 350 int *tt_cols; 351 { 352 struct winsize wsz; 353 #ifdef DEBUG_WINSZ 354 static int firsttime = TRUE; 355 #endif 356 357 /* see termio(4) under, e.g., SunOS */ 358 if (ioctl(1, TIOCGWINSZ, &wsz) == 0) { 359 #ifdef DEBUG_WINSZ 360 if (firsttime) { 361 firsttime = FALSE; 362 fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n", 363 wsz.ws_row); 364 fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n", 365 wsz.ws_col); 366 } 367 #endif 368 /* number of rows */ 369 if (tt_rows != NULL) 370 *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24); 371 /* number of columns */ 372 if (tt_cols != NULL) 373 *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80); 374 return 0; /* signal success */ 375 } else { /* this happens when piping to more(1), for example */ 376 #ifdef DEBUG_WINSZ 377 if (firsttime) { 378 firsttime = FALSE; 379 fprintf(stderr, 380 "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n")); 381 } 382 #endif 383 /* VT-100 assumed to be minimal hardware */ 384 if (tt_rows != NULL) 385 *tt_rows = 24; 386 if (tt_cols != NULL) 387 *tt_cols = 80; 388 return 1; /* signal failure */ 389 } 390 } 391 392 #else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */ 393 394 int screensize(tt_rows, tt_cols) 395 int *tt_rows; 396 int *tt_cols; 397 { 398 char *envptr, *getenv(); 399 int n; 400 int errstat = 0; 401 402 /* GRR: this is overly simplistic, but don't have access to stty/gtty 403 * system anymore 404 */ 405 if (tt_rows != NULL) { 406 envptr = getenv("LINES"); 407 if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) { 408 /* VT-100 assumed to be minimal hardware */ 409 *tt_rows = 24; 410 errstat = 1; /* signal failure */ 411 } else { 412 *tt_rows = n; 413 } 414 } 415 if (tt_cols != NULL) { 416 envptr = getenv("COLUMNS"); 417 if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) { 418 *tt_cols = 80; 419 errstat = 1; /* signal failure */ 420 } else { 421 *tt_cols = n; 422 } 423 } 424 return errstat; 425 } 426 427 #endif /* ?(TIOCGWINSZ && !M_UNIX) */ 428 #endif /* MORE */ 429 430 431 /* 432 * Get a character from the given file descriptor without echo or newline. 433 */ 434 int zgetch(__G__ f) 435 __GDEF 436 int f; /* file descriptor from which to read */ 437 { 438 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) 439 char oldmin, oldtim; 440 #endif 441 char c; 442 struct sgttyb sg; /* tty device structure */ 443 444 GTTY(f, &sg); /* get settings */ 445 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) 446 oldmin = sg.c_cc[VMIN]; /* save old values */ 447 oldtim = sg.c_cc[VTIME]; 448 sg.c_cc[VMIN] = 1; /* need only one char to return read() */ 449 sg.c_cc[VTIME] = 0; /* no timeout */ 450 sg.sg_flags &= ~ICANON; /* canonical mode off */ 451 #else 452 sg.sg_flags |= CBREAK; /* cbreak mode on */ 453 #endif 454 sg.sg_flags &= ~ECHO; /* turn echo off, too */ 455 STTY(f, &sg); /* set cbreak mode */ 456 GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */ 457 458 read(f, &c, 1); /* read our character */ 459 460 #if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)) 461 sg.c_cc[VMIN] = oldmin; /* restore old values */ 462 sg.c_cc[VTIME] = oldtim; 463 sg.sg_flags |= ICANON; /* canonical mode on */ 464 #else 465 sg.sg_flags &= ~CBREAK; /* cbreak mode off */ 466 #endif 467 sg.sg_flags |= ECHO; /* turn echo on */ 468 STTY(f, &sg); /* restore canonical mode */ 469 GLOBAL(echofd) = -1; 470 471 return (int)(uch)c; 472 } 473 474 475 #else /* !UNIX && !__BEOS__ */ 476 #ifndef VMS /* VMS supplies its own variant of getch() */ 477 478 479 int zgetch(__G__ f) 480 __GDEF 481 int f; /* file descriptor from which to read (must be open already) */ 482 { 483 char c, c2; 484 485 /*--------------------------------------------------------------------------- 486 Get a character from the given file descriptor without echo; can't fake 487 CBREAK mode (i.e., newline required), but can get rid of all chars up to 488 and including newline. 489 ---------------------------------------------------------------------------*/ 490 491 echoff(f); 492 read(f, &c, 1); 493 if (c != '\n') 494 do { 495 read(f, &c2, 1); /* throw away all other chars up thru newline */ 496 } while (c2 != '\n'); 497 echon(); 498 return (int)c; 499 } 500 501 #endif /* !VMS */ 502 #endif /* ?(UNIX || __BEOS__) */ 503 504 #endif /* UNZIP && !FUNZIP */ 505 #endif /* !HAVE_WORKING_GETCH */ 506 507 508 #if CRYPT /* getp() is only used with full encryption */ 509 510 /* 511 * Simple compile-time check for source compatibility between 512 * zcrypt and ttyio: 513 */ 514 #if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7)) 515 error: This Info-ZIP tool requires zcrypt 2.7 or later. 516 #endif 517 518 /* 519 * Get a password of length n-1 or less into *p using the prompt *m. 520 * The entered password is not echoed. 521 */ 522 523 #ifdef HAVE_WORKING_GETCH 524 /* 525 * For the AMIGA, getch() is defined as Agetch(), which is in 526 * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch() 527 * uses the infrastructure that is already in place in filedate.c, it is 528 * smaller. With this function, echoff() and echon() are not needed. 529 * 530 * For the MAC, a non-echo macgetch() function is defined in the MacOS 531 * specific sources which uses the event handling mechanism of the 532 * desktop window manager to get a character from the keyboard. 533 * 534 * For the other systems in this section, a non-echo getch() function 535 * is either contained the C runtime library (conio package), or getch() 536 * is defined as an alias for a similar system specific RTL function. 537 */ 538 539 #ifndef WINDLL /* WINDLL does not support a console interface */ 540 #ifndef QDOS /* QDOS supplies a variant of this function */ 541 542 /* This is the getp() function for all systems (with TTY type user interface) 543 * that supply a working `non-echo' getch() function for "raw" console input. 544 */ 545 char *getp(__G__ m, p, n) 546 __GDEF 547 ZCONST char *m; /* prompt for password */ 548 char *p; /* return value: line input */ 549 int n; /* bytes available in p[] */ 550 { 551 char c; /* one-byte buffer for read() to use */ 552 int i; /* number of characters input */ 553 char *w; /* warning on retry */ 554 555 /* get password */ 556 w = ""; 557 do { 558 fputs(w, stderr); /* warning if back again */ 559 fputs(m, stderr); /* display prompt and flush */ 560 fflush(stderr); 561 i = 0; 562 do { /* read line, keeping first n characters */ 563 if ((c = (char)getch()) == '\r') 564 c = '\n'; /* until user hits CR */ 565 if (c == 8 || c == 127) { 566 if (i > 0) i--; /* the `backspace' and `del' keys works */ 567 } 568 else if (i < n) 569 p[i++] = c; /* truncate past n */ 570 } while (c != '\n'); 571 PUTC('\n', stderr); fflush(stderr); 572 w = "(line too long--try again)\n"; 573 } while (p[i-1] != '\n'); 574 p[i-1] = 0; /* terminate at newline */ 575 576 return p; /* return pointer to password */ 577 578 } /* end function getp() */ 579 580 #endif /* !QDOS */ 581 #endif /* !WINDLL */ 582 583 584 #else /* !HAVE_WORKING_GETCH */ 585 586 587 #if (defined(UNIX) || defined(__MINT__) || defined(__BEOS__)) 588 589 #ifndef _PATH_TTY 590 # ifdef __MINT__ 591 # define _PATH_TTY ttyname(2) 592 # else 593 # define _PATH_TTY "/dev/tty" 594 # endif 595 #endif 596 597 char *getp(__G__ m, p, n) 598 __GDEF 599 ZCONST char *m; /* prompt for password */ 600 char *p; /* return value: line input */ 601 int n; /* bytes available in p[] */ 602 { 603 char c; /* one-byte buffer for read() to use */ 604 int i; /* number of characters input */ 605 char *w; /* warning on retry */ 606 int f; /* file descriptor for tty device */ 607 608 #ifdef PASSWD_FROM_STDIN 609 /* Read from stdin. This is unsafe if the password is stored on disk. */ 610 f = 0; 611 #else 612 /* turn off echo on tty */ 613 614 if ((f = open(_PATH_TTY, 0)) == -1) 615 return NULL; 616 #endif 617 /* get password */ 618 w = ""; 619 do { 620 fputs(w, stderr); /* warning if back again */ 621 fputs(m, stderr); /* prompt */ 622 fflush(stderr); 623 i = 0; 624 echoff(f); 625 do { /* read line, keeping n */ 626 read(f, &c, 1); 627 if (i < n) 628 p[i++] = c; 629 } while (c != '\n'); 630 echon(); 631 PUTC('\n', stderr); fflush(stderr); 632 w = "(line too long--try again)\n"; 633 } while (p[i-1] != '\n'); 634 p[i-1] = 0; /* terminate at newline */ 635 636 #ifndef PASSWD_FROM_STDIN 637 close(f); 638 #endif 639 640 return p; /* return pointer to password */ 641 642 } /* end function getp() */ 643 644 #endif /* UNIX || __MINT__ || __BEOS__ */ 645 646 647 648 #if (defined(VMS) || defined(CMS_MVS)) 649 650 char *getp(__G__ m, p, n) 651 __GDEF 652 ZCONST char *m; /* prompt for password */ 653 char *p; /* return value: line input */ 654 int n; /* bytes available in p[] */ 655 { 656 char c; /* one-byte buffer for read() to use */ 657 int i; /* number of characters input */ 658 char *w; /* warning on retry */ 659 FILE *f; /* file structure for SYS$COMMAND device */ 660 661 #ifdef PASSWD_FROM_STDIN 662 f = stdin; 663 #else 664 if ((f = fopen(ctermid(NULL), "r")) == NULL) 665 return NULL; 666 #endif 667 668 /* get password */ 669 fflush(stdout); 670 w = ""; 671 do { 672 if (*w) /* bug: VMS apparently adds \n to NULL fputs */ 673 fputs(w, stderr); /* warning if back again */ 674 fputs(m, stderr); /* prompt */ 675 fflush(stderr); 676 i = 0; 677 echoff(f); 678 do { /* read line, keeping n */ 679 if ((c = (char)getc(f)) == '\r') 680 c = '\n'; 681 if (i < n) 682 p[i++] = c; 683 } while (c != '\n'); 684 echon(); 685 PUTC('\n', stderr); fflush(stderr); 686 w = "(line too long--try again)\n"; 687 } while (p[i-1] != '\n'); 688 p[i-1] = 0; /* terminate at newline */ 689 #ifndef PASSWD_FROM_STDIN 690 fclose(f); 691 #endif 692 693 return p; /* return pointer to password */ 694 695 } /* end function getp() */ 696 697 #endif /* VMS || CMS_MVS */ 698 #endif /* ?HAVE_WORKING_GETCH */ 699 #endif /* CRYPT */ 700 #endif /* CRYPT || (UNZIP && !FUNZIP) */ 701