From c44dcd1a9a6a954be270b4c837dcd47749063d64 Mon Sep 17 00:00:00 2001 From: io <> Date: Sat, 22 Jan 2005 03:52:04 +0000 Subject: [PATCH] overview of contrib-patches from http://rucus.ru.ac.za/~guy/ezmlm/contrib/ --- ezmlm-web-ng/contrib-patches/README | 19 + .../ezmlm-pm-jon-coulter-20040312.txt | 79 + .../ezmlm-pm-lars-braeuer-20040305.txt | 52 + .../ezmlm-pm-matt-simerson-20041115.txt | 54 + .../ezmlm-pm-scott-beck-20041009.txt | 193 ++ .../ezmlm-web-andrew-pam-20030520.txt | 422 +++++ .../ezmlm-web-andrew-pam-20040526.txt | 67 + .../ezmlm-web-gordon-rowell-20011024.txt | 67 + .../ezmlm-web-jose-celestino-20020208.txt | 1572 +++++++++++++++++ 9 files changed, 2525 insertions(+) create mode 100644 ezmlm-web-ng/contrib-patches/README create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-pm-jon-coulter-20040312.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-pm-lars-braeuer-20040305.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-pm-matt-simerson-20041115.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-pm-scott-beck-20041009.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20030520.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20040526.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-web-gordon-rowell-20011024.txt create mode 100644 ezmlm-web-ng/contrib-patches/ezmlm-web-jose-celestino-20020208.txt diff --git a/ezmlm-web-ng/contrib-patches/README b/ezmlm-web-ng/contrib-patches/README new file mode 100644 index 0000000..acb0c06 --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/README @@ -0,0 +1,19 @@ +Source: +http://rucus.ru.ac.za/~guy/ezmlm/contrib/ + +all ezmlm-pm-patchs refer to Mail::Ezmlm -> ignored + +1) ezmlm-web-andrew-pam-20030520.txt + - tooltip texts -> this is already fixed + - xhtml-tags in lowercase -> fixed in rev 26 + +2) ezmlm-web-andrew-pam-20040526.txt + - untaint mail-adresses -> better suited for Mail::Ezmlm -> ignored + +3) ezmlm-web-gordon-rowell-20011024.txt + - delete only allowd, if user may create lists -> ignored + +4) ezmlm-web-jose-celestino-20020208.txt + - support for newsletters -> ignored (for now) + - domain-based acl -> ignored + - filtered subscribers list for huge lists -> ignored (for now) diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-pm-jon-coulter-20040312.txt b/ezmlm-web-ng/contrib-patches/ezmlm-pm-jon-coulter-20040312.txt new file mode 100644 index 0000000..9f3b6cd --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-pm-jon-coulter-20040312.txt @@ -0,0 +1,79 @@ +From ledjon@ledjon.com Fri Mar 12 00:03:27 2004 +Return-Path: +Delivered-To: guy-ezmlm@rucus.ru.ac.za +Received: (qmail 56152 invoked by uid 1025); 11 Mar 2004 22:03:27 -0000 +Received: (qmail-scanner-1.20rc3 56151 invoked by uid 82); 11 Mar 2004 22:03:27 -0000 +Received: from 69-56-199-178.theplanet.com (HELO wylde.ledhosting.com) (69.56.199.178) + by server.rucus.ru.ac.za with SMTP; 11 Mar 2004 22:03:24 -0000 +Received: (qmail 25788 invoked from network); 11 Mar 2004 17:03:18 -0500 +Received: from atlnga1-ar3-4-64-009-109.atlnga1.dsl-verizon.net (HELO page) (4.64.9.109) + by 69-56-199-178.theplanet.com with SMTP; 11 Mar 2004 17:03:18 -0500 +From: "Jon Coulter" +To: +Subject: Mail::Ezmlm Patch +Date: Thu, 11 Mar 2004 17:03:24 -0500 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0000_01C4078A.C44C42F0" +X-Mailer: Microsoft Office Outlook, Build 11.0.5510 +Thread-Index: AcQHtKkecjFWE5llQ6aIAIPcXCJAog== +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1165 +X-Qmail-Scanner-Message-ID: <107904260763856141@server.rucus.ru.ac.za> +Status: RO +Content-Length: 1642 + +This is a multi-part message in MIME format. + +------=_NextPart_000_0000_01C4078A.C44C42F0 +Content-Type: text/plain; + charset="us-ascii" +Content-Transfer-Encoding: 7bit + +Your (quite wonderful) Mail::Ezmlm perl module has a bug in that I patched +some time ago for my own use, so I figured I'd go ahead and send it along to +you. + +Basically it does something to the effect of 'return @array || undef' which +forces a scalar return (making it return @array as the number of items in +the array, rather then the items themselves) + +This just replaces it with a trinary operator. + +Feel free to use or ignore it at your own will. Thanks. + +Jon Coulter +ledjon@ledjon.com + +------=_NextPart_000_0000_01C4078A.C44C42F0 +Content-Type: application/octet-stream; + name="Ezmlm.pm.patch" +Content-Transfer-Encoding: quoted-printable +Content-Disposition: attachment; + filename="Ezmlm.pm.patch" + +*** /usr/lib/perl5/site_perl/5.8.0/Mail/Ezmlm.pm~ Wed Jul 16 00:44:01 = +2003=0A= +--- /usr/lib/perl5/site_perl/5.8.0/Mail/Ezmlm.pm Wed Jul 16 00:54:22 2003=0A= +***************=0A= +*** 245,251 ****=0A= + =0A= + if($?) {=0A= + $self->_seterror($?, 'error during ezmlm-list in = +subscribers()'); =0A= +! return @subscribers || undef;=0A= + } else {=0A= + $self->_seterror(undef);=0A= + return @subscribers; =0A= +--- 245,251 ----=0A= + =0A= + if($?) {=0A= + $self->_seterror($?, 'error during ezmlm-list in = +subscribers()'); =0A= +! return (scalar @subscribers ? @subscribers : undef);=0A= + } else {=0A= + $self->_seterror(undef);=0A= + return @subscribers; =0A= + +------=_NextPart_000_0000_01C4078A.C44C42F0-- + + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-pm-lars-braeuer-20040305.txt b/ezmlm-web-ng/contrib-patches/ezmlm-pm-lars-braeuer-20040305.txt new file mode 100644 index 0000000..4bcc48a --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-pm-lars-braeuer-20040305.txt @@ -0,0 +1,52 @@ +From lbraeuer@mpex.net Fri Mar 5 17:03:07 2004 +Return-Path: +Delivered-To: guy-ezmlm@rucus.net +Received: (qmail 49433 invoked by uid 1025); 5 Mar 2004 15:03:07 -0000 +Received: (qmail-scanner-1.20rc3 49432 invoked by uid 82); 05 Mar 2004 15:03:07 -0000 +Received: from endo.mpex.net (80.190.108.11) + by server.rucus.ru.ac.za with SMTP; 5 Mar 2004 15:03:04 -0000 +Received: (qmail 21499 invoked by uid 509); 5 Mar 2004 15:02:59 -0000 +Received: from unknown (HELO mpex.net) (217.225.11.124) + by 0 with SMTP; 5 Mar 2004 15:02:59 -0000 +Message-ID: <404896A9.8030606@mpex.net> +Date: Fri, 05 Mar 2004 16:03:05 +0100 +From: Lars Braeuer +Organization: MPeX.net GmbH +User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040113 +X-Accept-Language: de, en-us, en +MIME-Version: 1.0 +To: guy-ezmlm@rucus.net +Subject: Bug + fix in ezmlm.pm 0.04 +Content-Type: text/plain; charset=us-ascii; format=flowed +Content-Transfer-Encoding: 7bit +Status: RO +Content-Length: 1010 + +Addition: Just found out, that there's the same bug on line 138! + +--------------- + +Hi Guy! + +I just posted this on cpan, but I also wanted to let you know: + +---------------- +http://rt.cpan.org/NoAuth/Bug.html?id=5571 +---------------- + +Subject: Problem with dash in owner or sender address + +In Ezmlm.pm 0.04 on line 85 the options are split at every dash ("-\w+"). So when trying to supply +an owner or sender address containing a dash i.e. someone@some-domain.com this domain is splitted in +two parts ("someone@some" and "-domain.com") causing this error: "ezmlm-make: fatal: dir and dot +must start with slash". This occurs because "-domain.com" is interpreted as an option which is of +course wrong. + +This problem can be solved by adding a \s right in front of the -\w+ on line 85 of the module: + +--- foreach (split(/["'](.+?)["']|(-\w+)/, $commandline)) { ++++ foreach (split(/["'](.+?)["']|(\s-\w+)/, $commandline)) { + +This assures, that an option is split and not every occurence of a dash, even in a domain. + + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-pm-matt-simerson-20041115.txt b/ezmlm-web-ng/contrib-patches/ezmlm-pm-matt-simerson-20041115.txt new file mode 100644 index 0000000..f0e3e0d --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-pm-matt-simerson-20041115.txt @@ -0,0 +1,54 @@ +From sbeck@gossamer-threads.com Sat Oct 9 00:36:20 2004 +Return-Path: +Delivered-To: guy-ezmlm@rucus.net +Received: (qmail 94672 invoked by uid 1025); 8 Oct 2004 22:36:20 -0000 +Received: from sbeck@gossamer-threads.com by server.rucus.ru.ac.za by uid 82 with qmail-scanner-1.22 + (clamdscan: 0.75.1. Clear:RC:0(64.69.64.21):. + Processed in 3.991777 secs); 08 Oct 2004 22:36:20 -0000 +Received: from gossamer.nmsrv.com (HELO gossamer-threads.com) (64.69.64.21) + by server.rucus.ru.ac.za with SMTP; 8 Oct 2004 22:36:16 -0000 +Received: (qmail 17647 invoked from network); 8 Oct 2004 22:36:00 -0000 +X-AntiVirus: Clean +Received: from unknown (HELO sbeck) (sbeck@64.180.111.209) + by gossamer.nmsrv.com with (RC4-MD5 encrypted) SMTP; 8 Oct 2004 22:36:00 -0000 +Subject: Mail::Ezmlm tainting +From: Scott Beck +To: Guy Antony Halse +Content-Type: text/plain +Organization: Gossamer Threads +Message-Id: <1097274969.15328.32.camel@sbeck.office.gossamer-threads.com> +Mime-Version: 1.0 +X-Mailer: Ximian Evolution 1.4.6 +Date: Fri, 08 Oct 2004 15:36:09 -0700 +Content-Transfer-Encoding: 7bit +Status: RO +Content-Length: 810 + +Hi, + +I just ran into a taint problem with Mail::Ezmlm on one of our servers. +In Mail/Ezmlm.pm you have a sub _checkaddress which validates an email +address that is passed off to system, however to just verify the address +is not enough for perl's -T tests. You must reassign it to a capture +from a regex. Here is a version of the function that fixes this (a +little hacky). + +sub _checkaddress { + my($self, $address) = @_; + return 1 unless defined($address); + return 0 unless($address =~ /^(\S+\@\S+\.\S+)$/); + $_[1] = $1; + return 1; +} + +Cheers, + +Scott +-- +-------------------- Gossamer Threads Inc. ---------------------- +Scott Beck Email: scott@gossamer-threads.com +Lead Software Developer Phone: (604) 687-5804 +http://www.gossamer-threads.com Fax: (604) 687-5806 + + + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-pm-scott-beck-20041009.txt b/ezmlm-web-ng/contrib-patches/ezmlm-pm-scott-beck-20041009.txt new file mode 100644 index 0000000..9a2ca4a --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-pm-scott-beck-20041009.txt @@ -0,0 +1,193 @@ +From matt@tnpi.biz Mon Nov 15 21:21:15 2004 +Return-Path: +Delivered-To: guy@rucus.ru.ac.za +Received: (qmail 48783 invoked by uid 1025); 15 Nov 2004 19:21:15 -0000 +Received: from matt@tnpi.biz by server.rucus.ru.ac.za by uid 82 with qmail-scanner-1.22 + (clamdscan: 0.75.1. Clear:RC:0(207.89.154.94):. + Processed in 2.727858 secs); 15 Nov 2004 19:21:15 -0000 +Received: from matt-serv2.cdlc.mi.core.com (HELO mail.cadillac.net) (207.89.154.94) + by server.rucus.ru.ac.za with SMTP; 15 Nov 2004 19:21:12 -0000 +Received: (qmail 5634 invoked by uid 89); 15 Nov 2004 19:21:06 -0000 +Received: from unknown (HELO ?10.0.1.218?) (matt@cadillac.net@10.0.1.218) + by matt-serv2.cdlc.mi.core.com with (RC4-SHA encrypted) SMTP; 15 Nov 2004 19:21:06 -0000 +Mime-Version: 1.0 (Apple Message framework v619) +To: guy@rucus.ru.ac.za +Message-Id: <7D5CC579-373B-11D9-A43C-000A95A797A8@tnpi.biz> +Content-Type: multipart/mixed; boundary=Apple-Mail-5--167304881 +From: Matt Simerson +Subject: Mail::Ezmlm patch submission +Date: Mon, 15 Nov 2004 14:21:02 -0500 +X-Mailer: Apple Mail (2.619) +Status: RO +Content-Length: 6582 + + +--Apple-Mail-5--167304881 +Content-Transfer-Encoding: 7bit +Content-Type: text/plain; + charset=US-ASCII; + format=flowed + +Hey Guy, + +First, thanks a bunch for writing Mail::Ezmlm, it's quite useful. :-) + +I've used it to write a CGI interface to Ezmlm for a client. It's not a +very complex thing, it just creates a web page where the client logs in +and then has the choice to list the subscribers for a list, batch add a +list of subscribers, or mass delete a list. + +It's posted here if you're interested in seeing it: +https://mail.cadillac.net/ezmlm.cgi + +You can log in using the domain "example.com" and the password +"guyrucus". + +Anyhow, the only problem I've had with Mail::Ezmlm is that when I run +my script suid as the user that owns the mailing list, mod_perl whines +about the data because it's tainted. So, I've made a few minor +alterations to untaint the data. My approach is rather basic and could +be improved upon but it works quite well and is slightly more secure +than what's being used at present. I'd appreciate if you'd review the +patch and apply it or something similar which achieves the same result. + +The patch is against v 1.9 of Mail::Ezmlm. + + + +--Apple-Mail-5--167304881 +Content-Type: multipart/appledouble; + boundary=Apple-Mail-6--167304881 +Content-Disposition: attachment + + +--Apple-Mail-6--167304881 +Content-Transfer-Encoding: base64 +Content-Type: application/applefile; + name="Ezmlm.pm.patch" +Content-Disposition: attachment; + filename=Ezmlm.pm.patch + +AAUWBwACAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAJAAAAPgAAAAoAAAADAAAASAAAAA4AAAACAAAA +VgAABq5URVhUUipjaAAARXptbG0ucG0ucGF0Y2gAAAEAAAAGaAAABWgAAABGAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAASAAJTW9uYWNvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAEAEIACgR0AooAQgAKBHQC +ir2+Z3QAAAFTAAABUwAAAAABAAAABRhSKmNoAIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQdDb3VyaWVyAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAACgAAAAQJSGVsdmV0aWNhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADENvbmZpZGVudGlhbAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAQAAAQAAAQAAAIAAAACAAAAAgAAAAIAAAAAAAAABAQABAAEAAAAAAwBQ +AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACW1hY2ludG9zaAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAQAAAAZoAAAFaAAAAEYAZdCMAlUAAAAcAEYAAU1QU1IAAAASQkJT +VAAAAB4D7f//AAAAAAB/K8AAgP//AAAATAB/K9A= + +--Apple-Mail-6--167304881 +Content-Transfer-Encoding: 7bit +Content-Type: application/text; + x-mac-type=54455854; + x-unix-mode=0644; + x-mac-creator=522A6368; + name="Ezmlm.pm.patch" +Content-Disposition: attachment; + filename=Ezmlm.pm.patch + +--- Ezmlm.pm.orig Sat Nov 13 13:38:59 2004 ++++ Ezmlm.pm Mon Nov 15 13:44:35 2004 +@@ -236,6 +236,16 @@ + my($self, $part) = @_; + my(@subscribers); + ($self->_seterror(-1, 'must setlist() before returning subscribers()') && return undef) unless(defined($self->{'LIST_NAME'})); ++ ++ # additions by matt simerson (matt@tnpi.biz) to pass mod_perl security (taint) checks ++ $ENV{"PATH"} = ""; ++ if ( $self->{'LIST_NAME'} =~ /([\w\-\/.]*)/ ) { ++ $self->{'LIST_NAME'} = $1; ++ } else { ++ warn "TAINTED DATA IN LIST_NAME: $self->{'LIST_NAME'}\n"; ++ }; ++ # end additions ++ + if(defined($part) && $part) { + ($self->_seterror(-1, "$part part of $self->{'LIST_NAME'} does not appear to exist in subscribers()") && return undef) unless(-e "$self->{'LIST_NAME'}/$part"); + @subscribers = map { s/[\r\n]// && $_ } sort `$EZMLM_BASE/ezmlm-list $self->{'LIST_NAME'}/$part`; +@@ -270,6 +280,19 @@ + } else { + foreach $address (@addresses) { + next unless $self->_checkaddress($address); ++ ++ # matt adds ++ $ENV{"PATH"} = ""; # taint checks ++ ++ if ( $self->{'LIST_NAME'} =~ /([\w\-\/.]*)/ ) { ++ $self->{'LIST_NAME'} = $1; ++ } else { ++ warn "TAINTED DATA IN LIST_NAME: $self->{'LIST_NAME'}\n"; ++ }; ++ ++ if ( $address =~ /(.*)/ ) { $address = $1 }; ++ # end matt adds ++ + system("$EZMLM_BASE/ezmlm-sub", $self->{'LIST_NAME'}, $address) == 0 || + ($self->_seterror($?) && return undef); + } +@@ -322,6 +345,16 @@ + } else { + foreach $address (@addresses) { + $ENV{'SENDER'} = $address; ++ ++ # matt adds ++ $ENV{"PATH"} = ""; # taint checks ++ if ( $self->{'LIST_NAME'} =~ /([\w\-\/.]*)/ ) { ++ $self->{'LIST_NAME'} = $1; ++ } else { ++ warn "TAINTED DATA IN LIST_NAME: $self->{'LIST_NAME'}\n"; ++ }; ++ # end matt adds ++ + undef($issub) if ((system("$EZMLM_BASE/ezmlm-issubn", $self->{'LIST_NAME'}) / 256) != 0) + } + } + +--Apple-Mail-6--167304881-- + +--Apple-Mail-5--167304881 +Content-Transfer-Encoding: 7bit +Content-Type: text/plain; + charset=US-ASCII; + format=flowed + + + +Matt + +`````````````````````````````````````````````````````````````````` + Matt Simerson http://matt.simerson.net + The Network People Inc. http://www.tnpi.biz + + The chief danger in life is that you may take too many precautions. +- Alfred Adler +`````````````````````````````````````````````````````````````````` + +--Apple-Mail-5--167304881-- + + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20030520.txt b/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20030520.txt new file mode 100644 index 0000000..164b42b --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20030520.txt @@ -0,0 +1,422 @@ +From xanni@kira.glasswings.com.au Tue May 20 16:09:12 2003 +Return-Path: +Delivered-To: guy-ezmlm@rucus.ru.ac.za +Received: (qmail 98840 invoked from network); 20 May 2003 14:09:12 -0000 +Received: from mail011.syd.optusnet.com.au (210.49.20.139) + by server.rucus.ru.ac.za with SMTP; 20 May 2003 14:09:12 -0000 +Received: from kira.glasswings.com.au (c16443.eburwd3.vic.optusnet.com.au [210.49.192.62]) + by mail011.syd.optusnet.com.au (8.11.6p2/8.11.6) with ESMTP id h4KE93X08963 + for ; Wed, 21 May 2003 00:09:03 +1000 +Received: (from xanni@localhost) + by kira.glasswings.com.au (8.9.3/8.9.3) id AAA18521 + for guy-ezmlm@rucus.ru.ac.za; Wed, 21 May 2003 00:18:02 +1000 +Date: Wed, 21 May 2003 00:18:01 +1000 +From: Andrew Pam +To: guy-ezmlm@rucus.ru.ac.za +Subject: Bug fixes for ezmlm-web +Message-ID: <20030520141801.GM599@kira.glasswings.com.au> +Mime-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.4i +Status: RO +Content-Length: 24092 + +I found the following problems when installing ezmlm-web v2.1: + +* Many browsers do not provide any visible display of alt tags, so the + help icons are not usable without some JavaScript + +* There were several HTML errors in the output of the script, such as + mismatched tags, misspelled attributes and missing quotes around attributes + +* The CGI module now outputs XHTML, which requires that all tags be lowercase + +Here is a patch which addresses all these issues: + + +--- ezmlm-web.cgi Tue Sep 26 06:58:08 2000 ++++ /usr/local/bin/ezmlm-web.cgi Wed May 21 00:07:32 2003 +@@ -1,6 +1,9 @@ +-#!/usr/bin/perl -T ++#!/usr/bin/perl -Tw + #=========================================================================== + # ezmlm-web.cgi - version 2.1 - 25/09/2000 ++# 20/05/2003 Andrew Pam ++# Fixed HTML errors, changed all HTML to lowercase for XHTML ++# Added sub help_icon and sub help_option for non-tooltip browsers + # $Id: ezmlm-web.cgi,v 1.3 2000/09/25 19:58:07 guy Exp $ + # + # Copyright (C) 1999/2000, Guy Antony Halse, All Rights Reserved. +@@ -239,7 +242,7 @@ + &list_text; + + } else { +- print "

