[comp.sources.misc] v03i006: uucp mail for pc's

wswietse@eutrc3.UUCP (Wietse Venema) (04/20/88)

comp.sources.misc: Volume 3, Issue 6
Submitted-By: "Wietse Venema" <wswietse@eutrc3.UUCP>
Archive-Name: pcmail/Part5

#! /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 5 (of 8)."
# Contents:  ascf.c comm.h deskutil.c invoke.c kpres.c logs.c path.h
#   sendwork.c spoolfil.c srctoman.sh switcher.c unalias.c
# Wrapped by wietse@eutwc1 on Wed Apr 20 16:45:27 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f ascf.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ascf.c\"
else
echo shar: Extracting \"ascf.c\" \(4105 characters\)
sed "s/^X//" >ascf.c <<'END_OF_ascf.c'
X/*++
X/* NAME
X/*	ascf 3
X/* SUMMARY
X/*	stdio-like ascii filter
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	ascii filtering
X/* SYNOPSIS
X/*	FILE *ascopen(name,mode)
X/*	char *name;
X/*	char *mode;
X/*
X/*	int ascget(fp)
X/*	FILE *fp;
X/*
X/*	int ascclose(fp)
X/*	FILE *fp;
X/* DESCRIPTION
X/*	The functions in this module provide filtered stream i/o for
X/*	textfiles produced by word processors. Their calling sequence
X/*	has been modelled after the standard i/o library routines.
X/*
X/*	ascopen() is the analogon of fopen(3), ascget() returns the next
X/*	character in the filtered input stream, and ascclose() closes 
X/*	the stream. ascget() is a macro.
X/*
X/*	The following mappings are done: cr/lf, cr, lf, lf/cr are 
X/*	replaced by newline; all high bits are stripped off; wordstar
X/*	hyphens are converted to normal hyphens. Except for tabs,
X/*	all control characters are suppressed in the output.
X/*	In order to avoid problems in mailers, a newline
X/*	character is appended to the last line of each file.
X/* SEE ALSO
X/*	stdio(3)	standard i/o library interface.
X/* DIAGNOSTICS
X/*	ascopen() returns a null pointer on failure; ascget() returns
X/*	the value EOF when the end of a stream is reached. ascclose()
X/*	returns whatever fclose() returns.
X/* BUGS
X/*	Actually works with wordstar or clean ascii files only.
X/*	No character pushback.
X/*	Although allowed by ascopen(), the "w" file open mode is 
X/*	of no use. 
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 Jul  6 16:03:41 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:34:46 MET 1988
X/* VERSION/RELEASE
X/*	1.4
X/*--*/
X
X#include <ctype.h>
X
X#include "defs.h"
X#include "ascf.h"
X
X/* some systems do not define _NFILE in stdio.h */
X
X#ifndef _NFILE
X#  include <sys/param.h>		/* maybe we are a sun */
X#    ifdef NOFILE
X#    define _NFILE NOFILE
X#  else
X"ERROR: cannot get max nr of open files"
X#  endif
X#endif
X
X#define CTRL(x) ((x)^0100)		/* ASCII control characters */
X
X#ifdef MSDOS
X#include <fcntl.h>			/* to turn cr/lf mapping off */
X#endif
X
Xpublic Asc asc[_NFILE];			/* one filter structure per file */
X
X/* ascopen - open stream, initialize intermediate buffer */
X
Xpublic FILE *ascopen(file,mode)
Xchar *file,*mode;
X{
X    register FILE *fp;
X
X    if (fp = fopen(file,mode)) {	/* if file is accessable */
X	register Asc *ap = asc+fileno(fp);
X	if (ap->buf = malloc(BUFSIZ)) {	/* if buffer available */
X	    ap->cnt = 0;		/* init buffer count */
X	    ap->nlf = 0;		/* no newline appended yet */
X#ifdef O_BINARY
X	    setmode(fileno(fp),O_BINARY);
X#endif
X	} else {
X	    fclose(fp);			/* no room for that buffer */
X	    fp = 0;
X 	}
X    }
X    return(fp);
X}
X
X/* ascclose - release intermediate buffer and close the stream */
X
Xpublic int ascclose(fp)
Xregister FILE *fp;
X{
X    free(asc[fileno(fp)].buf);
X    return(fclose(fp));
X}
X
X/* ascbuf - ascii filter, make new buffer of text */
X
Xpublic int ascbuf(fp)
XFILE *fp;
X{
X    register Asc *ap = asc+fileno(fp);	/* intermediate buffer access */
X    register char *cp = ap->buf;	/* init write pointer */
X    register int c;			/* single-character input buffer */
X    int d;				/* look-ahead character */
X
X    while (cp < ap->buf+BUFSIZ && 
X	(c = getc(fp)) != EOF && (c &= 0177) != CTRL('Z')) {
X	if (c == ' ' || isprint(c) || c == '\t') {
X	    *cp++ = c;			/* accept character */
X	} else if ((c == '\r' && ((d = getc(fp)) == '\n' || (ungetc(d,fp),1)))
X	    || (c == '\n' && ((d = getc(fp)) == '\r' || (ungetc(d,fp),1)))) {
X	    *cp++ = '\n';		/* terminate line */
X	} else if (c == CTRL('_')) {
X	    *cp++ = '-';		/* wordstar hyphen */
X	} else {
X	    continue;			/* ignore other characters */
X	}
X    }
X    if (ap->cnt = cp-ap->buf) {		/* anything in the buffer? */
X	ap->ptr = ap->buf;		/* yes, set read pointer */
X	return(ascget(fp));		/* and return first character */
X    } else if (ap->nlf == 0) {		/* make sure file ends with \n */
X        return(ap->nlf = '\n');		/* append newline first */
X    } else {				/* now we're really done */
X	return(EOF);			/* that's it. */
X    }
X}
END_OF_ascf.c
if test 4105 -ne `wc -c <ascf.c`; then
    echo shar: \"ascf.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f comm.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"comm.h\"
