Common subdirectories: ./Doc and ../majordomo-1.94.2#4/Doc
diff -u ./INSTALL ../majordomo-1.94.2#4/INSTALL
--- ./INSTALL   Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/INSTALL       Sun Apr 20 18:10:30 1997
@@ -2,7 +2,7 @@
             |\/| |__|  | |  | |__/ |  \ |  | |\/| |  |
             |  | |  | _| |__| |  \ |__/ |__| |  | |__|

-                          Release 1.94.1
+                          Release 1.94.2
                              INSTALL
  --------------------------------------------------------------------------

@@ -25,17 +25,19 @@
   be a "trusted" user as far as Sendmail is concerned (i.e., the user
   name needs to appear on a "T" line in your sendmail.cf file).

-2) Choose a directory for Majordomo to install under.
+2) Choose a directory for Majordomo to install into. This must _NOT_
+   be the same directory you untarred the Majordomo files into or a
+   symbolic link to it.

3) Edit the Makefile, defining where Perl and the C compiler are, the
-   Majordomo home directory, the location of the manual pages, the user and
-   group that Majordomo will run under, and the permissions for the various
-   files and directories.
-   If running on a non-POSIX system, comment out the POSIX SECTION in the
-   Makefile.  Under POSIX, wrapper must be setuid "root", even if the
-   programs will be running as something other than "root" (i.e.,
-   "daemon"), or it won't work.  The symptom of this is that Perl starts
-   bitching about security violations and "unsafe usages".
+   Majordomo home directory (chosen in step 2), the location of the
+   manual pages, the user and group that Majordomo will run under, and
+   the permissions for the various files and directories. If running on
+   a non-POSIX system, comment out the POSIX SECTION in the Makefile.
+   Under POSIX, wrapper must be setuid "root", even if the programs will
+   be running as something other than "root" (i.e., "daemon"), or it
+   won't work. The symptom of this is that Perl starts complaining about
+   security violations and "unsafe usages".

4) Edit majordomo.cf.

@@ -74,27 +76,7 @@
   restrict the programs which may be run by it and further restricts the
   environment those programs run with.

-8) Chdir to the Majordomo home and (as a regular, unprivileged user, not
-   the Majordomo user or root) run the configuration test script:
-
-      % cd /path/to/majordomo
-      % ./wrapper config-test
-
-   This should check for the proper configuration of Majordomo. Fix
-   any errors, and run again.  When the process is complete and there are
-   no errors, config-test will offer to register your installation of
-   Majordomo by sending information on your operating system, your Perl
-   version, and the address of the Majordomo owner to the Majordomo
-   maintainers.  A copy of the message will also be sent to the Majordomo
-   owner at your site.
-
-   Note that if you have a setup which uses more than one configuration
-   file, you can have config-test check them by calling it with the name of
-   an alternate configuration file, like so:
-
-      % ./wrapper config-test alternate.cf
-
-9) Add the majordomo-related aliases to your Sendmail alias file.
+8) Add the majordomo-related aliases to your Sendmail alias file.
   This can either be /etc/aliases, or if you are using a more recent
   version of Sendmail (8.6 or above) a cleaner approach is to add an
   alias file specifically for Majordomo aliases by adding another
@@ -115,7 +97,27 @@
    majordomo-owner: you

   Note the program name (majordomo) after wrapper must not be a full path
-   name.  Also look at 'sample.aliases' for additional examples.
+   name.  Also look at 'majordomo.aliases' for additional examples.
+
+9) Chdir to the Majordomo home and (as a regular, unprivileged user, not
+   the Majordomo user or root) run the configuration test script:
+
+      % cd /path/to/majordomo
+      % ./wrapper config-test
+
+   This should check for the proper configuration of Majordomo. Fix
+   any errors, and run again.  When the process is complete and there are
+   no errors, config-test will offer to register your installation of
+   Majordomo by sending information on your operating system, your Perl
+   version, and the address of the Majordomo owner to the Majordomo
+   maintainers.  A copy of the message will also be sent to the Majordomo
+   owner at your site.
+
+   Note that if you have a setup which uses more than one configuration
+   file, you can have config-test check them by calling it with the name of
+   an alternate configuration file, like so:
+
+      % ./wrapper config-test alternate.cf

10) Test the configuration again by creating an empty file 'test' in
   $listdir, and issue a 'lists' command to Majordomo:
diff -u ./Makefile ../majordomo-1.94.2#4/Makefile
--- ./Makefile  Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/Makefile      Wed Mar 12 17:50:46 1997
@@ -1,9 +1,9 @@
-#$Modified: Wed Dec  4 21:13:38 1996 by cwilson $
+#$Modified: Wed Mar 12 17:30:11 1997 by cwilson $
#
# $Source: /sources/cvsrepos/majordomo/Makefile,v $
-# $Revision: 1.56 $
-# $Date: 1996/12/09 15:41:18 $
-# $Header: /sources/cvsrepos/majordomo/Makefile,v 1.56 1996/12/09 15:41:18 cwilson Exp $
+# $Revision: 1.60 $
+# $Date: 1997/03/12 16:50:46 $
+# $Header: /sources/cvsrepos/majordomo/Makefile,v 1.60 1997/03/12 16:50:46 cwilson Exp $
#

#  This is the Makefile for Majordomo.
@@ -69,7 +69,7 @@

#--------YOU SHOULDN'T HAVE TO CHANGE ANYTHING BELOW THIS LINE.-------------

-VERSION =      1.94.1
+VERSION =      1.94.2

# For those stupid machines that try to use csh. Doh!
SHELL = /bin/sh
@@ -93,7 +93,7 @@
               majordomo_version.pl request-answer resend \
               shlock.pl config-test archive2.pl digest

-INSTALL_FLAGS = -o $(W_USER) -g $(W_GROUP)
+INSTALL_FLAGS = -O $(W_USER) -g $(W_GROUP)

default:
       @echo "make what?"
@@ -130,7 +130,7 @@
#
config-scripts:
       @echo "Testing for perl ($(PERL))..."
-       @test -x $(PERL) || \
+       @test -f $(PERL) -a -x $(PERL) || \
               { echo "You didn't correctly tell me where Perl is."; exit 1; }
       @rm -rf $(TMP); mkdir $(TMP)
       @echo "Configuring scripts..."
@@ -207,9 +207,18 @@
       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
               Doc/man/digest.1 $(MAN)/man1/digest.1
       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
+               Doc/man/bounce.1 $(MAN)/man1/bounce.1
+       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
               Doc/man/bounce-remind.1 $(MAN)/man1/bounce-remind.1
       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
+               Doc/man/resend.1 $(MAN)/man1/resend.1
+       @echo ".so man1/bounce-remind.1" > $(TMPDIR)/BoUnCe.$(VERSION)
+       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
+               $(TMPDIR)/BoUnCe.$(VERSION) $(MAN)/man1/bounce.1
+       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
               Doc/man/majordomo.8 $(MAN)/man8/majordomo.8
+       @$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
+               Doc/man/resend.1 $(MAN)/man1/resend.1

wrapper: wrapper.c
       $(CC)  $(WRAPPER_FLAGS) -o wrapper wrapper.c
diff -u ./NEWLIST ../majordomo-1.94.2#4/NEWLIST
--- ./NEWLIST   Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/NEWLIST       Wed Apr  2 12:32:06 1997
@@ -2,7 +2,7 @@
             |\/| |__|  | |  | |__/ |  \ |  | |\/| |  |
             |  | |  | _| |__| |  \ |__/ |__| |  | |__|

-                            Release 1.94
+                           Release 1.94.2
                              NEWLIST
  --------------------------------------------------------------------------

@@ -19,7 +19,7 @@
   the initial introductory info for the list in it.

3) Create the appropriate entries for the list in your Sendmail
-   aliases file (/etc/aliases or a seperate majordomo.aliases file.)
+   aliases file (/etc/aliases or a separate majordomo.aliases file.)

   Each list requires several aliases.  For an example list called
   'test', these aliases are required:
@@ -32,9 +32,9 @@

   These would look like this:

-       test:            :include:/usr/test/majordomo-1.94/lists/test
+       test:            :include:/usr/test/majordomo-1.94.2/lists/test
       owner-test:      you,
-       test-request:    "|/usr/test/majordomo-1.94/wrapper request-answer test"
+       test-request:    "|/usr/test/majordomo-1.94.2/wrapper request-answer test"
       test-approval:   you

   It's more likely that the outgoing messages to the list will be
@@ -42,11 +42,11 @@
   give other useful features.  A typical set of aliases without anything
   fancy, such as archiving or digesting, would look like this:

-       test:    "|/usr/test/majordomo-1.94/wrapper resend -l test test-list"
-       test-list:  :include:/usr/test/majordomo-1.94/lists/test
+       test:    "|/usr/test/majordomo-1.94.2/wrapper resend -l test test-list"
+       test-list:  :include:/usr/test/majordomo-1.94.2/lists/test
       owner-test:   you,
       test-owner:   you
-       test-request: "|/usr/test/majordomo-1.94/wrapper majordomo -l test"
+       test-request: "|/usr/test/majordomo-1.94.2/wrapper majordomo -l test"

   Finally, a more complete set of aliases that provides digestification,
   archiving, and header manipulation would look like:
@@ -99,9 +99,7 @@
   Hopefully in a future release of majordomo archive2.pl will be
   integrated into majordomo so that the frequency of archive rollover
   (daily, monthly, yearly) will be controllable via the config file
-   mechanism. If you wish to use archive2 in the current release, you
-   MUST move it from the Tools subdirectory into the top level majordomo
-   directory.
+   mechanism.

       ***** NOTE: CONVERTING FROM A PREVIOUS MAJORDOMO VERSION *****
       For those who are converting from an earlier version of
@@ -111,23 +109,24 @@
       values for resend will be incorrect.


-   More examples of alias setups can be found in the file sample.aliases.
+   More examples of alias setups can be found in the file majordomo.aliases.
   For sendmail users, don't forget to run 'newaliases' to rebuild the
   alias database.


-4) Optional, create an archive directory for the list, in the location
-   specified by the $filedir and $filedir_suffix variables.
+4) If the list will be archived, create an archive directory in the
+   location specified by the $filedir and $filedir_suffix variables.

-5) Optional, create a digest work (incoming) directory for the list,
-   in the $digest_work_dir/<list-name>. you must create an archive
-   directory for the digest list as well as a work directory.
+5) If the list has a digest, create a digest work (incoming) subdirectory
+   under $digest_work_dir.  Use the same name as the digest list (example:
+   test-digest).  You also must create an archive directory for the digest
+   list as explained in step 4.

6) Finally, make sure everything is owned by user majordomo, group
   majordomo, and writable by both owner and group (i.e., mode 664 for
   files and mode 775 for directories).

-7) Now issue a 'config <listname> <listname.admin> command to
+7) Now issue a 'config <listname> <listname>.admin' command to
   Majordomo. This will cause it to create a default configuration
   file for the list, and send it back to you.  Make any desired
   changes, SUCH AS CHANGING THE DEFAULT PASSWORDS, as well as adding
diff -u ./README ../majordomo-1.94.2#4/README
--- ./README    Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/README        Sun Apr 20 18:10:39 1997
@@ -8,7 +8,7 @@
        Medieval Latin "major domus" - "chief of the house".
                     (Barnhart Concise Dictionary of Etymology)

-                           Release 1.94.1
+                           Release 1.94.2
                               README
--------------------------------------------------------------------------

@@ -24,9 +24,9 @@
-> upgrading will point out the variables you need to add.       <-


-     Release 1.94.1 of Majordomo is primarily a bugfix release,
+     Release 1.94.2 of Majordomo is primarily a bugfix release,
     incorporating changes which fix problems or correct pressing
-     deficiencies in version 1.94.  No substantial new
+     deficiencies in version 1.94.1.  No substantial new
     functionality has been added, but certain necessary
     modifications have been made.

@@ -46,7 +46,7 @@

   Majordomo is a program which automates the management of Internet
   mailing lists. Commands are sent to Majordomo via electronic mail to
-   handle all aspects of list maintainance. Once a list is set up,
+   handle all aspects of list maintenance. Once a list is set up,
   virtually all operations can be performed remotely, requiring no
   intervention upon the postmaster of the list site.

@@ -118,7 +118,7 @@
Majordomo and digest were originally written by Brent Chapman, however
he doesn't have the time currently to do more development on it.  John
Rouillard did a lot of work for configuration files and managed the
-releases for the 1.62 to 1.93 timeframe.  Chan Wilson
+releases for the 1.62 to 1.93 time frame.  Chan Wilson
([email protected]) is currently "release coordinator" for 1.94 and
beyond.

@@ -192,7 +192,7 @@

