home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume10
/
pcmail2
/
part06
< prev
next >
Wrap
Text File
|
1990-01-24
|
65KB
|
2,275 lines
Newsgroups: comp.sources.misc
subject: v10i038: PC-MAIL release 2, 6/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 38
Submitted-by: wswietse@lso.win.tue.nl (Wietse Venema)
Archive-name: pcmail2/part06
#! /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 6 (of 11)."
# Contents: main/connect.c main/email.c main/gmail.c main/gphys.c
# main/gpres.c main/mbox.c main/nmail.c main/startup.c main/str.c
# Wrapped by wswietse@tuewsa on Mon Jan 22 17:27:18 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f main/connect.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/connect.c\"
else
echo shar: Extracting \"main/connect.c\" \(6857 characters\)
sed "s/^X//" >main/connect.c <<'END_OF_main/connect.c'
X/*++
X/* NAME
X/* connect 3
X/* SUMMARY
X/* pre- and post protocol host access
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* int connect()
X/*
X/* int disconnect()
X/* DESCRIPTION
X/* connect() tries to make a connection to the remote host
X/* and to log on, using the dial-up script and login-name
X/* entries in the communications parameter file, and the password
X/* provided as command-line parameter to the cico program.
X/* A UUCP-like send/expect script facility is used. Thus a login
X/* sequence might look like:
X/*
X/* send expect send expect ...
X/*
X/* The program will send the first "send" string, then expect the
X/* first "expect" string, and so on.
X/*
X/* Alternative expect/send sequences can be specified in the usual manner:
X/*
X/* expect-send-expect-send-expect...
X/*
X/* If the first expect string fails, the alternative send string is
X/* transmitted and the alternative expect is tried, and so on, until
X/* an expect string succeeds, or until the list of alternatives is
X/* exhausted.
X/*
X/* After the dial-up script has completed the program
X/* proceeds with the following build-in send/expect sequence:
X/*
X/* ogin: your_login_name\\r ssword: your_password\\r
X/*
X/* disconnect() tries to break a connection, using the disconnect
X/* entry in the communications parameter file. Unlike connect()
X/* this function is not driven by a send-expect script.
X/*
X/* The following escape sequences are recognized in send or expect
X/* strings:
X/*
X/* .nf
X/* \\b backspace
X/* \\r carriage return
X/* \\n newline
X/* \\t tab
X/* \\s space
X/* \\f form feed
X/* \\nnn octal character value
X/* \\\\ a real backslash
X/* .fi
X/*
X/* In addition, the following "send" strings are given special
X/* treatment:
X/*
X/* .nf
X/* BREAK send a null character
X/* EOT send Control-D
X/* FUNCTIONS AND MACROS
X/* xwrite(), xgetc(), trap(), debug(4)(), log(), split()
X/* FILES
X/* $MAILDIR/s00000 communications parameter file
X/* $MAILDIR/LOGFILE system logfile
X/* SEE ALSO
X/* params(5) communications parameter file entries
X/* DIAGNOSTICS
X/* connect() returns a status E_BADSETUP if the systems parameter
X/* file contains bad data, and E_NOLINE if the login script fails.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Fri Mar 27 17:11:12 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:01:26
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <setjmp.h>
X#include <ctype.h>
X
X#include "defs.h"
X#include "params.h"
X#include "status.h"
X#include "comm.h"
X#include "logs.h"
X#include "sysdep.h"
X
Xhidden char *blnk = " \t"; /* send/expect separators */
X
X/* forward declarations */
X
Xhidden void conn_send();
Xhidden void conn_xpct();
Xhidden char *escape();
X
X/* connect - connect to remote system; simple script processing with retries */
X
Xpublic int connect()
X{
X int *savetrap = systrap; /* save exception handler */
X jmp_buf mytrap; /* our exception handler */
X int retval; /* completion code */
X char *seq = DIAL_SEQUENCE;
X register char *cp;
X
X /* set up exception handler */
X
X if (retval = setjmp(systrap = mytrap)) { /* get here if expect fails */
X systrap = savetrap; /* it just happened */
X return (retval);
X }
X /* optional dial-up sequence */
X
X for (cp = split(&seq, blnk); cp; cp = split(&seq, blnk)) {
X conn_send(escape(cp));
X if (cp = split(&seq, blnk))
X conn_xpct(escape(cp));
X }
X
X /* mandatory login sequence; hack this for non-UNIX hosts */
X
X conn_xpct("ogin:");
X conn_send(strcons("%s\r", LOGIN_NAME));
X conn_xpct("ssword:");
X conn_send(strcons("%s\r", password));
X
X /* restore exception handler */
X
X systrap = savetrap; /* get here if expect wins */
X return (0); /* say no problems... */
X}
X
X/* disconnect - disconnect line */
X
Xpublic int disconnect()
X{
X conn_send(escape(DISC_SEQUENCE)); /* send disconnect sequence */
X return (0); /* always succeeds... */
X}
X
X/* conn_send - send BREAK, EOT or string literal */
X
Xhidden void conn_send(s)
Xregister char *s;
X{
X static char null = '\0';
X static char eot = '\04';
X
X sleep(1);
X
X if (*s) {
X debug(4) ("Sending: %S\n", s);
X if (strcmp(s, "BREAK") == 0) {
X xwrite(ttfd, &null, 1);
X } else if (strcmp(s, "EOT") == 0) {
X xwrite(ttfd, &eot, 1);
X } else {
X while (*s) {
X delay();
X xwrite(ttfd, s++, 1);
X }
X }
X }
X}
X
X/* conn_xpct - pattern matching without meta characters */
X
Xhidden void conn_xpct(s)
Xchar *s;
X{
X int c;
X int i;
X int n;
X char *xp;
X char *sp;
X
X /*
X * Keep listening until we time out or until we receive the expected
X * string (thus, if the other end keeps sending garbage we will never
X * terminate). Make sure that we do not overrun our buffer. Parity bits
X * are ignored. If we do not succeed, try alternative sequences if they
X * are specified.
X */
X
X for (xp = split(&s, "-"); xp; xp = split(&s, "-")) {
X
X debug(4) ("Expecting: %S\nReceiving: ", xp);
X
X if (((n = strlen(xp)) > MSGBUF))
X n = MSGBUF;
X for (i = 0; (c = xgetc()) != EOF; /* void */ ) {
X msgin[i++] = (c &= 0177);
X debug(4) ("%C", c);
X if (i >= n && strncmp(xp, &msgin[i - n], n) == 0) {
X debug(4) (" ok!\n");
X return;
X } else if (i >= MSGBUF) {
X strncpy(msgin, &msgin[i - (n - 1)], n - 1);
X i = n - 1;
X }
X }
X debug(4) (" failed!\n");
X
X /* try alternative sequence, if specified, else fail */
X
X if (sp = split(&s, "-")) {
X conn_send(sp);
X } else {
X trap(E_NOLINE, "LOGIN FAILED (at \"%S\")", xp);
X }
X }
X}
X
X/* escape - interpret backslash sequences */
X
Xhidden char *escape(s)
Xregister char *s;
X{
X static char buf[BUFSIZ];
X register char *cp = buf;
X register char ch;
X int c;
X int i;
X
X while (*s && cp < buf + sizeof(buf) - 1) { /* don't overflow the buffer */
X
X if (*s != '\\') { /* ordinary character */
X *cp++ = *s++;
X } else if (isdigit(*++s) && *s < '8') { /* \nnn octal code */
X sscanf(s, "%3o", &c);
X *cp++ = c;
X i = 1;
X s++;
X while (i++ < 3 && isdigit(*s) && *s < '8')
X s++;
X } else if ((ch = *s++) == 0) { /* at string terminator */
X break;
X } else if (ch == 'b') { /* \b becomes backspace */
X *cp++ = '\b';
X } else if (ch == 'f') { /* \f becomes formfeed */
X *cp++ = '\f';
X } else if (ch == 'n') { /* \n becomes newline */
X *cp++ = '\n';
X } else if (ch == 'r') { /* \r becomes carriage ret */
X *cp++ = '\r';
X } else if (ch == 's') { /* \s becomes blank */
X *cp++ = ' ';
X } else if (ch == 't') { /* \t becomes tab */
X *cp++ = '\t';
X } else { /* \any becomes any */
X *cp++ = ch;
X }
X }
X *cp = '\0'; /* terminate the result */
X return (buf);
X}
END_OF_main/connect.c
if test 6857 -ne `wc -c <main/connect.c`; then
echo shar: \"main/connect.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/email.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/email.c\"
else
echo shar: Extracting \"main/email.c\" \(6160 characters\)
sed "s/^X//" >main/email.c <<'END_OF_main/email.c'
X/*++
X/* NAME
X/* email 3
X/* SUMMARY
X/* manipulate one message in preparation
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mail
X/* SYNOPSIS
X/* #include "mail.h"
X/*
X/* int work()
X/*
X/* int work_disp(def_addr)
X/* char *def_addr;
X/* DESCRIPTION
X/* The functions in this module are responsible for manipulations
X/* on mail messages in preparation.
X/*
X/* work() should be invoked when the user has selected an existing
X/* message in preparation. It does some initializations and invokes
X/* the work_disp() function.
X/*
X/* work_disp() allows the user to specify the disposition of a
X/* mail message in preparation. It should be used after the user has
X/* created a message, or after the user has selected a message in
X/* preparation.
X/*
X/* The message file is displayed on the screen and user the
X/* can choose to print, mail, edit or delete etc. the message.
X/*
X/* The def_addr argument contains a default mail destination: for example,
X/* an address extracted from a message being replied to. It should be an
X/* e-mail address or an empty string.
X/*
X/* The code in this module is a little tricky, to avoid "orphan" work
X/* files (message file without a metafile).
X/* COMMANDS
X/* The program specified in the EDITOR environment variable,
X/* or a system-dependent default.
X/* FILES
X/* mail.msg, file being edited in the current directory
X/* $MAILDIR/ennnnn, message file (body)
X/* $MAILDIR/cnnnnn, meta file (summary)
X/* $MAILDIR/header, template mail header file
X/* $MAILDIR/trailer, template signature file
X/* SEE ALSO
X/* pager(3), pager(5), kbdinp(3), edit(3)
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Tue May 12 15:35:20 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:01:35
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include <errno.h>
X#include "defs.h"
X#include "path.h"
X#include "pager.h"
X#include "screen.h"
X#include "mail.h"
X#include "status.h"
X
X/* forward declarations */
X
Xhidden void junk_work();
Xhidden int edit_work();
Xhidden int show_work();
Xhidden int hold_work();
Xhidden int send_work();
Xhidden int queue_work();
X
Xpublic char address[MAXLINE]; /* default destination */
Xhidden File *workfile = 0; /* pager file */
X
X/* work - user selected message in preparation */
X
Xpublic int work()
X{
X return (work_disp(""));
X}
X
X/* work_disp - ask disposition of a message in preparation */
X
Xpublic int work_disp(def_addr)
Xchar *def_addr;
X{
X static Screen screen[] = {
X 'C', "Close",hold_work,"Send message later, return to message-selection menu",
X#ifdef ATTACH
X 'A', "Attach",attach", "Attach file to message",
X#endif
X 'D', "Delete",delete, delcurr,
X 'E', "Edit", edit_work,"Edit this message",
X 'M', "Mail", send_work,"Send this message to destination",
X 'P', "Print",print, printcurr,
X PGUP, PgUp, pu_pager, pageup,
X PGDN, PgDn, pd_pager, pagedn,
X UP, "Up", up_pager, csrup,
X DOWN, "Down", dn_pager, csrdn,
X 0, 0, show_work,
X "(Reading a message in preparation)",
X };
X struct stat s;
X
X strcpy(address, def_addr); /* set up default address */
X kbdinp(screen); /* ask disposition */
X junk_work(); /* destroy mail pager file */
X return (S_REDRAW); /* say screen was changed */
X}
X
X/* show_work - show message in preparation or error message in middle window */
X
Xhidden int show_work()
X{
X if (workfile) { /* check pager file exists */
X set_pager(workfile); /* select existing display */
X } else if (rd_pager(workfile = open_pager(), message)) {
X mesg_pager(workfile, m_msgread); /* cannot display message */
X }
X ds_pager(); /* (re)draw display */
X return (0); /* screen is up-to-date */
X}
X
X/* junk_work - destroy message in preparation display */
X
Xhidden void junk_work()
X{
X if (workfile) { /* no-op if no display */
X close_pager(workfile); /* release memory */
X workfile = 0; /* say it is gone */
X }
X}
X
X/* edit_work - edit a message in preparation */
X
Xhidden int edit_work()
X{
X register int stat;
X
X if (stat = edit(message, MAILFILE)) /* try to edit the message */
X errdisp(stat); /* edit() had a problem */
X junk_work(); /* force new message display */
X return (S_REDRAW); /* say screen has changed */
X}
X
Xhidden int label_work();
X
X/* hold_work - stop editing but do not yet mail a message in preparation */
X
Xhidden int hold_work()
X{
X static Screen screen[] = {
X STRING, 0, label_work, int_error,
X 0, 0, 0,
X getsummary,
X };
X struct stat s;
X
X /*
X * The user does not yet want to send the message off. The purpose of the
X * following code is to ask for a one-line summary, but only if such a
X * comment does not yet exist. The summary is used to identify the
X * message in preparation in the message- selection display.
X */
X
X if (stat(message, &s) || !stat(comment, &s)) {
X return (S_BREAK); /* we are done here */
X } else {
X return (kbdinp(screen) | S_REDRAW); /* ask for a summary */
X }
X}
X
X/* label_work - save summary line to meta file */
X
Xhidden label_work(string)
Xchar *string;
X{
X register int stat;
X
X if (stat = metafile(comment, string, (char *) 0)) {
X errdisp(stat); /* oops, notify the user */
X return (S_REDRAW); /* say screen has changed */
X } else {
X chmod(comment, 0444); /* make comments read-only */
X junk_desk(); /* say mail box has changed */
X return (S_BREAK); /* say no more work */
X }
X}
X
X/* send_work - user wants to send message in preparation, ask for destination */
X
Xhidden int send_work()
X{
X static Screen screen[] = {
X EDIT, 0, queue_work, address,
X 0, 0, when,
X "Press ESC to cancel. Send message to:",
X };
X
X return (kbdinp(screen) | S_REDRAW);
X}
X
X/* queue_work - spool mail, delete message in preparation and meta file */
X
Xhidden int queue_work(to)
Xchar *to;
X{
X register int stat;
X
X if (stat = submit(message, to)) {
X errdisp(stat); /* cannot queue message */
X return (S_REDRAW); /* say screen has changed */
X } else {
X return (unspool() | S_BREAK); /* remove work and meta file */
X }
X}
END_OF_main/email.c
if test 6160 -ne `wc -c <main/email.c`; then
echo shar: \"main/email.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/gmail.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/gmail.c\"
else
echo shar: Extracting \"main/gmail.c\" \(6153 characters\)
sed "s/^X//" >main/gmail.c <<'END_OF_main/gmail.c'
X/*++
X/* NAME
X/* gmail 1
X/* SUMMARY
X/* deliver unsent mail via gnuucp
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* gnu
X/* SYNOPSIS
X/* gmail [-d debuglevel]
X/* DESCRIPTION
X/* This program replaces the sending function of the pc-mail "cico"
X/* program, on systems that use GNUUCP for message transport.
X/*
X/* gmail searches the pc-mail message data base for unsent mail
X/* (with the "Out" status) and queues it for transmission via GNUUCP.
X/* When a message has been queued it is renamed to reflect
X/* the "Sent" status.
X/*
X/* This program is intended to be called via the MAILCMD environment
X/* variable, so that it is invoked upon exit from the mail user
X/* interface program.
X/*
X/* In order to avoid corruption of the message data base, control-c
X/* interrupts are disabled while this program executes.
X/* ENVIRONMENT
X/* MAILDIR, path to pc-mail message data base
X/* COMMANDS
X/* rmail, the gnuucp mailer
X/* FILES
X/* In the spool directory:
X/* d<seqno> unsent mail, message body
X/* x<seqno> unsent mail, destination and subject
X/* q<seqno> sent mail, message body
X/* r<seqno> sent mail, destination and subject
X/* SEE ALSO
X/* path(5) spool directory, file name formats
X/* DIAGNOSTICS
X/* Problems are reported on the standard error output, and cause the
X/* program to terminate with a nonzero exit status.
X/* BUGS
X/* It is left up to GNUUCP to determine what to do with undeliverable mail.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Wed Jan 3 22:16:28 MET 1990
X/* LAST MODIFICATION
X/* 90/01/22 13:01:40
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <signal.h>
X#include <time.h>
X#include <varargs.h>
X
X#include "defs.h"
X#include "ndir.h"
X#include "path.h"
X
X#ifndef RMAIL
X#define RMAIL "rmail"
X#endif
X
X/* Forward declarations */
X
Xhidden char *get_dest();
Xhidden int uuqueue();
Xhidden void error();
Xhidden void frename();
Xhidden void parse_args();
Xhidden void scanmail();
Xhidden void usage();
X
X#define debug if (dflag) (void) printf
X
Xhidden int dflag = 0; /* debugging option */
X
Xpublic char *progname = "gmail"; /* for diagnostics */
X
X/* .. */
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X (void) signal(SIGINT, SIG_IGN); /* disable ctrl-c */
X if (pathinit()) /* get path info */
X error("no mail directory or MAILDIR environment variable not set");
X parse_args(argc, argv); /* parse command args */
X scanmail(); /* search for unsent mail */
X exit(0);
X /* NOTREACHED */
X}
X
X/* parse_args - process command-line arguments */
X
Xhidden void parse_args(argc, argv)
Xint argc;
Xchar **argv;
X{
X while (--argc && *++argv && **argv == '-') {/* process options */
X switch (*++*argv) {
X case 'd': /* turn debugging on */
X dflag++;
X break;
X default: /* unknown option */
X usage("invalid option: -%c", **argv);
X break;
X }
X }
X
X /* check for extraneous arguments */
X
X if (argc > 0)
X usage("unexpected argument: %s", *argv);
X}
X
X/* scan for unsent mail */
X
Xhidden void scanmail()
X{
X unsigned msgno; /* message sequence number */
X register DIR *dp;
X struct direct *de;
X char *dest;
X
X debug("directory: \"%s\"\n", maildir);
X
X /*
X * Scan the spool directory for unsent mail. After the message has been
X * piped through rmail, rename it to reflect the "Sent" status. Do not give
X * up if a file cannot be opened; just proceed with the next message.
X */
X
X if ((dp = opendir(maildir)) == 0)
X error("cannot read the mail directory: %s", maildir);
X
X while (de = readdir(dp)) {
X debug("file: \"%s\"\n", de->d_name);
X if (de->d_name[0] == OUT_META && (msgno = seqno(de->d_name))
X && (dest = get_dest(msgno)) && uuqueue(msgno, dest)) {
X frename(out_mesg(msgno), sent_mesg(msgno));
X frename(out_meta(msgno), sent_meta(msgno));
X }
X }
X closedir(dp);
X}
X
X/* uuqueue - queue one message */
X
Xhidden int uuqueue(msgno, dest)
Xunsigned msgno;
Xchar *dest;
X{
X char cmd[BUFSIZ];
X char *path;
X char *rcpt;
X static char sep[] = " \t\r\n";
X
X if (access(path = out_mesg(msgno), 04)) {
X debug("%s: cannot read message file: %s\n", path, sys_errlist[errno]);
X return (0);
X } else {
X
X /*
X * The GNUUCP rmail program has to invoked for each recipient. rmail
X * will have to deal with undeliverable mail anyway, so we ignore
X * that class of errors.
X */
X
X for (rcpt = strtok(dest, sep); rcpt; rcpt = strtok((char *) 0, sep)) {
X (void) sprintf(cmd, "%s %s <%s", RMAIL, rcpt, path);
X debug("command: %s\n", cmd);
X if (system(cmd) == 127)
X error("could not invoke the shell");
X }
X return (1);
X }
X}
X
X/* get_dest - extract recipients */
X
Xhidden char *get_dest(msgno)
Xunsigned msgno;
X{
X static char buf[MAXLINE];
X FILE *fp;
X char *ret;
X char *path;
X
X if ((fp = fopen(path = out_meta(msgno), "r")) == 0) {
X debug("%s: cannot open: %s\n", path, sys_errlist[errno]);
X return (0);
X } else {
X if ((ret = fgets(buf, sizeof(buf), fp)) == 0)
X debug("%s: no recipients found\n", path);
X (void) fclose(fp);
X return (ret);
X }
X}
X
X/* frename - forcibly change the name of a file */
X
Xhidden void frename(from, to)
Xchar *from;
Xchar *to;
X{
X debug("rename: %s -> %s\n", from, to);
X
X if (chmod(to, 0600) == 0)
X (void) unlink(to);
X if (rename(from, to))
X error("cannot rename %s to %s: %s", from, to, sys_errlist[errno]);
X}
X
X/* error - complain */
X
X/* VARARGS */
X
Xhidden void error(va_alist)
Xva_dcl
X{
X va_list ap;
X char *fmt;
X
X (void) fprintf(stderr, "%s: ", progname);
X va_start(ap);
X fmt = va_arg(ap, char *);
X (void) vfprintf(stderr, fmt, ap);
X va_end(ap);
X (void) putc('\n', stderr);
X exit(2);
X}
X
X/* usage - explain what is wrong */
X
X/* VARARGS */
X
Xhidden void usage(va_alist)
Xva_dcl
X{
X va_list ap;
X char *fmt;
X
X (void) fprintf(stderr, "%s: ", progname);
X va_start(ap);
X fmt = va_arg(ap, char *);
X (void) vfprintf(stderr, fmt, ap);
X va_end(ap);
X (void) fprintf(stderr, "\nusage: gmail [-d]\n");
X exit(2);
X}
END_OF_main/gmail.c
if test 6153 -ne `wc -c <main/gmail.c`; then
echo shar: \"main/gmail.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/gphys.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/gphys.c\"
else
echo shar: Extracting \"main/gphys.c\" \(6844 characters\)
sed "s/^X//" >main/gphys.c <<'END_OF_main/gphys.c'
X/*++
X/* NAME
X/* gphys 3
X/* SUMMARY
X/* g protocol packet input/output
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* #include "gp.h"
X/*
X/* void gsctrl(fd,c)
X/* int fd,c;
X/*
X/* void gsdata(fd,pk,c)
X/* int fd,c;
X/* Packet *pk;
X/*
X/* int grpack(fd,pk)
X/* int fd;
X/* Packet *pk;
X/* DESCRIPTION
X/* The functions in this module send and receive packets. Interfacing
X/* is based on Packet structures. Messages are interpreted elsewhere.
X/*
X/* gsctrl() sends a control packet to the remote receiver (no data
X/* segment).
X/*
X/* gsdata() sends a data packet to the remote receiver.
X/* The Packet structure is completed with a 16-bit checksum.
X/* This function expects read/write sequence information in
X/* the c parameter.
X/*
X/* grpack() receives a packet from the remote transmitter and checks
X/* its integrity. It fills in the k, c, len and check fields of the
X/* Packet structure and returns the type of message (DATA, SHORT,
X/* CLOSE, RJ, RR, etcetera).
X/* DIAGNOSTICS
X/* grpack() returns FAIL if a corrupted packet was received, and
X/* TIME if no packet was received within the time-out interval.
X/* BUGS
X/* No data re-reading in case of transmission errors.
X/* Some parts of the code rely on 8-bit bytes, 16-bit short integers.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Sun Apr 19 11:39:27 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:01:42
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <signal.h>
X#include <setjmp.h>
X#include "gp.h"
X
X/* local and forward declarations */
X
Xstatic jmp_buf timebuf;
Xstatic int chksum(),readhead(),readdata(),clkint();
X
X#define READ(fd,cp,n) { if (read(fd,cp,n) != n) clkint(); }
X
X/*
X* "A six byte framing envelope is constructed using the control"
X* "byte C of a packet and five other bytes as depicted below."
X* <DLE><k><c0><c1><C><x>
X* "The <DLE> symbol denotes the ASCII ctrl/P character. If the"
X* "envelope is to be followed by a data segment, <k> has the"
X* "value log2(size)-4; i.e. 1 <= k < 8. If k is 9, then the"
X* "envelope represents a control packet. The <c0> and <c1>"
X* "bytes are the low-order and high-order bytes respectively of"
X* "0xAAA minus a 16-bit checksum. For control packets, this"
X* "16-bit checksum is the same as the control byte C. For data"
X* "packets, the checksum is calculated by the program below."
X* "The <x> byte is the exclusive-or of <k><c0><c1><C>. Error"
X* "control is accomplished by checking a received framing"
X* "envelope for compliance with the definition, and comparing a"
X* "checksum function of the data segment with <c0><c1>."
X*/
X
X/* gsctrl - send control packet (no data segment) */
X
Xvoid gsctrl(fd,c)
Xint fd,c;
X{
X char header[6];
X register char chkhdr;
X register char *cp = header;
X int cksm = MAGIC-c; /* do checksum */
X
X *cp++ = CTRL('P'); /* start of header */
X chkhdr = *cp++ = KCTRL; /* k byte (control) */
X chkhdr ^= *cp++ = cksm; /* c0 byte (checksum lsb) */
X chkhdr ^= *cp++ = cksm>>8; /* c1 byte (checksum msb) */
X chkhdr ^= *cp++ = c; /* message|sequence info */
X *cp = chkhdr; /* header checksum */
X
X write(fd,header,sizeof(header)); /* send header */
X DEBUG(9,"xmt: %o\n",c&0377); /* show header */
X}
X
X/* gsdata - send data packet */
X
Xvoid gsdata(fd,pk,c)
Xint fd,c;
Xregister Packet *pk;
X{
X char header[6];
X register char chkhdr;
X register char *cp = header;
X int cval = pk->c|(c&077); /* fold in sequence info */
X
X pk->chk = MAGIC-(chksum(pk->data,pk->len)^(0377&cval));
X
X *cp++ = CTRL('P'); /* start of header */
X chkhdr = *cp++ = pk->k; /* k byte (message length) */
X chkhdr ^= *cp++ = pk->chk; /* c0 byte (checksum lsb) */
X chkhdr ^= *cp++ = pk->chk>>8; /* c1 byte (checksum msb) */
X chkhdr ^= *cp++ = cval; /* data|sequence info */
X *cp = chkhdr; /* header checksum */
X
X write(fd,header,sizeof(header)); /* send header */
X DEBUG(9,"xmt: %o\n",cval&0377); /* show header */
X
X write(fd,pk->data,pk->len); /* send data segment */
X DEBUG(9,"xmt: data %d bytes\n",pk->segl); /* show data */
X}
X
X/* grpack - receive one data or control packet; return packet type info */
X
Xint grpack(fd,pk)
Xint fd;
Xregister Packet *pk;
X{
X if (setjmp(timebuf)) /* in case we time out */
X return(TIME); /* it just happened */
X signal(SIGALRM,clkint); /* alarm clock response */
X alarm(ALARM); /* set alarm clock */
X
X if (readhead(fd,pk)) { /* read packet header */
X DEBUG(7,"rcv: bad header\n","");
X alarm(0); /* turn timer off */
X return(FAIL); /* header checksum error */
X } else if (pk->k == KCTRL) {
X alarm(0); /* turn timer off */
X return(MESG(pk->c)); /* CLOSE | RJ | RR etcetera */
X } else if (readdata(fd,pk)) {
X DEBUG(7,"rcv: bad data\n","");
X alarm(0); /* turn timer off */
X return(FAIL); /* data checksum error */
X } else {
X alarm(0); /* turn timer off */
X return(TYPE(pk->c)); /* DATA | SHORT */
X }
X}
X
X/* readhead - read header and check header checksum */
X
Xstatic int readhead(fd,pk)
Xint fd;
Xregister Packet *pk;
X{
X char header[5];
X int ok;
X register char chkhdr;
X register char *cp = header;
X
X do { /* start reading */
X READ(fd,cp,1); /* skip all garbage */
X } while (*cp != CTRL('P')); /* up to packet header */
X
X READ(fd,header,sizeof(header)); /* read packet header */
X
X chkhdr = pk->k = *cp++; /* data length or control */
X chkhdr ^= pk->chk = *cp++&0377; /* data checksum lsb */
X chkhdr ^= *cp;
X pk->chk |= (*cp++&0377)<<8; /* data checksum msb */
X chkhdr ^= pk->c = *cp++; /* control packet or data */
X if (ok = (chkhdr == *cp))
X DEBUG(9,"rcv: %o\n",pk->c&0377);
X return(!ok); /* check the checksum */
X}
X
X/* readdata - read data segment and check data checksum */
X
Xstatic int readdata(fd,pk)
Xint fd;
Xregister Packet *pk;
X{
X if (seglen[pk->k] > pk->len) {
X DEBUG(7,"rcv: data %d bytes too big\n",seglen[pk->k]);
X return(1);
X } else {
X register int i;
X DEBUG(9,"rcv: data %d bytes\n",pk->len = seglen[pk->k]);
X for (i = 0; i < pk->len; i++) {
X READ(fd,&pk->data[i],1);
X }
X return(pk->chk+(chksum(pk->data,pk->len)^(pk->c&0377)) != MAGIC);
X }
X}
X
X/* clkint - tiny time-out routine */
X
Xstatic int clkint()
X{
X DEBUG(9,"rcv: timed out\n","");
X longjmp(timebuf,1);
X /* NOTREACHED */
X}
X
X/* chksum - unix packet driver checksum algorithm */
X
Xstatic int chksum(s,n)
Xregister char *s;
Xregister n;
X{
X register short sum;
X register unsigned short t;
X register short x;
X
X sum = -1;
X x = 0;
X do {
X if (sum < 0) {
X sum <<= 1;
X sum++;
X } else
X sum <<= 1;
X t = sum;
X sum += (unsigned)*s++ & 0377;
X x += sum ^ n;
X if ((unsigned short)sum <= t) {
X sum ^= x;
X }
X } while (--n > 0);
X
X return(sum);
X}
END_OF_main/gphys.c
if test 6844 -ne `wc -c <main/gphys.c`; then
echo shar: \"main/gphys.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/gpres.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/gpres.c\"
else
echo shar: Extracting \"main/gpres.c\" \(6380 characters\)
sed "s/^X//" >main/gpres.c <<'END_OF_main/gpres.c'
X/*++
X/* NAME
X/* gpres.c 3
X/* SUMMARY
X/* g-protocol general interface
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* int gopen(fd);
X/* int fd;
X/*
X/* int gwrite(fd,buf,len)
X/* int fd,len;
X/* char *buf;
X/*
X/* int gread(fd,buf,len)
X/* int fd,len;
X/* char *buf;
X/*
X/* int gclose(fd)
X/* int fd;
X/* DESCRIPTION
X/* The functions in this module present an interface that closely
X/* resembles the unix kernel i/o interface.
X/*
X/* gopen() handles the initial message exchange. fd should be
X/* connected to a tty line. gopen() normally returns a zero value.
X/*
X/* gwrite() returns the number of bytes `written' to the remote system.
X/* It should be considered an error if this is not equal to the number
X/* of bytes requested.
X/* A zero-length write should be used to indicate EOF during file transfer.
X/*
X/* gread() returns the requested number of bytes or the number of
X/* bytes sent by the remote system, whichever is smaller.
X/* A zero-length read indicates EOF during file transfer.
X/*
X/* gclose() shuts the protocol down, but does not otherwise change
X/* communications line parameters. It normally returns a zero value.
X/* FUNCTIONS AND MACROS
X/* galloc(), gfree(), gsproto(), grproto()
X/* DIAGNOSTICS
X/* All functions return -1 in case of unrecoverable problems.
X/* BUGS
X/* All g protocol routines assume that the XON/XOFF flow control
X/* has been turned off.
X/* Some parts of the code rely on 8-bit bytes, 16-bit short integers.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Sun Apr 19 12:41:37 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:01:43
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <setjmp.h>
X#include "gp.h"
X
X/* local and forward declarations */
X
Xstatic jmp_buf failbuf;
Xstatic void gpeek(),gpoke(),memcpy();
X
X/* gfail - exception handling */
X
Xvoid gfail()
X{
X longjmp(failbuf,1);
X}
X
X/* gopen - not quite an analogon of unix open(2) */
X
Xint gopen(fd)
Xint fd;
X{
X return(ginit(fd)); /* do packet stuff elsewhere */
X}
X
X/* gwrite - g-protocol analogon of unix write(2) */
X
Xgwrite(fd,data,len)
Xint fd,len;
Xchar *data;
X{
X /* set up exception handling */
X
X if (setjmp(failbuf)) /* in case gsproto fails */
X return(FAIL); /* it just did */
X
X /* handle special case of zero-length writes separately */
X
X if (len <= 0) { /* end-of-file message */
X register Packet *pk = galloc(); /* allocate output packet */
X gpoke(pk,data,len); /* make null-data packet */
X gsproto(fd,pk); /* send to other side */
X } else { /* true data message */
X register int shot; /* quantum size */
X register int rest; /* amount left to do */
X for (rest = len; rest > 0; rest -= shot,data += shot) {
X register Packet *pk = galloc(); /* allocate output packet */
X gpoke(pk,data,shot = MIN(pk->len,rest));/* fill the packet */
X gsproto(fd,pk);
X }
X }
X return(len); /* no problems detected */
X}
X
X/* gread - g-protocol analogon of unix read(2) */
X
Xgread(fd,data,len)
Xint fd,len;
Xchar *data;
X{
X static Packet *pk; /* our byte stock */
X register int igot; /* our return value */
X
X /* set up exception handling */
X
X if (setjmp(failbuf)) /* in case grproto fails */
X return(FAIL); /* it just did */
X
X /* if no bytes in stock, get some fresh ones and see how much we got */
X
X if (pk == 0 || pk->segl <= 0) /* we are out of data */
X gpeek(pk = grproto(fd)); /* get fresh packet */
X
X /* return as many bytes as asked, or as in stock, whichever is less */
X
X if ((igot = MIN(len,pk->segl)) > 0) {
X memcpy(data,pk->segp,igot); /* copy to caller's buffer */
X pk->segp += igot; /* update stock pointer */
X pk->segl -= igot; /* update stock count */
X }
X if (pk->segl <= 0) /* if we exhausted the stock */
X gfree(pk); /* release packet */
X return(igot); /* no problems detected */
X}
X
X/* gclose - turn g protocol off */
X
Xgclose(fd)
Xint fd;
X{
X return(gfinit(fd)); /* not here! */
X}
X
X/*
X* "Each transmitter is constrained to observe the maximum data segment"
X* "size established during initial synchronization by the receiver that"
X* "it sends to. (...) `short' packets have zero or more data bytes but less"
X* "than the maximum. The first one or two bytes of the data segment of"
X* "a short packet are `count' bytes that indicate the difference between"
X* "the maximum size and the number of bytes in the short segment. If the"
X* "difference is less than 127, one count byte is used. If the difference"
X* "exceeds 127, then the low-order seven bits of the difference are put"
X* "in the first data byte and the remaining high-order bit is set as an"
X* "indication that the remaining bits of the difference are in the second"
X* "byte.
X*/
X
X/* gpoke - prepare packet for transmission */
X
Xstatic void gpoke(pk,data,len)
Xregister Packet *pk;
Xint len;
Xchar *data;
X{
X register int diff = pk->len-len; /* packet/data size mismatch */
X
X pk->segp = pk->data; /* set up write pointer */
X pk->segl = len; /* actual segment length */
X if (diff < 0 || len < 0) {
X DEBUG(7,"gpoke: trouble\n",""); /* something very wrong */
X gfail();
X /* NOTREACHED */
X } else if (diff == 0) {
X pk->c = DATA; /* long data segment */
X } else if (diff <= 127) {
X pk->c = SHORT; /* short data segment */
X *pk->segp++ = diff; /* one difference byte */
X } else if (diff > 127) {
X pk->c = SHORT; /* tiny data segment */
X *pk->segp++ = diff|0200; /* two difference bytes */
X *pk->segp++ = diff>>7;
X }
X memcpy(pk->segp,data,pk->segl); /* copy data into packet */
X}
X
X/* gpeek - prepare newly packet for reading */
X
Xstatic void gpeek(pk)
Xregister Packet *pk;
X{
X register int diff;
X
X pk->segp = pk->data; /* set up read pointer */
X if (TYPE(pk->c) == DATA) {
X diff = 0; /* long data segment */
X } else if (TYPE(pk->c) != SHORT) {
X DEBUG(7,"gread: trouble\n",""); /* something funny */
X gfail();
X /* NOTREACHED */
X } else if ((diff = *pk->segp++&0377)&0200) {/* short data segment */
X diff = (diff&0177)|((*pk->segp++&0377)<<7);
X }
X pk->segl = pk->len-diff; /* actual segment size */
X DEBUG(9,"rcv: data %d bytes\n",pk->segl);
X}
X
X/* memcpy - not-so-efficient implementation */
X
Xstatic void memcpy(dst,src,len)
Xregister char *dst,*src;
Xregister int len;
X{
X while (len-- > 0)
X *dst++ = *src++;
X}
END_OF_main/gpres.c
if test 6380 -ne `wc -c <main/gpres.c`; then
echo shar: \"main/gpres.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/mbox.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/mbox.c\"
else
echo shar: Extracting \"main/mbox.c\" \(6112 characters\)
sed "s/^X//" >main/mbox.c <<'END_OF_main/mbox.c'
X/*++
X/* NAME
X/* mbox 3
X/* SUMMARY
X/* display and manipulate one non-work message
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* mail
X/* SYNOPSIS
X/* int mbox(meta,msgid)
X/* int meta;
X/* unsigned msgid;
X/* DESCRIPTION
X/* mbox() is invoked when the user has selected a non-work mail message.
X/* It instructs the pager to display the selected mail message.
X/* The user has the usual options for manipulating the message
X/* being displayed.
X/*
X/* The meta parameter indicates the message type,
X/* and msgid is the numerical message id. If the message file is being
X/* read for the first time (meta == NEW_META), it will be marked as read
X/* by renaming the meta file.
X/*
X/* Message header lines can be suppressed selectively (see setup).
X/* FILES
X/* $MAILDIR/?nnnnn, message and meta files
X/* SEE ALSO
X/* pager(3), pager(5), kbdinp(3)
X/* DIAGNOSTICS
X/* If a selected mail message could not be found an error message
X/* is displayed instead.
X/* 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:01:12 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:11
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#include "defs.h"
X#include "path.h"
X#include "pager.h"
X#include "screen.h"
X#include "mail.h"
X#include "ascf.h"
X#include "params.h"
X#include "ms_parse.h"
X
X /*
X * Storage for header lines to be ignored. Both the strings with header
X * names, and the pointers to these strings, are kept together.
X */
X
Xstruct ignore {
X char strs[BUFSIZ]; /* null-terminated strings */
X char *ptrs[BUFSIZ / 2]; /* null-terminated list of pointers */
X};
X
Xhidden void ign_init(); /* forward declarations */
Xhidden int ign_header();
Xhidden int mbox_filter();
X
Xhidden File *letter = 0; /* pager file */
X
X/* show_letter - display selected mail message */
X
Xhidden int show_letter()
X{
X set_pager(letter); /* select message display */
X ds_pager(); /* put it on the screen */
X return (0); /* say screen is ok */
X}
X
X/* mbox - user has selected a message file */
X
Xpublic int mbox(meta, id)
Xint meta;
Xunsigned id;
X{
X static Screen screen[] = {
X 'C', "Close",0, initscreen,
X 'D', "Delete",delete, delcurr,
X 'M', "Mail", mailfile, "Mail a copy of this message",
X 'P', "Print",print, printcurr,
X 'R', "Reply",reply, "Create reply to sender",
X 'S', "Save", save, "Save this message to ordinary file",
X 'W', "Work", makework, "Save this message to work file",
X '|', "|", filter, "Filter this message through command",
X PGUP, PgUp, pu_pager, pageup,
X PGDN, PgDn, pd_pager, pagedn,
X UP, "Up", up_pager, csrup,
X DOWN, "Down", dn_pager, csrdn,
X 0, 0, show_letter, "(Reading a mail message)",
X };
X char *seen;
X
X /*
X * Mail being read for the first time is renamed to reflect the
X * status change.
X */
X
X if (mbox_filter(letter = open_pager(), message)) {
X mesg_pager(letter, m_msgread); /* no file or read error */
X } else if (meta != NEW_META) { /* unread message? */
X /* void */ ; /* no */
X } else if (rename(comment, seen = old_meta(id)) == 0) {
X strcpy(comment, seen); /* mark message as read */
X junk_desk(); /* say desk-top outdated */
X }
X kbdinp(screen); /* look at the screen */
X close_pager(letter), letter = 0; /* destroy the display */
X return (S_REDRAW); /* force screen redrawing */
X}
X
X/* mbox_filter - suppress some message-header lines */
X
Xhidden int mbox_filter(pp, path)
XFile *pp;
Xchar *path;
X{
X#if (defined(lint) && defined(iAPX286))
X static
X#endif
X struct ignore ignore;
X FILE *fp;
X
X if ((fp = ascopen(path, "r")) == 0) {
X return (1);
X } else {
X char buf[BUFSIZ];
X int ig_flag = 0;
X int ret;
X int context = MS_UUCP;
X
X ign_init(&ignore); /* initialize filter */
X
X /*
X * The header-line suppression algorithm is effective for RFC822-like
X * headers lines only. Its main use is to get rid of the "Received:"
X * lines that frequently show up in non-local mail.
X */
X
X while (ascgets(buf, sizeof(buf), fp)) {
X switch (context = ms_parse(context, buf)) {
X case MS_UUCP:
X app_pager(pp, buf);
X break;
X case MS_HEADER:
X if ((ig_flag = (ign_header(buf, &ignore))) == 0)
X app_pager(pp, buf);
X break;
X case MS_CONT:
X if (ig_flag == 0)
X app_pager(pp, buf);
X break;
X case MS_BODY:
X app_pager(pp, buf);
X break;
X }
X }
X ret = ferror(fp);
X ascclose(fp);
X return (ret);
X }
X}
X
X/* ign_init - setup header lines to be ignored */
X
Xhidden void ign_init(ig)
Xstruct ignore *ig;
X{
X Info *ip = getparams() + P_IGNORE;/* what to ignore */
X char *sp = ":, "; /* string separators */
X char **lp = ig->ptrs; /* separated strings */
X
X /*
X * This function takes, from the pc-mail setup file, a (blank or
X * comma)-separated list with names of mail headers to be ignored when a
X * message is displayed. The list of names is broken up into separate
X * strings. The result, a null-terminated list of string pointers, is
X * stored in the ig argument. We use strtok() for string splitting. Since
X * that function destroys its input, and since the user may change the
X * setup at any time, we keep in the ig argument a copy of the relevant
X * setup information.
X */
X
X if (ip->strval == 0) { /* nothing to ignore */
X *lp = 0;
X } else { /* copy, then split */
X (void) strncpy(ig->strs, ip->strval, sizeof(ig->strs));
X for (*lp = strtok(ig->strs, sp); *lp; *lp = strtok((char *) 0, sp))
X lp++;
X }
X}
X
X/* ign_header - do we ignore this header line */
X
Xhidden int ign_header(buf, ig)
Xregister char *buf;
Xstruct ignore *ig;
X{
X register int l; /* header name length */
X register char **list; /* ptr to ignored header names */
X
X /* Make sure that the header name is followed by a colon */
X
X for (list = ig->ptrs; *list; list++) {
X if (buf[l = strlen(*list)] == ':' && istrncmp(buf, *list, l) == 0)
X return (1);
X }
X return (0);
X}
END_OF_main/mbox.c
if test 6112 -ne `wc -c <main/mbox.c`; then
echo shar: \"main/mbox.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/nmail.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/nmail.c\"
else
echo shar: Extracting \"main/nmail.c\" \(6579 characters\)
sed "s/^X//" >main/nmail.c <<'END_OF_main/nmail.c'
X/*++
X/* NAME
X/* nmail
X/* SUMMARY
X/* extract originator and subject from new mail received by cico
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* nmail
X/* SYNOPSIS
X/* nmail [-d debuglevel]
X/* DESCRIPTION
X/* nmail searches for new mail files received by cico and extracts
X/* the originator's name, and message subject for later use by the
X/* mail visual shell.
X/*
X/* Return address formats we understand (in order of preference):
X/* .nf
X/*
X/* From: address (full_name) (take full_name)
X/* From: full_name <address> (take full_name)
X/* From: address (take address)
X/* >From address (take address)
X/* From address (take address)
X/*
X/* .fi
X/* To avoid tampering, new files will have read-only permission.
X/*
X/* In order to avoid corruption, control-c interrupts are disabled
X/* while this program executes.
X/* FILES
X/* In the spool directory:
X/* n<seqno> received mail message
X/* h<seqno> extracted originator name, subject
X/* SEE ALSO
X/* path(5) spool directory, file names
X/* cico(1) network process
X/* mail(1) visual mail shell
X/* DIAGNOSTICS
X/* Exit status zero when no errors were detected, nonzero in case of file
X/* access errors. See status(5) for error codes.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Tue Mar 31 20:14:11 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:20
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <signal.h>
X#include <time.h>
X#include <ctype.h>
X#include <varargs.h>
X
X#include "defs.h"
X#include "ndir.h"
X#include "path.h"
X#include "status.h"
X#include "ms_parse.h"
X
Xextern struct tm *localtime(); /* system functions */
X
Xhidden void parse_args(); /* forward declarations */
Xhidden void newmail();
Xhidden void extract();
Xhidden void usage();
X
Xhidden int dflag = 0; /* debugging option */
X
X#define debug if (dflag) printf
X
Xpublic char *progname = "nmail";
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X signal(SIGINT, SIG_IGN); /* disable ctrl-c */
X parse_args(argc, argv); /* parse command args */
X if (pathinit()) /* get path info */
X exit(E_NOSPOOL); /* bad MAILDIR variable */
X umask(0222); /* make files read-only */
X newmail(); /* get headers from new mail */
X exit(0);
X /* NOTREACHED */
X}
X
X/* parse_args - process command-line arguments */
X
Xhidden void parse_args(argc, argv)
Xint argc;
Xchar **argv;
X{
X while (--argc && *++argv && **argv == '-') {/* process options */
X switch (*++*argv) {
X case 'd': /* turn debugging on */
X if (--argc == 0)
X usage("missing debugging level argument");
X if ((dflag = atoi(*++argv)) < 0 || dflag > 9)
X dflag = 0;
X break;
X default: /* unknown option */
X usage("invalid option: -%c", **argv);
X break;
X }
X }
X
X /* check for extraneous arguments */
X
X if (argc > 0)
X usage("unexpected argument: %s", *argv);
X}
X
X/* scan for new mail that hasn't gotten yet a metafile */
X
Xhidden void newmail()
X{
X register DIR *dp;
X struct direct *de;
X unsigned msgno;
X
X debug("directory: \"%s\"\n", maildir);
X
X /*
X * Scan the spool directory for newly-arrived mail.
X *
X * Incoming mail message files have a name of "n<seqno>". The originator
X * name is normally present in files with names "h<seqno>" or "o<seqno>".
X * The presence of an "o" file implies that the file "n<seqno>" has been
X * read by the user. An "h" file means that the user has not yet read the
X * message file.
X *
X * If a message file has no corresponding "h" or "o" file we assume it is a
X * new mail message and create an "h" file with the name of the
X * originator and the subject of the message.
X */
X
X if ((dp = opendir(maildir)) == 0)
X exit(E_NOSPOOL);
X
X while (de = readdir(dp)) {
X debug("nmail: file \"%s\"\n", de->d_name);
X if (de->d_name[0] == NEW_MESG
X && (msgno = seqno(de->d_name))) {
X if (access(old_meta(msgno), 4) == 0) {
X /* already marked as read */ ;
X } else if (access(new_meta(msgno), 4) == 0) {
X /* already marked as unread */ ;
X } else { /* create meta file */
X extract(new_mesg(msgno), new_meta(msgno));
X }
X }
X }
X closedir(dp);
X}
X
X/* extract - extract originator and subject info from mail file to meta file */
X
Xhidden void extract(mail, meta)
Xchar *mail;
Xchar *meta;
X{
X FILE *mesgfp,
X *metafp;
X char line[MAXLINE];
X char from[MAXLINE]; /* name of sender */
X char subj[MAXLINE]; /* message subject */
X int context = MS_UUCP;
X
X debug("-- \"%s\" -> \"%s\"\n", mail, meta);
X
X if ((mesgfp = fopen(mail, "r")) == NULL) /* cannot open existing file */
X exit(E_SYSFAIL);
X
X strcpy(from, "Somewhere"); /* default originator */
X subj[0] = '\0'; /* initialize subject */
X
X /*
X * Some mailers generate real headers, separated from the message body by
X * an empty line. So we stop when we find an empty line. Other mailers
X * have no headers, so we stop when we see no header line. The following
X * algorithm tries to extract the real user name if possible, otherwise
X * it takes whatever it can get.
X */
X
X while ((context != MS_BODY) && fgets(line, sizeof(line), mesgfp)) {
X switch (context = ms_parse(context, line)) {
X case MS_UUCP:
X if (sscanf(line, "%*[>] From %s", from) != 1)
X (void) sscanf(line, "From %s", from);
X break;
X case MS_HEADER:
X if (hscanf(line, "Subject:", " %[^\n]", subj) == 0
X && hscanf(line, "From:", " %*s ( %[^)] )", from) == 0)
X (void) hscanf(line, "From:", " %[^<] <", from);
X break;
X }
X }
X
X /* carefully check all went well */
X
X if (ferror(mesgfp)) /* sorry, read problem */
X exit(E_READERR);
X if ((metafp = fopen(meta, "w")) == NULL) /* cannot create metafile */
X exit(E_WRITERR);
X fprintf(metafp, "%s\n%s\n", from, subj); /* write originator, subject */
X if (ferror(metafp)) {
X (void) fclose(metafp); /* ms-dog needs this! */
X (void) chmod(meta, 0666); /* sorry, write problem */
X (void) unlink(meta); /* delete metafile */
X exit(E_WRITERR);
X }
X (void) fclose(mesgfp);
X (void) fclose(metafp);
X}
X
X/* usage - explain what is wrong */
X
X/* VARARGS */
X
Xhidden void usage(va_alist)
Xva_dcl
X{
X va_list ap;
X char *fmt;
X
X va_start(ap);
X fmt = va_arg(ap, char *);
X vfprintf(stderr, fmt, ap);
X va_end(ap);
X fprintf(stderr, "\nusage: nmail [-d debugging_level]\n");
X exit(2);
X}
END_OF_main/nmail.c
if test 6579 -ne `wc -c <main/nmail.c`; then
echo shar: \"main/nmail.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/startup.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/startup.c\"
else
echo shar: Extracting \"main/startup.c\" \(6115 characters\)
sed "s/^X//" >main/startup.c <<'END_OF_main/startup.c'
X/*++
X/* NAME
X/* startup 3
X/* SUMMARY
X/* startup/terminate network protocol
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* cico
X/* SYNOPSIS
X/* startproto()
X/*
X/* endproto()
X/* DESCRIPTION
X/* startproto() should be called after a successfull login on a remote
X/* host. It performs the primary handshake with the other system
X/* (call accepted/locked) and negotiates a communications protocol.
X/* It then sets the function pointers Close/Read/Write to the
X/* appropriate values. Until endproto() is called, all i/o to the
X/* remote host should proceed through the functions pointed to by
X/* Read/Write.
X/*
X/* endproto() turns the protocol off, and sends the silly "OO" message
X/* to the remote system. It does not disconnect, nor does it change
X/* the state of the communications port.
X/* FUNCTIONS AND MACROS
X/* xgetc(), xwrite(), trap()
X/* DIAGNOSTICS
X/* The process of negotiation is shown when debugging is enabled.
X/* startproto() and endproto() return 0 in case of success, E_LOST
X/* if no response arrived and E_REJECT if the response differed
X/* from the expected response.
X/* BUGS
X/* startproto() assumes that the local system is the calling system.
X/* AUTHOR(S)
X/* W.Z. Venema
X/* Eindhoven University of Technology
X/* Department of Mathematics and Computer Science
X/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* CREATION DATE
X/* Fri Mar 27 13:43:00 GMT+1:00 1987
X/* LAST MODIFICATION
X/* 90/01/22 13:02:41
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <setjmp.h>
X
X#include "defs.h"
X#include "params.h"
X#include "comm.h"
X#include "logs.h"
X#include "status.h"
X#include "sysdep.h"
X
X/* forward declarations */
X
Xhidden char *xpct(); /* expect a string */
Xhidden char *send(); /* send a string */
X
X/* the functions that inplement the various protocols */
X
Xextern kopen(), kclose(), kread(), kwrite(); /* k protocol */
Xextern gopen(), gclose(), gread(), gwrite(); /* g protocol */
X
Xtypedef struct proto {
X char name; /* name of the protocol */
X int (*open) (); /* the open function */
X int (*close) (); /* the close function */
X int (*read) (); /* the read function */
X int (*write) (); /* the write function */
X};
X
X/* the order of protocols is significant! */
X
Xhidden struct proto ptbl[] = {
X 'k', kopen, kclose, kread, kwrite, /* try this first */
X 'g', gopen, gclose, gread, gwrite, /* then this one */
X /* add your protocols at the appropriate place */
X 0, /* terminator! */
X};
X
X/* startproto - do primary handshake, establish protocol and turn it on */
X
Xpublic startproto()
X{
X int *savetrap = systrap;
X jmp_buf mytrap;
X register struct proto *pp;
X register char *cp;
X int status;
X
X if (status = setjmp(systrap = mytrap)) { /* get here if expect fails */
X systrap = savetrap;
X return (status);
X }
X /* the primary handshake: who are we and is it ok we call right now */
X
X sscanf(xpct("Shere"), "Shere=%s", rmthost); /* try to get host name */
X log("SUCCEEDED (call to %s)", rmthost);
X
X /* some uucico implementations seem to have problems with debug level 0 */
X
X send(strcons("S%s -x%d", LOGIN_NAME, MAX(dflag, 1)));
X xpct("ROK"); /* we're accepted or rejected */
X
X /* choose a protocol from the list offered by the other side */
X
X for (cp = xpct("P") + 1, pp = ptbl; pp->name && !index(cp, pp->name); pp++)
X /* void */ ;
X if (pp->name == 0) { /* no common protocol */
X send("UN");
X trap(E_REJECT, "FAILED (no common protocol in \"%s\")", cp);
X /* NOTREACHED */
X }
X send(strcons("U%c", pp->name)); /* my choice of protocol */
X
X /* install protocol */
X
X Close = pp->close; /* for endproto() */
X Read = pp->read;
X Write = pp->write;
X if (pp->open && CALL(pp->open) (ttfd)) /* start up a protocol */
X trap(E_LOST, "FAILED (startup)");
X
X /* finish up */
X
X log("OK (startup)");
X systrap = savetrap; /* get here if expect wins */
X return (0);
X}
X
X/* endproto - terminate protocol */
X
Xpublic endproto()
X{
X int *savetrap = systrap; /* save exception handler */
X jmp_buf mytrap;
X int status;
X
X if (Close) /* check there is one */
X CALL(Close) (ttfd); /* turn protocol off */
X send("OOOOOO"); /* byebye */
X
X /* Don\'t wait for the other side\'s OOOOOO, just sleep and quit. */
X
X (void) sleep(1);
X log("OK (conversation complete)");
X return (0);
X}
X
X/* send - write message to remote host and return pointer to message */
X
Xhidden char *send(str)
Xchar *str;
X{
X xwrite(ttfd, "\020", 1); /* message header */
X xwrite(ttfd, str, strlen(str) + 1); /* include trailing null */
X debug(4) ("send: %S\n", str);
X return (str); /* return the message */
X}
X
X/* xpct - read message from host in "^Pmessage[\0\n]" format; trap on errors */
X
Xhidden char *xpct(pat)
Xchar *pat;
X{
X register int c;
X register char *p = msgin;
X register int inmsg = 0;
X
X /*
X * Keep reading until we time out, or until a complete message has been
X * received. Consider the link as lost in case of time out. Assume we are
X * rejected if the received message differs from what was expected.
X */
X
X debug(4) ("xpct: %S\n", pat);
X
X for (;;) {
X if ((c = xgetc()) == EOF) {
X trap(E_LOST, "FAILED (protocol handshake)");
X /* NOTREACHED */
X } else if ((c &= 0177) == '\020') {
X debug(4) (" got sync\n"); /* got start of message */
X p = msgin; /* reset */
X inmsg = 1;
X } else if (inmsg == 0) {
X debug(4) ("%C", c); /* don\'t store, just debug */
X } else if (*p++ = ((c == '\n') ? '\0' : c)) {
X debug(4) ("%C", c); /* store and debug */
X if (p >= msgin + MSGBUF) { /* spurious Ctrl-P seen? */
X p = msgin; /* reset */
X inmsg = 0; /* reset */
X }
X } else if ((debug(4) ("\n")), strncmp(pat, msgin, strlen(pat)) == 0) {
X return (msgin); /* expect succeeded */
X } else {
X msgin[30] = '\0'; /* truncate to 30 */
X trap(E_REJECT, "FAILED (%S)", msgin);
X /* NOTREACHED */
X }
X }
X}
END_OF_main/startup.c
if test 6115 -ne `wc -c <main/startup.c`; then
echo shar: \"main/startup.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f main/str.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"main/str.c\"
else
echo shar: Extracting \"main/str.c\" \(6415 characters\)
sed "s/^X//" >main/str.c <<'END_OF_main/str.c'
X/*++
X/* NAME
X/* strcons,istrcmp,strvec,vecstr,split 3
X/* SUMMARY
X/* string utility routines
X/* PROJECT
X/* pc-mail
X/* PACKAGE
X/* general stuff
X/* SYNOPSIS
X/* #include "defs.h"
X/*
X/* char *strcons(format,args)
X/* char *format;
X/*
X/* char *split(cpp, sep)
X/* char **cpp;
X/* char *sep;
X/*
X/* int istrncmp(s1,s2,n)
X/* char *s1,s2;
X/* int n;
X/*
X/* int istrcmp(s1,s2)
X/* char *s1,s2;
X/*
X/* char **strvec(string,separ)
X/* char *string;
X/* char *separ;
X/*
X/* freevec(vec)
X/* char **vec;
X/*
X/* char *vecstr(vector,separ)
X/* char **vector;
X/* char *separ;
X/* DESCRIPTION
X/* strcons() produces a formatted string, using printf()-like
X/* arguments. Basically it is an sprintf() that returns a
X/* pointer to the result. memory for the result is taken from
X/* a small memory pool that is recycled upon successive calls.
X/*
X/* split() searches the string pointed to by cpp for the occurrance
X/* of the text token (a string not containing any of the characters
X/* given in the "sep" argument). *cpp is updated if a token is
X/* found; a null pointer is returned otherwise. This function
X/* is an attempt to improve upon the strtok() function, which
X/* can parse only one string at a time. It still modifies its
X/* arguments, however.
X/*
X/* istrcmp() is a case-insensitive version of the strcmp() function.
X/*
X/* istrncmp() is a case-insensitive version of the strncmp() function.
X/*
X/* strvec() breaks a null-terminated string using the separators given
X/* in separ, and returns a null-terminated vector of pointers to the
X/* resulting substrings. Memory for the vector and substrings are
X/* allocated in dynamic memory. The original string is not modified.
X/*
X/* freevec() frees storage allocated by strvec().
X/*
X/* vecstr() takes a null-terminated vector of string pointers
X/* and builds a string from the strings pointed to by the vector
X/* argument, separated by the string in the separ argument.
X/* Memory for the result is allocated in dynamic memory.
X/* FUNCTIONS AND MACROS
X/* strtok(), malloc(), memcpy(), sprintf()
X/* DIAGNOSTICS
X/* strvec(), vecstr() return a null pointer if there was not enough memory
X/* avaliable to hold the result.
X/* BUGS
X/* strcons() does not do smart garbage collection; it just uses
X/* a circular buffer. The present implementation is not portable
X/* to machines that pass arguments via registers.
X/*
X/* strvec() cannot handle strings with more than BUFSIZ words.
X/* strvec() uses strtok(), which may have side effects.
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 Apr 5 20:59:29 MET 1988
X/* LAST MODIFICATION
X/* 90/01/22 13:02:43
X/* VERSION/RELEASE
X/* 2.1
X/*--*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <varargs.h>
X
X#include "defs.h"
X
X#define NBUF 4
X
X/* strcons - quick-and-dirty string constructor */
X
X/* VARARGS */
X
Xchar *strcons(va_alist)
Xva_dcl
X{
X va_list ap;
X static char strbuf[NBUF][BUFSIZ];
X static int where = 0;
X register char *cp;
X char *fmt;
X
X va_start(ap);
X fmt = va_arg(ap, char *);
X (void) vsprintf(cp = strbuf[where = (where + 1) % NBUF], fmt, ap);
X va_end(ap);
X return (cp);
X}
X
X/* istrcmp - case-insensitive string comparison */
X
X#define LOW(c) (isascii(c)&&isupper(c)?tolower(c):(c))
X
Xint istrcmp(s1, s2)
Xregister char *s1;
Xregister char *s2;
X{
X while (*s1 && (LOW(*s1) == LOW(*s2)))
X s1++, s2++;
X return (LOW(*s1) - LOW(*s2));
X}
X
X/* istrncmp - case-insensitive string comparison */
X
X#define LOW(c) (isascii(c)&&isupper(c)?tolower(c):(c))
X
Xint istrncmp(s1, s2, n)
Xregister char *s1;
Xregister char *s2;
Xregister int n;
X{
X while (n > 0 && *s1 && (LOW(*s1) == LOW(*s2)))
X n--, s1++, s2++;
X return (n > 0 ? LOW(*s1) - LOW(*s2) : 0);
X}
X
X/* strvec - make vector of substring pointers */
X
Xchar **strvec(str, sep)
Xchar *str;
Xchar *sep;
X{
X#ifdef lint
X static
X#endif
X char *tmp[BUFSIZ]; /* scratch substring pointer storage */
X register char **cpp = tmp;
X char *sp; /* ptr to private copy of original */
X register int bytec;
X
X /* make a copy of the original string */
X
X if ((sp = malloc(strlen(str) + 1)) == 0)
X return (0);
X (void) strcpy(sp, str);
X
X /* chop our copy at sequences of one or more separators */
X
X for (*cpp = strtok(sp, sep); *cpp; *++cpp = strtok((char *) 0, sep))
X /* void */ ;
X
X /* now construct the vector of pointers to the substrings */
X
X if ((cpp = (char **) malloc(bytec = (cpp - tmp + 1) * sizeof(*cpp))) == 0)
X return (0);
X return ((char **) memcpy((char *) cpp, (char *) tmp, bytec));
X}
X
X/* freevec - release storage allocated by strvec() */
X
Xfreevec(vec)
Xchar **vec;
X{
X free(vec[0]);
X free((char *) vec);
X}
X
X/* vecstr - from null-terminated vector of string pointers to one flat string */
X
Xpublic char *vecstr(vec, sep)
Xchar **vec;
Xchar *sep;
X{
X register char **cpp;
X register int len = 0; /* length of final string */
X register char *cp;
X register int flen = strlen(sep); /* filler between substrings */
X
X /* find out how big the resulting string will be */
X
X for (cpp = vec; *cpp; cpp++)
X len += strlen(*cpp) + flen;
X
X /* allocate and initialize the result string */
X
X if ((cp = malloc(len + 1)) == 0)
X return (0);
X *cp = '\0';
X
X /* fill the resulting string */
X
X for (cpp = vec; *cpp; cpp++) {
X (void) strcat(cp, *cpp);
X (void) strcat(cp, sep);
X }
X return (cp);
X}
X
X/* split - return next token in *cpp, update cpp */
X
Xpublic char *split(cpp, sep)
Xregister char **cpp;
Xregister char *sep;
X{
X register char *start;
X char *end;
X char *strpbrk();
X
X /*
X * Find the beginning of the first token. If none is found, just return a
X * null value. Otherwise, if there is a separator that follows the token,
X * nullify it and advance *cpp to the first character after the nullified
X * separator. If the token is not followed by a separator advance *cpp to
X * the null byte that follows the token.
X */
X
X start = *cpp + strspn(*cpp, sep);
X
X if (start[0] == 0) {
X return (0); /* no token */
X } else if (end = strpbrk(start, sep)) { /* look for separator */
X *end = '\0'; /* nullify */
X *cpp = end + 1; /* advance beyond end */
X return (start); /* return token */
X } else {
X *cpp = start + strlen(start); /* advance to terminator */
X return (start); /* return token */
X }
X}
END_OF_main/str.c
if test 6415 -ne `wc -c <main/str.c`; then
echo shar: \"main/str.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 6 \(of 11\).
cp /dev/null ark6isdone
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