home *** CD-ROM | disk | FTP | other *** search
- Subject: v25i040: listserv5.31 - mailing list management system, Part06/06
- Newsgroups: comp.sources.unix
- Approved: vixie@pa.dec.com
-
- Submitted-By: tasos@cs.bu.edu
- Posting-Number: Volume 25, Issue 40
- Archive-Name: listserv5.31/part06
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 6 (of 6)."
- # Contents: src/listserv.c
- # Wrapped by vixie@cognition.pa.dec.com on Fri Dec 13 18:31:10 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/listserv.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/listserv.c'\"
- else
- echo shar: Extracting \"'src/listserv.c'\" \(52668 characters\)
- sed "s/^X//" >'src/listserv.c' <<'END_OF_FILE'
- X/*
- X ----------------------------------------------------------------------------
- X | DISCUSSION LIST SERVER |
- X | |
- X | Version 5.31 |
- 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 system's server. People send requests to the listserv
- X for subscription, removal of subscription, general information request, etc.
- X The recognized commands are as follows:
- X help [command]
- X set <list> [<option> <value>] option: mail
- X value: ack, noack, postpone
- X subscribe <list> <name>
- X unsubscribe <list> (alias signoff)
- X recipients <list> (alias review)
- X information <list>
- X statistics <list> [subscriber email address(es)]
- X shutdown <password>
- X restart <password>
- X lists
- X index [archive]
- X get <archive> <filename> [parts]
- X release
- X
- X Commands are sent to listserv one on each line of the message. The user
- X is notified of the first invalid request; all subsequent commands
- X are ignored -- imagine someone sending an entire book!! For each
- X successfully completed command, a confirmation is sent back to the sender.
- X Commands/requests may be abbreviated.
- X
- X The user may request help in general, or on a specific command; he can
- X 'set list mail ack' in which case his/her messages to the list will be
- X echoed back to him/her, and 'set list mail noack' (the opposite);
- X A 'set list mail postpone' request will not send any
- X messages to the subscriber until he resets it to one of the other options
- X (used to suppress sending email temporarily). 'set list' with no arguments
- X returns the current values for all options.
- X To subscribe to the list, a user has to give his/her full name;
- X he/she may leave the list by issuing an 'unsubscribe' request;
- X a list of the current subscribers is obtained through a 'recipients' request;
- X a copy of the sender's message is also sent to peer lists in this case.
- X Moreover, general information is available by means of an 'information'
- X request, and finally 'statistics' compiles a count of messages sent by
- X each subscriber (unless specific subscriber address are given) as well as
- X a total count of messages on file; again, a copy of the message will be
- X forwarded to all peer lists.
- X
- X The entire system may be remotely shut down by way of a 'shutdown' request;
- X this request must be followed by a password that must match the one defined
- X in config. Note that this may result in requests being queued with the
- X 'shutdown' one not being serviced; note thought that a copy of the original
- X requests can be found in MAIL_COPY as defined in listserv.h.
- X Likewise, the system may be remotely restarted by issuing a 'restart'
- X request with the proper password. Note that a 'restart' request has no
- X effect after a 'shutdown' (because the server is not running), and that
- X any requests queued with the 'restart' will be serviced (the system will
- X not restart until all requests are serviced).
- X
- X A list of all discussion lists served by this server can be obtained by
- X a 'lists' request.
- X
- X Information on the current release of this server can be obtained by
- X a 'release' request.
- X
- X The system includes a means for users to obtain files. The files
- X can be placed anywhere in the system and are archived under
- X /usr/server/archives/*
- X Each of these archives has an index of subarchives and a directory
- X of files that can be obtained from that archive; there is a master
- X archive in archives/listserv: the file INDEX contains names and full paths
- X to all of the archives (including listserv); the file DIR is a directory
- X of files that are archived under listserv. A user
- X may obtain a list of all the archives and their files by sending an
- X 'index' request. That request followed by a specific archive will
- X send a list of files for that archive and all of its subsrchives.
- X The format of the INDEX file is as follows: one line per archive
- X with the following:
- X
- X archive-name full-path-to-its-directory
- X
- X A file can be obtained via a 'get' request, specifying the archive and
- X the file to get. It is possible that a file has been split in various
- X parts, in which case multiple emails with the various subparts will
- X be sent to the user. Note that only the master index is used in this
- X case for locating the archive. Individual parts of the split file may
- X be obtained by specifying them as arguments.
- X
- X A file may be archived with the farch utility, or manually by
- X editing the DIR file of the target archive. The format is as follows:
- X one line per file containing the following information:
- X
- X filename number-of-subparts directory-to-find-it
- X
- X The restriction is that the actual disk file should be all in lower case.
- X
- X A new archive may be created by creating a subdirectory under
- X /usr/server/archives (the new directory may not be all in lower-case letters),
- X updating the master INDEX (archives/listserv/INDEX) and all lower-level
- X indeces (if any), creating a new INDEX file in the new directory with one
- X entry (the new archive itself), and creating an empty DIR file in the
- X same new directory.
- X
- X The hierarchical structure is only logical and directory hierarchy does
- X not matter. All archives though have to be placed under /usr/server/archives.
- X
- X All commands may be abbreviated except 'shutdown' and 'restart'.
- X
- X COMMAND LINE OPTIONS:
- X -1: Same as for the list program.
- X -r: This option may be repeated an infinite number of times and is
- X always followed by a valid listserv command (as outlined above).
- X This forces a restriction to be placed on the specified command;
- X whenever a user makes such a request, the request will be rejected
- X if the number of users currently on the system is greater than
- X the threshold specified in listserv.h. This option was added due
- X to the fact that the 'statistics' request may take up a lot of
- X resources to complete.
- X -e: Echo reports to the screen.
- X -n: Do not notify peer servers.
- X -d: Disable a listserv command. This makes totally unknown to the server.
- X However, help is still available for the particular request.
- X -D: Turn debug on. A transaction of the last email sent out is kept
- X in the files /usr/server/sent and /usr/server/received. This assumes
- X use of the 'system' mail method.
- 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
- X Approximate algorithm:
- X {
- X Place a lock so that no other programs will access the same files.
- X Read the SERVER_MAIL_FILE
- X if new messages have arrived then {
- X For each message do {
- X If the message is sent by MAILER-DAEMON forward it to MANAGER
- X else {
- X if the person in not in the IGNORED file, then
- X scan each line of the body of the message and treat it as a
- X command with possible arguments. Reply to the sender for each such
- X request. If a request cannot be processed, send an error message to
- X the sender and ignore all subsequent requests.
- X }
- X }
- X }
- X }
- X
- X Required files:
- X SUBSCRIBERS <-- The list of subscribed people (diff. for each list)
- X ALIASES <-- Aliases of email addresses of subscribers, news &
- X peers.
- X PEERS <-- A list of peers for a particular list (where appl.)
- X IGNORED <-- The list of undesired people (one for the server
- X and one for each list)
- X SERVER_LOCK_FILE <-- Lock file
- X
- X Input files:
- X HEADERS <-- Used for the 'statistics' request (see list.c)
- X SERVER_MAIL_FILE <-- Where new messages go
- X MAIL_COPY <-- Copy of this file (actual work file)
- X MSG_NO <-- Read last message count
- X SUBSCRIBERS
- X IGNORED
- X
- X Output files:
- X SERVER_MBOX <-- A log of all messages sent
- X SUBSCRIBERS <-- After updating
- X OLD_SUBSCRIBERS <-- Temporary
- X MSG_NO <-- Write last message count
- X REPORT_SERVER <-- Progress report
- X MAILFORWARD <-- Completed message (with header and the
- X the body of the message) to be forwarded
- X
- X Format of the SUBSCRIBERS, PEERS and IGNORED files:
- X See comments for list.c
- X
- X Recommended usage:
- X % listserv [-r statistics] &
- X or
- X % listserv [-r statistics] -1
- X
- X*/
- X
- X#include <stdio.h>
- X#include <malloc.h>
- X#include <string.h>
- X#include <unistd.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <fcntl.h>
- X#include <signal.h>
- X#include "defs.h"
- X#include "listserv.h"
- X#include "struct.h"
- X#include "global.h"
- X
- X/*
- X Function prototypes:
- X*/
- X
- X#ifdef __STDC__
- X#include <stdarg.h>
- extern int syscom (char *, ...);
- X#else
- X#include <varargs.h>
- extern int syscom ();
- X#endif
- extern int sys_config (FILE *, SYS *);
- extern void report_progress (FILE *, char *, int);
- extern void init_signals (void);
- extern void catch_signals (void);
- extern void setup_string (char *, char *, char *);
- extern char *upcase (char *);
- extern char *locase (char *);
- extern void distribute (FILE *, void (*)(char *, char *, BOOLEAN),
- X FILE *, char *, char *, char *, char *);
- extern char *cleanup_name (char *);
- extern void cleanup_request (char *s);
- extern int getopt (int, char **, char *);
- extern void get_list_name (char *, char *);
- extern int get_list_id (char *, SYS *, int);
- extern void shrink (char *);
- extern BOOLEAN sysmail (char *);
- extern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *);
- extern BOOLEAN strinstr (char *, char *, char *);
- extern BOOLEAN ignore_sender (FILE *, char *, FILE *);
- extern BOOLEAN requested_part (char *, int);
- X
- void main (int, char **, char **);
- void process_message (char *, char *);
- void action (char *, char *, char *);
- void create_header (FILE **, char *, char *, char *, char *);
- void reject_mail (char *, char *);
- void help (char *, char *, char *);
- void unsubscribe (char *, char *, char *);
- void subscribe (char *, char *, char *);
- void set (char *, char *, char *);
- void recipients (char *, char *, char *);
- void info (char *, char *, char *);
- void stats (char *, char *, char *);
- void Shutdown (char *, char *, char *);
- void restart (char *, char *, char *);
- void lists (char *, char *, char *);
- void get (char *, char *, char *);
- void Index (char *, char *, char *);
- void notify_peer_servers (char *, char *, char *, char *);
- void init_commands (void);
- void usage (void);
- void server_config (char *);
- void gexit (void);
- X
- X/*
- X The control structure of the server. Check if mail has arrived.
- X If so, copy it to MAIL_COPY and proceed to lower level.
- X First, the command line options are analyzed (for restrictions, etc.).
- X*/
- X
- void main (int argc, char **argv, char **envp)
- X{
- X struct stat stat_buf;
- X char *options = "1r:d:enD";
- X int c;
- X BOOLEAN execute_once = FALSE, notok;
- X int i, j, k;
- X FILE *f;
- X char error [MAX_LINE];
- X
- X extern char *optarg;
- X extern int optopt;
- X
- X init_commands();
- 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 'n': do_not_notify_peer_server = TRUE; break;
- X case 'D': debug = TRUE; break;
- X case 'r':
- X case 'd':
- X notok = TRUE;
- X k = 0;
- X upcase (optarg);
- X for (i = 0; i < MAX_COMMANDS; ++i) {
- X notok &= (((j = strncmp (optarg, commands[i].name, strlen (optarg)))
- X != 0) ? 1 : 0);
- X if (!j) {
- X ++k;
- X if (c == 'r')
- X restricted_commands |= commands[i].mask;
- X else if (c == 'd')
- X disabled_commands |= commands[i].mask;
- X }
- X }
- X if (notok)
- X fprintf (stderr, "listserv: Unrecognized request '%s'\n", optarg),
- X exit (3);
- X if (k > 1) /* ambiguous command */
- X fprintf (stderr, "listserv: Ambiguous request '%s'\n", optarg),
- X exit (3);
- X break;
- X case ':':
- X fprintf (stderr, "listserv: Option '%c' requires an argument.\n",
- X optopt);
- X exit (3);
- X case '?':
- X default:
- X usage ();
- X }
- X#ifndef _MINIX
- X if (lockf (open (SERVER_LOCK_FILE, O_RDWR), F_TLOCK, 0))
- X fprintf (stderr, "listserv: Unable to lock %s. Aborting.\n",
- X SERVER_LOCK_FILE),
- X exit (2);
- X#endif
- X if (!execute_once)
- X printf ("%s\n", VERSION);
- X init_signals();
- X catch_signals();
- X if ((report = fopen (REPORT_SERVER, "a")) == NULL)
- X fprintf (stderr, "listserv: Unable to open %s\n", REPORT_SERVER),
- X exit (1);
- X nlists = sys_config (report, &sys);
- X if (sys.options & USE_ENV_VAR) {
- X if ((sys.mail.method = (char *) malloc (256 * sizeof (char))) == NULL)
- X report_progress (report, "\nmain(): malloc failed", TRUE),
- X exit (16);
- X sprintf (sys.mail.method, "env - %s=%s %s ", sys.mail.env_var,
- X sys.server.address, sys.mail.mail_prog);
- X }
- X if ((msg_no = fopen (MSG_NO, "r")) != NULL)
- X fscanf (msg_no, "%d\n", &request_no),
- X fclose (msg_no);
- X
- X if ((f = fopen (PID_SERVER, "w")) != NULL)
- X fprintf (f, "%d", getpid()),
- X fclose (f);
- X signal (SIGINT, gexit);
- X
- X do {
- X if (!stat (SERVER_MAIL_FILE, &stat_buf) && stat_buf.st_size > 0) {
- X syscom ("cp %s %s", SERVER_MAIL_FILE, MAIL_COPY);
- X syscom ("cat %s >> %s", MAIL_COPY, SERVER_MBOX);
- X syscom ("echo >> %s", SERVER_MBOX);
- X if (!unlink (SERVER_MAIL_FILE))
- X syscom ("touch %s", SERVER_MAIL_FILE), /* rewrite file */
- X syscom ("chmod 666 %s", SERVER_MAIL_FILE);
- X if ((mail = fopen (MAIL_COPY, "r")) == NULL)
- X sprintf (error, "listserv: Could not open %s", MAIL_COPY),
- X report_progress (report, error, TRUE),
- X exit (1);
- X report_progress (report, NEW_ARRIVAL, FALSE);
- X distribute (mail, (void *) process_message, report, NULL, NULL, NULL,
- X NULL);
- X fclose (mail); /* Done */
- X shrink (message_idsf);
- X unlink (MAIL_COPY); /* Done delivering */
- X }
- X else if (!execute_once) /* No mail to deliver */
- X if (sys.frequency > 0)
- X sleep (sys.frequency);
- X } while (!execute_once);
- X fclose (report);
- X free ((char *) sys.mail.method);
- X unlink (PID_SERVER);
- X if (restart_sys)
- X exit (7); /* Exit status of 7 signifies a restart request */
- X exit (0);
- X}
- X
- X/*
- X Process each message. Isolate each command and pass it to action().
- X Before that, check if the message is from MAILER_DAEMON, in which case
- X forward the message to MANAGER. Any messages from people listed in the
- X IGNORED file are not processed.
- X Note: Please look at the documentation for list.c for the definition of a
- X mailer daemon.
- X*/
- X
- void process_message (char *sender, char *linecopy)
- X{
- X char line [MAX_LINE]; /* ... from the the current message */
- X char request [MAX_LINE]; /* holds each command */
- X char report_msg [MAX_LINE]; /* message to be written to REPORT */
- X char sender_copy [MAX_LINE];
- X char id_copy [MAX_LINE];
- X FILE *f;
- X BOOLEAN loop = FALSE;
- X
- X peer_server_request = FALSE;
- X report_msg[0] = line[0] = message_id[0] = id_copy[0] = RESET (sender_copy);
- X strcpy (sender_copy, sender); /* we do not like converting the actual */
- X upcase (sender_copy); /* address to upper case */
- X sprintf (report_msg, "Request #%04d:%s\n", ++request_no, sender);
- X report_progress (report, report_msg, FALSE);
- X if ((msg_no = fopen (MSG_NO, "w")) == NULL)
- X sprintf (report_msg, "\nprocess_message(): Could not open %s", MSG_NO),
- X report_progress (report, report_msg, TRUE),
- X exit (1);
- X fprintf (msg_no, "%d\n", request_no);
- X fclose (msg_no);
- X
- X while (!feof (mail) && line[0] != '\n') { /* Skip to beginning of message */
- X if (!strncmp (line, SUBJECT, strlen (SUBJECT))) {
- X sprintf (line, "%s", line + strlen (SUBJECT));
- X if (!strncmp (line, PEER_SERVER_REQUEST, strlen (PEER_SERVER_REQUEST)))
- X peer_server_request = TRUE;
- X }
- X if (!strncmp (line, MESSAGE_ID1, strlen (MESSAGE_ID1)) ||
- X !strncmp (line, MESSAGE_ID2, strlen (MESSAGE_ID2)) ||
- X !strncmp (line, MESSAGE_ID3, strlen (MESSAGE_ID3)))
- X strcpy (message_id, line + strlen ("Message-") + 4),
- X message_id [strlen (message_id) - 1] = EOS, /* \n -> \0 */
- X strcpy (id_copy, message_id);
- X upcase (id_copy);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X
- X if (message_id[0] != EOS) { /* Check for mail loop using Message-Id: */
- X sprintf (message_idsf, "%s/%s", PATH", MESSAGE_IDS_F);
- X if (message_ids = fopen (message_idsf, "r")) {
- X if (ignore_sender (message_ids, id_copy, report))
- X loop = TRUE;
- X fclose (message_ids);
- X }
- X if (!loop) {
- X if ((message_ids = fopen (message_idsf, "a")) == NULL)
- X sprintf (report_msg, "\nprocess_message(): Could not open %s",
- X message_idsf),
- X report_progress (report, report_msg, TRUE),
- X exit (1);
- X fprintf (message_ids, "%s %s\n", message_id, sender); /* Save new id */
- X fclose (message_ids);
- X }
- X }
- X
- X if (strinstr (MAILER_DAEMON, sender_copy, "|")) {
- X /* Send message to MANAGER */
- X create_header (&f, MAILFORWARD, sys.server.address, sys.manager, sender);
- X fprintf (f, "\nReturned mail by %s\n--------------------------------------\
- X-----------------------------------------\n",
- X sender);
- X while (!feof (mail) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X fprintf (f, "%s", line);
- X }
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sys.manager);
- X RESET (report_msg);
- X sprintf (report_msg, "Forwarding message to %s\n", sys.manager);
- X report_progress (report, report_msg, FALSE);
- X }
- X else /* Isolate request and call action() */
- X while (!feof (mail) &&
- X (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
- X cleanup_request (line);
- X RESET (request);
- X sscanf (line, "%s ", request);
- X upcase (request);
- X if (!strcmp (request, START_OF_SIGNATURE))
- X one_rejection = TRUE; /* End of requests, start of .signature */
- X else if (request[0] != EOS && !one_rejection && !loop)
- X action (line, request, sender);
- X RESET (line);
- X fgets (line, MAX_LINE - 2, mail);
- X }
- X strcpy (linecopy, line);
- X one_rejection = FALSE;
- X report_progress (report, "", -TRUE); /* -TRUE for no leading newline */
- X}
- X
- X/*
- X Recognize the 'request' and call the appropriate routine, or reject the
- X message if the request is not recognized. Isolate any parameters.
- X If a restriction is in force for the recognized request, then get
- X the number of users currently on the system and reject the request if
- X this number is greater that the predetermined threshold.
- X*/
- X
- void action (char *line, char *request, char *sender)
- X{
- X char params [MAX_LINE];
- X char error [MAX_LINE];
- X char list_name [MAX_LINE];
- X int i, nusers;
- X FILE *f;
- X
- X report_progress (report, line, FALSE);
- X RESET (error);
- X sprintf (server_ignoredf, "%s/%s", PATH", IGNORED);
- X if ((ignored = fopen (server_ignoredf, "r")) == NULL)
- X sprintf (error, "action(): Could not open %s", server_ignoredf),
- X report_progress (report, error, TRUE),
- X exit (1);
- X if (ignore_sender (ignored, sender, report))
- X goto abort;
- X fclose (ignored);
- X upcase (sender);
- X RESET (params);
- X sprintf (params, "%s", line + strlen (request)); /* Get parameters */
- X upcase (params);
- X for (i = 0; i < MAX_COMMANDS; i++) /* Walk through the valid requests */
- X if (! strncmp (request, commands[i].name, strlen (request)) &&
- X ! (disabled_commands & commands[i].mask)) {
- X if (strncmp (request, "SHUTDOWN", strlen (request)) &&
- X strncmp (request, "RESTART", strlen (request)) &&
- X strncmp (request, "LISTS", strlen (request)) &&
- X strncmp (request, "INDEX", strlen (request)) &&
- X strncmp (request, "GET", strlen (request)) &&
- X strncmp (request, "RELEASE", strlen (request)) &&
- X strncmp (request, "HELP", strlen (request))) {
- X get_list_name (params, list_name);
- X listid = get_list_id (list_name, &sys, nlists);
- X server_config (list_name);
- X if (listid < 0) {
- X if (list_name[0] == EOS)
- X sprintf (error, "%s: Missing list name\n", request);
- X else
- X sprintf (error, "%s: Unknown list name %s\n", request, list_name);
- X reject_mail (sender, error);
- X return;
- X }
- X if ((ignored = fopen (ignoredf, "r")) == NULL)
- X sprintf (error, "action(): Could not open %s", ignoredf),
- X report_progress (report, error, TRUE),
- X exit (1);
- X if (ignore_sender (ignored, sender, report))
- X goto abort;
- X if (commands[i].mask & sys.lists[listid].disabled_commands) {
- X sprintf (error, "%s requests for list %s are disabled\n",
- X request, sys.lists[listid].alias);
- X reject_mail (sender, error);
- X goto abort;
- X }
- X }
- X if (restricted_commands & commands[i].mask) { /* Restriction set */
- X syscom ("%s | %s -F, '{ print $3 }' > %s", UPTIME, AWK, USERS_FILE);
- X if ((f = fopen (USERS_FILE, "r")) == NULL)
- X sprintf (error, "action(): Could not open %s", USERS_FILE),
- X report_progress (report, error, TRUE),
- X exit (1);
- X fscanf (f, "%d", &nusers);
- X fclose (f);
- X unlink (USERS_FILE);
- X if (nusers > sys.users) {
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "This request takes a considerable amount of resources \
- and certain restrictions\nare currently in force. Please resubmit your \
- request at a later time.\n");
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X strcat (request, ": restriction enforced\n");
- X report_progress (report, request, FALSE);
- X goto abort;
- X }
- X }
- X commands[i].func (request, params, sender); /* Call routine */
- X goto abort;
- X }
- X sprintf (error, "Unrecognized request %s\n", request);
- X reject_mail (sender, error);
- X abort:
- X fclose (ignored);
- X}
- X
- X/*
- X Create a message header addressed to 'sender' with the given 'subject'.
- X Note: some mailers require the following format when using telnet:
- X*/
- X
- void create_header (FILE **f, char *filename, char *sender, char *recipient,
- X char *subject)
- X{
- X char error [MAX_LINE];
- X
- X if ((*f = fopen (filename, "w")) == NULL)
- X RESET (error),
- X sprintf (error, "\ncreate_header(): Could not open %s", filename),
- X report_progress (report, error, TRUE),
- X exit (1);
- X locase (recipient);
- X if (sys.options & USE_TELNET)
- X fprintf (*f, "HELO\nMAIL From: <%s>\nRCPT To: <%s>\nDATA\n",
- X sender, recipient);
- X if (message_id[0] != EOS)
- X fprintf (*f, "Message-Id: %s\n", message_id);
- X fprintf (*f, "Comment: %s\nErrors-To: %s\nReply-To: <%s>\n\
- Sender: %s\nVersion: %s\nFrom: %s\nTo: %s\nSubject: %s\n\n",
- X sys.server.comment, sys.manager, sender, sender, VERSION, sender,
- X recipient, subject);
- X}
- X
- X/*
- X Send a message to 'sender' indicating an invalid request. The body of
- X the message is given in 'text'. Only one such mail is sent to the user
- X for each of his/her invalid requests. All subsequent requests are ignored.
- X*/
- X
- void reject_mail (char *sender, char *text)
- X{
- X FILE *f;
- X
- X if (one_rejection)
- X return;
- X report_progress (report, text, FALSE);
- X one_rejection = TRUE;
- X create_header (&f, MAILFORWARD, sys.server.address, sender,
- X "Invalid request");
- X fprintf (f, "%s\nReport any problems to '%s'.\nFor a list of the available \
- requests send a message to %s\nwith the word 'help' in the body of the \
- message.\n\nPS: Any subsequent requests that you might have submitted have \
- been ignored.\n", text, sys.manager, sys.server.address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Provide help on the various commands to 'sender'.
- X*/
- X
- void help (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char error [MAX_LINE];
- X char param [MAX_LINE];
- X char moreparams [MAX_LINE];
- X BOOLEAN notok = TRUE;
- X int i;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X error[0] = param[0] = RESET (moreparams);
- X sscanf (params, "%s %s\n", param, moreparams);
- X if (param[0] != EOS) { /* Check option validity */
- X for (i = 0; i < MAX_COMMANDS; ++i)
- X notok &= ((strncmp (param, commands[i].name, strlen (param)) != 0) ?
- X 1 : 0);
- X if (notok) {
- X sprintf (error, "Invalid HELP topic%s", params);
- X reject_mail (sender, error);
- X return;
- X }
- X }
- X if (moreparams[0] != EOS) { /* More than one option given */
- X sprintf (error, "Too many HELP topics: %s\n", moreparams);
- X reject_mail (sender, error);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fclose (f);
- X if (param[0] == EOS)
- X syscom ("cat %s >> %s", HELP_GENERAL, MAILFORWARD);
- X else {
- X if (!strncmp (param, "SET", strlen (param)))
- X syscom ("cat %s >> %s", HELP_SET, MAILFORWARD);
- X if (!strncmp (param, "SUBSCRIBE", strlen (param)))
- X syscom ("cat %s >> %s", HELP_SUBSCRIBE, MAILFORWARD);
- X if (!strncmp (param, "UNSUBSCRIBE", strlen (param)) ||
- X !strncmp (param, "SIGNOFF", strlen(param)))
- X syscom ("cat %s >> %s", HELP_UNSUBSCRIBE, MAILFORWARD);
- X if (!strncmp (param, "RECIPIENTS", strlen (param)) ||
- X !strncmp (param, "REVIEW", strlen(param)))
- X syscom ("cat %s >> %s", HELP_RECIPIENTS, MAILFORWARD);
- X if (!strncmp (param, "INFORMATION", strlen (param)))
- X syscom ("cat %s >> %s", HELP_INFORMATION, MAILFORWARD);
- X if (!strncmp (param, "STATISTICS", strlen (param)))
- X syscom ("cat %s >> %s", HELP_STATISTICS, MAILFORWARD);
- X if (!strncmp (param, "LISTS", strlen (param)))
- X syscom ("cat %s >> %s", HELP_LISTS, MAILFORWARD);
- X if (!strncmp (param, "INDEX", strlen (param)))
- X syscom ("cat %s >> %s", HELP_INDEX, MAILFORWARD);
- X if (!strncmp (param, "GET", strlen (param)))
- X syscom ("cat %s >> %s", HELP_GET, MAILFORWARD);
- X if (!strncmp (param, "RELEASE", strlen (param)))
- X syscom ("cat %s >> %s", HELP_RELEASE, MAILFORWARD);
- X }
- X APPEND_TELNET ("help");
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Unsubscribe a member if he/she is listed in SUBSCRIBERS.
- X*/
- X
- void unsubscribe (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char error [MAX_LINE];
- X char param [MAX_LINE];
- X BOOLEAN status;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS) { /* No parameters accepted */
- X sprintf (error, "Invalid UNSUBSCRIBE option%s", params);
- X reject_mail (sender, error);
- X return;
- X }
- X if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf))) {
- X sprintf (error, "%s: %sYou are not subscribed to %s\n", sender, request,
- X sys.lists[listid].address);
- X reject_mail (sender, error);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to unsubscribe new or peer");
- X return;
- X }
- X /* Now move the current list of subscribers to a temporary file; then
- X copy each entry of this file to SUBSCRIBERS excluding the
- X user to be removed. */
- X syscom ("mv %s %s", subscribersf, OLD_SUBSCRIBERS);
- X syscom ("grep -i -v '%s' %s > %s", sender, OLD_SUBSCRIBERS, subscribersf);
- X unlink (OLD_SUBSCRIBERS);
- X syscom ("mv %s %s", aliasesf, OLD_SUBSCRIBERS);
- X syscom ("grep -i -v %s %s > %s", sender, OLD_SUBSCRIBERS, aliasesf);
- X unlink (OLD_SUBSCRIBERS);
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "You have been removed from list %s\nThanks for being with us.\n",
- X sys.lists[listid].address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Subscribe a new user if he/she is not already subscribed.
- X*/
- X
- void subscribe (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char error [MAX_LINE];
- X char name [MAX_LINE];
- X int i;
- X BOOLEAN status;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = RESET (name);
- X cleanup_name (params); /* Remove extraneous characters */
- X sscanf (params, "%s\n", name);
- X if (name[0] == EOS) { /* No user's name */
- X sprintf (error, "No name given to SUBSCRIBE\n");
- X reject_mail (sender, error);
- X return;
- X }
- X if ((status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf)) == SUBSCRIBED) {
- X sprintf (error, "%s: You are already subscribed to %s\n", sender,
- X sys.lists[listid].address);
- X reject_mail (sender, error);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to subscribe news or peer");
- X return;
- X }
- X if ((f = fopen (subscribersf, "a")) == NULL)
- X sprintf (error, "subscribe(): Could not open %s", subscribersf),
- X report_progress (report, error, TRUE),
- X exit (1);
- X fprintf (f, "%s ", sender);
- X for (i = 0; i < MAX_SET_OPTIONS; i++) /* Copy all options */
- X fprintf (f, "%s ", default_values[i]);
- X fprintf (f, "%s\n", params);
- X fclose (f);
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "You have been added to list %s\nRequests to %s\n",
- X sys.lists[listid].address, sys.server.address);
- X fclose (f);
- X syscom ("cat %s >> %s", welcomef, MAILFORWARD);
- X APPEND_TELNET ("subscribe");
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Set options for user if he/she is subscribed.
- X Adding more SET options:
- X - In listserv.h, define the new MAX_SET_OPTIONS.
- X - In listserv.h, define the new option in options[], the valid
- X values in values[] and the default_values[].
- X - the MAIL option should be first in list; this assumption is made by list
- X and listserv.
- X*/
- X
- void set (char *request, char *params, char *sender)
- X{
- X FILE *f, *from, *to;
- X char error [MAX_LINE];
- X char option [MAX_LINE];
- X char subscriber [MAX_LINE];
- X char oldmodes [MAX_SET_OPTIONS] [MAX_LINE];
- X char newmode [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char name [MAX_LINE];
- X int i, index;
- X BOOLEAN status;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = option[0] = moreparams[0] = RESET (newmode);
- X sscanf (params, "%s %s %s\n", option, newmode, moreparams); /* Get params */
- X upcase (option);
- X upcase (newmode);
- X if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
- X aliasesf))) {
- X sprintf (error, "%s: %sYou are not subscribed to %s\n", sender, request,
- X sys.lists[listid].address);
- X reject_mail (sender, error);
- X return;
- X }
- X else if (status > SUBSCRIBED) { /* Notify manager */
- X NOTIFY_MANAGER ("Attempt to set mode for news or peer");
- X return;
- X }
- X if (option[0] != EOS) {
- X for (index = 0; index < MAX_SET_OPTIONS; index++)
- X if (! strcmp (option, options[index]))
- X break;
- X if (index == MAX_SET_OPTIONS) {
- X sprintf (error, "Invalid SET option %s\n", option);
- X reject_mail (sender, error);
- X return;
- X }
- X if (! strinstr (values[index], newmode, "|")) {
- X sprintf (error, "%s SET %s value %s\n",
- X (newmode[0] != EOS ? "Invalid" : "Missing"),
- X options[index], newmode);
- X reject_mail (sender, error);
- X return;
- X }
- X }
- X if (moreparams[0] != EOS) { /* More than one option given */
- X sprintf (error, "Too many SET parameters: %s\n", moreparams);
- X reject_mail (sender, error);
- X return;
- X }
- X if (option[0] == EOS) { /* Status inquiry */
- X syscom ("grep -i '%s' %s | %s -d' ' -f2,%d > %s", sender, subscribersf,
- X CUT, MAX_SET_OPTIONS + 1, OLD_SUBSCRIBERS);
- X if (! one_rejection) {
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "Current settings are:\n");
- X if ((from = fopen (OLD_SUBSCRIBERS, "r")) == NULL)
- X sprintf (error, "set(): Could not open %s", OLD_SUBSCRIBERS),
- X report_progress (report, error, TRUE),
- X exit (1);
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X RESET (newmode),
- X fscanf (from, "%s ", newmode),
- X fprintf (f, "%s = %s\n", options[i], newmode);
- X fflush (f);
- X fclose (from);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X unlink (OLD_SUBSCRIBERS);
- X return;
- X }
- X }
- X /* Change of mode */
- X syscom ("mv %s %s", subscribersf, OLD_SUBSCRIBERS);
- X if ((from = fopen (OLD_SUBSCRIBERS, "r")) == NULL)
- X sprintf (error, "set(): Could not open %s", OLD_SUBSCRIBERS),
- X report_progress (report, error, TRUE),
- X exit (1);
- X if ((to = fopen (subscribersf, "w")) == NULL)
- X sprintf (error, "set(): Could not open %s", subscribersf),
- X report_progress (report, error, TRUE),
- X exit (1);
- X while (!feof (from)) {
- X subscriber[0] = RESET (name);
- X extract_subscriber (from, subscriber);
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X RESET (oldmodes[i]),
- X fscanf (from, "%s ", oldmodes[i]);
- X fgets (name, MAX_LINE - 2, from);
- X upcase (subscriber);
- X if (!feof (from)) {
- X fprintf (to, "%s ", subscriber);
- X if (! strcmp (sender, subscriber))
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X fprintf (to, "%s ", (i == index) ? newmode : oldmodes[i]);
- X else
- X for (i = 0; i < MAX_SET_OPTIONS; i++)
- X fprintf (to, "%s ", oldmodes[i]);
- X fprintf (to, "%s", name);
- X }
- X }
- X fclose (from);
- X fclose (to);
- X unlink (OLD_SUBSCRIBERS);
- X if (! one_rejection) {
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "%s mode reset to %s\n", options[index], newmode);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X }
- X}
- X
- X/*
- X Provide user with the current list of subscribers. Peer servers are
- X also notified and they send their own compilations.
- X*/
- X
- void recipients (char *request, char *params, char *sender)
- X{
- X char error [MAX_LINE];
- X char param [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS) {
- X sprintf (error, "Invalid RECIPIENTS option%s", params);
- X reject_mail (sender, error);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "Here is the current list of subscribers:\n\n");
- X fclose (f);
- X syscom ("%s -d\" \" -f1,3-6 %s > %s", CUT, subscribersf, recipf);
- X syscom ("%s -f %s %s >> %s", AWK, AWK_PROG, recipf, MAILFORWARD);
- X unlink (recipf);
- X syscom ("echo Total number of subscribers: `cat %s | wc -l` >> %s",
- X subscribersf, MAILFORWARD);
- X APPEND_TELNET ("recipients");
- X DELIVER_MAIL (sender);
- X notify_peer_servers (peersf, "recipients", params, sender);
- X}
- X
- X/*
- X Provide user with general information about the list. A reminder, the
- X actual text is in the INFO_FILE.
- X*/
- X
- void info (char *request, char *params, char *sender)
- X{
- X char error [MAX_LINE];
- X char param [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X error[0] = RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS) {
- X sprintf (error, "Invalid INFORMATION option%s", params);
- X reject_mail (sender, error);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fclose (f);
- X syscom ("cat %s >> %s", infof, MAILFORWARD);
- X APPEND_TELNET ("info");
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Collect and send statistics about all subscribers, by grepping through
- X HEADERS. If a user has selected particular names (asterisks are OK) then
- X give statistics about these people only. Also include a total count
- X of messages on file. Peer servers are also notified and they send their
- X own compilations.
- X*/
- X
- void stats (char *request, char *params, char *sender)
- X{
- X FILE *f;
- X char subscriber [MAX_LINE], error [MAX_LINE];
- X char junk [MAX_LINE];
- X struct stat stat_buf;
- X
- X sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
- X params); /* Used as a subject */
- X params [strlen (params) - 1] = EOS; /* Remove \n */
- X junk[0] = RESET (error);
- X sscanf (params, "%s", junk);
- X if (junk[0] == EOS) /* No specific subscribers to report on */
- X RESET (params);
- X if (stat (headersf, &stat_buf)) {
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, no mail archive found.\n", NULL);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "Here are the number of messages per subscriber:\n\n");
- X fclose (f);
- X syscom ("%s %s %s %s %s %s", STATS_PROG, PATH", subscribersf,
- X headersf, MAILFORWARD, params);
- X APPEND_TELNET ("stats");
- X DELIVER_MAIL (sender);
- X notify_peer_servers (peersf, "statistics", params, sender);
- X}
- X
- X/*
- X Exit with a shutdown status if the correct password is provided.
- X*/
- X
- void Shutdown (char *request, char *params, char *sender)
- X{
- X char error [MAX_LINE];
- X char passwd [MAX_LINE];
- X
- X sscanf (params, "%s\n", passwd);
- X if (!strcmp (sys.server.password, passwd))
- X report_progress (report, "SHUTDOWN request accepted", TRUE),
- X exit (6); /* Exit status of 6 signifies a shutdown request */
- X RESET (error);
- X sprintf (error, "Unrecognized request %s\n", request),
- X reject_mail (sender, error);
- X}
- X
- X/*
- X Set the global variable 'restart_sys' to TRUE if the correct password
- X is given.
- X*/
- X
- void restart (char *request, char *params, char *sender)
- X{
- X char error [MAX_LINE];
- X char passwd [MAX_LINE];
- X
- X sscanf (params, "%s\n", passwd);
- X if (!strcmp (sys.server.password, passwd)) {
- X report_progress (report, "RESTART request accepted\n", FALSE);
- X restart_sys = TRUE;
- X return;
- X }
- X RESET (error);
- X sprintf (error, "Unrecognized request %s\n", request);
- X reject_mail (sender, error);
- X}
- X
- X/*
- X Provide 'sender' with a list of all discussion lists served by this server.
- X*/
- X
- void lists (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X FILE *f;
- X int i;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS) {
- X sprintf (param, "Invalid LISTS option%s", params);
- X reject_mail (sender, param);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "Here is the current active list of discussion lists served by \
- this server:\n\n");
- X for (i = 0; i < nlists; ++i)
- X fprintf (f, "%s\t%s\n", sys.lists[i].address, sys.lists[i].comment);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Get an index of files for the specified archive, or the master archive
- X if none specified.
- X
- X Adapted USER CONTRIBUTED FUNCTION.
- X*/
- X
- void Index (char *request, char *params, char *sender)
- X{
- X FILE *f, *index, *dir, *master;
- X char error [MAX_LINE];
- X char archive [MAX_LINE];
- X char arch [MAX_LINE];
- X char line [MAX_LINE];
- X char file [MAX_LINE];
- X char fullpath [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char fullname [MAX_LINE];
- X char desc [MAX_LINE];
- X char junk [MAX_LINE];
- X BOOLEAN found;
- X int count, parts;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X error[0] = archive[0] = fullpath[0] = fullname[0] = RESET (moreparams);
- X sscanf (params, "%s %s", archive, moreparams);
- X locase (archive);
- X if (moreparams[0] != EOS) {
- X sprintf (error, "Too many arguments to INDEX: %s\n", moreparams);
- X reject_mail (sender, error);
- X return;
- X }
- X if (archive[0] == EOS) /* Get archive */
- X strcpy (archive, DEFAULT_ARCHIVE);
- X sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X if ((master = fopen (fullpath, "r")) == NULL) {
- X NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no master index found.\n", archive);
- X return;
- X }
- X found = FALSE;
- X while (!feof (master)) { /* Look at the master index for fullpath */
- X fullpath[0] = arch[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", arch, fullpath);
- X locase (arch);
- X if (!strcmp (arch, archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found) {
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, archive %s not found.\n", archive);
- X return;
- X }
- X sprintf (fullname, "%s/%s", fullpath, INDEX);
- X if ((index = fopen (fullname, "r")) == NULL) { /* Open index */
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, no index found in archive %s.\n", archive);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X count = 0;
- X while (!feof (index)) { /* Echo archive; goto archive a get DIR file */
- X fullpath[0] = archive[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, index);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", archive, fullpath);
- X fprintf (f, "\n%s: %s -- Files:\n", (!count ? "Archive" : "Subarchive"),
- X archive);
- X if (chdir (fullpath))
- X fprintf (f, "%s: Sorry, archive out of date.\n", archive);
- X else { /* Open DIR and get file names */
- X if ((dir = fopen (DIR, "r")) == NULL)
- X fprintf (f, "Cannot obtain directory information.\n");
- X else
- X while (!feof (dir)) {
- X desc[0] = line[0] = junk[0] = RESET (file);
- X fscanf (dir, "%s %d %s", file, &parts, junk);
- X fgets (desc, MAX_LINE - 2, dir);
- X if (desc[strlen (desc) - 1] == '\n')
- X desc[strlen (desc) - 1] = EOS;
- X if (file[0] != EOS)
- X fprintf (f, " %s (%d part%s %s%s\n", file, parts,
- X (parts > 1 ? "s)" : ")"),
- X ((desc[0] != EOS) ? "--" : " "), desc);
- X }
- X fclose (dir);
- X }
- X }
- X ++count;
- X }
- X fclose (index);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Send the requested file from the specified archive. The file may have been
- X split in subparts, and in this case several emails will be sent -- one
- X for each part. The user may also obtain certain parts.
- X
- X Adapted USER CONTRIBUTED FUNCTION.
- X*/
- X
- void get (char *request, char *params, char *sender)
- X{
- X FILE *f, *dir, *master;
- X char error [MAX_LINE];
- X char archive [MAX_LINE];
- X char arch [MAX_LINE];
- X char fullpath [MAX_LINE];
- X char moreparams [MAX_LINE];
- X char filename [MAX_LINE];
- X char fullname [MAX_LINE];
- X char dirpath [MAX_LINE];
- X char file [MAX_LINE];
- X char line [MAX_LINE];
- X char copy [MAX_LINE];
- X struct stat stat_buf;
- X int i, count = 0;
- X BOOLEAN found;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X error[0] = archive[0] = fullpath[0] = fullname[0] = dirpath[0] =
- X filename[0] = RESET (moreparams);
- X params [strlen (params) - 1] = EOS; /* Remove \n */
- X sscanf (params, "%s %s %s", archive, filename, moreparams);
- X locase (archive);
- X locase (filename);
- X if (archive[0] == EOS || filename[0] == EOS) { /* Missing args */
- X sprintf (error, "GET: missing archive or file name\n");
- X reject_mail (sender, error);
- X return;
- X }
- X if (moreparams[0] != EOS) { /* Specified parts to get */
- X strcpy (copy, filename);
- X upcase (copy);
- X do {
- X sprintf (params, "%s", params + 1);
- X } while (strncmp (params, copy, strlen (copy)));
- X sprintf (params, "%s", params + strlen (copy));
- X sprintf (params, "%s", strchr (params, moreparams[0]));
- X }
- X sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
- X if ((master = fopen (fullpath, "r")) == NULL) {
- X NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no master index found.\n", archive);
- X return;
- X }
- X found = FALSE;
- X while (!feof (master)) { /* Look at the master index for fullpath */
- X fullpath[0] = arch[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, master);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %s\n", arch, fullpath);
- X locase (arch);
- X if (!strcmp (arch, archive)) {
- X found = TRUE;
- X break;
- X }
- X }
- X }
- X fclose (master);
- X if (!found) {
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, archive %s not found.\n", archive);
- X return;
- X }
- X sprintf (dirpath, "%s/%s", fullpath, DIR);
- X if ((dir = fopen (dirpath, "r")) == NULL) { /* Dir archive */
- X NOTIFY_OF_BAD_ARCHIVE ("Unable to dir archive %s\n", archive);
- X return;
- X }
- X while (!feof (dir)) { /* Get location and file-count of file to send */
- X file[0] = fullpath[0] = RESET (line);
- X fgets (line, MAX_LINE - 2, dir);
- X if (line[0] != EOS) {
- X sscanf (line, "%s %d %s", file, &count, fullpath);
- X locase (file);
- X if (!strcmp (filename, file))
- X break;
- X }
- X }
- X fclose (dir);
- X for (i = 1; i <= count; i++) { /* Send all parts of the file */
- X RESET (fullname);
- X if (count > 1)
- X sprintf (fullname, "%s/%s%d", fullpath, filename, i);
- X else
- X sprintf (fullname, "%s/%s", fullpath, filename);
- X if (moreparams[0] != EOS && !requested_part (params, i))
- X continue;
- X syscom ("uncompress %s > /dev/null 2>&1", fullname);
- X if (stat (fullname, &stat_buf)) {
- X NOTIFY_OF_BAD_ARCHIVE ("Sorry, file %s not found in specified archive.\n",
- X filename);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "Archive %s: file %s, part %d/%d:\n\n", archive, filename, i,
- X count);
- X fprintf (f, "------------------------------ Cut here \
- X------------------------------\n");
- X fclose (f);
- X syscom ("cat %s >> %s", fullname, MAILFORWARD);
- X syscom ("echo ------------------------------ Cut here \
- X------------------------------ >> %s", MAILFORWARD);
- X APPEND_TELNET ("get");
- X DELIVER_MAIL (sender);
- X syscom ("compress %s > /dev/null 2>&1", fullname);
- X }
- X}
- X
- X/*
- X Give specific information about this release.
- X*/
- X
- void release (char *request, char *params, char *sender)
- X{
- X char param [MAX_LINE];
- X FILE *f;
- X
- X sprintf (request + strlen (request), "%s", params); /* Used as a subject */
- X RESET (param);
- X sscanf (params, "%s", param);
- X if (param[0] != EOS) {
- X sprintf (param, "Invalid RELEASE option%s", params);
- X reject_mail (sender, param);
- X return;
- X }
- X create_header (&f, MAILFORWARD, sys.server.address, sender, request);
- X fprintf (f, "UNIX Listserv, version %s\n", VERSION);
- X fprintf (f, "Last update: %s\nManager: %s\nListserv address: %s\n",
- X UPDATE_DATE, sys.manager, sys.server.address);
- X COMPLETE_TELNET (f);
- X fclose (f);
- X DELIVER_MAIL (sender);
- X}
- X
- X/*
- X Forward a 'request' to all servers handling peer lists.
- X*/
- X
- void notify_peer_servers (char *file, char *request, char *params, char *sender)
- X{
- X FILE *f, *mail;
- X char *mail_method;
- X char email [MAX_LINE];
- X char mode [MAX_LINE];
- X char alias [MAX_LINE];
- X char listserv [MAX_LINE];
- X char servers [MAX_LINE];
- X char error [MAX_LINE];
- X char subject [MAX_LINE];
- X
- X if (peer_server_request || do_not_notify_peer_server)
- X return;
- X if ((f = fopen (file, "r")) == NULL)
- X sprintf (error, "notify_peer_servers(): Could not open %s", file),
- X report_progress (report, error, TRUE),
- X exit (1);
- X sprintf (subject, "%s%s", PEER_SERVER_REQUEST, sys.server.address);
- X RESET (servers);
- X if (sys.options & USE_ENV_VAR) {
- X if ((mail_method = (char *) malloc ((10 + strlen (sys.mail.env_var) +
- X strlen (sender) +
- X strlen (sys.mail.mail_prog))
- X * sizeof (char))) == NULL)
- X report_progress (report, "\nnotify_peer_servers(): malloc failed",
- X TRUE),
- X exit (16);
- X sprintf (mail_method, "env - %s=%s %s ", sys.mail.env_var,
- X sender, sys.mail.mail_prog);
- X }
- X else {
- X if ((mail_method = (char *) malloc ((strlen (sys.mail.method) + 1)
- X * sizeof (char))) == NULL)
- X report_progress (report, "\nnotify_peer_servers(): malloc failed",
- X TRUE),
- X exit (16);
- X strcpy (mail_method, sys.mail.method);
- X }
- X while (!feof (f)) {
- X email[0] = mode[0] = alias[0] = RESET (listserv);
- X fscanf (f, "%s %s %s %s\n", email, mode, alias, listserv);
- X if (email[0] != EOS) { /* Send mail to peer server */
- X sprintf (servers + strlen (servers), "%s\n", listserv);
- X create_header (&mail, MAILFORWARD, sender, listserv,
- X subject);
- X fprintf (mail, "%s %s %s\n", request, alias, params);
- X COMPLETE_TELNET (mail);
- X fclose (mail);
- X if (sys.options & USE_SYSMAIL)
- X sysmail (MAILFORWARD);
- X else
- X syscom ("%s %s < %s", mail_method,
- X (((sys.options & USE_TELNET) == 0) ? locase (listserv) : ""),
- X MAILFORWARD);
- X }
- X }
- X if (servers[0] != EOS) { /* Notify sender as well */
- X sprintf (subject, "Notification from %s", sys.server.address);
- X create_header (&mail, MAILFORWARD, sys.server.address, sender, subject);
- X fprintf (mail, "%s: Your request has been forwarded to the following peer \
- servers,\nwho will forward you with a copy of their own results:\n\n%s",
- upcase (request), servers);
- X COMPLETE_TELNET (mail);
- X fclose (mail);
- X if (sys.options & USE_SYSMAIL)
- X sysmail (MAILFORWARD);
- X else
- X syscom ("%s %s < %s", mail_method,
- X (((sys.options & USE_TELNET) == 0) ? locase (sender) : ""),
- X MAILFORWARD);
- X }
- X free ((char *) mail_method);
- X fclose (f);
- X}
- X
- X/*
- X Initialize the commands[].
- X*/
- X
- void init_commands ()
- X{
- X commands[0].name = "HELP";
- X commands[0].mask = 0x001;
- X commands[0].func = help;
- X commands[1].name = "SET";
- X commands[1].mask = 0x002;
- X commands[1].func = set;
- X commands[2].name = "SUBSCRIBE";
- X commands[2].mask = 0x004;
- X commands[2].func = subscribe;
- X commands[3].name = "UNSUBSCRIBE";
- X commands[3].mask = 0x008;
- X commands[3].func = unsubscribe;
- X commands[4].name = "SIGNOFF";
- X commands[4].mask = 0x008;
- X commands[4].func = unsubscribe;
- X commands[5].name = "RECIPIENTS";
- X commands[5].mask = 0x010;
- X commands[5].func = recipients;
- X commands[6].name = "REVIEW";
- X commands[6].mask = 0x010;
- X commands[6].func = recipients;
- X commands[7].name = "INFORMATION";
- X commands[7].mask = 0x020;
- X commands[7].func = info;
- X commands[8].name = "STATISTICS";
- X commands[8].mask = 0x040;
- X commands[8].func = stats;
- X commands[9].name = "SHUTDOWN";
- X commands[9].mask = 0x080;
- X commands[9].func = Shutdown;
- X commands[10].name = "RESTART";
- X commands[10].mask = 0x100;
- X commands[10].func = restart;
- X commands[11].name = "LISTS";
- X commands[11].mask = 0x200;
- X commands[11].func = lists;
- X commands[12].name = "INDEX";
- X commands[12].mask = 0x400;
- X commands[12].func = Index;
- X commands[13].name = "GET";
- X commands[13].mask = 0x800;
- X commands[13].func = get;
- X commands[14].name = "RELEASE";
- X commands[14].mask = 0x1000;
- X commands[14].func = release;
- X}
- X
- void usage ()
- X{
- X fprintf (stderr, "Usage: listserv [-1] [-e] [-n] {[-r <request>]}* \
- X{[-d <request>]}* [-D]\n\
- X-1: Execute only once.\n\
- X-e: Echo reports to the screen.\n\
- X-n: Do not notify peer servers.\n\
- X-r: Set restriction on 'request'.\n\
- X-d: Disable 'request'.\n\
- X-D: Turn debug on.\n");
- X exit (3);
- X}
- X
- void server_config (char *alias)
- X{
- X setup_string (infof, alias, INFO_FILE);
- X setup_string (recipf, alias, RECIP_FILE);
- X setup_string (welcomef, alias, WELCOME_FILE);
- 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 (headersf, alias, HEADERS);
- X setup_string (ignoredf, alias, IGNORED);
- X}
- X
- X/*
- X Graceful exit. Remove pid file.
- X*/
- X
- void gexit ()
- X{
- X unlink (PID_SERVER);
- X exit (0);
- X}
- END_OF_FILE
- if test 52668 -ne `wc -c <'src/listserv.c'`; then
- echo shar: \"'src/listserv.c'\" unpacked with wrong size!
- fi
- # end of 'src/listserv.c'
- fi
- echo shar: End of archive 6 \(of 6\).
- cp /dev/null ark6isdone
- 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
-