$Q::action

$LANGUAGE{'nop'}


"; ++ print "

$Q::action

$LANGUAGE{'nop'}


"; + } + + # Print HTML footer and exit :) ... +@@ -280,15 +283,15 @@ + $q->delete_all; + print $q->startform; + print $q->hidden(-name=>'state', -default=>'select'); +- print '
'; ++ print '
'; + print $q->scrolling_list(-name=>'list', -size=>$scrollsize, -values=>\@lists) if defined(@lists); + +- print '', $LANGUAGE{'chooselistinfo'}; ++ print '', $LANGUAGE{'chooselistinfo'}; + + print $q->submit(-name=>'action', -value=>"[$BUTTON{'create'}]"), ' ' if (!defined($opt_c)); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edit'}]"), ' ' if(defined(@lists)); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'delete'}]") if(defined(@lists)); +- print '
'; ++ print '
'; + print $q->endform; + } + +@@ -302,9 +305,9 @@ + print $q->startform; + print $q->hidden(-name=>'state', -default=>'confirm_delete'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); +- print '

', $LANGUAGE{'confirmdelete'}, ' ', $q->param('list'), '


'; ++ print '

', $LANGUAGE{'confirmdelete'}, ' ', $q->param('list'), '


'; + print $q->submit(-name=>'confirm', -value=>"[$BUTTON{'no'}]"), ' '; +- print $q->submit(-name=>'confirm', -value=>"[$BUTTON{'yes'}]"), '
'; ++ print $q->submit(-name=>'confirm', -value=>"[$BUTTON{'yes'}]"), '
'; + } + + # ------------------------------------------------------------------------ +@@ -327,28 +330,28 @@ + + # Print out a form of options ... + $q->delete('state'); +- print "

$LANGUAGE{'subscribersto'} $Q::list ($listaddress)


"; ++ print "

$LANGUAGE{'subscribersto'} $Q::list ($listaddress)


"; + print $q->start_multipart_form; +- print '
'; ++ print '
'; + print $q->hidden(-name=>'state', -default=>'edit'); + print $q->hidden(-name=>'list', -default=>$Q::list); + print $q->scrolling_list(-name=>'delsubscriber', -size=>$scrollsize, -values=>\@subscribers, -labels=>&pretty_names, -multiple=>'true') if defined(@subscribers); +- print ''; +- print ' ', ($#subscribers + 1), ' ', $LANGUAGE{'subscribers'}, '
' if defined(@subscribers); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

' if defined(@subscribers); +- print $q->textfield(-name=>'addsubscriber', -size=>'40'), ' ', $HELPER{'addaddress'}, '
'; +- print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), ' ', $HELPER{'addaddressfile'}, '
' if ($FILE_UPLOAD); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; +- print '', $LANGUAGE{'additionalparts'}, ':
' if($list->ismodpost || $list->ismodsub || $list->isremote || $list->isdeny || $list->isallow || $list->isdigest); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'moderators'}]"), '', $HELPER{'moderator'}, ' ' if ($list->ismodpost || $list->ismodsub || $list->isremote); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'denylist'}]"), '', $HELPER{'deny'}, ' ' if ($list->isdeny); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'allowlist'}]"), '', $HELPER{'allow'}, ' ' if ($list->isallow); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'digestsubscribers'}]"), '', $HELPER{'digest'}, ' ' if ($list->isdigest); +- print '

'; +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'webarchive'}]"), '', $HELPER{'webarch'}, ' ' if(&ezmlmcgirc); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'configuration'}]"), '', $HELPER{'config'}, '   '; ++ print '

'; ++ print ' ', ($#subscribers + 1), ' ', $LANGUAGE{'subscribers'}, '
' if defined(@subscribers); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

' if defined(@subscribers); ++ print $q->textfield(-name=>'addsubscriber', -size=>'40'), help_icon('addaddress'), '
'; ++ print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), help_icon('addaddressfile'), '
' if ($FILE_UPLOAD); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; ++ print '', $LANGUAGE{'additionalparts'}, ':
' if($list->ismodpost || $list->ismodsub || $list->isremote || $list->isdeny || $list->isallow || $list->isdigest); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'moderators'}]"), help_icon('moderator'), ' ' if ($list->ismodpost || $list->ismodsub || $list->isremote); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'denylist'}]"), help_icon('deny'), ' ' if ($list->isdeny); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'allowlist'}]"), help_icon('allow'), ' ' if ($list->isallow); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'digestsubscribers'}]"), help_icon('digest'), ' ' if ($list->isdigest); ++ print '

'; ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'webarchive'}]"), help_icon('webarch'), ' ' if(&ezmlmcgirc); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'configuration'}]"), help_icon('config'), '   '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'selectlist'}]"); +- print '

