Thread View: de.comp.sources.unix
1 messages
1 total messages
Started by Frank Kaefer
Wed, 22 Jul 1992 05:04
v01i005: Pcomm 2.0 - telecommunication program for Unix, Part05/08
Author: Frank Kaefer
Date: Wed, 22 Jul 1992 05:04
Date: Wed, 22 Jul 1992 05:04
3224 lines
86685 bytes
86685 bytes
Submitted-by: egray@osiris.cso.uiuc.edu (Emmet P. Gray)
Posting-number: Volume 1, Issue 5
Archive-name: pcomm/part05
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 5 (of 8)."
# Contents: pcomm-2.0/Release.notes pcomm-2.0/di_win.c
# pcomm-2.0/m_lib.c pcomm-2.0/main.c pcomm-2.0/vcs.c
# pcomm-2.0/x_rcv.c pcomm-2.0/x_send.c
# Wrapped by fkk@stasys on Tue Jul 21 22:06:00 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'pcomm-2.0/Release.notes' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/Release.notes'\"
else
echo shar: Extracting \"'pcomm-2.0/Release.notes'\" \(10747 characters\)
sed "s/^X//" >'pcomm-2.0/Release.notes' <<'END_OF_FILE'
X Pcomm version 2.0
X 18 Jul 92
X
XCompatibilities with v1.2:
X
X The pcomm.modem and pcomm.param support files under v1.2 are not
X compatible with the new release. There is a shell script called
X Convert.sh that will convert these files to the new format.
X
X The Script/TTY field of the dialing directory is now called
X the Auxiliary field. It now has three functions...
X 1) to specify a script to be played
X 2) to force a particular TTY to be selected
X 3) to select a modem configuration
X
XThings that have changed:
X
X This version of Pcomm requires a pseudo-tty driver and System V
X poll() or Berkeley select(). Pre-SRV3.2 versions of AT&T Unix
X are out-of-luck... sorry.
X
X There is a shell script called Configure.sh that will help you
X to configure Pcomm correctly for your system. I've added a
X Q_and_A file to provide help on diagnosing problems.
X
X There is no longer a "pcomm_input" program, those functions are
X now supported by the use of multiplexed I/O within the "pcomm"
X program. The external "modem_break" command has been removed.
X You might want to "search and destroy" those binaries.
X
X A new external command called "pcomm_cmd" has been added to
X allow "true" scripting capabilities. There is a manual page for
X pcomm_cmd that further describes its features.
X
X Each dialing directory entry can specify a modem configuration
X via the newly renamed Auxiliary field. This allows you to
X tailor the modem to match what is expected at the other end of
X the connection.
X
X Pcomm now supports DTE baud rates up to 38400 plus the odd-ball
X "connected" baud rates for V.32bis (7200, 12000, and 14400).
X
XFuture directions:
X
X Add zmodem as an internal protocol, since Omen Technologies
X deliberately broke sz/rz so that it wouldn't work from inside
X another program.
X
X Add the ability to "dial into" a machine via a network LAN
X rather than the serial port.
X
X xpcomm - a version of Pcomm using the X window toolkits.
X
X-------------------------------------------------------------------------------
X
X Pcomm version 1.2
X 4 Feb 89
X
XCompatibilities with v1.1:
X
X The support files used with the v1.1 release are compatible with
X the v1.2 release. However, the use of the "index" field (now
X called the "script" field) in the pcomm.dial_dir file has
X changed dramatically (see below).
X
XThings that have changed:
X
X Berkeley flavors of Unix are now supported. There are files
X called tty_att.c and tty_ucb.c that contain the code specific
X to the AT&T and Berkeley worlds. See the config.h file for
X the BSD pre-processor definition.
X
X Auto-login scripts are now supported. If the script field of
X the dialing directory contains the name of a valid Unix shell
X script, that shell script is "played" after the connection is
X made to perform the auto-login "chat" sequences. A example of a
X auto-login Bourne shell script (called Sample) is included in
X the distribution.
X
X Three new external programs. In order to assist in the creation
X of the auto-login shell scripts, three external programs are
X included in the distribution.
X
X waitfor - wait for a string, return a 1 if timed out
X matches - test if string2 is contained in string1
X modem_break - send a modem break
X
X There is a new support file called "pcomm.extrnl" that allows
X the user to embed the names of external file transfer programs
X into the list of available protocols. (The default file
X "Pcomm.extrnl", supplied with the distribution package, contains
X definitions for zmodem).
X
X The pcomm_input program has been changed to use multiple
X character buffered writes to the screen. Both the input and
X output buffer sizes are tunable parameters in config.h
X
X Newer versions of Xenix have changed the rules for creating UUCP
X lock files. See the config.h file for the description of
X XENIX_LOCKS.
X
X The -f option now looks at the name field of the dialing
X directory (rather than the index field). A match is found when
X the argument to the -f is contained in a name field (an exact
X match is not required). The match does not consider upper and
X lower case differences as significant.
X
XKnown limitations:
X
X The detection of VCS (video command sequences) is still limited
X to a very small subset of possible commands.
X
X For the VCS emulation to work, the terminfo entries on the host
X machine must match the entries on the remote. (Don't assume
X your vt100 terminfo data is identical to someone else's).
X
X The disp_tty() routine in s_tty.c currently does not support a
X NUM_TTY definition of greater than 10.
X
XFuture directions:
X
X That's about it folks...
X
X If Pcomm grows any more, I'll break the setup routines out as a
X separate program.
X
XMany thanks to the following people (and many others) for bug reports
Xand suggested improvements to the code.
X
X Andy Fyfe ...ames!elroy!cit-vax!andy
X Brian Antoine ...iscuva!tau-ceti!briana
X Chad R. Larson ...ncar!noao!nud!anasaz!dcfinc!chad
X David MacKenzie ...uunet!rocky2.rockefeller.edu!edf
X Gary S. Trujillo ...{linus,bbn,m2c}!spdcc!gnosys!gst
X George Pontis ...uunet!moldev!geo
X J. Eric Townsend ...uunet!nuchat!flatline!erict
X Jim Pickering ...csun!polyslo!rducky!jrp
X Jim Sanchez ...uunet!mcvax!syteke!jim
X Jonathan Bayer ...uunet!ispi!jbayer
X MAJ Dave Dockstader ...twsc4sac@mater1.arpa
X Michael Brady ...sun!portal!cup.portal.com!michealnc
X
X-------------------------------------------------------------------------------
X
X Pcomm version 1.1
X 21 Aug 88
X
XIncompatibilities with v1.0:
X
X I've added a few more fields to the pcomm.param and pcomm.modem
X files. This means that those files created under previous
X releases will not be compatible with the v1.1 release. It might
X be a good idea to abandon the older files and start over with
X the sample files in this release.
X
XThings that have changed:
X
X An awful lot of sloppy programming on my part has now been
X cleaned up. This means that porting Pcomm to different versions
X of Unix will be considerably less painful than before.
X
X All of the tunable parameters are now in "config.h".
X
X Pcomm now uses buffered I/O routines. This yields higher
X performance I/O at large baud rates.
X
X File transfers now use high performance CRC calculations.
X
X If a UUCP lockfile does exist, Pcomm now attempts to determine
X if the process is still active.
X
X An external file transfer program can be invoked from the file
X transfer menu.
X
X The keyboard macro feature is now supported (although it is
X rather crude).
X
X The virtual screen routine now understands a limited subset of
X escape sequences.
X
X The virtual screen can now be held in shared memory or in a file.
X
X The input routine is now contained in a separate program called
X pcomm_input.
X
X You can now include a "modem break" in a dial or initialization
X string.
X
X A separate "initialization speed" feature was added to support
X 9600 baud modems such as the Telebit Trailblazer. See Appendix
X C of the Doc file for more info on the use of this feature.
X
X I've added a transparent pass through mode to be used in a
X communications daisy chain.
X
XKnown limitations:
X
X Whenever Pcomm makes the transition from the terminal mode to
X the command mode, the true screen contents are lost. Pcomm
X tries to keep track of what the true screen looks like in an
X internal "virtual screen". This means that the escape sequences
X known to the hardware have to be emulated in the virtual screen.
X Unfortunately, the number of escape sequences that are emulated
X is quite small, so the representation of the true screen is
X sometimes wrong.
X
X For the VCS (video command sequence) emulation to work, the
X terminfo entries on the host machine must match the entries on
X the remote.
X
X The disp_tty() routine in s_tty.c currently does not support a
X NUM_TTY definition of greater than 10.
X
XFuture directions:
X
X Continue work on the virtual screen routines.
X
X Add dial back support.
X
X Use shared memory to overcome the current limitation of outgoing
X characters in the half duplex mode not appearing in the virtual
X screen, log files, and print logs.
X
XMany thanks to the following people for bug reports and ideas for
Ximproving the code:
X
X Andy Pitts ...{mtune,pacbell,kd4nc}!gladys!rbdc!andy
X Chris Wiener ...ihnp4!{killer,attnssc}!crlabs!cwiener
X David Brierley ...{sun,decuac,cbosgd,gatech,necntc,ukma}!rayssd!dhb
X Karl Fox ...cbosgd!mstar!karl
X Michael Young ...panda!genrad!mrst!sdti!mjy
X Mark Mendel ...ihnp4!umn-cs!hyper!mark
X Viet Hoang ...ihnp4!drutx!vgh
X
X--------------------------------------------------------------------------------
X
X Pcomm version 1.0
X 12 Mar 88
X
XIncompatibilities with the beta release:
X
X I've added a bunch of new parameters to the pcomm.param and
X pcomm.modem files, so the files used with the beta release won't
X work with the v1.0 release.
X
XThings that have changed:
X
X Pcomm will attempt to determine if the modem has synchronized at
X a baud rate different than what is expected, and make changes to
X the line settings as appropriate.
X
X The quit and interrupt signals are now ignored.
X
X All of the file transfer protocols are now functional.
X
X The directory search order used to find the support files has
X been changed slightly.
X
XKnown limitations:
X
X The keyboard macro feature is not implemented at this time.
X
X The true screen contents are lost when the "hot key" is pressed.
X Pcomm attempts to compensate (rather poorly) by repainting a
X virtual screen of what it thinks the true screen should look
X like. Escape sequences in the virtual screen image will be
X ignored when the background is repainted. For example, if
X you're on a vt100 and you receive a ^[[2J to clear the screen,
X the screen *will* be cleared... but when the screen is
X repainted, it will contain the characters ^[, [, 2, J (instead
X of performing the function).
X
X The disp_tty() routine in s_tty.c currently does not support a
X NUM_TTY definition of greater than 10.
X
X For some strange reason, the first keystroke is "lost" after a
X file transfer is complete or after starting data logging.
X
XFuture directions:
X
X The virtual screen routines need a lot of work. The most
X commonly used escape sequences (known to terminfo) will be
X processed.
X
X I plan to have an option at compile time to have the virtual
X screen buffer held on disk [] or in shared memory [].
X
X The input routine is designed so it could be a standalone
X program that gets called from Pcomm. []
X
X-------------------------------------------------------------------------------
X
XHave fun...
X
XEmmet P. Gray US Army, HQ III Corps & Fort Hood
X...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
Xfthood!egray@uxc.cso.uiuc.edu Directorate of Engineering & Housing
X Environmental Management Office
X Fort Hood, TX 76544-5057
END_OF_FILE
if test 10747 -ne `wc -c <'pcomm-2.0/Release.notes'`; then
echo shar: \"'pcomm-2.0/Release.notes'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/Release.notes'
fi
if test -f 'pcomm-2.0/di_win.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/di_win.c'\"
else
echo shar: Extracting \"'pcomm-2.0/di_win.c'\" \(9781 characters\)
sed "s/^X//" >'pcomm-2.0/di_win.c' <<'END_OF_FILE'
X/*
X * The dialing window routines.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
Xstatic int can_sync();
Xstatic void disp_queue();
X
X/*
X * The dialing window. Its job is to get a port, cycle thru the entries
X * in the queue, while interpreting both the user's requests and the
X * modem's responses. A non-zero return code means we failed to connect.
X */
X
Xint
Xdial_win(repeat)
Xint repeat;
X{
X extern int fd;
X WINDOW *di_win, *newwin();
X int i, j, key, want_out, pass, tic;
X long now, time();
X char *tbuf, *ctime(), *str, cr=13, *read_codes();
X void dial_it(), delay_times();
X void error_win(), line_set(), hang_up(), vs_clear(), log_calls();
X unsigned int baud, sleep();
X /* are we already talking? */
X hang_up(VERBOSE);
X
X touchwin(stdscr);
X refresh();
X
X /*
X * If the phone number points to NULL, then either you're on a
X * direct line, or you want to do the dialing yourself.
X */
X dir->d_cur = dir->q_num[0];
X if (*dir->number[dir->d_cur] == '\0') {
X /* check LD permission */
X if (limit_ld(0))
X return(1);
X
X if (get_port())
X return(1);
X /* can't talk directly to OBM */
X if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X error_win(0, "Can't access the On Board Modem directly",
X "You must use the automatic dialing feature");
X return(1);
X }
X
X vs_clear(1);
X touchwin(stdscr);
X clear();
X printw("Connected to /dev/%s at %d baud...\n", modem->tty[modem->t_cur], dir->baud[0]);
X refresh();
X /* We have to assume... */
X status->connected = 1;
X return(0);
X }
X
X di_win = newwin(17, 70, 3, 5);
X /* the basic window */
X mvwattrstr(di_win, 1, 20, A_BOLD, "D I A L I N G W I N D O W");
X horizontal(di_win, 2, 0, 70);
X mvwaddstr(di_win, 4, 23, "System name:");
X mvwaddstr(di_win, 5, 23, "Pass number:");
X mvwaddstr(di_win, 6, 14, "Elapse time this try:");
X mvwaddstr(di_win, 7, 13, "Time at start of dial:");
X mvwaddstr(di_win, 8, 9, "Time at start of this try:");
X mvwaddstr(di_win, 9, 16, "Connect delay time:");
X mvwaddstr(di_win, 10, 17, "Redial delay time:");
X mvwaddstr(di_win, 11, 25, "Auxiliary:");
X mvwaddstr(di_win, 12, 16, "Result of last try:");
X
X mvwaddstr(di_win, 14, 3, "<SPACE>: Recycle");
X mvwaddstr(di_win, 14, 22, "<DEL>: Remove from queue");
X mvwaddstr(di_win, 14, 49, "E: Change delays");
X
X /* the start time */
X time(&now);
X tbuf = ctime(&now);
X tbuf[19] = '\0';
X mvwaddstr(di_win, 7, 36, &tbuf[11]);
X
X mvwprintw(di_win, 9, 36, "%-4d", param->c_delay);
X mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
X
X box(di_win, VERT, HORZ);
X mvwaddstr(di_win, 16, 24, " Press <ESC> to abort ");
X
X pass = 0;
X i = 0;
X want_out = 0;
X while (!want_out && pass <= repeat) {
X key = -1;
X pass++;
X /* check LD permission */
X if (limit_ld(i)) {
X want_out++;
X break;
X }
X /* update the d_cur variable */
X dir->d_cur = dir->q_num[i];
X
X /* get a port */
X if (get_port()) {
X want_out++;
X break;
X }
X /* fill in the window */
X disp_queue(di_win, dir->d_cur, pass, now);
X now = 0L;
X
X /*
X * The actual dial routine. The "i" is the index into the
X * queue, not the entry number. Returns immediately without
X * waiting for a carrier.
X */
X dial_it(i);
X tty_flush(fd, 0);
X
X /*
X * Here we do a time-slice between reading the result codes
X * from the modem and reading the keyboard. The one second
X * granularity won't be too accurate, but who cares?
X */
X tic = 0;
X while (tic < param->c_delay) {
X if ((str = read_codes(tic)) == NULL) {
X mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X wrefresh(di_win);
X }
X else {
X /*
X * A return code that converts to an number
X * that is less than 300 is probably an error
X * message.
X */
X baud = (unsigned int) atoi(str);
X if (baud < 300) {
X mvwprintw(di_win, 12, 36, "%-20.20s", str);
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X break;
X }
X /* we're connected */
X beep();
X clear_line(di_win, 12, 36, TRUE);
X wattrstr(di_win, A_BLINK, "CONNECTED");
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X wait_key(di_win, 2);
X delwin(di_win);
X
X /*
X * Did the modem sync at a different baud
X * rate than what we expected?
X */
X if (dir->baud[0] != baud) {
X if (can_sync(baud)) {
X dir->baud[0] = baud;
X line_set();
X }
X }
X
X vs_clear(1);
X touchwin(stdscr);
X clear();
X printw("Connected to %s at %d baud...\n",
X dir->name[dir->d_cur], dir->baud[0]);
X refresh();
X status->connected = 1;
X
X /* log the call */
X log_calls(i);
X return(0);
X }
X if (tic == param->c_delay)
X break;
X /* ok... try the keyboard */
X if ((key = wait_key(di_win, 1)) != -1)
X break;
X
X mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X wrefresh(di_win);
X }
X /*
X * If the modem did not return a code, then we need to
X * stop it. Sending a CR will stop most modems cold,
X * except of course for the OBM...
X */
X if (str == NULL) {
X if (!strcmp(modem->mname[modem->m_cur], "OBM"))
X hang_up(QUIET);
X else
X write(fd, &cr, 1);
X sleep(2);
X }
X /* if we get here, no key was pressed */
X if (key == -1) {
X clear_line(di_win, 6, 14, TRUE);
X mvwaddstr(di_win, 6, 27, "Pausing:");
X /* no return code? */
X if (str == NULL) {
X clear_line(di_win, 12, 36, TRUE);
X waddstr(di_win, "TIMED OUT");
X wmove(di_win, 12, 36);
X }
X /* do the pause */
X tic = 0;
X while (tic < param->r_delay) {
X if ((key = wait_key(di_win, 1)) != -1)
X break;
X mvwprintw(di_win, 6, 36, "%-4d", ++tic);
X wrefresh(di_win);
X }
X clear_line(di_win, 6, 14, TRUE);
X waddstr(di_win, "Elapse time this try:");
X }
X mvwaddstr(di_win, 6, 36, "0 ");
X /* Process the keystroke */
X switch (key) {
X case ' ': /* next in the queue */
X clear_line(di_win, 12, 36, TRUE);
X waddstr(di_win, "RECYCLED");
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X /* FALLTHRU */
X case -1: /* no key was pressed */
X i++;
X if (i > NUM_QUEUE)
X i = 0;
X if (dir->q_num[i] == -1)
X i = 0;
X break;
X case DEL: /* <DEL> key, remove from queue */
X if (dir->q_num[1] == -1) {
X beep();
X clear_line(di_win, 12, 36, TRUE);
X waddstr(di_win, "NO MORE ENTRIES");
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X wait_key(di_win, 3);
X break;
X }
X clear_line(di_win, 12, 36, TRUE);
X waddstr(di_win, "ENTRY DELETED");
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X wait_key(di_win, 3);
X
X /* compact the queue */
X for (j=i; j<NUM_QUEUE-1; j++)
X dir->q_num[j] = dir->q_num[j+1];
X dir->q_num[NUM_QUEUE-1] = -1;
X
X if (dir->q_num[i] == -1)
X i = 0;
X break;
X case 'e':
X case 'E': /* change delay time */
X delay_times();
X touchwin(di_win);
X mvwprintw(di_win, 9, 36, "%-4d", param->c_delay);
X mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
X break;
X case ESC: /* <ESC> key */
X beep();
X clear_line(di_win, 12, 36, TRUE);
X wattrstr(di_win, A_BLINK, "DIAL ABORTED");
X wmove(di_win, 12, 36);
X wrefresh(di_win);
X wait_key(di_win, 3);
X want_out++;
X break;
X default:
X beep();
X break;
X }
X }
X /* clean up and go home */
X werase(di_win);
X wrefresh(di_win);
X delwin(di_win);
X if (!want_out)
X error_win(0, "Exceeded the maximum number of dialing attempts", "");
X return(1);
X}
X
X/*
X * Display what info we know at this time.
X */
X
Xstatic void
Xdisp_queue(win, entry, pass, first)
XWINDOW *win;
Xint entry, pass;
Xlong first;
X{
X long now, time();
X char *tbuf, *ctime();
X void st_line();
X /* redo the status line */
X st_line("");
X /* system name */
X clear_line(win, 4, 36, TRUE);
X waddstr(win, dir->name[entry]);
X /* pass number */
X mvwprintw(win, 5, 36, "%-4d", pass);
X /* time of this call */
X if (first)
X now = first;
X else
X time(&now);
X
X tbuf = ctime(&now);
X tbuf[19] = '\0';
X mvwaddstr(win, 8, 36, &tbuf[11]);
X /* the aux field */
X clear_line(win, 11, 36, TRUE);
X waddstr(win, dir->aux[entry]);
X
X wmove(win, 12, 36);
X wrefresh(win);
X return;
X}
X
X/*
X * Determine if the modem can detect the synchronization of the connected
X * baud rate. We check the modem database and see if the connect string
X * is unique. A non-zero return code means the modem can sync.
X */
X
Xstatic int
Xcan_sync(baud)
Xunsigned int baud;
X{
X int i;
X char *str;
X /* feature disabled? */
X if (modem->auto_baud[modem->m_cur] != 'Y')
X return(0);
X /* re-construct the string */
X switch (baud) {
X case 300:
X str = modem->con_3[modem->m_cur];
X break;
X case 1200:
X str = modem->con_12[modem->m_cur];
X break;
X case 2400:
X str = modem->con_24[modem->m_cur];
X break;
X case 4800:
X str = modem->con_48[modem->m_cur];
X break;
X case 7200: /* not really the DTE speed */
X if (modem->lock_sp[modem->t_cur])
X return(1);
X return(0);
X case 9600:
X str = modem->con_96[modem->m_cur];
X break;
X case 12000: /* not really the DTE speed */
X if (modem->lock_sp[modem->t_cur])
X return(1);
X return(0);
X case 14400: /* not really the DTE speed */
X if (modem->lock_sp[modem->t_cur])
X return(1);
X return(0);
X case 19200:
X str = modem->con_192[modem->m_cur];
X break;
X case 38400:
X str = modem->con_384[modem->m_cur];
X break;
X default:
X return(0);
X }
X
X if (*str == '\0')
X return(0);
X /* test "str" against all others */
X i = 0;
X if (!strcmp(str, modem->con_3[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_12[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_24[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_48[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_96[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_192[modem->m_cur]))
X i++;
X if (!strcmp(str, modem->con_384[modem->m_cur]))
X i++;
X /* should match only itself */
X if (i == 1)
X return(1);
X return(0);
X}
END_OF_FILE
if test 9781 -ne `wc -c <'pcomm-2.0/di_win.c'`; then
echo shar: \"'pcomm-2.0/di_win.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/di_win.c'
fi
if test -f 'pcomm-2.0/m_lib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/m_lib.c'\"
else
echo shar: Extracting \"'pcomm-2.0/m_lib.c'\" \(10184 characters\)
sed "s/^X//" >'pcomm-2.0/m_lib.c' <<'END_OF_FILE'
X/*
X * Routines to manipulate the pcomm.modem file
X */
X
X#include <stdio.h>
X#include "modem.h"
X
X/*
X * Read the modem/TTY database file. Returns a pointer to a static area
X * containing the MODEM structure. All modem entries and all TTY entries
X * are created regardless of the number of physical entries in the file.
X */
X
Xstruct MODEM *
Xread_modem()
X{
X extern char *null_ptr;
X FILE *fp, *uid_fopen();
X int i, tty, mod, line, oops, m_line, start, stop;
X char *str_dup(), buf[200], message[80], token[40], *str_tok(), *str;
X char *temp_token, *t_sep, *m_sep, *m_letter, *findfile();
X static struct MODEM m;
X void error_win();
X
X if ((m.m_path = findfile("pcomm.modem")) == NULL)
X error_win(1, "Support file \"pcomm.modem\" is missing", "or no read permission");
X
X if (!(fp = uid_fopen(m.m_path, "r"))) {
X sprintf(buf, "\"%s\" for read", m.m_path);
X error_win(1, "Can't open modem/TTY file", buf);
X }
X
X t_sep = ";;\n";
X m_sep = ";;;;\n;;;;;;;\n;;;\n";
X m_letter = "abc";
X oops = 0;
X tty = 0;
X mod = 0;
X line = 0;
X m_line = 0;
X while (fgets(buf, 200, fp) != NULL) {
X line++;
X if (tty >= NUM_TTY || mod >= NUM_MODEM)
X break;
X /* get the token */
X if (!(temp_token = str_tok(buf, '='))) {
X sprintf(message, "is missing a token at line %d", line);
X oops++;
X break;
X }
X if (*temp_token != 'T' && *temp_token != 'M') {
X sprintf(message, "is corrupted at line %d", line);
X oops++;
X break;
X }
X /* the TTY database */
X if (*temp_token == 'T') {
X /*
X * This is similar to the "real" strtok() command
X * but this one returns a pointer to NULL on a missing
X * token. Note the use of the field separator
X * array.
X */
X for (i=0; i<3; i++) {
X if (!(str = str_tok((char *) NULL, t_sep[i]))) {
X sprintf(message, "is missing a parameter at line %d", line);
X oops++;
X break;
X }
X switch (i) {
X case 0:
X m.tty[tty] = str_dup(str);
X break;
X case 1:
X m.tname[tty] = str_dup(str);
X break;
X case 2:
X m.lock_sp[tty] = atoi(str);
X break;
X }
X }
X if (oops)
X break;
X /* sanity checking */
X sprintf(token, "TTY_%d", tty+1);
X if (strcmp(token, temp_token)) {
X sprintf(message, "is corrupted at line %d", line);
X oops++;
X break;
X }
X tty++;
X continue;
X }
X /* the modem database */
X else {
X sprintf(token, "MODEM_%d%c", mod+1, m_letter[m_line]);
X if (strcmp(token, temp_token)) {
X sprintf(message, "is corrupted at line %d", line);
X oops++;
X break;
X }
X /*
X * There are three lines to the modem database. They
X * are distinguished by the letters a, b, and, c
X * appended to the entry number.
X */
X switch (m_line) {
X case 0:
X start = 0;
X stop = 5;
X break;
X case 1:
X start = 5;
X stop = 13;
X break;
X case 2:
X start = 13;
X stop = 17;
X break;
X }
X for (i=start; i<stop; i++) {
X if (!(str = str_tok((char *) NULL, m_sep[i]))) {
X sprintf(message, "is missing a parameter at line %d", line);
X oops++;
X break;
X }
X switch (i) {
X case 0:
X m.mname[mod] = str_dup(str);
X break;
X case 1:
X m.init[mod] = str_dup(str);
X break;
X case 2:
X m.dial[mod] = str_dup(str);
X break;
X case 3:
X m.suffix[mod] = str_dup(str);
X break;
X case 4:
X m.hang_up[mod] = str_dup(str);
X break;
X case 5:
X m.auto_baud[mod] = *str;
X break;
X case 6:
X m.con_3[mod] = str_dup(str);
X break;
X case 7:
X m.con_12[mod] = str_dup(str);
X break;
X case 8:
X m.con_24[mod] = str_dup(str);
X break;
X case 9:
X m.con_48[mod] = str_dup(str);
X break;
X case 10:
X m.con_96[mod] = str_dup(str);
X break;
X case 11:
X m.con_192[mod] = str_dup(str);
X break;
X case 12:
X m.con_384[mod] = str_dup(str);
X break;
X case 13:
X m.no_con1[mod] = str_dup(str);
X break;
X case 14:
X m.no_con2[mod] = str_dup(str);
X break;
X case 15:
X m.no_con3[mod] = str_dup(str);
X break;
X case 16:
X m.no_con4[mod] = str_dup(str);
X break;
X }
X }
X if (oops)
X break;
X m_line++;
X if (m_line >= 3) {
X m_line = 0;
X mod++;
X }
X }
X }
X fclose(fp);
X
X if (oops) {
X sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
X error_win(1, buf, message);
X }
X m.t_entries = tty;
X m.m_entries = mod;
X m.t_cur = -1;
X m.m_cur = -1;
X /* if empty database */
X if (!tty) {
X sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
X error_win(0, buf, "has no TTY data");
X }
X if (!mod) {
X sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
X error_win(0, buf, "has no modem data");
X }
X /* fill in the rest */
X for (; tty<NUM_TTY; tty++) {
X m.tty[tty] = null_ptr;
X m.tname[tty] = null_ptr;
X m.lock_sp[tty] = 0;
X }
X for (; mod<NUM_MODEM; mod++) {
X m.mname[mod] = null_ptr;
X m.init[mod] = null_ptr;
X m.dial[mod] = null_ptr;
X m.suffix[mod] = null_ptr;
X m.hang_up[mod] = null_ptr;
X
X m.auto_baud[mod] = 'Y';
X m.con_3[mod] = null_ptr;
X m.con_12[mod] = null_ptr;
X m.con_24[mod] = null_ptr;
X m.con_48[mod] = null_ptr;
X m.con_96[mod] = null_ptr;
X m.con_192[mod] = null_ptr;
X m.con_384[mod] = null_ptr;
X
X m.no_con1[mod] = null_ptr;
X m.no_con2[mod] = null_ptr;
X m.no_con3[mod] = null_ptr;
X m.no_con4[mod] = null_ptr;
X }
X return(&m);
X}
X
X/*
X * Update the modem database. Other routines actually do the changes
X * or deletions in memory. A non-zero return code means non-fatal error.
X */
X
Xint
Xup_modem()
X{
X FILE *fp, *uid_fopen();
X char buf[80];
X int i;
X void error_win();
X
X /* open for write */
X if (!(fp = uid_fopen(modem->m_path, "w"))) {
X sprintf(buf, "\"%s\"", modem->m_path);
X error_win(0, "No write permission on modem/TTY database file", buf);
X return(1);
X }
X /* put back the TTY entries */
X for (i=0; i<modem->t_entries; i++)
X fprintf(fp, "TTY_%d=%s;%s;%d\n", i+1, modem->tty[i],
X modem->tname[i], modem->lock_sp[i]);
X
X /* put back the modem entries */
X for (i=0; i<modem->m_entries; i++) {
X fprintf(fp, "MODEM_%da=%s;%s;%s;%s;%s\n", i+1, modem->mname[i],
X modem->init[i], modem->dial[i], modem->suffix[i],
X modem->hang_up[i]);
X
X fprintf(fp, "MODEM_%db=%c;%s;%s;%s;%s;%s;%s;%s\n", i+1,
X modem->auto_baud[i], modem->con_3[i], modem->con_12[i],
X modem->con_24[i], modem->con_48[i], modem->con_96[i],
X modem->con_192[i], modem->con_384[i]);
X
X fprintf(fp, "MODEM_%dc=%s;%s;%s;%s\n", i+1, modem->no_con1[i],
X modem->no_con2[i], modem->no_con3[i], modem->no_con4[i]);
X }
X
X fclose(fp);
X return(0);
X}
X
X/*
X * See if the new modem is already in the database. If it's not, create
X * a slot for it and update the modem->m_cur variable.
X */
X
Xvoid
Xcreate_modem(str)
Xchar *str;
X{
X int i;
X char *str_rep(), buf[80];
X void error_win();
X /* modem entry already exists? */
X for (i=0; i<modem->m_entries; i++) {
X if (!strcmp(str, modem->mname[i]))
X return;
X }
X /* empty slot available? */
X if (modem->m_entries == NUM_MODEM) {
X sprintf(buf, "\"%s\"", modem->m_path);
X error_win(0, "No empty modem slots in", buf);
X return;
X }
X /* create a new entry */
X i = modem->m_entries;
X modem->mname[i] = str_rep(modem->mname[i], str);
X
X /* update number of entries */
X modem->m_entries++;
X return;
X}
X
X/*
X * See if the modem names in the list still need to be in the database.
X * If you find a "lost" entry, delete it and collapse the list.
X */
X
Xvoid
Xdel_modem()
X{
X extern char *null_ptr;
X int i, j, match;
X char *str_rep();
X void free_ptr();
X
X for (i=0; i<modem->m_entries; i++) {
X match = 0;
X for (j=0; j<modem->t_entries; j++) {
X if (!strcmp(modem->mname[i], modem->tname[j])) {
X match++;
X break;
X }
X }
X /* found a "lost" modem name */
X if (!match) {
X for (j=i; j<modem->m_entries-1; j++) {
X /* copy the info */
X modem->mname[j] = str_rep(modem->mname[j], modem->mname[j+1]);
X modem->init[j] = str_rep(modem->init[j], modem->init[j+1]);
X modem->dial[j] = str_rep(modem->dial[j], modem->dial[j+1]);
X modem->suffix[j] = str_rep(modem->suffix[j], modem->suffix[j+1]);
X modem->hang_up[j] = str_rep(modem->hang_up[j], modem->hang_up[j+1]);
X
X modem->auto_baud[j] = modem->auto_baud[j+1];
X modem->con_3[j] = str_rep(modem->con_3[j], modem->con_3[j+1]);
X modem->con_12[j] = str_rep(modem->con_12[j], modem->con_12[j+1]);
X modem->con_24[j] = str_rep(modem->con_24[j], modem->con_24[j+1]);
X modem->con_48[j] = str_rep(modem->con_48[j], modem->con_48[j+1]);
X modem->con_96[j] = str_rep(modem->con_96[j], modem->con_96[j+1]);
X modem->con_192[j] = str_rep(modem->con_192[j], modem->con_192[j+1]);
X modem->con_384[j] = str_rep(modem->con_384[j], modem->con_384[j+1]);
X
X modem->no_con1[j] = str_rep(modem->no_con1[j], modem->no_con1[j+1]);
X modem->no_con2[j] = str_rep(modem->no_con2[j], modem->no_con2[j+1]);
X modem->no_con3[j] = str_rep(modem->no_con3[j], modem->no_con3[j+1]);
X modem->no_con4[j] = str_rep(modem->no_con4[j], modem->no_con4[j+1]);
X }
X j = modem->m_entries -1;
X
X free_ptr(modem->mname[j]);
X free_ptr(modem->init[j]);
X free_ptr(modem->dial[j]);
X free_ptr(modem->suffix[j]);
X free_ptr(modem->hang_up[j]);
X
X free_ptr(modem->con_3[j]);
X free_ptr(modem->con_12[j]);
X free_ptr(modem->con_24[j]);
X free_ptr(modem->con_48[j]);
X free_ptr(modem->con_96[j]);
X free_ptr(modem->con_192[j]);
X free_ptr(modem->con_384[j]);
X
X free_ptr(modem->no_con1[j]);
X free_ptr(modem->no_con2[j]);
X free_ptr(modem->no_con3[j]);
X free_ptr(modem->no_con4[j]);
X
X /* create an empty entry */
X modem->mname[j] = null_ptr;
X modem->init[j] = null_ptr;
X modem->dial[j] = null_ptr;
X modem->suffix[j] = null_ptr;
X modem->hang_up[j] = null_ptr;
X
X modem->auto_baud[j] = 'Y';
X modem->con_3[j] = null_ptr;
X modem->con_12[j] = null_ptr;
X modem->con_24[j] = null_ptr;
X modem->con_48[j] = null_ptr;
X modem->con_96[j] = null_ptr;
X modem->con_192[j] = null_ptr;
X modem->con_384[j] = null_ptr;
X
X modem->no_con1[j] = null_ptr;
X modem->no_con2[j] = null_ptr;
X modem->no_con3[j] = null_ptr;
X modem->no_con4[j] = null_ptr;
X
X /* update the counts */
X modem->m_entries--;
X if (modem->m_cur >= modem->m_entries)
X modem->m_cur = -1;
X return;
X }
X }
X return;
X}
END_OF_FILE
if test 10184 -ne `wc -c <'pcomm-2.0/m_lib.c'`; then
echo shar: \"'pcomm-2.0/m_lib.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/m_lib.c'
fi
if test -f 'pcomm-2.0/main.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/main.c'\"
else
echo shar: Extracting \"'pcomm-2.0/main.c'\" \(10162 characters\)
sed "s/^X//" >'pcomm-2.0/main.c' <<'END_OF_FILE'
X/*
X * Pcomm is a public domain telecommunication program for Unix that
X * is designed to operate similarly to the MSDOS program, ProComm.
X * ProComm (TM) is copyrighted by Datastorm Technologies, Inc.
X *
X * Emmet P. Gray US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray Attn: AFZF-DE-ENV
X * Directorate of Engineering & Housing
X * Environmental Management Office
X * Fort Hood, TX 76544-5057
X *
X * Release v1.0 12 Mar 88
X * Release v1.1 21 Aug 88
X * Release v1.2 4 Feb 89
X * Release v2.0 18 Jul 92
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#define MAIN
X#include "config.h"
X#include "dial_dir.h"
X#include "extrnl.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X#ifndef OLDCURSES
X#include <term.h>
X#else /* OLDCURSES */
X#ifdef UNIXPC
X#include <sgtty.h>
X#endif /* UNIXPC */
Xchar tcbuf[1024];
Xstruct sgttyb t_mode, c_mode;
X#ifndef cbreak
X#define cbreak crmode
X#endif
X#endif /* OLDCURSES */
X
Xstruct DIAL_DIR *dir;
Xstruct EXTRNL *extrnl;
Xstruct MODEM *modem;
Xstruct PARAM *param;
Xstruct STATUS *status;
X
Xint fd = -1; /* file descriptor for port */
Xint xmc; /* magic cookie terminal */
Xint msg_status; /* read/write permissions on TTY */
Xchar *null_ptr = ""; /* generic char pointer to a null */
X
Xstatic int quit(), ci_match();
Xstatic void print_usage();
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X extern char *optarg;
X int c, i, data_bits;
X unsigned baud;
X char *mytty, *ttyname(), *term, *getenv(), *sys_name, parity;
X char *extra_dir, buf[80], message[80], *str_dup(), *number;
X char *aux;
X struct DIAL_DIR *read_dir();
X struct EXTRNL *read_extrnl();
X struct MODEM *read_modem();
X struct PARAM *read_param();
X struct STATUS *init();
X struct stat stbuf;
X void exit(), error_win(), vcs_table(), terminal(), free_ptr();
X void info();
X#ifdef OLDCURSES
X char *tgetstr(), *t, tb[1024];
X t = tcbuf;
X#endif /* OLDCURSES */
X
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X signal(SIGTERM, (SIG_TYPE(*) ()) quit);
X signal(SIGHUP, (SIG_TYPE(*) ()) quit);
X
X extra_dir = NULL;
X sys_name = NULL;
X aux = NULL;
X parity = '\0';
X baud = 0;
X data_bits = 0;
X number = NULL;
X /* the command line */
X while ((c = getopt(argc, argv, "d:f:a:eonw:b:p:")) != EOF) {
X switch (c) {
X case 'd': /* the extra directory to search */
X extra_dir = str_dup(optarg);
X break;
X case 'f': /* the short cut into the dialing dir */
X sys_name = str_dup(optarg);
X break;
X case 'a': /* auxiliary (script, TTY, or modem) */
X aux = str_dup(optarg);
X break;
X case 'e':
X if (parity != '\0')
X print_usage("Parity values are mutually exclusive");
X parity = 'E';
X break;
X case 'o':
X if (parity != '\0')
X print_usage("Parity values are mutually exclusive");
X parity = 'O';
X break;
X case 'n':
X if (parity != '\0')
X print_usage("Parity values are mutually exclusive");
X parity = 'N';
X break;
X case 'w':
X data_bits = atoi(optarg);
X if (data_bits != 7 && data_bits != 8)
X print_usage("Unsupported number of word length (data bits)");
X break;
X case 'b':
X baud = (unsigned int) atoi(optarg);
X switch (baud) {
X case 300:
X case 1200:
X case 2400:
X case 4800:
X case 9600:
X case 19200:
X case 38400:
X break;
X default:
X print_usage("Unsupported baud rate");
X break;
X }
X break;
X case 'p':
X number = str_dup(optarg);
X break;
X case '?': /* default */
X print_usage("");
X break;
X }
X }
X /* get terminal type */
X term = getenv("TERM");
X if (term == NULL || *term == '\0') {
X fprintf(stderr, "Windows not supported (TERM not defined)\n");
X exit(1);
X }
X /* see if terminfo entry exists */
X#ifdef OLDCURSES
X i = tgetent(tb, term);
X#else /* OLDCURSES */
X setupterm(term, 1, &i);
X#endif /* OLDCURSES */
X
X if (i != 1) {
X fprintf(stderr, "Windows not supported (no terminfo data for \"%s\")\n", term);
X exit(1);
X }
X /* minimum screen size */
X#ifdef OLDCURSES
X if (tgetnum("co") < 80 || tgetnum("li") < 24) {
X#else /* OLDCURSES */
X if (columns < 80 || lines < 24) {
X#endif /* OLDCURSES */
X fprintf(stderr, "Windows not supported (minimum 80x24 screen required)\n");
X exit(1);
X }
X /* must have cursor movement */
X#ifdef OLDCURSES
X if (tgetstr("cm", &t) == NULL) {
X#else /* OLDCURSES */
X if (cursor_address == NULL) {
X#endif /* OLDCURSES */
X fprintf(stderr, "Windows not supported (terminal too dumb)\n");
X exit(1);
X }
X /* load magic cookie variable */
X#ifdef OLDCURSES
X xmc = tgetnum("sg");
X#else /* OLDCURSES */
X xmc = magic_cookie_glitch;
X#endif /* OLDCURSES */
X /* ok... now let's go! */
X#ifdef OLDCURSES
X ioctl(0, TIOCGETP, &t_mode);
X#endif /* OLDCURSES */
X
X initscr();
X nonl();
X cbreak();
X noecho();
X
X#ifdef OLDCURSES
X ioctl(0, TIOCGETP, &c_mode);
X#endif /* OLDCURSES */
X
X dir = (struct DIAL_DIR *) NULL;
X extrnl = (struct EXTRNL *) NULL;
X param = (struct PARAM *) NULL;
X modem = (struct MODEM *) NULL;
X /* display herald if no arguments */
X if (argc == 1) {
X info(AUTO_CLEAR);
X erase();
X refresh();
X }
X /* get "msgs" status */
X if (mytty = ttyname(0)) {
X stat(mytty, &stbuf);
X msg_status = stbuf.st_mode & 0777;
X chmod(mytty, 0600);
X }
X
X mvaddstr(12, 31, "Initializing...");
X refresh();
X /* create the VCS table */
X vcs_table();
X /* create the status structure */
X status = init(extra_dir);
X /* read the support files */
X param = read_param();
X dir = read_dir();
X extrnl = read_extrnl();
X modem = read_modem();
X
X /* warning about screen size */
X if (LINES > MAX_ROW || COLS > MAX_COL-1)
X error_win(0, "Your screen size exceeds an internal Pcomm limit",
X "The edges of the screen may contain garbage");
X
X /* short-cut to dialing window? */
X if (sys_name != NULL) {
X for (i=1; i<dir->d_entries+1; i++) {
X if (ci_match(dir->name[i], sys_name)) {
X dir->q_num[0] = i;
X dir->d_cur = i;
X if (!dial_win(25))
X aux = dir->aux[dir->d_cur];
X break;
X }
X }
X /* if match not found */
X if (dir->q_num[0] == -1) {
X sprintf(buf, "Can't match \"%s\" in dialing directory", sys_name);
X sprintf(message, "file \"%s\"", dir->d_path);
X error_win(0, buf, message);
X }
X free_ptr(sys_name);
X }
X /* phone number on the command line */
X else if (number != NULL) {
X dir->name[0] = str_dup(number);
X dir->number[0] = str_dup(number);
X if (baud)
X dir->baud[0] = baud;
X if (parity)
X dir->parity[0] = parity;
X if (data_bits)
X dir->data_bits[0] = data_bits;
X dir->q_num[0] = 0;
X dir->d_cur = 0;
X
X dial_win(25);
X free_ptr(number);
X }
X /* start terminal dialogue */
X terminal(aux);
X exit(0);
X}
X
X/*
X * Something dreadful happened... Clean up the mess we made with the
X * TTY driver and release the phone line.
X */
X
Xstatic int
Xquit()
X{
X void cleanup();
X
X cleanup(1);
X /* never returns... */
X return(0);
X}
X
X/*
X * Check write permission with the real UID and GID. Returns a 0 on
X * permission denied, 1 on OK, and 2 on OK-but the file already exists.
X */
X
Xint
Xcan_write(file)
Xchar *file;
X{
X char *p, path[256], *strcpy(), *strrchr();
X
X strcpy(path, file);
X /* dissect the path component */
X if (p = strrchr(path, '/'))
X *p = '\0';
X else
X strcpy(path, ".");
X /* if it already exists */
X if (!access(file, 0)) {
X if (!access(file, 2))
X return(OK_BUT_EXISTS);
X return(DENIED);
X }
X /* if path is writable */
X if (!access(path, 2))
X return(WRITE_OK);
X return(DENIED);
X}
X
X/*
X * Check the read and write permissions before opening a file. This
X * is a horrible kludge to work around the fact that a lot of systems
X * that claim to be SVID compatible don't treat setuid(2) and setgid(2)
X * properly. For example, on a Masscomp, you can't flip-flop back and
X * forth between the real and effective UID/GID.
X */
X
XFILE *
Xuid_fopen(file, mode)
Xchar *file, *mode;
X{
X FILE *fp;
X
X#ifdef SETUID_BROKE
X switch (*mode) {
X case 'a':
X case 'w':
X switch(can_write(file)) {
X case DENIED:
X fp = (FILE *) NULL;
X break;
X case OK_BUT_EXISTS:
X fp = fopen(file, mode);
X break;
X case WRITE_OK:
X fp = fopen(file, mode);
X chown(file, getuid(), getgid());
X break;
X }
X break;
X case 'r':
X if (access(file, 4))
X fp = (FILE *) NULL;
X else
X fp = fopen(file, mode);
X break;
X }
X#else /* SETUID_BROKE */
X int euid, egid;
X
X euid = geteuid();
X egid = getegid();
X /* abdicate the throne */
X setuid(getuid());
X setgid(getgid());
X
X fp = fopen(file, mode);
X /* put things back */
X setuid(euid);
X setgid(egid);
X#endif /* SETUID_BROKE */
X return(fp);
X}
X
X/*
X * See if s2 in contained in s1 (case insensitive). Returns a 1 on yes,
X * and a 0 on no.
X */
X
Xstatic int
Xci_match(s1, s2)
Xchar *s1, *s2;
X{
X int i;
X char str1[128], str2[128], *strstr();
X
X /* copy the strings to lower case */
X i = 0;
X while(*s1) {
X if (isupper(*s1))
X str1[i++] = tolower(*s1);
X else
X str1[i++] = *s1;
X
X if (i >= 127)
X break;
X s1++;
X }
X str1[i] = '\0';
X
X i = 0;
X while(*s2) {
X if (isupper(*s2))
X str2[i++] = tolower(*s2);
X else
X str2[i++] = *s2;
X
X if (i >= 127)
X break;
X s2++;
X }
X str2[i] = '\0';
X /* do they match? */
X if (strstr(str1, str2))
X return(1);
X return(0);
X}
X
Xstatic void
Xprint_usage(err_message)
Xchar *err_message;
X{
X void exit();
X
X if (*err_message != '\0')
X fprintf(stderr, "Error: %s\n", err_message);
X fprintf(stderr, "\nUsage: pcomm [-d directory] [-f system name] [-a auxiliary file]\n");
X fprintf(stderr, " [-e|o|n] [-w word length] [-b baud] [-p phone number]\n\n");
X fprintf(stderr, "Command line options:\n");
X fprintf(stderr, "\t-d use this directory to find Pcomm support files\n");
X fprintf(stderr, "\t-f dial the entry that matches this system name\n");
X fprintf(stderr, "\t-a auxiliary file (script, TTY, or modem)\n\n");
X fprintf(stderr, "The following are used for manual dialing:\n");
X fprintf(stderr, "\t-e use even parity\n");
X fprintf(stderr, "\t-o use odd parity\n");
X fprintf(stderr, "\t-n use no parity\n");
X fprintf(stderr, "\t-w word length (number of data bits 7 or 8)\n");
X fprintf(stderr, "\t-b baud rate (300, 1200, 2400, 4800, 9600, 19200, 38400)\n");
X fprintf(stderr, "\t-p phone number to dial\n");
X exit(1);
X}
END_OF_FILE
if test 10162 -ne `wc -c <'pcomm-2.0/main.c'`; then
echo shar: \"'pcomm-2.0/main.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/main.c'
fi
if test -f 'pcomm-2.0/vcs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/vcs.c'\"
else
echo shar: Extracting \"'pcomm-2.0/vcs.c'\" \(11086 characters\)
sed "s/^X//" >'pcomm-2.0/vcs.c' <<'END_OF_FILE'
X/*
X * Routines for VCS detection.
X */
X
X#include <stdio.h>
X#include "config.h"
X#include "status.h"
X#include "vcs.h"
X
X#ifndef OLDCURSES
X#include <curses.h>
X#include <term.h>
X#endif /* OLDCURSES */
X
Xstatic int vcs_codes[NUM_VCS][VCS_SIZE];/* the VCS codes */
Xstatic int vcs_leadin[NUM_VCS]; /* unique list of lead-in characters */
Xstatic int num_leadin; /* length of lead-in list */
Xstatic int putc_cnt;
Xstatic char putc_buf[VCS_SIZE];
Xstatic int substr(), fake_putc(), match_codes();
Xstatic void fake_it();
X
Xint vcs_param[NUM_VCS][5]; /* positional parameters */
Xint vcs_opt[NUM_VCS][10]; /* options unique to each VCS */
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 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++] = (unsigned char) 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 embedded 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 int i, j, k, match, temp[VCS_SIZE];
X char *p, *strcpy(), buf[VCS_SIZE];
X char *tparm(); /* <- comment out, if required */
X
X#ifdef OLDCURSES
X extern char tcbuf[1024];
X char *t, *cursor_home, *clr_eol, *clr_eos;
X char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
X char *cursor_left, *cursor_address, *tgetstr(), *tgoto();
X
X t = tcbuf;
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#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] = (unsigned char) 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 vcs_opt[MV_DIRECT][1] = 1;
X }
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((char *)tparm(cursor_address, 12, 34));
X#endif /* OLDCURSES */
X
X j = 0;
X while (putc_buf[j]) {
X temp[j] = (unsigned char) 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((char *)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((char *)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++] = (unsigned char) 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 */
X
Xstatic void
Xfake_it(s)
Xchar *s;
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}
X
Xstatic int
Xfake_putc(c)
Xchar c;
X{
X if (c != '\0')
X putc_buf[putc_cnt++] = (unsigned char) c;
X return((unsigned char) 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}
END_OF_FILE
if test 11086 -ne `wc -c <'pcomm-2.0/vcs.c'`; then
echo shar: \"'pcomm-2.0/vcs.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/vcs.c'
fi
if test -f 'pcomm-2.0/x_rcv.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/x_rcv.c'\"
else
echo shar: Extracting \"'pcomm-2.0/x_rcv.c'\" \(12062 characters\)
sed "s/^X//" >'pcomm-2.0/x_rcv.c' <<'END_OF_FILE'
X/*
X * Receive a list of files using a version of Ward Christensen's file
X * transfer protocol. A non-zero return code means the user must acknowledge
X * an error condition (a user generated abort returns a 0). Write errors
X * are considered fatal.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xunsigned char buf[1029];
Xchar file_name[15];
Xlong file_length;
X
Xstatic int err_method, tot_err, block_size;
Xstatic int send_first();
X
Xint
Xrcv_xmodem(win, list, type)
XWINDOW *win;
Xchar *list;
Xint type;
X{
X extern char *protocol[];
X FILE *fp, *uid_fopen();
X int i, default_err, is_batch, max_block, code, file_count, got_hdr;
X int hours, mins, secs, len;
X long block, recv, partial;
X float percent, performance;
X unsigned char blk;
X unsigned int sleep();
X char *file, *name, *strcpy(), *strrchr(), *strtok();
X void cancel_xfer();
X /* which protocol? */
X switch (type) {
X case XMODEM:
X default_err = CRC_CHECKSUM;
X is_batch = 0;
X max_block = 128;
X break;
X case XMODEM_1k:
X default_err = CRC_CHECKSUM;
X is_batch = 0;
X max_block = 1024;
X break;
X case MODEM7:
X default_err = CHECKSUM;
X is_batch = 1;
X max_block = 128;
X break;
X case YMODEM:
X default_err = CRC;
X is_batch = 1;
X max_block = 1024;
X performance = 1.09;
X break;
X case YMODEM_G:
X default_err = NONE;
X is_batch = 1;
X max_block = 1024;
X performance = 1.02;
X break;
X default:
X return(1);
X }
X
X tot_err = 0;
X file_count = 0;
X mvwaddstr(win, 2, 24, protocol[type -1]);
X mvwaddstr(win, 11, 24, "0 ");
X
X /* CONSTCOND */
X while (1) {
X file_count++;
X file_length = 0L;
X /* user supplied name */
X if (!is_batch) {
X if (file_count > 1)
X break;
X
X file = strtok(list, " \t");
X /* dissect the file name */
X if ((name = strrchr(file, '/')))
X strcpy(file_name, ++name);
X else
X strcpy(file_name, file);
X }
X /* get the modem7 file name */
X if (type == MODEM7) {
X if (code = rcv_modem7(win, default_err))
X return(code +1);
X
X file = file_name;
X }
X /* get the block 0 */
X if (type == YMODEM || type == YMODEM_G) {
X if (code = send_first(win, max_block, default_err))
X return(code +1);
X
X if (code = rcv_ymodem(win))
X return(code +1);
X
X /* at the end? */
X if (buf[3] == '\0') {
X beep();
X wrefresh(win);
X putc_line(ACK);
X sleep(1);
X return(0);
X }
X file = file_name;
X }
X /* any trouble? */
X if (file_name[0] == '\0')
X continue;
X
X clear_line(win, 3, 24, TRUE);
X waddstr(win, file_name);
X /* if file length is known */
X if (file_length != 0L) {
X mvwprintw(win, 4, 24, "%-10ld", file_length);
X
X secs = (file_length * 10.0 / dir->baud[0]) * performance;
X hours = secs / 3600;
X mins = (secs % 3600) / 60;
X secs = (secs % 3600) % 60;
X
X mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X }
X /* some starting numbers */
X mvwaddstr(win, 7, 24, "0 ");
X if (file_length != 0L)
X mvwaddstr(win, 8, 24, "0% ");
X mvwaddstr(win, 9, 24, "0 ");
X mvwaddstr(win, 10, 24, "0 ");
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NONE");
X wrefresh(win);
X
X /*
X * If the user supplied the name, write permission is checked
X * by the get_names() routine in xfer_menu(). If modem7
X * or ymodem supplied name, the name is unique and the write
X * permission on the directory is checked by the change_name()
X * routines. However, this is required for systems with
X * SETUID_BROKE set.
X */
X /* open the file */
X if (!(fp = uid_fopen(file, "w"))) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
X wrefresh(win);
X cancel_xfer(DOWN_LOAD);
X return(1);
X }
X /* ACK the block 0 */
X if (type == YMODEM || type == YMODEM_G)
X putc_line(ACK);
X
X if (code = send_first(win, max_block, default_err)) {
X fclose(fp);
X return(code +1);
X }
X /* here we go... */
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NONE");
X wrefresh(win);
X blk = 1;
X block = 1L;
X recv = 0L;
X got_hdr = 1;
X /* CONSTCOND */
X while (1) {
X code = rcv_block(win, got_hdr, max_block, blk);
X
X if (code < 0) {
X fclose(fp);
X return(code +1);
X }
X got_hdr = 0;
X /* are we done? */
X if (buf[0] == EOT) {
X if (!is_batch) {
X beep();
X wrefresh(win);
X sleep(1);
X }
X break;
X }
X /* if not a duplicate block */
X if (!code) {
X if (file_length != 0L) {
X partial = file_length - recv;
X if (partial > (long) block_size)
X len = block_size;
X else
X len = (int) partial;
X }
X else
X len = block_size;
X
X if (fwrite((char *) &buf[3], sizeof(char), len, fp) != len) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "WRITE ERROR");
X wrefresh(win);
X cancel_xfer(DOWN_LOAD);
X fclose(fp);
X /* fatal */
X return(1);
X }
X mvwprintw(win, 7, 24, "%-5ld", block);
X recv = recv + (unsigned int) len;
X mvwprintw(win, 9, 24, "%-10ld", recv);
X blk++;
X block++;
X }
X /*
X * If the length is known, give the same status
X * report as uploading
X */
X if (file_length != 0L) {
X percent = recv * 100.0 / file_length;
X if (percent > 100.0)
X percent = 100.0;
X mvwprintw(win, 8, 24, "%0.1f%%", percent);
X }
X wrefresh(win);
X putc_line(ACK);
X }
X if (file_length != 0L) {
X mvwaddstr(win, 8, 24, "100% ");
X wrefresh(win);
X }
X /*
X * If the file length is not known, search backwards from
X * the end of the file until you find a character that is
X * not the ^Z padding character.
X */
X if (file_length == 0L) {
X for (i=block_size+2; i>2; i--) {
X if (buf[i] != CTRLZ)
X break;
X }
X file_length = recv - (unsigned int) block_size + (unsigned int) i -2L;
X fclose(fp);
X if (fix_length(file, file_length)) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "TRUNCATE ERROR");
X wrefresh(win);
X sleep(1);
X }
X }
X else
X fclose(fp);
X /* ACK the EOT */
X putc_line(ACK);
X }
X return(0);
X}
X
X/*
X * Send the first character to start the transmission and set the error
X * checking method. Returns the standard error codes or 0 on success.
X * The variables err_method and block_size are global.
X */
X
Xstatic int
Xsend_first(win, max_block, default_err)
XWINDOW *win;
Xint max_block, default_err;
X{
X int i, err_count;
X unsigned int sleep();
X void cancel_xfer();
X /* default error method */
X err_method = default_err;
X if (default_err == CRC_CHECKSUM)
X err_method = CRC;
X /* send the first char */
X err_count = 0;
X while (err_count < MAX_ERRORS*2) {
X mvwprintw(win, 10, 24, "%-2d", err_count);
X
X /* scan the keyboard for abort */
X if (wgetch(win) == ESC) {
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "ABORTED");
X wrefresh(win);
X cancel_xfer(DOWN_LOAD);
X sleep(3);
X return(ABORT);
X }
X /* switch to checksum? */
X if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
X err_method = CHECKSUM;
X
X /* send error method code */
X clear_line(win, 5, 24, TRUE);
X switch (err_method) {
X case CHECKSUM:
X waddstr(win, "CHECKSUM");
X putc_line(NAK);
X break;
X case CRC:
X waddstr(win, "CRC");
X putc_line('C');
X break;
X case NONE:
X waddstr(win, "NONE");
X putc_line('G');
X break;
X }
X /*
X * We've cut the delay time in half, so we double
X * the allowable errors
X */
X if ((i = getc_line(5)) == -1) {
X err_count++;
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NO RESPONSE");
X wrefresh(win);
X continue;
X }
X buf[0] = (char) i;
X#ifdef DEBUG
X fprintf(stderr, "send_first: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
X#endif /* DEBUG */
X
X switch (buf[0]) {
X case SOH: /* small block follows */
X block_size = 128;
X return(0);
X case STX: /* large block follows */
X if (max_block == 1024) {
X block_size = 1024;
X return(0);
X }
X /* FALLTHRU */
X default:
X err_count++;
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "BAD HEADER");
X wrefresh(win);
X /* read some garbage... */
X while(fread_line(buf, 1028, 1) != -1)
X ;
X putc_line(NAK);
X break;
X }
X }
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "TIMED OUT");
X wrefresh(win);
X return(ERROR);
X}
X
X/*
X * Receive a block of info from the host. Returns a 0 on success, a 1 on
X * a duplicate block or the standard error codes. The variables
X * err_method and block_size are global.
X */
X
Xint
Xrcv_block(win, got_hdr, max_block, blk)
XWINDOW *win;
Xint got_hdr, max_block;
Xunsigned char blk;
X{
X int i, err_count, bad_block, out_of_sync;
X unsigned short crc, calc_crc();
X unsigned int packet, sleep();
X unsigned char blk_compliment, calc_sum(), crc_1, crc_2;
X void cancel_xfer();
X
X err_count = 0;
X while (err_count < MAX_ERRORS) {
X mvwprintw(win, 10, 24, "%-2d", err_count);
X mvwprintw(win, 11, 24, "%-3d", tot_err);
X
X /* scan the keyboard for abort */
X if (wgetch(win) == ESC) {
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "ABORTED");
X wrefresh(win);
X cancel_xfer(DOWN_LOAD);
X sleep(3);
X return(ABORT);
X }
X /* have we already got a hdr? */
X if (!got_hdr) {
X if ((i = getc_line(10)) == -1) {
X err_count++;
X tot_err++;
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NO RESPONSE");
X wrefresh(win);
X continue;
X }
X buf[0] = (char) i;
X#ifdef DEBUG
X fprintf(stderr, "rcv_block: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
X#endif /* DEBUG */
X /* what'd we get? */
X switch (buf[0]) {
X case EOT: /* we're done! */
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "TRANSFER COMPLETE");
X wrefresh(win);
X sleep(1);
X return(0);
X case SOH: /* small block follows */
X block_size = 128;
X break;
X case STX: /* large block follows */
X if (max_block == 1024) {
X block_size = 1024;
X break;
X }
X /* FALLTHRU */
X default:
X err_count++;
X tot_err++;
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "BAD HEADER");
X wrefresh(win);
X
X /* read some garbage... */
X while(fread_line(buf, 1028, 1) != -1)
X ;
X putc_line(NAK);
X continue;
X }
X }
X /* read the rest of the packet */
X packet = block_size + 2 + (err_method == CHECKSUM ? 1 : 2);
X if (fread_line(&buf[1], packet, 10) == -1) {
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "TIMED OUT");
X wrefresh(win);
X putc_line(NAK);
X err_count++;
X tot_err++;
X continue;
X }
X
X /*
X * Validation of the packet includes checking the
X * block number, its complement, and the crc/checksum.
X */
X out_of_sync = 0;
X blk_compliment = ~blk;
X if (buf[1] != blk || buf[2] != blk_compliment)
X out_of_sync++;
X
X bad_block = 0;
X switch (err_method) {
X case CHECKSUM:
X#ifdef DEBUG
X fprintf(stderr, "blk=%d, checksum=%d\n", blk, calc_sum(&buf[3], block_size));
X#endif /* DEBUG */
X if (buf[block_size +3] != calc_sum(&buf[3], block_size))
X bad_block++;
X break;
X case CRC:
X crc = calc_crc(&buf[3], block_size);
X crc_1 = crc >> 8;
X crc_2 = crc & 0xff;
X#ifdef DEBUG
X fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, crc_1, crc_2);
X#endif /* DEBUG */
X if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
X bad_block++;
X break;
X case NONE:
X return(0);
X }
X /* handle errors */
X if (bad_block) {
X clear_line(win, 12, 24, TRUE);
X if (err_method == CRC)
X waddstr(win, "CRC FAILED");
X else
X waddstr(win, "CHECKSUM FAILED");
X wrefresh(win);
X putc_line(NAK);
X err_count++;
X tot_err++;
X continue;
X }
X /* not really an error */
X if (out_of_sync) {
X /*
X * If a perfect packet is off by 1 block number,
X * (a lost ACK could cause this) then treat it as
X * a good block but don't write it to disk.
X */
X if (buf[1] == (unsigned char) blk-1)
X return(1);
X
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "OUT OF SYNC");
X wrefresh(win);
X putc_line(NAK);
X err_count++;
X tot_err++;
X continue;
X }
X return(0);
X }
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "TOO MANY ERRORS");
X wrefresh(win);
X cancel_xfer(DOWN_LOAD);
X return(ERROR);
X}
END_OF_FILE
if test 12062 -ne `wc -c <'pcomm-2.0/x_rcv.c'`; then
echo shar: \"'pcomm-2.0/x_rcv.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/x_rcv.c'
fi
if test -f 'pcomm-2.0/x_send.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pcomm-2.0/x_send.c'\"
else
echo shar: Extracting \"'pcomm-2.0/x_send.c'\" \(11671 characters\)
sed "s/^X//" >'pcomm-2.0/x_send.c' <<'END_OF_FILE'
X/*
X * Send a list of files using a version of Ward Christensen's file
X * transfer protocol. A non-zero return code means an error must be
X * acknowledged by the user (a user generated abort returns a 0).
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xstatic int tot_err, err_method;
Xstatic int rcv_first();
X
Xint
Xsend_xmodem(win, list, type)
XWINDOW *win;
Xchar *list;
Xint type;
X{
X extern char *protocol[];
X FILE *fp, *uid_fopen();
X int i, block_size, file_count, secs, mins, hours, big_blocks;
X int small_blocks, err_count, got_it, num, is_batch, code;
X int max_block, default_err;
X long size, block, sent, xmit_size;
X char *file, *strtok(), *name, *strrchr();
X unsigned short crc, calc_crc();
X unsigned char buf[1029], blk, calc_sum();
X unsigned int packet, sleep();
X float performance, percent;
X struct stat stbuf;
X /* which protocol? */
X switch (type) {
X case XMODEM:
X is_batch = 0;
X default_err = CRC_CHECKSUM;
X max_block = 128;
X performance = 1.36;
X break;
X case XMODEM_1k:
X is_batch = 0;
X default_err = CRC_CHECKSUM;
X max_block = 1024;
X performance = 1.09;
X break;
X case MODEM7:
X is_batch = 1;
X default_err = CHECKSUM;
X max_block = 128;
X performance = 1.36;
X break;
X case YMODEM:
X is_batch = 1;
X default_err = CRC;
X max_block = 1024;
X performance = 1.09;
X break;
X case YMODEM_G:
X is_batch = 1;
X default_err = NONE;
X max_block = 1024;
X performance = 1.02;
X break;
X default:
X return(1);
X }
X
X tot_err = 0;
X file_count = 0;
X mvwaddstr(win, 2, 24, protocol[type -1]);
X mvwaddstr(win, 11, 24, "0 ");
X
X /* each one in the list */
X file = strtok(list, " \t");
X do {
X /* is it a batch type? */
X file_count++;
X if (file_count > 1 && !is_batch)
X break;
X /* display the name */
X clear_line(win, 3, 24, TRUE);
X if ((name = strrchr(file, '/')))
X name++;
X else
X name = file;
X waddstr(win, name);
X wrefresh(win);
X /* get the file size */
X if (stat(file, &stbuf) < 0) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "CAN'T FIND FILE");
X wrefresh(win);
X sleep(3);
X continue;
X }
X /* sanity checking */
X if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "NOT REGULAR FILE");
X wrefresh(win);
X sleep(3);
X continue;
X }
X
X size = stbuf.st_size;
X mvwprintw(win, 4, 24, "%-10ld", size);
X clear_line(win, 5, 24, TRUE);
X
X if (!(fp = uid_fopen(file, "r"))) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "PERMISSION DENIED");
X wrefresh(win);
X sleep(3);
X continue;
X }
X /* get the xmit size */
X block_size = max_block;
X big_blocks = 0;
X small_blocks = 0;
X if (block_size == 128) {
X small_blocks = size / 128;
X if (size % 128)
X small_blocks++;
X }
X else {
X big_blocks = size / 1024;
X small_blocks = (size % 1024) / 128;
X if (size % 128)
X small_blocks++;
X
X if (small_blocks == 8 && !big_blocks) {
X big_blocks++;
X small_blocks = 0;
X }
X /* if tiny file */
X if (big_blocks == 0)
X block_size = 128;
X }
X
X xmit_size = ((unsigned int) big_blocks * 1024L) + ((unsigned int) small_blocks * 128L);
X /* add block 0 to the size */
X if (type == YMODEM || type == YMODEM_G)
X xmit_size += 128L;
X
X secs = (xmit_size * 10.0 / dir->baud[0]) * performance;
X hours = secs / 3600;
X mins = (secs % 3600) / 60;
X secs = (secs % 3600) % 60;
X
X mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X
X /* some starting numbers */
X mvwaddstr(win, 7, 24, " ");
X mvwaddstr(win, 8, 24, "0% ");
X mvwaddstr(win, 9, 24, "0 ");
X mvwaddstr(win, 10, 24, "0 ");
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NONE");
X wrefresh(win);
X /* send the batch stuff */
X switch (type) {
X case MODEM7:
X if (code = rcv_first(win, default_err)) {
X fclose(fp);
X return(code +1);
X }
X
X if (send_modem7(win, name)) {
X fclose(fp);
X return(1);
X }
X break;
X case YMODEM:
X case YMODEM_G:
X if (code = rcv_first(win, default_err)) {
X fclose(fp);
X return(code +1);
X }
X
X if (code = send_ymodem(win, name, size)) {
X fclose(fp);
X /*
X * CANCEL now means that the other
X * end can't open that file.
X */
X if (code == CANCEL)
X break;
X return(code +1);
X }
X xmit_size -= 128L;
X break;
X default:
X code = 0;
X break;
X }
X /* remote can't receive that file? */
X if (code == CANCEL)
X break;
X /* wait for first character */
X if (code = rcv_first(win, default_err)) {
X fclose(fp);
X return(code +1);
X }
X /* here we go... */
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NONE");
X wrefresh(win);
X sent = 0L;
X block = 1L;
X blk = 1;
X while (num = fread((char *) &buf[3], sizeof(char), block_size, fp)) {
X
X /* fill short block */
X if (num < block_size) {
X for (i=num; i<block_size; i++)
X buf[i+3] = CTRLZ;
X }
X
X /* show current stats */
X mvwprintw(win, 7, 24, "%-5ld", block);
X percent = sent * 100.0 / xmit_size;
X mvwprintw(win, 8, 24, "%0.1f%%", percent);
X mvwprintw(win, 9, 24, "%-10ld", sent);
X wrefresh(win);
X
X /* build the header */
X if (block_size == 128)
X buf[0] = SOH;
X else
X buf[0] = STX;
X
X buf[1] = blk;
X buf[2] = ~blk;
X
X /* build the error detection stuff */
X switch (err_method) {
X case CHECKSUM:
X buf[block_size+3] = calc_sum(&buf[3], block_size);
X#ifdef DEBUG
X fprintf(stderr, "blk=%d, checksum=%d\n", blk, buf[block_size+3]);
X#endif /* DEBUG */
X packet = block_size +4;
X break;
X case CRC:
X crc = calc_crc(&buf[3], block_size);
X buf[block_size+3] = crc >> 8;
X buf[block_size+4] = crc & 0xff;
X#ifdef DEBUG
X fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, buf[block_size+3], buf[block_size+4]);
X#endif /* DEBUG */
X packet = block_size +5;
X break;
X case NONE:
X buf[block_size+3] = 0;
X buf[block_size+4] = 0;
X packet = block_size +5;
X break;
X }
X
X /* send the block */
X if (code = send_block(win, buf, packet)) {
X fclose(fp);
X return(code +1);
X }
X block++;
X blk++;
X sent = sent + (unsigned int) block_size;
X
X /* change block size? */
X if (xmit_size - sent < 1024)
X block_size = 128;
X }
X mvwaddstr(win, 8, 24, "100% ");
X mvwprintw(win, 9, 24, "%-10ld", sent);
X /* at the end of the file */
X err_count = 0;
X got_it = 0;
X while (err_count < MAX_ERRORS) {
X putc_line(EOT);
X if (getc_line(10) == ACK) {
X got_it++;
X break;
X }
X err_count++;
X }
X clear_line(win, 12, 24, TRUE);
X if (!got_it) {
X /*
X * So what??? We don't do anything if there is
X * no acknowledge from the host!!
X */
X waddstr(win, "NO ACKNOWLEDGE");
X }
X else
X waddstr(win, "TRANSFER COMPLETE");
X if (!is_batch)
X beep();
X wrefresh(win);
X sleep(2);
X /* prepare to start again */
X fclose(fp);
X } while (file = strtok((char *) NULL, " \t"));
X
X /*
X * The end of batch markers... For modem7 it's an ACK and EOT, for
X * ymodem, it's an empty block 0.
X */
X switch (type) {
X case MODEM7:
X if (code = rcv_first(win, default_err))
X return(code +1);
X putc_line(ACK);
X putc_line(EOT);
X beep();
X wrefresh(win);
X break;
X case YMODEM:
X case YMODEM_G:
X if (code = rcv_first(win, default_err))
X return(code +1);
X
X if (code = send_ymodem(win, "", 0L))
X return(code +1);
X beep();
X wrefresh(win);
X break;
X default:
X break;
X }
X return(0);
X}
X
X/*
X * Wait for the first character to start the transmission. This first
X * character also sets the crc/checksum method. Returns the standard
X * error codes, or 0 on success. The variable err_method is global.
X */
X
Xstatic int
Xrcv_first(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X int i, err_count;
X unsigned int sleep();
X void cancel_xfer();
X
X err_count = 0;
X while (err_count < MAX_ERRORS) {
X
X /* scan the keyboard for abort */
X if (wgetch(win) == ESC) {
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "ABORTED");
X wrefresh(win);
X cancel_xfer(UP_LOAD);
X sleep(3);
X return(ABORT);
X }
X /* scan the TTY line */
X i = getc_line(10);
X#ifdef DEBUG
X fprintf(stderr, "rcv_first: got \"%c\", %02x, %03o, %d\n", i, i, i, i);
X#endif /* DEBUG */
X switch (i) {
X case -1: /* timed out */
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "NO RESPONSE");
X err_count++;
X break;
X case NAK: /* checksum marker */
X if (default_err == CHECKSUM || default_err == CRC_CHECKSUM) {
X mvwaddstr(win, 5, 24, "CHECKSUM");
X err_method = CHECKSUM;
X return(0);
X }
X err_count++;
X break;
X case 'C': /* CRC marker */
X if (default_err == CRC_CHECKSUM || default_err == CRC) {
X mvwaddstr(win, 5, 24, "CRC");
X err_method = CRC;
X return(0);
X }
X err_count++;
X break;
X case 'G': /* ymodem-g marker */
X if (default_err == NONE) {
X mvwaddstr(win, 5, 24, "NONE");
X err_method = NONE;
X return(0);
X }
X err_count++;
X break;
X case CAN: /* two CAN's and you're out! */
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 err_count++;
X break;
X default:
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "BAD HEADER");
X err_count++;
X break;
X }
X mvwprintw(win, 10, 24, "%-2d", err_count);
X wrefresh(win);
X }
X /* failed to get it right? */
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "TIMED OUT");
X wrefresh(win);
X return(ERROR);
X}
X
X/*
X * Send a block of data, scan the keyboard for a user abort, and check
X * the return codes from the host. Returns standard error codes or 0
X * on success.
X */
X
Xint
Xsend_block(win, blk, packet)
XWINDOW *win;
Xunsigned char *blk;
Xunsigned int packet;
X{
X extern int fd;
X int i, err_count;
X void cancel_xfer();
X unsigned int sleep();
X
X err_count = 0;
X mvwaddstr(win, 10, 24, "0 ");
X
X while (err_count < MAX_ERRORS) {
X /* write the block */
X write(fd, (char *) blk, packet);
X /* scan the keyboard for abort */
X if (wgetch(win) == ESC) {
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "ABORTED");
X wrefresh(win);
X cancel_xfer(UP_LOAD);
X sleep(3);
X return(ABORT);
X }
X /* ymodem-g doesn't need ACKs */
X if (err_method == NONE)
X return(0);
X /* wait for acknowledge */
X i = getc_line(10);
X#ifdef DEBUG
X fprintf(stderr, "send_block: got \"%c\", %02x, %03o, %d\n", i, i, i, i);
X#endif /* DEBUG */
X switch (i) {
X case -1: /* timed out */
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NO RESPONSE");
X err_count++;
X tot_err++;
X break;
X case ACK: /* Hooray!! we got it */
X return(0);
X case NAK: /* show our disappointment... */
X clear_line(win, 12, 24, TRUE);
X if (err_method == CRC)
X waddstr(win, "CRC FAILED");
X else
X waddstr(win, "CHECKSUM FAILED");
X err_count++;
X tot_err++;
X break;
X case CAN: /* two CAN's and you're out! */
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 /* FALLTHRU */
X default:
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "RESENDING");
X err_count++;
X tot_err++;
X break;
X }
X /* flush any pending garbage */
X tty_flush(fd, 0);
X
X mvwprintw(win, 10, 24, "%-2d", err_count);
X mvwprintw(win, 11, 24, "%-3d", tot_err);
X wrefresh(win);
X }
X /* failed to get it right */
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "TOO MANY ERRORS");
X wrefresh(win);
X cancel_xfer(UP_LOAD);
X return(ERROR);
X}
END_OF_FILE
if test 11671 -ne `wc -c <'pcomm-2.0/x_send.c'`; then
echo shar: \"'pcomm-2.0/x_send.c'\" unpacked with wrong size!
fi
# end of 'pcomm-2.0/x_send.c'
fi
echo shar: End of archive 5 \(of 8\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 8 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads