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