Path: seismo!harvard!talcott!panda!Jim Crammond From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: Sendmail UK-1.4 part 5 of 5 Message-ID: <1643@panda.UUCP> Date: 11 Apr 86 11:13:33 GMT Sender: jpn@panda.UUCP Lines: 1731 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 60 Submitted by: Jim Crammond # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. -----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # xtras # This archive created: Mon Mar 17 16:57:06 1986 echo shar: creating directory xtras mkdir xtras cd xtras echo shar: extracting SysV.sh '(866 characters)' cat << \SHAR_EOF > SysV.sh #!/bin/sh # # This shell script converts the BSD dependent parts of the MAKE shell # scripts into something suitable for SystemV. # # This must be run in the top level directory of the sendmail package. # for i in MAKE chn/MAKE dom/MAKE do if [ ! -f $i ] then echo $i non-existent exit 1 fi if [ ! -f $i.bsd ] then mv $i $i.bsd fi done # The top level make file sed -e 's/echo -n/echo/' \ -e 's/? "/? \\c"/' \ -e 's/: "/: \\c"/' \ -e 's/(y|n) "/(y|n) \\c"/' \ -e '/Complete/s/\."/.\\c"/' \ -e '/^Making/s/\.\. /.. \\c/' \ -e '/^creating/s/\.\. /.. \\c/' MAKE.bsd > MAKE # The channel make file sed -e "s;fmt | sed;nroff | sed -e '/^$/d' -e;" chn/MAKE.bsd > chn/MAKE # The domain make file sed -e "s;tail -r \(S..\);pr -t -n \1 | sort -r | sed 's/^......//';" \ -e "s;fmt | sed;nroff | sed -e '/^$/d' -e;" dom/MAKE.bsd > dom/MAKE SHAR_EOF if test 866 -ne "`wc -c SysV.sh`" then echo shar: error transmitting SysV.sh '(should have been 866 characters)' else chmod a+x SysV.sh fi echo shar: extracting distribute '(781 characters)' cat << \SHAR_EOF > distribute #!/bin/sh # # Send a mail message to users on a distribution list. The message header is # altered mainly to allow error messages to be returned to the list maintainer. # This script should be setuid to one of sendmail's trusted users. # # Usage: put an entry into /usr/lib/aliases of the following form: # # list-name: "|/usr/local/lib/distribute list-name user1 user2 ..." # if [ $# -lt 2 ] then echo Usage: $0 list-name user1 user2 ... exit 64 fi dlist=$1 shift sed -e '1,/^$/s/^$/EOH\ /' | sed -e '/^$/,$b' \ -e '/^From /d' \ -e '/^Via:/s//Original-Via:/' \ -e '/^Sender:/s//Original-Sender:/' \ -e '/^Acknowledge-To:/d' \ -e '/^Return-Receipt-To:/d' \ -e "/^EOH$/s//Sender: $dlist-request/" | /usr/lib/sendmail -f$dlist-request $* SHAR_EOF if test 781 -ne "`wc -c distribute`" then echo shar: error transmitting distribute '(should have been 781 characters)' else chmod a+x distribute fi echo shar: extracting sendproc.sh '(1762 characters)' cat << \SHAR_EOF > sendproc.sh #! /bin/sh file=${1-NRS} date=`date` # if a berkeley 4.2 site use this sed -n -e '/^\.H1 Reverse/q' \ -e '/^\.H1 Context MAIL-NIFTP Subnetwork JANET/,/^\.H1/p' \ -e '/^\.H1 Context MAIL-NIFTP Subnetwork PSS/,/^\.H1/p' $file | tr '[A-Z]' '[a-z]' | awk ' BEGIN { tmp1 = "/tmp/sm.1" tmp2 = "/tmp/sm.2" tmp3 = "/tmp/sm.3" tmp4 = "/tmp/sm.4" } /^standard name/ { long = $3 } /^abbreviated name/ { short = $3 } /^$/ { ln = split(long, ldom, "."); sn = split(short, sdom, "."); if (long ~ /uk\./) { if (ln == 2) printf "%-20s %s.%s\n", ldom[2],ldom[2],ldom[1] > tmp1 else printf "%-20s %s.%s.%s\n", ldom[3],ldom[3],ldom[2],ldom[1] > tmp1 } if (short ~ /uk\./) { if (ln == 2 && sdom[2] != ldom[2]) printf "%-12s %s.%s\n", sdom[2],sdom[2],sdom[1] > tmp2 else if (ln >= 3 && sdom[3] != ldom[3]) printf "%-12s %s.%s.%s\n", sdom[3],sdom[3],sdom[2],sdom[1] > tmp2 } if (long != short) { l1 = "" ; s1 = "" if (ln > 2) l1 = ldom[3] "." if (sn > 2) s1 = sdom[3] "." l1 = l1 ldom[2] "." ldom[1] s1 = s1 sdom[2] "." sdom[1] l2 = "" ; s2 = "" if (ln > 3) { l2 = ldom[ln] for (j=ln-1; j>=4; j--) l2 = l2 "." ldom[j] } if (sn > 3) { s2 = sdom[sn] for (j=sn-1; j>=4; j--) s2 = s2 "." sdom[j] } if (l2 != s2) { l1 = l2 "." l1 s1 = s2 "." s1 printf "%-18s %s\n", s1, l1 > tmp3 } else printf "%-18s %s\n", s1, l1 > tmp4 } short = long = "" } ' cat > uk.dom < abbrev.dom < checkaddr #!/bin/sh # shell script to verify what sendmail would do with given addresses # this version works for sendmail version 4.12 verbose=false if [ $1 = "-v" ] then verbose=true shift fi trap "/bin/rm /tmp/ver.$$; exit" 1 2 3 15 while [ $# -ge 1 ] do echo -n "$1: " /usr/lib/sendmail -bt > /tmp/ver.$$ < /tmp/ver.$$ then echo addr OK else sed -n -e '/deliverable/d' \ -e 's/\(.*\)\.\.\. \(.*\)/\2 (\1)/p' /tmp/ver.$$ fi if $verbose then aliases="" for a in `sed -n 's/\.\.\. deliverable//p' /tmp/ver.$$` do if [ "$a" = "$1" ] then echo "Routed to: channel=local, addr=$a" else aliases="$aliases $a" fi done if [ -n "$aliases" ] then echo "Aliased to:$aliases" $0 $aliases fi fi elif grep -s 'ruleset 0 returns: "^U" "error"' /tmp/ver.$$ then sed -n -e 's/"\([^"]*\)"/\1/g' \ -e '/ruleset 0 returns:/s/.*^W //p' /tmp/ver.$$ else echo addr OK if $verbose then sed -n '/ruleset 3 returns:/s/.*returns: //p' /tmp/ver.$$ | sed -n -e '$s/"\([^"]*\)"/\1/g' \ -e '$s/ \([!.@%]\) /\1/g' \ -e '$s/^/Normalised to: /p' sed -n '/ruleset 0 returns:/s/.*^U" //p' /tmp/ver.$$ | sed -e 's/"\([^"]*\)"/\1/g' \ -e 's/\(.*\) ^V \(.*\) ^W \(.*\)/Routed to: channel=\1, host=\2, addr=\3/'\ -e 's/\(.*\) ^W \(.*\)/Routed to: channel=\1, addr=\2/' \ -e 's/ \([!.@%]\) /\1/g' fi fi /bin/rm /tmp/ver.$$ shift done SHAR_EOF if test 1594 -ne "`wc -c checkaddr`" then echo shar: error transmitting checkaddr '(should have been 1594 characters)' else chmod a+x checkaddr fi echo shar: extracting csnet.note '(2947 characters)' cat << \SHAR_EOF > csnet.note This note contains a few hints on how csnet sites should configure their tables from information provided from info@sh.cs.net (info@csnet-sh) Domain Tables ------ ------ The CSNet information service provides you with the necessary "host tables" to create your domain and channel tables, almost automatically. There are three host tables that you can choose from: tbl-4a contains the TOP table, the CSNET table and the ARPA table. tbl-4c contains the TOP table and the CSNET table only. tbl-4t contains the TOP table only. The CIC recommend that you just use the TOP table, tbl-4t, and forward everything to csnet-relay. This is certainly the easiest option to take. It is quite feasible to include the CSNET table too: this will allow you to mail to "user@csnet-host" and let sendmail expand that to a domain name. Without this table, you have to mail to "user@csnet-host_._c_s_n_e_t" every time. However, I would strongly recommend that you do NOT attempt to include the ARPA table as well, since this table is so large. To obtain the TOP and CSNET tables, mail to info@sh.cs.net (info@csnet-sh) with the following lines in the message body: Request: info Topic: tbl-4c Request: end The TOP table looks like this: ARPA Forward to CSNET-RELAY.ARPA COM Forward to CSNET-RELAY.ARPA EDU Forward to CSNET-RELAY.ARPA GOV Forward to CSNET-RELAY.ARPA MIL Forward to CSNET-RELAY.ARPA NET Forward to CSNET-RELAY.ARPA ORG Forward to CSNET-RELAY.ARPA UK Forward to CSNET-RELAY.ARPA US Forward to CSNET-RELAY.ARPA This can be converted into the sendmail _t_o_p_._d_o_m by the command: "sed 's/Forward to//' | tr '[A-Z]' '[a-z]'" (Strictly speaking the tr command - to lowercase the names - is unnecessary. Sendmail is not fussy, - I just like to see lowercase tables!) The CSNET table looks like this: CSNET-RELAY CSNET-RELAY.CSNET CSNET-SH CSNET-SH.CSNET CSNET-CIC CSNET-SH.CSNET ALBANY ALBANY.CSNET SUNYA ALBANY.CSNET SUNY-A ALBANY.CSNET etc. This can be converted into the sendmail _c_s_n_e_t_._d_o_m by the command: "sed 's/,.*//' | tr '[A-Z]' '[a-z]'" (The sed command removes relay information, the tr command lowercases names.) Channel Tables ------- ------ The _t_o_p_._c_h_n channel table is linked/copied from top.dom in the domain tables. The top.dom defines the top level domains to recognise, the top.chn specifies the relay domain to route them to - i.e. csnet-relay.arpa. The _c_s_n_e_t_._c_h_n table contains the domain name(s) of the relay site on the LHS and the host name of the relay on the RHS. Thus, for csnet-relay you should have: csnet-relay.arpa csnet-relay csnet-relay.csnet csnet-relay relay.cs.net csnet-relay Finally, the _l_o_c_a_l_._c_h_n table should contain your hosts domain name(s). Examples of these tables can be found in the Examples.a files in the dom and chn directories. SHAR_EOF if test 2947 -ne "`wc -c csnet.note`" then echo shar: error transmitting csnet.note '(should have been 2947 characters)' fi echo shar: extracting checkaddr.1 '(622 characters)' cat << \SHAR_EOF > checkaddr.1 .TH CHECKADDR 1 "UK-sendmail" .UC 4 .SH NAME checkaddr - sendmail address verification program .SH SYNOPSIS .B checkaddr [-v] .B addresses... .SH DESCRIPTION The .I checkaddr program is used to check the validity of any address with the local mail system (sendmail). A list of addresses is given on the command line, checkaddr will then announce each address on a separate line and follow the address with its status (normally ``addr OK''). .PP By specifying the -v flag, checkaddr will print additional information about how it .I normalises the address and what routing it then does. .SH "SEE ALSO" sendmail(8) SHAR_EOF if test 622 -ne "`wc -c checkaddr.1`" then echo shar: error transmitting checkaddr.1 '(should have been 622 characters)' fi echo shar: extracting uknet.note '(4566 characters)' cat << \SHAR_EOF > uknet.note This note contains a few hints on what information you should have in your sendmail tables to cope with the new naming scheme. Domain Tables ------ ------ There are two domain tables that you need to include in your configuration: 1. uk.dom This table lists all the subdomains of ac.uk and co.uk. It allows users to specify partially qualified names and let sendmail expand them to fully qualified names, e.g jim@cs.heriot-watt => jim@cs.heriot-watt.ac.uk The UK-1.4 distribution contains such a table and updates will hopefully be posted to uk.net on a regular basis. This can be included as is. Perhaps the only change that you may want to make to the distributed table is to remove the entry for "co.ac.uk" which causes a name clash with "co.uk". 2. ukuucp.dom This table contains a list of entries of the form uucpname domainname Only those uucp sites directly connected to your site need to be included in this table. For example, here is the table we have at hwcs: aimmi aimmi.ac.uk cstvax cstvax.ed.ac.uk dice dice.ferr.co.uk edcaad caad.ed.ac.uk hwcs cs.hw.ac.uk kcl-cs cs.kcl.ac.uk spider spider.co.uk stl stl.stc.co.uk ulcs dcs.leeds.ac.uk This is particularly important for those directly connected sites which have V7mailers, as they will be relying on you to convert their uucpname to their domain name. There is a third domain table that you can include, which converts the abbreviated form of addresses to standard form. This, however, generates a lot of rules and so is only really practical on machines in which the "freeze file" works. This will be made available on uk.net shortly. Channel Tables ------- ------ There are four scenarios to consider here. 1. An academic site on Janet. Most of the routing in this case will be done by the x25 software as all UKnet sites not directly connected to Janet will have a Janet site registered as a relay to it. Thus hhcp forwards the mail to the relay. If there are UKnet sites using you as a Janet relay, then obviously the important thing is to have them in your uucp.chn table! As an example, cstvax.ed.ac.uk is likely to be the relay for a number of Edinburgh uucp sites. Their uucp.chn table will probably look something like this: caad.edinburgh.ac.uk edcaad!%s caad.ed.ac.uk edcaad!%s cs.heriot-watt.ac.uk hwcs!%s cs.hw.ac.uk hwcs!%s dice.ferranti.co.uk hwcs!dice!%s dice.ferr.co.uk hwcs!dice!%s spider.co.uk hwcs!spider!%s Note that both standard and abbreviated forms of the NRS name need to be included here. 2. An academic site only on UUCP. In this case you will need to specify a route to your Janet relay site in your uucp.chn together with routes for all uucp sites which do not go to the janet relay. The entries for these will be similar to those above. All other uk mail can be forwarded to the Janet relay in the top.chn, e.g. uk cstvax.ed.ac.uk Alternatively, this can be specified in the uucp.chn as e.g. uk pathto!cstvax!%s 3. A commercial site on PSS. This is very similar to the first case. Most routing will be done by the x25 software: academic sites will probably be relayed to a Janet gateway, PSS sites will have direct connections and the remaining UUCP sites will be forwarded to an appropriate uucp relay on PSS (e.g. ukc.ac.uk). 4. A Commercial site only on UUCP. Because commercial sites can only use Janet to send to academic sites, you need to be two relays: your Janet relay for academic sites and your UUCP relay for commercial sites. These relays can be specified in the uucp.chn file in the following way: ac.uk path_to_my_janet_relay!%s co.uk path_to_my_uucp_relay!%s So, the uucp.chn contains routes for all sites not to be sent to a relay, plus the two relay rules. As an example, the uucp.chn for spider.co.uk may look something like: cs.heriot-watt.ac.uk hwcs!%s cs.hw.ac.uk hwcs!%s dice.ferranti.co.uk hwcs!dice!%s dice.ferr.co.uk hwcs!dice!%s ac.uk hwcs!cstvax!%s co.uk hwcs!stl!%s It is recommended that the old "site.uucp" domain names should also be included in the uucp channel tables for a transition period whilst people change over to the new naming scheme. Finally, in the local channel table you should have three names: a) your standard form name (e.g. cs.heriot-watt.ac.uk) b) your abbreviated form name (e.g. cs.hw.ac.uk) c) your old uucp name (e.g. hwcs.uucp) (plus host specific names if this is a multi-host site). SHAR_EOF if test 4566 -ne "`wc -c uknet.note`" then echo shar: error transmitting uknet.note '(should have been 4566 characters)' fi echo shar: extracting distribute.1 '(1611 characters)' cat << \SHAR_EOF > distribute.1 .TH DISTRIBUTE 8 "UK-sendmail" .UC 4 .SH NAME distribute - send mail to a distribution list .SH SYNOPSIS .B /usr/local/lib/distribute .B list-name .B addresses... .SH DESCRIPTION .I Distribute sends a mail message to users on a distribution list. It alters the message header received from a contributor mainly to arrange for any error messages to be returned to the list maintainer. .PP .I Distribute is normally invoked by sendmail from an alias entry in /usr/lib/aliases of the form: .PP .DT list-name: "|/usr/local/lib/distribute list-name users..." .PP With lists containing many names, which maybe subject to frequent alteration, it is best to store the usernames in a file and replace the list of users with an argument to read the file, i.e. .PP .nf list-name: "|/usr/local/lib/distribute list-name `cat\ filename`" .fi .PP (this tends to work better than using sendmail's :include: feature, which typically limits the length of the shell command line to 128 bytes). .PP There should be a second entry in /usr/lib/aliases for the list maintainer. This is the name of the list with "\-request" appended. This should be aliased to the person who is responsible for maintaining the distribution list. e.g. .PP .DT list-name-request: postman-pat .PP .I Distribute should be setuid to one of sendmail's trusted users, so that it will set the sender address to that of the list maintainer. .SH FILES /usr/lib/aliases .SH "SEE ALSO" sendmail(8), aliases(5), newaliases(1) .br "Recommendations for implementors of the JNT Mail Protocol Specifications (MG.B)" by Steve Kille, April 1985 .SH AUTHOR Jim Crammond SHAR_EOF if test 1611 -ne "`wc -c distribute.1`" then echo shar: error transmitting distribute.1 '(should have been 1611 characters)' fi echo shar: extracting README '(3084 characters)' cat << \SHAR_EOF > README This directory contains a couple of extra programs and documentation which are not part of the main configuration package, but which might be useful. SysV.sh: This script converts the BSD dependent code into System V dependent code in the three MAKE files (MAKE, dom/MAKE and chn/MAKE). The main alterations necessary are changing the format of the "echo" command arguments, and replacing "cat -n" with "pr -n" and "fmt" with "nroff" (!). Just run it in the top level directory. uumailclean, hhmailclean: These are programs to clean up the mail queues for uucp and hhcp. These should be called from /usr/lib/crontab, say, once a day. Manual entry for both programs is supplied in uumailclean.8c. To make these programs: cc -O -c warn.c cc -O -c -I$(UUCPFLAGS) uumailclean.c cc -o uumailclean uumailclean.o warn.o -l$(UUCPLIB)/uulib.a install -o uucp -g uucp -m 6110 uumailclean /usr/lib/uucp cc -O -c warn.c cc -O -c -I$(X25FLAGS) hhmailclean.c cc -o hhmailclean hhmailclean.o warn.o install -m 755 hhmailclean /usr/lib/x25 where UUCPFLAGS, UUCPLIB and X25FLAGS should be the same as in Support/Makefile. checkaddr: This is a shell script to verify a list of addresses. This should be installed in /usr/local/checkaddr. Manual entry is supplied in checkaddr.1 NOTE: This version will work for sendmail version 4.12 (i.e. the standard BSD4.2 version); to adapt it to work version 4.40, run it through the following command:- "sed s/12/40/ checkaddr | tr UVW VWX > /usr/local/checkaddr" distribute: This is a shell script to mail a message on to a distribution list, having altered some headers first. This should be installed in /usr/local/lib/distribute. Manual entry is supplied in distribute.1 sendproc.sh: This is a shell script to generate two sendmail domain tables from the NRS database file. The first one is the "uk.dom" file, which contains all the subdomains of "ac.uk" and "co.uk". It is recommended that you do a `Namecheck' on the generated file, and remove any name clashes. In particular, removing the entry "co -> co.ac.uk" is probably essential. The second file generated is the "abbrev.dom" file which maps abbreviated form to standard form names. It trys it optimise the table to reduce the number of sendmail rules subsequently generated. Note that inclusion of this table will probably double the size of your configuration file and hence double sendmail's startup time. It should only be used if the frozen configuration facility works. It should be possible to reverse this table to get sendmail to map standard form to abbreviated form names. csnet.note: This is a note giving some hints on how to use the information service provided by sh.cs.net (csnet-sh.arpa) to build domain and channel tables for csnet sites. uknet.note: This is the note posted to uk.net last year on how to configure sendmail to handle the new naming scheme which is being adopted on UKnet. It may give a few useful hints. SHAR_EOF if test 3084 -ne "`wc -c README`" then echo shar: error transmitting README '(should have been 3084 characters)' fi echo shar: extracting uumailclean.c '(7456 characters)' cat << \SHAR_EOF > uumailclean.c #include "uucp.h" #include #include #ifdef BSD42 #include #endif BSD42 #ifdef NDIR #include #endif NDIR #ifdef LIBNDIR #include "LIBNDIR/ndir.h" #endif LIBNDIR /* * uumailclean - this program searches through the uucp spool directory * looking for mail files. Files which have been around for longer * than "failtime" hours will be returned to the sender. If a file * has been around longer than "warntime" hours, then a warning * message is sent (once) to the sender. * * If you use L.dirs to specify subdirectories, then failtime and * warntime can be specified as 3rd and 4th arguments to the directory * entries respectively: e.g. "C. 336 168 72" * By default, these times are 1 week and 3 days. * * Written by Jim Crammond 3/86 */ #define FAILTIME 168 /* default hours before returning the mail */ #define WARNTIME 72 /* default hours before sending a warning */ #define WARNFILE UUCPDIR/uucp/warnlist.mail" int warntime, failtime; main(argc, argv) char *argv[]; { #ifdef SUBCS FILE *fdirs; #endif SUBCS char file[NAMESIZE]; char cdir[ MAXFULLNAME ]; char *flds[10]; int nflds, ret; int orig_uid = getuid(); strcpy(Progname, "uumailclean"); uucpname(Myname); chkdebug(orig_uid); /* cd to spool */ ASSERT(subchdir(Spool) != -1, "cannot chdir to ", Spool, 0 ); init_warnedlist(WARNFILE); #ifdef SUBCS fdirs=fopen(DIRFILE,"r"); ASSERT(fdirs != NULL, "uumailclean cannot open", DIRFILE, 0); while (cfgets(cdir, sizeof(cdir), fdirs) != NULL) { nflds = getargs( cdir, flds ); ASSERT(nflds >= 1, "BAD entry in", DIRFILE, 0); /* only interested in command files */ if (flds[0][0] != CMDPRE) continue; failtime = (nflds > 2) ? atoi(flds[2]) : FAILTIME; warntime = (nflds > 3) ? atoi(flds[3]) : WARNTIME; checkfiles(flds[0]); } #else SUBCS failtime = FAILTIME; warntime = WARNTIME; checkfiles("."); #endif SUBCS exit(0); } /* * checkfiles - scan a directory looking for "old" control files. * For each one found, call fail or warn as appropriate. */ checkfiles(dir) char *dir; { DIR *dirp; char file[NAMESIZE]; struct stat stbuf; time_t now; int hours; time(&now); DEBUG(5, "checkfiles(%s)\n", dir); if ((dirp = opendir(dir)) == NULL) { printf("directory unreadable\n"); return; } while (gnamef(dirp, file)) { if (file[0] != CMDPRE) continue; if (stat(subfile(file), &stbuf) == -1) { DEBUG(4, "stat on %s failed\n", file); continue; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) continue; hours = (int) (now - stbuf.st_mtime) / 3600; if (hours >= failtime) fail(file, hours); else if (hours >= warntime) warn(file, hours); } } /* * fail - send a failure message to the sender and delete the mail. */ fail(cmdfile, hours) char *cmdfile; int hours; { char dfile[NAMESIZE], xfile[NAMESIZE]; char host[NAMESIZE]; char *from, **to; char *sender(), **recipients(); DEBUG(4, "fail called on %s\n", cmdfile); getfnames(cmdfile, dfile, xfile); if ((to = recipients(xfile)) == NULL) return; if ((from = sender(dfile)) == NULL) return; strcpy(host, &cmdfile[2]); host[ strlen(cmdfile)-7 ] = '\0'; sendfailure(from, to, host, hours, dfile); unlink(subfile(cmdfile)); unlink(subfile(dfile)); unlink(subfile(xfile)); return; } /* * warn - send a warning message to the sender and add the control file * to the list of files for which warnings have been sent. */ warn(cmdfile, hours) char *cmdfile; int hours; { char dfile[NAMESIZE], xfile[NAMESIZE]; char host[NAMESIZE]; char *from, **to; char *sender(), **recipients(); if (in_warnedlist(cmdfile)) return; DEBUG(4, "warn called on %s\n", cmdfile); getfnames(cmdfile, dfile, xfile); if ((to = recipients(xfile)) == NULL) return; if ((from = sender(dfile)) == NULL) return; strcpy(host, &cmdfile[2]); host[ strlen(cmdfile)-7 ] = '\0'; sendwarning(from, to, host, hours, failtime, dfile); add_warnedlist(cmdfile); return; } /* * getfnames - read the control file to find the data and execute files * which contain the message and list of recipients. * dfile is set to the datafile, xfile to the execute file. */ getfnames(cmdfile, dfile, xfile) char *cmdfile; char *dfile; char *xfile; { FILE *fp; char dline[100], xline[100]; char *wrkvec[10]; if ((fp = fopen(subfile(cmdfile), "r")) == NULL) return; if (fgets(dline, 100, fp) == NULL || fgets(xline, 100, fp) == NULL) { fclose(fp); return; } if (getargs(dline, wrkvec) <= QF_INDEX) { fclose(fp); return; } strcpy(dfile, wrkvec[ QF_INDEX ]); if (getargs(xline, wrkvec) < QF_INDEX) { fclose(fp); return; } strcpy(xfile, wrkvec[ QF_INDEX ]); fclose(fp); } /* * recipients - returns a list of recipients that the mail was intended * for, or NULL if the execute file is not a mail file. */ char ** recipients(xfile) char *xfile; { static char rbuf[BUFSIZ]; static char *tobuf[1000]; /* see uuxqt */ FILE *fp; char *p, **t; if ((fp = fopen(subfile(xfile), "r")) == NULL) return(NULL); while (fgets(rbuf, BUFSIZ, fp) != NULL) { if (rbuf[0] == X_CMD) { if (strncmp(rbuf, "C rmail ", 8) == SAME) { fclose(fp); /* turn into an array of addresses */ for (p = &rbuf[8], t=tobuf; *p;) { while (*p == ' ' || *p == '\n') *p++ = '\0'; *t = p; while (*p && *p != ' ' && *p != '\n') p++; if (*t != p) t++; } *t = NULL; return(tobuf); } } } fclose(fp); return(NULL); } /* * sender - returns the sender address from the uucp from line, * or NULL if not found. */ char * sender(dfile) char *dfile; { static char sender[BUFSIZ]; char buf[BUFSIZ]; FILE *fp; if ((fp = fopen(subfile(dfile), "r")) == NULL) return(NULL); if (fgets(buf, BUFSIZ, fp) == NULL) return(NULL); if (sscanf(buf, "From %s", sender) == 1) { fclose(fp); return(sender); } fclose(fp); return(NULL); } /* * exists - returns 1 if "file" exists, else 0. */ exists(file) char *file; { return( access(subfile(file),0) == 0 ); } /* * print_message - print the message in "dfile" on the stream "outp". * If the edited flag is set, then only print some * interesting headers and the first few lines of the body. */ print_message(dfile, outp, edited) char *dfile; FILE *outp; int edited; { FILE *dfp; char buf[BUFSIZ]; int iflg, linecount; if ((dfp = fopen(subfile(dfile), "r")) == NULL) return; /* skip unix from line */ fgets(buf, BUFSIZ, dfp); /* print header */ iflg = 0; while (fgets(buf, BUFSIZ, dfp) != NULL && buf[0] != '\n') { if (edited) { if (buf[0] == '\t' || buf[0] == ' ') { if (iflg) fputs(buf, outp); continue; } if (!interested(buf)) { iflg = 0; continue; } iflg = 1; } fputs(buf, outp); } putc('\n', outp); /* print body */ linecount = 0; while (fgets(buf, BUFSIZ, dfp) != NULL) { if (edited && ++linecount > 5) { fprintf(outp, ".....\n"); break; } fputs(buf, outp); } fclose(dfp); } static char *headers[] = { "From:", "Date:", "To:", "Cc:", "Subject:", 0 }; /* * interested - determine whether "hdr" is considered interesting * and thus should be printed in edited mode. */ interested(hdr) char *hdr; { char **hp = headers; while (*hp) { if (strncmp(hdr, *hp, strlen(*hp)) == SAME) return(1); hp++; } return(0); } cleanup(code) int code; { exit(code); } SHAR_EOF if test 7456 -ne "`wc -c uumailclean.c`" then echo shar: error transmitting uumailclean.c '(should have been 7456 characters)' fi echo shar: extracting warn.c '(3988 characters)' cat << \SHAR_EOF > warn.c #include /* * routines to maintain a list of mailfiles for which warning messages have * been sent out, plus routines to send out warning and failure messages. * * Written by Jim Crammond 3/86 */ #define SENDMAIL "/usr/lib/sendmail" #define NAMESIZE 15 #define BLKSIZE ((BUFSIZ/NAMESIZE) - 1) struct flist { char fname[BLKSIZE][NAMESIZE]; int nused; struct flist *next; }; struct flist warnlist; FILE *warnfp; /* * Initialise list of files for which warning messages have already been sent. * This involves reading the warnfile into a table, removing files which * no longer exist (i.e. been sent or deleted), and writing this out again. */ init_warnedlist(warnfile) char *warnfile; { struct flist *wp; char warned[NAMESIZE], *p; int i; char *index(); wp = &warnlist; wp->next = NULL; wp->nused = 0; if ((warnfp = fopen(warnfile, "r")) != NULL) { while (fgets(warned, NAMESIZE, warnfp) != NULL) { if ((p = index(warned, '\n')) != NULL) *p = '\0'; if (exists(warned)) { if (wp->nused >= BLKSIZE) { wp->next = (struct flist *) malloc(sizeof(warnlist)); wp = wp->next; wp->next = (struct flist *) NULL; wp->nused = 0; } strcpy(wp->fname[wp->nused], warned); wp->nused++; } } fclose(warnfp); } /* * Rewrite warnedlist removing files that no longer exist. * Could be really paranoid here and create a temporary file * first, rather than overwrite; in case of crashed */ if ((warnfp = fopen(warnfile, "w")) != NULL) { wp = &warnlist; while (wp) { for (i=0; i < wp->nused; i++) fprintf(warnfp, "%s\n", wp->fname[i]); wp = wp->next; } fflush(warnfp); } } /* * Determine whether the given filename is in the warn list. * Returns 1 if found, 0 otherwise. */ in_warnedlist(file) char *file; { struct flist *wp = &warnlist; int i; while (wp) { for (i=0; i < wp->nused; i++) { if (strcmp(file, wp->fname[i]) == 0) return(1); } wp = wp->next; } return(0); } /* * Add a filename to the warn list. */ add_warnedlist(file) char *file; { fprintf(warnfp, "%s\n", file); } /* * Send a Failed Mail message back to the sender, containing the whole * of the failed message. */ sendfailure(sender, rcpts, host, hours, msgfile) char *sender; char **rcpts; char *host; int hours; char *msgfile; { FILE *out, *popen(); char cmd[50]; sprintf(cmd, "%s -t", SENDMAIL); out = popen(cmd, "w"); fprintf(out, "From: MAILER-DAEMON\nSubject:Failed Mail\nTo: %s\n\n", sender); fprintf(out, "After %d days (%d hours), your message to the following people:\n\n", hours/24, hours); /* put out recipents */ while (*rcpts) { fprintf(out, "\t%s (host=%s)\n", *rcpts, host); rcpts++; } fprintf(out, "\ncould not be delivered.\n\n"); fprintf(out, " ----- Unsent message follows ----- \n"); /* print all of the message */ print_message(msgfile, out, 0); pclose(out); return; } /* * Send a Waiting Mail message back to the sender, containing a summary * of the delayed message (to remind him/her what it was about!). */ sendwarning(sender, rcpts, host, hours, failtime, msgfile) char *sender; char **rcpts; char *host; int hours; int failtime; char *msgfile; { FILE *out, *popen(); char cmd[50]; sprintf(cmd, "%s -t", SENDMAIL); out = popen(cmd, "w"); fprintf(out, "From: MAILER-DAEMON\nSubject:Waiting Mail\nTo: %s\n\n", sender); fprintf(out, "After %d days (%d hours), your message to the following people:\n\n", hours/24, hours); /* put out recipents */ while (*rcpts) { fprintf(out, "\t%s (host=%s)\n", *rcpts, host); rcpts++; } fprintf(out, "\nhas not yet been delivered. Attempts to deliver the message will\n"); fprintf(out, "continue for %d more days. No further action is required by you.\n\n", (failtime-hours)/24); fprintf(out, " ----- Queued message begins ----- \n"); /* print a summary of the message */ print_message(msgfile, out, 1); pclose(out); return; } SHAR_EOF if test 3988 -ne "`wc -c warn.c`" then echo shar: error transmitting warn.c '(should have been 3988 characters)' fi echo shar: extracting hhmailclean.c '(7113 characters)' cat << \SHAR_EOF > hhmailclean.c #include #include #include #include "local.h" #ifndef BSD4_2 #include "dir.h" #else #include #endif BSD4_2 #include "hhcp.h" /* * hhmailclean - this program searches through the hhcp spool directory * looking for mail files. Files which have been around for longer * than "failtime" hours will be returned to the sender. If a file * has been around longer than "warntime" hours, then a warning * message is sent (once) to the sender. * * These times can be specified using options -f and -w. * By default, these times are 1 week and 3 days. * * Written by Jim Crammond 3/86 */ #define FAILTIME 168 /* default hours before returning the mail */ #define WARNTIME 72 /* default hours before sending a warning */ #define WARNFILE "/usr/spool/hhcp/warnlist.mail" #define MAILPRE "/usr/spool/hhcp/M0" int warntime, failtime; char mfile[TEXTL]; /* path of mailfile */ main(argc, argv) char *argv[]; { DIR *dirp; char file[MAXNAMLEN]; struct direct *dirent, *readdir(); struct stat stbuf; time_t now; int hours; /* cd to spool */ chdir(SPOOLD); while (argc > 1 && argv[1][0] == '-') { switch (argv[1][1]) { case 'f': if (*&argv[1][2]) failtime = atoi(&argv[1][2]); else { failtime = atoi(argv[2]); argc--; argv++; } break; case 'w': if (*&argv[1][2]) warntime = atoi(&argv[1][2]); else { warntime = atoi(argv[2]); argc--; argv++; } break; default: fprintf(stderr, "unknown flag %s\n", argv[1]); break; } argc--; argv++; } if (failtime == 0) failtime = FAILTIME; if (warntime == 0) warntime = WARNTIME; init_warnedlist(WARNFILE); time(&now); if ((dirp = opendir(".")) == NULL) { printf("directory unreadable\n"); exit(1); } while ((dirent = readdir(dirp)) != NULL) { if (dirent->d_name[0] != 'P' || dirent->d_name[1] != 'B') continue; if (stat(dirent->d_name, &stbuf) == -1) { printf("cannot stat %s\n", dirent->d_name); continue; } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) continue; hours = (int) (now - stbuf.st_mtime) / 3600; if (hours >= failtime) fail(dirent->d_name, hours); else if (hours >= warntime) warn(dirent->d_name, hours); } exit(0); } /* * fail - send a failure message to the sender and delete the mail. */ fail(pbfile, hours) char *pbfile; int hours; { FILE *msgfp; char pafile[MAXNAMLEN]; char *host, *from, **to; char *gethost(), *sender(), **recipients(); strcpy(pafile,pbfile); pafile[1] = 'A'; host = gethost(pafile); if ((msgfp = fopen(pbfile, "r")) == NULL) return; if ((to = recipients(msgfp)) == NULL) return; if ((from = sender(msgfp)) == NULL) return; sendfailure(from, to, host, hours, pbfile); unlink(pafile); unlink(pbfile); unlink(mfile); return; } /* * warn - send a warning message to the sender and add the control file * to the list of files for which warnings have been sent. */ warn(pbfile, hours) char *pbfile; int hours; { FILE *msgfp; char pafile[MAXNAMLEN]; char *host, *from, **to; char *gethost(), *sender(), **recipients(); if (in_warnedlist(pbfile)) return; strcpy(pafile,pbfile); pafile[1] = 'A'; host = gethost(pafile); if ((msgfp = fopen(pbfile, "r")) == NULL) return; if ((to = recipients(msgfp)) == NULL) return; if ((from = sender(msgfp)) == NULL) return; sendwarning(from, to, host, hours, failtime, pbfile); add_warnedlist(pbfile); return; } /* * gethost - read the control file to determine if this is a mail file * and to find the host it is queued for. */ char * gethost(pafile) char *pafile; { FILE *fp; static TAB table; char *p; int flds; if ((fp = fopen(pafile, "r")) == NULL) return(NULL); if (fread(&table, sizeof(table), 1, fp) != 1) { fclose(fp); return; } fclose(fp); /* find 3rd string in text part and see if its a mailfile */ for (flds=0, p=table.text; flds < 2 && p < &table.text[TEXTL];) if (*p++ == '\0') flds++; if (strncmp(p, MAILPRE, strlen(MAILPRE)) != 0) return(NULL); strcpy(mfile, p); /* 1st string in text part is the hostname */ return(table.text); } /* * recipients - returns a list of recipients that the mail was intended * for, or NULL if the execute file is not a mail file. */ char ** recipients(msgfp) FILE *msgfp; { static char rbuf[BUFSIZ]; static char *tobuf[1000]; char buf[BUFSIZ]; char *c, *p, *rp, **t; rp = &rbuf[0]; t = &tobuf[0]; *t = rp; while (fgets(buf, BUFSIZ, msgfp) != NULL && buf[0] != '\n') { c = buf; while (*c && *c != '\n') { if (*c == ',') { if (*t != rp) { *rp++ = '\0'; *++t = rp; } c++; } else *rp++ = *c++; } if (*t != rp) { *rp++ = '\0'; *++t = rp; } } *t = NULL; return(tobuf); } /* * sender - returns the sender address from the message header, * or NULL if not found. */ char * sender(msgfp) FILE *msgfp; { static char sndbuf[BUFSIZ]; char buf[BUFSIZ]; char *p, *index(); int saved = 0; /* msgfp already points to start of headers */ while (fgets(buf, BUFSIZ, msgfp) != NULL && buf[0] != '\n') { /* * extract sender from one of the following headers, * in order of preference: "Reply-To", "Sender", "From" */ if (strncmp(buf, "Reply-To:", 9) == 0) { strcpy(sndbuf, &buf[9]); saved = 2; } else if (saved < 2 && strncmp(buf, "Sender:", 7) == 0) { strcpy(sndbuf, &buf[7]); saved = 1; } else if (saved < 1 && strncmp(buf, "From:", 5) == 0) strcpy(sndbuf, &buf[5]); } if ((p = index(sndbuf, '\n')) != NULL) *p = '\0'; fclose(msgfp); return(sndbuf); } /* * exists - returns 1 if "file" exists, else 0. */ exists(file) char *file; { return( access(file,0) == 0 ); } /* * print_message - print the message in "dfile" on the stream "outp". * If the edited flag is set, then only print some * interesting headers and the first few lines of the body. */ print_message(pbfile, outp, edited) char *pbfile; FILE *outp; int edited; { FILE *pfp; char buf[BUFSIZ]; int iflg, linecount; if ((pfp = fopen(pbfile, "r")) == NULL) return; /* skip JNT header */ while (fgets(buf, BUFSIZ, pfp) != NULL && buf[0] != '\n') ; /* print header */ iflg = 0; while (fgets(buf, BUFSIZ, pfp) != NULL && buf[0] != '\n') { if (edited) { if (buf[0] == '\t' || buf[0] == ' ') { if (iflg) fputs(buf, outp); continue; } if (!interested(buf)) { iflg = 0; continue; } iflg = 1; } fputs(buf, outp); } putc('\n', outp); /* print body */ linecount = 0; while (fgets(buf, BUFSIZ, pfp) != NULL) { if (edited && ++linecount > 5) { fprintf(outp, ".....\n"); break; } fputs(buf, outp); } fclose(pfp); } static char *headers[] = { "From:", "Date:", "To:", "Cc:", "Subject:", 0 }; /* * interested - determine whether "hdr" is considered interesting * and thus should be printed in edited mode. */ interested(hdr) char *hdr; { char **hp = headers; while (*hp) { if (strncmp(hdr, *hp, strlen(*hp)) == 0) return(1); hp++; } return(0); } SHAR_EOF if test 7113 -ne "`wc -c hhmailclean.c`" then echo shar: error transmitting hhmailclean.c '(should have been 7113 characters)' fi echo shar: extracting uumailclean.8c '(1938 characters)' cat << \SHAR_EOF > uumailclean.8c .TH UUMAILCLEAN 8C "UK-Sendmail" .UC 4 .SH NAME uumailclean \- uucp spool directory mail clean-up .br hhmailclean \- hhcp spool directory mail clean-up .SH SYNOPSIS .B /usr/lib/uucp/uumailclean .PP .B /usr/lib/uucp/hhmailclean [ .BI \-f failtime ] [ .BI \-w warntime ] .SH DESCRIPTION .I Uumailclean scans the uucp spool directory for mail files and checks to see how long they have been queued. If a mail message is found to have been queued for longer than .I failtime hours, then it is returned to the sender and deleted from the queue. If a mail message is found to have been queued for longer than .I warntime hours (but less than failtime), then a warning message is sent to the sender to inform them that the mail has yet to be delivered. .I Hhmailclean performs the same function on the hhcp spool directory. .PP By default, failtime is set to 168 hours (1 week) and warntime to 72 hours (3 days). With the subdirectories option of UKUUCP, .I uumailclean will override these defaults if times are specified in the .I L.dirs file as 3rd and 4th arguments to the subdirectory entries. For example, .nf C.hwcs 336 96 48 .fi specifies a failtime of 96 hours and a warntime of 48 hours. .PP The defaults can be overridden in .I hhmailclean with the options .BI \-f failtime and .BI \-w warntime. .PP Both programs maintain a list of mail files for which warning messages have already been sent out, so that the sender will only receive one warning message. This is normally the file .I warnlist.mail in the appropriate spool directory. .PP Both programs will typically be started by .IR cron (8). .SH FILES /usr/spool/uucp uucp spool directory .br /usr/spool/uucp/warnlist.mail list of warned mail files .br /usr/lib/uucp/L.dirs list of subdirectories of spool .br /usr/spool/hhcp hhcp spool directory .br /usr/spool/uucp/warnlist.mail list of warned mail files .SH "SEE ALSO" sendmail(8), uuclean(8C) .SH AUTHOR Jim Crammond SHAR_EOF if test 1938 -ne "`wc -c uumailclean.8c`" then echo shar: error transmitting uumailclean.8c '(should have been 1938 characters)' fi echo shar: done with directory xtras cd .. # End of shell archive exit 0