else
echo shar: Extracting \"comm.h\" \(1967 characters\)
sed "s/^X//" >comm.h <<'END_OF_comm.h'
X/*++
X/* NAME
X/*      comm 5
X/* SUMMARY
X/*      cico systems parameters
X/* PROJECT
X/*      pc-mail
X/* PACKAGE
X/*      cico
X/* SYNOPSIS
X/*      #include "params.h"
X/*      #include "comm.h"
X/* DESCRIPTION
X/* .nf
X
X/* /* roles and other behavioural codes */
X
X#define MASTER	1			/* who sends files */
X#define SLAVE	2			/* who receives files */
X#define DONE	3			/* no more files */
X
X#define YES	'Y'
X#define NO	'N'
X
X/* /* communications parameters (see params.h) */
X
X#define COMM_LINE	(comm[P_PORT].strval)
X#define COMM_RATE	(comm[P_BAUD].strval)
X#define DIAL_SEQUENCE	(comm[P_DIAL].strval)
X#define LOGIN_NAME	(comm[P_LOGIN].strval)  
X#define DISC_SEQUENCE	(comm[P_DISC].strval)
X
X/* /* related info */
X
Xextern int ttfd;			/* comm. port */
Xextern Info *comm;			/* comm. info */
Xextern char *password;			/* password */
Xextern char rmthost[];			/* remote system name */
X
X/* /* functions that use the above */
X
Xextern char *rmtname();			/* make remote spool-file name */
Xextern char *locname();			/* make local spool-file name */
X
X/* /* protocol function pointers */
X
Xextern int (*Read)();			/* protocol read */
Xextern int (*Write)();			/* protocol write */
Xextern int (*Close)();			/* protocol close */
X
X/* /* use these at your own risk */
X
X#define MSGBUF       4096		/* message buffer size */
X
Xextern char msgin[MSGBUF];		/* message receive buffer */
Xextern char msgout[MSGBUF];		/* message send buffer */
X
X/* /* message i/o functions */
X
Xextern int isok();			/* do request; get yes or no */
Xextern char *talk();			/* send message */
Xextern char *hear();			/* receive message */
X/* SEE ALSO
X/*      comm(3) implementation module
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 12 13:52:39 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:36:42 MET 1988
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
END_OF_comm.h
if test 1967 -ne `wc -c <comm.h`; then
    echo shar: \"comm.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f deskutil.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"deskutil.c\"
else
echo shar: Extracting \"deskutil.c\" \(4943 characters\)
sed "s/^X//" >deskutil.c <<'END_OF_deskutil.c'
X/*++
X/* NAME
X/*	deskutil 3
X/* SUMMARY
X/*	utility functions
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	mailsh
X/* SYNOPSIS
X/*	#include "mailsh.h"
X/*
X/*	void patience()
X/*
X/*	int when()
X/*
X/*	int delete()
X/*
X/*	int unspool()
X/*
X/*	int print()
X/*
X/*	int save()
X/*
X/*	char *tstamp(ltime)
X/*	long *ltime()
X/* DESCRIPTION
X/*	tstamp() converts absolute time to a string. If called with
X/*	recent time argument (less than 100 days ago) the string will
X/*	be of the form "Sun Apr 17 12:50", otherwise "Sun Apr 17  1988".
X/*
X/*      delete() gives the user another chance before a message is deleted.
X/*
X/*      unspool() actually deletes a message. As a side effect it destroys
X/*      the current mail box display so that the next display will
X/*	reflect the actual status of the spool directory.
X/*	The affected message and meta file names are taken from the
X/*	global "message" and "commant" string variables.
X/*
X/*	print() copies a pager file to the printer.
X/*
X/*	save() asks where the pager file should be saved.
X/*
X/*	when() should be called after the user has entered a mail destination
X/*	address. It informs the user that messages are not sent right away, 
X/*	but after selection of the Network option in the main menu.
X/*
X/*	patience() prints a 'one moment please' message in the middle
X/*	screen window. As a side effect, the current pager file is set
X/*	to none.
X/* FILES
X/*      mail header files in the spool directory
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/*	Tue May 12 15:35:20 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:38:26 MET 1988
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
X
X#include <errno.h>
X
X#include "defs.h"
X#include "pager.h"
X#include "mailsh.h"
X#include "screen.h"
X#include "status.h"
X
Xhidden int save_desk();
X
X/* patience - say this will take some time */
X
Xpublic void patience()
X{
X    static char *m_wait[] = {
X	"",
X	"One moment please...",
X	0,
X    };
X
X    register File *pp = open_pager();		/* create pager file */
X
X    mesg_pager(pp,m_wait);			/* write pager file */
X    ds_pager();					/* show om middle window */
X    close_pager(pp);				/* forget pager file */
X}
X
X/* delete - user wants to delete a message; ask for confirmation */
X
Xpublic int delete()
X{
X    static Screen screen[] = {
X	ESCCR,	"Enter",	unspool,int_error,
X	0,	0,		0,
X	"Press ESC to cancel. Confirm with ENTER",
X    };
X
X    return(kbdinp(screen)|S_REDRAW);
X}
X
X/* unspool - actually delete a message; force mail box display rebuild */
X
Xpublic int unspool()
X{
X    if (((chmod(message,0666) || unlink(message)) && errno != ENOENT)
X    || ((chmod(comment,0666) || unlink(comment)) && errno != ENOENT)) {
X	errdisp(E_UNLINK);			/* notify user of problem */
X	return(S_REDRAW);			/* say screen has changed */
X    } else {
X	junk_desk();				/* say mail box has changed */
X	return(S_BREAK);			/* no more work to do */
X    }
X}
X
X/* print - print pager display on default printer */
X
Xpublic int print()
X{
X    return(pr_pager() ? (errdisp(E_PRINTERR),S_REDRAW) : 0);
X}
X
X/* save - ask where pager display should be copied to */
X
Xpublic int save()
X{
X    static Screen screen[] = {
X	STRING,	0,              save_desk,int_error,
X	0,	0,              0,
X	"Press ESC to cancel. Save to file:",
X    };
X
X    kbdinp(screen);			/* prompt for file name, then copy */
X    return(S_REDRAW);			/* force screen repaint */
X}
X
X/* save_desk - copy pager file to ordinary file */
X
Xhidden int save_desk(to)
Xchar *to;
X{
X    if (cp_pager(to)) {			/* if file copy failed */
X	unlink(to);			/* remove that file */
X	errdisp(E_WRITERR);		/* notify the user */
X	return(S_BREAK|S_REDRAW);	/* redisplay, terminate caller */
X    } else {
X	junk_file();			/* say file display maybe outdated */
X	return(S_BREAK);		/* terminate caller */
X    }
X}
X
X/* when - say when mail will actually be sent */
X
Xpublic int when()
X{
X    static char *msg[] = {
X	"",
X	"To send messages through the network, use the Network",
X	"option in the main menu.",
X	0,
X    };
X    File *pp = open_pager();			/* open new pager file */
X
X    mesg_pager(pp,msg);				/* fill pager file */
X    ds_pager();					/* display the file */
X    close_pager(pp);				/* forget pager file */
X    return(0);					/* don't care value */
X}
X
X/* tstamp - time format as produced by the ls(1) command */
X
Xpublic char *tstamp(ltime)
Xlong *ltime;
X{
X    static char buf[25];
X
X    /*
X    * Output from asctime() is of the form
X    *	"Sun Apr 17 13:34:35 1988"
X    * Depending on how recent the time in question is, we
X    * supress the time or year field.
X    */
X
X    (void) strcpy(buf,asctime(localtime(ltime)));
X    if (time((long *)0)-*ltime > 60L*60L*24L*100L) {
X	buf[24] = '\0';				/* remove the \n */
X	(void) strcpy(buf+11,buf+19);		/* old file, show year */
X    } else
X	buf[16] = '\0';				/* recent, show time */
X    return(buf);
X}
END_OF_deskutil.c
if test 4943 -ne `wc -c <deskutil.c`; then
    echo shar: \"deskutil.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f invoke.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"invoke.c\"
