#include #include /* * MGET -- Extract messages from a mail file containing one of the given * patterns. This task acts as a simple filter. The arguments are the * patterns to be matched. These are fixed pattern strings, except for * an optional ^ metacharacter if the match is to be performed only at * the beginning of a line. The main difference between MGET and most * conventional mail programs is that MGET is a filter, and can be used to * do context sensitive searching and retrieval of messages from very large * mail databases (folders). * * Syntax: * * mget [-p] [-b beginstr] [-i] [-o] [pattern] [pattern] ... * * Switches: * * -p page messages (uses PAGER environment variable) * -t nblks examine only the tail (last nblks blocks) of the file * connected to the standard input * * -np npages number of pages to buffer in paged mode * * -b beginstr string which marks the beginning of a message * -i ignore case when matching the following pattern(s) * -o pass only messages which do NOT contain the pattern(s) * -a auto page advance (avoids page query), but still * * These switches are toggles, and may appear between successive pattern * arguments to turn the respective options on and off. * * Some examples: * * Display all messages to or from a specific user: * tail -100b mbox | mget '^From eric@cfa' '^To: eric@cfa' | pg * Search a mail database for all messages to or from a specific site: * rsh coma "zcat ~sites/sitemail.1988.Z" | mget munnari | pg * cat mbox.89.* | mget -i harvard.edu | pg * Find all messages pertaining to one of a list of topics: * cat $mdir/sunspots | mget -i nfs slip 'X terminals' | pg * Display the site mail for Feb 7: * tail -100b ~sites/sitemail | mget 'Feb 7' | pg +/"^From " * Display all messages from a certain user on a specific topic: * cat mbox | mget mvh@cfa | mget -i plio | pg * Display all messages from a user except those on a certain topic: * cat mbox | mget silva -o -i imfort | pg * Search USENET postings rather than a unix mail box: * cat comp/windows/x/* | mget -b 'Path: ' -i colormap | pg * * In these examples, pg is a file pager (e.g. "less") but of course there * are many other things that could be done with the mget output, e.g., one * could direct the output into a new mail folder. * * When used in the paged mode (-p switch) mget will pass each message to * the PAGER command instead of copying the message to the standard output. * An example of a useful PAGER is: setenv PAGER "less -C -E -M". In this * mode the messages that pass the filter given on the command line are * paged, with the last -np pages buffered internally by the program, * allowing keystrokes such as "f" and "b" to move to the next or previous * messages, "." to move to the earliest buffered message, "G" to move to * the end of file, "/" to search for a message containing a pattern, "s" to * save to a file, etc. (see HELP, below). * * For example, * * alias MG 'mget -p -t 128 -np 160 < /usr/spool/mail/' * * would define an alias MG which pages the last 128 blocks of the user's * mail file, buffering up to 160 pages in program memory (actually in * temporary files). If a new message arrives while the program is running, * the command "G" (go to end of file) will cause any new messages to be * read without need to exit and restart the program. */ #define SZ_MSGBUF 128000 /* max size message */ #define SZ_PATSTR 128 /* max size pattern string */ #define SZ_LINE 512 /* max size message line */ #define DEFPAGER "more" /* default page program */ #define DEFNPAGES 64 /* default number page buffers */ #define MAXNPAGES 1024 /* default number page buffers */ #define DEFTERM "vt100" /* default terminal type */ #define EOS '\0' #define IGNORE 1 #define HELP \ "[q=quit,f|sp=fwd,b=bak,.=back,Ng=goto,G=toEOF,/|n=search,s=save,r=redraw]" char svfile[128] = ""; static char tc[1024]; char msg[SZ_MSGBUF+1]; int curmsg; char beginmsg[SZ_PATSTR+1] = "From "; int ignorecase = 0; int omit = 0; int delmsg = 1; char *lower(); char *mktemp(), *getenv(); static tty_rawon(), tty_reset(); int putch(ch) {char cch=ch; write(1,&cch,1);} /* MGET -- Main routine. */ main (argc, argv) int argc; char **argv; { int passall, lastpat, pagemsg, pass, ateof, key, nb, i; int npages, curpage, lowpage, newpage, skipto, notfound; char *arg, *pager, *term, *lookfor; char tmpdir[64], cmd[128]; int autoquery, ival, nblks; char sval[256]; char prompt[80]; FILE *fp = stdin; /* Once through the argument list to set any global switches or * variables. */ npages = DEFNPAGES; lookfor = NULL; autoquery = 0; notfound = 0; lastpat = -1; passall = 1; pagemsg = 0; newpage = 0; skipto = 0; ateof = 0; for (i=1; i < argc && (arg=argv[i]) != NULL; i++) { if (strcmp (arg, "-o") == 0) { passall = 0; } else if (strcmp (arg, "-i") == 0) { ; } else if (strcmp (arg, "-b") == 0) { strncpy (beginmsg, argv[++i], SZ_PATSTR); } else if (strcmp (arg, "-p") == 0) { pagemsg++; } else if (strcmp (arg, "-a") == 0) { autoquery++; } else if (strcmp (arg, "-np") == 0) { npages = atoi(argv[++i]); if (npages < 1) npages = 1; else if (npages > MAXNPAGES) npages = MAXNPAGES; } else if (strcmp (arg, "-nd") == 0) { delmsg = 0; } else if (strcmp (arg, "-t") == 0) { nblks = atoi(argv[++i]); if (nblks < 1) nblks = 1; fseek (fp, -nblks*1024, 2); } else lastpat = i; } /* If paging is desired, create the page directory. */ if (pagemsg) { sprintf (tmpdir, "/tmp/mgetXXXXXX"); if (mktemp(tmpdir) == NULL) { fprintf (stderr, "cannot generate unique tmpdir name\n"); exit (1); } if (mkdir (tmpdir, 0700) == -1) { fprintf (stderr, "cannot create directory %s\n", tmpdir); exit (1); } if ((pager = getenv("PAGER")) == NULL) pager = DEFPAGER; if ((term = getenv("TERM")) == NULL) term = DEFTERM; if (tgetent (tc, term) < 0) { fprintf (stderr, "unrecognized terminal type\n"); exit (1); } curpage = 0; } /* Main loop: extract each message, search for patterns. The switches * -i and -o may be inserted in the argument list to toggle the options * ignorecase (case is ignored during pattern matching if set) and * omit (the message is passed to the ouput only if the given patterns * are NOT present). */ while (nextmsg (fp, msg, SZ_MSGBUF) != EOF) { ignorecase = 0; omit = 0; pass = 0; /* Evaluate the specified filter expression */ if (lastpat < 0) pass++; /* no patterns given */ else { for (i=1; i < argc && (arg=argv[i]) != NULL; i++) { if (arg[0] == '-') { if (strcmp (arg, "-i") == 0) { ignorecase = !ignorecase; continue; } else if (strcmp (arg, "-o") == 0) { omit = !omit; if (i == 1) pass = 1; continue; } else if ((strcmp (arg, "-b") == 0) || (strcmp (arg, "-t") == 0)) { i++; continue; } else continue; } if (match (msg, ignorecase ? lower(arg) : arg)) { if (omit) { pass = 0; break; } else { pass = 1; if (passall) break; } } else if (i >= lastpat && passall) break; } } /* If the page flag is set page the message, else copy the * message on to the standard output. */ if (pass) { showmsg: if (pagemsg) { char fname[64]; int fd; FILE *tp; if (ateof) { sprintf (fname, "%s/%d", tmpdir, curpage=newpage); if ((fd = open (fname, 0)) == -1) { fprintf (stderr, "cannot open file %s\n", fname); goto cleanup; } else { nb = read (fd, msg, SZ_MSGBUF); if (nb > 0) msg[nb] = EOS; close (fd); } skipto = 0; lookfor = NULL; curmsg = curpage; } else { newpage++; curmsg = curpage = newpage; lowpage = newpage - npages + 1; if (lowpage < 1) lowpage = 1; /* Delete oldest page. */ if (lowpage > 1) { sprintf (fname, "%s/%d", tmpdir, lowpage - 1); if (delmsg) unlink (fname); } /* Prepare the new page. */ sprintf (fname, "%s/%d", tmpdir, newpage); if ((tp = fopen (fname, "w")) == NULL) { fprintf (stderr, "cannot create file %s\n", fname); goto cleanup; } else { fputs (msg, tp); fclose (tp); } } /* Display the current page, query for the page * positioning command, and loop until a new page * is desired or quit is indicated. */ do { /* Don't display anything if skipping forward. */ if (skipto && (skipto == EOF || curpage < skipto)) break; /* Don't display anything if looking for a pattern * and we haven't found it yet. */ if (lookfor && !match (msg, lookfor)) break; if (notfound) { sprintf (prompt, "mget(%d): pattern not found (now at EOF)", curpage); key = query (prompt, &ival, sval); notfound = 0; lookfor = NULL; skipto = 0; goto action; } /* Buffer the page. */ if (curmsg != curpage) { if ((fd = open (fname, 0)) == -1) { fprintf (stderr, "cannot open file %s\n", fname); goto cleanup; } else { nb = read (fd, msg, SZ_MSGBUF); if (nb > 0) msg[nb] = EOS; curmsg = curpage; close (fd); } } /* Display the page. */ sprintf (fname, "%s/%d", tmpdir, curpage); sprintf (cmd, "%s %s", pager, fname); system (cmd); lookfor = NULL; skipto = 0; again: /* Get command keystroke. */ sprintf (prompt, "mget(%d)%s:", curpage, (ateof && curpage == newpage) ? "(EOF)" : ""); key = autoquery ? 'f' : query (prompt, &ival, sval); action: switch (key) { case IGNORE: goto again; case EOF: goto cleanup; break; case 'q': key = query ("really quit? (yes):", &ival, sval); if (key == '\r' || key == 'y') goto cleanup; break; case '?': key = query (HELP, &ival, sval); goto action; case 'r': break; case 'f': case ' ': if (curpage >= newpage) { if (ateof) goto extend; key = 0; } else curpage++; break; case 'b': curpage--; if (curpage < lowpage) curpage = lowpage; break; case 'g': skipto = ival; if (skipto < newpage) curpage = skipto; else curpage = newpage; break; case 'G': extend: if (ateof) { clearerr (fp); ateof = 0; } curpage = newpage; skipto = EOF; break; case '.': curpage = lowpage; break; case 'n': goto search; case '/': /* Search for the given pattern. */ if (sval[0] == '\0') strcpy (sval, lookfor); search: if (curpage < newpage) { curpage++; while (curpage <= newpage) { sprintf (fname, "%s/%d", tmpdir, curpage); if ((fd = open (fname, 0)) == -1) { fprintf (stderr, "cannot open %s\n",fname); goto cleanup; } else { nb = read (fd, msg, SZ_MSGBUF); if (nb > 0) msg[nb] = EOS; curmsg = curpage; close (fd); } if (match (msg, sval)) { skipto = curpage; goto foundone; } curpage++; if (curpage > newpage) { curpage = newpage; break; } } } if (ateof) { clearerr (fp); ateof = 0; } lookfor = sval; key = NULL; foundone: break; case 's': /* Save current message to a file. */ { int newfile = (access (sval, 0) == -1); FILE *fp = fopen (sval, "a"); if (fp == NULL) fprintf (stdout, "- failed\n"); else { char fname[128]; int in; sprintf (fname, "%s/%d", tmpdir, curpage); if ((in = open (fname, 0)) < 0) continue; if ((nb = read (in, msg, SZ_MSGBUF)) <= 0) continue; msg[nb] = EOS; fputs (msg, fp); close (in); fclose (fp); fprintf (stdout, "- %d bytes %s\n", strlen(msg), newfile ? "written" : "appended"); } } goto again; default: putch ('\007'); goto again; } } while (key); } else fputs (msg, stdout); } } ateof++; if (skipto == EOF) { goto showmsg; } else if (lookfor) { notfound++; goto showmsg; } else if (pagemsg && !autoquery) { key = query ("at EOF - want to quit? (yes):", &ival, sval); if (!(key == '\r' || key == 'y')) goto showmsg; } cleanup: if (delmsg) { sprintf (cmd, "/bin/rm -rf %s", tmpdir); system (cmd); } } /* NEXTMSG -- Extract the next message from the input file. The string * beginmsg (e.g., "From ") marks the beginning of each message. */ nextmsg (fp, msg, maxch) FILE *fp; char *msg; int maxch; { register char *ip, *op; register int n = maxch; static char lbuf[SZ_LINE+1] = ""; int nch; for (ip=lbuf, op=msg; (*op = *ip++) && --n >= 0; op++) ; nch = strlen (beginmsg); while (fgets (lbuf, SZ_LINE, fp) != NULL) { if (op > msg && strncmp (lbuf, beginmsg, nch) == 0) break; for (ip=lbuf; (*op = *ip++) && --n >= 0; op++) ; lbuf[0] = EOS; } return (op > msg ? 0 : EOF); } /* MATCH -- Match the given pattern against the input string. Return 1 for * match. If the pattern begins with a ^ the match will be performed only * at the beginning of a line. */ match (str, pat) char *str; char *pat; { register char *ip, *pp, *ii; register int ch; if (ignorecase) { # define LC(ip) (isupper(ch= *(ip))?tolower(ch):ch) if (*pat == '^') { /* Match at beginning of line only. */ pat++; for (ip=str; *ip; ) { for (pp=pat; *pp == LC(ip); pp++, ip++) ; if (*pp == EOS) return (1); while (*ip && *ip++ != '\n') ; } } else { /* Match fixed pattern anywhere. */ for (ip=str; *ip; ip++) { if (LC(ip) != *pat) continue; for (pp=pat, ii=ip; *pp == LC(ii); pp++, ii++) ; if (*pp == EOS) return (1); } } } else { if (*pat == '^') { /* Match at beginning of line only. */ pat++; for (ip=str; *ip; ) { for (pp=pat; *pp == *ip; pp++, ip++) ; if (*pp == EOS) return (1); while (*ip && *ip++ != '\n') ; } } else { /* Match fixed pattern anywhere. */ for (ip=str; *ip; ip++) { if (*ip != *pat) continue; for (pp=pat, ii=ip; *pp == *ii; pp++, ii++) ; if (*pp == EOS) return (1); } } } return (0); } /* LOWER -- Convert a pattern string to lower case. */ char * lower (s) char *s; { register int n, ch; register char *ip, *op; static char lwr[SZ_PATSTR+1]; for (ip=s, op=lwr, n=SZ_PATSTR; --n >= 0 && (ch = *ip++); ) *op++ = isupper(ch) ? tolower(ch) : ch; *op = EOS; return (lwr); } /* QUERY -- Issue a prompt and query the user for the command keystroke. */ query (prompt, ival, sval) char *prompt; int *ival; char *sval; { static char oldpat[80]; char ctrl[128], *cp=ctrl; int key, ch, fd, value; /* Output prompt. */ cp = ctrl; if (tgetstr ("so", &cp) != NULL) tputs (ctrl, 1, putch); write (1, prompt, strlen(prompt)); cp = ctrl; if (tgetstr ("se", &cp) != NULL) tputs (ctrl, 1, putch); /* Get command key in raw mode. */ if ((fd = tty_open ("/dev/tty", 2)) == -1) { fprintf (stderr, "cannot open terminal\n"); return (EOF); } tty_rawon (fd, 0); value = 0; sval[0] = '\0'; while ((ch = key = tty_getc (fd)) != EOF) { if (isdigit(ch)) value = value * 10 + ch - '0'; else break; } if (key == '/') { /* Pattern search. */ char *op = sval; erase_p: /* Erase the prompt and echo the '/'. */ putch ('\r'); cp = ctrl; if (tgetstr ("ce", &cp) != NULL) tputs (ctrl, 1, putch); tty_putc (fd, ch); while ((ch = tty_getc (fd)) != EOF) { if (ch == '\025') { op = sval; *op = '\0'; goto erase_p; } else if (ch == '\177' || ch == '\010') { if (op > sval) { tty_putc (fd, '\010'); tty_putc (fd, ' '); tty_putc (fd, '\010'); --op; } else { key = IGNORE; break; } } else if (ch == '\r') { *op++ = '\0'; break; } else { *op++ = ch; tty_putc (fd, ch); } } if (sval[0]) strcpy (oldpat, sval); else strcpy (sval, oldpat); } else if (key == 'n') { /* repeat search */ strcpy (sval, oldpat); } else if (key == 's') { /* Save message in a file. */ char buf[256]; char *op; erase_f: /* Prompt for the save file. */ putch ('\r'); cp = ctrl; if (tgetstr ("ce", &cp) != NULL) tputs (ctrl, 1, putch); sprintf (buf, "save file: %s", svfile); write (1, buf, strlen(buf)); /* Get save file name. */ op = svfile + strlen(svfile); while ((ch = tty_getc (fd)) != EOF) { if (ch == '\025') { svfile[0] = '\0'; goto erase_f; } else if (ch == '\177' || ch == '\010') { if (op > svfile) { tty_putc (fd, '\010'); tty_putc (fd, ' '); tty_putc (fd, '\010'); --op; } else { key = IGNORE; break; } } else if (ch == '\r') { tty_putc (fd, ' '); *op++ = '\0'; break; } else if (isprint(ch)) { *op++ = ch; tty_putc (fd, ch); } } strcpy (sval, svfile); } tty_close (fd); /* Erase the prompt. */ if (key != 's') putch ('\r'); if (key != '/' && key != 's') { cp = ctrl; if (tgetstr ("ce", &cp) != NULL) tputs (ctrl, 1, putch); } *ival = value; return (key); } /* * TERMINAL handling code. * --------------------------- * * fd = tty_open (device, mode) * tty_close (fd) * ch|EOF = tty_getc (fd) * tty_putc (fd, ch) * tty_rawon (fd, flags) * tty_reset (fd) */ #include #include #include #ifdef SYSV #include #else #include #endif # ifndef O_NDELAY #include # endif #define CTRLC 3 extern int errno; static jmp_buf jmpbuf; struct fiodes { int io_flags; /* fcntl flags */ short flags; /* access mode flags */ #ifdef SYSV #define _STDF_INIT 0,0,0, '\0','\0' short tc_iflag; /* saved SysV tty state */ short tc_oflag; short tc_lflag; char tc_cc[NCC]; #else #define _STDF_INIT 0 short sg_flags; /* save space for stty flags */ #endif }; #define KF_CHARMODE 001 /* char input mode, text files */ #define KF_NOSEEK 002 /* seeks are illegal on device */ #define KF_NOSTTY 004 /* stty,gtty calls illegal */ #define KF_NDELAY 010 /* nonblocking reads */ struct fiodes zfd; static int tty_fd = -1; /* FD of tty device */ static char tty_redraw = 'r'; /* screen redraw control code */ static int tty_getraw = 0; /* raw getc in progress */ #ifdef SYSV static struct termio tc_state; /* save terminal state */ #else static short tty_flags = 0; /* terminal driver flags */ #endif typedef int (*PFI)(); static PFI sigint, sigterm; static PFI sigtstp, sigcont; static int tty_onsig(), tty_stop(), tty_continue(); /* TTY_OPEN -- Open the terminal. */ tty_open (device, mode) char *device; int mode; { register int fd; if ((fd = open (device, mode)) == -1) return (-1); zfd.io_flags = 0; zfd.flags = KF_NOSEEK; return (fd); } /* TTY_CLOSE -- Close the terminal. */ tty_close (fd) int fd; { register struct fiodes *kfp = &zfd; if (kfp->flags & KF_CHARMODE) tty_reset (fd); close (fd); } /* TTY_GETC -- Read a character from the terminal. In the case of raw mode * reads, the process can be suspended and later resumed and a character * returned to redraw the screen. */ tty_getc (fd) int fd; { char ch; sigint = (PFI) signal (SIGINT, tty_onsig); sigterm = (PFI) signal (SIGTERM, tty_onsig); tty_getraw = 1; if ((ch = setjmp (jmpbuf)) == 0) { if (read (fd, &ch, 1) <= 0) ch = EOF; } signal (SIGINT, sigint); signal (SIGTERM, sigterm); tty_getraw = 0; return (ch); } /* TTY_PUTC -- Put a character to the terminal. */ tty_putc (fd, ch) int fd; int ch; { char cch = ch; write (fd, &cch, 1); } /* TTY_RAWON -- Turn on rare mode and turn off echoing and all input and * output character processing. Interrupts are caught and the interrupt * character is returned like any other character. Save sg_flags for * subsequent restoration. */ static tty_rawon (fd, flags) int fd; /* file descriptor */ int flags; /* file mode control flags */ { register struct fiodes *kfp = &zfd; register int i; if (!(kfp->flags & (KF_CHARMODE|KF_NOSTTY))) { #ifdef SYSV struct termio tc; ioctl (fd, TCGETA, &tc); /* Save terminal state. */ kfp->tc_iflag = tc.c_iflag; kfp->tc_oflag = tc.c_oflag; kfp->tc_lflag = tc.c_lflag; kfp->flags |= KF_CHARMODE; for (i=0; i < NCC; i++) kfp->tc_cc[i] = tc.c_cc[i]; /* Set raw mode. */ tc.c_iflag = 0; tc.c_oflag = 0; tc.c_lflag = ISIG; for (i=0; i < NCC; i++) tc.c_cc[i] = 0377; tc.c_cc[VMIN] = 2; tc.c_cc[VTIME] = 2; ioctl (fd, TCSETAF, &tc); /* Save FD, state flags of raw mode tty device. */ tty_fd = fd; tc_state = tc; #else struct sgttyb ttystat; ioctl (fd, TIOCGETP, &ttystat); kfp->sg_flags = ttystat.sg_flags; kfp->flags |= KF_CHARMODE; /* Set raw mode in the terminal driver. */ ttystat.sg_flags |= CBREAK; ttystat.sg_flags &= ~(ECHO|CRMOD); ioctl (fd, TIOCSETN, &ttystat); /* Save FD, SG_FLAGS of raw mode tty device. */ tty_fd = fd; tty_flags = ttystat.sg_flags; #endif /* Post signal handlers to clear/restore raw mode if process is * suspended. */ sigtstp = (PFI) signal (SIGTSTP, tty_stop); sigcont = (PFI) signal (SIGCONT, tty_continue); } /* Set any file descriptor flags, e.g., for nonblocking reads. */ if ((flags & KF_NDELAY) && !(kfp->flags & KF_NDELAY)) { kfp->io_flags = fcntl (fd, F_GETFL, 0); fcntl (fd, F_SETFL, kfp->io_flags | O_NDELAY); kfp->flags |= KF_NDELAY; } else if (!(flags & KF_NDELAY) && (kfp->flags & KF_NDELAY)) fcntl (fd, F_SETFL, kfp->io_flags); } /* TTY_RESET -- Clear character at a time mode on the terminal device, if in * effect. This will restore normal line oriented terminal i/o, even if raw * mode i/o was set on the physical device when the ioctl status flags were * saved. */ static tty_reset (fd) int fd; { register struct fiodes *kfp = &zfd; register int i; #ifdef SYSV struct termio tc; if (ioctl (fd, TCGETA, &tc) == -1) return; /* If no saved status use current tty status. */ if (!(kfp->flags & KF_CHARMODE)) { kfp->tc_iflag = tc.c_iflag; kfp->tc_oflag = tc.c_oflag; kfp->tc_lflag = tc.c_lflag; for (i=0; i < NCC; i++) kfp->tc_cc[i] = tc.c_cc[i]; } /* Clear raw mode. */ tc.c_iflag = (kfp->tc_iflag | ICRNL); tc.c_oflag = (kfp->tc_oflag | OPOST); tc.c_lflag = (kfp->tc_lflag | (ICANON|ISIG|ECHO)); for (i=0; i < NCC; i++) tc.c_cc[i] = kfp->tc_cc[i]; ioctl (fd, TCSETAF, &tc); kfp->flags &= ~KF_CHARMODE; #else struct sgttyb ttystat; if (ioctl (fd, TIOCGETP, &ttystat) == -1) return; if (!(kfp->flags & KF_CHARMODE)) kfp->sg_flags = ttystat.sg_flags; ttystat.sg_flags = (kfp->sg_flags | (ECHO|CRMOD)) & ~CBREAK; ioctl (fd, TIOCSETN, &ttystat); kfp->flags &= ~KF_CHARMODE; #endif if (kfp->flags & KF_NDELAY) { fcntl (fd, F_SETFL, kfp->io_flags & ~O_NDELAY); kfp->flags &= ~KF_NDELAY; } signal (SIGTSTP, sigtstp); signal (SIGCONT, sigcont); } /* TTY_ONSIG -- Catch interrupt and return a nonzero status. Active only while * we are reading from the terminal in raw mode. */ static tty_onsig (sig, code, scp) int sig; /* signal which was trapped */ int code; /* subsignal code (vax) */ struct sigcontext *scp; /* not used */ { longjmp (jmpbuf, CTRLC); } /* TTY_STOP -- Called when a process is suspended while the terminal is in raw * mode; our function is to restore the terminal to normal mode. */ static tty_stop (sig, code, scp) int sig; /* signal which was trapped */ int code; /* subsignal code (vax) */ struct sigcontext *scp; /* not used */ { #ifdef SYSV register struct fiodes *kfp = &zfd; register int i; struct termio tc; if (ioctl (tty_fd, TCGETA, &tc) != -1) { tc.c_iflag = (kfp->tc_iflag | ICRNL); tc.c_oflag = (kfp->tc_oflag | OPOST); tc.c_lflag = (kfp->tc_lflag | (ICANON|ISIG|ECHO)); for (i=0; i < NCC; i++) tc.c_cc[i] = kfp->tc_cc[i]; ioctl (tty_fd, TCSETAF, &tc); } #else struct sgttyb ttystat; if (ioctl (tty_fd, TIOCGETP, &ttystat) != -1) { ttystat.sg_flags = (tty_flags | (ECHO|CRMOD)) & ~CBREAK; ioctl (tty_fd, TIOCSETN, &ttystat); } #endif kill (getpid(), SIGSTOP); } /* TTY_CONTINUE -- Called when execution of a process which was suspended with * the terminal in raw mode is resumed; our function is to restore the terminal * to raw mode. */ static tty_continue (sig, code, scp) int sig; /* signal which was trapped */ int code; /* subsignal code (vax) */ struct sigcontext *scp; /* not used */ { #ifdef SYSV ioctl (tty_fd, TCSETAF, &tc_state); #else struct sgttyb ttystat; if (ioctl (tty_fd, TIOCGETP, &ttystat) != -1) { ttystat.sg_flags = tty_flags; ioctl (tty_fd, TIOCSETN, &ttystat); } #endif if (tty_redraw && tty_getraw) longjmp (jmpbuf, tty_redraw); }