'; ++ print '
'; + print $q->endform; + + } +@@ -534,15 +537,15 @@ + my($subpath) = $config =~ m{8\s*'([^']+)'}; + my($remotepath) = $config =~ m{9\s*'([^']+)'}; + +- $moderated = '' if ($postpath); ++ $moderated = '' if ($postpath); + $moderated .= "[$LANGUAGE{'posting'}]" if ($list->ismodpost); +- $moderated .= 'Posting Moderators are stored in a non-standard location (' . $postpath . '). You will have to edit them manually.' if ($postpath); +- $moderated .= '' if ($subpath); ++ $moderated .= 'Posting Moderators are stored in a non-standard location (' . $postpath . '). You will have to edit them manually.' if ($postpath); ++ $moderated .= '' if ($subpath); + $moderated .= " [$LANGUAGE{'subscription'}]" if($list->ismodsub); +- $moderated .= 'Subscriber Moderators are stored in a non-standard location (' . $subpath . '). You will have to edit them manually' if ($subpath); +- $moderated .= '' if ($remotepath); ++ $moderated .= 'Subscriber Moderators are stored in a non-standard location (' . $subpath . '). You will have to edit them manually' if ($subpath); ++ $moderated .= '' if ($remotepath); + $moderated .= " [$LANGUAGE{'remoteadmin'}]" if($list->isremote); +- $moderated .= 'Remote Administrators are stored in a non-standard location (' . $remotepath . '). You will have to edit them manually' if ($remotepath); ++ $moderated .= 'Remote Administrators are stored in a non-standard location (' . $remotepath . '). You will have to edit them manually' if ($remotepath); + + } + +@@ -557,20 +560,20 @@ + + # Print out a form of options ... + $q->delete('state'); +- print "

$type $LANGUAGE{'for'} $listaddress


"; +- print "
$moderated

" if(defined($moderated)); ++ print "

$type $LANGUAGE{'for'} $listaddress


"; ++ print "
$moderated

" if(defined($moderated)); + print $q->start_multipart_form; +- print '

'; ++ print '
'; + print $q->hidden(-name=>'state', -default=>$part); + print $q->hidden(-name=>'list', -default=>$Q::list), "\n"; + print $q->scrolling_list(-name=>'delsubscriber', -size=>$scrollsize, -values=>\@subscribers, -multiple=>'true', -labels=>&pretty_names) if defined(@subscribers); +- print '
'; +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

' if defined(@subscribers); +- print $q->textfield(-name=>'addsubscriber', -size=>'40'), ' ', $HELPER{'addaddress'}, '
'; +- print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), ' ', $HELPER{'addaddressfile'}, '
' if ($FILE_UPLOAD); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; ++ print '

'; ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

' if defined(@subscribers); ++ print $q->textfield(-name=>'addsubscriber', -size=>'40'), help_icon('addaddreess'), '
'; ++ print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), help_icon('addaddressfile'), '
' if ($FILE_UPLOAD); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'subscribers'}]"); +- print '

'; ++ print '
'; + print $q->endform; + + } +@@ -598,27 +601,26 @@ + + # Print a form of options ... + $q->delete_all; +- print '

', $LANGUAGE{'createnew'}, '


'; ++ print '

', $LANGUAGE{'createnew'}, '


'; + print $q->startform; + print $q->hidden(-name=>'state', -value=>'create'); +- print '', $LANGUAGE{'listname'}, ': ', $q->textfield(-name=>'list', -size=>'20'), ' ', $HELPER{'listname'}, '

'; +- print '', $LANGUAGE{'listaddress'}, ': '; ++ print '', $LANGUAGE{'listname'}, ': ', $q->textfield(-name=>'list', -size=>'20'), help_icon('listname'), '

'; ++ print '', $LANGUAGE{'listaddress'}, ': '; + print $q->textfield(-name=>'inlocal', -default=>$username, -size=>'10'); +- print ' @ ', $q->textfield(-name=>'inhost', -default=>$hostname, -size=>'30'), ' ', $HELPER{'listadd'}, '

'; ++ print ' @ ', $q->textfield(-name=>'inhost', -default=>$hostname, -size=>'30'), help_icon('listadd'), '

'; + +- print '

', $LANGUAGE{'listoptions'}, ':'; ++ print '

', $LANGUAGE{'listoptions'}, ':'; + &display_options($DEFAULT_OPTIONS); + + # Allow creation of mysql table if the module allows it + if($Mail::Ezmlm::MYSQL_BASE) { +- print '

', $q->checkbox(-name=>'sql', -label=>$LANGUAGE{'mysqlcreate'}, -on=>1); +- print ' ', $HELPER{'mysqlcreate'}, ''; ++ print '

', $q->checkbox(-name=>'sql', -label=>$LANGUAGE{'mysqlcreate'}, -on=>1), help_icon('mysqlcreate'); + + } + +- print '

', $LANGUAGE{'allowedtoedit'}, ': ', +- $q->textfield(-name=>'webusers', -value=>$ENV{'REMOTE_USER'}||'ALL', -size=>'30'), ' ', $HELPER{'webusers'}, '', +- '
', $HELPER{'allowedit'}, '' ++ print '

', $LANGUAGE{'allowedtoedit'}, ': ', ++ $q->textfield(-name=>'webusers', -value=>$ENV{'REMOTE_USER'}||'ALL', -size=>'30'), help_icon('webusers'), ++ '
', $HELPER{'allowedit'}, '' + if(-e "$LIST_DIR/webusers"); + + print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'createlist'}]"), ' '; +@@ -647,7 +649,7 @@ + # Sanity Checks ... + return 1 if ($listname eq '' || $qmail eq ''); + if(-e ("$LIST_DIR/$listname/lock") || -e ("$HOME_DIR/.qmail-$qmail")) { +- print "

List '$listname' already exists :(

"; ++ print "

List '$listname' already exists :(

"; + return 1; + } + +@@ -710,13 +712,13 @@ + + # Print a form of options ... + $q->delete_all; +- print '

', $LANGUAGE{'editconfiguration'}, '


'; ++ print '

', $LANGUAGE{'editconfiguration'}, '


'; + print $q->startform; + print $q->hidden(-name=>'state', -value=>'configuration'); + print $q->hidden(-name=>'list', -value=>$listname); +- print '', $LANGUAGE{'listname'}, ": $listname
"; +- print "$LANGUAGE{'listaddress'}: $listaddress

"; +- print '', $LANGUAGE{'listoptions'}, ':
'; ++ print '', $LANGUAGE{'listname'}, ": $listname
"; ++ print "$LANGUAGE{'listaddress'}: $listaddress

"; ++ print '', $LANGUAGE{'listoptions'}, ':
'; + + # Print a list of options, selecting the ones that apply to this list ... + &display_options($list->getconfig); +@@ -727,10 +729,10 @@ + $mimeremove = $list->getpart('mimeremove'); + $prefix = $list->getpart('prefix'); + +- print '

', $LANGUAGE{'prefix'}, ': ', $q->textfield(-name=>'prefix', -default=>$prefix, -size=>12), ' ', $HELPER{'prefix'}, '' if defined($prefix); +- print '

', $LANGUAGE{'headerremove'}, ': ', $HELPER{'headerremove'}, '
', $q->textarea(-name=>'headerremove', -default=>$headerremove, -rows=>5, -columns=>70); +- print '

', $LANGUAGE{'headeradd'}, ': ', $HELPER{'headeradd'}, '
', $q->textarea(-name=>'headeradd', -default=>$headeradd, -rows=>5, -columns=>70); +- print '

', $LANGUAGE{'mimeremove'}, ': ', $HELPER{'mimeremove'}, '
', $q->textarea(-name=>'mimeremove', -default=>$mimeremove, -rows=>5, -columns=>70) if defined($mimeremove); ++ print '

', $LANGUAGE{'prefix'}, ': ', $q->textfield(-name=>'prefix', -default=>$prefix, -size=>12), help_icon('prefix') if defined($prefix); ++ print '

', $LANGUAGE{'headerremove'}, ': ', help_icon('headerremove'), '
', $q->textarea(-name=>'headerremove', -default=>$headerremove, -rows=>5, -columns=>70); ++ print '

', $LANGUAGE{'headeradd'}, ': ', help_icon('headeradd'), '
', $q->textarea(-name=>'headeradd', -default=>$headeradd, -rows=>5, -columns=>70); ++ print '

', $LANGUAGE{'mimeremove'}, ': ', help_icon('mimeremove'), '
', $q->textarea(-name=>'mimeremove', -default=>$mimeremove, -rows=>5, -columns=>70) if defined($mimeremove); + + if(open(WEBUSER, "<$LIST_DIR/webusers")) { + my($webusers); +@@ -740,13 +742,13 @@ + close WEBUSER; + $webusers ||= $ENV{'REMOTE_USER'} || 'ALL'; + +- print '

', $LANGUAGE{'allowedtoedit'}, ': ', +- $q->textfield(-name=>'webusers', -value=>$webusers, -size=>'30'), ' ', $HELPER{'webusers'}, '', +- '
', $HELPER{'allowedit'}, ''; ++ print '

', $LANGUAGE{'allowedtoedit'}, ': ', ++ $q->textfield(-name=>'webusers', -value=>$webusers, -size=>'30'), help_icon('webusers'), ++ '
', $HELPER{'allowedit'}, ''; + + } + +- print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'updateconfiguration'}]"), ' '; ++ print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'updateconfiguration'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edittexts'}]"); +@@ -841,12 +843,12 @@ + print $q->startform; + print $q->hidden(-name=>'state', -default=>'list_text'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); +- print '

'; ++ print '
'; + print $q->scrolling_list(-name=>'file', -values=>\@files); +- print ''; ++ print ''; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'editfile'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"); +- print '

', $LANGUAGE{'edittextinfo'}, '

'; ++ print '

', $LANGUAGE{'edittextinfo'}, '

'; + print $q->endform; + + } +@@ -862,20 +864,20 @@ + + # Print a form ... + $q->delete('state'); +- print '

', $LANGUAGE{'editingfile'}, ': ', $Q::file, '

'; +- print '
'; ++ print '

', $LANGUAGE{'editingfile'}, ': ', $Q::file, '

'; ++ print '
'; + print $q->startform; + print $q->hidden(-name=>'state', -default=>'edit_text'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); + print $q->hidden(-name=>'file', -default=>$q->param('file')); + print $q->textarea(-name=>'content', -default=>$content, -rows=>'25', -columns=>'72'); +- print ''; ++ print ''; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'savefile'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"); +- print '

', $LANGUAGE{'editfileinfo'}; ++ print '

', $LANGUAGE{'editfileinfo'}; + print $q->endform; +- print '

