home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-01-24 | 59.8 KB | 1,988 lines |
- Newsgroups: comp.sources.misc
- subject: v10i040: PC-MAIL release 2, 8/11
- from: wswietse@lso.win.tue.nl (Wietse Venema)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 10, Issue 40
- Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
- Archive-name: pcmail2/part08
-
- #! /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 8 (of 11)."
- # Contents: daemon/pc-mail.c main/DEFAULT.ins main/desk.c
- # main/gtrans.c main/window.c
- # Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:20 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f daemon/pc-mail.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"daemon/pc-mail.c\"
- else
- echo shar: Extracting \"daemon/pc-mail.c\" \(11399 characters\)
- sed "s/^X//" >daemon/pc-mail.c <<'END_OF_daemon/pc-mail.c'
- X/*++
- X/* NAME
- X/* pc-mail 8
- X/* SUMMARY
- X/* deliver mail to nfs-based pc-mail users
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* nfs
- X/* SYNOPSIS
- X/* pc-mail user
- X/* DESCRIPTION
- X/* This program is to be run on the nfs server that exports mail
- X/* directories to MS-DOS pc-mail users. The program replaces the
- X/* UNIX -> MS-DOS file transfer function of the MS-DOS \fIcico\fR
- X/* program.
- X/*
- X/* Normally, the pc-mail delivery program is invoked by sendmail(8).
- X/* Its purpose is to deliver new mail in the mail directory of the
- X/* specified \fIuser\fR (default /usr/spool/pc-mail/\fIuser\fR).
- X/* Any error conditions detected by the pc-mail delivery program
- X/* are reported back in a sendmail-compatible manner.
- X/*
- X/* This program must be run with root privileges. It will assume
- X/* the (uid, gid) of the specified user before delivering mail.
- X/*
- X/* The program attempts to create any missing directories, and to
- X/* correct ownerships or protections where needed.
- X/* FILES
- X/* /usr/spool/pc-mail/\fIuser\fR/nNNNNN, mail message.
- X/* /usr/spool/pc-mail/\fIuser\fR/hNNNNN, sender of message and subject.
- X/* (NNNNN is the pc-mail "message id").
- X/* SEE ALSO
- X/* pc-maild(1)
- X/* DIAGNOSTICS
- X/* All conceivable error conditions cause the program to terminate
- X/* with a non-zero exit status, after printing an error message on
- X/* the standard error stream, and appending an entry to the system log.
- X/* See <sysexits.h> for details.
- X/* BUGS
- X/* There is no way to notify a pc-mail user of the arrival of new mail.
- 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 Oct 22 18:00:53 MED 1989
- X/* LAST MODIFICATION
- X/* 1/6/90 19:08:13
- X/* VERSION/RELEASE
- X/* 1.10
- X/*--*/
- X
- X#ifndef lint
- Xstatic char sccsid[] = "@(#) pc-mail.c 1.10 1/6/90 19:08:13";
- X
- X#endif
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <pwd.h>
- X#include <varargs.h>
- X
- X#ifdef SYSLOG
- X#include <syslog.h>
- X#else
- X#include "syslog.h"
- X#endif
- X
- X#ifdef SYSV
- X#include <ndir.h>
- X#else
- X#include <sys/dir.h>
- X#endif
- X
- X#ifdef SYSEXITS
- X#include <sysexits.h>
- X#else
- X#include "sysexits.h"
- X#endif
- X
- X#include "dosunix.h"
- X#include "percentm.h"
- X#include "ms_parse.h"
- X
- X/* Stuff related to failed system calls */
- X
- Xextern int errno;
- X
- X/* External functions */
- X
- Xextern struct passwd *getpwnam();
- Xextern long time();
- Xextern char *mktemp();
- Xextern void exit();
- Xextern unsigned sleep();
- X
- X/* Local declarations */
- X
- X#ifndef MAILDIR
- X#define MAILDIR "/usr/spool/pc-mail" /* pc-mail directory tree */
- X#endif
- X
- X#define LOCK "pc-mail.lck" /* the lock file */
- X#define STALE 1800 /* max age of lock file */
- X#define MAXTRY 60 /* max retry count for lock creation */
- X#define MSGFIL_FMT "n%05d" /* message file name format */
- X#define SNDFIL_FMT "h%05d" /* sender file name format */
- X#define MAXLINE 1024 /* max length of recipient line */
- X
- Xchar template[] = "pc.XXXXXX"; /* template lock file */
- X
- X/* local functions */
- X
- Xvoid sender();
- Xvoid message();
- Xvoid error();
- X
- Xchar *progname;
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X struct passwd *pwd;
- X static char userdir[BUFSIZ];
- X int seqno;
- X
- X progname = argv[0];
- X
- X /* Garbage in, garbage out */
- X
- X if (argc != 2)
- X error(EX_USAGE, "usage: %s user", *argv);
- X
- X#ifndef DEBUG
- X if (geteuid() != 0)
- X error(EX_USAGE, "must run with root privileges");
- X
- X /* need this for SYSVR2 or mkdir(1) fails */
- X#ifdef SYSV
- X if (setuid(0) != 0)
- X error(EX_OSERR, "cannot setuid(0)");
- X#endif
- X#endif
- X
- X if ((pwd = getpwnam(argv[1])) == 0)
- X error(EX_NOUSER, "unknown user: %s", argv[1]);
- X
- X /* Setup a somewhat safe environment */
- X
- X if (putenv("PATH=/bin:/usr/bin:/usr/ucb")
- X || putenv("IFS= \t\n"))
- X error(EX_TEMPFAIL, "putenv() failed");
- X
- X /* Check the necessary directories exist */
- X
- X (void) sprintf(userdir, "%s/%s", MAILDIR, argv[1]);
- X checkdir(userdir, pwd->pw_uid, pwd->pw_gid, 0700);
- X
- X /* Now with that out of the way, try to deliver the message */
- X
- X if (setgid(pwd->pw_gid))
- X error(EX_USAGE, "setgid(%s) failed: %m", argv[1]);
- X if (setuid(pwd->pw_uid))
- X error(EX_USAGE, "setuid(%s) failed: %m", argv[1]);
- X
- X /* make sure the user mail directory is accessible */
- X
- X if (chdir(userdir))
- X error(EX_TEMPFAIL, "can't access mail directory %s", userdir);
- X
- X /* deliver mail */
- X
- X seqno = newseqno(userdir); /* Allocate sequence number */
- X message(pwd, seqno); /* Create message file */
- X sender(seqno); /* Create metafile (sender) */
- X exit(EX_OK); /* Done. */
- X /* NOTREACHED */
- X}
- X
- X/* message - write message file */
- X
- Xvoid message(pwd, seqno)
- Xstruct passwd *pwd;
- Xint seqno;
- X{
- X static char buf[BUFSIZ];
- X register FILE *fp;
- X
- X /* Create the message file */
- X
- X (void) sprintf(buf, MSGFIL_FMT, seqno);
- X if ((fp = fopen(buf, "w")) == 0)
- X error(EX_CANTCREAT, "create error for file %s/%s: %m",
- X pwd->pw_name, buf);
- X if (unix2dos(stdin, fp)) {
- X (void) unlink(buf);
- X error(EX_CANTCREAT, "write error for file %s/%s: %m",
- X pwd->pw_name, buf);
- X }
- X (void) fclose(fp);
- X (void) chmod(buf, 0400); /* Avoid tampering */
- X}
- X
- X/* sender - extract sender from message */
- X
- Xvoid sender(seqno)
- Xint seqno;
- X{
- X register FILE *ifp;
- X register FILE *ofp;
- X static char fname[BUFSIZ]; /* file names */
- X static char line[MAXLINE]; /* read buffer */
- X static char from[MAXLINE] = "Unknown"; /* sender */
- X static char subject[MAXLINE] = ""; /* subject */
- X register int context = MS_UUCP;
- X
- X /*
- X * Try to open the message file; if that fails, let the pc software scan
- X * for the sender at a later time.
- X *
- X * We recognize the following From line formats:
- X *
- X * From name stuff use name
- X *
- X * >From name stuff use name
- X *
- X * From: address (full_name) use full_name
- X *
- X * From: full_name <address> use full_name
- X *
- X * From: full_name use full_name
- X */
- X
- X (void) sprintf(fname, MSGFIL_FMT, seqno);
- X if ((ifp = fopen(fname, "r")) == 0)
- X return;
- X
- X /* Extract sender and subject from message */
- X
- X while (dosgets(line, sizeof(line), ifp) != 0
- X && (context = ms_parse(context, line)) != MS_BODY) {
- X switch (context) {
- X case MS_UUCP:
- X if (sscanf(line, "%*[>] From %s", from) != 1)
- X (void) sscanf(line, "From %s", from);
- X break;
- X case MS_HEADER:
- X if (hscanf(line, "Subject:", " %[^\n]", subject) == 0
- X && hscanf(line, "From:", " %*s ( %[^)] )", from) == 0)
- X (void) hscanf(line, "From:", " %[^<]", from);
- X break;
- X }
- X }
- X (void) fclose(ifp);
- X
- X /*
- X * Try to create the meta file; if that fails, let the pc software try
- X * again at a later time.
- X */
- X
- X (void) sprintf(fname, SNDFIL_FMT, seqno);
- X if (ofp = fopen(fname, "w")) {
- X (void) fprintf(ofp, "%s\r\n%s\r\n", from, subject);
- X if (fflush(ofp) || ferror(ofp) || feof(ofp) || fclose(ofp)) {
- X (void) unlink(fname);
- X } else {
- X (void) chmod(fname, 0400); /* avoid tampering */
- X }
- X }
- X}
- X
- X/* newseqno - allocate new message sequence number */
- X
- Xint newseqno(userdir)
- Xchar *userdir;
- X{
- X register DIR *dd;
- X register struct direct *p;
- X struct stat st;
- X register int seqno = 0;
- X int tmp = 0;
- X int i;
- X char junk;
- X
- X /*
- X * When the pc adds a file to the "mail data base", the file name is
- X * composed of a single letter and a unique sequence number. The pc
- X * chooses a new sequence number by adding one to the highest existing
- X * sequence number.
- X *
- X * Now that the pc mounts its mail directory from the nfs server we must
- X * avoid possible concurrency conflicts when both pc and file server try
- X * to update the "mail data base".
- X *
- X * Since the pc does not know about concurrent access from the nfs server,
- X * the server has to add 2 to the highest existing message sequence
- X * number, in order to avoid conflicts. Fortunately, only one pc at a
- X * time will be accessing a mail directory of a particular user.
- X *
- X * Further concurrency conflicts are be avoided on the server side by using
- X * lock files.
- X *
- X * If we cannot create a lock file right now, we back off and let sendmail
- X * try again later.
- X */
- X
- X /* Get rid of stale lock files */
- X
- X if (stat(LOCK, &st) == 0 && st.st_mtime < time((long *) 0) - STALE)
- X (void) unlink(LOCK);
- X
- X /* Wait until we can create the lock file */
- X
- X if (creat(mktemp(template), 0400) < 0)
- X error(EX_TEMPFAIL, "cannot set lock in directory %s: check ownership",
- X userdir);
- X for (i = 0; link(template, LOCK) && i < MAXTRY; i++)
- X (void) sleep(1);
- X (void) unlink(template);
- X if (i >= MAXTRY)
- X error(EX_TEMPFAIL, "locked: %s", userdir);
- X
- X /* Scan the user mail directory for the highest existing message number */
- X
- X if ((dd = opendir(userdir)) == 0) {
- X (void) unlink(LOCK);
- X error(EX_TEMPFAIL, "opendir(\"%s\") failed: %m", userdir);
- X }
- X while (p = readdir(dd)) {
- X if (strlen(p->d_name) == 6
- X && sscanf(p->d_name + 1, "%d%c", &tmp, &junk) == 1 && tmp > seqno)
- X seqno = tmp;
- X }
- X
- X /* clean up and terminate */
- X
- X closedir(dd);
- X (void) unlink(LOCK);
- X return (seqno + 2);
- X}
- X
- X/* checkdir - check/update presence/ownership/protection of directory */
- X
- Xcheckdir(path, uid, gid, mode)
- Xchar *path;
- Xint uid;
- Xint gid;
- Xint mode;
- X{
- X struct stat st;
- X
- X /*
- X * If a user mail directory does not exist, try to create it. Otherwise,
- X * make sure it has sane permissions
- X */
- X
- X if (stat(path, &st) == -1) { /* no directory */
- X if (mkdir(path, mode)) /* try to create it */
- X error(EX_TEMPFAIL, "cannot create directory %s: %m", path);
- X if (chown(path, uid, gid)) /* set owner, group */
- X error(EX_TEMPFAIL, "cannot chown directory %s: %m", path);
- X } else { /* directory exists */
- X if ((st.st_mode & S_IFMT) != S_IFDIR) /* must be directory! */
- X error(EX_TEMPFAIL, "%s should be a directory", path);
- X if ((st.st_uid != uid || st.st_gid != gid) /* check owner/group */
- X &&chown(path, uid, gid)) /* correct owner, group */
- X error(EX_TEMPFAIL, "cannot chown directory %s: %m", path);
- X if ((st.st_mode & 0777) != mode /* check permissions */
- X && chmod(path, mode)) /* correct permissions */
- X error(EX_TEMPFAIL, "cannot chmod %o directory %s: %m", mode, path);
- X }
- X}
- X
- X/* error - print diagnostic and terminate */
- X
- X/* VARARGS */
- X
- Xvoid error(va_alist) va_dcl
- X{
- X va_list ap;
- X register int exstat;
- X register char *fmt;
- X char buf[BUFSIZ];
- X int err = errno;
- X
- X /* Format the error message */
- X
- X va_start(ap);
- X exstat = va_arg(ap, int); /* exit status */
- X fmt = va_arg(ap, char *); /* format string */
- X (void) vsprintf(buf, percentm(fmt, err), ap);
- X va_end(ap);
- X
- X /* Write message to standard error stream */
- X
- X (void) fprintf(stderr, "%s: %s\n", progname, buf);
- X
- X /* Append the same message to system log */
- X
- X (void) openlog("pc-mail", LOG_PID, LOG_MAIL);
- X (void) syslog(LOG_WARNING, "%s", buf);
- X (void) closelog();
- X
- X /* Notify sendmail of the nature of the problem */
- X
- X exit(exstat);
- X}
- X
- X#ifdef SYSV
- X
- X/* mkdir - create directory */
- X
- Xint mkdir(dir, mode)
- Xchar *dir;
- Xint mode;
- X{
- X char cmd[BUFSIZ];
- X
- X (void) sprintf(cmd, "mkdir %s 2>&1 >/dev/null 2>&1 && chmod %o %s",
- X dir, mode, dir);
- X return (system(cmd)); /* does not set errno */
- X}
- X
- X#endif
- END_OF_daemon/pc-mail.c
- if test 11399 -ne `wc -c <daemon/pc-mail.c`; then
- echo shar: \"daemon/pc-mail.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/DEFAULT.ins -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/DEFAULT.ins\"
- else
- echo shar: Extracting \"main/DEFAULT.ins\" \(11543 characters\)
- sed "s/^X//" >main/DEFAULT.ins <<'END_OF_main/DEFAULT.ins'
- X@(#) DEFAULT.ins 2.1 90/01/22 13:01:05
- X
- XThis document briefly describes how to set up a PC-mail system
- Xthat uses the default PC-mail UUCP software to exchange mail with
- Xits UNIX host. The examples given apply to `old' UNIX UUCP; your
- Xfile names and formats may vary.
- X
- XTHE UNIX SIDE OF THE CONNECTION
- X
- XThe PC-mail programs will need a UNIX host to exchange messages
- Xwith. This automatically gives access to other networks. I sug-
- Xgest the following strategy:
- X
- X - Get a UUCP login, say, `uuxyz' on a UNIX system. This will
- Xalso become the UUCP-node name of the PC. Sometimes, the UNIX
- XUUCP software will refuse to work with arbitrary (uid, gid)
- Xvalues; during the initial handshake messages, it will reply with
- XRLOGIN instead of ROK. On these systems, the (uid, gid) values of
- Xyour UUCP login should be small numbers, probably in the range
- X1-100.
- X
- XThe UUCP systems file (/usr/lib/uucp/L.sys) should be extended
- Xwith an entry for the `uuxyz' host, e.g.
- X
- X uuxyz Passive
- X
- XOn some systems one has to specify `Never' instead of `Passive'.
- XIt may also be necessary to update the UUCP permissions file
- X(/usr/lib/uucp/USERFILE).
- X
- X - Have all mail for user `uuxyz' forwarded to `uuxyz!somebody'.
- XWith Berkeley UNIX, this can be achieved by placing the address
- X`uuxyz!somebody' in the file ~uuxyz/.forward; with System-V UNIX
- Xone may have to put the text `Forward to uuxyz!somebody' in the
- Xfile /usr/mail/uuxyz, which should be read/writeable by group
- Xmail. Alternatively, you can ask the UNIX system administrator to
- Xdefine an alias that maps `uuxyz' to `uuxyz!somebody' if the
- Xlocal mailer supports aliases.
- X
- XIn the above examples, `somebody' is a name that can be freely
- Xchosen; it will not be used by the PC. Of course, mail can be
- Xforwarded to `uuxyz!somebody' from other accounts as well.
- X
- XThe result of all this is that you can send mail to any user on
- Xthe UNIX host by just specifying her login name; your mail will
- Xappear to come from the user `uuxyz' on the UNIX host. The UUCP-
- Xnode name of your PC will not appear in mail headers. People can
- Xsend mail to you by specifying `uuxyz' on the UNIX host. Since
- Xthe host name of the PC does not appear in mail headers there is
- Xno need to register the PC in, e.g., the UUCP maps.
- X
- XAs a minimum, the UNIX host should support the standard UUCP `g'
- Xprotocol. This protocol was developed for eight-bit data paths
- Xacross dial-up links (modems). Unfortunately, more advanced
- Xnetworks eat up XON/XOFF and other control characters. This must
- Xbe the price of progress.
- X
- XTo handle non-transparent networks I have written a simple
- Xstart/stop `k' protocol. It has been in use on the Eindhoven
- XUniversity Sytek network since 1986 and is part of the PC-mail
- Xdistribution. If you're really desperate (and have UNIX source)
- Xbuild this protocol into the uucico program by adding the
- Xfollowing line to struct Proto Ptbl[] in the file cntrl.c:
- X
- X 'k', kturnon, krdmsg, kwrmsg, krddata, kwrdata, kturnoff,
- X
- Xand linking the uucico objects with kio.c kp.h kphys.c kpres.c
- Xand ktrans.c.
- X
- XTHE PC SIDE OF THE CONNECTION
- X
- XA warning for MS-DOS users: TSR programs may interfere with the
- Xoperation of the dial-up and file transfer program.
- X
- XTo up bring PC-mail, copy the appropriate makefile.whatever file
- Xto makefile and edit it (there are template makefiles for UNIX
- Xand MS-DOS). The MS-DOS makefile is for a UNIX-compatible make
- Xutility posted to usenet near the end of 1986. There is a batch
- Xcommand file (DEFAULT.bat) for those who do not have a unix-
- Xcompatible make utility. The make utility provided with early
- Xreleases of MicroSoft C is definitely not UNIX compatible.
- X
- XSaying `make' should produce five programs:
- X
- X - mail, the menu-driven user interface
- X - cmail, a program that checks if there is new mail
- X - smail, a program that queues messages for transmission after
- X doing alias substitution on mail addresses
- X - nmail, extracts "From" and "Subject" info from new mail
- X - cico, the program that performs dialups and file transfers
- X
- XUnder MS-DOS, the cico program has to be compiled with the small
- Xmemory model; in order to handle mail messages larger than about
- X10 kbyte, the mail user interface program should be compiled with
- Xthe large memory model.
- X
- XThe programs access a common data base in the form of a spool
- Xdirectory with setup file, logfile and message files. Optionally
- Xthere may be header and trailer files to generate template
- Xmessages. There should be no other files in the spool directory,
- Xto avoid confusion. The spool directory should be created by
- Xhand; the PC-mail programs will not do that.
- X
- XYou will have to set some environment variables before running
- Xthe mail program.
- X
- X - MAILDIR, the location of your mail data base directory
- X - EDITOR, the name of your favourite editor program
- X - PATH, in order locate the PC-mail executables, and your editor
- X
- XIt is advised to use absolute path names that include the drive
- Xname. The editor command may be an MS-DOS batch file; in that
- Xcase you should include the '.bat' suffix in the command name.
- X
- XThe following two environment variables are optional.
- X
- X - MAILPRN, the name of a file, if printer output should not go to
- X the default printer.
- X - MAILCMD, a command that is executed on exit from the mail
- X program. If this is an MS-DOS batch file you should include
- X the '.bat' suffix in the command name.
- X
- XAt our site, these two variables are used to collect printer
- Xoutput in one file, and to send it to a networked printer upon
- Xexit from the program.
- X
- XMake sure that the limit on the number of open files is large
- Xenough (20 or so). On MS-DOS, this is handled by a line with
- X`files=20' in the CONFIG.SYS file.
- X
- XOn MS-DOS, the mail user interface requires the ANSI.SYS driver.
- XThe CONFIG.SYS file should specify a line with "device=ansi.sys".
- X
- XRun the interactive mail program and choose the setup command.
- X
- XAll entries must be filled or the cico program (for dial-up and
- Xfile transfer) will complain. On MS-DOS systems, only the com1
- Xport is supported (see the file comport.asm). I am not interested
- Xin 80*86 assembly-language programming; you will have hack your
- Xown com2 support.
- X
- XThe first item in the setup is not used by the dial-up and file-
- Xtransfer program.
- X
- XHere is my setup (some names changed) for getting through the
- Xhorrible port selector of our local university network (it needs
- Xto receive up to nine carriage returns in order to detect the
- Xbaud rate of a dial-up call, can you believe it):
- X
- X ignore_header_lines: received message-id
- X communications_port: com1
- X baud_rate: 2400
- X remote_host_name: eutwc1
- X login_name: uutest
- X dialup_sequence: atz\r OK atdt0,455215\r CONNECT \r \0 \r \0 \r
- X \0 \r \0 \0 \r \0 \r \0 \r \0 \r \0 \r \0 \r ease: abc\r ease: def\r
- X hoice:-\0-hoice: 1\r lled: b076\r CLOSED \r
- X disconnect_sequence: \0
- X
- XThe dial-up sequence requires some explanation. Basically it is a
- Xlist of words separated by whitespace:
- X
- X send1 expect1 send2 expect2 (and so on)
- X
- XThe first word is sent to the comm. port. The program will wait
- Xuntil it receives the second word. Then it sends the third word.
- XAnd so on. There is a retry facility, similar to the one in real
- XUUCP or later versions of Kermit, that works as follows: instead
- Xof an expect string you can specify an alternate sequence as
- Xwords separated by hyphen characters:
- X
- X expect-altsend1-altexpect1-altsend2-altexpect2 (and so on)
- X
- XIf the "expect" string is not received, the first alternate
- X"send" string is sent, and the program waits until it receives
- Xthe first alternate "expect" string. If that fails, the second
- Xalternate "send" string is sent and so on. The alternate sequence
- Xis terminated until an (alternate) expect succeeds or until the
- Xalternate sequence is exhausted, or due to time out.
- X
- XNote that carriage-return characters are not automatically
- Xappended to "send" strings. In order to specify these and other
- Xcontrol characters in send/expect strings I have stolen some
- Xescape sequences from the C programming language, and added some:
- X
- X \f formfeed
- X \n linefeed
- X \r carriage return
- X \s blank
- X \t tab
- X \\ backslash
- X \nnn octal code for a character
- X
- XIn order to send or expect an empty string, use the \0 sequence.
- XEmpty "send" strings introduce brief delays. An empty "expect"
- Xstring always succeeds.
- X
- XThe following "send" strings are given special treatment:
- X
- X BREAK causes a null character to be sent
- X EOT causes a Control-D character to be sent
- X
- XThe dial-up sequence specified in the setup file should terminate
- Xwhen the UNIX host is about to display its "login:" prompt; the
- Xremainder of the dialup sequence is wired into the software.
- XThis, and having (PC node name) equal to (UUCP login name) are to
- Xprevent fraud. If You have problems with this approach, you
- Xshould edit the file "connect.c".
- X
- XThus, assuming a Hayes-compatible modem, your dialup sequence
- Xcould be as simple as:
- X
- X atz\r OK atdt123456\r CONNECT
- X
- XWhen this dialup sequence succeeds, the program continues with
- Xits built-in sequence:
- X
- X ogin: your_uucp_login\r ssword: your_uucp_password\r
- X
- XThe disconnect sequence uses the same escape sequences as the
- Xdial-up sequence, but does not use the send/expect protocol. In
- Xthe example above, the disconnect sequence is a null string,
- Xwhich happens to be the default.
- X
- XIn order to test your dial-up sequence you can run the cico
- Xprogram by hand, for example:
- X
- X cico -d 9 -p your_uucp_password
- X
- XThis will produce a lot of debugging output. Setting the
- Xdebugging level to less than 9 reduces verbosity. Level 4 is
- Xsufficient to monitor the dial-up and login sequence.
- X
- XALIAS DATABASE
- X
- XThe user can define aliases for (groups of) mail addresses. The
- Xalias data base is a text file with on each line:
- X
- X alias replacement_part
- X
- XThe alias should be a single word; words are separated by blanks,
- Xtabs or commas. The replacement part may be one or more words.
- XWhenever the smail (mail spooler) program recognizes an alias, it
- Xis replaced by the `replacement part'. Aliases may be defined in
- Xterms of other aliases; the order in which they appear in the
- Xalias data base is not important (except when an alias is defined
- Xmore than once; the program remembers only the last definition of
- Xan alias). The alias expansion software is smart enough to detect
- Xinfinite loops and to suppress multiple occurrances of the same
- Xrecipient. Alias substitution is not case-sensitive.
- X
- XBATCH-MODE OPERATION
- X
- XThe cmail program can be run from a batch file (say, each time
- Xthe PC is turned on), to contact the UNIX host, and to report if
- Xthere is new mail. Also, you may want to auto-execute the cmail
- Xcommand when exiting from the interactive mail shell (using the
- XMAILCMD environment variable described above). See the manual
- Xpage in the cmail.c source.
- X
- XTEMPLATE FILES
- X
- XThe user can provide message templates with standard header and
- Xtrailer lines. If the file "header" is present in the mail
- Xdirectory, its contents will be included at the beginning of
- Xevery mail message created by the user. Similarly, the contents
- Xof a file "trailer" will be included at the end of mail messages.
- XThe "header" and "trailer" files should be ordinary text files.
- END_OF_main/DEFAULT.ins
- if test 11543 -ne `wc -c <main/DEFAULT.ins`; then
- echo shar: \"main/DEFAULT.ins\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/desk.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/desk.c\"
- else
- echo shar: Extracting \"main/desk.c\" \(12439 characters\)
- sed "s/^X//" >main/desk.c <<'END_OF_main/desk.c'
- X/*++
- X/* NAME
- X/* desk 3
- X/* CATEGORY
- X/* mail box display
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* mail
- X/* SYNOPSIS
- X/* #include "mail.h"
- X/*
- X/* void init()
- 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/* init() is the main entry point. It presents the user with a display
- X/* of message categories (create, unread, already seen, unsent, sent,
- X/* in preparation), and the number of messages in each category. After
- X/* the user has chosen a category, an editor is invoked, or a sorted
- X/* display of all messages in the respective category is displayed.
- 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 meta file (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/* 90/01/22 13:01:29
- X/* VERSION/RELEASE
- X/* 2.1
- X/*--*/
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <errno.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <time.h>
- X
- X#include "defs.h"
- X#include "mail.h"
- X#include "path.h"
- X#include "ndir.h"
- X#include "pager.h"
- X#include "screen.h"
- X#include "status.h"
- X#include "window.h"
- X#include "ascf.h"
- X#include "snapshot.h"
- X
- Xhidden void make_desk(); /* forward declarations */
- Xhidden int pick_desk();
- Xhidden int show_desk();
- Xhidden void desk();
- Xhidden void make_init();
- Xhidden int pick_init();
- Xhidden int show_init();
- Xhidden char *singular();
- X
- Xhidden File *deskfile = 0; /* mail box pager file */
- Xhidden File *initfile = 0; /* initial screen */
- Xpublic char message[BUFSIZ]; /* path to message file */
- Xpublic char comment[BUFSIZ]; /* path to meta file */
- X
- X/* Definitions of the various message categories */
- X
- Xtypedef struct {
- X char *type; /* work, incoming, outgoing, ... */
- X char mesg; /* message-file prefix */
- X char meta; /* meta-file prefix */
- X int (*access) (); /* message access function */
- X int flags; /* see below */
- X char *whatsit; /* explanation */
- X} CATEGORY;
- X
- X#define MULT 1 /* multi-message category */
- X#define DMON 2 /* subject to daemon activity */
- X
- Xhidden CATEGORY categories[] = {
- X "Create", WORK_MESG, WORK_META, create,0, "Create a new message",
- X "Work", WORK_MESG, WORK_META, work, MULT, "Message%S in preparation",
- X "New", NEW_MESG, NEW_META, mbox, MULT|DMON,"Unread message%S",
- X "In", OLD_MESG, OLD_META, mbox, MULT, "Message%S already read",
- X "Out", OUT_MESG, OUT_META, mbox, MULT|DMON,"Message%S not-yet sent",
- X "Sent", SENT_MESG, SENT_META, mbox, MULT|DMON,"Message%S already sent",
- X 0, /* terminator */
- X};
- X
- Xhidden CATEGORY *category; /* selected message category */
- X
- X/* table with all meta-file name prefixes */
- X
- Xhidden char metalist[] = {
- X WORK_META, NEW_META, OLD_META, OUT_META, SENT_META, 0,
- X};
- X
- Xhidden char initsingle[] = "%-6s %5s %s";
- Xhidden char initmulti[] = "%-6s %5u %s";
- Xhidden char scanmulti[] = "%s %u";
- X
- Xhidden char dispfmt[] = "%5u %.16s %.53s";
- Xhidden char dispfmts[] = "%5u %.16s %.40s \"%s\"";
- Xhidden char scanfmt[] = "%u";
- X
- X/* init - main entry point for message manipulations */
- X
- Xpublic void init()
- X{
- X static Screen screen[] = {
- X 'C', "Close", 0, "Terminate the program",
- X 'F', "File", file, "Mail a copy of an ordinary file",
- X#ifndef DAEMON
- X 'N', "Network", call, "Exchange mail with the network",
- X#endif
- X 'S', "Setup", setup, "Set communications parameters",
- X 'A', "Alias", alias, "Display the alias data base",
- X 'P', "Print", print, "Print contents of this display",
- X UP, "Up", up_pager, csrup,
- X DOWN, "Down", dn_pager, csrdn,
- X ENTER, "Enter", pick_init, "Select message category",
- X 0, 0, show_init,
- X "Select a message category 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_init - create or refresh the initial screen */
- X
- Xhidden int show_init()
- X{
- X if (initfile == 0) { /* no initial screen file */
- X patience(); /* one moment please */
- X make_init(initfile = open_pager()); /* build initial screen */
- X } else { /* pager file exists */
- X set_pager(initfile); /* select pager file */
- X }
- X ds_pager(); /* display it */
- X return (0); /* screen is ok */
- X}
- X
- X/* junk_init - force re-scan of mail directory and re-build of initial screen */
- X
- Xhidden void junk_init()
- X{
- X if (initfile) {
- X close_pager(initfile);
- X initfile = 0;
- X }
- X snap_junk(); /* re-scan mail directory */
- X}
- X
- X/* make_init - build initial screen */
- X
- Xhidden void make_init(pp)
- XFile *pp;
- X{
- X register SNAP_SHOT *s;
- X register unsigned count;
- X register CATEGORY *c;
- X
- X /*
- X * In case of multi-message categories, show the number of messages in
- X * that category.
- X */
- X
- X for (c = categories; c->type; c++) {
- X if (c->flags & MULT) { /* multi-message category */
- X for (count = 0, s = snap_shot(metalist); s->prefix; s++)
- X if (c->meta == s->prefix)
- X count++;
- X app_pager(pp, strcons(initmulti, c->type, count,
- X singular(count, c->whatsit)));
- X } else { /* single-message category */
- X app_pager(pp, strcons(initsingle, c->type, "", c->whatsit));
- X }
- X }
- X pp->opts |= PG_NOEND; /* suppress 'end-of-display' */
- X}
- X
- X/* exec_msg - execute access function for a particular message */
- X
- Xhidden int exec_msg(msgno)
- Xunsigned msgno;
- X{
- X (void) strcpy(message, mesg_file(category->mesg, msgno));
- X (void) strcpy(comment, meta_file(category->meta, msgno));
- X return (CALL(category->access) (category->meta, msgno));
- X}
- X
- X/* pick_init - user selected a message category */
- X
- Xhidden int pick_init()
- X{
- X char type[BUFSIZ];
- X register CATEGORY *c;
- X unsigned count;
- X
- X /*
- X * Read the message type (in, out, work etc) from the summary line in the
- X * initial display.
- X *
- X * On systems that do not use daemons for message delivery, disallow
- X * selection an empty message category.
- X */
- X
- X count = type[0] = 0; /* initialize */
- X (void) sscanf(gets_pager(), scanmulti, type, &count);
- X
- X for (c = categories; c->type; c++) { /* try to recognize the */
- X if (strcmp(c->type, type) == 0) { /* message type */
- X category = c; /* GLOBAL! */
- X if ((c->flags & MULT) == 0) { /* create-message category */
- X return (exec_msg(newseqno()));
- X#ifndef DAEMON
- X } else if (count == 0) { /* multi-message, empty */
- X break;
- X#endif
- X } else { /* multi-message */
- X desk();
- X return (S_REDRAW);
- X }
- X }
- X }
- X beep(); /* error */
- X return (0); /* nothing happened */
- X}
- X
- X/* desk - manipulate one category of messages */
- X
- Xhidden void desk()
- X{
- X static Screen screen[] = {
- X 'C', "Close", 0, initscreen,
- X 'F', "File", file, "Mail a copy of an ordinary file",
- X#ifndef DAEMON
- X 'N', "Network", call, "Exchange mail with the network",
- X#endif
- X 'S', "Setup", setup, "Set communications parameters",
- X 'A', "Alias", alias, "Display the alias data base",
- X 'P', "Print", print, "Print contents of this 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",
- X 0, 0, show_desk,
- X "Select a message with the cursor keys and press ENTER\n\
- Xor select one of the commands in the top line."
- X };
- X
- X /*
- X * On systems where daemon processes take care of message delivery, we
- X * re-scan the mail directory if the user selects a message category that
- X * can be affected by daemon activity, and force a re-scan of the mail
- X * directory upon return to the initial screen (unless that just happened
- X * as a result of some user action).
- X */
- X
- X#ifdef DAEMON
- X if (category->flags & DMON) /* if affected by daemons */
- X junk_init(); /* re-scan mail directory */
- X#endif
- X kbdinp(screen);
- X#ifdef DAEMON
- X junk_init(); /* re-scan mail directory */
- X#endif
- X close_pager(deskfile);
- X deskfile = 0;
- X}
- X
- X/* show_desk - create or refresh a display of a mail box selection */
- 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 display of summary lines of selected message type */
- X
- Xhidden void make_desk(pp)
- XFile *pp;
- X{
- X FILE *fp; /* used to read meta info */
- X char ident[MAXLINE]; /* usually person\'s name or address */
- X char subj[MAXLINE]; /* subject info */
- X char *line;
- X register SNAP_SHOT *s; /* snapshot table */
- X struct stat st;
- X
- X /*
- X * The message sequence number and type are already known; we just have
- X * to retrieve from the meta file: a person\'s name or address (first
- X * line) and an optional subject (second line).
- X *
- X * If Subject: information is present we truncate the person\'s name or
- X * address to (screen width - 40) columns. Any text that extends beyond
- X * the width of the screen is truncated as well.
- X */
- X
- X for (s = snap_shot(metalist); s->prefix; s++) {
- X if ((s->prefix == category->meta)
- X && (fp = ascopen(meta_file(s->prefix, s->msgno), "r"))) {
- X if ((ascgets(ident, sizeof(ident), fp) != 0)
- X && (fstat(fileno(fp), &st) == 0)) {
- X if (ascgets(subj, sizeof(subj), fp) && subj[0]) {
- X /* subject found; truncate person\'s name or address */
- X if (strlen(ident) > CO - 40)
- X (void) strcpy(ident + CO - 42, "..");
- X line = strcons(dispfmts, s->msgno,
- X tstamp(&(st.st_mtime)), ident, subj);
- X } else {
- X /* no subject info */
- X line = strcons(dispfmt, s->msgno,
- X tstamp(&(st.st_mtime)), ident);
- X }
- X /* truncate final result anyway */ if (strlen(line) >= CO - 1)
- X (void) strcpy(line + CO - 3, "..");
- X app_pager(pp, line);
- X }
- X ascclose(fp);
- X }
- X }
- X
- X/* sort summary lines in reverse order, i.e. newest comes first */
- X
- X sort_pager(pp, BACK_SORT);
- X}
- X
- X/* pick_desk - user selected a message */
- X
- Xhidden int pick_desk()
- X{
- X unsigned msgno;
- X
- X /*
- X * Read message sequence number from summary line in the mail box
- X * display. Build actual message file and meta file names. Then call the
- X * appropriate function to access that message.
- X */
- X
- X msgno = 0; /* initialize */
- X (void) sscanf(gets_pager(), scanfmt, &msgno);
- X
- X if (msgno) {
- X return (exec_msg(msgno));
- X } else {
- X beep(); /* unrecognized message id */
- X return (0); /* nothing happened */
- X }
- 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 junk_init(); /* and re-scan mail directory */
- X return (0); /* in case one wants it */
- X}
- X
- X/* singular - replace %S depending on whether a count is 1 */
- X
- Xhidden char *singular(c, s)
- Xint c;
- Xregister char *s;
- X{
- X static char buf[BUFSIZ];
- X register char *bp = buf;
- X
- X while (*s) {
- X if (*s == '%') {
- X if (s[1] == 'S') { /* expand %S */
- X if (c != 1)
- X *bp++ = 's';
- X s += 2;
- X } else if (s[1] == '\0') { /* don\'t fall off end */
- X *bp++ = *s++;
- X } else { /* leave %<any> alone */
- X *bp++ = *s++, *bp++ = *s++;
- X }
- X } else {
- X *bp++ = *s++;
- X }
- X }
- X *bp = '\0';
- X return (buf);
- X}
- END_OF_main/desk.c
- if test 12439 -ne `wc -c <main/desk.c`; then
- echo shar: \"main/desk.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/gtrans.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/gtrans.c\"
- else
- echo shar: Extracting \"main/gtrans.c\" \(10252 characters\)
- sed "s/^X//" >main/gtrans.c <<'END_OF_main/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/* 90/01/22 13:01:44
- X/* VERSION/RELEASE
- X/* 2.1
- 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_main/gtrans.c
- if test 10252 -ne `wc -c <main/gtrans.c`; then
- echo shar: \"main/gtrans.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f main/window.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"main/window.c\"
- else
- echo shar: Extracting \"main/window.c\" \(10368 characters\)
- sed "s/^X//" >main/window.c <<'END_OF_main/window.c'
- X/*++
- X/* NAME
- X/* window 3
- X/* SUMMARY
- X/* screen manipulator
- X/* PROJECT
- X/* pc-mail
- X/* PACKAGE
- X/* mail
- X/* SYNOPSIS
- X/* #include "window.h"
- X/*
- X/* int printcl(wp,line,s)
- X/* WIN *wp;
- X/* int line;
- X/* char *s;
- X/*
- X/* int printat(wp,line,s)
- X/* WIN *wp;
- X/* int line;
- X/* char *s;
- X/*
- X/* void setwin(wp)
- X/* WIN *wp;
- X/*
- X/* int wputc(c)
- X/* int c;
- X/*
- X/* int wputs(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()
- 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/* These can be manipulated via the window handles topwin, midwin
- X/* and botwin, respectively.
- X/* Use is made of the terminal capability database termcap, or terminfo,
- X/* or something else, depending on the OS we are dealing with.
- 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). All routines that
- X/* have a window agrument set the current window.
- 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/* setwin() sets the current window. The cursor is moved to the
- X/* current (row, column) of that window.
- X/*
- X/* wputs() writes a character string to the current cursor location
- X/* in the current window.
- X/*
- X/* wputc() does the same for characters.
- 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 manipulator 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/* All functions that do not take a "window" argument should not be
- X/* called before anything has appeared on the screen.
- X/*
- X/* This module should be replaced by a PD 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/* 90/01/22 13:02:55
- X/* VERSION/RELEASE
- X/* 2.1
- X/*--*/
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- 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
- X/* function-key strings, keypad control */
- X
- Xpublic char *KU, *KD, *KL, *KR, *PU, *PD;
- Xpublic char *KS, *KE;
- X
- X/* screen control capabilities */
- X
- Xhidden char *CL, *CD, *CM, *CE, *SO, *SE;
- X
- Xpublic int CO, LI; /* screen size */
- X
- X/* Storage for convenient capability lookup */
- X
- Xstruct strcaps {
- X char **dest; /* pointer to storage */
- X char *name; /* capability name */
- X};
- X
- Xstruct intcaps {
- X int *dest; /* pointer to storage */
- X char *name; /* capability name */
- X};
- X
- X/* Required string-valued termcap capabilities */
- X
- Xhidden struct strcaps reqd_str[] = {
- X &CE, "ce", /* clear to end of line */
- X &CD, "cd", /* clear to end of screen */
- X &CL, "cl", /* clear to end of screen */
- X#ifdef someday
- X &SO, "so", /* stand-out on */
- X &SE, "se", /* stand-out off */
- X#endif
- X &CM, "cm", /* cursor movement */
- X &KU, "ku", /* up-arrow */
- X &KD, "kd", /* down_arrow */
- X &KL, "kl", /* left-arrow */
- X &KR, "kr", /* right-arrow */
- X#ifdef unix
- X &PU, "k1", /* page-up (F1) */
- X &PD, "k2", /* page down (F2) */
- X#endif
- X#ifdef MSDOS
- X &PU, "PU", /* really PgUp */
- X &PD, "PD", /* really PgDn */
- X#endif
- X 0, 0,
- X};
- X
- X/* Required integer-valued terminal capabilities */
- X
- Xhidden struct intcaps reqd_int[] = {
- X &CO, "co", /* number of columns */
- X &LI, "li", /* number of lines */
- X 0, 0,
- X};
- X
- X/* Optional string-valued terminal capabilities */
- X
- Xhidden struct strcaps opt_str[] = {
- X &KS, "ks", /* keypad on */
- X &KE, "ke", /* keypad off */
- X 0, 0,
- X};
- X
- X/* Optional integer-valued terminal capabilities */
- X
- Xhidden struct intcaps opt_int[] = {
- X 0, 0,
- X};
- X
- X/* Window bases and sizes */
- X
- XWIN wins[3] = {
- X {0, 2, 0, 0}, /* top */
- X {2, 0, 0, 0}, /* middle */
- X {0, 5, 0, 0}, /* bottom */
- X};
- X
- X/* Stuff related to where we are on the screen */
- X
- Xhidden WIN *currwin = 0; /* what window we are in */
- X
- X/* convenient macros to update and set cursor location */
- X
- X#define moveto(wp) tputs(tgoto(CM,wp->x,wp->y+wp->base),1,fputchar)
- X#define moveset(wp,c,l) { wp->x = c; wp->y = l; moveto(wp); }
- X
- Xhidden void winout();
- X
- X/* checkline - validate line number */
- X
- Xhidden WIN *checkline(wp, line)
- XWIN *wp;
- Xint line;
- X{
- X if (line < 0 || line >= wp->size)
- X fatal("line %d not in window %d", line, wp - wins);
- X}
- X
- X/* printcl - print one line in a window, then clear to end of line */
- X
- Xpublic int printcl(wp, line, s)
- XWIN *wp;
- Xint line;
- Xchar *s;
- X{
- X checkline(currwin = wp, line);
- X
- X moveset(wp, 0, line);
- X winout(s);
- X if (wp->y < wp->size)
- X tputs(CE, 1, fputchar);
- X (void) fflush(stdout);
- X return (wp->y - line + 1);
- X}
- X
- X/* printat - print one line in a window */
- X
- Xpublic int printat(wp, line, s)
- XWIN *wp;
- Xint line;
- Xchar *s;
- X{
- X checkline(currwin = wp, line);
- X
- X moveset(wp, 0, line);
- X winout(s);
- X (void) fflush(stdout);
- X return (wp->y - line + 1);
- X}
- X
- X/* setwin - set focus and cursor */
- X
- Xpublic void setwin(wp)
- Xregister WIN *wp;
- X{
- X currwin = wp;
- X moveto(wp);
- X}
- X
- X/* wputc - put character at current location in current window */
- X
- Xpublic int wputc(c)
- Xint c;
- X{
- X register int line = currwin->y;
- X static char buf[] = "?";
- X
- X buf[0] = c;
- X winout(buf);
- X (void) fflush(stdout);
- X return (currwin->y - line + 1);
- X}
- X
- X/* wputs - print string at current location in current window */
- X
- Xpublic int wputs(s)
- Xchar *s;
- X{
- X register int line = currwin->y;
- X
- X winout(s);
- X (void) fflush(stdout);
- X return (currwin->y - line + 1);
- X}
- X
- X/* winout - update current window and keep track of where we are */
- X
- Xhidden void winout(s)
- Xregister char *s;
- X{
- X register int ch;
- X register WIN *wp;
- X static char dectrl[] = "^?";
- X
- X for (wp = currwin; (ch = (*s & 0177)) && wp->y < wp->size; s++) {
- X if (isprint(ch) || ch == ' ') { /* if printable */
- X putchar(ch), wp->x++; /* leave it alone */
- X } else if (ch == '\t') {
- X do {
- X winout(" "); /* expand it */
- X } while ((wp->x & 7) && wp->y < wp->size);
- X } else if (ch == '\b') {
- X if (wp->x > 0 || wp->y > 0) { /* don\'t leave the window */
- X if (wp->x-- == 0) { /* at beginning of line */
- X wp->x = CO - 1;
- X wp->y--;
- X moveto(wp);
- X } else {
- X putchar(ch);
- X }
- X }
- X } else if (ch == '\n') {
- X tputs(CE, 1, fputchar); /* erase rest of line */
- X moveset(wp, 0, wp->y + 1); /* advance */
- X } else if (ch == '\r') {
- X (wp->x = 0), moveto(wp); /* back to left margin */
- X } else if (ch == '\07') {
- X putchar(ch); /* make them sound */
- X } else {
- X dectrl[1] = ch ^ 0100; /* uncontrollify */
- X winout(dectrl); /* and output */
- X }
- X if (wp->x >= CO) /* wrap at end of line */
- X moveset(wp, 0, wp->y + 1);
- X }
- X}
- X
- X#ifdef unix
- 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 (void) putchar('\07');
- X (void) fflush(stdout);
- X}
- X
- X/* wininit - extract terminal info and initialize window routines */
- X
- Xpublic void wininit()
- X{
- X char *term;
- X struct strcaps *cp;
- X struct intcaps *ip;
- X
- X /* selected buffered standard output */
- X
- X setbuf(stdout, outbuf);
- X
- X /* make sure our terminal is known */
- X
- X#ifdef unix
- X if ((term = getenv("TERM")) == 0)
- X fatal("TERM not set");
- X#endif
- X
- X switch (tgetent(tcapent, term)) {
- X case -1:
- X fatal("no terminal database\n");
- X /* NOTREACHED */
- X case 0:
- X fatal("unknown terminal: %s\n", term);
- X /* NOTREACHED */
- X }
- X /* extract required terminal capabilities */
- X
- X for (cp = reqd_str; cp->name; cp++)
- X if ((*cp->dest = tgetstr(cp->name, &capptr)) == 0)
- X fatal("Your terminal is too dumb");
- X for (ip = reqd_int; ip->name; ip++)
- X if ((*ip->dest = tgetnum(ip->name)) == 0)
- X fatal("Your terminal is too dumb");
- X
- X /* set up per-window base and size */
- X
- X if (CO < 80)
- X fatal("Terminal screen is to narrow");
- X botwin->base = LI - botwin->size;
- X if ((midwin->size = botwin->base - midwin->base) < 10)
- X fatal("Not enough lines on this terminal");
- X
- X /* extract optional terminal capabilities */
- X
- X for (cp = opt_str; cp->name; cp++)
- X *cp->dest = tgetstr(cp->name, &capptr);
- X for (ip = opt_int; ip->name; ip++)
- X *ip->dest = tgetnum(ip->name);
- X}
- END_OF_main/window.c
- if test 10368 -ne `wc -c <main/window.c`; then
- echo shar: \"main/window.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 8 \(of 11\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 11 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-