home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
pcmail2
/
part04
< prev
next >
Wrap
Text File
|
1990-01-24
|
61KB
|
2,138 lines
Newsgroups: comp.sources.misc
subject: v10i036: PC-MAIL release 2, 4/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 36
Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
Archive-name: pcmail2/part04
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 11)."
# Contents: aux/srctoman.sh daemon/DAEMON.ins daemon/Makefile
# daemon/ms_parse.c main/Implement main/invoke.c main/msd_dir.c
# main/screen.h main/sendwork.c main/setup.c main/switcher.c
# main/unalias.c
# Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:16 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f aux/srctoman.sh -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"aux/srctoman.sh\"
else
echo shar: Extracting \"aux/srctoman.sh\" \(4444 characters\)
sed "s/^X//" >aux/srctoman.sh <<'END_OF_aux/srctoman.sh'
X: srctoman - see comment below
X
X: process arguments
X
Xwhile :
Xdo
X case $1 in
X [0-9]) SECT=$1;;
X -) LANG=$1; B='[#:]';;
X -awk) LANG=$1; B='#';;
X -c) LANG=$1; B='\/\*';;
X -f) LANG=$1; B='[Cc]';;
X -mk) LANG=$1; B='#';;
X -n|-t) LANG=$1; B='\\"';;
X -p) LANG=$1; B='{';;
X -r) LANG=$1; B='#';;
X -C) LANG=$1; B=$2; shift;;
X -*) ERROR="unknown option: $1"; break;;
X "") ERROR="missing file argument"; break;;
X *) break;;
X esac
X shift
Xdone
X
X: check error status
X
Xcase $ERROR in
X"") ;;
X *) echo "$0: $ERROR" 1>&2
X echo "usage: $0 [-|-awk|-c|-f|-mk|-n|-p|-t|-r] [section] file(s)" 1>&2; exit 1;;
Xesac
X
X: set up for file suffix processing
X
Xcase $LANG in
X"") sh='[:#]'; r='#'; rh=$r; awk='#'; mk='#';
X c='\/\*'; h=$c; y=$c; l=$c;
X f='[Cc]'; fh=$f; p='{'; ph=$p;
X ms='\\"'; nr=$ms; mn=$ms; man=$ms;
Xesac
X
X: extract comments
X
Xfor i in $*
Xdo
X case $LANG in
X "") eval B\="\$`expr $i : '^.*\.\([^.]*\)$'`"
X test "$B" || { echo "$0: unknown suffix: $i; assuming c" 1>&2; B=$c; }
X esac
X sed '
X /^'"$B"'++/,/^'"$B"'--/!d
X /^'"$B"'++/d
X /^'"$B"'--/d
X s/[ ]*$//
X /^'"$B"' \([A-Z]\)/{
X s//\1/
X /^NAME/{
X N
X s/^.*\n'"$B"'[ ]*//
X h
X y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
X s/^.*$/.TH & '"$SECT"'\
X.ad\
X.fi\
X.SH NAME/
X p
X g
X s/ [0-9]$//
X a\
X\\-
X p
X d
X }
X /^SUMMARY/d
X /^DESCRIPTION/s//.SH &\
X.ad\
X.fi/
X /^BUGS/s//.SH &\
X.ad\
X.fi/
X /^DIAGNOSTICS/s//.SH &\
X.ad\
X.fi/
X /^[A-Z][A-Z][A-Z][^a-z]*$/s//.SH &\
X.na\
X.nf/
X p
X d
X }
X s/^'"$B"'[ ]*//
X s/^[ ]*$//
X' $i
Xdone
X
Xexit
X
X:++
X: NAME
X: srctoman 1
X: SUMMARY
X: extract manual page from source file comment
X: PACKAGE
X: source file maintentance tools
X: SYNOPSIS
X: srctoman [-|-awk|-c|-f|-mk|-m|-n|-p|-t|-r] [section] file(s)
X: DESCRIPTION
X: Srctoman converts comments in various programming languages to
X: UNIX-style manual pages.
X: The command processes comments in the style of newsource(1);
X: its standard output is suitable for formatting with nroff(1) or
X: troff(1) using the "-man" macro package.
X: Typically, srctoman is integrated with make(1) scripts.
X:
X: Source files are processed in the indicated order; if no
X: files argument the command produces no output.
X:
X: The source file language can be specified through a command-line
X: option, or can be implied by the filename suffix.
X: The expected start-of-comment symbol is shown in the last column.
X:
X: .nf
X option language comment
X
X - shell [:#]
X -awk awk #
X -c c /*
X -f fortran [Cc]
X -mk make #
X -n nroff \\"
X -p pascal {
X -t troff \\"
X -r ratfor #
X -C any language next argument
X: .fi
X:
X: .nf
X suffix language comment
X
X .awk awk #
X .c c /*
X .f fortran [Cc]
X .fh fortran [Cc]
X .h c /*
X .l lex /*
X .man nroff,troff \\"
X .mk make #
X .me nroff,troff \\"
X .ms nroff,troff \\"
X .nr nroff,troff \\"
X .p pascal {
X .ph pascal {
X .r ratfor #
X .rh ratfor #
X .sh shell [:#]
X .y yacc /*
X: .fi
X:
X: The required format of comments is discussed below, where SOC
X: stands for the start-of-comment symbol of the language being used.
X:
X: 1) Start of manual: SOC, followed by `++'.
X:
X: 2) Section heading: SOC, blank, section name in upper case.
X:
X: 3) New paragraph: empty line or line with SOC only.
X:
X: 4) All other text: SOC and subsequent blanks or tabs are removed.
X: Lines that do not start with SOC are left unchanged (useful for
X: inclusion of program text).
X:
X: 5) End of manual: SOC, followed by `--'.
X: An end-of-comment may follow if the source file language requires this.
X:
X: The following manual sections receive a special treatment:
X: NAME and SUMMARY should appear at the beginning and in
X: this order; DESCRIPTION, DIAGNOSTICS and BUGS will be
X: right-margin adjusted.
X: Other sections may be added freely without confusing srctoman.
X: COMMANDS
X: sh(1), sed(1), expr(1)
X: SEE ALSO
X: newsource(1), modsource(1), xman(1)
X: The earlier commands new(1), mod(1), mkman(1) and dssman(1)
X: by Ruud Zwart and Ben Noordzij (Erasmus University, Rotterdam)
X: DIAGNOSTICS
X: The program complains if an unknown language is specified
X: or if the language cannot be deduced from the file suffix.
X: AUTHOR(S)
X: W.Z. Venema
X: Eindhoven University of Technology
X: Department of Mathematics and Computer Science
X: Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X: CREATION DATE
X: Fri Jan 17 22:59:27 MET 1986
X: LAST MODIFICATION
X: Thu Mar 10 20:08:15 MET 1988
X: VERSION/RELEASE
X: 1.20
X:--
X
X
END_OF_aux/srctoman.sh
if test 4444 -ne `wc -c <aux/srctoman.sh`; then
echo shar: \"aux/srctoman.sh\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f daemon/DAEMON.ins -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"daemon/DAEMON.ins\"
else
echo shar: Extracting \"daemon/DAEMON.ins\" \(4035 characters\)
sed "s/^X//" >daemon/DAEMON.ins <<'END_OF_daemon/DAEMON.ins'
X@(#) DAEMON.ins 1.3 90/01/06 19:47:10
X
XThis document describes how to install the daemon software on the file
Xserver that exports the per-user mail directories, and how to adapt the
Xlocal sendmail.cf file.
X
XOperation
X=========
X
XThe per-user mail directories are mounted from a file server. The UUCP
Xfile transfer functions of the pc-mail cico program are taken over by
Xthe following two programs that run on the file server:
X
Xpc-mail: deliver mail to a user's mail directory (the receiving
X function of the cico program). This program is intended
X to be called by sendmail.
X
Xpc-maild: scan user mail directories for unsent mail, and pipe it
X through the UNIX rmail command (the sending function of
X the cico program). This program should be started at
X system boot time.
X
XAll per-user mail directories live below the pc-mail spool directory
X(/var/spool/pc-mail by default).
X
XBoth programs report all problems via the syslog facility. Most error
Xconditions case the programs to retry at a later time.
X
XInstallation on the server
X==========================
X
XBuild the pc-mail and pc-maild programs. In the Makefile, you should
Xspecify the location of the executable programs and the pc-mail spool
Xdirectory, and how often the daemon program will scan user directories
Xfor unsent mail. You will probably have to do a `make depend' before
Xyou can `make' the programs.
X
XExecute the following command to create the pc-mail spool directory, and
Xto install the pc-mail and pc-maild programs. You must be root.
X
X % make install
X
XThe output from the "make" command will depend on how you specified the
Xpath names in the Makefile:
X
X mkdir /var/spool/pc-mail
X chmod 755 /var/spool/pc-mail
X cp pc-mail pc-maild /usr/local/lib
X chown root /usr/local/lib/pc-mail
X chmod u+s /usr/local/lib/pc-mail
X
XExecute the following command if you wish to install the manual pages.
X
X % make installman
X
XAgain, the output from make will depend on what you specified in the
XMakefile:
X
X cp pc-mail.8 pc-maild.8 /usr/local/man/man8
X
XAdd a line with the command
X
X /usr/local/lib/pc-maild
X
Xto the file /etc/rc.local (the exact name of the rc script depends on
Xyour version of unix, and the exact path name of the pc-maild program
Xdepends on where you installed it).
X
XFor now, you will have to start the pc-maild program by hand (unless
Xyou wish to reboot the machine).
X
XAdd to the sendmail.cf file a line that looks like:
X
X Mpc, P=/usr/local/lib/pc-mail, F=lsDFMn, S=xxx, R=yyy, A=pc-mail $u
X
XWhere xxx and yyy may be the same rewriting rules as used for the local
Xmailer (usually defined with the "Mlocal" line). The exact path name of
Xthe pc-mail executable depends on what you specified in the Makefile.
X
XIn the file sendmail.cf, at the end of ruleset S0, but just BEFORE the
Xlocal mailer will be invoked (something like "R$* $#local $:$1"), add a
Xline with
X
X R $=X $#pc $:$1
X
XUse a different letter if X is already in use.
X
XThere are two ways to define X as a list of pc-mail users. The list can
Xbe wired into the sendmail.cf file, e.g.:
X
X CXjohn marsha
X
XMultiple usernames on a line, and multiple CX lines are allowed.
X
XA better way is to have sendmail read the list from an external file, by
Xputting the following line into the sendmail.cf file:
X
X FX/etc/pc-mail-users %s
X
XThe /etc/pc-mail-users file should contain only a single login name per
Xline.
X
XEach time you change the list of pc-mail users (either in sendmail.cf,
Xor in the /etc/pc-mail-users file) you will have to kill the sendmail
Xdaemon and restart it.
X
XNote that the sendmail program ON THE NFS SERVER will never read the
Xpc-mail user's .forward file. That file will still be useful, however,
Xif the user's home directory is exported to OTHER hosts running
Xsendmail. In that case you will want to create a .forward file in the
Xuser's home directory containing
X
X username@fully-qualified-hostname-of-the-server
X
XThe same effect can be achieved, of course, by adding an entry to the
Xnetwork-wide alias data base:
X
X username: username@server
END_OF_daemon/DAEMON.ins
if test 4035 -ne `wc -c <daemon/DAEMON.ins`; then
echo shar: \"daemon/DAEMON.ins\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f daemon/Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"daemon/Makefile\"
else
echo shar: Extracting \"daemon/Makefile\" \(4614 characters\)
sed "s/^X//" >daemon/Makefile <<'END_OF_daemon/Makefile'
X# @(#) Makefile 1.7 12/29/89 18:08:05
X
X###############################
X# Start of configurable options. You will also have to do a `make depend'.
X
X# Compiler options.
X# -DSYSV is needed for system 5 release 2
X# -DRFC822 if you want the daemon to produce To: and From: header lines
X# -DSYSEXITS if your system has <sysexits.h>
X# -DSYSLOG if your system has a BSD 4.3-like syslog facility
X# -DSYSLOGFILE=\"/usr/spool/mqueue/syslog\" if you don't have BSD4.3-like syslog
X# You will also have to create that file, with mode 666.
X#
X#BSD4.X: DEFS = -DRFC822 -DSYSEXITS -DSYSLOG
X#SYSVR2: DEFS = -DRFC822 -DSYSV -DSYSLOGFILE=\"/usr/spool/mqueue/syslog\"
X
XDEFS = -DRFC822 -DSYSEXITS -DSYSLOG
X
X# Location of pc-mail spool area
X
XMAILDIR = /var/spool/pc-mail
X
X# How often the daeman will scan the pc-mail spool area for unsent mail.
X# This time interval can also be changed via the command line.
X
XDELAY = 30
X
X# Some system-5 implementations have a separate library with BSD-compatible
X# directory access routines.
X#
X#LIBS = -lndir
X
XLIBS =
X
X# Location of the pc-mail en pc-maild binaries
X
XEXEDIR = /usr/local/lib
X
X# If you want to, where to install the manual pages
X
XMANDIR = /usr/local/man/man8
X
X# End of configurable options
X#############################
X
XSHELL = /bin/sh
XCFLAGS = $(DEFS) -DDELAY=$(DELAY) -DMAILDIR=\"$(MAILDIR)\"
XARCHIVE = sarch
XSOURCES = README pc-mail.c pc-maild.c Makefile sysexits.h syslog.h \
X syslog.c util.c util.h mtime.c mtime.h dosunix.c dosunix.h \
X percentm.h percentm.c ms_parse.c ms_parse.h DAEMON.ins
X
XPCMOBJ = pc-mail.o syslog.o percentm.o dosunix.o ms_parse.o
XPCMSRC = pc-mail.c syslog.c percentm.c dosunix.c ms_parse.c
X
XPCMDOBJ = pc-maild.o syslog.o percentm.o dosunix.o util.o mtime.o
XPCMDSRC = pc-maild.c syslog.c percentm.c dosunix.c util.c mtime.c
X
Xall: pc-mail pc-maild
X
Xinstall: all
X -mkdir $(MAILDIR)
X chmod 755 $(MAILDIR)
X cp pc-mail pc-maild $(EXEDIR)
X chown root $(EXEDIR)/pc-mail
X chmod 4755 $(EXEDIR)/pc-mail
X
Xinstallman:
X cp pc-mail.8 pc-maild.8 $(MANDIR)
X
Xpc-mail: $(PCMOBJ)
X $(CC) $(CFLAGS) -o $@ $(PCMOBJ) $(LIBS)
X
Xpc-maild: $(PCMDOBJ)
X $(CC) $(CFLAGS) -o $@ $(PCMDOBJ) $(LIBS)
X
Xlint: lint1 lint2
X
Xlint1: $(PCMSRC)
X lint $(CFLAGS) $(PCMSRC)
X
Xlint2: $(PCMDSRC)
X lint $(CFLAGS) $(PCMDSRC)
X
Xshar: $(SOURCES) pc-mail.8 pc-maild.8
X @shar $(SOURCES) pc-mail.8 pc-maild.8
X
Xclean:
X rm -f *.o core nohup.out
X
Xclobber: clean
X rm -f pc-maild pc-mail
X
Xarchive: $(SOURCES)
X $(ARCHIVE) $?;
X touch archive
X
Xdepend:
X (sed '1,/^# do not edit/!d' Makefile; \
X for i in [a-z][a-z]*.c; do \
X $(CC) -E $(CFLAGS) $$i | sed -n '/^# *1 *"\([^"]*\)".*/{;s//'`echo $$i|sed 's/c$$/o/'`': \1/;p;}'; \
X done)>$$$$ && mv $$$$ Makefile
X
X# do not edit below this line - it was create with `make depend'
Xdosunix.o: dosunix.c
Xdosunix.o: /usr/include/stdio.h
Xdosunix.o: ./dosunix.h
Xms_parse.o: ms_parse.c
Xms_parse.o: /usr/include/stdio.h
Xms_parse.o: /usr/include/ctype.h
Xms_parse.o: ./dosunix.h
Xms_parse.o: ./ms_parse.h
Xmtime.o: mtime.c
Xmtime.o: /usr/include/syslog.h
Xmtime.o: ./mtime.h
Xpc-mail.o: pc-mail.c
Xpc-mail.o: /usr/include/stdio.h
Xpc-mail.o: /usr/include/sys/types.h
Xpc-mail.o: /usr/include/sys/sysmacros.h
Xpc-mail.o: /usr/include/sys/stat.h
Xpc-mail.o: /usr/include/pwd.h
Xpc-mail.o: /usr/include/varargs.h
Xpc-mail.o: /usr/include/syslog.h
Xpc-mail.o: /usr/include/sys/dir.h
Xpc-mail.o: /usr/include/sysexits.h
Xpc-mail.o: ./dosunix.h
Xpc-mail.o: ./percentm.h
Xpc-mail.o: ./ms_parse.h
Xpc-maild.o: pc-maild.c
Xpc-maild.o: /usr/include/stdio.h
Xpc-maild.o: /usr/include/pwd.h
Xpc-maild.o: /usr/include/time.h
Xpc-maild.o: /usr/include/signal.h
Xpc-maild.o: /usr/include/vm/faultcode.h
Xpc-maild.o: /usr/include/sys/types.h
Xpc-maild.o: /usr/include/sys/sysmacros.h
Xpc-maild.o: /usr/include/sys/stat.h
Xpc-maild.o: /usr/include/syslog.h
Xpc-maild.o: /usr/include/sys/types.h
Xpc-maild.o: /usr/include/sys/dir.h
Xpc-maild.o: /usr/include/sgtty.h
Xpc-maild.o: /usr/include/sys/ioctl.h
Xpc-maild.o: /usr/include/sys/ttychars.h
Xpc-maild.o: /usr/include/sys/ttydev.h
Xpc-maild.o: /usr/include/sys/ttold.h
Xpc-maild.o: /usr/include/sys/ioccom.h
Xpc-maild.o: /usr/include/sys/ttycom.h
Xpc-maild.o: /usr/include/sys/filio.h
Xpc-maild.o: /usr/include/sys/ioccom.h
Xpc-maild.o: /usr/include/sys/sockio.h
Xpc-maild.o: /usr/include/sys/ioccom.h
Xpc-maild.o: ./dosunix.h
Xpc-maild.o: ./util.h
Xpc-maild.o: ./mtime.h
Xpercentm.o: percentm.c
Xpercentm.o: /usr/include/stdio.h
Xpercentm.o: ./percentm.h
Xsyslog.o: syslog.c
Xutil.o: util.c
Xutil.o: /usr/include/stdio.h
Xutil.o: /usr/include/pwd.h
Xutil.o: /usr/include/sys/types.h
Xutil.o: /usr/include/sys/sysmacros.h
Xutil.o: /usr/include/sys/dir.h
Xutil.o: /usr/include/syslog.h
Xutil.o: ./util.h
END_OF_daemon/Makefile
if test 4614 -ne `wc -c <daemon/Makefile`; then
echo shar: \"daemon/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f daemon/ms_parse.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"daemon/ms_parse.c\"
else
echo shar: Extracting \"daemon/ms_parse.c\" \(4182 characters\)
sed "s/^X//" >daemon/ms_parse.c <<'END_OF_daemon/ms_parse.c'
X/*++
X/* NAME
X/* ms_parse 3
X/* SUMMARY
X/* message parser
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* nfs
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/* The context argument should have the value MS_UUCP in the initial
X/* call of ms_parse(). Upon successive calls the value should be equal
X/* to the last value returned by ms_parse().
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/* 1/6/90 19:45:16
X/* VERSION/RELEASE
X/* 1.7
X/*--*/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "ms_parse.h"
X
Xextern char *strchr();
X
X/* forward declarations */
X
Xstatic int isheader();
Xstatic int istrncmp();
X
X/* hscanf - match header and extract info from remainder of header line */
X
Xint 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
Xint 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
Xstatic 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 = strchr(buf, ':')) == 0) { /* check for colon */
X return (0);
X } else { /* find preceding blanks */
X for (cp = blanks; *cp; cp++)
X if ((blk = strchr(buf, *cp)) != 0 && blk < colon)
X return (0);
X }
X return (1);
X}
X
X#define low(x) ((isascii(x) && isupper(x)) ? tolower(x) : (x))
X
X/* istrncmp - case-insensitive strncmp */
X
Xstatic int istrncmp(s1, s2, len)
Xchar *s1;
Xchar *s2;
Xint len;
X{
X while (len > 0 && *s1 && *s2 && low(*s1) == low(*s2))
X len--, s1++, s2++;
X return (len > 0 ? low(*s1) - low(*s2) : 0);
X}
END_OF_daemon/ms_parse.c
if test 4182 -ne `wc -c <daemon/ms_parse.c`; then
echo shar: \"daemon/ms_parse.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/Implement -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/Implement\"
else
echo shar: Extracting \"main/Implement\" \(4560 characters\)
sed "s/^X//" >main/Implement <<'END_OF_main/Implement'
X@(#) Implement 2.1 90/01/22 13:01:08
X
XThis document describes some implementation aspects of the pc-mail
Xsoftware.
X
XMESSAGE DATA BASE
X
XThe message data base resides in the mail spool directory (de-
Xfined with the MAILDIR environment variable). There are various
Xclasses of message files:
X
X - mail received from the network
X
X - mail ready to send over the network
X
X - messages in preparation
X
X - mail that has been sent
X
XIn addition there are administrative files (LOGFILE, alias data
Xbase and communications parameters). Optional files are: header
X(with template message header) and trailer (with the user's
Xsignature).
X
XEach message takes two files: a data file (with the actual mes-
Xsage) and a meta file (with on the first line: originator or
Xdestination addresses, or a one-line summary in case of a message
Xin preparation; and on the second line: a subject).
X
XData/meta file names are constructed by concatenating a single-
Xcharacter prefix with a five-digit sequence number. Corresponding
Xdata and meta files have the same sequence number. The prefix
Xcharacters are:
X
X E message in preparation
X C description of message
X
X N message received from the net
X H originator address and subject in case of an unread message
X O originator address and subject in case of already read message
X
X D message ready to be sent over the net
X X destination of that message and subject
X
X Q message already sent over the net
X R destination of that message and subject
X
XAdministrative files are
X
X LOGFILE transaction log
X s00000 communications parameters
X a00000 alias data base
X
XAll files in the mail directory are ordinary text files, with a
Xpossible exception for the message in preparation (this depends
Xon the editor being used).
X
XFiles in the mail directory are normally write-protected to
Xprevent accidents.
X
XThe length of lines in the "meta" files is at most 1024 bytes
X(see the MAXLINE macro in the file defs.h).
X
XMost mailers will object to messages with lines longer than about
X132 characters.
X
XHOW THE PROGRAMS OPERATE
X
XThe message data base is shared by several programs. First of
Xall, there is the mail program itself that provides the main user
Xinterface. Other programs are: cico (takes unsent messages from
Xthe mail data base, and changes their status to "sent" after they
Xhave been sent over the network), smail (queues a message for
Xtransmission by the cico program), rmail (extracts originator
Xnames and subject information from messages received by the cico
Xprogram) and cmail (scans the mail data base for unread
Xmessages). If the mail directory is mounted from a file server,
Xthe cico program is not used; instead, its task is performed by
Xthe pc-mail and pc-maild daemon programs that run on the file
Xserver.
X
XThe following picture shows how the programs interact with each
Xother, and with the mail data base.
X
X-----------------------------------------------------------------
Xprogram |purpose |invokes
X--------+-------------------------------+--------------------------
Xmail |main user interface |cico, smail, rmail, editor
X | |
Xcico |file transfer program |none; invoked by mail, cmail
X | |
Xsmail |queue file for transmission |none; invoked by mail
X | |
Xrmail |extract sender and subject |none; invoked by mail, cmail
X | |
Xcmail |search for unread mail |none
X--------+-------------------------------+--------------------------
Xpc-mail |deliver mail (on file server) |none; invoked by sendmail
X | |
Xpc-maild|send mail (on file server) |/usr/bin/rmail
X-------------------------------------------------------------------
X
XUUCP FUNCTIONALITY
X
XThe cico program provided here supports a subset of the uucp file
Xexchange facilities, just enough to interface to the message
Xdatabase structure (spool directory) described in the previous
Xsection.
X
XThe main differences with the unix uucico program are:
X
X- No support for C (command) files. cico scans the spool
Xdirectory for message and destination files instead.
X
X- Only the H (hangup), S (send) and C (copy) requests are
Xsupported. R (receive) requests are not allowed. Sending or
Xreceiving files by path name is rarely allowed anyway, and works
Xonly between adjacent uucp nodes. This is only a minor
Xlimitation; files can still be sent as mail messages.
X
X- The cico program assumes that all incoming D (data) files are
Xmail messages.
X
X- The cico program ignores incoming X (execute) files. X files
Xnormally contain the commands to dispose of D (data) files.
X
END_OF_main/Implement
if test 4560 -ne `wc -c <main/Implement`; then
echo shar: \"main/Implement\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/invoke.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/invoke.c\"
else
echo shar: Extracting \"main/invoke.c\" \(4246 characters\)
sed "s/^X//" >main/invoke.c <<'END_OF_main/invoke.c'
X/*++
X/* NAME
X/* invoke 3
X/* SUMMARY
X/* system-dependent process control stuff
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mailsh
X/* SYNOPSIS
X/* #include "status.h"
X/*
X/* int invokelp(arg0,arg1,...)
X/* char *arg0,*arg1,...
X/*
X/* int invokevp(argv)
X/* char **argv;
X/* DESCRIPTION
X/* invokelp() creates a child process to execute a command.
X/* arg0, arg1,... is a null-terminated list of string pointers,
X/* the first being the name of the program. Use is made
X/* of the search path to locate the program in arg0.
X/* With MS-DOS, batch files can only be executed if their name is
X/* given including the suffix.
X/*
X/* invokevp() is similar to invokelp; the difference is that
X/* argv is an array of pointers to arguments, and that MS-DOS batch
X/* files are not supported.
X/* DIAGNOSTICS
X/* invokelp(), invokevp() return the exit status of the child process,
X/* E_SYSFAIL if there were insufficient resources, and
X/* E_NOPROG if the program in arg0 or argv[0] could not be found.
X/* BUGS
X/* The invokexx() functions should not be used if the command involves
X/* shell built-ins, i/o redirection or other shell meta characters.
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:01:50
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <varargs.h>
X#include <errno.h>
X
X#include "defs.h"
X#include "status.h"
X
X#ifdef MSDOS
X#include <process.h>
X#endif
X
X/* invokelp - create child process to execute command */
X
X/* VARARGS */
X
Xpublic int invokelp(va_alist)
Xva_dcl
X{
X va_list ap;
X#ifdef lint
X static
X#endif
X char *argv[BUFSIZ];
X char **cpp = argv;
X#ifdef MSDOS
X char *cp;
X
X /*
X * Under MS-DOS, we must explicitly invoke a command processor in case of
X * batch files. If we see the command is a batch file we just stick a
X * command processor invocation in front of the argument vector. We try
X * to avoid the command processor since it presently does not return exit
X * status codes.
X */
X
X va_start(ap);
X cp = va_arg(ap, char *);
X if (istrcmp(cp + strlen(cp) - 4, ".bat") == 0) {
X *cpp++ = "command";
X *cpp++ = "/c";
X }
X va_end(ap);
X#endif
X
X /* Copy variable-length argument list to variable-length vector */
X
X va_start(ap);
X while (*cpp++ = va_arg(ap, char *))
X /* void */ ;
X va_end(ap);
X
X /* invokevp will do the rest */
X
X return (invokevp(argv));
X
X#if (!defined(unix) && !defined(MSDOS))
X "Specify how to do process management"
X#endif
X}
X
X/* invokevp - create child process to execute command */
X
Xpublic int invokevp(argv)
Xchar **argv;
X{
X extern void _exit();
X
X /*
X * On unix systems we fork a process and overlay the child with the
X * desired program. This means we get -1 if the fork did not succeed,
X * otherwise the exit status of the child process. The code is a bit
X * elaborate since we want to handle various error conditions.
X */
X#ifdef unix
X register int pid;
X
X if ((pid = fork()) < 0) { /* fork off a process */
X return (E_SYSFAIL); /* resources exhausted */
X } else if (pid == 0) { /* this is the child process */
X (void) execvp(*argv, argv); /* try to replace it */
X _exit(errno == ENOENT ? E_NOPROG : E_SYSFAIL); /* sorry, failed */
X /* NOTREACHED */
X } else { /* this is the parent */
X int xstat,
X wstat;
X
X /* wait till above child terminates */
X
X while ((wstat = wait(&xstat)) != -1 && wstat != pid)
X /* void */ ;
X if (wstat == -1) {
X return (E_SYSFAIL); /* oops: no child! */
X } else if (xstat & 0377) {
X return (E_UNKNOWN); /* child was killed */
X } else {
X return (xstat >> 8); /* child died naturally */
X }
X /* NOTREACHED */
X }
X#endif
X
X /*
X * With MS-DOS, less can go wrong. On the other hand, MS-DOS can do less.
X */
X#ifdef MSDOS
X int stat;
X
X return ((stat = spawnvp(P_WAIT, *argv, argv)) >= 0 ?
X stat : (errno == ENOENT ? E_NOPROG : E_SYSFAIL));
X#endif
X
X#if (!defined(unix) && !defined(MSDOS))
X "Specify how to do process management"
X#endif
X}
END_OF_main/invoke.c
if test 4246 -ne `wc -c <main/invoke.c`; then
echo shar: \"main/invoke.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/msd_dir.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/msd_dir.c\"
else
echo shar: Extracting \"main/msd_dir.c\" \(4738 characters\)
sed "s/^X//" >main/msd_dir.c <<'END_OF_main/msd_dir.c'
X#ifdef MSDOS
X/*
X * @(#)msd_dir.c 1.4 87/11/06 Public Domain.
X *
X * A public domain implementation of BSD directory routines for
X * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield),
X * August 1897
X *
X * Return file names in lower case W.Z. Venema (wswietse@lso.win.tue.nl)
X * Aug 1988
X *
X * Added special-case code for the root directory WZV 891218
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "msd_dir.h" /* was: <sys/dir.h> */
X#include <malloc.h>
X#include <string.h>
X#include <dos.h>
X#include <ctype.h> /* for upper->lower case code */
X
X#ifndef NULL
X# define NULL 0
X#endif /* NULL */
X
X#ifndef MAXPATHLEN
X# define MAXPATHLEN 255
X#endif /* MAXPATHLEN */
X
X/* attribute stuff */
X#define A_RONLY 0x01
X#define A_HIDDEN 0x02
X#define A_SYSTEM 0x04
X#define A_LABEL 0x08
X#define A_DIR 0x10
X#define A_ARCHIVE 0x20
X
X/* dos call values */
X#define DOSI_FINDF 0x4e
X#define DOSI_FINDN 0x4f
X#define DOSI_SDTA 0x1a
X
X#define Newisnull(a, t) ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
X#define ATTRIBUTES (A_DIR | A_HIDDEN | A_SYSTEM)
X
X/* what find first/next calls look use */
Xtypedef struct {
X char d_buf[21];
X char d_attribute;
X unsigned short d_time;
X unsigned short d_date;
X long d_size;
X char d_name[13];
X} Dta_buf;
X
Xstatic char *getdirent();
Xstatic void setdta();
Xstatic void free_dircontents();
X
Xstatic Dta_buf dtabuf;
Xstatic Dta_buf *dtapnt = &dtabuf;
Xstatic union REGS reg, nreg;
X
X#if defined(M_I86LM)
Xstatic struct SREGS sreg;
X#endif
X
Xstatic char *Strcpy(); /* lower-case copy */
X
XDIR *
Xopendir(name)
X char *name;
X{
X struct stat statb;
X DIR *dirp;
X char c;
X char *s;
X struct _dircontents *dp;
X char nbuf[MAXPATHLEN + 1];
X
X /*
X * Need special-case code for ".", to avoid problems with stat()
X * in the root directory -- WZV 891218
X */
X
X if (strcmp(name, ".") != 0
X && (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR))
X return (DIR *) NULL;
X if (Newisnull(dirp, DIR))
X return (DIR *) NULL;
X if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/')
X (void) strcat(strcpy(nbuf, name), "\\*.*");
X else
X (void) strcat(strcpy(nbuf, name), "*.*");
X dirp->dd_loc = 0;
X setdta();
X dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
X if ((s = getdirent(nbuf)) == (char *) NULL)
X return dirp;
X do {
X if (Newisnull(dp, struct _dircontents) || (dp->_d_entry =
X malloc((unsigned) (strlen(s) + 1))) == (char *) NULL)
X {
X if (dp)
X free((char *) dp);
X free_dircontents(dirp->dd_contents);
X return (DIR *) NULL;
X }
X if (dirp->dd_contents)
X dirp->dd_cp = dirp->dd_cp->_d_next = dp;
X else
X dirp->dd_contents = dirp->dd_cp = dp;
X (void) strcpy(dp->_d_entry, s);
X dp->_d_next = (struct _dircontents *) NULL;
X } while ((s = getdirent((char *) NULL)) != (char *) NULL);
X dirp->dd_cp = dirp->dd_contents;
X
X return dirp;
X}
X
Xvoid
Xclosedir(dirp)
X DIR *dirp;
X{
X free_dircontents(dirp->dd_contents);
X free((char *) dirp);
X}
X
Xstruct direct *
Xreaddir(dirp)
X DIR *dirp;
X{
X static struct direct dp;
X
X if (dirp->dd_cp == (struct _dircontents *) NULL)
X return (struct direct *) NULL;
X dp.d_namlen = dp.d_reclen =
X strlen(Strcpy(dp.d_name, dirp->dd_cp->_d_entry));
X dp.d_ino = 0;
X dirp->dd_cp = dirp->dd_cp->_d_next;
X dirp->dd_loc++;
X
X return &dp;
X}
X
Xvoid
Xseekdir(dirp, off)
X DIR *dirp;
X long off;
X{
X long i = off;
X struct _dircontents *dp;
X
X if (off < 0)
X return;
X for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next)
X ;
X dirp->dd_loc = off - (i + 1);
X dirp->dd_cp = dp;
X}
X
Xlong
Xtelldir(dirp)
X DIR *dirp;
X{
X return dirp->dd_loc;
X}
X
Xstatic void
Xfree_dircontents(dp)
X struct _dircontents *dp;
X{
X struct _dircontents *odp;
X
X while (dp) {
X if (dp->_d_entry)
X free(dp->_d_entry);
X dp = (odp = dp)->_d_next;
X free((char *) odp);
X }
X}
X
Xstatic char *
Xgetdirent(dir)
X char *dir;
X{
X if (dir != (char *) NULL) { /* get first entry */
X reg.h.ah = DOSI_FINDF;
X reg.h.cl = ATTRIBUTES;
X#if defined(M_I86LM)
X reg.x.dx = FP_OFF(dir);
X sreg.ds = FP_SEG(dir);
X#else
X reg.x.dx = (unsigned) dir;
X#endif
X } else { /* get next entry */
X reg.h.ah = DOSI_FINDN;
X#if defined(M_I86LM)
X reg.x.dx = FP_OFF(dtapnt);
X sreg.ds = FP_SEG(dtapnt);
X#else
X reg.x.dx = (unsigned) dtapnt;
X#endif
X }
X#if defined(M_I86LM)
X intdosx(®, &nreg, &sreg);
X#else
X intdos(®, &nreg);
X#endif
X if (nreg.x.cflag)
X return (char *) NULL;
X
X return dtabuf.d_name;
X}
X
Xstatic void
Xsetdta()
X{
X reg.h.ah = DOSI_SDTA;
X#if defined(M_I86LM)
X reg.x.dx = FP_OFF(dtapnt);
X sreg.ds = FP_SEG(dtapnt);
X intdosx(®, &nreg, &sreg);
X#else
X reg.x.dx = (int) dtapnt;
X intdos(®, &nreg);
X#endif
X}
X
Xstatic char *Strcpy(to,from)
Xregister char *to,*from;
X{
X register int c;
X char *start = to;
X
X while (*to++ = (islower(c = *from++) ? c : tolower(c)))
X ;
X return(start);
X}
X#endif
END_OF_main/msd_dir.c
if test 4738 -ne `wc -c <main/msd_dir.c`; then
echo shar: \"main/msd_dir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/screen.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/screen.h\"
else
echo shar: Extracting \"main/screen.h\" \(4726 characters\)
sed "s/^X//" >main/screen.h <<'END_OF_main/screen.h'
X/*++
X/* NAME
X/* screen
X/* SUMMARY
X/* structure of mail shell command windows
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mail
X/* SYNOPSIS
X/* #include "screen.h"
X/* DESCRIPTION
X/* The data structures in this file are used by the interactive shell to
X/* define what a screen looks like, and what commands the user can give.
X/*
X/* For each screen, one has to define a table of (selector, command name,
X/* help string, and function pointer) tuples.
X/* The command names are listed in the top window. If the user enters
X/* the type of input specified by the selector, the associated function
X/* is called. A null function pointer means go back to the calling screen.
X/*
X/* The table is terminated with a null selector entry; its help
X/* string is displayed in the bottom window (as a prompt), and the
X/* associated function is invoked upon entry of the screen.
X/*
X/* The return value of an action function determines what happens next.
X/* An action function can signal an error condition, that the screen
X/* needs to be redrawn, and whether the calling screen should terminate.
X/*
X/* User input can be of various forms: single-character, string or
X/* escape/enter.
X/*
X/* In case of single-character input the selector fields should contain
X/* for each key the (upper case) key code,
X/* a label that is displayed at the top of the screen, and a help
X/* text that explains the key's function.
X/*
X/* In case of string input the associated function is called with the
X/* string input as argument. If that function returns an error status the
X/* text in the help field is printed in the error window and the
X/* user is given another chance.
X/*
X/* An alternative form of string input takes the text from the help field
X/* as default input, and allows the user to edit that. Otherwise the
X/* same functions are performed as with ordinary string input.
X/*
X/* A third form of string input only accepts yes or no. The action
X/* function is called with an integer argument (1 = yes, 0 = no).
X/*
X/* In case of escape/enter the interpreter invokes the action function when
X/* the user presses enter, and does nothing when escape is pressed.
X/* .nf
X
X /* there is a Screen structure for each command for each screen */
X
Xtypedef struct {
X short key; /* type of input */
X char *name; /* key label (for top window) */
X int (*action) (); /* action when command is selected */
X char *help; /* explanation (for H command) */
X} Screen;
X
X /* action function return masks */
X
X#define S_BREAK 1 /* return immediately after action */
X#define S_REDRAW 2 /* redraw screen */
X#define S_ERROR 4 /* action failed */
X
X /* input types: ordinary character keys are encoded as themselves */
X
X#define CTL(x) (x ^ 0100) /* ASCII control code */
X#define BS CTL('H')
X#define ENTER CTL('M')
X#define CTLU CTL('U')
X#define ESC CTL('[')
X#define DEL CTL('?')
X
X#define ANY 256 /* press any key */
X#define UP 257 /* up-arrow key */
X#define DOWN 258 /* down-arrow key */
X#define LEFT 259 /* left-arrow key */
X#define RIGHT 260 /* right-arrow key */
X#define PGUP 261 /* page-up */
X#define PGDN 262 /* page-down */
X#define STRING 263 /* string input, ESC to quit */
X#define ESCCR 264 /* CR to confirm, ESC to quit */
X#define EDIT 265 /* edit string, ESC to quit */
X#define YESNO 266 /* yes or no, ESC to quit */
X
X#define iskey(key) (key > 0 && key < STRING)
X
X /* system-dependent function-key labels */
X
X#ifdef unix
X# define PgUp "F1"
X# define PgDn "F2"
X#endif
X
X#ifdef MSDOS
X# define PgUp "PgUp"
X# define PgDn "PgDn"
X#endif
X
X /* often-used strings and messages */
X
Xextern char anykey[]; /* Press any key to continue */
Xextern char initscreen[]; /* Return to initial screen */
Xextern char prevscreen[]; /* Return to previous screen */
Xextern char int_error[]; /* The program is confused */
Xextern char pageup[]; /* Move screen one page upwards */
Xextern char pagedn[]; /* Move screen one page downwards */
Xextern char csrup[]; /* Move cursor upwards */
Xextern char csrdn[]; /* Move cursor downwards */
Xextern char getsummary[]; /* Press ESC to cancel/give summary */
Xextern char getaddr[]; /* Press ESC to cancel/enter address */
Xextern char printcurr[]; /* Print current message */
Xextern char delcurr[]; /* Delete current message */
Xextern char *m_msgread[]; /* Cannot read that message */
X
X/* SEE ALSO
X/* screen(3) screen table implementation
X/* kbdinp(3) screen table interpreter
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:34
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
END_OF_main/screen.h
if test 4726 -ne `wc -c <main/screen.h`; then
echo shar: \"main/screen.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/sendwork.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/sendwork.c\"
else
echo shar: Extracting \"main/sendwork.c\" \(4553 characters\)
sed "s/^X//" >main/sendwork.c <<'END_OF_main/sendwork.c'
X/*++
X/* NAME
X/* sendwork 3
X/* SUMMARY
X/* send local work to remote system
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* #include "work.h"
X/*
X/* void sendwork(wrk)
X/* work *wrk;
X/* DESCRIPTION
X/* sendwork converts names and contents of local work files,
X/* sends them to the remote system and deletes the files after
X/* successfull transfer.
X/*
X/* In particular, it generates appropriate "From " lines at the
X/* beginning of an outgoing mail message.
X/* SEE ALSO
X/* scanwork(3) locates work in the spool directory
X/* DIAGNOSTICS
X/* sendwork() returns via longjmp(systrap,errorcode) in case
X/* of unrecoverable problems.
X/*
X/* The error codes are: E_CONFUSED (unexpected work type),
X/* E_LOST (timed out), E_READERR (file read error).
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 Mar 26 11:32:23 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:35
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <time.h>
X
X#include "defs.h"
X#include "work.h"
X#include "logs.h"
X#include "status.h"
X#include "params.h"
X#include "comm.h"
X
Xextern struct tm *localtime(); /* std C library */
X
X /*
X * A pc-mail system can connect to the UNIX net in at least two modes:
X *
X * 1. As a real UUCP node, with it's own node name. This node name will have to
X * appear in the "From " lines of outgoing mail. A consequence is that the
X * pc mail node name should be known in mailer routing tables. Obviously
X * this implies some administrative work when a pc mail node is added to the
X * net or taken out of operation. This mode has not been tested by the
X * author.
X *
X * 2. As an ordinary user. The program lets the UNIX host believe that mail
X * messages come from an ordinary user. Recipients of mail will not be able
X * to see that the mail came from the pc. Only the UNIX host knows it should
X * forward mail for unixhost!xyz to the pc-mail node. This approach has the
X * advantage that adding/deleting pc-mail nodes is simpler.
X */
X
X#ifdef UUCP_NODE /* case 1 */
X# define UUSER "root" /* use current user's name */
X# define UHOST LOGIN_NAME /* use pc host name */
X#else /* case 2 */
X# define UUSER LOGIN_NAME /* use remote login name */
X# define UHOST rmthost /* use remote host name */
X#endif
X
X/* sendwork - adapt file contents for remote host */
X
Xpublic sendwork(wrk)
Xwork *wrk;
X{
X long secs;
X char buf[MAXLINE]; /* recipient addresses */
X
X switch (wrk->type) {
X
X /*
X * Local D files contain the mail message. Except for the addition of
X * a UUCP-style "From " line (with originator/date/system), D files
X * are sent without modification.
X */
X
X case 'd':
X case 'D':
X secs = time((long *) 0);
X say(strcons("From %s %.24s remote from %s\n",
X UUSER, asctime(localtime(&secs)), UHOST));
X send_file(wrk->fp);
X break;
X
X /*
X * The first line of local X files contains the destination address.
X * Real UUCP expects something entirely different.
X *
X * We make up some extra info to make the remote uuxqt program happy.
X */
X
X case 'x':
X case 'X':
X say(strcons("U %s %s\n", UUSER, UHOST));/* U user system */
X say(strcons("F %s\n",
X rmtname('D', wrk->seqno))); /* F D.rmtsysGnumber */
X say(strcons("I %s\n",
X rmtname('D', wrk->seqno))); /* I D.rmtsysGnumber */
X say("C rmail "); /* C rmail */
X (void) fgets(buf, sizeof(buf), wrk->fp);/* read destinations */
X say(buf); /* send destinations */
X say(""); /* send EOF */
X break;
X
X default:
X trap(E_CONFUSED, "INTERNAL ERROR (unexpected work type: %c)", wrk->type);
X }
X}
X
X/* say - write string to host */
X
Xhidden say(str)
Xchar *str;
X{
X if (CALL(Write) (ttfd, str, strlen(str)) < 0)
X trap(E_LOST, "FAILED (link lost)");
X}
X
X/* send_file - do the nitty-gritty of file transfer; traps on all errors */
X
Xhidden send_file(fp)
Xregister FILE *fp;
X{
X register int nread;
X register int nwrite = 0;
X char buf[BUFSIZ];
X register int rerror;
X
X while ((nread = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0
X && (nwrite = CALL(Write) (ttfd, buf, nread)) == nread)
X /* void */ ;
X rerror = ferror(fp);
X fclose(fp);
X
X if (rerror) {
X trap(E_READERR, "FILE READ ERROR (%s)", sys_errlist[errno]);
X /* NOTREACHED */
X } else if (nwrite < 0 || CALL(Write) (ttfd, buf, 0) != 0) {
X trap(E_LOST, "FAILED (link lost)");
X /* NOTREACHED */
X }
X}
END_OF_main/sendwork.c
if test 4553 -ne `wc -c <main/sendwork.c`; then
echo shar: \"main/sendwork.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/setup.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/setup.c\"
else
echo shar: Extracting \"main/setup.c\" \(4086 characters\)
sed "s/^X//" >main/setup.c <<'END_OF_main/setup.c'
X/*++
X/* NAME
X/* setup 3
X/* SUMMARY
X/* edit/display configuration parameters
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mail
X/* SYNOPSIS
X/* #include "mail.h"
X/*
X/* int setup()
X/* DESCRIPTION
X/* The functions in this module handle the configurations file with
X/* communications parameters.
X/*
X/* setup() starts a dialogue with the user. It allows the user to
X/* select a parameter and enter a new value. All modifications are
X/* done in core (pager file). Upon exit, the setup is written to
X/* disk if any changes were made.
X/* FUNCTIONS AND MACROS
X/* open_pager(), app_pager(), gets_pager(), puts_pager()
X/* kbdinp()
X/* FILES
X/* In the spool directory: the configuration file s00000.
X/* SEE ALSO
X/* cico(1) communications program.
X/* DIAGNOSTICS
X/* An error message if the setup file could not be created.
X/* BUGS
X/* Does not check parameter values at all, just like the UUCP
X/* configurations files L.sys etcetera.
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:16:18 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:36
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include "defs.h"
X#include "path.h"
X#include "screen.h"
X#include "mail.h"
X#include "pager.h"
X#include "params.h"
X#include "status.h"
X#include "window.h"
X
Xhidden void make_setup(); /* forward declarations */
Xhidden int change_setup();
Xhidden int pick_setup();
Xhidden int show_setup();
X
Xhidden File *setfile = 0; /* memory! */
Xhidden Info *prmtable = 0; /* more memory */
Xhidden int chgflag = 0; /* more flags! */
X
Xhidden char setfmt[] = "%-20s %s"; /* display format */
X#define LABLEN 20 /* length of first %s specifier */
X
X/* setup - start dialogue */
X
Xpublic int setup()
X{
X static Screen screen[] = {
X 'C', "Close",0, prevscreen,
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_setup, "Modify selected parameter",
X 0, 0, show_setup,
X "Select communications parameter with cursor keys, then press ENTER",
X };
X
X kbdinp(screen); /* start dialogue */
X if (chgflag && cp_pager(parm_file())) { /* save setup if changed */
X errdisp(E_WRITERR); /* save failed */
X } else {
X chgflag = 0; /* save succeeded */
X }
X close_pager(setfile);
X setfile = 0;
X return (S_REDRAW); /* refresh screen */
X}
X
X/* show_setup - make setup display or use existing one */
X
Xhidden int show_setup()
X{
X if (setfile == 0 || prmtable == 0) { /* no setup display */
X prmtable = getparams();
X setfile = open_pager();
X make_setup();
X } else { /* use existing display */
X set_pager(setfile);
X }
X ds_pager(); /* display it */
X return (0);
X}
X
X/* make_setup - create setup display */
X
Xhidden void make_setup()
X{
X register File *f = setfile;
X register Info *i;
X
X for (i = prmtable; i->ident; i++)
X app_pager(f, strcons(setfmt, i->ident, i->strval ? i->strval : ""));
X}
X
X/* pick_setup - user has selected one parameter */
X
Xhidden int pick_setup()
X{
X static Screen screen[] = {
X EDIT, 0, change_setup, 0,
X 0, 0, 0,
X "Press ESC to cancel. New parameter value:"
X };
X register char *sp = gets_pager();
X register Info *ip;
X
X for (ip = prmtable; ip->ident; ip++) /* check id string */
X if (strncmp(ip->ident, sp, ip->length) == 0)
X break;
X if (ip) {
X screen->help = sp + LABLEN + 1; /* default is current value */
X kbdinp(screen); /* ask for new value */
X return (S_REDRAW);
X } else {
X beep(); /* bad id string */
X return (0);
X }
X}
X
X/* change_setup - enter new communications parameter value */
X
Xhidden int change_setup(newval)
Xchar *newval;
X{
X register char *sp = gets_pager(); /* read from display */
X register Info *ip;
X
X for (ip = prmtable; ip->ident; ip++) { /* check id string */
X if (strncmp(ip->ident, sp, ip->length) == 0) {
X puts_pager(strcons(setfmt, ip->ident, newval));
X chgflag = 1; /* say change made */
X }
X }
X return (S_BREAK | S_REDRAW); /* screen changed */
X}
END_OF_main/setup.c
if test 4086 -ne `wc -c <main/setup.c`; then
echo shar: \"main/setup.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/switcher.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/switcher.c\"
else
echo shar: Extracting \"main/switcher.c\" \(4183 characters\)
sed "s/^X//" >main/switcher.c <<'END_OF_main/switcher.c'
X/*++
X/* NAME
X/* switcher 3
X/* SUMMARY
X/* master/slave protocol control switcher
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* int switcher(role)
X/* int role;
X/* DESCRIPTION
X/* switcher() takes care of the high-level protocol on top of
X/* the packet protocol.
X/*
X/* The system is in one of two roles: MASTER or SLAVE. In MASTER
X/* mode (initial mode of the caller) a system scans its local
X/* spool directory for work until no more is found, and then
X/* sends a H (hangup) request. The slave will respond with HY
X/* if it has no work, otherwise it will respond with HN and
X/* the two systems switch roles.
X/*
X/* Work can be of the form of S (send) requests or R (receive)
X/* requests. The slave responds with SY (RY) or SN (RN), depending on
X/* whether it is willing to process the request. The recipient
X/* of a message sends a CY or CN message, depending on whether
X/* transmission was successfull.
X/*
X/* Only H(angup) and S(end) requests are implemented here. This is
X/* for security reasons. Thus, the only way to exchange data is
X/* through electronic mail.
X/* FUNCTIONS AND MACROS
X/* isok, talk(), hear(), trap(), scanwork(), sendwork()
X/* rmtwork(), getwork()
X/* DIAGNOSTICS
X/* Various nonzero status codes are returned in case of problems.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Fri Mar 27 21:49:16 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:45
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <setjmp.h>
X
X#include "defs.h"
X#include "work.h"
X#include "params.h"
X#include "comm.h"
X#include "logs.h"
X#include "status.h"
X
X/* switcher - handles master/slave role swicthing until all work is done */
X
Xpublic switcher(role)
Xregister int role;
X{
X int *savetrap = systrap;
X jmp_buf mytrap;
X int status;
X
X if (status = setjmp(systrap = mytrap)) {
X systrap = savetrap; /* get here on fatal errors */
X return (status);
X }
X /* switch roles until both ends out of work */
X
X while (role != DONE) {
X switch (role) {
X case MASTER:
X role = master();
X break;
X case SLAVE:
X role = slave();
X break;
X default:
X trap(E_CONFUSED, "INTERNAL ERROR (unexpected role: %d)", role);
X }
X }
X systrap = savetrap; /* no fatal errors */
X return (0);
X}
X
X/* master - process local work; when done, switch roles or finish */
X
Xhidden int master()
X{
X register work *wrk;
X register char *resp;
X
X while (wrk = scanwork()) { /* scan for work */
X log("REQUEST (%s)", wrk->rqst);
X if (wrk->fp == 0) { /* check file exists */
X log("CAN'T READ DATA (%s)", sys_errlist[errno]);
X trap(E_SYSFAIL, "FAILED"); /* don\'t loop forever */
X } else if (isok(wrk->rqst) == NO) { /* check xfer allowed */
X log("PERMISSION (DENIED)");
X trap(E_REJECT, "FAILED"); /* don\'t loop forever */
X } else {
X sendwork(wrk); /* adapt and send data */
X log("REQUESTED (%s)", resp = hear());/* get remote status */
X if (strcmp(resp, "CY")) /* check for sucessful */
X trap(E_REJECT, "FAILED"); /* completion */
X unlink(wrk->sent); /* just in case */
X rename(wrk->path, wrk->sent); /* change status to "sent" */
X }
X }
X
X /* switch roles or finish if slave has no work */
X
X return (isok("H") == YES ? (talk("HY"), DONE) : SLAVE);
X}
X
X/* slave - process remote work; accept H and S requests only */
X
Xhidden int slave()
X{
X register char *cmnd;
X register work *wrk;
X
X for (;;) {
X switch ((cmnd = hear())[0]) {
X case 'S': /* master wants to send */
X log("REQUESTED (%s)", cmnd); /* log the request */
X wrk = rmtwork(cmnd); /* parse the request */
X talk("SY"); /* say ok */
X getwork(wrk); /* receive work */
X talk("CY"); /* we never copy */
X log("COPY (SUCCEEDED)");
X break;
X case 'H': /* master is out of work */
X return (scanwork() ? (talk("HN"), MASTER) : (talk("HY"), DONE));
X default:
X talk(strcons("%cN", cmnd[0])); /* refuse other type of work */
X break;
X }
X }
X}
END_OF_main/switcher.c
if test 4183 -ne `wc -c <main/switcher.c`; then
echo shar: \"main/switcher.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/unalias.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/unalias.c\"
else
echo shar: Extracting \"main/unalias.c\" \(4641 characters\)
sed "s/^X//" >main/unalias.c <<'END_OF_main/unalias.c'
X/*++
X/* NAME
X/* unalias 3
X/* SUMMARY
X/* alias processing
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* smail
X/* SYNOPSIS
X/* char **unalias(namevec)
X/* char **namevec;
X/* DESCRIPTION
X/* unalias() takes an array of string pointers and returns a vector
X/* with string pointers to their alias expansions. The resulting
X/* vector is in static memory.
X/*
X/* After alias expansion, all addresses are sorted and duplicate
X/* names are eliminated. The algorithms for alias expansion and
X/* duplicate elimination are case-insensitive.
X/*
X/* unalias() accesses the alias data base through the ascf ASCII
X/* filter.
X/* DIAGNOSTICS
X/* unalias() returns a null pointer in case of memory-allocation problems.
X/*
X/* unalias() terminates prematurely when the alias expansion has
X/* produced BUFSIZ recipients. This provides some defense against
X/* cycles in the alias data base. It is up to the caller to
X/* recognize this condition.
X/* BUGS
X/* The overflow/cycle detection algorithm is inelegant.
X/* FILES
X/* Alias data base in spool directory
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:02:54
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include "defs.h"
X#include "hsearch.h"
X#include "path.h"
X#include "ascf.h"
X
X/* forward declarations */
X
Xhidden int hash_alias();
Xhidden void sort_alias();
Xhidden void uniq_alias();
Xhidden char **find_alias();
X
X/* unalias - replace aliases by their equivalents */
X
Xpublic char **unalias(names)
Xchar **names;
X{
X static int dohash = 1; /* hash table not yet made */
X static char *recp[BUFSIZ + 1]; /* the result of alias expansion */
X char **stop = recp + BUFSIZ; /* overflow limit */
X
X if (dohash && (dohash = hash_alias())) /* build the hash table */
X return (0);
X if (stop > find_alias(names, recp, stop)) { /* build vector of addresses */
X sort_alias(recp); /* sort the recp list */
X uniq_alias(recp); /* eliminate duplicates */
X }
X return (recp);
X}
X
X/* hash_alias - copy alias data base to hash table */
X
Xhidden int hash_alias()
X{
X register FILE *fp;
X char buf[BUFSIZ];
X
X /* initialize the hash table */
X
X if (hcreate(BUFSIZ) == 0)
X return (-1);
X
X /*
X * Lines in the alias data base are of the form
X *
X * <left-hand part> <right-hand part>
X *
X * where the l.h. part is an alias, and the r.h. part one or more words. Of
X * course, those words can be aliases. The order in which aliases are
X * defined is not important. The alias data base is used only after it
X * has been loaded into memory.
X *
X * Each l.h. part is used as the key for finding the r.h. part in the hash
X * table. The r.h. part is stored as a vector of pointers to strings.
X */
X
X if (fp = ascopen(aliases(), "r")) { /* read through ASCII filter */
X while (ascgets(buf, sizeof(buf), fp)) { /* read entry from alias file */
X register char **cpp;
X ENTRY e;
X
X if ((cpp = strvec(buf, ", \t\r\n")) == 0) /* split alias entry */
X return (-1);
X if ((e.key = *cpp) /* left-hand part exists */
X &&(e.data = (char *) (cpp + 1)) /* right-hand part exists */
X &&(hsearch(e, ENTER) == 0)) /* enter hash table */
X return (-1);
X }
X ascclose(fp);
X }
X return (0);
X}
X
X/* find_alias - recursively expand aliases */
X
Xhidden char **find_alias(from, to, stop)
Xchar **from;
Xregister char **to;
Xregister char **stop;
X{
X register char **cpp;
X register ENTRY *sp;
X ENTRY e;
X
X /* recursively replace aliases, but don't crash in case of cycles */
X
X for (cpp = from; *cpp && (to < stop); cpp++) {
X e.key = *cpp;
X if (sp = hsearch(e, FIND)) {
X to = find_alias((char **) sp->data, to, stop);
X } else {
X *to++ = *cpp;
X }
X }
X *to = 0;
X return (to);
X}
X
X/* Istrcmp - interface between qsort and istrcmp */
X
Xhidden int Istrcmp(p1, p2)
Xchar **p1,
X **p2;
X{
X return (istrcmp(*p1, *p2));
X}
X
X/* sort_alias - sort the addresses after alias substitutions */
X
Xhidden void sort_alias(to)
Xchar **to;
X{
X register char **cpp;
X int istrcmp();
X
X /* find out length of the list */
X
X for (cpp = to; *cpp; cpp++)
X /* void */ ;
X
X /* sort the list */
X
X qsort((char *) to, cpp - to, sizeof(*to), Istrcmp);
X}
X
X/* uniq_alias - collapse sequences of identical addresses */
X
Xhidden void uniq_alias(to)
Xchar **to;
X{
X register char **in = to;
X register char **out = to;
X
X while (*out = *in) {
X while (*++in && istrcmp(*out, *in) == 0) {
X /* void */ ;
X }
X ++out;
X }
X}
END_OF_main/unalias.c
if test 4641 -ne `wc -c <main/unalias.c`; then
echo shar: \"main/unalias.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 4 \(of 11\).
cp /dev/null ark4isdone
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