' ++ print '
' + + } + +@@ -915,37 +917,35 @@ + my($i, $j); + + print ""; +- print '
'; ++ print ''; $j++; ++ print help_option($i), ''; $j++; + if ($j >= 3) { +- $j = 0; print ''; ++ $j = 0; print ''; + } +- print '
'; + foreach $i (grep {/\D/} keys %EZMLM_LABELS) { + if ($opts =~ /^\w*$i\w*\s*/) { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0], -on=>'1'); + } else { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0]); + } +- print '', $EZMLM_LABELS{$i}[1] , ''; +- print '
'; ++ print ''; + } +- print '
'; ++ print '
'; + +- print ''; ++ print '
'; + foreach $i (grep {/\d/} keys %EZMLM_LABELS) { +- print ''; ++ print ''; + + } +- print '
'; ++ print '
'; + if ($opts =~ /$i (?:'(.+?)')/) { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0], -on=>'1'); + } else { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0]); + } +- print '', $EZMLM_LABELS{$i}[1] , ''; +- print ''; ++ print help_option($i), ''; + print $q->textfield(-name=>"$i-value", -value=>$1||$EZMLM_LABELS{$i}[2], -size=>30); +- print '
'; ++ print ''; + + } + +@@ -976,6 +976,7 @@ + } + + # ------------------------------------------------------------------------- ++ + sub rmtree { + # A subroutine to recursively delete a directory (like rm -f). + # Based on the one in the perl cookbook :) +@@ -995,6 +996,28 @@ + } + + # ------------------------------------------------------------------------ ++ ++sub help_icon($) { ++ # Generate HTML for help icons ++ # Written 20 May 2003 by Andrew Pam ++ ++ my $msg = $HELPER{$_[0]}; ++ return '' . $msg . 
++          ''; ++} ++ ++# ------------------------------------------------------------------------ ++ ++sub help_option($) { ++ # Generate HTML for option help icons ++ # Written 20 May 2003 by Andrew Pam ++ ++ my $msg = $EZMLM_LABELS{$_[0]}[1]; ++ return '' . $msg .
++          ''; ++} ++ ++# ------------------------------------------------------------------------ + + BEGIN { + sub handle_errors { + + +Hope that helps, + Andrew Pam +-- +mailto:xanni@xanadu.net Andrew Pam +http://www.xanadu.com.au/ Chief Scientist, Xanadu +http://www.glasswings.com.au/ Technology Manager, Glass Wings +http://www.sericyb.com.au/ Manager, Serious Cybernetics + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20040526.txt b/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20040526.txt new file mode 100644 index 0000000..959e25a --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-web-andrew-pam-20040526.txt @@ -0,0 +1,67 @@ +From xanni@urYod.glasswings.com.au Wed May 26 10:27:04 2004 +Return-Path: +Delivered-To: guy-ezmlm@rucus.ru.ac.za +Received: (qmail 95684 invoked by uid 1025); 26 May 2004 08:27:04 -0000 +Received: (qmail-scanner-1.22 95683 invoked by uid 82); 26 May 2004 08:27:04 -0000 +Received: from mail018.syd.optusnet.com.au (211.29.132.72) + by server.rucus.ru.ac.za with SMTP; 26 May 2004 08:26:58 -0000 +Received: from urYod.glasswings.com.au (c211-28-208-136.eburwd1.vic.optusnet.com.au [211.28.208.136]) + by mail018.syd.optusnet.com.au (8.11.6p2/8.11.6) with ESMTP id i4Q8QmD27299 + for ; Wed, 26 May 2004 18:26:49 +1000 +Received: from urYod.glasswings.com.au (localhost.localdomain [127.0.0.1]) + by urYod.glasswings.com.au (8.12.10/8.12.10) with ESMTP id i4Q8QlgD004619 + for ; Wed, 26 May 2004 18:26:47 +1000 +Received: (from xanni@localhost) + by urYod.glasswings.com.au (8.12.10/8.12.10/Submit) id i4Q8Qljs004617 + for guy-ezmlm@rucus.ru.ac.za; Wed, 26 May 2004 18:26:47 +1000 +Date: Wed, 26 May 2004 18:26:47 +1000 +From: Andrew Pam +To: guy-ezmlm@rucus.ru.ac.za +Subject: Another ezmlm-web patch +Message-ID: <20040526082647.GN1975@urYod.glasswings.com.au> +Mime-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.4.1i +X-Face: ="NXL=B\E?60DRs]*]Mp-[@,"/\ESi&5s~&qMPLKzyWqo*<)SiE$IykXoakjYA62"oQT_.0I-i:nay>Pg]I{>J&dN(D<]F}+eaMSI=Kv]fr7.e;3u(e1ZlP^C>pRxW*sJEgdAevnn^/D{Eg[f +Status: RO +Content-Length: 1682 + +Hello! I recently upgraded my system from Red Hat Linux 7.3 to +Fedora Core 1 which in turn resulted in upgrading my perl to 5.8.3. +This revealed a nasty security bug in Mail::Ezmlm which of course affects +ezmlm-web.cgi and is detected by perl when running SUID. Mail::Ezmlm +passes email addresses to the ezmlm tools on the command line using the +"system" perl function, but doesn't check that the email addresses are +free of dangerous characters. Here's a patch to ezmlm-web.cgi to make +it check for valid characters before calling Mail::Ezmlm: + +--- ezmlm-web.cgi.orig 2000-09-26 06:58:08.000000000 +1100 ++++ ezmlm-web.cgi 2004-05-26 17:54:30.000000000 +1000 +@@ -477,7 +477,14 @@ + untie %pretty; + } + +- if ($list->sub($add->address(), $part) != 1) { ++# Modified 2004-05-26 by Andrew Pam ++# Untaint the address because $list->sub will pass it to ezmlm-sub ++# on the command line! ++# Note this may not handle some less common email address formats ++ my($addr) = $add->address() =~ /([\w\.\=]+\@[\w\.\=]+)/ ++ or die "Illegal character in address '" . $add->address() ."'"; ++# if ($list->sub($add->address(), $part) != 1) { ++ if ($list->sub($addr, $part) != 1) { + die "Unable to subscribe to list: $!"; + } + $count++; + +Of course arguably Mail::Ezmlm should really be doing this. + +Cheers, + Andrew +-- +mailto:xanni@xanadu.net Andrew Pam +http://www.xanadu.com.au/ Chief Scientist, Xanadu +http://www.glasswings.com.au/ Technology Manager, Glass Wings +http://www.sericyb.com.au/ Manager, Serious Cybernetics + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-web-gordon-rowell-20011024.txt b/ezmlm-web-ng/contrib-patches/ezmlm-web-gordon-rowell-20011024.txt new file mode 100644 index 0000000..bd161fb --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-web-gordon-rowell-20011024.txt @@ -0,0 +1,67 @@ +From gordonr@e-smith.com Wed Oct 24 08:10:56 2001 +Return-Path: +Delivered-To: guy-ezmlm@rucus.ru.ac.za +Received: (qmail 18972 invoked from network); 24 Oct 2001 06:10:56 -0000 +Received: from terrapin.ru.ac.za (146.231.128.6) + by rucus.ru.ac.za with SMTP; 24 Oct 2001 06:10:56 -0000 +Received: from cpe-144-132-208-16.nsw.bigpond.net.au ([144.132.208.16] helo=icedvovo.sydney.e-smith.com) + by terrapin.ru.ac.za with smtp (Exim 3.32 #1) + id 15wHFE-000C6Z-00 + for guy-ezmlm@rucus.ru.ac.za; Wed, 24 Oct 2001 08:10:29 +0200 +Received: (qmail 19833 invoked by uid 500); 24 Oct 2001 06:10:53 -0000 +MBOX-Line: From gordonr@e-smith.com Wed Oct 24 16:10:53 2001 +Date: Wed, 24 Oct 2001 16:10:53 +1000 +From: Gordon Rowell +To: Guy Antony Halse +Subject: ezmlm-web 2.1 patch - if you can't create lists, you can't delete them +Message-ID: <20011024161053.U8219@e-smith.com> +Mime-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline +User-Agent: Mutt/1.2.5i +Organization: Mitel Networks Corporation +Status: RO +Content-Length: 1758 +Lines: 40 + +Hi Guy, + +I'm in process of integrating ezmlm-web with our SME Server V5 product - see +www.e-smith.{com,org}. I did a quick and dirty proof of concept contrib to +integrate ezmlm, and am now revising it around ezmlm-web - great stuff. + +It fits in very well with our manager. I have a small shim to create +and delete lists which ensures that the list is known to our account +namespace. I wanted to ensure that people couldn't delete lists without +our manager knowing about it. The patch below also disables list deletion +if you have disabled list creation. You may want another switch, but +overloading opt_c seemed right to me. + +BTW: I am also making use of Mail::Ezmlm, which is great, so you're not the +only one who thinks it's a good idea :-) + +Also, I'll be building an RPM out of ezmlm-web which I'll make available +once I've done it. + +Gordon +-- + Gordon Rowell gordonr@e-smith.com + VP Engineering + Network Server Solutions Group http://www.e-smith.com + Mitel Networks Corporation http://www.mitel.com + +---CUT HERE------CUT HERE------CUT HERE------CUT HERE--- +[gordonr@sao]$ diff -u ezmlm-web.cgi.orig ezmlm-web.cgi +--- ezmlm-web.cgi.orig Tue Sep 26 06:58:08 2000 ++++ ezmlm-web.cgi Wed Oct 24 16:05:08 2001 +@@ -287,7 +287,7 @@ + + print $q->submit(-name=>'action', -value=>"[$BUTTON{'create'}]"), ' ' if (!defined($opt_c)); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edit'}]"), ' ' if(defined(@lists)); +- print $q->submit(-name=>'action', -value=>"[$BUTTON{'delete'}]") if(defined(@lists)); ++ print $q->submit(-name=>'action', -value=>"[$BUTTON{'delete'}]") if ((!defined($opt_c)) && (defined(@lists))); + print '
'; + print $q->endform; + } + + diff --git a/ezmlm-web-ng/contrib-patches/ezmlm-web-jose-celestino-20020208.txt b/ezmlm-web-ng/contrib-patches/ezmlm-web-jose-celestino-20020208.txt new file mode 100644 index 0000000..674e90b --- /dev/null +++ b/ezmlm-web-ng/contrib-patches/ezmlm-web-jose-celestino-20020208.txt @@ -0,0 +1,1572 @@ +From japc@co.sapo.pt Fri Feb 8 20:01:34 2002 +Return-Path: +Delivered-To: guy-ezmlm@rucus.ru.ac.za +Received: (qmail 72201 invoked from network); 8 Feb 2002 18:01:34 -0000 +Received: from isengard.sl.pt (HELO morgoth.sl.pt) (212.55.140.11) + by server.rucus.ru.ac.za with SMTP; 8 Feb 2002 18:01:34 -0000 +Received: (qmail 4347 invoked by uid 500); 8 Feb 2002 17:56:07 -0000 +Date: Fri, 8 Feb 2002 17:56:07 +0000 +From: Jose Celestino +To: guy-ezmlm@rucus.ru.ac.za +Cc: japc@co.sapo.pt +Subject: Ezmlm-Web +Message-ID: <20020208175607.GB4210@co.sapo.pt> +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="bg08WKrSYDhXBjb5" +Content-Disposition: inline +Content-Transfer-Encoding: 8bit +User-Agent: Mutt/1.3.27i +X-URL: http://xpto.org/~japc +X-System: Linux morgoth 2.4.18pre1 i686 +X-Subliminal: Exchange Microsoft +Status: RO +Content-Length: 63760 +Lines: 1546 + + +--bg08WKrSYDhXBjb5 +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +Hello Guy, + +don't know if you still maintain Ezmlm-Web but I've done some minor +changes/improvements; + +- subscriber list can be filtered by the start character or by regexp + (we had lists of nearly 50000 subscribers and it was a pain for the page to open); + +- support for $LIST/domains (for submission acls per domain): + In $LIST/editor top you should add the following line (one line only): + + |export SENDER=`echo $SENDER | sed s/^.*@/@/g`; /servers/ezmlm/bin/ezmlm-issubn + '/servers/virtualdomains/lists.mydomain.com/list1/domains' || { echo + "Sorry, I'm reject mail from your domain ($SENDER). + Contact sysadmin@mydomain.com if you have any questions about it.(#5.7.2)"; exit 100 ; } + + ad an extra list directory similar to mod for instance, $LIST/domains. + +- and, finally, support for newsletter administration (we use ezmlm here + for newsletter sending - games, technology, health, etc.) for the + non-technical dudes to manage and send issues for all the mailing list + subscribers. + +I found the subscripter filter to be extremely useful :) + +-- +Jose Celestino +--------------------------------- +Systems Administration - SAPO.pt + +--bg08WKrSYDhXBjb5 +Content-Type: text/plain; charset=iso-8859-1 +Content-Disposition: attachment; filename="ezmlm-web.cgi" +Content-Transfer-Encoding: 8bit + +#!/usr/bin/perl +#=========================================================================== +# ezmlm-web.cgi - version 2.1 - 25/09/2000 +# $Id: ezmlm-web.cgi,v 1.3 2000/09/25 19:58:07 guy Exp $ +# +# Copyright (C) 1999/2000, Guy Antony Halse, All Rights Reserved. +# Please send bug reports and comments to guy-ezmlm@rucus.ru.ac.za +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 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. +# +# Neither name Guy Antony Halse nor the names of any contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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. +# +# ========================================================================== +# All user configuration happens in the config file ``ezmlmwebrc'' +# POD documentation is at the end of this file +# ========================================================================== + +# Modules to include +use strict; +use Getopt::Std; +use Mail::Ezmlm; +use Mail::Address; +use DB_File; +use CGI; +use CGI::Carp qw(fatalsToBrowser set_message); + +# These two are actually included later and are put here so we remember them. +#use File::Find if ($UNSAFE_RM == 1); +#use File::Copy if ($UNSAFE_RM == 0); + +my @searchable=("TODOS","0-9","A","B","C","D","E","F","G","H","I","J","K", + "L","M","N","O","P","Q","R","S","T","U","V","X","W","Y","Z","_"); + +my $q = new CGI; +$q->import_names('Q'); +use vars qw[$opt_c $opt_d $opt_C]; +getopts('cd:C:'); + +# Suid stuff requires a secure path. +$ENV{'PATH'} = '/bin'; + +# We run suid so we can't use $ENV{'HOME'} and $ENV{'USER'} to determine the +# user. :( Don't alter this line unless you are _sure_ you have to. +my @tmp = getpwuid($>); my $USER=$tmp[0]; + +# use strict is a good thing++ + +use vars qw[$HOME_DIR]; $HOME_DIR=$tmp[7]; +use vars qw[$DEFAULT_OPTIONS %EZMLM_LABELS $UNSAFE_RM $ALIAS_USER $LIST_DIR]; +use vars qw[$QMAIL_BASE $EZMLM_CGI_RC $EZMLM_CGI_URL $HTML_BGCOLOR $PRETTY_NAMES]; +use vars qw[%HELPER $HELP_ICON_URL $HTML_HEADER $HTML_FOOTER $HTML_TEXT $HTML_LINK]; +use vars qw[%BUTTON %LANGUAGE $HTML_VLINK $HTML_TITLE $FILE_UPLOAD]; + +# Get user configuration stuff +if(defined($opt_C)) { + require "$opt_C"; # Command Line +} elsif(-e "$HOME_DIR/.ezmlmwebrc") { + require "$HOME_DIR/.ezmlmwebrc"; # User +} elsif(-e "/etc/ezmlm/ezmlmwebrc") { + require "/etc/ezmlm/ezmlmwebrc"; # System +} elsif(-e "./ezmlmwebrc") { + require "./ezmlmwebrc"; # Install +} else { + die "Unable to read config file"; +} + +# Allow suid wrapper to over-ride default list directory ... +if(defined($opt_d)) { + $LIST_DIR = $1 if ($opt_d =~ /^([-\@\w.\/]+)$/); +} + +# Work out default domain name from qmail (for David Summers) +my($DEFAULT_HOST); +open (GETHOST, "<$QMAIL_BASE/me") || open (GETHOST, "<$QMAIL_BASE/defaultdomain") || die "Unable to read $QMAIL_BASE/me: $!"; +chomp($DEFAULT_HOST = ); +close GETHOST; + +# Untaint form input ... +&untaint; + +# redirect must come before headers are printed +if(defined($Q::action) && $Q::action eq '[Web Archive]') { + print $q->redirect(&ezmlmcgirc); + exit; +} + +# Print header on every page ... +print $q->header(-pragma=>'no-cache', '-cache-control'=>'no-cache', -expires=>'-1d'); +print $q->start_html(-title=>$HTML_TITLE, -author=>'guy-ezmlm@rucus.ru.ac.za', -BGCOLOR=>$HTML_BGCOLOR, -LINK=>$HTML_LINK, -VLINK=>$HTML_VLINK, -TEXT=>$HTML_TEXT, -expires=>'-1d'); +print $HTML_HEADER; + +# This is where we decide what to do, depending on the form state and the +# users chosen course of action ... +unless (defined($q->param('state'))) { + # Default action. Present a list of available lists to the user ... + &select_list; + +} elsif ($Q::state eq 'select') { + # User selects an action to perorm on a list ... + + if ($Q::action eq "[$BUTTON{'create'}]") { # Create a new list ... + &allow_create_list; + } elsif (defined($Q::list)) { + if ($Q::action eq "[$BUTTON{'edit'}]") { # Edit an existing list ... + &display_list("NONE"); +# open (ZBR,">>/tmp/123"); +# print ZBR "FILTER:" . $q->param('filt') ."\n"; +# while (defined($q->param('filt'))) { +# print ZBR "DONEEEEEEEE\n"; +# &display_list($q->param('filt')); +# } +# close ZBR; + } elsif ($Q::action eq "[$BUTTON{'delete'}]") { # Delete a list ... + &confirm_delete; + } + } else { + &select_list; # NOP - Blank input ... + } + +} elsif ($Q::state eq 'edit') { + # User chooses to edit a list + + my($list); $list = $LIST_DIR . '/' . $q->param('list'); + if ($Q::action eq "[$BUTTON{'deleteaddress'}]") { # Delete a subscriber ... + &delete_address($list); + &display_list("NONE"); + + } elsif ($Q::action eq "[$BUTTON{'addaddress'}]") { # Add a subscriber ... + &add_address($list); + &display_list("NONE"); + + } elsif ($Q::action eq "[$BUTTON{'edit_newsletter'}]") { # Send a newsletter issue... + &edit_newsletter($list); + + } elsif ($Q::action eq "[$BUTTON{'moderators'}]") { # Edit the moderators ... + &part_subscribers('mod'); + + } elsif ($Q::action eq "[$BUTTON{'domains'}]") { # Edit the domains ... + &part_subscribers('domains'); + + } elsif ($Q::action eq "[$BUTTON{'denylist'}]") { # Edit the deny list ... + &part_subscribers('deny'); + + } elsif ($Q::action eq "[$BUTTON{'allowlist'}]") { # edit the allow list ... + &part_subscribers('allow'); + + } elsif ($Q::action eq "[$BUTTON{'digestsubscribers'}]") { # Edit the digest subscribers ... + &part_subscribers('digest'); + + } elsif ($Q::action eq "[$BUTTON{'configuration'}]") { # Edit the config ... + &list_config; + + } elsif (defined($q->param('filt'))) { + &display_list($q->param('filt')); + + } elsif (defined($q->param('search')) && defined($q->param('searchfor'))) { + &display_list($q->param('searchfor')); + + } else { # Cancel - Return a screen ... + &select_list; + } + +} elsif ($Q::state eq 'allow' || $Q::state eq 'mod' || $Q::state eq 'deny' || $q->param('state') eq 'digest') { + # User edits moderators || deny || digest ... + + my($part); + # Which list directory are we using ... + if($Q::state eq 'mod') { + $part = 'mod'; + } elsif($Q::state eq 'deny' ) { + $part = 'deny'; + } elsif($Q::state eq 'allow') { + $part = 'allow'; + } else { + $part = 'digest'; + } + + if ($Q::action eq '[Delete Address]') { # Delete a subscriber ... + &delete_address("$LIST_DIR/$Q::list", $part); + &part_subscribers($part); + + } elsif ($Q::action eq "[$BUTTON{'addaddress'}]") { # Add a subscriber ... + &add_address("$LIST_DIR/$Q::list", $part); + &part_subscribers($part); + + } else { # Cancel - Return to the list ... + &display_list("NONE"); + } + +} elsif ($Q::state eq 'confirm_delete') { + # User wants to delete a list ... + + &delete_list if($q->param('confirm') eq "[$BUTTON{'yes'}]"); # Do it ... + $q->delete_all; + &select_list; + +} elsif ($Q::state eq 'create') { + # User wants to create a list ... + + if ($Q::action eq "[$BUTTON{'createlist'}]") { + if (&create_list) { # Return if list creation is unsuccessful ... + &allow_create_list; + } else { + &select_list; # Else choose a list ... + } + + } else { # Cancel ... + &select_list; + } + +} elsif ($Q::state eq 'configuration') { + # User updates configuration ... + + if ($Q::action eq "[$BUTTON{'updateconfiguration'}]") { # Save current settings ... + &update_config; + &display_list("NONE"); + + } elsif ($Q::action eq "[$BUTTON{'edittexts'}]") { # Edit DIR/text ... + &list_text; + + } else { # Cancel - Return to list editing screen ... + &display_list("NONE"); + } + +} elsif ($Q::state eq 'list_text') { + # User wants to edit texts associated with the list ... + + if ($Q::action eq "[$BUTTON{'editfile'}]") { + &edit_text; + } else { + &list_config; # Cancel ... + } + +} elsif ($Q::state eq 'edit_text') { + # User wants to save a new version of something in DIR/text ... + + &save_text if ($Q::action eq "[$BUTTON{'savefile'}]"); + &list_text; + +} elsif ($Q::state eq 'edit_newsletter') { + # User wants to do something related with the newsletter + + if ($Q::action eq "[$BUTTON{'updateconfiguration'}]") { + my $issue=$q->param('newsletterissue'); + $issue="0$issue" if (($issue < 10) && ($issue !~ m/^0/)); + my ($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + # THOU SHALL NOT MESS $list->setpart("newsletter/localizacao", $q->param('newslettertree')); + $list->setpart("newsletter/ficheiro", $q->param('newsletterhtml')); + $list->setpart("newsletter/subject-da-edicao", $q->param('newslettersubject')); + # THOU SHALL NOT MESS $list->setpart("newsletter/sender", $q->param('newslettersender')); + $list->setpart("newsletter/edicao", $issue); + &edit_newsletter; + } + &edit_newsletter if ($Q::action eq "[$BUTTON{'resetform'}]"); + &sendnewsletter if ($Q::action eq "[$BUTTON{'sendnewsletter'}]"); + &display_list("NONE") if ($Q::action eq "[$BUTTON{'cancel'}]"); + +} else { + print "

$Q::action

$LANGUAGE{'nop'}


"; +} + +# Print HTML footer and exit :) ... +print $HTML_FOOTER, $q->end_html; +exit; + +# ========================================================================= + +sub select_list { + # List all mailing lists (sub directories) in the list directory. + # Allow the user to choose a course of action; either editing an existing + # list, creating a new one, or deleting an old one. + + my (@lists, @files, $i, $scrollsize); + + # Read the list directory for mailing lists. + opendir DIR, $LIST_DIR || die "Unable to read $LIST_DIR: $!"; + @files = grep !/^\./, readdir DIR; + closedir DIR; + + # Check that they actually are lists ... + foreach $i (0 .. $#files) { + if (-e "$LIST_DIR/$files[$i]/lock") { + if (-e "$LIST_DIR/webusers") { + if (&webauth($files[$i]) == 0) { + $lists[$#lists + 1] = $files[$i]; + } + } else { + $lists[$#lists + 1] = $files[$i]; + } + } + } + + # Keep selection box a resonable size - suggested by Sebastian Andersson + $scrollsize = 25 if(($scrollsize = $#lists + 1) > 25); + + # Print a form + $q->delete_all; + print $q->startform; + print $q->hidden(-name=>'state', -default=>'select'); + print '
'; + print $q->scrolling_list(-name=>'list', -size=>$scrollsize, -values=>\@lists) if defined(@lists); + + print '', $LANGUAGE{'chooselistinfo'}; + + print $q->submit(-name=>'action', -value=>"[$BUTTON{'create'}]"), ' ' if (!defined($opt_c)); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edit'}]"), ' ' if(defined(@lists)); + # JAPC // print $q->submit(-name=>'action', -value=>"[$BUTTON{'delete'}]") if(defined(@lists)); + print '
'; + print $q->endform; +} + +# ------------------------------------------------------------------------ + +sub confirm_delete { + # Make sure that the user really does want to delete the list! + + # Print a form ... + $q->delete('state'); + print $q->startform; + print $q->hidden(-name=>'state', -default=>'confirm_delete'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); + print '

