[comp.sources.unix] v10i014: The IDA Sendmail Kit, Part03/07

rs@uunet.UUCP (06/23/87)

Mod.sources: Volume 10, Number 14
Submitted by: Lennart Lovstrand <mcvax!ida.liu.se!lel>
Archive-name: ida/Part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 7)."
# Contents:  ida/aux/dbm.c ida/aux/rmail.c ida/aux/xalparse.c
#   ida/patches/alias.c.diff ida/patches/op.me.diff
#   ida/patches/sendmail.h.diff
# Wrapped by lenlo@prefix on Wed Jun 10 15:39:53 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f ida/aux/dbm.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/aux/dbm.c\"
else
echo shar: Extracting \"ida/aux/dbm.c\" \(10884 characters\)
sed "s/^X//" >ida/aux/dbm.c <<'END_OF_ida/aux/dbm.c'
X/*
X**  DBM -- General dbm management tool.
X**  Copyright (c) 1987 Lennart Lovstrand
X**  CIS Dept, Univ of Linkoping, Sweden
X**
X**  Use it, abuse it, but don't sell it.
X*/
X
X#include "useful.h"
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/file.h>
X#ifdef MDBM
X# include "mdbm_compat.h"
X#else MDBM
X# include <ndbm.h>
X# define DBMFILE DBM
X#endif MDBM
X
X#ifndef lint
Xstatic char	SccsId[] = "@(#)dbm.c 2.0 (lel@ida.liu.se) 4/20/87";
X#endif !lint
X
X#define	SAMECASE	0
X#define LOWERCASE	1
X#define UPPERCASE	2
X
X#define COMMENTCHAR	'#'
X
X#define streq(s, t)	(strcmp(s, t) == 0)
X#define MAKEDATUM(d, s)	{(d).dptr = s; (d).dsize = strlen(s) + 1;}
X
Xvoid do_clear(), do_delete(), do_dump(), do_fetch(), do_load(), do_make(),
X    do_parse(), do_store();
X
Xstruct comtab {
X    char *c_name;
X    void (*c_func)();
X} CommandTable[] = {
X    {"clear",	do_clear},
X    {"delete",	do_delete},
X    {"dump",	do_dump},
X    {"fetch",	do_fetch},
X    {"load",	do_load},
X    {"make",	do_make},
X    {"parse",	do_parse},
X    {"store",	do_store}
X};
X    
X/* global arguments */
Xint	Argc;
Xchar	**Argv;
X
X/* options */
Xint	Appending = FALSE;
Xint	Casing = SAMECASE;
Xbool	Debug = FALSE;
Xchar	*Outfile = NULL;
Xint	Mode = 0644;
Xchar	*Progname;
Xbool	Senteniel = FALSE;
Xint	Storeflag = DBM_INSERT;
Xbool	Storewarn = TRUE;
X
X/* Dbm globals */
XDBMFILE	*Dbm;
Xchar	*Dbmfile = NULL;
Xint	Dbmaccess;
Xdatum	key, val;
X
Xmain(argc, argv)
X     int argc;
X     char **argv;
X{
X    extern int optind;
X    extern char *optarg;
X    char *scantoken();
X    struct comtab *cmd;
X    int c;
X
X    Argc = argc;
X    Argv = argv;
X
X    Progname = Argv[0];
X
X    while ((c = getopt(Argc, Argv, "ADILRSUd:m:o:")) != EOF)
X	switch (c) {
X	  case 'A':
X	    Appending = TRUE;
X	    break;
X	  case 'D':
X	    Debug = TRUE;
X	    break;
X	  case 'I':
X	    Storeflag = DBM_INSERT;
X	    Storewarn = FALSE;
X	    break;
X	  case 'L':
X	    Casing = LOWERCASE;
X	    break;
X	  case 'R':
X	    Storeflag = DBM_REPLACE;
X	    break;
X	  case 'S':
X	    Senteniel = TRUE;
X	    break;
X	  case 'U':
X	    Casing = UPPERCASE;
X	    break;
X	  case 'd':
X	    Dbmfile = optarg;
X	    break;
X	  case 'm':
X	    if (optarg[0] == '0')
X		(void) sscanf(optarg, "%o", &Mode);
X	    else {
X		(void) sscanf(optarg, "%d", &Mode);
X		if (Mode == 0) {
X		    (void) fprintf(stderr, "%s: non-numeric mode: %s\n",
X				   Progname, optarg);
X		    exit(1);
X		}
X	    }
X	    break;
X	  case 'o':
X	    Outfile = optarg;
X	    break;
X	  default:
X	    (void) fprintf(stderr,
X			   "usage: %s [-ADILNRSU] [-d dbm_file] [-m mode] %s", 
X			   Progname, "[-o output_file] command [args]\n");
X	    exit(1);
X	}
X
X    Argc -= optind;
X    Argv += optind;
X
X    if (Argc > 0) {
X	for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
X						     sizeof(*CommandTable)];
X	     cmd++)
X	    if (streq(*Argv, cmd->c_name)) {
X		(*cmd->c_func)();
X		exit(0);
X	    }
X	(void) fprintf(stderr, "%s: unknown dbm command %s", Progname, *Argv);
X    } else
X	(void) fprintf(stderr, "%s: missing dbm command", Progname);
X    (void) fprintf(stderr, ", use one of the following:\n");
X    for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
X						 sizeof(*CommandTable)]; cmd++)
X	(void) fprintf(stderr, "%s%s", cmd == CommandTable ? "" : "\t",
X		       cmd->c_name);
X    (void) fprintf(stderr, "\n");
X    exit(3);
X}
X
Xopendbm(access)
X     int access;
X{
X    if (Dbmfile == NULL) {
X	if (Argc > 1) {
X	    /* use last argument */
X	    Dbmfile = Argv[Argc-1];
X	    Argc--;
X	} else {
X	    (void) fprintf(stderr, "%s: dbm file not specified\n", Progname);
X	    exit(3);
X	}
X    }
X    Dbm = dbm_open(Dbmfile, access, Mode);
X    if (Dbm == NULL) {
X	perror(Dbmfile);
X	exit(4);
X    }
X    Dbmaccess = access;
X}
X
Xclosedbm()
X{
X    if ((Dbmaccess & O_RDONLY) == 0 && Senteniel) {
X	MAKEDATUM(key, "@@@");
X	if (dbm_store(Dbm, key, key, DBM_REPLACE) != NULL) {
X	    (void) fprintf(stderr, "%s: could not store senteniel \"@@@\"\n",
X			   Progname);
X	    perror(Progname);
X	    exit(5);
X	}
X    }
X	
X    dbm_close(Dbm);
X}
X
XFILE *
Xopenfile(filename, access)
X     char *filename;
X     char *access;
X{
X    FILE *f;
X
X    if (streq(filename, "-"))
X	if (streq(access, "r"))
X	    return stdin;
X	else
X	    return stdout;
X    else {
X	f = fopen(filename, access);
X	if (f == NULL) {
X	    perror(filename);
X	    exit(4);
X	}
X	return f;
X    }
X}
X
Xvoid
Xclosefile(f)
X     FILE *f;
X{
X    if (f != stdin && f != stdout)
X	(void) fclose(f);
X}
X/*
X**	DO_CLEAR -- Clear out database leaving it emtpy.
X*/
X
Xvoid
Xdo_clear()
X{
X    if (Dbmfile != NULL) {
X	opendbm(O_RDWR | O_CREAT | O_TRUNC);
X	closedbm();
X    }
X    while (Argc > 1) {
X	opendbm(O_RDWR | O_CREAT | O_TRUNC);
X	closedbm();
X    }
X}
X
X   
X/*
X**	DO_DELETE -- Delete individual entries from the database.
X*/
X
Xvoid
Xdo_delete()
X{
X    opendbm(O_RDWR | O_CREAT);
X
X    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	casify(*Argv, Casing);
X	MAKEDATUM(key, *Argv);
X	if (dbm_delete(Dbm, key) != NULL) {
X	    perror(*Argv);
X	    exit(5);
X	}
X    }
X
X    closedbm();
X}
X
X/*
X**	DO_DUMP -- List all entries in the database.
X*/
X 
Xvoid
Xdo_dump()
X{
X    FILE *output;
X    
X    opendbm(O_RDONLY);
X
X    if (Outfile == NULL)
X	output = stdout;
X    else
X	output = openfile(Outfile, "w");
X
X#ifdef MDBM
X    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm, key
)) {
X#else MDBM
X    for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm)) {
X#endif MDBM
X	val = dbm_fetch(Dbm, key);
X	if (val.dptr == NULL)
X	    perror(key.dptr);
X	else
X	    (void) fprintf(output, "%s\t%s\n", key.dptr, val.dptr);
X    }
X}
X/*
X**	DO_FETCH -- Lookup individual keys in the database.
X*/
X 
Xvoid
Xdo_fetch()
X{
X    opendbm(O_RDONLY);
X
X    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	casify(*Argv, Casing);
X	MAKEDATUM(key, *Argv);
X	val = dbm_fetch(Dbm, key);
X	if (val.dptr == NULL)
X	    (void) printf("%s\t[NOT FOUND]\n", *Argv);
X	else
X	    (void) printf("%s\t%s\n", *Argv, val.dptr);
X    }
X
X    closedbm();
X}
X
X/*
X**	DO_STORE -- Insert individual entries into the database.
X*/
X
Xvoid
Xdo_store()
X{
X    /* barf if # of args - 1 is even and no dbm file has been specified */
X    if (Argc & 1 == 1 && Dbmfile == NULL) {
X	(void) fprintf(stderr, "%s: no dbm file specified\n", Progname);
X	exit(3);
X    }
X
X    opendbm(O_RDWR | O_CREAT);
X
X    for (Argc--, Argv++; Argc > 1; Argc -= 2, Argv += 2) {
X	casify(Argv[0], Casing);
X	MAKEDATUM(key, Argv[0]);
X	MAKEDATUM(val, Argv[1]);
X	if (dbm_store(Dbm, key, val, Storeflag) != NULL) {
X	    extern int errno;
X
X	    if (errno != 0) {
X		perror(Argv[0]);
X		exit(5);
X	    } else if (Storewarn)
X		(void) fprintf(stderr,
X			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
X			       Progname, Argv[0], Argv[1]);
X	}
X    }
X    if (Argc > 0)
X	(void) fprintf(stderr, "%s: no value for last key \"%s\"--ignored\n",
X		       Progname, Argv[0]);
X
X    closedbm();
X}
X
X/*
X**	DO_PARSE -- Parse a textual database file and produce key-value
X**		pairs separated by a tab (suitable for input to the ``load''
X**		function).
X*/
X
Xvoid
Xdo_parse()
X{
X    FILE *input, *output;
X    
X    if (Outfile == NULL)
X	output = stdout;
X    else
X	output = openfile(Outfile, "w");
X
X    if (Argc == 1)
X	parsefile(stdin, output);
X    else
X	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	    input = openfile(*Argv, "r");
X	    parsefile(input, output);
X	    closefile(input);
X	}
X}
X
X/*
X**	DO_MAKE -- Parse the textual input and load the result into
X**		the database.
X*/
X
Xvoid
Xdo_make()
X{
X    FILE *input, *pipin, *pipout;
X    int pipes[2];
X
X    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
X
X    if (pipe(pipes) != NULL) {
X	perror("pipe");
X	exit(9);
X    }
X    pipin = fdopen(pipes[0], "r");
X    pipout = fdopen(pipes[1], "w");
X
X    if (fork() == 0) {
X	/* child process */
X	(void) fclose(pipout);
X
X	loadfile(pipin);
X    } else {
X	/* parent process */
X	(void) fclose(pipin);
X
X	if (Argc == 1)
X	    parsefile(stdin, pipout);
X	else
X	    for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X		input = openfile(*Argv, "r");
X		parsefile(input, pipout);
X		closefile(input);
X	    }
X    }
X    closedbm();
X}
X
X/*
X**	DO_LOAD -- Load the dbm database from a text file.  The input should
X**		be key-value pairs separated by a tab, each on a single line.
X*/
X
Xvoid
Xdo_load()
X{
X    FILE *input;
X
X    opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC));
X
X    if (Argc == 1)
X	loadfile(stdin);
X    else
X	for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
X	    input = openfile(*Argv, "r");
X	    loadfile(input);
X	    closefile(input);
X	}
X    closedbm();
X}    
X
X/*
X**	PARSEFILE, LOADFILE
X*/ 
X
Xparsefile(input, output)
X     FILE *input, *output;
X{
X    extern char *index();
X    char buf[BUFSIZ], *key, *val = NULL;
X    register char *p;
X
X    while (fgets(buf, sizeof(buf), input) != NULL) {
X	if (buf[0] == COMMENTCHAR || buf[0] == '\n' || buf[0] == '\0')
X	    continue;
X	if (!isspace(buf[0])) {
X	    /* extract value */
X	    p = scantoken(buf);
X	    if (val != NULL)
X		free(val);
X	    val = (char *) malloc(p - buf + 1);
X	    (void) strncpy(val, buf, p - buf);
X	    val[p - buf] = '\0';
X	}
X	casify(buf, Casing);
X	for (p = buf; *p != '\0';) {
X	    while (*p != '\0' && isspace(*p)) p++;
X	    if (*p == '\0' || *p == COMMENTCHAR)
X		break;
X	    key = p;
X	    p = scantoken(p);
X	    if (*p == COMMENTCHAR)
X		*p = '\0';
X	    else if (*p != '\0')
X		*p++ = '\0';
X	    (void) fprintf(output, "%s\t%s\n", key, val);
X	}
X    }
X}
X
Xloadfile(input)
X     FILE *input;
X{
X    char buf[BUFSIZ];
X    register char *tab, *nl;
X    extern char *index();
X
X    while (fgets(buf, sizeof(buf), input) != NULL) {
X	nl = index(buf, '\n');
X	if (nl != NULL)
X	    *nl = '\0';
X
X	tab = index(buf, '\t');
X	if (tab == NULL) {
X	    (void) fprintf(stderr, "%s: missing tab in \"%s\"--ignored\n",
X			   Progname, buf);
X	    continue;
X	}
X	*tab++ = '\0';
X	casify(buf, Casing);
X	MAKEDATUM(key, buf);
X	MAKEDATUM(val, tab);
X	if (dbm_store(Dbm, key, val, Storeflag) != NULL && Storewarn) {
X	    extern int errno;
X
X	    if (errno != 0) {
X		perror(buf);
X		exit(5);
X	    } else if (Storewarn)
X		(void) fprintf(stderr,
X			       "%s: duplicate key \"%s\" => \"%s\" ignored\n",
X			       Progname, buf, tab);
X	}
X    }
X}
X
Xchar *
Xscantoken(p)
X     register char *p;
X{
X  register bool quotedchar = FALSE, insidestring = FALSE, insideroute = FALSE;
X
X  /* hidious address scanner */
X  while (*p != '\0' && (quotedchar || insidestring || insideroute || 
X			(*p != COMMENTCHAR && !isspace(*p)))) {
X    /* special quote character handling */
X    if (quotedchar)
X      quotedchar = FALSE;
X    else {
X      quotedchar = (*p == '\\');
X      if (!insidestring)
X	if (*p == '<')
X	  insideroute = TRUE;
X	else if (*p == '>')
X	  insideroute = FALSE;
X      if (*p == '"')
X	insidestring = !insidestring;
X    }
X    p++;
X  }
X
X  return p;
X}
X
Xcasify(p, c)
X     register char *p;
X     int c;
X{
X    switch (c) {
X      case LOWERCASE:
X	for (; *p != '\0'; p++)
X	    if (isupper(*p))
X		*p = tolower(*p);
X	break;
X      case UPPERCASE:
X	for (; *p != '\0'; p++)
X	    if (islower(*p))
X		*p = toupper(*p);
X	break;
X    }
X}
END_OF_ida/aux/dbm.c
if test 10884 -ne `wc -c <ida/aux/dbm.c`; then
    echo shar: \"ida/aux/dbm.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ida/aux/rmail.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/aux/rmail.c\"
