Subject: v16i076: IDA Sendmail kit, Part04/08 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Lennart Lovstrand Posting-number: Volume 16, Issue 76 Archive-name: ida2/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh ida/README <<'END_OF_ida/README' X# X# README -- The IDA Sendmail Enhancement Kit. X# Copyright (c) 1987, 1988 Lennart Lovstrand X# CIS Dept, Univ of Linkoping, Sweden X# X# Use it, abuse it, but don't sell it. X# X# Revision 1 of Wed May 27 04:29:05 MET DST 1987 [sendmail 5.51] X# Revision 1.1 of Sun Jun 19 00:36:52 BST 1988 [sendmail 5.58] X# Revision 1.2 of Thu Aug 25 13:36:47 BST 1988 [sendmail 5.59] X# Revision 1.2.5 of Thu Sep 15 20:17:12 1988 [sendmail 5.59] X X X Welcome to The IDA Sendmail Enhancement Kit. X X XThis Kit includes a set of source code modifications to the BSD 4.3 Xsendmail program (version 5.59), which will enable it to have direct Xaccess to dbm(3) files, separate envelope/header rewritings, multi-token Xclass matches, and many other things. Also included is the IDA Sendmail XMaster Configuration file and a sample setup used at the CIS Dept, U of XLinkoping. The configuration file together with the supplied data files Xand utility programs, implement such nice features as pathalias based Xsystems routing within sendmail, fully !-/@-translating rulesets, and Xgeneric local user addresses. X XThe new sendmail functions are breifly listed below and further Xdescribed in the accompanying paper, which also discusses electronic Xmail addressing in general and hybrid addresses in particular. (The Xnumbers to the right indicate in what section of the paper they are Xdescribed.) X X Nameserver Default Argument............................... 7.1 X Direct Access to Dbm(3) Files............................. 7.2 X Batched SMTP Support...................................... 7.3 X Separate Envelope/Header Rewriting Rulesets............... 7.4 X Separate Local UUCP Host Name............................. 7.5 X Return Path for UUCP Mailers.............................. 7.6 X UUCP Header Address Relativization........................ 7.7 X Support for Multi-Token Matches........................... 7.8 X Support for Embedded Subruleset Calls..................... 7.9 X Elaborate Matching Algorithm for Unknown Local Recipients 7.10 X Support for Maryland's Mdbm Package...................... 7.11 X Improved Test Mode Output................................ 7.12 X Better To: and Cc: Headers of Returned Messages.......... 7.13 X Queue Bug Fixed.......................................... 7.14 X Shared Input SMTP Bug Tentatively Fixed.................. 7.15 X Optional BSD 2.9 and 4.2 Compatibility Code.............. 7.16 X Miscellaneous Changes.................................... 7.17 X XIf you are reading this without actually having a copy of the kit, look Xfor it in your nearest comp.sources.unix archive or use anonymous ftp to Xfetch a compressed tape archive from arisia.xerox.com in ftp1/ida.tar.Z. X XRead more in INSTALL about how to get it all together. Send bug reports Xand dito fixes to the author, but please note he (and his employer) may Xbelieve that there is more in life than maintaining everybody else's Xmail systems. Also note that this is an unsupported package as far as Xthe University of Linkoping and Rank Xerox Ltd are concerend -- so do Xnot go to your local Xerox Copy Center and complain about the rewriting Xrules. Remember: you got it for free => you can't get your money back. X XEnjoy! X X--Lennart Lovstrand X Rank Xerox EuroPARC X 61 Regent Street X Cambridge X CB2 1AB X England X X DARPA Internet: Lovstrand.EuroPARC@Xerox.COM X Xerox Internet: Lovstrand:EuroPARC:RX X X X====================================================================== XAddendum for the 2nd release (1.1) of the IDA Sendmail Enhancement Kit X---------------------------------------------------------------------- X XRelease 1.1 of the Kit has been upgraded to work with Sun's ported Xversion of sendmail (5.58). Only minor changes has been made to Xsendmail.h.diff and srvrsmtp.c.diff in order to patch the new source Xcorrectly, but queue.c.diff was removed entirely since that bug now Xshould be fixed in the BSD release -- subsequently, you should ignore Xsection 7.14 of the IDA Kit documentation. Expect some of the patches Xto install with a minor offset reported by patch -- they have not been Xchanged since 1.0 but should still be correct. X X X====================================================================== XAddendum for the 3rd release (1.2) of the IDA Sendmail Enhancement Kit X---------------------------------------------------------------------- X XA complete new set of patches has been made for this release, which Xapplies to sendmail 5.59 with MX. For this, the BSD4.2 and BSD2.9 Xcompatibility code has been removed but it will still compile on Suns Xwith SunOS 3.x or greater. A new addition is the support for Sun's XYellow Pages in the dbm routines--if the name of a database you specify Xbegins with a percent sign, eg: X X OKP%pathtable X Xthen lookups to that database will be handled by YP instead of a local Xdbm file. See example in lib/Makefile on how to set up a shared Xpathalias database for a local area network. X XFurthermore, the code that searches dbm files has been changed to Xautomatically notice if a database has been changed and to reinitialize Xitself accordingly. Also, both sendmail and dbm(1) has been modified to Xuse file locking when updating local dbm files. This won't help for Xshared nfs file systems, though--use YP instead. X XThe syntax for set (class) declarations has been extended to allow Xprograms as well as files to define a set. If a file name in an F Xstatement begins with a vertical bar, as in: X X FU|uuname X Xit is assumed to be followed by the name of a program, which will Xproduce the set's members on its standard output. Scanf formats are Xallowed as usual. X XA set of patches received from gamiddleton@waterloo has been included in Xthis release: X X$&x -- Delayed macro evaluation [from gatech?] X X This macro is used in the config file to delay interpretation X until run-time. A typical application would be to delay X evaluation of the 'r' macro, which is usually passed to sendmail X by other programs to define the sending protocol; e.g. rmail X does: X sendmail -oMrUUCP ... X If you don't use $&r and then freeze the configuration file, X you'll get the value of $r at "freezing" time instead of X "thawing" time. Note that this only applies to RHS expressions X in rules; use $r elsewhere. X X$!x -- RFC822 quoted macro expansion X X Used to keep address legal wrt RFC822 when constructing the X From: line for a local user. The macro is expanded as usual, X but if any character in it is illegal, the whole string gets X quoted. Eg, with: X Dq$?x$!x $.<$g> X an address like 'Joe User @ Waterloo ' X would be rewritten as '"Joe User @ Waterloo" ' X to make it legal. X XAddress rewriting loop detection X X We found address rewriting was looping if the sendmail.cf file X was slightly wrong; this code keeps sendmail from looping forever. X XAn extra compile-time frozen file check X X The date of the frozen configuration file is compared to the X time sendmail itself was compiled. If the .fc file is older, it X is ignored and the .cf file is used instead. X X XBe aware that you will need the latest version (4.8) of BIND in order to Xcompile sendmail 5.59 with MX support. If you don't want to install its Xinclude and library files in the system directories, add an additional X-I{bind}/include to CFLAGS in sendmail/src/Makefile and -L{bind}/res in Xfront of the LIBS variable ({bind} = location of bind directory). X XSun users: Make sure that your syslog.o {in /lib/libc.a} has been Xcompiled with the BSD4.3 netdb.h if you want to use the LOG option. XAlso note that sendmail compiled with bind's resolver won't use the XYellow Pages host table at all. For your convenience, a compressed Xbinary copy of IDA sendmail for Sun-3 is available in X~ftp/pub1/ida-sendmail-sun3.Z on Arisia.Xerox.COM via anonymous ftp. X X XNote for BIND experts X--------------------- XOne of the changes I made to the code was to use the gethostbyname() Xthat BIND's resolver supplies instead of the internal getcanonname() Xthat does repeated res_searches for CNAME records. This was because I Xneeded both an acknowledgement of the domain's existance as well as its Xfully qualified name (eg. foo.bar => foo.bar.edu), of which the old code Xsupported neither. But this now means that there has to be an IN A X(Internet address) record for the domain name we wish to canonicalize. XAnother possible option could have been to modify getcanonname() to do Xwildcard lookups, but I'm not convinced that's the right way to go. On Xthe other hand, I'm no name server wizard, so if you think I'm wrong, Xplease let me know why (and how) and I'll change it. X X XBugs X---- X o There is currently no equivalent of $[...$] for MX records, so the X IDA Sendmail.mc file will always use any available pathalias routing X before defaulting to MX/TCP. X o When a name server responds with an athoritive "host not found", X there is currently no way of finding out who is responsible for this X information -- we'll need to do our own NS lookups to do so. X o It has been reported that a syserr of "net timeout" {in util.c} may X cause sendmail to exit ungracefully without removing the lock file X and without making a note of which recipients the message already X has been delivered to. X X XMinor Revisions X--------------- X1.2.1 - Various changes to Sendmail.mc regarding its interpretation of X hybrid addresses; made to parse according to receiving protocol. X (Reimplemented BANGIMPLIESUUCP; obsoleted UUCPPRECEDENCE; added X STRICTLY822, UUCPMAILER.) X1.2.2 - Made database lookups NOT send result through sprintf if there X was no sprintf arg in call, ie. $(X foo $) or $(X foo $: bar $). X This will make it less error-prone for usage with non-pathalias X databases. Note, however, that from this version of IDA, double X percent signs will NOT be reduced to single percents (ie, you may X need to update your databases if you had adjusted for this before). X1.2.3 - Split the TCP mailer into TCP and TCP-D (DECnet gateway); added X a TCP-U mailer and ruleset 13 for UUCP gateways that require X hybrid addresses, ie. UUCP !-paths on top of @-domains (brr). X Made sure the h macro (remote host) is defined in buildaddr() X before the mailer rulesets are called. Added TCPMAILER option. X1.2.4 - Sendmail.mc: A list of well-known pseudo-domains (PSEUDODDOMAINS) X has been added to reduce load on the root name server by X avoiding name server lookups on domains ending in these. X1.2.5 - Sendmail.mc: Experimental support for XNS Mail (XNSMAIL, XNSDOMAIN). X Improved the error reporting code in usersmtp.c to mention what X host it was talking to when the error occurred. Also made X deliver.c tell a little more about "host unknown" errors. END_OF_ida/README if test 10672 -ne `wc -c 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 X#include X#include X#ifdef MDBM X# include "mdbm_compat.h" X#else MDBM X# include X# define DBMFILE DBM X# define DB_DIREXT ".dir" X# define DB_PAGEXT ".pag" X#endif MDBM X X#ifndef lint Xstatic char SccsId[] = "@(#)dbm.c 2.1 (lel@ida.liu.se) 8/15/88"; X#endif !lint X X#define SAMECASE 0 X#define LOWERCASE 1 X#define UPPERCASE 2 X X#define COMMENTCHAR '#' X#define SENTENIEL "@@@" 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; Xchar *Senteniel = NULL; 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:s:")) != 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 if (Senteniel == NULL) X Senteniel = SENTENIEL; 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 case 's': X Senteniel = 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 char *filename = (char *) malloc(strlen(Dbmfile) + 20); X sprintf(filename, "%s{%s,%s}", Dbmfile, DB_DIREXT, DB_PAGEXT); X perror(filename); X exit(4); X } X (void) flock(dbm_dirfno(Dbm), LOCK_EX); X Dbmaccess = access; X} X Xclosedbm() X{ X if ((Dbmaccess & O_RDONLY) == 0 && Senteniel != NULL) { X MAKEDATUM(key, Senteniel); X if (dbm_store(Dbm, key, key, DBM_REPLACE) != NULL) { X (void) fprintf(stderr, "%s: could not store senteniel \"%s\"\n", X Progname, Senteniel); X perror(Progname); X exit(5); X } X } X X (void) flock(dbm_dirfno(Dbm), LOCK_UN); 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 11274 -ne `wc -c ida/patches/daemon.c.diff <<'END_OF_ida/patches/daemon.c.diff' X*** daemon.c.orig Sat Apr 2 00:43:22 1988 X--- daemon.c Tue Aug 30 01:57:23 1988 X*************** X*** 32,37 **** X--- 32,40 ---- X # include X # include X # include X+ # include X+ # include X+ # include X X /* X ** DAEMON.C -- routines to use when running as a daemon. X*************** X*** 62,67 **** X--- 65,78 ---- X ** maphostname(hbuf, hbufsize) X ** Convert the entry in hbuf into a canonical form. It X ** may not be larger than hbufsize. X+ ** X+ ** mapinit(c) X+ ** Open and initialize a dbm database. Reopen if our current X+ ** file descriptor is out of date. X+ ** X+ ** mapkey(c, key, argval, argsiz) X+ ** Search a database for a match to the given key, sprintf'ing X+ ** the argument through the result if found. X */ X /* X ** GETREQUESTS -- open mail IPC port and get requests. X*************** X*** 492,520 **** X } X X /* X! * MAPHOSTNAME -- turn a hostname into canonical form X! * X! * Parameters: X! * hbuf -- a buffer containing a hostname. X! * hbsize -- the size of hbuf. X! * X! * Returns: X! * none. X! * X! * Side Effects: X! * Looks up the host specified in hbuf. If it is not X! * the canonical name for that host, replace it with X! * the canonical name. If the name is unknown, or it X! * is already the canonical name, leave it unchanged. X! */ X maphostname(hbuf, hbsize) X char *hbuf; X int hbsize; X { X register struct hostent *hp; X! u_long in_addr; X! char ptr[256]; X! struct hostent *gethostbyaddr(); X X /* X * If first character is a bracket, then it is an address X--- 503,532 ---- X } X X /* X! ** MAPHOSTNAME -- turn a hostname into canonical form X! ** X! ** Parameters: X! ** hbuf -- a buffer containing a hostname. X! ** hbsize -- the size of hbuf. X! ** X! ** Returns: X! ** An exit code telling if the hostname was found and X! ** canonicalized. X! ** X! ** Side Effects: X! ** Looks up the host specified in hbuf. If it is not X! ** the canonical name for that host, replace it with X! ** the canonical name. If the name is unknown, or it X! ** is already the canonical name, leave it unchanged. X! **/ X! bool X maphostname(hbuf, hbsize) X char *hbuf; X int hbsize; X { X register struct hostent *hp; X! extern struct hostent *gethostbyname(); X! static char tmphbuf[MAXNAME]; X X /* X * If first character is a bracket, then it is an address X*************** X*** 522,543 **** X * strip the brackets and to preserve hbuf if address is X * unknown. X */ X! if (*hbuf != '[') { X! getcanonname(hbuf, hbsize); X! return; X } X! *index(strcpy(ptr, hbuf), ']') = '\0'; X! in_addr = inet_addr(&ptr[1]); X! hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); X if (hp == NULL) X! return; X if (strlen(hp->h_name) >= hbsize) X hp->h_name[hbsize - 1] = '\0'; X! (void)strcpy(hbuf, hp->h_name); X } X X # else DAEMON X! /* code for systems without sophisticated networking */ X X /* X ** MYHOSTNAME -- stub version for case of no daemon code. X--- 534,573 ---- X * strip the brackets and to preserve hbuf if address is X * unknown. X */ X! if (*hbuf == '[') X! { X! extern struct hostent *gethostbyaddr(); X! u_long in_addr; X! X! (void) strncpy(tmphbuf, hbuf+1, strlen(hbuf)-2); X! in_addr = inet_addr(tmphbuf); X! hp = gethostbyaddr((char *) &in_addr, sizeof(struct in_addr), AF_INET); X } X! else X! { X! hp = gethostbyname(hbuf); X! if (hp == NULL) { X! /* try lowercase version */ X! (void) strcpy(tmphbuf, hbuf); X! (void) makelower(tmphbuf); X! } X! } X! #ifdef DEBUG X! if (tTd(9, 1)) X! printf("maphostname(%s, %d) => %.*s\n", X! hbuf, hbsize, hbsize-1, hp ? hp->h_name : "NOT_FOUND"); X! #endif DEBUG X if (hp == NULL) X! return FALSE; X! X if (strlen(hp->h_name) >= hbsize) X hp->h_name[hbsize - 1] = '\0'; X! (void) strcpy(hbuf, hp->h_name); X! return TRUE; X } X X # else DAEMON X! /* code for systems without sophisticated networking */ X X /* X ** MYHOSTNAME -- stub version for case of no daemon code. X*************** X*** 564,570 **** X } X return (NULL); X } X! /* X ** MAPHOSTNAME -- turn a hostname into canonical form X ** X ** Parameters: X--- 594,601 ---- X } X return (NULL); X } X! X! /* X ** MAPHOSTNAME -- turn a hostname into canonical form X ** X ** Parameters: X*************** X*** 572,578 **** X ** hbsize -- the size of hbuf. X ** X ** Returns: X! ** none. X ** X ** Side Effects: X ** Looks up the host specified in hbuf. If it is not X--- 603,610 ---- X ** hbsize -- the size of hbuf. X ** X ** Returns: X! ** An exit code telling if the hostname was found and X! ** canonicalized. X ** X ** Side Effects: X ** Looks up the host specified in hbuf. If it is not X*************** X*** 586,592 **** X char *hbuf; X int hbsize; X { X! return; X } X X #endif DAEMON X--- 618,876 ---- X char *hbuf; X int hbsize; X { X! return (FALSE); X } X X #endif DAEMON X+ /* X+ ** MAPINIT -- Open and (re)initialize a dbm database X+ ** X+ ** Parameters: X+ ** c -- the (one character) name of the database X+ ** X+ ** Returns: X+ ** An exit code telling if we could open the database. X+ ** X+ */ X+ #ifdef NDBM X+ bool X+ mapinit(c) X+ char c; X+ { X+ struct stat stb; X+ struct dbm_table *db; X+ char buf[MAXNAME]; X+ X+ db = &DbmTab[c & 0177]; X+ X+ if (db->db_name == NULL) { X+ syserr("database '%c' has not been defined", c); X+ return FALSE; X+ } X+ X+ #ifdef YPMARK X+ /* X+ * Yellow pages are always supposed to be ready X+ */ X+ if (db->db_name[0] == YPMARK) X+ return TRUE; X+ #endif YPMARK X+ X+ /* X+ * Have we already (unsuccessfully) tried to open it? X+ */ X+ if (db->db_dbm == DB_NOSUCHFILE) { X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("mapinit(%c) => NO_FILE\n", c); X+ #endif DEBUG X+ return FALSE; X+ } X+ X+ /* X+ * If it already is open, check if it has been changed. X+ */ X+ (void) sprintf(buf, "%s%s", db->db_name, DB_DIREXT); X+ if (db->db_dbm != DB_NOTYETOPEN) { X+ if (stat(buf, &stb) < 0 && (sleep(30), stat(buf, &stb) < 0)) { X+ syserr("somebody removed %s for db '%c'", buf, c); X+ db->db_dbm = DB_NOSUCHFILE; X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("mapinit(%c) => FILE_REMOVED\n", c); X+ #endif DEBUG X+ return FALSE; X+ } X+ if (db->db_mtime != stb.st_mtime) { X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("database '%c' [%s] has changed; reopening it\n", X+ c, db->db_name); X+ #endif DEBUG X+ (void) dbm_close(db->db_dbm); X+ db->db_dbm = DB_NOTYETOPEN; X+ } X+ } X+ X+ /* X+ * Initialize database if not already open (r/w for aliases) X+ */ X+ if (db->db_dbm == DB_NOTYETOPEN) { X+ db->db_dbm = dbm_open(db->db_name, X+ c == DB_ALIAS ? O_RDWR : O_RDONLY, 0); X+ if (db->db_dbm == DB_NOSUCHFILE) { X+ /* try once more */ X+ sleep(30); X+ db->db_dbm = dbm_open(db->db_name, X+ c == DB_ALIAS ? O_RDWR : O_RDONLY, 0); X+ } X+ if (db->db_dbm == DB_NOSUCHFILE) { X+ syserr("can't open database '%c' [%s]", c, db->db_name); X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("mapinit(%c) => CAN'T OPEN %s\n", c, db->db_name); X+ #endif DEBUG X+ return FALSE; X+ } X+ if (stat(buf, &stb) < 0 && (sleep(30), stat(buf, &stb) < 0)) { X+ syserr("can't stat %s", buf); X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("mapinit(%c) => FILE_REMOVED\n", c); X+ #endif DEBUG X+ return FALSE; X+ } X+ db->db_mtime = stb.st_mtime; X+ X+ /* X+ * Make sure the database isn't being updated X+ */ X+ if (flock(dbm_dirfno(db->db_dbm), LOCK_EX | LOCK_NB) < 0) X+ if (errno == EWOULDBLOCK) { X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("%s%s is locked, waiting...\n", X+ db->db_name, DB_DIREXT); X+ #endif DEBUG X+ (void) flock(dbm_dirfno(db->db_dbm), LOCK_EX); X+ } else X+ syserr("flock failed for db %c [%s]", c, db->db_name); X+ (void) flock(dbm_dirfno(db->db_dbm), LOCK_UN); X+ } X+ return TRUE; X+ } X+ /* X+ ** MAPKEY -- Search a dbm database. X+ ** X+ ** Search the named database using the given key. If X+ ** a result is found, sprintf the argument through the X+ ** result back into the key and return TRUE; X+ ** otherwise return FALSE and do nothing. X+ ** X+ ** Keysize may also be given as zero, in which case the X+ ** sprintf'ed result is returned if the key matched. X+ ** X+ ** Parameters: X+ ** c -- the database X+ ** key -- search string X+ ** argval -- sprintf argument & result X+ ** argsiz -- size of argval X+ ** X+ ** Returns: X+ ** An exit code telling if there was a match. X+ ** X+ ** Side Effects: X+ ** The argval is rewritten to reflect what was found X+ ** in the database. X+ */ X+ X+ mapkey(c, key, keysiz, arg) X+ char c, *key, *arg; X+ int keysiz; X+ { X+ struct dbm_table *db; X+ DATUM dkey, result; X+ static char lowkey[MAXNAME]; X+ #ifdef YPMARK X+ static char *yp_domain = NULL; X+ #endif YPMARK X+ X+ db = &DbmTab[c & 0177]; X+ X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("mapkey('%c', \"%s\", \"%s\") => ", c, key, arg ? arg : "--"); X+ #endif DEBUG X+ X+ /* X+ * Init the database; return if failure X+ */ X+ if (!mapinit(c)) X+ return FALSE; X+ X+ /* X+ * Normalize key (ie turn it to lowercase) X+ */ X+ (void) strcpy(lowkey, key); X+ (void) makelower(lowkey); X+ X+ #ifdef YPMARK X+ /* X+ * Test for yellow page database first X+ */ X+ if (db->db_name[0] == YPMARK) { X+ if (yp_domain == NULL) X+ (void) yp_get_default_domain(&yp_domain); X+ X+ /* X+ * We include the null after the string, but Sun doesn't X+ */ X+ if (yp_match(yp_domain, &db->db_name[1], lowkey, X+ strlen(key)+1, &result.dptr, &result.dsize) != 0 && X+ yp_match(yp_domain, &db->db_name[1], lowkey, X+ strlen(key), &result.dptr, &result.dsize) != 0) X+ result.dptr = NULL; X+ else X+ /* smash newline */ X+ result.dptr[result.dsize] = '\0'; X+ } else { X+ #endif YPMARK X+ /* X+ * Go look for matching dbm entry X+ */ X+ dkey.dptr = lowkey; X+ dkey.dsize = strlen(dkey.dptr) + 1; X+ result = dbm_fetch(db->db_dbm, dkey); X+ #ifdef YPMARK X+ } X+ #endif YPMARK X+ X+ /* X+ * Well, were we successful? X+ */ X+ if (result.dptr == NULL) { X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("NOT_FOUND\n"); X+ #endif DEBUG X+ return FALSE; X+ } X+ X+ /* X+ * Yes, rewrite result if sprintf arg was given. X+ */ X+ if (arg == NULL) X+ (void) strcpy(lowkey, result.dptr); X+ else X+ (void) sprintf(lowkey, result.dptr, arg); X+ /* if keysiz is zero, that means we should return a string from the heap */ X+ if (keysiz == 0) X+ key = newstr(lowkey); X+ else { X+ if (strlen(lowkey)+1 > keysiz) { X+ syserr("mapkey: result \"%s\" too long after expansion\n", X+ lowkey, keysiz); X+ lowkey[keysiz-1] = '\0'; X+ } X+ (void) strcpy(key, lowkey); X+ } X+ #ifdef DEBUG X+ if (tTd(60, 1)) X+ printf("%s\n", key); X+ #endif DEBUG X+ X+ /* Ugly kludge that assumes that sizeof(int) == sizeof(char *) */ X+ return (int) key; X+ } X+ X+ #else NDBM X+ X+ /* should really read the table into the stab instead */ X+ mapkey(db, key, keysiz, arg) X+ char db, *key, *arg; X+ int keysiz; X+ { X+ return FALSE; X+ } X+ X+ #endif NDBM END_OF_ida/patches/daemon.c.diff if test 11203 -ne `wc -c ida/patches/op.me.diff <<'END_OF_ida/patches/op.me.diff' X*** op.me.orig Thu May 5 22:28:51 1988 X--- op.me Thu Aug 25 15:15:49 1988 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! Rank Xerox EuroPARC, Cambridge, England 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*** 1868,1873 **** X--- 1897,1920 ---- X .b $| ) X clause may be omitted. X .pp X+ To make sure that a string (phrase) conforms with RFC822, a special X+ construct X+ .b $! \c X+ .i x X+ can be used. When it is expanded, it will be checked against certain X+ illegal character and quoted using a pair of double quotes if necessary. X+ This would typically be used when defining the X+ .i q X+ macro as in: X+ .(b X+ Dq$?x$!x $.<$g> X+ .)b X+ Here, an address like `Joe User @ Waterloo ' would X+ be rewritten as `"Joe User @ Waterloo" ' in order to X+ make it legal. See more below on the X+ .i q X+ macro. X+ .pp X The following macros X .i must X be defined to transmit information into X*************** X*** 1878,1886 **** X j The \*(lqofficial\*(rq domain name for this site 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--- 1925,1944 ---- X j The \*(lqofficial\*(rq domain name for this site X l The format of the UNIX from line X n The name of the daemon (for error messages) X! o The set of \*(lqoperators\*(rq 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*** 2087,2094 **** X and X .b $s X fields are set to the protocol used to communicate with sendmail X! and the sending hostname; X! these are not supported in the current version. X .sh 3 "Special classes" X .pp X The class X--- 2145,2151 ---- X and X .b $s X fields are set to the protocol used to communicate with sendmail X! and the sending hostname. X .sh 3 "Special classes" X .pp X The class 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--- 2164,2171 ---- 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--- 2198,2208 ---- 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\fIx\fP Force runtime evaluation of macro \fIx\fP 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--- 2237,2304 ---- 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+ You can also make sendmail search a X+ .i "Yellow Pages" X+ database if your machine supports this. To do this, use the same X+ definition as above but prefix the map name with a percent sign, as in: X+ .(b X+ OKP%mail.aliases X+ .)b X+ Only maps in your default domain can currently be accessed. 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 aliases database is automatically available as database X+ .b @ . X+ It can either be defined using the X+ .b A X+ option or by a X+ .b OK@ X+ declaration and is in both cases allowed to be a YP map. 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--- 2311,2317 ---- 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--- 2356,2372 ---- 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*** 2253,2260 **** X .pp X Substitution occurs in the order described, X that is, X! parameters from the LHS are substituted, X! hostnames are canonicalized, X .q subroutines X are called, X and finally X--- 2373,2380 ---- X .pp X Substitution occurs in the order described, X that is, X! parameters from the LHS are substituted and runtime macros are expanded, X! hostnames are canonicalized and database lookups are performed, X .q subroutines X are called, X and finally X*************** X*** 2710,2720 **** X as it proceeds, X finally showing you the address it ends up with. X You may use a comma separated list of rwsets X! for sequential application of rules to an input; X! ruleset three is always applied first. X For example: X .(b X! 1,21,4 monet:bollard X .)b X first applies ruleset three to the input X .q monet:bollard. X--- 2830,2839 ---- X as it proceeds, X finally showing you the address it ends up with. X You may use a comma separated list of rwsets X! for sequential application of rules to an input. X For example: X .(b X! 3,1,21,4 monet:bollard X .)b X first applies ruleset three to the input X .q monet:bollard. X*************** X*** 2854,2859 **** X--- 2973,2979 ---- 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--- 3004,3016 ---- 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 envelope 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--- 3153,3159 ---- 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--- 3178,3188 ---- 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--- 3299,3318 ---- 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--- 3553,3564 ---- 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--- 3599,3620 ---- 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--- 3768,3782 ---- 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--- 4103,4109 ---- 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--- 4111,4128 ---- 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 15423 -ne `wc -c