summaryrefslogtreecommitdiff
path: root/ttyio.c
diff options
context:
space:
mode:
Diffstat (limited to 'ttyio.c')
-rw-r--r--ttyio.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/ttyio.c b/ttyio.c
new file mode 100644
index 0000000..5899fdc
--- /dev/null
+++ b/ttyio.c
@@ -0,0 +1,702 @@
+/*
+ ttyio.c - Zip 3
+
+ Copyright (c) 1990-2005 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2005-Feb-10 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+*/
+/*---------------------------------------------------------------------------
+
+ ttyio.c
+
+ This file contains routines for doing console input/output, including code
+ for non-echoing input. It is used by the encryption/decryption code but
+ does not contain any restricted code itself. This file is shared between
+ Info-ZIP's Zip and UnZip.
+
+ Contains: echo() (VMS only)
+ Echon() (Unix only)
+ Echoff() (Unix only)
+ screensize() (Unix only)
+ zgetch() (Unix, VMS, and non-Unix/VMS versions)
+ getp() ("PC," Unix/Atari/Be, VMS/VMCMS/MVS)
+
+ ---------------------------------------------------------------------------*/
+
+#define __TTYIO_C /* identifies this source module */
+
+#include "zip.h"
+#include "crypt.h"
+
+#if (CRYPT || (defined(UNZIP) && !defined(FUNZIP)))
+/* Non-echo console/keyboard input is needed for (en/de)cryption's password
+ * entry, and for UnZip(SFX)'s MORE and Pause features.
+ * (The corresponding #endif is found at the end of this module.)
+ */
+
+#include "ttyio.h"
+
+#ifndef PUTC
+# define PUTC putc
+#endif
+
+#ifdef ZIP
+# ifdef GLOBAL /* used in Amiga system headers, maybe others too */
+# undef GLOBAL
+# endif
+# define GLOBAL(g) g
+#else
+# define GLOBAL(g) G.g
+#endif
+
+#if (defined(__ATHEOS__) || defined(__BEOS__)) /* why yes, we do */
+# define HAVE_TERMIOS_H
+#endif
+
+#ifdef _POSIX_VERSION
+# ifndef USE_POSIX_TERMIOS
+# define USE_POSIX_TERMIOS /* use POSIX style termio (termios) */
+# endif
+# ifndef HAVE_TERMIOS_H
+# define HAVE_TERMIOS_H /* POSIX termios.h */
+# endif
+#endif /* _POSIX_VERSION */
+
+#ifdef UNZIP /* Zip handles this with the unix/configure script */
+# ifndef _POSIX_VERSION
+# if (defined(SYSV) || defined(CRAY)) && !defined(__MINT__)
+# ifndef USE_SYSV_TERMIO
+# define USE_SYSV_TERMIO
+# endif
+# ifdef COHERENT
+# ifndef HAVE_TERMIO_H
+# define HAVE_TERMIO_H
+# endif
+# ifdef HAVE_SYS_TERMIO_H
+# undef HAVE_SYS_TERMIO_H
+# endif
+# else /* !COHERENT */
+# ifdef HAVE_TERMIO_H
+# undef HAVE_TERMIO_H
+# endif
+# ifndef HAVE_SYS_TERMIO_H
+# define HAVE_SYS_TERMIO_H
+# endif
+# endif /* ?COHERENT */
+# endif /* (SYSV || CRAY) && !__MINT__ */
+# endif /* !_POSIX_VERSION */
+# if !(defined(BSD4_4) || defined(SYSV) || defined(__convexc__))
+# ifndef NO_FCNTL_H
+# define NO_FCNTL_H
+# endif
+# endif /* !(BSD4_4 || SYSV || __convexc__) */
+#endif /* UNZIP */
+
+#ifdef HAVE_TERMIOS_H
+# ifndef USE_POSIX_TERMIOS
+# define USE_POSIX_TERMIOS
+# endif
+#endif
+
+#if (defined(HAVE_TERMIO_H) || defined(HAVE_SYS_TERMIO_H))
+# ifndef USE_SYSV_TERMIO
+# define USE_SYSV_TERMIO
+# endif
+#endif
+
+#if (defined(UNZIP) && !defined(FUNZIP) && defined(UNIX) && defined(MORE))
+# include <sys/ioctl.h>
+# define GOT_IOCTL_H
+ /* int ioctl OF((int, int, zvoid *)); GRR: may need for some systems */
+#endif
+
+#ifndef HAVE_WORKING_GETCH
+ /* include system support for switching of console echo */
+# ifdef VMS
+# include <descrip.h>
+# include <iodef.h>
+# include <ttdef.h>
+# include <starlet.h>
+# include <ssdef.h>
+# else /* !VMS */
+# ifdef HAVE_TERMIOS_H
+# include <termios.h>
+# define sgttyb termios
+# define sg_flags c_lflag
+# define GTTY(f, s) tcgetattr(f, (zvoid *) s)
+# define STTY(f, s) tcsetattr(f, TCSAFLUSH, (zvoid *) s)
+# else /* !HAVE_TERMIOS_H */
+# ifdef USE_SYSV_TERMIO /* Amdahl, Cray, all SysV? */
+# ifdef HAVE_TERMIO_H
+# include <termio.h>
+# endif
+# ifdef HAVE_SYS_TERMIO_H
+# include <sys/termio.h>
+# endif
+# ifdef NEED_PTEM
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# endif
+# define sgttyb termio
+# define sg_flags c_lflag
+# define GTTY(f,s) ioctl(f,TCGETA,(zvoid *)s)
+# define STTY(f,s) ioctl(f,TCSETAW,(zvoid *)s)
+# else /* !USE_SYSV_TERMIO */
+# ifndef CMS_MVS
+# if (!defined(MINIX) && !defined(GOT_IOCTL_H))
+# include <sys/ioctl.h>
+# endif
+# include <sgtty.h>
+# define GTTY gtty
+# define STTY stty
+# ifdef UNZIP
+ /*
+ * XXX : Are these declarations needed at all ????
+ */
+ /*
+ * GRR: let's find out... Hmmm, appears not...
+ int gtty OF((int, struct sgttyb *));
+ int stty OF((int, struct sgttyb *));
+ */
+# endif
+# endif /* !CMS_MVS */
+# endif /* ?USE_SYSV_TERMIO */
+# endif /* ?HAVE_TERMIOS_H */
+# ifndef NO_FCNTL_H
+# ifndef UNZIP
+# include <fcntl.h>
+# endif
+# else
+ char *ttyname OF((int));
+# endif
+# endif /* ?VMS */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+
+#ifndef HAVE_WORKING_GETCH
+#ifdef VMS
+
+static struct dsc$descriptor_s DevDesc =
+ {11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND"};
+ /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
+
+/*
+ * Turn keyboard echoing on or off (VMS). Loosely based on VMSmunch.c
+ * and hence on Joe Meadows' file.c code.
+ */
+int echo(opt)
+ int opt;
+{
+ /*
+ * For VMS v5.x:
+ * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
+ * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
+ * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
+ * System Services Reference Manual, pp. sys-23, sys-379
+ * fixed-length descriptor info: Programming, Vol. 3, System Services,
+ * Intro to System Routines, sec. 2.9.2
+ * Greg Roelofs, 15 Aug 91
+ */
+
+ short DevChan, iosb[4];
+ long status;
+ unsigned long ttmode[2]; /* space for 8 bytes */
+
+
+ /* assign a channel to standard input */
+ status = sys$assign(&DevDesc, &DevChan, 0, 0);
+ if (!(status & 1))
+ return status;
+
+ /* use sys$qio and the IO$_SENSEMODE function to determine the current
+ * tty status (for password reading, could use IO$_READVBLK function
+ * instead, but echo on/off will be more general)
+ */
+ status = sys$qiow(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
+ ttmode, 8, 0, 0, 0, 0);
+ if (!(status & 1))
+ return status;
+ status = iosb[0];
+ if (!(status & 1))
+ return status;
+
+ /* modify mode buffer to be either NOECHO or ECHO
+ * (depending on function argument opt)
+ */
+ if (opt == 0) /* off */
+ ttmode[1] |= TT$M_NOECHO; /* set NOECHO bit */
+ else
+ ttmode[1] &= ~((unsigned long) TT$M_NOECHO); /* clear NOECHO bit */
+
+ /* use the IO$_SETMODE function to change the tty status */
+ status = sys$qiow(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
+ ttmode, 8, 0, 0, 0, 0);
+ if (!(status & 1))
+ return status;
+ status = iosb[0];
+ if (!(status & 1))
+ return status;
+
+ /* deassign the sys$input channel by way of clean-up */
+ status = sys$dassgn(DevChan);
+ if (!(status & 1))
+ return status;
+
+ return SS$_NORMAL; /* we be happy */
+
+} /* end function echo() */
+
+
+/*
+ * Read a single character from keyboard in non-echoing mode (VMS).
+ * (returns EOF in case of errors)
+ */
+int tt_getch()
+{
+ short DevChan, iosb[4];
+ long status;
+ char kbbuf[16]; /* input buffer with - some - excess length */
+
+ /* assign a channel to standard input */
+ status = sys$assign(&DevDesc, &DevChan, 0, 0);
+ if (!(status & 1))
+ return EOF;
+
+ /* read a single character from SYS$COMMAND (no-echo) and
+ * wait for completion
+ */
+ status = sys$qiow(0,DevChan,
+ IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
+ &iosb, 0, 0,
+ &kbbuf, 1, 0, 0, 0, 0);
+ if ((status&1) == 1)
+ status = iosb[0];
+
+ /* deassign the sys$input channel by way of clean-up
+ * (for this step, we do not need to check the completion status)
+ */
+ sys$dassgn(DevChan);
+
+ /* return the first char read, or EOF in case the read request failed */
+ return (int)(((status&1) == 1) ? (uch)kbbuf[0] : EOF);
+
+} /* end function tt_getch() */
+
+
+#else /* !VMS: basically Unix */
+
+
+/* For VM/CMS and MVS, non-echo terminal input is not (yet?) supported. */
+#ifndef CMS_MVS
+
+#ifdef ZIP /* moved to globals.h for UnZip */
+ static int echofd=(-1); /* file descriptor whose echo is off */
+#endif
+
+/*
+ * Turn echo off for file descriptor f. Assumes that f is a tty device.
+ */
+void Echoff(__G__ f)
+ __GDEF
+ int f; /* file descriptor for which to turn echo off */
+{
+ struct sgttyb sg; /* tty device structure */
+
+ GLOBAL(echofd) = f;
+ GTTY(f, &sg); /* get settings */
+ sg.sg_flags &= ~ECHO; /* turn echo off */
+ STTY(f, &sg);
+}
+
+/*
+ * Turn echo back on for file descriptor echofd.
+ */
+void Echon(__G)
+ __GDEF
+{
+ struct sgttyb sg; /* tty device structure */
+
+ if (GLOBAL(echofd) != -1) {
+ GTTY(GLOBAL(echofd), &sg); /* get settings */
+ sg.sg_flags |= ECHO; /* turn echo on */
+ STTY(GLOBAL(echofd), &sg);
+ GLOBAL(echofd) = -1;
+ }
+}
+
+#endif /* !CMS_MVS */
+#endif /* ?VMS */
+
+
+#if (defined(UNZIP) && !defined(FUNZIP))
+
+#ifdef ATH_BEO_UNX
+#ifdef MORE
+
+/*
+ * Get the number of lines on the output terminal. SCO Unix apparently
+ * defines TIOCGWINSZ but doesn't support it (!M_UNIX).
+ *
+ * GRR: will need to know width of terminal someday, too, to account for
+ * line-wrapping.
+ */
+
+#if (defined(TIOCGWINSZ) && !defined(M_UNIX))
+
+int screensize(tt_rows, tt_cols)
+ int *tt_rows;
+ int *tt_cols;
+{
+ struct winsize wsz;
+#ifdef DEBUG_WINSZ
+ static int firsttime = TRUE;
+#endif
+
+ /* see termio(4) under, e.g., SunOS */
+ if (ioctl(1, TIOCGWINSZ, &wsz) == 0) {
+#ifdef DEBUG_WINSZ
+ if (firsttime) {
+ firsttime = FALSE;
+ fprintf(stderr, "ttyio.c screensize(): ws_row = %d\n",
+ wsz.ws_row);
+ fprintf(stderr, "ttyio.c screensize(): ws_col = %d\n",
+ wsz.ws_col);
+ }
+#endif
+ /* number of rows */
+ if (tt_rows != NULL)
+ *tt_rows = (int)((wsz.ws_row > 0) ? wsz.ws_row : 24);
+ /* number of columns */
+ if (tt_cols != NULL)
+ *tt_cols = (int)((wsz.ws_col > 0) ? wsz.ws_col : 80);
+ return 0; /* signal success */
+ } else { /* this happens when piping to more(1), for example */
+#ifdef DEBUG_WINSZ
+ if (firsttime) {
+ firsttime = FALSE;
+ fprintf(stderr,
+ "ttyio.c screensize(): ioctl(TIOCGWINSZ) failed\n"));
+ }
+#endif
+ /* VT-100 assumed to be minimal hardware */
+ if (tt_rows != NULL)
+ *tt_rows = 24;
+ if (tt_cols != NULL)
+ *tt_cols = 80;
+ return 1; /* signal failure */
+ }
+}
+
+#else /* !TIOCGWINSZ: service not available, fall back to semi-bogus method */
+
+int screensize(tt_rows, tt_cols)
+ int *tt_rows;
+ int *tt_cols;
+{
+ char *envptr, *getenv();
+ int n;
+ int errstat = 0;
+
+ /* GRR: this is overly simplistic, but don't have access to stty/gtty
+ * system anymore
+ */
+ if (tt_rows != NULL) {
+ envptr = getenv("LINES");
+ if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+ /* VT-100 assumed to be minimal hardware */
+ *tt_rows = 24;
+ errstat = 1; /* signal failure */
+ } else {
+ *tt_rows = n;
+ }
+ }
+ if (tt_cols != NULL) {
+ envptr = getenv("COLUMNS");
+ if (envptr == (char *)NULL || (n = atoi(envptr)) < 5) {
+ *tt_cols = 80;
+ errstat = 1; /* signal failure */
+ } else {
+ *tt_cols = n;
+ }
+ }
+ return errstat;
+}
+
+#endif /* ?(TIOCGWINSZ && !M_UNIX) */
+#endif /* MORE */
+
+
+/*
+ * Get a character from the given file descriptor without echo or newline.
+ */
+int zgetch(__G__ f)
+ __GDEF
+ int f; /* file descriptor from which to read */
+{
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ char oldmin, oldtim;
+#endif
+ char c;
+ struct sgttyb sg; /* tty device structure */
+
+ GTTY(f, &sg); /* get settings */
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ oldmin = sg.c_cc[VMIN]; /* save old values */
+ oldtim = sg.c_cc[VTIME];
+ sg.c_cc[VMIN] = 1; /* need only one char to return read() */
+ sg.c_cc[VTIME] = 0; /* no timeout */
+ sg.sg_flags &= ~ICANON; /* canonical mode off */
+#else
+ sg.sg_flags |= CBREAK; /* cbreak mode on */
+#endif
+ sg.sg_flags &= ~ECHO; /* turn echo off, too */
+ STTY(f, &sg); /* set cbreak mode */
+ GLOBAL(echofd) = f; /* in case ^C hit (not perfect: still CBREAK) */
+
+ read(f, &c, 1); /* read our character */
+
+#if (defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS))
+ sg.c_cc[VMIN] = oldmin; /* restore old values */
+ sg.c_cc[VTIME] = oldtim;
+ sg.sg_flags |= ICANON; /* canonical mode on */
+#else
+ sg.sg_flags &= ~CBREAK; /* cbreak mode off */
+#endif
+ sg.sg_flags |= ECHO; /* turn echo on */
+ STTY(f, &sg); /* restore canonical mode */
+ GLOBAL(echofd) = -1;
+
+ return (int)(uch)c;
+}
+
+
+#else /* !ATH_BEO_UNX */
+#ifndef VMS /* VMS supplies its own variant of getch() */
+
+
+int zgetch(__G__ f)
+ __GDEF
+ int f; /* file descriptor from which to read (must be open already) */
+{
+ char c, c2;
+
+/*---------------------------------------------------------------------------
+ Get a character from the given file descriptor without echo; can't fake
+ CBREAK mode (i.e., newline required), but can get rid of all chars up to
+ and including newline.
+ ---------------------------------------------------------------------------*/
+
+ echoff(f);
+ read(f, &c, 1);
+ if (c != '\n')
+ do {
+ read(f, &c2, 1); /* throw away all other chars up thru newline */
+ } while (c2 != '\n');
+ echon();
+ return (int)c;
+}
+
+#endif /* !VMS */
+#endif /* ?ATH_BEO_UNX */
+
+#endif /* UNZIP && !FUNZIP */
+#endif /* !HAVE_WORKING_GETCH */
+
+
+#if CRYPT /* getp() is only used with full encryption */
+
+/*
+ * Simple compile-time check for source compatibility between
+ * zcrypt and ttyio:
+ */
+#if (!defined(CR_MAJORVER) || (CR_MAJORVER < 2) || (CR_MINORVER < 7))
+ error: This Info-ZIP tool requires zcrypt 2.7 or later.
+#endif
+
+/*
+ * Get a password of length n-1 or less into *p using the prompt *m.
+ * The entered password is not echoed.
+ */
+
+#ifdef HAVE_WORKING_GETCH
+/*
+ * For the AMIGA, getch() is defined as Agetch(), which is in
+ * amiga/filedate.c; SAS/C 6.x provides a getch(), but since Agetch()
+ * uses the infrastructure that is already in place in filedate.c, it is
+ * smaller. With this function, echoff() and echon() are not needed.
+ *
+ * For the MAC, a non-echo macgetch() function is defined in the MacOS
+ * specific sources which uses the event handling mechanism of the
+ * desktop window manager to get a character from the keyboard.
+ *
+ * For the other systems in this section, a non-echo getch() function
+ * is either contained the C runtime library (conio package), or getch()
+ * is defined as an alias for a similar system specific RTL function.
+ */
+
+#ifndef WINDLL /* WINDLL does not support a console interface */
+#ifndef QDOS /* QDOS supplies a variant of this function */
+
+/* This is the getp() function for all systems (with TTY type user interface)
+ * that supply a working `non-echo' getch() function for "raw" console input.
+ */
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+
+ /* get password */
+ w = "";
+ do {
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* display prompt and flush */
+ fflush(stderr);
+ i = 0;
+ do { /* read line, keeping first n characters */
+ if ((c = (char)getch()) == '\r')
+ c = '\n'; /* until user hits CR */
+ if (c == 8 || c == 127) {
+ if (i > 0) i--; /* the `backspace' and `del' keys works */
+ }
+ else if (i < n)
+ p[i++] = c; /* truncate past n */
+ } while (c != '\n');
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* !QDOS */
+#endif /* !WINDLL */
+
+
+#else /* !HAVE_WORKING_GETCH */
+
+
+#if (defined(ATH_BEO_UNX) || defined(__MINT__))
+
+#ifndef _PATH_TTY
+# ifdef __MINT__
+# define _PATH_TTY ttyname(2)
+# else
+# define _PATH_TTY "/dev/tty"
+# endif
+#endif
+
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+ int f; /* file descriptor for tty device */
+
+#ifdef PASSWD_FROM_STDIN
+ /* Read from stdin. This is unsafe if the password is stored on disk. */
+ f = 0;
+#else
+ /* turn off echo on tty */
+
+ if ((f = open(_PATH_TTY, 0)) == -1)
+ return NULL;
+#endif
+ /* get password */
+ w = "";
+ do {
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* prompt */
+ fflush(stderr);
+ i = 0;
+ echoff(f);
+ do { /* read line, keeping n */
+ read(f, &c, 1);
+ if (i < n)
+ p[i++] = c;
+ } while (c != '\n');
+ echon();
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+
+#ifndef PASSWD_FROM_STDIN
+ close(f);
+#endif
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* ATH_BEO_UNX || __MINT__ */
+
+
+
+#if (defined(VMS) || defined(CMS_MVS))
+
+char *getp(__G__ m, p, n)
+ __GDEF
+ ZCONST char *m; /* prompt for password */
+ char *p; /* return value: line input */
+ int n; /* bytes available in p[] */
+{
+ char c; /* one-byte buffer for read() to use */
+ int i; /* number of characters input */
+ char *w; /* warning on retry */
+ FILE *f; /* file structure for SYS$COMMAND device */
+
+#ifdef PASSWD_FROM_STDIN
+ f = stdin;
+#else
+ if ((f = fopen(ctermid(NULL), "r")) == NULL)
+ return NULL;
+#endif
+
+ /* get password */
+ fflush(stdout);
+ w = "";
+ do {
+ if (*w) /* bug: VMS apparently adds \n to NULL fputs */
+ fputs(w, stderr); /* warning if back again */
+ fputs(m, stderr); /* prompt */
+ fflush(stderr);
+ i = 0;
+ echoff(f);
+ do { /* read line, keeping n */
+ if ((c = (char)getc(f)) == '\r')
+ c = '\n';
+ if (i < n)
+ p[i++] = c;
+ } while (c != '\n');
+ echon();
+ PUTC('\n', stderr); fflush(stderr);
+ w = "(line too long--try again)\n";
+ } while (p[i-1] != '\n');
+ p[i-1] = 0; /* terminate at newline */
+#ifndef PASSWD_FROM_STDIN
+ fclose(f);
+#endif
+
+ return p; /* return pointer to password */
+
+} /* end function getp() */
+
+#endif /* VMS || CMS_MVS */
+#endif /* ?HAVE_WORKING_GETCH */
+#endif /* CRYPT */
+#endif /* CRYPT || (UNZIP && !FUNZIP) */