else
echo shar: Extracting \"ida/aux/rmail.c\" \(6732 characters\)
sed "s/^X//" >ida/aux/rmail.c <<'END_OF_ida/aux/rmail.c'
X/*
X**  RMAIL -- Receive remote mail requests.
X**  Copyright (c) 1987 Lennart Lovstrand
X**  CIS Dept, Univ of Linkoping, Sweden
X**
X**  Use it, abuse it, but don't sell it.
X**
X**  Version 2.6 of 5-May-87.
X**
X**  This time logging selected header lines + more liberal parsing of
X**  the initial from-line but not yet with accounting & like; 14-Apr-85.
X**  Dbm lookup of UUCP domain names added 5-May-87.
X*/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <ctype.h>
X#include <sys/time.h>
X#include <strings.h>
X#ifdef MDBM
X# include "mdbm_compat.h"
X#else MDBM
X# include <ndbm.h>
X# define DBMFILE DBM
X#endif MDBM
X#include "useful.h"
X
X#define STRSIZ		1024
X#define COMMA		','
X#define LOGFILE		"/usr/lib/uucp/rmail.log"
X#define SENDMAIL	"/usr/lib/sendmail"
X#define NETCHRS		"%@!:"
X#define DEFAULT_HOST	"liuida"
X#define DEFAULT_DOMAIN	"UUCP"
X#define DOMAINTABLE	"/usr/lib/mail/domaintable"
X
X#define H_CC		"cc"
X#define H_FROM		"from"
X#define H_MESSAGE_ID	"message_id"
X#define H_RETURN_PATH	"return-path"
X#define H_TO		"to"
X#define H_VIA		"via"
X
X#define MAKELC(C)	(isupper(C) ? tolower(C) : C)
X#define EATSPACE(P)	while (*P == ' ') P++
X
XFILE *popen();
Xchar *Progname;
Xint Debug = FALSE;
XDBMFILE	*Dbm;
X
Xmain(argc, argv)
X    int argc;
X    char **argv;
X{
X    char from_[STRSIZ], cmd[STRSIZ], s_mac[STRSIZ], f_opt[STRSIZ], s[STRSIZ];
X    char *v_opt = "";
X    char *p, *user, *host, *domain = DEFAULT_DOMAIN;
X    char *acctsys = (char *) getenv("ACCTSYS");
X    FILE *outf;
X#ifdef LOGFILE
X    FILE *logf = NULL;
X#endif LOGFILE
X#ifdef DOMAINTABLE
X    datum key, val;
X#endif DOMAINTABLE
X    int insideheader, printedlast = FALSE;
X    int c, errflg = FALSE;
X    
X    extern int optind;
X    extern char *optarg;
X
X    Progname = argv[0];
X    while ((c = getopt(argc, argv, "D:dv")) != EOF) {
X	switch (c) {
X	  case 'D':
X	    domain = optarg;
X	    break;
X	  case 'd':
X	    Debug++;
X	    break;
X	  case 'v':
X	    v_opt = " -v";
X	    break;
X	  default:
X	    errflg = TRUE;
X	    break;
X	}
X    }
X    if (errflg || optind >= argc) {
X	(void) fprintf(stderr, "usage: %s [-Ddomain] user ...\n", Progname);
X	exit(2);
X    }
X
X    /*
X     * set our real uid to root as well as our effective uid so
X     * make sendmail accept the -oM options
X     */
X    (void) setreuid(0, 0);
X
X#ifdef DOMAINTABLE
X    Dbm = dbm_open(DOMAINTABLE, O_RDONLY);
X    if (Dbm == NULL)
X	perror(DOMAINTABLE);
X#endif DOMAINTABLE
X
X#ifdef LOGFILE
X    if ((logf = fopen(Debug ? "/dev/tty" : LOGFILE, "a")) != NULL) {
X	struct timeval t;
X	int a;
X
X	(void) gettimeofday(&t, (struct timezone *) NULL);
X	(void) fprintf(logf, "\n[%.12s] ", ctime(&t.tv_sec) + 4);
X	for (a = 0; a < argc; a++)
X	    (void) fprintf(logf, " '%s'", argv[a]);
X	(void) putc('\n', logf);
X    } else
X	(void) fprintf(stderr, "%s: couldn't open log file \"%s\"\n",
X		       Progname, LOGFILE);
X#endif LOGFILE
X
X    user = NULL;
X    host = NULL;
X    (void) gets(from_);
X
X#ifdef LOGFILE
X    if (logf != NULL)
X	(void) fprintf(logf, "%s\n", from_);
X#endif LOGFILE
X
X    if (strncmp(from_, "From ", 5) == 0 || strncmp(from_, ">From ", 6) == 0) {
X	user = index(from_, ' ') + 1;
X	EATSPACE(user);
X	if ((p = index(user, ' ')) != NULL) {
X	    *p = '\0';
X	    while ((p = index(p + 1, 'r')) != NULL) {
X		if (strncmp(p, "remote from ", 12) == 0) {
X		    host = p + 12;
X		    EATSPACE(host);
X		    if ((p = index(host, '\n')) != NULL)
X			*p = '\0';
X		    if (strcmp(host, "somewhere") == 0)
X			host = NULL;
X		    break;
X		}
X	    }
X	}
X    }
X
X    if (acctsys == NULL)
X	acctsys = host;
X
X    if (host)
X	(void) sprintf(f_opt, " -f%s!%s", host, user);
X    else if (user)
X	(void) sprintf(f_opt, " -f%s", user);
X    else
X	*f_opt = '\0';
X
X    if (acctsys) {
X#ifdef DOMAINTABLE
X	if (Dbm != NULL) {
X	    key.dptr = acctsys;
X	    key.dsize = strlen(acctsys) + 1;
X	    val = dbm_fetch(Dbm, key);
X	    if (val.dptr != NULL)
X		acctsys = val.dptr;
X	}
X#endif DOMAINTABLE
X	if (index(acctsys, '.') == NULL)
X	    (void) sprintf(s_mac, " -oMs%s.%s", acctsys, domain);
X	else
X	    (void) sprintf(s_mac, " -oMs%s", acctsys);
X    } else
X	*s_mac = '\0';
X
X    (void) sprintf(cmd, "exec %s -ee -i -oMrUUCP%s%s%s",
X		   SENDMAIL, s_mac, f_opt, v_opt);
X
X    for (; optind < argc; optind++) {
X	(void) strcat(cmd, " '");
X#ifdef DEFAULT_HOST
X	if (anyin(argv[optind], NETCHRS) == NULL) {
X	    (void) strcat(cmd, DEFAULT_HOST);
X	    (void) strcat(cmd, "!");
X	}
X#endif DEFAULT_HOST
X	if (*argv[optind] == '(')
X	    (void) strncat(cmd, &argv[optind][1], strlen(argv[optind])-2);
X	else
X	    (void) strcat(cmd, argv[optind]);
X	(void) strcat(cmd, "'");
X    }
X
X#ifdef LOGFILE
X    if (logf != NULL)
X	(void) fprintf(logf, "%s\n", cmd);
X#endif LOGFILE
X    if (Debug)
X	outf = stdout;
X    else {
X	outf = popen(cmd, "w");
X	if (outf == NULL) {
X	    (void) fprintf(stderr, "%s: could not open pipe thru %s\n",
X			   Progname, cmd);
X	    exit(1);
X	}
X    }
X
X    insideheader = TRUE;
X    while (gets(s)) {
X	if (*s == NULL)
X	    insideheader = FALSE;
X
X#ifdef LOGFILE
X	if (logf != NULL && insideheader &&
X	    ((printedlast && isspace(*s)) ||
X	     iskey(H_FROM, s) || iskey(H_TO, s) || iskey(H_CC, s) ||
X	     iskey(H_RETURN_PATH, s) || iskey(H_MESSAGE_ID, s))) {
X		 (void) fprintf(logf, "\t%s\n", s);
X		 printedlast = TRUE;
X	     } else
X		 printedlast = FALSE;
X#endif LOGFILE
X	(void) fprintf(outf, "%s\n", s);
X    }
X
X#ifdef LOGFILE
X    if (logf != NULL)
X	(void) fclose(logf);
X#endif LOGFILE
X
X    if (!Debug)
X	exit((pclose(outf) >> 8) & 0377);
X}
X
X/*
X**	ANYIN -- Does the target string contain chars from the pattern string?
X*/
Xanyin(t, p)
X    char *t;
X    register char *p;
X{
X    for (; *p != '\0'; p++)
X	if (index(t, *p) != NULL)
X	    return TRUE;
X    return FALSE;
X}
X
X/*
X**	ISKEY -- Checks if the line is prefixed by the supplied keyword
X**	(immediately followed by a colon)
X*/
Xiskey(key, line)
X    char *key, *line;
X{
X    for (; *key != NULL && *line != NULL; key++, line++)
X	if (MAKELC(*key) != MAKELC(*line))
X	    break;
X
X    return *key == NULL && *line == ':';
X}
X
X/*
X**	EXTRACT_ADDRESS -- Finds and extracts the machine address part
X**	of an address field.
X*/
X
Xchar *
Xextract_address(field, address)
X    char *field, *address;
X{
X    char *address_start = address;
X
X    while(*field && *field != COMMA && *field != '>')
X	switch (*field) {
X	  case '<':
X	    return extract_address(field, address_start);
X	  case '(':
X	    while (*field && *field != ')');
X	    field++;
X	    break;
X	  case '"':
X	    do
X		*address++ = *field++;
X	    while (*field && *field != '"');
X	    if (*field)
X		*address++ = *field++;
X	    break;
X	  case ' ':
X	    *address++ = *field++;
X	    EATSPACE(field);
X	    break;
X	  case '\\':
X	    *address++ = *field++;
X	    /* fall through */
X	  default:
X	    *address++ = *field++;
X	}
X    *address = NULL;
X    if (*field)
X	return index(field, COMMA)+1;
X    else
X	return field;
X}
X
X
END_OF_ida/aux/rmail.c
if test 6732 -ne `wc -c <ida/aux/rmail.c`; then
    echo shar: \"ida/aux/rmail.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ida/aux/xalparse.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/aux/xalparse.c\"