While this chapter is a good introduction to setting up the majordomo
software, it is a tad out of date, since it covers version 1.62. :-( Jerry
-is in the process of updating this for 1.94.1, and an updated version will
+is in the process of updating this for 1.94.2, and an updated version will
hopefully be included in future releases.

The original LISA 6 (Oct 1992, Long Beach, CA) paper describing
@@ -354,15 +354,15 @@
    open/append/read a to a file that it was supposed to be able to
    access.  Usually this is caused by improper permissions.

-  chmod(, link(, operation not permited -- the corresponding chmod or
+  chmod(, link(, operation not permitted -- the corresponding chmod or
    link operation failed when it shouldn't have. Usually this is caused
    by improper permissions, most often on the wrapper.  Make certain
-    that it is unstalled setuid, and that "wrapper config-test" run as a
+    that it is installed setuid, and that "wrapper config-test" run as a
    normal user (not root or the majordomo user) reports no problems.

  Can't invoke -- the program majordomo wanted to invoke to send mail
    couldn't be invoked.  This error is usually only seen when you are
-    tracing the smtp connection using /usr/ucb/Mail -v.
+    tracing the SMTP connection using /usr/ucb/Mail -v.

  Can't connect to sendmail -- for some reason the attempt to run
    sendmail in the function resend_sendmail in the resend program
@@ -372,30 +372,31 @@
    could not be run; make certain that config-test reports that the
    mailer is properly accessible.  Bugs in previous versions caused
    errors of the form "mailer -fMajordomo-Owner not executable."  These
-    bugs should be fixed; please report any occurrances of this type of
+    bugs should be fixed; please report any occurrences of this type of
    error just in case the bugs persist.

-  mailer exited unexpectedly with error XXXX -- it is expected that the
-    mailer will return a zero exit code upon success, so any nonzero code
-    is reported as an error.  The mail may or may not have been propperly
-    sent to your list.  To track down the source of this error, first
-    inspect the debug logs (see Debugging below) to see if the mailer
-    emitted any diagnostics.  Failing that, the true exit status of the
-    program can be obtained by dividing the error number by 256.  Consult
-    your mailer's documentation for the meaning of the exit statis, or if
-    you use Sendmail, consult the chart below for some of the more common
+  mailer exited unexpectedly with error XX -- it is expected that the
+    mailer will return a zero exit code upon success, so any nonzero
+    code is reported as an error. The mail may or may not have been
+    properly sent to your list. To track down the source of this
+    error, first inspect the debug logs (see Debugging below) to see
+    if the mailer emitted any diagnostics. Failing that, consult your
+    mailer's documentation for the meaning of the exit status, or if you
+    use Sendmail, consult the chart below for some of the more common
    errors:

    64 - EX_USAGE - Sendmail uses this to indicate a command line usage
      error, but it also uses it to report a general error condition.
      Some versions of Sendmail do this somewhat unpredictably and for
-      this reason the '-oee' flag has been added to the defaut mailer
+      this reason the '-oee' flag has been added to the default mailer
      definitions.  This flag should prevent these errors for versions of
      Sendmail that support it.
+
    67 - EX_NOUSER - The alias that is used to send out list mail (which
      is passed as the last argument on resend's command line) does not
      exist.  Make certain that there are no typographical errors in your
      alias file, and that the file has been properly rebuilt.
+
    69 through 74, 77 - These are generally serious errors that are
      caused by either lack of resources or improper configuration of
      Sendmail.  You should consult the Sendmail documentation.
@@ -492,7 +493,7 @@
  that contains this list if the file name used for the -I flag to
  resend.  For example the filename "<listname>-can_post" can be
  created in the majordomo mailing lists directory. This list should
-  be unadvertized and closed. Don't bother creating any sendmail
+  be unadvertised and closed. Don't bother creating any sendmail
  aliases for it. This allows people to be added to or removed from
  the list using majordomo commands.

@@ -538,7 +539,7 @@

If you want to change the defaults, change the values assigned to each
keyword. There is some documentation in the config_parse.pl file. The
-config_parse.pl file is also a man page describing the programatic
+config_parse.pl file is also a man page describing the programmatic
interface to the config file parser and some other details about the
config file parser.

diff -u ./approve ../majordomo-1.94.2#4/approve
--- ./approve   Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/approve       Sat Apr  5 21:18:36 1997
@@ -56,15 +56,20 @@
# +1 415 962 0841                                 Mountain View, CA  94041

# $Source: /sources/cvsrepos/majordomo/approve,v $
-# $Revision: 1.13 $
-# $Date: 1996/12/03 18:11:53 $
+# $Revision: 1.15 $
+# $Date: 1997/04/05 19:18:36 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker:  $

-$MAILER = '/usr/lib/sendmail';
+$MAILER = '/usr/lib/sendmail' if -x '/usr/lib/sendmail';
+$MAILER = '/usr/sbin/sendmail' if -x '/usr/sbin/sendmail';

+die "Couldn't find a sendmail to invoke, please define!"
+    if !$MAILER;
+
+
require "getopts.pl";

&Getopts("df:") ||
@@ -150,16 +155,19 @@
           if (defined($opt_d)) {
               open(MAIL, ">&STDOUT");
               print MAIL "-" x 20, "\n";
-               print MAIL "To: $reply_to\n\n";
           } else {
               open(MAIL, "|$MAILER $reply_to") ||
                   die ("open(\"|$MAILER ...\"): $!");
           }
+
+           print MAIL "To: $reply_to\n\n";
           print MAIL "approve $passwd $_";
           close(MAIL);
           last;
       }
    }
+    print STDERR "Mailed approved command to $list list.\n"
+       unless defined $opt_d;
}

sub process_bounce {
diff -u ./config-test ../majordomo-1.94.2#4/config-test
--- ./config-test       Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/config-test   Mon Mar 10 18:22:05 1997
@@ -1,5 +1,5 @@
#!/bin/perl
-# $Id: config-test,v 1.15 1996/12/23 15:03:08 cwilson Exp $
+# $Id: config-test,v 1.17 1997/03/10 17:22:05 cwilson Exp $
# configuration test for majordomo
# provided with majordomo, modifications by darren stalder <[email protected]>
# more mods by Vince Skahan <[email protected]>
@@ -27,7 +27,7 @@
    ;
    sleep 2;
    if (-x "./wrapper") {
-       exec("./wrapper config-test");
+       exec("./wrapper config-test", @ARGV);
    } else {
       print <<"dummy"
Well, shoot, you forget to run
@@ -289,13 +289,14 @@
open(S, 'sample.cf') || &bad("Couldn't open sample.cf for reading, $!");

while (<S>) {
-    next if !/^(\$\w+)/;
+    next unless /^\s*(\$\w+(('|::)\w+)*)/;
    $config{$1} = 2;
}

while (<$cf>) {
-    next if !/^(\$\w+)/;
-    $config{$1}++;
+    next unless /^\s*(\$\w+(('|::)\w+)*)/;
+    $config{$1} = 1 unless defined $config{$1}; # Keeps -w happy
+    $config{$1} |= 1;
}

close (S);
@@ -369,10 +370,10 @@
#'
    print "[yes] ";
       if ( <> !~ /n/i) {
-           open(f,">$registration_file")
+           open(RF,">$registration_file")
               || die "couldn't create $registration_file, $!";
-           print f $majordomo_version;
-           close f;
+           print RF $majordomo_version;
+           close RF;

           $sendmail_command = "/usr/lib/sendmail"
               unless defined $sendmail_command;
@@ -379,7 +380,7 @@
           $bounce_mailer = "$sendmail_command -f\$sender -t"
               unless defined $bounce_mailer;
           &set_abort_addr($whoami_owner);
-           &set_mail_from($whoami);
+           &set_mail_from($whoami); $x = $whoami; # Keeps -w happy
           &set_mail_sender($whoami_owner);
           &set_mailer($bounce_mailer);

diff -u ./config_parse.pl ../majordomo-1.94.2#4/config_parse.pl
--- ./config_parse.pl   Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/config_parse.pl       Sun Apr 20 18:06:58 1997
@@ -5,7 +5,7 @@
# writes into the global variable %main'config_opts
#

-# $Header: /sources/cvsrepos/majordomo/config_parse.pl,v 1.60 1996/12/23 15:03:24 cwilson Exp $
+# $Header: /sources/cvsrepos/majordomo/config_parse.pl,v 1.63 1997/04/20 16:06:58 cwilson Exp $
# $Modified: Tue Dec 17 19:29:14 1996 by cwilson $

# this array holds the interesting info for use by all tools
@@ -146,34 +146,46 @@
# The text is wrapped and filled on output.
%comments = (
'get_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'index_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'who_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'which_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'info_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'intro_access',
-"One of three values: open, list, closed.  Open allows anyone
-access to this command.  List allows only list members access,
-while closed completely disables the command for everyone.",
+"One of three values: open, list, closed. Open allows anyone
+access to this command and closed completely disables the
+command for everyone. List allows only list members access,
+or if restrict_post is defined, only the addresses in those
+files are allowed access.",

'advertise',
"If the requestor email address matches one of these
@@ -180,7 +192,7 @@
regexps, then the list will be listed
in the output of a lists command.
Failure to match any regexp excludes the list from
-the output. The regexps under noadvertise overide these regexps.",
+the output. The regexps under noadvertise override these regexps.",

'comments',
"Comment string that will be retained across config file rewrites.",
@@ -207,7 +219,7 @@
subscribe requests to the list.  Adding '+confirm', ie,
'open+confirm', will cause majordomo to send a reply back to the
subscriber which includes a authentication number which must be sent
-back in with another subscribe commad.",
+back in with another subscribe command.",

'unsubscribe_policy',
"One of three values: open, closed, auto.  Open allows people to
@@ -287,11 +299,15 @@
This is the value of the reply-to header for digest lists.",

'restrict_post',
-"If defined only address listed in one of the files (colon or
-space separated) can post to the mailing list. This is less useful than
-it seems it should be since there is no way to create these files if you
-do not have access to the machine running resend. This mechanism will
-be replaced in a future version of majordomo/resend.",
+"If defined, only addresses listed in these files (colon or
+space separated) can post to the mailing list. By default,
+these files are relative to the lists directory. These files
+are also checked when get_access, index_access, info_access,
+intro_access, which_access, or who_access is set to 'list'.
+This is less useful than it seems it should be since there
+is no way to create these files if you do not have access to
+the machine running resend. This mechanism will be replaced
+in a future version of majordomo/resend.",

'resend_host',
"The host name that is appended to all address
@@ -718,10 +734,17 @@
########
#
# The function that does all of the real work.
-#     Called with a list directory and a list name.
+#     Called with a list directory, a list name, and optionally a flag
+#     that indicates the config file is already locked if true (and
+#     should be left locked on return).
+#
+# List config file locking is different than other files in that a
+# distinct lock file is used instead of just lopen() locking because
+# it's easier to manage a persistent lock than to try to keep the file
+# open (and thus locked) and pass the filehandle around.
#
sub main'get_config {
-  local($listdir, $list) = @_;
+  local($listdir, $list, $locked) = @_;
  local($parse, $here_doc, $stop, $end) = ();
  $end = 0;

@@ -758,8 +781,10 @@
  &handle_flag_files($listdir, $list); # this looks for files of
                                       # the form listname.function

-  &main'set_lock("$listdir/$list.config.LOCK") ||
-    &main'abort( "Can't get lock for $listdir/$list.config");
+  unless ($locked) {
+    &main'set_lock("$listdir/$list.config.LOCK") ||
+      &main'abort( "Can't get lock for $listdir/$list.config");
+  }

  print("making default\n")
    if ($debug > 1) && (! -e "$listdir/$list.config");
@@ -768,7 +793,7 @@
                unless -e "$listdir/$list.config" ;

  print STDERR "parsing config get_config($listdir, $list)\n" if $debug > 1;
-  &main'lopen(CONFIG, "", "$listdir/$list.config")
+  open(CONFIG, "$listdir/$list.config")
                        || &main'abort( "Can't open $listdir/$list.config");

  while ($_ = <CONFIG>) {
@@ -852,9 +877,9 @@
     }
  }

-&main'lclose(CONFIG);
+close(CONFIG);

-&main'free_lock("$listdir/$list.config.LOCK");
+&main'free_lock("$listdir/$list.config.LOCK") unless $locked;

print STDERR @errors if $debug > 1;

@@ -1063,16 +1088,22 @@
           # m:yyy: ; `/bin/mail evil_hacker < /etc/passwd` ; "bar" =~ m:yyy:
           # END
           #
-           elsif (($re =~ m:^((/)|m([^\w\s])): , $dlm=($2||$3)) &&
-                  $re !~ m:^m?$dlm[^\\$dlm]*(\\.[^\\$dlm]*)*$dlm[gimosx]*$: ){
+           elsif ($re !~ m:^((/)|m([^\w\s])):) {
               push(@re_errors,
                   "|$re| not a valid pattern match expression at line $.\n");
-           }
-           elsif (eval "'' =~ $re", $@) {
-               push(@re_errors, $@);
-           }
-           else {
-               push(@return_re, $re);
+           }
+           else {
+               $dlm=($2||$3);
+               if ($re !~ m:^m?$dlm[^\\$dlm]*(\\.[^\\$dlm]*)*$dlm[gimosx]*$:) {
+                   push(@re_errors,
+                    "|$re| not a valid pattern match expression at line $.\n");
+               }
+               elsif (eval "'' =~ $re", $@) {
+                   push(@re_errors, $@);
+               }
+               else {
+                   push(@return_re, $re);
+               }
           }
       }

@@ -1087,7 +1118,7 @@
       local($list) = @_;
       local(@files) = ();

-        @files = split (/[:\t\n]+/, $list);
+        @files = split (/[:\s]+/, $list);
       foreach (@files) {
           # add listdir if no leading /
           #
Common subdirectories: ./contrib and ../majordomo-1.94.2#4/contrib
diff -u ./digest ../majordomo-1.94.2#4/digest
--- ./digest    Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/digest        Mon Mar 10 18:11:25 1997
@@ -5,12 +5,12 @@
# Heavily modified by Brent Chapman <[email protected]>

# $Source: /sources/cvsrepos/majordomo/digest,v $
-# $Revision: 1.20 $
-# $Date: 1996/12/23 15:41:51 $
+# $Revision: 1.22 $
+# $Date: 1997/03/10 17:11:25 $
# $Author: cwilson $
# $State: Exp $
#
-# $Header: /sources/cvsrepos/majordomo/digest,v 1.20 1996/12/23 15:41:51 cwilson Exp $
+# $Header: /sources/cvsrepos/majordomo/digest,v 1.22 1997/03/10 17:11:25 cwilson Exp $
#
#

@@ -24,10 +24,6 @@
$TEMP = "$TMPDIR/digest.$$" || "/usr/tmp/digest.$$";

$sendmail_command = "/usr/lib/sendmail" if ! defined $sendmail_command ;
-
-$lockfile = "$V{'INCOMING'}/.LOCK";
-exit($EX_TEMPFAIL) unless &set_lock($lockfile);
-$lock_set = 1;

if (defined($opt_r)) {
    &receive_message;
@@ -316,8 +312,8 @@
               &abort("-C used without -l");
           } else {
               # Read and execute the .cf file
-               $cf = $ENV{"MAJORDOMO_CF"} ||
-                       "/etc/majordomo.cf";
+               $cf = $opt_c || $ENV{"MAJORDOMO_CF"} ||
+                   "/etc/majordomo.cf";
               require "$cf";

               chdir($homedir);
@@ -339,7 +335,13 @@
&set_mailer($bounce_mailer);

               # get the digest config file
-               &get_config($listdir, $opt_l);
+               # Let's hope that nobody ever invokes us both with and
+               # without -C, since these locks don't interact
+               $lockfile = "$listdir/$opt_l.config.LOCK";
+               &set_lock($lockfile) ||
+                   &abort("$program_name: can't get lock '$lockfile'\n");
+               $lock_set = 1;
+               &get_config($listdir, $opt_l, "locked");

               # map config opts to internal variables and $V array
               $HEADER = $config_opts{$opt_l,"message_fronter"};
@@ -355,9 +357,11 @@
               $V{'DIGEST_LINES'} = $config_opts{$opt_l, "digest_maxlines"};
               $V{'MAX_AGE'} = $config_opts{$opt_l, "digest_maxdays"};
               $V{'ERRORS-TO'} = $config_opts{$opt_l,"sender"} . "@" .
-                                       $config_opts{$opt_l,"resend_host"};
+                                       ($config_opts{$opt_l,"resend_host"}
+                                        ||$whereami);
               $V{'FROM'} = $config_opts{$opt_l, "sender"}. "@" .
-                                       $config_opts{$opt_l,"resend_host"};
+                                       ($config_opts{$opt_l,"resend_host"}
+                                        ||$whereami);
               $V{'INCOMING'} = "$digest_work_dir/$opt_l";
               $V{'NAME'} = $config_opts{$opt_l,"digest_name"};
               $V{'REALLY-TO'} = $ARGV[0];
@@ -383,6 +387,13 @@
          }
          close(config);

+          # Let's hope that nobody ever invokes us both with and
+          # without -C, since these locks don't interact
+          $lockfile = "$V{'INCOMING'}/.LOCK";
+          &set_lock($lockfile) ||
+               &abort("$program_name: can't get lock '$lockfile'\n");
+          $lock_set = 1;
+
          open(header,$V{'HEADER'}) || &abort("$V{'HEADER'}: $!\n");
          $HEADER = join("",<header>);
          close(header);
@@ -400,10 +411,6 @@
          $NUMBER = join("",<NUM_FILE>);
          chop($NUMBER);
          close(NUM_FILE);
-
-          if (defined($V{'HOME'})) {
-              unshift(@INC, $V{'HOME'});
-          }

       } # end not using -C
}
Common subdirectories: ./include and ../majordomo-1.94.2#4/include
diff -u ./majordomo ../majordomo-1.94.2#4/majordomo
--- ./majordomo Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/majordomo     Sun Apr 20 18:11:49 1997
@@ -1,5 +1,5 @@
#!/bin/perl
-# $Modified: Tue Dec 10 19:32:17 1996 by cwilson $
+# $Modified: Sun Apr 20 18:10:00 1997 by cwilson $

# majordomo: a person who speaks, makes arrangements, or takes charge
#      for another.
@@ -8,8 +8,8 @@
#   usage rights.
#
# $Source: /sources/cvsrepos/majordomo/majordomo,v $
-# $Revision: 1.76 $
-# $Date: 1996/12/10 18:39:47 $
+# $Revision: 1.87 $
+# $Date: 1997/04/20 16:11:49 $
# $Author: cwilson $
# $State: Exp $
#
@@ -165,6 +165,7 @@
# Process the rest of the message as commands
while (<>) {
    $approved = 0;                     # all requests start as un-approved
+    $quietnonmember = 0;               # show non-member on unsubscribe
    while ( /\\\s*$/ ) {               # if the last non-whitespace
       &chop_nl($_);                    # character is  '\', chop the nl
       s/\\\s*$/ /;                     # replace \ with space char
@@ -343,12 +344,14 @@
    @lists = readdir(RD_DIR);
    closedir(RD_DIR);

+    $quietnonmember=1;
+
    foreach (sort @lists) {
       $list = $_;
-       $list =~ s,^.*/,,;              # strip off leading path
       $list =~ /[^-_0-9a-zA-Z]/ && next; # skip non-list files (*.info, etc.)

-       print REPLY "Doing 'unsubscribe $list ", join(' ', @parts), "'.\n";
+       print REPLY "Doing 'unsubscribe $list ", join(' ', @parts), "'.\n"
+           if $DEBUG;
       unshift(@parts, $list);
       &do_unsubscribe(@parts);
       shift(@parts);
@@ -363,12 +366,12 @@
    local($sm) = "unsubscribe";
    local($list) = shift;
    local($clean_list);
+
    if ($list =~ /^\*$/) {
       &do_unsubscribe_all(@_);
       return 0;
    }

-
    if ( ((!$list) || ! ($clean_list = &valid_list($listdir, $list)))
       && defined($deflist)) {
        unshift(@_,$list) ;                            # Not a list name, put it back.
@@ -397,10 +400,12 @@

       # Check to see if the subscriber really is subscribed to the list.
       if (! &is_list_member($subscriber, $listdir, $clean_list)) {
-           print REPLY <<"EOM";
+           unless ($quietnonmember) {
+               print REPLY <<"EOM";
**** unsubscribe: '$subscriber' is not a member of list '$list'.
**** contact "$list-approval\@$whereami" if you need help.
EOM
+           }
           return 0;
       }

@@ -459,12 +464,15 @@
               if (defined $deflist) {
                 print REPLY "Succeeded (from list $deflist).\n";
               }
+               elsif ($quietnonmember) {
+                 print REPLY "Succeeded (from list $clean_list).\n";
+               }
               else {
                 print REPLY "Succeeded.\n";
               }
               &log("unsubscribe $clean_list $subscriber");
               &sendmail(BYE, "$clean_list-approval\@$whereami",
-                         "UNSUBSCRIBE $clean_list");
+                         "UNSUBSCRIBE $clean_list $subscriber");
               print BYE "$subscriber has unsubscribed from $clean_list.\n";
               print BYE "No action is required on your part.\n";
               close(BYE);
@@ -542,9 +550,9 @@
                    || $cmd eq "intro"
                    || $cmd eq "who"
                    || $cmd eq "which") {
-               &log("approve PASSWORD $cmd $clean_list");
+               &log("approve PASSWORD $cmd $clean_list " . join(" ", @_));
               $sub = "do_$cmd";
-               &$sub($clean_list, $subscriber);
+               &$sub($clean_list, @_);
           } else {
               # you can only approve the above
               &squawk("approve: invalid command '$cmd'");
@@ -622,7 +630,6 @@
    closedir(RD_DIR);

    foreach (sort @lists) {
-       s,^.*/,,;                       # strip off the leading path
       /[^-_0-9a-zA-Z]/ && next;       # skip non-list files (*.info, etc.)
       $list = $_;

@@ -968,19 +975,23 @@
    (local($passwd) = shift)   || &squawk("config: needs password");
    if ($clean_list ne "") {
       # The list is valid, parse the config file
-       &get_config($listdir, $clean_list) if !&cf_ck_bool($clean_list, '', 1);
+       &set_lock("$listdir/$clean_list.config.LOCK") ||
+           &abort( "Can't get lock for $listdir/$clean_list.config");
+       &get_config($listdir, $clean_list, "locked")
+           if !&cf_ck_bool($clean_list, '', 1);

       #so check the password
       if (&valid_passwd($listdir, $clean_list, $passwd)) {
       # The password is valid, so send the new config if it exists

-           if (&lopen(LCONFIG, "", "$listdir/$clean_list.config")) {
+           if (open(LCONFIG, "$listdir/$clean_list.config")) {
           while (<LCONFIG>) {
               print REPLY $_;
           }
           print REPLY "\n#[Last updated ",
                       &chop_nl(&ctime((stat(LCONFIG))[9])), "]\n";
-           &lclose(LCONFIG);
+           close(LCONFIG) ||
+               print REPLY "Error writing config for $clean_list: $!";

           } else {
           print REPLY "#### No config available for $clean_list.\n";
@@ -989,6 +1000,7 @@
           &squawk("config: invalid password.");
           &log("FAILED config $clean_list PASSWORD");
        }
+       &free_lock("$listdir/$clean_list.config.LOCK");
    } else {
       &squawk("config: unknown list '$list'.");
    }
@@ -1011,7 +1023,10 @@
    (local($passwd) = shift)   || &squawk("newconfig: needs password");
    if ($clean_list ne "") {
       # The list is valid, parse the config file
-       &get_config($listdir, $clean_list) if !&cf_ck_bool($clean_list, '', 1);
+       &set_lock("$listdir/$clean_list.config.LOCK") ||
+           &abort( "Can't get lock for $listdir/$clean_list.config");
+       &get_config($listdir, $clean_list, "locked")
+           if !&cf_ck_bool($clean_list, '', 1);

       # so check the password
       if (&valid_passwd($listdir, $clean_list, $passwd)) {
@@ -1018,7 +1033,7 @@
           # The password is valid, so write the new config
           # off to the side to validate it.
           local($oldumask) = umask($config_umask);
-           if (&lopen(NCONFIG, ">", "$listdir/$clean_list.new.config")) {
+           if (open(NCONFIG, ">$listdir/$clean_list.new.config")) {
               while (<>) {
                   $_ = &chop_nl($_);
                   if ($_ eq "EOF") {
@@ -1026,10 +1041,11 @@
                   }
                   print NCONFIG $_, "\n";
               }
-               &lclose(NCONFIG);
+               close(NCONFIG) ||
+                   &abort("Can't write $listdir/$clean_list.config: $!");
               umask($oldumask);

-               if ( &get_config($listdir, "$clean_list.new"))  {
+               if ( &get_config($listdir, "$clean_list.new", "locked"))  {
                   print REPLY "The new config file for $clean_list was NOT accepted because:\n";
                   print REPLY @config'errors;
                   &log("FAILED (syntax) newconfig $clean_list PASSWORD");
@@ -1037,26 +1053,23 @@
                   return (1);
               }

-               &set_lock( "$listdir/$clean_list.config.LOCK") ||
-                   &abort( "Can't get lock for $listdir/$clean_list.config");
               $rename_fail = 0;
-               do { print REPLY "rename current -> old failed $!";
-                       $rename_fail = 1; }
-                       if ( !rename("$listdir/$clean_list.config",
-                                    "$listdir/$clean_list.old.config") );
-               do { print REPLY "rename new -> current failed $!";
-                       $rename_fail = 1; }
-                       if ( !$rename_fail &&
-                            !rename("$listdir/$clean_list.new.config",
-                                    "$listdir/$clean_list.config"));
-
-               &free_lock( "$listdir/$clean_list.config.LOCK");
+               if ( !rename("$listdir/$clean_list.config",
+                           "$listdir/$clean_list.old.config") ) {
+                   print REPLY "rename current -> old failed $!";
+                   $rename_fail = 1;
+               }
+               elsif ( !rename("$listdir/$clean_list.new.config",
+                            "$listdir/$clean_list.config")) {
+                   print REPLY "rename new -> current failed $!";
+                   $rename_fail = 1;
+               }

               print REPLY "New config for list $clean_list accepted.\n"
                       if !$rename_fail;

               &log("newconfig $clean_list PASSWORD");
-               &get_config($listdir, $clean_list);
+               &get_config($listdir, $clean_list, "locked");
           } else {
               &abort("Can't write $listdir/$clean_list.config: $!");
           }
@@ -1069,11 +1082,9 @@
                   last;
               }
           }
-           # if we read to actual end-of-file, we are done
-           if (eof) {
-               &done();
-           }
       }
+       &free_lock("$listdir/$clean_list.config.LOCK");
+
    } else {
       &squawk("newconfig: unknown list '$list'.");
        while (<>) {
@@ -1082,10 +1093,6 @@
                   last;
           }
       }
-        # if we read to actual end-of-file, we are done
-       if (eof) {
-           &done();
-       }
    }
}

@@ -1105,12 +1112,15 @@
    (local($passwd) = shift)   || &squawk("writeconfig: needs password");
    if ($clean_list ne "") {
       # The list is valid, parse the config file
-       &get_config($listdir, $clean_list) if !&cf_ck_bool($clean_list, '', 1);
+       &set_lock("$listdir/$clean_list.config.LOCK") ||
+           &abort( "Can't get lock for $listdir/$clean_list.config");
+       &get_config($listdir, $clean_list, "locked")
+           if !&cf_ck_bool($clean_list, '', 1);

       # so check the password
       if (&valid_passwd($listdir, $clean_list, $passwd)) {
           # The password is valid, so write current config
-               &config'writeconfig($listdir, $list);
+               &config'writeconfig($listdir, $clean_list);
               print REPLY "wrote new config for list $clean_list.\n";
               &log("writeconfig $clean_list PASSWORD");
       } else {
@@ -1117,6 +1127,7 @@
           &squawk("writeconfig: invalid password.");
           &log("FAILED writeconfig $clean_list PASSWORD");
       }
+       &free_lock("$listdir/$clean_list.config.LOCK");
    } else {
       &squawk("writeconfig: unknown list '$list'.");
    }
@@ -1192,9 +1203,9 @@

    foreach (sort @lists) {
       $list = $_;
-       $list =~ s,^.*/,,;              # strip off leading path
       $list =~ /[^-_0-9a-zA-Z]/ && next; # skip non-list files (*.info, etc.)
-       next if /^(RCS|core)/;  # my favorite two.
+       next if /^(RCS|CVS|core)$/;     # files and directories to ignore
+       next if (-d "$listdir/$list"); # skip directories

       &get_config($listdir, $list) if !&cf_ck_bool($list, '', 1);

@@ -1226,6 +1237,9 @@
               }


+           $result  = &is_list_member($reply_to, $listdir, $list)
+               if ! $result;
+
               printf REPLY "  %-23s %-.56s\n", $list,
                       $config_opts{$list, 'description'} if $result;
       } else {
@@ -1428,8 +1442,197 @@
    $listrequest = "." unless $majordomo_request;

    print REPLY <<"EOM";
-This is the "Majordomo" mailing list manager, version $majordomo_version.
+
+This help message is being sent to you from the Majordomo mailing list
+management system at $whoami.
+
+This is version $majordomo_version of Majordomo.
+
+If you're familiar with mail servers, an advanced user's summary of
+Majordomo's commands appears at the end of this message.
+
+Majordomo is an automated system which allows users to subscribe
+and unsubscribe to mailing lists, and to retrieve files from list
+archives.
+
+You can interact with the Majordomo software by sending it commands
+in the body of mail messages addressed to "$whoami".
+Please do not put your commands on the subject line; Majordomo does
+not process commands in the subject line.
+
+You may put multiple Majordomo commands in the same mail message.
+Put each command on a line by itself.
+
+If you use a "signature block" at the end of your mail, Majordomo may
+mistakenly believe each line of your message is a command; you will
+then receive spurious error messages.  To keep this from happening,
+either put a line starting with a hyphen ("-") before your signature,
+or put a line with just the word
+
+       end
+
+on it in the same place.  This will stop the Majordomo software from
+processing your signature as bad commands.
+
+Here are some of the things you can do using Majordomo:
+
+I.     FINDING OUT WHICH LISTS ARE ON THIS SYSTEM
+
+To get a list of publicly-available mailing lists on this system, put the
+following line in the body of your mail message to $whoami:
+
+       lists
+
+Each line will contain the name of a mailing list and a brief description
+of the list.
+
+To get more information about a particular list, use the "info" command,
+supplying the name of the list.  For example, if the name of the list
+about which you wish information is "demo-list", you would put the line
+
+       info demo-list
+
+in the body of the mail message.
+
+II.    SUBSCRIBING TO A LIST
+
+Once you've determined that you wish to subscribe to one or more lists on
+this system, you can send commands to Majordomo to have it add you to the
+list, so you can begin receiving mailings.
+
+To receive list mail at the address from which you're sending your mail,
+simply say "subscribe" followed by the list's name:
+
+       subscribe demo-list

+If for some reason you wish to have the mailings go to a different address
+(a friend's address, a specific other system on which you have an account,
+or an address which is more correct than the one that automatically appears
+in the "From:" header on the mail you send), you would add that address to
+the command.  For instance, if you're sending a request from your work
+account, but wish to receive "demo-list" mail at your personal account
+(for which we will use "jqpublic\@my-isp.com" as an example), you'd put
+the line
+
+       subscribe demo-list jqpublic\@my-isp.com
+
+in the mail message body.
+
+Based on configuration decisions made by the list owners, you may be added
+to the mailing list automatically.  You may also receive notification
+that an authorization key is required for subscription.  Another message
+will be sent to the address to be subscribed (which may or may not be the
+same as yours) containing the key, and directing the user to send a
+command found in that message back to $whoami.  (This can be
+a bit of extra hassle, but it helps keep you from being swamped in extra
+email by someone who forged requests from your address.)  You may also
+get a message that your subscription is being forwarded to the list owner
+for approval; some lists have waiting lists, or policies about who may
+subscribe.  If your request is forwarded for approval, the list owner
+should contact you soon after your request.
+
+Upon subscribing, you should receive an introductory message, containing
+list policies and features.  Save this message for future reference; it
+will also contain exact directions for unsubscribing.  If you lose the
+intro mail and would like another copy of the policies, send this message
+to $whoami:
+
+       intro demo-list
+
+(substituting, of course, the real name of your list for "demo-list").
+
+III.   UNSUBSCRIBING FROM MAILING LISTS
+
+Your original intro message contains the exact command which should be
+used to remove your address from the list.  However, in most cases, you
+may simply send the command "unsubscribe" followed by the list name:
+
+       unsubscribe demo-list
+
+(This command may fail if your provider has changed the way your
+address is shown in your mail.)
+
+To remove an address other than the one from which you're sending
+the request, give that address in the command:
+
+       unsubscribe demo-list jqpublic\@my-isp.com
+
+In either of these cases, you can tell $whoami to remove
+the address in question from all lists on this server by using "*"
+in place of the list name:
+
+       unsubscribe *
+       unsubscribe * jqpublic\@my-isp.com
+
+IV.    FINDING THE LISTS TO WHICH AN ADDRESS IS SUBSCRIBED
+
+To find the lists to which your address is subscribed, send this command
+in the body of a mail message to $whoami:
+
+       which
+
+You can look for other addresses, or parts of an address, by specifying
+the text for which Majordomo should search.  For instance, to find which
+users at my-isp.com are subscribed to which lists, you might send the
+command
+
+       which my-isp.com
+
+Note that many list owners completely or fully disable the "which"
+command, considering it a privacy violation.
+
+V.     FINDING OUT WHO'S SUBSCRIBED TO A LIST
+
+To get a list of the addresses on a particular list, you may use the
+"who" command, followed by the name of the list:
+
+       who demo-list
+
+Note that many list owners allow only a list's subscribers to use the
+"who" command, or disable it completely, believing it to be a privacy
+violation.
+
+VI.    RETRIEVING FILES FROM A LIST'S ARCHIVES
+
+Many list owners keep archives of files associated with a list.  These
+may include:
+- back issues of the list
+- help files, user profiles, and other documents associated with the list
+- daily, monthly, or yearly archives for the list
+
+To find out if a list has any files associated with it, use the "index"
+command:
+
+       index demo-list
+
+If you see files in which you're interested, you may retrieve them by
+using the "get" command and specifying the list name and archive filename.
+For instance, to retrieve the files called "profile.form" (presumably a
+form to fill out with your profile) and "demo-list.9611" (presumably the
+messages posted to the list in November 1996), you would put the lines
+
+       get demo-list profile.form
+       get demo-list demo-list.9611
+
+in your mail to $whoami.
+
+VII.   GETTING MORE HELP
+
+To contact a human site manager, send mail to $whoami_owner.
+To contact the owner of a specific list, send mail to that list's
+approval address, which is formed by adding "-approval" to the user-name
+portion of the list's address.  For instance, to contact the list owner
+for demo-list\@$whereami, you would send mail to demo-list-approval\@$whereami.
+
+To get another copy of this help message, send mail to $whoami
+with a line saying
+
+       help
+
+in the message body.
+
+VIII.  COMMAND SUMMARY FOR ADVANCED USERS
+
In the description below items contained in []'s are optional. When
providing the item, do not include the []'s around it.  Items in angle
brackets, such as <address>, are meta-symbols that should be replaced
@@ -1681,6 +1884,10 @@
print MSG <<"EOM";
command in the body of your email message:

+    unsubscribe $list
+
+or from another account, besides $subscriber:
+
    unsubscribe $list $subscriber

EOM
@@ -1719,7 +1926,7 @@
    close(MSG);

    # tell the list owner of the new subscriber
-    &sendmail(NOTICE, "$list-approval\@$whereami", "SUBSCRIBE $list");
+    &sendmail(NOTICE, "$list-approval\@$whereami", "SUBSCRIBE $list $subscriber");
    print NOTICE "$subscriber has been added to $list.\n";
    print NOTICE "No action is required on your part.\n";
    close(NOTICE);
diff -u ./majordomo.aliases ../majordomo-1.94.2#4/majordomo.aliases
--- ./majordomo.aliases Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/majordomo.aliases     Wed Apr  2 12:32:32 1997
@@ -14,12 +14,12 @@
# restart sendmail.
#

-majordomo:  "|/usr/test/majordomo-1.94/wrapper majordomo"
+majordomo:  "|/usr/test/majordomo-1.94.2/wrapper majordomo"
majordomo-owner: chan
owner-majordomo: chan

-test:          "|/usr/test/majordomo-1.94/wrapper resend -l test test-list"
-test-list:     :include:/usr/test/majordomo-1.94/lists/test
+test:          "|/usr/test/majordomo-1.94.2/wrapper resend -l test test-list"
+test-list:     :include:/usr/test/majordomo-1.94.2/lists/test
owner-test:    chan
test-owner:    chan
test-request:  chan
diff -u ./majordomo.pl ../majordomo-1.94.2#4/majordomo.pl
--- ./majordomo.pl      Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/majordomo.pl  Wed Apr  2 16:04:14 1997
@@ -1,12 +1,12 @@
# General subroutines for Majordomo

# $Source: /sources/cvsrepos/majordomo/majordomo.pl,v $
-# $Revision: 1.52 $
-# $Date: 1996/12/23 15:03:52 $
+# $Revision: 1.55 $
+# $Date: 1997/04/02 14:04:14 $
# $Author: cwilson $
# $State: Exp $
#
-# $Header: /sources/cvsrepos/majordomo/majordomo.pl,v 1.52 1996/12/23 15:03:52 cwilson Exp $
+# $Header: /sources/cvsrepos/majordomo/majordomo.pl,v 1.55 1997/04/02 14:04:14 cwilson Exp $
#

# The exit codes for abort.  Look in /usr/include/sysexits.h.
@@ -13,8 +13,8 @@
#
$EX_DATAERR = 65;
$EX_TEMPFAIL = 75;
+$EX_NOUSER = 67;

-
package Majordomo;

$DEBUG = $main'DEBUG;
@@ -94,7 +94,7 @@
sub main'ParseAddrs {
    local($_) = shift;
    1 while s/\([^\(\)]*\)//g;                 # strip comments
-    1 while s/"[^"]*"//g;              # strip comments"
+    1 while s/"[^"]*"\s//g;            # strip comments"
    split(/,/);                                # split into parts
    foreach (@_) {
       1 while s/.*<(.*)>.*/$1/;
@@ -301,7 +301,8 @@
    local($err);
    if ( ! -w $log_file ) {
       if ( ! -e $log_file ) {                 # log file may not exist, check dir perms.
-           local($dir) = $log_file =~ m@^(/\S+/)@;
+           local($dir);
+           ($dir) = $log_file =~ m@^(/\S+)/@;
           if ( ! -w $dir ) {
               $err .= "Unable to create log file in $dir, check permissions.\n"; #
           }
@@ -515,8 +516,8 @@
    # Deal with unbalanced brackets or parenthesis in an address.
    $temp = $_;

-    # Nuke anything within quotes.  Placate Emacs -------v
-    1 while $temp =~ s/(^|([^\\\"]|\\.)+)\"([^\\\"]|\\.|$)*\"?/$1/g;
+    # Nuke anything within quotes.
+    1 while $temp =~ s/(^|([^\\\"]|\\.)+)\"(([^\\\"]|\\.)*|$)\"?/$1/g;

    # Remove nested parentheses " <- placate emacs' highlighting
    1 while $temp =~ s/\([^\(\)]*\)//g;
@@ -707,27 +708,30 @@

sub main'is_list_member {
    local($subscriber, $listdir, $clean_list) = @_;
-    local($matches);
+    local($matches) = 0;
    local(*LIST);
    local($_);

    print STDERR "is_list_member: enter\n" if $DEBUG;

-    open(LIST, "$listdir/$clean_list")
-       || &main'abort("Can't read $listdir/$clean_list: $!"); #'"";
-
-    print STDERR "is_list_member: checking $listdir/$clean_list for $subscriber\n"
-         if $DEBUG;
-
-    while (<LIST>) {
-       if (&main'addr_match($subscriber, $_,
-          (&main'cf_ck_bool($clean_list,"mungedomain") ? 2 : undef))) {
-           $matches++;
+    $clean_list = "$listdir/$clean_list" if $listdir;
+    print STDERR "is_list_member: checking $clean_list for $subscriber\n"
+       if $DEBUG;
+    if (open(LIST, $clean_list)) {
+       while (<LIST>) {
+           if (&main'addr_match($subscriber, $_,
+              (&main'cf_ck_bool($clean_list,"mungedomain") ? 2 : undef))) {
+               $matches++;
+               last;
+           }
       }
+       close(LIST);
+    }
+    else {
+       &main'bitch("Can't read $clean_list: $!"); #'"";
    }
-    close(LIST);

-    print STDERR "is_list_member: exit\n" if $DEBUG;
+    print STDERR "is_list_member: exit $matches\n" if $DEBUG;

    return($matches);
}
@@ -783,7 +787,8 @@
        } else {
            $altlist = "$clean_list-digest";
        }
-        @lists = ($clean_list,$altlist);
+        @lists = ($clean_list);
+       push(@lists, $altlist) if -e "$listdir/$altlist";
    }

    print STDERR "access_check: checking lists " , join(', ', @lists), "\n"
@@ -791,8 +796,8 @@

    $total = 0;
    foreach $list (@lists) {
-        next unless (-e "$listdir/$list");
-        $total += &main'is_list_member($subscriber, $listdir, $list);
+       $list = "$listdir/$list" unless ($list =~ m|^/|);
+       $total += &main'is_list_member($subscriber, "", $list);
    }
    print STDERR "access_check: exit\n" if $DEBUG;
    return $total;
diff -u ./majordomo_version.pl ../majordomo-1.94.2#4/majordomo_version.pl
--- ./majordomo_version.pl      Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/majordomo_version.pl  Sun Apr 20 18:48:22 1997
@@ -1,5 +1,5 @@
-# $Header: /sources/cvsrepos/majordomo/majordomo_version.pl,v 1.18 1996/11/22 17:30:58 cwilson Exp $
+# $Header: /sources/cvsrepos/majordomo/majordomo_version.pl,v 1.23 1997/04/20 16:48:22 cwilson Exp $

-$majordomo_version = "1.94.1";
+$majordomo_version = "1.94.2_spin4";
1;

Common subdirectories: ./md-sub and ../majordomo-1.94.2#4/md-sub
diff -u ./medit ../majordomo-1.94.2#4/medit
--- ./medit     Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/medit Sun Apr 20 18:25:08 1997
@@ -6,8 +6,8 @@
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/medit,v $
-# $Revision: 1.7 $
-# $Date: 1996/12/09 16:50:17 $
+# $Revision: 1.8 $
+# $Date: 1997/04/20 16:25:08 $
# $Author: cwilson $
# $State: Exp $
#
@@ -35,7 +35,7 @@

# Here's where the fun begins...

-chdir "$listdir" || &die("cannot access $listdir");
+defined($listdir) && chdir "$listdir" || die("can't access \$listdir $listdir");


$editor = $ENV{"EDITOR"} || "vi";
Only in .: regress
diff -u ./resend ../majordomo-1.94.2#4/resend
--- ./resend    Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/resend        Wed Apr  2 16:04:48 1997
@@ -1,12 +1,12 @@
#!/bin/perl
-# $Modified: Mon Dec 23 14:59:36 1996 by cwilson $
+# $Modified: Wed Apr  2 14:16:55 1997 by cwilson $

# Copyright 1992, D. Brent Chapman.  All Rights Reserved.  For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/resend,v $
-# $Revision: 1.80 $
-# $Date: 1996/12/23 15:04:45 $
+# $Revision: 1.85 $
+# $Date: 1997/04/02 14:04:48 $
# $Author: cwilson $
# $State: Exp $
#
@@ -133,6 +133,11 @@
    open (STDERR, ">>$TMPDIR/resend.debug");
}

+# XXX some standard way of setting defaults needs to be done..
+#
+$MAX_HEADER_LINE_LENGTH = $MAX_HEADER_LINE_LENGTH || 128;
+$MAX_TOTAL_HEADER_LENGTH = $MAX_TOTAL_HEADER_LENGTH || 1024;
+
print STDERR "$0 [$$]: starting.\n" if $DEBUG;

if ( ! @ARGV) {
@@ -191,16 +196,6 @@
&set_abort_addr($sender);
&set_log($log, $opt_h, "resend", $opt_l);

-# if approve_passwd (or -a) starts with a leading /, there is a file
-# that holds the password.
-#
-if (defined($opt_a)) {
-    if ($opt_a =~ /^\//) {
-       open(PWD, $opt_a) || die("resend: open(PWD, \"$opt_a\"): $!");
-       $opt_a = &chop_nl(<PWD>);
-    }
-}
-
if (defined($opt_A) && ! defined($opt_a)) {
    die("resend: must also specify '-a passwd' if using '-A' flag");
}
@@ -460,7 +455,7 @@
    local($footer) =
       &config'substitute_values(
           $config_opts{$opt_l,"message_footer"}, $opt_l);   #'
-    $footer =~ s/\001/\n/g;
+    $footer =~ s/\001|$/\n/g;
    print OUT $footer;
}

@@ -523,7 +518,11 @@
#
close(MAILIN);
unlink(&fileglob("$TMPDIR", "^resend\.$$\.")) || &abort("Error unlinking temp files: $!");
-close(MAILOUT) || &abort("Mailer $sendmail_cmd exited unexpectedly with error $?");
+close(MAILOUT) || do {
+    $? >>= 8;
+    &abort("Mailer $sendmail_cmd exited unexpectedly with error $?")
+       unless ($sendmail_cmd =~ /sendmail/ && $? == $EX_NOUSER);
+};

# Seeya.
#
@@ -552,45 +551,18 @@
    #  [[[ Scary, I just realized that !@$#% is almost valid perl... ]]]
    local(@files) = split (/[:\s]+/, $opt_I);

-  RESTRICT:
    foreach $file (@files) {
       # add $listdir if not explicitly set.
       #
-       $file = "$listdir/$file" if ($file !~ /^\//);
-
-        open ($file, "$file")
-           || do {
-               &bitch("Majordomo couldn't open the restrict_post file\n" .
-                      "\"$file\" \n for the list \"$opt_l\".\nThis should be fixed.");
-               next RESTRICT;
-           };
-
-       # Check the from address.  To Quote:
-       #   "Note that this is not guaranteed to contribute to the readability of your program. "
-       #
-       @output = grep (
-                       &addr_match($from, $_,
-                                   (&main'cf_ck_bool($opt_l,"mungedomain")  #';
-                                    ? 2
-                                    : undef)), <$file>);
-
-       if ( $#output != -1 ) {                                 # found a match.
-           close ($file);                                      # tidy up
-           return ();
-       }
+       $file = "$listdir/$file" unless ($file =~ m|^/|);

-       seek( $file, 0, 0 );                                    # rewind
-
-       # No match, so check the reply-to address if set.
+       # Return a null message if the sender (from the From: or
+       # Reply-To: headers) is found
       #
-       if ( defined($reply_to)
-           && $reply_to ne $from) {                            # ie, don't bother if reply-to == from
-           @output = grep (&addr_match($reply_to, $_), <$file>);
-       }
-
-       close ($file);
-
-       return if ( $#output != -1 );
+       return "" if &is_list_member($from, "", $file) ||
+           (defined $reply_to  &&
+           $reply_to ne $from  &&
+           &is_list_member($reply_to, "", $file));
    }

    # We only get here if nothing matches.
@@ -646,7 +618,7 @@
       print STDERR "$0: parse_header: [$.] administrative_header check\n"
           if $DEBUG;

-       if ($#admin_headers >= $[ && !$approved &&
+       if ($#admin_headers >= $[ && !$approved && defined($opt_s) &&
           eval $is_admin_header) {
           $gonna_bounce .= "Admin request: $taboo ";
           print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
@@ -674,8 +646,10 @@
               $approved = &chop_nl($1);
               if ($approved ne $opt_a                         # check the p/w given against approve_passwd
                   && !(&main'valid_passwd($listdir, $opt_l, $approved))) { # and also against admin_passwd ')
-                   $gonna_bounce  .= "Invalid 'Approved:' header ";
-                   print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
+                   if (defined($opt_A)) { # bounce only if list is moderated
+                       $gonna_bounce  .= "Invalid 'Approved:' header ";
+                       print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
+                   }
                   undef $approved;
               } else {
                   # reset the bounce counter, so that we return cleanly.
@@ -777,7 +751,7 @@
    if ( $config_opts{$opt_l,"message_headers"} ne '' ) {
       local($headers) = &config'substitute_values (
                       $config_opts{$opt_l,"message_headers"}, $opt_l);#';
-       $headers =~ s/\001/\n/g;
+       $headers =~ s/\001|$/\n/g;
       print OUT $headers;
    }
    print STDERR "$0: parse_header:  returning with '$gonna_bounce'\n" if $DEBUG;
diff -u ./sample.cf ../majordomo-1.94.2#4/sample.cf
--- ./sample.cf Mon Apr  7 21:28:41 1997
+++ ../majordomo-1.94.2#4/sample.cf     Mon Apr  7 20:57:43 1997
@@ -84,13 +84,13 @@
#
#$max_loadavg = 10;                 # Choose the maximum allowed load
#
-#$uptime = `/usr/bin/uptime` if -x </usr/bin/uptime>;     # Get system uptime
-#$uptime = `/usr/bsd/uptime` if -x </usr/bsd/uptime>;     # or uptime is over here.
+#$uptime = `/usr/bin/uptime` if -x '/usr/bin/uptime';     # Get system uptime
+#$uptime = `/usr/bsd/uptime` if -x '/usr/bsd/uptime';     # or uptime is over here.
#
#($avg_1_minute, $avg_5_minutes, $avg_15_minutes) =
#    $uptime =~ /average:\s+(\S+),\s+(\S+),\s+(\S+)/;
#
-#exit 75 if ($avg_15_minute >= $max_loadavg);           # E_TEMPFAIL
+#exit 75 if ($avg_15_minutes >= $max_loadavg);           # E_TEMPFAIL
#

# Set the default subscribe policy for new lists here.
@@ -227,6 +227,7 @@
/^subject:\s*help\b/i
/^subject:\s.*\bchange\b.*\baddress\b/i
/^subject:\s*request\b(.*\b)?addition\b/i
+/^subject:\s*cancel\b/i
END

# Common things that people send to the wrong address.
@@ -239,6 +240,7 @@
# each new majordomo command.
#
$admin_body = <<'END';
+/\bcancel\b/i
/\badd me\b/i
/\bdelete me\b/i
/\bremove\s+me\b/i
@@ -282,6 +284,7 @@
/^subject:\s*Returned mail\b/i
/^subject:\s*unable to deliver mail\b/i
/^subject:\s.*\baway from my mail\b/i
+/^subject:\s*Autoreply/i
END

# Taboo body contents to catch and forward to the approval address
@@ -298,7 +301,7 @@

# Majordomo will not send replies to addresses which match this.
# The match is done case-insensitively.
-$majordomo_dont_reply = '(mailer-daemon|uucp|listserv|majordomo)\@';
+$majordomo_dont_reply = '(mailer-daemon|uucp|listserv|majordomo|listproc)\@';

1;
-# $Header: /sources/cvsrepos/majordomo/sample.cf,v 1.28 1996/12/23 15:05:15 cwilson Exp $
+# $Header: /sources/cvsrepos/majordomo/sample.cf,v 1.32 1997/04/07 18:57:43 cwilson Exp $
diff -u ./shlock.pl ../majordomo-1.94.2#4/shlock.pl
--- ./shlock.pl Mon Apr  7 21:28:39 1997
+++ ../majordomo-1.94.2#4/shlock.pl     Mon Mar 10 18:01:15 1997
@@ -7,16 +7,20 @@
package shlock;
require 'majordomo.pl'; # For bitch() and abort()

-sub alert { &main'bitch(@_); }
-
-$shlock_debug = 0;
+# These can be predefined elsewhere, e.g. majordomo.cf
+$waittime     = 600 unless $waittime;
+$shlock_debug = 0   unless $shlock_debug;
+$warncount    = 20  unless $warncount;
+
+sub alert {
+    &main'bitch(@_);
+    &main'abort("shlock: too many warnings") unless --$warncount;
+}

$EPERM = 1;
$ESRCH = 3;
$EEXIST = 17;

-$waittime = 600 if !$waittime; # can be set before the require.
-
# Lock a process via lockfile.
#
sub main'shlock {
@@ -27,16 +31,16 @@
    print STDERR "trying lock '$file' for pid $$\n" if $shlock_debug;
    return(undef) unless ($tmp = &extant_file($file));

-    while (1) {
+    { # redo-controlled loop
       unless (link($tmp, $file)) {
           if ($! == $EEXIST) {
               print STDERR "lock '$file' already exists\n" if $shlock_debug;
               if (&check_lock($file)) {
                   print STDERR "extant lock is valid\n" if $shlock_debug;
-                   last;
               } else {
                   print STDERR "lock is invalid; removing\n" if $shlock_debug;
                   unlink($file); # no message because it might be gone by now
+                   redo;
               }
           } else {
               &alert("shlock: link('$tmp', '$file'): $!");
@@ -45,7 +49,6 @@
           print STDERR "got lock '$file'\n" if $shlock_debug;
           $retcode = 1;
       }
-       last;
    }

    unlink($tmp) || &alert("shlock: unlink('$file'): $!");
@@ -182,10 +185,10 @@
       if (! -e $tempdir) {
           &main'abort("shlock: '$tempdir' does not exist");
       }
-       elsif (! -d $tempdir) {
+       elsif (! -d _) {
           &main'abort("shlock: '$tempdir' is not a directory\n");
       }
-       elsif (! -w $tempdir) {
+       elsif (! -w _) {
           &main'abort("shlock: '$tempdir' is not writable by UID $> GID",
               (split(" ", $) ))[0], "\n");
       }
@@ -252,7 +255,7 @@

    print STDERR "checking extant lock '$file'\n" if $shlock_debug;
    unless (open(FILE, "$file")) {
-       &alert("shlock: open('$file'): $!");
+       &alert("shlock: open('$file'): $!") if $shlock_debug;
       return 1;
    }

@@ -281,10 +284,11 @@
    }
    print STDERR "temporary filename '$tempname'\n" if $shlock_debug;

-    while (1) {
+    { # redo-controlled loop
       if ( -e $tempname ) {
           print STDERR "file '$tempname' exists\n" if $shlock_debug;
-           unlink($tempname) || &alert("shlock: unlink('$tempname'): $!");
+           unlink($tempname); # no message because it might be gone by now.
+           redo;
       }
       elsif (! &main'open_temp(FILE, $tempname)) {
           print STDERR "can't create temporary file '$tempname': $!"
@@ -291,7 +295,6 @@
               if $shlock_debug;
           return(undef);
       }
-       last;
    }

    unless (print FILE "$$\n") {
Binary files ./wrapper and ../majordomo-1.94.2#4/wrapper differ