', $LANGUAGE{'confirmdelete'}, ' ', $q->param('list'), '


'; + print $q->submit(-name=>'confirm', -value=>"[$BUTTON{'no'}]"), ' '; + print $q->submit(-name=>'confirm', -value=>"[$BUTTON{'yes'}]"), '
'; +} + +# ------------------------------------------------------------------------ + +sub display_list { + # Show a list of subscribers to the user ... + + my ($i, $list, $listaddress, $moderated, @subscribers, $scrollsize); + my ($filt) = @_; + my @subscribersfilt; + + # Work out the address of this list ... + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $listaddress = &this_listaddress; + + # Get a list of subscribers from ezmlm ... + @subscribers = $list->subscribers; + + if ("$filt" ne "NONE") { + if ($filt eq "0-9") { $filt='\d' }; + if ($filt eq "TODOS") { $filt='.*$' }; + for (@subscribers) { + if (defined($q->param('search'))) { + push @subscribersfilt, $_ if (m/$filt/i); + } else { + push @subscribersfilt, $_ if (m/^$filt/i); + } + } + } + + # Keep selection box a resonable size - suggested by Sebastian Andersson + $scrollsize = 25 if(($scrollsize = $#subscribers + 1) > 25); + + # Print out a form of options ... + $q->delete('state'); + print "

$LANGUAGE{'subscribersto'} $Q::list ($listaddress)


"; + print $q->start_multipart_form; + print '
'; + print $q->hidden(-name=>'state', -default=>'edit'); + print $q->hidden(-name=>'list', -default=>$Q::list); + print $q->scrolling_list(-name=>'delsubscriber', -size=>$scrollsize, -values=>\@subscribersfilt, -labels=>&pretty_names, -multiple=>'true');# if defined(@subscribersfilt) && ($#subscribers <= 50); + print ''; + print '
', ($#subscribers + 1), ' ', $LANGUAGE{'subscribers'}, ' || ', ($#subscribersfilt + 1), ' ', $LANGUAGE{'selected'},' (', $filt ,')

' if defined(@subscribers); + if (defined(@subscribers)) { + print "Filtrar:
"; + for (@searchable) { + print $q->submit(-name=>'filt', -value=>"$_"); + } + print "
[regexp]:" . $q->textfield(-name=>'searchfor', -size=>'40'); + print $q->submit(-name=>'search', -value=>"[$BUTTON{'search'}]"), '

'; + } + print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

'; # if (defined(@subscribers) && ($#subscribers >= 51)); + print $q->textfield(-name=>'addsubscriber', -size=>'40'), ' ', $HELPER{'addaddress'}, '
'; + print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), ' ', $HELPER{'addaddressfile'}, '
' if ($FILE_UPLOAD); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; + print '', $LANGUAGE{'additionalparts'}, ':
' if($list->ismodpost || $list->ismodsub || $list->isremote || $list->isdeny || $list->isallow || $list->isdigest); + # JAPC // + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edit_newsletter'}]"), '', $HELPER{'edit_newsletter'}, ' '; + #if ($list->ismodpost || $list->ismodsub || $list->isremote); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'moderators'}]"), '', $HELPER{'moderator'}, ' ' if ($list->ismodpost || $list->ismodsub || $list->isremote); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'domains'}]"), '', $HELPER{'domains'}, ' ' if (-d "$LIST_DIR/domains"); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'denylist'}]"), '', $HELPER{'deny'}, ' ' if ($list->isdeny); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'allowlist'}]"), '', $HELPER{'allow'}, ' ' if ($list->isallow); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'digestsubscribers'}]"), '', $HELPER{'digest'}, ' ' if ($list->isdigest); + print '

'; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'webarchive'}]"), '', $HELPER{'webarch'}, ' ' if(&ezmlmcgirc); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'configuration'}]"), '', $HELPER{'config'}, '   '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'selectlist'}]"); + print '