else
echo shar: Extracting \"ida/aux/xalparse.c\" \(6648 characters\)
sed "s/^X//" >ida/aux/xalparse.c <<'END_OF_ida/aux/xalparse.c'
X/*
X**  XALPARSE -- Xaliases file parser.
X**  Copyright (c) 1987 Lennart Lovstrand
X**  CIS Dept, Univ of Linkoping, Sweden
X**
X**  Use it, abuse it, but don't sell it.
X*/
X
X#include "useful.h"
X#include <stdio.h>
X#include <ctype.h>
X
X#ifndef lint
Xstatic char	SccsId[] = "@(#)xalparse.c 1.1 (lel@ida.liu.se) 4/12/87";
X#endif !lint
X
Xstruct alias {
X  bool a_in, a_out;
X  char *a_name;
X};
X
X#define ANULL	(struct alias *) NULL
X
X/*
X**  XPARSE -- Parse an xaliases file, producing aliases + generics files.
X**
X**	This program parses a file in ``xaliases'' format, producing
X**	a standard aliases file + a generics file.  The xaliases input
X**	file has entry of the following format:
X**		generic_list: mbox_list
X**	where elements in both lists are separated by commas.  In
X**	addition, each element in the mbox_list may be prefixed with
X**	either or both of the ``redirection characters,'' "<" and ">".
X
X**	In its simplest form, the generic_list has just one member and
X**	the mbox_list uses no redirection characters.  This
X**	corresponds exactly to the standard aliases format and
X**	function.
X
X**	The first extention is made by allowing more than one entry on
X**	the left hand side, thus making "a, b: c" as shorthand for the
X**	two entries "a: c" and "b: c".
X
X**	The second extension is made by adding the previously
X**	mentioned redirection characters to the addresses on the right
X**	hand side.  These control in what direction the aliases should
X**	be used.
X**
X**	etc.
X*/
X
Xint iflag = FALSE, Iflag = FALSE, Oflag = FALSE;
X
Xmain(argc, argv)
X     int argc;
X     char **argv;
X{
X  extern int optind;
X  extern char *optarg;
X  char c;
X  FILE *xaliases, *aliases, *generics;
X
X
X  if (argc != 4) {
X    fprintf(stderr, "usage: %s xaliases aliases generics\n", argv[0]);
X    exit(1);
X  }
X
X  if (strcmp(argv[1], "-") == 0)
X    xaliases = stdin;
X  else {
X    xaliases = fopen(argv[1], "r");
X    if (xaliases == NULL)
X      perror(argv[1]), exit(2);
X  }
X  aliases = fopen(argv[2], "w");
X  if (aliases == NULL)
X    perror(argv[2]), exit(2);
X  generics = fopen(argv[3], "w");
X  if (generics == NULL)
X    perror(argv[3]), exit(2);
X  
X  parsefile(xaliases, aliases, generics);
X  exit(0);
X}
X
Xparsefile(xaliases, aliases, generics)
X     FILE *xaliases, *aliases, *generics;
X{
X  extern char *index();
X  char line[BUFSIZ];
X  struct alias *rhs[BUFSIZ], *lhs[BUFSIZ];
X  struct alias **a, **r, **first;
X
X  while (readline(line, sizeof(line), xaliases) >= 0) {
X    parseline(line, lhs, rhs);
X
X    for (first = rhs; *first != ANULL; first++)
X      if ((*first)->a_in)
X	break;
X    if (*first != ANULL)
X      for (a = lhs; *a != ANULL; a++) {
X	fprintf(aliases, "%s:%s", (*a)->a_name, (*first)->a_name);
X	for (r = first+1; *r != ANULL; r++)
X	  if ((*r)->a_in)
X	    fprintf(aliases, ",%s", (*r)->a_name);
X	fprintf(aliases, "\n");
X      }
X
X    for (first = rhs; *first != ANULL; first++)
X      if ((*first)->a_out)
X	break;
X    if (*first != ANULL) {
X      fprintf(generics, "%s\t%s", lhs[0]->a_name, (*first)->a_name);
X      for (r = first+1; *r != ANULL; r++)
X	if ((*r)->a_out)
X	  fprintf(generics, " %s", (*r)->a_name);
X      fprintf(generics, "\n");
X    }
X
X    freebufs(lhs, rhs);
X  }
X}
X
X/**
X **	PEEKC -- Return the next char to be read.
X **/
X
Xpeekc(stream)
X     FILE *stream;
X{
X  int c;
X
X  c = getc(stream);
X  if (c != EOF)
X    ungetc(c, stream);
X  return c;
X}
X
X/**
X **	READLINE -- Read a (logical) line and return the # of chars read
X **/
X
Xreadline(buf, bufsiz, stream)
X     char *buf;
X     int bufsiz;
X     FILE *stream;
X{
X  int len;
X  char *sharp;
X
X  if (fgets(buf, bufsiz, stream) == NULL)
X    return -1;
X  buf[strlen(buf)-1] = '\0';
X
X  /*
X  if ((sharp = index(buf, '#')) != NULL)
X    *sharp = '\0';
X  */
X  if (buf[0] == '#')
X    buf[0] = '\0';
X
X  len = strlen(buf);
X  if (isspace(peekc(stream)))
X    return len + readline(&buf[len], bufsiz-len, stream);
X  else
X    return len;
X}
X
X/**
X **	PARSETHING
X **/
X
X
X#define LHS	1
X#define RHS	2
X
Xchar *
Xparsething(line, thing, side)
X     char *line;
X     struct alias **thing;
X     int side;
X{
X  register char *s, *d;
X  register bool
X    insideroute = FALSE,
X    insidestring = FALSE,
X    quotedchar = FALSE;
X  bool i_mark, o_mark;
X  char buf[BUFSIZ];
X  extern char *malloc();
X
X  s = line;
X  d = buf;
X
X  while (*s != '\0' && isspace(*s)) s++;
X  if (side == RHS) {
X    if (o_mark = (*s == '<')) s++;
X    if (i_mark = (*s == '>')) s++;
X    i_mark = i_mark || !o_mark;			/* default to '>' */
X    while (*s != '\0' && isspace(*s)) s++;
X  }
X
X  for (;*s != '\0'; s++) {
X    /* exit if non-quoted comma (or colon & LHS) */
X    if (!insidestring && !quotedchar && !insideroute &&
X	*s == ',' || ((side == LHS) && *s == ':'))
X      break;
X
X    /* copy if not unquoted whitespace */
X    if (insidestring || quotedchar || !isspace(*s))
X      *d++ = *s;
X
X    /* special quote character handling */
X    if (quotedchar)
X      quotedchar = FALSE;
X    else {
X      quotedchar = (*s == '\\');
X      if (!insidestring)
X	if (*s == '<')
X	  insideroute = TRUE;
X	else if (*s == '>')
X	  insideroute = FALSE;
X      if (*s == '"')
X	insidestring = !insidestring;
X    }
X  }
X  while (d > buf && isspace(d[-1])) d--;
X  *d = '\0';
X
X  if (d == buf && *s == '\0') {
X    *thing = ANULL;
X    return NULL;
X  } else {
X    *thing = (struct alias *) malloc(sizeof(struct alias));
X    (*thing)->a_in = i_mark;
X    (*thing)->a_out = o_mark;
X    (*thing)->a_name = malloc(strlen(buf) + 1);
X    strcpy((*thing)->a_name, buf);
X    return s;
X  }
X}
X
X/**
X **	PARSELINE
X **/
X
Xparseline(line, lhs, rhs)
X     char *line;
X     struct alias **lhs, **rhs;
X{
X  line--;
X
X  while ((line = parsething(line+1, lhs++, LHS)) != NULL)
X    if (*line == ':')
X      break;
X  *lhs = NULL;
X
X  if (line != NULL)
X    while ((line = parsething(line+1, rhs++, RHS)) != NULL);
X  *rhs = ANULL;
X}
X
X/**
X **	FREEBUFS
X **/
X
Xfreebufs(lhs, rhs)
X     struct alias **lhs, **rhs;
X{
X  while (*lhs != ANULL) {
X    free((*lhs)->a_name);
X    free(*lhs);
X    lhs++;
X  }
X  while (*rhs != ANULL) {
X    free((*rhs)->a_name);
X    free(*rhs);
X    rhs++;
X  }
X}
X
X/**
X **	COMPRESSLINE -- Remove all heading & trailing whitespace around items.
X **/
X
Xcompressline(line)
X     char *line;
X{
X  register char *d, *s, *b, *e;
X
X  for (d = s = line; *s != '\0'; s++) {
X		/* eat initial whitespace */
X    while (*s != '\0' && isspace(*s)) s++;
X    if (*s == '\0')
X      break;
X		/* remember beginning of "word" and find end */
X    b = s;
X    while (*s != '\0' && *s != ',' && *s != ':') s++;
X    e = s - 1;
X		/* backspace end thru whitespace */
X    while (e >= b && isspace(*e)) e--;
X		/* copy "word" w/o whitespace */
X    while (b <= e) *d++ = *b++;
X		/* copy separator */
X    *d++ = *s;
X    if (*s == '\0')
X      return;
X  }
X  *d = '\0';
X}
END_OF_ida/aux/xalparse.c
if test 6648 -ne `wc -c <ida/aux/xalparse.c`; then
    echo shar: \"ida/aux/xalparse.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ida/patches/alias.c.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/patches/alias.c.diff\"
