home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-13 | 98.8 KB | 4,260 lines |
- Newsgroups: comp.sources.unix
- From: fthood!egray@uxc.cso.uiuc.edu (Emmet Gray)
- Subject: v26i156: pcomm-2.0.2 - a serial communications program (clone of ProComm), Part04/06
- Sender: unix-sources-moderator@vix.com
- Approved: paul@vix.com
-
- Submitted-By: fthood!egray@uxc.cso.uiuc.edu (Emmet Gray)
- Posting-Number: Volume 26, Issue 156
- Archive-Name: pcomm-2.0.2/part04
-
- #! /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 4 (of 6)."
- # Contents: Pcomm.1 curses.c di_win.c dial.c m_lib.c main.c vcs.c
- # x_rcv.c x_send.c
- # Wrapped by vixie@gw.home.vix.com on Wed Apr 14 00:38:43 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'Pcomm.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Pcomm.1'\"
- else
- echo shar: Extracting \"'Pcomm.1'\" \(9657 characters\)
- sed "s/^X//" >'Pcomm.1' <<'END_OF_FILE'
- X.\" use tbl and the man macro package
- X.if n .ds rq ""
- X.el .ds rq ''
- X.if n .ds lq ""
- X.el .ds lq ``
- X.TH pcomm L
- X.SH NAME
- pcomm \- a telecommunication program
- X.SH SYNOPSIS
- X.B pcomm
- X[
- X.B \-d
- directory ] [
- X.B \-f
- system name ] [
- X.B \-a
- auxiliary file ] [
- X.B \-e
- X|
- X.B o
- X|
- X.B n
- X] [
- X.B -w
- word length ] [
- X.B -b
- baud rate ] [
- X.B -p
- phone number ]
- X.SH DESCRIPTION
- X.I Pcomm
- is a public domain telecommunication program for Unix that is designed
- to operate similarly to the MSDOS program, ProComm. ProComm (TM) is
- copyrighted by Datastorm Technologies, Inc.
- X.PP
- The
- X.I \-d
- option is used to specify an additional path to search for the Pcomm
- support files.
- X.PP
- The
- X.I \-f
- option is used to specify automatic dialing of an entry in the dialing
- directory. The
- X.I name
- field in the dialing directory is checked against the string given on
- the command line. If a match is found, that entry is automatically
- dialed.
- X.PP
- The
- X.I \-a
- option is used to specify a script file to be \*(lqplayed\*(rq, the TTY
- to be used, or the modem to be used.
- X.PP
- The remaining options are used to set the parity, data bits, baud rate,
- and telephone number from the command line. The normal method of
- dialing is from the dialing directory.
- X.PP
- X.RS 5
- X.B \-e
- X Set the parity to even.
- X.br
- X.B \-o
- X Set the parity to odd.
- X.br
- X.B \-n
- X Set the parity to none.
- X.br
- X.B \-w
- X Set the word length (number of data bits).
- X.br
- X.B \-b
- X Set the baud rate.
- X.br
- X.B \-p
- X Dial this phone number.
- X.RE
- X.PP
- Whenever
- X.I Pcomm
- is in the command mode, a status line is displayed at the bottom of the
- screen. The eight fields of the status line are:
- X.PP
- X.RS 5
- X.nf
- X\(bu help screen command (or a temporary message)
- X\(bu name of the TTY device in use
- X\(bu duplex mode (FDX = full duplex, HDX = half duplex)
- X\(bu current line settings
- X\(bu status of data logging option
- X\(bu status of printer logging option
- X\(bu incoming CR translation
- X\(bu outgoing CR translation
- X.fi
- X.RE
- X.SH COMMANDS
- The following commands are accessible by pressing a user definable
- X\*(lqhot key\*(rq followed by a letter, number, or arrow key. The
- default \*(lqhot key\*(rq is control-A. The notation \*(lq^A-X\*(rq
- means control-A followed by the letter X. The dash (\-) is for clarity,
- and is not a part of the command sequence.
- X.TP
- X.B ^A-0
- Help Screen. Display a brief review of the available commands. Uses
- the number zero \*(lq0\*(rq not the letter \*(lqO\*(rq.
- X.TP
- X.B ^A-D
- Dialing Directory. The dialing directory screen is used to display and
- maintain the database of phone number entries, and to select an entry
- for dialing. To dial an entry, just enter the entry number at the
- prompt. If the script field contains valid Unix shell script, that file
- is \*(lqplayed\*(rq, after the connection is made, to typically log the
- user on to the remote system. See the Pcomm Reference Manual for the
- format and use of the script files. The following commands are
- available from the dialing directory:
- X.RS 5
- X.TP
- X.B R
- Revise (or add) a dialing directory entry or a long distance dialing
- code.
- X.TP
- X.B P
- Print (display) the long distance dialing codes.
- X.TP
- X.B up/down
- Scroll the dialing directory up or down 10 lines. Uses the up and down
- arrow keys.
- X.TP
- X.B M
- Manual dial. Prompts for a phone number rather than using a number
- already in the dialing directory.
- X.TP
- X.B D
- Delete an entry or a range of entries.
- X.TP
- X.B L
- Print. Send the dialing directory to the printer or a file of your
- choice.
- X.RE
- X.TP
- X.B ^A-R
- Automatic redial of selected dialing directory entries. Prompts the
- user for a list of directory entries to be placed in the queue.
- X.I Pcomm
- will dial the numbers in a cycle until one of them answers.
- X.TP
- X.B ^A-M
- Allows the user to maintain a list of keyboard macros assigned to the
- shifted number keys. When pressed, the string assigned to that key is
- sent to the remote system.
- X.TP
- X.B ^A-P
- Adjust the current communication line settings. Display a menu of baud
- rate, parity, data bit, and stop bit choices. Allows the new choice to
- be saved and become the default. After dialing a remote, the line
- settings in the dialing directory entry are automatically used. The
- current line settings are shown in the status line.
- X.TP
- X.B ^A-X
- XExit from
- X.I Pcomm.
- X.TP
- X.B ^A-4
- Spawn a Unix shell while still communicating with the remote system.
- Uses the \*(lqnative\*(rq shell as described in the SHELL environmental
- variable.
- X.TP
- X.B ^A-5
- Select a script file to be used to automate common keyboard input and
- to perform Pcomm command sequences.
- X.TP
- X.B ^A-I
- Display the program information screen.
- X.TP
- X.B ^A-S
- Display a choice of setup screens. The following sub-menus are
- available:
- X.RS 5
- X.TP
- X.B 1
- TTY Setup. This setup assigns the TTY ports that
- X.I Pcomm
- is allowed to use, and what is attached to each port.
- X.TP
- X.B 2
- Modem Setup. The modem setup contains the commands to make the modem
- dial, hang up the phone, etc.
- X.TP
- X.B 3
- Terminal Setup. The terminal setup contains the definition of the
- X\*(lqhot key\*(rq and the mapping of the end-of-line characters.
- X.TP
- X.B 4
- General Setup. The general setup contains the default log file name,
- and the set of character synonyms.
- X.TP
- X.B 5
- ASCII Transfer Setup. This setup screen contains additional character
- translations allowed during ASCII file transfers.
- X.TP
- X.B 6
- XExternal Protocol Setup. This setup screen allows the user to embed the
- names of external file transfer programs into the list of available
- protocols.
- X.TP
- X.B S
- Save the changes to disk.
- X.RE
- X.TP
- X.B ^A-B
- Change the current working directory.
- X.TP
- X.B ^A-C
- Clear the local screen and home the cursor.
- X.TP
- X.B ^A-E
- Toggle the duplex mode from full to half, or from half to full. The
- status line shows the current duplex mode.
- X.TP
- X.B ^A-H
- Hang up the phone. Disconnect the phone, but remain in
- X.I Pcomm.
- X.TP
- X.B ^A-L
- Toggle the printer on and off. Since the printer is accessed through
- the normal Unix spool program, the output is not sent to the printer
- until
- X.B after
- this feature is turned off.
- X.TP
- X.B ^A-3
- Toggle the incoming line termination characters between the carriage
- return and the carriage return line feed pair. This affects the
- terminal session only, not the file transfers. The current settings are
- shown in the status line.
- X.TP
- X.B ^A-7
- Send a modem break. This is
- X.B not
- the same as the break key on the keyboard.
- X.TP
- X.B ^A-up
- Display a menu of file transfer protocols to be used to send files to a
- remote system. Uses the up arrow key.
- X.TP
- X.B ^A-down
- Display file transfer protocols to be used to receive files from a
- remote system. Uses the down arrow key.
- X.TP
- X.B ^A-F
- Display the contents of a Unix directory.
- X.TP
- X.B ^A-G
- Dump the contents of the screen to a specified file. Special graphics
- characters may not be represented accurately in the file.
- X.TP
- X.B ^A-1
- Begin data logging. Prompts the user for the name of the file that will
- be used to collect a complete record of the terminal session.
- X.TP
- X.B ^A-2
- Toggle the data logging option without prompting for a new file name.
- The status line shows the current data logging mode.
- X.SH "FILE TRANSFERS"
- X.I Pcomm
- understands the following file transfer protocols:
- X.PP
- X.RS 5
- X.TS
- l l l l
- l l l l
- X_ _ _ _
- l l l l.
- protocol packet error multiple
- name size method files?
- xmodem 128 checksum/CRC no
- xmodem-1k 128/1024 checksum/CRC no
- modem7 128 checksum yes
- ymodem 128/1024 CRC yes
- ymodem-g 128/1024 none yes
- ASCII none none no
- zmodem 128/1024 CRC yes
- X(external) ? ? ?
- X.TE
- X.RE
- X.PP
- X.I Pcomm
- can use an external program, such as Kermit or a proprietary program, to
- transfer files. Commonly used external programs (such as zmodem in the
- example above) can have their names embedded into the list of available
- protocols.
- X.PP
- X.SH CONFIGURATION
- X.I Pcomm
- must have access to the terminfo or termcap data for the terminal being
- used. The minimum capabilities include a screen size of at least 80
- columns by 24 lines and cursor movement capabilities. Running
- X.I Pcomm
- from terminals at relatively slow speeds (i.e. 1200 baud) will cause the
- windows to appear sluggish.
- X.PP
- Terminals that don't have arrow keys or systems without the newer
- versions of curses(3) will require the user to substitute the letter
- X\*(lqU\*(rq for \*(lqup arrow\*(rq and \*(lqN\*(rq for \*(lqdown
- arrow\*(rq.
- X.PP
- There are four Pcomm support files that contain the dialing directory,
- the external file transfer programs, the modem/TTY database, and the
- start-up default parameters. Users may maintain private versions of
- these files in a directory of their choice.
- X.I Pcomm
- also uses normal Unix shell scripts to perform the \*(lqchat\*(rq
- sequences necessary to automatically log a user onto a remote system.
- Scripts that invoke Pcomm commands require the use of the
- X.I Pcomm_cmd
- command. See pcomm_cmd(1).
- X.I Pcomm
- uses the environmental variable PCOMM to search for the
- X\*(lqprivate\*(rq support files and script files. The following
- directories are searched to find the files:
- X.PP
- X.RS 5
- X.nf
- X\(bu directory given with the \fI\-d\fP option
- X\(bu directory in the PCOMM environmental variable
- X\(bu current directory
- X\(bu default directory (compiled into Pcomm)
- X.fi
- X.RE
- X.PP
- The script field in the dialing directory serves two purposes. The
- first use is to identify the shell script to use for automating command
- keyboard and command sequences. The second use is to specify a TTY name
- for a given entry. If the script is a valid device name, that device is
- used instead of searching the TTY database for a free port.
- X.SH FILES
- X.TS
- l l.
- pcomm.dial_dir the dialing directory
- pcomm.extrnl the external file transfer programs
- pcomm.modem the modem/TTY database
- pcomm.param the start-up default parameters
- X.TE
- X.SH "SEE ALSO"
- Pcomm Reference Manual, pcomm_cmd(1), waitfor(1), matches(1)
- END_OF_FILE
- if test 9657 -ne `wc -c <'Pcomm.1'`; then
- echo shar: \"'Pcomm.1'\" unpacked with wrong size!
- fi
- # end of 'Pcomm.1'
- fi
- if test -f 'curses.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'curses.c'\"
- else
- echo shar: Extracting \"'curses.c'\" \(8961 characters\)
- sed "s/^X//" >'curses.c' <<'END_OF_FILE'
- X/*
- X * Miscellaneous curses(3) routines.
- X */
- X
- X#define STR_WIDTH 256
- X#define NUM_WIDTH 16
- X
- X#include <stdio.h>
- X#include <curses.h>
- X#include <signal.h>
- X#include "config.h"
- X#include "misc.h"
- X#include "status.h"
- X
- X#ifdef BSD
- X#include <setjmp.h>
- jmp_buf wk_buf;
- X#endif /* BSD */
- X
- X#ifndef OLDCURSES
- X#include <term.h>
- X#else /* OLDCURSES */
- X#ifdef UNIXPC
- X#include <sgtty.h>
- X#endif /* UNIXPC */
- X#endif /* OLDCURSES */
- X
- X/*
- X * Get a string from a window. Similar to wgetstr(), except we limit
- X * the length, return a NULL (not pointer to NULL) on <ESC> key, beep
- X * at any character in "disallow" string, and beep at any character not
- X * in "allow". (It doesn't make sense to use both "allow" and "disallow"
- X * at the same time). Returns a pointer to a static area.
- X */
- X
- char *
- get_str(win, num, allow, disallow)
- WINDOW *win;
- int num;
- char *allow, *disallow;
- X{
- X int count, x, y;
- X char ans, *strchr();
- X static char buf[STR_WIDTH];
- X
- X count = 0;
- X while ((ans = wgetch(win)) != '\r') {
- X /* do our own backspace */
- X if (ans == BS || ans == DEL) {
- X if (!count) {
- X beep();
- X continue;
- X }
- X count--;
- X buf[count] = '\0';
- X getyx(win, y, x);
- X x--;
- X wmove(win, y, x);
- X waddch(win, (chtype) ' ');
- X wmove(win, y, x);
- X wrefresh(win);
- X continue;
- X }
- X /* an <ESC> anywhere in the string */
- X if (ans == ESC)
- X return(NULL);
- X
- X /* illegal character? */
- X if (*disallow != '\0' && strchr(disallow, ans)) {
- X beep();
- X continue;
- X }
- X if (*allow != '\0' && !strchr(allow, ans)) {
- X beep();
- X continue;
- X }
- X /* exceeded the max? */
- X if (count >= num || count >= STR_WIDTH) {
- X beep();
- X continue;
- X }
- X
- X buf[count] = ans;
- X waddch(win, (chtype) ans);
- X wrefresh(win);
- X count++;
- X }
- X buf[count] = '\0';
- X return(buf);
- X}
- X
- X/*
- X * Get a number from a window. We limit the length and return a -1
- X * on <ESC> key.
- X */
- X
- int
- get_num(win, num)
- WINDOW *win;
- int num;
- X{
- X int count, x, y, number;
- X char ans, buf[NUM_WIDTH];
- X
- X count = 0;
- X while ((ans = wgetch(win)) != '\r') {
- X /* do our own backspace */
- X if (ans == BS || ans == DEL) {
- X if (!count) {
- X beep();
- X continue;
- X }
- X count--;
- X buf[count] = '\0';
- X getyx(win, y, x);
- X x--;
- X wmove(win, y, x);
- X waddch(win, (chtype) ' ');
- X wmove(win, y, x);
- X wrefresh(win);
- X continue;
- X }
- X /* an <ESC> anywhere in the string */
- X if (ans == ESC)
- X return(-1);
- X /* only digits are allowed */
- X if (ans < '0' || ans > '9') {
- X beep();
- X continue;
- X }
- X /* exceeded the max? */
- X if (count >= num || count >= NUM_WIDTH) {
- X beep();
- X continue;
- X }
- X
- X buf[count] = ans;
- X waddch(win, (chtype) ans);
- X wrefresh(win);
- X count++;
- X }
- X buf[count] = '\0';
- X number = atoi(buf);
- X return(number);
- X}
- X
- X/*
- X * Change video attributes while printing a string. The use of the
- X * pre-processor definition NOPROMOTE (located in config.h) means that
- X * strings will be printed without any special video attribute if the
- X * requested capability doesn't exist.
- X */
- X
- wattrstr(win, attr, str)
- WINDOW *win;
- chtype attr;
- char *str;
- X{
- X int do_it;
- X /* if nothing, do nothing */
- X if (str == NULL || *str == '\0')
- X return(0);
- X
- X#ifdef OLDCURSES
- X if (attr)
- X wstandout(win);
- X waddstr(win, str);
- X if (attr)
- X wstandend(win);
- X#else /* OLDCURSES */
- X
- X#ifdef NOPROMOTE
- X /* does the capability exist? */
- X do_it = 0;
- X if ((attr & A_STANDOUT) && enter_standout_mode)
- X do_it++;
- X if ((attr & A_UNDERLINE) && enter_underline_mode)
- X do_it++;
- X if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
- X do_it++;
- X if ((attr & A_BLINK) && enter_blink_mode)
- X do_it++;
- X if ((attr & A_BOLD) && enter_bold_mode)
- X do_it++;
- X if ((attr & A_DIM) && enter_dim_mode)
- X do_it++;
- X#else /* NOPROMOTE */
- X do_it = 1;
- X#endif /* NOPROMOTE */
- X
- X if (do_it)
- X wattron(win, attr);
- X /* print the string */
- X waddstr(win, str);
- X if (do_it)
- X wattroff(win, attr);
- X#endif /* OLDCURSES */
- X return(0);
- X}
- X
- X/*
- X * Change video attributes while printing a character.
- X */
- X
- wattrch(win, attr, c)
- WINDOW *win;
- chtype attr;
- char c;
- X{
- X int do_it;
- X
- X if (c == '\0')
- X return(0);
- X#ifdef OLDCURSES
- X if (attr)
- X wstandout(win);
- X waddch(win, (chtype) c);
- X if (attr)
- X wstandend(win);
- X#else /* OLDCURSES */
- X
- X#ifdef NOPROMOTE
- X /* does the capability exist? */
- X do_it = 0;
- X if ((attr & A_STANDOUT) && enter_standout_mode)
- X do_it++;
- X if ((attr & A_UNDERLINE) && enter_underline_mode)
- X do_it++;
- X if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
- X do_it++;
- X if ((attr & A_BLINK) && enter_blink_mode)
- X do_it++;
- X if ((attr & A_BOLD) && enter_bold_mode)
- X do_it++;
- X if ((attr & A_DIM) && enter_dim_mode)
- X do_it++;
- X#else /* NOPROMOTE */
- X do_it = 1;
- X#endif /* NOPROMOTE */
- X
- X if (do_it)
- X wattron(win, attr);
- X /* print the character */
- X waddch(win, (chtype) c);
- X if (do_it)
- X wattroff(win, attr);
- X#endif /* OLDCURSES */
- X return(0);
- X}
- X
- X
- X/*
- X * Change video attributes while printing a number.
- X */
- X
- wattrnum(win, attr, num)
- WINDOW *win;
- chtype attr;
- int num;
- X{
- X int do_it;
- X char buf[40];
- X
- X sprintf(buf, "%d", num);
- X
- X#ifdef OLDCURSES
- X if (attr)
- X wstandout(win);
- X waddstr(win, buf);
- X if (attr)
- X wstandend(win);
- X#else /* OLDCURSES */
- X
- X#ifdef NOPROMOTE
- X /* does the capability exist? */
- X do_it = 0;
- X if ((attr & A_STANDOUT) && enter_standout_mode)
- X do_it++;
- X if ((attr & A_UNDERLINE) && enter_underline_mode)
- X do_it++;
- X if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
- X do_it++;
- X if ((attr & A_BLINK) && enter_blink_mode)
- X do_it++;
- X if ((attr & A_BOLD) && enter_bold_mode)
- X do_it++;
- X if ((attr & A_DIM) && enter_dim_mode)
- X do_it++;
- X#else /* NOPROMOTE */
- X do_it = 1;
- X#endif /* NOPROMOTE */
- X
- X if (do_it)
- X wattron(win, attr);
- X /* print the character */
- X waddstr(win, buf);
- X if (do_it)
- X wattroff(win, attr);
- X#endif /* OLDCURSES */
- X return(0);
- X}
- X
- X/*
- X * Prompt for a Yes or No answer. Echo the single key input as words.
- X * Handle the funny cursor movement problems with magic cookie terminals.
- X * Returns a 1 on yes.
- X */
- X
- int
- yes_prompt(win, y, x, attr, str)
- WINDOW *win;
- int y, x;
- chtype attr;
- char *str;
- X{
- X int ret_code, ans;
- X char new_str[80], *strcpy(), *strcat();
- X /* sanity checking */
- X if (strlen(str) > 71)
- X *(str+71) = '\0';
- X /* build and display the prompt */
- X strcpy(new_str, str);
- X strcat(new_str, "? (y/n):");
- X mvwattrstr(win, y, x, attr, new_str);
- X wmove(win, y, strlen(new_str)+x+2);
- X wrefresh(win);
- X
- X ret_code = -1;
- X while (ret_code == -1) {
- X /* if inside a script */
- X if (status->dup_fd != -1)
- X ans = wait_key(win, 5);
- X else
- X ans = wgetch(win);
- X
- X switch (ans) {
- X case -1:
- X case 'y':
- X case 'Y':
- X waddstr(win, "Yes");
- X ret_code = 1;
- X break;
- X case 'n':
- X case 'N':
- X case ESC:
- X waddstr(win, "No");
- X ret_code = 0;
- X break;
- X default:
- X beep();
- X
- X }
- X }
- X wrefresh(win);
- X return(ret_code);
- X}
- X
- X/*
- X * Handy routine for clear-to-end-of-line. Fixes up the box if requested.
- X */
- X
- int
- clear_line(win, y, x, re_box)
- WINDOW *win;
- int y, x, re_box;
- X{
- X if (wmove(win, y, x) == ERR)
- X return(ERR);
- X
- X wclrtoeol(win);
- X
- X if (re_box) {
- X mvwaddch(win, y, win->_maxx-1, (chtype) ACS_VLINE);
- X wmove(win, y, x);
- X }
- X return(0);
- X}
- X
- X/*
- X * Routine to make a horizontal line. Does NOT do a wrefresh().
- X */
- X
- int
- horizontal(win, x, y, len)
- WINDOW *win;
- int x, y, len;
- X{
- X wmove(win, x, y);
- X
- X while (len--)
- X waddch(win, ACS_HLINE);
- X
- X return(0);
- X}
- X
- X/*
- X * Wait for a key or time out. Returns a -1 on timeout. This is similar
- X * to the half-delay mode in the newer versions of curses(3).
- X */
- X
- static int wk_flag;
- static int wk_force();
- X
- X/* ARGSUSED */
- int
- wait_key(win, sec)
- WINDOW *win;
- unsigned int sec;
- X{
- X int key;
- X unsigned int alarm();
- X#ifdef WGETCH_BROKE
- X char c;
- X#endif /* WGETCH_BROKE */
- X
- X signal(SIGALRM, (SIG_TYPE(*) ()) wk_force);
- X wk_flag = 0;
- X
- X alarm(sec);
- X
- X#ifdef BSD
- X if (setjmp(wk_buf))
- X return(-1);
- X#endif /* BSD */
- X
- X#ifdef WGETCH_BROKE
- X read(0, &c, 1);
- X key = c & 0x7f;
- X#else /* WGETCH_BROKE */
- X key = wgetch(win);
- X#endif /* WGETCH_BROKE */
- X
- X if (wk_flag)
- X return(-1);
- X alarm(0);
- X return(key);
- X}
- X
- X/* ARGSUSED */
- static int
- wk_force(dummy)
- int dummy;
- X{
- X#ifdef BSD
- X longjmp(wk_buf, 1);
- X#else /* BSD */
- X signal(SIGALRM, (SIG_TYPE(*) ()) wk_force);
- X wk_flag = 1;
- X return(0);
- X#endif /* BSD */
- X}
- X
- X/*
- X * Here are some routines that are probably missing from the older
- X * flavors of curses(3).
- X */
- X
- X#ifdef OLDCURSES
- X/*
- X * Make the terminal bell go off
- X */
- X
- int
- beep()
- X{
- X fputc(BEL, stderr);
- X return(0);
- X}
- X
- X/*
- X * Take the terminal out of the "curses mode". The t_mode structure was
- X * captured before we initialized the curses mode.
- X */
- X
- int
- resetterm()
- X{
- X extern char _putchar();
- X extern struct sgttyb t_mode;
- X
- X ioctl(0, TIOCSETP, &t_mode);
- X tputs(TE, 1, _putchar);
- X tputs(VE, 1, _putchar);
- X return(0);
- X}
- X
- X/*
- X * Put the terminal back into the "curses mode". The c_mode structure was
- X * captured after we initialized the curses mode.
- X */
- X
- int
- fixterm()
- X{
- X extern char _putchar();
- X extern struct sgttyb c_mode;
- X
- X ioctl(0, TIOCSETP, &c_mode);
- X tputs(TI, 1, _putchar);
- X tputs(VS, 1, _putchar);
- X return(0);
- X}
- X#endif /* OLDCURSES */
- END_OF_FILE
- if test 8961 -ne `wc -c <'curses.c'`; then
- echo shar: \"'curses.c'\" unpacked with wrong size!
- fi
- # end of 'curses.c'
- fi
- if test -f 'di_win.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'di_win.c'\"
- else
- echo shar: Extracting \"'di_win.c'\" \(9781 characters\)
- sed "s/^X//" >'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
- static int can_sync();
- static 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
- int
- dial_win(repeat)
- int 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
- static void
- disp_queue(win, entry, pass, first)
- WINDOW *win;
- int entry, pass;
- long 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
- static int
- can_sync(baud)
- unsigned 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 <'di_win.c'`; then
- echo shar: \"'di_win.c'\" unpacked with wrong size!
- fi
- # end of 'di_win.c'
- fi
- if test -f 'dial.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dial.c'\"
- else
- echo shar: Extracting \"'dial.c'\" \(9366 characters\)
- sed "s/^X//" >'dial.c' <<'END_OF_FILE'
- X/*
- X * The routines that dial the modem and listen for the return codes.
- X */
- X
- X#define HZ 60
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include "config.h"
- X#include "dial_dir.h"
- X#include "misc.h"
- X#include "modem.h"
- X#include "param.h"
- X
- X#ifdef BSD
- X#include <sys/time.h>
- X#else /* BSD */
- X#include <sys/types.h>
- X#include <sys/times.h>
- X#endif /* BSD */
- X
- X#ifdef UNIXPC
- X#include <sys/phone.h>
- X#endif /* UNIXPC */
- X
- static void do_pause();
- static int match();
- X
- X/*
- X * Get the dial string ready, send it to the modem. The parameter is not
- X * the actual entry number, it is an index into the queue.
- X */
- X
- void
- dial_it(num)
- int num;
- X{
- X int i, skip;
- X char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
- X void send_str();
- X#ifdef UNIXPC
- X extern int fd;
- X struct updata pbuf;
- X unsigned int sleep();
- X#endif /* UNIXPC */
- X
- X /*
- X * Create the string to be sent to the modem. The long distance
- X * codes are added if they are requested.
- X */
- X s[0] = '\0';
- X strcpy(s, modem->dial[modem->m_cur]);
- X
- X switch (dir->q_ld[num]) {
- X case 0: /* no ld code requested */
- X break;
- X case '+':
- X strcat(s, param->ld_plus);
- X break;
- X case '-':
- X strcat(s, param->ld_minus);
- X break;
- X case '@':
- X strcat(s, param->ld_at);
- X break;
- X case '#':
- X strcat(s, param->ld_pound);
- X break;
- X }
- X /*
- X * Purify the phone number by removing all the pretty characters
- X * that don't need to be sent to the modem. Typically the "-",
- X * "(", ")", and space characters are just for looks. To prevent
- X * this action, prepend a "\" to the character.
- X */
- X i = 0;
- X skip = 0;
- X n = dir->number[dir->q_num[num]];
- X while (*n) {
- X if (*n == '\\' && !skip) {
- X skip++;
- X n++;
- X continue;
- X }
- X if (!strchr("-() ", *n) || skip)
- X number[i++] = *n;
- X n++;
- X skip = 0;
- X }
- X number[i] = '\0';
- X /* add it to the string */
- X strcat(s, number);
- X strcat(s, modem->suffix[modem->m_cur]);
- X#ifdef DEBUG
- X fprintf(stderr, "raw dial string: \"%s\"\n", s);
- X#endif /* DEBUG */
- X
- X#ifdef UNIXPC
- X /* special case for OBM */
- X if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
- X /* prepare the modem */
- X pbuf.c_lineparam = DATA|DTMF;
- X pbuf.c_waitdialtone = 5;
- X pbuf.c_linestatus = 0;
- X pbuf.c_feedback = SPEAKERON|NORMSPK;
- X pbuf.c_waitflash = 500;
- X ioctl(fd, PIOCSETP, &pbuf);
- X sleep(1);
- X /* connect the dialer */
- X ioctl(fd, PIOCRECONN);
- X sleep(2);
- X /* dial each digit */
- X n = s;
- X while (*n) {
- X /* switch tone/pulse dialing? */
- X switch (*n) {
- X case '^':
- X pbuf.c_lineparam = DATA|PULSE;
- X ioctl(fd, PIOCSETP, &pbuf);
- X break;
- X case '%':
- X pbuf.c_lineparam = DATA|DTMF;
- X ioctl(fd, PIOCSETP, &pbuf);
- X break;
- X default:
- X ioctl(fd, PIOCDIAL, n);
- X break;
- X }
- X n++;
- X }
- X /*
- X * It seems that the OBM doesn't always talk reliably to
- X * other types of modems (most notibly Telebits). Here
- X * is some witchcraft to fix the problem.
- X */
- X ioctl(fd, PIOCOVSPD);
- X return;
- X }
- X#endif /* UNIXPC */
- X
- X send_str(s, SLOW);
- X return;
- X}
- X
- X/*
- X * Send a string to the modem. Performs all the character synonym
- X * translations.
- X */
- X
- void
- send_str(s, slow)
- char *s;
- int slow;
- X{
- X extern int fd;
- X int skip, has_pause;
- X char *strchr();
- X unsigned int sleep();
- X /* empty string? */
- X if (s == NULL || *s == '\0')
- X return;
- X
- X /* contains a pause? */
- X has_pause = 0;
- X if (strchr(s, '~'))
- X has_pause++;
- X
- X tty_flush(fd, 1);
- X /*
- X * Change the character synonyms to their real values. Writes
- X * the characters to the modem. To remove the special meaning
- X * of one of the characters, prepend a "\" to it.
- X */
- X skip = 0;
- X while (*s) {
- X /* send the literal character */
- X if (skip) {
- X skip = 0;
- X write(fd, s, 1);
- X if (has_pause || slow)
- X tty_drain(fd);
- X if (slow)
- X do_pause();
- X#ifdef DEBUG
- X fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
- X#endif /* DEBUG */
- X s++;
- X continue;
- X }
- X /* turn off the special meaning */
- X if (*s == '\\') {
- X skip++;
- X s++;
- X continue;
- X }
- X /* pause synonym */
- X if (*s == param->pause_char) {
- X sleep(1);
- X s++;
- X continue;
- X }
- X /* carriage return synonym */
- X if (*s == param->cr_char)
- X *s = '\r';
- X /* 2 character control sequence */
- X if (*s == param->ctrl_char) {
- X s++;
- X /* premature EOF? */
- X if (*s == '\0')
- X break;
- X /* upper and lower case */
- X if (*s > '_')
- X *s -= 96;
- X else
- X *s -= 64;
- X }
- X /* escape synonym */
- X if (*s == param->esc_char)
- X *s = ESC;
- X /* modem break synonym */
- X if (*s == param->brk_char) {
- X tty_break(fd);
- X sleep(1);
- X s++;
- X continue;
- X }
- X
- X write(fd, s, 1);
- X#ifdef DEBUG
- X fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
- X#endif /* DEBUG */
- X /*
- X * Because the pause char makes the timing critical, we
- X * wait until the buffer is clear before we continue.
- X */
- X if (has_pause || slow)
- X tty_drain(fd);
- X if (slow)
- X do_pause();
- X s++;
- X }
- X return;
- X}
- X
- X/*
- X * Read the result codes coming back from the modem. Test for the 7
- X * "connect" strings and the 4 "no connect" strings. Return the connected
- X * baud rate (as a string) or the error message.
- X */
- X
- char *
- read_codes(tic)
- int tic;
- X{
- X int i, j, k;
- X char c;
- X static char rc_buf[512];
- X static int rc_index;
- X#ifdef UNIXPC
- X extern int fd;
- X unsigned int sleep();
- X struct updata pbuf;
- X /* special case for OBM */
- X if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
- X ioctl(fd, PIOCGETP, &pbuf);
- X
- X /*
- X * The OBM doesn't use a return message to announce the
- X * connection to a remote, so we fake one. The 1200
- X * is quite arbitrary... it is not an indicator of the
- X * connected baud rate.
- X */
- X if (pbuf.c_linestatus & MODEMCONNECTED)
- X return("1200");
- X
- X sleep(1);
- X return(NULL);
- X }
- X#endif /* UNIXPC */
- X if (tic == 0)
- X rc_index = 0;
- X /* search for key words */
- X for (; rc_index<511; rc_index++) {
- X if ((i = getc_line(1)) <= 0)
- X return(NULL);
- X
- X c = i & 0x7f;
- X#ifdef DEBUG
- X fprintf(stderr, "read_codes: \"%c\", %02x, %03o, %d\n", c, c, c, c);
- X#endif /* DEBUG */
- X /* no NULLs please */
- X if (c == '\0') {
- X if (rc_index)
- X rc_index--;
- X continue;
- X }
- X rc_buf[rc_index] = c;
- X rc_buf[rc_index+1] = '\0';
- X /* the connect strings */
- X if (match(rc_buf, modem->con_3[modem->m_cur]))
- X return("300");
- X
- X if (match(rc_buf, modem->con_12[modem->m_cur]))
- X return("1200");
- X
- X if (match(rc_buf, modem->con_24[modem->m_cur]))
- X return("2400");
- X
- X if (match(rc_buf, modem->con_48[modem->m_cur]))
- X return("4800");
- X
- X if (match(rc_buf, modem->con_96[modem->m_cur]))
- X return("9600");
- X
- X if (match(rc_buf, modem->con_192[modem->m_cur]))
- X return("19200");
- X
- X if (match(rc_buf, modem->con_384[modem->m_cur]))
- X return("38400");
- X
- X /* the no connect strings */
- X if (match(rc_buf, modem->no_con1[modem->m_cur]))
- X return(modem->no_con1[modem->m_cur]);
- X
- X if (match(rc_buf, modem->no_con2[modem->m_cur]))
- X return(modem->no_con2[modem->m_cur]);
- X
- X if (match(rc_buf, modem->no_con3[modem->m_cur]))
- X return(modem->no_con3[modem->m_cur]);
- X
- X if (match(rc_buf, modem->no_con4[modem->m_cur]))
- X return(modem->no_con4[modem->m_cur]);
- X /*
- X * OK.. this is the tricky part. What if the modem returns
- X * the connected rate (in lieu of the DTE rate)? For
- X * example, the message is "CONNECT 14400", but the DTE
- X * is locked at 38400.
- X */
- X if (modem->lock_sp[modem->t_cur]) {
- X for (j=0; j<512; j++) {
- X if (rc_buf[j] == '\0')
- X break;
- X if (isdigit(rc_buf[j])) {
- X k = atoi(&rc_buf[j]);
- X switch(k) {
- X case 7200:
- X return("7200");
- X case 12000:
- X return("12000");
- X case 14400:
- X return("14400");
- X }
- X break;
- X }
- X }
- X }
- X
- X }
- X /* ran out of buffer? */
- X return("ERROR");
- X}
- X
- X/*
- X * Test for a match between two character strings. A non-zero return code
- X * means that s2 was found at the end of s1.
- X */
- X
- static int
- match(s1, s2)
- char *s1, *s2;
- X{
- X register int i;
- X int skip, diff;
- X char new[40];
- X /* if no string to match */
- X if (*s2 == '\0')
- X return(0);
- X /* translate synonyms */
- X i = 0;
- X skip = 0;
- X while (*s2) {
- X /* literal character */
- X if (skip) {
- X skip = 0;
- X new[i++] = *s2;
- X s2++;
- X continue;
- X }
- X /* turn off the special meaning */
- X if (*s2 == '\\') {
- X skip++;
- X s2++;
- X continue;
- X }
- X /* carriage return synonym */
- X if (*s2 == param->cr_char)
- X *s2 = '\r';
- X
- X /* 2 character control sequence */
- X if (*s2 == param->ctrl_char) {
- X s2++;
- X if (*s2 == '\0')
- X break;
- X if (*s2 > '_')
- X *s2 -= 96;
- X else
- X *s2 -= 64;
- X }
- X /* escape synonym */
- X if (*s2 == param->esc_char)
- X *s2 = ESC;
- X
- X new[i++] = *s2;
- X s2++;
- X }
- X new[i] = '\0';
- X
- X diff = strlen(s1) - strlen(new);
- X /* is it possible? */
- X if (diff < 0)
- X return(0);
- X /* test it out */
- X if (!strcmp(&s1[diff], new))
- X return(1);
- X return(0);
- X}
- X
- X/*
- X * Apparently some modems can't take input at the rated speed while
- X * in the command mode. Therefore, a 0.10 sec pause a required between
- X * characters.
- X */
- X
- static void
- do_pause()
- X{
- X#ifdef HAVE_USLEEP
- X usleep(100000);
- X#else /* HAVE_USLEEP */
- X /* Hey! I know these routines are a hack */
- X#ifdef BSD
- X struct timeval tv;
- X struct timezone tz;
- X double t1;
- X
- X gettimeofday(&tv, &tz);
- X t1 = tv.tv_sec + (tv.tv_usec / 1000000.0);
- X do
- X gettimeofday(&tv, &tz);
- X while ((tv.tv_sec + (tv.tv_usec / 1000000.0) - t1) < 0.1);
- X#else /* BSD */
- X struct tms t;
- X long t1;
- X
- X t1 = times(&t);
- X while ((times(&t) - t1) < HZ/10)
- X ;
- X#endif /* BSD */
- X#endif /* HAVE_USLEEP */
- X return;
- X}
- END_OF_FILE
- if test 9366 -ne `wc -c <'dial.c'`; then
- echo shar: \"'dial.c'\" unpacked with wrong size!
- fi
- # end of 'dial.c'
- fi
- if test -f 'm_lib.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'m_lib.c'\"
- else
- echo shar: Extracting \"'m_lib.c'\" \(10182 characters\)
- sed "s/^X//" >'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
- struct MODEM *
- read_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
- int
- up_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
- void
- create_modem(str)
- char *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
- void
- del_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 10182 -ne `wc -c <'m_lib.c'`; then
- echo shar: \"'m_lib.c'\" unpacked with wrong size!
- fi
- # end of 'm_lib.c'
- fi
- if test -f 'main.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'main.c'\"
- else
- echo shar: Extracting \"'main.c'\" \(10162 characters\)
- sed "s/^X//" >'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 */
- char tcbuf[1024];
- struct sgttyb t_mode, c_mode;
- X#ifndef cbreak
- X#define cbreak crmode
- X#endif
- X#endif /* OLDCURSES */
- X
- struct DIAL_DIR *dir;
- struct EXTRNL *extrnl;
- struct MODEM *modem;
- struct PARAM *param;
- struct STATUS *status;
- X
- int fd = -1; /* file descriptor for port */
- int xmc; /* magic cookie terminal */
- int msg_status; /* read/write permissions on TTY */
- char *null_ptr = ""; /* generic char pointer to a null */
- X
- static int quit(), ci_match();
- static void print_usage();
- X
- main(argc, argv)
- int argc;
- char *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
- static int
- quit()
- 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
- int
- can_write(file)
- char *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 *
- uid_fopen(file, mode)
- char *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
- static int
- ci_match(s1, s2)
- char *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
- static void
- print_usage(err_message)
- char *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 <'main.c'`; then
- echo shar: \"'main.c'\" unpacked with wrong size!
- fi
- # end of 'main.c'
- fi
- if test -f 'vcs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vcs.c'\"
- else
- echo shar: Extracting \"'vcs.c'\" \(11086 characters\)
- sed "s/^X//" >'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
- static int vcs_codes[NUM_VCS][VCS_SIZE];/* the VCS codes */
- static int vcs_leadin[NUM_VCS]; /* unique list of lead-in characters */
- static int num_leadin; /* length of lead-in list */
- static int putc_cnt;
- static char putc_buf[VCS_SIZE];
- static int substr(), fake_putc(), match_codes();
- static void fake_it();
- X
- int vcs_param[NUM_VCS][5]; /* positional parameters */
- int 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
- int
- vcs_filter(c)
- char 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
- static int
- match_codes(test, code, k)
- int 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
- void
- vcs_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
- static void
- fake_it(s)
- char *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
- static int
- fake_putc(c)
- char 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
- static int
- substr(s1, s2)
- char *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 <'vcs.c'`; then
- echo shar: \"'vcs.c'\" unpacked with wrong size!
- fi
- # end of 'vcs.c'
- fi
- if test -f 'x_rcv.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'x_rcv.c'\"
- else
- echo shar: Extracting \"'x_rcv.c'\" \(12062 characters\)
- sed "s/^X//" >'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
- unsigned char buf[1029];
- char file_name[15];
- long file_length;
- X
- static int err_method, tot_err, block_size;
- static int send_first();
- X
- int
- rcv_xmodem(win, list, type)
- WINDOW *win;
- char *list;
- int 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
- static int
- send_first(win, max_block, default_err)
- WINDOW *win;
- int 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
- int
- rcv_block(win, got_hdr, max_block, blk)
- WINDOW *win;
- int got_hdr, max_block;
- unsigned 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 <'x_rcv.c'`; then
- echo shar: \"'x_rcv.c'\" unpacked with wrong size!
- fi
- # end of 'x_rcv.c'
- fi
- if test -f 'x_send.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'x_send.c'\"
- else
- echo shar: Extracting \"'x_send.c'\" \(11671 characters\)
- sed "s/^X//" >'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
- static int tot_err, err_method;
- static int rcv_first();
- X
- int
- send_xmodem(win, list, type)
- WINDOW *win;
- char *list;
- int 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
- static int
- rcv_first(win, default_err)
- WINDOW *win;
- int 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
- int
- send_block(win, blk, packet)
- WINDOW *win;
- unsigned char *blk;
- unsigned 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 <'x_send.c'`; then
- echo shar: \"'x_send.c'\" unpacked with wrong size!
- fi
- # end of 'x_send.c'
- fi
- echo shar: End of archive 4 \(of 6\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 5 6 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 6 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
-