v03i003: uucp mail for pc's (2 of 8)
Wietse Venema
wswietse at eutrc3.UUCP
Thu Apr 21 02:42:31 AEST 1988
comp.sources.misc: Volume 3, Issue 3
Submitted-By: "Wietse Venema" <wswietse at eutrc3.UUCP>
Archive-Name: pcmail/Part2
#! /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 2 (of 8)."
# Contents: desk.c errdisp.c gtrans.c kbdinp.c kio.c window.c
# Wrapped by wietse at eutwc1 on Wed Apr 20 16:45:02 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f desk.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"desk.c\"
else
echo shar: Extracting \"desk.c\" \(7613 characters\)
sed "s/^X//" >desk.c <<'END_OF_desk.c'
X/*++
X/* NAME
X/* desk 3
X/* SUMMARY
X/* mail box display
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* #include "mailsh.h"
X/*
X/* void desk()
X/*
X/* int junk_desk()
X/*
X/* char message[];
X/* char comment[];
X/* DESCRIPTION
X/* Most functions in this module are invoked by the keyboard interpreter
X/* and are responsible for the mail box view of message summary lines.
X/*
X/* desk() is the main entry point. It presents the user with a sorted
X/* display of message files and a list of commands to choose from.
X/*
X/* patience() informs the user that an operation may take some time.
X/* It puts the 'one moment please..' in the middle screen window.
X/* As a side effect, it sets the current pager file to none.
X/*
X/* junk_desk() should be invoked when the number of files in the mail box
X/* may have changed. Always returns a zero value. This function
X/* should be called when a message is added to, or deleted from, the
X/* spool directory.
X/*
X/* The strings "message" and "comment" hold path names of the currently
X/* selected message file, and its associated metafile (with message
X/* destination, origin or comments). These names are used by functions
X/* that read, delete or otherwise manipulate message files.
X/* FILES
X/* mail header files in the spool directory
X/* SEE ALSO
X/* pager(3), pager(5), kbdinp(3)
X/* DIAGNOSTICS
X/* If a selected mail message could not be found an error message
X/* is displayed instead.
X/* BUGS
X/* Since a message can be accessed only if its metafile exists,
X/* a message is "lost" when for some reason the metafile is
X/* not available.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Tue May 12 15:35:20 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:37:48 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <time.h>
X#include "defs.h"
X#include "mailsh.h"
X#include "path.h"
X#include "dir.h"
X#include "pager.h"
X#include "screen.h"
X#include "status.h"
X#include "window.h"
X
Xextern struct tm *localtime(); /* std C library */
X
Xhidden void make_desk(); /* forward declarations */
Xhidden int pick_desk();
Xhidden int show_desk();
Xhidden void add_desk();
X
Xhidden File *deskfile = 0; /* mail box pager file */
Xpublic char message[BUFSIZ]; /* path to message file */
Xpublic char comment[BUFSIZ]; /* path to comment file */
Xhidden int msgid; /* message id */
X
X/* description of the mail summary lines in the main screen */
X
Xtypedef struct {
X char *category; /* work, incoming, outgoing, ... */
X char *comtype; /* from, to, ... */
X char *msgpfx; /* message-file prefix */
X char *compfx; /* meta-file prefix */
X int (*access)(); /* message access function */
X} Summary;
X
Xhidden char makeletter[] = "(create a new message)";
X
Xhidden Summary summary[] = {
X "new", makeletter, EDTPFX, COMPFX, mail, /* new mail */
X "Work", "Name:", EDTPFX, COMPFX, mail, /* in preparation */
X "Out", "To:", MSGPFX, XQTPFX, mbox, /* queued */
X "New", "From:", NEWPFX, HDRPFX, mbox, /* new mail */
X "In", "From:", NEWPFX, OLDPFX, mbox, /* old mail */
X 0, /* terminator */
X};
X
Xhidden char dispfmt[] = "%-4s %5d %s %-5s %s";
Xhidden char scanfmt[] = "%s %d";
X
X/* desk - main entry point for message manipulations */
X
Xpublic void desk()
X{
X static Screen screen[] = {
X 'C', "Close", 0, "Terminate the program",
X 'F', "File", file, "Mail a copy of an ordinary file",
X 'N', "Network", call, "Exchange mail with the network",
X 'S', "Setup", setup, "Set communications parameters",
X 'A', "Alias", alias, "Display the alias data base",
X 'P', "Print", print, "Print message-summary display",
X PGUP, PgUp, pu_pager,pageup,
X PGDN, PgDn, pd_pager,pagedn,
X UP, "Up", up_pager,csrup,
X DOWN, "Down", dn_pager,csrdn,
X ENTER, "Enter", pick_desk,"Select message at cursor",
X 0, 0, show_desk,
X "Select a message with cursor keys and press ENTER\n\
Xor select one of the commands in the top line."
X };
X
X kbdinp(screen); /* and there they go... */
X}
X
X/* show_desk - create or refresh a display of the mail box */
X
Xhidden int show_desk()
X{
X if (deskfile == 0) { /* no mail box pager file */
X patience(); /* one moment please... */
X make_desk(deskfile = open_pager()); /* build mail box display */
X } else { /* pager file exists */
X set_pager(deskfile); /* select pager file */
X }
X ds_pager(); /* display it */
X return(0); /* screen is ok */
X}
X
X/* make_desk - build pager file of summary lines */
X
Xhidden void make_desk(pp)
XFile *pp;
X{
X register Summary *s = summary;
X
X /* display the "empty sheet of paper" line first */
X
X app_pager(pp,strcons(dispfmt,s->category,0,s->comtype,"",""));
X
X /* display summary lines for "New", "Work" and "Old" messages */
X
X for (s = summary+1; s->category; s++)
X add_desk(pp,s);
X
X /* sort summary lines in reverser order */
X
X sort_pager(pp,BACK_SORT); /* sort mail box display */
X}
X
X/* pick_desk - user selected a message */
X
Xhidden int pick_desk()
X{
X char type[BUFSIZ];
X register Summary *s;
X
X /*
X * Read message type (in, out, work etc) and sequence number from
X * summary line in the mail box display. Then call the appropriate
X * function to access that message.
X */
X
X type[0] = msgid = 0; /* initialize */
X scan_pager(deskfile,scanfmt,type,&msgid); /* which message chosen? */
X if (msgid == 0) /* new message? */
X msgid = newseqno(); /* choose new message id */
X
X for (s = summary; s->category; s++) { /* try to recognize the */
X if (strcmp(s->category,type) == 0) { /* message type */
X strcpy(message,mesg_file(s->msgpfx,msgid)); /* msg file name */
X strcpy(comment,meta_file(s->compfx,msgid)); /* metafile name */
X return(CALL(s->access)(type,msgid));/* display the message */
X }
X }
X beep(); /* unrecognized message type */
X return(0); /* nothing happened */
X}
X
X/* junk_desk - force rebuilding of mail box display */
X
Xpublic int junk_desk()
X{
X if (deskfile) {
X close_pager(deskfile); /* delete pager file */
X deskfile = 0; /* say it's gone */
X }
X return(0); /* in case one wants it */
X}
X
X/*
X* add_desk() is invoked to build the main mail box menu screen.
X* It searches the spool directory for metafiles of the
X* specified type and writes their contents to the specified
X* pager file, together with message type, message id and
X* creation time of the corresponding message file.
X*/
X
X/* add_desk - append summaries with type in s to pager file in pp */
X
Xhidden void add_desk(pp,s)
XFile *pp;
Xregister Summary *s;
X{
X int prelen = strlen(s->msgpfx); /* length of prefix */
X FILE *fp; /* used to read summaries */
X char *f; /* message file name */
X int dd; /* dir search id */
X int msgno; /* message number */
X struct stat st; /* file information */
X
X for (dd = opendir(maildir); f = readdir(dd); /* void */) {
X if (!strncmp(s->msgpfx,f,prelen) && sscanf(f+prelen,"%d",&msgno)
X && stat(mesg_file(s->msgpfx,msgno),&st) == 0
X && (fp = fopen(meta_file(s->compfx,msgno),"r"))) {
X char meta[BUFSIZ]; /* meta-file info */
X fgets(meta,BUFSIZ,fp); /* read meta info */
X meta[strlen(meta)-1] = '\0'; /* chop off newline char */
X app_pager(pp,strcons(dispfmt,s->category,msgno,
X tstamp(&st.st_mtime),s->comtype,meta));
X fclose(fp);
X }
X }
X closedir(dd); /* terminate file search */
X}
END_OF_desk.c
if test 7613 -ne `wc -c <desk.c`; then
echo shar: \"desk.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f errdisp.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"errdisp.c\"
else
echo shar: Extracting \"errdisp.c\" \(7706 characters\)
sed "s/^X//" >errdisp.c <<'END_OF_errdisp.c'
X/*++
X/* NAME
X/* errdisp 3
X/* SUMMARY
X/* produce an error message display
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* int errdisp(errcode);
X/* int errcode;
X/* DESCRIPTION
X/* errdisp() produces an error display in the middle screen
X/* window. The error code must be one defined in status.h.
X/* Otherwise, an "unknown error" message is displayed.
X/* errdisp() gives the user a chance to read it, before resuming
X/* the program. errdisp() returns its argument, or the
X/* value E_UNKNOWN if an unknown error code was specified.
X/* FUNCTIONS AND MACROS
X/* kbdinp(), open_pager(), app_pager(), ds_pager(), close_pager()
X/* BUGS
X/* Cannot force the user to really stop. It just recommends
X/* to do so.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Thu Apr 9 21:19:05 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:39:44 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include "defs.h"
X#include "screen.h"
X#include "pager.h"
X#include "status.h"
X#include "window.h"
X
X/* forward declarations */
X
Xhidden int ds_error();
X
X/* A list of error mesages */
X
X/* when the spool directory is not found */
X
Xhidden char *e_nospool[] = {
X "",
X "The mail program cannot access essential data files.",
X "",
X "Please check whether the spool directory is present",
X "and whether the environment variable MAILDIR has been",
X "set correctly.",
X 0,
X};
X
X/* when we cannot open as many files as we need */
X
Xhidden char *e_fileno[] = {
X "",
X#ifdef MSDOS
X "Check your CONFIG.SYS file. It should have a line",
X "stating (for example)",
X " FILES = 20 .",
X "While you're at it, also make sure that file also",
X "has a line (for example)",
X " DEVICE = ANSI.SYS .",
X "If your system does not have such a file create",
X "one with an editor and place the file in the root",
X "directory.",
X "Reboot after making the changes and try again.",
X#endif
X#ifdef unix
X "Your UNIX is crippled (not enough file descriptors",
X "per process). Rebuild the system or buy a better one.",
X#endif
X 0,
X};
X
X/* when a program is not found */
X
Xhidden char *e_noprog[] = {
X "",
X "The mail program cannot execute an essential program file.",
X "",
X "Please make sure that the environment variable PATH has",
X "been set to include the directories with the SMAIL, RMAIL,",
X "CICO and EDITOR programs.",
X "Also, make sure that the environment variable EDITOR has",
X "been set to the editor of your preference, and that the",
X "machine has enough free memory",
X 0,
X};
X
X/* when a read error ocurred, or a file could not be opened */
X
Xhidden char *e_readerr[] = {
X "",
X "The mail program cannot read a data file.",
X "",
X "Please check your disk. This may be a serious problem.",
X 0,
X};
X
X/* when a write error occurred */
X
Xhidden char *e_writerr[] = {
X "",
X "The mail program cannot write a data file.",
X "",
X "Please make sure that the disk is not write protected",
X "and that there is sufficient free space.",
X 0,
X};
X
X/* when the program is confused */
X
Xhidden char *e_confused[] = {
X "",
X "The mail program has detected a serious internal problem.",
X "",
X "You are requested to leave the mail system as it is and",
X "call an expert.",
X 0,
X};
X
X/* an unknown error (perhaps the editor returned a nonzero status) */
X
Xhidden char *e_unknown[] = {
X "",
X "The mail program has detected a unknown error. This may",
X "not be a serious problem.",
X 0,
X};
X
X/* when the UNIX host does not ask for login/password */
X
Xhidden char *e_noline[] = {
X "",
X "The mail program is not able to exchange mail with the",
X "network.",
X "",
X "Please check the password, or try again later.",
X 0,
X};
X
X/* when the UNIX host does not send initial protocol messages */
X
Xhidden char *e_noresp[] = {
X "",
X "The mail program is not able to exchange mail with the",
X "network. Probably the password was incorrect.",
X 0,
X};
X
X/* when the UNIX host does not want to talk to us */
X
Xhidden char *e_reject[] = {
X "",
X "The mail program is not able to exchange mail with the",
X "network. Please contact the system administrator who is",
X "responsible for the nearest UNIX system.",
X 0,
X};
X
X/* when the link is lost (timeout,...) */
X
Xhidden char *e_lost[] = {
X "",
X "The mail program has lost contact with the network.",
X "",
X "We suggest that you try again at a later time.",
X 0,
X};
X
X/* the resources are exhausted */
X
Xhidden char *e_sysfail[] = {
X "",
X "The mail program cannot proceed due to the fact",
X "that the computer system is overloaded.",
X "",
X "Consult your local systems manager.",
X 0,
X};
X
X/* bad setup parameter */
X
Xhidden char *e_badsetup[] = {
X "",
X "The mail program cannot communicate with the network",
X "due to missing or invalid data in the setup.",
X "",
X "Check the Setup command in the main menu.",
X 0,
X};
X
X/* when a file could not be removed */
X
Xhidden char *e_unlink[] = {
X "",
X "The mail program cannot remove a data file.",
X "",
X "Please make sure that your disk is not write protected",
X 0,
X};
X
X/* when a file could not be printed */
X
Xhidden char *e_printerr[] = {
X "",
X "The mail programm cannot write to the printer",
X "",
X "Please check your default printer device",
X 0,
X};
X
Xhidden char *e_nouser[] = {
X "",
X "An unknown local user name was specified",
X "",
X "Please check the list of user names",
X 0,
X};
X
Xhidden char *e_ovalias[] = {
X "",
X "There probably is an error in your alias data base,",
X "such that an alias is defined in terms of itself.",
X "",
X "Please check your alias data base, and then try to",
X "send this message again.",
X 0,
X};
X
X/* The folowing data structure links an error code to an error message */
X
Xtypedef struct {
X short code; /* error return value */
X char **msg; /* associated message */
X} msgmap;
X
Xhidden msgmap errmap[] = { /* lookup table for error codes */
X E_UNKNOWN, e_unknown, /* don't remove this one! */
X E_SYSFAIL, e_sysfail,
X E_NOPROG, e_noprog, /* and error messages */
X E_NOSPOOL, e_nospool,
X E_READERR, e_readerr,
X E_WRITERR, e_writerr,
X E_CONFUSED, e_confused,
X E_FILENO, e_fileno,
X E_NOLINE, e_noline,
X E_NORESP, e_noresp,
X E_REJECT, e_reject,
X E_LOST, e_lost,
X E_BADSETUP, e_badsetup,
X E_UNLINK, e_unlink,
X E_PRINTERR, e_printerr,
X E_NOUSER, e_nouser,
X E_OVALIAS, e_ovalias,
X 0, 0, /* terminator */
X};
X
X/* errdisp - set up error pager file, return error code */
X
Xpublic int errdisp(code)
Xint code;
X{
X static Screen screen[] = {
X ENTER, "Enter", 0, "Resume the mail program",
X 0, 0, ds_error,"Press ENTER to continue",
X };
X register msgmap *mp;
X
X /* linear table search; this code is not used heavily */
X
X for (mp = errmap; mp->code && mp->code != code; mp++)
X /* void */ ; /* look it up in table */
X if (mp->code == 0) {
X return(errdisp(E_UNKNOWN)); /* unknown error code */
X } else {
X File *pp = open_pager(); /* open pager file */
X beep(); /* red alert! red alert! */
X mesg_pager(pp,mp->msg); /* copy to pager file */
X kbdinp(screen); /* give a chance to read it */
X close_pager(pp); /* forget screen display */
X return(code); /* return error code */
X }
X}
X
X/* ds_error - display error window */
X
Xhidden int ds_error()
X{
X ds_pager(); /* use "current" pager file */
X return(0); /* say screen up-to-date */
X}
END_OF_errdisp.c
if test 7706 -ne `wc -c <errdisp.c`; then
echo shar: \"errdisp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f gtrans.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"gtrans.c\"
else
echo shar: Extracting \"gtrans.c\" \(10263 characters\)
sed "s/^X//" >gtrans.c <<'END_OF_gtrans.c'
X/*++
X/* NAME
X/* gtrans 3
X/* SUMMARY
X/* g protocol strategy functions
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* #include "gp.h"
X/*
X/* int ginit(fd)
X/* int fd;
X/*
X/* Packet *galloc()
X/*
X/* void gsproto(fd,pk)
X/* int fd;
X/* Packet *pk;
X/*
X/* Packet *grproto(fd)
X/* int fd;
X/*
X/* void gfree(pk)
X/* Packet *pk;
X/*
X/* int gfinit(fd)
X/* int fd;
X/* DESCRIPTION
X/* ginit() exchanges the initial g protocol messages and allocates
X/* memory for packet buffers.
X/*
X/* galloc() returns a pointer to a free packet, after filling
X/* in its k and len fields. This packet is supposed to be filled
X/* with data, and to be subsequently queued with gsproto().
X/*
X/* grproto() extracts the next packet from the input queue.
X/* The packet should be returned to the free pool with gfree().
X/*
X/* gfinit() sends protocol termination messages until it receives one
X/* or until it gets bored.
X/* FUNCTIONS AND MACROS
X/* gsctrl(), gsdata(), grpack(), gfail()
X/* DIAGNOSTICS
X/* ginit(), gfinit() return a nonzero value if there was a problem.
X/*
X/* The other functions return through a call of gfail() in case of
X/* unrecoverable problems.
X/* BUGS
X/* Window size is equal to one. This implies that the program
X/* only sends new data when the previous packet was acknowledged.
X/* However, only the functions in *this* module need to be adapted
X/* to accomodate larger transmission window sizes.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Sun Apr 19 17:30:08 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:41:52 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include "gp.h"
X
X/*
X* "The protocol is defined in terms of message transmissions of 8-bit bytes."
X* "Each message includes one control byte plus a data segment of zero or more"
X* "information bytes. The allowed data segment sizes range between 32 and"
X* "4096 as determined by the formula 32*2^k where k is a 3-bit number."
X*/
X
Xint seglen[] = { /* data segment sizes */
X 1,32,64,128,256,512,1024,2048,4096,
X};
X
Xstatic int sndseg; /* data segment k-value they want */
Xstatic int sndlen; /* data segment length they want */
Xstatic int sndwin; /* transmission window size they want */
X
X#define ourseg 2 /* data segment k-value we want */
X#define ourlen 64 /* data segment length we want */
X#define ourwin 1 /* transmission window size we want */
X
Xstatic Packet *inpk = 0; /* receive packet "pool" */
Xstatic Packet *outpk = 0; /* send packet "pool" */
X
Xstatic int rval = 0; /* our R value */
Xstatic int sval = 1; /* our S value */
X
X/*
X* "Initial synchronization is accomplished with two 3-way handshakes:"
X* "two each of INITA/INITB/INITC. Each sender transmits INITA messages"
X* "repeatedly. When an INITA message is received, INITB is sent in return."
X* "When an INITB message is received *and* an INITB message has been sent,"
X* "an INITC message is sent. The INITA and INITB messages carry with them"
X* "the packet and window size that each receiver wants to use, and the"
X* "senders are supposed to comply. When a receiver has seen all three INIT"
X* "messages, the channel is considered to be open. (...) the INIT messages"
X* "are ignored elsewhere. (...)"
X* "After initial synchronization each receiver sets a modulo-8"
X* "incrementing counter R to 0; each sender sets a similar counter S to 1."
X* "The value of R is always the number of the most recent correctly received"
X* "packet. The value of S is always the first sequence number in the output"
X* "window."
X*
X* Since INIT messages are ignored once the channel has been opened, we
X* set the initial values of R and S at compile time.
X*/
X
X/* ginit - g-protocol start-up */
X
Xint ginit(fd)
Xint fd;
X{
X register int state = 0;
X register int next = 0;
X int count = 0;
X
X /* set up receive packet buffers */
X
X if ((inpk = (Packet *) malloc((unsigned)sizeof(Packet)+ourlen)) == 0) {
X DEBUG(7,"gopen: malloc failed\n","");
X return(FAIL);
X }
X
X /*
X * Very simple automaton for initial message exchanges.
X * We send a packet, receive a packet and so on. The
X * automaton terminates when it reaches its accepting state,
X * when a time-out error occurs, or when it seems to get
X * stuck in one state.
X */
X
X while (state
!= INITC) {
X
X /* select action to be done in this state */
X
X switch (state) {
X case 0: /* initial state */
X gsctrl(fd,INITA|IFLD(ourwin)); /* send INITA message */
X break;
X case INITA: /* we received INITA */
X gsctrl(fd,INITB|IFLD(ourseg-1)); /* send INITB in response */
X break;
X case INITB: /* we received INITB */
X gsctrl(fd,INITC|IFLD(ourwin)); /* assume we sent INITB */
X break;
X }
X
X /*
X * Transition part of the automaton. Receive a packet and process
X * its contents. Depending on the packet and the current state
X * select a new state. Stay in the current state when a corrupted
X * packet is received or when we receive an unexpected packet.
X * If no packet is received assume we have lost contact and terminate.
X */
X
X switch (next = grpack(fd,inpk)) { /* see what we get */
X case INITA:
X sndwin = IVAL(inpk->c); /* transmission window size */
X state = next;
X break;
X case INITB:
X sndseg = IVAL(inpk->c)+1; /* send-segment type */
X sndlen = seglen[sndseg]; /* send-segment length */
X state = (state == INITA ? next : state);
X break;
X case INITC:
X state = (state == INITB ? next : state);
X break;
X case FAIL: /* corrupted message received */
X break;
X case TIME: /* no message received */
X return(FAIL);
X }
X
X /* check we don't stay in the same state forever */
X
X if (state == next) {
X count = 0;
X } else if (count++ > MAXTRY) {
X return(FAIL);
X }
X }
X
X /* set up transmission buffer "pool" */
X
X if ((outpk = (Packet *) malloc((unsigned)sizeof(Packet)+sndlen)) == 0) {
X DEBUG(7,"gopen: malloc failed\n","");
X return(FAIL);
X }
X return(0);
X}
X
X/*
X* The current version used a window size of 1, i.e. no further data
X* transmissions until the last transmitted data have been acknowledged.
X* The following routines anticipate on future versions with a real pool of
X* transmit and receive buffers.
X*/
X
X/* galloc - allocate send packet, fill in size info */
X
XPacket *galloc()
X{
X register Packet *pk = outpk;
X
X pk->k = sndseg; /* data segment type */
X pk->len = sndlen; /* data segment size */
X return(pk);
X}
X
X/* gfree - release receive packet */
X
Xvoid gfree(pk)
Xregister Packet *pk;
X{
X /* this function intentionally left blank */
X}
X
X/*
X* The central part of the protocol is in the routines gsproto() and
X* grproto(). These are the functions that negotiate with the other
X* host about what data to (re)transmit and to (n)ack.
X* Major changes are to be expected here when larger transmission
X* window sizes are to be supported.
X*/
X
X/* gsproto - queue one packet for transmission */
X
Xvoid gsproto(fd,pk)
Xint fd;
XPacket *pk;
X{
X int numtry = 0; /* retry count */
X
X gsdata(fd,pk,SFLD(sval)|RFLD(rval)); /* send data packet */
X
X inpk->k = ourseg; /* "allocate" receive packet */
X inpk->len = ourlen;
X
X while (numtry < MAXTRY) {
X switch (grpack(fd,inpk)) { /* what is the reply */
X case SHORT: /* SHORT DATA */
X case DATA: /* LONG DATA */
X gsctrl(fd,RJ|RFLD(rval)); /* not now please */
X case RJ: /* REJECT */
X case RR: /* RECEIVER READY */
X if (RVAL(inpk->c) == sval) { /* check their R value */
X sval = (sval+1)&07; /* update our S value */
X return;
X }
X case FAIL: /* bad packet received */
X case TIME: /* no packet received */
X gsdata(fd,pk,SFLD(sval)|RFLD(rval));/* send data packet again */
X numtry++; /* but not forever */
X break;
X case CLOSE:
X gfail(); /* surprise! */
X /* NOTREACHED */
X }
X }
X gfail(); /* too may retries, abort */
X /* NOTREACHED */
X}
X
X/* grproto - take one packet from input queue */
X
XPacket *grproto(fd)
Xint fd;
X{
X int numtry = 0; /* retry count */
X int xpct = (rval+1)&07; /* expected sequence nr */
X register Packet *pk = inpk; /* take one from the "pool" */
X
X pk->k = ourseg; /* initialize receive packet */
X pk->len = ourlen;
X
X while (numtry < MAXTRY) { /* don't loop forever */
X switch (grpack(fd,pk)) { /* see what we got */
X case DATA: /* LONG DATA */
X case SHORT: /* SHORT DATA */
X if (SVAL(pk->c) == xpct) { /* you're the 1 that I want */
X gsctrl(fd,RR|RFLD(rval = xpct));/* update R and acknowledge */
X return(pk); /* we are done here */
X } /* else ignore the packet */
X case FAIL: /* bad packet */
X gsctrl(fd,RJ|RFLD(rval)); /* reset their S value */
X case TIME: /* no packet, no nak */
X numtry++; /* don't loop forever */
X break; /* read another packet */
X case RR: /* RECEIVER READY */
X case RJ: /* REJECT */
X break; /* ignore */
X case CLOSE: /* surprise! */
X gfail(); /* boy, am I confused */
X /* NOTREACHED */
X }
X }
X gfail(); /* too may retries, abort */
X /* NOTREACHED */
X}
X
X/*
X* "The CLOSE message is used to terminate communications. Software on"
X* "either or both ends of the communication channel may initiate"
X* "termination. In any case when one end wants to terminate it sends"
X* "CLOSE messages until one is received from the other end or until a"
X* "programmable limit on the number of CLOSE messages is reached. Receipt"
X* "of a CLOSE message causes a CLOSE message to be sent."
X*
X* Normally systems decide together when to turn off the protocol so
X* that each system will start sending CLOSE messages at the same time.
X*
X* When a CLOSE message is received in the middle of a conversation
X* a protocol error is generated in grproto() or gsproto(). Then
X* gfinit() is called, so that the other system still sees a few CLOSE
X* messages.
X*/
X
X/* gfinit - shut down the g protocol */
X
Xint gfinit(fd)
Xint fd;
X{
X register int numtry;
X
X for (numtry = 0; numtry < MAXTRY; numtry++) { /* programmable limit */
X gsctrl(fd,CLOSE); /* send CLOSE message */
X if (grpack(fd,inpk) == CLOSE) /* hope for same */
X return(0); /* got it */
X }
X return(FAIL); /* no CLOSE received */
X}
END_OF_gtrans.c
if test 10263 -ne `wc -c <gtrans.c`; then
echo shar: \"gtrans.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f kbdinp.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"kbdinp.c\"
else
echo shar: Extracting \"kbdinp.c\" \(12538 characters\)
sed "s/^X//" >kbdinp.c <<'END_OF_kbdinp.c'
X/*++
X/* NAME
X/* kbdinp 3
X/* SUMMARY
X/* keyboard interpreter
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* void kbdinp(screen)
X/* Screen *screen;
X/*
X/* void kbdinit()
X/* void kbdrest()
X/* DESCRIPTION
X/* The keyboard interpreter is the machine that executes the program
X/* that is recorded in the form of Screen data structures.
X/* Its task is to interpret keyboard input and to
X/* invoke the appropriate action functions.
X/*
X/* Depending on the return value of an action function
X/* the keyboard interpreter i) returns (S_BREAK), ii) repaints the
X/* screen (S_REDRAW), or iii) just waits for more keyboard
X/* input. Error handling is entirely up to the action functions.
X/*
X/* The routines in this module are responsible for what appears in the
X/* top (function-key labels) and bottom sections (command dialogue)
X/* of the tty screen.
X/*
X/* The middle screen section is handled by the pager (except when
X/* help info is displayed).
X/*
X/* kbdinit() sets the tty driver and keypad modes (no echo,
X/* punctual input).
X/* kbrest() restores the modes to what they were before the
X/* program was entered.
X/*
X/* Terminal-specific codes for function keys and keypad are borrowed
X/* from window.c.
X/* FUNCTIONS AND MACROS
X/* printcl(), printat(), putw(), printw(), beep(), winout()
X/* SEE ALSO
X/* window(3) window management routines, function key codes
X/* window(5) window definitions
X/* screen(3) command key tables for each screen
X/* screen(5) structure of command key tables
X/* DIAGNOSTICS
X/* It beeps when an illegal key is pressed. Otherwise, no error
X/* handling at all.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Thu Apr 2 18:43:12 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:42:29 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include <signal.h>
X#include <ctype.h>
X#include "defs.h"
X#include "mailsh.h"
X#include "screen.h"
X#include "window.h"
X
X#ifdef unix
X# if (SIII||SYSV) /* AT&T */
X# include <termio.h>
X struct termio oldmode;
X# else /* V7 or Berkeley */
X# include <sgtty.h>
X struct sgttyb oldmode;
X# endif
X#endif
X
X#define QUEST "? " /* prompt for input */
X#define STRLEN ((wsize[BOT]-1)*CO-sizeof(QUEST)-2) /* max. input length */
X
Xhidden void kb_help(),kb_pause(); /* forward declarations */
Xhidden int kb_paint();
Xhidden int kb_str(),kb_key(),kb_cr();
Xhidden int input(),isempty(); /* forward declarations */
X
Xhidden char sect[] = "===============================================================================";
X
X/* kbdinp - recursively interpret screen descriptions */
X
Xpublic int kbdinp(screen)
XScreen *screen;
X{
X kb_paint(screen);
X
X if (iskey(screen->key))
X return(kb_key(screen)); /* single-key commands */
X else if (screen->key == STRING)
X return(kb_str(screen)); /* string input screen */
X else if (screen->key == ESCCR)
X return(kb_cr(screen)); /* confirm/cancel screen */
X else
X fatal("kbdinp"); /* unexpected screen type */
X /* NOTREACHED */
X}
X
X/* kb_paint - paint the screen (clean up this function) */
X
Xhidden int kb_paint(p)
Xregister Screen *p;
X{
X char topline[BUFSIZ]; /* key label line */
X register int k; /* loop control variable */
X int stat; /* status from mid window */
X int promptloc; /* where prompt "?" goes */
X
X /*
X * The top section of the screen consists of one line with
X * key labels (in case of single-key input screen) and a
X * bar that separates this section from the middle screen section.
X *
X * We always add a Help and ? label. The keyboard interpreter
X * preempts the H and ? characters.
X */
X
X for (topline[0] = 0; p->key; p++) { /* start top window */
X if (iskey(p->key)) { /* keystroke input ? */
X strcat(topline,p->name); /* append key label */
X strcat(topline," "); /* and some blanks */
X } else if (topline[0]) { /* leak if first entry */
X fatal("mixed single-key and string input");
X }
X }
X printcl(TOP,0,topline); /* display key labels */
X if (topline[0]) /* if there are labels */
X printw("Help ?"); /* display help key label too */
X printcl(TOP,1,sect); /* finish top window with bar */
X
X /*
X * The bottom section of the screen consists of a bar that separates
X * us from the middle section, followed by the "help" string in
X * the last entry of the current screen definition, followed by
X * (if not a single-key input screen) a prompting question mark.
X *
X * We display the middle window after doing most of the bottom
X * section, so that the cursor can stay in the middle window in
X * case of single-key input screens.
X *
X * We display the prompt (no single-key input screens) in the
X * bottom section after doing the middle screen section, so that
X * the cursor can stay together with the prompt.
X */
X
X printcl(BOT,0,sect); /* start lower window */
X promptloc = printcl(BOT,1,p->help ? p->help : "")+1; /* general info */
X for (k = promptloc; k < wsize[BOT]; k++) /* clear rest of lower window */
X printcl(BOT,k,""); /* lower window done */
X
X if (p->action) /* fill middle window */
X stat = CALL(p->action)(); /* middle window done */
X
X if (topline[0] == '\0') /* single-key screen? */
X printat(BOT,promptloc,QUEST); /* output "?" prompt */
X
X return(stat); /* from middle window filler */
X}
X
X/* kb_str - handle string input */
X
Xhidden int kb_str(p)
Xregister Screen *p;
X{
X char string[BUFSIZ]; /* a character buffer */
X register char *cp = string; /* a character pointer */
X register int c; /* a character */
X register int stat;
X
X for (;;) {
X if (!isascii(c = input())) { /* ignore non-ascii codes */
X beep(); /* complain */
X } else if (c == ESC) { /* ESC means don't do it */
X printw(" (ESC)"); /* confirm input */
X return(0); /* nothing left here to do */
X } else if ((c == ' ' || isprint(c)) && cp-string < STRLEN) {
X putw(*cp++ = c); /* accept/echo the character */
X } else if (cp > string && (c == BS || c == DEL)) {/* delete character */
X cp--; /* remove char from buffer */
X printw("\b \b"); /* remove char from screen */
X } else if (c != ENTER || (*cp = 0,isempty(string))) {
X beep(); /* complain */
X } else if (putw(c),((stat = CALL(p->action)(string)) & S_BREAK)) {
X return(stat); /* we're done here */
X } else if (stat & S_REDRAW) { /* screen was changed */
X kb_paint(p); /* restore display */
X }
X }
X}
X
X/* kb_key - handle single-key input */
X
Xhidden int kb_key(p)
XScreen *p;
X{
X register int c; /* a character */
X register Screen *q; /* a screen (eh?) */
X register int stat; /* a status */
X
X for (;;) {
X if ((c = getkey()) == '?' || c == 'H') {/* is it a help request */
X kb_help(p); /* yes, display key info */
X continue; /* skip rest of loop */
X }
X for (q = p; q->key && q->key != c; q++) /* look key up in table */
X /* void */;
X if (q->key == 0) { /* unrecognized key */
X beep(); /* complain */
X continue; /* skip rest of loop */
X } else if (q->action == 0) { /* action-less key */
X return(0); /* we are done here */
X } else if ((stat = CALL(q->action)()) & S_BREAK) {/* action key */
X return(stat); /* we are done here */
X } else if (stat & S_REDRAW) { /* screen was changed */
X kb_paint(p); /* restore screen */
X }
X }
X}
X
X/* kb_cr - handle escape/enter input */
X
Xhidden int kb_cr(p)
XScreen *p;
X{
X register int c;
X
X for (;;) {
X if ((c = input()) == ESC) { /* don't do it */
X printw(" (ESC)"); /* confirm input */
X return(0); /* we are done */
X } else if (c == ENTER) { /* do the action */
X register int stat = CALL(p->action)();
X if (stat & S_BREAK) { /* child kills parent */
X return(stat); /* we are done */
X } else if (stat & S_REDRAW) { /* screen was changed */
X kb_paint(p); /* restore screen */
X }
X } else { /* unacceptable input */
X beep(); /* complain */
X }
X }
X}
X
X/* kb_help - display per-key help info; redraw screen when done */
X
Xhidden void kb_help(p)
Xregister Screen *p;
X{
X static char any[] = "Press any key to continue";
X register int k;
X
X for (k = 0; k < wsize[MID]; k++) /* erase middle window */
X printcl(MID,k,"");
X for (k = 0; p[k].key; k++) /* display key info */
X printcl(MID,k+1,strcons(" %-10s %s",p[k].name,p[k].help));
X for (k = 1; k < wsize[BOT]-1; k++) /* erase bottom window */
X printcl(BOT,k,"");
X printcl(BOT,1,any); /* press any key to continue */
X getkey();
X kb_paint(p); /* redraw screen */
X}
X
X/* structure that associates token value with function-key strings */
X
Xtypedef struct {
X int token; /* key value */
X char **seq; /* key string */
X} Key;
X
Xhidden Key kv[] = {
X UP, &KU, /* key strings are set */
X DOWN, &KD, /* in window.c */
X LEFT, &KL,
X RIGHT, &KR,
X PGUP, &PU,
X PGDN, &PD,
X 0, 0,
X};
X
X/* getkey - get key stroke, detect function keys, ignore case otherwise */
X
Xhidden int getkey()
X{
X register int c;
X register Key *kp;
X char kstr[BUFSIZ];
X
X /*
X * We assume that all function keys produce strings that start with
X * the same character, and that those strings all have the same
X * length. This is a reasonable assumption for cursor-control keys.
X */
X
X if ((c = input()) == *(kv[0].seq)[0]) { /* lead-in char */
X register int lvl;
X for (lvl = 1; lvl < strlen(*(kv[0].seq)); lvl++)
X kstr[lvl] = c = input(); /* read characters first */
X kstr[lvl] = '\0';
X for (kp = kv; kp->token; kp++) /* then compare with strings */
X if (strcmp(*(kp->seq)+1,kstr+1) == 0)
X return(kp->token); /* return token value */
X }
X return(islower(c) ? toupper(c) : c); /* return last character */
X}
X
X/* input - read one character without echoing or waiting for carriage return */
X
Xhidden int input()
X{
X /*
X * On unix systems, the terminal driver has been instructed to
X * not echo and to return one character as soon as it comes available.
X * Also the stdio routines have been instructed to work in an unbuffered
X * fashion. See kbdinit().
X */
X
X#ifdef unix
X return(getchar());
X#endif
X
X /*
X * On IBM-PC machines a function key produces a null character
X * followed by a scan code. We translate the null prefix to
X * an escape character since that is more like normal terminals do.
X * The trick is to find out when we read a null character whether it
X * was produced by pressing a real function-key or by pressing ctrl- at .
X */
X
X#ifdef MSDOS
X register int c;
X return((c = getch()) ? c : kbhit() ? ESC : 0);
X#endif
X}
X
X/* kbdinit - set input mode, turn keypad on */
X
Xpublic void kbdinit()
X{
X /*
X * On unix systems, instruct the terminal driver to not echo
X * terminal input, and to return from a read as soon as one
X * character comes available.
X */
X
X#ifdef unix
X# if (SIII||SYSV)
X struct termio newmode; /* AT&T */
X
X ioctl(0,TCGETA,&oldmode); /* save terminal mode */
X ioctl(0,TCGETA,&newmode); /* get terminal mode */
X newmode.c_iflag &= ~(INLCR|ICRNL|IUCLC|BRKINT);
X newmode.c_oflag &= ~OPOST;
X newmode.c_lflag &= ~(ICANON|ISIG|ECHO);
X newmode.c_cc[4] = 1; /* do single-character reads */
X ioctl(0,TCSETAF,&newmode); /* set terminal mode */
X# else
X struct sgttyb newmode; /* V7 or Berkeley */
X
X gtty(0,&oldmode); /* save terminal mode */
X gtty(0,&newmode); /* get terminal mode */
X newmode.sg_flags |= RAW; /* don't wait for newline */
X newmode.sg_flags &= ~(ECHO|CRMOD); /* no echo, crlf mapping */
X stty(0,&newmode); /* set terminal mode */
X# endif
X#endif
X
X signal(SIGINT,SIG_IGN); /* ignore control-c */
X
X#ifdef unix
X setbuf(stdin,(char *) 0); /* select unbuffered input */
X
X if (KS && *KS) /* if there is a keypad */
X tputs(KS,1,fputchar); /* enable it */
X#endif
X}
X
X/* kbdrest - reset terminal driver to previous state, turn keypad off */
X
Xpublic void kbdrest()
X{
X#ifdef unix
X# if (SIII||SYSV) /* AT&T */
X ioctl(0,TCSETAF,&oldmode);
X# else /* V7 or Berkeley */
X stty(0,&oldmode); /* restore terminal mode */
X# endif
X
X if (KE && *KE) /* if there is a keypad */
X tputs(KE,1,fputchar); /* disable it */
X#endif
X}
X
X/* isempty - check a string is all blanks or empty */
X
Xhidden int isempty(s)
Xregister char *s;
X{
X return(*s == 0 || (isspace(*s) && isempty(s+1)));
X}
END_OF_kbdinp.c
if test 12538 -ne `wc -c <kbdinp.c`; then
echo shar: \"kbdinp.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f kio.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"kio.c\"
else
echo shar: Extracting \"kio.c\" \(4784 characters\)
sed "s/^X//" >kio.c <<'END_OF_kio.c'
X/*++
X/* NAME
X/* kio 3
X/* SUMMARY
X/* interface between uucico and k-protocol driver
X/* PACKAGE
X/* uucp on the TUEnet
X/* SYNOPSIS
X/* kturnon()
X/*
X/* kwrmsg(type,str,fn)
X/* char type, *str;
X/* int fn;
X/*
X/* krdmsg(str,fn)
X/* char *str;
X/* int fn;
X/*
X/* krddata(fn,fp)
X/* int fn;
X/* FILE *fp;
X/*
X/* kwrdata(fp,fn)
X/* FILE *fp;
X/* int fn;
X/*
X/* kturnoff()
X/* IMPLICIT INPUTS
X/* Ifn, Ofn, file descriptors
X/* Debug, debugging level
X/* DESCRIPTION
X/* The k protocol has been developed for the Sytek Localnet local area
X/* network at the Eindhoven University of Technology (THE).
X/* Main features of this network are:
X/*
X/* .IP o
X/* Network partners may talk at different baudrates. This implies
X/* that the network does some buffering and that it needs flow control.
X/* .IP o
X/* The network is normally not transparent for some control
X/* characters (XON,XOFF and locally-defined others), independent
X/* of the value of the eigth bit.
X/* .IP o
X/* Some network stations are connected to telephone modems.
X/*
X/* For these reasons, the k protocol must (i) rely on XON/XOFF flow
X/* control, (ii) be suitable for 7-bit data paths, (iii) avoid
X/* sending of control characters and (iv) provide reliable operation
X/* over dial-in and dial-out telephone lines.
X/*
X/* Data are sent as checksummed 512-byte packets, terminated by an
X/* ASCII CR. Except for packet headers (^P), the k protocol only uses
X/* ASCII codes 040 through 0137. Three data bytes are expanded to four
X/* bytes upon transmission.
X/*
X/* The functions in kio.c form the interface between the uucico
X/* controlling functions, and the k-protocol packet driver.
X/*
X/* kturnon() sets the terminal line characteristics (XON/XOFF). Always
X/* returns zero status.
X/*
X/* krdmsg(), kwrmsg() exchange null-terminated strings.
X/* Exit status zero, or FAIL.
X/*
X/* krddata(), kwrdata() perform file i/o, and accounting. Exit status
X/* zero or FAIL.
X/*
X/* kturnoff() sends a protocol abort sequence. Always returns zero
X/* status.
X/* FUNCTIONS AND MACROS
X/* kread, kread, kwrite, kclose, k-protocol presentation layer
X/* AUTHOR(S)
X/* Wietse Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Mon Feb 3 10:13:34 MET 1986
X/* LAST MODIFICATION
X/* Mon Apr 4 23:42:46 MET 1988
X/* VERSION/RELEASE
X/* 2.4
X/*--*/
X
X#include "uucp.h"
X
X#define BUFLEN BUFSIZ
X
Xkturnon()
X{
X kopen(Ifn);
X return 0;
X}
X
X
Xkturnoff()
X{
X kclose(Ofn);
X return 0;
X}
X
X
Xkwrmsg(type,str,fn)
Xchar type,*str;
Xint fn;
X{
X char bufr[BUFSIZ],*s;
X
X bufr[0] = type;
X s = &bufr[1];
X while (*str)
X *s++ = *str++;
X *s = '\0';
X if (*(--s) == '\n')
X *s = '\0';
X DEBUG(6," kwrmsg: \"%s\"\n",bufr);
X
X return (kwrite(fn,bufr,strlen(bufr)+1) > 0 ? 0 : FAIL);
X}
X
X
Xkrdmsg(str,fn)
Xchar *str;
Xint fn;
X{
X int len;
X
X for (;;) {
X if ((len = kread(fn,str,BUFSIZ)) == 0) {
X continue;
X } else if (len > 0) {
X str[len] = 0;
X DEBUG(6," krdmsg: \"%s\"\n",str);
X str += len;
X if (str[-1] == '\0')
X return 0;
X } else {
X return FAIL;
X }
X }
X}
X
X
Xkwrdata(fp1,fn)
XFILE *fp1;
X{
X char bufr[BUFLEN];
X int len;
X int ret;
X time_t t1,t2;
X long bytes;
X char text[BUFSIZ];
X
X ret = FAIL;
X bytes = 0L;
X time(&t1);
X while ((len = fread(bufr,sizeof (char),BUFLEN,fp1)) > 0) {
X bytes += len;
X if (kwrblk(bufr,len,fn) != len)
X goto acct;
X if (len != BUFLEN)
X break;
X }
X ret = kwrblk(bufr,0,fn);
Xacct:
X time(&t2);
X sprintf(text,ret == 0 ?
X "sent data %ld bytes %ld secs" :
X "send failed after %ld bytes",
X bytes,t2 - t1);
X DEBUG(1,"%s\n",text);
X syslog(text);
X sysacct(bytes,t2 - t1);
X if (ret)
X sysaccf(NULL); /* force accounting */
X return ret;
X}
X
X
Xkrddata(fn,fp2)
XFILE *fp2;
X{
X int len,ret;
X char bufr[BUFLEN];
X time_t t1,t2;
X long bytes;
X char text[BUFSIZ];
X
X ret = FAIL;
X bytes = 0L;
X time(&t1);
X for (;;) {
X len = krdblk(bufr,BUFLEN,fn);
X if (len < 0)
X goto acct;
X bytes += len;
X if (fwrite(bufr,sizeof (char),len,fp2) != len)
X goto acct;
X if (len < BUFLEN)
X break;
X }
X ret = 0;
Xacct:
X time(&t2);
X sprintf(text,ret == 0 ?
X "received data %ld bytes %ld secs" :
X "receive failed after %ld bytes",
X bytes,t2 - t1);
X DEBUG(1,"%s\n",text);
X syslog(text);
X sysacct(bytes,t2 - t1);
X if (ret)
X sysaccf(NULL); /* force accounting */
X return ret;
X}
X
X
Xkrdblk(blk,len, fn)
Xchar *blk;
Xint len,fn;
X{
X int i,ret;
X
X for (i = 0; i < len; i += ret) {
X if ((ret = kread(fn,blk,len-i)) == 0) {
X break;
X } else if (ret > 0) {
X blk += ret;
X } else {
X return FAIL;
X }
X }
X return i;
X}
X
X
Xkwrblk(blk,len,fn)
Xchar *blk;
Xint len,fn;
X{
X return kwrite(fn,blk,len);
X}
END_OF_kio.c
if test 4784 -ne `wc -c <kio.c`; then
echo shar: \"kio.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f window.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"window.c\"
else
echo shar: Extracting \"window.c\" \(9885 characters\)
sed "s/^X//" >window.c <<'END_OF_window.c'
X/*++
X/* NAME
X/* window 3
X/* SUMMARY
X/* screen manager
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* #include "window.h"
X/*
X/* int printcl(window,line,s)
X/* int window;
X/* int line;
X/* char *s;
X/*
X/* int printat(window,line,s)
X/* int window;
X/* int line;
X/* char *s;
X/*
X/* int putw(c)
X/* int c;
X/*
X/* int printw(s)
X/* char *s;
X/*
X/* void clrtoeol()
X/*
X/* void clrtobot()
X/*
X/* void clrscreen()
X/*
X/* void beep()
X/*
X/* int fputchar(c)
X/* int c;
X/*
X/* void wininit() /* extract terminal control from database */
X/* DESCRIPTION
X/* The window manipulator is responsable for three screen windows:
X/* the top window for key labels, the middle window for
X/* information, and the lower window for messages and dialogue.
X/* Use is made of the terminal capability database termcap.
X/*
X/* For MS-DOS systems, there is a termcap facility that generates
X/* escape sequences for the ANSI.SYS terminal driver.
X/*
X/* Appropriate macros for window selection are given in window.h.
X/* Needless to say, all screen output should proceed through
X/* functions in this module.
X/*
X/* All character output functions return the number of screen lines
X/* used for outputting the text (at least 1).
X/*
X/* printat() writes the specified line in the specified window,
X/* starting at the left margin.
X/*
X/* printcl() performs the same functions as printat() and erases to
X/* the end of the line.
X/*
X/* printw() writes a character string to the current cursor location.
X/* putw() does the same for characters. These two functions are
X/* mostly used for output to the top and bottom windows.
X/*
X/* cltroeol(), clrtobot() erase the screen from the cursor to the
X/* end of the line and screen respectively. beep() makes some noise.
X/*
X/* fputchar() outputs a character to stdout, just as putchar,
X/* but it is not a macro.
X/*
X/* wininit() initializes the window manipulator. It reads the
X/* terminal capabilities from the termcap database.
X/* FILES
X/* /etc/termcap, $TERMCAP on V7 or BSD UNIX
X/* /usr/lib/terminfo, $TERMINFO on System-V UNIX
X/* SEE ALSO
X/* window(5) window manager definitions
X/* DIAGNOSTICS
X/* The program is terminated with an error message if no terminal
X/* descriptions could be found, if the terminal lacks some
X/* essential features or if an attempt is made to write outside
X/* a window.
X/* BUGS
X/* This module is a big mess. It should be replaced by a PD
X/* curses/termcap library.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Wed Apr 1 21:14:53 GMT+1:00 1987
X/* LAST MODIFICATION
X/* Mon Apr 4 23:51:29 MET 1988
X/* VERSION/RELEASE
X/* 1.3
X/*--*/
X
X#include <ctype.h>
X#include "defs.h"
X#include "window.h"
X
X#define BUFFERSIZE 1024 /* max. length of termcap entry */
X
Xhidden char outbuf[BUFSIZ]; /* for stdio */
X
Xhidden char tcapent[BUFFERSIZE]; /* storage for termcap entry */
Xhidden char capst[BUFFERSIZE]; /* storage for tgetstr */
Xhidden char *capptr = capst; /* pointer to next tgetstr output */
X
Xextern char *tgetstr(); /* returns capability string */
Xextern char *getenv();
Xextern char *tgoto(); /* returns cursor addressing code */
X
Xpublic char *KU,*KD,*KL,*KR,*PU,*PD; /* function-key strings */
Xpublic char *KS,*KE; /* keypad enable/disable */
X
Xhidden char *CL,*CD,*CM,*CE,*SO,*SE; /* screen capabilities */
Xpublic int CO,LI; /* screen size */
X
Xpublic int wbase[BOT+1]; /* where windows start */
Xpublic int wsize[BOT+1]; /* how big windows are */
X
Xhidden int curwin = 0; /* what window we are in */
Xhidden int curx = 0; /* where we are on the screen */
Xhidden int cury = 0; /* line in that window */
X
Xhidden void winout();
X
X/* printcl - print one line in a window, then clear to end of line */
X
Xpublic int printcl(window,line,s)
Xint window;
Xint line;
Xchar *s;
X{
X if (line < 0 || line >= wsize[window])
X fatal("line %d not in window %d",line,window);
X
X tputs(tgoto(CM,curx = 0,(cury = line)+wbase[curwin = window]),1,fputchar);
X winout(s);
X if (cury < wsize[curwin])
X tputs(CE,1,fputchar);
X fflush(stdout);
X return(cury-line+1);
X}
X
X/* printat - print one line in a window */
X
Xpublic int printat(window,line,s)
Xint window;
Xint line;
Xchar *s;
X{
X if (line < 0 || line >= wsize[window])
X fatal("line %d not in window %d",line,window);
X
X tputs(tgoto(CM,curx = 0,(cury = line)+wbase[curwin = window]),1,fputchar);
X winout(s);
X fflush(stdout);
X return(cury-line+1);
X}
X
X/* putw - put character at current location */
X
Xpublic int putw(c)
Xint c;
X{
X register int line = cury;
X char buf[2];
X
X buf[0] = c;
X buf[1] = '\0';
X winout(buf);
X fflush(stdout);
X return(cury-line+1);
X}
X
X/* printw - formatted print at current location */
X
Xpublic int printw(s)
Xchar *s;
X{
X register int line = cury;
X
X winout(s);
X fflush(stdout);
X return(cury-line+1);
X}
X
X/* winout - keep track of the column we are in (clean this up) */
X
X/*
X* Routine to check that output stays within its window.
X* It takes care of terminals that cannot wrap long lines
X* or cannot backspace across the beginning of a line.
X*/
X
Xhidden void winout(s) /* implicit inputs/outputs: cury,curx,curwin,wsize */
Xregister char *s;
X{
X register int ch;
X int limit;
X
X for (limit = wsize[curwin]; (ch = (*s&0177)) && cury < limit; s++) {
X if (isprint(ch) || ch == ' ') { /* if printable */
X putchar(ch),curx++; /* leave it alone */
X } else if (ch == '\t') { /* if horizontal tab */
X do {
X winout(" "); /* expand it */
X } while (curx&7 && cury < limit);
X } else if (ch == '\b') { /* backspace */
X if (curx == 0 && cury == 0) {
X /* void */ ; /* don't leave the window */
X } else if ((curx = (curx > 0 ? curx-1 : (cury--,CO-1))) != CO-1) {
X putchar(ch); /* not at start of line */
X } else {
X tputs(tgoto(CM,curx,cury+wbase[curwin]),1,fputchar);
X }
X } else if (ch == '\n') { /* if newline */
X tputs(CE,1,fputchar); /* erase rest of line */
X if ((curx = 0),++cury < limit) /* advance virtual cursor */
X fputs("\r\n",stdout); /* advance physical cursor */
X } else if (ch == '\r') { /* if carriage return */
X putchar(ch),curx = 0; /* output it and reset curx */
X } else if (ch == '\07') { /* if the bell */
X putchar(ch); /* make them sound */
X } else { /* otherwise garbage */
X char buf[3];
X sprintf(buf,"^%c",ch^0100); /* uncontrollify */
X winout(buf); /* output it */
X }
X if (curx >= CO) /* at rhs of screen */
X tputs(tgoto(CM,curx = 0,++cury+wbase[curwin]),1,fputchar);
X }
X}
X
X#ifdef unix
X
X/* fputchar - output a character on stdout */
X
Xpublic int fputchar(c)
Xint c;
X{
X return(putchar(c));
X}
X
X#endif /* unix */
X
X/* clrtoeol - clear to end of line */
X
Xpublic void clrtoeol()
X{
X tputs(CE,1,fputchar);
X}
X
X/* clrtobot - clear to end of screen */
X
Xpublic void clrtobot()
X{
X tputs(CD,1,fputchar);
X}
X
X/* clrscreen - clear screen */
X
Xpublic void clrscreen()
X{
X tputs(CL,1,fputchar);
X}
X
X/* beep - ring the bell */
X
Xpublic void beep()
X{
X putw('\07');
X}
X/* wininit - extract terminal info and initialize window manager */
X
Xpublic void wininit()
X{
X char *term;
X
X setbuf(stdout,outbuf); /* buffer stdout */
X
X term = getenv("TERM");
X switch(tgetent(tcapent,term = getenv("TERM"))) {
X case -1:
X fatal("termcap database not found\n");
X /* NOTREACHED */
X case 0:
X fatal("unknown terminal: %s\n",term);
X /* NOTREACHED */
X }
X /* extract capabilities. should use tables, but what the heck */
X
X if ((CE = tgetstr("ce",&capptr)) == 0 /* clear to end of line */
X || (CD = tgetstr("cd",&capptr)) == 0 /* clear to end of screen */
X || (CL = tgetstr("cl",&capptr)) == 0 /* clear to end of screen */
X#ifdef someday
X || (SO = tgetstr("so",&capptr)) == 0 /* stand-out on */
X || (SE = tgetstr("se",&capptr)) == 0 /* stand-out off */
X#endif
X || (CM = tgetstr("cm",&capptr)) == 0 /* cursor movement */
X || (KU = tgetstr("ku",&capptr)) == 0 /* up-arrow */
X || (KD = tgetstr("kd",&capptr)) == 0 /* down_arrow */
X || (KL = tgetstr("kl",&capptr)) == 0 /* left-arrow */
X || (KR = tgetstr("kr",&capptr)) == 0 /* right-arrow */
X#ifdef unix
X || (PU = tgetstr("k1",&capptr)) == 0 /* page-up (F1) */
X || (PD = tgetstr("k2",&capptr)) == 0 /* page down (F2) */
X#endif
X#ifdef MSDOS
X || (PU = tgetstr("PU",&capptr)) == 0 /* really PgUp */
X || (PD = tgetstr("PD",&capptr)) == 0 /* really PgDn */
X#endif
X || (CO = tgetnum("co")) == 0
X || (LI = tgetnum("li")) == 0)
X fatal("Your terminal is too dumb");
X
X /* the following capabilities are not mandatory */
X
X KS = tgetstr("ks",&capptr); /* keypad on */
X KE = tgetstr("ke",&capptr); /* keypad off */
X
X /* set window base and size */
X
X if (CO < 80)
X fatal("Terminal screen is to narrow");
X wsize[TOP] = 2;
X wbase[TOP] = 0;
X wsize[BOT] = 5;
X wbase[BOT] = LI-wsize[BOT];
X wbase[MID] = wbase[TOP]+wsize[TOP];
X if ((wsize[MID] = wbase[BOT]-wbase[MID]) < 5)
X fatal("Not enough lines on this terminal");
X}
END_OF_window.c
if test 9885 -ne `wc -c <window.c`; then
echo shar: \"window.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 8\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 8 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
uucp: mcvax!eutrc3!wswietse | Eindhoven University of Technology
bitnet: wswietse at heithe5 | Dept. of Mathematics and Computer Science
surf: tuerc5::wswietse | Eindhoven, The Netherlands.
More information about the Comp.sources.misc
mailing list