else
echo shar: Extracting \"ida/patches/alias.c.diff\" \(5555 characters\)
sed "s/^X//" >ida/patches/alias.c.diff <<'END_OF_ida/patches/alias.c.diff'
X*** alias.c.orig	Fri Mar 13 18:51:08 1987
X--- alias.c	Wed May 27 02:03:20 1987
X***************
X*** 55,68 ****
X  */
X  
X  
X! #ifdef DBM
X! typedef struct
X! {
X! 	char	*dptr;
X! 	int	dsize;
X! } DATUM;
X  extern DATUM fetch();
X! #endif DBM
X  
X  alias(a, sendq)
X  	register ADDRESS *a;
X--- 55,63 ----
X  */
X  
X  
X! #if defined(DBM) && !defined(NDBM)
X  extern DATUM fetch();
X! #endif DBM && !NDBM
X  
X  alias(a, sendq)
X  	register ADDRESS *a;
X***************
X*** 122,128 ****
X  **		none.
X  **
X  **	Warnings:
X! **		The return value will be trashed across calls.
X  */
X  
X  char *
X--- 117,124 ----
X  **		none.
X  **
X  **	Warnings:
X! **		The return value will be trashed across calls
X! **		unless using a multi-file dbm (mdbm or ndbm).
X  */
X  
X  char *
X***************
X*** 131,151 ****
X  {
X  # ifdef DBM
X  	DATUM rhs, lhs;
X  
X  	/* create a key for fetch */
X! 	lhs.dptr = name;
X  	lhs.dsize = strlen(name) + 1;
X  	rhs = fetch(lhs);
X  	return (rhs.dptr);
X  # else DBM
X  	register STAB *s;
X  
X  	s = stab(name, ST_ALIAS, ST_FIND);
X  	if (s == NULL)
X  		return (NULL);
X  	return (s->s_alias);
X  # endif DBM
X  }
X  /*
X  **  INITALIASES -- initialize for aliasing
X  **
X--- 127,204 ----
X  {
X  # ifdef DBM
X  	DATUM rhs, lhs;
X+ 	char *lowname = xalloc(strlen(name) + 1);
X  
X  	/* create a key for fetch */
X! 	strcpy(lowname, name);
X! 	makelower(lowname);
X! 	lhs.dptr = lowname;
X  	lhs.dsize = strlen(name) + 1;
X+ # ifdef DEBUG
X+ 	if (tTd(27, 3))
X+ 	    printf("aliaslookup(\"%s\") => ", lhs.dptr);
X+ # endif DEBUG
X+ # ifdef NDBM
X+ 	rhs = dbm_fetch(AliasDbm.dbm, lhs);
X+ 	if (rhs.dptr != NULL)
X+ 	    rhs.dptr = newstr(rhs.dptr);
X+ # else NDBM
X  	rhs = fetch(lhs);
X+ # endif NDBM
X+ # ifdef DEBUG
X+ 	if (tTd(27, 3))
X+ 	    printf("%s\n", rhs.dptr == NULL ? "NOT_FOUND" : rhs.dptr);
X+ # endif DEBUG
X+ 	(void) free(lowname);
X  	return (rhs.dptr);
X  # else DBM
X  	register STAB *s;
X  
X  	s = stab(name, ST_ALIAS, ST_FIND);
X+ # ifdef DEBUG
X+ 	if (tTd(27, 3))
X+ 	    printf("%s\n", s == NULL ? "NOT_FOUND" : s->s_alias);
X+ # endif DEBUG
X  	if (s == NULL)
X  		return (NULL);
X  	return (s->s_alias);
X  # endif DBM
X  }
X+ 
X+ #ifdef NDBM
X+ /*
X+ **  NDBMINIT -- initialize the ndbm database
X+ **
X+ **	Only for use with NDBM and the keyed database table.
X+ **
X+ **	Parameters:
X+ **		aliasfile -- name of alias database file
X+ **
X+ **	Returns:
X+ **		None.
X+ **
X+ **	Side Effects:
X+ **		Opens the named database and initializes the DB_ALIAS
X+ **		entry of DbmTab.
X+ */
X+ ndbminit(aliasfile)
X+      char *aliasfile;
X+ {
X+   AliasDbm.name = aliasfile;
X+ 
X+   if (AliasDbm.dbm != DB_NOTYETOPEN)
X+     (void) dbm_close(AliasDbm.dbm);
X+ 
X+   AliasDbm.dbm = dbm_open(AliasDbm.name, O_RDWR, 0);
X+   if (AliasDbm.dbm == DB_NOSUCHFILE) {
X+     syserr("Cannot open %s", AliasDbm.name);
X+     NoAlias = TRUE;
X+     errno = 0;
X+     return;
X+   }
X+ }
X+ 
X+ #endif NDBM
X  /*
X  **  INITALIASES -- initialize for aliasing
X  **
X***************
X*** 200,206 ****
X--- 253,263 ----
X  	*/
X  
X  	if (!init)
X+ # ifdef NDBM
X+ 		ndbminit(aliasfile);
X+ # else NDBM
X  		dbminit(aliasfile);
X+ # endif NDBM
X  	atcnt = SafeAlias * 2;
X  	if (atcnt > 0)
X  	{
X***************
X*** 218,224 ****
X  
X  			sleep(30);
X  # ifdef NDBM
X! 			dbminit(aliasfile);
X  # endif NDBM
X  		}
X  	}
X--- 275,281 ----
X  
X  			sleep(30);
X  # ifdef NDBM
X! 			ndbminit(aliasfile);
X  # endif NDBM
X  		}
X  	}
X***************
X*** 236,242 ****
X  
X  	modtime = stb.st_mtime;
X  	(void) strcpy(buf, aliasfile);
X! 	(void) strcat(buf, ".pag");
X  	stb.st_ino = 0;
X  	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 
0))
X  	{
X--- 293,299 ----
X  
X  	modtime = stb.st_mtime;
X  	(void) strcpy(buf, aliasfile);
X! 	(void) strcat(buf, DB_PAGEXT);
X  	stb.st_ino = 0;
X  	if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 
0))
X  	{
X***************
X*** 356,362 ****
X  	{
X  		oldsigint = signal(SIGINT, SIG_IGN);
X  		(void) strcpy(line, aliasfile);
X! 		(void) strcat(line, ".dir");
X  		if (close(creat(line, DBMMODE)) < 0)
X  		{
X  			syserr("cannot make %s", line);
X--- 413,419 ----
X  	{
X  		oldsigint = signal(SIGINT, SIG_IGN);
X  		(void) strcpy(line, aliasfile);
X! 		(void) strcat(line, DB_PAGEXT);
X  		if (close(creat(line, DBMMODE)) < 0)
X  		{
X  			syserr("cannot make %s", line);
X***************
X*** 364,370 ****
X  			return;
X  		}
X  		(void) strcpy(line, aliasfile);
X! 		(void) strcat(line, ".pag");
X  		if (close(creat(line, DBMMODE)) < 0)
X  		{
X  			syserr("cannot make %s", line);
X--- 421,427 ----
X  			return;
X  		}
X  		(void) strcpy(line, aliasfile);
X! 		(void) strcat(line, DB_DIREXT);
X  		if (close(creat(line, DBMMODE)) < 0)
X  		{
X  			syserr("cannot make %s", line);
X***************
X*** 371,377 ****
X--- 428,438 ----
X  			(void) signal(SIGINT, oldsigint);
X  			return;
X  		}
X+ # ifdef NDBM
X+ 		ndbminit(aliasfile);
X+ # else NDBM
X  		dbminit(aliasfile);
X+ # endif NDBM
X  	}
X  
X  	/*
X***************
X*** 475,480 ****
X--- 536,542 ----
X  				break;
X  			LineNumber++;
X  		}
X+ 
X  		if (al.q_mailer != LocalMailer)
X  		{
X  			syserr("cannot alias non-local names");
X***************
X*** 497,503 ****
X--- 559,569 ----
X  			key.dptr = al.q_user;
X  			content.dsize = rhssize;
X  			content.dptr = rhs;
X+ # ifdef NDBM
X+ 			(void) dbm_store(AliasDbm.dbm, key, content);
X+ # else NDBM
X  			store(key, content);
X+ # endif NDBM
X  		}
X  		else
X  # endif DBM
X***************
X*** 521,527 ****
X--- 587,597 ----
X  
X  		key.dsize = 2;
X  		key.dptr = "@";
X+ # ifdef NDBM
X+ 		(void) dbm_store(AliasDbm.dbm, key, key);
X+ # else NDBM
X  		store(key, key);
X+ # endif NDBM
X  
X  		/* restore the old signal */
X  		(void) signal(SIGINT, oldsigint);
END_OF_ida/patches/alias.c.diff
if test 5555 -ne `wc -c <ida/patches/alias.c.diff`; then
    echo shar: \"ida/patches/alias.c.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ida/patches/op.me.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/patches/op.me.diff\"
else
echo shar: Extracting \"ida/patches/op.me.diff\" \(12488 characters\)
sed "s/^X//" >ida/patches/op.me.diff <<'END_OF_ida/patches/op.me.diff'
X*** op.me.orig	Fri Mar 13 18:47:47 1987
X--- op.me	Tue Apr 28 18:20:28 1987
X***************
X*** 7,13 ****
X  .\"
X  .\"	@(#)op.me	5.8 (Berkeley) 5/9/86
X  .\"
X! .\" eqn % | troff -me
X  .\"if n .ls 2
X  .\".he 'Sendmail Installation and Operation Guide''%'
X  .\".fo 'Version 5.8''Last Mod 5/9/86'
X--- 7,13 ----
X  .\"
X  .\"	@(#)op.me	5.8 (Berkeley) 5/9/86
X  .\"
X! .\" pic % | eqn | troff -me
X  .\"if n .ls 2
X  .\".he 'Sendmail Installation and Operation Guide''%'
X  .\".fo 'Version 5.8''Last Mod 5/9/86'
X***************
X*** 40,46 ****
X  Eric Allman
X  Britton-Lee, Inc.
X  .sp
X! Version 5.8
X  .)l
X  .sp 2
X  .pp
X--- 40,51 ----
X  Eric Allman
X  Britton-Lee, Inc.
X  .sp
X! .sz 8
X! Enhancements by Lennart L\o"o\(um"vstrand
X! Dept of Comp and Info Sci, U of Link\o"o\(um"ping, Sweden
X! .sz 10
X! .sp
X! Version 5.8++
X  .)l
X  .sp 2
X  .pp
X***************
X*** 524,529 ****
X--- 529,546 ----
X  will print the contents of the mail queue;
X  see below).
X  This should be a link to /usr/lib/sendmail.
X+ .sh 3 "/usr/ucb/bsmtp"
X+ .pp
X+ If
X+ .i sendmail
X+ is invoked as
X+ .q bsmtp,
X+ it will simulate the
X+ .b \-bb
X+ flag (i.e.,
X+ .i sendmail
X+ will start accepting batched SMTP commands from stdin; see below).
X+ This should be a link to /usr/lib/sendmail.
X  .sh 1 "NORMAL OPERATIONS"
X  .sh 2 "Quick Configuration Startup"
X  .pp
X***************
X*** 823,834 ****
X  .(b
X  name: name1, name2, ...
X  .)b
X! Only local names may be aliased;
X  e.g.,
X  .(b
X  eric@mit-xx: eric@berkeley.EDU
X  .)b
X! will not have the desired effect.
X  Aliases may be continued by starting any continuation lines
X  with a space or a tab.
X  Blank lines and lines beginning with a sharp sign
X--- 840,855 ----
X  .(b
X  name: name1, name2, ...
X  .)b
X! It is possible not
X! only local names may be aliased,
X! but even non-locals if the configuration file is properly set up;
X  e.g.,
X  .(b
X  eric@mit-xx: eric@berkeley.EDU
X  .)b
X! will have the desired effect if the
X! .i aliases
X! database is searched before determining mailer in ruleset 0.
X  Aliases may be continued by starting any continuation lines
X  with a space or a tab.
X  Blank lines and lines beginning with a sharp sign
X***************
X*** 1136,1141 ****
X--- 1157,1170 ----
X  it defaults to
X  .i sendmail.cf
X  in the current directory.
X+ .pp
X+ You can also specify a different frozen configuration file with the
X+ .b \-Z
X+ option.  It is used the same way as the
X+ .b \-C
X+ flag and defaults to
X+ .i sendmail.fc
X+ in the current directory.
X  .sh 2 "Changing the Values of Options"
X  .pp
X  Options can be overridden using the
X***************
X*** 1705,1712 ****
X  .ta 1i
X  Path	The pathname of the mailer
X  Flags	Special flags for this mailer
X! Sender	A rewriting set for sender addresses
X! Recipient	A rewriting set for recipient addresses
X  Argv	An argument vector to pass to this mailer
X  Eol	The end-of-line string for this mailer
X  Maxsize	The maximum message length to this mailer
X--- 1734,1741 ----
X  .ta 1i
X  Path	The pathname of the mailer
X  Flags	Special flags for this mailer
X! Sender	Rewriting sets for sender addresses
X! Recipient	Rewriting sets for recipient addresses
X  Argv	An argument vector to pass to this mailer
X  Eol	The end-of-line string for this mailer
X  Maxsize	The maximum message length to this mailer
X***************
X*** 1879,1886 ****
X  l	The format of the UNIX from line
X  n	The name of the daemon (for error messages)
X  o	The set of "operators" in addresses
X! q	default format of sender address
X  .)b
X  The
X  .b $e
X  macro is printed out when SMTP starts up.
X--- 1908,1926 ----
X  l	The format of the UNIX from line
X  n	The name of the daemon (for error messages)
X  o	The set of "operators" in addresses
X! q	Default format of sender address
X  .)b
X+ In addition, you also have the
X+ .b $k
X+ macro:
X+ .(b
X+ .ta 4n
X+ k	Your node's UUCP hostname
X+ .)b
X+ which is optional to define (it defaults to the value of
X+ .b $w,
X+ your normal hostname).
X+ .pp
X  The
X  .b $e
X  macro is printed out when SMTP starts up.
X***************
X*** 2107,2114 ****
X  \fB$*\fP	Match zero or more tokens
X  \fB$+\fP	Match one or more tokens
X  \fB$\-\fP	Match exactly one token
X! \fB$=\fP\fIx\fP	Match any token in class \fIx\fP
X! \fB$~\fP\fIx\fP	Match any token not in class \fIx\fP
X  .)b
X  If any of these match,
X  they are assigned to the symbol
X--- 2147,2154 ----
X  \fB$*\fP	Match zero or more tokens
X  \fB$+\fP	Match one or more tokens
X  \fB$\-\fP	Match exactly one token
X! \fB$=\fP\fIx\fP	Match any sequence of tokens in class \fIx\fP
X! \fB$~\fP\fIx\fP	Match any sequence of tokens not in class \fIx\fP
X  .)b
X  If any of these match,
X  they are assigned to the symbol
X***************
X*** 2141,2149 ****
X  unless they begin with a dollar sign.
X  Metasymbols are:
X  .(b
X! .ta \w'$#mailer  'u
X  \fB$\fP\fIn\fP	Substitute indefinite token \fIn\fP from LHS
X! \fB$[\fP\fIname\fP\fB$]\fP	Canonicalize \fIname\fP
X  \fB$>\fP\fIn\fP	\*(lqCall\*(rq ruleset \fIn\fP
X  \fB$#\fP\fImailer\fP	Resolve to \fImailer\fP
X  \fB$@\fP\fIhost\fP	Specify \fIhost\fP
X--- 2181,2190 ----
X  unless they begin with a dollar sign.
X  Metasymbols are:
X  .(b
X! .ta \w'$(x key$@arg$:default$)  'u
X  \fB$\fP\fIn\fP	Substitute indefinite token \fIn\fP from LHS
X! \fB$[\fP\fIname\fP\fB$:\fP\fIdefault\fP\fB$]\fP	Canonicalize \fIname\fP
X! \fB$(\fP\fIx key\fP\fB$@\fP\fIarg\fP\fB$:\fP\fIdefault\fP\fB$)\fP	Lookup 
the \fIkey\fP in database \fIx\fP, and sprintf \fIarg\fP through the result.
X  \fB$>\fP\fIn\fP	\*(lqCall\*(rq ruleset \fIn\fP
X  \fB$#\fP\fImailer\fP	Resolve to \fImailer\fP
X  \fB$@\fP\fIhost\fP	Specify \fIhost\fP
X***************
X*** 2178,2184 ****
X--- 2219,2270 ----
X  .q $[[128.32.130.2]$]
X  would become
X  .q vangogh.berkeley.edu.
X+ The
X+ .b $: \c
X+ .i default
X+ part is optional and specifies what should be substituted
X+ in case that the
X+ .i name
X+ is not known to 
X+ .i gethostent \|(3).
X  .pp
X+ General 
X+ .i dbm \|(3)
X+ databases may be searched using the
X+ .b $( \c
X+ .i "x key" \c
X+ .b $)
X+ syntax.  The expression may be supplied with an optional result argument,
X+ .b $@ \c
X+ .i arg,
X+ and a default string,
X+ .b $: \c
X+ .i default.
X+ The database is specified by a single character and defined using the
X+ .q K
X+ option as in
X+ .(b
X+ OKP/usr/lib/mail/pathtable
X+ .)b
X+ which defines database
X+ .b P
X+ to be associated with the dbm files /usr/lib/mail/pathtable.{dir,pag}.
X+ An expression like
X+ .q "$(P sun $@ soren $: backbone!sun!soren $)"
X+ would look for the string
X+ .q sun
X+ in the
X+ .q P
X+ database and sprintf
X+ .q soren
X+ through the result, or substitute
X+ .q backbone!sun!soren
X+ if the key could not be found.
X+ If no 
X+ .i default
X+ argument is supplied and the key could not be found, the whole
X+ expression is replaced with the key.
X+ .pp
X  The
X  .b $> \c
X  .i n
X***************
X*** 2191,2197 ****
X  then becomes
X  the substitution for this rule.
X  .pp
X! The
X  .b $#
X  syntax should
X  .i only
X--- 2277,2283 ----
X  then becomes
X  the substitution for this rule.
X  .pp
X! In most cases, the
X  .b $#
X  syntax should
X  .i only
X***************
X*** 2236,2252 ****
X  .b $@
X  and
X  .b $:
X! prefixes may precede a
X  .b $>
X! spec;
X  for example:
X  .(b
X  .ta 8n
X! R$+	$:$>7$1
X  .)b
X  matches anything,
X! passes that to ruleset seven,
X! and continues;
X  the
X  .b $:
X  is necessary to avoid an infinite loop.
X--- 2322,2338 ----
X  .b $@
X  and
X  .b $:
X! prefixes may precede
X  .b $>
X! specs;
X  for example:
X  .(b
X  .ta 8n
X! R$+	$:$>7$>8$1
X  .)b
X  matches anything,
X! passes that to ruleset eight and the result of that to ruleset seven,
X! and finally continues;
X  the
X  .b $:
X  is necessary to avoid an infinite loop.
X***************
X*** 2854,2859 ****
X--- 2940,2946 ----
X  Other flags are described
X  in Appendix C.
X  .pp
X+ .pp
X  The S and R fields in the mailer description
X  are per-mailer rewriting sets
X  to be applied to sender and recipient addresses
X***************
X*** 2884,2889 ****
X--- 2971,2983 ----
X  These sets can also be used
X  to do special purpose output rewriting
X  in cooperation with ruleset four.
X+ If required, the R and S rulesets may be specified independently for envelop
e
X+ and header addresses by separating them with a slash.  E.g.,
X+ .q R=13/14
X+ means that envelope recipient addresses should be sent through ruleset 13
X+ while those in the header should be passed to ruleset 14. 
X+ You can disable any mailer specific rewriting by specifying the ruleset as
X+ zero or by leaving it blank.
X  .pp
X  The E field defines the string to use
X  as an end-of-line indication.
X***************
X*** 3026,3031 ****
X--- 3120,3126 ----
X  i	Initialize the alias database
X  p	Print the mail queue
X  z	Freeze the configuration file
X+ b	Run in Batched SMTP mode
X  .)b
X  The special processing for the
X  ARPANET
X***************
X*** 3050,3055 ****
X--- 3145,3155 ----
X  .i Sendmail
X  runs as the invoking user (rather than root)
X  when this flag is specified.
X+ .ip \-Z\fIfile\fP
X+ Use a different frozen configuration file.
X+ .i Sendmail
X+ runs as the invoking user (rather than root)
X+ when this flag is specified.
X  .ip \-d\fIlevel\fP
X  Set debugging level.
X  .ip \-o\fIx\|value\fP
X***************
X*** 3166,3171 ****
X--- 3266,3285 ----
X  for SMTP.
X  .ip i
X  Ignore dots in incoming messages.
X+ .ip K\fIxfile\fP
X+ Declare the 
X+ keyed database
X+ .i x
X+ to be associated with the 
X+ .i dbm \|(3)
X+ file
X+ .i file.
X+ (\fIX\fP is a single letter.)
X+ The database
X+ .q @
X+ is always bound to the 
X+ .i aliases
X+ database.
X  .ip L\fIn\fP
X  Set the default log level to
X  .i n .
X***************
X*** 3406,3415 ****
X  will not terminate the message prematurely.
X  .ip L
X  Limit the line lengths as specified in RFC821.
X! .ip P
X  Use the return-path in the SMTP
X  .q "MAIL FROM:"
X! command
X  rather than just the return address;
X  although this is required in RFC821,
X  many hosts do not process return paths properly.
X--- 3520,3531 ----
X  will not terminate the message prematurely.
X  .ip L
X  Limit the line lengths as specified in RFC821.
X! .ip p
X  Use the return-path in the SMTP
X  .q "MAIL FROM:"
X! command or in the UUCP
X! .q From_
X! line
X  rather than just the return address;
X  although this is required in RFC821,
X  many hosts do not process return paths properly.
X***************
X*** 3450,3455 ****
X--- 3566,3587 ----
X  Escape lines beginning with
X  .q From
X  in the message with a `>' sign.
X+ .ip V
X+ Make all header addresses UUCP !-relative with respect to ourselves
X+ and the recipient host.  This means that all header lines will have
X+ working paths relative to the recipient host.  Routes through the
X+ remote host, i.e. addresses that begin with
X+ .q remote!
X+ are stripped of that part unless the ultimate
X+ recipient resides on the remote host (i.e., there are no more bangs in
X+ the address).  All other addresses are prefixed with
X+ .q ourhost!
X+ if not already there.
X+ .i Ourhost
X+ is fetched from the 
X+ .b $k
X+ macro, which defaults to your hostname as supplied by
X+ .i gethostname \|(3).
X  .+c "OTHER CONFIGURATION"
X  .rm $0
X  .nr ii 1i
X***************
X*** 3603,3608 ****
X--- 3735,3749 ----
X  that allows multiple databases will be used.
X  .q DBM
X  must also be set.
X+ .ip MDBM
X+ If set, Maryland's
X+ .i mdbm \|(3)
X+ package should be substituted for the
X+ .i ndbm \|(3)
X+ routines.  This should only be used if you want the keyed database
X+ functionality (\fB$(x key$)\fP), but don't have
X+ .i ndbm \|(3)
X+ available.
X  .ip DEBUG
X  If set, debugging information is compiled in.
X  To actually get the debugging output,
X***************
X*** 3929,3935 ****
X  .ip "/usr/lib/sendmail"
X  The binary of
X  .i sendmail .
X! .ip /usr/bin/newaliases
X  A link to /usr/lib/sendmail;
X  causes the alias database to be rebuilt.
X  Running this program is completely equivalent to giving
X--- 4070,4076 ----
X  .ip "/usr/lib/sendmail"
X  The binary of
X  .i sendmail .
X! .ip /usr/ucb/newaliases
X  A link to /usr/lib/sendmail;
X  causes the alias database to be rebuilt.
X  Running this program is completely equivalent to giving
X***************
X*** 3937,3948 ****
X  the
X  .b \-bi
X  flag.
X! .ip /usr/bin/mailq
X  Prints a listing of the mail queue.
X  This program is equivalent to using the
X  .b \-bp
X  flag to
X  .i sendmail .
X  .ip /usr/lib/sendmail.cf
X  The configuration file,
X  in textual form.
X--- 4078,4095 ----
X  the
X  .b \-bi
X  flag.
X! .ip /usr/ucb/mailq
X  Prints a listing of the mail queue.
X  This program is equivalent to using the
X  .b \-bp
X  flag to
X  .i sendmail .
X+ .ip /usr/ucb/bsmtp
X+ A link to /usr/lib/sendmail; starts up
X+ .i sendmail
X+ in Batched SMTP mode (as if supplied with the
X+ .b \-bb
X+ option).
X  .ip /usr/lib/sendmail.cf
X  The configuration file,
X  in textual form.
END_OF_ida/patches/op.me.diff
if test 12488 -ne `wc -c <ida/patches/op.me.diff`; then
    echo shar: \"ida/patches/op.me.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ida/patches/sendmail.h.diff -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ida/patches/sendmail.h.diff\"
else
echo shar: Extracting \"ida/patches/sendmail.h.diff\" \(5801 characters\)
sed "s/^X//" >ida/patches/sendmail.h.diff <<'END_OF_ida/patches/sendmail.h.diff
'
X*** sendmail.h.orig	Fri Mar 13 18:51:00 1987
X--- sendmail.h	Wed May 27 01:58:25 1987
X***************
X*** 32,38 ****
X  # include "useful.h"
X  
X  # ifdef LOG
X! # include <sys/syslog.h>
X  # endif LOG
X  
X  # ifdef DAEMON
X--- 32,42 ----
X  # include "useful.h"
X  
X  # ifdef LOG
X! #  ifdef vax
X! #   include <sys/syslog.h>
X! #  else vax
X! #   include <syslog.h>
X! #  endif vax
X  # endif LOG
X  
X  # ifdef DAEMON
X***************
X*** 121,128 ****
X  	BITMAP	m_flags;	/* status flags, see below */
X  	short	m_mno;		/* mailer number internally */
X  	char	**m_argv;	/* template argument vector */
X! 	short	m_s_rwset;	/* rewriting set for sender addresses */
X! 	short	m_r_rwset;	/* rewriting set for recipient addresses */
X  	char	*m_eol;		/* end of line string */
X  	long	m_maxsize;	/* size limit on message to this mailer */
X  };
X--- 125,134 ----
X  	BITMAP	m_flags;	/* status flags, see below */
X  	short	m_mno;		/* mailer number internally */
X  	char	**m_argv;	/* template argument vector */
X! 	short	m_se_rwset;	/* rewriting ruleset for envelope senders */
X! 	short	m_sh_rwset;	/* rewriting ruleset for header senders */
X! 	short	m_re_rwset;	/* rewriting ruleset for envelope recipients */
X! 	short	m_rh_rwset;	/* rewriting ruleset for header recipient */
X  	char	*m_eol;		/* end of line string */
X  	long	m_maxsize;	/* size limit on message to this mailer */
X  };
X***************
X*** 130,135 ****
X--- 136,142 ----
X  typedef struct mailer	MAILER;
X  
X  /* bits for m_flags */
X+ # define M_BSMTP	'B'	/* don't wait for SMTP responses */
X  # define M_CANONICAL	'C'	/* make addresses canonical "u@dom" */
X  # define M_EXPENSIVE	'e'	/* it costs to use this mailer.... */
X  # define M_ESCFROM	'E'	/* escape From lines to >From */
X***************
X*** 147,152 ****
X--- 154,160 ----
X  # define M_RESTR	'S'	/* must be daemon to execute */
X  # define M_USR_UPPER	'u'	/* preserve user case distinction */
X  # define M_UGLYUUCP	'U'	/* this wants an ugly UUCP from line */
X+ # define M_RELATIVIZE	'V'	/* !-relativize all addresses */
X  # define M_XDOT		'X'	/* use hidden-dot algorithm */
X  
X  EXTERN MAILER	*Mailer[MAXMAILERS+1];
X***************
X*** 317,326 ****
X  # define CONDELSE	'\033'	/* conditional else */
X  # define CONDFI		'\034'	/* conditional fi */
X  
X! /* bracket characters for host name lookup */
X  # define HOSTBEGIN	'\035'	/* hostname lookup begin */
X  # define HOSTEND	'\036'	/* hostname lookup end */
X  
X  /* \001 is also reserved as the macro expansion character */
X  /*
X  **  Information about hosts that we have looked up recently.
X--- 325,338 ----
X  # define CONDELSE	'\033'	/* conditional else */
X  # define CONDFI		'\034'	/* conditional fi */
X  
X! /* bracket characters for host name & database keyed lookup */
X  # define HOSTBEGIN	'\035'	/* hostname lookup begin */
X  # define HOSTEND	'\036'	/* hostname lookup end */
X+ # define KEYBEGIN	'\037'	/* keyed lookup begin */
X+ # define KEYEND		'\017'	/* keyed lookup end */
X  
X+ /*
X+ 
X  /* \001 is also reserved as the macro expansion character */
X  /*
X  **  Information about hosts that we have looked up recently.
X***************
X*** 379,384 ****
X--- 391,401 ----
X  # define ST_ALIAS	4	/* an alias */
X  # define ST_HOST	5	/* host information */
X  
X+ /* s_host is defined is /usr/include/whatever on sun's */
X+ # ifdef s_host
X+ #  undef s_host
X+ # endif
X+ 
X  # define s_class	s_value.sv_class
X  # define s_address	s_value.sv_addr
X  # define s_mailer	s_value.sv_mailer
X***************
X*** 438,443 ****
X--- 455,461 ----
X  #define MD_INITALIAS	'i'		/* initialize alias database */
X  #define MD_PRINT	'p'		/* print the queue */
X  #define MD_FREEZE	'z'		/* freeze the configuration file */
X+ #define MD_BSMTP	'b'		/* batched smtp mode */
X  
X  
X  EXTERN char	SendMode;	/* send mode, see below */
X***************
X*** 465,470 ****
X--- 483,525 ----
X   */
X  #define	MAX_ERRNO	100
X  /*
X+ **  Database ([n]dbm) definitions.
X+ */
X+ 
X+ #ifdef DBM
X+ 
X+ typedef struct {
X+ 	char	*dptr;
X+ 	int	dsize;
X+ } DATUM;
X+ 
X+ # define DB_DIREXT	".dir"
X+ # define DB_PAGEXT	".pag"
X+ 
X+ # ifdef NDBM
X+ 
X+ #  undef DBM			/* while including ndbm.h */
X+ #  include <ndbm.h>		/* DBM is typedef'ed here */
X+ typedef DBM DBMFILE;		/* move typedef to DBMFILE */
X+ #  define DBM			/* and restore DBM definition */
X+ #  include <fcntl.h>		/* needed for dbm_open */
X+ 
X+ #  define DATUM datum		/* use the definition in ndbm.h */
X+ 
X+ struct dbm_table {
X+   char *name;			/* database file name */
X+   DBMFILE *dbm;		/* dbm file descriptor */
X+ };
X+ 
X+ #  define DB_NOSUCHFILE	((DBMFILE *)  0) /* file could not be found */
X+ #  define DB_NOTYETOPEN	((DBMFILE *) -1) /* file has not yet been opene
d */
X+ 
X+ #  define DB_ALIAS	'@'	/* "name" of aliases database */
X+ #  define AliasDbm	DbmTab[DB_ALIAS]
X+ 
X+ # endif NDBM
X+ #endif DBM
X+ /*
X  **  Global variables.
X  */
X  
X***************
X*** 525,534 ****
X--- 580,593 ----
X  EXTERN int	WkClassFact;	/* multiplier for message class -> priority */
X  EXTERN int	WkRecipFact;	/* multiplier for # of recipients -> priority *
/
X  EXTERN int	WkTimeFact;	/* priority offset each time this job is run */
X+ EXTERN bool	SplitRewriting;	/* use split envelope/header rewriting */
X  EXTERN int	CheckPointLimit;	/* deliveries before checkpointing */
X  EXTERN char	*PostMasterCopy;	/* address to get errs cc's */
X  EXTERN char	*TrustedUsers[MAXTRUST+1];	/* list of trusted users */
X  EXTERN char	*UserEnviron[MAXUSERENVIRON+1];	/* saved user environment */
X+ #ifdef NDBM
X+ EXTERN struct dbm_table DbmTab[128];	/* keyed database table */
X+ #endif NDBM
X  /*
X  **  Trace information
X  */
X***************
X*** 572,574 ****
X--- 631,645 ----
X  extern char	*sfgets();
X  extern char	*queuename();
X  extern time_t	curtime();
X+ 
X+ /*
X+ **  Metamacro definitions.
X+ */
X+ 
X+ struct metamac
X+ {
X+ 	char	metaname;
X+ 	char	metaval;
X+ };
X+ 
X+ extern struct metamac	MetaMacros[];
END_OF_ida/patches/sendmail.h.diff
if test 5801 -ne `wc -c <ida/patches/sendmail.h.diff`; then
    echo shar: \"ida/patches/sendmail.h.diff\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 7\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 7 archives.
    echo "See ida/README and ida/INSTALL for further instructions."
    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