Compare commits

..

17 Commits

Author SHA1 Message Date
tuend-work
f3dc5468bb Create options.conf 2025-11-13 15:08:52 +07:00
tuend-work
a75d061aba ud 2025-11-13 13:34:21 +07:00
tuend-work
1cd3654f62 Update directadmin-1.62.4.tar.gz 2025-11-13 11:42:41 +07:00
tuend-work
0d4f7e4f28 a 2025-11-13 11:39:36 +07:00
tuend-work
a1cb058090 Update setup.sh 2025-11-13 11:30:03 +07:00
tuend-work
585bff665c Update setup.sh 2025-11-13 11:28:34 +07:00
tuend-work
3c7e9f3116 Update setup.sh 2025-11-13 11:24:31 +07:00
tuend-work
c92e9eb7b5 ud 2025-11-13 11:19:26 +07:00
tuend-work
ff3e72d2a0 Update install.sh 2025-11-13 11:19:01 +07:00
tuend-work
330f41c4c0 a 2025-11-13 11:16:55 +07:00
tuend-work
728597f603 a 2025-11-13 11:13:25 +07:00
tuend-work
e11958f103 a 2025-11-13 11:09:41 +07:00
tuend-work
27eec3dcc6 a 2025-11-13 11:08:42 +07:00
tuend-work
3b52e718ca Update update.tar.gz 2025-11-13 10:30:09 +07:00
tuend-work
260d0c33db ud 2025-11-13 10:29:12 +07:00
tuend-work
18736081c6 a 2025-11-13 08:41:45 +07:00
tuend-work
1b646f6a89 Update install.sh 2025-11-13 08:14:31 +07:00
181 changed files with 72454 additions and 84 deletions

View File

@@ -21,7 +21,7 @@ systemctl restart NetworkManager
\# INSTALL DIRECTADMIN ONLY CENTOS7 64BIT
```
wget -O setup.sh https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/install.sh && chmod +x setup.sh && ./setup.sh
wget -O setup.sh https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/setup.sh && chmod +x setup.sh && ./setup.sh
```

22
conf/cacert.pem Normal file
View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrTCCAzOgAwIBAgISBpAc3POovD/BldvTuecdW6CiMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
ODAeFw0yNTA5MjMxNjE3MjBaFw0yNTEyMjIxNjE3MTlaMB0xGzAZBgNVBAMTEnMx
NzJkMTUud3BjbG91ZC52bjB2MBAGByqGSM49AgEGBSuBBAAiA2IABE3C3sYKiRef
w/Rmr6Cvbm3C010NjyGwLxYUhW/LPHOwvQDmeZF0CAlCwXRmkSo/fOWUTOBrZd5q
P5jdpIezVwFqpWwksw/pNlWmm3JnKme1BkTfOFQz4PV0PKYGzovlaKOCAh8wggIb
MA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUM9BoxfyDUoTiwPSZXWlgme4F+fMwHwYD
VR0jBBgwFoAUjw0TovYuftFQbDMYOF1ZjiNykcowMgYIKwYBBQUHAQEEJjAkMCIG
CCsGAQUFBzAChhZodHRwOi8vZTguaS5sZW5jci5vcmcvMB0GA1UdEQQWMBSCEnMx
NzJkMTUud3BjbG91ZC52bjATBgNVHSAEDDAKMAgGBmeBDAECATAtBgNVHR8EJjAk
MCKgIKAehhxodHRwOi8vZTguYy5sZW5jci5vcmcvMzUuY3JsMIIBAwYKKwYBBAHW
eQIEAgSB9ASB8QDvAHYApELFBklgYVSPD9TqnPt6LSZFTYepfy/fRVn2J086hFQA
AAGZd5MOYwAABAMARzBFAiAyNaj9y43AvttAAez1hse6Slav1scemDSMokurCNjG
UQIhALgfjSCbtAUKg3SKovi/v6CA2Zh67VN4Ks3YFjCow2M8AHUAzPsPaoVxCWX+
lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGZd5MOjAAABAMARjBEAiAYw1fJiS+U
KFFt4O+GZ8zEWEmjNOUnG6OFZbKnQTO/fAIgeRCJ1F88/IYhoVjv2c1MQLngfewK
IdqXPYO3aiRopH8wCgYIKoZIzj0EAwMDaAAwZQIwIO4NIB2cmUHtWHOsG6o5pVi7
0uUs0H3JoRvGfSaKg+DZXc4z5Ytb/J9lWCk8zHJ9AjEA3vm4HwTplGEGoAUNAAhz
BM5d4cxIxyuGbb8XjJZuUgIRLV873ksIslKKvNmQlSVc
-----END CERTIFICATE-----

49
conf/cacert.pem.combined Normal file
View File

@@ -0,0 +1,49 @@
-----BEGIN CERTIFICATE-----
MIIDrTCCAzOgAwIBAgISBpAc3POovD/BldvTuecdW6CiMAoGCCqGSM49BAMDMDIx
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
ODAeFw0yNTA5MjMxNjE3MjBaFw0yNTEyMjIxNjE3MTlaMB0xGzAZBgNVBAMTEnMx
NzJkMTUud3BjbG91ZC52bjB2MBAGByqGSM49AgEGBSuBBAAiA2IABE3C3sYKiRef
w/Rmr6Cvbm3C010NjyGwLxYUhW/LPHOwvQDmeZF0CAlCwXRmkSo/fOWUTOBrZd5q
P5jdpIezVwFqpWwksw/pNlWmm3JnKme1BkTfOFQz4PV0PKYGzovlaKOCAh8wggIb
MA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUM9BoxfyDUoTiwPSZXWlgme4F+fMwHwYD
VR0jBBgwFoAUjw0TovYuftFQbDMYOF1ZjiNykcowMgYIKwYBBQUHAQEEJjAkMCIG
CCsGAQUFBzAChhZodHRwOi8vZTguaS5sZW5jci5vcmcvMB0GA1UdEQQWMBSCEnMx
NzJkMTUud3BjbG91ZC52bjATBgNVHSAEDDAKMAgGBmeBDAECATAtBgNVHR8EJjAk
MCKgIKAehhxodHRwOi8vZTguYy5sZW5jci5vcmcvMzUuY3JsMIIBAwYKKwYBBAHW
eQIEAgSB9ASB8QDvAHYApELFBklgYVSPD9TqnPt6LSZFTYepfy/fRVn2J086hFQA
AAGZd5MOYwAABAMARzBFAiAyNaj9y43AvttAAez1hse6Slav1scemDSMokurCNjG
UQIhALgfjSCbtAUKg3SKovi/v6CA2Zh67VN4Ks3YFjCow2M8AHUAzPsPaoVxCWX+
lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGZd5MOjAAABAMARjBEAiAYw1fJiS+U
KFFt4O+GZ8zEWEmjNOUnG6OFZbKnQTO/fAIgeRCJ1F88/IYhoVjv2c1MQLngfewK
IdqXPYO3aiRopH8wCgYIKoZIzj0EAwMDaAAwZQIwIO4NIB2cmUHtWHOsG6o5pVi7
0uUs0H3JoRvGfSaKg+DZXc4z5Ytb/J9lWCk8zHJ9AjEA3vm4HwTplGEGoAUNAAhz
BM5d4cxIxyuGbb8XjJZuUgIRLV873ksIslKKvNmQlSVc
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c
S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb
R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB
9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j
cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB
BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE
DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j
ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0
RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d
AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8
otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA
aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm
Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2
HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1
Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR
xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d
tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/
jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
u1igv3OefnWjSQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1 @@
1758647751

6
conf/cakey.pem Normal file
View File

@@ -0,0 +1,6 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBkHYx/1v2aLVa6BxbMRVe0277DH3Miw9pSp9jLGX4ConZbX10k+Jqm
+7qIue4JMW+gBwYFK4EEACKhZANiAARNwt7GCokXn8P0Zq+gr25twtNdDY8hsC8W
FIVvyzxzsL0A5nmRdAgJQsF0ZpEqP3zllEzga2Xeaj+Y3aSHs1cBaqVsJLMP6TZV
pptyZypntQZE3zhUM+D1dDymBs6L5Wg=
-----END EC PRIVATE KEY-----

27
conf/carootcert.pem Normal file
View File

@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c
S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb
R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB
9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j
cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB
BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE
DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j
ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0
RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d
AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8
otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA
aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm
Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2
HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1
Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR
xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d
tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/
jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
u1igv3OefnWjSQ==
-----END CERTIFICATE-----

87
conf/directadmin.conf Normal file
View File

@@ -0,0 +1,87 @@
add_userdb_quota=1
admin_ssl_check_retries=0
apache_public_html=0
apache_ver=2.0
backup_gzip=2
brute_dos_count=100
brute_force_log_scanner=1
brute_force_scan_apache_logs=2
brute_force_time_limit=1200
brutecount=10
bruteforce=1
carootcert=/usr/local/directadmin/conf/carootcert.pem
check_load=0
check_partitions=1
check_subdomain_owner=0
clear_blacklist_ip_time=86400
clear_brute_log_entry_time=4
clear_brute_log_time=24
cloud_cache=0
da_gzip=1
dataskq_max_instances=1
default_private_html_link=1
demodocsroot=./data/skins/evolution
disable_ip_check=1
disk_usage_suspend=0
dkim=1
dns_ttl=1
docsroot=./data/skins/evolution
dovecot=1
email_ftp_password_change=1
enforce_difficult_passwords=0
ethernet_dev=eth0:100
exempt_local_block=1
filemanager_du=1
frontpage_on=0
get_current_version_timeout=0
hide_brute_force_notifications=1
http2=1
ip_brutecount=20
ipv6=0
jail=1
letsencrypt=1
litespeed=0
logs_to_keep=5
lost_password=0
mail_sni=1
max_per_email_send_limit=-1
max_username_length=30
maxfilesize=21474836480
mysql_detect_correct_methods=1
nginx=1
nginx_proxy=0
notify_on_license_update=0
ns1=ns1.s172d15.wpcloud.vn
ns2=ns2.s172d15.wpcloud.vn
one_click_pma_login=1
one_click_webmail_login=1
openlitespeed=0
partition_usage_threshold=95
php_fpm_max_children_default=10
pointers_own_virtualhost=1
port=8443
pureftp=0
purge_spam_days=0
quota_partition=/
random_password_length=20
secure_access_group=access
servername=s172d15.wpcloud.vn
session_minutes=600
show_info_in_header=0
show_info_in_title=0
special_characters_in_random_passwords=2
ssl=1
ssl_redirect_host=s172d15.wpcloud.vn
system_user_to_virtual_passwd=1
timeout=600
unblock_brute_ip_time=86400
unified_ftp_password_file=1
use_cookie_expires=0
use_xfs_quota=1
user_brutecount=20
user_can_set_email_limit=1
webmail_link=roundcube
x_frame_options=sameorigin
zip=1
zstd=1
check_referer=0

BIN
conf/license.key Normal file

Binary file not shown.

3
conf/my.cnf Normal file
View File

@@ -0,0 +1,3 @@
[client]
user=da_admin
password=T1k2XeWHEpnMQYA

2
conf/mysql.conf Normal file
View File

@@ -0,0 +1,2 @@
user=da_admin
passwd=T1k2XeWHEpnMQYA

110
conf/options.conf Normal file
View File

@@ -0,0 +1,110 @@
#PHP Settings
php1_release=8.1
php1_mode=php-fpm
php2_release=7.4
php2_mode=php-fpm
php3_release=8.2
php3_mode=php-fpm
php4_release=8.4
php4_mode=php-fpm
secure_php=yes
php_ini=yes
php_timezone=Asia/Ho_Chi_Minh
php_ini_type=production
x_mail_header=yes
#MySQL Settings
mysql=8.0
mariadb=10.6
mysql_inst=mariadb
mysql_backup=yes
mysql_backup_gzip=yes
mysql_backup_dir=/usr/local/directadmin/custombuild/mysql_backups
mysql_force_compile=no
#WEB Server Settings
unit=no
webserver=nginx
http_methods=ALL
litespeed_serialno=trial
modsecurity=yes
modsecurity_ruleset=comodo
apache_ver=2.4
apache_mpm=auto
mod_ruid2=no
userdir_access=yes
harden_symlinks_patch=yes
use_hostname_for_alias=yes
redirect_host=s172d15.wpcloud.vn
redirect_host_https=yes
#WEB Applications Settings
phpmyadmin=yes
phpmyadmin_public=yes
phpmyadmin_ver=5
squirrelmail=no
roundcube=no
webapps_inbox_prefix=no
#ClamAV-related Settings
clamav=no
clamav_exim=no
modsecurity_uploadscan=no
proftpd_uploadscan=no
pureftpd_uploadscan=no
suhosin_php_uploadscan=no
#Mail Settings
exim=no
eximconf=no
eximconf_release=4.5
blockcracking=no
easy_spam_fighter=no
spamd=no
sa_update=no
dovecot=no
dovecot_conf=no
mail_compress=no
pigeonhole=no
#FTP Settings
ftpd=proftpd
#Statistics Settings
awstats=no
webalizer=yes
#PHP Extension Settings
#CustomBuild Settings
custombuild=2.0
custombuild_plugin=yes
autover=no
bold=yes
clean=yes
cleanapache=yes
clean_old_tarballs=yes
clean_old_webapps=yes
downloadserver=da-mirror.wpcloud.vn
unofficial_mirrors=yes
#Cronjob Settings
cron=yes
cron_frequency=daily
email=email@domain.com
notifications=no
updates=no
webapps_updates=no
#CloudLinux Settings
cloudlinux=no
cloudlinux_beta=no
cagefs=no
#Advanced Settings
csf=yes
curl=yes
ssl_configuration=intermediate
#PHP extensions can be found in php_extensions.conf
redis=yes
da_autoupdate=no

Binary file not shown.

Binary file not shown.

View File

@@ -401,7 +401,7 @@ getServices() {
servfile=`cat ./setup.txt | grep services= | cut -d= -f2`;
#get the md5sum
wget https://raw.githubusercontent.com/irf1404/Directadmin/master/services/${servfile}.md5 -O ${SERVICES_FILE}.md5
wget https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/services/${servfile}.md5 -O ${SERVICES_FILE}.md5
if [ ! -s ${SERVICES_FILE}.md5 ];
then
echo "";
@@ -410,7 +410,7 @@ getServices() {
sleep 4;
fi
wget https://raw.githubusercontent.com/irf1404/Directadmin/master/services/${servfile} -O $SERVICES_FILE
wget https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/services/${servfile} -O $SERVICES_FILE
if [ $? -ne 0 ]
then
echo "Error downloading the services file";
@@ -436,19 +436,29 @@ getServices() {
if [ $? -ne 0 ]; then
exit 1
fi
echo "Chạy doGetInfo"
doGetInfo
echo "Chạy doSetHostname"
doSetHostname
echo "Chạy createDAbase"
createDAbase
echo "Chạy copyStartupScripts"
copyStartupScripts
echo "Chạy "
#copyCronFile #moved lower, after custombuild, march 7, 2011
echo "Chạy touchExim"
touchExim
echo "Chạy ./fstab.sh"
./fstab.sh
${DA_SCRIPTS}/cron_deny.sh
touch /root/.skip_get_license
echo "Chạy getLicense"
getLicense
#getServices
echo "-------------------------------------------------------------"
echo "Chạy getServices"
echo "-------------------------------------------------------------"
getServices
if [ ! -e ${DA_PATH}/custombuild/options.conf ] && [ -e /etc/redhat-release ] && [ ! -e /etc/init.d/xinetd ] && [ -e /usr/bin/yum ]; then
yum -y install xinetd
@@ -494,19 +504,26 @@ if [ -s ${DA_SCRIPTS}/majordomo.sh ]; then
${DA_SCRIPTS}/majordomo.sh
fi
echo "Chạy ${DA_SCRIPTS}/sysbk.sh"
${DA_SCRIPTS}/sysbk.sh
echo "Chạy ./build all d"
cd ${DA_PATH}/custombuild
echo "Bắt đầu build....."
echo "-------------------------------------------------------------"
echo "Bắt đầu build..... "
echo "-------------------------------------------------------------"
chmod 755 build
./build update_script
./build update
./build all d
if [ $? -ne 0 ]; then
copyCronFile
exit 1
fi
echo "Chạy copyCronFile"
#moved here march 7, 2011
copyCronFile
@@ -529,10 +546,10 @@ if [ ! -e /usr/local/bin/php ]; then
exit 1
fi
echo "Chạy ./directadmin i"
cd ${DA_PATH}
./directadmin i
echo "Chạy /directadmin p"
cd ${DA_PATH}
./directadmin p

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
FAQ
The Majordomo FAQ, originally written by Vincent
D. Skahan, now maintained by barr@math.psu.edu (David Barr).
majordomo-faq.html
An html version of the FAQ.
majordomo.lisa6.ps
The original Majordomo paper from the USENIX LISA VI conference
in October, 1992. While this paper is somewhat out of date
(some of the details about how Majordomo works have changed,
and many of the items mentioned as "to be implemented later"
have since been implemented), it remains a valuable
introduction to Majordomo's basic form and structure.
list-owner-info
has information for list owner to get them started using
majordomo and the config files.
majordomo.ora
This file is the chapter about Majordomo from the Nutshell Handbook
"Managing Internet Information Services," written by Jerry Peek.
The chapter is (c) Copyright 1994 by O'Reilly & Associates, Inc.,
and was included in the Majordomo distribution by permission of the
publisher.
This chapter is a good introduction to setting up the
majordomo software, be warned that it does not cover much of
the list operation details under 1.90 that deal with config
files. Then again the config files are supposed to be self
documenting. A newer version of this chapter that has been
updated for 1.90 is in the works, and should make it into the
"Managing Internet Information Services" book. This newer
chapter should be available via ftp in due time. Stay tuned to
the majordomo-announce or majordomo-users mailing list for
details.
man
Some man pages for majordomo and approve.

View File

@@ -0,0 +1,110 @@
This digestifier follows RFC 934, so it should be compatible with
almost any digest-digester that comes along.
This creates a properly formatted digest and mails it. It automatically
increments the issue number, but not the volume number.
The digest script has two modes: receiving messages and creating a
digest. It receives email messages via stdin and places them in
a work directory. In digest-creation mode, it takes those messages
from the work directory, assembles them into a digest in an archive
directory, and mails the digest.
If there are no messages in the work directory, it exits saying,
"No messages to process."
One of the digest's required configuration values is the size limit
in characters. If you use digest's -r option to receive digests, a
digest will automatically be sent whenever this limit is passed.
There are also two optional parameters that can cause digests to
be created and sent: the digest length limit in lines, and the
age in days of the oldest undigested message.
These values are checked every time a message is received (if
you are using the -r option).
There are two ways of setting up a digest: as a majordomo list,
or as a standalone. All of the files in this directory (excepting
the digest script) are for the standalone configuration. They are
IGNORED by majordomo.
If you are setting up a majordomo digest list, ALL your configuration
values come from majordomo.cf and the digest list's config file
(whatever-digest.config), NOT from the files in this directory.
To set up a majordomo digest list, you need
- digest work directory for incoming messages.
This must be under the root $digest_work_dir from majordomo.cf
- digest archive directory for completed digests.
This must be under the root $filedir from majordomo.cf,
and the directory name must end in $filedir_suffix.
- the majordomo digest list. This is just like an ordinary
majordomo list, except that you need to set the various
digest parameters in the list's configuration file
($listdir/whatever-digest.config). They are well commented.
Make sure that in the message_footer and message_fronter
that you begin all lines that need to be blank with a '-',
and if you want the line to begin with whitespace, precede
the whitespace with a '-'.
- aliases for the digest. There are examples in aliases.slice.
You can set up a cron job to make the digests go at regular intervals.
If you take incoming messages with the -r option, digests will also
be created whenever there are long enough messages, or whenever the first
message is old enough. The -R option will prevent this from happening;
it just accepts messages, so digests can be mailed whenever you or your
cron job say. The -m option (which is used by majordomo's mkdigest
command) will make a digest if there are ANY messages. The -p option
will only make a digest if there are enough messages, or if the
first message is old enough. Both the -m and -p options could cause
more than one digest to be created and sent.
If you only want to set up a majordomo digest, stop reading now,
because the rest of this file is about the standalone configuration.
------------------------------------------------------------------------------
If you are setting up a standalone digest, ALL of your configuration
values come from the digest configuration file. There is a sample
config file in this directory (firewalls-digest.cf). The default
name for the configuration file is ~/.digestrc, which could make
it easy to pipe mail from your mail reader into the digest, if
that's how you want to feed it.
To make a standalone digest, you need these things:
- digest work directory for incoming messages
- digest archive directory for completed digests
- a digest config file, ~/.digestrc by default (sample in
firewalls-digest.cf)
- a digest header file (sample is firewalls-digest.header)
- a digest trailer file (sample is firewalls-digest.trailer)
- a digest volume-number file (sample is firewalls-digest.vol)
- a digest issue-number file (sample is firewalls-digest.num)
- RFC-822 messages, stored one per file
The config file is commented, and the format should be obvious. The
only two things to watch for in the header and trailer files are:
- a line containing _SUBJECTS_ in the header file will be
replaced by lines consisting of all of the subjects in the
included messages, in order, indented as far as _SUBJECTS_ is.
- lines beginning with "-" in these files will not be
properly encapsulated, and will be interpreted by
undigesting software as message breaks.
You need to pipe the incoming messages to "digest [-c config_file]"
for example:
cat email_message | digest -c /usr/local/digest/banjo.cf
And you can use either the -m or -p option to build a digest:
digest -m -c /usr/local/digest/banjo.cf
for example.

View File

@@ -0,0 +1,69 @@
sequencer - a majordomo module
Shane P. McCarron
MACS, Inc.
Copyright MACS Inc, 1996
All rights to this package are hereby contributed to the community,
and in particular to the MajorDomo development group, to do with as
they see fit.
Introduction
Sequencer is a perl script based upon the resend script in the
majordomo release 1.9.3. The script has been modified to (optionally)
provide for sequence numbering of messages in their subject lines.
This modification takes advantage of the 'subject-prefix'
configuration variable already supported by majordomo, expanding it by
including an additiona '$SEQNUM' expandable variable. Expansion of
this variable is handled in the sequencer script so that the majordomo
and config-parse.pl scripts did not have to be modified. Processing of
$SEQNUM could be moved back into the config-parse.pl library if the
development team believes this is useful.
Documentation
Sequencing is invoked by calling the sequencer script
with a '-n' (numbering) option. When this option is selected, the
script uses a listname.seq file in the $filedir directory to determine
the next message number. It uses the shlock.pl library to keep this file
locked while the message is being processed (to prevent multiple use
of the same sequence number, and skipping of sequence numbers when a
message is bounced late in the script).
If there is a subject-prefix defined for the mailing list, and if
there is a $SEQNUM in the defined subject-prefix, then the message's
sequence number is placed in the subject line.
This script also provides for archiving the messages by sequence
number. If the -N option is selected, then a copy of the message will
be placed in the list's archive directory with the file name equal to
the message's sequence number. In addition, if there is a file called
INDEX in the archive directory, the message's date, time, author, and
subject will be placed in that INDEX. Note that the -N option
necessarily implies the -n option, since archiving without a valid
sequnce number would be silly. Logically, -N is just a bigger
version of -n.
This script also handles the absence of a subject. If there is no
subject, the script creates a Subject: line with a subject of
"Message for listname". This subject will also get a sequence number
of the requirements specified above are satisfied.
Finally, the script increments the sequence number and updates the
number in the listname.seq file, releasing the lock.
Conclusion
These extensions are pretty straightforward. I would recommend rolling
them into the resend script. I would further recommend adding the
$SEQNUM processing to the subject-prefix handler and getting the
special case code out of the script. However, this could continue to
exist as a standalone script. That is how I have done my
implementation.
Also, I think it would be useful to include a man page for resend. If
you don't have the time, I would be happy to try and put one together.
However, I haven't written using the man macros in quite a while :-)

View File

@@ -0,0 +1,18 @@
firewalls: "|/usr/local/mail/majordomo/wrapper resend -l firewalls -h GreatCircle.COM firewalls-outgoing"
firewalls-outgoing: :include:/usr/local/mail/lists/firewalls, firewalls-archive, firewalls-digestify
firewalls-request: "|/usr/local/mail/majordomo/wrapper majordomo -l firewalls"
firewalls-approval: brent
owner-firewalls: brent
owner-firewalls-outgoing: owner-firewalls
firewalls-archive: /usr/local/mail/archive/firewalls
firewalls-digestify: "|/usr/local/mail/majordomo/wrapper digest -r -C -l firewalls-digest firewalls-digest-outgoing"
firewalls-digest: firewalls
firewalls-digest-outgoing: :include:/usr/local/mail/lists/firewalls-digest
firewalls-digest-request: "|/usr/local/mail/majordomo/wrapper majordomo -l firewalls-digest"
firewalls-digest-approval: brent
owner-firewalls-digest-outgoing: owner-firewalls

View File

@@ -0,0 +1,51 @@
#Digest configuration file
#
#name that appears in subject line and digest banner
NAME=Firewalls Digest
#address reader send to to reply to the entire list
REPLY-TO=Firewalls@GreatCircle.COM
#address error messages should go to
ERRORS-TO=Firewalls-Digest-Owner@GreatCircle.COM
#address the digest itself appears to be sent to
TO=Firewalls-Digest@GreatCircle.COM
#address the digest really is sent to
REALLY-TO=Firewalls-Digest-Send@GreatCircle.COM
#address administrative nonsense should go to
FROM=Firewalls-Digest-Owner@GreatCircle.COM
#file containing header text
HEADER=/mycroft/brent/digest/firewalls-digest.header
#file containing trailer text
TRAILER=/mycroft/brent/digest/firewalls-digest.trailer
#directory to store incoming messages
#INCOMING=/usr/local/mail/digests/incoming/firewalls
INCOMING=/mycroft/brent/digest/incoming
#file containing volume number
VOL_FILE=/mycroft/brent/digest/firewalls-digest.vol
#file containing issue number
NUM_FILE=/mycroft/brent/digest/firewalls-digest.num
#directory to archive outgoing issues
ARCHIVE=/mycroft/brent/digest/archive
#directory containing shlock.pl and other stuff
HOME=/mycroft/brent/digest
#how big do we let digests get before sending?
DIGEST_SIZE=40000
#how many lines can a digest accumulate before we send it?
DIGEST_LINES=
#what is the oldest message we will put in a digest?
MAX_DAYS=

View File

@@ -0,0 +1,6 @@
In this issue:
_SUBJECTS_
See the end of the digest for information on subscribing to the Firewalls
or Firewalls-Digest mailing lists and on how to retrieve back issues.

View File

@@ -0,0 +1 @@
13

View File

@@ -0,0 +1,18 @@
To subscribe to Firewalls-Digest, send the command:
subscribe firewalls-digest
in the body of a message to "Majordomo@GreatCircle.COM". If you want
to subscribe something other than the account the mail is coming from,
such as a local redistribution list, then append that address to the
"subscribe" command; for example, to subscribe "local-firewalls":
subscribe firewalls-digest local-firewalls@your.domain.net
A non-digest (direct mail) version of this list is also available; to
subscribe to that instead, replace all instances of "firewalls-digest"
in the commands above with "firewalls".
Back issues are available for anonymous FTP from FTP.GreatCircle.COM, in
pub/firewalls/digest/vNN.nMMM (where "NN" is the volume number, and "MMM"
is the issue number).

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,588 @@
Majordomo address: # Majordomo@FooBar.COM
Majordomo-Owner address:# Majordomo-Owner@FooBar.COM
List Name: # ListName
Is resend used: # yes
Is the list archived: # no
List posting address: # ListName@FooBar.COM
List request address: # ListName-Request@FooBar.COM
List password: # whatever
Digest list name: # ListName-digest
Digest list password: # whatever
Your mailing list has been established. It is being served by an
automated mailing list manager that responds to commands emailed to
the "Majordomo address" listed above. This message has all the details
of how to manage your list remotely using Majordomo. If you have any
questions, refer them to the Majordomo-Owner address listed above.
******
There's a lot of info here, so please read this completely and
carefully, and save it for future reference. If you have any questions,
you should send them to the Majordomo-Owner address above.
******
Your list-owner password is shown above. Keep track of this; you'll
need it later. Instructions for changing your password are below.
As soon as possible, please issue a "newinfo" command for your
list (see below) to create the file that someone will receive when
they join or ask about your list.
You can issue a "who" command for your list to see who's already on your
list. You may or may not already be subscribed to your own list.
================
The Gory Details
================
Your mailing list is managed by an automated mailing list management
program called Majordomo. Majordomo should free you from dealing
with most of the administrivia usually associated with running mailing
lists (adding users, dropping users, etc.).
To submit something to your list, you (or anybody else) should simply
mail it to the list posting address shown at the top of this file.
To be added to your list, a user simply sends a message to majordomo.
There are two ways to do it:
address-- To: ListName-request@FooBar.COM
message-- subscribe
OR
address-- To: majordomo@FooBar.COM
message-- subscribe ListName
Majordomo understands several commands, and is not limited to a single
command per message (it will process commands until reaching
end-of-message or the command "end"). The command "help" will tell
you about all the other commands.
Actually, it won't tell you about _all_ the other commands that
Majordomo understands. There are several commands there for use by
list owners such as yourself, which are not advertised to the public.
All of these commands are password-protected on a list-by-list basis,
but anyone with a valid list/password combination can invoke these
commands. This is not exactly high-tech security, but it's more
intended to keep annoyance to a minimum than to be foolproof.
The "documented" commands which Majordomo understands and which are
for everyone to use are:
subscribe <list> [<address>]
unsubscribe <list> [<address>]
which [<address>]
who <list>
info <list>
index <list>
get <list>
lists
help
end
You can get detailed explanations of all of these by asking for "help"
from Majordomo (send a message containing just the word "help" as the
message text to majordomo@FooBar.COM).
The "undocumented" commands for use by list owners are:
approve <passwd> {subscribe|unsubscribe} <list> [<address>]
This is so that you can approve subscription or unsubscription
actions that need approval by the list owner. Note that this
is just a standard "subscribe" or "unsubscribe" command prefixed
with "approve <password>" (where you substitute the password for
your list, which is listed above, for "<password>").
approve <passwd> who <list>
This allows you to get the list of addresses for your
anonymous list. Without the password, even the list owner can
not see who is on the list.
passwd <list> <old_passwd> <new_passwd>
This is so you can change the password for your list, if you desire.
newintro <list> <password>
This is so that you can replace the information file that people
get when they do "intro <list>" or "subscribe <list>". It reads
everything after the "newintro" command to end-of-message or the
word "EOF" on a line by itself as the new intro for the list.
newinfo <list> <password>
This replaces the information file that people get when they do
"info <list>". (This file is also sent by "subscribe <list>" if
the intro file doesn't exist.) This reads everything after the
"newinfo" command to end-of-message or the word "EOF" on a line
by itself as the new info for the list.
config <list> <password>
Retrieves a self-documenting configuration file for
the list <list>. The <password> can be the password
contained in the file <list>.passwd or the
admin_password in the configuration file.
newconfig <list> <password>
Validates and installs a new configuration file. It reads
everything after the "newconfig" command to end-of-message or
the word "EOF" on a line by itself as the new info for the
list. The config file is expected to be a complete config
file as returned by "config". Incremental changing of the
config file is not yet supported. As soon as the config file
is validated and installed its settings are available for
use. This is useful to remember if you have multiple commands
in your mail message since they will be subject to the
settings of the new config file. If there is an error in the
config file (incorrect value...), the config file will not be
accepted and the error message identifying the problem line(s)
will be returned to the sender. Note that only the error
messages are returned to the sender not the entire config
file, so it would be a good idea to keep a copy of your
outgoing email message.
writeconfig <list> <password>
Write a new config file in standard form. Writeconfig forces a
rewrite of the config file with all default values in place (or
current values if the config file already exists). It is
useful to use after an upgrade of majordomo since it will add
the new keywords for people to change. It also updates the
documentation in the file if that has changed.
mkdigest <digest list name> <password>
mkdigest <digest list name> <digest outgoing alias> <password>
Generate a digest immediately without waiting to reach the
maxlength given in the config file. The first form will cause the
digest to be sent to an alias found by appending "-outgoing" to the
digest list name. Because this can be a security concern, the
second form allows specification of the name of the alias that the
outgoing digest will be sent to.
Configuring Your List
=====================
You should retrieve the configuration file for your list. To do this,
send an email message to the majordomo address listed at the top of
this form. The contents of this message should be:
config <list> <List password>
Where <list> <List password> are given at the top of the form. You
will receive a config file that can be used to change the operation of
your list. If the information at the top of this form shows that
resend is being used, you want to configure the majordomo and resend
subsystems. Otherwise you only have to configure those items that are
associated with the majordomo system.
The configuration file is meant to be self documenting. Once you have
completed all of the changes to the config file, You should use the
newconfig command (described above) to put a new configuration file in
place.
If you have a digest version of your list, you should retrieve the
config file for the digest as well using:
config <Digest List Name> <Digest list password>
and configure the parameters for the digest and majordomo subsystems.
Regular Expressions
===================
For some of the configuration options, a rudimentary knowledge of perl
style regular expressions will help you run Majordomo through its
tricks. A regular expression is a concise way of expressing a pattern
in a series of characters. The full power of regular expressions can
make some difficult tasks quite easy, but we will only brush the
surface here.
The character / is used to mark the beginning and end of a regular
expression. Letters and numbers stand for themselves. Many of the
other characters are symbolic. Some commonly used ones are:
\@ the `@' found in nearly all addresses; it must be preceeded by a
backslash in later versions of perl to avoid errors
. (period) any character
* previous character, zero or more times; note especially...
.* any character, zero or more times
+ previous character, one or more times; so for example...
a+ letter "a", one or more times
\ next character stands for itself; so for example...
\. literally a period, not meaning "any character"
^ beginning of the string; so for example...
^a a string beginning with letter "a"
$ end of the string; so for example...
a$ a string ending with letter "a"
Example 1.
/cs\.umb\.edu/
Notice the periods are preceded by a backslash to make them be
literally periods. This matches any string containing cs.umb.edu
such as:
cs.umb.edu
foo.cs.umb.edu
user@foo.cs.umb.edu
users%foo.cs.umb.edu@greatcircle.com
Example 2.
/rouilj\@.*cs\.umb\.edu/
The `@' has special meaning to later versions of perl and must be prefixed
with a backslash to avoid errors. The string ".*" means "any character,
zero or more times". So this matches:
rouilj@cs.umb.edu
rouilj@terminus.cs.umb.edu
arouilj@terminus.cs.umb.edu@greatcircle.com
but it doesn't match
rouilj@umb.edu
brent@cs.umb.edu
Example 3.
/^rouilj\@.*cs\.umb\.edu$/
This is similar to Example 2, and matches the same first two strings:
rouilj@cs.umb.edu
rouilj@terminus.cs.umb.edu
but it doesn't match
arouilj@terminus.cs.umb.edu@greatcircle.com
because the regular expression says the string has to begin with
letter "r" and end with letter "u", by using the ^ and $ symbols, and
neither of those is true for arouilj@terminus.cs.umb.edu@greatcircle.com.
Example 4.
/.*/
This is the regular expression that matches anything.
Example 5.
/.\*rouilj/
Here the * is preceded by a \, so it refers literally to an asterisk
character and not the symbolic meaning "zero or more times". The . still
has its symbolic meaning of "any one character", so it would match for
example
a*rouilj
s*rouilj
It would not match this because the . by itself implies one character:
*rouilj
Normally all matches are case sensitive; you can make any match case
insensitive by appending an `i' to the end of the expression.
Example 6.
/aol\.com/i
This would match aol.com, AOL.com, AoL.cOm, etc. Removing the `i':
/aol\.com/
would match aol.com but not AOL.com or any other capitalization.
To be on the safe side put a \ in front of any characters in the
regular expressions that are not numbers or letters. In order to put
a / into the regular expression, the same rule holds: precede it
with a \. Thus, with \ in front of the / and = characters, this
/\/CO\=US/
matches /CO=US and may be a useful regular expression to those of you
who need to deal with X.400 addresses that contain / characters.
Approval
========
When Majordomo requests your approval for something, it sends you a
message that includes a template of the approval message; if you concur,
you simply need to replace "PASSWORD" in the template with your list
password, and send the template line back to Majordomo.
The requests for approval that Majordomo generates all start with
"APPROVE" in the "Subject:" line.
You aren't limited to approving only things to Majordomo requests
approval for. You can approve any "subscribe" or "unsubscribe" request,
regardless of whether Majordomo has requested this approval, with an
"approve" command. Thus, you can subscribe or unsubscribe people from
your list without them having to send anything to Majordomo; just
send an appropriate "approve PASSWORD subscribe LIST ADDRESS" or
"approve PASSWORD unsubscribe LIST ADDRESS" command off to Majordomo.
If you use a mailer which is capable of sending a message to an external
program, can run perl and can run sendmail or a program capable of behaving
like it for the purposes of sending mail, then all you have to do is send
the entire approval message (including all of the headers, which are very
important and which are automatically removed by some mailers unless
configured to do otherwise) to the approve script. Approve looks for a
file called ".majordomo" in your home directory to find the approval
password for your list. The format of this file is given in the following
excerpt from the approve manual page:
approve assumes that the approve password for each list is
the same as the approval password used by resend, and that
this password is stored in a file called .majordomo in the
user's home directory. The file has the following format:
this-list passwd1 Majordomo@This.COM
other-list passwd2 Majordomo@Other.GOV
The first column specifies the name of the mailing list, the
second column specifies the list-owner's password for the
given list, and the third column specifies the e-mail
address of the associated Majordomo server. It is assumed
that the value in the third column is an Internet-style
"something@somewhere" address, and that postings for "List"
should be sent to "List@somewhere". Since this file only
needs to be read by the user, it should be mode 600 to pro-
tect the passwords.
If you have the necessary environment for running the approve script,
contact the Majordomo owner at the site that serves your list and request
it.
Bounced Messages
================
Majordomo may bounce certain messages that people attempt to post to your
mailing list. These messages may be bounced because they appear to be
administrative requests (i.e., someone mailed a request to subscribe or
unsubscribe to the posting address rather than to Majordomo or to the
-request address), because they are too long, because they match strings
that you or the list server owner has defined as being "taboo", or for any
of a number of other reasons, many of which may seem annoying but have been
decided upon as being useful in stopping unwanted messages from making it
onto your list. (These are often configurable, so if you find a check to
be too restrictive you can generally turn it off.) Note also that the
bounces mentioned here are not the same as the errors that will be returned
by various mail servers when addresses or hosts are unreachable. Those are
generally referred to as bounces, also; sorry for the confusion.
Majordomo will forward these messages to you in another message whose
subject line begins with the word "BOUNCE"; the subject line will also
indicate the name of the list the message was bounced from (in case you
manage more than one list) and the reason the message was bounced.
If you decide that the message is OK and should not have been bounced, then
you can cause Majordomo to post it anyway by sending the message back to
the posting address (NOT to the Majordomo address) with a special
"Approved: password" header. There are two ways to do this; the method you
use depends on your having access to and the ability to run the approve
script mentioned in the previous section. If you can run approve it is
recommended that you do so, as this method is much less prone to errors and
will reduce the time you spend moderating your list.
If you cannot run the approve script, you can manually approve the
message. To do so, follow the following directions _exactly_:
1) Save the original message (the body of the message you received
from Majordomo) in a file. The portion you need will consist of
the headers of the original message, followed by a single blank
line, followed by the text of the original message. You do not
need to include any of the headers of the message which contained
the original message. Here's a quick example:
From: majordomo@list.server \
To: your-list-approval@list.server | Don't want these headers
Subject: BOUNCE: taboo_header found /
- Blank line
>From list-member@her.site date \
Received: some long routing info | Headers of original message;
From: list-member@her.site | You want these. It's OK if you
To: your-list@list.server | don't have the first line.
Subject: Just a message /
- Blank line, you _must_ have this!
Hello. I'm just writing to \
consume some bandwidth and | Message body; include all of
take up space in your mail | this.
spool! /
Basically you want everything after (and not including) the first
blank line.
2) Edit the file to insert a line that says "Approved: password" (where
"password" is the password for your list) at the top, before the
original message, with absolutely no intervening space:
Approved: sekrit
>From list-member@her.site date
Received: some long routing info
From: list-member@her.site
To: your-list@list.server
Subject: Just a message
Hello. I'm just writing to
consume some bandwidth and
take up space in your mail
spool!
3) Send this edited file back to the posting address for your list (NOT
to Majordomo). You should make sure that your mailer doesn't try
to do anything like include your prepared mail as an attachment,
encode it somehow, indent every line, or add anything extra to the
beginning or end of the message. There are mailers that will do
pretty horrible things to messages before they are sent; you should
take care that you aren't using one or, if you are, you have it
configured to pass your text on unadulterated.
This time around, Majordomo will notice the "Approved:" line and check it
against your list password. If it matches, Majordomo will strip off the
header of your message and the "Approved:" line (leaving just the original
message), and send the original message on through.
Even your own messages bay be bounced to you for approval. To send out your
own message without server checks (perhaps you know it contains something
the list server will complain about) you can pre-approve the message one of
the two following ways:
If you're using a mailer that can add additional headers, add one like the
following:
Approved: sekrit
It's precise location within the headers is not important.
If your mailer does not allow you to add additional headers, you can add
the line:
Approved: sekrit
as the first line of the message, followed by a blank line (which is
required for your message to be sent properly) followed by the text of your
message. The Approved: line and one following blank line will be deleted
and the message will be passed without being checked. The blank line is
important because it is used to differentiate between a pre-approval and the
approval of a bounced message, outlined above.
Moderation
==========
If your list is moderated, (the moderate parameter in the config
file is yes) then messages without an "Approved:" line are bounced,
just as described above. To cause them to be posted to the list, you
add a valid "Approved:" line and send them back, just as described
above.
Again, the "approve" program automates all this if you wish to use it. You
can also use the above pre-approval method to send your own messages
without them being bounced back to you.
If you have any questions about all of this, send them to the Majordomo-Owner
address shown at the top of this file.
Restricting Posting
===================
An easier alternative to moderation is to restrict who can post to the
list, which can be done with the restrict_post configuration variable.
The variable requires a file listing the people who can post.
The most common case is to limit posting to people who are subscribed
to the list. This keeps out advertisements and other junk mail sent
by non-subscribers. Since majordomo already has a file of subscribers,
you don't need to create and maintain a file, so it's easy to set.
Change the restrict_post line to this, where <listname> is the name of
your list:
restrict_post = <listname>
If you want to restrict posting to any other set of people, you'll
need to ask majordomo-owner for help. Unfortunately there's no way to
tell majordomo about keeping another file of people who are allowed to
post, so a file would have to be set in place "by hand". Some future
release of majordomo may provide a way to do this automatically.
Archive
=======
Archiving has to be set or unset by the system administrators reached
at majordomo-owner@FooBar.COM. It is not the default but must be
requested. Here is what can be done.
Archive files can be split by years, months, or days. This means all
mail to the list for one of those periods of time will be collected
into one archive file. People who want to get archived mail will need
to get one such file as a unit.
We are running an indexer program nightly. It produces two index files
that subscribers can get: CONTENTS lists what subject lines are in each
archive file; TOPICS lists what archive files contain each subject.
Subscribers use the "get" command to see files in the archives. Examples:
get ListName CONTENTS # gets the CONTENTS file
get ListName ListName.9507 # gets the July 1995 archive file
Access to archives is controlled by the get_access variable in the
config file. The default "list" means they must be subscribers to get
archived files.
Subscribers can also get a list of filenames and dates in the archive
by sending an "index" command. Example:
index ListName
This is controlled by the config file variable index_access similarly.
Notes on archiving.
- It's possible for the archive to contain files besides the indexes
and the archive files of messages. However, majordomo offers no
method for you to put them there. In an unusual case you can ask
majordomo-owner to put a file there for you.
- Archiving could be accomplished by directing a copy of messages to
some other place besides the majordomo archive. Ask, if you have
something in mind.
Digest
=======
A digest version of a list is a way to reduce the number of messages sent
from Majordomo to subscribers. Normally, each message to the list is
remailed to all the subscribers, but with a digest, several messages are
collected into a batch and then sent together as one message. This does
not reduce the total size too much, although there are fewer mail header
lines-- the main purpose is to reduce the number of separate messages.
This actually helps the mail systems at both ends, and may help subscribers
reduce clutter in their mailboxes.
A Majordomo digest is actually a separate mailing list. The digest of
ListName would normally be called ListName-digest.
People subscribe independently to ListName and ListName-digest.
Very likely no one would want to be on both lists. To change between
ListName and ListName-digest, a subscriber needs to unsubscribe
from one list and subscribe to the other. This can be done with one
message to majordomo@FooBar.COM with two command lines in it, e.g.:
unsubscribe ListName
subscribe ListName-digest
Remember that ListName-digest will have its own information file and
configuration file. Change them, if you want to, when you change the
same files for ListName.
Majordomo will send a digest automatically when the size of the digest
exceeds the size given as max_length in the configuration file of the
digest list. The default max_length is 40 K. Thus the interval
between digests can vary, but they will be of a predictable size.
The listowner can also tell Majordomo to make a digest (meaning, compile
and send out a digest) by sending the command mkdigest at any time:
mkdigest ListName-digest password
A daily digest (or for some other time period) could be achieved by
setting the max_length high enough so as not to be reached normally in
a day, and then setting up a job to run daily that sends mail to
Majordomo with the mkdigest command. On a unix system, give the
commands "man crontab" and "man 5 crontab" at the shell for an
explanation of such jobs, or ask majordomo-owner for help.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
'\" t
.TH APPROVE 1
.SH NAME
approve \- approve a Majordomo request
.SH SYNOPSIS
.B approve [filename]
.SH "DESCRIPTION"
.B approve
automates the task of replying to an approval request from Majordomo. Input
is the e-mail message containing Majordomo's request, read from
.IR filename ,
or read from standard input if no filename is specified.
.PP
.B approve
currently understands two types of requests; those requesting
subscription to a
.I closed
list, and those which bounced due to a lack of permission to post to a
moderated, or
.IR private ,
mailing list.
.B approve
reads the body of the message from Majordomo to determine the appropriate
action. Assuming a message containing a subscription request like the
following:
.sp 1
.RS 3
From: Majordomo@This.COM
.sp 0
To: this-list-approval@This.COM
.sp 1
Joe User <User@Fubar.COM> requests you approve the following:
.sp 1
.RS 3
subscribe this-list Joe User <User@Fubar.COM>
.RE
.sp 1
If you approve, send a line such as the following to Majordomo@This.COM:
.sp 1
.RS 3
approve PASSWD subscribe this-list Joe User <User@Fubar.COM>
.RE
.RE
.sp 1
then running
.B approve
on the message by saving it in a file, e.g.,
.sp 1
.RS 3
approve /tmp/request
.RE
.sp 1
or
.sp 1
.RS 3
approve < /tmp/request
.RE
.sp 1
will result in the following reply to Majordomo:
.sp 1
.RS 3
To: Majordomo@This.COM
.sp 1
approve PASSWD subscribe this-list User@Fubar.COM (Joe User)
.sp 1
.RE
If
.B approve
is on the user's path, then it's possible to execute it via a shell escape,
piping the current message to
.B approve
from a mail program, e.g.,
.sp
.RS 3
!approve
.RE
.sp
would
.I approve
the current message in /usr/ucb/Mail.
.PP
If, in the latter case, the "Subject:" line of the request from Majordomo is
"BOUNCE <list>: <reason>", the message is treated as a posting rejected by
.B resend
for some reason, and is reformatted with appropriate "Approved:" headers to
cause it to succeed, and then it is resubmitted to Majordomo for posting.
This provides an easy mechanism for the moderator of a mailing list to
approve postings to the list.
.SH CONFIGURATION
.B approve
assumes that the
.I approve
password for each list is the same as the
.I approval
password used by
.BR resend ,
and that this password is stored
in a file called
.I .majordomo
in the user's home directory. The file has the following format:
.RS 5
.TS
l l l .
.sp
this-list passwd1 Majordomo@This.COM
other-list passwd2 Majordomo@Other.GOV
.sp
.TE
.RE
The first column specifies the name of the mailing list, the second column
specifies the list-owner's password for the given list, and the third column
specifies the e-mail address of the associated Majordomo server. It is
assumed that the value in the third column is an Internet-style
"something@somewhere" address, and that postings for "List" should be sent
to "List@somewhere". Since this file
.B only
needs to be read by the user, it should be mode 600 to protect the
passwords.
.SH FILES
~/.majordomo
.sp 0
/usr/local/lib/mail/majordomo/
.SH SEE ALSO
majordomo(8),perl(1),resend(1).
.SH BUGS
There is no direct support for MH(1), so MH users will have to run
.B approve
directly on the message file in their inbox.
.sp
The
.I .majordomo
file requires an at-sign, "@", in the address of the Majordomo server, even
if it colocated on the same system as the list-owner.
.SH AUTHORS
Majordomo and most of the ancillary perl code was written by Brent Chapman,
<brent@GreatCircle.COM>.
This man page was written by Jim Duncan, <jim@math.psu.edu>.

View File

@@ -0,0 +1,132 @@
APPROVE(1) USER COMMANDS APPROVE(1)
NAME
approve - approve a Majordomo request
SYNOPSIS
approve [filename]
DESCRIPTION
approve automates the task of replying to an approval
request from Majordomo. Input is the e-mail message con-
taining Majordomo's request, read from _f_i_l_e_n_a_m_e, or read
from standard input if no filename is specified.
approve currently understands two types of requests; those
requesting subscription to a _c_l_o_s_e_d list, and those which
bounced due to a lack of permission to post to a moderated,
or _p_r_i_v_a_t_e, mailing list. approve reads the body of the
message from Majordomo to determine the appropriate action.
Assuming a message containing a subscription request like
the following:
From: Majordomo@This.COM
To: this-list-approval@This.COM
Joe User <User@Fubar.COM> requests you approve the fol-
lowing:
subscribe this-list Joe User <User@Fubar.COM>
If you approve, send a line such as the following to
Majordomo@This.COM:
approve PASSWD subscribe this-list Joe User
<User@Fubar.COM>
then running approve on the message by saving it in a file,
e.g.,
approve /tmp/request
or
approve < /tmp/request
will result in the following reply to Majordomo:
To: Majordomo@This.COM
approve PASSWD subscribe this-list User@Fubar.COM (Joe
User)
If approve is on the user's path, then it's possible to exe-
cute it via a shell escape, piping the current message to
Sun Release 4.1 Last change: 1
APPROVE(1) USER COMMANDS APPROVE(1)
approve from a mail program, e.g.,
!approve
would _a_p_p_r_o_v_e the current message in /usr/ucb/Mail.
If, in the latter case, the "Subject:" line of the request
from Majordomo is "BOUNCE <list>: <reason>", the message is
treated as a posting rejected by resend for some reason, and
is reformatted with appropriate "Approved:" headers to cause
it to succeed, and then it is resubmitted to Majordomo for
posting. This provides an easy mechanism for the moderator
of a mailing list to approve postings to the list.
CONFIGURATION
approve assumes that the _a_p_p_r_o_v_e password for each list is
the same as the _a_p_p_r_o_v_a_l password used by resend, and that
this password is stored in a file called ._m_a_j_o_r_d_o_m_o in the
user's home directory. The file has the following format:
this-list passwd1 Majordomo@This.COM
other-list passwd2 Majordomo@Other.GOV
The first column specifies the name of the mailing list, the
second column specifies the list-owner's password for the
given list, and the third column specifies the e-mail
address of the associated Majordomo server. It is assumed
that the value in the third column is an Internet-style
"something@somewhere" address, and that postings for "List"
should be sent to "List@somewhere". Since this file only
needs to be read by the user, it should be mode 600 to pro-
tect the passwords.
FILES
~/.majordomo
/usr/local/lib/mail/majordomo/
SEE ALSO
majordomo(8),perl(1),resend(1).
BUGS
There is no direct support for MH(1), so MH users will have
to run approve directly on the message file in their inbox.
The ._m_a_j_o_r_d_o_m_o file requires an at-sign, "@", in the address
of the Majordomo server, even if it colocated on the same
system as the list-owner.
AUTHORS
Majordomo and most of the ancillary perl code was written by
Brent Chapman, <brent@GreatCircle.COM>. This man page was
written by Jim Duncan, <jim@math.psu.edu>.
Sun Release 4.1 Last change: 2

View File

@@ -0,0 +1 @@
.so man1/bounce.1

View File

@@ -0,0 +1,198 @@
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
NNNNAAAAMMMMEEEE
bounce, bounce-remind - handle majordomo list subscribers
whose mail is undeliverable
SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
bbbboooouuuunnnncccceeee [[[[----dddd]]]] [[[[----ffff _c_o_n_f_i_g-_f_i_l_e ]]]] [[[[----mmmmaaaajjjjoooorrrrddddoooommmmoooo _s_e_r_v_e_r-_a_d_d_r_e_s_s ]]]]
[[[[----uuuunnnnssssuuuubbbb]]]] _m_a_j_o_r_d_o_m_o-_l_i_s_t _u_s_e_r-_a_d_d_r_e_s_s
bbbboooouuuunnnncccceeee [[[[----dddd]]]] [[[[----ffff _c_o_n_f_i_g-_f_i_l_e ]]]] [[[[----mmmmaaaajjjjoooorrrrddddoooommmmoooo _s_e_r_v_e_r-_a_d_d_r_e_s_s ]]]]
----eeeexxxxppppiiiirrrreeee [[[[----mmmmaaaaxxxxaaaaggggeeee _d_a_y_s ]]]] _b_o_u_n_c_e-_a_d_d_r_e_s_s-_f_i_l_e
bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd
AAAAVVVVAAAAIIIILLLLAAAABBBBIIIILLLLIIIITTTTYYYY
Provided with distributions of Majordomo.
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
bbbboooouuuunnnncccceeee and bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd are perl scripts which help list
owners handle subscribers whose mail is bouncing. Mail is
"bounced" in this context when it is undeliverable because
hosts or addresses are unreachable or because of other mail
errors.
Mail is also "bounced" by the resend script for various
administrative reasons; these bounces are described in
aaaapppppppprrrroooovvvveeee(1).
When a list owner observes that an email address
consistently causes mail errors, the owner may use bbbboooouuuunnnncccceeee to
remove the address from the list and place the address on a
special bbbboooouuuunnnncccceeeessss mailing list.
bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd,,,, which should be run nightly by ccccrrrroooonnnn(4M),
sends a message to each of the user addresses on the bbbboooouuuunnnncccceeeessss
list, on the chance that the mail error has been corrected.
The message informs the addressee that their mail has been
undeliverable and that they have been removed from one or
more majordomo lists. It also instructs them how to
unsubscribe from the bbbboooouuuunnnncccceeeessss list and re-subscribe to the
list of their choice.
bbbboooouuuunnnncccceeee can also be used to expire addresses off the bbbboooouuuunnnncccceeeessss
list after a predetermined number of days.
If bbbboooouuuunnnncccceeee is invoked under a name that contains ``unsub'' it
will simply unsubscribe the offending address from the
majordomo list; it will not place the address on the bbbboooouuuunnnncccceeeessss
list.
OOOOPPPPTTTTIIIIOOOONNNNSSSS
These options relate to bbbboooouuuunnnncccceeee;;;; bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd takes no
arguments or options.
Page 1 (printed 9/24/96)
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
----dddd Debug; print what would be done, but don't do it.
----ffff ccccoooonnnnffffiiiigggg----ffffiiiilllleeee
Use the specified configuration file. The default
is ~~~~////....mmmmaaaajjjjoooorrrrddddoooommmmoooo,,,, and the format for this file is
described in the CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN section of the
aaaapppppppprrrroooovvvveeee(1) man page. This file provides the
list-owner's password for each list and the
address of the corresponding Majordomo server.
----mmmmaaaajjjjoooorrrrddddoooommmmoooo sssseeeerrrrvvvveeeerrrr----aaaaddddddddrrrreeeessssssss
Use this _s_e_r_v_e_r-_a_d_d_r_e_s_s for majordomo rather than
the address from the configuration file.
----uuuunnnnssssuuuubbbb Unsubscribes the offending address from the
majordomo list, without entering that address on
the bbbboooouuuunnnncccceeeessss list. This is equivalent to invoking
bbbboooouuuunnnncccceeee under a name containing ``unsub''.
----eeeexxxxppppiiiirrrreeee Expire entries from the specified bbbboooouuuunnnncccceeeessss list.
----mmmmaaaaxxxxaaaaggggeeee ddddaaaayyyyssss
Expire entries older than ddddaaaayyyyssss.... The default is
coded into the bbbboooouuuunnnncccceeee script as $$$$ddddeeeeffffaaaauuuulllltttt____mmmmaaaaxxxxaaaaggggeeee
days. It is set to 21 days in the majordomo
distribution.
OOOOPPPPEEEERRRRAAAANNNNDDDDSSSS
mmmmaaaajjjjoooorrrrddddoooommmmoooo----lllliiiisssstttt
The list from which the offending user-address
should be removed.
uuuusssseeeerrrr----aaaaddddddddrrrreeeessssssss
The address to which mail is currently
undeliverable.
bbbboooouuuunnnncccceeee----aaaaddddddddrrrreeeessssssss----ffffiiiilllleeee
The name of the file that contains the bbbboooouuuunnnncccceeeessss
list.
CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN
If bbbboooouuuunnnncccceeee is going to be used only to unsubscribe users, a
link can be created whose name contains ``unsub'' so that
users could be unsubscribed simply by typing
unsub firewalls-digest fury@world.std.com
for example.
In any case, a configuration file must exist and must
contain the names of the owner's lists, along with their
respective passwords and the email address of the associated
Page 2 (printed 9/24/96)
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
Majordomo server. The format of this file is given in the
CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN section of the aaaapppppppprrrroooovvvveeee(1) man page. The
default name for this file is ~~~~////....mmmmaaaajjjjoooorrrrddddoooommmmoooo,,,, and the same
file can serve for both the aaaapppppppprrrroooovvvveeee and bbbboooouuuunnnncccceeee scripts.
The bbbboooouuuunnnncccceeeessss list, if it is used, must be created. It is
like any other Majordomo list excepting that the priority of
this list should be set to jjjjuuuunnnnkkkk and its owner and sender
should be nnnnoooobbbbooooddddyyyy.... Of course, the ``nobody'' mail alias must
exist; it is should be set to /dev/null. That is,
nobody: /dev/null
This will spare the human list owner as well as the
postmaster from having to deal with mail bouncing from the
bbbboooouuuunnnncccceeeessss list.
A ccccrrrroooonnnn(1M) job should be set up to run bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd every
night. bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd must run on the same server as the
bbbboooouuuunnnncccceeeessss list; it mails a message to everyone on the list
advising them that they have been removed from one or more
Majordomo lists and instructs them how to get off the
bbbboooouuuunnnncccceeeessss list and back on the list of their choice.
bbbboooouuuunnnncccceeee can only expire addresses if it has a copy of the
bbbboooouuuunnnncccceeeessss subscriber file, so this can either be run on the
server occasionally by the Majordomo administrator or by a
cron job. It can also be run remotely with a copy of the
bbbboooouuuunnnncccceeeessss file retrived by the use of the ``who bounces''
command to majordomo.
FFFFIIIILLLLEEEESSSS
////eeeettttcccc////aaaalllliiiiaaaasssseeeessss
////eeeettttcccc////mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff
SSSSEEEEEEEE AAAALLLLSSSSOOOO
mmmmaaaajjjjoooorrrrddddoooommmmoooo((((8888)))),,,,aaaapppppppprrrroooovvvveeee((((1111))))
AAAAUUUUTTTTHHHHOOOORRRR
Majordomo and most of the ancillary perl code was written by
Brent Chapman <brent@GreatCircle.COM>. Majordomo is
available via anonymous FTP from FTP.GreatCircle.COM, in the
directory pub/majordomo. This man page was written by Kevin
Kelleher <fury@world.std.com>.
Page 3 (printed 9/24/96)

View File

@@ -0,0 +1,221 @@
.TH bounce 1
.SH NAME
bounce, bounce-remind \- handle majordomo list subscribers whose mail is undeliverable
.LP
.SH SYNOPSIS
.B bounce [\-d] [\-f
.I config-file
.B ] [\-majordomo
.I server-address
.B ] [\-unsub]
.I majordomo-list user-address
.LP
.B bounce [\-d] [\-f
.I config-file
.B ] [\-majordomo
.I server-address
.B ] \-expire [\-maxage
.I days
.B ]
.I bounce-address-file
.LP
.B bounce-remind
.LP
.SH AVAILABILITY
Provided with distributions of Majordomo.
.LP
.SH DESCRIPTION
.B bounce
and
.B bounce-remind
are perl scripts which help list owners
handle subscribers whose mail is bouncing. Mail is "bounced"
in this context when it is undeliverable because hosts or
addresses are unreachable or because of other mail errors.
.LP
Mail is also "bounced" by the resend script for various administrative
reasons; these bounces are described in
.BR approve (1).
.LP
When a list owner observes that an email address consistently causes
mail errors, the owner may use
.B bounce
to remove the address from the list and place the address on a special
.BR bounces
mailing list.
.LP
.B bounce-remind,
which should be run nightly by
.BR cron (4M),
sends a message to each of the user addresses on the
.BR bounces
list, on the chance that the mail error has been corrected.
The message informs the addressee that their mail has been
undeliverable and that they have been removed from one or
more majordomo lists. It also instructs them how to unsubscribe
from the
.BR bounces
list and re-subscribe to the list of their choice.
.LP
.B bounce
can also be used to expire addresses off the
.BR bounces
list after a predetermined number of days.
.LP
If
.B bounce
is invoked under a name that contains ``unsub'' it will simply
unsubscribe the offending address from the majordomo list; it
will not place the address on the
.BR bounces
list.
.LP
.SH OPTIONS
These options relate to
.B bounce; bounce-remind
takes no arguments or options.
.LP
.TP 10
.B \-d
Debug; print what would be done, but don't do it.
.TP
.B \-f config-file
Use the specified configuration file. The default is
.BR ~/.majordomo,
and the format for this file is described in the
.BR CONFIGURATION
section of the
.BR approve (1)
man page. This file provides the list-owner's password for
each list and the address of the corresponding Majordomo
server.
.TP
.B \-majordomo server-address
Use this
.IR server-address
for majordomo rather than the address from the configuration file.
.TP
.B \-unsub
Unsubscribes the offending address from the majordomo list,
without entering that address on the
.BR bounces
list. This is equivalent to invoking
.BR bounce
under a name containing ``unsub''.
.TP
.B \-expire
Expire entries from the specified
.BR bounces
list.
.TP
.B \-maxage days
Expire entries older than
.BI days.
The default is coded into the
.BR bounce
script as
.BI $default_maxage
days. It is set to 21 days in the majordomo distribution.
.LP
.SH OPERANDS
.TP 10
.B majordomo-list
The list from which the offending user-address should be removed.
.TP
.B user-address
The address to which mail is currently undeliverable.
.TP
.B bounce-address-file
The name of the file that contains the
.BR bounces
list.
.LP
.SH CONFIGURATION
If
.B bounce
is going to be used only to unsubscribe users, a link can be
created whose name contains ``unsub'' so that users could be
unsubscribed simply by typing
.sp 1
.RS 3
unsub firewalls-digest fury@world.std.com
.RE
.sp 1
for example.
.LP
In any case, a configuration file must exist and must contain
the names of the owner's lists, along with their respective
passwords and the email address of the associated Majordomo
server. The format of this file is given in the
.B CONFIGURATION
section of the
.BR approve (1)
man page. The default name for this file is
.BR ~/.majordomo,
and the same file can serve for both the
.B approve
and
.B bounce
scripts.
.LP
The
.B bounces
list, if it is used, must be created. It is like any other
Majordomo list excepting that the priority of this list
should be set to
.B junk
and its owner and sender should be
.B nobody.
Of course, the ``nobody'' mail alias must exist; it is should
be set to /dev/null. That is,
.sp 1
.RS 3
nobody: /dev/null
.RE
.sp 1
This will spare the human list owner as well as the postmaster
from having to deal with mail bouncing from the
.B bounces
list.
.LP
A
.BR cron (1M)
job should be set up to run
.B bounce-remind
every night.
.B bounce-remind
must run on the same server as the
.B bounces
list; it mails a message to everyone on the list advising
them that they have been removed from one or more Majordomo
lists and instructs them how to get off the
.B bounces
list and back on the list of their choice.
.LP
.B bounce
can only expire addresses if it has a copy of the
.B bounces
subscriber file, so this can either be run on the server
occasionally by the Majordomo administrator or by a cron
job. It can also be run remotely with a copy of the
.B bounces
file retrived by the use of the ``who bounces'' command
to majordomo.
.LP
.SH FILES
.PD 0
.TP 20
.B /etc/aliases
.TP
.B /etc/majordomo.cf
.PD
.LP
.SH SEE ALSO
.B majordomo(8),approve(1)
.LP
.SH AUTHOR
Majordomo and most of the ancillary perl code was written by
Brent Chapman <brent@GreatCircle.COM>.
Majordomo is available via anonymous FTP
from FTP.GreatCircle.COM, in the directory pub/majordomo. This
man page was written by Kevin Kelleher <fury@world.std.com>.

View File

@@ -0,0 +1,198 @@
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
NNNNAAAAMMMMEEEE
bounce, bounce-remind - handle majordomo list subscribers
whose mail is undeliverable
SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
bbbboooouuuunnnncccceeee [[[[----dddd]]]] [[[[----ffff _c_o_n_f_i_g-_f_i_l_e ]]]] [[[[----mmmmaaaajjjjoooorrrrddddoooommmmoooo _s_e_r_v_e_r-_a_d_d_r_e_s_s ]]]]
[[[[----uuuunnnnssssuuuubbbb]]]] _m_a_j_o_r_d_o_m_o-_l_i_s_t _u_s_e_r-_a_d_d_r_e_s_s
bbbboooouuuunnnncccceeee [[[[----dddd]]]] [[[[----ffff _c_o_n_f_i_g-_f_i_l_e ]]]] [[[[----mmmmaaaajjjjoooorrrrddddoooommmmoooo _s_e_r_v_e_r-_a_d_d_r_e_s_s ]]]]
----eeeexxxxppppiiiirrrreeee [[[[----mmmmaaaaxxxxaaaaggggeeee _d_a_y_s ]]]] _b_o_u_n_c_e-_a_d_d_r_e_s_s-_f_i_l_e
bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd
AAAAVVVVAAAAIIIILLLLAAAABBBBIIIILLLLIIIITTTTYYYY
Provided with distributions of Majordomo.
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
bbbboooouuuunnnncccceeee and bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd are perl scripts which help list
owners handle subscribers whose mail is bouncing. Mail is
"bounced" in this context when it is undeliverable because
hosts or addresses are unreachable or because of other mail
errors.
Mail is also "bounced" by the resend script for various
administrative reasons; these bounces are described in
aaaapppppppprrrroooovvvveeee(1).
When a list owner observes that an email address
consistently causes mail errors, the owner may use bbbboooouuuunnnncccceeee to
remove the address from the list and place the address on a
special bbbboooouuuunnnncccceeeessss mailing list.
bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd,,,, which should be run nightly by ccccrrrroooonnnn(4M),
sends a message to each of the user addresses on the bbbboooouuuunnnncccceeeessss
list, on the chance that the mail error has been corrected.
The message informs the addressee that their mail has been
undeliverable and that they have been removed from one or
more majordomo lists. It also instructs them how to
unsubscribe from the bbbboooouuuunnnncccceeeessss list and re-subscribe to the
list of their choice.
bbbboooouuuunnnncccceeee can also be used to expire addresses off the bbbboooouuuunnnncccceeeessss
list after a predetermined number of days.
If bbbboooouuuunnnncccceeee is invoked under a name that contains ``unsub'' it
will simply unsubscribe the offending address from the
majordomo list; it will not place the address on the bbbboooouuuunnnncccceeeessss
list.
OOOOPPPPTTTTIIIIOOOONNNNSSSS
These options relate to bbbboooouuuunnnncccceeee;;;; bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd takes no
arguments or options.
Page 1 (printed 9/24/96)
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
----dddd Debug; print what would be done, but don't do it.
----ffff ccccoooonnnnffffiiiigggg----ffffiiiilllleeee
Use the specified configuration file. The default
is ~~~~////....mmmmaaaajjjjoooorrrrddddoooommmmoooo,,,, and the format for this file is
described in the CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN section of the
aaaapppppppprrrroooovvvveeee(1) man page. This file provides the
list-owner's password for each list and the
address of the corresponding Majordomo server.
----mmmmaaaajjjjoooorrrrddddoooommmmoooo sssseeeerrrrvvvveeeerrrr----aaaaddddddddrrrreeeessssssss
Use this _s_e_r_v_e_r-_a_d_d_r_e_s_s for majordomo rather than
the address from the configuration file.
----uuuunnnnssssuuuubbbb Unsubscribes the offending address from the
majordomo list, without entering that address on
the bbbboooouuuunnnncccceeeessss list. This is equivalent to invoking
bbbboooouuuunnnncccceeee under a name containing ``unsub''.
----eeeexxxxppppiiiirrrreeee Expire entries from the specified bbbboooouuuunnnncccceeeessss list.
----mmmmaaaaxxxxaaaaggggeeee ddddaaaayyyyssss
Expire entries older than ddddaaaayyyyssss.... The default is
coded into the bbbboooouuuunnnncccceeee script as $$$$ddddeeeeffffaaaauuuulllltttt____mmmmaaaaxxxxaaaaggggeeee
days. It is set to 21 days in the majordomo
distribution.
OOOOPPPPEEEERRRRAAAANNNNDDDDSSSS
mmmmaaaajjjjoooorrrrddddoooommmmoooo----lllliiiisssstttt
The list from which the offending user-address
should be removed.
uuuusssseeeerrrr----aaaaddddddddrrrreeeessssssss
The address to which mail is currently
undeliverable.
bbbboooouuuunnnncccceeee----aaaaddddddddrrrreeeessssssss----ffffiiiilllleeee
The name of the file that contains the bbbboooouuuunnnncccceeeessss
list.
CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN
If bbbboooouuuunnnncccceeee is going to be used only to unsubscribe users, a
link can be created whose name contains ``unsub'' so that
users could be unsubscribed simply by typing
unsub firewalls-digest fury@world.std.com
for example.
In any case, a configuration file must exist and must
contain the names of the owner's lists, along with their
respective passwords and the email address of the associated
Page 2 (printed 9/24/96)
bbbboooouuuunnnncccceeee((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV bbbboooouuuunnnncccceeee((((1111))))
Majordomo server. The format of this file is given in the
CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN section of the aaaapppppppprrrroooovvvveeee(1) man page. The
default name for this file is ~~~~////....mmmmaaaajjjjoooorrrrddddoooommmmoooo,,,, and the same
file can serve for both the aaaapppppppprrrroooovvvveeee and bbbboooouuuunnnncccceeee scripts.
The bbbboooouuuunnnncccceeeessss list, if it is used, must be created. It is
like any other Majordomo list excepting that the priority of
this list should be set to jjjjuuuunnnnkkkk and its owner and sender
should be nnnnoooobbbbooooddddyyyy.... Of course, the ``nobody'' mail alias must
exist; it is should be set to /dev/null. That is,
nobody: /dev/null
This will spare the human list owner as well as the
postmaster from having to deal with mail bouncing from the
bbbboooouuuunnnncccceeeessss list.
A ccccrrrroooonnnn(1M) job should be set up to run bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd every
night. bbbboooouuuunnnncccceeee----rrrreeeemmmmiiiinnnndddd must run on the same server as the
bbbboooouuuunnnncccceeeessss list; it mails a message to everyone on the list
advising them that they have been removed from one or more
Majordomo lists and instructs them how to get off the
bbbboooouuuunnnncccceeeessss list and back on the list of their choice.
bbbboooouuuunnnncccceeee can only expire addresses if it has a copy of the
bbbboooouuuunnnncccceeeessss subscriber file, so this can either be run on the
server occasionally by the Majordomo administrator or by a
cron job. It can also be run remotely with a copy of the
bbbboooouuuunnnncccceeeessss file retrived by the use of the ``who bounces''
command to majordomo.
FFFFIIIILLLLEEEESSSS
////eeeettttcccc////aaaalllliiiiaaaasssseeeessss
////eeeettttcccc////mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff
SSSSEEEEEEEE AAAALLLLSSSSOOOO
mmmmaaaajjjjoooorrrrddddoooommmmoooo((((8888)))),,,,aaaapppppppprrrroooovvvveeee((((1111))))
AAAAUUUUTTTTHHHHOOOORRRR
Majordomo and most of the ancillary perl code was written by
Brent Chapman <brent@GreatCircle.COM>. Majordomo is
available via anonymous FTP from FTP.GreatCircle.COM, in the
directory pub/majordomo. This man page was written by Kevin
Kelleher <fury@world.std.com>.
Page 3 (printed 9/24/96)

View File

@@ -0,0 +1,357 @@
.TH digest 1
.SH NAME
digest \- receive a file for a digest, or create and mail a digest
.LP
.SH SYNOPSIS
.B digest \-r|R|m|p \-C \-l
.I majordomo-listname recipient
.LP
.B digest \-r|R|m|p
[
.B \-c
.I configuration-file
]
.LP
.SH AVAILABILITY
Provided with distributions of Majordomo.
.LP
.SH DESCRIPTION
The digest script is a perl script which automates the
management of digests of electronic mail. It can be
run in a standalone configuration or as part of Majordomo.
.LP
It requires two directories: a work directory and an
archive directory. Incoming email messages are held
in the work directory until they are collected into a
digest. The digests are created and stored
in the archive directory.
.LP
Incoming email messages are given
numerical names starting with ``001'' and are numbered in
order of arrival. The digests are named according to volume
and number. For example, the filename ``v01.n028'' indicates
volume 1, number 28 of the digest.
.LP
It should be noted that digest needs a configuration file
to define all of its operating parameters. If no such
file is specified, digest will use the
.SB $HOME/.digestrc
file.
.LP
Several aspects of digest configuration determine how and
when a digest is created. A digest can be created at
regular intervals (as long as there are incoming messages)
or whenever certain configurable conditions are met. These
conditions are: how large the digest can be (in characters),
how long the digest can be (in lines), and how old the messages
in the digest can be (in days).
.LP
.SH OPTIONS
.TP 10
.B \-r
Receive an email message via standard input
and place the file into the working directory.
If any one of the conditions for digest creation
are met, create and mail a digest. These conditions
are the same as those described under option
.BR \-p.
.TP
.B \-R
Similar to
.BR \-r,
except that it will not create a digest. It simply
places the message in the work directory and stops.
.TP
.B \-m
If there are any numbered files in the working
directory, create and mail a digest. Store the
digest in the archive directory. This is the
option used by majordomo's mkdigest command.
.TP
.B \-p
Conditionally creates a digest. If any one of the
conditions for digest creation are met, the digest
is created and sent. There are three conditions,
which are connected to three limits: the digest
size in characters, the digest length in lines, and
the age of the oldest message in days. If one of the
files is older than the age limit, a digest is created.
If the sum of the messages exceeds either of the size
limits, a digest is created. The size limit in characters
must be configured; the other two limits are optional.
.TP
.B \-c configuration-file
Use the parameters defined in
.IR configuration-file.
.TP
.B \-C
Read the majordomo configuration file
(either /etc/majordomo.cf or ~majordomo/majordomo.cf)
and the configuration file for the Majordomo list specified in the
.BR \-l
option to define operational parameters. If both
.BR \-C
and
.BR \-c
options are specified (not recommended) only the
.BR \-C
option will be used.
.TP
.B \-l majordomo-listname
This option is ignored if used without the
.BR \-C
option. Specifies the Majordomo email list.
.LP
.SH OPERANDS
.TP 10
.B recipient
Email recipient of the digest. This operand is ignored if used
without the
.BR \-C
option. It specifies one of the system mail
aliases created for the Majordomo list named in the
.BR \-l
option.
.LP
.SH MAJORDOMO DIGEST CONFIGURATION
When used as a part of Majordomo, digest takes these parameters
from
.B majordomo.cf
(either /etc/majordomo.cf or ~majordomo/majordomo.cf):
.LP
.PD 0
.B $listdir
\- the location of the mailing lists
.LP
.B $digest_work_dir
\- parent directory for the digests' work directories
.LP
.B $filedir
\- parent directory for archive directories
.LP
.B $filedir_suffix
\- an optional identifier (may be the null string)
.PD
.LP
Incoming messages for
.B $listname-digest
will be held in
.B $digest_work_dir/$listname-digest.
.LP
Digests will be stored in
.B $filedir/$listname-digest$filedir_suffix.
.LP
The list's configuration file will be
.B $listdir/$listname-digest.config.
.LP
Examples of these values are given in
.SB EXAMPLES,
below.
.LP
The list's configuration file contains several digest parameters that
are not yet implemented and/or should NOT be changed from their defaults
(blank):
.B digest_archive, digest_rm_footer, digest_rm_fronter, digest_work_dir.
.LP
The parameters which specifically deal with digest creation
and maintenance are:
.LP
.PD 0
.B digest_name
\- the title of the digest
.LP
.B digest_volume
\- volume number
.LP
.B digest_issue
\- issue number
.LP
.B digest_maxdays
\- age limit in days for oldest message in the digest
.LP
.B digest_maxlines
\- maximum number of lines in a digest
.LP
.B maxlength
\- maximum number of characters in a digest
.LP
.B message_fronter
\- text prepended to the digest
.LP
.B message_footer
\- text appended to the digest
.PD
.LP
The last three parameters are also used in the configuration of
an ordinary (non-digest) Majordomo list.
.LP
Each digest begins with the a line containing the
.B digest_name, current date, digest_volume and digest_issue.
. The digest script will update the issue number in the configuration file.
.LP
A blank line follows, and then the text from the
.B message_fronter,
if any. The message fronter may contain the
.SB _SUBJECT_
token, which will be replaced by the subject lines from the messages
in the digest.
.LP
The text in the
.B message_footer,
if any, will be appended to the digest.
.LP
To embed a blank line in the
.B message_footer
or
.B message_fronter,
put a `-' as the first and ONLY character on the line. To
preserve whitespace at the beginning of a line, put a `-'
on the line before the whitespace to be preserved. To put
a literal `-' at the beginning of a line, double it.
.LP
Both message_footer and message_fronter may also use the tokens
.SB $LIST, $SENDER,
and
.SB $VERSION,
which will be expanded to,
respectively: the name of the current list, the sender as taken
from the from line, and the current version of Majordomo.
.LP
Examples of the aliases usually used with the digest are
given in
.SB EXAMPLES,
below.
.LP
The list owner can prompt Majordomo to build a digest by
sending the command
.LP
mkdigest
.I digest-name
[
.I outgoing-address
]
.I digest-password
.LP
to majordomo either via email or from cron. The cron
command has the format:
.LP
echo mkdigest
.I digest-name
[
.I outgoing-address
]
.I digest-password
| mail majordomo@domain.com
.LP
.SH STANDALONE DIGEST CONFIGURATION
The Majordomo distribution comes with a ``digest'' subdirectory.
The sample configuration file is called firewalls-digest.cf.
A file in this format must be used if digest is invoked in
standalone configuration.
.LP
If no configuration file is specified when digest is invoked,
it looks for a file named
.SB $HOME/.digestrc
that must be in the same format as the example file.
.LP
The configuration file defines the email addresses of the
sender and recipient of the digest. It also locates the
work and archive directories, the digest's size limit,
and the names of the files that contain the digest's volume,
number, header and footer.
.LP
The easiest way to configure a standalone digest is to copy
the five files (firewalls-digest.*) and edit them to taste.
.LP
Incoming mail is piped to digest with the
.B \-r
option. This can be done from some mail-reading programs, through
the command line, or via mail aliases similar to those
found in
.SB EXAMPLES,
below.
.LP
.SH EXAMPLES
.LP
1. Example values from
.B /etc/majordomo.cf:
.LP
.PD 0
.B $listdir = ``usr/local/mail/lists'';
.LP
.B $digest_work_dir = ``usr/local/mail/digest'';
.LP
.B $filedir = ``listdir'';
.LP
.B $filedir_suffix ``archive'';
.PD
.LP
If our digest's name is banjo-digest, the work directory will
be /usr/local/mail/digest/banjo-digest; the archive directory
will be /usr/local/mail/lists/banjo-digest.archive. Note
that these are names of directories, not files.
.LP
2. Typical aliases for Majordomo digests:
.LP
Usually a Majordomo digest is associated to a regular (non-digest)
list. The digest's name is the regular listname plus ``-digest''.
The list ``banjo'' will have the digest ``banjo-digest''.
.LP
.PD 0
.B banjo-digest-approval: kevink
.LP
.B banjo-digest-outgoing: :include:/usr/local/lists/banjo-digest
.LP
.B owner-banjo-digest-outgoing: kevink
.LP
.B banjo-digestify: ``|usr/majordomo/wrapper digest \-r
.B \-C \-l banjo-digest banjo-digest-outgoing''
.LP
.B banjo-digest: banjo
.PD
.LP
Note that mail to ``banjo-digest'' is routed to the regular list.
The ``digestify'' alias must be added to the regular list's outgoing
alias:
.LP
.B banjo-outgoing: :include:/usr/local/lists/banjo,banjo-digestify
.LP
.SH NOTES
The volume number does not change automatically; it must be
incremented manually.
.LP
For testing/debugging purposes there is a ``hidden'' option
.B -d
that creates the digest as /tmp/testdigest.nnn
(where
.I nnn
is the current digest number). Since it is for testing and
debugging purposes, it does not mail the digest, it does not
place the digest in the archive directory, and it does not
update the digest number.
.LP
.SH EXIT STATUS
The following exit values are returned:
.TP 10
.B 0
Successful completion.
.TP
.B >0
An error occurred.
.LP
.SH FILES
.PD 0
.TP 20
.B /etc/aliases
.TP
.B /etc/majordomo.cf
.PD
.LP
.SH SEE ALSO
.B majordomo(8)
.LP
.SH AUTHOR
The digest script was written by Brent Chapman <brent@GreatCircle.COM>.
It is available with distributions of Majordomo via anonymous FTP
from FTP.GreatCircle.COM, in the directory pub/majordomo. This
man page was written by Kevin Kelleher <fury@world.std.com>.

View File

@@ -0,0 +1,396 @@
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
NNNNAAAAMMMMEEEE
digest - receive a file for a digest, or create and mail a
digest
SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
ddddiiiiggggeeeesssstttt ----rrrr||||RRRR||||mmmm||||pppp ----CCCC ----llll _m_a_j_o_r_d_o_m_o-_l_i_s_t_n_a_m_e _r_e_c_i_p_i_e_n_t
ddddiiiiggggeeeesssstttt ----rrrr||||RRRR||||mmmm||||pppp [ ----cccc _c_o_n_f_i_g_u_r_a_t_i_o_n-_f_i_l_e ]
AAAAVVVVAAAAIIIILLLLAAAABBBBIIIILLLLIIIITTTTYYYY
Provided with distributions of Majordomo.
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
The digest script is a perl script which automates the
management of digests of electronic mail. It can be run in
a standalone configuration or as part of Majordomo.
It requires two directories: a work directory and an archive
directory. Incoming email messages are held in the work
directory until they are collected into a digest. The
digests are created and stored in the archive directory.
Incoming email messages are given numerical names starting
with ``001'' and are numbered in order of arrival. The
digests are named according to volume and number. For
example, the filename ``v01.n028'' indicates volume 1,
number 28 of the digest.
It should be noted that digest needs a configuration file to
define all of its operating parameters. If no such file is
specified, digest will use the file.
Several aspects of digest configuration determine how and
when a digest is created. A digest can be created at
regular intervals (as long as there are incoming messages)
or whenever certain configurable conditions are met. These
conditions are: how large the digest can be (in
characters), how long the digest can be (in lines), and how
old the messages in the digest can be (in days).
OOOOPPPPTTTTIIIIOOOONNNNSSSS
----rrrr Receive an email message via standard input and
place the file into the working directory. If any
one of the conditions for digest creation are met,
create and mail a digest. These conditions are
the same as those described under option ----pppp....
----RRRR Similar to ----rrrr,,,, except that it will not create a
digest. It simply places the message in the work
directory and stops.
----mmmm If there are any numbered files in the working
Page 1 (printed 9/23/96)
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
directory, create and mail a digest. Store the
digest in the archive directory. This is the
option used by majordomo's mkdigest command.
----pppp Conditionally creates a digest. If any one of the
conditions for digest creation are met, the digest
is created and sent. There are three conditions,
which are connected to three limits: the digest
size in characters, the digest length in lines,
and the age of the oldest message in days. If one
of the files is older than the age limit, a digest
is created. If the sum of the messages exceeds
either of the size limits, a digest is created.
The size limit in characters must be configured;
the other two limits are optional.
----cccc ccccoooonnnnffffiiiigggguuuurrrraaaattttiiiioooonnnn----ffffiiiilllleeee
Use the parameters defined in _c_o_n_f_i_g_u_r_a_t_i_o_n-_f_i_l_e.
----CCCC Read the majordomo configuration file (either
/etc/majordomo.cf or ~majordomo/majordomo.cf) and
the configuration file for the Majordomo list
specified in the ----llll option to define operational
parameters. If both ----CCCC and ----cccc options are
specified (not recommended) only the ----CCCC option
will be used.
----llll mmmmaaaajjjjoooorrrrddddoooommmmoooo----lllliiiissssttttnnnnaaaammmmeeee
This option is ignored if used without the ----CCCC
option. Specifies the Majordomo email list.
OOOOPPPPEEEERRRRAAAANNNNDDDDSSSS
rrrreeeecccciiiippppiiiieeeennnntttt Email recipient of the digest. This operand is
ignored if used without the ----CCCC option. It
specifies one of the system mail aliases created
for the Majordomo list named in the ----llll option.
MMMMAAAAJJJJOOOORRRRDDDDOOOOMMMMOOOO DDDDIIIIGGGGEEEESSSSTTTT CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN
When used as a part of Majordomo, digest takes these
parameters from mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff (either /etc/majordomo.cf or
~majordomo/majordomo.cf):
$$$$lllliiiissssttttddddiiiirrrr - the location of the mailing lists
$$$$ddddiiiiggggeeeesssstttt____wwwwoooorrrrkkkk____ddddiiiirrrr - parent directory for the digests' work
directories
$$$$ffffiiiilllleeeeddddiiiirrrr - parent directory for archive directories
$$$$ffffiiiilllleeeeddddiiiirrrr____ssssuuuuffffffffiiiixxxx - an optional identifier (may be the null
string)
Incoming messages for $$$$lllliiiissssttttnnnnaaaammmmeeee----ddddiiiiggggeeeesssstttt will be held in
$$$$ddddiiiiggggeeeesssstttt____wwwwoooorrrrkkkk____ddddiiiirrrr////$$$$lllliiiissssttttnnnnaaaammmmeeee----ddddiiiiggggeeeesssstttt....
Page 2 (printed 9/23/96)
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
Digests will be stored in $$$$ffffiiiilllleeeeddddiiiirrrr////$$$$lllliiiissssttttnnnnaaaammmmeeee----
ddddiiiiggggeeeesssstttt$$$$ffffiiiilllleeeeddddiiiirrrr____ssssuuuuffffffffiiiixxxx....
The list's configuration file will be $$$$lllliiiissssttttddddiiiirrrr////$$$$lllliiiissssttttnnnnaaaammmmeeee----
ddddiiiiggggeeeesssstttt....ccccoooonnnnffffiiiigggg....
Examples of these values are given in below.
The list's configuration file contains several digest
parameters that are not yet implemented and/or should NOT be
changed from their defaults (blank): ddddiiiiggggeeeesssstttt____aaaarrrrcccchhhhiiiivvvveeee,,,,
ddddiiiiggggeeeesssstttt____rrrrmmmm____ffffooooooootttteeeerrrr,,,, ddddiiiiggggeeeesssstttt____rrrrmmmm____ffffrrrroooonnnntttteeeerrrr,,,, ddddiiiiggggeeeesssstttt____wwwwoooorrrrkkkk____ddddiiiirrrr....
The parameters which specifically deal with digest creation
and maintenance are:
ddddiiiiggggeeeesssstttt____nnnnaaaammmmeeee - the title of the digest
ddddiiiiggggeeeesssstttt____vvvvoooolllluuuummmmeeee - volume number
ddddiiiiggggeeeesssstttt____iiiissssssssuuuueeee - issue number
ddddiiiiggggeeeesssstttt____mmmmaaaaxxxxddddaaaayyyyssss - age limit in days for oldest message in the
digest
ddddiiiiggggeeeesssstttt____mmmmaaaaxxxxlllliiiinnnneeeessss - maximum number of lines in a digest
mmmmaaaaxxxxlllleeeennnnggggtttthhhh - maximum number of characters in a digest
mmmmeeeessssssssaaaaggggeeee____ffffrrrroooonnnntttteeeerrrr - text prepended to the digest
mmmmeeeessssssssaaaaggggeeee____ffffooooooootttteeeerrrr - text appended to the digest
The last three parameters are also used in the configuration
of an ordinary (non-digest) Majordomo list.
Each digest begins with the a line containing the
ddddiiiiggggeeeesssstttt____nnnnaaaammmmeeee,,,, ccccuuuurrrrrrrreeeennnntttt ddddaaaatttteeee,,,, ddddiiiiggggeeeesssstttt____vvvvoooolllluuuummmmeeee aaaannnndddd ddddiiiiggggeeeesssstttt____iiiissssssssuuuueeee....
A blank line follows, and then the text from the
mmmmeeeessssssssaaaaggggeeee____ffffrrrroooonnnntttteeeerrrr,,,, if any. The message fronter may contain
the token, which will be replaced by the subject lines from
the messages in the digest.
The text in the mmmmeeeessssssssaaaaggggeeee____ffffooooooootttteeeerrrr,,,, if any, will be appended to
the digest.
To embed a blank line in the mmmmeeeessssssssaaaaggggeeee____ffffooooooootttteeeerrrr or
mmmmeeeessssssssaaaaggggeeee____ffffrrrroooonnnntttteeeerrrr,,,, put a `-' as the first and ONLY character
on the line. To preserve whitespace at the beginning of a
line, put a `-' on the line before the whitespace to be
preserved. To put a literal `-' at the beginning of a line,
double it.
Both message_footer and message_fronter may also use the
tokens and which will be expanded to, respectively: the name
of the current list, the sender as taken from the from line,
and the current version of Majordomo.
Page 3 (printed 9/23/96)
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
Examples of the aliases usually used with the digest are
given in below.
The list owner can prompt Majordomo to build a digest by
sending the command
mkdigest _d_i_g_e_s_t-_n_a_m_e [ _d_i_g_e_s_t-_p_a_s_s_w_o_r_d ]
to majordomo either via email or from cron. The cron
command has the format:
echo mkdigest _d_i_g_e_s_t-_n_a_m_e [ _d_i_g_e_s_t-_p_a_s_s_w_o_r_d ] | mail
majordomo@domain.com
SSSSTTTTAAAANNNNDDDDAAAALLLLOOOONNNNEEEE DDDDIIIIGGGGEEEESSSSTTTT CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN
The Majordomo distribution comes with a ``digest''
subdirectory. The sample configuration file is called
firewalls-digest.cf. A file in this format must be used if
digest is invoked in standalone configuration.
If no configuration file is specified when digest is
invoked, it looks for a file named that must be in the same
format as the example file.
The configuration file defines the email addresses of the
sender and recipient of the digest. It also locates the work
and archive directories, the digest's size limit, and the
names of the files that contain the digest's volume, number,
header and footer.
The easiest way to configure a standalone digest is to copy
the five files (firewalls-digest.*) and edit them to taste.
Incoming mail is piped to digest with the ----rrrr option. This
can be done from some mail-reading programs, through the
command line, or via mail aliases similar to those found in
below.
EEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
1. Example values from ////eeeettttcccc////mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff::::
$$$$lllliiiissssttttddddiiiirrrr ==== ````````uuuussssrrrr////llllooooccccaaaallll////mmmmaaaaiiiillll////lllliiiissssttttssss'''''''';;;;
$$$$ddddiiiiggggeeeesssstttt____wwwwoooorrrrkkkk____ddddiiiirrrr ==== ````````uuuussssrrrr////llllooooccccaaaallll////mmmmaaaaiiiillll////ddddiiiiggggeeeesssstttt'''''''';;;;
$$$$ffffiiiilllleeeeddddiiiirrrr ==== ````````lllliiiissssttttddddiiiirrrr'''''''';;;;
$$$$ffffiiiilllleeeeddddiiiirrrr____ssssuuuuffffffffiiiixxxx ````````aaaarrrrcccchhhhiiiivvvveeee'''''''';;;;
If our digest's name is banjo-digest, the work directory
will be /usr/local/mail/digest/banjo-digest; the archive
directory will be /usr/local/mail/lists/banjo-
digest.archive. Note that these are names of directories,
not files.
Page 4 (printed 9/23/96)
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
2. Typical aliases for Majordomo digests:
Usually a Majordomo digest is associated to a regular (non-
digest) list. The digest's name is the regular listname
plus ``-digest''. The list ``banjo'' will have the digest
``banjo-digest''.
bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt----aaaapppppppprrrroooovvvvaaaallll:::: kkkkeeeevvvviiiinnnnkkkk
bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt----oooouuuuttttggggooooiiiinnnngggg:::: ::::iiiinnnncccclllluuuuddddeeee::::////uuuussssrrrr////llllooooccccaaaallll////lllliiiissssttttssss////bbbbaaaannnnjjjjoooo----
ddddiiiiggggeeeesssstttt
oooowwwwnnnneeeerrrr----bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt----oooouuuuttttggggooooiiiinnnngggg:::: kkkkeeeevvvviiiinnnnkkkk
bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeessssttttiiiiffffyyyy:::: ````````||||uuuussssrrrr////mmmmaaaajjjjoooorrrrddddoooommmmoooo////wwwwrrrraaaappppppppeeeerrrr ddddiiiiggggeeeesssstttt ----rrrr ----CCCC ----llll
bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt----oooouuuuttttggggooooiiiinnnngggg''''''''
bbbbaaaannnnjjjjoooo----ddddiiiiggggeeeesssstttt:::: bbbbaaaannnnjjjjoooo
Note that mail to ``banjo-digest'' is routed to the regular
list. The ``digestify'' alias must be added to the regular
list's outgoing alias:
bbbbaaaannnnjjjjoooo----oooouuuuttttggggooooiiiinnnngggg:::: ::::iiiinnnncccclllluuuuddddeeee::::////uuuussssrrrr////llllooooccccaaaallll////lllliiiissssttttssss////bbbbaaaannnnjjjjoooo,,,,bbbbaaaannnnjjjjoooo----
ddddiiiiggggeeeessssttttiiiiffffyyyy
NNNNOOOOTTTTEEEESSSS
The volume number does not change automatically; it must be
incremented manually.
For testing/debugging purposes there is a ``hidden'' option
----dddd that creates the digest as /tmp/testdigest.nnn (where _n_n_n
is the current digest number). Since it is for testing and
debugging purposes, it does not mail the digest, it does not
place the digest in the archive directory, and it does not
update the digest number.
EEEEXXXXIIIITTTT SSSSTTTTAAAATTTTUUUUSSSS
The following exit values are returned:
0000 Successful completion.
>>>>0000 An error occurred.
FFFFIIIILLLLEEEESSSS
////eeeettttcccc////aaaalllliiiiaaaasssseeeessss
////eeeettttcccc////mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff
SSSSEEEEEEEE AAAALLLLSSSSOOOO
mmmmaaaajjjjoooorrrrddddoooommmmoooo((((8888))))
AAAAUUUUTTTTHHHHOOOORRRR
The digest script was written by Brent Chapman
<brent@GreatCircle.COM>. It is available with distributions
of Majordomo via anonymous FTP from FTP.GreatCircle.COM, in
the directory pub/majordomo. This man page was written by
Page 5 (printed 9/23/96)
ddddiiiiggggeeeesssstttt((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV ddddiiiiggggeeeesssstttt((((1111))))
Kevin Kelleher <fury@world.std.com>.
Page 6 (printed 9/23/96)

View File

@@ -0,0 +1,300 @@
.TH MAJORDOMO 8
.SH NAME
Majordomo \- manage multiple mailing lists
.SH SYNOPSIS
.B Majordomo
.SH "DESCRIPTION"
.B Majordomo
is a perl script which automates the management of Internet mailing lists.
It is executed via electronic mail; users send e-mail to
.B Majordomo
with instructions in the body of the message, and the perl script performs
the requested actions and responds with the results. Any text in the
"Subject:" line is ignored.
.SH "COMMANDS"
.B Majordomo
understands the following commands (arguments in "[]" are optional):
.TP 5
.B
subscribe \fIlist\fR [\fIaddress\fR]
.P
Subscribe yourself (or
.I address
if specified) to the named
.IR list .
.TP 5
.B
unsubscribe \fIlist\fR [\fIaddress\fR]
.P
Unsubscribe yourself (or
.I address
if specified) from the named
.IR list .
If
.IR list
is ``*'' (an asterisk), unsubscribe from all lists on this Majordomo
server.
.TP 5
.B
auth \fIspecial-word\fP subscribe \fIlist address\fP
.P
If the
.I list
subscribe policy setting includes \fI+confirm\fR,
Majordomo will ask for confirmation before a subscription
is approved.
The conformation request will show the
.I special-word
to send with
.I auth .
.TP 5
.B
get \fIlist\fR \fIfile\fR
.P
Get the
.I file
related to
.IR list .
.TP 5
.B
index \fIlist\fR
.P
Return an index of the files you can
.I get
associated with
.IR list .
.TP 5
.B
which [\fIaddress\fR]
.P
Find out to which lists you (or
.I address
if specified) are subscribed.
.TP 5
.B
who \fIlist\fR
.P
Find out who is on the named
.IR list .
.TP 5
.B
info \fIlist\fR
.P
Retrieve the general introductory information for the named
.IR list .
.TP 5
.B
intro \fIlist\fR
.P
Retrieve the introductory message sent to new users
of
.IR list .
Non-subscribers may not be able to retrieve this.
.TP 5
.B
lists
.P
Show the lists served by this Majordomo server. It will also show a 50
character list description if one has been provided.
.TP 5
.B
help
.P
Retrieve an informational message, a brief synopsis of the user portion of
this manual page.
.TP 5
.B
end
.P
Stop processing commands (useful if your mailer adds a signature).
.PP
A command may be split across multiple lines if all of the lines in
the command except the last end with a backslash "\\".
.PP
In addition, the owner of the list can issue the following commands:
.TP 5
.B
approve \fIpassword\fR subscribe \fIlist\fR \fIaddress\fR
.P
Instruct Majordomo to add
.I address
to
.IR list .
The password is required to authenticate the list owner. This is very weak
authentication as the password is transmitted in the clear in an e-mail
message. No claims are made that it will provide anything other than
rudimentary protection against abuse of the Majordomo server.
.TP 5
.B
approve \fIpassword\fR unsubscribe \fIlist\fR \fIaddress\fR
.P
Instruct Majordomo to delete
.I address
from
.IR list .
The password is required to authenticate the list owner. See the comments
above regarding the password.
.TP 5
.B
newinfo \fIlist\fR \fIpassword\fR
.P
Update the informational message for
.I list
with the text which follows on subsequent lines. No formatting of the
message occurs, so the list owner should be careful to constrain the message
to eighty columns. Majordomo will include everything up to the string
.B EOF
or to the end of the mail message, whichever comes first. This is useful in
case the owner wants to verify the new message immediately, e.g.,
.sp 1
.RS 10
To: majordomo
.sp 0
newinfo list password
.sp
This is new information for the "list" list.
.sp
EOF
.sp 0
info list
.sp
.RE
.RS 5
This will simultaneously update the information for the list, and then
retrieve it for verification. Note that blank lines are preserved in the
message.
.RE
.TP 5
.B
newintro \fIlist\fR \fIpassword\fR
.P
Similar to
.I newinfo ,
but updates the (optional) introductory message sent to new
.I list
subscribers.
.B
passwd \fIlist\fR \fIold-password\fR \fInew-password\fR
.P
Replace the password for
.I list
with
.IR new-password .
.TP 5
.B
config \fIlist\fR \fIpassword\fR
.P
retrieve a self-documenting configuration file for
the list <list>. The \fIpassword\fR can be the password
contained in the file <listname>.passwd or the
admin_password in the configuration file.
.TP 5
.B
newconfig \fIlist\fR \fIpassword\fR
.P
Validates and installs a new configuration file. The config file
includes everything up to the string
.B EOF
or to the end of the mail message, whichever comes first. The config
file is expected to be a complete config file as returned by the
"config" command. Incremental changing of the config file is not yet
supported. As soon as the config file is validated and installed its
settings are available for use. This is useful to remember if you have
multiple commands in your mail message since they will be subject to
the settings of the new config file. If there is an error in the
config file (incorrect value...), the config file will not be accepted
and the error message identifying the problem line(s) will be returned
to the sender. Note that only the errors are returned to the
sender not the entire config file.
.TP 5
.B
writeconfig \fIlist\fR \fIpassword\fR
.P
Write a new config in standard form. All of the config
file documentation is optional. Only the keywords and
values are necessary. If a config file, stripped of
all comments is installed using newconfig, that is
what is returned by config. Writeconfig forces a
rewrite of the config file with all comments and
default values in place. It is useful to use after an
upgrade of majordomo since it will add the new
keywords for people to change. It also updates the
documentation in the file if that has changed.
.TP 5
.B mkdigest
.I digest-list-name
[
.I outgoing-address
]
.I password
.P
This will force a digest for the specified list to be created. It is
most useful if you don't have an account on the machine that handles
the digest for your list.
The optional
.I outgoing-address
will override the default address,
.IR listname -outgoing ,
for distributing the digests;
this is usually done for security.
.SH CONFIGURATION
(Note that this section has not been updated to majordomo version 1.90).
.B Majordomo
supports
.I open
and
.I closed
lists. An
.I open
list is one to which anyone can subscribe themselves. A subscription
request sent to
.B Majordomo
for a
.I closed
list is forwarded to the owner of the list for approval. If a user tries to
subscribe an address which is different from their own (for example, a local
list exploder),
.B Majordomo
will forward the request to the list owner for approval, regardless of the
open or closed status of the list.
.PP
.B Majordomo
depends on the existence of certain system mail aliases. The first three
are for running the perl script on incoming e-mail and specifying the
responsible person in charge of the server:
.sp 1
majordomo: "|/usr/local/mail/majordomo/wrapper majordomo"
.sp 0
majordomo-owner: brent
.sp 0
owner-majordomo: brent
.sp 1
These next few aliases are for a list called "sample":
.sp 1
sample: :include:/usr/local/mail/lists/sample
.sp 0
owner-sample: sample-owner
.sp 0
sample-request: "|/usr/local/mail/majordomo/wrapper request-answer sample"
.sp 0
owner-sample-request: sample-owner
.sp 0
sample-owner: brent
.sp 0
sample-approval: brent
.sp 1
.SH FILES
/etc/majordomo.cf
.sp 0
/usr/local/lib/mail/majordomo/
.SH BUGS
This man page has not been fully updated to conform to majordomo 1.90.
.SH AUTHORS
Majordomo and most of the ancillary perl code was written by Brent Chapman,
<brent@GreatCircle.COM>. The latest version of the code is available by
anonymous FTP from FTP.GreatCircle.COM, in directory pub/majordomo.
This man page was written by Jim Duncan, <jim@math.psu.edu>. Minimal
update of the man page by John Rouillard <rouilj@cs.umb.edu>.

View File

@@ -0,0 +1,264 @@
MAJORDOMO(8) MAINTENANCE COMMANDS MAJORDOMO(8)
NAME
Majordomo - manage multiple mailing lists
SYNOPSIS
Majordomo
DESCRIPTION
Majordomo is a perl script which automates the management of
Internet mailing lists. It is executed via electronic mail;
users send e-mail to Majordomo with instructions in the body
of the message, and the perl script performs the requested
actions and responds with the results. Any text in the
"Subject:" line is ignored.
COMMANDS
Majordomo understands the following commands (arguments in
"[]" are optional):
subscribe _l_i_s_t [_a_d_d_r_e_s_s]
Subscribe yourself (or _a_d_d_r_e_s_s if specified) to the
named _l_i_s_t.
unsubscribe _l_i_s_t [_a_d_d_r_e_s_s]
Unsubscribe yourself (or _a_d_d_r_e_s_s if specified) from the
named _l_i_s_t.
get _l_i_s_t _f_i_l_e
Get the _f_i_l_e related to _l_i_s_t.
index _l_i_s_t
Return an index of the files you can _g_e_t associated
with _l_i_s_t.
which [_a_d_d_r_e_s_s]
Find out to which lists you (or _a_d_d_r_e_s_s if specified)
are subscribed.
who _l_i_s_t
Find out who is on the named _l_i_s_t.
info _l_i_s_t
Retrieve the general introductory information for the
named _l_i_s_t.
lists
Show the lists served by this Majordomo server. It will
also show a 50 character list description if one has
been provided.
help Retrieve an informational message, a brief synopsis of
the user portion of this manual page.
Sun Release 4.1 Last change: 1
MAJORDOMO(8) MAINTENANCE COMMANDS MAJORDOMO(8)
end Stop processing commands (useful if your mailer adds a
signature).
A command may be split across multiple lines if all of the
lines in the command except the last end with a backslash
"\".
In addition, the owner of the list can issue the following
commands:
approve _p_a_s_s_w_o_r_d subscribe _l_i_s_t _a_d_d_r_e_s_s
Instruct Majordomo to add _a_d_d_r_e_s_s to _l_i_s_t. The pass-
word is required to authenticate the list owner. This
is very weak authentication as the password is
transmitted in the clear in an e-mail message. No
claims are made that it will provide anything other
than rudimentary protection against abuse of the Major-
domo server.
approve _p_a_s_s_w_o_r_d unsubscribe _l_i_s_t _a_d_d_r_e_s_s
Instruct Majordomo to delete _a_d_d_r_e_s_s from _l_i_s_t. The
password is required to authenticate the list owner.
See the comments above regarding the password.
newinfo _l_i_s_t _p_a_s_s_w_o_r_d
Update the informational message for _l_i_s_t with the text
which follows on subsequent lines. No formatting of
the message occurs, so the list owner should be careful
to constrain the message to eighty columns. Majordomo
will include everything up to the string EOF or to the
end of the mail message, whichever comes first. This
is useful in case the owner wants to verify the new
message immediately, e.g.,
To: majordomo
newinfo list password
This is new information for the "list" list.
EOF
info list
This will simultaneously update the information for the
list, and then retrieve it for verification. Note that
blank lines are preserved in the message.
passwd _l_i_s_t _o_l_d-_p_a_s_s_w_o_r_d _n_e_w-_p_a_s_s_w_o_r_d
Replace the password for _l_i_s_t with _n_e_w-_p_a_s_s_w_o_r_d.
config _l_i_s_t _p_a_s_s_w_o_r_d
retrieve a self-documenting configuration file for the
list <list>. The _p_a_s_s_w_o_r_d can be the password
Sun Release 4.1 Last change: 2
MAJORDOMO(8) MAINTENANCE COMMANDS MAJORDOMO(8)
contained in the file <listname>.passwd or the
admin_password in the configuration file.
newconfig _l_i_s_t _p_a_s_s_w_o_r_d
Validates and installs a new configuration file. The
config file includes everything up to the string EOF or
to the end of the mail message, whichever comes first.
The config file is expected to be a complete config
file as returned by the "config" command. Incremental
changing of the config file is not yet supported. As
soon as the config file is validated and installed its
settings are available for use. This is useful to
remember if you have multiple commands in your mail
message since they will be subject to the settings of
the new config file. If there is an error in the con-
fig file (incorrect value...), the config file will not
be accepted and the error message identifying the prob-
lem line(s) will be returned to the sender. Note that
only the errors are returned to the sender not the
entire config file.
writeconfig _l_i_s_t _p_a_s_s_w_o_r_d
Write a new config in standard form. All of the config
file documentation is optional. Only the keywords and
values are necessary. If a config file, stripped of all
comments is installed using newconfig, that is what is
returned by config. Writeconfig forces a rewrite of
the config file with all comments and default values in
place. It is useful to use after an upgrade of major-
domo since it will add the new keywords for people to
change. It also updates the documentation in the file
if that has changed.
mkdigest _d_i_g_e_s_t-_l_i_s_t-_n_a_m_e _p_a_s_s_w_o_r_d
This will force a digest for the specified list to be
created. It is most useful if you don't have an account
on the machine that handles the digest for your list.
CONFIGURATION
(Note that this section has not been updated to majordomo
version 1.90). Majordomo supports _o_p_e_n and _c_l_o_s_e_d lists.
An _o_p_e_n list is one to which anyone can subscribe them-
selves. A subscription request sent to Majordomo for a
_c_l_o_s_e_d list is forwarded to the owner of the list for appro-
val. If a user tries to subscribe an address which is dif-
ferent from their own (for example, a local list exploder),
Majordomo will forward the request to the list owner for
approval, regardless of the open or closed status of the
list.
Sun Release 4.1 Last change: 3
MAJORDOMO(8) MAINTENANCE COMMANDS MAJORDOMO(8)
Majordomo depends on the existence of certain system mail
aliases. The first three are for running the perl script on
incoming e-mail and specifying the responsible person in
charge of the server:
majordomo: "|/usr/local/mail/majordomo/wrapper majordomo"
majordomo-owner: brent
owner-majordomo: brent
These next few aliases are for a list called "sample":
sample: :include:/usr/local/mail/lists/sample
owner-sample: sample-owner
sample-request: "|/usr/local/mail/majordomo/wrapper
request-answer sample"
owner-sample-request: sample-owner
sample-owner: brent
sample-approval: brent
FILES
/etc/majordomo.cf
/usr/local/lib/mail/majordomo/
BUGS
This man page has not been fully updated to conform to
majordomo 1.90.
AUTHORS
Majordomo and most of the ancillary perl code was written by
Brent Chapman, <brent@GreatCircle.COM>. The latest version
of the code is available by anonymous FTP from
FTP.GreatCircle.COM, in directory pub/majordomo. This man
page was written by Jim Duncan, <jim@math.psu.edu>. Minimal
update of the man page by John Rouillard
<rouilj@cs.umb.edu>.
Sun Release 4.1 Last change: 4

View File

@@ -0,0 +1,184 @@
.TH resend 1
.SH NAME
resend \- resend messages after evaluation
.LP
.SH SYNOPSIS
.B resend
.B [\-A]
.B [\-C config-file]
.B [\-I file-list]
.B [\-M max-msg-length]
.B [\-R]
.B [\-a passwd]
.B [\-d]
.B [\-f from-addr]
.B [\-h host-name]
.B \-l list-name
.B [\-n]
.B [\-p precedence]
.B [\-r reply-to]
.B [\-s]
.B destination
.LP
.SH AVAILABILITY
Provided with distributions of Majordomo.
.LP
.SH DESCRIPTION
.B resend
is a perl script that is usually used to redirect mail messages to
a mailing list after evaluating and parsing the headers. Mail is
"resent" by handing it off to the mailer again with an alternate
destination as specified by the final operand.
.LP
Any message that
.B resend
doesn't like is sent to the list owner (the
"-f" address, or "<list-name>-owner" if -f isn't used) along with a
comment indicating what "resend" didn't like about it. To go ahead
and send the message, just feed it to resend without the flag that
caused it to reject it (in other words, if it rejected it because it
was too long, omit the "-M <>" flag; if it rejected it because it was
administrivia, omit the "-s" flag).
.LP
If you specify "-a <passwd>" flag, this "approval" password can be
used in an "Approved: <passwd>" line to override most of the other
checks (those enabled by "-s", "-M", and so forth). The "Approved:
<passwd>" line can either be one of the mail headers, or the first
line of the body of the message. If it is in the headers, the rest
of the headers are resent as part of the approved message. If it is
in the body, the current headers are discarded in favor of the headers
from the original message which should follow the "Approved:" line in
the body.
.LP
The owner of a mailing list can thus post messages that were initially
bounced by adding an "Approved: <passwd>" line and resubmitting the
message. Any "Approved: <passwd>" line is stripped before the message
is sent to the mailing list, so that list members won't learn the
password. If the <passwd> argument to the "-a" flag begins with a "/",
it is assumed to be a file name from which the actual password is read.
.LP
You can make a list "moderated" by specifying the "-A" flag. If the
"-A" flag is set, then any messages not containing a valid "Approved:"
line are sent to the list owner, rather than the whole list.; the
list owner can then review the message, add an appropriate "Approved:"
line, and resubmit them (these last two steps can be done easily with
the "approve" command that comes with Majordomo). If you specify
the "-A" flag, you must also specify the "-a <passwd>" flag, so that
resend knows what approval password to use.
.LP
If you only want to accept messages from members of a list, you can
use the "-I <file-list>" flag to do this. "<file-list>" should be a
colon-separated list of files in the $listdir directory (specified in
the config file) that "resend" will check the address in "From:" line
of a message against. If the address doesn't show up in one of those
files, and the message doesn't have a valid "approved" header on it,
it will be bounced to the list owner.
.LP
.SH OPTIONS
The following options can be used with resend:
.LP
.TP 10
.B \-A
Approve; enable list moderation by requiring an Approved: header to be
present in the message before resending. Messages without an Approved:
header will be redirected to the list owner for approval.
.TP
.B \-C config-file
Alternate configuration file; tell resend to use the file
.TP
.B config-file
instead of the default list-name.config.
.TP
.B \-I file-list
Include; ensure that the message sender (as represented in the From:
line of the incoming message) is in one of the file(s) specified in
.BR file-list .
.B file-list
may contain multiple colon separated pathnames. Each pathname should
point to a file that contains a sendmail-style mailing list.
.TP
.B [\-M max-msg-length]
Maximum; Specify the maximum length of the relayed message in octets.
.TP
.B [\-R]
Delete the "Received:" lines in the incoming message header. This can
make the relayed messages considerably shorter at the expense of
losing some potentially interesting debugging information.
.TP
.B [\-a passwd_file]
Specify the pathname of the file containing the approval password for
the list. This password is used to check Approved: headers when
relaying messages to lists that are marked as moderated through the
.B \-A
option above.
.TP
.B [\-d]
Debug; print what would be done, but don't do it.
.TP
.B [\-f from-addr]
Set the From: address to
.B from-addr
.TP
.B [\-h host-name]
Set the name of the local host to
.BR host-name .
This name will be used in the From: and To: lines when updating the
headers.
.TP
.B \-l list-name
Specify the name of the mailing list as
.BR list-name .
This option is required, as
.B resend
uses this name to derive the names
of many other files.
.TP
.B [\-n]
Assign a sequence number to each message as it comes through. The next
sequence number is stored in the file lists/list-name.seq. If the
string $SEQNUM is found in the $subject-prefix configuration variable,
it is replaced with the current sequence number. Thus, a
$subject_prefix of "($LIST $SEQNUM)" would render a Subject: line of
(list-name sequence-number).
.TP
.B [\-p precedence]
Set the Precedence: header to
.BR precedence .
.TP
.B [\-r reply-to]
Set the Reply-To: header to
.BR reply-to .
.TP
.B [\-s]
Administrivia; Search the message for strings commonly found in
administrative messages send to majordomo mailing lists (e.g.
subscribe, unsubscribe). If these are found in the first 10 or so
lines of the message, the message will be relayed to the list owner
instead of being sent on to the mailing list.
.SH OPERANDS
.TP 10
.B destination
The alias to which to redirect the message if it is a proper list
submission.
.LP
.SH CONFIGURATION
.LP
.SH FILES
.PD 0
.TP 20
.B /etc/aliases
.TP
.B /etc/majordomo.cf
.TP
.B lists/list-name.config
.PD
.LP
.SH SEE ALSO
.B majordomo(8),approve(1)
.LP
.SH AUTHOR
Majordomo and most of the ancillary perl code was written by
Brent Chapman <brent@GreatCircle.COM>.
Majordomo is available via anonymous FTP
from FTP.GreatCircle.COM, in the directory pub/majordomo. This
man page was written by Shane McCarron <ahby@themacs.com>.

View File

@@ -0,0 +1,264 @@
rrrreeeesssseeeennnndddd((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV rrrreeeesssseeeennnndddd((((1111))))
NNNNAAAAMMMMEEEE
resend - resend messages after evaluation
SSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
rrrreeeesssseeeennnndddd [[[[----AAAA]]]] [[[[----CCCC ccccoooonnnnffffiiiigggg----ffffiiiilllleeee]]]] [[[[----IIII ffffiiiilllleeee----lllliiiisssstttt]]]] [[[[----MMMM mmmmaaaaxxxx----mmmmssssgggg----
lllleeeennnnggggtttthhhh]]]] [[[[----RRRR]]]] [[[[----aaaa ppppaaaasssssssswwwwdddd]]]] [[[[----dddd]]]] [[[[----ffff ffffrrrroooommmm----aaaaddddddddrrrr]]]] [[[[----hhhh hhhhoooosssstttt----nnnnaaaammmmeeee]]]]
----llll lllliiiisssstttt----nnnnaaaammmmeeee [[[[----nnnn]]]] [[[[----pppp pppprrrreeeecccceeeeddddeeeennnncccceeee]]]] [[[[----rrrr rrrreeeeppppllllyyyy----ttttoooo]]]] [[[[----ssss]]]]
ddddeeeessssttttiiiinnnnaaaattttiiiioooonnnn
AAAAVVVVAAAAIIIILLLLAAAABBBBIIIILLLLIIIITTTTYYYY
Provided with distributions of Majordomo.
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
rrrreeeesssseeeennnndddd is a perl script that is usually used to redirect
mail messages to a mailing list after evaluating and parsing
the headers. Mail is "resent" by handing it off to the
mailer again with an alternate destination as specified by
the final operand.
Any message that rrrreeeesssseeeennnndddd doesn't like is sent to the list
owner (the "-f" address, or "<list-name>-owner" if -f isn't
used) along with a comment indicating what "resend" didn't
like about it. To go ahead and send the message, just feed
it to resend without the flag that caused it to reject it
(in other words, if it rejected it because it was too long,
omit the "-M <>" flag; if it rejected it because it was
administrivia, omit the "-s" flag).
If you specify "-a <passwd>" flag, this "approval" password
can be used in an "Approved: <passwd>" line to override most
of the other checks (those enabled by "-s", "-M", and so
forth). The "Approved: <passwd>" line can either be one of
the mail headers, or the first line of the body of the
message. If it is in the headers, the rest of the headers
are resent as part of the approved message. If it is in the
body, the current headers are discarded in favor of the
headers from the original message which should follow the
"Approved:" line in the body.
The owner of a mailing list can thus post messages that were
initially bounced by adding an "Approved: <passwd>" line and
resubmitting the message. Any "Approved: <passwd>" line is
stripped before the message is sent to the mailing list, so
that list members won't learn the password. If the <passwd>
argument to the "-a" flag begins with a "/", it is assumed
to be a file name from which the actual password is read.
You can make a list "moderated" by specifying the "-A" flag.
If the "-A" flag is set, then any messages not containing a
valid "Approved:" line are sent to the list owner, rather
than the whole list.; the list owner can then review the
message, add an appropriate "Approved:" line, and resubmit
Page 1 (printed 12/10/96)
rrrreeeesssseeeennnndddd((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV rrrreeeesssseeeennnndddd((((1111))))
them (these last two steps can be done easily with the
"approve" command that comes with Majordomo). If you
specify the "-A" flag, you must also specify the "-a
<passwd>" flag, so that resend knows what approval password
to use.
If you only want to accept messages from members of a list,
you can use the "-I <file-list>" flag to do this. "<file-
list>" should be a colon-separated list of files in the
$listdir directory (specified in the config file) that
"resend" will check the address in "From:" line of a message
against. If the address doesn't show up in one of those
files, and the message doesn't have a valid "approved"
header on it, it will be bounced to the list owner.
OOOOPPPPTTTTIIIIOOOONNNNSSSS
The following options can be used with resend:
----AAAA Approve; enable list moderation by requiring an
Approved: header to be present in the message
before resending. Messages without an Approved:
header will be redirected to the list owner for
approval.
----CCCC ccccoooonnnnffffiiiigggg----ffffiiiilllleeee
Alternate configuration file; tell resend to use
the file
ccccoooonnnnffffiiiigggg----ffffiiiilllleeee
instead of the default list-name.config.
----IIII ffffiiiilllleeee----lllliiiisssstttt
Include; ensure that the message sender (as
represented in the From: line of the incoming
message) is in one of the file(s) specified in
ffffiiiilllleeee----lllliiiisssstttt. ffffiiiilllleeee----lllliiiisssstttt may contain multiple colon
separated pathnames. Each pathname should point to
a file that contains a sendmail-style mailing
list.
[[[[----MMMM mmmmaaaaxxxx----mmmmssssgggg----lllleeeennnnggggtttthhhh]]]]
Maximum; Specify the maximum length of the relayed
message in octets.
[[[[----RRRR]]]] Delete the "Received:" lines in the incoming
message header. This can make the relayed messages
considerably shorter at the expense of losing some
potentially interesting debugging information.
[[[[----aaaa ppppaaaasssssssswwwwdddd____ffffiiiilllleeee]]]]
Specify the pathname of the file containing the
approval password for the list. This password is
Page 2 (printed 12/10/96)
rrrreeeesssseeeennnndddd((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV rrrreeeesssseeeennnndddd((((1111))))
used to check Approved: headers when relaying
messages to lists that are marked as moderated
through the ----AAAA option above.
[[[[----dddd]]]] Debug; print what would be done, but don't do it.
[[[[----ffff ffffrrrroooommmm----aaaaddddddddrrrr]]]]
Set the From: address to ffffrrrroooommmm----aaaaddddddddrrrr
[[[[----hhhh hhhhoooosssstttt----nnnnaaaammmmeeee]]]]
Set the name of the local host to hhhhoooosssstttt----nnnnaaaammmmeeee. This
name will be used in the From: and To: lines when
updating the headers.
----llll lllliiiisssstttt----nnnnaaaammmmeeee
Specify the name of the mailing list as lllliiiisssstttt----nnnnaaaammmmeeee.
This option is required, as rrrreeeesssseeeennnndddd uses this name
to derive the names of many other files.
[[[[----nnnn]]]] Assign a sequence number to each message as it
comes through. The next sequence number is stored
in the file lists/list-name.seq. If the string
$SEQNUM is found in the $subject-prefix
configuration variable, it is replaced with the
current sequence number. Thus, a $subject_prefix
of "($LIST $SEQNUM)" would render a Subject: line
of (list-name sequence-number).
[[[[----pppp pppprrrreeeecccceeeeddddeeeennnncccceeee]]]]
Set the Precedence: header to pppprrrreeeecccceeeeddddeeeennnncccceeee.
[[[[----rrrr rrrreeeeppppllllyyyy----ttttoooo]]]]
Set the Reply-To: header to rrrreeeeppppllllyyyy----ttttoooo.
[[[[----ssss]]]] Administrivia; Search the message for strings
commonly found in administrative messages send to
majordomo mailing lists (e.g. subscribe,
unsubscribe). If these are found in the first 10
or so lines of the message, the message will be
relayed to the list owner instead of being sent on
to the mailing list.
OOOOPPPPEEEERRRRAAAANNNNDDDDSSSS
ddddeeeessssttttiiiinnnnaaaattttiiiioooonnnn
The alias to which to redirect the message if it
is a proper list submission.
CCCCOOOONNNNFFFFIIIIGGGGUUUURRRRAAAATTTTIIIIOOOONNNN
FFFFIIIILLLLEEEESSSS
////eeeettttcccc////aaaalllliiiiaaaasssseeeessss
////eeeettttcccc////mmmmaaaajjjjoooorrrrddddoooommmmoooo....ccccffff
lllliiiissssttttssss////lllliiiisssstttt----nnnnaaaammmmeeee....ccccoooonnnnffffiiiigggg
Page 3 (printed 12/10/96)
rrrreeeesssseeeennnndddd((((1111)))) UUUUNNNNIIIIXXXX SSSSyyyysssstttteeeemmmm VVVV rrrreeeesssseeeennnndddd((((1111))))
SSSSEEEEEEEE AAAALLLLSSSSOOOO
mmmmaaaajjjjoooorrrrddddoooommmmoooo((((8888)))),,,,aaaapppppppprrrroooovvvveeee((((1111))))
AAAAUUUUTTTTHHHHOOOORRRR
Majordomo and most of the ancillary perl code was written by
Brent Chapman <brent@GreatCircle.COM>. Majordomo is
available via anonymous FTP from FTP.GreatCircle.COM, in the
directory pub/majordomo. This man page was written by Shane
McCarron <ahby@themacs.com>.
Page 4 (printed 12/10/96)

View File

@@ -0,0 +1,105 @@
QUICK DIGEST SETUP:
For the purpose of example, let's say that you have a majordomo list
called "banjo" and that you want to create "banjo-digest".
1. You need to create two directories: the digest's work directory
and the digest's archive directory. They CAN'T be the same directory.
Where should these directories be created? Look in your majordomo.cf
file to see how these three variables are defined: $digest_work_dir,
$filedir, $filedir_suffix. Let's say they look like this:
$digest_work_dir = "/usr/local/mail/digest";
$filedir = "/usr/local/mail/files";
$filedir_suffix = ".archive";
That being the case, you must create these two directories:
/usr/local/mail/digest/banjo-digest
/usr/local/mail/files/banjo-digest.archive
The first is the work directory, the second is the archive directory.
Make sure that majordomo has write permission on both directories.
2. You must create a majordomo list called "banjo-digest".
In most respects it is just like any ordinary list, but when you
set up the configuration file (banjo-digest.config), you will
have to configure these parameters:
digest_issue = 1
digest_name = Banjo Digest
digest_volume = 1
digest_maxdays =
digest_maxlines =
maxlength = 40000
message_footer << END
END
message_fronter << END
END
Remember that these variables are in banjo-digest.config, NOT banjo.config.
Also, do NOT touch the variables digest_archive, digest_rm_header, etc.
Both digest_issue and digest_number should start at 1 unless you have
some special reason to do otherwise. The digest name should be an
obvious choice, but don't make it longer than 24 characters.
"maxlength" is the maximum size in characters (bytes) for a digest.
"digest_maxlines" is the maximum number of lines in a digest.
"digest_maxdays" is the maximum age in days of an article in a digest.
The last two parameters are optional, but maxlength must be defined.
A digest will automatically be created if any one of the three limits
is exceeded.
You can put this sort of material in the header or footer:
message_fronter << END
In this issue:
-
- _SUBJECTS_
-
See the end of the digest for information about banjo-digest.
END
Note that you need to indicate blank lines by placing a '-'
character at the beginning of the line. You also indicate
whitespace at the beginning of a line by putting a '-' in
front of the whitespace.
The _SUBJECTS_ token will be expanded to all of the subject lines
of the messages in the digest, one subject per line.
3. Create some aliases.
You need to add to the banjo-outgoing alias:
banjo-outgoing: :include:/path/to/lists/banjo, banjo-digestify
and then you need the banjo-digest aliases:
banjo-digestify: "|/path/to/wrapper digest -r -C -l banjo-digest banjo-digest-outgoing"
banjo-digest: banjo
banjo-digest-outgoing: :include:/path/to/lists/banjo-digest
owner-banjo-digest-outgoing: harry
banjo-digest-approval: harry
4. Add a cron job.
If you want digests to be created at regular intervals, put this
line in your cron table:
echo mkdigest banjo-digest pluck | mail majordomo@mj.server.com
("pluck" is the digest's password).
5. Test it!

View File

@@ -0,0 +1,229 @@
_ _ ____ _ ____ ____ ___ ____ _ _ ____
|\/| |__| | | | |__/ | \ | | |\/| | |
| | | | _| |__| | \ |__/ |__| | | |__|
Release 1.94
FUTURE
--------------------------------------------------------------------------
* Where is Majordomo headed?
----------------------------
In it's current release, 1.94, Majordomo is a stable, yet tangled,
collection of code. As the README says...
Along the way, it has picked up many features and additions
from various authors. Because of this, and due to the initial
design of Majordomo, certain features (archiving, digesting,
and moderated lists) are currently done in a "non-optimum"
fashion. In short, configuring Majordomo to do some of the
advanced features can be confusing. This is a known problem
and is being worked on.
Perhaps it would be enlightening to start with a vision of what
Majordomo should look like in the future, and then expand on the
vision.
1) Interaction with Majordomo should be easier; for the list user,
the list owner, and the Majordomo owner. This means an
integrated Web interface, as well as a better mail interface.
2) Existing facilities should be integrated better. Archiving and
digesting need integration.
3) Access to Majordomo functions and lists should be extensively
configurable, assignable, and easy to control.
4) Improvements to adequately handle large lists, and large numbers
of lists.
5) Majordomo "plugins", configurable down to a per-list basis.
Hooks for pre & post operations to commands. (ie, substitute a
different method of access checking for certain lists.)
6) Reduce, if possible, the morass of aliases needed for a large
Majordomo installation.
7) Consider the potential of integrating bulkmailer, TLB, or another
delivery agent into MD for large lists.
Now, how are we going to get from here to there? That's the tough
question.
The first step is to require perl5. This gives us heaps of good
stuff, and will potentially greatly reduce the tangle of current
code.
Next, abstract, define, and API-ize the core bits. This is where the
hooks to allow custom routines would come in, as well as allowing
drop-in plugins. Archiving and digesting are perfect examples of
this; these are basically post and pre sending operations.
API-izing things basically enables all the rest to be done easily and
coherently, allowing for the seperate development of some quite useful
features:
o using a DBM database, or perl5 file-struct for all list
configs.
o well-integrated pluggable web interface
o a queue mechanism for busy servers.
o fine-grained access control
o customized address matching
o post and pre Majordomo, List, and Command hooks
o subscriber level features, such as digesting and encryption.
Some other ideas that come from brainstorming a bit on the MD vision:
o Group Lists: Define a collection of lists, and manage them
the same way, with the same owners. A 'leader list' would
have 'leader variables' that the other lists 'follow'.
o From a different viewpoint, Group Lists is simply ownership
delegation. Put Majordomo-owner at the top:
Mojo Hierarchy
--------------
Mojo God: All lists
|
Group God: Some lists or commands
|
Command God: Some commands
|
List God: One list
|
Variable God: Some variables
o Command queuing: Either plain, ala sendmail, or 'alarm
clocking' -- queue commands, then process when the requests
stop for a certain period. Or perhaps...
o Majordomo Server. Likely run from inetd, this would be an
interesting way of solving the startup overhead.
Now, will all these happen at once? No, not unless someone spends
some development money. What's far more likely is an incremental
change, creaping up to a fabled Majordomo 2.0 knows all, sees all.
Broken down into manageable chunks, I see the following rough order
happening:
Perl5. APIs, abstraction, and definition of the 'interface
layer' to Majordomo. Perl5 modules replacing bits of
majordomo, and conversion of internal functions to the API.
Hook implementation. Web interface. Integration of archiving,
digesting. Group Lists, ownership delegation. Access lists.
Plugins. Database backend for lists, subscribers. Custom
operators. Backend delivery support.
Now, by all means, this isn't a complete list. Rather, it's a
compilation of the various ideas that have floated around the
majordomo-workers list and the majordomo developers.
What is greatly desired is to have the necessary core bits to allow
development of other features to happen in parallel. This could
follow the perl5 module design, with signup of projects to interested
parties.
Below here is Section 5 of the old README file (1.92), kept as a
placeholder for known bugs as well as random ideas.
----------------------------------------------------------------------
The next major planned release will be majordomo 2.0. The
specification document has been written for it, and is is in the
process of being written. The intent with 2.0 is to have a defined
programmers interface that allows people to develop portable modules
that can be added into majordomo to provide additional
functionality. If you think of majordomo as a stripped down car, and
the addin modules as extra options that you can "buy", then you have
the right idea. Majordomo 1.9x is being released to test the config
file code, and because some of the resend and majordomo features seem
to be needed by people on the majordomo-users list.
Before the next planned release, there may be other releases in the
1.9x series as bugs are found, and as additional functionality that is
currently hinted at in the config file is added.
5.1.1 Bugs/Misfeatures/Todo
The following is a list of things that I want to address at some
point. The items marked with a * imply that patches to implement the
feature have been written, but it is too late in this cycle to apply
the patch and test it. Hopefully some of these items will be fixed
in later versions of majordomo 1.9x.
1) Resend only recognizes an Approved: header as the first line in the body.
The approved header should be recognized if it is the first non-blank
line in the body. [[[ fixed in 1.94 ]]]
2)* Resend should have a separate moderater address to bounce email to
3) Multiple privacy levels have to be provided. yes, no, password protected
4) The number of reported hits from which should be tunable
5) approve has to be extended to handle almost all commands
6) new-list should be part of resend
7)* wrapper.c should use sysexits.h for its error codes
[[[ fixed in 1.94 ]]]
8) auto lists should prevent the list from being subscribed to itself
9)* auto lists should make sure that listserv style addresses aren't used
[[[ fixed in 1.94 ]]]
10) provide the ability to smash case of all incoming addresses under
majordomo administrator control.
11) ability to specify banned users whose posts are ignored.
[[[ fixed in 1.94 with taboo_headers ]]]
12) rework the advertise/noadvertise interface
13) Look at supporting #included/#exploder lists for mail sublists.
14) set up reply to be smart enough to break mail loops
(using received: headers)
15) should -h not be required by resend, or should resend_host keyword go
away?
16) config should return the input file if there is an error.
17) digest needs to strip headers and footers from list info. Maybe there
should be a back channel out of resend that doesn't do any
body massaging.
18) have resend/majordomo check to see if the last Received: line is a
right hand sub/super string of the user's from address.
19) fix help messages to remove syntax diagram info to stop address
subscriptions like: subscribe list [user@site]
20)* Support auto digest creation based on number of lines, and age.
21) Have resend log messages as it sends them through. Can be used to
prevent mail loops as well as provide stats for later use.
22) analyze code to make sure all areas that require locks are in place
23) detect error condition (e.g. out of disk space) and deal with them better
[[[ fixed in 1.94 ]]]
24) add code to support incremental config file changes.
25) add ability to add arbitrary headers to message and check that the
headers are in the proper form.
26) add the ability to do load limiting of majordomo commands
27) RCPT messages shouldn't be bounced as administrivia. They should be
in a different class, and should be user settable.
28) digest always needs to have its archive directory present. Digest
should be rewritten to place its outgoing digest into the
incoming directory, and it should use archive to do archiving if
need be.

View File

@@ -0,0 +1,187 @@
_ _ ____ _ ____ ____ ___ ____ _ _ ____
|\/| |__| | | | |__/ | \ | | |\/| | |
| | | | _| |__| | \ |__/ |__| | | |__|
Release 1.94.5
INSTALL
--------------------------------------------------------------------------
-> Current users of Majordomo whom are upgrading will want to <--
-> read the NEWS and Changelog for details on what has changed <--
-> between versions of Majordomo. <--
--------------------------------------------------------------------------
** SECURITY ALERT **
The default installation of Majordomo, including the checks that
config-test does, WILL NOT RESULT IN A SECURE INSTALLATION. In
particular, the majordomo home directory and the "wrapper" program
are, by default, accessible to any user. These open privileges can be
(mis)used to change list membership, list configuration details, forge
email, perhaps even create and/or delete lists, and anything else that
the majordomo user has permissions to do.
If Majordomo is *NOT* installed on a secured system with controlled
access (and if you are paranoid, even if it is), you will need to take
additional steps to prevent access to the majordomo directories.
Usually, changing the privileges of the majordomo home directory to be
0750 fixes these problems, but creates the additional burden of
needing to configure the MTA (sendmail, qmail, exim) properly so that
it can read and execute "wrapper". Such configuration is beyond the
scope of this install document, and is left to the FAQ (Doc/FAQ,
Doc/majordomo-faq.html) and the support group
majordomo-users@greatcircle.com to answer.
** SECURITY ALERT **
UPGRADING:
----------
If you're upgrading from a release before 1.94.4, you'll need to either do
a clean install or patch your 1.94.X to 1.94.4 using the patches found at
ftp://ftp.greatcircle.com/pub/majordomo. Then...
Folks upgrading from 1.94.4 to 1.94.5 have three options:
1) A clean install. See below.
2) Patch your _distribution_ of 1.94.4 to 1.94.5:
% cd distribution/majordomo-1.94.4
% patch < ...../patches/majordomo-1.94.5/1.94.4-to-1.94.5-patch
If there are no *.rej files, do a 'make install'. Otherwise, examine
each .rej file and merge the changes in by hand.
3) Patch your _installation_ of 1.94.4 to 1.94.5:
% cd /usr/majordomo (ie, where you've installed majordomo)
% patch < ....../majordomo-1.94.5/patches/1.94.4-to-1.94.5-installed-patch
If there are no *.rej files, you're done! Otherwise, examine
each .rej file and merge the changes in by hand.
--------------------------------------------------------------------------
Steps to do a clean installation of Majordomo:
1) Pick a group and user ID for Majordomo to run under. Usually this
is "majordomo.daemon". If you're this group, you can do all the
majordomo management functions (creating new lists, etc.) without
having to "su" to Majordomo. You can create and use a group other
id than "daemon" if you want, but if you do, that UID needs to
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 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 (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.
If this is a new install, copy sample.cf to majordomo.cf first.
This .cf file is "require"ed into majordomo, so it needs to be valid
Perl. Here are the important variables to set:
$whereami What machine am I on?
$whoami Who do users send requests to me as?
$whoami_owner Who is the owner of the above, for problems?
$homedir Where can I find my extra .pl files?
$listdir Where are the mailing lists?
$log Where do I write my log?
$sendmail_command Where the sendmail program resides.
$mailer What program and args do I use to send mail to the
lists?
$bounce_mailer What program and args do I use to send administrative
messages?
If this is an upgrade, examine sample.cf for new configuration
variables to place in your existing majordomo.cf. Alternately, running
config-test after the installation is complete will show all the
variables that are missing.
5) Do a 'make wrapper' to verify that the wrapper program compiles
cleanly.
6) Do a 'make install' to install the Majordomo programs. This must be
done either as root or as the Majordomo user in order to properly set
the ownership of the various files and directories.
7) Do a 'make install-wrapper' as root to install the wrapper. This must
be done as root because wrapper must be installed setuid and on POSIX
systems must be owned by root. The wrapper takes care to severely
restrict the programs which may be run by it and further restricts the
environment those programs run with.
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
"OA" line to /etc/sendmail.cf:
OA/path/to/majordomo/majordomo.aliases
If you use the M4 configuration system of recent sendmails, you can add
the following line to your .mc file to achieve the same effect:
define(`ALIAS_FILE',`/etc/aliases,/path/to/majordomo/majordomo.aliases')
Whichever method chosen, add the following aliases for Majordomo
itself:
majordomo: "|/path/to/majordomo/wrapper majordomo"
owner-majordomo: you,
majordomo-owner: you
Note the program name (majordomo) after wrapper must not be a full path
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:
% touch /path/to/majordomo/lists/test
% echo 'lists' | mail majordomo
If everything is working correctly, you should get a message back
from Majordomo, and not Mailer-Daemon.
11) Browse the Frequently Asked Questions (Doc/FAQ), it can answer
many questions that you might have.
That's it! To create new lists, read the NEWLIST file.

View File

@@ -0,0 +1,142 @@
MAJORDOMO LICENSE AGREEMENT
Version 1.1
18 May 96
Great Circle Associates (GCA) is the original developer of Majordomo,
a package for managing Internet mailing lists. Since its initial
release, many organizations and individuals have contributed
enhancements and fixes, but the original copyright has been retained
by Great Circle Associates.
Majordomo is distributed in source code form, with almost all
modules written in Perl (there is one small C program), and runs
on many UNIX platforms. Majordomo is not a supported product of
Great Circle Associates, but is made available for use on the following
basis.
GCA grants you a license as follows to the Majordomo package:
1. LICENSE. GCA grants you a non-exclusive, non-transferable
license for the Majordomo package ("Majordomo") and its associated
documentation, subject to all of the following terms and conditions.
In accepting a copy of Majordomo you agree to the following terms
and conditions.
This license permits you to use, copy, and modify Majordomo
solely for your organization's use.
2. LIMITATIONS ON LICENSE.
a. You may only use, copy, and modify Majordomo
as expressly provided for in this Agreement.
You must reproduce and include this Agreement, and
GCA's copyright notices on any copy and its
associated documentation.
b. No part of Majordomo may be incorporated into any
program or other product that is sold, or for which any
revenue is received without written permission of
Great Circle Associates, with the following exceptions:
You may install Majordomo at your site and run
mailing lists for other using it, and charge for
that service.
You may install Majordomo at other sites, and
charge for your time to install, configure,
customize, and manage it.
You may charge for enhancements you've made to
the Majordomo software, subject to the distribution
restrictions listed below.
You may not charge for the Majordomo software
itself.
A commercial license will be required in all other cases.
c. If Majordomo is being provided or configured for a
customer, the provider must clearly state in
documentation and bid/proposal materials that the
Majordomo technologies are licensed and provided
by Great Circle Associates, and a copy of this
license must be included with the configured
system.
d. Majordomo, if modified, must carry prominent notices
stating that changes have been made, and the dates of
any such changes.
You may publicly distribute an unmodified and
complete version of Majordomo, for instance as
part of a collection of free software packages,
but you must distribute the whole package, and
you must tell people where they can obtain the
latest version:
ftp://ftp.greatcircle.com/pub/majordomo/
You may not publicly distribute a modified or
incomplete version of Majordomo. You may make
such a version available to your own clients,
subject to the restrictions below, but not to the
general public (for instance, by placing it on an
anonymous FTP site).
You may not distribute (publicly or privately) a modified
version of Majordomo without clearly identifying it as such
(by changing the version string in majordomo_version.pl),
identifying the changes (through appropriate README
documentation and/or comments in the code),
identifying who will be responsible for supporting
the modified version, and informing people receiving
the modified version where they can find an
unmodified version:
ftp://ftp.greatcircle.com/pub/majordomo/
e. All rights not expressly granted herein are reserved to GCA.
3. NO GCA OBLIGATION: You are solely responsible for maintaining
your copy of Majordomo and the security of the operating environment in
which Majordomo may be used. You are solely responsible for all of your
costs and expenses incurred in connection with the distribution of Majordomo
or any Application Program hereunder, and GCA shall have no liability,
obligation or responsibility therefor. GCA shall have no obligation to
provide maintenance, support, upgrades, or new releases to you.
4. NO WARRANTY OF PERFORMANCE. Majordomo and its associated
documentation are licensed "as is" without warranty as to their
performance, merchantability, or fitness for any particular purpose.
The entire risk as to the results and performance of Majordomo is
assumed by you. Should Majordomo prove defective, you assume the
entire cost of all necessary servicing, repair, or correction.
5. LIMITATION OF LIABILITY. Neither GCA nor any other
person who has been involved in the creation, production or delivery
of Majordomo shall be liable to you or to any other person for any
direct, indirect, special, incidental, consequential, or punitive
damages, even if GCA has been advised of the possibility of such
damages.
6. TERM. The license granted hereunder is effective until
terminated. This license shall automatically terminate without notice
if you breach any of the provisions hereof. You may terminate it at
any time by destroying Majordomo and its associated documentation.
7. GENERAL.
a. This Agreement shall be governed by the laws of
the State of California.
b. Address all correspondence regarding this license
to GCA's electronic mail address
<majordomo-license@greatcircle.com>, or to
Great Circle Associates
1057 West Dana Street
Mountain View, CA 94041
USA
[ Note: the form of this license was derived, by permission, from the license
for the Firewalls Toolkit distributed by Trusted Information Systems, Inc. ]

View File

@@ -0,0 +1,237 @@
#$Modified: Tue Jan 18 14:58:24 2000 by cwilson $
#
# $Source: /sources/cvsrepos/majordomo/Makefile,v $
# $Revision: 1.64 $
# $Date: 2000/01/18 14:01:17 $
# $Header: /sources/cvsrepos/majordomo/Makefile,v 1.64 2000/01/18 14:01:17 cwilson Exp $
#
# This is the Makefile for Majordomo.
#
#------------- Configure these items ----------------#
#
# Put the location of your Perl binary here:
PERL = /usr/bin/perl
# What do you call your C compiler?
CC = cc
# Where do you want Majordomo to be installed? This CANNOT be the
# current directory (where you unpacked the distribution)
W_HOME = /etc/virtual/majordomo
# Where do you want man pages to be installed?
MAN = $(W_HOME)/man
# You need to have or create a user and group which majordomo will run as.
# Enter the numeric UID and GID (not their names!) here:
W_USER = 987
W_GROUP = 2
# These set the permissions for all installed files and executables (except
# the wrapper), respectively. Some sites may wish to make these more
# lenient, or more restrictive.
FILE_MODE = 644
EXEC_MODE = 755
HOME_MODE = 751
# If your system is POSIX (e.g. Sun Solaris, SGI Irix 5 and 6, Dec Ultrix MIPS,
# BSDI or other 4.4-based BSD, Linux) use the following four lines. Do not
# change these values!
WRAPPER_OWNER = root
WRAPPER_GROUP = $(W_GROUP)
WRAPPER_MODE = 4755
POSIX = -DPOSIX_UID=$(W_USER) -DPOSIX_GID=$(W_GROUP)
# Otherwise, if your system is NOT POSIX (e.g. SunOS 4.x, SGI Irix 4,
# HP DomainOS) then comment out the above four lines and uncomment
# the following four lines.
# WRAPPER_OWNER = $(W_USER)
# WRAPPER_GROUP = $(W_GROUP)
# WRAPPER_MODE = 6755
# POSIX =
# Define this if the majordomo programs should *also* be run in the same
# group as your MTA, usually sendmail. This is rarely needed, but some
# MTAs require certain group memberships before allowing the message sender
# to be set arbitrarily.
# MAIL_GID = numeric_gid_of_MTA
# This is the environment that (along with LOGNAME and USER inherited from the
# parent process, and without the leading "W_" in the variable names) gets
# passed to processes run by "wrapper"
W_SHELL = /bin/sh
W_PATH = /bin:/usr/bin:/usr/ucb
W_MAJORDOMO_CF = $(W_HOME)/majordomo.cf
# A directory for temp files..
TMPDIR = /tmp
#--------YOU SHOULDN'T HAVE TO CHANGE ANYTHING BELOW THIS LINE.-------------
VERSION = 1.94.5
# For those stupid machines that try to use csh. Doh!
SHELL = /bin/sh
WRAPPER_FLAGS = -DBIN=\"$(W_HOME)\" -DPATH=\"PATH=$(W_PATH)\" \
-DHOME=\"HOME=$(W_HOME)\" -DSHELL=\"SHELL=$(W_SHELL)\" \
-DMAJORDOMO_CF=\"MAJORDOMO_CF=$(W_MAJORDOMO_CF)\" \
$(POSIX)
INSTALL = ./install.sh
TMP = $(TMPDIR)/mj-install-$(VERSION)
TOOLS = archive.pl archive_mh.pl \
digest.send makeindex.pl \
logsummary.pl new-list sequencer
BINBIN = approve bounce medit
BIN = bounce-remind config_parse.pl majordomo majordomo.pl \
majordomo_version.pl request-answer resend \
shlock.pl config-test archive2.pl digest
INSTALL_FLAGS = -O $(W_USER) -g $(W_GROUP)
default:
@echo "make what?"
@echo " install: installs everything."
@echo " install-wrapper: only install wrapper."
@echo " install-scripts: only install the scripts."
@echo " wrapper: only make wrapper."
install: wrapper install-scripts install-cf install-man
@echo ""
@echo "To finish the installation, 'su' to root and type:"
@echo ""
@echo " make install-wrapper"
@echo ""
@echo "If not installing the wrapper, type"
@echo ""
@echo " cd $(W_HOME); ./wrapper config-test"
@echo ""
@echo "(no 'su' necessary) to verify the installation."
install-wrapper: wrapper
$(INSTALL) -o $(WRAPPER_OWNER) -g $(WRAPPER_GROUP) \
-m $(WRAPPER_MODE) wrapper $(W_HOME)/wrapper
@echo ""
@echo "To verify that all the permissions and etc are correct,"
@echo "run the command"
@echo ""
@echo " cd $(W_HOME); ./wrapper config-test"
# fix where perl lives.
# Create a tmp directory to stuff all the files in, so we
# don't go blithly changing the master copies of stuff.
#
config-scripts:
@echo "Testing for perl ($(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..."
@for file in $(TOOLS); do \
cp contrib/$$file $(TMP) ; \
done
@cp $(BINBIN) $(BIN) $(TMP)
@cd $(TMP); $(PERL) -p -i -e 's@^#!\S+perl.*@#!$(PERL)@' $(TOOLS) $(BINBIN) $(BIN)
install-scripts: config-scripts
$(INSTALL) -m $(HOME_MODE) $(INSTALL_FLAGS) . $(W_HOME)
$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) . $(W_HOME)/bin
@echo "Copying tools to $(W_HOME)/bin"
@for file in $(BINBIN); do \
$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
$(TMP)/$$file $(W_HOME)/bin/$$file; \
done
@echo "Copying Majordomo files to $(W_HOME)"
@for file in $(BIN); do \
$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
$(TMP)/$$file $(W_HOME)/$$file; \
done
@echo "Copying archiving and other tools to $(W_HOME)/Tools"
$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) . $(W_HOME)/Tools
@for file in $(TOOLS); do \
$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
$(TMP)/$$file $(W_HOME)/Tools/$$file; \
done
@rm -rf $(TMP)
# the install.cf target will install the sample config file in the proper
# place unless a majordomo.cf file exists, in which case the majordomo.cf
# file will be used. It won't overwrite an existing majordomo.cf file. In
# all cases, the sample.cf file must be installed so that config-test will
# be able to check for new variables.
install-cf:
@if [ ! -f $(W_HOME)/majordomo.cf ]; \
then \
if [ -f majordomo.cf ]; \
then \
echo "Using majordomo.cf"; \
$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
majordomo.cf $(W_HOME)/majordomo.cf; \
else \
echo "Using sample.cf"; \
$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
sample.cf $(W_HOME)/majordomo.cf; \
fi; \
else \
echo "Using installed majordomo.cf"; \
fi;
@$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
sample.cf $(W_HOME)
install-man:
@echo "Installing manual pages in $(MAN)"
@$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
. $(MAN)
@$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
. $(MAN)/man1
@$(INSTALL) -m $(EXEC_MODE) $(INSTALL_FLAGS) \
. $(MAN)/man8
@$(INSTALL) -m $(FILE_MODE) $(INSTALL_FLAGS) \
Doc/man/approve.1 $(MAN)/man1/approve.1
@$(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
@$(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
clean:
rm -f wrapper *~
dist-clean: clean
rm -f majordomo.cf .cvsignore todo.local .dcl archive
rm -rf regress Doc/samples Tools
distribution: dist-clean
mkdir majordomo-$(VERSION)
mv * .??* majordomo-$(VERSION) || exit 0
rm -rf majordomo-$(VERSION)/CVS majordomo-$(VERSION)/*/CVS \
majordomo-$(VERSION)/*/*/CVS
tar -cvf majordomo-$(VERSION).tar.Z\
majordomo-$(VERSION)

View File

@@ -0,0 +1,138 @@
_ _ ____ _ ____ ____ ___ ____ _ _ ____
|\/| |__| | | | |__/ | \ | | |\/| | |
| | | | _| |__| | \ |__/ |__| | | |__|
Release 1.94.4
NEWLIST
--------------------------------------------------------------------------
List names must be of the form "[a-z0-9_-]+" (in other words, letters,
digits, underbars, or dashes only). List may be of mixed or upper
case, but all references to the list name below must be specified
in lower case EXCEPT for the -l arguments of resend and majordomo.
To create a list:
1) Create an empty file called <list-name> in $listdir, mode 664.
2) Create a file called "<list-name>.info" in $listdir, mode 664, with
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 separate majordomo.aliases file.)
Each list requires several aliases. For an example list called
'test', these aliases are required:
test The list alias itself
owner-test The owner of the list (who should get bounces)
test-request The address for administrative requests.
test-approval The person who approves postings to the list
(for moderated lists as well as unmoderated ones)
These would look like this:
test: :include:/usr/test/majordomo-1.94.3/lists/test
owner-test: you,
test-request: "|/usr/test/majordomo-1.94.3/wrapper request-answer test"
test-approval: you
It's more likely that the outgoing messages to the list will be
passed through "resend" to catch Majordomo commands, as well as
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.3/wrapper resend -l test test-list"
test-list: :include:/usr/test/majordomo-1.94.3/lists/test
owner-test: you,
test-owner: you
test-request: "|/usr/test/majordomo-1.94.3/wrapper majordomo -l test"
Finally, a more complete set of aliases that provides digestification,
archiving, and header manipulation would look like:
test:"|/tools/majordomo/wrapper resend -l test -h cs.umb.edu test-outgoing"
test-digest:test
# I put the digest and archive programs on the outgoing list so that
# messages bounced by resend don't end up in the digest or archive
# unless I send them through resend explicitly.
test-outgoing: :include:/usr/local/Lists/test,
"| /tools/majordomo/wrapper digest -r -C -l test-digest test-digest-outgoing",
"| /tools/majordomo/wrapper archive2.pl -a -m
-f /usr/local/mail/archive/test/test.archive"
# archive produces a monthly archive with the -m flag.
test-digest-outgoing::include:/usr/local/Lists/test-digest
owner-test:you,
owner-test-outgoing:owner-test
# note that the "-digest" and "-digest-outgoing" suffixes
# are required to allow the majordomo mkdigest command, and the
# config code to work properly.
owner-test-digest:owner-test
owner-test-digest-outgoing:owner-test
test-request: "|/tools/majordomo/wrapper request-answer test"
test-digest-request: "|/tools/majordomo/wrapper request-answer test-digest"
test-approval:you,
test-digest-approval:test-approval
As you can see, setting up a list can be quite complex.
You can run majordomo at the -request address (recommended), and it will
handle requests such as:
subscribe
unsubscribe
signoff
without requiring the user to supply a list name. To do this set up an
alias similar to:
test-request: "|/tools/majordomo/wrapper majordomo -l test"
Where the argument to -l is the name of the list.
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.
***** NOTE: CONVERTING FROM A PREVIOUS MAJORDOMO VERSION *****
For those who are converting from an earlier version of
majordomo, note that resend has very few command line
arguments. If you don't strip the command line arguments from resend,
the comments in the configuration file that deal with default
values for resend will be incorrect.
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) If the list will be archived, create an archive directory in the
location specified by the $filedir and $filedir_suffix variables.
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
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
a description, and send it back with the 'newconfig' command.
Now send a test subscribe and unsubscribe, just to further verify that
the list is working.

View File

@@ -0,0 +1,148 @@
Changes from 1.94.4 to 1.94.5
A straightforward patch release, 99% from the collected
1.94.4 patches:
o digest_rm_fronter and digest_rm_footer now work.
o unsubcribe_policy now has +confirm feature
o More hostile address checking
o archive2.pl makes archives world readable.
o bounce had an innocuous y2k bug, and wanted a 'bounces' list password even
when called as unsub
o better description of the moderator function.
o Fixes 'restrict_post = #!$list' substitution and blank lines
in config files
o Better error reporting when majordomo.cf is wrong.
o Detects some attachments sent as commands
o Approve commands can span lines now.
o resend has better messages for taboo_headers problems
o fixed: header corruption when Subject: is blank and subject tags are used.
=========================================================================================
archive2.pl.0 () Ensures archives are world readable.
bounce.0 () Bounce script and unsub.
config_parse.pl.1 () Another trivial 1.94.4 patch: moderator
config_parse.pl.2 (B) Fixes 'restrict_post = #!$list' substitution
config_parse.pl.5 (F) Fixes failing to accept newconfig... (cleaned)
config_parse.pl.6 (B) Fixes bug when several consecutive blank lines
or a trailing blank line appear in a string array
digest-config_parse.pl.1 (F) Adds the functionality promised by digest_rm_fronter
majordomo-config.1 (F) +config patches for unsubscribe_policy
majordomo.0b (B+) Fixes some error messages and minor bugs related to
aliasing <listname>-request to invoking majordomo with -l
majordomo.1 (F) PATCH: no attachments (was Re: Strange stuff)
majordomo.3 () A minor little patch that cleans up newinfo/newintro
majordomo.6 (F) Patch for APPROVE linewraps
majordomo.7 () Work-around for Perl 5.005 problem
majordomo.pl.1 (S+) Fixes security hole with :include:syslog (untested)
request-answer.0 () Request-answer should not reply to mailer-daemon et al
resend.2 (F) A nice patch for debugging taboo_headers
resend.5 (B++) Fixes header corruption when Subject: is
blank and subject tags are used
resend.8 () More headers for the skip headers string
resend_parse.1 () Corrected PATCH: moderator behavior
Changes from 1.94.3 to 1.94.4
o Security fix for advertise/noadvertise eval hole.
o Security fix for wrapper env overrun
o Fixed race condition in unsubscribing, config lock not being freed,
EOF tests fail due to bad assumptions
o mungedomain wasn't working properly
o fixes to commented-out sample.cf code.
o archive2.pl now has -D -M -Y arguments for 4 digit years.
o added "welcome" and "announcments" keywords.
o Digest fixes for -C
Changes from 1.94.2 to 1.94.3:
o removed wrapper since it snuck into the tarball
o fixed medit.
Changes from 1.94.1 to 1.94.2:
o More documentation fixes.
o increased checking in regexps
o better locking
o ignore directories in the list directory.
o resend doesn't abort if the sendmail error is EX_NOUSER
Changes from 1.94 to 1.94.1
Improved Installation:
The installation process has been improved. The Makefile is now simpler
and makes use of an external "install" program (included as install.sh).
The permissions for all installed files can be easily set in the Makefile.
In addition, the default permission for $homedir has been made slightly
more lenient, to avoid problems with the mailer not being able to execute
the wrapper.
The installation checker, config-test, has been improved with more checks
and better detection of situations where it's being run improperly. It
will automatically warn of new configuration variables that should be set
in majordomo.cf.
The digest and archive2.pl programs have been moved from the Tools
directory to the main directory since they are usually run by the wrapper
and must be there anyway.
Changes visible to the Majordomo owner:
The default $sendmail_command now includes the -oee option to force
sendmail to mail as many errors as possible instead of exiting with nonzero
exit code at unpredictable times.
Code is provided in majordomo.cf to prevent majordomo, resend and the
tools from running when the system load average exceeds a configurable
limit. This code is disabled by default. It requires the standard
"uptime" command.
The default umask for all majordomo-created files is now set in
majordomo.cf, and defaults to 007.
The variable $shlock'retries has been renamed to $shlock'waittime to better
match its actual meaning as the maximum time (in seconds) that the locking
system will wait for a lock.
A new variable, $majordomo_dont_reply, has been added. Majordomo will not
respond to any piece of mail sent from an address matching this regular
expression. It defaults to '(mailer-daemon|uucp|listserv|majordomo)\@'.
The locking system has been improved and should have much greater
resistance to looping and otherwise uncontrolled behavior in the face of
improperly set permissions and nonexistent files.
Many bugs relating to an improperly set $bounce_mailer have been fixed.
This should end the abort messages complaining about null mailers not being
executable.
Changes visible to list owners:
If a list adds its own Reply-To: header, any Reply-To: header in
incoming messages will be removed.
Changes visible to end users:
Requests for confirmation have been made more detailed, and the backslash
syntax for splitting long lines has been explained in those messages.
Confirmation messages sent by the "subscribe" command have been
improved. They contain more reasons why a confirmation request
may not be received.
Many more checks for illegal addresses have been included. Users are
informed when they supply only their name or otherwise supply a nonsense
address.
The response to the who command includes a subscriber count.

View File

@@ -0,0 +1,569 @@
_ _ ____ _ ____ ____ ___ ____ _ _ ____
|\/| |__| | | | |__/ | \ | | |\/| | |
| | | | _| |__| | \ |__/ |__| | | |__|
Majordomo, noun: a person who speaks, makes
arrangements, or takes charge for another. From
Italian maggiordomo or Spanish mayordomo, both from
Medieval Latin "major domus" - "chief of the house".
(Barnhart Concise Dictionary of Etymology)
Release 1.94.5
README
--------------------------------------------------------------------------
-> Current users of Majordomo whom are upgrading will want to <-
-> read the NEWS file for details on what has changed between <-
-> this and the previous version of Majordomo. <-
Release 1.94.5 of Majordomo is primarily a security and bugfix
release, incorporating changes which fix problems or correct
pressing deficiencies in version 1.94.4. Please read the
NEWS file for changes between versions 1.94.4 and 1.94.5
* * * * * * * * * * * * * *
If you know what Majordomo is and simply want install it, read the
INSTALL file. Browse through this file, though; there's probably
something new here.
* * * * * * * * * * * * * *
--------------------
* What is Majordomo?
--------------------
From the fine Majordomo FAQ (found in Doc/FAQ), maintained by Dave Barr
<barr@math.psu.edu> :
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 maintenance. Once a list is set up,
virtually all operations can be performed remotely, requiring no
intervention upon the postmaster of the list site.
Here's a short list of some of the features of Majordomo.
* supports various types of lists, including moderated ones.
* List options can be set easily through a configuration file,
editable remotely.
* Supports archival and remote retrieval of messages.
* Supports digests.
* Written in Perl, - easily customizable and expandable.
* Modular in design.
* Includes support for FTPMAIL.
Majordomo is a "groupware" project. It has evolved from the initial
code base done by Brent Chapman (brent@greatcircle.com), with further
maintenance done by John Rouillard (rouilj@cs.umb.edu). The current
Majordomo maintainer is Chan Wilson (cwilson@sgi.com).
Along the way, it has picked up many features and additions from
various authors. Because of this, and due to the initial design of
Majordomo, certain features (archiving, digesting, and moderated
lists) are currently done in a "non-optimum" fashion. In short,
configuring Majordomo to do some of the advanced features can be
confusing. This is a known problem and is being worked on.
You'll need the following to use Majordomo:
o Perl, version 4.036 or version 5.002 (or better)
**NOTE** Future versions of Majordomo will *NOT* work
with perl4.
o a C compiler
Other programs that might be useful are:
o bulk_mailer: ftp://cs.utk.edu/pub/moore/bulk_mailer
For large lists.
* * * * * * * * * * * * * *
The INSTALL file details how to install and configure Majordomo.
Once you've installed Majordomo, the NEWLIST file describes how to add
new lists under Majordomo control.
* * * * * * * * * * * * * *
The rest of this README file fills in background information on
Majordomo, where to get help, find others using Majordomo, common
problems, and some other bits:
* Attributions
* Mailing Lists/Support
* More Documentation
* The list configuration files
* Common Problems
* Error Messages
* Using Digest and Archive
* Other Programs
* Tricks
* Customizing the default list config values
--------------
* Attributions
--------------
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 time frame. Chan Wilson
(cwilson@sgi.com) is currently "release coordinator" for 1.94 and
beyond.
The FAQ was compiled by Vincent D. Skahan and is currently being
maintained by David Barr <barr@pop.psu.edu>.
In addition to those above, the following people deserve recognition for
their contributions in shaping Majordomo:
Andrew Boyd
Paul Close
R. Gary Cutbill
Hamilton Gilbert
Jennifer Joy
Alan Millar
John C. Orthoefer
Jerry Peek
Paul Pomes
Jason L Tibbitts III <tibbs@hpc.uh.edu>
Dave Wolfe <david_wolfe@risc.sps.mot.com>
To anybody I left off the attributions list, my apologies. Let me know
that I left you off, and I will make sure that you get mention in a
future release.
-----------------------
* Mailing Lists/Support
-----------------------
There are four mailing lists about Majordomo on GreatCircle.com.
The wise Majordomo-Owner is strongly advised to subscribe to
Majordomo-Announce to learn of new versions and patches to Majordomo.
This list is very low volume.
People with questions about configuring, installing, or using
Majordomo should subscribe to Majordomo-Users.
People interesting in technical discussion of Majordomo, and
developments on it, should join Majordomo-Workers.
Majordomo-Users - for discussions on using Majordomo
Majordomo-Announce - for announcements of new releases
Majordomo-Workers - for people interested in development of
Majordomo.
Majordomo-Docs - for people interested in development of
documentation for Majordomo.
To subscribe to any of the lists above, send an appropriate
"subscribe" command to "Majordomo@GreatCircle.COM".
--------------------
* More Documentation
--------------------
The 'Doc' directory contains the FAQ (Frequently Asked Questions),
which should answer most of your questions.
In the 'Doc/man' directory, you'll find manual pages for approve,
bounce, bounce-remind, digest, resend, and majordomo.
For your list-managers, the file Doc/list-owner-info contains some
good information. It can be sent to them and should be enough
information to get them started using majordomo. You'll want to
update it for your site-specific needs.
'Doc/majordomo.ora' contains the chapter about Majordomo from the
Nutshell Handbook "Managing Internet Information Services," written by
Jerry Peek. The chapter is (c) Copyright 1994 by O'Reilly &
Associates, Inc., and was included in the Majordomo distribution by
permission of the publisher.
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.3, and an updated version will
hopefully be included in future releases.
The original LISA 6 (Oct 1992, Long Beach, CA) paper describing
Majordomo is at Doc/majordomo.lisa6.ps. PLEASE NOTE that it is useful
only for getting a feel for majordomo. It should not be used as an
installation document.
You did read the FAQ, didn't you?
------------------------------
* The list configuration files
------------------------------
Each list has a configuration file associated with it,
<listname>.config. If a list does not have it's .config file, issue a
'lists' command to Majordomo -- it'll create one for you.
Ideally, the config file is meant to be self-documenting, but at the
moment it can be overwhelming to a novice user. This will be fixed in a
future release. The best way to learn about the configuration file is to
issue a 'config <listname> <list administrative password>' to Majordomo,
and carefully read through the results. Also read the
Doc/list-owner-info file, which explains some of the more commonly
tweaked variables.
In addition to the .config file, there are .info and .intro files that
hold informative and introduction information about the list. These
files are best changed via Majordomo's 'newinfo' and 'newintro' commands.
The file <list-name>.intro contains the "intro" text for the list,
which is sent in response to "intro" and successful "subscribe"
commands. The file <list-name>.info contains the "info" text for the
list, which is sent in response to "info"; it's also sent after a
"subscribe" command if no "intro" file exists.
In a future version of majordomo, the option will be provided to keep
the info in the config file rather than using an external
file. However, the external file is useful if you are serving up the
info information by some means other than majordomo (e.g. Web, finger,
ftp).
-------------------------------
* Common Problems and Debugging
-------------------------------
Nearly all the install problems are now caught by the 'config-test'
script that one runs after the install.
What is left, then, is primarily incorrect usage caused by configuring
the aliases improperly, and changing the ownership of Majordomo files
after it is up and running. If you're still stuck, it's easy to turn
some debugging on.
If all else fails, the mailing lists mentioned above are a good place
to ask for help.
** Insecure Usage
If you get complaints about "insecure usage" from "wrapper", then you're
probably invoking it incorrectly. The first argument to "wrapper" should
be the simple filename of the program in the W_BIN directory (defined in
the Makefile) that you want to run. You should NOT specify the full path
name to the program; as a security measure, to keep people from being able
to run anything they want with the setuid/setgid permissions of "wrapper"
"wrapper" will ONLY run programs from the W_BIN directory. If what "wrapper"
is told to run contains a "/", it assumes somebody is trying to make it run
something from somewhere else, and complains about "insecure usage". For
example, the right way to use wrapper is in something like this:
majordomo: "|/usr/local/majordomo/wrapper majordomo"
The WRONG way is "|/usr/local/majordomo/wrapper /usr/local/majordomo/majordomo"
** Permissions
Make sure you've got all the permissions right. In particular, you need
to watch for permissions of DIRECTORIES files are in, as well as
permissions on the files themselves. Almost any time Majordomo tries to
read a file, and every time it tries to write one, it tries to create a
lock file in the same directory as the file. If it can't create that
lock file for any reason (because the directory permissions won't allow
it, or because a lock already exists for that file), Majordomo waits
between 1 and 10 seconds (chosen randomly) and then tries again; it keeps
trying for (by default) 5 minutes. If Majordomo isn't working for you,
and takes some multiple of 5 minutes to fail, you've almost certainly
got a permission problem; check the Majordomo log file. If there's
nothing in the log file, then you've got a permission problem with the
log file and/or the directory it's in.
----------------
** Debugging
If messages to a particular list are getting mangled, perhaps due to
custom headers, footers, or something else, try defining the 'debug'
variable for the list. This will cause resend (the Majordomo program
that sends the message out to the list) to *not* send the message out,
but leave it in $TMPDIR/resend.<process-id>.out. You can then examine
the message contents.
If you suspect something deeper is amiss, then put '$DEBUG = 1;' in
your majordomo.cf. This causes Majordomo and resend to spew debug
messages to $TMPDIR/majordomo.debug and $TMPDIR/resend.debug,
respectively, but operate as normally. If you invoke your mailer in
verbose mode ('Mail -v' or 'mail -v' will hopefully do this) then
debug output will get sent to your terminal instead of the files.
Finally, if you're up to mucking around in the perl code, symlinking
perl into ~majordomo and invoking it via wrapper will give you a debug
environment with Majordomo's permissions and view of the world:
~majordomo% ./wrapper perl -d majordomo
Now set breakpoints, type 'continue', give it a valid email header and
the desired Majordomo command. The only header that you need is a
valid "reply-to" field. The rest is up to you.
* Error Messages
----------------
Majordomo now catches most of problems that plagued earlier versions;
disk space shortages, permissions problems, other resource problems.
When at all possible, a comprehensible email is sent to the
Majordomo-Owner, who should be able to fix things. List-specific
problems are usually sent to the list-owner. Before attempting to track
down errors and checking debug logs, be certain that running "wrapper
config-test" as a normal user reports no problems. The config-test code
will detect most common causes of errors.
Here's most of the error messages that Majordomo will return, and an
explanation of why they might be seen:
MAJORDOMO ABORT - This error occurs anytime some anomaly occurs during
the majordomo run. It causes majordomo to send an error message to the
majordomo owner, and exit immediately. No further commands in the
input message are processed. Mail is sent to the originator of the
message that caused the abort consisting of the output from all command
in the message that had succeeded before the abort. The types of
errors that cause an abort are shown below.
Hostile Address -- somebody submitted an address that majordomo deemed
to be a potential security problem. Some mailers will execute any
command line appearing after a vertical bar, and will use addresses
beginning with a dash as an option instead of an address. In
addition, if the addresses matches an existing file, the mailer may
attempt to overwrite it. For these reasons, majordomo will refuse to
process such addresses. Majordomo will do additional checks on
messages containing '/' characters to verify that they are correct
X400 addresses; these checks may be disabled in majordomo.cf. (See
$no_true_x400 and $no_x400at.)
Non-domained Address -- an address was submitted that was of the form
user@host without a fully qualified domain name. Addresses of this
form are usually caused by either confused users or improperly
configured mail transfer agents. If your host is generating them, it
is misconfigured.
Can't open/append/read -- for some reason majordomo can't
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 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 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.
Can't connect to sendmail -- for some reason the attempt to run
sendmail in the function resend_sendmail in the resend program
failed.
mailer not executable -- either the configured mailer did not exist or
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 occurrences of this type of
error just in case the bugs persist.
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 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.
unknown mailer error XX - This can be caused by a number of things all
relating to the wrappers inability to execute the perl script.
This can include:
the perl script is not executable
the location of the perl program specified with the #!
line is incorrect
the location where the wrapper looks for the perl
scripts is not the location where the scripts are
located.
The current wrapper doesn't use the standard sendmail error
codes, hence the "unknown mailer error" annotation in the
error message. A future wrapper version will use the
appropriate errors from sysexits.h.
--------------------------
* Using Digest and Archive
--------------------------
Digesting and Archiving will be integrated into Majordomo soon. In
the meantime, they require setting up additional aliases and
configuring a few other things.
For digests, read the README.digest and quick-digest-setup files in the
Doc subdirectory, as well as the manual page in Doc/man
For archiving, there are three archive programs available. The best one
to use is called archive2.pl, and it is present in the main Majordomo
directory. (If you'd like to use one of the other archivers, be sure to
move it to, or make a link to it in, the main directory.) Comments at
the top of the file explain all the options available, and here's a brief
extract that details what most people want:
# A sample /etc/aliases file entry to use "archive" add each incoming message
# to a "my-list.YYMM" file in the "/usr/local/mail/lists/my-list.archive"
# directory:
#
# my-list-archive: "|/usr/local/mail/majordomo/wrapper archive2.pl
# -f /usr/local/mail/lists/my-list.archive/my-list
# -m -a"
----------------
* Other Programs
----------------
The "bounce-remind" script should be run out of cron using a line similar to:
10 2 * * * /tools/majordomo/wrappers/bblisa/wrapper bounce-remind
This sends mail to all of the people on the bounces list to warn them
that they are no longer on the lists they thought they were on.
The "medit" program is used to hand edit the mailing list files, but
it locks the files first so that majordomo won't touch them while you
are editing them. You may need to edit this program and change the
location of the majordomo.cf file if the majordomo.cf file is not
accessible as /etc/majordomo.cf).
The "new-list" is used when starting a new list. Often there is a
flood of mail when a list starts up. If you wish to allow a grace
period for people to subscribe before actually putting the list
"on-line", the new-list script can be put at the list address, and it
will notify people that the list is not yet open for business.
The "request-answer" program attached to the "-request" address for
the list sends back a recording telling folks how to use the Majordomo
address for their requests, or how to contact a human if they really
need to. You can use majordomo with the -l option to sit at the
-request address instead of using request-answer if you like.
The "approve" program is intended to be used by a mailing list
administrator to approve messages send by majordomo or resend.
The "bounce" program removes an address from an active majordomo list,
and subscribes it to the bounces list. This is used when mail to the
address starts bouncing.
--------
* Tricks
--------
This section has a few tricks when using majordomo and resend.
1) How do I maintain the restrict_post file for resend?
The easiest way is to create a pseudo list in majordomo. The file
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 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.
2) How can I have more than one moderator/owner for a list?
Again majordomo is your friend. Create a mailing list called
"<listname>-owner". Again create it nonadvertised and closed.
Set up the appropriate aliases for the list:
owner-listname::include:/usr/local/Lists/<listname>-owner
listname-owner:owner-listname
owner-owner-listname: owner-majordomo
and you are done.
3) I run smail. How do I set up majordomo to work in this environment?
Just set $sendmail_command to /bin/smail in your majordomo.cf.
It has been reported that by default smail does not understand the
:include: syntax, and that can be fixed by adding the following to
/etc/smail/directors:
aliasinclude:
driver=aliasinclude,
nobody;
copysecure,
copyowners,
(Thanks to Steve Casey <cm5292@scitsc.wlv.ac.uk> for this information.)
------------------------------------------------
* Customizing the default list config values
------------------------------------------------
The default values of the list configuration files are taken from the
file 'config_parse.pl' in the associative array %known_keys.
It's best to read the above section _The list configuration files_ and
the Doc/list-owner-info file, as well as carefully reading an existing
list configuration before continuing.
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 programmatic
interface to the config file parser and some other details about the
config file parser.
Paul Pomes p-pomes@uiuc.edu suggests the following as replacements for
the message_fronter and message_footer default values. I haven't
tested them, but they may be useful:
'message_fronter', '#! local($TEMP) = $list;
if ( $list =~ /-digest$/ ) {
$TEMP =~ s/-digest$//;
"In this issue:\n\n\t_SUBJECTS_\n\nSee the end of the digest for information on subscribing to the $TEMP\nor $TEMP-digest mailing lists.\n";
} else {
"";
}',
'message_footer', '#! local($TEMP) = $list;
if ( $list =~ /-digest$/ ) {
$TEMP =~ s/-digest$//;
"To subscribe to $TEMP-digest, send the command:\n\n\t
subscribe $TEMP-digest\n\nin the body of a message to \"Majordomo@
Majordomo.cso.uiuc.edu\". If you want\nto subscribe something
other than the account the mail is coming from,\nsuch as a local
redistribution list, then append that address to the\n\"subscribe\"
command; for example, to subscribe \"local-$TEMP\":\n\n\tsubscribe
$TEMP-digest local-$TEMP@your.domain.net\n\nA non-digest
(direct mail) version of this list is also available;
to\nsubscribe to that instead, replace all instances of
\"$TEMP-digest\"\nin the commands above with \"$TEMP\".";
} else {
"";
}',
Note that the strings are all one line long. I have wrapped and broken
them here for ease of viewing.
--------------------

View File

@@ -0,0 +1,81 @@
eVote is a majordomo-addon that allows the list's members to take
polls. It attaches to a majordomo-run email list by insertion into
the alias:
sample: "|/usr/local/majordomo/wrapper eVote_insert resend ..."
You can get the free Linux-ready software, in French or English, at
http://www.deliberate.com or you can join a fiddle@deliberate.com
majordomo-run list to play with it.
eVote also provides support for multi-lingual web/email petitions
(English, French, and Spanish).
eVoted Email Lists
====== ===== =====
eVote-enabled email lists feature:
* Polls are initialized and administered by the members of the email
list with overriding powers given to the list's owner.
* Members can change their own votes -- until the poll closes.
* Poll types supported are:
+ "Yes/No" votes or "Numeric" votes.
+ "Single" items or "Grouped" items, examples being "Vote for One
of the Next Five" and "Distribute 20 Votes over the Next 10 Items".
* 3 secrecy options:
+ "Public" items: Members can see how other members voted.
+ "Private" items: Votes are secret.
+ "If-Voted" items: Members can see IF but not HOW others have voted.
* The vote tally can be displayed while the poll is open, or hidden
until the poll is closed.
How it works: eVote attaches to the email list in the alias file. Most
messages sent to the list's address are broadcast to the list as
usual. However, messages that start with the word "eVote" are scooped
out of the message stream and processed by eVote.
eVote Petitions
===== =========
eVote provides support for multi-lingual petitions that are signed and
administered by email.
* Allows only one signature per email address.
* Verifies email addresses by email receipt.
* Provides bounced mail support.
* Allows the signer to remove his own signature.
* Provides optional display of signatures.
* Integrates with remote WWW sites.
* Signatures are collected from the web site via Javascript.
* Customized html reports are updated automatically via ftp.
* Supports email forms as specified by the initializer of the petition.
* Provides remote initialization and administration of petitions.
* Optionally integrates with Majordomo allowing petitions to be
administered by committee.
* Software limited to over 4 billion signers.
The Clerk
=== =====
The Clerk is the underlying vote-server that maintains the data for
all eVote's interfaces. There is no other database server involved.
The Clerk is an object-oriented C++ specialized database server,
specialized in that it can only serve vote data. It has no flexibility
in the data types it can store as do generalized relational or
object-oriented database servers.
What is lost in flexibility is gained in automation: control of each
datum is given to the person who contributes it; the data are
maintained completely automatically. The administrator is not
involved.
Questions? Write marilyn@deliberate.com.
http://www.deliberate.com

View File

@@ -0,0 +1,252 @@
#!/bin/perl
# Approve Majordomo requests or "resend" bounces.
#
# Given arguments, approves the requests in those files;
# given no arguments, reads standard input.
#
# If the "Subject: " line is "APPROVE <list>", the message is treated as
# a request for approval from Majordomo. An appropriate command is generated
# and mailed to Majordomo to approve the request.
#
# If the "Subject: " line is "BOUNCE <list>: <reason>", the message is treated
# as a posting rejected by "resend" for some reason, and is reformatted with
# appropriate "Approved:" headers to cause it to succeed, then resubmitted
# for posting.
#
# Assumes that the "approve" password for each list is the same as the
# "approval" password used by "resend", and that this password is stored
# in a file called ".majordomo" in the user's home directory, in the
# following format:
#
# List Password Majordomo-Address
#
# Assumes that the "Majordomo-Address" field is an Internet-style
# "something@somewhere" address, and that postings for "List" should
# be sent to "List@somewhere".
#
# Here's an example of what a .majordomo file should look like:
#
# this-list passwd1 Majordomo@This.COM
# other-list passwd2 Majordomo@Other.GOV
#
# If, for instance, /tmp/request contains a standard request from Majordomo
# to a list manager, such as:
#
# From: Majordomo@This.COM
# To: this-list-approval@This.COM
#
# User@Fubar.COM (Joe User) requests you approve the following:
#
# subscribe this-list User@Fubar.COM (Joe User)
#
# If you approve, send a line such as the following to Majordomo@This.COM:
#
# approve PASSWD subscribe this-list User@Fubar.COM (Joe User)
#
# Then, if you run "approve /tmp/request" or "approve < /tmp/request", the
# following message will be sent to Majordomo@This.COM:
#
# To: Majordomo@This.COM
#
# approve passwd1 subscribe this-list User@Fubar.COM (Joe User)
#
# Brent Chapman Great Circle Associates
# Brent@GreatCircle.COM 1057 West Dana Street
# +1 415 962 0841 Mountain View, CA 94041
# $Source: /sources/cvsrepos/majordomo/approve,v $
# $Revision: 1.15 $
# $Date: 1997/04/05 19:18:36 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
$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;
use Getopt::Std;
getopts("df:") ||
die("USAGE: approve [-f <config-file>] [-d] [<file> ...]\nStopped");
if (!defined($opt_f)) {
$opt_f = "$ENV{HOME}/.majordomo";
}
&read_config();
# Read the headers. Look at the "Reply-To:" header to figure out where to
# respond to. Look at the "Subject:" header to figure out if this is an
# APPROVE or a BOUNCE request.
if (@ARGV) {
foreach $file (@ARGV) {
open(FILE, $file) || (warn("can't open \"$file\"; skipping"), next);
&process_file(FILE);
close(FILE);
}
} else {
&process_file(STDIN);
}
exit(0);
sub process_file {
local($FILE) = shift;
local($reply_to);
local($subject);
local($request);
local($list);
while (<$FILE>) {
s/\n$//;
if (/^reply-to:/i) {
s/^\S*:\s+//;
$reply_to = $_;
$reply_to =~ tr/A-Z/a-z/;
next;
}
if (/^subject:/i) {
s/^\S*:\s+//;
$subject = $_;
$subject =~ tr/A-Z/a-z/;
($request, $list) = split(/\s/, $subject, 2);
$list =~ s/:.*//;
next;
}
if (/^$/) {
last;
}
}
# we've read the headers, so we should know now if this is an "APPROVE"
# or a "BOUNCE" that we're processing.
if ($request eq "approve") { &process_approve($FILE); }
elsif ($request eq "bounce") { &process_bounce($FILE); }
else {
warn("unknown request type '$request' in file '$file'; skipping");
}
}
sub process_approve {
local($FILE) = shift;
while (<$FILE>) {
if ((/^\tsubscribe\s/) || (/^\tunsubscribe\s/)) {
if (!defined($reply_to)) {
warn("No \"Reply-To:\"; exiting");
exit(1);
}
s/^\t//;
split;
$list = $_[1];
$list =~ tr/A-Z/a-z/;
$passwd = $passwd{"$list\@$reply_to"};
if (! $passwd) {
warn("no password for list $list; skipping \"$_\"");
next;
}
if (defined($opt_d)) {
open(MAIL, ">&STDOUT");
print MAIL "-" x 20, "\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 {
local($FILE) = shift;
local ($from_skipped);
# we've already skipped the header, so set up to approve the message
# first, figure out where to send it
if (defined($reply_to)) {
# if there's a "Reply-To:" field set, use it.
$post_to = $reply_to;
} elsif ($list =~ /\@/) {
# if the list name already appears fully qualified, use it
$post_to = $list;
} else {
# Well, can we figure it out?
if ($site{$list} eq "MULTIPLE") {
warn("Can't distinguish between multiple lists named '$list'\nSkipping '$file'");
return;
} else {
$post_to = $list . "\@" . $site{$list};
}
}
if (!defined($passwd{$list})) {
warn "Can't find password for list $list, Stopped";
return;
}
if (defined($opt_d)) {
open(MAIL, ">&STDOUT");
print MAIL "-" x 20, "\n";
print MAIL "To: $post_to\n\n";
} else {
open(MAIL, "|$MAILER $post_to") || die("open(\"|$MAILER...\"): $!");
}
print MAIL "Approved: $passwd{$list}\n";
while (<$FILE>) {
if (/^>?From / && ! defined($from_skipped)) {
# Skip any initial "From " or ">From " line
$from_skipped = 1;
next;
}
s/^~/~~/;
print MAIL $_;
}
close(MAIL);
print STDERR "Mailed approved message to $list list.\n";
}
sub read_config {
local($l);
local($p);
local($m);
local($s);
open(CONF, $opt_f) || die("open(CONF, \"$opt_f\"): $!");
while (<CONF>) {
s/\n$//;
s/#.*//;
if (/^$/) { next; }
split;
$l = $_[0]; $l =~ tr/A-Z/a-z/; # list
$p = $_[1]; # password
$m = $_[2]; $m =~ tr/A-Z/a-z/; # majordomo@site
split(/\@/, $m);
$s = $_[1]; $s =~ tr/A-Z/a-z/; # site
$passwd{$l} = $p;
$passwd{"$l\@$m"} = $p;
$passwd{"$l\@$s"} = $p;
if (defined($site{$l})) {
# if it's already defined, there's more than one list by this name
$site{$l} = "MULTIPLE";
} else {
$site{$l} = $s;
}
}
close(CONF);
}

View File

@@ -0,0 +1,188 @@
#!/bin/perl
# Copyright 1993, D. Brent Chapman. All Rights Reserved. For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/archive2.pl,v $
# $Revision: 1.11 $
# $Date: 2000/01/07 11:00:49 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
# archive -f <archive> {-u|-a} [-d|-m|-y] [file ...]
# -f <archive> REQUIRED; specifies base file name for archive
# -u Input is a UNIX archive (separated by "From " lines) to split
# -a Input is a message to append to archive
# -d Archive file is <archive>.YYMMDD
# -D Archive file is <archive>.YYYYMMDD
# -m Archive file is <archive>.YYMM
# -M Archive file is <archive>.YYYYMM
# -y Archive file is <archive>.YY
# -Y Archive file is <archive>.YYYY
# Exactly one of "-u" or "-a" must be specified.
# At most one of "-d", "-D", "-m", "-M", "-y", or "-Y" may be specified;
# if none is specified, archive name is simply <archive>
#
# An example of using "archive" to split an existing UNIX-style archive
# named "my-list.archive" into by-day archive files named "my-list.YYMMDD":
#
# archive -f my-list -d -u my-list.archive
#
# A sample /etc/aliases file entry to use "archive" add each incoming message
# to a "my-list.YYMM" file in the "/usr/local/mail/lists/my-list.archive"
# directory:
#
# my-list-archive: "|/usr/local/mail/majordomo/wrapper archive
# -f /usr/local/mail/lists/my-list.archive/my-list
# -m -a"
# set our path explicitly
# PATH it is set in the wrapper, so there is no need to set it here.
#$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
($program_name = $0) =~ s|.*/||;
# Change directory to our home
chdir($ENV{'HOME'}) if $ENV{'HOME'};
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
# All these should be in the standard PERL library
unshift(@INC, $homedir);
use POSIX qw(ctime);
require "majordomo_version.pl"; # What version of Majordomo is this?
require "majordomo.pl"; # all sorts of general-purpose Majordomo subs
require "shlock.pl"; # NNTP-style file locking
$hostname = &chop_nl(`hostname`);
&set_abort_addr($whoami_owner);
&set_log($log, $hostname, $program_name, "UNKNOWN");
# Here's where the fun begins...
use Getopt::Std;
$m = 1;
foreach (@ctime'MoY) {
$MoY{$_} = $m++;
}
$usage = "Usage: $0 -f <file> {-u|-a} [-d|-D|-m|-M|-y|-Y] [file ...]";
getopts("f:uadDmMyY") || die("$usage\nStopped");
if (!defined($opt_f)) {
print STDERR "'-f <list>' required\n$usage\n";
exit 1;
}
$sendmail_command = $sendmail_command || "/usr/lib/sendmail";
$bounce_mailer = $bounce_mailer || "$sendmail_command -f\$sender -t";
&set_abort_addr($whoami_owner);
&set_mail_from($whoami);
&set_mail_sender($whoami_owner);
&set_mailer($bounce_mailer);
&set_log($log, $hostname, $program_name, $opt_f);
if (defined($opt_a)) { $mutex++; }
if (defined($opt_u)) { $mutex++; }
if ($mutex != 1) {
print STDERR "Either '-a' or '-u' required\n$usage\n";
exit 2;
}
$mutex = 0;
if (defined($opt_d)) { $mutex++; }
if (defined($opt_D)) { $mutex++; }
if (defined($opt_m)) { $mutex++; }
if (defined($opt_M)) { $mutex++; }
if (defined($opt_y)) { $mutex++; }
if (defined($opt_Y)) { $mutex++; }
if ($mutex > 1) {
print STDERR "Only one of '-d', '-D', '-m', '-M', -y', or '-Y' allowed\n$usage\n";
exit 3;
}
if (defined($opt_a)) {
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime(time);
&open_archive(FILE, $year, $mon + 1, $mday);
}
while (<>) {
# remove Approved header (Doh!) if present and still in the header.
next if /^Approved:/ && $. < 30;
if (/^From\s/) {
if (/^From\s+\S+\s+(Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d\d?\s+\d\d?:\d\d:\d\d\s+\d{2,4}\s*$/i) {
if (defined($opt_u)) {
if (defined($is_open)) {
print FILE "\n";
&lclose(FILE);
}
&open_archive_unix(FILE, $_);
}
print FILE "$_";
} else {
print FILE ">$_";
}
} else {
print FILE $_;
}
}
print FILE "\n";
&lclose(FILE);
sub open_archive_unix {
local($FH) = shift;
local($from) = shift;
local($junk, $addr, $dow, $moy, $dom, $time, $year, @rest);
($junk, $addr, $dow, $moy, $dom, $time, $year, @rest) = split(/\s+/,$from);
&open_archive($FH, $year % 100, $MoY{$moy}, $dom);
}
sub open_archive {
local($FH) = shift;
local($year) = shift;
local($mon) = shift;
local($mday) = shift;
local($suffix);
if (defined($opt_y)) {
$suffix = sprintf(".%02d", $year % 100);
}
if (defined($opt_Y)) {
$suffix = sprintf(".%04d", $year + 1900);
}
if (defined($opt_m)) {
$suffix = sprintf(".%02d%02d", $year % 100, $mon);
}
if (defined($opt_M)) {
$suffix = sprintf(".%04d%02d", $year + 1900, $mon);
}
if (defined($opt_d)) {
$suffix = sprintf(".%02d%02d%02d", $year % 100, $mon, $mday);
}
if (defined($opt_D)) {
$suffix = sprintf(".%04d%02d%02d", $year + 1900, $mon, $mday);
}
&lopen($FH, ">>", "$opt_f$suffix") ||
die("Can't append to $opt_f$suffix: $!");
$is_open = 1;
chmod 0664, "$opt_f$suffix";
}

View File

@@ -0,0 +1,188 @@
#!/bin/perl
# Copyright 1993, D. Brent Chapman. All Rights Reserved. For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/archive2.pl,v $
# $Revision: 1.11 $
# $Date: 2000/01/07 11:00:49 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
# archive -f <archive> {-u|-a} [-d|-m|-y] [file ...]
# -f <archive> REQUIRED; specifies base file name for archive
# -u Input is a UNIX archive (separated by "From " lines) to split
# -a Input is a message to append to archive
# -d Archive file is <archive>.YYMMDD
# -D Archive file is <archive>.YYYYMMDD
# -m Archive file is <archive>.YYMM
# -M Archive file is <archive>.YYYYMM
# -y Archive file is <archive>.YY
# -Y Archive file is <archive>.YYYY
# Exactly one of "-u" or "-a" must be specified.
# At most one of "-d", "-D", "-m", "-M", "-y", or "-Y" may be specified;
# if none is specified, archive name is simply <archive>
#
# An example of using "archive" to split an existing UNIX-style archive
# named "my-list.archive" into by-day archive files named "my-list.YYMMDD":
#
# archive -f my-list -d -u my-list.archive
#
# A sample /etc/aliases file entry to use "archive" add each incoming message
# to a "my-list.YYMM" file in the "/usr/local/mail/lists/my-list.archive"
# directory:
#
# my-list-archive: "|/usr/local/mail/majordomo/wrapper archive
# -f /usr/local/mail/lists/my-list.archive/my-list
# -m -a"
# set our path explicitly
# PATH it is set in the wrapper, so there is no need to set it here.
#$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
($program_name = $0) =~ s|.*/||;
# Change directory to our home
chdir($ENV{'HOME'}) if $ENV{'HOME'};
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
# All these should be in the standard PERL library
unshift(@INC, $homedir);
require "ctime.pl"; # To get MoY definitions for month abbrevs
require "majordomo_version.pl"; # What version of Majordomo is this?
require "majordomo.pl"; # all sorts of general-purpose Majordomo subs
require "shlock.pl"; # NNTP-style file locking
$hostname = &chop_nl(`hostname`);
&set_abort_addr($whoami_owner);
&set_log($log, $hostname, $program_name, "UNKNOWN");
# Here's where the fun begins...
require "getopts.pl";
$m = 1;
foreach (@ctime'MoY) {
$MoY{$_} = $m++;
}
$usage = "Usage: $0 -f <file> {-u|-a} [-d|-D|-m|-M|-y|-Y] [file ...]";
&Getopts("f:uadDmMyY") || die("$usage\nStopped");
if (!defined($opt_f)) {
print STDERR "'-f <list>' required\n$usage\n";
exit 1;
}
$sendmail_command = $sendmail_command || "/usr/lib/sendmail";
$bounce_mailer = $bounce_mailer || "$sendmail_command -f\$sender -t";
&set_abort_addr($whoami_owner);
&set_mail_from($whoami);
&set_mail_sender($whoami_owner);
&set_mailer($bounce_mailer);
&set_log($log, $hostname, $program_name, $opt_f);
if (defined($opt_a)) { $mutex++; }
if (defined($opt_u)) { $mutex++; }
if ($mutex != 1) {
print STDERR "Either '-a' or '-u' required\n$usage\n";
exit 2;
}
$mutex = 0;
if (defined($opt_d)) { $mutex++; }
if (defined($opt_D)) { $mutex++; }
if (defined($opt_m)) { $mutex++; }
if (defined($opt_M)) { $mutex++; }
if (defined($opt_y)) { $mutex++; }
if (defined($opt_Y)) { $mutex++; }
if ($mutex > 1) {
print STDERR "Only one of '-d', '-D', '-m', '-M', -y', or '-Y' allowed\n$usage\n";
exit 3;
}
if (defined($opt_a)) {
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
localtime(time);
&open_archive(FILE, $year, $mon + 1, $mday);
}
while (<>) {
# remove Approved header (Doh!) if present and still in the header.
next if /^Approved:/ && $. < 30;
if (/^From\s/) {
if (/^From\s+\S+\s+(Sun|Mon|Tue|Wed|Thu|Fri|Sat)\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d\d?\s+\d\d?:\d\d:\d\d\s+\d{2,4}\s*$/i) {
if (defined($opt_u)) {
if (defined($is_open)) {
print FILE "\n";
&lclose(FILE);
}
&open_archive_unix(FILE, $_);
}
print FILE "$_";
} else {
print FILE ">$_";
}
} else {
print FILE $_;
}
}
print FILE "\n";
&lclose(FILE);
sub open_archive_unix {
local($FH) = shift;
local($from) = shift;
local($junk, $addr, $dow, $moy, $dom, $time, $year, @rest);
($junk, $addr, $dow, $moy, $dom, $time, $year, @rest) = split(/\s+/,$from);
&open_archive($FH, $year % 100, $MoY{$moy}, $dom);
}
sub open_archive {
local($FH) = shift;
local($year) = shift;
local($mon) = shift;
local($mday) = shift;
local($suffix);
if (defined($opt_y)) {
$suffix = sprintf(".%02d", $year % 100);
}
if (defined($opt_Y)) {
$suffix = sprintf(".%04d", $year + 1900);
}
if (defined($opt_m)) {
$suffix = sprintf(".%02d%02d", $year % 100, $mon);
}
if (defined($opt_M)) {
$suffix = sprintf(".%04d%02d", $year + 1900, $mon);
}
if (defined($opt_d)) {
$suffix = sprintf(".%02d%02d%02d", $year % 100, $mon, $mday);
}
if (defined($opt_D)) {
$suffix = sprintf(".%04d%02d%02d", $year + 1900, $mon, $mday);
}
&lopen($FH, ">>", "$opt_f$suffix") ||
die("Can't append to $opt_f$suffix: $!");
$is_open = 1;
chmod 0664, "$opt_f$suffix";
}

View File

@@ -0,0 +1,202 @@
#!/bin/perl
# move problem addresses from <list> to "bounces"
#
# Assumes that the "approve" password for each list is stored in a file
# called ".majordomo" in the user's home directory, in the following format:
#
# List Password Majordomo-Address
#
# When you bounce someone from a list, it looks up that lists's password
# and Majordomo-Address (the address of the Majordomo server serving that
# list) in the .majordomo file, and looks for another list named "bounces"
# with the same Majordomo-Address.
#
# Here's an example of what a .majordomo file should look like:
#
# this-list passwd1 Majordomo@This.COM
# other-list passwd2 Majordomo@Other.GOV
# bounces passwd3 Majordomo@This.COM
# bounces passwd4 Majordomo@Other.GOV
#
# A command of "bounce this-list user@fubar.com" will mail the
# following message to Majordomo@This.COM:
#
# approve passwd1 unsubscribe this-list user@fubar.com
# approve passwd3 subscribe bounces user@fubar.com (930401 this-list)
#
# Note that the date and the list the user was bounced from are included
# as a comment in the address used for the "subscribe bounces" command.
#
# Brent Chapman Great Circle Associates
# Brent@GreatCircle.COM 1057 West Dana Street
# +1 415 962 0841 Mountain View, CA 94041
# $Source: /sources/cvsrepos/majordomo/bounce,v $
# $Revision: 1.11 $
# $Date: 2000/01/07 14:09:24 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
$MAILER = "/usr/lib/sendmail";
$default_maxage = 21;
# if this program is called unsub, then only unsubscribe, don't add to bounces
($basename = $0) =~ s!.*/!!;
if ($basename =~ /unsub/) {
$unsub_only = 1;
}
while ($ARGV[0] =~ /^(-.*)/ && shift) {
if ($1 eq "-f") {
$opt_f = shift;
}
elsif ($1 eq "-d") {
$debug = 1;
}
elsif ($1 eq "-unsub") {
$unsub_only = 1;
}
elsif ($1 eq "-expire") {
$expire = 1;
}
elsif ($1 eq "-majordomo") {
$majordomo = shift;
}
elsif ($1 eq "-maxage") {
$maxage = int(shift);
if ($maxage <= 0) {
warn "$maxage is not a positive integer; ignoring.\n";
$maxage = 0;
}
}
else {
warn "bad option: $1\n";
&usage();
}
}
if (! defined($opt_f)) {
$opt_f = "$ENV{HOME}/.majordomo";
}
if ($maxage && !$expire) {
warn "Can't specify -maxage without -expire\n";
&usage();
}
&read_config();
if ($expire) {
if ($maxage <= 0) {
$maxage = $default_maxage;
}
# convert maxage in days to seconds
$maxage *= 24*60*60;
$list = 'bounces';
if ($majordomo) {
$majordomo{$list} = $majordomo;
}
}
else {
$list = shift(@ARGV);
$list =~ tr/A-Z/a-z/;
$list =~ s/\@.*//;
$list_passwd = $passwd{$list};
if (! $list_passwd) {
die("no password for list $list; stopping");
}
$maxage = 0;
}
$bounce_passwd = $passwd{"bounces\@$majordomo{$list}"};
if (! $unsub_only ) {
if (! $bounce_passwd) {
die("no password for list bounces; stopping");
}
}
($sec,$min,$hour,$mday,$mon,$year) = localtime(time-$maxage);
$year += 1900;
if ($debug) {
open(MSG, ">&STDOUT");
} else {
open(MSG, "|$MAILER $majordomo{$list}") ||
die("open(MSG, \"|$MAILER $majordomo{$list}\"): $!\nStopped");
}
print MSG "To: $majordomo{$list}\n";
print MSG "Subject: expired bounces entries\n" if $expire;
print MSG "\n";
if ($expire) {
$expire_date = sprintf("%02d%02d%02d", $year, $mon+1, $mday);
while (<>) {
# bounce format is user.name (yymmdd listname), we want yymmdd
next unless /.*\s\((\d+) \w.*\)/;
if ($1 <= $expire_date) {
printf MSG "approve %s unsubscribe bounces %s", $bounce_passwd, $_;
}
}
} else {
foreach (@ARGV) {
printf MSG "approve %s unsubscribe %s %s\n", $list_passwd, $list, $_;
if (! $unsub_only) {
printf MSG "approve %s subscribe bounces %s (%02d%02d%02d %s)\n",
$bounce_passwd, $_, $year, $mon+1, $mday, $list;
}
}
}
close(MSG);
exit 0;
sub read_config {
open(CONF, $opt_f) || die("open(CONF, \"$opt_f\"): $!");
while (<CONF>) {
chop;
s/#.*//;
next if /^\s*$/;
local($list,$passwd,$majordomo) = split(' ',$_,3);
$list =~ tr/A-Z/a-z/;
$majordomo =~ tr/A-Z/a-z/;
if (! defined($passwd{$list})) {
$passwd{$list} = $passwd;
$majordomo{$list} = $majordomo;
}
$passwd{"$list\@$majordomo"} = $passwd;
}
close(CONF);
}
sub usage {
print STDERR <<EOT;
Usage: $0 [-d] [-f <config-file>] [-unsub] <list> <user>
$0 [-d] [-f <config-file>] -expire [-maxage <days>]
[-majordomo <addr>] <bounce_entries>
Options:
-d Debug: print what would be done, but don't do it.
-f config_file Specify a list/passwd file (default ~/.majordomo)
-unsub Unsubscribe the user from the list, but don't add
to bounces. On by default if the program name
contains "unsub".
-expire Expire entries from the specified bounces list.
-maxage days Expire entries older than maxage days (default
$default_maxage days).
-majordomo addr Send expired bounces to this majordomo (default is
the majordomo corresponding to the first 'bounces'
list).
bounce_entries A file containing bounce entries (eg. the bounces list)
EOT
exit(1);
}

View File

@@ -0,0 +1,105 @@
#!/bin/perl
# send a reminder to folks on a bounce list
# Brent Chapman Great Circle Associates
# Brent@GreatCircle.COM 1057 West Dana Street
# +1 415 962 0841 Mountain View, CA 94041
# $Source: /sources/cvsrepos/majordomo/bounce-remind,v $
# $Revision: 1.9 $
# $Date: 1996/12/09 16:49:46 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
$main'program_name = 'mj_bounce-remind';
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
# Go to the home directory specified by the .cf file
chdir("$homedir");
# All these should be in the standard PERL library
unshift(@INC, $homedir);
# Set these here so that they can be interploated on the $mailer command line.
$sender = "nobody\@$whereami";
$to = "Bounces\@$whereami";
$from = "nobody\@$whereami";
$subject = "Bouncing email from mailing lists at $whereami";
$mail_cmd = eval qq/"$mailer"/;
open(MSG, "|$mail_cmd bounces\@$whereami") ||
die("open(MSG, \"|$mail_cmd bounces\@$whereami\"): $!\nStopped");
print MSG <<EOF;
To: $to
From: $from
Subject: $subject
Reply-To: $whoami
Your address has been moved to Bounces\@$whereami
from some other mailing list at $whereami
because email to you was bouncing.
Here are the addresses currently on Bounces\@$whereami
so that you can see which of your addresses is among them.
The comment for each address shows the date it was moved,
and the first list it was removed from. If you were on
multiple lists here, you may have been removed from them
as well, but only the first list you were removed from
will show up in the comment below.
EOF
open(LIST, "$listdir/bounces")
|| die("Can't read $listdir/bounces: $!; aborting");
while (<LIST>) {
print MSG "\t$_";
}
close(LIST);
print MSG <<EOF;
If the problem has been fixed, you can get off of
Bounces and back on to the other list by sending the
following to $whoami:
subscribe list_name
unsubscribe bounces
To subscribe or unsubscribe an address other than where you're
sending the command from, append the other address to the end
of the "subscribe" or "unsubscribe" command (for example,
"subscribe your_list foo\@bar.com").
You'll need to access the mailing list archives if you want to catch
up on whatever you missed while you were off the main list.
If you don't want to keep getting these reminders every day, but
don't want to resubscribe to the list, send just the "unsubscribe"
command shown above.
If you need to contact a human being regarding this, send a message
to $whoami_owner.
EOF
close(MSG);
exit 0;

View File

@@ -0,0 +1,418 @@
#!/bin/perl
# $Id: config-test,v 1.18 1997/08/27 15:17:13 cwilson Exp $
# configuration test for majordomo
# provided with majordomo, modifications by darren stalder <torin@daft.com>
# more mods by Vince Skahan <vince@atc.boeing.com>
#
# execute this by cd to your majordomo dir, then 'wrapper config-test'
#
use POSIX qw(ctime);
@requires = ( "majordomo_version.pl",
"majordomo.pl",
"shlock.pl",
"config_parse.pl",
);
$registration_file = ".majordomo_registration";
$default_uid = 123;
if (!$ENV{'MAJORDOMO_CF'}) {
print <<"STOP"
\a\aYou're attempting to run $0 the wrong way!
Let's try running it through ./wrapper instead, hmm?
STOP
;
sleep 2;
if (-x "./wrapper") {
exec("./wrapper config-test", @ARGV);
} else {
print <<"dummy"
Well, shoot, you forget to run
make install-wrapper
as well! Better go do that...
dummy
;
exit 1;
}
}
&header('');
&header("Config-test for Majordomo");
&header('');
print "\n\n";
&header("Obvious things:");
&header("environment variables");
foreach $e (sort keys %ENV) {
print " $e=$ENV{$e}\n";
}
&header("euid/egid checks");
$euid_name=getpwuid($>);
push(@egid_group_numbers,(split(' ',$) ))); # it switches groups...
foreach $groupnum (@egid_group_numbers) {
$name = getgrgid($groupnum);
push(@egid_names,$name);
}
print " effective user = $euid_name (uid $>)\n";
print " effective group = @egid_names (gid $) )\n";
&header("uid/gid checks");
$uid_name=getpwuid($<);
push(@gid_group_numbers,(split(' ',$( ))); # it switches groups...
foreach $groupnum (@gid_group_numbers) {
$name = getgrgid($groupnum);
push(@gid_names,$name);
}
print " real user = $uid_name (uid $<)\n";
print " real group = @gid_names (gid $( )\n";
if ($< == $default_uid) { # the default uid
print <<"idontthinkso"
I think it's highly unlikely that you're using the default
user id of $default_uid for majordomo. Lemme check...
idontthinkso
;
$name = (getpwuid($default_uid))[0];
if (! $name ) {
print <<"ithoughtso"
Hah! I thought so! You've forgotten to use the right user id
in the Makefile. Make sure that W_USER and W_GROUP are set to
the correct values in the Makefile, and run
make install-wrapper
again.
ithoughtso
;#'
exit 1;
} else {
print <<"wellokay"
Hmm! The user with the uid of $default_uid is $name, so
at least the user exists. If this isn't the majordomo user,
make sure that W_USER and W_GROUP are set to the correct values
in the Makefile, and run
make install-wrapper
again.
wellokay
;#'
}
}
&header('');
print "\n\tNon obvious things that cause headaches:\n\n";
&header('');
$cf = $ARGV[0] || $ENV{'MAJORDOMO_CF'};
if (eval "require '$cf'") {
&good("'require'd $cf okay.");
} else {
&bad("something's wrong with $cf: $@");
}
foreach (@requires) {
if (require $_) {
&good("found $_ okay.");
} else {
&bad("failed to find $_ in \@INC");
}
}
print "\n";
print "You're running Majordomo Version $majordomo_version.\n";
print "\n--==> Majordomo home directory is $homedir.\n";
unshift(@INC, $homedir);
&header("Include directories");
foreach (@INC) {
print "\t$_\n";
}
&header("Home");
if (chdir($homedir)) {
&good("changedir to $homedir succeeded.");
} else {
&bad("changedir to $homedir failed, $!");
}
if (open(TEST, ">cftest.$$")) {
&good("Created a mock lock file.");
close(TEST);
unlink("cftest.$$");
}
else {
&bad("Couldn't create a mock lock file.\n \$homedir ($homedir) needs to be writable.");
}
&header("temp directory");
if (! defined $TMPDIR) {
&bad("\$TMPDIR not defined by majordomo.cf");
}
elsif (-d $TMPDIR) {
if (open(TEST, ">$TMPDIR/cftest.$$")) {
&good("Created a temp file in \$TMPDIR ($TMPDIR).");
close(TEST);
unlink("$TMPDIR/cftest.$$");
}
else {
&bad("Couldn't create a file in $TMPDIR.");
}
}
else {
&bad("\$TMPDIR ($TMPDIR) does not exist.");
}
&header("list directory");
if (-d $listdir) {
if (-r $listdir && -w $listdir && -x $listdir) {
&good("list directory $listdir has good permissions.");
} else {
&bad("list directory $listdir has bad permissions");
}
} else {
print "Hmmm, list directory $listdir doesn't exist\n or isn't a directory.\n";
print "Let me try to make it for you...\n";
if ( mkdir( $listdir, 0777) ) {
&good("list directory $listdir created.\n");
} else {
&bad("Couldn't create $listdir, $!");
}
}
&header("log");
if ( ! -e $log ) {
print "Logfile $log didn't exist, trying to create...\n ";
if (open(A, ">$log") && close(A) ) { # sesame
print "okay, now chmod'ing..\n";
chmod (0664, $log) || &bad( "chmod on $log failed, $!");
} else {
&bad("Couldn't create logfile $log, $!\n");
}
}
if ( -f $log && -r $log && -w $log) {
&good("logfile $log exists and is writeable.");
} else {
&bad("logfile $log exists, but is not writeable or isn't a file.");
}
&header ("Mailers");
if ($mailer) {
print "You have defined a mailer for delivery.\n";
if ($mailer =~ /sendmail.*\s-t/i) {
print "Whoa! You have given the \"-t\" option to sendmail. This can cause mail\n";
print "loops when used for outbound delivery.\n";
$BAD++;
}
($x = $mailer) =~ s/\s.*$//; # Remove everything after and including
# the first space
}
elsif ($sendmail_command) {
print "You haven't defined a \$mailer to be used for delivery, but you have\n";
print "defined \$sendmail_command. Majordomo will use\n";
print "$sendmail_command -f\\\$sender\n";
print "to deliver mail to the list unless you define list-specific cases.\n";
$x = $sendmail_command;
}
else {
print "You have defined neither \$mailer, nor \$sendmail_command.\n";
print "Majordomo will use\n";
print "/usr/lib/sendmail -f\\\$sender\n";
print "to deliver mail to the list.\n";
$x = "/usr/lib/sendmail";
}
print "Attempting to verify that this is a valid mailer...";
if ( -x $x ) {
print "looks okay.\n";
} else {
print "nope, $x is not executable\n";
$BAD++;
}
if ($bounce_mailer) {
print "You have defined a mailer for delivering administrative messages.\n";
($x = $mailer) =~ s/\s.*$//; # Remove everything after and including
# the first space
}
elsif ($sendmail_command) {
print "You haven't defined a \$bounce_mailer to be used for delivering\n";
print "administrative messages, but you have defined \$sendmail_command.\n";
print "Majordomo will use\n";
print "$sendmail_command -f\\\$sender -t\n";
print "to deliver administrative mail.\n";
$x = $sendmail_command;
}
else {
print "You have defined neither \$mailer, nor \$sendmail_command.\n";
print "Majordomo will use\n";
print "/usr/lib/sendmail -f\\\$sender -t\n";
print "to deliver administrative mail.\n";
$x = "/usr/lib/sendmail";
}
print "Attempting to verify that this is a valid mailer...";
if ( -x $x ) {
print "looks okay.\n";
} else {
print "nope, $x is not executable\n";
$BAD++;
}
&header("Checking majordomo.cf");
print "Checking to see if there are new variables that should be in\n";
print "your majordomo.cf file...";
open($cf, $cf) || &bad("Couldn't open $cf for reading, $!");
open(S, 'sample.cf') || &bad("Couldn't open sample.cf for reading, $!");
while (<S>) {
next unless /^\s*(\$\w+(('|::)\w+)*)/;
$config{$1} = 2;
}
while (<$cf>) {
next unless /^\s*(\$\w+(('|::)\w+)*)/;
$config{$1} = 1 unless defined $config{$1}; # Keeps -w happy
$config{$1} |= 1;
}
close (S);
close $cf;
# $config{whatever} == 1 if only in their majordomo.cf,
# == 2 if only in sample.cf,
# == 3 if in both.
#
foreach (sort keys %config) {
push (@new, $_) if $config{$_} == 2;
push (@unknown, $_) if $config{$_} == 1;
}
if ($#new >= 0) {
print "\nNew configuration variables (see sample.cf):\n";
foreach (@new) { print "\t$_\n"; }
}
if ($#unknown >= 0) {
print "\nUnknown configuration variables in existing majordomo.cf:\n";
foreach (@unknown) { print "\t$_\n"; }
}
if ($#new == -1 && $#unknown == -1) {
print "Nope, none that I see.\n";
}
print "\nHave you configured where Majordomo is?\n";
print "\t\$whereami is $whereami\n";
if ($whereami eq "example.com") {
&bad("\$whereami hasn't been changed yet!");
} else {
&good("yup!");
}
&header("end of tests");
print "\n\n";
if ($BAD) {
print "$BAD bad ", $BAD == 1 ? "thing was" : "things were", " found.\n";
print "Please fix before attempting to run Majordomo.\n";
} else {
print <<"ZOT";
Nothing bad found! Majordomo _should_ work correctly.
If it doesn't, check your configuration file
($cf)
closely, and if it still looks okay, consider asking the majordomo-users
mailing list at "majordomo-users\@greatcircle.com" for assistance. Be sure
and fully specify what your problems are, and what type of machine (and
operating system) you are using.
Enjoy!
ZOT
#'
if ( ! -e $registration_file ||
`cat $registration_file` ne $majordomo_version) {
print <<"ZOT";
I see you haven't registered this version of Majordomo.
By registering, you will be notified of patches and further releases
of Majordomo. Shall I send email to majordomo-registration\@greatcircle.com
to register this version? (I'll cc $whoami_owner)
ZOT
#'
print "[yes] ";
if ( <> !~ /n/i) {
open(RF,">$registration_file")
|| die "couldn't create $registration_file, $!";
print RF $majordomo_version;
close RF;
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$bounce_mailer = "$sendmail_command -f\$sender -t"
unless defined $bounce_mailer;
&set_abort_addr($whoami_owner);
&set_mail_from($whoami); $x = $whoami; # Keeps -w happy
&set_mail_sender($whoami_owner);
&set_mailer($bounce_mailer);
&sendmail(REG, "majordomo-registration\@greatcircle.com,$whoami_owner",
"Majordomo Registration");
print REG "Majordomo Version: $majordomo_version\n";
print REG "Perl version $]\n";
print REG "Majordomo Owner: $whoami_owner\n";
print REG "Uname: " . `uname -a`;
close REG;
} else {
print "Ooooh, like to live dangerously, eh?!\n\n";
}
}
}
######################################################################
sub good { print "Good: $_[0]\n"; }
sub bad { print "BAD: $_[0]\n"; $BAD++;}
sub header {
if (length $_[0]) {
print '-' x ( ( 60 - (length($_[0]) + 2) ) / 2),
" $_[0] ", '-' x ( ( 60 - (length($_[0]) + 2) ) / 2), "\n";
} else {
print '-' x 60, "\n";
}
}
#
# that's all folks

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
#!/bin/perl
#(Message inbox:15)
#Return-Path: Majordomo-Users-Owner@greatcircle.com
#Message-Id: <m0oXmfl-0002wDC@hock.bolis.sf-bay.org>
#From: Alan Millar <amillar@bolis.sf-bay.org>
#Subject: Perl prog to create list archives
#To: majordomo-users@greatcircle.com
#Date: Wed, 1 Sep 1993 00:32:03 -0800 (PDT)
#Cc: brent@greatcircle.com
#Reply-To: Alan Millar <AMillar@bolis.sf-bay.org>
#
#
#Hi-
#
#Here is a perl program I wrote to keep mailing list archives.
#It is designed to produce list archive files similar to Revised
#Listserv. Each message is separated by a line of "==="s and
#most of the header "noise" is gone. Instead of being stored
#in one big file, they are split into one file per month with
#the name logYYMM where YY and MM are the numeric year and
#month.
#
#I call it from /usr/lib/aliases using:
#
# listname-archive: "|/usr/local/mail/majordomo/wrapper archive.pl \
# /usr/local/mail/lists/listname.archive"
#
#Where the last parameter is the directory name to put the
#log files into.
#
#Give it a try and let me know what you think.
#
#- Alan
#
#---- ,,,,
#Alan Millar amillar@bolis.SF-Bay.org __oo \
#System Administrator =___/
#The skill of accurate perception is called cynicism by those who don't
#possess it.
#----
# archive.pl
# Mailing list archiver. Specify the directory (not the file)
# on the command line. Messages are written to a file
# called 'logYYMM' in that directory, where YY is the two digit
# year and MM is the two-digit month.
# Written by Alan Millar August 25 1993.
# All these should be in the standard PERL library
unshift(@INC, $homedir);
require "majordomo.pl"; # all sorts of general-purpose Majordomo subs
require "shlock.pl"; # NNTP-style file locking
# The headers we want to keep, in order:
@keepHeaders =
( "To", "cc"
, "from", "reply-to", "organization"
, "date", "subject"
, "summary", "keywords"
, "Content-Type"
);
#-----------------------------------
# Set up output file. See if directory is specified on command line.
$outputDir = $ARGV[0];
if (! -d $outputDir) {
$outputDir = "/tmp";
}
$outputDir =~ s/\/$//; # drop trailing slash
#------------------------------------
# Get date for log file name
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
# log file name is form "logYYMM"
$logFile = sprintf("$outputDir/log%2.2d%2.2d",$year,$mon + 1);
# open output file
&lopen(OUTPUT,">>",$logFile);
# Parse the mail header of the message, so we can figure out who to reply to
&ParseMailHeader(STDIN, *hdrs);
# Print the headers we want
print OUTPUT "========================================";
print OUTPUT "======================================\n";
foreach $key (@keepHeaders) {
$key =~ tr[A-Z][a-z];
if (defined($hdrs{$key})) {
$newKey = $key; substr($newKey,0,1) =~ tr/a-z/A-Z/;
printf OUTPUT "%-15s%s\n", "$newKey: ", $hdrs{$key};
} # if non-blank
} # foreach
print OUTPUT "\n";
# copy the rest of the message
while (<STDIN>) {
print OUTPUT $_;
}
print OUTPUT "\n";
&lclose(OUTPUT);

View File

@@ -0,0 +1,34 @@
#!/bin/perl
# archive: A hack to use mh to handle the archives
#
# You may redistribute this file, or inlcude it into the offical majordomo
# package
#
# $Source: /sources/cvsrepos/majordomo/contrib/archive_mh.pl,v $
# $Revision: 1.4 $
# $Date: 1997/03/10 15:40:41 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
# set our path explicitly
$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/tools/majordomo-1.56/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
# Go to the home directory specified by the .cf file
chdir("$homedir");
exec("/tools/mh-6.8/lib/mh/rcvstore +$filedir/$ARGV[0] -nocreate\n");

View File

@@ -0,0 +1,348 @@
From: pdc@lunch.asd.sgi.com (Paul Close)
Subject: Digest code diffs for 1.90
Date: Thu, 21 Apr 1994 17:56:22 -0700 (PDT)
Here are my changes to digest which support config file settings for
specifying the digest size in lines and/or the maximum age of the oldest
article, in days. Also support a new flag, -p (for "push"), intended for
use by cron jobs. It checks to see if a digest should be sent, and sends
it if it should (pretty well because an article is too old, but you could
use this to send all the time).
A few comments on the code. In &should_be_sent, I calculate how big the
article would be if the headers were stripped, both in bytes and in lines.
I add in a bit of a fudge factor for mail headers, just so we don't get too
close to maxlength bytes before sending. Typically, the line count will
cause a digest to be sent before the byte count would (I see the maxlength
count as more of a mailer issue than a digest issue).
The old digest code had a strange construct: s/\n+$/\n/; I assumed that
this was to trim newlines off the end of the string, but multi-line regexps
don't work that way. The only way I could get this to work is:
$len = length($body) - 1;
$len-- while (substr($body,$len,1) eq "\n");
substr($body,$len+1) = "";
Any clever hacks appreciated. In the same area, I changed the code that
reads the body of the message to read the whole thing at once (undef $/)
rather than do multiple string concatenations. Seems more efficient. I
also added a ^From escaper, using enough of a real "From " line pattern,
that it shouldn't match just any line beginning with From.
Under the heading of random perl lore, to count the number of newlines in a
multi-line string, I used:
$lines += ($body =~ s/\n/\n/g);
seems pretty straightforward, but I have the nagging suspicion there's an
easier way.
Finally, I made digest safe past the year 2000, by printing $year+1900
rather than 19$year. Whoopee!
Comments welcome! The code is based on 1.90b2, which is the latest I have.
Index: digest/digest
*** digest/digest.old Sun Mar 6 14:47:06 1994
--- digest/digest Thu Apr 21 17:35:33 1994
***************
*** 63,72 ****
if (defined($opt_r)) {
&receive_message;
} elsif (defined($opt_m)) {
&make_digest;
} else {
! &abort("Usage: digest {-r|-m} [-c config|(-C -l list)]\nStopped");
}
&free_lock;
--- 63,79 ----
if (defined($opt_r)) {
&receive_message;
+ if (&should_be_sent()) {
+ &make_digest;
+ }
} elsif (defined($opt_m)) {
&make_digest;
+ } elsif (defined($opt_p)) {
+ if (&should_be_sent()) {
+ &make_digest;
+ }
} else {
! &abort("Usage: digest {-r|-m|-p} [-c config|(-C -l list)]\nStopped");
}
&free_lock;
***************
*** 73,97 ****
exit(0);
sub receive_message {
- $sum = 0;
$i = 0;
do {
! $i++;
! $file = sprintf("%s/%03d", $V{'INCOMING'}, $i);
! $sum += (-s $file);
} until (! -e $file);
print STDERR "Receiving $i\n";
open(MSG, ">$file") || &abort("open(MSG, \">$file\"): $!");
while (<STDIN>) {
print MSG $_;
}
close(MSG);
- $sum += (-s $file);
- if ($sum > $V{'DIGEST_SIZE'}) {
- &make_digest;
- }
- return(1);
}
--- 80,146 ----
exit(0);
+ sub should_be_sent {
+ # fudge factors for headers and footers
+ $sum = 600 + length($HEADER) + length($HEADERS) + length($TRAILER);
+ $lines = 25;
+ $i = 0;
+ while (1) {
+ $file = sprintf("%s/%03d", $V{'INCOMING'}, ++$i);
+ last unless (-e $file);
+ open(COUNT, "<$file") || &abort("open(COUNT, \"<$file\"): $!");
+
+ $/ = ''; # grab the header
+ $head = <COUNT>;
+
+ # only count From/Date/Subject header fields to get a
+ # more accurate size and line count.
+ $head =~ s/\n\s+/ /g;
+ $head =~ /^(From:\s+.*)/i && ($sum += length($1)+1, $lines++);
+ $head =~ /^(Subject:\s+.*)/i && ($sum += length($1)+1, $lines++);
+ $head =~ /^(Date:\s+.*)/i && ($sum += length($1)+1, $lines++);
+ $sum++, $lines++;
+
+ # count the body of the message
+ undef $/;
+ $body = <COUNT>;
+ $sum += length($body);
+ $lines += ($body =~ s/\n/\n/g); # count newlines
+
+ $/ = "\n";
+ close(COUNT);
+ $sum += length($EB) + 2, $lines += 2; # account for message delimiter
+
+ if ($V{'DIGEST_SIZE'} && $sum > $V{'DIGEST_SIZE'}) {
+ return(1);
+ }
+ if ($V{'DIGEST_LINES'} && $lines > $V{'DIGEST_LINES'}) {
+ return(1);
+ }
+ if ($V{'MAX_AGE'} && (-M $file) > $V{'MAX_AGE'}) {
+ return(1);
+ }
+ }
+ print "don't send. sum = $sum, lines = $lines\n";
+
+ return(0);
+ }
+
sub receive_message {
$i = 0;
do {
! $file = sprintf("%s/%03d", $V{'INCOMING'}, ++$i);
} until (! -e $file);
+
print STDERR "Receiving $i\n";
open(MSG, ">$file") || &abort("open(MSG, \">$file\"): $!");
+
+ # copy the message
while (<STDIN>) {
print MSG $_;
}
+
close(MSG);
}
***************
*** 111,129 ****
$head = <message>;
$head =~ s/\n\s+/ /g;
$body = "";
! ($subj) = ($head =~ /^subject:\s+(.*)/i);
! $subj = "[none]" unless $subj;
! ($from) = ($head =~ /^from:\s+(.*)/i);
! ($date) = ($head =~ /^date:\s+(.*)/i);
! $/ = "\n";
! while (<message>) {
! s/^-/- -/; #escape encapsulation boundaries in message
! $body .= $_;
! }
close(message);
! $body =~ s/\n+$/\n/;
push(@subj,$subj);
print TEMP <<EOF;
From: $from
--- 160,184 ----
$head = <message>;
$head =~ s/\n\s+/ /g;
$body = "";
! $subj = ($head =~ /^Subject:\s+(.*)/i)? $1: "[none]";
! ($from) = $head =~ /^From:\s+(.*)/i;
! ($date) = $head =~ /^Date:\s+(.*)/i;
! undef $/;
! $body = <message>;
close(message);
!
! # escape ^From <user> <weekday> <month> <day> <hr:min:sec> ...
! $body =~
! s/^From (\S+\s+\w{3}\s+\w{3}\s+\d+\s+\d+:\d+:\d+)/>From $1/g;
! $body =~ s/^-/- -/g; # escape encapsulation boundaries in message
! # trim trailing \n's
! $len = length($body) - 1;
! $len-- while (substr($body,$len,1) eq "\n");
! substr($body,$len+1) = "";
+ $/ = "\n";
+
push(@subj,$subj);
print TEMP <<EOF;
From: $from
***************
*** 131,136 ****
--- 186,192 ----
Subject: $subj
$body
+
$EB
EOF
***************
*** 204,211 ****
$* = 1;
$HOME = $ENV{"HOME"} || (getpwuid($>))[7];
chdir($HOME);
! &getopt("rmc:Cl:") ||
! &abort("Usage: digest {-r|-m} [-c config|(-C -l list)]\nStopped");
$config = $opt_c || "$HOME/.digestrc";
$TEMP = "/tmp/digest.$$";
$SIG{'INT'} = 'cleanup';
--- 260,267 ----
$* = 1;
$HOME = $ENV{"HOME"} || (getpwuid($>))[7];
chdir($HOME);
! &getopt("rmpc:Cl:") ||
! &abort("Usage: digest {-r|-m|-p} [-c config|(-C -l list)]\nStopped");
$config = $opt_c || "$HOME/.digestrc";
$TEMP = "/tmp/digest.$$";
$SIG{'INT'} = 'cleanup';
***************
*** 245,252 ****
$NUMBER = $config_opts{$opt_l,"digest_issue"};
$Precedence = $config_opts{$opt_l,"precedence"};
$Precedence = "bulk" if ($Precedence eq "");
! $V{'ARCHIVE'} = "$filedir/$opt_l$filedirsuffix";
$V{'DIGEST_SIZE'} = $config_opts{$opt_l, "maxlength"};
$V{'ERRORS-TO'} = $config_opts{$opt_l,"sender"};
$V{'FROM'} = $config_opts{$opt_l, "sender"};
$V{'INCOMING'} = "$digest_work_dir/$opt_l";
--- 301,310 ----
$NUMBER = $config_opts{$opt_l,"digest_issue"};
$Precedence = $config_opts{$opt_l,"precedence"};
$Precedence = "bulk" if ($Precedence eq "");
! $V{'ARCHIVE'} = "$filedir/$opt_l$filedir_suffix";
$V{'DIGEST_SIZE'} = $config_opts{$opt_l, "maxlength"};
+ $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"};
$V{'FROM'} = $config_opts{$opt_l, "sender"};
$V{'INCOMING'} = "$digest_work_dir/$opt_l";
***************
*** 327,333 ****
sub getdate {
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
! return($DAYS[$wday] . ", $mday " . $MONTHS[$mon] . " 19$year");
}
sub set_lock {
--- 385,392 ----
sub getdate {
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
! $year += 1900;
! return("$DAYS[$wday], $mday $MONTHS[$mon] $year");
}
sub set_lock {
Index: config_parse.pl
*** config_parse.pl.old Thu Apr 21 07:32:50 1994
--- config_parse.pl Thu Apr 21 07:41:33 1994
***************
*** 128,133 ****
--- 128,135 ----
'digest_archive', '',
'digest_rm_footer', '',
'digest_rm_fronter', '',
+ 'digest_maxlines', '',
+ 'digest_maxdays', '',
# general stuff below
'comments', '', # comments about config file
);
***************
*** 331,336 ****
--- 333,346 ----
Just like digest_rm_footer, it is also non-operative.',
);
+ 'digest_maxlines',
+ "automatically generate a new digest when the size of the digest exceeds
+ this number of lines.",
+
+ 'digest_maxdays',
+ "automatically generate a new digest when the age of the oldest article in
+ the queue exceeds this number of days.",
+
# match commands to their subsystem, by default only 4 subsystems
# exist, majordomo, resend, digest and config.
%subsystem = (
***************
*** 372,377 ****
--- 382,389 ----
'digest_archive', 'digest',
'digest_rm_footer', 'digest',
'digest_rm_fronter', 'digest',
+ 'digest_maxlines', 'digest',
+ 'digest_maxdays', 'digest',
# general stuff here
'comments', 'config',
);
***************
*** 418,423 ****
--- 430,437 ----
'digest_archive', 'grab_absolute_dir',
'digest_rm_footer', 'grab_word',
'digest_rm_fronter', 'grab_word',
+ 'digest_maxlines', 'grab_integer',
+ 'digest_maxdays', 'grab_integer',
# general stuff below
'comments', 'grab_string_array',
);
--
Paul Close pdc@sgi.com ...!{ames, decwrl, uunet}!sgi!pdc
No fate but what we make

View File

@@ -0,0 +1,45 @@
#!/usr/local/bin/perl
# Program name digest.num -- Digest numbering.
#
# Lindsay Haisley, FMP Computer Serivces (fmouse@fmp.com)
#
# Usage: digest.num -l list_name [-i issue_num] [-v volume_num]
#
# Sets number for next digest issue and volume number in the config file
# for list list_name. If issue_num and volume_num are not supplied, they
# are set to 0.
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
require "$cf";
# chdir("$homedir");
require "shlock.pl";
require "config_parse.pl";
require "getopt.pl";
&Getopt('liv');
die "No list config specified\n" if !defined($opt_l);
die "List config file $opt_l.config does not exist\n" unless -e "$listdir/$opt_l.config";
&get_config($listdir, $opt_l);
if (defined($opt_v)) {
$volume = $opt_v;
} else {
$volume = 0;
}
if (defined($opt_i)) {
$issue = $opt_i;
} else {
$issue = 0;
}
$config_opts{$opt_l, "digest_volume"} = $volume;
$config_opts{$opt_l, "digest_issue"} = $issue;
&set_lock("$listdir/$opt_l.config.LOCK");
&config'writeconfig($listdir, $opt_l);
&free_lock("$listdir/$opt_l.config.LOCK");
print STDERR "Config for list $opt_l set to volume $volume, issue $issue\n";

View File

@@ -0,0 +1,28 @@
#! /bin/sh
# This script was contributed by "Paul Pomes" <P-Pomes@uiuc.edu>
#
# It only works with versions of "digest" that have been modified
# to work with the config file moddifications in majordomo 1.90 and above.
# This script can be called from cron to automatically generate
# digests for all of the lists in DIGESTDIR. E.G.
#
# daily
# 0 2 * * * /path/to/digest.send
#
# weekly (on monday)
# 0 2 * * 1 /path/to/digest.send
#
# monthly (first of the month)
# 0 2 1 * * /path/to/digest.send
#
DIGESTDIR=/usr/spool/digests
cd $DIGESTDIR
for i in *
do
if [ -f $i/001 ];
then
/path/to/majordomo/wrapper digest -m -C -l $i ${i}-outgoing
fi
done

View File

@@ -0,0 +1,156 @@
#!/bin/perl
#
# Print various statistics about the Log file
#
# Todo: summarize admin commands
#
# Paul Close, April 1994
#
while (<>) {
if (($mon,$day,$time,$who,$cmd) =
/([A-Za-z]+) (\d+) ([\d:]+)\s+.*majordomo\[\d+\]\s+{(.*)} (.*)/)
{
@f = split(' ',$cmd);
$cmd = $f[0];
$f[1] =~ s/[<>]//g;
$f[2] =~ s/[<>]//g;
$count{$cmd}++;
# help
# lists
# which [address]
# approve PASSWD ...
if ($cmd eq "approve" ||
$cmd eq "help" ||
$cmd eq "lists" ||
$cmd eq "which")
{
${$cmd}++;
}
# index list
# info list
# who list
elsif ($cmd eq "index" ||
$cmd eq "info" ||
$cmd eq "who")
{
if ($#f == 1) {
$lists{$f[1]}++;
$f[1] =~ s/-//g;
${$f[1]}{$cmd}++;
} else {
$bad{$cmd}++;
}
}
# get list file
# newinfo list passwd
elsif ($cmd eq "get" ||
$cmd eq "newinfo")
{
if ($#f == 2) {
$lists{$f[1]}++;
$f[1] =~ s/-//g;
${$f[1]}{$cmd}++;
if ($cmd eq "get") {
$req = &ParseAddrs($who);
$long{$req} = $who;
$getcount{$req}++;
}
} else {
$bad{$cmd}++;
}
}
# subscribe list [address]
# unsubscribe list [address]
elsif ($cmd eq "subscribe" ||
$cmd eq "unsubscribe")
{
if ($#f >= 1) {
$lists{$f[1]}++;
$f[1] =~ s/-//g;
${$f[1]}{$cmd}++;
} else {
$bad{$cmd}++;
}
}
# request cmd list subscribe (for approval)
elsif ($cmd eq "request") {
if ($#f >= 2) {
$lists{$f[2]}++;
$f[2] =~ s/-//g;
${$f[2]}{$cmd}++;
} else {
$bad{$cmd}++;
}
}
else {
$unrecognized{$cmd}++;
}
} else {
warn "line $. didn't match!\n" if !/^$/;
}
}
#print "Command summary:\n";
#foreach $cmd (sort keys %count) {
# printf " %-20s %4d\n", $cmd, $count{$cmd};
#}
print "Global commands:\n";
printf(" %-15s %4d\n", "help", $help) if defined($help);
printf(" %-15s %4d\n", "lists", $lists) if defined($lists);
printf(" %-15s %4d\n", "which", $which) if defined($which);
print "\n";
#print "Unrecognized commands:\n";
#foreach $cmd (sort keys %unrecognized) {
# printf " %-15s %4d\n", $cmd, $unrecognized{$cmd};
#}
#print "\n";
if (defined(%bad)) {
print "Incomplete commands:\n";
foreach $cmd (sort keys %bad) {
printf " %-15s %4d\n", $cmd, $bad{$cmd};
}
print "\n";
}
# skip request and newinfo
print "List subscr unsub index get info who config approve\n";
foreach $list (sort keys %lists) {
printf "%-20s", substr($list,0,20);
$list =~ s/-//g;
%l = %{$list};
printf " %6d %6d %6d %6d %6d %6d %6d %6d\n", $l{subscribe}, $l{unsubscribe},
$l{index}, $l{get}, $l{info}, $l{who}, $l{config}, $l{approve};
}
print "\n";
@reqs = sort {$getcount{$b}<=>$getcount{$a};} keys %getcount;
if ($#reqs >= 0) {
print "Top requestors (get command):\n";
for ($i=0; $i < 5; $i++) {
printf " %5d %s\n", $getcount{$reqs[$i]}, $long{$reqs[$i]};
last if ($i == $#reqs);
}
}
# from majordomo.pl, modified to work on a single address
# $addrs = &ParseAddrs($addr_list)
sub ParseAddrs {
local($_) = shift;
1 while s/\([^\(\)]*\)//g; # strip comments
1 while s/"[^"]*"//g; # strip comments
1 while s/.*<(.*)>.*/\1/;
s/^\s+//;
s/\s+$//;
$_;
}

View File

@@ -0,0 +1,98 @@
#!/bin/perl
#
# Given an archive directory, create a table of contents file and a topics
# file. The table of contents file simply lists each subject that appears
# in each archive file, while the topics file is a list of each unique
# subject and the files that subject appears in.
#
# I run this from cron every night....
#
# Paul Close, April 1994
#
if ($#ARGV != -1) {
$dir = $ARGV[0];
shift;
}
else {
die "usage: $0 archive_directory\n";
}
opendir(FILES, $dir) || die "Can't open directory $dir: $!\n";
@files = readdir(FILES); # get all files in archive directory
closedir(FILES);
open(INDEX,">$dir/CONTENTS") || die "Can't open $dir/CONTENTS: $!\n";
open(TOPICS,">$dir/TOPICS") || die "Can't open $dir/TOPICS: $!\n";
foreach $basename (@files) {
next if $basename eq '.';
next if $basename eq '..';
next if $basename eq "CONTENTS";
next if $basename eq "TOPICS";
print INDEX "\n$basename:\n";
open(FILE, "$dir/$basename") || next;
while (<FILE>) {
if (/^Subject:\s+(.*)/i) {
($subj = $1) =~ s/\s*$//;
next if $subj eq "";
#
# for index file, just print the subject
#
print INDEX " $subj\n";
#
# for topics file, strip Re:'s, remove digest postings,
# and trim the length to 40 chars for pretty-printing.
#
1 while ($subj =~ s/^Re(\[\d+\]|2?):\s*//i); # trim all Re:'s
next if $subj eq "";
next if $subj =~ /[A-Za-z]+ Digest, Volume \d+,/i;
next if $subj =~ /[A-Za-z]+ Digest V\d+ #\d+/i;
if (length($subj) > 40) {
$subj = substr($subj, 0, 37) . "...";
}
#
# Make a key that's all lower case, and no whitespace to
# reduce duplicate topics that differ only by those. This
# also results in a list of topics sorted case-independent.
#
($key = $subj) =~ tr/A-Z/a-z/;
$key =~ s/\s+//g;
$subjlist{$key} .= "$basename,";
if (!defined($realsubj{$key})) {
$realsubj{$key} = $subj;
}
}
}
close(FILE);
}
close(INDEX);
foreach $subj (sort keys %subjlist) {
#
# for each subject, record each file it was found in
#
undef %found;
undef @names;
for (split(",", $subjlist{$subj})) {
$found{$_} = 1;
}
#
# make list of 'found' names and wrap at 80 columns
#
$names = join(", ", sort keys %found);
undef @namelist;
while (length($names) > 40) {
$index = 40;
$index-- until (substr($names, $index, 1) eq " " || $index < 0);
push(@namelist,substr($names,0,$index));
$names = substr($names,$index+1);
}
push(@namelist,$names);
printf TOPICS "%-40s %s\n", $realsubj{$subj}, $namelist[0];
for ($i=1; $i <= $#namelist; $i++) {
print TOPICS " " x 41, $namelist[$i], "\n";
}
}
close(TOPICS);

View File

@@ -0,0 +1,103 @@
#!/bin/perl
# $Source: /sources/cvsrepos/majordomo/contrib/new-list,v $
# $Revision: 1.14 $
# $Date: 1996/12/09 16:50:45 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
# set our path explicitly
$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
require "majordomo.pl";
require "shlock.pl";
&ParseMailHeader(STDIN, *hdrs);
$reply_to = &RetMailAddr(*hdrs);
$reply_to = join(", ", &ParseAddrs($reply_to));
die("new-list: $reply_to is not a valid return address.\n")
if (! &valid_addr($reply_to));
$in_reply_to = $hdrs{"message-id"} . ", from " . $hdrs{"from"};
$list = $ARGV[0];
# Define all of the mailer properties:
# It is possible that one or both of $sendmail_command and $bounce_mailer
# are not defined, so we provide reasonable defaults.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$bounce_mailer = "$sendmail_command -f\$sender -t"
unless defined $bounce_mailer;
$sender = "$list-approval";
$mailcmd = eval qq/"$bounce_mailer"/;
if (defined($isParent = open(MAIL, "|-"))) {
&do_exec_sendmail(split(' ', $mailcmd))
unless $isParent;
} else {
&abort("Failed to fork prior to mailer exec");
}
print MAIL <<"EOM";
To: $reply_to
Cc: $list-approval
From: $list-approval
Subject: Your mail to $list\@$whereami
In-Reply-To: $in_reply_to
Reply-To: $list-approval\@$whereami
This pre-recorded message is being sent in response to your recent
email to $list\@$whereami.
If you were trying to subscribe to the list, please send your request
to $whoami, not to $list\@$whereami.
This is a new list. Your message is being returned unsent, but please
hold on to it. After a few days, when the flood of subscription
requests has died down somewhat, the owner of the list will announce
that the list is "open for business"; you should resubmit your posting
then. This way, everybody who joins the list within the first few days
of its existence starts out on an even footing, and we don't end up
with every other message asking "what did I miss?".
Here's your original, unsent message:
EOM
;
foreach ("From", "To", "Cc", "Subject", "Date", "Message-ID") {
($hdr = $_) =~ tr/A-Z/a-z/;
if (defined($hdrs{$hdr})) {
print MAIL $_, ": ", $hdrs{$hdr}, "\n";
}
}
print MAIL "\n";
while (<STDIN>) {
print MAIL $_;
}
close(MAIL);
exit 0;

View File

@@ -0,0 +1,559 @@
#!/usr/bin/perl -U
# Copyright 1996 MACS, Inc.
# Copyright 1992, D. Brent Chapman. See the Majordomo license agreement
# for usage rights.
#
# $Source: /sources/cvsrepos/majordomo/contrib/sequencer,v $
# $Revision: 1.2 $
# $Date: 1996/12/09 16:50:48 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
# sequence - a program for sequencing and archiving e-mail messages
# from majordomo
#
# Based heavily upon the resend script included in the majordomo distribution
# set our path explicitly
$ENV{'PATH'} = "/bin:/usr/bin:/usr/sbin:/sbin";
# What shall we use for temporary files?
$tmp = "/tmp/majordomo.$$";
# Before doing anything else tell the world I am sequencer
# The mj_ prefix is reserved for tools that are part of majordomo proper.
$main'program_name = 'sequencer';
# If the first argument is "@filename", read the real arguments
# from "filename", and shove them onto the ARGV for later processing
# by &Getopts()
if ($ARGV[0] =~ /^@/) {
$fn = shift(@ARGV);
$fn =~ s/^@//;
open(AV, $fn) || die("open(AV, \"$fn\"): $!\nStopped");
undef($/); # set input field separator
$av = <AV>; # read whole file into string
close(AV);
@av = split(/\s+/, $av);
unshift(@ARGV, @av);
$/ = "\n";
}
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
use Getopt::Std;
require "majordomo.pl";
require "majordomo_version.pl";
require "config_parse.pl";
require "shlock.pl";
getopts("Aa:df:h:I:l:m:M:nNp:Rr:s") || die("sequencer: Getopts() failed: $!");
if (! defined($opt_l) || ! defined($opt_h)) {
die("sequencer: must specify both '-l list' and '-h host' arguments");
}
# smash case for the list name
$opt_l =~ tr/A-Z/a-z/;
if ( ! @ARGV) {
die("sequencer: must specify outgoing list as last arg(s)");
}
$opt_r = "$opt_r@$opt_h" if ( defined($opt_r) );
&get_config($listdir, $opt_l);
$opt_A = &cf_ck_bool($opt_l,"moderate") if &cf_ck_bool($opt_l,"moderate");
$opt_h = $config_opts{$opt_l,"resend_host"}
if($config_opts{$opt_l,"resend_host"} ne '');
$opt_a = $config_opts{$opt_l,"approve_passwd"}
if ($config_opts{$opt_l,"approve_passwd"} ne '');
$opt_M = $config_opts{$opt_l,"maxlength"}
if ($config_opts{$opt_l,"maxlength"} ne '');
$opt_f = $config_opts{$opt_l,"sender"}
if ($config_opts{$opt_l,"sender"} ne '');
$opt_p = $config_opts{$opt_l,"precedence"}
if ($config_opts{$opt_l,"precedence"} ne '');
$opt_r = $config_opts{$opt_l,"reply_to"}
if ($config_opts{$opt_l,"reply_to"} ne '');
$opt_I = $config_opts{$opt_l,"restrict_post"}
if ($config_opts{$opt_l,"restrict_post"} ne '');
$opt_R = &cf_ck_bool($opt_l,"purge_received")
if &cf_ck_bool($opt_l,"purge_received");
$opt_s = &cf_ck_bool($opt_l,"administrivia")
if &cf_ck_bool($opt_l,"administrivia");
$opt_d = &cf_ck_bool($opt_l,"debug")
if &cf_ck_bool($opt_l,"debug");
if (defined($opt_f)) {
$sendmail_sender = $opt_f;
} else {
$sendmail_sender = "$opt_l-request";
}
if (defined($opt_a)) {
if ($opt_a =~ /^\//) {
open(PWD, $opt_a) || die("sequencer: open(PWD, \"$opt_a\"): $!");
$opt_a = &chop_nl(<PWD>);
}
}
if (defined($opt_A) && ! defined($opt_a)) {
die("sequencer: must also specify '-a passwd' if using '-A' flag");
}
# code added for getting new sequence number
if (defined($opt_N)) {
$opt_n = $opt_N;
}
if (defined($opt_n)) {
$seqfile = "$listdir/$opt_l.seq";
if (! -r $seqfile) { # if there is no sequence file, make one
open(SEQ, ">$seqfile") || die("sequencer: open of $seqfile failed: $!");
print SEQ "1\n";
close SEQ;
}
&main'lopen(SEQ, "<", "$seqfile") || die("sequencer: locked open of $seqfile failed: $!");
chop($seqnum = <SEQ>);
# note that the sequence file is opened and locked from here until
# the message is sent
}
$sender = "$sendmail_sender@$opt_h";
&open_temp(OUT, "/tmp/sequencer.$$.out") ||
&abort("sequencer:1 Can't open /tmp/sequencer.$$.out: $!");
&open_temp(IN, "/tmp/sequencer.$$.in") ||
&abort("sequencer: Can't open /tmp/sequencer.$$.in: $!");
while (<STDIN>) {
print IN $_;
}
close(IN);
open(IN, "/tmp/sequencer.$$.in") ||
die("sequencer: Can't open /tmp/sequencer.$$.tmp: $!");
do {
$restart = 0;
$pre_hdr = 1;
while (<IN>) {
if ($pre_hdr) {
if (/^\s*$/) {
# skip leading blank lines; usually only there if this is a
# restart after an in-body "Approved:" line
next;
} else {
$pre_hdr = 0;
$in_hdr = 1;
$kept_last = 0;
}
}
if ($in_hdr) {
if (/^\s*$/) {
# end of header; add new header fields
# if there is no subject, create one
if (!defined($subject)) {
local($foo);
if ($config_opts{$opt_l,"subject_prefix"} ne '') {
$foo = &config'substitute_values(
$config_opts{$opt_l,"subject_prefix"}, $opt_l);
# for sequencing we add a special keyword!
if (defined($opt_n)) {
$foo =~ s/\$SEQNUM/$seqnum/;
}
local($foo_pat) = $foo;
$foo_pat =~ s/(\W)/\\$1/g;
if (!/$foo_pat/) {
$foo = $foo . " ";
}
}
$subject = $foo . "Message for " . $opt_l;
print OUT $subject, "\n";
}
print OUT "Sender: $sender\n";
if (defined($opt_p)) {
print OUT "Precedence: $opt_p\n";
}
if (defined($opt_r)) {
print OUT "Reply-To: ", &config'substitute_values($opt_r),
"\n";
}
# print out additonal headers
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;
print OUT $headers;
}
$in_hdr = 0;
print OUT $_;
# print out front matter
if ( $config_opts{$opt_l,"message_fronter"} ne '' ) {
local($fronter) = &config'substitute_values (
$config_opts{$opt_l,"message_fronter"}, $opt_l);
$fronter =~ s/\001|$/\n/g;
print OUT $fronter;
}
} elsif (/^approved:\s*(.*)/i && defined($opt_a)) {
$approved = &chop_nl($1);
if ($approved ne $opt_a &&
!(&main'valid_passwd($listdir, $opt_l, $approved))) {
&bounce("Invalid 'Approved:' header");
}
} elsif (/^from /i # skip all these headers
|| /^sender:/i
|| /^return-receipt-to:/i
|| /^errors-to:/i
|| /^return-path:/i
|| (/^reply-to:/i && defined($opt_r)) # skip only if "-r" set
|| (/^precedence:/i && defined($opt_p)) # skip only if "-p" set
|| (/^received:/i && defined($opt_R)) # skip only if "-R" set
|| (/^\s/ && ! $kept_last) # skip if skipped last
) {
# reset $kept_last in case next line is continuation
$kept_last = 0;
} else {
# check for administrivia requests
if (defined($opt_s) && ! defined($approved)
&& (/^subject:\s*subscribe\b/i ||
/^subject:\s*unsubscribe\b/i ||
/^subject:\s*help\b/i ||
/^subject:\s*RCPT:\b/ ||
/^subject:\s*Delivery Confirmation\b/ ||
/^subject:\s*NON-DELIVERY of:/ ||
/^subject:\s*Undeliverable Message\b/ ||
/^subject:\s*Receipt Confirmation\b/ ||
/^subject:\s*Failed mail\b/ ||
/^subject:\s.*\bchange\b.*\baddress\b/ ||
/^subject:\s*request\b.*\baddition\b/i)) {
&bounce("Admin request");
}
# prepend subject prefix
if ( (/^subject:\s*/i) &&
($config_opts{$opt_l,"subject_prefix"} ne '')
) {
local($foo) = &config'substitute_values(
$config_opts{$opt_l,"subject_prefix"}, $opt_l);
# for sequencing we add a special keyword!
if (defined($opt_n)) {
$foo =~ s/\$SEQNUM/$seqnum/;
}
$subject = $_;
$subject =~ s/^subject:\s*(.*)/$1/i;
$subject = &chop_nl($foo . " " . $subject);
local($foo_pat) = $foo;
$foo_pat =~ s/(\W)/\\$1/g;
s/^subject:\s*/Subject: $foo /i if !/$foo_pat/;
}
if ( /^from:\s*(.+)/i )
{
$from = $1;
$from_last = 1;
}
elsif ( defined($from_last) )
{
if ( /^\s+(.+)/ )
{
$from .= " $1";
}
else
{
undef($from_last);
}
}
&check_hdr_line($_); # check for length & balance
$kept_last = 1;
print OUT $_;
}
} else {
# this isn't a header line, so print it (maybe)
# first, though, is the first line of the body an "Approved:" line?
if (($body_len == 0) && /^approved:\s*(.*)/i && defined($opt_a)) {
# OK, is it a valid "Approved:" line?
$approved = &chop_nl($1);
if ($approved ne $opt_a &&
!(&main'valid_passwd($listdir, $opt_l, $approved))) {
&bounce("Invalid 'Approved:' header");
} else {
# Yes, it's a valid "Approved:" line...
# So, we start over
$restart = 1;
close(OUT);
unlink("/tmp/sequencer.$$.out");
&open_temp(OUT, "/tmp/sequencer.$$.out") ||
&abort("sequencer:2 Can't open /tmp/sequencer.$$.out: $!");
last;
}
}
$body_len += length($_);
# make sure it doesn't make the message too long
if (defined($opt_M) && ! defined($approved)
&& ($body_len > $opt_M)) {
&bounce("Message too long (>$opt_M)");
}
# add admin-request recognition heuristics here... (body)
if (defined($opt_s) && ! defined($approved) && ($body_line++ < 5) && (
/\badd me\b/i
|| /\bdelete me\b/i || /\bremove\s+me\b/i
|| /\bchange\b.*\baddress\b/
|| /\bsubscribe\b/i || /^sub\b/i
|| /\bunsubscribe\b/i || /^unsub\b/i
|| /^\s*help\s*$/i # help
|| /^\s*info\s*$/i # info
|| /^\s*info\s+\S+\s*$/i # info list
|| /^\s*lists\s*$/i # lists
|| /^\s*which\s*$/i # which
|| /^\s*which\s+\S+\s*$/i # which address
|| /^\s*index\s*$/i # index
|| /^\s*index\s+\S+\s*$/i # index list
|| /^\s*who\s*$/i # who
|| /^\s*who\s+\S+\s*$/i # who list
|| /^\s*get\s+\S+\s*$/i # get file
|| /^\s*get\s+\S+\s+\S+\s*$/i # get list file
|| /^\s*approve\b/i
|| /^\s*passwd\b/i
|| /^\s*newinfo\b/i
|| /^\s*config\b/i
|| /^\s*newconfig\b/i
|| /^\s*writeconfig\b/i
|| /^\s*mkdigest\b/i
)) {
&bounce("Admin request");
}
print OUT $_;
}
}
} while ($restart);
if ( $config_opts{$opt_l,"message_footer"} ne '' ) {
local($footer) = &config'substitute_values(
$config_opts{$opt_l,"message_footer"}, $opt_l);
$footer =~ s/\001/\n/g;
print OUT $footer;
}
close(OUT);
if ( defined($opt_I) && defined($from) && ! defined($approved) ) {
local($infile) = 0;
@files = split (/[:\t\n]+/, $opt_I);
foreach $file (@files) {
if ($file !~ /^\//) {
$file = "$listdir/$file";
}
if ( open (LISTFD, "<${file}") != 0 ) {
@output = grep (&addr_match($from, $_), <LISTFD>);
close (LISTFD);
if ( $#output != -1 ) {
$infile = 1;
last;
}
} else {
die("sequencer:Can't open $file: $!");
}
}
if ( $infile == 0 ) {
&bounce ("Non-member submission from [$from]");
}
}
if (defined($opt_A) && ! defined($approved)) {
&bounce("Approval required");
}
$sendmail_cmd = "/usr/lib/sendmail $opt_m -f$sendmail_sender " .
join(" ", @ARGV);
if (defined($opt_d)) {
$| = 1;
print "Command: $sendmail_cmd\n";
$status = (system("cat /tmp/sequencer.$$.out") >> 8);
unlink(</tmp/sequencer.$$.*>);
#remember to unlock the sequence file here!
if (defined($opt_n)) {
&main'lclose(SEQ);
}
exit($status);
} else {
local(*MAILOUT, *MAILIN, @mailer);
@mailer = split(' ', "$sendmail_cmd");
open(MAILOUT, "|-") || &do_exec_sendmail(@mailer);
# create archival copy
if (defined($opt_N)) {
if (open (INDEX, ">>$filedir/$opt_l$filedir_suffix/INDEX")) {
$timenow = localtime(time);
printf(INDEX "%s\n\tFrom %s on %s\n", $subject, $from, $timenow);
close (INDEX);
}
open (ARCHIVE, ">$filedir/$opt_l$filedir_suffix/$seqnum");
}
open(MAILIN, "/tmp/sequencer.$$.out");
while (<MAILIN>) {
print MAILOUT $_;
if (defined($opt_N)) {
print ARCHIVE $_;
}
}
close(MAILOUT);
if (defined($opt_N)) {
close(ARCHIVE);
}
if (defined($opt_n)) {
$seqnum++;
&main'lreopen(SEQ, ">", "$seqfile");
print SEQ $seqnum, "\n";
&main'lclose(SEQ);
}
close(MAILIN);
unlink(</tmp/sequencer.$$.*>);
exit(0);
}
sub check_balance {
# set a temporary variable
local($t) = shift;
# strip out all nested parentheses
1 while $t =~ s/\([^\(\)]*\)//g;
# strip out all nested angle brackets
1 while $t =~ s/\<[^\<\>]*\>//g;
# if any parentheses or angle brackets remain, were imbalanced
if ($t =~ /[\(\)\<\>]/ && ! defined($approved)) {
&bounce("Imbalanced parentheses or angle brackets");
return(undef);
}
return(1);
}
sub check_hdr_line {
local($_) = shift;
if (! /^\s/) { # is this a continuation line?
# Not a continuation line.
# If $balanced_fld is defined, it means the last field was one
# that needed to have balanced "()" and "<>" (i.e., "To:", "From:",
# and "Cc:", so check it. We do it here in case the last field was
# multi-line.
if (defined($balanced_fld)) {
&check_balance($balanced_fld);
}
# we undefine $balanced_fld and reset $field_len; these may be set below
undef($balanced_fld);
$field_len = 0;
}
# is this a field that must be checked for balanced "()" and "<>"?
if (defined($balanced_fld) || /^from:/i || /^cc:/i || /^to:/i) {
# yes it is, but we can't check it yet because there might be
# continuation lines. Buffer it to be checked at the beginning
# of the next non-continuation line.
# is this line too long?
if ((length($_) > 128) && ! defined($approved)) {
&bounce("Header line too long (>128)");
return(undef);
}
# is this field too long?
if ((($field_len += length($_)) > 1024) && ! defined($approved)) {
&bounce("Header field too long (>1024)");
return(undef);
}
$balanced_fld .= $_;
chop($balanced_fld);
}
# if we get here, everything was OK.
return(1);
}
sub bounce {
local($reason) = shift;
local($_);
&resend_sendmail(BOUNCE, $sender, "BOUNCE $opt_l@$opt_h: $reason");
seek(IN, 0, 0);
while (<IN>) {
print BOUNCE $_;
}
close(BOUNCE);
unlink(</tmp/sequencer.$$.*>);
exit(0);
}
sub resend_sendmail {
local(*MAIL) = shift;
local($to) = shift;
local($subject) = shift;
# clean up the addresses, for use on the sendmail command line
local(@to) = &ParseAddrs($to);
for (@to) {
$_ = join(", ", &ParseAddrs($_));
}
$to = join(", ", @to);
# open the process
if (defined($opt_d)) {
# debugging, so just say it, don't do it
open(MAIL, ">-");
print MAIL ">>> /usr/lib/sendmail -f$sendmail_sender -t\n";
} else {
local(@mailer) = split(' ',"/usr/lib/sendmail -f$sendmail_sender -t");
open(MAIL, "|-") || &do_exec_sendmail(@mailer);
}
# generate the header
print MAIL <<"EOM";
To: $to
From: $sender
Subject: $subject
EOM
return;
}

View File

@@ -0,0 +1,504 @@
#!/bin/perl
# Original from J Greely <jgreely@cis.ohio-state.edu>, 9/30/92
#
# Heavily modified by Brent Chapman <Brent@GreatCircle.COM>
# $Source: /sources/cvsrepos/majordomo/digest,v $
# $Revision: 1.24 $
# $Date: 2000/01/07 11:04:34 $
# $Author: cwilson $
# $State: Exp $
#
# $Header: /sources/cvsrepos/majordomo/digest,v 1.24 2000/01/07 11:04:34 cwilson Exp $
#
#
# Before doing anything else tell the world I am majordomo
# The mj_ prefix is reserved for tools that are part of majordomo proper.
$main'program_name = 'mj_digest'; # ';
&init;
&readconfig;
$TEMP = (defined $TMPDIR && -d $TMPDIR) ?
"$TMPDIR/digest.$$" : "/usr/tmp/digest.$$";
if (defined($opt_r)) {
&receive_message;
if (&should_be_sent(1)) {
&make_digest;
}
} elsif (defined($opt_R)) {
&receive_message;
} elsif (defined($opt_m)) {
&make_digest;
} elsif (defined($opt_p)) {
if (&should_be_sent(1)) {
&make_digest;
}
} else {
&abort("Usage: digest {-r|-R|-m|-p} [-c config|(-C -l list)]\nStopped");
}
&free_lock($lockfile);
exit(0);
sub receive_message {
$i = 0;
do {
$file = sprintf("%s/%03d", $V{'INCOMING'}, ++$i);
} until (! -e $file);
print STDERR "Receiving $i\n";
open(MSG, ">$file") || &abort("open(MSG, \">$file\"): $!");
# copy the message
while (<STDIN>) {
print MSG $_;
}
close(MSG);
}
#
# Use config variables to determine if a digest should be contructed
# and sent, or not. Measures line count and byte count of messages
# as they would appear in the digest, not as they exist in the spool
# dir. Side-effect: $file is the last file that should be included
# in this digest, based on the config variables.
#
sub should_be_sent {
# fudge factors for headers and footers
$sum = 600 + length($HEADER) + length($HEADERS) + length($TRAILER);
$lines = 25 + ($HEADER =~ s/\n/\n/g) + ($HEADERS =~ s/\n/\n/g) +
($TRAILER =~ s/\n/\n/g);
##print "start: lines = $lines\n";
$i = shift;
while (1) {
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, $i++);
last unless (-e $nextfile);
$file = $nextfile;
open(COUNT, "<$file") || &abort("open(COUNT, \"<$file\"): $!");
$/ = ''; # grab the header
$head = <COUNT>;
# only count From/Date/Subject header fields to get a
# more accurate size and line count.
$head =~ s/\n\s+/ /g;
$head =~ /^(From:\s+.*)/i && ($sum += length($1)+1, $lines++);
$head =~ /^(Subject:\s+.*)/i && ($sum += length($1)+1, $lines++);
$head =~ /^(Date:\s+.*)/i && ($sum += length($1)+1, $lines++);
$sum++, $lines++;
# count the body of the message
undef $/;
$body = <COUNT>;
$sum += length($body);
$lines += ($body =~ s/\n/\n/g); # count newlines
$/ = "\n";
close(COUNT);
$sum += length($EB) + 3, $lines += 3; # account for message delimiter
##printf "After message %03d, lines = $lines\n", $i-1;
if ($V{'DIGEST_SIZE'} && $sum > $V{'DIGEST_SIZE'}) {
return(1);
}
if ($V{'DIGEST_LINES'} && $lines > $V{'DIGEST_LINES'}) {
return(1);
}
if ($V{'MAX_AGE'} && (-M $file) > $V{'MAX_AGE'}) {
return(1);
}
}
return(0);
}
#
# Loop through calling 'should_be_sent' to find out how large each digest
# should be and calling send_digest to construct and send each digest.
# All the files in the spool directory are sent. This could be modified
# to only send "complete" digests.
#
# Note that this will quietly terminate if there are no messages in the
# spool. I find this preferable to an abort.
#
sub make_digest {
# disable age detection
$V{'MAX_AGE'} = 0;
# use 'should_be_sent' to find out how large each digest should be
# and loop through the spool dir until it's empty
$fnum = 0;
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, ++$fnum);
while (-e $nextfile) {
# starts at $fnum, sets '$file' to the last file to use
&should_be_sent($fnum);
&send_digest($file);
($fnum) = $file =~ m#/(\d+)$#;
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, ++$fnum);
$NUMBER++;
}
if (! $opt_d) {
if ( ! defined($opt_C) ) {
open(NUM_FILE, ">$V{'NUM_FILE'}") ||
&abort("open(NUM_FILE, \">$NUM_FILE\"): $!");
printf NUM_FILE "%d\n", $NUMBER;
close(NUM_FILE);
} else { # hurrah we are using the majordomo config file
$config_opts{$opt_l,"digest_issue"} = $NUMBER;
&config'writeconfig($listdir, $opt_l);
}
}
}
#
# Contruct and send a digest using files in the spool directory up to and
# including the "last file" specified as the first argument.
#
sub send_digest {
local($lastfile) = shift;
if (opendir(DIR, $V{'INCOMING'})) {
@files = grep(/^\d+$/, readdir(DIR));
closedir(DIR);
}
else {
&abort("Error opening $V{'INCOMING'}: $!\nStopped ");
}
&abort("No messages.\nStopped ") unless @files;
open(TEMP,">$TEMP") || &abort("$TEMP: $!\n");
print STDERR "producing $V{'NAME'} V$VOLUME #$NUMBER\n";
foreach (sort(@files)) {
$message = "$V{'INCOMING'}/$_";
open(message) || &abort("$message: $!\n");
print STDERR "\tprocessing $message\n";
push(@processed,$message);
$/ = '';
$head = <message>;
$head =~ s/\n\s+/ /g;
$body = "";
$subj = ($head =~ /^Subject:\s+(.*)/i)? $1: "[none]";
($from) = $head =~ /^From:\s+(.*)/i;
($date) = $head =~ /^Date:\s+(.*)/i;
undef $/;
$body = <message>;
close(message);
# trim message fronter and footers inserted by resend in
# non digest version of list
if ($RMHEADER) {
$body =~ s/$RMHEADER/\n/;
}
if ($RMTRAILER) {
$body =~ s/$RMTRAILER/\n/;
}
# escape ^From <user> <weekday> <month> <day> <hr:min:sec> ...
$body =~
s/^From (\S+\s+\w{3}\s+\w{3}\s+\d+\s+\d+:\d+:\d+)/>From $1/g;
$body =~ s/^-/- -/g; # escape encapsulation boundaries in message
# trim trailing \n's
$len = length($body) - 1;
$len-- while (substr($body,$len,1) eq "\n");
substr($body,$len+1) = "";
$/ = "\n";
## note -- RFC 1153 claims the following headers should be retained, and
## presented in the following order:
## Date:, From:, To:, Cc:, Subject:, Message-ID:, and Keywords:
push(@subj,$subj);
print TEMP <<EOF;
Date: $date
From: $from
Subject: $subj
$body
$EB
EOF
last if ($message eq $lastfile);
}
close(TEMP);
if ($opt_d) {
$DIGEST = "$TMPDIR/testdigest.$NUMBER";
} else {
$DIGEST = sprintf("%s/v%02d.n%03d", $V{'ARCHIVE'}, $VOLUME, $NUMBER);
}
open(DIGEST, ">$DIGEST") || &abort("open(DIGEST, \">$DIGEST\"): $!");
print DIGEST <<EOF;
From: $V{'FROM'} ($V{'NAME'})
To: $V{'TO'}
Subject: $V{'NAME'} V$VOLUME #$NUMBER
Reply-To: $V{'REPLY-TO'}
Sender: $V{'ERRORS-TO'}
Errors-To: $V{'ERRORS-TO'}
Precedence: $Precedence
$HEADERS
EOF
$PDATE = &getdate();
$volstr = sprintf("Volume %02d : Number %03d\n\n",$VOLUME,$NUMBER);
$width = length($V{'NAME'}) + length($PDATE) + length($volstr);
if ($width < 76) {
$center = " " x int((78 - $width) / 2);
} else {
$center = " ";
}
print DIGEST $V{'NAME'},$center,$PDATE,$center,$volstr,"\n\n";
foreach (split(/\n/,$HEADER)) {
if (/_SUBJECTS_/) {
$pre = $`;
foreach $subj (@subj) {
print DIGEST $pre,$subj,"\n";
}
}else{
print DIGEST "$_\n";
}
}
print DIGEST "\n";
print DIGEST "-" x 70,"\n\n";
open(TEMP);
print DIGEST <TEMP>;
close(TEMP);
unlink($TEMP);
$end = sprintf("End of %s V%d #%d", $V{'NAME'}, $VOLUME, $NUMBER);
print DIGEST $end, "\n";
print DIGEST "*" x length($end), "\n";
print DIGEST "\n";
print DIGEST $TRAILER;
close(DIGEST);
if ($opt_d) {
warn "digest output in $TMPDIR/testdigest.$NUMBER\n";
} else {
$sender = $V{'ERRORS-TO'};
$mailcmd = eval qq/"$mailer"/;
system("$mailcmd $V{'REALLY-TO'} < $DIGEST");
foreach $file (@processed) {
unlink($file);
}
}
undef @subj;
undef @processed;
return 0;
}
sub init {
$HOME = $ENV{"HOME"} || (getpwuid($>))[7];
chdir($HOME);
&getopt("drRmpc:Cl:z") ||
&abort("Usage: digest {-r|-R|-m|-p} [-c config|(-C -l list)]\nStopped");
$config = $opt_c || "$HOME/.digestrc";
$SIG{'INT'} = 'cleanup';
@MONTHS = ("January","February","March","April","May","June","July",
"August","September","October","November","December");
@DAYS = ("Sunday","Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday");
$EB = "-" x 30;
}
sub readconfig {
if (defined($opt_C)) {
if (!defined($opt_l)) {
&abort("-C used without -l");
} else {
# Read and execute the .cf file
$cf = $opt_c || $ENV{"MAJORDOMO_CF"} ||
"/etc/majordomo.cf";
require "$cf";
chdir($homedir);
$opt_l =~ tr/A-Z/a-z/;
require "config_parse.pl";
# Define all of the mailer properties:
# It is possible that one or both of $sendmail_command and $bounce_mailer
# are not defined, so we provide reasonable defaults.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$mailer = "$sendmail_command -oi -oee -f\$sender"
unless defined $mailer;
$bounce_mailer = "$sendmail_command -f\$sender -t"
unless defined $bounce_mailer;
&set_abort_addr($whoami_owner);
&set_mail_from($whoami);
&set_mail_sender($whoami_owner);
&set_mailer($bounce_mailer);
# get the digest config file
# 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");
# get details of parent list footers and headers
if ($config_opts{$opt_l,"digest_rm_fronter"}) {
&get_config($listdir, $config_opts{$opt_l,"digest_rm_fronter"});
$RMHEADER = $config_opts{$config_opts{$opt_l,"digest_rm_fronter"},
"message_fronter"};
$RMHEADER =~ s/([^A-Za-z0-9 \001])/\\\1/g;
$RMHEADER =~ s/\\\$(SENDER|VERSION|LIST)/\[\^\\n\]\*/g;
$RMHEADER =~ s/\001/\\n/g;
}
if ($config_opts{$opt_l,"digest_rm_footer"}) {
if ($config_opts{$opt_l,"digest_rm_footer"} ne
$config_opts{$opt_l,"digest_rm_fronter"}) {
&get_config($listdir, $config_opts{$opt_l,"digest_rm_footer"});
}
$RMTRAILER = $config_opts{$config_opts{$opt_l,"digest_rm_footer"},
"message_footer"};
$RMTRAILER =~ s/([^A-Za-z0-9 \001])/\\\1/g;
$RMTRAILER =~ s/\\\$(SENDER|VERSION|LIST)/\[\^\\n\]\*/g;
$RMTRAILER =~ s/\001/\\n/g;
}
# map config opts to internal variables and $V array
$HEADER = $config_opts{$opt_l,"message_fronter"};
$HEADER =~ s/\001/\n/g;
$TRAILER = $config_opts{$opt_l,"message_footer"};
$TRAILER =~ s/\001/\n/g;
$VOLUME = $config_opts{$opt_l,"digest_volume"};
$NUMBER = $config_opts{$opt_l,"digest_issue"};
$Precedence = $config_opts{$opt_l,"precedence"};
$Precedence = "bulk" if ($Precedence eq "");
$V{'ARCHIVE'} = "$filedir/$opt_l$filedir_suffix";
$V{'DIGEST_SIZE'} = $config_opts{$opt_l, "maxlength"};
$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"}
||$whereami);
$V{'FROM'} = $config_opts{$opt_l, "sender"}. "@" .
($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]."@".${whereami};
$V{'REPLY-TO'} = $config_opts{$opt_l,"reply_to"};
$V{'TO'} = "$opt_l\@$whereami";
# make the headers keyword work
if ( $config_opts{$opt_l,"message_headers"} ne '' ) {
$from = $V{'FROM'};
$HEADERS = &config'substitute_values (
$config_opts{$opt_l,"message_headers"}, $opt_l);
$HEADERS =~ s/\001/\n/g;
}
} # list is defined
} else { # not using -C
require "config_parse.pl";
# Define all of the mailer properties:
# The majordomo.cf file isn't used in this option, so fake everything.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$mailer = "$sendmail_command -oi -oee -f\$sender"
unless defined $mailer;
$bounce_mailer = "$sendmail_command -fmajordomo-owner -t"
unless defined $bounce_mailer;
&set_abort_addr("majordomo-owner");
&set_mail_from("majordomo-owner");
&set_mail_sender("majordomo-owner");
&set_mailer($bounce_mailer);
open(config) || &abort("$config: $!\n");
while (<config>) {
next if /^\s*$|^\s*#/;
chop;
($key,$value) = split(/\s*=\s*/,$_,2);
$V{$key} = $value;
}
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);
open(trailer,$V{'TRAILER'}) || &abort("$V{'TRAILER'}: $!\n");
$TRAILER = join("",<trailer>);
close(trailer);
open(VOL_FILE,$V{'VOL_FILE'}) || &abort("$V{'VOL_FILE'}: $!\n");
$VOLUME = join("",<VOL_FILE>);
chop($VOLUME);
close(VOL_FILE);
open(NUM_FILE,$V{'NUM_FILE'}) || &abort("$V{'NUM_FILE'}: $!\n");
$NUMBER = join("",<NUM_FILE>);
chop($NUMBER);
close(NUM_FILE);
} # end not using -C
}
#my favorite of the existing getopt routines; twisted
#
sub getopt {
local($_,%opt,$rest) = (split(/([^:])/,$_[0]),'');
while ($_ = $ARGV[0], /^-(.)/ && shift(@ARGV)) {
$rest = $';
last if $1 eq '-';
if (!defined $opt{$1}) {
warn "Unrecognized switch \"-$1\".\n";
return 0;
}elsif ($opt{$1}) {
$rest = shift(@ARGV) if $rest eq '';
eval "\$opt_$1 = \$rest";
}else{
eval "\$opt_$1 = 1";
$rest =~ /^(.)/;
redo if $rest ne '';
}
}
return 1;
}
sub cleanup {
unlink($TEMP);
exit(1);
}
sub getdate {
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
return("$DAYS[$wday], $MONTHS[$mon] $mday $year");
}
sub abort {
local($msg) = shift;
&free_lock($lockfile) if $lock_set;
die($msg);
}

View File

@@ -0,0 +1,503 @@
#!/bin/perl
# Original from J Greely <jgreely@cis.ohio-state.edu>, 9/30/92
#
# Heavily modified by Brent Chapman <Brent@GreatCircle.COM>
# $Source: /sources/cvsrepos/majordomo/digest,v $
# $Revision: 1.24 $
# $Date: 2000/01/07 11:04:34 $
# $Author: cwilson $
# $State: Exp $
#
# $Header: /sources/cvsrepos/majordomo/digest,v 1.24 2000/01/07 11:04:34 cwilson Exp $
#
#
# Before doing anything else tell the world I am majordomo
# The mj_ prefix is reserved for tools that are part of majordomo proper.
$main'program_name = 'mj_digest'; # ';
&init;
&readconfig;
$TEMP = (defined $TMPDIR && -d $TMPDIR) ?
"$TMPDIR/digest.$$" : "/usr/tmp/digest.$$";
if (defined($opt_r)) {
&receive_message;
if (&should_be_sent(1)) {
&make_digest;
}
} elsif (defined($opt_R)) {
&receive_message;
} elsif (defined($opt_m)) {
&make_digest;
} elsif (defined($opt_p)) {
if (&should_be_sent(1)) {
&make_digest;
}
} else {
&abort("Usage: digest {-r|-R|-m|-p} [-c config|(-C -l list)]\nStopped");
}
&free_lock($lockfile);
exit(0);
sub receive_message {
$i = 0;
do {
$file = sprintf("%s/%03d", $V{'INCOMING'}, ++$i);
} until (! -e $file);
print STDERR "Receiving $i\n";
open(MSG, ">$file") || &abort("open(MSG, \">$file\"): $!");
# copy the message
while (<STDIN>) {
print MSG $_;
}
close(MSG);
}
#
# Use config variables to determine if a digest should be contructed
# and sent, or not. Measures line count and byte count of messages
# as they would appear in the digest, not as they exist in the spool
# dir. Side-effect: $file is the last file that should be included
# in this digest, based on the config variables.
#
sub should_be_sent {
# fudge factors for headers and footers
$sum = 600 + length($HEADER) + length($HEADERS) + length($TRAILER);
$lines = 25 + ($HEADER =~ s/\n/\n/g) + ($HEADERS =~ s/\n/\n/g) +
($TRAILER =~ s/\n/\n/g);
##print "start: lines = $lines\n";
$i = shift;
while (1) {
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, $i++);
last unless (-e $nextfile);
$file = $nextfile;
open(COUNT, "<$file") || &abort("open(COUNT, \"<$file\"): $!");
$/ = ''; # grab the header
$head = <COUNT>;
# only count From/Date/Subject header fields to get a
# more accurate size and line count.
$head =~ s/\n\s+/ /g;
$head =~ /^(From:\s+.*)/i && ($sum += length($1)+1, $lines++);
$head =~ /^(Subject:\s+.*)/i && ($sum += length($1)+1, $lines++);
$head =~ /^(Date:\s+.*)/i && ($sum += length($1)+1, $lines++);
$sum++, $lines++;
# count the body of the message
undef $/;
$body = <COUNT>;
$sum += length($body);
$lines += ($body =~ s/\n/\n/g); # count newlines
$/ = "\n";
close(COUNT);
$sum += length($EB) + 3, $lines += 3; # account for message delimiter
##printf "After message %03d, lines = $lines\n", $i-1;
if ($V{'DIGEST_SIZE'} && $sum > $V{'DIGEST_SIZE'}) {
return(1);
}
if ($V{'DIGEST_LINES'} && $lines > $V{'DIGEST_LINES'}) {
return(1);
}
if ($V{'MAX_AGE'} && (-M $file) > $V{'MAX_AGE'}) {
return(1);
}
}
return(0);
}
#
# Loop through calling 'should_be_sent' to find out how large each digest
# should be and calling send_digest to construct and send each digest.
# All the files in the spool directory are sent. This could be modified
# to only send "complete" digests.
#
# Note that this will quietly terminate if there are no messages in the
# spool. I find this preferable to an abort.
#
sub make_digest {
# disable age detection
$V{'MAX_AGE'} = 0;
# use 'should_be_sent' to find out how large each digest should be
# and loop through the spool dir until it's empty
$fnum = 0;
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, ++$fnum);
while (-e $nextfile) {
# starts at $fnum, sets '$file' to the last file to use
&should_be_sent($fnum);
&send_digest($file);
($fnum) = $file =~ m#/(\d+)$#;
$nextfile = sprintf("%s/%03d", $V{'INCOMING'}, ++$fnum);
$NUMBER++;
}
if (! $opt_d) {
if ( ! defined($opt_C) ) {
open(NUM_FILE, ">$V{'NUM_FILE'}") ||
&abort("open(NUM_FILE, \">$NUM_FILE\"): $!");
printf NUM_FILE "%d\n", $NUMBER;
close(NUM_FILE);
} else { # hurrah we are using the majordomo config file
$config_opts{$opt_l,"digest_issue"} = $NUMBER;
&config'writeconfig($listdir, $opt_l);
}
}
}
#
# Contruct and send a digest using files in the spool directory up to and
# including the "last file" specified as the first argument.
#
sub send_digest {
local($lastfile) = shift;
if (opendir(DIR, $V{'INCOMING'})) {
@files = grep(/^\d+$/, readdir(DIR));
closedir(DIR);
}
else {
&abort("Error opening $V{'INCOMING'}: $!\nStopped ");
}
&abort("No messages.\nStopped ") unless @files;
open(TEMP,">$TEMP") || &abort("$TEMP: $!\n");
print STDERR "producing $V{'NAME'} V$VOLUME #$NUMBER\n";
foreach (@files) {
$message = "$V{'INCOMING'}/$_";
open(message) || &abort("$message: $!\n");
print STDERR "\tprocessing $message\n";
push(@processed,$message);
$/ = '';
$head = <message>;
$head =~ s/\n\s+/ /g;
$body = "";
$subj = ($head =~ /^Subject:\s+(.*)/i)? $1: "[none]";
($from) = $head =~ /^From:\s+(.*)/i;
($date) = $head =~ /^Date:\s+(.*)/i;
undef $/;
$body = <message>;
close(message);
# trim message fronter and footers inserted by resend in
# non digest version of list
if ($RMHEADER) {
$body =~ s/$RMHEADER/\n/;
}
if ($RMTRAILER) {
$body =~ s/$RMTRAILER/\n/;
}
# escape ^From <user> <weekday> <month> <day> <hr:min:sec> ...
$body =~
s/^From (\S+\s+\w{3}\s+\w{3}\s+\d+\s+\d+:\d+:\d+)/>From $1/g;
$body =~ s/^-/- -/g; # escape encapsulation boundaries in message
# trim trailing \n's
$len = length($body) - 1;
$len-- while (substr($body,$len,1) eq "\n");
substr($body,$len+1) = "";
$/ = "\n";
## note -- RFC 1153 claims the following headers should be retained, and
## presented in the following order:
## Date:, From:, To:, Cc:, Subject:, Message-ID:, and Keywords:
push(@subj,$subj);
print TEMP <<EOF;
Date: $date
From: $from
Subject: $subj
$body
$EB
EOF
last if ($message eq $lastfile);
}
close(TEMP);
if ($opt_d) {
$DIGEST = "$TMPDIR/testdigest.$NUMBER";
} else {
$DIGEST = sprintf("%s/v%02d.n%03d", $V{'ARCHIVE'}, $VOLUME, $NUMBER);
}
open(DIGEST, ">$DIGEST") || &abort("open(DIGEST, \">$DIGEST\"): $!");
print DIGEST <<EOF;
From: $V{'FROM'} ($V{'NAME'})
To: $V{'TO'}
Subject: $V{'NAME'} V$VOLUME #$NUMBER
Reply-To: $V{'REPLY-TO'}
Sender: $V{'ERRORS-TO'}
Errors-To: $V{'ERRORS-TO'}
Precedence: $Precedence
$HEADERS
EOF
$PDATE = &getdate();
$volstr = sprintf("Volume %02d : Number %03d\n\n",$VOLUME,$NUMBER);
$width = length($V{'NAME'}) + length($PDATE) + length($volstr);
if ($width < 76) {
$center = " " x int((78 - $width) / 2);
} else {
$center = " ";
}
print DIGEST $V{'NAME'},$center,$PDATE,$center,$volstr,"\n\n";
foreach (split(/\n/,$HEADER)) {
if (/_SUBJECTS_/) {
$pre = $`;
foreach $subj (@subj) {
print DIGEST $pre,$subj,"\n";
}
}else{
print DIGEST "$_\n";
}
}
print DIGEST "\n";
print DIGEST "-" x 70,"\n\n";
open(TEMP);
print DIGEST <TEMP>;
close(TEMP);
unlink($TEMP);
$end = sprintf("End of %s V%d #%d", $V{'NAME'}, $VOLUME, $NUMBER);
print DIGEST $end, "\n";
print DIGEST "*" x length($end), "\n";
print DIGEST "\n";
print DIGEST $TRAILER;
close(DIGEST);
if ($opt_d) {
warn "digest output in $TMPDIR/testdigest.$NUMBER\n";
} else {
$sender = $V{'ERRORS-TO'};
$mailcmd = eval qq/"$mailer"/;
system("$mailcmd $V{'REALLY-TO'} < $DIGEST");
unlink(@processed);
}
undef @subj;
undef @processed;
return 0;
}
sub init {
$* = 1;
$HOME = $ENV{"HOME"} || (getpwuid($>))[7];
chdir($HOME);
&getopt("drRmpc:Cl:z") ||
&abort("Usage: digest {-r|-R|-m|-p} [-c config|(-C -l list)]\nStopped");
$config = $opt_c || "$HOME/.digestrc";
$SIG{'INT'} = 'cleanup';
@MONTHS = ("January","February","March","April","May","June","July",
"August","September","October","November","December");
@DAYS = ("Sunday","Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday");
$EB = "-" x 30;
}
sub readconfig {
if (defined($opt_C)) {
if (!defined($opt_l)) {
&abort("-C used without -l");
} else {
# Read and execute the .cf file
$cf = $opt_c || $ENV{"MAJORDOMO_CF"} ||
"/etc/majordomo.cf";
require "$cf";
chdir($homedir);
$opt_l =~ tr/A-Z/a-z/;
require "config_parse.pl";
# Define all of the mailer properties:
# It is possible that one or both of $sendmail_command and $bounce_mailer
# are not defined, so we provide reasonable defaults.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$mailer = "$sendmail_command -oi -oee -f\$sender"
unless defined $mailer;
$bounce_mailer = "$sendmail_command -f\$sender -t"
unless defined $bounce_mailer;
&set_abort_addr($whoami_owner);
&set_mail_from($whoami);
&set_mail_sender($whoami_owner);
&set_mailer($bounce_mailer);
# get the digest config file
# 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");
# get details of parent list footers and headers
if ($config_opts{$opt_l,"digest_rm_fronter"}) {
&get_config($listdir, $config_opts{$opt_l,"digest_rm_fronter"});
$RMHEADER = $config_opts{$config_opts{$opt_l,"digest_rm_fronter"},
"message_fronter"};
$RMHEADER =~ s/([^A-Za-z0-9 \001])/\\\1/g;
$RMHEADER =~ s/\\\$(SENDER|VERSION|LIST)/\[\^\\n\]\*/g;
$RMHEADER =~ s/\001/\\n/g;
}
if ($config_opts{$opt_l,"digest_rm_footer"}) {
if ($config_opts{$opt_l,"digest_rm_footer"} ne
$config_opts{$opt_l,"digest_rm_fronter"}) {
&get_config($listdir, $config_opts{$opt_l,"digest_rm_footer"});
}
$RMTRAILER = $config_opts{$config_opts{$opt_l,"digest_rm_footer"},
"message_footer"};
$RMTRAILER =~ s/([^A-Za-z0-9 \001])/\\\1/g;
$RMTRAILER =~ s/\\\$(SENDER|VERSION|LIST)/\[\^\\n\]\*/g;
$RMTRAILER =~ s/\001/\\n/g;
}
# map config opts to internal variables and $V array
$HEADER = $config_opts{$opt_l,"message_fronter"};
$HEADER =~ s/\001/\n/g;
$TRAILER = $config_opts{$opt_l,"message_footer"};
$TRAILER =~ s/\001/\n/g;
$VOLUME = $config_opts{$opt_l,"digest_volume"};
$NUMBER = $config_opts{$opt_l,"digest_issue"};
$Precedence = $config_opts{$opt_l,"precedence"};
$Precedence = "bulk" if ($Precedence eq "");
$V{'ARCHIVE'} = "$filedir/$opt_l$filedir_suffix";
$V{'DIGEST_SIZE'} = $config_opts{$opt_l, "maxlength"};
$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"}
||$whereami);
$V{'FROM'} = $config_opts{$opt_l, "sender"}. "@" .
($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];
$V{'REPLY-TO'} = $config_opts{$opt_l,"reply_to"};
$V{'TO'} = "$opt_l\@$whereami";
# make the headers keyword work
if ( $config_opts{$opt_l,"message_headers"} ne '' ) {
$from = $V{'FROM'};
$HEADERS = &config'substitute_values (
$config_opts{$opt_l,"message_headers"}, $opt_l);
$HEADERS =~ s/\001/\n/g;
}
} # list is defined
} else { # not using -C
require "config_parse.pl";
# Define all of the mailer properties:
# The majordomo.cf file isn't used in this option, so fake everything.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$mailer = "$sendmail_command -oi -oee -f\$sender"
unless defined $mailer;
$bounce_mailer = "$sendmail_command -fmajordomo-owner -t"
unless defined $bounce_mailer;
&set_abort_addr("majordomo-owner");
&set_mail_from("majordomo-owner");
&set_mail_sender("majordomo-owner");
&set_mailer($bounce_mailer);
open(config) || &abort("$config: $!\n");
while (<config>) {
next if /^\s*$|^\s*#/;
chop;
($key,$value) = split(/\s*=\s*/,$_,2);
$V{$key} = $value;
}
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);
open(trailer,$V{'TRAILER'}) || &abort("$V{'TRAILER'}: $!\n");
$TRAILER = join("",<trailer>);
close(trailer);
open(VOL_FILE,$V{'VOL_FILE'}) || &abort("$V{'VOL_FILE'}: $!\n");
$VOLUME = join("",<VOL_FILE>);
chop($VOLUME);
close(VOL_FILE);
open(NUM_FILE,$V{'NUM_FILE'}) || &abort("$V{'NUM_FILE'}: $!\n");
$NUMBER = join("",<NUM_FILE>);
chop($NUMBER);
close(NUM_FILE);
} # end not using -C
}
#my favorite of the existing getopt routines; twisted
#
sub getopt {
local($_,%opt,$rest) = (split(/([^:])/,$_[0]),'');
while ($_ = $ARGV[0], /^-(.)/ && shift(@ARGV)) {
$rest = $';
last if $1 eq '-';
if (!defined $opt{$1}) {
warn "Unrecognized switch \"-$1\".\n";
return 0;
}elsif ($opt{$1}) {
$rest = shift(@ARGV) if $rest eq '';
eval "\$opt_$1 = \$rest";
}else{
eval "\$opt_$1 = 1";
$rest =~ /^(.)/;
redo if $rest ne '';
}
}
return 1;
}
sub cleanup {
unlink($TEMP);
exit(1);
}
sub getdate {
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
return("$DAYS[$wday], $MONTHS[$mon] $mday $year");
}
sub abort {
local($msg) = shift;
&free_lock($lockfile) if $lock_set;
die($msg);
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)sysexits.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _SYSEXITS_H_
#define _SYSEXITS_H_
/*
* SYSEXITS.H -- Exit status codes for system programs.
*
* This include file attempts to categorize possible error
* exit statuses for system programs, notably delivermail
* and the Berkeley network.
*
* Error numbers begin at EX__BASE to reduce the possibility of
* clashing with other exit statuses that random programs may
* already return. The meaning of the codes is approximately
* as follows:
*
* EX_USAGE -- The command was used incorrectly, e.g., with
* the wrong number of arguments, a bad flag, a bad
* syntax in a parameter, or whatever.
* EX_DATAERR -- The input data was incorrect in some way.
* This should only be used for user's data & not
* system files.
* EX_NOINPUT -- An input file (not a system file) did not
* exist or was not readable. This could also include
* errors like "No message" to a mailer (if it cared
* to catch it).
* EX_NOUSER -- The user specified did not exist. This might
* be used for mail addresses or remote logins.
* EX_NOHOST -- The host specified did not exist. This is used
* in mail addresses or network requests.
* EX_UNAVAILABLE -- A service is unavailable. This can occur
* if a support program or file does not exist. This
* can also be used as a catchall message when something
* you wanted to do doesn't work, but you don't know
* why.
* EX_SOFTWARE -- An internal software error has been detected.
* This should be limited to non-operating system related
* errors as possible.
* EX_OSERR -- An operating system error has been detected.
* This is intended to be used for such things as "cannot
* fork", "cannot create pipe", or the like. It includes
* things like getuid returning a user that does not
* exist in the passwd file.
* EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
* etc.) does not exist, cannot be opened, or has some
* sort of error (e.g., syntax error).
* EX_CANTCREAT -- A (user specified) output file cannot be
* created.
* EX_IOERR -- An error occurred while doing I/O on some file.
* EX_TEMPFAIL -- temporary failure, indicating something that
* is not really an error. In sendmail, this means
* that a mailer (e.g.) could not create a connection,
* and the request should be reattempted later.
* EX_PROTOCOL -- the remote system returned something that
* was "not possible" during a protocol exchange.
* EX_NOPERM -- You did not have sufficient permission to
* perform the operation. This is not intended for
* file system problems, which should use NOINPUT or
* CANTCREAT, but rather for higher level permissions.
*/
#define EX_OK 0 /* successful termination */
#define EX__BASE 64 /* base value for error messages */
#define EX_USAGE 64 /* command line usage error */
#define EX_DATAERR 65 /* data format error */
#define EX_NOINPUT 66 /* cannot open input */
#define EX_NOUSER 67 /* addressee unknown */
#define EX_NOHOST 68 /* host name unknown */
#define EX_UNAVAILABLE 69 /* service unavailable */
#define EX_SOFTWARE 70 /* internal software error */
#define EX_OSERR 71 /* system error (e.g., can't fork) */
#define EX_OSFILE 72 /* critical OS file missing */
#define EX_CANTCREAT 73 /* can't create (user) output file */
#define EX_IOERR 74 /* input/output error */
#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
#define EX_PROTOCOL 76 /* remote error in protocol */
#define EX_NOPERM 77 /* permission denied */
#define EX_CONFIG 78 /* configuration error */
#define EX__MAX 78 /* maximum listed value */
#endif /* !_SYSEXITS_H_ */

View File

@@ -0,0 +1,251 @@
#! /bin/sh
## (From INN-1.4, written by Rich Salz)
## $Revision: 1.1 $
## A script to install files and directories.
PROGNAME=`basename $0`
## Paths to programs. CHOWN and WHOAMI are checked below.
CHOWN=chown
CHGRP=chgrp
CHMOD=chmod
CP=cp
LN=ln
MKDIR=mkdir
MV=mv
RM=rm
STRIP=strip
WHOAMI=whoami
## Some systems don't support -x, so we have to use -f.
if [ ${CHOWN} = chown ] ; then
if [ -f /etc/chown ] ; then
CHOWN=/etc/chown
else
if [ -f /usr/etc/chown ] ; then
CHOWN=/usr/etc/chown
fi
fi
fi
if [ ${WHOAMI} = whoami ] ; then
if [ -f /usr/ucb/whoami ] ; then
WHOAMI=/usr/ucb/whoami
fi
fi
## Defaults.
CHOWNIT=false
CHGROUPIT=false
CHMODIT=false
STRIPIT=false
BACKIT=false
TOUCHIT=true
SAVESRC=false
ROOT=unknown
## Process JCL.
MORETODO=true
while ${MORETODO} ; do
case X"$1" in
X-b)
BACKIT=true
BACKUP="$2"
shift
;;
X-b*)
BACKIT=true
BACKUP=`expr "$1" : '-b\(.*\)'`
;;
X-c)
SAVESRC=true
;;
X-g)
GROUP="$2"
CHGROUPIT=true
shift
;;
X-g*)
GROUP=`expr "$1" : '-g\(.*\)'`
CHGROUPIT=true
;;
X-G)
case ${ROOT} in
unknown)
case `${WHOAMI}` in
root)
ROOT=true
;;
*)
ROOT=false
;;
esac
;;
esac
GROUP="$2"
shift
${ROOT} && CHGROUPIT=true
;;
X-G*)
case ${ROOT} in
unknown)
case `${WHOAMI}` in
root)
ROOT=true
;;
*)
ROOT=false
;;
esac
;;
esac
if ${ROOT} ; then
GROUP=`expr "$1" : '-g\(.*\)'`
CHGROUPIT=true
fi
;;
X-m)
MODE="$2"
CHMODIT=true
shift
;;
X-m*)
MODE=`expr "$1" : '-m\(.*\)'`
CHMODIT=true
;;
X-n)
TOUCHIT=false
;;
X-o)
OWNER="$2"
CHOWNIT=true
shift
;;
X-o*)
OWNER=`expr "$1" : '-o\(.*\)'`
CHOWNIT=true
;;
X-O)
case ${ROOT} in
unknown)
case `${WHOAMI}` in
root)
ROOT=true
;;
*)
ROOT=false
;;
esac
;;
esac
OWNER="$2"
shift
${ROOT} && CHOWNIT=true
;;
X-O*)
case ${ROOT} in
unknown)
case `${WHOAMI}` in
root)
ROOT=true
;;
*)
ROOT=false
;;
esac
;;
esac
if ${ROOT} ; then
OWNER=`expr "$1" : '-o\(.*\)'`
CHOWNIT=true
fi
;;
X-s)
STRIPIT=true
;;
X--)
shift
MORETODO=false
;;
X-*)
echo "${PROGNAME}: Unknown flag $1" 1>&2
exit 1
;;
*)
MORETODO=false
;;
esac
${MORETODO} && shift
done
## Process arguments.
if [ $# -ne 2 ] ; then
echo "Usage: ${PROGNAME} [flags] source destination"
exit 1
fi
## Making a directory?
if [ X"$1" = X. ] ; then
DEST="$2"
if [ ! -d "${DEST}" ] ; then
${MKDIR} "${DEST}" || exit 1
fi
if ${CHOWNIT} ; then
${CHOWN} "${OWNER}" "${DEST}" || exit 1
fi
if ${CHGROUPIT} ; then
${CHGRP} "${GROUP}" "${DEST}" || exit 1
fi
if ${CHMODIT} ; then
umask 0
${CHMOD} "${MODE}" "${DEST}" || exit 1
fi
exit 0
fi
## Get the destination and a temp file in the destination diretory.
if [ -d "$2" ] ; then
DEST="$2/$1"
TEMP="$2/$$.tmp"
else
DEST="$2"
TEMP="`expr "$2" : '\(.*\)/.*'`/$$.tmp"
fi
## If not given the same name, we must try to copy.
if [ X"$1" != X"$2" -o $SAVESRC ] ; then
if cmp -s "$1" "${DEST}" ; then
## Files are same; touch or not.
${TOUCHIT} && touch "${DEST}"
else
## If destination exists and we wish to backup, link to backup.
if [ -f "${DEST}" ] ; then
if ${BACKIT} ; then
${RM} -f "${DEST}${BACKUP}"
${LN} "${DEST}" "${DEST}${BACKUP}"
fi
fi
## Copy source to the right dir, then move to right spot.
## Done in two parts so we can hope for atomicity.
${RM} -f "${TEMP}" || exit 1
${CP} "$1" "${TEMP}" || exit 1
${MV} -f "${TEMP}" "${DEST}" || exit 1
fi
fi
## Strip and set the modes.
if ${STRIPIT} ; then
${STRIP} "${DEST}" || exit 1
fi
if ${CHOWNIT} ; then
${CHOWN} "${OWNER}" "${DEST}" || exit 1
fi
if ${CHGROUPIT} ; then
${CHGRP} "${GROUP}" "${DEST}" || exit 1
fi
if ${CHMODIT} ; then
umask 0
${CHMOD} "${MODE}" "${DEST}" || exit 1
fi
exit 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
#
# The aliases file for majordomo. This works best if you tell sendmail about it
# in your sendmail.cf file (either /usr/lib/sendmail.cf or /etc/sendmail.cf).
#
# You need to be running a recent (8.6, at least) version of sendmail; one that
# groks multiple alias files.
#
# Look for a line that says "OA/usr/lib/aliases" or somesuch, and add a line below
# it, w/o the leading # sign, that looks like this:
#
# OA/usr/test/majordomo/majordomo.aliases
#
# After doing this, you should refreeze the sendmail cf via '/usr/lib/sendmail -bz' and
# restart sendmail.
#
majordomo: "|/usr/test/majordomo-1.94.5/wrapper majordomo"
majordomo-owner: you
owner-majordomo: you
test: "|/usr/test/majordomo-1.94.5/wrapper resend -l test test-list"
test-list: :include:/usr/test/majordomo-1.94.5/lists/test
owner-test: you
test-owner: you
test-request: you

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,828 @@
# General subroutines for Majordomo
# $Source: /sources/cvsrepos/majordomo/majordomo.pl,v $
# $Revision: 1.58 $
# $Date: 2000/01/07 12:32:04 $
# $Author: cwilson $
# $State: Exp $
#
# $Header: /sources/cvsrepos/majordomo/majordomo.pl,v 1.58 2000/01/07 12:32:04 cwilson Exp $
#
# The exit codes for abort. Look in /usr/include/sysexits.h.
#
$EX_DATAERR = 65;
$EX_TEMPFAIL = 75;
$EX_NOUSER = 67;
package Majordomo;
$DEBUG = $main'DEBUG;
# Mail header hacking routines for Majordomo
#
# Derived from:
# Routines to parse out an RFC 822 mailheader
# E. H. Spafford, last mod: 11/91
#
# ParseMailHeader breaks out the header into an % array
# indexed by a lower-cased keyword, e.g.
# &ParseMailHeader(STDIN, *Array);
# use $Array{'subject'}
#
# Note that some duplicate lines (like "Received:") will get joined
# into a single entry in %Array; use @Array if you want them separate
# $Array will contain the unprocessed header, with embedded
# newlines
# @Array will contain the header, one line per entry
#
# RetMailAddr tries to pull out the "preferred" return address
# based on the presence or absence of various return-reply fields
# Call as &ParseMailHeader(FileHandle, *array)
sub main'ParseMailHeader ## Public
{
local($save1) = ($/);
local($FH, *array) = @_;
local ($keyw, $val);
%array = ();
# force unqualified filehandles into callers' package
local($package) = caller;
$FH =~ s/^[^':]+$/$package'$&/;
$/ = '';
$array = $_ = <$FH>;
s/\n\s+/ /gms;
@array = split('\n');
foreach $_ (@array)
{
($keyw, $val) = m/^([^:]+):\s*(.*\S)\s*$/gms;
$keyw =~ y/A-Z/a-z/;
if (defined($array{$keyw})) {
$array{$keyw} .= ", $val";
} else {
$array{$keyw} = $val;
}
}
$/ = $save1;
}
# Call as $addr = &RetMailAddr(*array)
# This assumes that the header is in RFC 822 format
# We used to strip the raw address from the header here, but the address is
# stripped again before it gets to the mailer and we may want to use the
# whole thing when we do a subscription.
sub main'RetMailAddr ## Public
{
local(*array) = @_;
local($ReplyTo) = defined($array{'reply-to'}) ?
$array{'reply-to'} : $array{'from'};
$ReplyTo = $array{'apparently-from'} unless $ReplyTo;
$ReplyTo;
}
# @addrs = &ParseAddrs($addr_list)
sub main'ParseAddrs {
local($_) = shift;
1 while s/\([^\(\)]*\)//g; # strip comments
1 while s/"[^"]*"\s//g; # strip comments"
my @x = split(/,/); # split into parts
foreach (@x) {
1 while s/.*<(.*)>.*/$1/;
s/^\s+//;
s/\s+$//;
}
@x;
}
# Check to see if a list is valid. If it is, return the validated list
# name; if it's not, return ""
sub main'valid_list {
local($listdir) = shift;
# start with a space-separated list of the rest of the arguments
local($taint_list) = join(" ", @_);
# strip harmless matched leading and trailing angle brackets off the list
1 while $taint_list =~ s/^<(.*)>$/$1/;
# strip harmless trailing "@.*" off the list
$taint_list =~ s/\@.*$//;
# anything else funny with $taint_list probably isn't harmless; let's check
# start with $clean_list the same as $taint_list
local($clean_list) = $taint_list;
# clean up $clean_list
$clean_list =~ s/[^-_0-9a-zA-Z]*//g;
# if $clean_list no longer equals $taint_list, something's wrong
if ($clean_list ne $taint_list) {
return "";
}
# convert to all-lower-case
$clean_list =~ tr/A-Z/a-z/;
# check to see that $listdir/$clean_list exists
if (! -e "$listdir/$clean_list") {
return "";
}
return $clean_list;
}
# compare two email address to see if they "match" by converting to all
# lower case, then stripping off comments and comparing what's left. If
# a optional third argument is specified and it's not undefined, then
# partial matches (where the second argument is a substring of the first
# argument) should return true as well as exact matches.
#
# if optional third argument is 2, then compare the two addresses looking
# to see if the addresses are of the form user@dom.ain.com and user@ain.com
# if that is the format of the two addresses, then return true.
sub main'addr_match {
local($a1) = &main'chop_nl(shift);
local($a2) = &main'chop_nl(shift);
local($partial) = shift; # may be "undef"
print STDERR "addr_match: enter\n" if $DEBUG;
print STDERR "addr_match: comparing $a1 against $a2\n" if $DEBUG;
if ($partial == 1) {
$a1 =~ tr/A-Z/a-z/;
$a2 =~ tr/A-Z/a-z/;
if (index($a1, $a2) >= $[) {
return(1);
} else {
return(undef);
}
}
local(@a1, @a2);
$a1 =~ tr/A-Z/a-z/;
$a2 =~ tr/A-Z/a-z/;
@a1 = &main'ParseAddrs($a1);
@a2 = &main'ParseAddrs($a2);
if (($#a1 != 0) || ($#a2 != 0)) {
# Can't match, because at least one of them has either zero or
# multiple addresses
return(undef);
}
if ($partial == 2 && ($a1[0] ne $a2[0])) { # see if addresses are
# foo@baz.bax.edu, foo@bax.edu
local(@addr1,@addr2);
@addr1 = split(/\@/, $a1[0]);
@addr2 = split(/\@/, $a2[0]);
if ( $#addr1 == $#addr2 && $#addr1 == 1 &&
$addr1[0] eq $addr2[0] && (index($addr1[1], $addr2[1]) >= $[))
{
return(1);
}
}
return($a1[0] eq $a2[0]);
}
# These are package globals referenced by &setabortaddr and &abort
$abort_addr = "owner-majordomo";
sub main'set_abort_addr {
$abort_addr = shift unless ($#_ < $[);
}
# Abort the process, for the reason stated as the argument
local($log_disabled);
local($logging_abort, $mailing_abort);
sub main'abort { #'
# first, tell the requestor that something bad happened.
# XXX is this really meaningful for, say, resend?
if (-e main'REPLY) {
print main'REPLY <<END_MSG;
>>> Sorry, an error has occurred while processing your request
>>> The caretaker of Majordomo ( $abort_addr ) has been notified
>>> of the problem.
END_MSG
close (main'REPLY);
}
# print the reason for the abort to stderr; maybe someone will see it
print STDERR "$main'program_name: ABORT\n", join(" ", @_), "\n";
# log the reason for the abort, if possible. We don't log if the
# log is inaccessible, or if we're aborting trying to log that we're
# aborting.
unless ($log_disabled || $logging_abort) {
$logging_abort = join(" ", @_);
&main'log("ABORT", $logging_abort);
$logging_abort = "";
}
else {
# Use previous message if we recursed
@_ = ($logging_abort) if $logging_abort;
}
# send a message to the Majordomo owner, if possible. We don't mail
# if we're aborting trying to mail that we're aborting.
if (! $mailing_abort &&
defined($abort_addr) && defined($main'bounce_mailer)) {
$mailing_abort = 1; # Break recursion loops
# We must set the mailer correctly here just in case it was
# originally set to the normal mailer; that probably won't get us
# anywhere
&main'set_mailer($main'bounce_mailer);
&main'sendmail(ABORT, $abort_addr, "MAJORDOMO ABORT ($main'program_name)");#'
print ABORT <<"EOM";
MAJORDOMO ABORT ($main'program_name)!!
@_
EOM
close(ABORT);
}
exit $EX_DATAERR;
}
# bitch about a serious problem, but not fatal.
local($logging_warning, $mailing_warning);
sub main'bitch {
# print the warning to stderr in case all else fails
# maybe someone will see it
print STDERR "$main'program_name: WARNING\n", join(" ", @_), "\n";
# log the warning, if possible
unless ($log_disabled || $logging_warning) {
$logging_warning = 1;
&main'log("WARNING ", join(" ", @_), "\n"); #';
$logging_warning = 0;
}
# send a message to the Majordomo owner, if possible
if (! $mailing_warning &&
defined($abort_addr) && defined($main'bounce_mailer)) {
$mailing_warning = 1; # Break recursion loops
# We must set the mailer correctly here just in case it was
# originally set to the normal mailer; that probably won't get us
# anywhere
&main'set_mailer($main'bounce_mailer);
&main'sendmail(WARN, $abort_addr, "MAJORDOMO WARNING ($main'program_name)");#';
print WARN <<"EOM";
MAJORDOMO WARNING ($main'program_name)!!
@_
EOM
close(WARN);
$mailing_warning = 0;
}
}
# do a quick check of permissions.
#
sub main'check_permissions {
local($err);
if ( ! -w $log_file ) {
if ( ! -e $log_file ) { # log file may not exist, check dir perms.
local($dir);
($dir) = $log_file =~ m@^(/\S+)/@;
if ( ! -w $dir ) {
$err .= "Unable to create log file in $dir, check permissions.\n"; #
}
} else {
$err .= "Unable to write to log file, check permissions on $log_file\n";
}
}
if ( ! -w $main'listdir ) {
$err .= "Unable to write to list directory \$listdir, check permissions on $main'listdir\n";
}
if (length $err) {
$err = "While running with an effective uid of $> and an effective gid of $), Majordomo\nran into the following problems:\n" .
$err;
$log_disabled = 1;
&main'abort($err);#';
}
}
# These are package globals referenced by &setlogfile and &log
$log_file = "/tmp/log.$$";
$log_host = "UNKNOWN";
$log_program = "UNKNOWN";
$log_session = "UNKNOWN";
# set the log file
sub main'set_log {
$log_file = shift unless ($#_ < $[);
$log_host = shift unless ($#_ < $[);
$log_program = shift unless ($#_ < $[);
$log_session = shift unless ($#_ < $[);
}
# Log a message to the log
sub main'log {
print STDERR "$0: main'log()\n" if $DEBUG;
local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
local(*MAILMSG);
print STDERR "$0: main'log(): opening logfile $log_file\n" if $DEBUG;
if (&main'lopen(LOG, ">>", $log_file)) { #';
# if the log is open, write to the log
printf LOG "%s %02d %02d:%02d:%02d %s %s[%d] {%s} ",
$ctime'MoY[$mon], $mday, $hour, $min, $sec,
$log_host, $log_program, $$, $log_session;
print LOG join(" ", @_), "\n";
&main'lclose(LOG);
} else {
print STDERR "$0: main'log(): log not open, writing to STDERR and attempting to mail.\n" if $DEBUG;
# otherwise, write to stderr
printf STDERR "%s[%d] {%s} ", $log_program, $$, $log_session;
print STDERR join(" ", @_), "\n";
# send a message to the Majordomo owner, if possible
if (defined($abort_addr)) {
&main'sendmail(MAILMSG, $abort_addr, # '(
"MAJORDOMO NOTICE: Can't open log");
printf MAILMSG "%s[%d] {%s} ", $log_program, $$, $log_session;
print MAILMSG join(" ", @_), "\n";
}
}
print STDERR "$0: main'log(): done\n" if $DEBUG;
}
# Globals referenced by &set_mail* and &sendmail
$mail_prog = "$sendmail_command -f\$sender -t";
$mail_from = $whoami;
$mail_sender = $whoami_owner;
# set the mailer
sub main'set_mailer {
$mail_prog = shift;
}
# set the default from address
sub main'set_mail_from {
$mail_from = shift;
}
# set the default sender address
sub main'set_mail_sender {
$mail_sender = shift;
}
# Exec a mailer process
sub main'do_exec_sendmail {
&main'abort("do_exec_sendmail, number of args <= 1 unsafe to exec")
if scalar(@_) <= 1;
# It makes sense to check to see that the mailer is valid here, but the
# abort routine must make certain that recursion doesn't develop,
# because abort calls this routine.
&main'abort("$main'program_name: do_exec_sendmail, mailer $_[0] not executable")
unless (-x $_[0]);
exec(@_);
die("Failed to exec mailer \"@_\": $!");
}
# Open a mailer on the far end of a filehandle
sub main'sendmail { #''
local($MAIL) = shift;
local($to) = shift;
local($subject) = shift;
local($from) = $mail_from;
local($sender) = $mail_sender;
# The following eval expands embedded variables like $sender
local($mail_cmd) = eval qq/"$mail_prog"/;
local($isParent);
if ($#_ >= $[) { $from = shift; }
if ($#_ >= $[) { $sender = shift; }
# force unqualified filehandles into caller's package
local($package) = caller;
$MAIL =~ s/^[^':]+$/$package'$&/;
# clean up the addresses, for use on the mailer command line
local(@to) = &main'ParseAddrs($to);
for (@to) {
$_ = join(", ", &main'ParseAddrs($_));
}
$to = join(", ", @to); #';
print STDERR "$0: main'sendmail: To $to, Subject $subject, From $from\n"
if $DEBUG;
print STDERR "$0: main'sendmail: Sender $sender, mail_cmd = $mail_cmd\n"
if $DEBUG;
# open the process
if (defined($isParent = open($MAIL, "|-"))) {
&main'do_exec_sendmail(split(' ', $mail_cmd))
unless ($isParent);
} else {
&main'abort("Failed to fork prior to mailer exec");
}
# Generate the header. Note the line beginning with "-"; this keeps
# this message from being reprocessed by Majordomo if some misbegotten
# mailer out there bounces it back.
print $MAIL
"To: $to
From: $from
Subject: $subject
Reply-To: $from
--
";
return;
}
# check the password for a list
sub main'valid_passwd {
local($listdir, $list, $passwd) = @_;
# is it a valid list?
local($clean_list) = &main'valid_list($listdir, $list);
if ($clean_list ne "") {
# it's a valid list check config passwd first
if (defined($main'config_opts{$clean_list,"admin_passwd"}) &&
$passwd eq $main'config_opts{$clean_list,"admin_passwd"} )
{ return 1; }
# read the password from the file in any case
if (&main'lopen(PASSWD, "", "$listdir/$clean_list.passwd")) {
local($file_passwd) = <PASSWD>;
&main'lclose(PASSWD);
$file_passwd = &main'chop_nl($file_passwd);
# got the password; now compare it to what the user sent
if ($passwd eq $file_passwd) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
}
# Check to see that this is a valid address.
# A valid address is a single address with
# no "|" in the address part. It may not start with a - either.
# If it has a / in it, we use some heuristics to find out if the address
# may be a file. Some other heuristics attempt to look for a valid X.400
# address. This is not infalible.
sub main'valid_addr {
local($addr, $list) = @_;
local(@addrs, $temp);
# Parse the address out into parts
@addrs = &main'ParseAddrs($addr);
# if there's not exactly 1 part, it's no good
# XXX Should inform the poor user of this fact.
if ($#addrs != 0) {
return undef;
}
local($_) = $addrs[0];
# Deal with unbalanced brackets or parenthesis in an address.
$temp = $_;
# Nuke anything within quotes.
1 while $temp =~ s/(^|([^\\\"]|\\.)+)\"(([^\\\"]|\\.)*|$)\"?/$1/g;
# Remove nested parentheses " <- placate emacs' highlighting
1 while $temp =~ s/\([^\(\)]*\)//g;
# Remove nested angle brackets
1 while $temp =~ s/\<[^\<\>]*\>//g;
# remove nested square brackets
1 while $temp =~ s/\[[^\[\]]*\]//g;
# If any parentheses of brackets remain, they are unbalanced and the
# address is illegal.
if ($temp =~ /[\(\)\<\>\[\]]/) {
if (-e main'REPLY) {
print main'REPLY <<"EOM"
**** The address you supplied, $_
**** Does not seem to be a legal Internet address. It seems to have an
**** uneven number of parentheses or brackets.
EOM
}
&main'log("WARNING", "Unbalanced address: $_");
return undef;
}
if ($temp =~ /[,;:]/) {
if (-e main'REPLY) {
print main'REPLY <<"EOM"
**** The address you supplied, $_
**** Does not seem to be a legal Internet address. It seems to have
**** unquoted colons, commas, or semicolons.
EOM
}
&main'log("WARNING", "Illegal chars in address: $_");
return undef;
}
# Deal with legal spaces in a stripped address, then check and reject
# any remaining space. Note that as I write this, the comment stripper
# ParseAddrs does not handle things like a quoted local part but I've
# included the correct routines just in case it ever does.
$temp = $_;
# We assume that the comment stripper will have eaten leading and
# trailing space.
# This mess turns "jason ti bb i tt s"@hpc.uh.edu into
# "jasontibbitts"@hpc.uh.edu
1 while $temp =~ s/\"(.*)\s(.*)\"/\"$1$2\"/g;
# This compresses space before dots or `@'s. " <- placate emacs' highlighting
1 while $temp =~ s/\s(\.|@)/$1/g;
# This compresses space after dots or `@'s.
1 while $temp =~ s/(\.|@)\s/$1/g;
# We've taken out all legitimate space from the address (yes, RFC822
# permits that kind of bogosity), so if the address has spaces, we have
# a problem.
if ($temp =~ /\s/) {
if (-e main'REPLY) {
print main'REPLY <<"EOM";
**** The address you supplied, $_
**** does not seem to be a legal Internet address. You may have supplied
**** your full name instead of your address, or you may have included your
**** name along with your address in a manner that does not comply with
**** Internet standards for addresses.
**** It is also possible that you are using a mailer that wraps long lines
**** and the end of your request ended up on the following line. If the
**** latter is true, try using backslashes to split long lines. (Split the
**** line between words, then put a backslash at the end of all but the
**** last line.)
EOM
}
&main'log("WARNING", "Illegal space in address: $_");
return undef;
}
# Addresses must have both an @ and a .
if (!(/\@/ && /\./)) {
if (-e main'REPLY) {
print main'REPLY <<"EOM";
**** The address you supplied, $_
**** is not a complete address. When providing an address, you must give
**** the full name of the machine including the domain part (like
**** host.corp.com), not just your user name or your name and the short
**** name of the machine (just user or user\@host is not legal).
EOM
}
&main'log("WARNING", "Non-domained address: $_");
return undef;
}
# o if there's a "|" in it, it's hostile
# o if there is a - sign at the front of the address, it may be an attempt
# to pass a flag to the MTA
# o bail if they're attempting to subscribe the list to itself
#
print STDERR "$0: valid_addr: comparing '$addr' to '$list'\n" if $DEBUG;
# XXX Should at least tell the user that there was a problem.
if ( /\|/ || /^-/ ) {
&main'abort("HOSTILE ADDRESS (invalid first char or |) $addr"); #'
return undef;
}
# Some sendmails are dumb enough to do bad things with this
if (/\:include\:/) {
&main'abort("HOSTILE ADDRESS (tried to use :include: syntax) $addr"); #'
return undef;
}
if ( $addr eq $list ) {
&main'abort("HOSTILE ADDRESS (tried to subscribe list) $addr"); # '
return undef;
}
# if the is a / in it, it may be an attempt to write to a file.
# or it may be an X.400, HP Openmail or some other dain bramaged
# address 8-(. We check this by breaking the address on '/'s
# and checking to see if the first component of the address
# exists. If it does we bounce it as a hostile address.
# XXX Again, we shouldn't be aborting without telling the user
if ( m#/# ) {
local(@components) = ($_ =~ /([\/\@]?[^\/\@]+)/g);
&main'abort("HOSTILE ADDRESS (path exists to /file) $addr")
if (-e "/$components[0]"); #'
&main'abort("HOSTILE ADDRESS (path exists to file) $addr")
if (-e "$components[0]"); #'
# then as an extra check that can be turned off in the majordomo.cf
# file we make sure that the last component of the address has an
# @ sign on it for an X.400->smtp gateway translation.
if (!$main'no_x400at) {
&main'abort("HOSTILE ADDRESS (no x400 \@) $addr") if (
"$components[$#components]" !~ /\@/); #'
}
# check to see that the c= and a[dm]= parts exist
if (!$main'no_true_x400) {
&main'abort("HOSTILE ADDRESS (no x400 c=) $addr")
if ($_ !~ m#/c=#); #'
&main'abort("HOSTILE ADDRESS (no x400 a[dm]=) $addr")
if ($_ !~ m#/a[dm]=#); #'
}
}
print STDERR "$0: valid_addr: exit\n" if $DEBUG;
return $_;
}
# is this a valid filename?
sub main'valid_filename {
local($directory) = shift;
local($list) = shift;
local($suffix) = shift;
local($taint_filename) = shift;
local($clean_filename);
# Safety check the filename.
if ($taint_filename =~ /^[\/.]|\.\.|[^-_0-9a-zA-Z.\/] /) {
return undef;
} else {
$clean_filename = $taint_filename;
}
if (! -f "$directory/$list$suffix/$clean_filename") {
return undef;
}
return "$directory/$list$suffix/$clean_filename";
}
# Chop any trailing newlines off of a string, and return the string
sub main'chop_nl {
if ($#_ >= $[) {
local($x) = shift;
$x =~ s/\n+$//;
return($x);
} else {
return(undef);
}
}
# Perform simple filename globbing, so we don't have to use the <...> glib
# syntax which has caused problems.
sub main'fileglob {
local($dir) = shift;
local($pat) = shift;
local(@files) = ();
opendir(DIR, $dir) || return undef;
@files = grep(/$pat/, readdir(DIR));
grep($_ = "$dir/$_", @files); # perl4 doesn't have map!
closedir(DIR);
return @files;
}
sub main'is_list_member {
local($subscriber, $listdir, $clean_list, $file) = @_;
local($matches) = 0;
local(*LIST);
local($_);
print STDERR "is_list_member: enter\n" if $DEBUG;
$file = "$listdir/$file" if defined $file && $file !~ m|^/|;
$file = "$listdir/$clean_list" unless defined $file;
print STDERR "is_list_member: checking $file for $subscriber\n"
if $DEBUG;
if (open(LIST, $file)) {
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 $file: $!"); #'"";
}
print STDERR "is_list_member: exit $matches\n" if $DEBUG;
return($matches);
}
# From: pdc@lunch.engr.sgi.com (Paul Close)
# > Shouldn't list and list-digest be equivalent for things like
# > retrieval of files? As it stands now, if I subscribe to
# > foo-list-digest and I want to retrieve a file for foo-list or list the
# > members of foo-list, and foo-list is a private list for these
# > purposes, then I'm out of luck.
#
# I agree. The approach I took for solving this was to add a function called
# private_okay() to use instead of list_member() in cases where you wanted to
# restrict function to members of the list or list-digest.
#
# If restrict_post is defined, private_okay searches those lists, otherwise
# it searches list and list-digest. Anywhere majordomo consults a private_*
# variable, I use private_okay instead of list_member. Works quite nicely.
#
# Added in access checking mechanisms as well to replace
# private_XYZ with some flexability. This will be exanded to be
# more flexible than the current [open|list|closed] capability.
# --Chan 96/04/23
#
sub main'access_check {
local($cmd, $subscriber,$listdir,$clean_list) = @_;
local(@lists,$list,$altlist,$total);
print STDERR "access_check: enter\n" if $DEBUG;
# bail right away if the command is disabled.
#
if ($main'config_opts{$clean_list, "${cmd}_access"} =~ /closed/) {#'
print STDERR "access_check: ${cmd}_access is closed.\n" if $DEBUG;
return 0 ;
}
# bail right away if the command is wide open
#
if ($main'config_opts{$clean_list, "${cmd}_access"} =~ /open/) {#'
print STDERR "access_check: ${cmd}_access is open.\n" if $DEBUG;
return 1;
}
# now check a little deeper.
#
if ( length($main'config_opts{$clean_list,'restrict_post'} )) {
@lists = split(/[:\s]+/,
$main'config_opts{$clean_list,'restrict_post'});
} else {
if ($clean_list =~ /(.*)-digest/) {
$altlist = $1;
} else {
$altlist = "$clean_list-digest";
}
@lists = ($clean_list);
push(@lists, $altlist) if -e "$listdir/$altlist";
}
print STDERR "access_check: checking lists " , join(', ', @lists), "\n"
if $DEBUG;
$total = 0;
foreach $list (@lists) {
$total += &main'is_list_member($subscriber, $listdir, $clean_list, $list);
}
print STDERR "access_check: exit\n" if $DEBUG;
return $total;
}
1;

View File

@@ -0,0 +1,5 @@
# $Header: /sources/cvsrepos/majordomo/majordomo_version.pl,v 1.28 2000/01/18 13:28:07 cwilson Exp $
$majordomo_version = "1.94.5";
1;

View File

@@ -0,0 +1,20 @@
#!/usr/local/gnu/bin/perl
#
# catdb
#
# Author: John Orthoefer <jco@direwolf.com>
# Date: 7 Jan 1996
#
# Introduction
# This program dumps out a dbm file so you can see what the keys are and
# what the values are.
dbmopen( %DB, "$ARGV[0]", 0666);
foreach $i (keys %DB) {
print "$i = \"$DB{$i}\"\n";
}
dbmclose( DB);
exit 0;

View File

@@ -0,0 +1,170 @@
#!/usr/local/bin/perl -- -*- C -*-
# Perl Routines to Manipulate CGI input
# S.E.Brenner@bioc.cam.ac.uk
# $Header: /sources/cvsrepos/majordomo/md-sub/cgi-lib.pl,v 1.1 1996/02/01 15:17:43 cwilson Exp $
#
# Copyright 1994 Steven E. Brenner
# Unpublished work.
# Permission granted to use and modify this library so long as the
# copyright above is maintained, modifications are documented, and
# credit is given for any use of the library.
#
# Thanks are due to many people for reporting bugs and suggestions
# especially Meng Weng Wong, Maki Watanabe, Bo Frese Rasmussen,
# Andrew Dalke, Mark-Jason Dominus and Dave Dittrich.
# For more information, see:
# http://www.bio.cam.ac.uk/web/form.html
# http://www.seas.upenn.edu/~mengwong/forms/
# Minimalist http form and script (http://www.bio.cam.ac.uk/web/minimal.cgi):
#
# require "cgi-lib.pl";
# if (&ReadParse(*input)) {
# print &PrintHeader, &PrintVariables(%input);
# } else {
# print &PrintHeader,'<form><input type="submit">Data: <input name="myfield">';
#}
# ReadParse
# Reads in GET or POST data, converts it to unescaped text, and puts
# one key=value in each member of the list "@in"
# Also creates key/value pairs in %in, using '\0' to separate multiple
# selections
# Returns TRUE if there was input, FALSE if there was no input
# UNDEF may be used in the future to indicate some failure.
# Now that cgi scripts can be put in the normal file space, it is useful
# to combine both the form and the script in one place. If no parameters
# are given (i.e., ReadParse returns FALSE), then a form could be output.
# If a variable-glob parameter (e.g., *cgi_input) is passed to ReadParse,
# information is stored there, rather than in $in, @in, and %in.
sub ReadParse {
local (*in) = @_ if @_;
local ($i, $key, $val);
# Read in text
if (&MethGet) {
$in = $ENV{'QUERY_STRING'};
} elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN,$in,$ENV{'CONTENT_LENGTH'});
}
@in = split(/&/,$in);
foreach $i (0 .. $#in) {
# Convert plus's to spaces
$in[$i] =~ s/\+/ /g;
# Split into key and value.
($key, $val) = split(/=/,$in[$i],2); # splits on the first =.
# Convert %XX from hex numbers to alphanumeric
$key =~ s/%(..)/pack("c",hex($1))/ge;
$val =~ s/%(..)/pack("c",hex($1))/ge;
# Associate key and value
$in{$key} .= "\0" if (defined($in{$key})); # \0 is the multiple separator
$in{$key} .= $val;
}
return length($in);
}
# PrintHeader
# Returns the magic line which tells WWW that we're an HTML document
sub PrintHeader {
return "Content-type: text/html\n\n";
}
# MethGet
# Return true if this cgi call was using the GET request, false otherwise
sub MethGet {
return ($ENV{'REQUEST_METHOD'} eq "GET");
}
# MyURL
# Returns a URL to the script
sub MyURL {
return 'http://' . $ENV{'SERVER_NAME'} . $ENV{'SCRIPT_NAME'};
}
# CgiError
# Prints out an error message which which containes appropriate headers,
# markup, etcetera.
# Parameters:
# If no parameters, gives a generic error message
# Otherwise, the first parameter will be the title and the rest will
# be given as different paragraphs of the body
sub CgiError {
local (@msg) = @_;
local ($i,$name);
if (!@msg) {
$name = &MyURL;
@msg = ("Error: script $name encountered fatal error");
};
print &PrintHeader;
print "<html><head><title>$msg[0]</title></head>\n";
print "<body><h1>$msg[0]</h1>\n";
foreach $i (1 .. $#msg) {
print "<p>$msg[$i]</p>\n";
}
print "</body></html>\n";
}
# PrintVariables
# Nicely formats variables in an associative array passed as a parameter
# And returns the HTML string.
sub PrintVariables {
local (%in) = @_;
local ($old, $out, $output);
$old = $*; $* =1;
$output .= "<DL COMPACT>";
foreach $key (sort keys(%in)) {
foreach (split("\0", $in{$key})) {
($out = $_) =~ s/\n/<BR>/g;
$output .= "<DT><B>$key</B><DD><I>$out</I><BR>";
}
}
$output .= "</DL>";
$* = $old;
return $output;
}
# PrintVariablesShort
# Nicely formats variables in an associative array passed as a parameter
# Using one line per pair (unless value is multiline)
# And returns the HTML string.
sub PrintVariablesShort {
local (%in) = @_;
local ($old, $out, $output);
$old = $*; $* =1;
foreach $key (sort keys(%in)) {
foreach (split("\0", $in{$key})) {
($out = $_) =~ s/\n/<BR>/g;
$output .= "<B>$key</B> is <I>$out</I><BR>";
}
}
$* = $old;
return $output;
}
1; #return true

View File

@@ -0,0 +1,413 @@
#!/usr/local/gnu/bin/perl
#
# md-sub.cgi
#
# Author: John Orthoefer <jco@direwolf.com>
# Date: 17 Jan 1996
#
# Introduction
# This cgi allows people web surfing to subscribe to mailing list.
# It presents the person with a form when called with out options.
# when called with options it will send a mail message to the
# mailing list.
#
# Installing
# To install this software:
# o put the script in the cgi-bin directory
# o set the following varables up for your site
# cgiloc - url of this script as refered to via the web
# listsdb - where the database of lists is going to live
# logfile - where the log for script activity should go
# sendmail - the sending e-mail program, it should have the
# option to read the incoming stream for the To
# address set, '-t' on sendmail.
# o initialize the database
# + list all your mailing lists and contact addresses in a file
# one per line as in
# firewalls majordomo@greatcircle.com
# warhammerfb majordomo@direwolf.com
# majordomo-workers majordomo@greatcircle.com
# default warhammerfb
# help webmaster@here.org
#
# note: there are 3 special names
# default -- This is the mailing list that will be
# selected when the form is first
# presented to the user.
# help -- This is the address for people to send
# help to.
# info -- This is used to specify a URL for information about
# a mailing list.
# the format is:
# info listname url
# where: listname matches a list that is specifed
# elsewhere in the file.
# url is some url on the web.
# + then run the the script with the '-C filename' option
# to construct the database. The create option will only
# add to the database. If you want to clear the database,
# you need to 'rm $listsdb*' (there will be two file a
# .dir and .pag file.)
# o add a link to the scripts URL in your web pages.
# + if you want to make different default mailing lists based on
# which pages you came from you can do this by passing the param
# default=listname
# as part of the URL.
# ie: <href url="http://mypage.domain.org/md-sub.cgi?default=mylist">
# This will cause mylist to be the default selected one instead of
# the database default.
#
# Misc
# This script needs two perl libs cgi-lib.pl (included in this
# distrubution.) and getopts.pl (which should be included with
# your perl distrubution.)
#
# Scalars that need to be changed
#
$cgiloc = "http://stout/~jco/md-sub.cgi";
$listsdb = "/usr/jco/.md-subrc";
$logfile = "/usr/jco/md-sub.log";
#$sendmail = "|/usr/lib/sendmail -t";
$sendmail = "|/usr/bin/cat - > /tmp/test.out"; # This one is for
# testing...
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# NOTHING BELOW HERE SHOULD NEED TO BE CHANGED
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# Required file
require 'cgi-lib.pl';
use Getopt::Std;
#
# Version number
$version = "1.0";
#
# Info
$info = "jco\@direwolf.com";
#
# Call Getopts
getopts( 'C:v');
#
# Check to see if we are creating a DB
if ($opt_C) {
&create_lists( $opt_C);
exit 0;
}
#
# Check to see if the version is being intergated.
if ($opt_v) {
print "Version: $version\n";
exit 0;
}
#
# Read the list DB
&load_lists;
#
# Figure out if we have a filled in form or we need to send a form
if (&ReadParse && !defined( $in{ 'default'})) {
if (defined $in{ 'infopage'} ) {
&infopage;
} else {
$in{ 'mailing_list'} =~ s/\*$//; # drop the * at the end of the name.
&sendmessage;
}
} else {
&form;
}
#
# Birthday party, cheesecake, jelly bean, boom!
# R.E.M.
exit 0;
#
# create_lists
# Create the DBM file.
sub create_lists {
local( $file) = @_;
open( LISTS, $file);
dbmopen( %MLRC, $listsdb, 0644);
while( <LISTS>) {
chop;
($name, $address) = /(\S*)\s*(.*)/;
if ($name =~ /info/i) {
($name, $address) = $address =~/(\S*)\s*(.*)/;
$MLRC{ "LISTINFO-$name"} = $address;
@info = (@info, $name);
} else {
@ml = (@ml, $name);
$MLRC{ "LISTNAME-$name"} = $address;
}
}
$MLRC{ 'mailing-lists'} = join( ";", @ml);
$MLRC{ 'mailing-info'} = join( ";", @info);
dbmclose( MLRC);
}
#
# load_lists
# read in the DBM file.
sub load_lists {
if (!dbmopen( %MLRC, $listsdb, undef)) {
&log( "Can't open $listsdb");
exit 1;
}
foreach $i (split(/;/, $MLRC{'mailing-lists'})) {
$ml{$i} = $MLRC{ "LISTNAME-$i"};
}
foreach $i (split(/;/, $MLRC{'mailing-info'})) {
$mi{$i} = $MLRC{ "LISTINFO-$i"};
}
dbmclose( MLRC);
}
#
# form
# Present the form to the user to fill out
sub form {
# Form header
print <<EOF;
Content-type: text/html
<html>
<title>Mailing List Subscription</title>
<body>
<font size=5>
<center><b>Mailing List Subscription Form</b></center>
</font>
<br>
To subscribe to any of these mailing lists all you need to do is fill
out the form compeletly. And submit it. The form will then be
processed and you should be added to the mailing list shortly.<p>
EOF
if (defined %mi) {
print <<EOF;
If a mailing list has a star (*) after it. That means there is online info
about that list. To access the descriptions for those lists click
<a href=\"$cgiloc?infopage\">here</a>.<p>
EOF
}
print <<EOF;
<hr>
<form action="$cgiloc" method="post">
Mailing List:
EOF
# Generate the list of mailing lists
print "<select name=\"mailing_list\">\n";
foreach $i (keys %ml) {
next if ($i eq 'default');
next if ($i eq 'help');
if ( $i eq $in{ 'default'}) {
print "<option selected>$i";
} elsif ( $i eq $ml{ 'default'} && !defined( $in{ 'default'})) {
print "<option selected>$i";
} else {
print "<option>$i";
}
print "*" if (defined $mi{ $i});
print "\n";
}
print "</select>\n";
# form trailer
print <<EOF
<br>
Real name: <input type="text" name="rname" size=30> <br>
E-mail Address: <input type="text" name="email" size=30> <br>
<br>
What action would you like to take?
<blockquote>
<input checked type=radio name="function" value="subscribe">Subscribe
to the list<br>
<input type=radio name="function" value="unsubscribe">Unsubscribe from
the list<br>
<input type=radio name="function" value="who">Have a list of who is on the list
mailed to you<br>
<input type=radio name="function" value="info">Get a detailed description
of the list mailed to you<br>
</blockquote>
<input type="submit" value="Send request">
<input type="reset" value="Reset">
</form>
<hr>
<address>
<a href="mailto:$ml{ 'help'}">Webmaster</a> /
<a href="mailto:$info>md-sub.cgi</a> /
$version
</address>
</body>
</html>
EOF
}
#
# infopage
# This sends the page with all the info lists on it.
sub infopage {
print <<EOF;
Content-type: text/html
<html>
<title>Mailing List Information</title>
<body>
<font size=5>
<center><b>Mailing List Information</b></center>
</font>
<br>
<hr>
EOF
print "<ul>\n";
foreach $i (keys %mi) {
print "<li><a href=\"$mi{ $i}\">$i</a>\n";
}
print "</ul>\n";
print <<EOF;
<hr>
<address>
<a href="mailto:$ml{ 'help'}">Webmaster</a> /
<a href="mailto:$info>md-sub.cgi</a> /
$version
</address>
</body>
</html>
EOF
}
#
# log
# This routine is called to print data out to the log file it should
# be trival to make it use syslog if you are so inclined.
sub log {
local( $msg) = @_;
open( LOG, ">>$logfile");
print LOG &DTG;
print LOG " - $msg\n";
close( LOG);
}
#
# DTG
# Date Time Group, This is a military thing. Express time in GMT (aka
# Zulu) it this kinda funky format (ddhhmmZ MON YY). I used it because
# it's a canned routine I have.
sub DTG {
local( $time) = @_;
local( @months) = ( 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN',
'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC');
$time = time if ($time);
sprintf( "%2.2d%2.2d%2.2dZ %s %2.2d",
(gmtime( $time))[3],
(gmtime( $time))[2],
(gmtime( $time))[1],
@months[(gmtime( $time))[4]],
(gmtime( $time))[5]);
}
#
# sendmessage
# This is the worker routine. Sends a nice HTML message to the user and
# sends a nice e-mail to the mailing list admin.
#
sub sendmessage {
local( $i);
if ($in{ 'email'} eq "") {
print <<EOF;
Content-type: text/html
<html>
<font size=6>
<center><b>SORRY</b></center><br>
</font>
I'm sorry but you must fill in your e-mail address.
Press "back" and try again.
</html>
EOF
exit 0;
}
$in{ 'email'} = "$in{ 'email'}@$ENV{'REMOTE_HOST'}"
if ( !( $in{ 'email'} =~ /\S*@\S*/));
&log( "<$in{ 'email'}> \"$in{ 'rname'}\" ".
"$in{ 'function'} $in{ 'mailing_list'}");
open( SM, "$sendmail");
print SM <<EOF;
To: $ml{$in {'mailing_list'}}
From: "$in{ 'rname'}" <$in{'email'}>
Reply-To: "$in{ 'rname'}" <$in{'email'}>
$in{ 'function'} $in{'mailing_list'}
EOF
close( SM);
print <<EOF;
Content-type: text/html
<HTML>
<TITLE>Thank You</TITLE>
<BODY>
<FONT SIZE=5>
<CENTER><B>THANK YOU</B></CENTER>
</FONT><br>
Your request has been forwarded to the list owner for processing.
You should be added soon.
<br>
If the list owner has any questions about adding you they should be in
touch with you shortly.
<br>
<br>
The following information will be sent for you:
<br>
<br>
<TT>
EOF
print "To: $ml{$in {'mailing_list'}}<br>\n";
print "From: \"$in{ 'rname'}\" &lt;$in{'email'}&gt;<br><br>\n";
print "$in{ 'function'} $in{'mailing_list'} <br>\n";
print <<EOF;
</TT>
</BODY>
</HTML>
EOF
}

View File

@@ -0,0 +1,9 @@
warhammerfb majordomo@direwolf.com
warhammerfb-digest majordomo@direwolf.com
test jco@bbn.com
Firewalls majordomo@greatcircle.com
info Firewalls http://www.greatcircle.com/firewalls/
info Firewalls-digest http://www.greatcircle.com/firewalls/
Firewalls-digest majordomo@greatcircle.com
help webmaster@www.noname.org
default warhammerfb

View File

@@ -0,0 +1,61 @@
#!/bin/perl
# medit: lock and edit a Majordomo-managed file, then unlock when done.
#
# Copyright 1992, D. Brent Chapman. All Rights Reserved. For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/medit,v $
# $Revision: 1.10 $
# $Date: 1997/04/28 18:38:05 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
# set our path explicitly
$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
# All these should be in the standard PERL library
unshift(@INC, $homedir);
require "shlock.pl"; # NNTP-style file locking
require "majordomo.pl";
# Here's where the fun begins...
(defined($listdir) && chdir "$listdir")
|| die("can't access \$listdir $listdir");
$editor = $ENV{"EDITOR"} || "vi";
foreach (@ARGV) {
$lockfile = $_;
$lockfile =~ s,([^/]*)$,L.$1,;
$shlock'waittime = 5;
for ($tries = 0 ; $tries < 60 ; $tries++) {
if (&set_lock($lockfile)) {
# got the lock
system("$editor $_");
&free_lock($lockfile);
last;
} else {
print "Waiting for lock on $_...\n";
}
}
if ($tries > 60) {
print "Giving up on lock for $_...\n";
}
}

View File

@@ -0,0 +1,145 @@
#!/bin/perl
# $Source: /sources/cvsrepos/majordomo/request-answer,v $
# $Revision: 1.15 $
# $Date: 2000/01/07 11:10:18 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
# set our path explicitly
# PATH it is set in the wrapper, so there is no need to set it here.
#$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Read and execute the .cf file
$cf = $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
if ($ARGV[0] eq "-C") {
$cf = $ARGV[1];
shift(@ARGV);
shift(@ARGV);
}
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
require "shlock.pl";
require "majordomo.pl";
$majordomo_dont_reply = $majordomo_dont_reply
|| '(mailer-daemon|uucp|listserv|majordomo)\@';
&ParseMailHeader(STDIN, *hdrs);
$reply_to = &RetMailAddr(*hdrs);
$reply_to = join(", ", &ParseAddrs($reply_to));
die("request-answer: $reply_to is not a valid return address.\n")
if (! &valid_addr($reply_to));
# robots should not reply to other robots...
if ($reply_to =~ m/$majordomo_dont_reply/i) {
&abort( "$whoami: not replying to $1 to avoid mail loop.\n");
}
$in_reply_to = $hdrs{"message-id"} . ", from " . $hdrs{"from"};
$list = $ARGV[0];
# Define all of the mailer properties:
# It is possible that one or both of $sendmail_command and $bounce_mailer
# are not defined, so we provide reasonable defaults.
$sendmail_command = "/usr/lib/sendmail"
unless defined $sendmail_command;
$bounce_mailer = "$sendmail_command -f\$sender -t"
unless defined $bounce_mailer;
$sender = "$list-approval\@$whereami";
$mailcmd = eval qq/"$bounce_mailer"/;
if (defined($isParent = open(MAIL, "|-"))) {
&do_exec_sendmail(split(' ',$mailcmd))
unless $isParent;
} else {
&abort("Failed to fork prior to mailer exec");
}
print MAIL <<"EOM";
To: $reply_to
From: $list-request\@$whereami
Subject: Your mail to $list-request\@$whereami
In-Reply-To: $in_reply_to
Reply-To: $list-approval\@$whereami
This pre-recorded message is being sent in response to your recent
email to $list-request\@$whereami.
All routine administrative requests (including subscriptions and
unsubscriptions) concerning this mailing list are handled by an
automated server. Please read this message carefully to find the
information relevant to you.
SUBSCRIBING
===========
To subscribe to $list, send the following in the body (not
the subject line) of an email message to "$whoami":
subscribe $list
This will subscribe the account from which you send the message to
the $list list.
If you wish to subscribe another address instead (such as a local
redistribution list), you can use a command of the form:
subscribe $list other-address\@your_site.your_net
UNSUBSCRIBING
=============
To unsubscribe from $list, send the following in the body (not
the subject line) of an email message to "$whoami":
unsubscribe $list
This will unsubscribe the account from which you send the message.
If you are subscribed with some other address, you'll have to send
a command of the following form instead:
unsubscribe $list other-address\@your_site.your_net
If you don't know what address you are subscribed with, you can send
the following command to see who else is on the list (assuming that
information isn't designated "private" by the owner of the list):
who $list
If you want to search non-private lists at this server, you can do that
by sending a command like:
which string
This will return a list of all entries on all lists that contain "string".
HELP
====
To find out more about the automated server and the commands it
understands, send the following command to "$whoami":
help
If you feel you need to reach a human, send email to:
$list-approval\@$whereami
EOM
close(MAIL);
exit 0;

View File

@@ -0,0 +1,970 @@
#!/bin/perl
# $Modified: Fri Jan 7 16:32:17 2000 by cwilson $
# Copyright 1992, D. Brent Chapman. All Rights Reserved. For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/resend,v $
# $Revision: 1.90 $
# $Date: 2000/01/07 15:32:39 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
# Okay, resend accepts many command line arguments, as revealed by the
# Getopts call:
# &Getopts("Aa:df:h:I:l:M:p:Rr:s") || die("resend: Getopts() failed: $!");
# Most of these are defined via the list config file, so in general,
# it's a really bad idea to hardcode them in the alias definition.
# In a future version of majordomo, these will likely all be removed.
#
# Here's a description of them, just to be documentive. Note that the
# only REQUIRED option is -l. Even that will probably go away in the future.
#
# -l <list-name> REQUIRED: specify list name
# -h <host-name> specify host name
# -f <from-addr> specify "sender" (default <list-name>-request)
# -M <max-msg-length> specify max message length to forward
# -p <precedence> add "Precedence: <precedence>" header
# -r <reply-to> add "Reply-To: <reply-to>" header
# -I <file-list> Bounce messages from users not listed in file
# in colon-separated <file-list>
# -a <passwd> approval password
# -A moderate list (require "Approved:" for posting)
# -R delete "Received:" lines
# -s enable "administrivia" checks
# -d debug; say it, but don't do it
# -C alternate config file
#
#$DEBUG = 1;
# set our path explicitly
# PATH it is set in the wrapper, so there is no need to set it here.
#$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Before doing anything else tell the world I am resend
# The mj_ prefix is reserved for tools that are part of majordomo proper.
# (not that anything uses this variable.)
$main'program_name = 'mj_resend'; #';
# If the first argument is "@filename", read the real arguments
# from "filename", and shove them onto the ARGV for later processing
# by &Getopts()
#
if ($ARGV[0] =~ /^\@/) {
$fn = shift(@ARGV);
$fn =~ s/^@//;
open(AV, "< $fn" ) || die("open(AV, \"< $fn\"): $!\nStopped");
undef($/); # set input field separator
$av = <AV>; # read whole file into string
close(AV);
@av = split(/\s+/, $av);
unshift(@ARGV, @av);
$/ = "\n";
}
# Parse arguments here. We do this first so that we can conditionally
# evaluate code in majordomo.cf based on $opt_l (or any other command line
# argument). Here I've assumed that perl was installed correctly and
# getopts.pl was place where it's supposed to be. This changes previous
# behavior which allowed getopts.pl to be in the same place as
# majordomo.cf.
use Getopt::Std;
getopts("C:c:Aa:df:h:I:l:M:p:Rr:s") || die("resend: Getopts() failed: $!");
if (! defined($opt_l)) {
die("resend: must specify '-l list'");
}
# Read and execute the .cf file
$cf = $opt_C || $opt_c || $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
# Despite not having a place to send the remains of the body,
# it would be nice to send a message to root or postmaster, at least...
#
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
use POSIX qw(ctime); # For logging purposes
require "majordomo.pl";
require "majordomo_version.pl";
require "config_parse.pl";
# pickup hostname from majordomo.cf unless defined on the command line
$opt_h = $opt_h || $whereami;
# smash case for the list name
$opt_l =~ tr/A-Z/a-z/;
# We must set up the mailers and logging as soon possible so that we can
# send and log complaints and aborts somewhere. Unfortunately we need to
# parse the config file to get some of the variables. So we fake it here,
# and set them properly later.
# XXX It is possible that owner-$opt_l won't be the right address, but we
# have little choice. Sending the bounces to $whoami_owner is an option,
# but might not clearly indicate the list name.
$sendmail_command = $sendmail_command || "/usr/lib/sendmail";
$bounce_mailer = $bounce_mailer || "$sendmail_command -f\$sender -t";
&set_mail_from("owner-$opt_l");
&set_mail_sender("owner-$opt_l");
&set_mailer($bounce_mailer);
&set_abort_addr("owner-$opt_l");
&set_log($log, $opt_h, "resend", $opt_l);
if (! defined ($TMPDIR)) {
&bitch("\$TMPDIR wasn't defined in $cf. Using /usr/tmp instead.\n".
"Please define in $cf.\n");
$TMPDIR = '/usr/tmp';
}
# if we're running from a tty, just spit to stderr, else
# open up a temp file for the debug output.
#
if (! -t STDERR) {
close STDERR;
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) {
die("resend: must specify outgoing list as last arg(s)");
# this doesn't have to be this way. It could slurp it
# from the alias it was invoked as...?
}
# A classic case of feeping creaturism. While there are possibly good reasons
# why all these things can be classified on the command line, there's
# *NO* good reason why everything is "opt_X". YATTF.
#
$opt_r = "$opt_r\@$opt_h" if ( defined($opt_r) );
&get_config($listdir, $opt_l);
$opt_A = &cf_ck_bool($opt_l,"moderate") if &cf_ck_bool($opt_l,"moderate");
$opt_h = $config_opts{$opt_l,"resend_host"}
if($config_opts{$opt_l,"resend_host"} ne '');
$opt_a = $config_opts{$opt_l,"approve_passwd"}
if ($config_opts{$opt_l,"approve_passwd"} ne '');
$opt_M = $config_opts{$opt_l,"maxlength"}
if ($config_opts{$opt_l,"maxlength"} ne '');
$opt_f = $config_opts{$opt_l,"sender"}
if ($config_opts{$opt_l,"sender"} ne '');
$opt_p = $config_opts{$opt_l,"precedence"}
if ($config_opts{$opt_l,"precedence"} ne '');
$opt_r = $config_opts{$opt_l,"reply_to"}
if ($config_opts{$opt_l,"reply_to"} ne '');
$opt_I = $config_opts{$opt_l,"restrict_post"}
if ($config_opts{$opt_l,"restrict_post"} ne '');
$opt_R = &cf_ck_bool($opt_l,"purge_received")
if &cf_ck_bool($opt_l,"purge_received");
$opt_s = &cf_ck_bool($opt_l,"administrivia")
if &cf_ck_bool($opt_l,"administrivia");
$opt_d = &cf_ck_bool($opt_l,"debug")
if &cf_ck_bool($opt_l,"debug");
# Construct the envelope sender for outbound messages
if (defined($opt_f)) {
$sender = $opt_f;
} else {
$sender = "$opt_l-request";
}
# If the sender doesn't contain an `@', tack on one, followed by the
# hostname
if ($sender !~ /\@/) {
$sender .= "\@$opt_h";
}
# We can now properly define some of the mailer properties.
&set_mail_from($sender);
&set_mail_sender($sender);
&set_abort_addr($sender);
&set_log($log, $opt_h, "resend", $opt_l);
if (defined($opt_A) && ! defined($opt_a)) {
die("resend: must also specify '-a passwd' if using '-A' flag");
}
#
# These are headers to skip
#
$skip_headers = '/^from /i' .
'|| /^x-confirm-reading-to:/i' . # pegasus mail (windoze)
'|| /^disposition-notification-to:/i' . # eudora
'|| /^x-ack:/i' .
'|| /^sender:/i' .
'|| /^return-receipt-to:/i' .
'|| /^errors-to:/i' .
'|| /^flags:/i' .
'|| /^resent-/i' .
'|| /^priority/i' .
'|| /^x-pmrqc:/i' .
'|| /^return-path:/i' .
'|| /^encoding:/i' # could munge the length of the message
;
#
# Define the eval's used to catch "taboo" headers, message contents,
# and administrative headers. The taboo headers can be global
# or per list. The administrative headers are global.
#
# The eval is a construct like so:
# foo: { /^subject:\s*subscribe/ && ( $taboo = '/^subject:\s*subscribe/', last foo); }
# so that the eval returns the regexp that matched.
#
print STDERR "$0: defining evals to catch the bad stuff.\n" if $DEBUG;
if ($config_opts{$opt_l, 'taboo_headers'} ne '') {
@taboo_headers = split(/\001/,$config_opts{$opt_l, 'taboo_headers'});
if ($#taboo_headers >= $[) {
$is_taboo_header = "foo: {\n";
foreach $t (@taboo_headers) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_taboo_header .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_taboo_header .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if ($config_opts{$opt_l, 'taboo_body'} ne '') {
@taboo_body = split(/\001/,$config_opts{$opt_l, 'taboo_body'});
if ($#taboo_body >= $[) {
$is_taboo_body = "foo: {\n";
foreach $t (@taboo_body) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_taboo_body .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_taboo_body .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if (defined($global_taboo_headers)) {
@global_taboo_headers = split(/\n/,$global_taboo_headers);
if ($#global_taboo_headers >= $[) {
$is_global_taboo_header = "foo: {\n";
foreach $t (@global_taboo_headers) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_global_taboo_header .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_global_taboo_header .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if (defined($global_taboo_body)) {
@global_taboo_body = split(/\n/,$global_taboo_body);
if ($#global_taboo_body >= $[) {
$is_global_taboo_body = "foo: {\n";
foreach $t (@global_taboo_body) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_global_taboo_body .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_global_taboo_body .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
#"; dammit.
# admin subject checks. Since $admin_headers is defined in $cf
# (majordomo.cf), an upgrade may not have $admin_headers.
# Bitch about it if so.
#
if (! defined($admin_headers)) {
&bitch("resend: \$admin_headers not defined in $cf !!\n" .
"Majordomo will only catch \"subscribe\" and \"unsubscribe\" in\n" .
"the subject field...\n");
@admin_headers = ('/^subject:\s*subscribe\b/i' ,
'/^subject:\s*unsubscribe\b/i');
} else {
@admin_headers = split(/\n/, $admin_headers);
}
$is_admin_header = "foo: {\n";
foreach $t (@admin_headers) {
$is_admin_header .= "$t && (\$taboo = '$t', last foo);\n";
}
$is_admin_header .= "\$taboo = \"\";\n}; \$taboo;\n";
# Body Check!
# Common things that people send to the wrong address.
# These are caught in the first 10 lines of the message body
# if 'administravia' is turned on and the message isn't marked approved.
#
# The code that catches this should transparently redirect
# majordomo commands to majordomo. That would give the additional
# advantage of not having to add to this silly construct for
# each new majordomo command.
#
# $admin_body should be defined in the $cf file, but an upgrade
# may miss this fact. Bitch about it, and use a minimal list if so.
#
if (! defined($admin_body)) {
&bitch("resend: \$admin_body not defined in $cf !!\n" .
"Majordomo will only catch \"subscribe\" and \"unsubscribe\" in\n" .
"the body.\nLook at $homedir/sample.cf for a good definition.");
@admin_body = ('/^subject:\s*subscribe\b/i' ,
'/^subject:\s*unsubscribe\b/i');
} else {
@admin_body = split(/\n/, $admin_body);
}
$is_admin_body = "foo: {\n";
foreach $t (@admin_body) {
$is_admin_body .= "$t && (\$taboo = '$t', last foo);\n";
}
$is_admin_body .= "\$taboo = \"\";\n}; \$taboo;\n";
print STDERR "$0: caching the message.\n" if $DEBUG;
#
# cache the message, so the parent sendmail process can exit.
#
&open_temp(OUT, "$TMPDIR/resend.$$.out") ||
&abort("resend: Can't open $TMPDIR/resend.$$.out: $!");
&open_temp(IN, "$TMPDIR/resend.$$.in") ||
&abort("resend: Can't open $TMPDIR/resend.$$.in: $!");
while (<STDIN>) {
print IN $_;
}
close(IN);
open(IN, "$TMPDIR/resend.$$.in") ||
die("resend: Can't open $TMPDIR/resend.$$.tmp: $!");
#
# Message parsing starts here
#
print STDERR "$0: parsing header.\n" if $DEBUG;
# parse the header for bad lines, etc. We'll bounce in a moment.
#
$result = &parse_header;
# The first line of the body could hold an approved line. Let's check.
#
$_ = <IN>;
if (/^approved:\s*(.*)/i # aha!
&& defined($opt_a)) {
# OK, is it a valid "Approved:" line?
$approved = &chop_nl($1);
if ($approved ne $opt_a
&& !(&main'valid_passwd($listdir, $opt_l, $approved))) { #Augh!')){
$result .= " Invalid 'Approved:' header";
undef $approved;
}
# The Approved: line is valid
# Look at the next line:
$_ = <IN>;
if (/\S/) {
# We have something other than a blank line. We _assume_ it's
# header. Consequences: if it's not a header, things get screwed
# badly. If we reverse the logic and look instead for something
# header-like, we permit the possibility of the moderator leaving
# out the blank line, which is not a good idea because they might
# get used to it, which will bite them when they approve a message
# starting something that looks like a header.
# XXX Options: complain if we find no blank line and no header-like
# stuff.
close OUT; # Nuke the output so far.
unlink "$TMPDIR/resend.$$.out"; # XXX These filenames should be in
# variables.
# Open a new temp file.
&open_temp(OUT, "$TMPDIR/resend.$$.out") ||
&abort("resend: Can't open $TMPDIR/resend.$$.out: $!");
# We'll be nice and skip a From_ mailbox separator, which just
# might have been quoted by some intervening mail munger.
if (!/^>?From /) {
# Rewind back over the header line we just pulled
seek(IN, - length($_), 1);
}
# Parse the following as a completely new message.
$result .= &parse_header; # The return value won't matter; we're
# approved.
}
# else the line was blank; we let it be eaten and continue
} else {
# No approved line, dniwer
seek(IN, - length($_), 1);
}
print STDERR "$0: checking for valid sender.\n" if $DEBUG;
# Check for a valid sender, if the list has restrict_post set
# and the message isn't approved.
#
# aauuuugggh! 'moderator' != 'restrict_post' !! They should be the
# same!!
#
$result .= &check_sender if ( defined( $opt_I ) && ! defined ($approved));
# If approval is required, and we haven't got it, boing it goes..
#
$result = "Approval required: $result" if
(defined($opt_A) && ! defined($approved));
print STDERR "$0: sender check: '$result'\n" if $DEBUG;
# Print the RFC822 separator
print OUT "\n";
# Print out any message_fronters
#
if ( $config_opts{$opt_l,"message_fronter"} ne '' ) {
local($fronter) = &config'substitute_values (
$config_opts{$opt_l,"message_fronter"}, $opt_l);#';
$fronter =~ s/\001|$/\n/g;
print OUT $fronter;
}
# We are guaranteed to be just after a blank line now. Slurp the body
$result .= &parse_body;
# Yes Tigger, *now* you can bounce. We've checked for
# any Approved headers & lines, taboo_headers, and taboo_bodies
&bounce($result) if ( $result =~ /\S/ && ! defined($approved));
# Print out any message_footers
#
print STDERR "$0: adding any footers.\n" if $DEBUG;
if ( $config_opts{$opt_l,"message_footer"} ne '' ) {
local($footer) =
&config'substitute_values(
$config_opts{$opt_l,"message_footer"}, $opt_l); #'
$footer =~ s/\001|$/\n/g;
print OUT $footer;
}
# Finished munging the message and decided it's valid, now send it out.
#
close OUT;
# The following eval expands embedded variables like $sender
$sendmail_cmd = eval qq/"$mailer"/;
$sendmail_cmd .= " " . join(" ", @ARGV);
# check for the dreaded -t option to sendmail, which will cause
# mail to loop 26 times...
#
if ($sendmail_cmd =~ /sendmail/ && $sendmail_cmd =~ /\s-t/) {
$sendmail_cmd =~ s/-t//;
&bitch("resend: \$sendmail_cmd (aka \$mailer in majordomo.cf\n" .
"had a -t option. This will cause mail to loop 26 times.\n" .
"Since this probably isn't what you want to have happen,\n".
"resend has not passed that option to sendmail.\n");
}
print STDERR "$0: \$sendmail_cmd is $sendmail_cmd\n" if $DEBUG;
# To debug or not debug, that is the question.
#
if (defined($opt_d)) {
$| = 1;
$, = ' ';
print STDERR "Command: $sendmail_cmd\n";
open (IN, "$TMPDIR/resend.$$.out");
while (<IN>) {
print STDERR $_;
}
unlink(&fileglob("$TMPDIR", "^resend\.$$\."));
exit(0);
}
# open the mailer
#
local(*MAILOUT, *MAILIN);
if (defined($isParent = open(MAILOUT, "|-"))) {
&do_exec_sendmail(split(' ', $sendmail_cmd))
unless $isParent; # only if we're in the child
} else {
&abort("Failed to fork prior to mailer exec");
}
# open our tmp file
#
open(MAILIN, "$TMPDIR/resend.$$.out");
# spit it out!
#
while (<MAILIN>) {
print MAILOUT $_;
}
# cleanup
#
close(MAILIN);
unlink(&fileglob("$TMPDIR", "^resend\.$$\.")) || &abort("Error unlinking temp files: $!");
close(MAILOUT) || do {
$? >>= 8;
&abort("Mailer $sendmail_cmd exited unexpectedly with error $?")
unless ($sendmail_cmd =~ /sendmail/ && $? == $EX_NOUSER);
};
# Seeya.
#
exit(0);
######################################################################
#
# Subroutines.
#
######################################################################
# check for a valid sender for moderated lists.
#
sub check_sender {
# Uh, who?
return " This may be hard to believe, but there was no \"From:\" field" .
"in this message I just received. I'm not gonna send it out, " .
"but you can... " if ! defined($from);
local($file) = 0;
# !@$#% cryptic variables. opt_I is restrict_post, which is a colon
# or whitespace seperated list of files that can contain valid
# senders.
# [[[ Scary, I just realized that !@$#% is almost valid perl... ]]]
local(@files) = split (/[:\s]+/, $opt_I);
foreach $file (@files) {
# Return a null message if the sender (from the From: or
# Reply-To: headers) is found
#
return "" if &is_list_member($from, $listdir, $opt_l, $file) ||
(defined $reply_to &&
$reply_to ne $from &&
&is_list_member($reply_to, $listdir, $opt_l, $file));
}
# We only get here if nothing matches.
#
" Non-member submission from [$from] ";
}
#
# parse_header.
# Slurp in the header, checking for bad things. Returns a non-zero length string if
# a taboo or administrative header is found.
#
# [[[ Why couldn't one simply slurp the header in, assign it to an
# assoc. array, and print out everything but the bad stuff? ]]]
#
sub parse_header {
local($gonna_bounce);
local($kept_last) = 0; # our return flag/string.
print STDERR "$0: parse_header: enter.\n" if $DEBUG;
print STDERR "$0: parse_header: taboo_headers = $is_taboo_header\n" if $DEBUG;
print STDERR "$0: parse_header: global_taboo_headers = $is_global_taboo_header\n" if $DEBUG;
print STDERR "$0: parse_header: admin_headers = $is_admin_header\n" if $DEBUG;
while (<IN>) {
print STDERR "$0: parse_header: [$.: $_]" if $DEBUG;
last if /^$/; # stop when we hit the end. RFC822.
next unless /\S/; # skip leading blank lines; usually only
# there if this is a restart after an
# in-body "Approved:" line
print STDERR "$0: parse_header: [$.] taboo_header check\n"
if $DEBUG;
# check for taboo_headers or approved header
#
if ($#taboo_headers >= $[ && !$approved &&
eval $is_taboo_header) {
$gonna_bounce .= "taboo header: $taboo ";
print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
}
if ($DEBUG && $@) {
# Something went boink in eval, say something useful.
print STDERR "$0: parse_header: taboo_header error $@\n";
}
if ($#global_taboo_headers >= $[ && !$approved &&
eval $is_global_taboo_header) {
$gonna_bounce .= "global taboo header: $taboo ";
print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
}
if ($DEBUG && $@) {
# Something went boink in eval, say something useful.
print STDERR "$0: parse_header: global_taboo_header error $@\n";
}
# check for administative headers:
# Usually subscribe, unsubscribe, etc, in Subject field
#
print STDERR "$0: parse_header: [$.] administrative_header check\n"
if $DEBUG;
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;
}
print STDERR "$0: parse_header: Approved check\n" if $DEBUG;
# Check for Approved line
#
# Oddly enough, we may already be approved when we get here. In
# that case, we should nuke any extra Approved: headers we see.
# Why? Well, consider this: you change the password, but send an
# approved message out before the config change takes effect. So
# it bounces back to you with the Approved: line in it. This line
# is now valid. You approve the bounce using the cut-and-paste
# method, putting another Approved: line in front of the headers of
# the raw bounced message and send it off. There are now two
# Approved: headers. If we don't remove the Approved: header from
# the headers of the message you pasted, we've revealed your list
# password.
if (/^approved:\s*(.*)/i && defined($opt_a)) {
if (!$approved) {
print STDERR "$0: parse_header: found an approved header\n" if $DEBUG;
$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 ')
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.
# this allows a message with a taboo_header or admin_header
# but with a valid Approved line to be posted.
$gonna_bounce = '';
next; # gotta remove that approved line, dontcha know
}
}
else {
# We have already been approved, so skip this header
next;
}
}
print STDERR "$0: parse_header: skipping headers\n" if $DEBUG;
# skip all these headers
if (eval $skip_headers) {
$kept_last = 0;
print STDERR "$0: skipped\n" if $DEBUG;
next;
}
# skip these special headers
if ((/^precedence:/i && defined($opt_p)) # skip only if "-p" set
|| (/^received:/i && defined($opt_R)) # skip only if "-R" set
|| (/^reply-to:/i && defined($opt_r)) # skip only if "-r" set
|| (/^\s/ && ! $kept_last)) # skip if skipped last
{
$kept_last = 0;
print STDERR "$0: skipped\n" if $DEBUG;
next;
}
# reset $kept_last in case next line is continuation
# this should go someplace now... but where?
print STDERR "$0: kept\n" if $DEBUG;
$kept_last = 1;
# prepend subject prefix
#
if ( (/^subject:\s*/i)
&& ($config_opts{$opt_l,"subject_prefix"} ne '')) {
print STDERR "$0: parse_header: adding subject prefix\n" if $DEBUG;
local($foo) = &config'substitute_values($config_opts{$opt_l,"subject_prefix"}, $opt_l);#';
local($foo_pat) = $foo;
$foo_pat =~ s/(\W)/\\$1/g;
s/^subject:[^\S\n]*/Subject: $foo /i if !/$foo_pat/;
}
# snag reply-to field
#
$reply_to = $1 if /^reply-to:\s*(.+)/i;
# snag from line
#
if ( /^from:\s*(.+)/i ) {
$from = $1;
$from_last = 1; # the from line can span lines
}
elsif ( defined($from_last) ) {
if ( /^\s+(.+)/ ) {
$from .= " $1";
} else {
undef($from_last);
}
}
# Virtual Majordomo Hack
# s/^to:(.*)\b$opt_l\b(.*)$/To:$1 $opt_l\@$whereami $2/i ;
&check_hdr_line($_); # check for length & balance on from, cc, and to fields.
print OUT $_;
}
# finished with the header.
# Now, we aren't going to bounce yet, even if it looks bad,
# because we allow an Approved line as the _first_ line in the *body*.
#
# return $gonna_bounce if length($gonna_bounce);
print STDERR "$0: parse_header: adding header fields\n"
if $DEBUG;
# add new header fields
print OUT "Sender: $sender\n";
if (defined($opt_p)) {
print OUT "Precedence: $opt_p\n";
}
if (defined($opt_r)) {
print OUT "Reply-To: ", &config'substitute_values($opt_r), "\n"; #';
}
# print out per-list additonal headers
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;
print OUT $headers;
}
print STDERR "$0: parse_header: returning with '$gonna_bounce'\n" if $DEBUG;
" $gonna_bounce ";
}
# Meander through the message body, checking for
# administravia, taboo stuff, and excessive length.
#
sub parse_body {
local($body_line_count, $body_len) = 0;
local($gonna_bounce);
print STDERR "$0: parse_body: enter\n" if $DEBUG;
while (<IN>) {
$body_line_count++;
$body_len += length($_);
# check for administravia in the first 10 lines of the body
# if so told and not approved.
if ($body_line_count < 10
&& defined($opt_s)
&& !defined($approved)
&& eval $is_admin_body) {
$gonna_bounce .=
" Admin request of type $taboo at line $body_line_count ";
next;
}
# if not approved, check for taboo body stuff
# and message length
#
if ( !defined($approved)) {
if ( $#taboo_body >= $[
&& eval $is_taboo_body) {
$gonna_bounce .=
" taboo body match \"$taboo\" at line $body_line_count ";
next;
}
if ($#global_taboo_body >= $[
&& eval $is_global_taboo_body) {
$gonna_bounce .=
" global taboo body match \"$taboo\" " .
"at line $body_line_count ";
next;
}
# make sure it doesn't make the message too long
if (defined($opt_M)
&& $body_len > $opt_M
&& !$already_bitched_about_length) {
$already_bitched_about_length++;
print STDERR "$0: parse_body: message too long\n" if $DEBUG;
$gonna_bounce .= " Message too long (>$opt_M chars) ";
next;
}
}
print OUT $_;
} # while
print STDERR "$0: parse_body: exiting with '$gonna_bounce'\n"
if $DEBUG;
" $gonna_bounce ";
}
sub check_balance {
print STDERR "$0: check_balance: enter: $_\n" if $DEBUG;
# set a temporary variable
local($t) = shift;
# Remove quoted material
# ( looks like lisp, don't it? )
1 while $t =~ s/(^|([^\\\"]|\\.)+)\"([^\\\"\n]|\\.)*\"?/$1/g; #"
# strip out all nested parentheses
1 while $t =~ s/\([^\(\)]*\)//g;
# strip out all nested angle brackets
1 while $t =~ s/\<[^\<\>]*\>//g;
# if any parentheses or angle brackets remain, were imbalanced
if ($t =~ /[\(\)\<\>]/ && ! defined($approved)) {
&bounce("Imbalanced parentheses or angle brackets");
return(undef);
}
return(1);
}
sub check_hdr_line {
local($_) = shift;
print STDERR "$0: check_hdr_line: enter: $_\n" if $DEBUG;
if (! /^\s/) { # is this a continuation line?
# Not a continuation line.
# If $balanced_fld is defined, it means the last field was one
# that needed to have balanced "()" and "<>" (i.e., "To:", "From:",
# and "Cc:", so check it. We do it here in case the last field was
# multi-line.
if (defined($balanced_fld)) {
&check_balance($balanced_fld);
}
# we undefine $balanced_fld and reset $field_len; these may be set below
undef($balanced_fld);
$field_len = 0;
}
# is this a field that must be checked for balanced "()" and "<>"?
if (defined($balanced_fld) || /^from:/i || /^cc:/i || /^to:/i) {
# yes it is, but we can't check it yet because there might be
# continuation lines. Buffer it to be checked at the beginning
# of the next non-continuation line.
# is this line too long?
if ((length($_) > $MAX_HEADER_LINE_LENGTH) && ! defined($approved)) {
&bounce("Header line too long (>$MAX_HEADER_LINE_LENGTH)");
return(undef);
}
# is this field too long?
if ((($field_len += length($_)) > $MAX_TOTAL_HEADER_LENGTH) && ! defined($approved)) {
&bounce("Header field too long (>$MAX_TOTAL_HEADER_LENGTH)");
return(undef);
}
$balanced_fld .= $_;
chop($balanced_fld);
}
# if we get here, everything was OK.
return(1);
}
sub bounce {
local(*BOUNCE);
local($reason) = shift;
local($_);
print STDERR "$0: bounce enter\n" if $DEBUG;
&send_bounce(BOUNCE,
(( $config_opts{$opt_l, 'moderator'} ne "") ?
$config_opts{$opt_l, 'moderator'} : "$opt_l-approval\@$whereami"),
"BOUNCE $opt_l\@$opt_h: $reason");
seek(IN, 0, 0);
while (<IN>) {
print BOUNCE $_;
}
close(BOUNCE);
unlink(&fileglob("$TMPDIR", "^resend\.$$\."));
print STDERR "$0: bounce exiting\n" if $DEBUG;
exit(0);
}
sub send_bounce {
local(*MAIL) = shift;
local($to) = shift;
local($subject) = shift;
local($isParent);
local($mailcmd);
if (defined $bounce_mailer) {
# The eval expands embedded variables like $sender
$mailcmd = eval qq/"$bounce_mailer"/;
}
else {
# Painful, but we have to provide some kind of backwards
# compatibility and this is what 1.93 used
$mailcmd = "/usr/lib/sendmail -f$sender -t";
}
# clean up the addresses, for use on the sendmail command line
local(@to) = &ParseAddrs($to);
$to = join(", ", @to);
# open the process
if (defined($opt_d)) {
# debugging, so just say it, don't do it
open(MAIL, ">-");
print MAIL ">>> $mailcmd\n";
} else {
if (defined($isParent = open(MAIL, "|-"))) {
&do_exec_sendmail(split(' ', $mailcmd))
unless $isParent;
} else {
&abort("Failed to fork prior to mailer exec");
}
}
# generate the header
print MAIL <<"EOM";
To: $to
From: $sender
Subject: $subject
EOM
return;
}

View File

@@ -0,0 +1,969 @@
#!/bin/perl
# $Modified: Fri Jan 7 16:32:17 2000 by cwilson $
# Copyright 1992, D. Brent Chapman. All Rights Reserved. For use by
# permission only.
#
# $Source: /sources/cvsrepos/majordomo/resend,v $
# $Revision: 1.90 $
# $Date: 2000/01/07 15:32:39 $
# $Author: cwilson $
# $State: Exp $
#
# $Locker: $
#
# Okay, resend accepts many command line arguments, as revealed by the
# Getopts call:
# &Getopts("Aa:df:h:I:l:M:p:Rr:s") || die("resend: Getopts() failed: $!");
# Most of these are defined via the list config file, so in general,
# it's a really bad idea to hardcode them in the alias definition.
# In a future version of majordomo, these will likely all be removed.
#
# Here's a description of them, just to be documentive. Note that the
# only REQUIRED option is -l. Even that will probably go away in the future.
#
# -l <list-name> REQUIRED: specify list name
# -h <host-name> specify host name
# -f <from-addr> specify "sender" (default <list-name>-request)
# -M <max-msg-length> specify max message length to forward
# -p <precedence> add "Precedence: <precedence>" header
# -r <reply-to> add "Reply-To: <reply-to>" header
# -I <file-list> Bounce messages from users not listed in file
# in colon-separated <file-list>
# -a <passwd> approval password
# -A moderate list (require "Approved:" for posting)
# -R delete "Received:" lines
# -s enable "administrivia" checks
# -d debug; say it, but don't do it
# -C alternate config file
#
#$DEBUG = 1;
# set our path explicitly
# PATH it is set in the wrapper, so there is no need to set it here.
#$ENV{'PATH'} = "/bin:/usr/bin:/usr/ucb";
# Before doing anything else tell the world I am resend
# The mj_ prefix is reserved for tools that are part of majordomo proper.
# (not that anything uses this variable.)
$main'program_name = 'mj_resend'; #';
# If the first argument is "@filename", read the real arguments
# from "filename", and shove them onto the ARGV for later processing
# by &Getopts()
#
if ($ARGV[0] =~ /^\@/) {
$fn = shift(@ARGV);
$fn =~ s/^@//;
open(AV, "< $fn" ) || die("open(AV, \"< $fn\"): $!\nStopped");
undef($/); # set input field separator
$av = <AV>; # read whole file into string
close(AV);
@av = split(/\s+/, $av);
unshift(@ARGV, @av);
$/ = "\n";
}
# Parse arguments here. We do this first so that we can conditionally
# evaluate code in majordomo.cf based on $opt_l (or any other command line
# argument). Here I've assumed that perl was installed correctly and
# getopts.pl was place where it's supposed to be. This changes previous
# behavior which allowed getopts.pl to be in the same place as
# majordomo.cf.
require "getopts.pl";
&Getopts("C:c:Aa:df:h:I:l:M:p:Rr:s") || die("resend: Getopts() failed: $!");
if (! defined($opt_l)) {
die("resend: must specify '-l list'");
}
# Read and execute the .cf file
$cf = $opt_C || $opt_c || $ENV{"MAJORDOMO_CF"} || "/etc/majordomo.cf";
# Despite not having a place to send the remains of the body,
# it would be nice to send a message to root or postmaster, at least...
#
if (! -r $cf) {
die("$cf not readable; stopped");
}
require "$cf";
chdir($homedir) || die("Can't chdir(\"$homedir\"): $!");
unshift(@INC, $homedir);
require "ctime.pl"; # For logging purposes
require "majordomo.pl";
require "majordomo_version.pl";
require "config_parse.pl";
# pickup hostname from majordomo.cf unless defined on the command line
$opt_h = $opt_h || $whereami;
# smash case for the list name
$opt_l =~ tr/A-Z/a-z/;
# We must set up the mailers and logging as soon possible so that we can
# send and log complaints and aborts somewhere. Unfortunately we need to
# parse the config file to get some of the variables. So we fake it here,
# and set them properly later.
# XXX It is possible that owner-$opt_l won't be the right address, but we
# have little choice. Sending the bounces to $whoami_owner is an option,
# but might not clearly indicate the list name.
$sendmail_command = $sendmail_command || "/usr/lib/sendmail";
$bounce_mailer = $bounce_mailer || "$sendmail_command -f\$sender -t";
&set_mail_from("owner-$opt_l");
&set_mail_sender("owner-$opt_l");
&set_mailer($bounce_mailer);
&set_abort_addr("owner-$opt_l");
&set_log($log, $opt_h, "resend", $opt_l);
if (! defined ($TMPDIR)) {
&bitch("\$TMPDIR wasn't defined in $cf. Using /usr/tmp instead.\n".
"Please define in $cf.\n");
$TMPDIR = '/usr/tmp';
}
# if we're running from a tty, just spit to stderr, else
# open up a temp file for the debug output.
#
if (! -t STDERR) {
close STDERR;
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) {
die("resend: must specify outgoing list as last arg(s)");
# this doesn't have to be this way. It could slurp it
# from the alias it was invoked as...?
}
# A classic case of feeping creaturism. While there are possibly good reasons
# why all these things can be classified on the command line, there's
# *NO* good reason why everything is "opt_X". YATTF.
#
$opt_r = "$opt_r\@$opt_h" if ( defined($opt_r) );
&get_config($listdir, $opt_l);
$opt_A = &cf_ck_bool($opt_l,"moderate") if &cf_ck_bool($opt_l,"moderate");
$opt_h = $config_opts{$opt_l,"resend_host"}
if($config_opts{$opt_l,"resend_host"} ne '');
$opt_a = $config_opts{$opt_l,"approve_passwd"}
if ($config_opts{$opt_l,"approve_passwd"} ne '');
$opt_M = $config_opts{$opt_l,"maxlength"}
if ($config_opts{$opt_l,"maxlength"} ne '');
$opt_f = $config_opts{$opt_l,"sender"}
if ($config_opts{$opt_l,"sender"} ne '');
$opt_p = $config_opts{$opt_l,"precedence"}
if ($config_opts{$opt_l,"precedence"} ne '');
$opt_r = $config_opts{$opt_l,"reply_to"}
if ($config_opts{$opt_l,"reply_to"} ne '');
$opt_I = $config_opts{$opt_l,"restrict_post"}
if ($config_opts{$opt_l,"restrict_post"} ne '');
$opt_R = &cf_ck_bool($opt_l,"purge_received")
if &cf_ck_bool($opt_l,"purge_received");
$opt_s = &cf_ck_bool($opt_l,"administrivia")
if &cf_ck_bool($opt_l,"administrivia");
$opt_d = &cf_ck_bool($opt_l,"debug")
if &cf_ck_bool($opt_l,"debug");
# Construct the envelope sender for outbound messages
if (defined($opt_f)) {
$sender = $opt_f;
} else {
$sender = "$opt_l-request";
}
# If the sender doesn't contain an `@', tack on one, followed by the
# hostname
if ($sender !~ /\@/) {
$sender .= "\@$opt_h";
}
# We can now properly define some of the mailer properties.
&set_mail_from($sender);
&set_mail_sender($sender);
&set_abort_addr($sender);
&set_log($log, $opt_h, "resend", $opt_l);
if (defined($opt_A) && ! defined($opt_a)) {
die("resend: must also specify '-a passwd' if using '-A' flag");
}
#
# These are headers to skip
#
$skip_headers = '/^from /i' .
'|| /^x-confirm-reading-to:/i' . # pegasus mail (windoze)
'|| /^disposition-notification-to:/i' . # eudora
'|| /^x-ack:/i' .
'|| /^sender:/i' .
'|| /^return-receipt-to:/i' .
'|| /^errors-to:/i' .
'|| /^flags:/i' .
'|| /^resent-/i' .
'|| /^priority/i' .
'|| /^x-pmrqc:/i' .
'|| /^return-path:/i' .
'|| /^encoding:/i' # could munge the length of the message
;
#
# Define the eval's used to catch "taboo" headers, message contents,
# and administrative headers. The taboo headers can be global
# or per list. The administrative headers are global.
#
# The eval is a construct like so:
# foo: { /^subject:\s*subscribe/ && ( $taboo = '/^subject:\s*subscribe/', last foo); }
# so that the eval returns the regexp that matched.
#
print STDERR "$0: defining evals to catch the bad stuff.\n" if $DEBUG;
if ($config_opts{$opt_l, 'taboo_headers'} ne '') {
@taboo_headers = split(/\001/,$config_opts{$opt_l, 'taboo_headers'});
if ($#taboo_headers >= $[) {
$is_taboo_header = "foo: {\n";
foreach $t (@taboo_headers) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_taboo_header .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_taboo_header .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if ($config_opts{$opt_l, 'taboo_body'} ne '') {
@taboo_body = split(/\001/,$config_opts{$opt_l, 'taboo_body'});
if ($#taboo_body >= $[) {
$is_taboo_body = "foo: {\n";
foreach $t (@taboo_body) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_taboo_body .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_taboo_body .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if (defined($global_taboo_headers)) {
@global_taboo_headers = split(/\n/,$global_taboo_headers);
if ($#global_taboo_headers >= $[) {
$is_global_taboo_header = "foo: {\n";
foreach $t (@global_taboo_headers) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_global_taboo_header .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_global_taboo_header .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
if (defined($global_taboo_body)) {
@global_taboo_body = split(/\n/,$global_taboo_body);
if ($#global_taboo_body >= $[) {
$is_global_taboo_body = "foo: {\n";
foreach $t (@global_taboo_body) {
($ts = $t) =~ s/(['\\])/\\$1/g;
$is_global_taboo_body .= "$t && (\$taboo = '$ts', last foo);\n";
}
$is_global_taboo_body .= "\$taboo = \"\";\n}; \$taboo;\n";
}
}
#"; dammit.
# admin subject checks. Since $admin_headers is defined in $cf
# (majordomo.cf), an upgrade may not have $admin_headers.
# Bitch about it if so.
#
if (! defined($admin_headers)) {
&bitch("resend: \$admin_headers not defined in $cf !!\n" .
"Majordomo will only catch \"subscribe\" and \"unsubscribe\" in\n" .
"the subject field...\n");
@admin_headers = ('/^subject:\s*subscribe\b/i' ,
'/^subject:\s*unsubscribe\b/i');
} else {
@admin_headers = split(/\n/, $admin_headers);
}
$is_admin_header = "foo: {\n";
foreach $t (@admin_headers) {
$is_admin_header .= "$t && (\$taboo = '$t', last foo);\n";
}
$is_admin_header .= "\$taboo = \"\";\n}; \$taboo;\n";
# Body Check!
# Common things that people send to the wrong address.
# These are caught in the first 10 lines of the message body
# if 'administravia' is turned on and the message isn't marked approved.
#
# The code that catches this should transparently redirect
# majordomo commands to majordomo. That would give the additional
# advantage of not having to add to this silly construct for
# each new majordomo command.
#
# $admin_body should be defined in the $cf file, but an upgrade
# may miss this fact. Bitch about it, and use a minimal list if so.
#
if (! defined($admin_body)) {
&bitch("resend: \$admin_body not defined in $cf !!\n" .
"Majordomo will only catch \"subscribe\" and \"unsubscribe\" in\n" .
"the body.\nLook at $homedir/sample.cf for a good definition.");
@admin_body = ('/^subject:\s*subscribe\b/i' ,
'/^subject:\s*unsubscribe\b/i');
} else {
@admin_body = split(/\n/, $admin_body);
}
$is_admin_body = "foo: {\n";
foreach $t (@admin_body) {
$is_admin_body .= "$t && (\$taboo = '$t', last foo);\n";
}
$is_admin_body .= "\$taboo = \"\";\n}; \$taboo;\n";
print STDERR "$0: caching the message.\n" if $DEBUG;
#
# cache the message, so the parent sendmail process can exit.
#
&open_temp(OUT, "$TMPDIR/resend.$$.out") ||
&abort("resend: Can't open $TMPDIR/resend.$$.out: $!");
&open_temp(IN, "$TMPDIR/resend.$$.in") ||
&abort("resend: Can't open $TMPDIR/resend.$$.in: $!");
while (<STDIN>) {
print IN $_;
}
close(IN);
open(IN, "$TMPDIR/resend.$$.in") ||
die("resend: Can't open $TMPDIR/resend.$$.tmp: $!");
#
# Message parsing starts here
#
print STDERR "$0: parsing header.\n" if $DEBUG;
# parse the header for bad lines, etc. We'll bounce in a moment.
#
$result = &parse_header;
# The first line of the body could hold an approved line. Let's check.
#
$_ = <IN>;
if (/^approved:\s*(.*)/i # aha!
&& defined($opt_a)) {
# OK, is it a valid "Approved:" line?
$approved = &chop_nl($1);
if ($approved ne $opt_a
&& !(&main'valid_passwd($listdir, $opt_l, $approved))) { #Augh!')){
$result .= " Invalid 'Approved:' header";
undef $approved;
}
# The Approved: line is valid
# Look at the next line:
$_ = <IN>;
if (/\S/) {
# We have something other than a blank line. We _assume_ it's
# header. Consequences: if it's not a header, things get screwed
# badly. If we reverse the logic and look instead for something
# header-like, we permit the possibility of the moderator leaving
# out the blank line, which is not a good idea because they might
# get used to it, which will bite them when they approve a message
# starting something that looks like a header.
# XXX Options: complain if we find no blank line and no header-like
# stuff.
close OUT; # Nuke the output so far.
unlink "$TMPDIR/resend.$$.out"; # XXX These filenames should be in
# variables.
# Open a new temp file.
&open_temp(OUT, "$TMPDIR/resend.$$.out") ||
&abort("resend: Can't open $TMPDIR/resend.$$.out: $!");
# We'll be nice and skip a From_ mailbox separator, which just
# might have been quoted by some intervening mail munger.
if (!/^>?From /) {
# Rewind back over the header line we just pulled
seek(IN, - length($_), 1);
}
# Parse the following as a completely new message.
$result .= &parse_header; # The return value won't matter; we're
# approved.
}
# else the line was blank; we let it be eaten and continue
} else {
# No approved line, dniwer
seek(IN, - length($_), 1);
}
print STDERR "$0: checking for valid sender.\n" if $DEBUG;
# Check for a valid sender, if the list has restrict_post set
# and the message isn't approved.
#
# aauuuugggh! 'moderator' != 'restrict_post' !! They should be the
# same!!
#
$result .= &check_sender if ( defined( $opt_I ) && ! defined ($approved));
# If approval is required, and we haven't got it, boing it goes..
#
$result = "Approval required: $result" if
(defined($opt_A) && ! defined($approved));
print STDERR "$0: sender check: '$result'\n" if $DEBUG;
# Print the RFC822 separator
print OUT "\n";
# Print out any message_fronters
#
if ( $config_opts{$opt_l,"message_fronter"} ne '' ) {
local($fronter) = &config'substitute_values (
$config_opts{$opt_l,"message_fronter"}, $opt_l);#';
$fronter =~ s/\001|$/\n/g;
print OUT $fronter;
}
# We are guaranteed to be just after a blank line now. Slurp the body
$result .= &parse_body;
# Yes Tigger, *now* you can bounce. We've checked for
# any Approved headers & lines, taboo_headers, and taboo_bodies
&bounce($result) if ( $result =~ /\S/ && ! defined($approved));
# Print out any message_footers
#
print STDERR "$0: adding any footers.\n" if $DEBUG;
if ( $config_opts{$opt_l,"message_footer"} ne '' ) {
local($footer) =
&config'substitute_values(
$config_opts{$opt_l,"message_footer"}, $opt_l); #'
$footer =~ s/\001|$/\n/g;
print OUT $footer;
}
# Finished munging the message and decided it's valid, now send it out.
#
close OUT;
# The following eval expands embedded variables like $sender
$sendmail_cmd = eval qq/"$mailer"/;
$sendmail_cmd .= " " . join(" ", @ARGV);
# check for the dreaded -t option to sendmail, which will cause
# mail to loop 26 times...
#
if ($sendmail_cmd =~ /sendmail/ && $sendmail_cmd =~ /\s-t/) {
$sendmail_cmd =~ s/-t//;
&bitch("resend: \$sendmail_cmd (aka \$mailer in majordomo.cf\n" .
"had a -t option. This will cause mail to loop 26 times.\n" .
"Since this probably isn't what you want to have happen,\n".
"resend has not passed that option to sendmail.\n");
}
print STDERR "$0: \$sendmail_cmd is $sendmail_cmd\n" if $DEBUG;
# To debug or not debug, that is the question.
#
if (defined($opt_d)) {
$| = 1;
$, = ' ';
print STDERR "Command: $sendmail_cmd\n";
open (IN, "$TMPDIR/resend.$$.out");
while (<IN>) {
print STDERR $_;
}
unlink(&fileglob("$TMPDIR", "^resend\.$$\."));
exit(0);
}
# open the mailer
#
local(*MAILOUT, *MAILIN);
if (defined($isParent = open(MAILOUT, "|-"))) {
&do_exec_sendmail(split(' ', $sendmail_cmd))
unless $isParent; # only if we're in the child
} else {
&abort("Failed to fork prior to mailer exec");
}
# open our tmp file
#
open(MAILIN, "$TMPDIR/resend.$$.out");
# spit it out!
#
while (<MAILIN>) {
print MAILOUT $_;
}
# cleanup
#
close(MAILIN);
unlink(&fileglob("$TMPDIR", "^resend\.$$\.")) || &abort("Error unlinking temp files: $!");
close(MAILOUT) || do {
$? >>= 8;
&abort("Mailer $sendmail_cmd exited unexpectedly with error $?")
unless ($sendmail_cmd =~ /sendmail/ && $? == $EX_NOUSER);
};
# Seeya.
#
exit(0);
######################################################################
#
# Subroutines.
#
######################################################################
# check for a valid sender for moderated lists.
#
sub check_sender {
# Uh, who?
return " This may be hard to believe, but there was no \"From:\" field" .
"in this message I just received. I'm not gonna send it out, " .
"but you can... " if ! defined($from);
local($file) = 0;
# !@$#% cryptic variables. opt_I is restrict_post, which is a colon
# or whitespace seperated list of files that can contain valid
# senders.
# [[[ Scary, I just realized that !@$#% is almost valid perl... ]]]
local(@files) = split (/[:\s]+/, $opt_I);
foreach $file (@files) {
# Return a null message if the sender (from the From: or
# Reply-To: headers) is found
#
return "" if &is_list_member($from, $listdir, $opt_l, $file) ||
(defined $reply_to &&
$reply_to ne $from &&
&is_list_member($reply_to, $listdir, $opt_l, $file));
}
# We only get here if nothing matches.
#
" Non-member submission from [$from] ";
}
#
# parse_header.
# Slurp in the header, checking for bad things. Returns a non-zero length string if
# a taboo or administrative header is found.
#
# [[[ Why couldn't one simply slurp the header in, assign it to an
# assoc. array, and print out everything but the bad stuff? ]]]
#
sub parse_header {
local($gonna_bounce);
local($kept_last) = 0; # our return flag/string.
print STDERR "$0: parse_header: enter.\n" if $DEBUG;
print STDERR "$0: parse_header: taboo_headers = $is_taboo_header\n" if $DEBUG;
print STDERR "$0: parse_header: global_taboo_headers = $is_global_taboo_header\n" if $DEBUG;
print STDERR "$0: parse_header: admin_headers = $is_admin_header\n" if $DEBUG;
while (<IN>) {
print STDERR "$0: parse_header: [$.: $_]" if $DEBUG;
last if /^$/; # stop when we hit the end. RFC822.
next unless /\S/; # skip leading blank lines; usually only
# there if this is a restart after an
# in-body "Approved:" line
print STDERR "$0: parse_header: [$.] taboo_header check\n"
if $DEBUG;
# check for taboo_headers or approved header
#
if ($#taboo_headers >= $[ && !$approved &&
eval $is_taboo_header) {
$gonna_bounce .= "taboo header: $taboo ";
print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
}
if ($DEBUG && $@) {
# Something went boink in eval, say something useful.
print STDERR "$0: parse_header: taboo_header error $@\n";
}
if ($#global_taboo_headers >= $[ && !$approved &&
eval $is_global_taboo_header) {
$gonna_bounce .= "global taboo header: $taboo ";
print STDERR "$0: parse_header: [$.: boing: $gonna_bounce\n" if $DEBUG;
}
if ($DEBUG && $@) {
# Something went boink in eval, say something useful.
print STDERR "$0: parse_header: global_taboo_header error $@\n";
}
# check for administative headers:
# Usually subscribe, unsubscribe, etc, in Subject field
#
print STDERR "$0: parse_header: [$.] administrative_header check\n"
if $DEBUG;
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;
}
print STDERR "$0: parse_header: Approved check\n" if $DEBUG;
# Check for Approved line
#
# Oddly enough, we may already be approved when we get here. In
# that case, we should nuke any extra Approved: headers we see.
# Why? Well, consider this: you change the password, but send an
# approved message out before the config change takes effect. So
# it bounces back to you with the Approved: line in it. This line
# is now valid. You approve the bounce using the cut-and-paste
# method, putting another Approved: line in front of the headers of
# the raw bounced message and send it off. There are now two
# Approved: headers. If we don't remove the Approved: header from
# the headers of the message you pasted, we've revealed your list
# password.
if (/^approved:\s*(.*)/i && defined($opt_a)) {
if (!$approved) {
print STDERR "$0: parse_header: found an approved header\n" if $DEBUG;
$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 ')
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.
# this allows a message with a taboo_header or admin_header
# but with a valid Approved line to be posted.
$gonna_bounce = '';
next; # gotta remove that approved line, dontcha know
}
}
else {
# We have already been approved, so skip this header
next;
}
}
print STDERR "$0: parse_header: skipping headers\n" if $DEBUG;
# skip all these headers
if (eval $skip_headers) {
$kept_last = 0;
print STDERR "$0: skipped\n" if $DEBUG;
next;
}
# skip these special headers
if ((/^precedence:/i && defined($opt_p)) # skip only if "-p" set
|| (/^received:/i && defined($opt_R)) # skip only if "-R" set
|| (/^reply-to:/i && defined($opt_r)) # skip only if "-r" set
|| (/^\s/ && ! $kept_last)) # skip if skipped last
{
$kept_last = 0;
print STDERR "$0: skipped\n" if $DEBUG;
next;
}
# reset $kept_last in case next line is continuation
# this should go someplace now... but where?
print STDERR "$0: kept\n" if $DEBUG;
$kept_last = 1;
# prepend subject prefix
#
if ( (/^subject:\s*/i)
&& ($config_opts{$opt_l,"subject_prefix"} ne '')) {
print STDERR "$0: parse_header: adding subject prefix\n" if $DEBUG;
local($foo) = &config'substitute_values($config_opts{$opt_l,"subject_prefix"}, $opt_l);#';
local($foo_pat) = $foo;
$foo_pat =~ s/(\W)/\\$1/g;
s/^subject:[^\S\n]*/Subject: $foo /i if !/$foo_pat/;
}
# snag reply-to field
#
$reply_to = $1 if /^reply-to:\s*(.+)/i;
# snag from line
#
if ( /^from:\s*(.+)/i ) {
$from = $1;
$from_last = 1; # the from line can span lines
}
elsif ( defined($from_last) ) {
if ( /^\s+(.+)/ ) {
$from .= " $1";
} else {
undef($from_last);
}
}
# Virtual Majordomo Hack
# s/^to:(.*)\b$opt_l\b(.*)$/To:$1 $opt_l\@$whereami $2/i ;
&check_hdr_line($_); # check for length & balance on from, cc, and to fields.
print OUT $_;
}
# finished with the header.
# Now, we aren't going to bounce yet, even if it looks bad,
# because we allow an Approved line as the _first_ line in the *body*.
#
# return $gonna_bounce if length($gonna_bounce);
print STDERR "$0: parse_header: adding header fields\n"
if $DEBUG;
# add new header fields
print OUT "Sender: $sender\n";
if (defined($opt_p)) {
print OUT "Precedence: $opt_p\n";
}
if (defined($opt_r)) {
print OUT "Reply-To: ", &config'substitute_values($opt_r), "\n"; #';
}
# print out per-list additonal headers
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;
print OUT $headers;
}
print STDERR "$0: parse_header: returning with '$gonna_bounce'\n" if $DEBUG;
" $gonna_bounce ";
}
# Meander through the message body, checking for
# administravia, taboo stuff, and excessive length.
#
sub parse_body {
local($body_line_count, $body_len) = 0;
local($gonna_bounce);
print STDERR "$0: parse_body: enter\n" if $DEBUG;
while (<IN>) {
$body_line_count++;
$body_len += length($_);
# check for administravia in the first 10 lines of the body
# if so told and not approved.
if ($body_line_count < 10
&& defined($opt_s)
&& !defined($approved)
&& eval $is_admin_body) {
$gonna_bounce .=
" Admin request of type $taboo at line $body_line_count ";
next;
}
# if not approved, check for taboo body stuff
# and message length
#
if ( !defined($approved)) {
if ( $#taboo_body >= $[
&& eval $is_taboo_body) {
$gonna_bounce .=
" taboo body match \"$taboo\" at line $body_line_count ";
next;
}
if ($#global_taboo_body >= $[
&& eval $is_global_taboo_body) {
$gonna_bounce .=
" global taboo body match \"$taboo\" " .
"at line $body_line_count ";
next;
}
# make sure it doesn't make the message too long
if (defined($opt_M)
&& $body_len > $opt_M
&& !$already_bitched_about_length) {
$already_bitched_about_length++;
print STDERR "$0: parse_body: message too long\n" if $DEBUG;
$gonna_bounce .= " Message too long (>$opt_M chars) ";
next;
}
}
print OUT $_;
} # while
print STDERR "$0: parse_body: exiting with '$gonna_bounce'\n"
if $DEBUG;
" $gonna_bounce ";
}
sub check_balance {
print STDERR "$0: check_balance: enter: $_\n" if $DEBUG;
# set a temporary variable
local($t) = shift;
# Remove quoted material
# ( looks like lisp, don't it? )
1 while $t =~ s/(^|([^\\\"]|\\.)+)\"([^\\\"\n]|\\.)*\"?/$1/g; #"
# strip out all nested parentheses
1 while $t =~ s/\([^\(\)]*\)//g;
# strip out all nested angle brackets
1 while $t =~ s/\<[^\<\>]*\>//g;
# if any parentheses or angle brackets remain, were imbalanced
if ($t =~ /[\(\)\<\>]/ && ! defined($approved)) {
&bounce("Imbalanced parentheses or angle brackets");
return(undef);
}
return(1);
}
sub check_hdr_line {
local($_) = shift;
print STDERR "$0: check_hdr_line: enter: $_\n" if $DEBUG;
if (! /^\s/) { # is this a continuation line?
# Not a continuation line.
# If $balanced_fld is defined, it means the last field was one
# that needed to have balanced "()" and "<>" (i.e., "To:", "From:",
# and "Cc:", so check it. We do it here in case the last field was
# multi-line.
if (defined($balanced_fld)) {
&check_balance($balanced_fld);
}
# we undefine $balanced_fld and reset $field_len; these may be set below
undef($balanced_fld);
$field_len = 0;
}
# is this a field that must be checked for balanced "()" and "<>"?
if (defined($balanced_fld) || /^from:/i || /^cc:/i || /^to:/i) {
# yes it is, but we can't check it yet because there might be
# continuation lines. Buffer it to be checked at the beginning
# of the next non-continuation line.
# is this line too long?
if ((length($_) > $MAX_HEADER_LINE_LENGTH) && ! defined($approved)) {
&bounce("Header line too long (>$MAX_HEADER_LINE_LENGTH)");
return(undef);
}
# is this field too long?
if ((($field_len += length($_)) > $MAX_TOTAL_HEADER_LENGTH) && ! defined($approved)) {
&bounce("Header field too long (>$MAX_TOTAL_HEADER_LENGTH)");
return(undef);
}
$balanced_fld .= $_;
chop($balanced_fld);
}
# if we get here, everything was OK.
return(1);
}
sub bounce {
local(*BOUNCE);
local($reason) = shift;
local($_);
print STDERR "$0: bounce enter\n" if $DEBUG;
&send_bounce(BOUNCE,
(( $config_opts{$opt_l, 'moderator'} ne "") ?
$config_opts{$opt_l, 'moderator'} : "$opt_l-approval\@$whereami"),
"BOUNCE $opt_l\@$opt_h: $reason");
seek(IN, 0, 0);
while (<IN>) {
print BOUNCE $_;
}
close(BOUNCE);
unlink(&fileglob("$TMPDIR", "^resend\.$$\."));
print STDERR "$0: bounce exiting\n" if $DEBUG;
exit(0);
}
sub send_bounce {
local(*MAIL) = shift;
local($to) = shift;
local($subject) = shift;
local($isParent);
local($mailcmd);
if (defined $bounce_mailer) {
# The eval expands embedded variables like $sender
$mailcmd = eval qq/"$bounce_mailer"/;
}
else {
# Painful, but we have to provide some kind of backwards
# compatibility and this is what 1.93 used
$mailcmd = "/usr/lib/sendmail -f$sender -t";
}
# clean up the addresses, for use on the sendmail command line
local(@to) = &ParseAddrs($to);
$to = join(", ", @to);
# open the process
if (defined($opt_d)) {
# debugging, so just say it, don't do it
open(MAIL, ">-");
print MAIL ">>> $mailcmd\n";
} else {
if (defined($isParent = open(MAIL, "|-"))) {
&do_exec_sendmail(split(' ', $mailcmd))
unless $isParent;
} else {
&abort("Failed to fork prior to mailer exec");
}
}
# generate the header
print MAIL <<"EOM";
To: $to
From: $sender
Subject: $subject
EOM
return;
}

View File

@@ -0,0 +1,316 @@
#
# A sample configuration file for majordomo. You must read through this and
# edit it accordingly!
#
# $whereami -- What machine am I running on?
#
$whereami = "example.com";
# $whoami -- Who do users send requests to me as?
#
$whoami = "Majordomo\@$whereami";
# $whoami_owner -- Who is the owner of the above, in case of problems?
#
$whoami_owner = "Majordomo-Owner\@$whereami";
# $homedir -- Where can I find my extra .pl files, like majordomo.pl?
# the environment variable HOME is set by the wrapper
#
if ( defined $ENV{"HOME"}) {
$homedir = $ENV{"HOME"};
} else {
$homedir = "/etc/virtual/majordomo";
}
# $listdir -- Where are the mailing lists?
#
$listdir = "$homedir/lists";
# $digest_work_dir -- the parent directory for digest's queue area
# Each list must have a subdirectory under this directory in order for
# digest to work. E.G. The bblisa list would use:
# /usr/local/mail/digest/bblisa
# as its directory.
#
$digest_work_dir = "/usr/local/mail/digest";
# $log -- Where do I write my log?
#
$log = "$homedir/Log";
# $sendmail_command -- Pathname to the sendmail program
# usually /usr/lib/sendmail, but some newer BSD systems
# seem to prefer /usr/sbin/sendmail
#
$sendmail_command = "/usr/lib/sendmail";
# $sendmail_command = "/usr/sbin/sendmail";
# $mailer -- What program and args do I use to send mail to the list?
# $bounce_mailer -- What is used to send mail anywhere else?
# The variables $to, $from, $subject, and $sender can be interpolated into
# this command line. Note, however, that the $to, $from, and $subject
# variables may be provided by the person sending mail, and much mischief
# can be had by playing with this variable. It is perfectly safe to use
# $sender, but the others are insecure.
#
# Sendmail option -oi: Do not take a . on a line by itself as the message
# terminator.
# Sendmail option -oee: Force sendmail to exit with a zero exit status if
# if it's not going to give useful information.
#
$mailer = "$sendmail_command -oi -oee -f\$sender";
$bounce_mailer = "$sendmail_command -oi -oee -f\$sender -t";
# You can special case the mailer used to deliver outbound mail as follows:
#
# To use TLB and use no outgoing alias:
# if ($main'program_name eq 'mj_resend' && $opt_l eq 'test-list') {
# $mailer = "/usr/local/majordomo/tlb /usr/local/lists/${opt_l}.tlb";
# }
#
# To use a different Sendmail queue for this list's mail:
# if ($main'program_name eq 'mj_resend' && $opt_l eq 'test-list') {
# $mailer = "$sendmail_command -oQ /var/spool/listq -f\$sender";
# }
# You can force Majordomo to delay any processing if the system load is too
# high by uncommenting the following lines. THIS ONLY WORKS if your "uptime"
# command (usually found in /usr/bin/uptime or /usr/bsd/uptime)
# returns a string like:
# 5:23pm up 5:51, 9 users, load average: 0.19, 0.25, 0.33
#
#$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.
#
#($avg_1_minute, $avg_5_minutes, $avg_15_minutes) =
# $uptime =~ /average:\s+(\S+),\s+(\S+),\s+(\S+)/;
#
#exit 75 if ($avg_15_minutes >= $max_loadavg); # E_TEMPFAIL
#
# Set the default subscribe policy for new lists here.
# If not defined, defaults to "open", but in today's increasingly
# imbecile Internet, "open+confirm" or "auto+confirm" is a wiser
# choice for publicly available Majordomo servers.
#
$config'default_subscribe_policy = "open+confirm";
#
# Configure X400 parsing here. This is functional, but not well tested
# and rather a hack.
# By default all addresses that look x400-ish will be checked for a
# @ sign (meaning that it's headed to an smtp->x400 gateway, as well
# as the 'c=' and 'a[dm]=' parts, which mean something as well.
#
# If you will be receiving x400 style return addresses that do not have
# an @ sign in them indicating an smtp->x400 gateway, set $no_x400at to 1.
# Otherwise, leave $no_x400 at 0.
#
$no_x400at = 0;
#
# If you will be receiving x400 addresses without the c= or a[dm]= parts
# set the $no_true_x400 variable to 1. This will disable checking for
# "c=" and "a[dm]=" pieces.
#
$no_true_x400 = 0;
#--------------------------------------------------------------------
# Stuff below here isn't commonly changed....
#--------------------------------------------------------------------
#
# Majordomo will look for "get" and "index" files related to $list in
# directory "$filedir/$list$filedir_suffix", so set $filedir and
# $filedir_suffix appropriately. For instance, to look in
# /usr/local/mail/files/$list, use:
# $filedir = "/usr/local/mail/files";
# $filedir_suffix = ""; # empty string
# or to look in $listdir/$list.archive, use:
# $filedir = "$listdir";
# $filedir_suffix = ".archive";
$filedir = "$listdir";
$filedir_suffix = ".archive";
# What command should I use to process an "index" request?
#
$index_command = "/bin/ls -lRL";
# If you want to use FTPMAIL, rather than local access, for file transfer
# and access, define the following:
# $ftpmail_address = "ftpmail\@decwrl.dec.com";
# $ftpmail_location = "FTP.$whereami";
# if you want the subject of the request to be included as part of the
# subject of the reply (useful when automatically testing, or submitting
# multiple command sets), set $return_subject to 1.
#
$return_subject = 1;
# If you are using majordomo at the -request address, set the
# following variable to 1. This affects the welcome message that is
# sent to a new subscriber as well as the help text that is generated.
#
$majordomo_request = 0;
# If you have lists that have who turned off, but still allow which
# requests to work for subscribed members, and you don't want to have
# "which @" to act like a who, the variable $max_which_hits sets the
# number of hits that are allowed using which before an error is returned.
# Arguably this should be a per list settable number.
#
$max_which_hits = 0;
# Set the umask for the process. Used to set default file status for
# config file.
#
umask(007);
$config_umask = 007;
# don't change this. It checks to make sure that you have a new enough
# version of perl to run majordomo. It is in here because this file is
# used by almost all of the majordomo programs.
#
die "Perl version $] too old\n" if ($] < 4.019);
# the safe locations for archive directories
# None of the parameters that use safedirs are actually used, so
# @safedirs is a placeholder for future functionality.
# Just ignore it for version 1.90 through 1.94.
#
@safedirs = ( );
# Directory where resend temporarily puts its rewritten output message.
# For the paranoid, this could be changed to a directory that only
# majordomo has r/w permission to.
# Uses the environment variable TMPDIR, since that's pretty common
#
$TMPDIR = $ENV{'TMPDIR'} || "/usr/tmp";
# Tune how long set_lock tries to obtain a lock before giving up. Each
# attempt waits 1 to 10 seconds before trying again and waittime is
# the total minimum time spent trying. This defaults to 600 seconds (5
# minutes), which translates to no less then 60 nor more than 600 tries.
#
# $shlock'waittime = 1200;
# tune the cookie for subscribe_policy=confirm. Normally this is
# set to $homedir. *Don't* make this something like rand(400),
# the key isn't saved between sessions.
#
# $cookie_seed = "Harry Truman, Doris Day, Red China, Johnnie Ray" .
# " South Pacific, Walter Winchell, Joe DiMaggio";
# The maximum character length of the header lines for resend
#
$MAX_HEADER_LINE_LENGTH = 128;
# The maximum character length of the _entire_ header for resend
#
$MAX_TOTAL_HEADER_LENGTH = 1024;
# List of perl regular expressions that, if found in the headers of a message,
# will cause the message to be bounced to the list approver.
# Put each regular expression on a separate line before the "END" mark, with
# no trailing ";"
# For example:
# $global_taboo_headers = <<'END';
# /^from:.*trouble\@hassle\.net/i
# /^subject:.*non-delivery notice/i
# END
# NOTE! Using ' instead of " in the 'END' is VERY IMPORTANT!!!
#
# Administrative checks. These used to be buried in the resend code
#
$admin_headers = <<'END';
/^subject:\s*subscribe\b/i
/^subject:\s*unsubscribe\b/i
/^subject:\s*uns\w*b/i
/^subject:\s*.*un-sub/i
/^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.
# These are caught in the first 10 lines of the message body
# if 'administrivia' is turned on and the message isn't marked approved.
#
# The code that catches this should transparently redirect
# majordomo commands to majordomo. That would give the additional
# advantage of not having to add to this silly construct for
# each new majordomo command.
#
$admin_body = <<'END';
/\bcancel\b/i
/\badd me\b/i
/\bdelete me\b/i
/\bremove\s+me\b/i
/\bchange\b.*\baddress\b/
/\bsubscribe\b/i
/^sub\b/i
/\bunsubscribe\b/i
/^unsub\b/i
/\buns\w*b/i
/^\s*help\s*$/i
/^\s*info\s*$/i
/^\s*info\s+\S+\s*$/i
/^\s*lists\s*$/i
/^\s*which\s*$/i
/^\s*which\s+\S+\s*$/i
/^\s*index\s*$/i
/^\s*index\s+\S+\s*$/i
/^\s*who\s*$/i
/^\s*who\s+\S+\s*$/i
/^\s*get\s+\S+\s*$/i
/^\s*get\s+\S+\s+\S+\s*$/i
/^\s*approve\b/i
/^\s*passwd\b/i
/^\s*newinfo\b/i
/^\s*config\b/i
/^\s*newconfig\b/i
/^\s*writeconfig\b/i
/^\s*mkdigest\b/i
END
# taboo headers to catch
#
$global_taboo_headers = <<'END';
/^subject: ndn: /i
/^subject:\s*RCPT:/i
/^subject:\s*Delivery Confirmation\b/i
/^subject:\s*NON-DELIVERY of:/i
/^subject:\s*Undeliverable Message\b/i
/^subject:\s*Receipt Confirmation\b/i
/^subject:\s*Failed mail\b/i
/^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
#
# For example:
# $global_taboo_body = <<'END';
# /taboo topic/i
# /another taboo/i
# END
# NOTE! Using ' instead of " in the next line is VERY IMPORTANT!!!
#
$global_taboo_body = <<'END';
END
# Majordomo will not send replies to addresses which match this.
# The match is done case-insensitively.
$majordomo_dont_reply = '(mailer-daemon|uucp|listserv|majordomo|listproc)\@';
1;
# $Header: /sources/cvsrepos/majordomo/sample.cf,v 1.34 1997/08/27 15:00:31 cwilson Exp $

View File

@@ -0,0 +1,312 @@
# PERL implementation of Erik E. Fair's 'shlock' (from the NNTP distribution)
# Ported by Brent Chapman <Brent@GreatCircle.COM>
# Taken from shlock.pl and majordomo.pl in Majordomo distribution
# Merged into package by Bill Houle <Bill.Houle@SanDiegoCA.NCR.COM>
package shlock;
require 'majordomo.pl'; # For bitch() and abort()
# 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;
# Lock a process via lockfile.
#
sub main'shlock {
local($file) = shift;
local($tmp);
local($retcode) = 0;
print STDERR "trying lock '$file' for pid $$\n" if $shlock_debug;
return(undef) unless ($tmp = &extant_file($file));
{ # 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;
} 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'): $!");
}
} else {
print STDERR "got lock '$file'\n" if $shlock_debug;
$retcode = 1;
}
}
unlink($tmp) || &alert("shlock: unlink('$file'): $!");
return($retcode);
}
# Create a lock file (with retry).
#
sub main'set_lock {
local($lockfile) = @_;
local($slept) = 0;
while ($slept < $waittime) {
return 1 if &main'shlock("$lockfile");
# didn't get the lock; wait 1-10 seconds and try again.
$slept += sleep(int(rand(9) + 1));
}
# if we got this far, we ran out of tries on the lock.
return undef;
}
sub main'free_lock {
unlink $_[0];
}
# open a file locked for exclusive access; we remember the name of the lock
# file, so that we can delete it when we close the file
#
sub main'lopen {
local($FH) = shift;
local($mode) = shift;
local($file) = shift;
# $fm is what will actually get passed to open()
local($fm) = "$mode$file";
local($status);
# create name for lock file
local($lockfile) = $file;
$lockfile =~ s,([^/]*)$,L.$1,;
# force unqualified filehandles into callers' package
local($package) = caller;
$FH =~ s/^[^':]+$/$package'$&/;
return undef unless &main'set_lock("$lockfile");
# Got the lock; now try to open the file
if ($status = open($FH, $fm)) {
# File successfully opened; remember the lock file for deletion
$lock_files[fileno($FH)] = "$lockfile";
} else {
# File wasn't successfully opened; delete the lock
&main'free_lock($lockfile);
}
# return the success or failure of the open
return $status;
}
# reopen a file already opened and locked (probably to change read/write mode).
# We remember the name of the lock file, so that we can delete it when
# we close the file
#
sub main'lreopen {
local($FH) = shift;
local($mode) = shift;
local($file) = shift;
# $fm is what will actually get passed to open()
local($fm) = "$mode$file";
# create name for lock file
local($lockfile) = $file;
$lockfile =~ s,([^/]*)$,L.$1,;
# force unqualified filehandles into callers' package
local($package) = caller;
$FH =~ s/^[^':]+$/$package'$&/;
# close the old file handle, and delete the lock reference
if ($lock_files[fileno($FH)]) {
undef($lock_files[fileno($FH)]);
close($FH);
} else {
# the file wasn't already locked
# unlink("$lockfile"); ### Do we really want to do this?
return(undef);
}
# We've already got the lock; now try to open the file
$status = open($FH, $fm);
if (defined($status)) {
# File successfully opened; remember the lock file for deletion
$lock_files[fileno($FH)] = "$lockfile";
} else {
# File wasn't successfully opened; delete the lock
unlink("$lockfile");
}
# return the success or failure of the open
return($status);
}
# Close a locked file, deleting the corresponding .lock file.
#
sub main'lclose {
local($FH) = shift;
# force unqualified filehandles into callers' package
local($package) = caller;
$FH =~ s/^[^':]+$/$package'$&/;
local($lock) = $lock_files[fileno($FH)];
close($FH);
unlink($lock);
}
# Open a temp file. Ensure it is temporary by checking for other links, etc.
#
sub main'open_temp {
local($FH_name, $filename) = @_;
local($inode1, $inode2, $dev1, $dev2) = ();
# force unqualified filehandles into callers' package
local($package) = caller;
$FH_name =~ s/^[^':]+$/$package'$&/;
if ( -e $filename ) {
&alert("Failed to open temp file '$filename', it exists");
return(undef);
}
unless (open($FH_name, ">> $filename")) {
local($tempdir) = ($filename =~ m|(.*)/|) ? $1 : ".";
if (! -e $tempdir) {
&main'abort("shlock: '$tempdir' does not exist");
}
elsif (! -d _) {
&main'abort("shlock: '$tempdir' is not a directory\n");
}
elsif (! -w _) {
&main'abort("shlock: '$tempdir' is not writable by UID $> GID",
(split(" ", $) ))[0], "\n");
}
else {
&alert("open of temp file '$filename' failed: $!");
}
return(undef);
}
if ( -l $filename ) {
&alert("Temp file '$filename' is a symbolic link after opening");
return(undef);
}
if ( (stat(_))[3] != 1 ) {
&alert("'$filename' has more than one link after opening");
return(undef);
}
($dev1, $inode1) = (lstat(_))[0..1];
local(*FH) = $FH_name;
($dev2, $inode2) = (stat(FH))[0..1];
if ($inode1 != $inode2) {
&alert("Inode for filename does not match filehandle! Inode1=$inode1 Inode2=$inode2");
return(undef);
}
if ($dev1 != $dev2) {
&alert("Device for filename does not match filehandle! Dev1=$dev1 Dev2=$dev2");
return(undef);
}
if ( (stat(_))[3] != 1 ) {
&alert("filehandle has more than one link after opening");
return(undef);
}
return(1);
}
sub is_process {
local($pid) = shift;
print STDERR "process $pid is " if $shlock_debug;
if ($pid <= 0) {
print STDERR "invalid\n" if $shlock_debug;
return(0);
}
if (kill(0, $pid) <= 0) {
if ($! == $ESRCH)
{ print STDERR "dead\n" if $shlock_debug; return 0; }
elsif ($! == $EPERM)
{ print STDERR "alive\n" if $shlock_debug; return 1; }
else
{ print STDERR "state unknown: $!\n" if $shlock_debug; return 1; }
}
print "alive\n" if $shlock_debug;
return 1;
}
sub check_lock {
local($file) = shift;
local(*FILE, $pid, $buf);
print STDERR "checking extant lock '$file'\n" if $shlock_debug;
unless (open(FILE, "$file")) {
&alert("shlock: open('$file'): $!") if $shlock_debug;
return 1;
}
$pid = int($buf = <FILE>);
if ($pid <= 0) {
close(FILE);
print STDERR "lock file format error\n" if $shlock_debug;
return 0;
}
close(FILE);
return(&is_process($pid));
}
sub extant_file {
local($file) = shift;
local(*FILE);
local($tempname);
$tempname = $file;
if ($tempname =~ /\//) {
$tempname =~ s,/[^\/]*$,/,;
$tempname .= "shlock.$$";
} else {
$tempname = "shlock.$$";
}
print STDERR "temporary filename '$tempname'\n" if $shlock_debug;
{ # redo-controlled loop
if ( -e $tempname ) {
print STDERR "file '$tempname' exists\n" if $shlock_debug;
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': $!"
if $shlock_debug;
return(undef);
}
}
unless (print FILE "$$\n") {
&alert("shlock failed: write('$tempname', '$$'): $!");
close(FILE);
unlink($tempname) || &alert("shlock: unlink('$tempname'): $!");
return(undef);
}
close(FILE);
sleep(15) if $shlock_debug; # give me a chance to look at the lock file
return($tempname);
}
1;

View File

@@ -0,0 +1,100 @@
Partial: add code to override the archive directory on a per list basis.
config file recognizes keyword archive_dir, majordomo get/index
doesn't use it yet.
Partial: add more keywords:
DONE: comments (array)- allow commentary/rcs log info
process - time interval - if in time interval, process
requests, otherwise exit status 75
file-process - see process, for get/put
resend-process - see process
load - three floats (1, 5, 15 minute load average. 0.0 means
doesn't matter). If
uptime load > any one of these, then exit with code 75 to
have sendmail requeue the job and try later.
file-times - a time/day spec for times that majordomo should process
get/index and other specs. Exit w/ code 75 if wrong time.
resend-times - a time/day spec for when resend shouldn't run.
Exit w/ code 75 if wrong time.
exclude-user - opposite of -I flag to exclude ability of people
to post to a mailing list.
NOT: analyze code to make sure all areas that require locks are in place
NOT: Analyze code to replace all mailer invocation with code that can be
set in the majordomo.cf file. This includes normalizing the
variable for the -f argument to sendmail, and the sendmail location etc.
NOT: detect error condition (e.g. out of disk space) and deal with them
(e.g. check close return values)
NOT: clean up messages that are put into the config file. Diction and
parallelism needs work.
NOT: vett any and all \001's that may be in the config file.
NOT: create an addin that uses the config file stuff.
NOT: after alan's stuff add pre/post message hook to the code.
NOT: add code to support incremental config file changes.
NOT: Add support for delayed reply REPLY handling.
Remove sendmail open from majordomo, add send_reply command
have all prints to reply be pushes onto $Reply.
First shot screwed up something with the filehandles. Need to
try again. It may be perl 4.019 rearing its ugly head.
partial: add ability to add arbitrary headers to message
config file elements in place as type string array. This should
probably be specialized so that only known or X- headers can
be specified. Also the code in resend has to be modified to
remove duplicate headers, and to allow override headers.
DONE (12/8/93): add ability to add reply to header that has sender's
from address
Just specify $SENDER as the value of the reply_to string.
Actually the entire set of $<NAME> elements recognized
by &config'substitute_values is recognized.
DONE (11/18/93): fix bug with mixing pipleines that allows portions on
incoming data stream into config file due to fork. When
running write_config (formally mk_default_config).
DONE: add configure get password
DONE: add functions absolute_dir and absolute_file to look for / forms of
paths
DONE: add support for enumerated keywords
DONE: Add keyword subscribe_policy to have values open, closed, or auto
config file recognizes it, majordomo uses it.
DONE: add support for array keyword values
Have added code to recognize key << END, and read it into a \001
seperated stringified array.
the only array values currently are: advertize/noadvertize
and majordomo can deal with the arrays.
Also comments is an array, but is only for internal config file use.
DONE: fix do_approve so it loads the config file when it gets called
this will allow config file password to be used for approves.
DONE: fix keywords so they all use _ or - as a seperator character.
chose _
DONE: enhance resend so that trailer text can be added to the code.
keyword message_footer

Binary file not shown.

View File

@@ -0,0 +1,157 @@
/*
* $Source: /sources/cvsrepos/majordomo/wrapper.c,v $
* $Revision: 1.8 $
* $Date: 1997/08/27 15:01:12 $
* $Author: cwilson $
* $State: Exp $
*
* $Locker: $
*
*/
#ifndef lint
static char rcs_header[] = "$Header: /sources/cvsrepos/majordomo/wrapper.c,v 1.8 1997/08/27 15:01:12 cwilson Exp $";
#endif
#include <stdio.h>
#include <sysexits.h>
#if defined(sun) && defined(sparc)
#include <stdlib.h>
#endif
#ifndef STRCHR
# include <string.h>
# define STRCHR(s,c) strchr(s,c)
#endif
#ifndef BIN
# define BIN "/usr/local/mail/majordomo"
#endif
#ifndef PATH
# define PATH "PATH=/bin:/usr/bin:/usr/ucb"
#endif
#ifndef HOME
# define HOME "HOME=/usr/local/mail/majordomo"
#endif
#ifndef SHELL
# define SHELL "SHELL=/bin/sh"
#endif
char * new_env[] = {
HOME, /* 0 */
PATH, /* 1 */
SHELL, /* 2 */
#ifdef MAJORDOMO_CF
MAJORDOMO_CF, /* 3 */
#endif
0, /* possibly for USER or LOGNAME */
0, /* possible for LOGNAME */
0, /* possibly for timezone */
0
};
int new_env_size = 7; /* to prevent overflow problems */
main(argc, argv, env)
int argc;
char * argv[];
char * env[];
{
char * prog;
int e, i;
if (argc < 2) {
fprintf(stderr, "USAGE: %s program [<arg> ...]\n", argv[0]);
exit(EX_USAGE);
}
/* if the command contains a /, then don't allow it */
if (STRCHR(argv[1], '/') != (char *) NULL) {
/* this error message is intentionally cryptic */
fprintf(stderr, "%s: error: insecure usage\n", argv[0]);
exit(EX_NOPERM);
}
if ((prog = (char *) malloc(strlen(BIN) + strlen(argv[1]) + 2)) == NULL) {
fprintf(stderr, "%s: error: malloc failed\n", argv[0]);
exit(EX_OSERR);
}
sprintf(prog, "%s/%s", BIN, argv[1]);
/* copy the "USER=" and "LOGNAME=" envariables into the new environment,
* if they exist.
*/
#ifdef MAJORDOMO_CF
e = 4; /* the first unused slot in new_env[] */
#else
e = 3; /* the first unused slot in new_env[] */
#endif
for (i = 0 ; env[i] != NULL && e <= new_env_size; i++) {
if ((strncmp(env[i], "USER=", 5) == 0) ||
(strncmp(env[i], "TZ=", 3) == 0) ||
(strncmp(env[i], "LOGNAME=", 8) == 0)) {
new_env[e++] = env[i];
}
}
#if defined(SETGROUP)
/* renounce any previous group memberships if we are running as root */
if (geteuid() == 0) { /* Should I exit if this test fails? */
char *setgroups_used = "setgroups_was_included"; /* give strings a hint */
#if defined(MAIL_GID)
int groups[] = { POSIX_GID, MAIL_GID, 0 };
if (setgroups(2, groups) == -1) {
#else
int groups[] = { POSIX_GID, 0 };
if (setgroups(1, groups) == -1) {
#endif
extern int errno;
fprintf(stderr, "%s: error setgroups failed errno %d", argv[0],
errno);
}
}
#endif
#ifdef POSIX_GID
setgid(POSIX_GID);
#else
setgid(getegid());
#endif
#ifdef POSIX_UID
setuid(POSIX_UID);
#else
setuid(geteuid());
#endif
if ((getuid() != geteuid()) || (getgid() != getegid())) {
fprintf(stderr, "%s: error: Not running with proper UID and GID.\n", argv[0]);
fprintf(stderr, " Make certain that wrapper is installed setuid, and if so,\n");
fprintf(stderr, " recompile with POSIX flags.\n");
exit(EX_SOFTWARE);
}
execve(prog, argv+1, new_env);
/* the exec should never return */
fprintf(stderr, "wrapper: Trying to exec %s failed: ", prog);
perror(NULL);
fprintf(stderr, " Did you define PERL correctly in the Makefile?\n");
fprintf(stderr, " HOME is %s,\n", HOME);
fprintf(stderr, " PATH is %s,\n", PATH);
fprintf(stderr, " SHELL is %s,\n", SHELL);
fprintf(stderr, " MAJORDOMO_CF is %s\n", MAJORDOMO_CF);
exit(EX_OSERR);
}

View File

@@ -0,0 +1,13 @@
#! /bin/sh
PATH=/bin:/usr/bin
IFS=" "
if [ -d /sys/node_data ]; then
arch="DomainOS"
else
arch=`arch`
fi
exec $0.${arch} "$@"
# $Header: /sources/cvsrepos/majordomo/wrapper.sh,v 1.4 1994/05/09 17:41:29 rouilj Exp $

Binary file not shown.

View File

@@ -0,0 +1 @@
e217b8408be282fec0ad2f1f11a54a0b services_es80_64.tar.gz

Binary file not shown.

View File

@@ -243,12 +243,7 @@ clean_dev()
echo -n "Is $DEVS your network adaptor with the license IP ($DIP)? (y,n) : ";
read yesno;
if [ "$yesno" = "n" ]; then
echo -n "Enter the name of the ethernet device you wish to use : ";
read ETH_DEV;
else
ETH_DEV=$DEVS
fi
else
# more than one
echo "The following ethernet devices/IPs were found. Please enter the name of the device you wish to use:";
@@ -309,45 +304,45 @@ clean_dev()
fi
if [ $CMD_LINE -eq 0 ]; then
# if [ $CMD_LINE -eq 0 ]; then
echo -n "Your external IP: ";
wget -q -O - http://myip.directadmin.com
echo "";
echo "The external IP should typically match your license IP.";
echo "";
# echo -n "Your external IP: ";
# wget -q -O - http://myip.directadmin.com
# echo "";
# echo "The external IP should typically match your license IP.";
# echo "";
if [ "$IP" = "" ]; then
yesno="n";
else
echo -n "Is $IP the IP in your license? (y,n) : ";
read yesno;
fi
# if [ "$IP" = "" ]; then
# yesno="n";
# else
# echo -n "Is $IP the IP in your license? (y,n) : ";
# read yesno;
# fi
if [ "$yesno" = "n" ]; then
echo -n "Enter the IP used in your license file : ";
read IP;
fi
# if [ "$yesno" = "n" ]; then
# echo -n "Enter the IP used in your license file : ";
# read IP;
# fi
if [ "$IP" = "" ]; then
echo "The IP entered is blank. Please try again, and enter a valid IP";
fi
fi
# if [ "$IP" = "" ]; then
# echo "The IP entered is blank. Please try again, and enter a valid IP";
# fi
# fi
############
echo "";
echo "DirectAdmin will now be installed on: $OS $OS_VER";
if [ $CMD_LINE -eq 0 ]; then
echo -n "Is this correct? (must match license) (y,n) : ";
read yesno;
# if [ $CMD_LINE -eq 0 ]; then
# echo -n "Is this correct? (must match license) (y,n) : ";
# read yesno;
if [ "$yesno" = "n" ]; then
echo -e "\nPlease change the value in your license, or install the correct operating system\n";
exit 1;
fi
fi
# if [ "$yesno" = "n" ]; then
# echo -e "\nPlease change the value in your license, or install the correct operating system\n";
# exit 1;
# fi
# fi
# Hexan
PWD_DIR=`pwd`
@@ -716,9 +711,7 @@ if ${DOWNLOAD_BETA}; then
else
APPEND_BETA=""
fi
#$BIN_DIR/wget $WGET_OPTION -S --tries=5 --timeout=60 -O $DA_PATH/update.tar.gz $BIND_ADDRESS "https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/directadmin-1.62.4.tar.gz"
$BIN_DIR/wget $WGET_OPTION -S --tries=5 --timeout=60 -O $DA_PATH/update.tar.gz $BIND_ADDRESS "https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/update.tar.gz"
$BIN_DIR/wget $WGET_OPTION -S --tries=5 --timeout=60 -O $DA_PATH/update.tar.gz $BIND_ADDRESS "https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/directadmin-1.62.4.tar.gz"
if [ ! -e $DA_PATH/update.tar.gz ]; then
echo "Unable to download $DA_PATH/update.tar.gz";
exit 3;
@@ -753,7 +746,7 @@ fi
###############################################################################
# write the setup.txt
echo "Chạy write the setup.txt $SETUP"
echo "hostname=$HOST" > $SETUP;
echo "email=$EMAIL" >> $SETUP;
echo "mysql=$DB_ROOT_PASS" >> $SETUP;
@@ -782,7 +775,9 @@ chmod 600 $SETUP
# Install it
cd $SCRIPTS_PATH;
echo "-----------------"
echo "Chạy ./install.sh $CMD_LINE"
echo "-----------------"
./install.sh $CMD_LINE
RET=$?
@@ -844,6 +839,28 @@ fi
rm -f /usr/lib/sendmail
ln -s ../sbin/sendmail /usr/lib/sendmail
echo "-------------------------------------------------------------"
echo "UPDATE DIRECTADMIN LÊN BẢN MỚI... "
echo "-------------------------------------------------------------"
#$BIN_DIR/wget $WGET_OPTION -S --tries=5 --timeout=60 -O $DA_PATH/update.tar.gz $BIND_ADDRESS "https://git.wpcloud.vn/tuend/DirectAdmin-1.62.4/raw/branch/main/update.tar.gz"
if [ ! -e $DA_PATH/update.tar.gz ]; then
echo "Unable to download $DA_PATH/update.tar.gz";
exit 3;
fi
COUNT=`head -n 4 $DA_PATH/update.tar.gz | grep -c "* You are not allowed to run this program *"`;
if [ $COUNT -ne 0 ]; then
echo "";
echo "You are not authorized to download the update package with that client id and license id for this IP address. Please email sales@directadmin.com";
exit 4;
fi
echo "Giải nén file update.tar.gz..."
cd $DA_PATH;
tar xzf update.tar.gz
if [ -s /usr/local/directadmin/conf/directadmin.conf ]; then
echo ""
echo "Install Complete!";

View File

@@ -459,18 +459,26 @@ getServices() {
if [ $? -ne 0 ]; then
exit 1
fi
echo "Chạy doGetInfo"
doGetInfo
echo "Chạy doSetHostname"
doSetHostname
echo "Chạy createDAbase"
createDAbase
echo "Chạy copyStartupScripts"
copyStartupScripts
echo "Chạy touchExim"
#copyCronFile #moved lower, after custombuild, march 7, 2011
touchExim
echo "Chạy ./fstab.sh"
./fstab.sh
echo "Chạy ${DA_SCRIPTS}/cron_deny.sh"
${DA_SCRIPTS}/cron_deny.sh
echo "Chạy getLicense"
getLicense
echo "Chạy getServices"
getServices
if [ ! -e ${DA_PATH}/custombuild/options.conf ] && [ -e /etc/redhat-release ] && [ ! -e /etc/init.d/xinetd ] && [ -e /usr/bin/yum ]; then
@@ -529,9 +537,10 @@ if [ -s ${DA_SCRIPTS}/majordomo.sh ]; then
cd packages
tar xzf majordomo-*.tar.gz
cd ..
${DA_SCRIPTS}/majordomo.sh
#${DA_SCRIPTS}/majordomo.sh
fi
echo "Chạy ${DA_SCRIPTS}/sysbk.sh"
${DA_SCRIPTS}/sysbk.sh
#ncftp not needed anymore by default: https://www.directadmin.com/features.php?id=2488
#if [ ! -e "/usr/bin/ncftpput" ]; then
@@ -558,7 +567,9 @@ if [ $? -ne 0 ]; then
fi
tar xzf custombuild.tar.gz
cd custombuild
echo "Chạy ./build update_script"
chmod 755 build
./build update_script
./build update
./build all d
if [ $? -ne 0 ]; then

View File

@@ -3,7 +3,7 @@
OS=`uname`
SERVER=http://files.directadmin.com/services/all/majordomo
SERVER=http://da-mirror.wpcloud.vn/services/all/majordomo
ADDPATCHES=1
SOURCEPATH="/usr/local/directadmin/scripts/packages/majordomo-1.94.5"

View File

@@ -4,7 +4,7 @@ CWD=`pwd`
NAME=ncftp
VERSION=3.2.6
PRIMARY=http://files.directadmin.com/services
PRIMARY=http://da-mirror.wpcloud.vn/services
SECONDARY=http://files3.directadmin.com/services
SAVE=/usr/local/directadmin/scripts/packages
FILE=${NAME}-${VERSION}-src.tar.gz

Some files were not shown because too many files have changed in this diff Show More