'; + print $q->endform; + +} + +# ------------------------------------------------------------------------ + +sub delete_list { + # Delete a list ... + + # Fixes a bug from the previous version ... when the .qmail file has a + # different name to the list. We use outlocal to handle vhosts ... + my ($list, $listaddress, $listadd); + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + if ($listadd = $list->getpart('outlocal')) { + chomp($listadd); + } else { + $listadd = $q->param('list'); + } + $listaddress = $1 if ($listadd =~ /-?(\w+)$/); + + if ($UNSAFE_RM == 0) { + # This doesn't actually delete anything ... It just moves them so that + # they don't show up. That way they can always be recovered by a helpful + # sysadmin should he be in the mood :) + + use File::Copy; + + my ($oldfile); $oldfile = "$LIST_DIR/$Q::list"; + my ($newfile); $newfile = "$LIST_DIR/.$Q::list"; + move($oldfile, $newfile) or die "Unable to rename list: $!"; + mkdir "$HOME_DIR/deleted.qmail", 0700 if(!-e "$HOME_DIR/deleted.qmail"); + + opendir(DIR, "$HOME_DIR") or die "Unable to get directory listing: $!"; + my @files = map { "$HOME_DIR/$1" if m{^(\.qmail.+)$} } grep { /^\.qmail-$listaddress/ } readdir DIR; + closedir DIR; + foreach (@files) { + unless (move($_, "$HOME_DIR/deleted.qmail/")) { + die "Unable to move .qmail files: $!"; + } + } + warn "List '$oldfile' moved (deleted)"; + } else { + # This, however, does DELETE the list. I don't like the idea, but I was + # asked to include support for it so ... + if (!rmtree("$LIST_DIR/$Q::list")) { + die "Unable to delete list: $!"; + } + opendir(DIR, "$HOME_DIR") or die "Unable to get directory listing: $!"; + my @files = map { "$HOME_DIR/$1" if m{^(\.qmail.+)$} } grep { /^\.qmail-$listaddress/ } readdir DIR; + closedir DIR; + if (unlink(@files) <= 0) { + die "Unable to delete .qmail files: $!"; + } + warn "List '$list->thislist()' deleted"; + } +} + +# ------------------------------------------------------------------------ +sub untaint { + + $DEFAULT_HOST = $1 if $DEFAULT_HOST =~ /^([\w\d\.-]+)$/; + + # Go through all the CGI input and make sure it is not tainted. Log any + # tainted data that we come accross ... See the perlsec(1) man page ... + + my (@params, $i, $param); + @params = $q->param; + + foreach $i (0 .. $#params) { + my(@values); + next if($params[$i] eq 'addfile'); + foreach $param ($q->param($params[$i])) { + next if $param eq ''; + if ($param =~ /^([#-\@\w\.\/\[\]\:\n\r\>\< ]+)$/) { + push @values, $1; + } else { + warn "Tainted input in '$params[$i]': " . $q->param($params[$i]); + } + $q->param(-name=>$params[$i], -values=>\@values); + } + } + $q->import_names('Q'); +} + +# ------------------------------------------------------------------------ + +sub add_address { + # Add an address to a list .. + + my ($address, $list, @addresses, $count); my ($listname, $part) = @_; + $list = new Mail::Ezmlm($listname); + + if($q->param('addfile')) { + + # Sanity check + die "File upload must be of type text/*" unless($q->uploadInfo($q->param('addfile'))->{'Content-Type'} =~ m{^text/}); + + # Handle file uploads of addresses + my($fh) = $q->upload('addfile'); + return unless (defined($fh)); + while (<$fh>) { + next if (/^\s*$/ or /^#/); # blank, comments + next unless (/\@/); # email address ... + chomp(); + push @addresses, $_; + } + + } else { + + # User typed in an address + return if ($q->param('addsubscriber') eq ''); + + $address = $q->param('addsubscriber'); + $address .= $DEFAULT_HOST if ($q->param('addsubscriber') =~ /\@$/); + push @addresses, $address; + + } + + foreach $address (@addresses) { + + my($add) = Mail::Address->parse($address); + if(defined($add->name()) && $PRETTY_NAMES) { + my(%pretty); + tie %pretty, "DB_File", "$LIST_DIR/$Q::list/webnames"; + $pretty{$add->address()} = $add->name(); + untie %pretty; + } + + if ($list->sub($add->address(), $part) != 1) { + die "Unable to subscribe to list: $!"; + } + $count++; + } + + $q->delete('addsubscriber'); +} + +# ------------------------------------------------------------------------ + +sub delete_address { + # Delete an address from a list ... + + my ($list, @address); my($listname, $part) = @_; + $list = new Mail::Ezmlm($listname); + return if ($q->param('delsubscriber') eq ''); + + @address = $q->param('delsubscriber'); + + if ($list->unsub(@address, $part) != 1) { + die "Unable to unsubscribe from list $list: $!"; + } + + if($PRETTY_NAMES) { + my(%pretty, $add); + tie %pretty, "DB_File", "$LIST_DIR/$Q::list/webnames"; + foreach $add (@address) { + delete $pretty{$add}; + } + untie %pretty; + } + + $q->delete('delsubscriber'); +} + +# ------------------------------------------------------------------------ + +sub part_subscribers { + my($part) = @_; + # Deal with list parts .... + + my ($i, $list, $listaddress, @subscribers, $moderated, $scrollsize, $type); + + # Work out the address of this list ... + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $listaddress = &this_listaddress; + + if($part eq 'mod') { + # Lets know what is moderated :) + + # do we store things in different directories? + my $config = $list->getconfig; + my($postpath) = $config =~ m{7\s*'([^']+)'}; + my($subpath) = $config =~ m{8\s*'([^']+)'}; + my($remotepath) = $config =~ m{9\s*'([^']+)'}; + + $moderated = '' if ($postpath); + $moderated .= "[$LANGUAGE{'posting'}]" if ($list->ismodpost); + $moderated .= 'Posting Moderators are stored in a non-standard location (' . $postpath . '). You will have to edit them manually.' if ($postpath); + $moderated .= '' if ($subpath); + $moderated .= " [$LANGUAGE{'subscription'}]" if($list->ismodsub); + $moderated .= 'Subscriber Moderators are stored in a non-standard location (' . $subpath . '). You will have to edit them manually' if ($subpath); + $moderated .= '' if ($remotepath); + $moderated .= " [$LANGUAGE{'remoteadmin'}]" if($list->isremote); + $moderated .= 'Remote Administrators are stored in a non-standard location (' . $remotepath . '). You will have to edit them manually' if ($remotepath); + + } + + # What type of sublist is this? + ($type) = $Q::action =~ m/^\[(.+)\]$/; + + # Get a list of moderators from ezmlm ... + @subscribers = $list->subscribers($part); + + # Keep selection box a resonable size - suggested by Sebastian Andersson + $scrollsize = 25 if(($scrollsize = $#subscribers + 1) > 25); + + # Print out a form of options ... + $q->delete('state'); + print "

$type $LANGUAGE{'for'} $listaddress


"; + print "
$moderated

" if(defined($moderated)); + print $q->start_multipart_form; + print '

'; + print $q->hidden(-name=>'state', -default=>$part); + print $q->hidden(-name=>'list', -default=>$Q::list), "\n"; + print $q->scrolling_list(-name=>'delsubscriber', -size=>$scrollsize, -values=>\@subscribers, -multiple=>'true', -labels=>&pretty_names) if defined(@subscribers); + print '
'; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'deleteaddress'}]"), '

' if defined(@subscribers); + print $q->textfield(-name=>'addsubscriber', -size=>'40'), ' ', $HELPER{'addaddress'}, '
'; + print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), ' ', $HELPER{'addaddressfile'}, '
' if ($FILE_UPLOAD); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'addaddress'}]"), '

'; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'subscribers'}]"); + print '

'; + print $q->endform; + +} + +# ------------------------------------------------------------------------ + +sub allow_create_list { + # Let the user select options for list creation ... + + my($username, $hostname, %labels, $j); + + # Work out if this user has a virtual host and set input accordingly ... + if(-e "$QMAIL_BASE/virtualdomains") { + open(VD, "<$QMAIL_BASE/virtualdomains") || warn "Can't read virtual domains file: $!"; + while() { + last if(($hostname) = /(.+?):$USER/); + } + close VD; + } + + if(!defined($hostname)) { + $username = "$USER-" if ($USER ne $ALIAS_USER); + $hostname = $DEFAULT_HOST; + } + + # Print a form of options ... + $q->delete_all; + print '

', $LANGUAGE{'createnew'}, '


'; + print $q->startform; + print $q->hidden(-name=>'state', -value=>'create'); + print '', $LANGUAGE{'listname'}, ': ', $q->textfield(-name=>'list', -size=>'20'), ' ', $HELPER{'listname'}, '

'; + print '', $LANGUAGE{'listaddress'}, ': '; + print $q->textfield(-name=>'inlocal', -default=>$username, -size=>'10'); + print ' @ ', $q->textfield(-name=>'inhost', -default=>$hostname, -size=>'30'), ' ', $HELPER{'listadd'}, '

'; + + print '

', $LANGUAGE{'listoptions'}, ':'; + &display_options($DEFAULT_OPTIONS); + + # Allow creation of mysql table if the module allows it + if($Mail::Ezmlm::MYSQL_BASE) { + print '

', $q->checkbox(-name=>'sql', -label=>$LANGUAGE{'mysqlcreate'}, -on=>1); + print ' ', $HELPER{'mysqlcreate'}, ''; + + } + + print '

', $LANGUAGE{'allowedtoedit'}, ': ', + $q->textfield(-name=>'webusers', -value=>$ENV{'REMOTE_USER'}||'ALL', -size=>'30'), ' ', $HELPER{'webusers'}, '', + '
', $HELPER{'allowedit'}, '' + if(-e "$LIST_DIR/webusers"); + + print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'createlist'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"); + print $q->endform; + +} + +# ------------------------------------------------------------------------ + +sub create_list { + # Create a list acording to user selections ... + + # Check the list directory exists and create if necessary ... + if(!-e $LIST_DIR) { + die "Unable to create directory ($LIST_DIR): $!" unless mkdir $LIST_DIR, 0700; + } + + my ($qmail, $listname, $options, $i); + + # Some taint checking ... + $qmail = $1 if $q->param('inlocal') =~ /(?:$USER-)?([^\<\>\\\/\s]+)$/; + $listname = $q->param('list'); $listname =~ s/ /_/g; # In case some git tries to put a space in the file name + + # Sanity Checks ... + return 1 if ($listname eq '' || $qmail eq ''); + if(-e ("$LIST_DIR/$listname/lock") || -e ("$HOME_DIR/.qmail-$qmail")) { + print "

