Subject: v25i036: listserv5.31 - mailing list management system, Part02/06 Newsgroups: comp.sources.unix Approved: vixie@pa.dec.com Submitted-By: tasos@cs.bu.edu Posting-Number: Volume 25, Issue 36 Archive-Name: listserv5.31/part02 #! /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 'src/README' <<'END_OF_FILE' X X X DISCUSSION LIST SERVER SYSTEM X ----------------------------- X X Copyright (c) 1991, Anastasios C. Kotsikonas X X tasos@cs.bu.edu X Boston University X December 9 1991 X AGREEMENT: This software can be used and distributed freely as long as you do not remove or alter the Copyright notice in the file defs.h; this notice is #define'd in the symbol VERSION. By using this software you are bound by this agreement. This software comes with no warranties and cannot be sold for profit. The AGREEMENT and COPYRIGHT notices should be included in all source files when distributing this software. COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas X UPDATES: All updates can be obtained from cs.bu.edu (128.197.10.1) via anonymous ftp, in the directory pub/listserv. If you downloaded this version from another ftp site, please keep an eye on cs.bu.edu. Bug fixes will be posted periodically over there, and no notifications will be posted to news; you should check the directory periodically. X COMPILER: The programs are written with ANSI C function prototypes; if your compiler cannot handle them, I suggest you also download unproto.tar.Z from cs.bu.edu; cd pub/unproto; this is a nice set of programs that will convert ANSI-isms to old style C -- please send any questions about unproto to its author, not me. There is also a script (oldc -- found in pub/utils) that will step through all of its input files and use unproto to make the conversions. For those compilers that die when they see a contol-L in the source code, I have written a C program that "cleans" source files; it is called clean.c and can be found in pub/utils as well; compile as follows: X % cc -Dunix clean.c -o clean X PREPROCESSOR: ANSI C preprocessors complain about the way I concatenate strings (as is the case with the PATH symbol). This is expected since I do not conform to ANSI C in this respect. In this case you should use the script /usr/server/stds; suggested usage is: X % stds /usr/server/src/*.h /usr/server/src/*.c Use this script before compilation, of course. Unfortunately, I cannot convert to ANSI C string concatenation, because unproto does not work in this case, and people without ANSI C compilers will be in a lot of trouble. X ACKNOWLEDGEMENTS: I would like to thank the following people for their suggestions and contributions to this package (not all suggestions have been incorporated): X1) Bob Boyd (rbn@epavax.rtpnc.epa.gov): IRIX port, gateway connections X feedback, 5.3 beta testing. X2) Stefan Schroer (Stefan.Schroer@cyber.urz.uni-wuppertal.dbp.de): MINIX port, X help files, 'get' and 'index' requests. X3) Scott J. Ellentuch (tuc@stormking.com): IBM R6000 port, enhancements to X the farch utility, 5.3 beta testing. X4) David Warner (warner@austin.onu.edu): IBM R6000 bug fixing, 5.3 beta X testing, tolerance with my obnoxious code -- I owe this gentleman a lot. X X The discussion list server system includes 65 files: X X /usr/server/doc: X server.nr -- the man page for the system (% more server.nr) X farch.nr -- the man page for the file archiving utility X queue.nr -- the man page for tha mail queueing system X README -- instructions for installing the man pages on your system X X /usr/server/help: X general -- general help file X information -- help on the information request X lists -- help on the lists request X recipients -- help on the recipients request X set -- help on the set request X statistics -- help on the statistics request X subscribe -- help on the subscribe request X unsubscribe -- help on the unsubscribe request X index -- help on the index request X get -- help on the get request X release -- help on the release request X X /usr/server/archives: X /usr/server/archives/listserv: Master archive: X DIR -- info on files and directories they are located X INDEX -- master index of all archives (listserv, pub, unix) X refcard -- list of all commands X info -- info on this archive X /usr/server/archives/listserv/example.dat: X example.dat1 -- part 1 of file example.dat in archive listserv X example.dat2 -- part 2 of file example.dat in archive listserv X example.dat3 -- part 3 of file example.dat in archive listserv X /usr/server/archives/pub: Subarchive of listserv: X DIR -- info on files and directories they are located X INDEX -- index of all archives in this archive X info -- info on this archive X /usr/server/archives/pub/unix: Subarchive of pub: X DIR -- info on files and directories they are located X INDEX -- index of files in this archive X info -- info on this archive X X /usr/server/src: X REGISTRATION -- registration form for using this software X README -- this file X global.h -- global variables definitions X struct.h -- defines the server structure X defs.h -- general definitions X tlock.c -- tests for locks, i.e. whether any server programs are running X on another file system via NFS X list.h -- specific definitions for list.c X list.c -- the list's server X listserv.h -- specific definitions for listserv.c X listserv.c -- server for individual requests X pqueue.h -- specific definitions for pqueue.c X pqueue.c -- processes the mail queue X serverd.h -- specific definitions for serverd.c X serverd.c -- parent program that spawns list or listserv X start.h -- specific definitions for start.c X start.c -- does housekeeping before spawning serverd, makes sure that X files exist, kills any running server processes, etc X sysmail.h -- specific definitions for sysmail.c X sysmail.c -- system mailmethod routines X signals.c -- signal processing routines X sender.c -- sender address manipulation routines X misc.c -- general purpose routines X farch.c -- utility for easy archiving of files X Makefile -- to build your own server X X /usr/server X setup -- a script to be run before starting for the first time X queued -- daemon controlling the processing of the mail queue X peer -- script to add a peer list X news -- script to add a news group to a list X reformat -- script used to reformat incoming messages (see documentation) X stds -- script used to do string concatenation before compilation X redux -- script that reduces the size of mbox by removing unnecessary X fields from the header of each message X ulock -- in conjunction with the 'flocks' file, this utility X removes all locked files (unlocks them) X flocks -- shell script to remove locked files X .awk -- awk program used for the 'statistics' and 'recipients' X listserv requests X .stats -- shell script used for the 'statistics' listserv request X .grep -- shell program used for the 'statistics' listserv request X .ignored -- a list of email addresses whose messages are ignored X config -- the system's configuration file X X X |-->-----------> START X | | X | | X ^ (spawns-and-dies) X | | X | | X |--<--restart--- SERVERD <--shutdown-<--| X /\ r X / \ e X / \ s X (spawns either one as necessary) t X / \ a X / \ r X LIST LISTSERV --->---t X X The diagram shows that 'start' spawns 'serverd' and then dies, and that X'listserv' may request 'serverd' to die (shutdown) or request that the system is restarted, in which case 'serverd' spawns 'start' and dies. X XEnjoy! X Revision history: X Version Date Status Comments X------------------------------------------------------------------------------ X 3.45 12/20/90 Outdated * First public version; bugs with listserv X 3.67 01/03/91 Outdated Bugs fixed X 3.68 01/04/91 Outdated * v3.67 + tlock utility X 4.0 04/09/91 Exprmntl v3.68 + STATISTICS listserv command X 4.1 04/16/91 Outdated v4.0 + redux utility X 4.2 05/02/91 Outdated v4.1 w/ optimized source code, better doc. X 4.21 05/03/91 Outdated v4.2 w/ redux which was left out by mistake X 4.3 05/03/91 Outdated * v4.21 w/ better mailer-daemon msg handling X 4.4 05/22/91 Exprmntl v4.3 w/ enhanced tlock,control,start,listserv X 4.5 06/12/91 Exprmntl v4.3 w/ enhanced listserv X 5.0 07/17/91 Outdated * v4.4 + support for multiple lists X 5.1 08/27/91 Outdated * v5.0 + bug fixes, enhanced listserv X 5.1 Rev I 10/03/91 Outdated v5.0 + more bug fixes X 5.2 10/08/91 Outdated * v5.1 + archives, GET, INDEX requests, X farch utility, moderated lists, X disabled listserv commands on a per list X basis, link with peer lists and news X feeds X 5.2 Rev A 10/10/91 Outdated v5.2 + bug fixes X 5.21 10/15/91 Exprmntl v5.2A + multiple recipients in one message X 5.3 beta 10/31/91 Exprmntl v5.21 + system mailmethod, bug fixes X 5.3 12/05/91 Outdated * v5.2A + bug fixes, universal system mailmethod, X multiple recipients in one message, X support for blanks in email addresses, X user-set limit on size of messages, X RFC 821 compliant SMTP implementation, X extensive mail loop detection mechanism, X new scripts (stds, reformat), enhanced X GET request, and more. X 5.31 12/09/91 Released * v5.3 + mail queuing capability/subsystem + X RELEASE request X X*These versions have been made public via news. END_OF_FILE if test 9846 -ne `wc -c <'src/README'`; then echo shar: \"'src/README'\" unpacked with wrong size! fi # end of 'src/README' fi if test -f 'src/defs.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/defs.h'\" else echo shar: Extracting \"'src/defs.h'\" \(4982 characters\) sed "s/^X//" >'src/defs.h' <<'END_OF_FILE' X/* X AGREEMENT: This software can be used and distributed freely as long X as you do not remove or alter the Copyright notice in this file; X this notice is #define'd in the symbol VERSION. Although you may alter X the code provided, you may not alter the functions create_header() X and create_multi_recipient_header() in list.c and listserv.c. X By using this software you are bound by this agreement. X This software comes with no warranties and cannot be sold for profit. X The AGREEMENT and COPYRIGHT notices should be included in all source X files when distributing this software. X COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas X X General system definitions. X X WARNING: Do not use the gcc preprocessor. X X WARNING: DO NOT CHANGE THE NAME OF THE 'SERVERD', 'LIST' or 'LISTSERV' X PROGRAMS in the #define's below. If you do so, make sure that command line X options are separated by at least a space from the filename. X DO NOT INCLUDE ANY CHARACTERS SUCH AS &, |, <, >. etc. X X Preserve any quotes and new lines that appear below; change only path names. X X ALWAYS SPECIFY ABSOLUTE PATHS. X X*/ X X#define VERSION "5.31 -- Copyright (c) 1991, Anastasios Kotsikonas" X#define PATH "/usr/server X#define COMPLETE_FILE(f) fprintf (f, "\n.\nQUIT\n") X#define TELNET "telnet `hostname` 25 > /dev/null 2>&1 " X#define BINMAIL "/bin/mail > /dev/null 2>&1" X#define INEWS "/usr/lib/news/inews" X#define SUBSCRIBERS ".subscribers" X#define ALIASES ".aliases" X#define NEWSF ".news" X#define PEERS ".peers" X#define HEADERS ".headers" X#define RESTRICTED ".restricted" X#define IGNORED ".ignored" X#define INFO_FILE ".info" X#define WELCOME_FILE ".welcome" X#define REPORT_LIST ".report.list" X#define WARNING PATH/.warning" X#define REPORT_SERVER PATH/.report.server" X#define REPORT_SERVERD PATH/.report.daemon" X#define REPORT_PQUEUE PATH/.report.pqueue" X#define CONFIG PATH/config" X#define LIST PATH/list -1 -L " X#define SERVER PATH/listserv -1 " X#define LIST_MAIL_FILE "mail" X#define LIST_MODERATED_F "moderated" X#define MESSAGE_IDS_F ".message.ids" X#define SERVER_MAIL_FILE PATH/requests" X#define SERVERD PATH/serverd" X#define PQUEUE PATH/pqueue" X#define START PATH/start"/* Do not give ANY command line options */ X#define START_OPTIONS "-cr" /* provide them here */ X#define SERVERD_LOCK_FILE PATH/.lock.serverd" X#define LIST_LOCK_FILE PATH/.lock.list" X#define SERVER_LOCK_FILE PATH/.lock.server" X#define PQUEUE_LOCK_FILE PATH/.lock.pqueue" X#define PID_PQUEUE PATH/.pid.pqueue" X#define PID_SERVERD PATH/.pid.daemon" X#define PID_SERVER PATH/.pid.server" X#define PID_LIST PATH/.pid.list" X#define CUT "cut" X#define AWK "awk" /* Do a 'which awk' for proper path */ X#define UPTIME "uptime" /* 'which uptime' */ X#define MAILER_DAEMON "MAILER|MAILER-DAEMON|MAILER-DEAMON|MAILER-DEMON|\ DAEMON|DEAMON|DEMON|POSTMASTER|POST-MASTER|UUCP|ROOT" X /* Preserve upper case; put all possibilities above X separated by a '|'; all of the above entries will X be used to identify mailer daemon messages so X they can get special treatment */ X#define UCB_MAIL "/usr/ucb/mail" /* Path to UCB mail program. Remove X it if UCB mail is not installed on your system, X in which case no mail is sent to MANAGER by 'serverd' X or when the programs receive various signals. */ X X/* X These #define's should not be altered. X*/ X X#define MAX_COMMANDS 15 X#define KEEP_MESSAGE_IDS 500 X#define DEFAULT_SERVER_ADDRESS "listserv" X#define DEFAULT_SERVER_CMDOPTIONS "" X#define DEFAULT_SERVER_COMMENT "Boston University List Server" X#define DEFAULT_MANAGER "server" X#define MAX_LINE 256 X#define EOS '\0' X#define RESET(var) (var[0]) = EOS X#define BSD_PS 0x01 X#define SYSV_PS 0x02 X#define USE_TELNET 0x04 X#define USE_ENV_VAR 0x08 X#define USE_MY_SYSTEM 0x10 X#define BSD_MAIL 0x20 X#define POST_MAIL 0x40 X#define GATE_MAIL 0x80 X#define USE_SYSMAIL 0x100 X#define LIMIT_MSG 0x200 X#define START_OF_MESSAGE "From " /* UNIX mail messages start w/ this string */ X#define ACK "ACK" /* Send message back to sender */ X#define NOACK "NOACK" /* Do not send message back to sender */ X#define POSTPONE "POSTPONE" /* Postpone sending mail */ X#define MAX_SIGNAL NSIG /* Highest system signal caught */ X#define BOOLEAN unsigned short int X#define TRUE 1 X#define FALSE 0 X#define SUBSCRIBED TRUE /* Subscribed sender */ X#define NOTSUBSCRIBED FALSE /* Sender is not subscribed */ X#define NEWS TRUE+1 /* News feed */ X#define PEER TRUE+2 X#define NEW_ARRIVAL "\n--- NEW MAIL HAS ARRIVED ---\n" X#define MAX_LISTS 10 X#define SUBJECT "Subject: " X#define MESSAGE_ID1 "Message-Id: " X#define MESSAGE_ID2 "Message-ID: " X#define MESSAGE_ID3 "Message-id: " X X#define COMPLETE_TELNET(f) \ X if (sys.options & USE_TELNET) \ X COMPLETE_FILE (f) END_OF_FILE if test 4982 -ne `wc -c <'src/defs.h'`; then echo shar: \"'src/defs.h'\" unpacked with wrong size! fi # end of 'src/defs.h' fi if test -f 'src/sender.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sender.c'\" else echo shar: Extracting \"'src/sender.c'\" \(6930 characters\) sed "s/^X//" >'src/sender.c' <<'END_OF_FILE' X/* X ---------------------------------------------------------------------------- X | SENDER ORIENTED FUNCTIONS | X | | X | Version 2.0 | X | | X | (or, when Computer Science gets to you) | X | | X | Written by Anastasios Kotsikonas | X | (tasos@cs.bu.edu) | X | | X | AGREEMENT: This software can be used and distributed freely as long | X | as you do not remove or alter the Copyright notice in the file defs.h; | X | this notice is #define'd in the symbol VERSION. Although you may alter | X | the code provided, you may not alter the functions create_header() | X | and create_multi_recipient_header() in list.c and listserv.c. | X | By using this software you are bound by this agreement. | X | This software comes with no warranties and cannot be sold for profit. | X | The AGREEMENT and COPYRIGHT notices should be included in all source | X | files when distributing this software. | X | COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas | X ---------------------------------------------------------------------------- X*/ X X#include X#include X#include X#include "defs.h" X extern void report_progress (FILE *, char *, int); extern char *upcase (char *); extern void extract_subscriber (FILE *, char *); X BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *); BOOLEAN check_file (FILE *, char *, char *, BOOLEAN); BOOLEAN ignore_sender (FILE *, char *, FILE *); void extract_sender (char *); void extract_subscriber (FILE *f, char *subscriber); void extract_origin (char *); X X/* X Check if 'sender' is subscribed. Return SUBSCRIBED, NEWS PEER or X NOTSUBSCRIBED. Comparisons are done in upper case. X*/ X BOOLEAN subscribed (FILE *report, char *sender, char *subscribersf, X char *newsf, char *peersf, char *aliasesf) X{ X if (subscribersf == NULL) /* call made by distribute () in listserv.c */ X return NOTSUBSCRIBED; X if (check_file (report, sender, subscribersf, FALSE) || X check_file (report, sender, aliasesf, TRUE)) X return SUBSCRIBED; X else if (newsf != NULL && (check_file (report, sender, newsf, FALSE) || X check_file (report, sender, aliasesf, TRUE))) X return NEWS; X else if (peersf != NULL && (check_file (report, sender, peersf, FALSE) || X check_file (report, sender, aliasesf, TRUE))) X return PEER; X return NOTSUBSCRIBED; X} X X/* X Check the given file for subscription. If the file is an aliases file X and the sender is listed in there, store his actual mailing address X in 'sender'. X*/ X BOOLEAN check_file (FILE *report, char *sender, char *file, X BOOLEAN checking_aliases) X{ X char subscriber [MAX_LINE]; X char mode [MAX_LINE]; X char name [MAX_LINE]; X char error [MAX_LINE]; X FILE *f; X X if ((f = fopen (file, "r")) == NULL) X RESET (error), X sprintf (error, "\ncheck_file(): Could not open %s", file), X report_progress (report, error, TRUE), X exit (1); X upcase (sender); /* Convert to upper case */ X while (!feof (f)) { /* Check list of subscribers */ X subscriber[0] = mode[0] = RESET (name); X extract_subscriber (f, subscriber); X fscanf (f, "%s ", mode); X if (!checking_aliases) X fgets (name, MAX_LINE - 2, f); X upcase (subscriber); X if (!strcmp (sender, subscriber)) { X fclose (f); X if (checking_aliases) X upcase (mode), X strcpy (sender, mode); X return SUBSCRIBED; X } X } X fclose (f); X return NOTSUBSCRIBED; X} X X/* X Check if 'sender' appears in the IGNORED file. X*/ X BOOLEAN ignore_sender (FILE *ignored, char *sender, FILE *report) X{ X char report_msg [MAX_LINE]; X char ignored_user [MAX_LINE]; X char line[MAX_LINE]; X X rewind (ignored); X while (!feof (ignored)) { /* Check the IGNORED file first */ X line[0] = RESET (ignored_user); X fgets (line, MAX_LINE - 2, ignored); X sscanf (line, "%s", ignored_user); X upcase (ignored_user); X if (ignored_user[0] != EOS) X if (!strcmp (ignored_user, sender)) { X RESET (report_msg); X sprintf (report_msg, "User %s and message ignored.\n", sender); X report_progress (report, report_msg, FALSE); X return TRUE; X } X } X return FALSE; X} X X/* X Extract the sender's email address. To do that, skip over the leading X "From ". That's where the address starts. Then put an EOS character at X the end of this address (a blank terminates this address string). X*/ X void extract_sender (char *s) X{ X int nsquote = 0, ndquote = 0, nparen = 0, nangle = 0, nsquare = 0; X BOOLEAN done = FALSE; X X sprintf (s, "%s", s + strlen (START_OF_MESSAGE)); X while (*s && !done) { /* Look for end of address substring */ X (*s == '\"' ? (nsquote ? (nsquote = 0) : (nsquote = 1)) : 0); X (*s == '\"' ? (ndquote ? (ndquote = 0) : (ndquote = 1)) : 0); X (*s == '(' ? ++nparen : 0); X (*s == ')' ? --nparen : 0); X (*s == '<' ? ++nangle : 0); X (*s == '>' ? --nangle : 0); X (*s == '[' ? ++nsquare : 0); X (*s == ']' ? --nsquare : 0); X ((*s == ' ' || *s == '\t') ? X ((nsquote || ndquote || nparen || nangle || nsquare) ? X 0 : (done = TRUE)) : 0); X ++s; X } X *(s - 1) = EOS; /* 's' is now pointing to the sender's address */ X} X X/* X Extract the subscriber's address from the file. X*/ X void extract_subscriber (FILE *f, char *subscriber) X{ X int nsquote = 0, ndquote = 0, nparen = 0, nangle = 0, nsquare = 0, i = 0; X BOOLEAN done = FALSE; X char c; X X while (!feof (f) && !done) { X c = fgetc (f); X (c == '\"' ? (nsquote ? (nsquote = 0) : (nsquote = 1)) : 0); X (c == '\"' ? (ndquote ? (ndquote = 0) : (ndquote = 1)) : 0); X (c == '(' ? ++nparen : 0); X (c == ')' ? --nparen : 0); X (c == '<' ? ++nangle : 0); X (c == '>' ? --nangle : 0); X (c == '[' ? ++nsquare : 0); X (c == ']' ? --nsquare : 0); X ((c == ' ' || c == '\t') ? X ((nsquote || ndquote || nparen || nangle || nsquare) ? X 0 : (done = TRUE)) : 0); X subscriber [i++] = c; X } X if (i > 0) X subscriber[i - 1] = EOS; X} X X/* X Extract the originator of the message, i.e. the list that the original X message first originated from. X*/ X void extract_origin (char *s) X{ X char *p; X X if (p = strchr (s, '<')) X sprintf (s, "%s", p + 1); /* Remove '<' */ X if (p = strchr (s, '>')) X *p = EOS; /* Remove '>' */ X else { /* Get to the end of the address */ X while (*s != EOS && !isspace (*s)) X ++s; X *s = EOS; X } X} END_OF_FILE if test 6930 -ne `wc -c <'src/sender.c'`; then echo shar: \"'src/sender.c'\" unpacked with wrong size! fi # end of 'src/sender.c' fi if test -f 'src/serverd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/serverd.c'\" else echo shar: Extracting \"'src/serverd.c'\" \(9491 characters\) sed "s/^X//" >'src/serverd.c' <<'END_OF_FILE' X/* X ---------------------------------------------------------------------------- X | DISCUSSION LIST SYSTEM DAEMON | X | | X | Version 3.0 | X | | X | (or, when Computer Science gets to you) | X | | X | Written by Anastasios Kotsikonas | X | (tasos@cs.bu.edu) | X | | X | AGREEMENT: This software can be used and distributed freely as long | X | as you do not remove or alter the Copyright notice in the file defs.h; | X | this notice is #define'd in the symbol VERSION. Although you may alter | X | the code provided, you may not alter the functions create_header() in | X | list.c and listserv.c. By using this software you are bound by this | X | agreement. | X | This software comes with no warranties and cannot be sold for profit. | X | The AGREEMENT and COPYRIGHT notices should be included in all source | X | files when distributing this software. | X | COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas | X ---------------------------------------------------------------------------- X X Spawn list or listserv upon arrival of new messages. Send mail to X MANAGER if something went wrong (only if using UCB mail). X serverd will not spawn if the current load average is above max_load X and the -l flag is on, until it has delayed MAX_TRIES * 30 seconds. X serverd communicates with listerv via exit status 6 and 7; this are X the request to shutdwon/restart the system; on status 7, serverd spawns X start and dies; if it cannot restart, it sends mail and commits suicide. X serverd reports to REPORT_SERVERD. X X COMMAND LINE OPTIONS: X -1: Execute only once -- to be used with cron. X -l: Enforce restrictions based on the current load average. X -e: Echo reports to the screen. X X EXIT CODES: X 0: OK X 1: Could not open file X 2: Could not lock file X 3: Command line option error X 4: Syntax error in file X 5: Could not spawn X 6: Shutdown request X 7: Restart request X 8: Received system signal X 9: Too many multiple recipients X 10: Could not connect to server X 11: Server broke connection X 12: Could not create socket X 13: No such host X 14: Could not connect to port X 15: Connection timed out X 16: Malloc failed X*/ X X#include X#include X#include X#include X#include X#include X#include "defs.h" X#include "serverd.h" X#include "struct.h" X#include "global.h" X X#ifdef __STDC__ X#include extern int syscom (char *, ...); X#else X#include extern int syscom (); X#endif extern double atof (); extern int sys_config (FILE *, SYS *); extern int getopt (int, char **, char *); extern void init_signals (void); extern void catch_signals (void); X void main (int, char **, char **); void serverd_config (char *alias); void usage (void); void gexit (void); X char *exit_string[] = { /* Define exit status strings */ X/* 0 */ "OK", X/* 1 */ "Could not open file", X/* 2 */ "Could not lock file", X/* 3 */ "Command line option error", X/* 4 */ "Syntax error in file", X/* 5 */ "Could not spawn", X/* 6 */ "Shutdown request", X/* 7 */ "Restart request", X/* 8 */ "Received system signal", X/* 9 */ "Too many multiple recipients", X/* 10 */"Could not connect to server", X/* 11 */"Server broke connection", X/* 12 */"Could not create socket", X/* 13 */"No such host", X/* 14 */"Could not connect to port", X/* 15 */"Could not deliver mail", X/* 16 */"Malloc failed", X/* 17 */ "Unknown exit code" X}; X void main (int argc, char **argv, char **envp) X{ X struct stat stat_buf; X int i, status, try, fd, nlists; X FILE *f, *loadf, *report; X float load, max_load; X BOOLEAN loadr = FALSE, execute_once = FALSE; X char list [MAX_LINE]; X char server [MAX_LINE]; X char msg [MAX_LINE]; X int c; X char *options = "1l:e"; X extern char *optarg; X extern int optopt; X X while ((c = getopt (argc, argv, options)) != EOF) X switch ((char) c) { X case '1': execute_once = TRUE; break; X case 'e': tty_echo = TRUE; break; X case 'l': loadr = TRUE; X max_load = (float) atof (optarg); X break; X case ':': X fprintf (stderr, "serverd: Option '%c' requires an argument.\n", X optopt); X exit (3); X case '?': X default: X usage (); X } X#ifndef _MINIX X if (lockf ((fd = open (SERVERD_LOCK_FILE, O_RDWR)), F_TLOCK, 0)) X fprintf (stderr, "serverd: Unable to lock %s. Aborting.\n", X SERVERD_LOCK_FILE), X exit (2); X#endif X if ((report = fopen (REPORT_SERVERD, "a")) == NULL) X fprintf (stderr, "serverd: Could not open %s\n", REPORT_SERVERD), X exit (1); X X if ((f = fopen (PID_SERVERD, "w")) != NULL) X fprintf (f, "%d", getpid()), X fclose (f); X signal (SIGINT, gexit); X init_signals(); X catch_signals (); X X nlists = sys_config (report, &sys); X while (007) { X for (i = 0; i < nlists; ++i) { X serverd_config (sys.lists[i].alias); X if (!stat (list_mail_f, &stat_buf) && stat_buf.st_size > 0) { X sprintf (msg, "\n--- NEW MAIL FOR %s ---\n", sys.lists[i].alias); X report_progress (report, msg, FALSE); X if (loadr) { /* enforce restrictions */ X try = 0; X again_list: X syscom ("%s | %s -F, '{ print $4 }' | %s -d' ' -f5 > %s", X UPTIME, AWK, CUT, LOAD_FILE); X if ((loadf = fopen (LOAD_FILE, "r")) == NULL) X sprintf (msg, "\nCould not open %s", LOAD_FILE), X report_progress (report, msg, TRUE), X exit (1); X fscanf (loadf, "%f", &load); X fclose (loadf); X unlink (LOAD_FILE); X if (load > max_load && try < MAX_TRIES) { X ++try; X sleep (30); X goto again_list; X } X } X RESET (list); X sprintf (list, "%s %s %s", LIST, sys.lists[i].alias, X sys.lists[i].cmdoptions); X report_progress (report, list, TRUE); X if ((status = system (list)) > 127) { /* run list */ X sprintf (msg, "serverd died: LIST: %s", exit_string[status / 256]); X if (sys.options & BSD_MAIL) X syscom ("%s -s \"%s\" %s < /dev/null", UCB_MAIL, msg, sys.manager); X report_progress (report, msg, TRUE); X exit (status / 256); X } X else if (status == 127) { X sprintf (msg, "serverd died: could not execute shell for list"); X if (sys.options & BSD_MAIL) X syscom ("%s -s \"%s\" %s < /dev/null", UCB_MAIL, msg, sys.manager); X report_progress (report, msg, TRUE); X exit (5); X } X } X if (sys.frequency > 0) X sleep (sys.frequency); /* do a quickie to The Spy Who Loved Him */ X } X if (!stat (SERVER_MAIL_FILE, &stat_buf) && stat_buf.st_size > 0) { X report_progress (report, "\n--- NEW MAIL FOR SERVER ---\n", FALSE); X if (loadr) { /* Enforce restrictions */ X try = 0; X again_server: X syscom ("%s | %s -F, '{ print $4 }' | %s -d' ' -f5 > %s", X UPTIME, AWK, CUT, LOAD_FILE); X if ((loadf = fopen (LOAD_FILE, "r")) == NULL) X sprintf (msg, "\nCould not open %s", LOAD_FILE), X report_progress (report, msg, TRUE), X exit (1); X fscanf (loadf, "%f", &load); X fclose (loadf); X unlink (LOAD_FILE); X if (load > max_load && try < MAX_TRIES) { X ++try; X sleep (30); X goto again_server; X } X } X RESET (server); X sprintf (server, "%s %s", SERVER, sys.server.cmdoptions); X report_progress (report, server, TRUE); X if ((status = system (server)) > 127) { /* run server */ X sprintf (msg,"serverd died: LISTSERV: %s", exit_string[status / 256]); X if (sys.options & BSD_MAIL) X syscom ("%s -s \"%s\" %s < /dev/null", UCB_MAIL, msg, sys.manager); X report_progress (report, msg, TRUE); X if (status == 6 * 256) /* Shutdown request */ X unlink (PID_SERVERD), X exit (6); X if (status == 7 * 256) { /* Restart request */ X execl (START, START_OPTIONS, START_OPTIONS, NULL); X sprintf (msg, "serverd commits suicide: Could not restart system"); X report_progress (report, msg, TRUE); X if (sys.options & BSD_MAIL) X syscom ("%s -s \"%s\" %s < /dev/null", UCB_MAIL, msg, sys.manager); X exit (5); X } X else X exit (status / 256); X } X else if (status == 127) { X sprintf (msg, "serverd died: could not execute shell for listserv"); X if (sys.options & BSD_MAIL) X syscom ("%s -s \"%s\" %s < /dev/null", UCB_MAIL, msg, sys.manager); X report_progress (report, msg, TRUE); X exit (5); X } X } X if (execute_once) X gexit(); X if (sys.frequency > 0) X sleep (sys.frequency); /* do a quickie to Money Penny */ X } X} X void serverd_config (char *alias) X{ X setup_string (list_mail_f, alias, LIST_MAIL_FILE); X} X void usage () X{ X fprintf (stderr, "Usage: serverd [-1] [-e] [-l load]\n\ X-1: Execute only once.\n\ X-e: Echo reports to the screen.\n\ X-l: Enforce load restrictions.\n"); X exit (3); X} X X/* X Graceful exit. Remove pid file. X*/ X void gexit () X{ X unlink (PID_SERVERD); X exit (0); X} END_OF_FILE if test 9491 -ne `wc -c <'src/serverd.c'`; then echo shar: \"'src/serverd.c'\" unpacked with wrong size! fi # end of 'src/serverd.c' fi if test -f 'src/start.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/start.c'\" else echo shar: Extracting \"'src/start.c'\" \(12157 characters\) sed "s/^X//" >'src/start.c' <<'END_OF_FILE' X/* X ---------------------------------------------------------------------------- X | DISCUSSION LIST SYSTEM HOUSEKEEPER | X | | X | Version 2.5 | X | | X | (or, when Computer Science gets to you) | X | | X | Written by Anastasios Kotsikonas | X | (tasos@cs.bu.edu) | X | | X | AGREEMENT: This software can be used and distributed freely as long | X | as you do not remove or alter the Copyright notice in the file defs.h; | X | this notice is #define'd in the symbol VERSION. Although you may alter | X | the code provided, you may not alter the functions create_header() | X | and create_multi_recipient_header() in list.c and listserv.c. | X | By using this software you are bound by this agreement. | X | This software comes with no warranties and cannot be sold for profit. | X | The AGREEMENT and COPYRIGHT notices should be included in all source | X | files when distributing this software. | X | COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas | X ---------------------------------------------------------------------------- X X This is the proper way of starting the discussion list. The program verifies X that no other serverd, list or listserv programs are running on the X system (and kills them before proceeding -- after confirming), X makes sure the required files exist (and creates new ones if missing -- X after confirming), backs up all reports into files with extension .acc, X creates new directories for new discussion lists as necessary, X and finally spawns serverd. start reports to REPORT_START. X X COMMAND LINE OPTIONS: X -k: just kill all pertinent programs that may already be running; no X discussion list is started in this case. X -c: Do not confirm before killing a process. X -r: Do not report; useful when starting up when system is rebooted. X X WARNING: The program won't work correctly in the absence of an extended X egrep facility that does matching at the end of a line with a $ and X accepts multiple regular expressions separated by a |. In this case, X the user may have to manually look for and terminate any such programs. X Also when the output of the 'ps' command exceeds 80 characters (due perhaps X to long path names) the user may again have to terminate programs by hand. X Note that a file locking mechanism for serverd, list and listserv is used X to ensure against multiple executions of the same program. X X WARNING: When using the SYSV ps command and it chops output to 80 characters, X start may not be able to locate processes already running; this may occur if X the path to /usr/server is too long. X*/ X X#include X#include X#include X#include X#include "defs.h" X#include "start.h" X#include "struct.h" X#include "global.h" X X#define GET_RESPONSE {\ X fflush (stdout); \ X fflush (stdin); \ X c = fgetc (stdin); \ X if (c != '\n' && c != EOF) \ X while (fgetc (stdin) != '\n'); \ X fflush (stdin);\ X } X X/* X Function prototypes: X*/ X X#ifdef __STDC__ X#include extern int syscom (char *, ...); X#else X#include extern int syscom (); X#endif extern char *extract_filename (char *); extern void report_progress (FILE *, char *, int); extern int getopt (int, char **, char *); void main (int, char **); void check_for (char *, FILE *, BOOLEAN, BOOLEAN); void usage (void); void start_abort (void); void backup (char *, char *); void start_config (char *); X void main (int argc, char **argv) X{ X char command [256]; X char line [MAX_LINE]; X char msg [2 * MAX_LINE]; X char dir [MAX_LINE]; X char *addr1, *addr2, *addr3, *addr4, *options = "ckr"; X int c; X FILE *f, *p, *report; X int i, nlists, pid, procs_killed = 0, procs; X BOOLEAN just_kill = FALSE, confirm = TRUE, do_report = TRUE; X struct stat stat_buf; X extern char *optarg; X extern int optopt; X X while ((c = getopt (argc, argv, options)) != EOF) X switch ((char) c) { X case 'c': confirm = FALSE; break; X case 'k': just_kill = TRUE; break; X case 'r': do_report = FALSE; break; X case '?': X default: X usage(); X } X X /* First make sure no other SERVERD programs are running. If so, kill X them all (after confirming) before proceeding. */ X X backup (REPORT_START, REPORT_START_ACC); X if ((report = fopen (REPORT_START, "a")) == NULL) X fprintf (stderr, "start: Could not open %s\n", REPORT_START), X start_abort(); X nlists = sys_config (report, &sys); X if (just_kill) X report_progress (report, "\n--- SHUTTING LISTSERV SYSTEM DOWN ---\n",FALSE); X else X report_progress (report, "\n--- STARTING LISTSERV SYSTEM ---\n", FALSE); X#ifndef _MINIX X if (sys.options & BSD_PS) X syscom ("ps -gx > /tmp/ps"); /* do not combine the two "syscom"'s */ X else X syscom ("ps -ef | grep %s > /tmp/ps", getenv ("LOGNAME")); X tty_echo = FALSE; X syscom ("egrep '%s$|%s|%s$|%s |%s$|%s |%s|%s |queued' /tmp/ps > /tmp/found", X (addr1 = extract_filename (SERVERD)), addr1, X (addr2 = extract_filename (LIST)), addr2, X (addr3 = extract_filename (SERVER)), addr3, X (addr4 = extract_filename (PQUEUE)), addr4); X free ((char *) addr1); X free ((char *) addr2); X free ((char *) addr3); X free ((char *) addr4); X unlink ("/tmp/ps"); X tty_echo = TRUE; X if ((f = fopen ("/tmp/found", "r")) == NULL) X sprintf (msg, "Error opening /tmp/found. Aborting. %s", X ((just_kill == FALSE) ? "No discussion list started." : "")), X report_progress (report, msg, TRUE), X start_abort (); X X syscom ("wc -l /tmp/found > /tmp/nprocs"); X if ((p = fopen ("/tmp/nprocs", "r")) != NULL) { X fscanf (p, "%d", &procs); X if (do_report) X sprintf (msg, "OLD LISTSERV PROCESSES RUNNING:\t%d\n", procs), X report_progress (report, msg, FALSE); X fclose (p); X unlink ("/tmp/nprocs"); X } X else X sprintf (msg, "Error opening /tmp/nprocs. Aborting. %s", X ((just_kill == FALSE) ? "No discussion list started." : "")), X report_progress (report, msg, TRUE), X start_abort (); X X while (!feof (f)) { /* get pid's and kill processes after confirming */ X RESET (line); X fgets (line, MAX_LINE - 2, f); X if (line[0] != EOS) { X if (sys.options & BSD_PS) X sscanf (line, "%d ", &pid); X else X sscanf (line, "%s %d ", command, &pid); X if (confirm) { X c = EOS; X while (c != EOF && c != 'Y' && c != 'N') { X sprintf (msg, "\n%s\n%c[7m%s%c[mKill it to proceed ? (Y/N) ", X ((just_kill == FALSE) ? X "ERROR: another listserv-system program running:" : X "Listserv-system program found:"), X 27, line, 27); X report_progress (report, msg, FALSE); X GET_RESPONSE; X } X if (c == 'N' || c == EOF) X sprintf (msg, "start aborted. %s\n", X ((just_kill == FALSE) ? "System not started.":"")), X report_progress (report, msg, TRUE), X exit (1); X } X kill (pid, SIGINT); X ++procs_killed; X } X } X fclose (f); X unlink ("/tmp/found"); X if ((f = fopen (PID_SERVERD, "r")) != NULL) X fscanf (f, "%d", &pid), X kill (pid, SIGINT), X ++procs_killed, X fclose (f), X unlink (PID_SERVERD); X if ((f = fopen (PID_LIST, "r")) != NULL) X fscanf (f, "%d", &pid), X kill (pid, SIGINT), X ++procs_killed, X fclose (f), X unlink (PID_LIST); X if ((f = fopen (PID_SERVER, "r")) != NULL) X fscanf (f, "%d", &pid), X kill (pid, SIGINT), X ++procs_killed, X fclose (f), X unlink (PID_SERVER); X if ((f = fopen (PID_PQUEUE, "r")) != NULL) X fscanf (f, "%d", &pid), X kill (pid, SIGINT), X ++procs_killed, X fclose (f), X unlink (PID_PQUEUE); X if (do_report) X sprintf (msg, "OLD LISTSERV PROCESSES KILLED:\t%d\n", procs_killed), X report_progress (report, msg, FALSE); X X if (just_kill) /* Done */ X report_progress (report, "", -TRUE), X fclose (report), X exit (0); X#endif X X syscom ("echo Serverd lock file > %s", SERVERD_LOCK_FILE); X syscom ("echo List lock file > %s", LIST_LOCK_FILE); X syscom ("echo Server lock file > %s", SERVER_LOCK_FILE); X syscom ("echo Pqueue lock file > %s", PQUEUE_LOCK_FILE); X X backup (REPORT_SERVER, REPORT_SERVER_ACC); X backup (REPORT_SERVERD, REPORT_SERVERD_ACC); X backup (REPORT_PQUEUE, REPORT_PQUEUE_ACC); X sprintf (server_ignoredf, "%s/%s", PATH", IGNORED); X check_for (server_ignoredf, report, do_report, confirm); X for (i = 0; i < nlists; ++i) { X start_config (sys.lists[i].alias); X sprintf (dir, "%s/lists/%s", PATH", sys.lists[i].alias); X if (stat (dir, &stat_buf)) { X if (mkdir (dir, 475)) X sprintf (msg, "Could not create directory %s", dir), X report_progress (report, msg, TRUE), X start_abort (); X syscom ("chmod 733 %s", dir); X if (do_report) X sprintf (msg, "*** New list %s ***\n", sys.lists[i].alias), X report_progress (report, msg, FALSE); X syscom ("cp %s %s", server_ignoredf, dir); X syscom ("echo %s >> %s/%s", sys.lists[i].alias, dir, IGNORED); X syscom ("echo %s >> %s/%s", sys.lists[i].address, dir, IGNORED); X syscom ("echo %s | sed 's/listserv/server/' >> %s/%s", sys.server.address, X dir, IGNORED); X syscom ("touch %s", infof); X syscom ("touch %s", welcomef); X syscom ("touch %s/%s", dir, LIST_MAIL_FILE); X syscom ("chmod 666 %s/%s", dir, LIST_MAIL_FILE); X syscom ("touch %s/%s", dir, MODERATED_MAIL_FILE); X syscom ("chmod 666 %s/%s", dir, MODERATED_MAIL_FILE); X } X check_for (subscribersf, report, do_report, confirm); X check_for (aliasesf, report, do_report, confirm); X check_for (newsf, report, do_report, confirm); X check_for (peersf, report, do_report, confirm); X check_for (restrictedf, report, do_report, confirm); X backup (report_listf, report_list_accf); X } X syscom ("%s %s &", SERVERD, sys.serverd_cmdoptions); X report_progress (report, "", -TRUE); X fclose (report); X exit (0); X} X X/* X Make sure that file 's' exists. Create a new one if necessary. X*/ X void check_for (char *s, FILE *report, BOOLEAN do_report, BOOLEAN confirm) X{ X char c = EOS, msg [MAX_LINE]; X struct stat stat_buf; X X if (stat (s, &stat_buf)) { /* make sure we have file 's' */ X if (confirm) { X while (c != EOF && c != 'Y' && c != 'N') { X if (do_report) X sprintf (msg, "No %s file found. Create a new one? (Y/N) ", s), X report_progress (report, msg, FALSE); X GET_RESPONSE; X } X if (c == 'N' || c == EOF) X start_abort (); X } X syscom ("touch %s", s); X } X} X X/* X Append 'src' to 'dest' and create a brand new 'src'. X*/ X void backup (char *src, char *dest) X{ X struct stat stat_buf; X X if (!stat (src, &stat_buf)) /* prepare for backup */ X syscom ("cat %s >> %s", src, dest), X unlink (src), X syscom ("touch %s", src); X} X X/* X Print usage. X*/ X void usage () X{ X fprintf (stderr, "Usage: start [-k] [-c] [-r]\n\ X-k: Just kill any listserv-system programs running.\n\ X-c: Do not confirm before killing processes.\n\ X-r: Restrict reporting to screen.\n"); X exit (1); X} X X/* X Abort after printing a message. X*/ X void start_abort () X{ X fprintf (stderr, "### start aborted; discussion list not started. ###\n"); X exit (1); X} X void start_config (char *alias) X{ X setup_string (subscribersf, alias, SUBSCRIBERS); X setup_string (aliasesf, alias, ALIASES); X setup_string (newsf, alias, NEWSF); X setup_string (peersf, alias, PEERS); X setup_string (restrictedf, alias, RESTRICTED); X setup_string (ignoredf, alias, IGNORED); X setup_string (report_listf, alias, REPORT_LIST); X setup_string (infof, alias, INFO_FILE); X setup_string (welcomef, alias, WELCOME_FILE); X setup_string (report_list_accf, alias, REPORT_LIST_ACC); X} END_OF_FILE if test 12157 -ne `wc -c <'src/start.c'`; then echo shar: \"'src/start.c'\" unpacked with wrong size! fi # end of 'src/start.c' fi if test -f 'src/sysmail.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sysmail.c'\" else echo shar: Extracting \"'src/sysmail.c'\" \(6501 characters\) sed "s/^X//" >'src/sysmail.c' <<'END_OF_FILE' X/* X ---------------------------------------------------------------------------- X | SYSTEM MAILING ROUTINES | X | | X | Version 1.0 | X | | X | (or, when Computer Science gets to you) | X | | X | Written by Anastasios Kotsikonas | X | (tasos@cs.bu.edu) | X | | X | AGREEMENT: This software can be used and distributed freely as long | X | as you do not remove or alter the Copyright notice in the file defs.h; | X | this notice is #define'd in the symbol VERSION. Although you may alter | X | the code provided, you may not alter the functions create_header() | X | and create_multi_recipient_header() in list.c and listserv.c. | X | By using this software you are bound by this agreement. | X | This software comes with no warranties and cannot be sold for profit. | X | The AGREEMENT and COPYRIGHT notices should be included in all source | X | files when distributing this software. | X | COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas | X ---------------------------------------------------------------------------- X X These routines implement the 'system' mailmethod. The system opens a socket X and connects directly with sendmail for mail delivery. During the process X of porting the code to various platforms, lots of grosse things were X encountered with sockets and protocols, so the code may seem kludgy. X X When mail cannot be sent due to network problems, it is queued up and will X be delivered later by the queue daemon. X*/ X X#include X#include X#include X#include X#include X#include X#include "defs.h" X#include "struct.h" X#include "sysmail.h" X X#ifdef __STDC__ X#include extern int syscom (char *, ...); X#else X#include extern int syscom (); X#endif extern FILE *report; extern SYS sys; extern BOOLEAN debug; X extern void report_progress (FILE *, char *, int); X BOOLEAN sysmail (char *); BOOLEAN _sysmail (char *, int); int server_response (int, FILE *); int build_tcp_connection (FILE *); void queue_up (char *file); X X/* X The return value depends on the return value of _sysmail (). X*/ X BOOLEAN sysmail (char *file) X{ X char error [MAX_LINE]; X X queue = FALSE; X if (debug) { X if ((sent = fopen (SENT, "w")) == NULL) X sprintf (error, "\nsysmail(): Could not open %s", SENT), X report_progress (report, error, TRUE), X exit (1); X if ((received = fopen (RECEIVED, "w")) == NULL) X sprintf (error, "\nsysmail(): Could not open %s", RECEIVED), X report_progress (report, error, TRUE), X exit (1); X } X return _sysmail (file, 1); X} X X/* X 'system' mailmethod. It returns TRUE if the mail was successfully X delivered, FALSE if it was queued. X*/ X BOOLEAN _sysmail (char *file, int call) X{ X char buf [MAX_LINE] ; X char error [MAX_LINE]; X FILE *msg; X int sock_fd, cmd, timeout; X X if ((msg = fopen (file, "r")) == NULL) X sprintf (error, "\n_sysmail(): Could not open %s", file), X report_progress (report, error, TRUE), X exit (1); X sock_fd = build_tcp_connection (report); X if ((cmd = server_response (sock_fd, report)) != ACKNOWLEDGE) { X report_progress (report, "\n_sysmail(): Could not connect to server", TRUE); X queue = TRUE; X goto abort; X } X X PROTOCOL (DATA); X while (!feof (msg) && strcmp (buf, END_OF_TEXT)) { /* Copy header and text */ X RESET (buf); X fgets (buf, MAX_LINE - 2, msg); X write (sock_fd, buf, strlen (buf)); X if (debug) X fprintf (sent, "%s", buf), X fflush (sent); X } X cmd = server_response (sock_fd, report); X PROTOCOL (CLOSE_CONNECTION); X abort: X if (queue) X queue_up (file); X CLOSEF; X if (debug) X fclose (sent), X fclose (received); X if (queue) X return FALSE; X else X return TRUE; X} X X/* X Get server response. Return the command number that the server sent. X*/ X int server_response (int sock_fd, FILE *report) X{ X char buf [MAX_LINE]; X int cmd, i; X X if (read (sock_fd, buf, 3) < 0) /* Get server command */ X report_progress (report, "\nserver_response(): Server dropped connection", X TRUE), X exit (11); X RESET (message); X buf[3] = EOS; X cmd = atoi (buf); X sprintf (message, "%s", buf); X i = strlen (message); X if (debug) X fprintf (received, "%s", buf), X fflush (received); X while (buf[0] != '\n') { /* Read till the end of socket */ X if (read (sock_fd, buf, 1) < 1) { X if (debug) X fprintf (received, "%s", buf), X fflush (received); X message [i] = EOS; X break; X } X message [i++] = (buf[0] != '\n' ? buf[0] : EOS); X if (debug) X fprintf (received, "%c", buf[0]), X fflush (received); X } X return cmd; X} X X/* X Establish connection with sendmail/smtp. X*/ X int build_tcp_connection (FILE *report) X{ X int sock_fd; X struct sockaddr_in sin; X struct hostent *hostentry; X X if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) X report_progress (report, "\nbuild_tcp_connection(): Could not create \ socket", TRUE), X exit(12); X if (! (hostentry = gethostbyname ("localhost"))) X report_progress (report, "\nbuild_tcp_connection(): No such host", TRUE), X exit(13); X sin.sin_family = AF_INET; X sin.sin_port = htons (PORT); X memcpy ((char *) &sin.sin_addr.s_addr, (char *) hostentry->h_addr, X hostentry->h_length); X memset (sin.sin_zero, EOS, sizeof (sin.sin_zero)); X if (connect (sock_fd, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)) X < 0) X report_progress (report, "\nbuild_tcp_connection(): Could not connect to \ port", TRUE), X exit (14); X return sock_fd; X} X X/* X Queue up a file for later delivery. X*/ X void queue_up (char *file) X{ X FILE *id; X int id_no = 0; X char msg [MAX_LINE]; X X if ((id = fopen (IDF, "r")) != NULL) X fscanf (id, "%d\n", &id_no), X fclose (id); X syscom ("mv %s %s/%d", file, QUEUE_DIR, ++id_no); X syscom ("echo %d > %s", id_no, IDF); X sprintf (msg, "File %s placed in the mail queue", file); X report_progress (report, msg, TRUE); X} END_OF_FILE if test 6501 -ne `wc -c <'src/sysmail.c'`; then echo shar: \"'src/sysmail.c'\" unpacked with wrong size! fi # end of 'src/sysmail.c' fi if test -f 'src/sysmail.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'src/sysmail.h'\" else echo shar: Extracting \"'src/sysmail.h'\" \(6146 characters\) sed "s/^X//" >'src/sysmail.h' <<'END_OF_FILE' X/* X AGREEMENT: This software can be used and distributed freely as long X as you do not remove or alter the Copyright notice in the file defs.h; X this notice is #define'd in the symbol VERSION. Although you may alter X the code provided, you may not alter the functions create_header() X and create_multi_recipient_header() in list.c and listserv.c. X By using this software you are bound by this agreement. X This software comes with no warranties and cannot be sold for profit. X The AGREEMENT and COPYRIGHT notices should be included in all source X files when distributing this software. X COPYRIGHT: Copyright (c) 1991, Anastasios C. Kotsikonas X*/ X X#define PORT 25 X#define TIMEOUT 10 X#define MAX_CALLS 1 X#define SENT PATH/sent" X#define RECEIVED PATH/received" X#define IDF PATH/.queue.id" X#define QUEUE_DIR PATH/mqueue" X X/* List of SMTP commands recognized */ X X#define ACKNOWLEDGE 220 X#define CLOSE_CONNECTION 221 X#define OK 250 X#define WILL_FORWARD 251 X#define DATA 354 X#define SERVICE_UNAVAIL 421 X#define PERMISSION_DENIED 450 X#define HOST_ABORTED 451 X#define DISK_FULL 452 X#define NOT_RECOGNIZED 500 X#define SYNTAX_ERROR 501 X#define BAD_SEQUENCE 503 X#define USER_UNKNOWN 550 X#define USER_NOT_LOCAL 551 X#define TOO_MUCH_DATA 552 X#define USER_AMBIGUOUS 553 X#define TRANS_FAILED 554 X#define END_OF_TEXT ".\n" X X#define CLOSEF \ X fclose (msg),\ X close (sock_fd) X X#define NOTIFY_MANAGER \ X if (sys.options & BSD_MAIL)\ X syscom ("%s -s \"Error during message delivery: check the report \ files\" %s &", UCB_MAIL, sys.manager);\ X X#define WARN_MANAGER \ X if (sys.options & BSD_MAIL)\ X syscom ("%s -s \"Warning during message delivery: check the report \ files\" %s &", UCB_MAIL, sys.manager);\ X X#define ABORT_CONNECTION \ X if (write (sock_fd, "QUIT\n", 5) < 5)\ X report_progress (report, "_sysmail(): WARNING: Error writing to \ socket, while closing connection", TRUE);\ X if (debug)\ X fprintf (sent, "QUIT\n"),\ X fflush (sent);\ X cmd = server_response (sock_fd, report); X X#define PROTOCOL(arg) \ X while (!feof (msg) && cmd != arg) {\ X RESET (buf);\ X fgets (buf, MAX_LINE - 2, msg);\ X if (write (sock_fd, buf, strlen (buf)) < strlen (buf))\ X report_progress (report, "_sysmail(): WARNING: Error writing to \ socket, trying again", TRUE);\ X if (debug)\ X fprintf (sent, "%s", buf),\ X fflush (sent);\ X cmd = server_response (sock_fd, report);\ X timeout = 0;\ X while (cmd != OK && cmd != arg && timeout < TIMEOUT) {\ X ++timeout;\ X if (write (sock_fd, buf, strlen (buf)) < strlen (buf))\ X report_progress (report, "_sysmail(): WARNING: Error rewriting to \ socket", TRUE);\ X if (debug)\ X fprintf (sent, "%s", buf),\ X fflush (sent);\ X cmd = server_response (sock_fd, report);\ X }\ X if (timeout == TIMEOUT) {\ X char error [1024];\ X if (cmd == SYNTAX_ERROR || cmd == TRANS_FAILED ||\ X cmd == NOT_RECOGNIZED) {\ X sprintf (error, "_sysmail(): Command: %snot recognized by sendmail.\ X\n%s\nCould not deliver mail", buf, message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X ABORT_CONNECTION;\ X CLOSEF;\ X exit (15);\ X }\ X else if (cmd == BAD_SEQUENCE) {\ X sprintf (error, "_sysmail(): Command: %sissued too soon.\ X\n%s\nCould not deliver mail", buf, message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X ABORT_CONNECTION;\ X CLOSEF;\ X exit (15);\ X }\ X else if (cmd == SERVICE_UNAVAIL || cmd == HOST_ABORTED) {\ X sprintf (error, "_sysmail(): Service unavailable.\ X\n%s\nCould not deliver mail", message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X ABORT_CONNECTION;\ X queue = TRUE;\ X goto abort;\ X }\ X else if (cmd == DISK_FULL) {\ X sprintf (error, "_sysmail(): File system full.\n%s\nCould not \ deliver mail", message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X ABORT_CONNECTION;\ X queue = TRUE;\ X goto abort;\ X }\ X else if (cmd == TOO_MUCH_DATA) {\ X sprintf (error, "_sysmail(): Too many recipients or message \ too long.\n%s\nCould not deliver mail", message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X ABORT_CONNECTION;\ X CLOSEF;\ X exit (15);\ X }\ X else if (cmd == USER_UNKNOWN) {\ X sprintf (error, "_sysmail(): Address: %snot recognized.\n%s\nMessage \ not delivered to this recipient", buf, message);\ X report_progress (report, error, TRUE);\ X WARN_MANAGER;\ X continue;\ X }\ X else if (cmd == USER_NOT_LOCAL) {\ X sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\ X report_progress (report, error, TRUE);\ X WARN_MANAGER;\ X continue;\ X }\ X else if (cmd == USER_AMBIGUOUS) {\ X sprintf (error, "_sysmail(): Address ambiguous: %s%s\nMessage not \ delivered to this address", buf, message);\ X report_progress (report, error, TRUE);\ X WARN_MANAGER;\ X continue;\ X }\ X else if (cmd == PERMISSION_DENIED) {\ X sprintf (error, "_sysmail(): Permission denied for address %s%s\n\ Message not delivered to this recipient", buf, message);\ X report_progress (report, error, TRUE);\ X WARN_MANAGER;\ X continue;\ X }\ X else if (cmd == WILL_FORWARD) {\ X sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\ X report_progress (report, error, TRUE);\ X WARN_MANAGER;\ X continue;\ X }\ X sprintf (error, "_sysmail(): ERROR: Return value %d for command: %s%s\n\ Please notify tasos@cs.bu.edu", cmd, buf, message);\ X report_progress (report, error, TRUE);\ X NOTIFY_MANAGER;\ X if (call < MAX_CALLS)\ X CLOSEF,\ X sleep (60),\ X _sysmail (file, call + 1);\ X report_progress (report, "_sysmail(): ERROR: Could not deliver mail", \ TRUE);\ X CLOSEF,\ X exit (15);\ X }\ X } X static char message [1024]; static FILE *sent, *received; static BOOLEAN queue; END_OF_FILE if test 6146 -ne `wc -c <'src/sysmail.h'`; then echo shar: \"'src/sysmail.h'\" unpacked with wrong size! fi # end of 'src/sysmail.h' fi echo shar: End of archive 2 \(of 6\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0