From decwrl!purdue!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!allbery Tue Jan 30 08:50:13 PST 1990 Article 1305 of comp.sources.misc: Path: decwrl!purdue!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!allbery From: wswietse@lso.win.tue.nl (Wietse Venema) Newsgroups: comp.sources.misc Subject: v10i035: PC-MAIL release 2, 3/11 Message-ID: <77510@uunet.UU.NET> Date: 25 Jan 90 00:41:32 GMT Sender: allbery@uunet.UU.NET Lines: 2192 Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) Posting-number: Volume 10, Issue 35 Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema) Archive-name: pcmail2/part03 #! /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 daemon/util.c <<'END_OF_daemon/util.c' X/*++ X/* NAME X/* util 3 X/* SUMMARY X/* wrappers around standard library functions X/* PROJECT X/* pc-mail X/* PACKAGE X/* nfs X/* SYNOPSIS X/* #include X/* #include X/* #include X/* X/* FILE *u_fopen(uinfo,path,mode) X/* struct passwd *uinfo; X/* char *path; X/* char *mode; X/* X/* int u_link(uinfo, old, new) X/* struct passwd *uinfo; X/* char *old; X/* char *new; X/* X/* int u_unlink(uinfo, path) X/* struct passwd *uinfo; X/* char *path; X/* X/* DIR *e_opendir(path) X/* char *path; X/* X/* int e_chdir(path) X/* char *path; X/* X/* int e_fork() X/* DESCRIPTION X/* These functions are wrappers around some standard library functions. X/* In case of problems, they append an entry to the system log (with X/* priority LOG_WARNING). The \fIuinfo\fR argument specifies the owner X/* of the mail subdirectory in which the problem occurred. X/* SEE ALSO X/* syslog(3) X/* DIAGNOSTICS X/* Diagnostics are logged via the syslog package; error return values X/* are identical to those of the underlying library functions. X/* AUTHOR(S) X/* Wietse 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 29 16:21:02 MET 1989 X/* LAST MODIFICATION X/* 12/4/89 23:22:13 X/* VERSION/RELEASE X/* 1.2 X/*--*/ X X#ifndef lint Xstatic char sccsid[] = "@(#) util.c 1.2 12/4/89 23:22:13"; X X#endif X X#include X#include X X#ifdef SYSV X#include X#else X#include X#include X#endif X X#ifdef SYSLOG X#include X#else X#include "syslog.h" X#endif X X#include "util.h" /* consistency check */ X X/* u_fopen - open file in user directory, log any errors */ X XFILE *u_fopen(uinfo, file, mode) Xstruct passwd *uinfo; Xchar *file; Xchar *mode; X{ X register FILE *fp; X X if ((fp = fopen(file, mode)) == 0) X syslog(LOG_WARNING, "cannot open %s/%s: %m", uinfo->pw_name, file); X return (fp); X} X X/* u_unlink - unlink file in user directory, log any errors */ X Xint u_unlink(uinfo, file) Xstruct passwd *uinfo; Xchar *file; X{ X register int stat; X X if (stat = unlink(file)) X syslog(LOG_WARNING, "cannot unlink %s/%s: %m", uinfo->pw_name, file); X return (stat); X} X X/* u_link - link file in user directory, log any errors */ X Xint u_link(uinfo, old, new) Xstruct passwd *uinfo; Xchar *old; Xchar *new; X{ X register int stat; X X if (stat = link(old, new)) X syslog(LOG_WARNING, "cannot link %s/%s: %m", uinfo->pw_name, new); X return (stat); X} X X/* e_opendir - open directory, log any errors */ X XDIR *e_opendir(path) Xchar *path; X{ X register DIR *dd; X X if ((dd = opendir(path)) == 0) X syslog(LOG_WARNING, "cannot open directory %s: %m", path); X return (dd); X} X X/* e_chdir - change directory, log any errors */ X Xint e_chdir(path) Xchar *path; X{ X register int ret; X X if (ret = chdir(path)) X syslog(LOG_WARNING, "cannot chdir to directory %s: %m", path); X return (ret); X} X X/* e_fork - do a fork(), log any errors */ X Xint e_fork() X{ X register int stat; X X if ((stat = fork()) == -1) X syslog(LOG_WARNING, "fork() failed: %m"); X return (stat); X} X END_OF_daemon/util.c if test 3152 -ne `wc -c main/PORTING <<'END_OF_main/PORTING' X@(#) PORTING 2.1 90/01/22 13:01:09 X XThis document gives some hints to people who might consider to port the Xprograms to an environment different from UNIX or MS-DOS. Fortunately, Xthe programs themselves are written in portable (old-style) C. The only Xexception is the MS-DOS serial port driver, which isn't portable at all. X XFirst of all, search the source files for #ifdef constructs. This Xshould give an idea where the system-dependencies lurk. X XThe main problem will be serial-port I/O. If possible, try to build on Xtop of what the GNUUCP people have already done in this field. X XA less severe problem should be console input/output. The programs do Xnot use any graphics at all, nor are special input devices such as mice Xrequired. If your machine provides some kind of vt52 or vt100 Xemulation, adapt the console.c and tgoto.c files in the termcap Xsubdirectory. On machines without some form of text window on the Xconsole, porting will require too much work. Most keyboards generate Xcodes that can be easily encoded in the console.c file in the termcap Xsubdirectory. Most C compilers provide some form of "raw" keyboard i/o Xthat does not require the user to press ENTER, and that produces no Xecho. You may wish to consult a UNIX programmer's manual to find out Xwhat the two-letter codes in console.c are all about. X XProcess management may need some attention. The programs were written Xin the UNIX style, i.e. many small programs dedicated to a single task. XPrograms invoke other programs. Each program returns an exit status, Xsuch that the parent program can take appropriate action if things went Xwrong. If your operating system does not provide facilities to invoke, Xfrom with a program, other programs with command-line arguments, you Xlose. Sometimes, programs can only be invoked with the "aid" of a Xcommand-language interpreter. This often causes the exit status of Xprograms to be lost; the net result will be less reliable operation of Xthe pc-mail software. In the case of MS-DOS I compromised: batch Xcommand files must be given including their suffix, so that special Xarrangements can be made; other programs are invoked directly without Xintervention of a command interpreter. X XFile i/o should be taken care of by your C library; make sure that X"text" and "binary" modes are used at the appropriate places. Just look Xup where O_BINARY appears in the source. If your C library does not Xneed to distinguish between text and binary file i/o, you are lucky. X XYou will have to provide some form of the Berkeley-UNIX directory Xlibrary routines; they allow any program to scan directories for the Xnames of files. By now, these routines should be publicly available for Xmost reasonable operating systems. Make sure that the version you use Xproduces file names in lower case (or take appropriate measures), and Xthat it behaves well even in the root directory of a file system X(MS-DOS doesn't, so I had to compromise again). END_OF_main/PORTING if test 2946 -ne `wc -c
main/alias.c <<'END_OF_main/alias.c' X/*++ X/* NAME X/* alias X/* SUMMARY X/* manipulate alias data base X/* PROJECT X/* pc-mail X/* PACKAGE X/* mail X/* SYNOPSIS X/* #include "mail.h" X/* X/* int alias() X/* DESCRIPTION X/* The alias data base is a text file. Each line is of the form X/* X/* word one or more words X/* X/* The first word is the alias; words are separated by blanks X/* or commas. Upon alias expansion, the alias will be replaced X/* by the words on the remainder of the line of its definition. X/* An alias may be defined in terms of other aliases, but in terms X/* of itself. Aliases may defined in any order. If an alias is defined X/* more than once, only the last definition will be effective. X/* X/* alias() is invoked from the main menu and displays the contents X/* of the alias data base. An editor is invoked if the user wants X/* to make changes. 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/* $MAILDIR/a00000, alias data base X/* SEE ALSO X/* pager(3), pager(5), kbdinp(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/* Wed Apr 6 20:21:35 MET 1988 X/* LAST MODIFICATION X/* 90/01/22 13:01:13 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include "defs.h" X#include "path.h" X#include "pager.h" X#include "mail.h" X#include "screen.h" X#include "status.h" X X/* forward declarations */ X Xhidden int edit_alias(); Xhidden void junk_alias(); Xhidden int show_alias(); X Xhidden File *afile = 0; /* pager file */ X X/* alias - display alias data base */ X Xpublic int alias() X{ X static Screen screen[] = { X 'C', "Close", 0, prevscreen, X 'E', "Edit", edit_alias,"Edit alias data base", X 'P', "Print", print, "Print alias data base", 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_alias, X "(Reading alias database)", X }; X X kbdinp(screen); /* ask disposition */ X junk_alias(); /* forget alias display */ X return(S_REDRAW); /* say screen was changed */ X} X X/* show_alias - show alias data base or default message in middle window */ X Xhidden int show_alias() X{ X static char *noalias[] = { /* Ha ha ha ho ho hum */ X "", X "The alias data base is empty. Normally it holds lines of the form", X "", X " alias-name one-or-more-mail-addresses", X "", X "You can create or change the alias data base with the E command.", X 0, X }; X if (afile) { /* check pager file exists */ X set_pager(afile); /* select existing display */ X } else if (rd_pager(afile = open_pager(),aliases())) { X mesg_pager(afile,noalias); /* no alias database */ X } X ds_pager(); /* (re)draw display */ X return(0); /* screen is up-to-date */ X} X X/* junk_alias - destroy alias data base display */ X Xhidden void junk_alias() X{ X if (afile) { /* no-op if no display */ X close_pager(afile); /* release memory */ X afile = 0; /* say it is gone */ X } X} X X/* edit_alias - edit or create alias data base */ X Xhidden int edit_alias() X{ X register int stat; X X if (stat = edit(aliases(),TMPALIAS)) X errdisp(stat); /* edit() had a problem */ X junk_alias(); /* force new display */ X return(S_REDRAW); /* say screen has changed */ X} END_OF_main/alias.c if test 3434 -ne `wc -c
main/cmail.c <<'END_OF_main/cmail.c' X/*++ X/* NAME X/* cmail 1 X/* SUMMARY X/* report if there are unread messages X/* PROJECT X/* pc-mail X/* PACKAGE X/* cmail X/* SYNOPSIS X/* cmail [-p password] X/* DESCRIPTION X/* cmail reports if there are unread mail messages in the X/* pc-mail spool directory. X/* X/* If the -p option is present, cmail first invokes the cico X/* program to contact the mail server host. X/* X/* Typically cmail is run immediately after system startup, X/* while you are getting your first cup of coffee. X/* X/* The program returns a nonzero exit status if it could not X/* find any mail. X/* COMMANDS X/* cico file transfer program X/* nmail processes new mail X/* FILES X/* Various files in the spool directory X/* X/* LOGFILE system status messages X/* n mail messages X/* h header line of new mail X/* o header line of old mail X/* DIAGNOSTICS X/* Error messages in case the environment is not properly set up. X/* BUGS X/* Invites people to put their mail password into the autoexec file. 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 3 19:34:57 MET 1988 X/* LAST MODIFICATION X/* 90/01/22 13:01:19 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X#include X X#include "defs.h" X#include "ndir.h" X#include "path.h" X#include "status.h" X Xhidden void parse_args(); /* forward declarations */ Xhidden void usage(); Xhidden void error(); Xhidden int newmail(); X Xhidden char *password = 0; /* set by the -p option */ X Xpublic char *progname = "cmail"; /* for diagnostics */ 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 if (pathinit()) /* check path info */ X error("cmail: bad MAILDIR environment variable"); X if (password && *password && X invokelp(CICO, "-p", password, (char *) 0) == E_NOPROG) X error("cmail: cannot execute the CICO program"); X if (invokelp(NMAIL, (char *) 0) == E_NOPROG) X error("cmail: cannot execute the NMAIL program"); X exit(newmail() == 0); /* look for new mail */ 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 'p': /* call cico first */ X if (--argc == 0) X usage("missing password"); X password = *++argv; X break; X default: /* unknown option */ X usage("invalid option: -%s", *argv); X break; X } X } X X /* check for extraneous arguments */ X X if (argc > 0) X usage("unexpected argument: %s", *argv); X} X X/* scan for new unread mail */ X Xhidden int newmail() X{ X DIR *dp; X struct direct *de; X FILE *fp; X char from[MAXLINE]; X int msgcount = 0; X unsigned msgno; X X /* X * Scan the spool directory for unread messages and extract the X * originator address from the corresponding meta file. X */ X X if ((dp = opendir(maildir)) == 0) { X error("cmail: cannot access the mail directory"); X } else { X while (de = readdir(dp)) { X if (de->d_name[0] == NEW_MESG X && (msgno = seqno(de->d_name)) X && (fp = fopen(new_meta(msgno), "r")) != 0) { X if (fgets(from, sizeof(from), fp)) X printf("You have new mail from %s", from); X msgcount++; X fclose(fp); X } X } X closedir(dp); X } X return (msgcount); X} X Xhidden void error(str) Xchar *str; X{ X fprintf(stderr, "%s\n", str); X exit(1); X} X X/* VARARGS */ X Xhidden void usage(va_alist) Xva_dcl X{ X va_list ap; X char *fmt; X X va_start(ap); X fmt = va_arg(ap, char *); X vfprintf(stderr, fmt, ap); X va_end(ap); X fprintf(stderr, "\nusage: cmail [-p password]\n"); X exit(1); X} END_OF_main/cmail.c if test 3814 -ne `wc -c
main/comport.h <<'END_OF_main/comport.h' X/* X * Comport.h X * X * defines the bit masking for the get_mcr() X * X * @(#) comport.h Version hoptoad-1.3 87/03/24 X * X * Copyright (C) Tim M. Pozar 1987 X * Anyone can use this code for anything, but it is copyright by Tim X * and you must leave his copyright in the code. X * X */ X X/* X * get_msr() X * Function to read (get) the byte located in the Modem Status X * Register (3FEh). The table below describes the byte returned. X * bit description X * 0 Delta Clear to Send (DCTS) X * Indicates that the !CTS input to the chip has changed state X * since the last time it was read by the processor. X * 1 Delta Data Set Ready (DDSR) X * Indicates that the !DRS input to the chip has changed since X * last time it was read by the processor. X * 2 Trailing Edge Ring Indicator (TERI) X * Indicates that the !RI input to the chip has changed from X * an on (logical 1) to an off (logical 0) condition. X * 3 Delta Rx Line Signal detect (DRLSD) X * Indicates that the !RLSD input to the chip has changed state. X * NOTE: Whenever bit 0, 1, 2, or 3 is set to a logical 1, a modem status X * interrupt is generated. X * X * 4 Clear to Send (CTS) X * This bit is the complement of the clear to send (!CTS) input. X * If bit 4 (LOOP) of the MCR is set to a logical 1, this is X * equivalent to RTS in the MCR. X * 5 Data Set Ready (DSR) X * This bit is the complement of the data set ready (!DSR) input. X * If bit 4 (LOOP) of the MCR is set to a logical 1, this is X * equivalent to DTR in the MCR. X * 6 Ring Indicator (RI) X * This bit is the complement of the ring indicator (!RI) input. X * If bit 4 (LOOP) of the MCR is set to a logical 1, this is X * equivalent to OUT 1 in the MCR. X * 7 Receive Line Signal Detect (RLSD) or Carrier Detect (CD). X * This bit is the complement of the received line signal detect X * (!RLSD) input. If bit 4 (LOOP) of the MCR is set to a logical 1, X * this is equivalent to OUT 2 in the MCR. X */ X X#define DCTS 1 X#define DDSR 2 X#define TERI 4 X#define DRLSD 8 X#define CTS 16 X#define DST 32 X#define RI 64 X#define RLSD 128 /* Also known as ... */ X#define CD 128 X#define set_tty SET_TTY /* find current settings, and initialize */ X#define reset_tty RESET_TTY /* reset to settings that set_tty() found */ X#define get_msr GET_MSR /* get MSR byte from port. */ X#define init_comm INIT_COMM /* initialize the comm port interupts, */ X#define uninit_comm UNINIT_COMM /* remove initialization, */ X#define set_xoff SET_XOFF /* enable/disable XON/XOFF, */ X#define get_xoff GET_XOFF /* read XON/XOFF state, */ X#define rcvd_xoff RCVD_XOFF /* returns true if XOFF rcvd, */ X#define sent_xoff SENT_XOFF /* true if XOFF sent, */ X#define inp_cnt INP_CNT /* returns count of rcv chars, */ X#define inp_char INP_CHAR /* get one char from buffer, */ X#define inp_flush INP_FLUSH /* flush input buffer, */ X#define outp_char OUTP_CHAR /* output a character, */ END_OF_main/comport.h if test 3203 -ne `wc -c
main/edit.c <<'END_OF_main/edit.c' X/*++ X/* NAME X/* edit 3 X/* SUMMARY X/* edit a file X/* PROJECT X/* pc-mail X/* PACKAGE X/* mail X/* SYNOPSIS X/* #include "mail.h" X/* X/* int edit(fname,tname) X/* char *fname,*tname; X/* DESCRIPTION X/* edit() copies the file in fname to the file tname, X/* invokes the editor, and copies the result back. X/* COMMANDS X/* the program specified in the EDITOR environment variable, X/* or a system-dependent default. 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 6 20:21:35 MET 1988 X/* LAST MODIFICATION X/* 90/01/22 13:01:34 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X X#include "defs.h" X#include "path.h" X#include "mail.h" X#include "status.h" X X#ifdef MSDOS X# include X#endif X X /* X * Some editors (wordstar) do not accept path names. grrrr. So we copy the X * edit file to a temp file in the current directory. After editing, the X * temp file is copied back. We do not move files, since current dir and the X * spool dir may be in different file systems, and people might turn off the X * machine and lose their work. X */ X X/* edit - edit or create a file */ X Xpublic int edit(fname, tname) Xchar *fname, X *tname; X{ X register int stat = 0; X register FILE *fp; X X /* X * First make sure that we can get write permission on the permanent file X * and temporary file (if they exist). Create an empty temp file if we X * are not editing an existing file. X */ X X if (chmod(fname, 0666) && errno != ENOENT) { X stat = E_WRITERR; /* original file is protected */ X } else if (chmod(tname, 0666) && errno != ENOENT) { X stat = E_WRITERR; /* scratch file is protected */ X } else if ((fp = fopen(fname, "a")) == 0) { X stat = E_WRITERR; /* file system is protected? */ X } else if (fclose(fp), stat = cpfile(fname, tname)) { X /* void */ ; /* could not make edit copy */ X } else { X patience(); /* this may take some time */ X kbdrest(); /* reset tty modes */ X if (stat = invokelp(editor, tname, (char *) 0)) /* call editor */ X stat = (stat == E_NOPROG ? stat : E_UNKNOWN); X else X stat = cpfile(tname, fname); /* copy back */ X kbdinit(); /* set tty modes */ X unlink(tname); /* don't check status */ X } X chmod(fname, 0444); /* protect destination file */ X return (stat); X} X X/* cpfile - yet another file copy function */ X Xhidden int cpfile(from, to) Xchar *from; Xchar *to; X{ X register FILE *in, X *out; /* file pointers */ X int stat = 0; /* error status */ X register int c; /* character buffer */ X X if ((in = fopen(from, "r")) == 0) { /* cannot read source */ X return (E_READERR); X } else if ((out = fopen(to, "w")) == 0) { /* cannot write destination */ X fclose(in); X return (E_WRITERR); X } else { X X#ifdef O_BINARY X setmode(fileno(in), O_BINARY); /* get rid of the */ X setmode(fileno(out), O_BINARY); /* crlf translation */ X#endif X while ((c = getc(in)) != EOF) X putc(c, out); X if (ferror(in)) /* check read error status */ X stat = E_READERR; X else if (ferror(out)) /* check write error status */ X stat = E_WRITERR; X fclose(in); X fclose(out); X return (stat); /* at most one type of error */ X } X} END_OF_main/edit.c if test 3336 -ne `wc -c
main/getwork.c <<'END_OF_main/getwork.c' X/*++ X/* NAME X/* getwork 3 X/* SUMMARY X/* receive work from remote system X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* #include "work.h" X/* X/* work *rmtwork(rqst) X/* char *rqst; X/* X/* void getwork(wrk) X/* work *wrk; X/* DESCRIPTION X/* rmtwork() parses a remote Send request. A suitable destination X/* file is opened. The resulting work structure is for use by X/* getwork(). X/* X/* getwork() receives a file from the remote system, after the X/* necessary preparations have been done by rmtwork(). X/* The file is deleted in case of transmission failure. X/* FUNCTIONS AND MACROS X/* trap(), locname() X/* SEE ALSO X/* sendwork(), scanwork() X/* DIAGNOSTICS X/* Exceptions are handled with longjmp(systrap,errorcode). X/* X/* rmtwork() traps in case of invalid requests or if the destination X/* file could not be opened. X/* X/* getwork() traps in case of read/write errors. 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 16:57:57 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:01:39 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X X#include "defs.h" X#include "logs.h" X#include "status.h" X#include "work.h" X#include "params.h" X#include "comm.h" X X/* rmtwork - parse remote S request and open destination file */ X Xpublic work *rmtwork(rqst) Xchar *rqst; X{ X static work wrk; X char path[BUFSIZ]; X X if (sscanf(rqst, "S %*s %s", path) != 1) /* pick destination file name */ X trap(E_LOST, "BAD REQUEST FORMAT"); X debug(5) ("rmtwork: path %s\n", path); X strcpy(wrk.path, locname(path)); /* convert to local name */ X debug(5) ("rmtwork: file %s\n", wrk.path); X if ((wrk.fp = fopen(wrk.path, "w")) == 0) /* try to open that file */ X trap(E_WRITERR, "CAN'T CREATE FILE (%s)", sys_errlist[errno]); X return (&wrk); X} X X/* getwork - receive file from remote host */ X Xpublic void getwork(wrk) Xregister work *wrk; X{ X char buf[BUFSIZ]; X register int nread; X register int werror; X X while ((nread = CALL(Read) (ttfd, buf, BUFSIZ)) > 0 && X fwrite(buf, sizeof(*buf), nread, wrk->fp) == nread) X /* void */ ; X werror = ferror(wrk->fp); /* record error status */ X fclose(wrk->fp); X X /* X * In case of any errors we force a protocol shutdown. The oher side will X * send the same file again next time we make a connection. X */ X X if (nread < 0) { /* did the protocol fail? */ X chmod(wrk->path, 0666); /* make file deletable */ X unlink(wrk->path); /* remove file */ X trap(E_LOST, "FAILED (lost link)"); /* handle exception */ X /* NOTREACHED */ X } else if (werror) { /* file write error? */ X chmod(wrk->path, 0666); /* make file deletable */ X unlink(wrk->path); /* remove file */ X trap(E_WRITERR, "FILE WRITE ERROR (%s)", sys_errlist[errno]); X /* NOTREACHED */ X } else { X chmod(wrk->path, 0444); /* protect the file */ X } X} END_OF_main/getwork.c if test 2974 -ne `wc -c
main/hsearch.3 <<'END_OF_main/hsearch.3' X.TH HSEARCH 3c local X.SH NAME Xhsearch, hcreate, hdestroy \- manage hash search tables X.SH SYNOPSIS X.nf X.ft B Xtypedef struct entry { X char *key; X char *data; X } ENTRY; X Xtypedef enum { X FIND, X ENTER X } ACTION; X XENTRY *hsearch (item, action) XENTRY item; XACTION action; X Xint hcreate (nel) Xunsigned int nel; X Xvoid hdestroy (); X.br X.ft R X.fi X.SH DESCRIPTION X.I Hsearch Xis a simple, public domain, reimplementation of the routine of the same Xname in X.SM UNIX XSystem V. X.PP X.I Hsearch Xreturns a pointer into a hash table where a given element can be found. XAn X.I item Xto be stored in the table is of type ENTRY. X.I Item.key Xpoints to the key used for comparison, while X.I item.data Xpoints to the data to be associated with the key. XIf the data pointed to is not a character string, it should be cast Xto type pointer-to-character before being assigned. XNote that X.I item Xis a structure, and X.I not Xa pointer to a structure. XIf the value of X.I action Xis FIND, X.I hsearch Xwill return a pointer to the item in the table, if it is there, otherwise Xit will return NULL. If the action is ENTER, it will return a pointer Xto the new item, or NULL if it could not add the item to the table. XNote that if the action is ENTER, and the item was already in the table, the X.I data Xfield will be updated from the new X.IR item . X.PP X.I Hsearch Xdoes not provide all the (compile-time) options of the original routine; Xinstead it uses a X.I remainder modulo table size Xhashing algorithm, X.I chaining X(linked lists) to resolve collisions, with new entries being placed at Xthe end, and X.IR strcmp (3) Xfor the comparison function. XIt was felt that a simple reimplementation was called for, Xinstead of a brand new hash table package, Xsince the interface provided is a clean one, Xbut the original source code is not publicly available. X.PP X.I Hcreate Xcreates the hash table, allocating enough space for it. It must be Xcalled before X.IR hsearch . X.I Nel Xis an estimate of the number of hash buckets that will be needed; Xthe table size will be adjusted up to the next largest prime number. If X.I nel Xis larger than the largest prime known to X.IR hcreate , " nel" Xwill be used directly. X.PP X.I Hdestroy Xdestroys the hash table, freeing up all its storage. It may be followed Xby another call to X.IR hcreate . X.SH SEE ALSO X.IR malloc (3), X.IR strcmp (3), Xthe various other searching routines available with System V. X.SH DIAGNOSTICS X.I Hsearch Xreturns NULL Xif either the action was FIND and the item is not in the table, or Xthe action was ENTER but the item could not be inserted. X.PP X.I Hcreate Xreturns zero if it could not create the initial table; it returns Xone if all went well. X.SH BUGS X.PP XOnly one hash table may be active at a given time. X.PP XNot as flexible as the original System V implementation. X.SH AUTHOR X.nf XArnold Robbins XSchool of Information and Computer Science XGeorgia Institute of Technology XAtlanta, Georgia 30332 X XCSNET: arnold@gatech XARPA: arnold%gatech.csnet@csnet-relay.arpa XUUCP: { akgua, allegra, hplabs, ihnp4, seismo, ut-sally }!gatech!arnold END_OF_main/hsearch.3 if test 3042 -ne `wc -c
main/kproto.ms <<'END_OF_main/kproto.ms' X.TL Xuucp k protocol description X.AU XW.Z. Venema XEindhoven University of Technology X.AE X.NH XIntroduction X.LP XThe k protocol has been developed for the Sytek Localnet local area Xnetwork at the Eindhoven University of Technology (TUE). XMain features of this network are: X.IP 1 XNetwork partners may talk at different baudrates. This implies that the network Xdoes some buffering. This may cause timing Xproblems (e.g. a system sending at 9600 baud to a system reading at 1200 baud). X.IP 2 XThe network needs a flow control mechanism. Usually this is Xbased on the XON/XOFF protocol. Other control character sequences are used Xfor commands to the network. X.IP 3 XSome network stations are connected to telephone modems. X.LP XFor these reasons, the k protocol must (i) cope with on XON/XOFF flow Xcontrol, (ii) be suitable for 7-bit data paths, (iii) avoid Xcontrol characters and (iv) provide reliable operation Xover telephone lines as well as over the local area network. X.NH XPackets X.LP XData are sent as checksummed 256-byte packets, terminated by an XASCII CR. Except for the packet header (^P), the k protocol only uses XASCII codes 040 through 0137. Three data bytes are expanded to four Xbytes upon transmission. Theoretically, this reduces throughput by 25 percent. XAt 1200 baud, actual performances are: X.DS Xuucp, g protocol 110 cps Xuucp, k protocol 74 cps Xc-kermit 67 cps X.DE XNote that the values for c-kermit are for text files, with repeat-count Xcompression enabled. X.PP XThe packet types are a subset of those used in the kermit programs: X.DS XD packets contain data. XY packets are sent when a correct data packet was received. XN packets are sent when incorrect data was received. XA packets are sent to shut down the k protocol. X.DE XA packet always begins with a header: X.DS XSOH packet header, ASCII control-P Xlen (size of data, low 6 bits) + 32 Xlen (size of data, high 6 bits) + 32 Xnum (packet number mod 64) + 32 Xtype packet type Xcheck one-byte type-1 kermit checksum X.DE X.LP XThe header is followed by checksummed data if len > 0: X.DS Xdata len data bytes Xcheck1 (upper 2 bits of type-3 kermit 16-bit checksum) + 32 Xcheck2 (middle 6 bits of type-3 kermit 16-bit checksum) + 32 Xcheck3 (lower 6 bits of type-3 kermit 16-bit checksum) + 32 X.DE X.LP XEvery packet is followed by an ASCII carriage return, which is Xignored upon reception of a packet. It prevents timeout errors Xwhen one byte gets lost (the most common case). X.NH XHandshake X.LP XHandshake is on a per-packet basis; a transmitter will not send Xanother data packet before it knows that the receiver got the data Xin good condition. There are various ways to obtain that knowledge: Xthe receiver may send an ACK message (usual case), or a NAK for Xthe next data packet, or a data packet with the next sequence number. X.PP XThe protocol is aborted when an unexpected Xpacket type or when a packet out of sequence is received. XSince 'A' packets are never expected, they always cause a protocol Xfault. END_OF_main/kproto.ms if test 2984 -ne `wc -c
main/lmail.c <<'END_OF_main/lmail.c' X/*++ X/* NAME X/* lmail 1 X/* SUMMARY X/* local delivery of mail received via GNUUCP X/* PROJECT X/* pc-mail X/* PACKAGE X/* gnu X/* SYNOPSIS X/* lmail [arguments] X/* DESCRIPTION X/* This program replaces the receiving function of the pc-mail "cico" X/* program, on systems that use GNUUCP for message transport. X/* X/* lmail reads one mail message from its standard input and installs X/* it as a message file in the pc-mail mail data base. Any command-line X/* arguments are ignored (since pc-mail is a single-user mail system). X/* X/* This command should be installed such that it can be found by the X/* GNUUCP "rmail" command. The actual program name may be different X/* from "lmail"; this depends on how the GNUUCP software was configured. X/* ENVIRONMENT X/* MAILDIR, path to pc-mail message data base X/* FILES X/* In the spool directory: X/* h new mail message. X/* SEE ALSO X/* path(5) spool directory, file names X/* nmail(1) extracts sender and subject from new mail. X/* DIAGNOSTICS X/* Problems are reported on the standard error output, and cause the X/* program to terminate with a nonzero exit status. 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 Jan 3 22:16:08 MET 1990 X/* LAST MODIFICATION X/* 90/01/22 13:02:00 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X X#include "defs.h" X#include "path.h" X Xextern int errno; Xextern char *sys_errlist[]; X Xextern char *fgets(); X Xhidden void error(); Xpublic char *progname = "lmail"; X X/* pc-mail is a single-user mailer, so we ignore command-line arguments */ X Xmain() X{ X char buf[BUFSIZ]; X char *fname; X FILE *fp; X X /* Find out where the mail data base lives */ X X if (pathinit()) X error("no mail directory or MAILDIR environment variable not set"); X X /* Create a mail message file only - let nmail extract sender and subject */ X X (void) umask(0222); /* make files read-only */ X if ((fp = fopen(fname = new_mesg(newseqno()), "w")) == 0) X error("cannot open %s: %s", fname, sys_errlist[errno]); X X /* Copy standard input to message file */ X X while (fgets(buf, sizeof(buf), stdin)) X (void) fputs(buf, fp); X X /* Error checking */ X X if (fflush(fp) || ferror(fp) || fclose(fp)) X error("%s: write error: %s", fname, sys_errlist[errno]); X X exit(0); X /* NOTREACHED */ X} X X/* error - complain */ X X/* VARARGS */ X Xhidden void error(va_alist) Xva_dcl X{ X va_list ap; X char *fmt; X X (void) fprintf(stderr, "%s: ", progname); X va_start(ap); X fmt = va_arg(ap, char *); X (void) vfprintf(stderr, fmt, ap); X va_end(ap); X (void) putc('\n', stderr); X exit(2); X} END_OF_main/lmail.c if test 2815 -ne `wc -c
main/mail.c <<'END_OF_main/mail.c' X/*++ X/* NAME X/* mail X/* SUMMARY X/* visual mail-shell X/* PROJECT X/* pc-mail X/* PACKAGE X/* mail X/* SYNOPSIS X/* mail X/* DESCRIPTION X/* mail is an interactive program for reading, receiving X/* and producing electronic mail. Actually, most of the work X/* is done by programs called by the mail program. X/* X/* By default, the program presents the user display of a list of X/* mail messages in the form of one-line summaries. Single-key X/* commands are available to select and manipulate mail messages. X/* Mail messages are created with an editor chosen by the user. X/* X/* The name of the spool directory, printer program and editor X/* are taken from the environment, or assume system-dependent defaults. X/* ENVIRONMENT X/* MAILDIR name of spool directory X/* EDITOR name of program to create mail X/* MAILPRN name of program/file to print with/to X/* MAILCMD command to execute upon termination X/* COMMANDS X/* cico network communications program X/* nmail postprocessor for mail received by cico X/* FILES X/* The mail system maintains various files in a spool directory, X/* as well as a logfile of all network transactions. X/* SEE ALSO X/* path(3) system-dependent path names X/* DIAGNOSTICS X/* Error messages should be self-explanatory. X/* BUGS X/* The user has to explicitly tell the system to contact a remote X/* mail host. This is a limitation of MS-DOS, not of the program. X/* AUTHOR(S) X/* W.Z. Venema X/* Eindhoven University of Technology X/* Department of Mathematics and Computer Science X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands X/* CREATION DATE X/* Thu Apr 2 21:54:08 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:02:04 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X#include "defs.h" X#include "path.h" X#include "status.h" X#include "mail.h" X#include "window.h" X Xpublic char *progname = "mail"; /* for diagnostics */ X X/* forward declarations */ X Xhidden int checkfiles(); X X/* for now, don't even try to look at command args */ X Xpublic main(argc, argv) Xint argc; Xchar **argv; X{ X register int stat; X X /* X * Initializations: get screen control and function-key codes (wininit). X * check if the limit on the number of open files is ok (checkfiles), get X * the values from environment variables (pathinit), set the terminal X * driver to the desired mode (kbdinit), check for partally processed new X * mail with the nmail program. Also make sure that our file permissions X * are safe (umask). X */ X X if (!isatty(fileno(stdin))) { X perror("mail: standard input"); X exit(1); X } X umask(022); /* avoid problems */ X wininit(); /* do termcap stuff */ X clrscreen(); /* clear screen */ X (stat = checkfiles()) /* get max nbr of open files */ X ||(stat = pathinit()) /* get spool, printer, editor */ X ||(stat = invokelp(NMAIL, (char *) 0)); /* just in case there's mail */ X kbdinit(); /* set to tty RAW, NOECHO */ X if (stat) { X errdisp(stat); /* we have a problem */ X } else { X init(); /* start the machine */ X } X X /* finalizations */ X X kbdrest(); /* restore tty driver */ X clrscreen(); /* clear screen */ X fflush(stdout); X if (stat == 0) X onexit(mailcmd); /* do exit command */ X exit(stat); X /* NOTREACHED */ X} X X/* checkfiles - make sure we can open as many files as we want */ X Xhidden int checkfiles() X{ X register int i; X int fds[MINFILES]; X register int stat; X X for (i = 0; i < MINFILES; i++) /* try to open many files */ X if ((fds[i] = open(NULLDEV, 0)) < 0) X break; X X stat = (i < MINFILES ? E_FILENO : 0); /* did we fail? */ X X while (--i >= 0) /* release files */ X close(fds[i]); X return (stat); X} X X/* onexit - exec another command */ X Xint onexit(command) Xchar *command; X{ X if (command && *command) X return (system(command)); X} END_OF_main/mail.c if test 4002 -ne `wc -c
main/ms_parse.c <<'END_OF_main/ms_parse.c' X/*++ X/* NAME X/* ms_parse 3 X/* SUMMARY X/* message parser X/* PROJECT X/* pc-mail X/* PACKAGE X/* mailsh X/* SYNOPSIS X/* #include "ms_parse.h" X/* X/* int ms_parse(context, line) X/* int context; X/* char *line; X/* X/* int hscanf(line, prefix, format, result) X/* char *line; X/* char *prefix; X/* char *format; X/* char *result; X/* DESCRIPTION X/* The routines in this module recognize X/* the context in which successive lines of text occur within an X/* e-mail message, or extract specific information from header X/* lines. X/* X/* The expected format of an e-mail message is: UUCP header lines, X/* RFC822-like header lines, message body. Each of these sections X/* may be missing from the message. A header line is a line that X/* has no blanks before the first colon appearing on that line. X/* X/* ms_parse() determines the context in which a line of text was found: X/* X/* .nf X MS_UUCP UUCP-style From_ line X MS_HEADER RFC822-like header line X MS_CONT Continued header line X MS_BODY Line within message body X/* .fi X/* X/* During the first call of ms_parse(), the context argument should have X/* the value MS_UUCP. Upon successive calls the value should be equal X/* to the last value returned by ms_parse(). The algorithm is transparent X/* to other context values (i.e. they cause no transitions). X/* X/* hscanf() compares the beginning of a line with the specified prefix X/* (ignoring case differences), and if the comparison succeeds, it X/* invokes sscanf() on the remainder of that line. A zero return value X/* means that no information was extracted with sscanf. 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 Dec 9 18:50:35 MET 1989 X/* LAST MODIFICATION X/* 90/01/22 13:02:12 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X X#include "defs.h" X#include "ms_parse.h" X X/* forward declarations */ X Xhidden int isheader(); X X/* hscanf - match header and extract info from remainder of header line */ X Xpublic int hscanf(line, pre, fmt, ptr) Xchar *line; Xchar *pre; Xchar *fmt; Xchar *ptr; X{ X int len = strlen(pre); X X return (istrncmp(pre, line, len) == 0 && sscanf(line + len, fmt, ptr) == 1); X} X X/* ms_parse - parse one message line */ X Xpublic int ms_parse(context, line) Xregister int context; Xregister char *line; X{ X X /* X * A message may begin with UUCP header lines ("From blablabla", X * sometimes escaped with a ">" character), followed by RFC822-like X * header lines (lines that start with a word + colon, or continuation X * lines that start with whitespace), followed by the remainder of the X * message. Header and body are usually separated by an empty line (on X * systems that can handle that) but the we do not require this. X */ X X switch (context) { X case MS_UUCP: X if (line[0] == '>' || strncmp(line, "From ", 5) == 0) X return (MS_UUCP); X if (isspace(line[0])) X return (MS_BODY); X /* FALLTHROUGH */ X case MS_HEADER: X case MS_CONT: X if (isspace(line[0])) X return (MS_CONT); X if (isheader(line)) X return (MS_HEADER); X /* FALLTHROUGH */ X case MS_BODY: X return (MS_BODY); X } X /* NOTREACHED */ X} X X/* isheader - does this line look like a header? */ X Xhidden int isheader(buf) Xchar *buf; X{ X static char blanks[] = " \t\f"; X char *cp; X char *blk; X char *colon; X X /* X * A header line has no blanks before the first colon. Which means that a X * line that starts with a colon character is treated as header line. X * This turns out to be what many sendmail implementations do, too. X */ X X if ((colon = index(buf, ':')) == 0) { /* check for colon */ X return (0); X } else { /* find preceding blanks */ X for (cp = blanks; *cp; cp++) X if ((blk = index(buf, *cp)) != 0 && blk < colon) X return (0); X } X return (1); X} END_OF_main/ms_parse.c if test 3953 -ne `wc -c
main/params.c <<'END_OF_main/params.c' X/*++ X/* NAME X/* params 3 X/* SUMMARY X/* communication parameter access X/* PROJECT X/* pc-mail X/* PACKAGE X/* library X/* SYNOPSIS X/* #include "params.h" X/* X/* Info *getparams(); X/* DESCRIPTION X/* getparams() returns a pointer to a table with communications X/* parameters. Usually communications parameters are set with the X/* "setup" option in the main menu of the interactive mail program. X/* X/* First getparams() attempts to read from the setup file. X/* If that fails it creates an empty parameter table with X/* null string pointers as parameter values. X/* FUNCTIONS AND MACROS X/* myalloc() X/* BUGS X/* getparams() silently ignores any information in the X/* parameter file that it does not recognize. X/* getparams() will read the parameter file upon each call, even X/* if nothing has changed since the last read. Let us say that X/* it anticipates on multi-user environments. 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 8 15:39:23 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:02:24 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X X#include "defs.h" X#include "path.h" X#include "params.h" X X/* Storage area for setup parameters */ X Xhidden Info params[] = { X /* name */ /* name length */ /* value */ /* default */ X S_IGNORE, sizeof(S_IGNORE) -1, 0, D_IGNORE, X#ifndef DAEMON X S_PORT, sizeof(S_PORT) - 1, 0, 0, X S_BAUD, sizeof(S_BAUD) - 1, 0, 0, X S_HOST, sizeof(S_HOST) - 1, 0, 0, X S_LOGIN, sizeof(S_LOGIN) - 1, 0, 0, X S_DIAL, sizeof(S_DIAL) - 1, 0, 0, X S_DISC, sizeof(S_DISC) - 1, 0, D_DISC, X#endif X 0, 0, 0, 0, X}; X Xhidden char *hackstr(); /* forward declaration */ X X/* getparams - try to get info from file, else make empty table */ X Xpublic Info *getparams() X{ X char line[BUFSIZ]; X register Info *ip; X FILE *fp; X X /* for cleanliness, we first clear all table entries */ X X for (ip = params; ip->ident; ip++) { X if (ip->strval) X free(ip->strval); X ip->strval = 0; X } X X /* then, try to copy parameter file info to the table */ X X if (fp = fopen(parm_file(), "r")) { X while (fgets(line, sizeof(line), fp)) { X for (ip = params; ip->ident; ip++) { X if (strncmp(ip->ident, line, ip->length) == 0) { X ip->strval = hackstr(line + ip->length); X break; X } X } X } X (void) fclose(fp); X } X X /* set defaults for undefined values */ X X for (ip = params; ip->ident; ip++) X if (ip->strval == 0 && ip->defval != 0) X ip->strval = hackstr(ip->defval); X X return (params); X} X X/* hackstr - cut away blanks around string and make copy */ X Xhidden char *hackstr(s) Xregister char *s; X{ X register char *r; X int len; X X /* strip leading and trailing blanks */ X X while (*s && isspace(*s)) X s++; X for (r = s + strlen(s); r > s && isspace(r[-1]); r--) X /* void */ ; X X /* X * s is at the terminator or first non-blank char. r is at the terminator X * or first blank after the last non-blank char. Thus, the actual string X * length is r-s. We add one for the terminator. We don't allocate memory X * if the string is empty. X */ X X if (len = r - s) { X char *cp = strncpy(myalloc(len + 1), s, len); X X cp[len] = '\0'; X return (cp); X } else { X return (0); X } X} END_OF_main/params.c if test 3364 -ne `wc -c
main/path.c <<'END_OF_main/path.c' X/*++ X/* NAME X/* path 3 X/* SUMMARY X/* system-dependent file name stuff X/* PROJECT X/* pc-mail X/* PACKAGE X/* general X/* SYNOPSIS X/* #include "str.h" X/* #include "path.h" X/* X/* int pathinit() X/* X/* FILE *propen() X/* X/* char *fspool(file) X/* char *file; X/* DESCRIPTION X/* The routines in this module know the system-dependent rules X/* for file names and printers. X/* X/* pathinit() extracts the values of the environment variables X/* MAILDIR, MAILPRN, MAILCMD and EDITOR, and assumes system-dependent X/* defaults for undefined environment variables. It checks for the X/* existence of the spool directory. X/* X/* Under Unix, the MAILPRN environment variable should be the name X/* of a command. Under MS-DOS, it should be the name of a device or file. X/* X/* propen() returns a stream to print to. X/* X/* fspool() constructs a path name from the spool directory and X/* the file name in its argument. X/* Real unix uses uucp spool file names of the form X/* X/* . X/* X/* This is problematic for MS-DOS and similar systems that X/* only allow three characters after the dot. Instead of building X/* a tiny file system on top of MS-DOS, the pc-mail programs X/* use a different way of spool file naming: X/* X/* X/* X/* This scheme assumes that the pc has access to exactly one unix X/* host, since the host name is not part of spool file names. X/* COMMANDS X/* lp(1) (under unix) printer spooler program X/* FILES X/* PRN under MS-DOS X/* DIAGNOSTICS X/* pathinit() returns a nonzero value (see status(5)) if one of the X/* environment variables (or defaults) are incorrect. X/* X/* File open functions return a null pointer when a file could not X/* be opened. X/* BUGS X/* pathinit() only verifies the MAILDIR name. X/* X/* fspool() returns a pointer to static memory. 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 5 15:27:37 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:02:26 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X#include "defs.h" X#include "path.h" X#include "status.h" X X /* X * Environment variables are loaded here. Most of them have a default; We X * only check the validity of the MAILDIR variable. X */ X Xpublic char *maildir = DEFSPOOL; /* spool directory */ Xpublic char *editor = DEFEDIT; /* editor program */ Xpublic char *mailprn = DEFPRINT; /* where to print to */ Xpublic char *mailcmd = 0; /* do this on exit */ X Xtypedef struct { X char *vname; X char **ptr; X} Environ; X Xstatic Environ env[] = { X "SPOOL", &maildir, /* backwards compatibility... */ X "MAILDIR", &maildir, X "EDITOR", &editor, X "MAILPRN", &mailprn, X "MAILCMD", &mailcmd, X 0, 0, /* terminator */ X}; X X/* pathinit - consult the environment; checks existence of spool directory */ X Xpublic int pathinit() X{ X register char *cp; X struct stat s; X register Environ *ep; X X /* load environment variables */ X X for (ep = env; ep->vname; ep++) X if (cp = getenv(ep->vname)) X *(ep->ptr) = cp; X X /* check existence of the spool directory */ X X return (stat(maildir, &s) || (s.st_mode & S_IFMT) != S_IFDIR ? E_NOSPOOL : 0); X} END_OF_main/path.c if test 3423 -ne `wc -c
main/scanwork.c <<'END_OF_main/scanwork.c' X/*++ X/* NAME X/* scanwork 3 X/* SUMMARY X/* search spool directory for outbound messages X/* PROJECT X/* pc-mail X/* PACKAGE X/* cico X/* SYNOPSIS X/* #include "work.h" X/* X/* work *scanwork() X/* DESCRIPTION X/* scanwork() searches the spool directory for files to be sent to X/* the remote system. If a file is found, scanwork() attempts to X/* open that file. A null pointer is returned if no work was found. X/* X/* The result is normally used by sendwork(). X/* FUNCTIONS AND MACROS X/* scandir(), newseqno(), fspool() X/* SEE ALSO X/* sendwork() send spool file to remote host X/* getwork() receive remote spool file X/* rmtname() local spool-file to remote-file name mapping 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 17:28:09 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:02:31 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X#include X X#include "defs.h" X#include "params.h" X#include "comm.h" X#include "work.h" X#include "path.h" X#include "ndir.h" X#include "logs.h" X X /* X * The present implementation assumes that work for the remote system is in X * the form of pairs of spool files with names d and x. X * X * The d files contain an electronic mail message, and the x files contain the X * destination. Both have the same suffix which is just a five-digit X * sequence number. X * X * The task of scanwork() thus is trivial: just locate a file of which the name X * begins with a d or x and do some file name parsing. The major work is X * done by rmtname() and sendwork(): depending on the type of file, generate X * an appropriate remote file name and send the appropriate messages to the X * remote system. X * X * After a file has been transmitted it is renamed to reflect the "Sent" X * status. X */ X X/* scanwork - search spool directory for work */ X Xpublic work *scanwork() X{ X register DIR *dp; X register struct direct *de; X static work wrk; /* overwritten each time */ X static char unsent[] = "DdXx"; /* prefixes for unsent messages */ X char *p_unsent; /* pointer into unsent array */ X static char sent[] = "qqrr"; /* prefixes for sent messages */ X X if ((dp = opendir(maildir)) == 0) { X return (0); X } else { X while (de = readdir(dp)) { X debug(5) ("scanwork: file %s\n", de->d_name); X if (((p_unsent = index(unsent, wrk.type = de->d_name[0])) != 0) X && (wrk.seqno = seqno(de->d_name))) { X strcpy(wrk.path, fspool(de->d_name)); X strcpy(wrk.sent, fspool(strcons(SPOOLFMT, X sent[p_unsent - unsent], wrk.seqno))); X sprintf(wrk.rqst, "S %s %s %s - %s 0660", de->d_name, X rmtname(wrk.type, wrk.seqno), "uucp", de->d_name); X wrk.fp = fopen(wrk.path, "r"); X break; X } X } X closedir(dp); X return (de ? &wrk : NULL); X } X} END_OF_main/scanwork.c if test 2975 -ne `wc -c
main/smail.c <<'END_OF_main/smail.c' X/*++ X/* NAME X/* smail 1 X/* SUMMARY X/* mail spooler X/* PROJECT X/* pc-mail X/* PACKAGE X/* smail X/* SYNOPSIS X/* smail file destinations X/* DESCRIPTION X/* smail makes preparations to send a copy of a text file X/* to another person. If a "-" is specifie instead of a file X/* name, standard input is read. X/* X/* The contents of the original file are filtered in order to X/* get rid of control characters, high most-significant bits, X/* or non-standard carriage-control conventions. The filter X/* has no effect on ordinary flat text files, such as program X/* sources. X/* X/* Aliases in the list of destinations are expanded, and multiple X/* occurrances of the same recipient are eliminated. The algorithms X/* that manipulate the list of destinations are case-insensitive. X/* FILES X/* In the spool directory. Files that belong together have the X/* same sequence number in their name. X/* d message body (data file) X/* x destination and message subject (meta file) X/* SEE ALSO X/* ascf(3) ASCII filter X/* spoolfil(3) create data-file/meta-file pair X/* path(5) system-dependent path names X/* unalias(3) alias expansion and cleanup X/* DIAGNOSTICS X/* Error messages if invoked with insufficient arguments. X/* The program terminates with a nonzero exit status if X/* problems were detected (out of memory, file access problems, X/* loops in the alias data base). The exit status indicates the X/* nature of the problem. 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/* Mon Apr 6 16:58:42 GMT+1:00 1987 X/* LAST MODIFICATION X/* 90/01/22 13:02:38 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X X#include "defs.h" X#include "path.h" X#include "status.h" X Xextern char **unalias(); X Xpublic char *progname = "smail"; /* for diagnostics */ X Xmain(argc,argv) Xint argc; Xchar **argv; X{ X int stat = 0; /* pathinit() status code */ X char **vec; /* final destinations vector */ X char *str; /* final destinations string */ X X if (argc <= 2) { X fprintf(stderr,"usage: smail filename destination(s)\n"); X exit(1); X } else if (stat = pathinit()) { /* check environment vars */ X exit(stat); X } else if ((vec = unalias(argv+2)) == 0) { /* expand aliases */ X exit(E_SYSFAIL); X } else if (vec[BUFSIZ-1]) { /* alias overflow */ X exit(E_OVALIAS); X } else if ((str = vecstr(vec," ")) == 0) { /* list -> string conversion */ X exit(E_SYSFAIL); X } else if (strlen(str) >= MAXLINE) { X exit(E_TOOLONG); /* too many recipients */ X } else { X exit(sendmail(argv[1],str)); /* make spool files */ X } X /* NOTREACHED */ X} END_OF_main/smail.c if test 2780 -ne `wc -c
main/snapshot.c <<'END_OF_main/snapshot.c' X/*++ X/* NAME X/* snapshot 3 X/* SUMMARY X/* keep overview of the mail directory X/* PROJECT X/* pc-mail X/* PACKAGE X/* mail X/* SYNOPSIS X/* #include "snapshot.h" X/* X/* SNAP_SHOT *snap_shot(list) X/* char *list; X/* X/* void snap_junk() X/* DESCRIPTION X/* These functions maintain a "snapshot" of the mail directory; X/* this is a table of meta files. X/* X/* snap_shot() make sure that a "snapshot" exists. list is X/* a null-terminated string of metafile suffix characters. X/* This function returns a list with as terminator an entry X/* with all zeros. X/* X/* snap_junk() schedules a re-scan of the mail directory. X/* FILES X/* mail header files in the spool directory 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/* Sun Dec 17 19:52:12 MET 1989 X/* LAST MODIFICATION X/* 90/01/22 13:02:38 X/* VERSION/RELEASE X/* 2.1 X/*--*/ X X#include X X#include "defs.h" X#include "path.h" X#include "ndir.h" X#include "snapshot.h" X X#define SNAP_ALLOC 200 /* growth increment of table */ X Xhidden SNAP_SHOT *snap_table = 0; /* at most 16k messages on a PC */ Xhidden int snap_used = 0; /* nr of elements actually used */ Xhidden int snap_length = 0; /* actual length of table */ X X/* snap_add - add message to snapshot table */ X Xhidden void snap_add(msgno, prefix) Xunsigned msgno; Xchar prefix; X{ X /* myrealloc() accepts a null pointer */ X X if (snap_used >= snap_length) { X snap_length += SNAP_ALLOC; X if ((snap_table = (SNAP_SHOT *) myrealloc((char *) snap_table, X snap_length * sizeof(snap_table))) == 0) X fatal("insufficient free memory for operation"); X } X snap_table[snap_used].msgno = msgno; X snap_table[snap_used].prefix = prefix; X snap_used++; X} X X/* snap_build - record meta files in the mail directory */ X Xhidden void snap_build(list) Xchar *list; X{ X DIR *dp; /* dir search id */ X register struct direct *de; /* directory entry */ X unsigned msgno; /* message sequence number */ X X if (dp = opendir(maildir)) { X while (de = readdir(dp)) { X if ((msgno = seqno(de->d_name)) && strchr(list, de->d_name[0]) != 0) X snap_add(msgno, de->d_name[0]); X } X closedir(dp); X } X snap_add(0, 0); /* add terminator */ X} X X/* snap_junk - schedule re-build of snapshot table */ X Xpublic void snap_junk() X{ X snap_used = 0; X} X X/* snap_shot - make sure snapshot table exists */ X Xpublic SNAP_SHOT *snap_shot(list) Xchar *list; X{ X if (snap_used == 0) X snap_build(list); X return(snap_table); X} END_OF_main/snapshot.c if test 2760 -ne `wc -c