List '$listname' already exists :(

"; + return 1; + } + + # Work out the command line options + foreach $i (grep {/\D/} keys %EZMLM_LABELS) { + if (defined($q->param($i))) { + $options .= $i; + } else { + $options .= uc($i); + } + } + + foreach $i (grep {/\d/} keys %EZMLM_LABELS) { + if (defined($q->param($i))) { + $options .= " -$i '" . $q->param("$i-value") . "'"; + } + } + + my($list) = new Mail::Ezmlm; + + unless ($list->make(-dir=>"$LIST_DIR/$listname", + -qmail=>"$HOME_DIR/.qmail-$qmail", + -name=>$q->param('inlocal'), + -host=>$q->param('inhost'), + -switches=>$options, + -user=>$USER) + ) { + die 'List creation failed', $list->errmsg(); + } + + # handle MySQL stuff + if($q->param('sql') && $options =~ m/-6\s+/) { + unless($list->createsql()) { + die 'SQL table creation failed: ', $list->errmsg(); + } + } + + # Handle authentication stuff + if ($Q::webusers) { + open(WEBUSER, ">>$LIST_DIR/webusers") || die "Unable to open webusers: $!"; + print WEBUSER "$Q::list: $Q::webusers\n"; + close WEBUSER; + } + + return 0; +} + +# ------------------------------------------------------------------------ + +sub list_config { + # Allow user to alter the list configuration ... + + my ($list, $listaddress, $listname, $options); + my ($headeradd, $headerremove, $mimeremove, $prefix, $j); + + # Store some variables before we delete them ... + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $listname = $q->param('list'); + $listaddress = &this_listaddress; + + # Print a form of options ... + $q->delete_all; + print '

', $LANGUAGE{'editconfiguration'}, '


'; + print $q->startform; + print $q->hidden(-name=>'state', -value=>'configuration'); + print $q->hidden(-name=>'list', -value=>$listname); + print '', $LANGUAGE{'listname'}, ": $listname
"; + print "$LANGUAGE{'listaddress'}: $listaddress

"; + print '', $LANGUAGE{'listoptions'}, ':
'; + + # Print a list of options, selecting the ones that apply to this list ... + &display_options($list->getconfig); + + # Get the contents of the headeradd, headerremove, mimeremove and prefix files + $headeradd = $list->getpart('headeradd'); + $headerremove = $list->getpart('headerremove'); + $mimeremove = $list->getpart('mimeremove'); + $prefix = $list->getpart('prefix'); + + print '

', $LANGUAGE{'prefix'}, ': ', $q->textfield(-name=>'prefix', -default=>$prefix, -size=>12), ' ', $HELPER{'prefix'}, '' if defined($prefix); + print '

', $LANGUAGE{'headerremove'}, ': ', $HELPER{'headerremove'}, '
', $q->textarea(-name=>'headerremove', -default=>$headerremove, -rows=>5, -columns=>70); + print '

', $LANGUAGE{'headeradd'}, ': ', $HELPER{'headeradd'}, '
', $q->textarea(-name=>'headeradd', -default=>$headeradd, -rows=>5, -columns=>70); + print '

', $LANGUAGE{'mimeremove'}, ': ', $HELPER{'mimeremove'}, '
', $q->textarea(-name=>'mimeremove', -default=>$mimeremove, -rows=>5, -columns=>70) if defined($mimeremove); + + if(open(WEBUSER, "<$LIST_DIR/webusers")) { + my($webusers); + while() { + last if (($webusers) = m{^$listname\s*\:\s*(.+)$}); + } + close WEBUSER; + $webusers ||= $ENV{'REMOTE_USER'} || 'ALL'; + + print '

', $LANGUAGE{'allowedtoedit'}, ': ', + $q->textfield(-name=>'webusers', -value=>$webusers, -size=>'30'), ' ', $HELPER{'webusers'}, '', + '
', $HELPER{'allowedit'}, ''; + + } + + print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'updateconfiguration'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'edittexts'}]"); + print $q->endform; + +} + +# ------------------------------------------------------------------------ + +sub update_config { + # Save the new user entered config ... + + my ($list, $options, $i, @inlocal, @inhost); + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + + # Work out the command line options ... + foreach $i (grep {/\D/} keys %EZMLM_LABELS) { + if (defined($q->param($i))) { + $options .= $i; + } else { + $options .= uc($i); + } + } + + foreach $i (grep {/\d/} keys %EZMLM_LABELS) { + if (defined($q->param($i))) { + $options .= " -$i '" . $q->param("$i-value") . "'"; + } + } + + # Actually update the list ... + unless($list->update($options)) { + die "List update failed"; + } + + # Update headeradd, headerremove, mimeremove and prefix ... + $list->setpart('headeradd', $q->param('headeradd')); + $list->setpart('headerremove', $q->param('headerremove')); + $list->setpart('mimeremove', $q->param('mimeremove')) if defined($q->param('mimeremove')); + $list->setpart('prefix', $q->param('prefix')) if defined($q->param('prefix')); + + if($Q::webusers) { + # Back up web users file + open(TMP, ">/tmp/ezmlm-web.$$"); + open(WU, "<$LIST_DIR/webusers"); + while() { print TMP; } + close TMP; close WU; + + open(TMP, "$LIST_DIR/webusers"); + while() { + if(/^$Q::list\s*:/) { + print WU "$Q::list\: $Q::webusers\n"; + } else { + print WU; + } + } + close TMP; close WU; + unlink "/tmp/ezmlm-web.$$"; + } + +} + +# ------------------------------------------------------------------------ + +sub this_listaddress { + # Work out the address of this list ... Used often so put in its own subroutine ... + + my ($list, $listaddress); + $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + chomp($listaddress = $list->getpart('outlocal')); + $listaddress .= '@'; + chomp($listaddress .= $list->getpart('outhost')); + return $listaddress; +} + +# ------------------------------------------------------------------------ + +sub list_text { + # Show a listing of what is in DIR/text ... + + my(@files, $list); + $list = $LIST_DIR . '/' . $q->param('list'); + + # Read the list directory for text ... + opendir DIR, "$list/text" || die "Unable to read DIR/text: $!"; + @files = grep !/^\./, readdir DIR; + closedir DIR; + + # Print a form ... + $q->delete('state'); + print $q->startform; + print $q->hidden(-name=>'state', -default=>'list_text'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); + print '

'; + print $q->scrolling_list(-name=>'file', -values=>\@files); + print ''; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'editfile'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"); + print '

', $LANGUAGE{'edittextinfo'}, '

'; + print $q->endform; + +} + +# ------------------------------------------------------------------------ + +sub edit_text { + # Allow user to edit the contents of DIR/text ... + + my ($content); + my($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $content = $list->getpart("text/$Q::file"); + + # Print a form ... + $q->delete('state'); + print '

', $LANGUAGE{'editingfile'}, ': ', $Q::file, '

'; + print '
'; + print $q->startform; + print $q->hidden(-name=>'state', -default=>'edit_text'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); + print $q->hidden(-name=>'file', -default=>$q->param('file')); + print $q->textarea(-name=>'content', -default=>$content, -rows=>'25', -columns=>'72'); + print ''; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'savefile'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"); + print '

', $LANGUAGE{'editfileinfo'}; + print $q->endform; + print '

' + +} + +# ------------------------------------------------------------------------ + +sub save_text { + # Save new text in DIR/text ... + + my ($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $list->setpart("text/$Q::file", $q->param('content')); + +} + +# ------------------------------------------------------------------------ + +sub webauth { + + # Read authentication level from webusers file. Format of this file is + # somewhat similar to the unix groups file + my($listname) = @_; + open (USERS, "<$LIST_DIR/webusers") || die "Unable to read webusers file: $!"; + while() { + if (/^($listname|ALL)\:/i) { + if (/(\:\s*|,\s+)((?:$ENV{'REMOTE_USER'})|(?:ALL))\s*(,|$)/) { + close USERS; return 0; + } + } + } + close USERS; + return 1; +} + +# --------------------------------------------------------------------------- + +sub display_options { + my($opts) = shift; + my($i, $j); + + print ""; + print ''; $j++; + if ($j >= 3) { + $j = 0; print ''; + } + print '
'; + foreach $i (grep {/\D/} keys %EZMLM_LABELS) { + if ($opts =~ /^\w*$i\w*\s*/) { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0], -on=>'1'); + } else { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0]); + } + print '', $EZMLM_LABELS{$i}[1] , ''; + print '
'; + } + print '
'; + + print ''; + foreach $i (grep {/\d/} keys %EZMLM_LABELS) { + print ''; + + } + print '
'; + if ($opts =~ /$i (?:'(.+?)')/) { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0], -on=>'1'); + } else { + print $q->checkbox(-name=>$i, -value=>$i, -label=>$EZMLM_LABELS{$i}[0]); + } + print '', $EZMLM_LABELS{$i}[1] , ''; + print ''; + print $q->textfield(-name=>"$i-value", -value=>$1||$EZMLM_LABELS{$i}[2], -size=>30); + print '
'; + +} + +# --------------------------------------------------------------------------- + +sub edit_newsletter { + # Edit a newsletter configuration + my ($file,$subject,$sender,$tree,$issue) = (); + my $listaddress = &this_listaddress; + + my ($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + + $file="newsletter.html" unless ($file = $list->getpart("newsletter/ficheiro")); + $subject="Ediçao XX" unless ($subject = $list->getpart("newsletter/subject-da-edicao")); + $sender="$listaddress" unless ($sender = $list->getpart("newsletter/sender")); + $tree="/edicaoXX/" unless ($tree = $list->getpart("newsletter/localizacao")); + $issue="" unless ($issue = $list->getpart("newsletter/edicao")); + + $q->delete('state'); + print $q->start_multipart_form; + print $q->hidden(-name=>'state', -default=>'edit_newsletter'); + print $q->hidden(-name=>'list', -default=>$q->param('list')); + print $q->hidden(-name=>'file', -default=>$q->param('file')); + print '
'; + print '

', $LANGUAGE{'newslettertree'}, ': ', $HELPER{'newslettertree'}, ''; + print '

', $LANGUAGE{'newsletterhtml'}, ': ', $HELPER{'newsletterhtml'}, ''; + print '

', $LANGUAGE{'newslettersubject'}, ': ', $HELPER{'newslettersubject'}, ''; + print '

', $LANGUAGE{'newslettersender'}, ': ', $HELPER{'newslettersender'}, ''; + print '

', $LANGUAGE{'newsletterissue'}, ': ', $HELPER{'newsletterissue'}, ''; + print '

'; + # THOU SHALL NOT MESS print '

', $q->textfield(-name=>'newslettertree', -size=>'50', -default=>"$tree"), ''; + print '

', "$tree/edicao$issue", ''; + print '

', $q->textfield(-name=>'newsletterhtml', -size=>'30', -default=>"$file"), ''; + print '

', $q->textfield(-name=>'newslettersubject', -size=>'50', -default=>"$subject"), ''; + # THOU SHALL NOT MESS print '

', $q->textbox(-name=>'newslettersender', -size=>'30', -default=>"$sender"), ''; + print '

', "$sender", ''; + print '

', $q->textfield(-name=>'newsletterissue', -size=>'10', -default=>"$issue"), ''; + print '

'; + + print $q->hidden(-name=>'newslettertree', -default=>$q->param("$tree")); + print $q->hidden(-name=>'newslettersender', -default=>$q->param("$sender")); + + print '

', $q->submit(-name=>'action', -value=>"[$BUTTON{'updateconfiguration'}]"), ' '; + print $q->reset(-value=>"[$BUTTON{'resetform'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'cancel'}]"), ' '; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'sendnewsletter'}]"); + + print $q->endform; +} + +# --------------------------------------------------------------------------- + +sub sendnewsletter { + # Send newsletter + my ($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + my $listaddress = &this_listaddress; + my ($file,$subject,$sender,$tree,$issue) = (); + + $file="newsletter.html" unless ($file = $list->getpart("newsletter/ficheiro")); + $subject="Ediçao XX" unless ($subject = $list->getpart("newsletter/subject-da-edicao")); + $sender="$listaddress" unless ($sender = $list->getpart("newsletter/sender")); + $tree="/edicaoXX/" unless ($tree = $list->getpart("newsletter/localizacao")); + $issue="" unless ($issue = $list->getpart("newsletter/edicao")); + + print " COMING SOON "; +} + +# --------------------------------------------------------------------------- + +sub ezmlmcgirc { + my($listno); + if(open(WWW, "<$EZMLM_CGI_RC")) { + while() { + last if (($listno) = m{(\d+)(\D)\d+\2$LIST_DIR/$Q::list\2}); + } + close WWW; + return "$EZMLM_CGI_URL/$listno" if(defined($listno)); + } return undef; + +} + +# --------------------------------------------------------------------------- + +sub pretty_names { + return undef unless($PRETTY_NAMES); + my (%pretty, %prettymem); + tie %pretty, "DB_File", "$LIST_DIR/$Q::list/webnames"; + %prettymem = %pretty; + untie %pretty; + + return \%prettymem; +} + +# ------------------------------------------------------------------------- +sub rmtree { + # A subroutine to recursively delete a directory (like rm -f). + # Based on the one in the perl cookbook :) + + use File::Find qw(finddepth); + File::Find::finddepth sub { + # assume that File::Find::name is secure since it only uses data we pass it + my($name) = $File::Find::name =~ m{^(.+)$}; + + if (!-l && -d _) { + rmdir($name) or warn "couldn't rmdir $name: $!"; + } else { + unlink($name) or warn "couldn't unlink $name: $!"; + } + }, @_; + 1; +} + +# ------------------------------------------------------------------------ + +BEGIN { + sub handle_errors { + my $msg = shift; + print << "EOM"; + +
+

A fatal error has occoured

+ Something you did caused this script to bail out. The error + message we got was

+ $msg

+ Please try what you were doing again, checking everything you entered.
+ If you still find yourself getting this error, please + contact the site administrator + quoting the error message above. +

+EOM + + } + set_message(\&handle_errors); +} + +# ------------------------------------------------------------------------ +# End of ezmlm-web.cgi v2.1 +# ------------------------------------------------------------------------ +__END__ + +=head1 NAME + +ezmlm-web - A web configuration interface to ezmlm mailing lists + +=head1 SYNOPSIS + +ezmlm-web [B<-c>] [B<-C> EFE] [B<-d> EFE] + +=head1 DESCRIPTION + +=over 4 + +=item B<-c> Disable list configuration + +=item B<-C> Specify an alternate configuration file given as F +If not specified, ezmlm-web checks first in the users home directory, then in +F and then the current directory + +=item B<-d> Specify an alternate directory where lists live. This is now +depreciated in favour of using a custom ezmlmwebrc, but is left for backward +compatibility. + +=back + +=head1 SUID WRAPPER + +C<#include stdio.h> + +C + C + C +C<}> + + +=head1 DOCUMENTATION/CONFIGURATION + + Please refer to the example ezmlmwebrc which is well commented, and + to the README file in this distribution. + +=head1 FILES + +F<~/.ezmlmwebrc> +F +F<./ezmlmwebrc> + +=head1 AUTHOR + + Guy Antony Halse + +=head1 BUGS + + None known yet. Please report bugs to the author. + +=head1 S + + ezmlm(5), ezmlm-cgi(1), Mail::Ezmlm(3) + + http://rucus.ru.ac.za/~guy/ezmlm/ + http://www.ezmlm.org/ + http://www.qmail.org/ + +--bg08WKrSYDhXBjb5 +Content-Type: text/plain; charset=iso-8859-1 +Content-Disposition: attachment; filename="ezmlmwebrc.PT" +Content-Transfer-Encoding: 8bit + +# $Id: ezmlmwebrc,v 1.5 2000/09/25 18:25:26 guy Exp $ +# Configuration file for ezmlm-web 2.1 +# =========================================================================== + +# This file is not just an ordinary configuration file - it contains valid +# perl statements that are executed just like any other perl script. When +# editing this file, be careful that it is still valid perl when you have +# finished (perl -w ezmlmwebrc ;-) + +# It is divided into to logical parts. The first part configures the way +# ezmlm-web runs, and the second changes the language, etc of ezmlm-web. You +# can not arbitarilly exclude any statement, since the script doesn't define +# any defaults of its own. You could, however, always split this file up and +# include the parts with +# +# require('/path/to/other/part'); + +# --------------------------------------------------------------------------- + +# Where do we store lists on this server ... Try "$HOME_DIR/lists". +# This directory will automatically be created if needed. +$LIST_DIR = "/servers/virtualdomains/lists.mydomain.com"; + +# Safe list deletion? +# 0 = move list to .list and the .qmails to deleted.qmail/. Recoverable :) +# 1 = allow user to delete list completely. No backup, therefore no recovery. +$UNSAFE_RM = 0; + +# Who is the alias user on this system (usually alias ;) +$ALIAS_USER = 'alias'; + +# Where do the qmail control files live on this system ... +$QMAIL_BASE = $Mail::Ezmlm::QMAIL_BASE . '/control'; + +# The url to our web interface - so we can use ezmlm-cgi if necessary +$EZMLM_CGI_URL = 'http://listadmin.mydomain.com/'; + +# Where our ezcgirc file lives (probably /etc/ezmlm/ezcgirc +$EZMLM_CGI_RC = '/etc/ezmlm/ezcgirc'; + +# Do we want to allow ``pretty'' names - ie more human readable ones +# This will slow ezmlm-web down a bit for large lists +$PRETTY_NAMES = 1; + +# Do we want to allow the users to be allowed to upload a file containing +# lists of email addresses to subscribe? +$FILE_UPLOAD = 1; + +# What switches to we want ezmlm-web to have on as default. The ezmlm-make +# defaults are aBDFGHIJKLMNOpQRSTUWX (small means enabled, CAPITALS mean +# disabled). The defaults below should be reasonable - I use them ;) +$DEFAULT_OPTIONS = 'aBDFGHiJkLMNOpQRSTUWx'; + +# Where do we find the nice little help icon - by default HELP_ICON_URL +# points to resources on http://rucus.ru.ac.za/. This will work, but we +# would appreciate it if you changed this to a local site. +$HELP_ICON_URL = 'http://mail-int.sl.pt/images/q.gif'; + +# Header for every page (.= concatinates) +$HTML_HEADER = '