else
echo shar: Extracting \"invoke.c\" \(4946 characters\)
sed "s/^X//" >invoke.c <<'END_OF_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/*
X/*	int onexit(command)
X/*	char *command;
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/*
X/*	invokevp() is similar to invokelp; the difference is that
X/*	argv is an array of pointers to arguments.
X/*
X/*	onexit() executes a command, thereby terminating the current process.
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/*
X/*	onexit() return -1 if there were problems.
X/* BUGS
X/*	The invokexx() functions should not be used if the command needs to 
X/*	be handled by a command-language processor (e.g. shell built-ins,
X/*	or i/o redirection).
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/*	Wed Apr  6 00:19:56 MET 1988
X/* VERSION/RELEASE
X/*	1.4
X/*--*/
X
X#include <errno.h>
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/* VARARGS2 */
X
Xpublic int invokelp(arg0,arg1,arg2,arg3,arg4)
Xchar *arg0,*arg1,*arg2,*arg3,*arg4;
X{
X    /*
X    * On unix systems we fork a process and overlay the child with
X    * the desired program.
X    * This means we get -1 if the fork did not succeed, otherwise
X    * the exit status if the child process. The code is a bit elaborate
X    * 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	execlp(arg0,arg0,arg1,arg2,arg3,arg4);/* try to replace it */
X	_exit(errno == ENOENT ? E_NOPROG : E_SYSFAIL); /* sorry, failed */
X	/* NOTREACHED */
X    } else {
X	int xstat,wstat;		/* wait till above child terminates */
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    * On MS-DOS systems we try to avoid the command.com shell because
X    * it always returns a zero status code. 
X    */
X#ifdef MSDOS
X    int stat;
X    char *p;
X
X    if ((stat = spawnlp(P_WAIT,arg0,arg0,arg1,arg2,arg3,arg4)) < 0
X    && errno == ENOENT 
X    && (strcmp(p = arg0+strlen(arg0)-4,".bat") == 0 || strcmp(p,".BAT") == 0))
X	stat = spawnlp(P_WAIT,"command","command","/c",arg0,arg1,arg2,arg3,arg4);
X    return(stat >= 0 ? stat : (errno == ENOENT ? E_NOPROG : E_SYSFAIL));
X#endif
X}
X
X/* invokelp - create child process to execute command */
X
Xpublic int invokevp(argv)
Xchar **argv;
X{
X    /*
X    * On unix systems we fork a process and overlay the child with
X    * the desired program.
X    * This means we get -1 if the fork did not succeed, otherwise
X    * the exit status if the child process. The code is a bit elaborate
X    * 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	execvp(*argv,argv);		/* try to replace it */
X	_exit(errno == ENOENT ? E_NOPROG : E_SYSFAIL); /* sorry, failed */
X	/* NOTREACHED */
X    } else {
X	int xstat,wstat;		/* wait till above child terminates */
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    * On MS-DOS systems we try to avoid the command.com shell because
X    * it always returns a zero status code. 
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
X/* onexit - exec another command */
X
Xint onexit(command)
Xchar *command;
X{
X    if (command && *command) {
X#ifdef unix
X	return(execlp("/bin/sh","sh","-c",command));
X#endif
X
X#ifdef MSDOS
X	return(system(command));
X#endif
X    }
X}
END_OF_invoke.c
if test 4946 -ne `wc -c <invoke.c`; then
    echo shar: \"invoke.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f kpres.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"kpres.c\"
else
echo shar: Extracting \"kpres.c\" \(4951 characters\)
sed "s/^X//" >kpres.c <<'END_OF_kpres.c'
X/*++
X/* NAME
X/*	kpres
X/* SUMMARY
X/*	k-protocol presentation layer
X/* PACKAGE
X/*	uucp across thenet
X/* SYNOPSIS
X/*	#include "kp.h"
X/*
X/*	kopen(fd)
X/*	int fd;
X/*
X/*	kwrite(fd,buf,len)
X/*	int fd,len;
X/*	char *buf;
X/*
X/*	kread(fd,buf,len)
X/*	int fd,len;
X/*	char *buf;
X/*
X/*	kclose(fd)
X/*	int fd;
X/* DESCRIPTION
X/*	This section contains functions that imitate standard unix
X/*	unbuffered i/o facilities. A status code of FAIL is returned when
X/*	the network partner wants to terminate the protocol, or when the
X/*	the transmission error rate is excessive.
X/*
X/*	Eight-bit data bytes are transported as harmless six-bit data bytes
X/*	in the ASCII range 32 through 95. This introduces an overhead of 33%.
X/*	For textfiles, this is hardly worse than kermit (typical overhead 
X/*	10 %). For binary files the overhead is much less than with kermit 
X/*	(typical overhead 60%).
X/*
X/*	Kopen() sets up the terminal characteristics of the specified file
X/*	descriptors (no echo, raw, tandem). Always returns zero status.
X/*
X/*	Kwrite() attempts to send the bytes in buf. A zero-length buffer 
X/*	should be written to indicate an end-of-file condition. Return status: 
X/*	the number of bytes requested, or FAIL.
X/*
X/*	Kread() attempts to read the requested number of bytes. Status code:
X/*	the number of bytes actually read, or FAIL. A read of zero bytes
X/*	normally indicates an end-of-file condition (see kwrite).
X/*
X/*	Kclose() sends a protocol abort sequence to the network partner.
X/*	This function should be called to terminate the k protocol driver
X/*	at the other end, or to confirm reception of a protocol abort sequence.
X/*	Kclose always returns zero exit status.
X/*
X/*	The function kfail() is called by the strategy layer functions to 
X/*	indicate protocol failure or termination.
X/* FUNCTIONS AND MACROS
X/*	kwproto, krproto, kclsproto
X/* BUGS
X/*	Zero byte read/writes are a clumsy way to handle end-of-files. 
X/*	They have been implemented for the sake of compatibility with uucico.
X/* AUTHOR(S)
X/*	Wietse Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/*	Mon Feb  3 11:14:13 MET 1986
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:43:28 MET 1988
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
X
X#ifdef unix
X# ifdef	SIII
X#   include <termio.h>
X# else
X#   include <sgtty.h>
X# endif
X#endif
X#include <setjmp.h>
X#include "kp.h"
X
Xstatic jmp_buf Failbuf;
X
Xkfail()
X{
X    longjmp(Failbuf,TRUE);
X}
X
Xkopen(fd)
Xint fd;
X{
X#ifdef unix
X# ifdef SIII
X    struct termio ttymode;
X
X    ioctl(fd,TCGETA,&ttymode);
X    ttymode.c_iflag = IXOFF|IXON|ISTRIP;
X    ttymode.c_cc[VMIN] = 1;
X    ttymode.c_cc[VTIME] = 0;
X    ioctl(fd,TCSETA,&ttymode);
X# else
X    struct sgttyb ttymode;
X
X    gtty(fd,&ttymode);
X    ttymode.sg_flags |= (TANDEM|RAW);
X    ttymode.sg_flags &= ~(ECHO|CBREAK);
X    stty(fd,&ttymode);
X# endif
X#else
X    xioctl(1);
X#endif
X    return 0;
X}
X
Xkwrite(fd,buf,len)
Xint fd;
Xregister char *buf;
Xregister int len;
X{
X    static char  packbuf[MAXPACKSIZ];
X    static char *packptr = packbuf;
X    register int c,i,rest,shift;
X
X    /* set error trap */
X
X    if (setjmp(Failbuf))
X	return FAIL;
X
X    /* if 'end of data' send null packet */
X
X    if (len <= 0) {
X	kwproto(fd,NULLP,0);
X	return 0;
X
X    /* expand 3 eight-bit bytes to four six-bit bytes */
X
X    } else {
X	for (rest = shift = i = 0; i < len; shift = (shift+STEP)%OUT,i++) {
X
X	    c = *buf++ & 0377;				/* No sign extension */
X	    *packptr++ = tosix(rest|(c << shift));	/* Assemble byte */
X	    rest = (c >> (OUT-shift));			/* Save unused bits */
X
X	    if (shift == (OUT-STEP)) {			/* At byte boundary? */
X		*packptr++ = tosix(rest);		/* Make 'fourth' byte */
X		rest = 0;				/* No unused bits now */
X		if (packptr-packbuf > PACKSIZ-4) {	/* Check packet size */
X		    kwproto(fd,packbuf,packptr-packbuf);
X		    packptr = packbuf;
X		}
X	    }
X	}
X	if (shift) {					/* Any bits left? */
X	    *packptr++ = tosix(rest);			/* Put them there */
X	}
X	if (packptr > packbuf) {			/* Flush buffer */
X	    kwproto(fd,packbuf,packptr-packbuf);	/* Ship it off */
X	    packptr = packbuf;
X	}
X	return i;
X    }
X}
X
Xkread(fd,buf,len)
Xint fd;
Xchar *buf;
Xint len;
X{
X    static char packbuf[MAXPACKSIZ] = "";
X    static char *packptr = packbuf;
X    static int  packsiz = 0;
X    register int i,c;
X    static int shift,rest;
X
X    /* set error trap */
X
X    if (setjmp(Failbuf))
X	return FAIL;
X
X    /* read packet if buffer is empty */
X
X    if (packsiz <= 0) {
X	krproto(fd,packptr = packbuf,&packsiz);
X	rest = shift = 0;
X    }
X
X    /* unpack (remainder of) buffer; return 0 if empty packet received */
X
X    for (i = 0; (i < len) && packsiz--; shift = (shift+STEP)%IN) 
X    {
X	c = unsix(*packptr++);
X	if (shift)
X	    buf[i++] = (rest | (c << (IN-shift)));
X	rest = (c >> shift);
X    }
X    return i;
X}
X
Xkclose(fd)
Xint fd;
X{
X    /* not here - pass job to the lower layer that understands packet types */
X
X    kclsproto(fd);
X    return 0;
X}
X
X
END_OF_kpres.c
if test 4951 -ne `wc -c <kpres.c`; then
    echo shar: \"kpres.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f logs.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"logs.c\"
else
echo shar: Extracting \"logs.c\" \(4714 characters\)
sed "s/^X//" >logs.c <<'END_OF_logs.c'
X/*++
X/* NAME
X/*      logs 3
X/* SUMMARY
X/*      error logging, status reports, debugging
X/* PROJECT
X/*      pc-mail
X/* PACKAGE
X/*      cico
X/* SYNOPSIS
X/*      void dbg(fmt[,args]);
X/*      char *fmt;
X/*
X/*      int open_log();
X/*
X/*      void log(fmt[,args]);
X/*      char *fmt;
X/*
X/*      void trap(code,fmt[,args]);
X/*      char *fmt;
X/* DESCRIPTION
X/*      All functions in this module do some form of logging, and accept
X/*      printf-like format strings with %s, %c, and %S, %C. The latter
X/*	two cause output mapping of arbitrary byte values to printable codes.
X/*
X/*      dbg() formats its arguments and writes the result to the standard
X/*      output.
X/*
X/*      open_log() tries to open the logfile for writing. It returns
X/*      a status E_WRITERR if the file could not be opened or created.
X/*
X/*      log() writes status info to the log file. If debugging is enabled,
X/*	the message is also written to the standard output.
X/*
X/*      trap() writes a message to the log file and performs a longjmp call
X/*      (systrap) with the status as given in the code parameter. If 
X/*	debugging is enabled, the message is also written to the standard 
X/*	output.
X/* FUNCTIONS AND MACROS
X/*      longjmp()
X/* FILES
X/*      LOGFILE         status reports
X/* BUGS
X/*      Logfile info may be lost if the program terminates abnormally.
X/*      We do not open/close the with each log() call since that would
X/*      slow down performance on floppy-based systems dramatically.
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 17:45:19 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:44:00 MET 1988
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
X
X#include <setjmp.h>
X#include <ctype.h>
X#include <varargs.h>
X#include "defs.h"
X#include "logs.h"
X#include "path.h"
X#include "status.h"
X
X#define	dbgout	stdout		/* where debugging output should go */
X
Xhidden FILE *logfp = NULL;	/* log file file pointer */
Xhidden char *visible();		/* map characters to readable codes */
Xhidden void dprintf();		/* special-purpose formatting function */
X
X/* dbg - write debugging info to the debugging output */
X
X/* VARARGS1 */
X
Xpublic void dbg(fmt,va_alist)
Xregister char *fmt;
Xva_dcl
X{
X    va_list s;
X
X    va_start(s);
X    dprintf(dbgout,fmt,s);
X    va_end(s);
X}
X
X/* open_log - check the logfile can be written */
X
Xpublic int open_log()
X{
X    if (logfp == NULL && (logfp = fopen(logfile(),"a")) == NULL)
X	return(E_WRITERR);
X    else
X	return(0);
X}
X
X/* log - write status info to the log file */
X
X/* VARARGS1 */
X
Xpublic void log(fmt,va_alist)
Xregister char *fmt;
Xva_dcl
X{
X    va_list s;
X
X    /* log file should be open! */
X
X    if (logfp == NULL)
X	exit(E_CONFUSED);
X
X    /* write status record to log file */
X
X    va_start(s);
X    dprintf(logfp,fmt,s);
X    putc('\n',logfp);
X    va_end(s);
X
X    /* if debugging on, write also to debugging output */
X
X    if (dflag) {
X	va_start(s);
X	dprintf(dbgout,fmt,s);
X	putc('\n',dbgout);
X	va_end(s);
X   }
X}
X
X/* trap - exception handler */
X
X/* VARARGS2 */
X
Xpublic void trap(code,fmt,va_alist)
Xint code;
Xchar *fmt;
Xva_dcl
X{
X    va_list s;
X
X    /* write exception record to log file */
X
X    va_start(s);
X    dprintf(logfp,fmt,s);
X    putc('\n',logfp);
X    va_end(s);
X
X    /* if debugging on, write also to debugging output */
X
X    if (dflag) {
X	va_start(s);
X	dprintf(dbgout,fmt,s);
X	putc('\n',logfp);
X	va_end(s);
X    }
X    longjmp(systrap,code);
X}
X
X/* visible - turn arbitrary character into something visible */
X
Xstatic char *visible(c)
Xregister int c;
X{
X    static char buf[5];
X
X    switch(c&=0377) {
X    default:
X	sprintf(buf,isascii(c) && isprint(c) ? "%c" : "\\%03o",c);
X	return(buf);
X    case ' ':
X	return("\\s");
X    case '\b':
X	return("\\b");
X    case '\t':
X	return("\\t");
X    case '\r':
X	return("\\r");
X    case '\n':
X	return("\\n");
X    case '\f':
X	return("\\f");
X    case '\\':
X	return("\\\\");
X    }
X}
X
X/* dprintf - handle %s, %c, %S and %C format requests */
X
Xstatic void dprintf(fp,fmt,s)
Xregister FILE *fp;
Xregister char *fmt;
Xva_list s;
X{
X    register int c;
X
X    for (/* void */; c = *fmt; fmt++) {
X	if (c != '%') {
X	    putc(c,fp);
X	} else if ((c = *++fmt) == 'S') {		/* %S: translated */
X	    register char *cp = va_arg(s,char *);
X	    while(*cp)
X		fputs(visible(*cp++&0377),fp);
X	} else if (c == 'C') {				/* %C: translated */
X	    fputs(visible(va_arg(s,int)),fp);
X	} else if (c == 's') {				/* %s: string, as is */
X	    fputs(va_arg(s,char *),fp);
X	} else if (c == 'c') {				/* %c: char, as is */
X	    putc(va_arg(s,int),fp);
X	} else if (c == '%') {				/* real % character */
X	    putc(c,fp);
X	}
X    }
X}
END_OF_logs.c
if test 4714 -ne `wc -c <logs.c`; then
    echo shar: \"logs.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f path.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"path.h\"
else
echo shar: Extracting \"path.h\" \(4342 characters\)
sed "s/^X//" >path.h <<'END_OF_path.h'
X/*++
X/* NAME
X/*	path
X/* SUMMARY
X/*	system-dependent file name definitions
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	general
X/* SYNOPSIS
X/*	#include "path.h"
X/* DESCRIPTION
X/*	File-system dependent definitions should be changed here.
X/* .nf
X
X/* /* the minmal number of open files we think we need */
X
X#define	MINFILES	10
X
X/* /*	system-dependent defaults */
X
X#ifdef	unix
X#define	THISDIR		"."		/* current directory */
X#define	DEFSPOOL	"./spool"	/* default spool directory */
X#define	DEFEDIT		"vi"		/* default editor */
X#ifdef SIII
X#define	DEFPRINT	"lp"		/* printer spooler */
X#else
X#define	DEFPRINT	"lpr"		/* printer spooler */
X#endif
X#define	MAILFILE	"mail.msg"	/* temporary message file */
X#define	TMPALIAS	"tmp.alias"	/* temp alias file */
X#define	NULLDEV		"/dev/null"	/* bit dump */
X#endif
X
X#ifdef	MSDOS
X#define	THISDIR		"."		/* current directory */
X#define	DEFSPOOL	"\\spool"	/* spool directory */
X#define	DEFEDIT		"edlin"		/* default editor */
X#define DEFPRINT	"PRN"		/* default printer */
X#define	MAILFILE	"mail.msg"	/* temp message file */
X#define	TMPALIAS	"alias.tmp"	/* temp alias file */
X#define	NULLDEV		"NUL"		/* bit dump */
X#endif
X
X/* /* system-dependent function calls for file & printer access */
X
X#ifdef unix
X#define	propen()	popen(mailprn,"w")	/* open printe stream */
X#define	prclose(p)	pclose(p)		/* close print stream */
X#define	fspool(file)	strcons("%s/%s",maildir,file)
X#endif
X
X#ifdef MSDOS
X#define	propen()	fopen(mailprn,"a")	/* open print stream */
X#define	prclose(p)	(putc('\014',p),fclose(p)) /* close print stream */
X#define	fspool(file)	strcons("%s\\%s",maildir,file)
X#endif
X
X/* /* system-independent file names */
X
X#define	SMAIL	"smail"			/* queues a mail message */
X#define	CICO	"cico"			/* file transfer program */
X#define	RMAIL	"rmail"			/* extract originator address */
X
X/* /*
X* The spool directory is used for storage of all files manipulated
X* by the mail programs. Message files should always have a meta file
X* with information about the destination or origin of a message file.
X*
X* Message/meta file names are of the form <letter><sequence number>.
X* Corresponding message/meta files have the same sequene number.
X* The following definitions are for the <letter> part of spool files.
X*/
X
X#define	LOGFILE	"LOGFILE"		/* transaction logs */
X
X#define	NEWPFX	"n"			/* received message */
X#define	HDRPFX	"h"			/* originator of new mail */
X#define	OLDPFX	"o"			/* originator of old mail */
X
X#define	MSGPFX	"d"			/* message ready to be sent */
X#define	XQTPFX	"x"			/* its destination */
X
X#define	EDTPFX	"e"			/* message being worked on */
X#define	COMPFX	"c"			/* its description */
X
X#define	SETPFX	"s"			/* system parameter file */
X
X#define	ALIPFX	"a"			/* alias data base */
X
X#define	SPLFMT	"%s%05d"		/* spool-file name format */
X
X/* /* 
X* The following macros provide convenient access of spool files, so we
X* don't have to remember the spool file name format and prefix stuff.
X*/
X
X#define	sendmail(file,to)	spoolfil(file,to,MSGPFX,XQTPFX)
X#define	workon(fname,meta)	spoolfil(fname,meta,EDTPFX,COMPFX)
X
X#define	parm_file()		fspool(strcons(SPLFMT,SETPFX,0))
X#define	aliases()		fspool(strcons(SPLFMT,ALIPFX,0))
X#define logfile()		fspool(LOGFILE)
X
X#define meta_file(type,id)	fspool(strcons(SPLFMT,type,id))
X#define mesg_file(type,id)	fspool(strcons(SPLFMT,type,id))
X
X#define	work_meta(id)		fspool(strcons(SPLFMT,COMPFX,id))
X#define	work_mesg(id)		fspool(strcons(SPLFMT,EDTPFX,id))
X
X#define	in_mesg(id)		fspool(strcons(SPLFMT,NEWPFX,id))
X#define	in_meta(id)		fspool(strcons(SPLFMT,OLDPFX,id))
X
X#define	new_mesg(id)		fspool(strcons(SPLFMT,NEWPFX,id))
X#define	new_meta(id)		fspool(strcons(SPLFMT,HDRPFX,id))
X
X#define	out_mesg(id)		fspool(strcons(SPLFMT,MSGPFX,id))
X#define out_meta(id)		fspool(strcons(SPLFMT,XQTPFX,id))
X
X/* /* stuff taken from the environment */
X
Xextern char *editor;		/* path to editor */
Xextern char *maildir;		/* spool directory */
Xextern char *mailprn;		/* how to print */
Xextern char *mailcmd;		/* do this on exit */
X
Xextern int pathinit();		/* get path info from environment */
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 13:23:45 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Wed Apr  6 00:21:29 MET 1988
X/* VERSION/RELEASE
X/*	1.4
X/*--*/
END_OF_path.h
if test 4342 -ne `wc -c <path.h`; then
    echo shar: \"path.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sendwork.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sendwork.c\"
else
echo shar: Extracting \"sendwork.c\" \(4326 characters\)
sed "s/^X//" >sendwork.c <<'END_OF_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/* FUNCTIONS AND MACROS
X/*      rmtname()
X/* SEE ALSO
X/*      scanwork(3)     locates work in the spool directory
X/*      rmtname(3)      rules for remote file name construction
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/*	Wed Apr  6 00:22:23 MET 1988
X/* VERSION/RELEASE
X/*	1.4
X/*--*/
X
X#include <time.h>
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
X* have to appear in the "From " lines of outgoing mail. A consequence 
X* is that the pc mail node name should be known in mailer routing tables.
X* Obviously this implies some administrative work when a pc mail node 
X* is added to the net or taken out of operation. 
X*
X* 2. As an ordinary user. The program lets the UNIX host believe that
X* mail messages come from an ordinary user. Recipients of mail will
X* not be able to see that the mail came from the pc. Only the UNIX host 
X* knows it should forward mail for unixhost!xyz to the pc-mail node.
X* This approach has the advantage that adding/deleting pc-mail nodes 
X* is simpler.
X*/
X
X#ifdef	UUCP_NODE				/* case 1 */
X#   define U_USER	"root"			/* use current user's name */
X#   define U_HOST	LOGIN_NAME		/* use pc host name */
X#else						/* case 2 */
X#   define U_USER	LOGIN_NAME		/* use remote login name */
X#   define U_HOST	rmthost			/* use remote host name */
X#endif
X
X/* sendwork - adapt file contents for remote host */
X
Xpublic sendwork(wrk)
Xwork *wrk;
X{
X    register char *date;
X    long secs;
X
X    switch (wrk->type) {
X
X	/* 
X	* Local D files contain the mail message, nothing more, nothing less.
X	* We add a "From " line with originator/date/system.
X	* Otherwise, D files can be sent as is.
X	*/
X
X    case 'D':
X	secs = time((long *)0);
X	(date = asctime(localtime(&secs)))[24] = '\0';
X	say(strcons("From %s %s remote from %s\n",U_USER,date,U_HOST));
X	send_file(wrk->fp);
X	break;
X
X	/* 
X	* Local X files contain the destination network address only.
X	* Therefore we must mock up some extra info to make the 
X	* remote uuxqt program happy.
X	*/
X
X    case 'X':
X	say(strcons("U %s %s\n",U_USER,U_HOST));	/* U user system */
X	say(strcons("F %s\n",rmtname('D',wrk->tail)));	/* F D.rmtsysGnumber */
X	say(strcons("I %s\n",rmtname('D',wrk->tail)));	/* I D.rmtsysGnumber */
X	say("C rmail ");				/* C rmail */
X	send_file(wrk->fp);				/* send destination */
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,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	/* empty */;
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_sendwork.c
if test 4326 -ne `wc -c <sendwork.c`; then
    echo shar: \"sendwork.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f spoolfil.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"spoolfil.c\"
else
echo shar: Extracting \"spoolfil.c\" \(4020 characters\)
sed "s/^X//" >spoolfil.c <<'END_OF_spoolfil.c'
X/*++
X/* NAME
X/*	spoolfil,metafile 3
X/* SUMMARY
X/*	create message file and meta file
X/* PROJECT
X/*	pc-mail
X/* PACKAGE
X/*	general utilities
X/* SYNOPSIS
X/*	int spoolfil(mesg,meta_info,mesg_prefix,meta_prefix)
X/*	char *mesg;
X/*	char *meta_info;
X/*	char *mesg_prefix;
X/*	char *meta_prefix;
X/*
X/*	int metafile(string,path)
X/*	char *string;
X/*	char *path;
X/* DESCRIPTION
X/*	spoolfil() creates a message, meta file pair in the spool
X/*	directory. 
X/*
X/*	"mesg" should be null-terminated string with the name of an existing 
X/*	file. The contents of that file are filtered to produce a
X/*	clean ASCII file.
X/*
X/*	"meta-info" is a string with additional information that is 
X/*	written to a meta file (usually name of mail recipient, mail
X/*	originator or a comment describing the contents of the message file).
X/*
X/*	"mesg_prefix," "meta_prefix" are strings that will be used for building
X/*	names for files in the spool directory.
X/*
X/*	metafile() creates a file, writes a string to it and terminates
X/*	the file with a newline character. This function is typically used
X/*	to create a file with meta information (mail originator, message
X/*	summary etc.).
X/* FUNCTIONS AND MACROS
X/*	ascopen(), ascget(), ascclose(), newseqno()
X/* DIAGNOSTICS
X/*	A nonzero return value indicates an error condition (see status.h)
X/* SEE ALSO
X/*	status(5)	return values
X/*	ascf(3)		ASCII filter
X/* BUGS
X/*	Wordprocessor control codes etc will be lost when spoolfil copies 
X/*	a 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/*	Mon May 18 18:45:10 GMT+1:00 1987
X/* LAST MODIFICATION
X/*	Mon Apr  4 23:50:14 MET 1988
X/* VERSION/RELEASE
X/*	1.3
X/*--*/
X
X#include "defs.h"
X#include "path.h"
X#include "ascf.h"
X#include "status.h"
X
X/* metafile - create a one-liner file */
X
Xpublic int metafile(string,file)
Xchar *string;
Xchar *file;
X{
X    register FILE *fp;
X
X    if ((fp = fopen(file,"w")) == 0) {
X	return(E_WRITERR);
X    } else if (fprintf(fp,"%s\n",string),ferror(fp)) {
X	fclose(fp);
X	return(E_WRITERR);
X    } else {
X	fclose(fp);
X	return(0);
X    }
X}
X	
X/* spoolfil - make arbitrary spool file */
X
Xpublic int spoolfil(fname,meta,msgpfx,auxpfx)
Xchar *fname;
Xchar *meta;
Xchar *msgpfx;
Xchar *auxpfx;
X{
X    register int newid = newseqno();			/* new message id */
X    register int stat;					/* some status */
X    char *msgpath;					/* new message file */
X    char *auxpath;					/* new meta file */
X
X    msgpath = mesg_file(msgpfx,newid);			/* message file path */
X    auxpath = meta_file(auxpfx,newid);			/* meta file path */
X
X    /* copy disk file to spool file, check for errors */
X
X    if (stat = copyfile(fname,msgpath)) {		/* read/write error */
X	unlink(msgpath);				/* delete msg file */
X	return(stat);					/* notify caller */
X
X    /* create file for meta information, check for errors */
X
X    } else if (stat = metafile(meta,auxpath)) {		/* metafile error */
X	unlink(msgpath);				/* delete msg file */
X	unlink(auxpath);				/* delete meta file */
X	return(stat);					/* notify caller */
X
X    /* when nothing went wrong */
X
X    } else {
X	chmod(msgpath,0444);				/* message read-only */
X	chmod(auxpath,0444);				/* metafile read-only */
X	return(0);					/* own error handling */
X    }
X}
X
X/* copyfile - copy a file and filter it */
X
Xpublic int copyfile(from,to)
Xchar *from;
Xchar *to;
X{
X    register FILE *in,*out;			/* file pointers */
X    int rerr,werr;				/* error status */
X
X    if ((in = ascopen(from,"r")) == 0) {	/* cannot read ?? */
X	return(E_READERR);
X    } else if ((out = fopen(to,"w")) == 0) {	/* cannot write */
X	ascclose(in);
X	return(E_WRITERR);
X    } else {
X	register int c;
X	while ((c = ascget(in)) != EOF)		/* ASCII filter */
X	   putc(c,out);
X	rerr = ferror(in);			/* check read status */
X	werr = ferror(out);			/* check write status */
X	ascclose(in);
X	fclose(out);
X	if (rerr) {
X	    return(E_READERR);
X	} else if (werr) {
X	    return(E_WRITERR);
X	} else {
X	    return(0);
X	}
X    }
X}
END_OF_spoolfil.c
if test 4020 -ne `wc -c <spoolfil.c`; then
    echo shar: \"spoolfil.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f srctoman.sh -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"srctoman.sh\"
else
echo shar: Extracting \"srctoman.sh\" \(4444 characters\)
sed "s/^X//" >srctoman.sh <<'END_OF_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_srctoman.sh
if test 4444 -ne `wc -c <srctoman.sh`; then
    echo shar: \"srctoman.sh\" unpacked with wrong size!
fi
chmod +x srctoman.sh
# end of overwriting check
fi
if test -f switcher.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"switcher.c\"
else
echo shar: Extracting \"switcher.c\" \(4041 characters\)
sed "s/^X//" >switcher.c <<'END_OF_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/*	Wed Apr  6 00:23:14 MET 1988
X/* VERSION/RELEASE
X/*	1.4
X/*--*/
X
X#include <setjmp.h>
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
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;                 /* get here if 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	} else if (isok(wrk->rqst) == NO) {		/* check xfer allowed */
X	    log("PERMISSION (DENIED)");
X	} else {					/* adapt + send data */
X	    sendwork(wrk);
X	    log("REQUESTED (%s)",resp = hear());
X	    if (strcmp(resp,"CY"))			/* check sucessfull */
X		trap(E_REJECT,"FAILED");		/* completion */
X	    chmod(wrk->path,0666);			/* delete workfile */
X	    unlink(wrk->path);				/* only if all well */
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_switcher.c
if test 4041 -ne `wc -c <switcher.c`; then
    echo shar: \"switcher.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f unalias.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"unalias.c\"
else
echo shar: Extracting \"unalias.c\" \(4581 characters\)
sed "s/^X//" >unalias.c <<'END_OF_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/*	Wed Apr  6 20:21:35 MET 1988
X/* VERSION/RELEASE
X/*	1.0
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);		/* squeeze out identical addresses */
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
X    * words. Of course, those words can be aliases. The order in which
X    * aliases are defined is not important. The alias data base is used
X    * only after it has been loaded into memory.
X    * 
X    * Each l.h. part is used as the key for finding the r.h. part in the
X    * hash 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 (fgets(buf,BUFSIZ,fp)) {		/* read alias entry */
X	    register char **cpp;
X	    ENTRY e;
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
X    /* recursively replace aliases, but don't crash in case of cycles */
X
X    for (cpp = from; *cpp && (to < stop); cpp++) {
X	ENTRY e;
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,**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_unalias.c
if test 4581 -ne `wc -c <unalias.c`; then
    echo shar: \"unalias.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 5 \(of 8\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
uucp:	mcvax!eutrc3!wswietse	| Eindhoven University of Technology
bitnet:	wswietse@heithe5	| Dept. of Mathematics and Computer Science
surf:	tuerc5::wswietse	| Eindhoven, The Netherlands.