[comp.sources.misc] v03i003: uucp mail for pc's

wswietse@eutrc3.UUCP (Wietse Venema) (04/20/88)

comp.sources.misc: Volume 3, Issue 3
Submitted-By: "Wietse Venema" <wswietse@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@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-@.
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@heithe5	| Dept. of Mathematics and Computer Science
surf:	tuerc5::wswietse	| Eindhoven, The Netherlands.