wswietse@eutrc3.UUCP (Wietse Venema) (04/20/88)
comp.sources.misc: Volume 3, Issue 5 Submitted-By: "Wietse Venema" <wswietse@eutrc3.UUCP> Archive-Name: pcmail/Part4 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 4 (of 8)." # Contents: Watchit cico.c connect.c email.c gp.h gpres.c ktrans.c # makefile.msc rmail.c startup.c # Wrapped by wietse@eutwc1 on Wed Apr 20 16:45:16 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Watchit -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Watchit\" else echo shar: Extracting \"Watchit\" \(649 characters\) sed "s/^X//" >Watchit <<'END_OF_Watchit' XMicrosoft decided to change the order of function arguments of Xthe rename() function. Check the source against the documentation Xof your compiler. X XSome functions are used in all programs. Therefore, everything has to Xbe compiled with the same memory model. X XSince the assembly-language serial port driver assumes a small Xmemory model, all programs have to be compiled with the small memory Xmodel. X XThe MAILDIR, EDITOR environment variables should hold absolute path Xnames. On MS-DOS systems (floppies!) it is a good idea to include Xthe drive name as well. X XOn some MS-DOS systems the directory listing (file command) does Xnot show the ".." entry. END_OF_Watchit if test 649 -ne `wc -c <Watchit`; then echo shar: \"Watchit\" unpacked with wrong size! fi # end of overwriting check fi if test -f cico.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cico.c\" else echo shar: Extracting \"cico.c\" \(4984 characters\) sed "s/^X//" >cico.c <<'END_OF_cico.c' X/*++ X/* NAME X/* cico 1 X/* SUMMARY X/* uucp file transfer X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* cico -p password [-d debuglevel] X/* DESCRIPTION X/* cico is a program that connects to a real unix host X/* for exchange of spool files. It is a simplified X/* version of the unix uucico (copy-in-copy-out) program. X/* X/* Options: X/* .TP X/* -p password X/* The password that cico will use when logging in on the X/* unix host. X/* .TP X/* -d debuglevel X/* Set the debugging level. It makes both the local cico X/* and the remote uucico more verbose. Default debugging X/* level is 0. X/* FILES X/* cico manipulates various files in the spool directory. X/* See path(5) for the implementation of the message data base. X/* X/* LOGFILE transaction logging X/* s00000 communications parameters X/* SEE ALSO X/* comm(5) communications parameters X/* status(5) error returns X/* DIAGNOSTICS X/* The program terminates with a non-zero exit status if there X/* were problems. The error status codes can be translated X/* to meaningful messages (see status(5)). X/* More technical messages are written to the logfile. X/* BUGS X/* cico only supports the functions needed for exchange of X/* electronic mail. Every incoming data file is treated as X/* if it were a mail message for the user of the pc. 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/* Sat Mar 28 19:58:06 GMT+1:00 1987 X/* LAST MODIFICATION X/* Wed Apr 6 00:18:29 MET 1988 X/* VERSION/RELEASE X/* 1.6 X/*--*/ X X#include <setjmp.h> X#include "defs.h" X#include "logs.h" X#include "params.h" X#include "comm.h" X#include "status.h" X#include "path.h" X Xpublic int *systrap; /* panic button */ Xpublic int dflag = 0; /* debug flag */ X#ifdef unix X public int Debug = 0; /* UUCP compatibility */ X#endif X Xhidden void parse_args(),sanity(); /* forward declarations */ X X/* main program - parse command line options and pull the ropes */ X Xmain(argc,argv) Xint argc; Xchar **argv; X{ X register int status; /* most recent error code */ X jmp_buf mainbuf; /* catch-all */ X X parse_args(argc,argv); /* process cmd arguments */ X X sanity(); /* check systems parameters */ X X if (setjmp(systrap = mainbuf)) /* safety net in case of */ X exit(E_CONFUSED); /* too many long jumps */ X X xopen(); /* init comm. line */ X if ((status = connect()) == 0 /* login on remote system */ X && (status = startproto()) == 0) { /* start comm. protocol */ X status = switcher(MASTER); /* use the protocol */ X endproto(); /* terminate the protocol */ X } /* (ignore errors) */ X disconnect(); /* as it says */ X xclose(); /* close comm. line */ X X exit(status); X /* NOTREACHED */ X} X X/* parse_args - take care of command-line arguments */ X Xhidden void parse_args(argc,argv) Xint argc; Xchar **argv; X{ X while (--argc && *++argv && **argv == '-') { X switch (*++*argv) { X case 'p': X if (--argc == 0) X usage("missing password argument"); X password = *++argv; X break; X case 'd': X if (--argc == 0) X usage("missing debugging level argument"); X sscanf(*++argv,"%d",&dflag); X#ifdef unix X Debug = X#endif X dflag = ((dflag < 0 ? 0 : dflag) > 10 ? 10 : dflag); X break; X default: X usage(strcons("invalid option: -%s",*argv)); X break; X } X } X if (argc > 0) X usage(strcons("unexpected argument: %s",*argv)); X} X X/* sanity - some preliminary work; mainly checks on sanity */ X Xhidden void sanity() X{ X register int status; X register Info *ip; X X if (status = pathinit()) /* check environment */ X exit(status); /* bad environment */ X X if (status = open_log()) /* check the logfile */ X exit(status); /* cannot write */ X X for (ip = comm = getparams(); ip->ident; ip++) { /* check param. file */ X if (ip->strval == 0 || ip->strval[0] == '\0') X exit(E_BADSETUP); /* incomplete setup */ X debug(6)("%s %s\n",ip->ident,ip->strval ? ip->strval : ""); X } X if (password == 0 || *password == 0) X usage("no password specified"); /* no password */ X X strcpy(rmthost,ip[P_HOST].strval); /* remote host name */ X} X X/* usage - print error message and usage string */ X Xusage(str) Xchar *str; X{ X fprintf(stderr,"%s\nusage: cico -p password [-d debuglevel]\n",str); X exit(2); X} END_OF_cico.c if test 4984 -ne `wc -c <cico.c`; then echo shar: \"cico.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f connect.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"connect.c\" else echo shar: Extracting \"connect.c\" \(5702 characters\) sed "s/^X//" >connect.c <<'END_OF_connect.c' X/*++ X/* NAME X/* connect 3 X/* SUMMARY X/* pre- and post protocol host access X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* int connect() X/* X/* int disconnect() X/* DESCRIPTION X/* connect() tries to make a connection to the remote host X/* and to log on, using the dial-up script and login-name X/* entries in the communications parameter file, and the password X/* provided as command-line parameter to the cico program. X/* A simple send-expect script facility is used (no retries X/* or delays). After the dial-up script has completed the program X/* proceeds by expecting the login: prompt and does the final login. X/* X/* disconnect() tries to break a connection, using the disconnect X/* entry in the communications parameter file. Unlike connect() X/* this function is not driven by a send-expect script. X/* X/* The following escape sequences are recognized in send or expect X/* strings: X/* X/* .nf X/* \\b backspace X/* \\r carriage return X/* \\n newline X/* \\t tab X/* \\s space X/* \\f form feed X/* \\nnn octal character value X/* \\\\ a real backslash X/* FUNCTIONS AND MACROS X/* xwrite(), xgetc(), trap(), debug(4)(), log() X/* FILES X/* $MAILDIR/s00000 communications parameter file X/* $MAILDIR/LOGFILE system logfile X/* SEE ALSO X/* params(5) communications parameter file entries X/* DIAGNOSTICS X/* connect() returns a status E_BADSETUP if the systems parameter X/* file contains bad data, and E_NOLINE if the login script fails. 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/* Fri Mar 27 17:11:12 GMT+1:00 1987 X/* LAST MODIFICATION X/* Wed Apr 6 00:19:26 MET 1988 X/* VERSION/RELEASE X/* 1.4 X/*--*/ X X#include <setjmp.h> X#include <ctype.h> X#include "defs.h" X#include "params.h" X#include "status.h" X#include "comm.h" X#include "logs.h" X#include "sysdep.h" X Xhidden char *blnk = " \t"; /* send/expect separators */ X X/* forward declarations */ X Xhidden void conn_send(); Xhidden void conn_xpct(); Xhidden char *escape(); X X/* connect - connect to remote system; simple script processing (no retries) */ X Xpublic int connect() X{ X int *savetrap = systrap; /* save exception handler */ X jmp_buf mytrap; /* our exception handler */ X int retval; /* completion code */ X register char *cp; X X /* set up exception handler */ X X if (retval = setjmp(systrap = mytrap)) { /* get here if expect fails */ X systrap = savetrap; /* it just happened */ X return(retval); X } X X /* optional dial-up sequence */ X X for (cp = strtok(DIAL_SEQUENCE,blnk); cp; cp = strtok((char *)0,blnk)) { X conn_send(escape(cp)); X if (cp = strtok((char *)0,blnk)) X conn_xpct(escape(cp)); X } X X /* mandatory login sequence */ X X conn_xpct("ogin:"); X conn_send(strcons("%s\r",LOGIN_NAME)); X conn_xpct("ssword:"); X conn_send(strcons("%s\r",password)); X X /* restore exception handler */ X X systrap = savetrap; /* get here if expect wins */ X return(0); /* say no problems... */ X} X X/* disconnect - disconnect line */ X Xpublic int disconnect() X{ X conn_send(escape(DISC_SEQUENCE)); /* send disconnect sequence */ X return(0); /* always succeeds... */ X} X X/* conn_send - quick-and-dirty output function */ X Xhidden void conn_send(s) Xregister char *s; X{ X sleep(1); X X if (*s) { X debug(4)("Sending: %S\n",s); X while (*s) { X delay(); X xwrite(ttfd,s++,1); X } X } X} X X/* conn_xpct - primitive pattern matching without meta characters */ X Xhidden void conn_xpct(s) Xchar *s; X{ X register int c,i; X register int n = strlen(s); X X /* X * Keep listening until we time out or until we receive the X * expected string. Make sure that we do not overrun our buffer. X * Parity bits are ignored. X */ X X if (n) { X debug(4)("Expecting: %S\nReceiving: ",s); X X if (n > MSGBUF) n = MSGBUF; X X for (i = 0; (c = xgetc()) != EOF; ) { X msgin[i++] = (c &= 0177); X debug(4)("%C",c); X if (i >= n && strncmp(s,&msgin[i-n],n) == 0) { X debug(4)(" ok!\n"); X return; X } else if (i >= MSGBUF) { X strncpy(msgin,&msgin[i-(n-1)],n-1); X i = n-1; X } X } X debug(4)(" failed!\n"); X trap(E_NOLINE,"LOGIN FAILED (at \"%S\")",s); X } X} X X/* escape - interpret backslash sequences (this function is too big) */ X Xhidden char *escape(s) Xregister char *s; X{ X static char buf[BUFSIZ]; X register char *cp = buf; X X while (*s && cp < buf+BUFSIZ-1) { /* don't overflow the buffer */ X register char ch; X if (*s != '\\') { /* ordinary character */ X *cp++ = *s++; X } else if (isdigit(*++s) && *s < '8') { /* \nnn octal code */ X int c, i; X sscanf(s,"%3o",&c); X *cp++ = c; X i = 1; X s++; X while (i++ < 3 && isdigit(*s) && *s <'8') X s++; X } else if ((ch = *s++) == 0) { /* at string terminator */ X break; X } else if (ch == 'b') { /* \b becomes backspace */ X *cp++ = '\b'; X } else if (ch == 'f') { /* \f becomes formfeed */ X *cp++ = '\f'; X } else if (ch == 'n') { /* \n becomes newline */ X *cp++ = '\n'; X } else if (ch == 'r') { /* \r becomes carriage ret */ X *cp++ = '\r'; X } else if (ch == 's') { /* \s becomes blank */ X *cp++ = ' '; X } else if (ch == 't') { /* \t becomes tab */ X *cp++ = '\t'; X } else { /* \any becomes any */ X *cp++ = ch; X } X } X *cp = '\0'; /* terminate the result */ X return(buf); X} END_OF_connect.c if test 5702 -ne `wc -c <connect.c`; then echo shar: \"connect.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f email.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"email.c\" else echo shar: Extracting \"email.c\" \(5428 characters\) sed "s/^X//" >email.c <<'END_OF_email.c' X/*++ X/* NAME X/* email X/* SUMMARY X/* manipulate work files (mail in preparation) X/* PROJECT X/* pc-mail X/* PACKAGE X/* mailsh X/* SYNOPSIS X/* #include "email.h" X/* X/* int mail() X/* DESCRIPTION X/* The functions in this module are responsible for manipulations X/* on work files and other mail messages in preparation. X/* X/* mail() can be called either when the user has selected a work file in X/* the mail box display or when the user wants to create a new letter. X/* X/* The message file is displayed on the screen and the can choose X/* to print, mail, edit or delete etc. the message. X/* X/* The code in this module is a little tricky, to avoid that a work X/* file exists without a metafile (for the mail box display). X/* COMMANDS X/* the program specified in the EDITOR environment variable, X/* or a system-dependent default. X/* FILES X/* temporary edit file in current directory X/* work file and meta file in spool directory X/* SEE ALSO X/* pager(3), pager(5), kbdinp(3), edit(3) 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:39:13 MET 1988 X/* VERSION/RELEASE X/* 1.3 X/*--*/ X X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X#include "defs.h" X#include "path.h" X#include "dir.h" X#include "pager.h" X#include "screen.h" X#include "mailsh.h" X#include "status.h" X X/* forward declarations */ X Xhidden void junk_work(); Xhidden int queue_work(); Xhidden int edit_work(); Xhidden int show_work(); Xhidden int send_work(); Xhidden int hold_work(); Xhidden int label_work(); X Xhidden File *workfile = 0; /* pager file */ X X/* mail - user has made a choice. show message at cursor */ X Xpublic int mail() X{ X static Screen screen[] = { X 'C', "Close", hold_work,"Send message later, return to main menu", X 'D', "Delete", delete, delcurr, X 'E', "Edit", edit_work,"Edit this message", X 'M', "Mail", send_work,"Send this message to destination", X 'P', "Print", print, printcurr, 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 0, 0, show_work, X "(Reading a message in preparation)", X }; X struct stat s; X X if (stat(message,&s) && errno == ENOENT) /* if new message file */ X edit_work(); /* invoke editor first */ X kbdinp(screen); /* ask disposition */ X junk_work(); /* destroy mail pager file */ X return(S_REDRAW); /* say screen was changed */ X} X X/* show_work - show work file or error message in middle window */ X Xhidden int show_work() X{ X if (workfile) { /* check pager file exists */ X set_pager(workfile); /* select existent display */ X } else if (rd_pager(workfile = open_pager(),message)) {/* create display */ X mesg_pager(workfile,m_msgread); /* cannot display message */ X } X ds_pager(); /* (re)draw display */ X return(0); /* screen is up-to-date */ X} X X/* junk_work - destroy work file display */ X Xhidden void junk_work() X{ X if (workfile) { /* no-op if no display */ X close_pager(workfile); /* release memory */ X workfile = 0; /* say it is gone */ X } X} X X/* edit_work - edit or create a work file */ X Xhidden int edit_work() X{ X register int stat; X X if (stat = edit(message,MAILFILE)) X errdisp(stat); /* edit() had a problem */ X junk_work(); /* force new message display */ X return(S_REDRAW); /* say screen has changed */ X} X X/* hold_work - stop editing but do not yet mail a work file */ X Xhidden int hold_work() X{ X static Screen screen[] = { X STRING, 0, label_work,int_error, X 0, 0, 0, X getsummary, X }; X struct stat s; X X /* X * The user has terminated an editor session, but does not yet want X * to send the message off. The purpose of the following code is to X * ask for a one-line summary, but only if such a comment does not yet X * exist. The summary is used to identify the work file in the main X * mail box display. X */ X X if (stat(message,&s) || !stat(comment,&s)) {/* no msg, or comment exists */ X return(S_BREAK); /* we are done here */ X } else { X return(kbdinp(screen)|S_REDRAW); /* ask for a summary */ X } X} X X/* label_work - save summary line to meta file */ X Xhidden label_work(string) Xchar *string; X{ X register int stat; X X if (stat = metafile(string,comment)) { /* try to create meta file */ X errdisp(stat); /* oops, notify the user */ X return(S_REDRAW); /* say screen has changed */ X } else { X chmod(comment,0444); /* make comments read-only */ X junk_desk(); /* say mail box has changed */ X return(S_BREAK); /* say no more work */ X } X} X X/* send_work - user wants to send work file, ask for destination */ X Xhidden int send_work() X{ X static Screen screen[] = { X STRING, 0, queue_work,int_error, X 0, 0, when, X "Press ESC to cancel. Send message to:", X }; X return(kbdinp(screen)|S_REDRAW); X} X X/* queue_work - spool mail, delete work file and meta file */ X Xhidden int queue_work(to) Xchar *to; X{ X register int stat; X X if (stat = submit(message,to)) { X errdisp(stat); /* cannot queue message */ X return(S_REDRAW); /* say screen has changed */ X } else { X return(unspool()|S_BREAK); /* remove work and meta file */ X } X} END_OF_email.c if test 5428 -ne `wc -c <email.c`; then echo shar: \"email.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f gp.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"gp.h\" else echo shar: Extracting \"gp.h\" \(5523 characters\) sed "s/^X//" >gp.h <<'END_OF_gp.h' X/*++ X/* NAME X/* gp 5 X/* SUMMARY X/* g-protocol internal definitions X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* #include "gp.h" X/* DESCRIPTION X/* .nf X X/* /* include-once file */ X X#ifndef GP X#define GP X X#include <stdio.h> /* needed for stderr */ X X#define MAXTRY 10 /* max nr of retries */ X#define CTRL(x) ((x)^0100) /* for ascii control characters */ X#define MIN(x,y) ((x) < (y) ? (x) : (y)) X#define MAX(x,y) ((x) > (y) ? (x) : (y)) X X#define ALARM 10 /* time-out interval */ X#define MAGIC 0xAAAA /* checksum magic number */ X#define KCTRL 9 /* control packet */ X X#define FAIL (-1) /* corrupted packet */ X#define TIME (-2) /* timed out */ X X/* X* The protocol is defined in terms of message transmissions of 8-bit X* bytes. Each message includes one control byte plus a data segment X* of zero or more information bytes. (...) X* The control byte is partitioned into three fields as depicted below. X* bit 7 6 5 4 3 2 1 0 X* t t x x x y y y X* The t bits indicate a packet type and determine the interpretation X* to be placed on the xxx and yyy the fields. The various interpretations X* are as follows: X* tt interpretation X* 00 control packet X* 10 data packet X* 11 short data packet X* 01 alternate channel X* A data segment accompanies all non-control packets. (...) Type 01 packets X* are never used by UUCP (...) X*/ X X#define TYPE(x) ((x)&0300) /* extract message field */ X X#define CONTROL 0000 /* control message */ X#define DATA 0200 /* data, fixed size */ X#define SHORT 0300 /* short (variable) length data */ X#define ALTCH 0100 /* alternate channel (unused) */ X X/* X* The sequence number of a non-control packet is given by the xxx field. X* Control packets are not sequenced. The newest sequence number, X* excluding duplicate transmissions, accepted by a receiver is placed in X* the yyy field of non-control packets sent to the `other' receiver. X*/ X X#define TVAL(x) (((x)&0377)>>6) /* extract message type */ X#define MVAL(x) (((x)&070)>>3) /* extract control message */ X#define SVAL(x) (((x)&070)>>3) /* extract S(equence) value */ X#define RVAL(x) ((x)&07) /* extract R(received) value */ X#define IVAL(x) ((x)&07) /* extract init value */ X#define SFLD(x) (((x)&07)<<3) /* create S(equence) field */ X#define RFLD(x) ((x)&07) /* create R(received) field */ X#define IFLD(x) ((x)&07) /* create init field */ X X/* X* There are no data bytes associated with a control packet, the xxx field X* is interpreted as a control message, and the yyy field is a value X* accompanying the control message. The control messages are listed X* below in decreasing priority. That is, if several control messags X* are to be sent, the lower-numbered ones are sent first. X* xxx name yyy X* 1 CLOSE n/a X* 2 RJ last correctly received sequence number X* 3 SRJ sequence number to retransmit X* 4 RR last correctly received sequence number X* 5 INITC window size X* 6 INITB data segment size X* 7 INITA window size X*/ X X#define MESG(x) ((x)&070) /* extract control message field */ X X#define CLOSE 0010 /* close message */ X#define RJ 0020 /* reject message */ X#define SRJ 0030 /* selective-reject message (unused) */ X#define RR 0040 /* received ok message */ X#define INITC 0050 /* initialization message */ X#define INITB 0060 /* initialization message */ X#define INITA 0070 /* initialization message */ X X/* declarations for tiny systems without tty driver, timer support etc. */ X X#ifndef unix X X#define read xread X#define write xwrite X#define alarm(x) /* nothing */ X#define signal(x,y) /* nothing */ X#define DEBUG(x,y,z) if (dflag >= x) printf(y,z) X Xextern int dflag; X X#else X X#define DEBUG(l,f,s) if (Debug >= l) fprintf(stderr,f,s) X Xextern int Debug; X X#endif X X/* X* We use one data structre for communication between various levels X* of the g-protocol implementation. Fields in parentheses are relevant X* only when a packet holds data. X* field meaning set by X* c message type gwrite(), grpack() X* (k data segment length galloc(), grpack()) X* (chk 16-bit checksum packet i/o functions) X* (len max. data segment length galloc(), gwrite(), grpack()) X* (data start of "len" bytes this field is fixed) X* (segl nbr of data bytes left gread()) X* (segp start of "segl" bytes gread()) X*/ X X/* structure for communication between various program layers */ X Xtypedef struct { X char k; /* message segment size */ X char c; /* message type */ X int chk; /* data checksum */ X short segl; /* nr of data bytes left */ X char *segp; /* start of the "segl" bytes */ X short len; /* maximum data segment size */ X char data[1]; /* actually a lot of characters */ X} Packet; X X/* functions that manipulate packets */ X Xextern Packet *grproto(); /* take packet from input queue */ Xextern void gfree(); /* release input packet */ Xextern Packet *galloc(); /* allocate output packet */ Xextern void gwproto(); /* place packet in output queue */ Xextern void gfail(); /* panic button */ Xextern void gsctrl(); /* send one control packet */ Xextern void gsdata(); /* send one data packet */ Xextern int grpack(); /* receive one packet */ X Xextern int seglen[]; /* data segment size table */ X X/* standard unix library */ X Xextern char *malloc(); X X#endif /* GP */ 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 12:41:37 GMT+1:00 1987 X/* LAST MODIFICATION X/* Mon Apr 4 23:40:57 MET 1988 X/* VERSION/RELEASE X/* 1.3 X/*--*/ END_OF_gp.h if test 5523 -ne `wc -c <gp.h`; then echo shar: \"gp.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f gpres.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"gpres.c\" else echo shar: Extracting \"gpres.c\" \(6391 characters\) sed "s/^X//" >gpres.c <<'END_OF_gpres.c' X/*++ X/* NAME X/* gpres.c 3 X/* SUMMARY X/* g-protocol general interface X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* int gopen(fd); X/* int fd; X/* X/* int gwrite(fd,buf,len) X/* int fd,len; X/* char *buf; X/* X/* int gread(fd,buf,len) X/* int fd,len; X/* char *buf; X/* X/* int gclose(fd) X/* int fd; X/* DESCRIPTION X/* The functions in this module present an interface that closely X/* resembles the unix kernel i/o interface. X/* X/* gopen() handles the initial message exchange. fd should be X/* connected to a tty line. gopen() normally returns a zero value. X/* X/* gwrite() returns the number of bytes `written' to the remote system. X/* It should be considered an error if this is not equal to the number X/* of bytes requested. X/* A zero-length write should be used to indicate EOF during file transfer. X/* X/* gread() returns the requested number of bytes or the number of X/* bytes sent by the remote system, whichever is smaller. X/* A zero-length read indicates EOF during file transfer. X/* X/* gclose() shuts the protocol down, but does not otherwise change X/* communications line parameters. It normally returns a zero value. X/* FUNCTIONS AND MACROS X/* galloc(), gfree(), gsproto(), grproto() X/* DIAGNOSTICS X/* All functions return -1 in case of unrecoverable problems. X/* BUGS X/* All g protocol routines assume that the XON/XOFF flow control X/* has been turned off. X/* Some parts of the code rely on 8-bit bytes, 16-bit short integers. 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 12:41:37 GMT+1:00 1987 X/* LAST MODIFICATION X/* Mon Apr 4 23:41:36 MET 1988 X/* VERSION/RELEASE X/* 1.3 X/*--*/ X X#include <setjmp.h> X#include "gp.h" X X/* local and forward declarations */ X Xstatic jmp_buf failbuf; Xstatic void gpeek(),gpoke(),memcpy(); X X/* gfail - exception handling */ X Xvoid gfail() X{ X longjmp(failbuf,1); X} X X/* gopen - not quite an analogon of unix open(2) */ X Xint gopen(fd) Xint fd; X{ X return(ginit(fd)); /* do packet stuff elsewhere */ X} X X/* gwrite - g-protocol analogon of unix write(2) */ X Xgwrite(fd,data,len) Xint fd,len; Xchar *data; X{ X /* set up exception handling */ X X if (setjmp(failbuf)) /* in case gsproto fails */ X return(FAIL); /* it just did */ X X /* handle special case of zero-length writes separately */ X X if (len <= 0) { /* end-of-file message */ X register Packet *pk = galloc(); /* allocate output packet */ X gpoke(pk,data,len); /* make null-data packet */ X gsproto(fd,pk); /* send to other side */ X } else { /* true data message */ X register int shot; /* quantum size */ X register int rest; /* amount left to do */ X for (rest = len; rest > 0; rest -= shot,data += shot) { X register Packet *pk = galloc(); /* allocate output packet */ X gpoke(pk,data,shot = MIN(pk->len,rest));/* fill the packet */ X gsproto(fd,pk); X } X } X return(len); /* no problems detected */ X} X X/* gread - g-protocol analogon of unix read(2) */ X Xgread(fd,data,len) Xint fd,len; Xchar *data; X{ X static Packet *pk; /* our byte stock */ X register int igot; /* our return value */ X X /* set up exception handling */ X X if (setjmp(failbuf)) /* in case grproto fails */ X return(FAIL); /* it just did */ X X /* if no bytes in stock, get some fresh ones and see how much we got */ X X if (pk == 0 || pk->segl <= 0) /* we are out of data */ X gpeek(pk = grproto(fd)); /* get fresh packet */ X X /* return as many bytes as asked, or as in stock, whichever is less */ X X if ((igot = MIN(len,pk->segl)) > 0) { X memcpy(data,pk->segp,igot); /* copy to caller's buffer */ X pk->segp += igot; /* update stock pointer */ X pk->segl -= igot; /* update stock count */ X } X if (pk->segl <= 0) /* if we exhausted the stock */ X gfree(pk); /* release packet */ X return(igot); /* no problems detected */ X} X X/* gclose - turn g protocol off */ X Xgclose(fd) Xint fd; X{ X return(gfinit(fd)); /* not here! */ X} X X/* X* "Each transmitter is constrained to observe the maximum data segment" X* "size established during initial synchronization by the receiver that" X* "it sends to. (...) `short' packets have zero or more data bytes but less" X* "than the maximum. The first one or two bytes of the data segment of" X* "a short packet are `count' bytes that indicate the difference between" X* "the maximum size and the number of bytes in the short segment. If the" X* "difference is less than 127, one count byte is used. If the difference" X* "exceeds 127, then the low-order seven bits of the difference are put" X* "in the first data byte and the remaining high-order bit is set as an" X* "indication that the remaining bits of the difference are in the second" X* "byte. X*/ X X/* gpoke - prepare packet for transmission */ X Xstatic void gpoke(pk,data,len) Xregister Packet *pk; Xint len; Xchar *data; X{ X register int diff = pk->len-len; /* packet/data size mismatch */ X X pk->segp = pk->data; /* set up write pointer */ X pk->segl = len; /* actual segment length */ X if (diff < 0 || len < 0) { X DEBUG(7,"gpoke: trouble\n",""); /* something very wrong */ X gfail(); X /* NOTREACHED */ X } else if (diff == 0) { X pk->c = DATA; /* long data segment */ X } else if (diff <= 127) { X pk->c = SHORT; /* short data segment */ X *pk->segp++ = diff; /* one difference byte */ X } else if (diff > 127) { X pk->c = SHORT; /* tiny data segment */ X *pk->segp++ = diff|0200; /* two difference bytes */ X *pk->segp++ = diff>>7; X } X memcpy(pk->segp,data,pk->segl); /* copy data into packet */ X} X X/* gpeek - prepare newly packet for reading */ X Xstatic void gpeek(pk) Xregister Packet *pk; X{ X register int diff; X X pk->segp = pk->data; /* set up read pointer */ X if (TYPE(pk->c) == DATA) { X diff = 0; /* long data segment */ X } else if (TYPE(pk->c) != SHORT) { X DEBUG(7,"gread: trouble\n",""); /* something funny */ X gfail(); X /* NOTREACHED */ X } else if ((diff = *pk->segp++&0377)&0200) {/* short data segment */ X diff = (diff&0177)|((*pk->segp++&0377)<<7); X } X pk->segl = pk->len-diff; /* actual segment size */ X DEBUG(9,"rcv: data %d bytes\n",pk->segl); X} X X/* memcpy - not-so-efficient implementation */ X Xstatic void memcpy(dst,src,len) Xregister char *dst,*src; Xregister int len; X{ X while (len-- > 0) X *dst++ = *src++; X} END_OF_gpres.c if test 6391 -ne `wc -c <gpres.c`; then echo shar: \"gpres.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f ktrans.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"ktrans.c\" else echo shar: Extracting \"ktrans.c\" \(4983 characters\) sed "s/^X//" >ktrans.c <<'END_OF_ktrans.c' X/*++ X/* NAME X/* ktrans 3 X/* SUMMARY X/* k-protocol strategy routines X/* PACKAGE X/* uucp across the TUEnet X/* SYNOPSIS X/* #include "kp.h" X/* X/* krproto(fd,data,size) X/* int fd, *size; X/* char data[MAXPACKSIZ]; X/* X/* kwproto(fd,data,size) X/* int fd, size; X/* char data[MAXPACKSIZ]; X/* X/* kclsproto(fd) X/* int fd; X/* DESCRIPTION X/* The functions in this file take care of handshake and error X/* detection/recovery. The read/write functions return through an X/* external function kfail() in case of fatal errors, or protocol X/* termination by the network partner. X/* X/* The following packet types are used: X/* X/* .nf X/* .in +5 X/* D packets contain data. X/* Y packets are sent when a correct data packet was received. X/* N packets are sent when incorrect data was received. X/* A packets are sent to shut down the k protocol. X/* .fi X/* X/* Krproto() sends the data and either returns normally, or through X/* kfail(). X/* X/* Kwproto() returns the received data or returns through kfail(). X/* X/* Kclsproto() sends the protocol termination sequence to the other X/* side, either to signal the end of transfers, or to confirm X/* reception of an end-of-protocol sequence. X/* X/* The strategy for sending data is as follows: X/* X/* Send packet. X/* If (ACK for last packet) or (NAK for next packet) received, terminate. X/* If (NAK for last packet) or no response received, retransmit. X/* If data received with previous packet nr, ignore and wait for NAK. X/* If data received with next packet nr, NAK that data and terminate. X/* Otherwise (bad packet number, unexpected packet type) abort. X/* X/* The strategy for receiving data is complementary: X/* X/* Wait for packet X/* If expected packet received, ACK it and terminate. X/* If previous data packet received, ACK it and wait for next packet. X/* If bad packet received, send NAK for expected packet. X/* If nothing received, wait for another packet. X/* Otherwise (bad packet number, unexpected packet type) abort. X/* FUNCTIONS AND MACROS X/* kspack, krpack, kfail 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 13:12:08 MET 1986 X/* LAST MODIFICATION X/* Mon Apr 4 23:43:42 MET 1988 X/* VERSION/RELEASE X/* 1.4 X/*--*/ X X#include "kp.h" X Xstatic char recpkt[MAXPACKSIZ]; /* receive packet buffer */ Xstatic int n = 0; /* packet number */ X Xkwproto( fd, packet, size) Xint fd; Xchar *packet; Xint size; X{ X int num, numtry; /* Packet number, tries */ X int len; X X kspack(fd, 'D',n,size,packet); /* Send a D packet */ X X for (numtry = 0; numtry < MAXTRY; numtry++) { X switch(krpack(fd,&num,&len,recpkt)) /* What was the reply? */ X { X case 'D': /* DATA */ X if ((num+1)%64 == n) { /* Previous packet ? */ X numtry = 0; /* Reset counter */ X break; /* Don't ack it; read again */ X } else if (num != (n+1)%64) /* Fatal error, unless it */ X kfail(); /* carries next packet number */ X kspack(fd,'N',num,0,NULLP); /* Can't use data now */ X X case 'N': /* NAK */ X if (n == num) { /* Send another one, */ X kspack(fd, 'D',n,size,packet); X break; X } X num = (--num<0 ? 63:num); /* unless NAK for next packet */ X X case 'Y': /* ACK */ X if (n != num) kfail(); /* If wrong ACK, fail */ X n = (n+1)%64; /* Bump packet count */ X return; X X case TIME: /* No response */ X case FAIL: /* Bad packet */ X kspack(fd, 'D',n,size,packet); X break; /* Send data packet again */ X X default: X kfail(); /* Something else, abort */ X } X } X kfail(); /* Too may retries, abort */ X} X Xkrproto( fd, packet, size) Xint fd; Xchar *packet; Xint *size; X{ X int num, numtry; /* Packet number, tries */ X X for (numtry = 0; numtry < MAXTRY; numtry++) X { X switch (krpack(fd,&num,size,packet)) /* Get packet */ X { X case 'D': X if (num == n) { /* Right packet? */ X kspack(fd,'Y',n,0,NULLP); /* Acknowledge the packet */ X n = (n+1)%64; /* Bump packet number, mod 64 */ X return; X } else if (num == ((n==0) ? 63:n-1)) { /* Previous packet? */ X kspack(fd,'Y',num,0,NULLP); /* Re-ack previous packet */ X numtry = 0; /* Reset counter */ X break; /* Read another packet */ X } else X kfail(); /* Sorry, wrong number */ X X case TIME: /* No packet */ X break; /* Don't NAK */ X X case FAIL: /* Bad packet */ X kspack(fd,'N',n,0,NULLP); /* Return a NAK */ X break; /* Read another packet */ X X default: X kfail(); /* Something else, abort */ X } X } X kfail(); /* Too may retries, abort */ X} X Xkclsproto( fd) Xint fd; X{ X kspack( fd, 'A', 0, 0, NULLP); /* Send an 'A' packet */ X kspack( fd, 'A', 0, 0, NULLP); /* and another two since */ X kspack( fd, 'A', 0, 0, NULLP); /* we won't get ACKs */ X return 0; X} END_OF_ktrans.c if test 4983 -ne `wc -c <ktrans.c`; then echo shar: \"ktrans.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f makefile.msc -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"makefile.msc\" else echo shar: Extracting \"makefile.msc\" \(5643 characters\) sed "s/^X//" >makefile.msc <<'END_OF_makefile.msc' XRM = rm -f XMV = mv XCC = cl XAS = masm X XSHOBJ1 = call.o email.o file.o screen.o mbox.o desk.o XSHOBJ2 = kbdinp.o pager.o window.o setup.o errdisp.o invoke.o XSHOBJ3 = makework.o mailfile.o deskutil.o submit.o edit.o alias.o XSHLIBS = shlib1.lib shlib2.lib shlib3.lib X XSMOBJ = smail.o unalias.o hsearch.o X XRMOBJ = rmail.o X XCMOBJ = cmail.o invoke.o X XCIOBJ1 = comm.o connect.o getwork.o kphys.o kpres.o ktrans.o logs.o XCIOBJ2 = newseqno.o protomsg.o rmtname.o scanwork.o sendwork.o startup.o XCIOBJ3 = switcher.o xpres.o gpres.o gtrans.o gphys.o XCILIBS = cilib1.lib cilib2.lib cilib3.lib X XGENSRC = dir.c myalloc.c params.c path.c newseqno.c ascf.c spoolfil.c \ X str.c XGENOBJ = dir.o myalloc.o params.o path.o newseqno.o ascf.o spoolfil.o \ X str.o X XCFLAGS = -Gs XLDFLAGS = -F 2000 X X.s.o: X $(AS) $*.s ; X $(MV) $*.obj $*.o X X.c.o: X $(CC) $(CFLAGS) -c $*.c X $(MV) $*.obj $*.o X Xall: mail.exe smail.exe rmail.exe cico.exe cmail.exe X Xmail.exe: mailsh.o $(SHLIBS) libgen.lib X $(CC) $(LDFLAGS) -o mail mailsh.o -link $(SHLIBS) libgen.lib \lib\termcap X -exepack mail.exe junk X $(MV) junk mail.exe X Xsmail.exe: $(SMOBJ) libgen.lib X $(CC) $(LDFLAGS) -o smail $(SMOBJ) -link libgen.lib X -exepack smail.exe junk X $(MV) junk smail.exe X Xcmail.exe: cmail.o libgen.lib X $(CC) $(LDFLAGS) -o cmail cmail.o invoke.o -link libgen.lib X -exepack cmail.exe junk X $(MV) junk cmail.exe X Xrmail.exe: rmail.o libgen.lib X $(CC) $(LDFLAGS) -o rmail rmail.o -link libgen.lib X -exepack rmail.exe junk X $(MV) junk rmail.exe X Xcico.exe: cico.o comport.o $(CILIBS) X $(CC) $(LDFLAGS) -o junk cico.o comport.o -link $(CILIBS) libgen X -exepack junk.exe cico.exe X $(RM) junk.exe X Xshlib1.lib: $(SHOBJ1) X $(RM) shlib1.lib X lib shlib1.lib $(SHOBJ1) ; X Xshlib2.lib: $(SHOBJ2) X $(RM) shlib2.lib X lib shlib2.lib $(SHOBJ2) ; X Xshlib3.lib: $(SHOBJ3) X $(RM) shlib3.lib X lib shlib3.lib $(SHOBJ3) ; X Xlibgen.lib: $(GENOBJ) X $(RM) $@ X lib libgen $(GENOBJ) ; X Xcilib1.lib: $(CIOBJ1) X $(RM) $@ X lib cilib1 $(CIOBJ1) ; X Xcilib2.lib: $(CIOBJ2) X $(RM) $@ X lib cilib2 $(CIOBJ2) ; X Xcilib3.lib: $(CIOBJ3) X $(RM) $@ X lib cilib3 $(CIOBJ3) ; X Xdepend: X @grep '^# *include *"' *.c|sed 's/c:# *include *"\([^"]*\)".*/o: \1/g' X Xalias.o: defs.h Xalias.o: path.h Xalias.o: pager.h Xalias.o: mailsh.h Xalias.o: screen.h Xalias.o: status.h Xascf.o: defs.h Xascf.o: ascf.h Xcall.o: defs.h Xcall.o: path.h Xcall.o: screen.h Xcall.o: pager.h Xcall.o: mailsh.h Xcico.o: defs.h Xcico.o: logs.h Xcico.o: params.h Xcico.o: comm.h Xcico.o: status.h Xcico.o: path.h Xcmail.o: defs.h Xcmail.o: dir.h Xcmail.o: path.h Xcmail.o: status.h Xcomm.o: defs.h Xcomm.o: params.h Xcomm.o: comm.h Xconnect.o: defs.h Xconnect.o: params.h Xconnect.o: status.h Xconnect.o: comm.h Xconnect.o: logs.h Xconnect.o: sysdep.h Xdesk.o: defs.h Xdesk.o: mailsh.h Xdesk.o: path.h Xdesk.o: dir.h Xdesk.o: pager.h Xdesk.o: screen.h Xdesk.o: status.h Xdesk.o: window.h Xdeskutil.o: defs.h Xdeskutil.o: pager.h Xdeskutil.o: mailsh.h Xdeskutil.o: screen.h Xdeskutil.o: status.h Xdir.o: defs.h Xdir.o: dir.h Xedit.o: defs.h Xedit.o: path.h Xedit.o: mailsh.h Xedit.o: status.h Xemail.o: defs.h Xemail.o: path.h Xemail.o: dir.h Xemail.o: pager.h Xemail.o: screen.h Xemail.o: mailsh.h Xemail.o: status.h Xerrdisp.o: defs.h Xerrdisp.o: screen.h Xerrdisp.o: pager.h Xerrdisp.o: status.h Xerrdisp.o: window.h Xfile.o: defs.h Xfile.o: screen.h Xfile.o: pager.h Xfile.o: mailsh.h Xfile.o: dir.h Xfile.o: path.h Xfile.o: status.h Xfile.o: window.h Xgetwork.o: defs.h Xgetwork.o: logs.h Xgetwork.o: status.h Xgetwork.o: work.h Xgetwork.o: params.h Xgetwork.o: comm.h Xgphys.o: gp.h Xgpres.o: gp.h Xgtrans.o: gp.h Xhsearch.o: hsearch.h Xinvoke.o: defs.h Xinvoke.o: status.h Xkbdinp.o: defs.h Xkbdinp.o: mailsh.h Xkbdinp.o: screen.h Xkbdinp.o: window.h Xkphys.o: kp.h Xkpres.o: kp.h Xktrans.o: kp.h Xlogs.o: defs.h Xlogs.o: logs.h Xlogs.o: path.h Xlogs.o: status.h Xmailfile.o: defs.h Xmailfile.o: path.h Xmailfile.o: screen.h Xmailfile.o: mailsh.h Xmailsh.o: defs.h Xmailsh.o: path.h Xmailsh.o: status.h Xmailsh.o: mailsh.h Xmailsh.o: window.h Xmakework.o: defs.h Xmakework.o: path.h Xmakework.o: screen.h Xmakework.o: mailsh.h Xmbox.o: defs.h Xmbox.o: path.h Xmbox.o: pager.h Xmbox.o: screen.h Xmbox.o: mailsh.h Xmyalloc.o: defs.h Xnewseqno.o: defs.h Xnewseqno.o: path.h Xnewseqno.o: dir.h Xpager.o: defs.h Xpager.o: window.h Xpager.o: pager.h Xpager.o: path.h Xpager.o: ascf.h Xparams.o: defs.h Xparams.o: path.h Xparams.o: params.h Xpath.o: defs.h Xpath.o: path.h Xpath.o: status.h Xprotomsg.o: defs.h Xprotomsg.o: params.h Xprotomsg.o: comm.h Xprotomsg.o: logs.h Xprotomsg.o: status.h Xrmail.o: defs.h Xrmail.o: dir.h Xrmail.o: path.h Xrmail.o: status.h Xrmtname.o: defs.h Xrmtname.o: params.h Xrmtname.o: comm.h Xrmtname.o: logs.h Xrmtname.o: status.h Xrmtname.o: path.h Xscanwork.o: defs.h Xscanwork.o: params.h Xscanwork.o: comm.h Xscanwork.o: work.h Xscanwork.o: path.h Xscanwork.o: dir.h Xscanwork.o: logs.h Xscreen.o: defs.h Xscreen.o: screen.h Xsendwork.o: defs.h Xsendwork.o: work.h Xsendwork.o: logs.h Xsendwork.o: status.h Xsendwork.o: params.h Xsendwork.o: comm.h Xsetup.o: defs.h Xsetup.o: path.h Xsetup.o: screen.h Xsetup.o: mailsh.h Xsetup.o: pager.h Xsetup.o: params.h Xsetup.o: status.h Xsetup.o: window.h Xsmail.o: defs.h Xsmail.o: path.h Xsmail.o: status.h Xspoolfil.o: defs.h Xspoolfil.o: path.h Xspoolfil.o: ascf.h Xspoolfil.o: status.h Xstartup.o: defs.h Xstartup.o: params.h Xstartup.o: comm.h Xstartup.o: logs.h Xstartup.o: status.h Xstartup.o: sysdep.h Xstr.o: defs.h Xsubmit.o: defs.h Xsubmit.o: path.h Xswitcher.o: defs.h Xswitcher.o: work.h Xswitcher.o: params.h Xswitcher.o: comm.h Xswitcher.o: logs.h Xswitcher.o: status.h Xunalias.o: defs.h Xunalias.o: hsearch.h Xunalias.o: path.h Xunalias.o: ascf.h Xwindow.o: defs.h Xwindow.o: window.h Xxpres.o: defs.h Xxpres.o: params.h Xxpres.o: comm.h Xxpres.o: status.h Xxpres.o: sysdep.h Xxpres.o: logs.h END_OF_makefile.msc if test 5643 -ne `wc -c <makefile.msc`; then echo shar: \"makefile.msc\" unpacked with wrong size! fi # end of overwriting check fi if test -f rmail.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"rmail.c\" else echo shar: Extracting \"rmail.c\" \(6168 characters\) sed "s/^X//" >rmail.c <<'END_OF_rmail.c' X/*++ X/* NAME X/* rmail X/* SUMMARY X/* extract originator from new mail received by cico X/* PROJECT X/* pc-mail X/* PACKAGE X/* rmail X/* SYNOPSIS X/* rmail X/* DESCRIPTION X/* rmail searches for new mail files received by cico and extracts X/* the originator's name, for later use by the mail visual shell. X/* X/* Return address formats we understand (in order of preference): X/* .nf X/* X/* From: address (full_name) (accept the full_name) X/* From: address (accept the address) X/* >From address (take address and keep scanning) X/* From address (take address and keep scanning) X/* X/* .fi X/* To avoid tampering, new files will have read-only permission. X/* X/* In order to avoid corruption, control-c interrupts are disabled. X/* FILES X/* In the spool directory: X/* n<seqno> received mail message X/* h<seqno> extracted originator address X/* SEE ALSO X/* path(5) spool directory, file names X/* cico(1) network process X/* mailsh(1) visual mail shell X/* DIAGNOSTICS X/* Exit status zero when no errors were detected, nonzero in case of file X/* access errors. See status(5) for error codes. X/* BUGS X/* Note that the format "From: full_name <address>" is not X/* recognized. The program will just pick up the first word from X/* full_name. X/* X/* Does not really do a good job when parsing the mail headers. X/* At least, not good enough to extract a return path. 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 Mar 31 20:14:11 GMT+1:00 1987 X/* LAST MODIFICATION X/* Wed Apr 6 00:21:54 MET 1988 X/* VERSION/RELEASE X/* 1.4 X/*--*/ X X#include <setjmp.h> X#include <signal.h> X#include <time.h> X#include <ctype.h> X#include "defs.h" X#include "dir.h" X#include "path.h" X#include "status.h" X Xextern struct tm *localtime(); /* system functions */ X Xhidden void parse_args(); /* forward declarations */ Xhidden void newmail(); Xhidden void extract(); Xhidden void usage(); X X#define HLEN 20 /* nbr of header lines scanned */ X Xhidden int dflag = 0; /* debugging option */ X X#define debug if (dflag) printf X Xmain(argc,argv) Xint argc; Xchar **argv; X{ X signal(SIGINT,SIG_IGN); /* disable ctrl-c */ X parse_args(argc,argv); /* parse command args */ X pathinit(); /* get path info */ X umask(0222); /* make files read-only */ X newmail(); /* get headers from new mail */ X exit(0); X /* NOTREACHED */ X} X X/* parse_args - process command-line arguments */ X Xhidden void parse_args(argc,argv) Xint argc; Xchar **argv; X{ X while (--argc && *++argv && **argv == '-') { /* process options */ X switch (*++*argv) { X case 'd': /* turn debugging on */ X if (--argc == 0) X usage("missing debugging level argument"); X sscanf(*++argv,"%d",&dflag); X if (dflag < 0 || dflag > 9) X dflag = 0; X break; X default: /* unknown option */ X usage(strcons("invalid option: -%c",**argv)); X break; X } X } X X /* check for extraneous arguments */ X X if (argc > 0) X usage(strcons("unexpected argument: %s",*argv)); X} X X/* scan for new mail that hasn't gotten yet a metafile */ X Xhidden void newmail() X{ X register int dd; X int pfxlen = sizeof(NEWPFX)-1; X char *f; X X debug("directory: \"%s\"\n",maildir); /* verify */ X X /* X * Scan the spool directory for newly-arrived mail. X * X * Incoming mail message files have a name of "n<seqno>". X * The originator name is normally present in files with names X * "h<seqno>" or "o<seqno>". X * The presence of an "o" file implies that the file "n<seqno>" X * has been read by the user. An "h" file means that the user X * has not yet read the message file. X * X * If a message file has no corresponding "h" or "o" file we X * assume it is a new mail message and create an "h" file with X * the name of the originator. X */ X X for (dd = opendir(maildir); f = readdir(dd); /* void */) { X int seqno; X debug("rmail: file \"%s\"\n",f); X if (strncmp(f,NEWPFX,pfxlen) == 0 && sscanf(f+pfxlen,"%d",&seqno)) { X if (access(in_meta(seqno),4) == 0) { /* message already */ X /* void */ ; /* marked as read */ X } else if (access(new_meta(seqno),4) == 0) {/* message already */ X /* void */ ; /* marked as unread */ X } else { /* create meta file */ X extract(new_mesg(seqno),new_meta(seqno)); X } X } X } X closedir(dd); X} X X/* extract - extract originator info from mail file to meta file */ X Xhidden void extract(mail,meta) Xchar *mail; Xchar *meta; X{ X FILE *mesgfp,*metafp; X char line[BUFSIZ]; X char from[BUFSIZ]; X int n; X X debug("-- \"%s\" -> \"%s\"\n",mail,meta); X X if ((mesgfp = fopen(mail,"r")) == NULL) /* cannot open existing file */ X exit(E_SYSFAIL); X X strcpy(from,"Somewhere"); /* default originator */ X X /* X * Some mailers generate real headers, separated from the message X * body by an empty line. So we stop when we find an empty line. X * Other mailers have no headers, so we stop after HLEN lines. X * The following algorithm tries to extract the real user name X * if possible, otherwise it takes whatever it can get. X */ X X for (n = 0; n < HLEN && fgets(line,BUFSIZ,mesgfp) && *line != '\n'; n++) { X if (sscanf(line,"From: %*s ( %[^)] )",from) == 1) X break; X if (sscanf(line,"From: %s",from) == 1) X break; X sscanf(line,"%*[>] From %s",from) || sscanf(line,"From %s",from); X } X X /* carefully check all went well */ X X if (ferror(mesgfp)) /* sorry, read problem */ X exit(E_READERR); X if ((metafp = fopen(meta,"w")) == NULL) /* cannot create metafile */ X exit(E_WRITERR); X fprintf(metafp,"%s\n",from); /* write originator */ X if (ferror(metafp)) { X fclose(metafp); /* ms-dog needs this! */ X chmod(meta,0666); /* sorry, write problem */ X unlink(meta); /* delete metafile */ X exit(E_WRITERR); X } X fclose(mesgfp); X fclose(metafp); X} X X/* usage - explain what is wrong */ X Xhidden void usage(str) Xchar *str; X{ X fprintf(stderr,"%s\nusage: rmail [-d debugging_level]\n",str); X exit(2); X} END_OF_rmail.c if test 6168 -ne `wc -c <rmail.c`; then echo shar: \"rmail.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f startup.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"startup.c\" else echo shar: Extracting \"startup.c\" \(6331 characters\) sed "s/^X//" >startup.c <<'END_OF_startup.c' X/*++ X/* NAME X/* startup 3 X/* SUMMARY X/* startup/terminate network protocol X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* startproto() X/* X/* endproto() X/* DESCRIPTION X/* startproto() should be called after a successfull login on a remote X/* host. It performs the primary handshake with the other system X/* (call accepted/locked) and negotiates a communications protocol. X/* It then sets the function pointers Close/Read/Write to the X/* appropriate values. Until endproto() is called, all i/o to the X/* remote host should proceed through the functions pointed to by X/* Read/Write. X/* X/* endproto() turns the protocol off, and sends the silly "OO" message X/* to the remote system. It does not disconnect, nor does it change X/* the state of the communications port. X/* FUNCTIONS AND MACROS X/* xgetc(), xwrite(), trap() X/* DIAGNOSTICS X/* The process of negotiation is shown when debugging is enabled. X/* startproto() and endproto() return 0 in case of success, E_LOST X/* if no response arrived and E_REJECT if the response differed X/* from the expected response. X/* BUGS X/* startproto() assumes that the local system is the calling system. 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/* Fri Mar 27 13:43:00 GMT+1:00 1987 X/* LAST MODIFICATION X/* Wed Apr 6 00:22:51 MET 1988 X/* VERSION/RELEASE X/* 1.4 X/*--*/ X X#include <setjmp.h> X#include "defs.h" X#include "params.h" X#include "comm.h" X#include "logs.h" X#include "status.h" X#include "sysdep.h" X X/* forward declarations */ X Xhidden char *xpct(); /* expect a string */ Xhidden char *send(); /* send a string */ X X/* the functions that inplement the various protocols */ X Xextern kopen(),kclose(),kread(),kwrite(); /* k protocol */ Xextern gopen(),gclose(),gread(),gwrite(); /* g protocol */ X Xtypedef struct proto { X char name; /* name of the protocol */ X int (*open)(); /* the open function */ X int (*close)(); /* the close function */ X int (*read)(); /* the read function */ X int (*write)(); /* the write function */ X}; X X/* the order of protocols is significant! */ X Xhidden struct proto ptable[] = { X 'k', kopen, kclose, kread, kwrite, /* try this first */ X 'g', gopen, gclose, gread, gwrite, /* then this one */ X /* add your protocols at the appropriate place */ X 0, /* terminator! */ X}; X X/* startproto - do primary handshake, establish protocol and turn it on */ X Xpublic startproto() X{ X int *savetrap = systrap; X jmp_buf mytrap; X register struct proto *pp; X register char *cp; X int status; X X if (status = setjmp(systrap = mytrap)) { /* get here if expect fails */ X systrap = savetrap; X return(status); X } X X /* the primary handshake: who are we and is it ok we call right now */ X X sscanf(xpct("Shere"),"Shere=%s",rmthost); /* try to get host name */ X log("SUCCEEDED (call to %s)",rmthost); X send(strcons("S%s -x%d",LOGIN_NAME,MAX(dflag,1))); /* name + debug level */ X xpct("ROK"); /* we're accepted or rejected */ X X /* choose a protocol from the list offered by the other side */ X X for (cp = xpct("P")+1,pp = ptable; pp->name && !index(cp,pp->name); pp++) X /* void */ ; X if (pp->name == 0) { /* no common protocol */ X send("N"); X trap(E_REJECT,"FAILED (no common protocol in \"%s\")",cp); X /* NOTREACHED */ X } X send(strcons("U%c",pp->name)); /* my choice of protocol */ X X /* install protocol */ X X Close = pp->close; /* for endproto() */ X Read = pp->read; X Write = pp->write; X if (pp->open && CALL(pp->open)(ttfd)) /* start up a protocol */ X trap(E_LOST,"FAILED (startup)"); X X log("OK (startup)"); X systrap = savetrap; /* get here if expect wins */ X return(0); X} X X/* endproto - terminate protocol */ X Xpublic endproto() X{ X int *savetrap = systrap; X jmp_buf mytrap; X int status; X X if (status = setjmp(systrap = mytrap)) { /* get here if expect fails */ X systrap = savetrap; X return(status); X } X if (Close) /* check there is one */ X CALL(Close)(ttfd); /* turn protocol off */ X send("OOOOOO"); /* byebye */ X xpct("OO"); /* bye */ X log("OK (conversation complete)"); X X systrap = savetrap; /* get here if expect wins */ X return(0); X} X X/* send - write message to remote host and return pointer to message */ X Xhidden char *send(str) Xchar *str; X{ X xwrite(ttfd,"\020",1); /* message header */ X xwrite(ttfd,str,strlen(str)+1); /* include trailing null */ X debug(4)("send: %S\n",str); X return(str); /* return the message */ X} X X/* xpct - read message from host in "^Pmessage[\0\n]" format; trap on errors */ X Xhidden char *xpct(pat) Xchar *pat; X{ X register int c; X register char *p = msgin; X register int inmsg = 0; X X /* X * Keep reading until we time out, the buffer is full, or until a X * complete message has been received. Consider the link as lost X * in case of time out or buffer overflow. Assume we are rejected X * if the received message differs from what was expected. X */ X X while (p < msgin+MSGBUF && (c = xgetc()) != EOF) { X if ((c &= 0177) == '\020') { /* got start of message */ X debug(4)(" got sync\n"); X p = msgin; /* clear msg buffer */ X inmsg = 1; X } else if (inmsg == 0 || (*p++ = (c == '\n' ? 0 : c))) { X debug(4)("%C",c); X } else { /* message completed */ X debug(4)("\n"); X if (strncmp(pat,msgin,strlen(pat))) /* compare prefix only */ X break; X return(msgin); X } X } X trap((c == EOF || p >= msgin+MSGBUF ? E_LOST : E_REJECT), X "FAILED (%s)",msgin); X /* NOTREACHED */ X} END_OF_startup.c if test 6331 -ne `wc -c <startup.c`; then echo shar: \"startup.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 4 \(of 8\). cp /dev/null ark4isdone 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.