rsalz@uunet.uu.net (Rich Salz) (10/26/89)
Submitted-by: Emmet P. Gray <uiucuxc!fthood!egray> Posting-number: Volume 20, Issue 73 Archive-name: pcomm1.2/part07 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # terminal.c # tty_att.c # tty_ucb.c # vcs.c # vcs.h # waitfor.c # x_ascii.c # x_batch.c # x_extrnl.c export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'terminal.c'" '(9863 characters)' if test -f 'terminal.c' then echo shar: "will not over-write existing file 'terminal.c'" else sed 's/^X//' << \SHAR_EOF > 'terminal.c' X/* X * Start the terminal dialogue, fork the input routine, watch for the X * hot key so we can execute an option. X */ X X#include <stdio.h> X#include <curses.h> X#include <signal.h> X#include "config.h" X#include "dial_dir.h" X#include "misc.h" X#include "modem.h" X#include "param.h" X#include "status.h" X#include "xmodem.h" X X#ifdef UNIXPC X#include <sys/phone.h> X#include <fcntl.h> X#endif /* UNIXPC */ X Xstatic int pid = -1; X Xterminal(extra_dir, input_status) Xchar *extra_dir; Xint input_status; X{ X extern int fd; X int i, j, k, cr_lf, script; X char c, lf=10, *str_rep(), *keymac, *memset(); X void help_screen(), line_set(), n_shell(), load_vs(), send_str(); X void release_port(), do_input(), list_dir(), pexit(), zap_vs(); X void st_line(), chg_dir(), screen_dump(), input_off(), suspend(); X void info(), term_mode(), macro(), do_script(); X X /* if starting out in command mode */ X if (!input_status) { X erase(); X refresh(); X st_line(""); X } X /* put stdin/stdout in terminal mode */ X resetterm(); X term_mode(); X cr_lf = !strcmp(param->cr_out, "CR/LF"); X X if (input_status) { X do_script(extra_dir); X do_input(); X } X X while (1) { X read(0, &c, 1); X c &= 0x7f; X /* is it the hot key? */ X if (c == param->hot) { X /* suspend input */ X input_status = 0; X suspend(TRUE); X script = 0; X X /* X * Put the terminal in the curses mode, load the X * virtual screen and add the status line at the bottom. X */ X fixterm(); X load_vs(); X st_line(""); X#ifndef OLDCURSES X keypad(stdscr, TRUE); X#endif /* OLDCURSES */ X i = wgetch(stdscr); X /* map an additional hot key to -1 */ X if (i == param->hot) X i = -1; X X keymac = ""; X /* look for options */ X k = -1; X switch (i) { X case -1: /* 2 "hots" means send 1 */ X k = param->hot; X break; X case '0': /* help screen */ X help_screen(param->ascii_hot); X break; X case 'd': X case 'D': /* dialing directory */ X if (dial_menu()) X input_status = dial_win(); X script = input_status; X break; X case 'r': X case 'R': /* redial */ X if (redial()) X input_status = dial_win(); X script = input_status; X break; X case 'm': X case 'M': /* keyboard macros */ X macro(); X break; X case 'p': X case 'P': /* line settings */ X if (ls_menu()) X line_set(); X break; X case 'x': X case 'X': /* exit */ X pexit(); X break; X case '4': /* Unix gateway */ X n_shell(); X break; X case 'i': X case 'I': /* program info screen */ X info(MANUAL_CLEAR); X break; X case 's': /* setup menu */ X case 'S': X input_status = setup_menu(); X break; X case 'c': /* clear the screen */ X case 'C': X zap_vs(); X erase(); X#ifdef SHAREDMEM X if (pid == -1) { X for (j=0; j<LINES; j++) X memset(status->vs[j], ' ', COLS); X } X#endif /* SHAREDMEM */ X break; X case 'b': X case 'B': /* change directory */ X chg_dir(); X break; X case 'e': X case 'E': /* toggle duplex */ X if (dir->duplex[dir->d_cur] == 'F') X dir->duplex[dir->d_cur] = 'H'; X else X dir->duplex[dir->d_cur] = 'F'; X X /* show changes */ X st_line(""); X k = wait_key(stdscr, 2); X break; X case 'h': X case 'H': /* hang up phone */ X release_port(VERBOSE); X input_off(); X break; X case 'l': X case 'L': /* toggle printer */ X status->print = status->print ? 0 : 1; X#ifndef SHAREDMEM X if (pid != -1) X kill(pid, SIGUSR2); X#endif /* SHAREDMEM */ X /* show changes */ X st_line(""); X k = wait_key(stdscr, 2); X break; X case '3': /* toggle CR - CR/LF */ X if (!strcmp(param->cr_in, "CR")) { X param->cr_in = str_rep(param->cr_in, "CR/LF"); X status->add_lf = 1; X } X else { X param->cr_in = str_rep(param->cr_in, "CR"); X status->add_lf = 0; X } X#ifndef SHAREDMEM X input_off(); X input_status++; X#endif /* SHAREDMEM */ X /* show changes */ X st_line(""); X k = wait_key(stdscr, 2); X break; X case '7': /* break key */ X if (fd != -1) X tty_break(fd); X X st_line(" break"); X break; X#ifndef OLDCURSES X case KEY_UP: X#endif /* OLDCURSES */ X case 'u': X case 'U': /* send files */ X input_status = xfer_menu(UP_LOAD); X break; X#ifndef OLDCURSES X case KEY_DOWN: X case '\n': X#endif /* OLDCURSES */ X case 'n': X case 'N': /* receive files */ X input_status = xfer_menu(DOWN_LOAD); X break; X case 't': X case 'T': X input_status = pass_thru(); X break; X case 'f': X case 'F': /* list directory */ X list_dir(); X break; X case 'g': /* screen dump */ X case 'G': X screen_dump(); X st_line(" screen dump"); X k = wait_key(stdscr, 2); X break; X case '1': /* data logging */ X input_status = data_logging(); X break; X case '2': /* toggle log */ X if (!strcmp(status->log_path, "NOT_DEFINED")) { X beep(); X st_line(" no log file"); X k = wait_key(stdscr, 2); X break; X } X status->log = status->log ? 0 : 1; X#ifndef SHAREDMEM X if (pid != -1) X kill(pid, SIGUSR1); X#endif /* SHAREDMEM */ X /* show changes */ X st_line(""); X k = wait_key(stdscr, 2); X break; X /* X * The following are the keyboard macros X * corresponding to the shifted number keys. X * (Too many keys... [control] [A] [shift] [1] X * is hardly a shortcut!) X */ X case '!': X keymac = param->mac_1; X break; X case '@': X keymac = param->mac_2; X break; X case '#': X keymac = param->mac_3; X break; X case '$': X keymac = param->mac_4; X break; X case '%': X keymac = param->mac_5; X break; X case '^': X keymac = param->mac_6; X break; X case '&': X keymac = param->mac_7; X break; X case '*': X keymac = param->mac_8; X break; X case '(': X keymac = param->mac_9; X break; X case ')': X keymac = param->mac_0; X break; X default: X fputc(BEL, stderr); X break; X } X X /* X * Repaint the stdscr (if we are already talking), X * get the stdin/stdout out of the curses mode and X * into the terminal mode. X */ X if (fd != -1) { X touchwin(stdscr); X refresh(); X } X resetterm(); X term_mode(); X X /* X * Some of the output processing options have to be X * faked... Unfortunately, adding a LF to CR on X * output is one of them. X */ X cr_lf = !strcmp(param->cr_out, "CR/LF"); X X /* run the auto-login script */ X if (script) X do_script(extra_dir); X X /* re-start input routine */ X if (input_status) X do_input(); X else X suspend(FALSE); X X /* send the macro */ X if (*keymac != '\0') X send_str(keymac, FAST); X /* X * If you pressed a key during one of the sleeping X * periods (typically the delay to see the status X * line change), let the keyboard value fall thru X * to the write() below. X */ X if (k == -1) X continue; X c = k; X } X /* ignore errors if fd == -1 */ X write(fd, &c, 1); X /* map cr to cr_lf? */ X if (c == '\r' && cr_lf) X write(fd, &lf, 1); X } X} X X/* X * Fire up the input routine... X */ X Xvoid Xdo_input() X{ X extern int fd; X void error_win(); X char first[(sizeof(int)*8)+1]; X#ifdef SHAREDMEM X extern int shm_id; X#else /* SHAREDMEM */ X char add_lf[2], log[2], print[2], dup_fd[3]; X#endif /* SHAREDMEM */ X /* if no TTY, or already on */ X if (pid != -1 || fd == -1) X return; X X status->fd = fd; X status->add_lf = !strcmp(param->cr_in, "CR/LF"); X X#ifdef SHAREDMEM X sprintf(first, "%d", shm_id); X#else /* SHAREDMEM */ X sprintf(first, "%d", status->fd); X sprintf(dup_fd, "%d", status->dup_fd); X sprintf(add_lf, "%d", status->add_lf); X sprintf(log, "%d", status->log); X sprintf(print, "%d", status->print); X#endif /* SHAREDMEM */ X X /* fork the input routine */ X if (!(pid = fork())) { X#ifdef BSD X setpgrp(0, getpid()); X#else /* BSD */ X setpgrp(); X#endif /* BSD */ X X#ifdef SETUGID X setuid(getuid()); X setgid(getgid()); X#endif /* SETUGID */ X X#ifdef SHAREDMEM X execlp("pcomm_input", "pcomm_input", first, (char *) 0); X#else /* SHAREDMEM */ X execlp("pcomm_input", "pcomm_input", first, dup_fd, add_lf, X log, print, status->log_path, status->vs_path, (char *) 0); X#endif /* SHAREDMEM */ X error_win(1, "Cannot find (or execute) the 'pcomm_input' program", ""); X } X X return; X} X X/* X * shut it down... X */ X Xvoid Xinput_off() X{ X if (pid != -1) { X kill(pid, SIGTERM); X pid = -1; X } X return; X} X X/* X * Hang up the phone but remain in the Pcomm command state. Uses the X * hang_up string only, does *not* drop the DTR! X */ X Xvoid Xhang_up(verbose) Xint verbose; X{ X extern int fd; X void send_str(), st_line(), line_set(); X char buf[80], *strcpy(), *ttyname(); X /* sanity checking */ X if (modem == NULL) X return; X /* anything to hang up? */ X if (modem->m_cur == -1 || fd == -1) X return; X X if (verbose) X st_line("disconnecting"); X /* special case for OBM */ X#ifdef UNIXPC X if (!strcmp(modem->mname[modem->m_cur], "OBM")) { X ioctl(fd, PIOCDISC); X /* X * The PIOCDISC ioctl screws up the file descriptor!!! X * No other phone(7) ioctl can fix it. Whatever it does, X * it seems to escape detection with PIOCGETA and TCGETA. X * The best I can do is close the port and start over. X */ X strcpy(buf, ttyname(fd)); X close(fd); X fd = open(buf, O_RDWR|O_NDELAY); X line_set(); X fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY); X } X else X#endif /* UNIXPC */ X send_str(modem->hang_up[modem->m_cur], SLOW); X X if (verbose) X st_line(""); X return; X} X X/* X * Suspend or un-suspend the input routine. The argument is used in X * non-shared memory configurations to give the vs_path file a fighting X * chance of being written to disk before load_vs() reads it. X */ X X/* ARGSUSED */ Xvoid Xsuspend(on) Xint on; X{ X unsigned int sleep(); X X if (pid == -1) X return; X kill(pid, SIGINT); X X#ifndef SHAREDMEM X if (on) X sleep(1); X#endif /* SHAREDMEM */ X X return; X} SHAR_EOF if test 9863 -ne "`wc -c < 'terminal.c'`" then echo shar: "error transmitting 'terminal.c'" '(should have been 9863 characters)' fi fi echo shar: "extracting 'tty_att.c'" '(4795 characters)' if test -f 'tty_att.c' then echo shar: "will not over-write existing file 'tty_att.c'" else sed 's/^X//' << \SHAR_EOF > 'tty_att.c' X/* X * System V specific routines for manipulating the TTY X */ X X#include <stdio.h> X#include <termio.h> X#include <fcntl.h> X#include "dial_dir.h" X#include "param.h" X X/* X * Change the communication line settings to the new values. X */ X Xvoid Xline_set() X{ X extern int fd; X struct termio tbuf; X X /* X * The manual dial entry also serves to store the previous X * line settings. How else would the manual dial entry X * know what line setting to use? X */ X if (dir->d_cur != 0) { X dir->baud[0] = dir->baud[dir->d_cur]; X dir->parity[0] = dir->parity[dir->d_cur]; X dir->dbits[0] = dir->dbits[dir->d_cur]; X dir->sbits[0] = dir->sbits[dir->d_cur]; X } X /* nothing to do! */ X if (fd == -1) X return; X /* get the current settings */ X ioctl(fd, TCGETA, &tbuf); X /* set some beginning values */ X tbuf.c_cc[4] = 1; /* VMIN */ X tbuf.c_cc[5] = 0; /* VTIME */ X tbuf.c_oflag = 0; X tbuf.c_iflag = 0; X tbuf.c_cflag = (CREAD|HUPCL|CLOCAL); X tbuf.c_lflag = 0; X X if (*param->flow == 'X') X tbuf.c_iflag |= (IXON|IXOFF); X /* strip high bit? */ X if (*param->strip == 'Y') X tbuf.c_iflag |= ISTRIP; X /* the baud rate */ X switch (dir->baud[dir->d_cur]) { X case 300: X tbuf.c_cflag |= B300; X break; X case 1200: X tbuf.c_cflag |= B1200; X break; X case 2400: X tbuf.c_cflag |= B2400; X break; X case 4800: X tbuf.c_cflag |= B4800; X break; X case 9600: X tbuf.c_cflag |= B9600; X break; X case 19200: X#ifdef B19200 X tbuf.c_cflag |= B19200; X#else /* B19200 */ X#ifdef EXTA X tbuf.c_cflag |= EXTA; X#endif /* EXTA */ X#endif /* B19200 */ X break; X } X /* the parity */ X switch (dir->parity[dir->d_cur]) { X case 'N': X break; X case 'O': X tbuf.c_cflag |= (PARENB|PARODD); X break; X case 'E': X tbuf.c_cflag |= PARENB; X break; X } X /* the data bits */ X if (dir->dbits[dir->d_cur] == 8) X tbuf.c_cflag |= CS8; X else X tbuf.c_cflag |= CS7; X /* the stop bits */ X if (dir->sbits[dir->d_cur] == 2) X tbuf.c_cflag |= CSTOPB; X X /* now set 'em! */ X ioctl(fd, TCSETAF, &tbuf); X return; X} X X/* X * Put the stdin/stdout in terminal mode. We've divided up the X * responsibility for the line settings options between the serial port X * and the stdin and stdout. X */ X Xvoid Xterm_mode() X{ X struct termio tbuf; X X ioctl(0, TCGETA, &tbuf); X X tbuf.c_cc[4] = 1; /* VMIN */ X tbuf.c_cc[5] = 0; /* VTIME */ X tbuf.c_iflag = 0; X tbuf.c_oflag = 0; X tbuf.c_lflag = 0; X /* duplex */ X if (dir->duplex[dir->d_cur] == 'H') X tbuf.c_lflag = ECHO; X X ioctl(0, TCSETAF, &tbuf); X return; X} X X/* X * Put the TTY driver in the mode suitable for xmodem transfers. X */ X Xvoid Xxmodem_mode(fds) Xint fds; X{ X struct termio tbuf; X X ioctl(fds, TCGETA, &tbuf); X /* X * Turn off the XON/XOFF flow control, turn off echoing, and X * switch to 8 bit no parity. X */ X tbuf.c_cc[4] = 1; /* VMIN */ X tbuf.c_cc[5] = 0; /* VTIME */ X tbuf.c_iflag = 0; /* no flow control or mapping */ X tbuf.c_oflag = 0; /* no char mapping or delays */ X tbuf.c_lflag = 0; /* no echo or signals */ X tbuf.c_cflag &= ~(PARENB|CSIZE);/* no parity */ X tbuf.c_cflag |= CS8; /* 8 bit */ X X ioctl(fds, TCSETAF, &tbuf); X return; X} X X/* X * Put the TTY line in a mode suitable for the ASCII transfer. Puts the X * terminal in the raw, non-blocking mode. X */ X Xvoid Xascii_mode(up) Xint up; X{ X extern int fd; X struct termio tbuf; X X ioctl(fd, TCGETA, &tbuf); X tbuf.c_oflag = 0; X /* flow control & 8th bit stripping */ X if (up) { X tbuf.c_iflag = (ISTRIP|IXON); X X /* if no CR's, use NL delays */ X if (!strcmp(param->cr_up, "STRIP")) X tbuf.c_oflag = (OPOST|ONLRET); X X /* CR delay times */ X switch (param->cr_delay) { X case 0: X break; X case 100: X tbuf.c_oflag |= (OPOST|CR2); X break; X case 150: X tbuf.c_oflag |= (OPOST|CR3); X break; X } X } X /* if down loading */ X else X tbuf.c_iflag = (ISTRIP|IXOFF); X X ioctl(fd, TCSETAF, &tbuf); X return; X} X X/* X * Flush the file descriptor X */ X Xint Xtty_flush(fds, mode) Xint fds, mode; X{ X return(ioctl(fds, TCFLSH, mode)); X} X X/* X * Wait for the output to drain X */ X Xint Xtty_drain(fds) Xint fds; X{ X return(ioctl(fds, TCSBRK, 1)); X} X X/* X * Send a modem break X */ X Xint Xtty_break(fds) Xint fds; X{ X return(ioctl(fds, TCSBRK, 0)); X} X X/* X * Fix the file descriptor so that a read is satisfied immediately. When X * read() is called it returns the character in the queue, or an error if X * no key was pressed. X */ X Xint Xtty_noblock(fds, on) Xint fds, on; X{ X int current; X X current = fcntl(fds, F_GETFL, 0); X if (on) X return(fcntl(fds, F_SETFL, current | O_NDELAY)); X else X return(fcntl(fds, F_SETFL, current & ~O_NDELAY)); X} X X/* X * Get the current baud rate of the terminal X */ X Xint Xmy_speed() X{ X static int speed[15] = {0, 50, 75, 110, 134, 150, 200, 300, 600, X 1200, 1800, 2400, 4800, 9600, 19200}; X struct termio tbuf; X X ioctl(0, TCGETA, &tbuf); X return(speed[tbuf.c_cflag & CBAUD]); X} SHAR_EOF if test 4795 -ne "`wc -c < 'tty_att.c'`" then echo shar: "error transmitting 'tty_att.c'" '(should have been 4795 characters)' fi fi echo shar: "extracting 'tty_ucb.c'" '(4666 characters)' if test -f 'tty_ucb.c' then echo shar: "will not over-write existing file 'tty_ucb.c'" else sed 's/^X//' << \SHAR_EOF > 'tty_ucb.c' X/* X * Berkeley specific routines for manipulating the TTY X */ X X#include <stdio.h> X#include <sgtty.h> X#include <fcntl.h> X#include "dial_dir.h" X#include "param.h" X X/* X * Change the communication line settings to the new values. X */ X Xvoid Xline_set() X{ X extern int fd; X struct sgttyb tbuf; X X /* X * The manual dial entry also serves to store the previous X * line settings. How else would the manual dial entry X * know what line setting to use? X */ X if (dir->d_cur != 0) { X dir->baud[0] = dir->baud[dir->d_cur]; X dir->parity[0] = dir->parity[dir->d_cur]; X dir->dbits[0] = dir->dbits[dir->d_cur]; X dir->sbits[0] = dir->sbits[dir->d_cur]; X } X /* nothing to do! */ X if (fd == -1) X return; X /* get the current settings */ X ioctl(fd, TIOCGETP, &tbuf); X /* set some beginning values */ X tbuf.sg_flags = CBREAK; X X if (*param->flow == 'X') X tbuf.sg_flags |= TANDEM; X /* the baud rate */ X switch (dir->baud[dir->d_cur]) { X case 300: X tbuf.sg_ispeed = B300; X tbuf.sg_ospeed = B300; X break; X case 1200: X tbuf.sg_ispeed = B1200; X tbuf.sg_ospeed = B1200; X break; X case 2400: X tbuf.sg_ispeed = B2400; X tbuf.sg_ospeed = B2400; X break; X case 4800: X tbuf.sg_ispeed = B4800; X tbuf.sg_ospeed = B4800; X break; X case 9600: X tbuf.sg_ispeed = B9600; X tbuf.sg_ospeed = B9600; X break; X case 19200: X#ifdef B19200 X tbuf.sg_ispeed = B19200; X tbuf.sg_ospeed = B19200; X#else /* B19200 */ X#ifdef EXTA X tbuf.sg_ispeed = EXTA; X tbuf.sg_ospeed = EXTA; X#endif /* EXTA */ X#endif /* B19200 */ X break; X } X /* the parity */ X switch (dir->parity[dir->d_cur]) { X case 'N': X tbuf.sg_flags |= ANYP; X break; X case 'O': X tbuf.sg_flags |= ODDP; X break; X case 'E': X tbuf.sg_flags |= EVENP; X break; X } X /* now set 'em! */ X ioctl(fd, TIOCSETP, &tbuf); X return; X} X X/* X * Put the stdin/stdout in terminal mode. We've divided up the X * responsibility for the line settings options between the serial port X * and the stdin and stdout. X */ X Xvoid Xterm_mode() X{ X struct sgttyb tbuf; X X ioctl(0, TIOCGETP, &tbuf); X X tbuf.sg_flags |= CBREAK; X tbuf.sg_flags &= ~(RAW|CRMOD|ECHO); X X if (dir->duplex[dir->d_cur] == 'H') X tbuf.sg_flags |= ECHO; X X ioctl(0, TIOCSETP, &tbuf); X return; X} X X/* X * Put the TTY driver in the mode suitable for xmodem transfers. X */ X Xvoid Xxmodem_mode(fds) Xint fds; X{ X struct sgttyb tbuf; X X ioctl(fds, TIOCGETP, &tbuf); X /* X * Turn off the XON/XOFF flow control, turn off echoing, and X * switch to 8 bit no parity. X */ X tbuf.sg_flags |= (RAW|ANYP); X tbuf.sg_flags &= ~ECHO; X ioctl(fds, TIOCSETP, &tbuf); X return; X} X X/* X * Put the TTY line in a mode suitable for the ASCII transfer. X */ X Xvoid Xascii_mode(up) Xint up; X{ X extern int fd; X struct sgttyb tbuf; X X ioctl(fd, TIOCGETP, &tbuf); X X tbuf.sg_flags |= (CBREAK|TANDEM); X tbuf.sg_flags &= ~(RAW|CRMOD|ECHO|CRDELAY); X X if (up) { X /* CR delay times */ X switch (param->cr_delay) { X case 0: X break; X case 100: X tbuf.sg_flags |= CR1; X break; X case 150: X tbuf.sg_flags |= CR2; X break; X } X } X X ioctl(fd, TIOCSETP, &tbuf); X return; X} X X/* X * Flush the file descriptor. Very messy... flushing the input causes a X * wait for the ouput to drain, and there is no output flushing. X */ X Xint Xtty_flush(fds, mode) Xint fds, mode; X{ X int ret_code = 0; X struct sgttyb tbuf; X X switch(mode) { X case 0: /* flush input queue */ X ioctl(fds, TIOCGETP, &tbuf); X ioctl(fds, TIOCSETP, &tbuf); X break; X case 1: /* flush output queue */ X /* sorry! */ X break; X case 2: /* flush both input and output */ X ioctl(fds, TIOCFLUSH, 0); X break; X default: X ret_code++; X break; X } X return(ret_code); X} X X/* X * Wait for the output to drain X */ X Xint Xtty_drain(fds) Xint fds; X{ X struct sgttyb tbuf; X /* this flushes the input too */ X ioctl(fds, TIOCGETP, &tbuf); X return(ioctl(fds, TIOCSETP, &tbuf)); X} X X/* X * Send a modem break X */ X Xint Xtty_break(fds) Xint fds; X{ X unsigned int sleep(); X X ioctl(fds, TIOCSBRK, (struct sgttyb *) 0); X sleep(1); X return(ioctl(fds, TIOCCBRK, (struct sgttyb *) 0)); X} X X/* X * Fix the file descriptor so that a read is satisfied immediately. When X * read() is called it returns the character in the queue, or an error if X * no key was pressed. X */ X Xint Xtty_noblock(fds, on) Xint fds, on; X{ X int current; X X current = fcntl(fds, F_GETFL, 0); X if (on) X return(fcntl(fds, F_SETFL, current | FNDELAY)); X else X return(fcntl(fds, F_SETFL, current & ~FNDELAY)); X} X X/* X * Get the current baud rate of the terminal X */ X Xint Xmy_speed() X{ X static int speed[15] = {0, 50, 75, 110, 134, 150, 200, 300, 600, X 1200, 1800, 2400, 4800, 9600, 19200}; X struct sgttyb tbuf; X X ioctl(0, TIOCGETP, &tbuf); X return(speed[tbuf.sg_ispeed]); X} SHAR_EOF if test 4666 -ne "`wc -c < 'tty_ucb.c'`" then echo shar: "error transmitting 'tty_ucb.c'" '(should have been 4666 characters)' fi fi echo shar: "extracting 'vcs.c'" '(10939 characters)' if test -f 'vcs.c' then echo shar: "will not over-write existing file 'vcs.c'" else sed 's/^X//' << \SHAR_EOF > 'vcs.c' X/* X * Routines for VCS detection. X */ X X#include <stdio.h> X#include "config.h" X#include "vcs.h" X X#ifndef OLDCURSES X#include <curses.h> X#include <term.h> X#endif /* OLDCURSES */ X Xstatic int putc_cnt; Xstatic char putc_buf[VCS_SIZE]; X X/* X * Test for possible VCS (video command sequence). A character return X * code means no match. An return code greater than 255 means a VCS X * was found. X */ X Xint Xvcs_filter(c) Xchar c; X{ X extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_leadin[NUM_VCS]; X extern int num_leadin; X static int vcs_buf[VCS_SIZE]; X static int ptr = 0; X register int i; X int maybe, possible; X X /* see if possible */ X possible = 0; X if (ptr == 0) { X /* X * This is kinda crude... I'm checking to see if the X * lead-in character is greater than the space character. X * If so, it most probably is NOT a VCS. X */ X if (c >= ' ') X return(c & 0xff); X /* check the list */ X for (i=0; i<num_leadin; i++) { X if (c == vcs_leadin[i]) { X possible++; X break; X } X } X if (!possible) X return(c & 0xff); X } X X /* build the string */ X vcs_buf[ptr++] = c; X vcs_buf[ptr] = -1; X /* test for match */ X maybe = 0; X for (i=0; i<NUM_VCS; i++) { X switch (match_codes(vcs_buf, vcs_codes[i], i)) { X case YES: X ptr = 0; X return(i+256); X case NO: X break; X case MAYBE: X maybe++; X break; X } X } X /* abandon what you've got */ X if (maybe && ptr == VCS_SIZE-1) { X ptr = 0; X return(c & 0xff); X } X /* hang on, wait and see */ X if (maybe) X return(MAYBE); X /* a clean miss */ X ptr = 0; X return(c & 0xff); X} X X/* X * See if the two integer arrays "match". Character parameters are X * designated by codes > 1000 and ASCII digit parameters are designated X * by codes > 2000. Uses a simple linear search, so if NUM_VCS grows X * this routine will have to mature a bit. X */ X Xstatic int Xmatch_codes(test, code, k) Xint test[], code[], k; X{ X extern int vcs_param[NUM_VCS][5]; X register int i, j; X int pos, done; X /* doesn't exist */ X if (code[0] == -1) X return(NO); X X i = 0; X j = 0; X while (i<VCS_SIZE && j<VCS_SIZE) { X /* at the end (a match) */ X if (test[i] == -1 && code[j] == -1) X return(YES); X /* ran out of input */ X if (test[i] == -1) X break; X /* X * The char parameter (code 1000) always matches the X * next character. X */ X if (code[j] >= 1000 && code[j] < 2000) { X pos = code[j] -1000; X vcs_param[k][pos] = test[i]; X i++; X j++; X continue; X } X /* X * The digit parameter (code 2000) tries to match as many X * ASCII digits as it can. X */ X if (code[j] >= 2000) { X pos = code[j] -2000; X /* done with this number? */ X if (vcs_param[k][pos]) X done = 1; X else X done = 0; X /* only digits */ X while (test[i] >= 48 && test[i] <= 57) { X if (!done) X vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48; X i++; X } X /* ended in a digit */ X if (test[i] == -1 && code[j+1] != -1) { X vcs_param[k][pos] = 0; X break; X } X j++; X continue; X } X /* a clean miss */ X if (test[i] != code[j]) { X for (j=0; j<5; j++) X vcs_param[k][j] = 0; X return(NO); X } X i++; X j++; X } X /* a maybe */ X return(MAYBE); X} X X/* X * Build the table of VCS codes. Actually we cheat... We tell curses(3) X * to build the strings to perform the function, and then we decipher X * what it did. X * X * For example: On a vt100 the cursor motion string in terminfo is: X * cup=\E[%i%p1%d;%p2%dH$<5> X * X * This gets translated to the integer array vcs_code[] as: X * \E [ %p1%d ; %p2%d H X * 27, 91, 2000, 59, 2001, 72 X * X * Notice that the "%p1" and "%p2" parameters get translated to 2000 and X * 2001. This is to signify that the parameters are multiple digit ASCII X * encoded numbers. The "%i" and "%d" codes are imbedded into the vcs_opt[] X * array in somewhat of a loose manner. In other words, there is no set X * format for the vcs_opt[] array. The padding info "$<5>" is ignored. X */ X Xvoid Xvcs_table() X{ X extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_opt[NUM_VCS][10]; X extern int vcs_leadin[NUM_VCS], num_leadin, max_row, max_col; X int i, j, k, match, temp[VCS_SIZE]; X char *p, *strcpy(), buf[VCS_SIZE], *getenv(), *tparm(); X void fake_it(); X X#ifdef OLDCURSES X char tcbuf[1024], tb[1024], *t, *cursor_home, *clr_eol, *clr_eos; X char *clear_screen, *cursor_up, *cursor_down, *cursor_right; X char *cursor_left, *cursor_address, *getenv(), *tgetstr(), *tgoto(); X X tgetent(tb, getenv("TERM")); X t = tcbuf; X X cursor_home = tgetstr("ho", &t); X clr_eol = tgetstr("ce", &t); X clr_eos = tgetstr("cd", &t); X clear_screen = tgetstr("cl", &t); X cursor_up = tgetstr("up", &t); X cursor_down = tgetstr("do", &t); X cursor_right = tgetstr("nd", &t); X cursor_left = tgetstr("le", &t); X cursor_address = tgetstr("cm", &t); X max_row = tgetnum("li"); X max_col = tgetnum("co"); X#else /* OLDCURSES */ X setupterm(getenv("TERM"), 1, &i); X max_row = lines; X max_col = columns; X#endif /* OLDCURSES */ X X /* X * Do the easy ones first. These don't take positional parameters, X * so all we have to do is strip the padding info. X */ X for (i=0; i<NUM_VCS; i++) { X switch (i) { X case HOME: X p = cursor_home; X break; X case CLR_EOL: X p = clr_eol; X break; X case CLR_EOS: X p = clr_eos; X break; X case CLEAR: X p = clear_screen; X break; X case MV_UP: X p = cursor_up; X break; X case MV_DOWN: X p = cursor_down; X break; X case MV_RIGHT: X p = cursor_right; X break; X case MV_LEFT: X p = cursor_left; X break; X default: X p = ""; X break; X } X /* X * Either the capability doesn't exist, or we're gonna X * do this one by hand (i.e.: ones with positional parameters) X */ X if (!p) { X vcs_codes[i][0] = -1; X continue; X } X /* fake an "output" */ X fake_it(p); X /* copy what it did */ X j = 0; X while (putc_buf[j]) { X vcs_codes[i][j] = putc_buf[j]; X j++; X if (j == VCS_SIZE-1) X break; X } X vcs_codes[i][j] = -1; X } X X /* X * And now for the difficult ones. The way it's done is: load the X * string with a few known parameters and then find where the X * parameters end up. The vcs_opt[][] array is "free-flowing" X * and means something only to the routine being used. X */ X /* add one to the param */ X if (substr(cursor_address, "%i") > 0) X vcs_opt[MV_DIRECT][0] = 1; X /* decimal codes used */ X if (substr(cursor_address, "%d") > 0) X vcs_opt[MV_DIRECT][1] = 1; X /* character codes used */ X if (substr(cursor_address, "%c") > 0) X vcs_opt[MV_DIRECT][2] = 1; X /* add an offset */ X if (substr(cursor_address, "%+") > 0) X vcs_opt[MV_DIRECT][3] = 1; X /* subtract an offset */ X if (substr(cursor_address, "%-") > 0) X vcs_opt[MV_DIRECT][4] = 1; X /* load with parameters 12 & 34 */ X#ifdef OLDCURSES X fake_it(tgoto(cursor_address, 12, 34)); X#else /* OLDCURSES */ X fake_it(tparm(cursor_address, 12, 34)); X#endif /* OLDCURSES */ X X j = 0; X while (putc_buf[j]) { X temp[j] = putc_buf[j]; X j++; X if (j == VCS_SIZE-1) X break; X } X temp[j] = -1; X /* if decimal parameters */ X if (vcs_opt[MV_DIRECT][1]) { X /* if add one */ X if (vcs_opt[MV_DIRECT][0]) X strcpy(buf, "13"); X else X strcpy(buf, "12"); X /* where is the 12 (or 13)? */ X if ((i = substr(putc_buf, buf)) > 0) { X temp[i] = 2000; X temp[i+1] = -2; X } X else X temp[0] = -1; X /* if add one */ X if (vcs_opt[MV_DIRECT][0]) X strcpy(buf, "35"); X else X strcpy(buf, "34"); X /* where is the 34 (or 35)? */ X if ((i = substr(putc_buf, buf)) > 0) { X temp[i] = 2001; X temp[i+1] = -2; X } X else X temp[0] = -1; X } X /* if character parameters */ X if (vcs_opt[MV_DIRECT][2]) { X /* original with 12 and 34 */ X strcpy(buf, putc_buf); X /* change 12 to 13 */ X#ifdef OLDCURSES X fake_it(tgoto(cursor_address, 13, 34)); X#else /* OLDCURSES */ X fake_it(tparm(cursor_address, 13, 34)); X#endif /* OLDCURSES */ X /* where are they different */ X i = 0; X while (buf[i] != '\0') { X if (buf[i] != putc_buf[i]) X break; X i++; X } X /* sanity checking */ X if (buf[i] == '\0') X temp[0] = -1; X /* if add, what is offset? */ X if (vcs_opt[MV_DIRECT][3]) X vcs_opt[MV_DIRECT][5] = temp[i] - 13; X X /* if subtract, what is offset? */ X if (vcs_opt[MV_DIRECT][4]) X vcs_opt[MV_DIRECT][5] = 13 - temp[i]; X X temp[i] = 1000; X /* change 34 to 35 */ X#ifdef OLDCURSES X fake_it(tgoto(cursor_address, 12, 35)); X#else /* OLDCURSES */ X fake_it(tparm(cursor_address, 12, 35)); X#endif /* OLDCURSES */ X /* where are they different */ X i = 0; X while (buf[i] != '\0') { X if (buf[i] != putc_buf[i]) X break; X i++; X } X temp[i] = 1001; X if (buf[i] == '\0') X temp[0] = -1; X } X /* strip the -2's out, if any */ X i = 0; X j = 0; X while (temp[i] != -1) { X if (temp[i] != -2) X vcs_codes[MV_DIRECT][j++] = temp[i]; X i++; X } X vcs_codes[MV_DIRECT][j] = -1; X X /* X * Simplify the list. Some codes are already handled by the X * virtual screen routines... no need to duplicate them. X */ X if (vcs_codes[MV_DOWN][0] == '\n') X vcs_codes[MV_DOWN][0] = -1; X X if (vcs_codes[MV_LEFT][0] == 8) X vcs_codes[MV_LEFT][0] = -1; X X /* X * Often the "clear screen" sequence will contain the "home" X * sequence... if so, don't duplicate the "home" portion. X */ X fake_it(cursor_home); X strcpy(buf, putc_buf); X X fake_it(clear_screen); X /* if "home" inside "clear screen" */ X if ((k = substr(putc_buf, buf)) >= 0) { X /* if at the beginning */ X if (k == 0) { X i = 0; X for (j=strlen(buf); j<VCS_SIZE; j++) X vcs_codes[CLEAR][i++] = putc_buf[j]; X vcs_codes[CLEAR][i] = -1; X } X /* if at the end */ X else if (strlen(buf)+k == strlen(putc_buf)) X vcs_codes[CLEAR][k] = -1; X } X /* is "clear screen" still unique */ X k = 0; X for (i=0; i<NUM_VCS; i++) { X if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1) X break; X if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) { X k++; X break; X } X } X if (k == 0) X vcs_codes[CLEAR][0] = -1; X X /* X * Make a list of unique lead-in characters to be used as a X * simple hash table. X */ X num_leadin = 0; X for (i=0; i<NUM_VCS; i++) { X if (vcs_codes[i][0] == -1) X continue; X /* add any new lead-in character */ X match = 0; X for (j=0; j<num_leadin; j++) { X if (vcs_leadin[j] == vcs_codes[i][0]) X match++; X } X if (!match) X vcs_leadin[num_leadin++] = vcs_codes[i][0]; X } X return; X} X X/* X * The routine that fakes curses(3) into outputting the string info with X * the padding removed. X */ Xstatic void Xfake_it(s) Xchar *s; X{ X int fake_putc(); X X putc_cnt = 0; X putc_buf[0] = '\0'; X tputs(s, 1, fake_putc); X putc_buf[putc_cnt] = '\0'; X return; X} Xstatic int Xfake_putc(c) Xchar c; X{ X if (c != '\0') X putc_buf[putc_cnt++] = c; X return(c); X} X X/* X * Is string2 contained in string1? If so, return the offset, otherwise X * return a -1. X */ X Xstatic int Xsubstr(s1, s2) Xchar *s1, *s2; X{ X int i, len; X X len = strlen(s2); X /* not possible */ X if (len > strlen(s1)) X return(-1); X X i = 0; X while (*s1) { X if (!strncmp(s1, s2, len)) X return(i); X s1++; X i++; X } X return(-1); X} SHAR_EOF if test 10939 -ne "`wc -c < 'vcs.c'`" then echo shar: "error transmitting 'vcs.c'" '(should have been 10939 characters)' fi fi echo shar: "extracting 'vcs.h'" '(330 characters)' if test -f 'vcs.h' then echo shar: "will not over-write existing file 'vcs.h'" else sed 's/^X//' << \SHAR_EOF > 'vcs.h' X/* X * Definitions to support the detection of video command sequences X */ X X#define VCS_SIZE 25 X#define NUM_VCS 9 X X#define HOME 0 X#define CLR_EOL 1 X#define CLR_EOS 2 X#define CLEAR 3 X#define MV_UP 4 X#define MV_DOWN 5 X#define MV_RIGHT 6 X#define MV_LEFT 7 X#define MV_DIRECT 8 X X#define YES 1 X#define NO 0 X#define MAYBE (-1) SHAR_EOF if test 330 -ne "`wc -c < 'vcs.h'`" then echo shar: "error transmitting 'vcs.h'" '(should have been 330 characters)' fi fi echo shar: "extracting 'waitfor.c'" '(2108 characters)' if test -f 'waitfor.c' then echo shar: "will not over-write existing file 'waitfor.c'" else sed 's/^X//' << \SHAR_EOF > 'waitfor.c' X/* X * Wait for a string on the stdin. Returns a 0 on success, 1 on failure X * and -1 on error. This is an external program designed to be used in X * shell scripts. X */ X X#define TIMEOUT 10 X#define BUF_SIZ 1024 X#define HZ 60 X#define STRSTR X Xint wf_flag; X X#include <stdio.h> X#include <signal.h> X#include <sys/types.h> X#include <sys/times.h> X X#ifdef BSD X#include <setjmp.h> Xjmp_buf wf_buf; X#endif /* BSD */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X int i, j, timeout; X char c, buf[BUF_SIZ], *string, *strstr(); X struct tms t; X long t1; X void exit(); X X if (argc < 2 || argc > 3) { X fprintf(stderr, "Usage: waitfor -n string\n"); X exit(-1); X } X X if (argv[1][0] == '-') { X timeout = atoi(&argv[1][1]); X if (argc != 3) { X fprintf(stderr, "Usage: waitfor -n string\n"); X exit(-1); X } X string = argv[2]; X } X else { X timeout = TIMEOUT; X string = argv[1]; X } X /* here we go.. */ X i = 0; X t1 = times(&t); X while ((times(&t) - t1) < (HZ * timeout)) { X if ((j = getc_line()) != -1) { X c = j & 0x7f; X /* no NULLs please */ X if (c != '\0') { X buf[i++] = c; X buf[i] = '\0'; X } X X if (i >= BUF_SIZ) { X fprintf(stderr, "waitfor: buffer overflow\n"); X exit(-1); X } X /* yea.. we found it! */ X if (strstr(buf, string)) X exit(0); X } X } X exit(1); X} X Xint Xgetc_line() X{ X int wf_force(); X char c; X unsigned int alarm(); X X signal(SIGALRM, wf_force); X wf_flag = 0; X X alarm(1); X X#ifdef BSD X if (setjmp(wf_buf)) X return(-1); X#endif /* BSD */ X X if (read(0, &c, 1) <= 0) { X alarm(0); X return(-1); X } X if (wf_flag) X return(-1); X alarm(0); X return(c & 0xff); X} X X/* ARGSUSED */ Xstatic int Xwf_force(dummy) Xint dummy; X{ X#ifdef BSD X longjmp(wf_buf, 1); X#else /* BSD */ X signal(SIGALRM, wf_force); X wf_flag = 1; X#endif /* BSD */ X} X X#ifdef STRSTR X/* X * Return a pointer to the first occurance of string str2 in str1. X * Returns a NULL if str2 is not in str1. X */ X Xchar * Xstrstr(str1, str2) Xchar *str1, *str2; X{ X int len; X len = strlen(str2); X while (*str1) { X if (*str2 == *str1) { X if (!strncmp(str2, str1, len)) X return(str1); X } X str1++; X } X return(NULL); X} X#endif /* STRSTR */ SHAR_EOF if test 2108 -ne "`wc -c < 'waitfor.c'`" then echo shar: "error transmitting 'waitfor.c'" '(should have been 2108 characters)' fi fi echo shar: "extracting 'x_ascii.c'" '(6450 characters)' if test -f 'x_ascii.c' then echo shar: "will not over-write existing file 'x_ascii.c'" else sed 's/^X//' << \SHAR_EOF > 'x_ascii.c' X/* X * Transfer a file using just XON/XOFF flow control. Currently limited to X * 7 bit ASCII codes. (If this causes too much trouble, I'll change it). X */ X X#include <stdio.h> X#include <curses.h> X#include <signal.h> X#include "config.h" X#include "misc.h" X#include "param.h" X X#ifdef BSD X#include <setjmp.h> Xjmp_buf bl_buf; X#endif /* BSD */ X Xvoid Xxfer_ascii(list, up) Xchar *list; Xint up; X{ X int cr_lf; X char *file, *strtok(); X void send_ascii(), rcv_ascii(), line_set(), st_line(), suspend(); X void load_vs(), ascii_mode(), input_off(), term_mode(); X unsigned int sleep(); X X touchwin(stdscr); X refresh(); X /* only one file from list */ X file = strtok(list, " \t"); X X cr_lf = !strcmp(param->cr_out, "CR/LF"); X ascii_mode(up); X /* out of curses mode */ X resetterm(); X term_mode(); X tty_noblock(0, TRUE); X X if (up) { X /* un-suspend the input routine */ X suspend(FALSE); X send_ascii(file, cr_lf); X suspend(TRUE); X } X else { X input_off(); X rcv_ascii(file, cr_lf); X } X X /* X * Restoring the TTY modes is easier than setting them... The X * fixterm() and line_set() routines fix most of the damage. X */ X line_set(); X fixterm(); X tty_noblock(0, FALSE); X X /* X * On downloading, the contents of the virtual screen won't contain X * the characters shown during the transfer. Too bad... X */ X load_vs(); X beep(); X st_line("xfer complete"); X X sleep(2); X return; X} X X/* X * Send a file. The local echo option is independent of the duplex option, X * and would very rarely be used since the characters are most likely X * being echoed on the screen anyway. X */ X Xstatic void Xsend_ascii(file, cr_lf) Xchar *file; Xint cr_lf; X{ X extern int fd; X FILE *fp, *my_fopen(); X int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, lecho, pace; X char buf[80]; X unsigned char c, last; X unsigned int sleep(); X void error_win(); X /* permission already checked */ X if (!(fp = my_fopen(file, "r"))) { X sprintf(buf, "\"%s\"", file); X error_win(0, "Can't open file for read", buf); X return; X } X /* ASCII transfer options */ X strip_cr = !strcmp(param->cr_up, "STRIP"); X add_lf = !strcmp(param->cr_up, "ADD LF"); X strip_lf = !strcmp(param->lf_up, "STRIP"); X add_cr = !strcmp(param->lf_up, "ADD CR"); X expand = !strcmp(param->expand, "YES"); X lecho = !strcmp(param->lecho, "YES"); X pace = !strcmp(param->pace, "YES"); X X last = 0; X while ((i = fgetc(fp)) != EOF) { X /* any keyboard activity? */ X switch (j = getchar()) { X case -1: /* no key was pressed */ X break; X case ESC: /* <ESC> key for abort */ X fclose(fp); X sleep(2); X tty_drain(fd); X return; X default: /* send the char */ X c = j; X putc_line(c); X if (c == '\r' && cr_lf) X putc_line('\n'); X break; X } X c = i & 0x7f; X /* expand blank lines */ X if (expand && last == '\n' && c == '\n') X putc_line(' '); X last = c; X X /* CR translations */ X if (c == '\r' && strip_cr) X continue; X if (c == '\r' && add_lf) { X putc_line(c); X putc_line('\n'); X continue; X } X /* LF translations */ X if (c == '\n' && strip_lf) X continue; X if (c == '\n' && add_cr) { X putc_line('\r'); X putc_line(c); X continue; X } X putc_line(c); X /* X * There's really no mechanism for delaying characters X * going to the output, so we fake it by waiting for X * each character to clear the I/O buffer. X */ X if (pace) X tty_drain(fd); X if (lecho) { X putchar((char) c); X fflush(stdout); X } X } X fclose(fp); X sleep(2); X tty_drain(fd); X return; X} X X/* X * Receive a file. The timer is used to end the transfer. This is not X * that much different from the data logging option. The use of bgetc_line() X * and non-blocking input makes it seem like full duplex, but it's not. X * Be aware that while the timer is active the keyboard is deaf. Input is X * NOT loaded into the virtual screen!! X */ X Xstatic void Xrcv_ascii(file, cr_lf) Xchar *file; Xint cr_lf; X{ X FILE *fp, *my_fopen(); X int i, strip_cr, strip_lf, add_cr, add_lf, got_first; X unsigned int delay; X char c, buf[80]; X void error_win(); X /* permission already checked */ X if (!(fp = my_fopen(file, "w"))) { X sprintf(buf, "\"%s\"", file); X error_win(0, "Can't open file for write", buf); X return; X } X /* ASCII transfer options */ X strip_cr = !strcmp(param->cr_dn, "STRIP"); X add_lf = !strcmp(param->cr_dn, "ADD LF"); X strip_lf = !strcmp(param->lf_dn, "STRIP"); X add_cr = !strcmp(param->lf_dn, "ADD CR"); X X got_first = 0; X delay = 1; X while (1) { X /* keyboard activity */ X switch (i = getchar()) { X case -1: /* no key was pressed */ X break; X case ESC: /* <ESC> key */ X fclose(fp); X return; X default: /* send it */ X c = i; X putc_line((unsigned char) c); X if (c == '\r' && cr_lf) X putc_line('\n'); X break; X } X /* read a character */ X if ((i = bgetc_line(delay)) == -1) { X /* X * The transfer timeout is not activated until the X * first character is received. Until then, it polls X * the line for one second and loops backs for X * keyboard input. X */ X if (got_first) { X fclose(fp); X return; X } X continue; X } X got_first = 1; X delay = param->timer; X c = i & 0x7f; X /* display it on the screen */ X putchar(c); X fflush(stdout); X /* CR translations */ X if (c == '\r' && strip_cr) X continue; X if (c == '\r' && add_lf) { X fputc(c, fp); X fputc('\n', fp); X continue; X } X /* LF translations */ X if (c == '\n' && strip_lf) X continue; X if (c == '\n' && add_cr) { X fputc('\r', fp); X fputc(c, fp); X continue; X } X fputc(c, fp); X } X} X X/* X * Get a character from the line (using buffered I/O) with a specified X * time-out period in seconds. If the function times-out, it returns a -1. X */ X Xstatic int bl_flag; X Xstatic int Xbgetc_line(sec) Xunsigned int sec; X{ X int c, bl_force(); X unsigned int alarm(); X X signal(SIGALRM, bl_force); X bl_flag = 0; X X alarm(sec); X X#ifdef BSD X if (setjmp(bl_buf)) X return(-1); X#endif /* BSD */ X X if ((c = buf_read()) < 0) { X alarm(0); X return(-1); X } X if (bl_flag) X return(-1); X alarm(0); X return(c); X} X X/* ARGSUSED */ Xstatic int Xbl_force(dummy) Xint dummy; X{ X#ifdef BSD X longjmp(bl_buf, 1); X#else /* BSD */ X signal(SIGALRM, bl_force); X bl_flag = 1; X#endif /* BSD */ X} X X/* X * Do a single character buffered read from the serial port. X */ X Xstatic int Xbuf_read() X{ X extern int fd; X static char buf[CLIST_SIZ]; X static char *bufp = buf; X static int n = 0; X X if (n <= 0) { X n = read(fd, buf, CLIST_SIZ); X bufp = buf; X } X if (--n >= 0) X return(*bufp++ & 0xff); X return(-1); X} SHAR_EOF if test 6450 -ne "`wc -c < 'x_ascii.c'`" then echo shar: "error transmitting 'x_ascii.c'" '(should have been 6450 characters)' fi fi echo shar: "extracting 'x_batch.c'" '(8686 characters)' if test -f 'x_batch.c' then echo shar: "will not over-write existing file 'x_batch.c'" else sed 's/^X//' << \SHAR_EOF > 'x_batch.c' X/* X * Routines to support the batch protocols. X */ X X#include <stdio.h> X#include <ctype.h> X#include <curses.h> X#include "config.h" X#include "misc.h" X#include "xmodem.h" X X/* X * Send the file name for the modem7 batch. Only uses 11 characters X * of the filename. Returns zero on success or the standard error codes. X */ X Xint Xsend_modem7(win, name) XWINDOW *win; Xchar *name; X{ X char *new_name, *fix_name(); X unsigned char sum, calc_sum(); X X /* convert to 11 character name */ X new_name = fix_name(name); X sum = calc_sum((unsigned char *) new_name, 12); X X putc_line(ACK); X /* for each character in the name */ X while (*new_name != CTRLZ) { X putc_line((unsigned char) *new_name); X X switch (getc_line(3)) { X case -1: /* timed out */ X clear_line(win, 12, 24, TRUE); X waddstr(win, "NO RESPONSE"); X wrefresh(win); X return(ERROR); X case ACK: /* got it! */ X break; X case CAN: /* cancel transmission */ X if (getc_line(2) == CAN) { X beep(); X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "REMOTE ABORTED"); X wrefresh(win); X return(CANCEL); X } X /* fall thru... */ X default: X clear_line(win, 12, 24, TRUE); X waddstr(win, "NAME FAILED"); X wrefresh(win); X return(ERROR); X } X new_name++; X } X putc_line(CTRLZ); X /* verify the checksum */ X if (getc_line(10) != sum) { X putc_line('u'); X clear_line(win, 12, 24, TRUE); X waddstr(win, "CHECKSUM FAILED"); X wrefresh(win); X return(ERROR); X } X putc_line(ACK); X return(0); X} X X/* X * Receive a modem7 file name. Returns zero on success, the standard error X * codes, or a -1 on the end-of-batch. (Oddly enough, the end-of-batch code X * is the same as the code for a user abort) X */ X Xint Xrcv_modem7(win, default_err) XWINDOW *win; Xint default_err; X{ X extern char file_name[15]; X int i, j, err_method, err_count, got_it; X unsigned char sum, calc_sum(); X char temp_name[13]; X void change_name(), unfix_name(); X X err_method = default_err; X if (default_err == CRC_CHECKSUM) X err_method = CRC; X X err_count = 0; X got_it = 0; X while (err_count < MAX_ERRORS) { X /* switch to checksum? */ X if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2) X err_method = CHECKSUM; X X if (err_method == CRC) X putc_line('C'); X else X putc_line(NAK); X /* what'd we get? */ X switch (getc_line(10)) { X case -1: /* timed out */ X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "NO RESPONSE"); X wrefresh(win); X err_count++; X case ACK: /* ready to go... */ X got_it++; X break; X default: /* huh? */ X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "BAD HEADER"); X wrefresh(win); X err_count++; X } X } X if (!got_it) X return(ERROR); X /* get the name */ X for (i=0; i<12; i++) { X j = getc_line(3); X X switch (j) { X case -1: /* timed out */ X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "NO RESPONSE"); X wrefresh(win); X return(ERROR); X case EOT: /* end of batch? */ X return(-1); X case CAN: /* cancel transmission */ X if (getc_line(2) == CAN) { X beep(); X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "REMOTE ABORTED"); X wrefresh(win); X return(CANCEL); X } X /* fall thru... */ X case 'u': /* bad name character */ X beep(); X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "BAD NAME"); X wrefresh(win); X return(ERROR); X default: /* the name... */ X temp_name[i] = j & 0xff; X if (j != CTRLZ) X putc_line(ACK); X break; X } X } X temp_name[12] = '\0'; X /* send our checksum */ X sum = calc_sum((unsigned char *) temp_name, 12); X putc_line(sum); X /* do they agree? */ X if (getc_line(10) != ACK) { X beep(); X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "BAD NAME"); X wrefresh(win); X return(ERROR); X } X /* load the file_name array */ X unfix_name(temp_name); X /* any name collisions? */ X change_name(win, file_name); X return(0); X} X X/* X * Send the block 0 information for a ymodem batch transfer. Uses only X * the name component of the path and the file size. X */ X Xint Xsend_ymodem(win, file, size) XWINDOW *win; Xchar *file; Xlong size; X{ X unsigned short crc, calc_crc(); X char *strcpy(), *memset(); X unsigned char buf[133]; X /* start with a clean block */ X memset(buf, '\0', 133); X /* the header */ X buf[0] = SOH; X buf[1] = 0; X buf[2] = 255; X X /* X * The block zero consists of the file name (no path component), X * a NULL, and the file length (as a string). The end of batch X * marker is an empty block. X */ X if (*file != '\0') { X strcpy((char *) &buf[3], file); X sprintf((char *) &buf[strlen(file)+4], "%ld", size); X } X /* the crc */ X crc = calc_crc(&buf[3], 128); X buf[131] = crc >> 8; X buf[132] = crc; X /* the block count */ X mvwaddstr(win, 7, 24, "0 "); X X return(send_block(win, buf, 133)); X} X X/* X * Receive the block 0 information for a ymodem batch transfer. We X * only use the file name and the size (if present). Currently doesn't X * support full path names. X */ X Xint Xrcv_ymodem(win) XWINDOW *win; X{ X extern unsigned char buf[1029]; X extern long file_length; X extern char file_name[15]; X int code, length_is_at; X long atol(); X X file_length = 0L; X file_name[0] = '\0'; X /* read the zero block */ X if (code = rcv_block(win, 1, 1024, 0)) X return(code); X /* at end of batch */ X if (buf[3] == '\0') X return(0); X /* get the file name */ X change_name(win, (char *) &buf[3]); X /* any trouble? */ X if (file_name[0] == '\0') { X putc_line(CAN); X return(0); X } X /* X * The file length is placed after the NULL of the file name X * and is terminated by another NULL. If the length is missing, X * atol() will see a NULL and return 0. X */ X length_is_at = strlen((char *) &buf[3]) + 4; X file_length = atol((char *) &buf[length_is_at]); X return(0); X} X X/* X * Handle file name collisions. Prepend an "X" to the name until you find X * a name that doesn't already exist. Creates a NULL name on error. X * Loads the global character array "file_name". X */ X Xvoid Xchange_name(win, str) XWINDOW *win; Xchar *str; X{ X extern char file_name[15]; X register int i; X int modified; X char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat(); X unsigned int sleep(); X /* dissect the name component */ X if ((s = strrchr(str, '/'))) X strcpy(temp, ++s); X else X strcpy(temp, str); X X strcpy(ans, temp); X file_name[0] = '\0'; X /* write permission on directory? */ X if (access(".", 2)) { X beep(); X clear_line(win, 12, 24, TRUE); X wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY"); X wrefresh(win); X return; X } X /* prepend up to 13 "X"s */ X modified = 0; X for (i=1; i<14; i++) { X if (access(ans, 0)) { X if (modified) { X beep(); X clear_line(win, 12, 24, TRUE); X waddstr(win, "NAME COLLISION"); X wrefresh(win); X sleep(1); X } X strcpy(file_name, ans); X return; X } X X modified++; X strcpy(temp, "X"); X strncat(temp, ans, 13); X temp[14] = '\0'; X strcpy(ans, temp); X } X beep(); X clear_line(win, 12, 24, TRUE); X waddstr(win, "BAD NAME"); X wrefresh(win); X return; X} X X/* X * Convert a perfectly good Unix file name to fit the CP/M file name X * rules. Used for the modem7 batch file transfer. Returns a pointer X * to a static area containing the new name. X */ X Xchar * Xfix_name(path) Xchar *path; X{ X int dot; X char *s, *name, temp[15], *ext, *strcpy(), *strrchr(); X static char ans[13]; X /* ignore the path component */ X if (s = strrchr(path, '/')) X strcpy(temp, ++s); X else X strcpy(temp, path); X name = temp; X X ext = ""; X dot = 0; X for (s=name; *s; ++s) { X if (*s == '.' && !dot) { X dot++; X *s = '\0'; X ext = s + 1; X } X if (islower(*s)) X *s = toupper(*s); X } X /* if null name component */ X if (*name == '\0') X name = "X"; X /* if name too long */ X if (strlen(name) > 8) X *(name+8) = '\0'; X /* if extension too long */ X if (strlen(ext) > 3) X *(ext+3) = '\0'; X X sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ); X return(ans); X} X X/* X * Convert a CP/M style filename into a legal Unix file name. Loads the X * global character array "file_name". X */ X Xvoid Xunfix_name(cpm_name) Xchar *cpm_name; X{ X extern char file_name[15]; X register int i, n; X int dot; X char temp[15]; X X file_name[0] = '\0'; X if (*cpm_name == '\0') X return; X X strcpy(temp, cpm_name); X /* 8 character of the name */ X n = 0; X for (i=0; i<8; i++) { X if (temp[i] != ' ') { X if (isupper(temp[i])) X file_name[n++] = tolower(temp[i]); X else X file_name[n++] = temp[i]; X } X } X /* 3 character extension */ X dot = 0; X for (i=8; i<11; i++) { X if (temp[i] != ' ') { X if (!dot) { X dot++; X file_name[n++] = '.'; X } X if (isupper(temp[i])) X file_name[n++] = tolower(temp[i]); X else X file_name[n++] = temp[i]; X } X } X file_name[n] = '\0'; X return; X} SHAR_EOF if test 8686 -ne "`wc -c < 'x_batch.c'`" then echo shar: "error transmitting 'x_batch.c'" '(should have been 8686 characters)' fi fi echo shar: "extracting 'x_extrnl.c'" '(2965 characters)' if test -f 'x_extrnl.c' then echo shar: "will not over-write existing file 'x_extrnl.c'" else sed 's/^X//' << \SHAR_EOF > 'x_extrnl.c' X/* X * Spawn a shell with the stdin and stdout swapped with the remote X * system, ie: X * +----------+ X * TTYin ------------> stdin | | X * | shell | X * TTYout <---------- stdout | | X * +----------+ X * X * An undocumented feature: The external protocol gateway X * can be used to pipe the output of a normal Unix command to the X * remote system. X */ X X#include <stdio.h> X#include <signal.h> X#include <curses.h> X#include <errno.h> X#include "config.h" X X#ifdef BSD X#include <sys/file.h> X#else /* BSD */ X#include <fcntl.h> X#endif /* BSD */ X Xvoid Xdo_extrnl(cmd) Xchar *cmd; X{ X extern int fd, errno; X WINDOW *xt_win, *newwin(); X SIG_TYPE (*istat)(), (*qstat)(); X int epid, want_out, sig_status; X char buf[80], *ttyname(), *strcpy(); X unsigned int sleep(); X void _exit(), input_off(); X X input_off(); X /* a full window */ X xt_win = newwin(LINES, COLS, 0, 0); X touchwin(xt_win); X wrefresh(xt_win); X /* out of curses mode */ X resetterm(); X X if (!(epid = fork())) { X /* create a new process group ID */ X#ifdef BSD X setpgrp(0, getpid()); X#else /* BSD */ X setpgrp(); X#endif /* BSD */ X /* recreate the device name */ X strcpy(buf, ttyname(fd)); X close(fd); X /* swap the stdin */ X close(0); X#ifdef UNIXPC X/* X * Some strange things here... The OBM uses the second parameter of X * open() to determine if the port should be in the DATA mode or X * the VOICE mode. Therefore, we must always open with read and write. X */ X if (!strncmp(buf, "/dev/ph", 7)) X open(buf, O_RDWR); X else X#endif /* UNIXPC */ X open(buf, O_RDONLY); X /* swap the stdout */ X close(1); X#ifdef UNIXPC X if (!strncmp(buf, "/dev/ph", 7)) X open(buf, O_RDWR); X else X#endif /* UNIXPC */ X open(buf, O_WRONLY); X#ifdef SETUGID X setgid(getgid()); X setuid(getuid()); X#endif /* SETUGID */ X execl("/bin/sh", "sh", "-c", cmd, (char *) 0); X _exit(1); X } X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X X /* X * Check the keyboard while the external program is running. If X * the user hits the <ESC> key, then kill the entire process X * group associated with the new shell. X */ X want_out = 0; X while(1) { X switch(wait_key(stdscr, 1)) { X case -1: /* timed out */ X break; X case 27: /* a user abort */ X#ifdef BSD X killpg(epid, SIGKILL); X#else /* BSD */ X kill(-epid, SIGKILL); X#endif /* BSD */ X want_out++; X break; X default: X beep(); X break; X } X if (want_out) X break; X /* see if the process it still active */ X#ifdef BSD X if ((kill(epid, 0) == -1) && errno == ESRCH) X#else /* BSD */ X if ((kill(-epid, 0) == -1) && errno == ESRCH) X#endif /* BSD */ X break; X } X /* wait for the zombie process */ X wait(&sig_status); X X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X /* back to curses mode */ X sleep(1); X fixterm(); X X clearok(curscr, TRUE); X werase(xt_win); X wrefresh(xt_win); X delwin(xt_win); X return; X} SHAR_EOF if test 2965 -ne "`wc -c < 'x_extrnl.c'`" then echo shar: "error transmitting 'x_extrnl.c'" '(should have been 2965 characters)' fi fi exit 0 # End of shell archive -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.