Lists Admin - mydomain.com

'; + +$HTML_HEADER .= '

'; + +# Footer for every page (.= concatinates) +$HTML_FOOTER = '
'; +$HTML_FOOTER .= '
'; +$HTML_FOOTER .= 'ezmlm-web (v2.1) -- Contactar mydomain.com
'; + +# What colour do we want the background to be? +$HTML_BGCOLOR = '#000000'; + +# What colour do we want text? +$HTML_TEXT = '#0f0f0f'; + +# What color do we want links? +$HTML_LINK = '#3333ff'; + +# What color to we want visited links? +$HTML_VLINK = '#8888ff'; + +# What is the title of this document? +$HTML_TITLE = 'mydomain.com - List Admin'; + +# --------------------------------------------------------------------------- + +# The meanings of the various ezmlm-make command line switches. The default +# ones match the ezmlm-idx 0.4 default ezmlmrc ... Alter them to suit your +# own ezmlmrc. Removing options from this list makes them unavailable +# through ezmlm-web - this could be useful for things like -w + +%EZMLM_LABELS = ( +# option => ['Short Name', +# 'Long Help Description'], + + a => ['Arquivadas', + 'O sistema arquivará mensagens novas'], + b => ['Arquivo Bloqueado', + 'Apenas aos moderadores é permitido aceder ao arquivo'], +# c => config. This is implicity called, so is not defined here + d => ['Digest', + 'Constituir uma lista de "digest" das mensagens da lista'], +# e => edit. Also implicity called, so not defined here + f => ['Prefixo', + 'O subject das mensagens sera alterado com este prefixo'], + g => ['Arquivo Guardado', + 'Pedidos de acesso ao arquivo originados de SENDERs desconhecidos são rejeitados'], + h => ['Ajuda na Subscrição', + 'As subscrições não precisam de confirmação'], + i => ['Indexada', + 'Indexada para arquivo acessível via WWW'], + j => ['Saída Rápida', + 'As dessubscrições não necessitam de confirmação'], + k => ['Kill', + 'As mensagens originárias de endereços listados em dir/deny/ são rejeitadas'], + l => ['Lista de Subscritos', + 'Os administradores remotos podem requerer uma lista dos subscritos'], + m => ['Moderação das Mensagens', + 'Todas as mensagens recebidas são moderadas'], + n => ['Edição de Textos', + 'É permitida aos administradores remotos a edição de ficheiros em dir/text/'], + o => ['Rejeição de Outros', + 'Mensagens de endereços que não os dos moderadores serão rejeitadas'], + p => ['Publica', + 'A lista responderá a pedidos administrativos e a pedidos do arquivo'], + q => ['Endereço de Pedidos e Serviços', + 'Processar comandos enviados no subject para local-request@host'], + r => ['Administração Remota', + 'Permitir a administração remota da lista'], + s => ['Subscrição Moderada', + 'Subscrições para a lista principal e para a digest são moderadas'], + t => ['Trailer', + 'Adicionar um trailer a todas as mensagens enviadas'], + u => ['Apenas de Subscritos', + 'Mensagens originárias de remetentes desconhecidos são rejeitadas'], +# v => version. I doubt you will really need this ;-) + w => ['Remover Warn', + 'Remover as invocações do ezmlm-warn(1) da configuração da lista. Parte-se do princípio que o ezmlm-warn(1) será invocado de outra forma'], + x => ['Extra', + 'Remover certos mimetypes, etc'], +# y => not used +# z => not used + +# These all take an extra argument, which is the default value to use + + 0 => ['Sublista', + 'Fazer a lista uma sublista da lista mainlist@host', + 'mainlist@host'], +# 1 => not used +# 2 => not used + 3 => ['Do Endereço', + 'Substituir o header "From:" da mensagem por "From: fromarg"', + 'fromarg'], + 4 => ['Opções de Digest', + 'Switches para o ezmlm-tstdig(1)', + '-t24 -m30 -k64'], + 5 => ['Dono da Lista', + 'Endereço e-mail do dono da lista', + ''], + 6 => ['Base de dados SQL', + 'Dados para ligação á base de dados SQL. Necessita de suporte para SQL', + 'host:port:user:password:datab:table'], + 7 => ['Caminho para a Moderação de Mensagens', + 'Caminho para a base de dados dos moderadores das mensagens, se a lista tiver sido configurada para moderação de mensagens', + '/some/full/path'], + 8 => ['Caminho para a Moderação de Subscrições', + 'Caminho para a base de dados dos moderadores das subscrições, se a lista tiver sido configurada para moderação de subscrições', + '/some/full/path'], + 9 => ['Caminho para a Administração Remota', + 'Caminho para a base de dados dos administradores, se a lista tiver sido configurada para administração remota', + '/some/full/path'] + +); + +# This list defines most of the context sensitive help in ezmlm-web. What +# isn't defined here is the options, which are defined above ... You can +# alter these if you feel something else would make more sense to your users +# Just be careful of what can fit on a screen! + +%HELPER = ( + + # These should be self explainitory + addaddress => 'Poderá introduzir um endereço conforme o RFC822, incluindo a parte de comentário. Por exemplo Zacarias Albertino ', + addaddressfile => 'ou poderá introduzir o nome de um ficheiro de texto contendo múltiplos endereços RFC822, um por linha', + moderator => 'Moderadores: Controlam quem se pode subscrever ou enviar mail para uma lista', + deny => 'Deny: Uma lista de endereços que estão explicitamente impedidos de enviar mail para a lista', + allow => 'Allow: A list of address that are allowed to mail the list even if the configuration otherwise restricts it', + digest => 'Digest: Endereços que recebem o digest de todas as mensagens da lista', + webarch => 'Ver o arquivo web desta lista', + config => 'Alterar as configurações desta lista', + listname => 'Nome da lista. É também o nome do subdirectório que contém a lista', + listadd => 'Endereço de e-mail da lista. Por defeito vem da configuração do qmail. Apenas deverá ser alterada a parte local (antes da @)', + webusers => 'NB! Por enquanto quaisquer utilizadores especificados deverão existir. A criação de utilizadores será adicionada numa versão futura', + prefix => 'Texto a adicionar ao subject de todas as mensagens enviadas', + headerremove => 'Lista de headers a remover de todas as mensagens enviadas', + headeradd => 'Lista de headers a adicionar a todas as mensagens enviadas', + mimeremove => 'Qualquer mensagem cujo "Content-Type" coincida com um destes mime types será devolvida ao remetente', + allowedit => 'Lista (separada por vírgulas) dos utilizadores, ou ALL (todos os utilizadores válidos)', + domains => 'Aos dominios nesta lista é permitido enviar mail para a mailing list', + mysqlcreate => 'Isto permite criar as tabelas de MySQL necessárias se a configuração da lista acima assim o exigir', + edit_newsletter => 'Clique para editar e enviar a newsletter associada a esta lista', + newsletterhtml => 'Nome do ficheiro html que contém a newsletter', + newslettersubject => 'Subject da newsletter', + newslettersender => 'Sender da newsletter', + newslettertree => 'Localização em disco (ou ftp) do ficheiro que contém a newsletter', + newsletterissue => 'Número desta edição da newsletter', +); + +# This defines the captions of each of the buttons in ezmlm-web, and allows +# you to configure them for your own language or taste. Since these are used +# by the switching algorithm it is important that every button has a unique +# caption - ie we can't have two 'Edit' buttons doing different things. + +%BUTTON = ( + + # These MUST all be unique! + create => 'Criar', + createlist => 'Criar Lista', + edit => 'Editar', + delete => 'Remover', + deleteaddress => 'Remover Endereço', + addaddress => 'Adicionar Endereço', + moderators => 'Moderadores', + denylist => 'Lista "Deny"', + allowlist => 'Lista "Allow"', + digestsubscribers => 'Subscritores do "Digest"', + configuration => 'Configuração', + yes => 'Sim', + no => 'Não', + updateconfiguration => 'Actualizar a Configuração', + edittexts => 'Editar Textos', + editfile => 'Editar Ficheiro', + savefile => 'Guardar Ficheiro', + webarchive => 'Arquivo Web', + selectlist => 'Seleccionar Lista', + subscribers => 'Subscritos', + search => 'Procurar', + domains => 'Dominios', + cancel => 'Cancelar', + resetform => 'Reset do Form', + edit_newsletter => 'Editar Newsletter', + sendnewsletter => 'Enviar Newsletter' + +); + +# This defines the fixed text strings that are used in ezmlm-web. By editing +# these along with the button labels and help texts, you can convert ezmlm-web +# to another language :-) If anyone gets arround to doing complete templates +# for other languages I would appreciate a copy so that I can include it in +# future releases of ezmlm-web. + +%LANGUAGE = ( + nop => 'Acção por implementar', + chooselistinfo => "

  • Escolha a Lista da caixa à esquerda ou clique em [$BUTTON{'create'}].
  • Clique em [$BUTTON{'edit'}] para editar a Lista seleccionada.
  • Clique em [$BUTTON{'delete'}] para remover a Lista seleccionada.
", + confirmdelete => 'Confirme a remoção de', # list name + subscribersto => 'Subscritos na', # list name + subscribers => 'subscritos', + selected => 'seleccionados', + additionalparts => 'Configuração da Lista', + posting => 'Posting', + subscription => 'Subscrição', + remoteadmin => 'Administração Remota', + for => 'de', # as in; moderators for blahlist + createnew => 'Criar uma nova Lista', + listname => 'Nome da Lista', + listaddress => 'Endereço da Lista', + listoptions => 'Opções da Lista', + allowedtoedit => 'Utilizadores com acesso para edição desta Lista', + editconfiguration => 'Editar a configuração da Lista', + prefix => 'Prefixo para os subjects das mensagens', + headerremove => 'Headers a excluir de todas as mensagens enviadas', + headeradd => 'Headers a incluir em todas as mensagens enviadas', + mimeremove => 'Mime types a excluir de todas as mensagens enviadas', + edittextinfo => "A caixa à esquerda contém uma lista dos ficheiros disponíveis no directório
DIR/text. Estes ficheiros são enviados nas respostas a certos pedidos (via e-mail) dos utilizadores, ou como parte de todas as mensagens enviadas.

Para editar um ficheiro seleccione o seu nome na caixa, de seguida clique em [$BUTTON{'editfile'}].

Clique em [$BUTTON{'cancel'}] quando tiver terminado a edição.", + editingfile => 'A editar o ficheiro', + editfileinfo => 'ezmlm-manage
<#l#> O nome da Lista
<#A#> O endereço de subscrição
<#R#> O endereço de resposta para os subscritores

ezmlm-store
<#l#> O nome da Lista
<#A#> O endereço de aceitação
<#R#> O endereço de rejeição', + mysqlcreate => 'Criar as tabelas para a base de dados MySQL se necessário', + newsletterhtml => 'Conteúdo', + newslettersubject => 'Subject', + newslettersender => 'Sender', + newslettertree => 'Localização', + newsletterissue => 'Edição', + +); + +# === Configuration file ends === + +--bg08WKrSYDhXBjb5-- +