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.