commit d1c44878e2ecd437b22257472f889e6522cae8bb Author: lars Date: Fri May 20 21:54:47 2005 +0000 subversion layout restructured diff --git a/ezmlm-web-2.1.tar.gz b/ezmlm-web-2.1.tar.gz new file mode 100644 index 0000000..3b220b3 Binary files /dev/null and b/ezmlm-web-2.1.tar.gz differ diff --git a/ezmlm-web-2.1/CHANGES b/ezmlm-web-2.1/CHANGES new file mode 100644 index 0000000..58b2a08 --- /dev/null +++ b/ezmlm-web-2.1/CHANGES @@ -0,0 +1,84 @@ +$Id: CHANGES,v 1.2 2000/09/25 17:54:06 guy Exp $ + +REVISION HISTORY - ezmlm-web.cgi +================================ + +Version 0.1 - 10/04/98 (Not Released) +* University Vac - I was bored and started to play. The first version just + let people play with the subscribers list. No moderators, no nothing. + +Version 0.2 - 13/04/98 (Not Released) +* Allow list creation +* Allowed users to edit moderators + +Version 0.3 - 15/04/98 +* Allow list deletion (for balin@moria.org) +* Made changes to allow it to run on RedHat 4.2 as well as FreeBSD 3.0 +* Fixed some minor bugs (cosmetic irritaions really) that people noticed +* Sorted subscribers list into alphabetical order. +* Added command line switch to change list directory (for nxsy@moria.org) +* Wrote some documentation ... + +Version 0.4 - 28/04/98 +* Fixed up virtual domain (inlocal) stuff as spotted by bryan@rucus +* Allowed the list directory to be automatically created if necessary. + +Version 0.5 - 12/05/98 (Not Released) +* More bug fixes. Mainly for mathew@graham. + +Version 1.0 - 01/08/98 +* Complete re-write to convert to perl5 and CGI.pm +* Removed a lot of dependancy on the OS. Use builtin functions instead :) +* Added support for ezmlm-idx +* Added a lot more command line option support (-adfgiklmnpqsrstux5) +* Added support for digests and digest subscribers +* Added support for blacklists +* Allowed users to edit the config of existing lists +* Allowed the user to edit headeradd and headerremove as well as mimeremove +* Allowed user to edit any of the files in DIR/text +* Revised interface to make it more user-friendly and ergonomic. +* Changed the background colour for Kether (clb@rucus) *gryn* +* Removed a big bug in the delete_list function that had gone unnoticed. + +Version 1.0.1 - 10/08/98 +* Fixed a bug in the way 1.0 re-configured virtual hosts (bryan@rucus) +* Made the script read the /var/qmail/control files instead of explicitly + setting variables (for david@summersoft) + +Version 1.0.2 - 28/08/98 +* Fixed the bug introduced in v1.0.1 :( (keith@rucus) +* Fixed the way we recreate config files (noticed by Glen Stewart) +* Made the script check return values of system calls properly +* Fixed some of the taint checking stuff ... reports less in the logs now. + +Version 1.0.3 - 03/10/98 +* Fixed the alias-alias-alias-list bug in inlocal (bryan@rucus) +* Added a bit of online help +* Fixed the & in list owner (bryan@rucus) +* Added multi-level access to lists (based on idea by Glen Stewart) + +Version 2.0 - 01/01/00 +* Rewrote most of the code to take advantage of Mail::Ezmlm +* Made the webuser file more functional (users can alter it) +* Now handles all current, and future command line options +* Changed the colours :) +* Added support for ezmlm-cgi web archives +* Made it -w and use strict clean +* Moved all user config to a separate file +* Fixed the way we worked out list config - now complete +* Allowed a user specific config over-ride ``ezmlmwebrc'' +* Allowed the printing of `nice' usernames (for Rhodes CS Dept) +* Took account of non-standard paths for moderators +* Removed all system() and `` calls from ezmlm-web.cgi +* Made `look and feel' virtually all user configurable +* Added a lot more context sensitive help +* Made ezmlm-web 99% language configurable - but no other templates yet :( +* Added support for creating databases + +Version 2.1 - 25/09/00 +* Fixed the multiple delete thing - finally! +* Fixed the '-' in username problem - The '-' in hostnames problem is fixed + in the new version of Mail::Ezmlm +* Fixed the '_' in list names problem +* Added support for file uploads of email addresses (multiple subscribe) +* Made error handling more friendly diff --git a/ezmlm-web-2.1/README b/ezmlm-web-2.1/README new file mode 100644 index 0000000..3ec4b1b --- /dev/null +++ b/ezmlm-web-2.1/README @@ -0,0 +1,323 @@ +$Id: README,v 1.2 2000/09/25 17:57:21 guy Exp $ + +================= +| ezmlm-web-2.1 | +================= + +Contents +======== + I. Copyright Stuff + II. Some Background + III. Requirements + IV. Files + V. Installation + VI. Notes + VII. Multi-level list access +VIII. Language Portability + IX. Bugs && Bug Reports + X. Acknowledgements + XI. Availability + + +I. Copyright Stuff - essentially the FreeBSD licence ... +================== +ezmlm-web - version 2.1 - 25/09/2000 + +Copyright (C) 1998, 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. + +II. Some Background +=================== +The need for ezmlm-web arose from the fact that we host many student +societies on our system. These societies usually have a virtual host for web +and email, which is administered by a computer rep from the society. These +computer reps often have little or no knowledge of Unix and so we needed a +user friendly system that would let the create and maintain mailing lists +(such as members@foo.soc.ru.ac.za, committee@foo.soc.ru.ac.za, etc). + +Since I am never keen to re-invent the wheel, I had a look at Steve Peterson's +script (http://virtation.com/qmail/ml-sub), which allows people to subscribe +and unsubscribe from mailing lists using a form->email gateway. This is fine +for putting on a web page saying "here come and join our mailing list", but +doesn't really allow you to administrate a list. + +Security of mailing lists was a concern, as we really didn't want +unauthorised people to be able to alter some users list. Ezmlm-web itself +implements no security checks (apart from un-tainting input) and so relies +on the web server to do this (re-inventing the wheel again :). We use an +Apache webserver, so one can control access to a directory using a .htaccess +file or in the access.conf file. ApacheWeek have a good article on doing +this at http://www.apacheweek.com/features/userauth. I also give examples +later in this document. + +This version of ezmlm-web (2.0) is based to a large extent on previous +versions that I have developed. It has however been totally re-written to +make use of the Mail::Ezmlm perl module I wrote. At the same time it was +updated and extended to include the new features of ezmlm-idx. It includes +many new features that have been suggested to me over the last few months, +and hopefully is now useful to a much larger group of people. + +III. Requirements +================= +This version of ezmlm-web requires the following; + +* qmail v1.03 +* ezmlm v0.53 (idx v0.40) +* Perl v5.004 and the following modules; + + Mail::Ezmlm v0.03 + + Mail::Address v1.15 + + CGI v2.6 + + CGI::Carp v1.06 + + DB_File v1.65 + + Getopt::Std v4.1 + + File::Find v? + + File::Copy v2.02 + +The version number indicates the version of the module that ezmlm-web was +developed with. Earlier versions may work, but then they haven't been +tested. Have a look on http://www.CPAN.org/, http://www.qmail.org/, and +http://www.ezmlm.org/ for anything you are missing. + +IV. Files +========= +In this distribution you should find 8 files; + +README This file. Provides some background information, notes on + installation, etc. Not needed to run ezmlm-web. + +CHANGES The change history. Not needed to run ezmlm-web + +TODO This file is a list of things I intend doing in future + versions of ezmlm-web. That is if there are any future + versions :) Not needed to run ezmlm-web. + +ezmlm-web.cgi The ezmlm-web script proper. This program requires that + you have perl5 installed on your machine and that your web + server is capable of running CGI scripts. + +index.c A C wrapper to allow ezmlm-web.cgi to run suid. Not + strictly necessary if your setup allows perl scripts to + run suid, but I prefer using wrappers anyway. It needs to + be edited and compiled to suit your system. Not needed to + run ezmlm-web. + +htaccess.sample A sample Apache .htaccess file for controlling access to + the mailing lists. If you use another web server, you will + have to work this bit out for yourself. + +webusers.sample A sample webusers file for multi-level access control. + +V. Installation +=============== +1. Copy ezmlm-web.cgi to some publically readable directory. It does not + have to be in a path accessible to your web server, but any user with a + mailing list must be able to run it (Check the read and execute rights + on both the file and directory). We put our copy in + /usr/local/bin ... + +3. Edit the ezmlmwebrc file and alter the variables at the top to suit + your particular system. In particular, you will probably have to change + the $ENV{'PATH'} variable. Be particularly careful about what you set + as the path. Too much is a security risk and too little will cause the + script to malfunction. Version 2.0 requires that the following programs + be accessible in your path; mv, rm + + Also be careful about the $LIST_DIR variable. This script assumes that + all users store their mailing lists in the same sub directory of the + home directory (eg ~/lists). You can override this for an individual + user by recompiling the C wrapper to call ezmlm-web.cgi with a -d + option. + + Other configurable options are documented in the ezmlmwebrc file + itself. I have tried to keep the amount of information that you need to + supply to a minimum and also make reasonable guesses about default + values. + +4. Edit the index.c file and change the path to the path of your copy + of ezmlm-web.cgi. Then compile this file. You can do this by issuing + the command; gcc -o index.cgi index.c + +5. For every user/virtual host that needs to manage mailing lists, you + need to create a SUID (user not root!!) copy of index.cgi (see + chmod(1) for details). These need to reside somewhere accessible by + the web server. I suggest that you put them in a sub directory (see + about security) of each user/virtual host's home directory (eg + /home/luser/public_html/ezmlm for Apache on Redhat). + + The copies don't actually have to be called index.cgi, but it is nice + for web servers that can resolve a cgi script as an index page (see the + srm.conf file in Apache). It is important to make sure that whichever + directory you choose to put them can i: Execute CGI Scripts and ii: Be + access controlled (here I mean both web and user access) by some method + (eg .htaccess, access.conf for Apache). + +6. Install some method of securing access to the page. The following + information is applicable to Apache web servers ... Detailed + information on user authentication can be obtained from the Apache + documentation (http://www.apache.org) and ApacheWeek + (http://www.apacheweek.com/features/userauth) + +6.1 Ensure that your Apache setup will allow .htaccess file to control + access in the directory that contains. This is controlled by the + AllowOverride tag in access.conf. (Also ensure you have the + necessary Apache modules installed) + +6.2 Create a htpasswd file. This is done using the htpasswd command that + comes with Apache. Its command line syntax is; + htpasswd [-c] passwordfile username + + You need to put the passwordfile somewhere that is not accessible by + people through the web, and create an entry for each user you want + to have access ... See the ApacheWeek article for more details. + +6.3 Create a .htaccess file in the directory that contains index.cgi. + Note that using Apache's built in access control, you can only control + access to directories, not individual files, hence the need for a + sub-directory in step 5. + + The format of the .htaccess file should be along the lines of this; + + AuthName EZ Mailing List Manager + AuthType Basic + AuthUserFile /path/to/passwordfile + require valid-user # or require user username + + Again, see the ApacheWeek article for details. + +7. Test the installation through the web. You should be asked for a + username and password (supplied in 6.2) and then be presented with a + screen entitled EZ Mailing List Manger. You can then try to create and + edit mailing lists ... Have Fun :) + +VI. Notes +========= +* There is a function to delete mailing lists, but I really don't like the + idea. The only reason I put it in is that bvi@rucus asked for it. + If you set $UNSAFE_RD = 0 (the default) in the config section, the + ezmlm-web won't actually delete the list. In this case it moves the + to . and all the associated .qmail files to a sub-directory called + deleted.qmail/ (In the users home directory. This is by far a safer way + (since you can restore lists) and therefore I recommend it. + +* The HTML interface has been tested using Nutscrape, Internet Exploder, and + Lynx. If anyone uses anything else and has problems, please let me know. + +* I suggest that you make use of custom ezmlmwebrc files rather than using + the -d command line switches - it makes fault diagnosis easier ... + +* Please see the section on languages below. + +VII. Multi-Level Access +======================= +Ezmlm-web has a multi-level access system. This depends on a file called +webusers being present in $LIST_DIR. If the file is not present, then any +valid user has access to all lists. If, however, this file exists a number +of constraints come into place. + +- The webusers file is scanned for either the list name (case insensitive) or + an ALL (case sensitive) entry. +- The list entry (or ALL) is scanned for the current user (as set in + $REMOTE_USER) or an ALL entry. +- If any valid match is made, then the user is allowed to edit the list. + Otherwise the user is politely told to go away ;-) + +If list creation is allowed and the webusers file exists, then the person who +creates the list is the default owner. As of yet there is no way to add users +through the web interface, but I intend to do this eventually. + +The format of a webusers file is as follows; + +list1: user1, user2, user3 +ALL: user1, user2 +list2: ALL + +ie; listname colon (:) and a comma (,) separated list of users. Spaces are +ignored but each list must appear on a new line. + +Once this file exists, the ezmlm-web script will allow the list users to +configure their access lists along with any other options. + +Oh, and BTW, list creation through the web can now be disabled. The way to do +this is to compile the wrapper calling ezmlm-web.cgi with a -c switch. See the +example index.c file for more details. + +VIII. Language Portablity +========================= +One of the great new features of version 2.0 is that it is essentially +language independant (okay, not quite, but is 99% of the way there). Most of +the fixed strings, help, etc is defined in the RC file and thus can be +altered to suite a particular locale, language or even your own taste. + +If anyone gets round to writing full templates for languages I would +appreciate it if you would do two things; + +Firstly, make them public and announce them on the ezmlm@lists.cr.yp.to +mailing list so that others may benefit. + +Secondly, please mail me a copy (guy-ezmlm@rucus.ru.ac.za) so that I may use +them in any future releases of ezmlm-web. + + +IX. Bugs && Bug Reports +======================= +I don't know of any bugs, but then this is a rewrite and a first release. It +has been tested reasonably well, but not exhaustively. I know it works on +FreeBSD 4.0-STABLE, FreeBSD 3.4-RELEASE, RedHat 5.1 and Redhat 6.0 all using +an Apache web server, but I would be interested to know whether it works on +other OSs and with other web servers. This version is far less dependent on +the OS than previous versions so I don't see any reason why it shouldn't. + +Please mail bug reports and comments to guy-ezmlm@rucus.ru.ac.za + +X. Acknowledgements +=================== +* Keith Burdis (keith@rucus.ru.ac.za) - For constantly bugging me and + ensuring that I actually got round to writing some code :) +* Bryan Kilian (bryan@rucus.ru.ac.za) and the administrators of the + Litestep mailing list - For helping beta test and putting up with me + pestering them. +* Several societies at Rhodes. For switching to my web interface and so + unknowingly helping to beta test it. +* Barry Irwin (bvi@moria.org) - For trusting me and moving the Grahamstown + Foundation over to qmail and ezmlm - yet another beta tester :-) +* David Summers (david@summersoft.fay.ar.us) - For some ideas. And for + offering to make up an RPM version. I hope the offer still exists for + version 2.0 :-) +* Glen Stewart (glen_stewart@associate.com) - For a multitude of ideas. +* Fred Lindberg (lindberg@id.wustl.edu) for his useful posts to the + mailing list, suggestions, help, etc +* Galen Johnson (gjohnson@totalsports.net) - For some ideas on bugfixes. + +XI. Availability +================= +The latest version of ezmlm-web will always be available on; +ftp://rucus.ru.ac.za/pub/mail/ezmlm/ + +More information on ezmlm-web and developments to ezmlm-web can be found at; +http://rucus.ru.ac.za/~guy/ezmlm/ diff --git a/ezmlm-web-2.1/TODO b/ezmlm-web-2.1/TODO new file mode 100644 index 0000000..75d3540 --- /dev/null +++ b/ezmlm-web-2.1/TODO @@ -0,0 +1,8 @@ +$Id: TODO,v 1.3 2000/09/25 19:58:02 guy Exp $ + +TODO - ezmlm-web 2.1 + +- More Documentation +- Maybe allowing user specific overides on the -c option. +- Some nice install method. But then I use FreeBSD and ported it + so that might just count as my nice install method :) diff --git a/ezmlm-web-2.1/UPGRADING b/ezmlm-web-2.1/UPGRADING new file mode 100644 index 0000000..03e20fc --- /dev/null +++ b/ezmlm-web-2.1/UPGRADING @@ -0,0 +1,18 @@ +$Id: UPGRADING,v 1.1 2000/09/25 19:24:20 guy Exp $ + +UPGRADING ezmlm-web 2.0 to ezmlm-web 2.1 + +There are no major changes that need to be made in order to upgrade. All +that is necessary is to add two new lines to your ezmlmwebrc ... In the top +section of the file add + +$FILE_UPLOAD = 1; + +and in the %HELPER section, you need to add + +addaddressfile => 'or you may enter the filename of a plain text file containing multiple RFC822 email addresses, one per line', + +(or just copy the new ezmlmwebrc :) + +Have a look for these two lines in the new ezmlmwebrc included in this +distribution if you are unsure of how/where to put these. diff --git a/ezmlm-web-2.1/ezmlm-web.cgi b/ezmlm-web-2.1/ezmlm-web.cgi new file mode 100755 index 0000000..0072489 --- /dev/null +++ b/ezmlm-web-2.1/ezmlm-web.cgi @@ -0,0 +1,1084 @@ +#!/usr/bin/perl -T +#=========================================================================== +# 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 $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; + } 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; + + } elsif ($Q::action eq "[$BUTTON{'addaddress'}]") { # Add a subscriber ... + &add_address($list); + &display_list; + + } elsif ($Q::action eq "[$BUTTON{'moderators'}]") { # Edit the moderators ... + &part_subscribers('mod'); + + } 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; + + } 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; + } + +} 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; + + } elsif ($Q::action eq "[$BUTTON{'edittexts'}]") { # Edit DIR/text ... + &list_text; + + } else { # Cancel - Return to list editing screen ... + &display_list; + } + +} 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; + +} 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)); + 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); + + # 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; + + # 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=>\@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 $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 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/ diff --git a/ezmlm-web-2.1/ezmlmwebrc b/ezmlm-web-2.1/ezmlmwebrc new file mode 100644 index 0000000..7c37330 --- /dev/null +++ b/ezmlm-web-2.1/ezmlmwebrc @@ -0,0 +1,268 @@ +# $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 = "$HOME_DIR/lists"; + +# 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://some.server.that.has/cgi-bin/ezmlm-cgi'; + +# 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://rucus.ru.ac.za/icons/small/unknown.gif'; + +# Header for every page (.= concatinates) +$HTML_HEADER = '
E Z Mailing List Manager

'; +$HTML_HEADER .= '
'; + +# Footer for every page (.= concatinates) +$HTML_FOOTER = '
'; +$HTML_FOOTER .= '
'; +$HTML_FOOTER .= 'ezmlm-web (v2.1) A web interface to ezmlm
'; + +# What colour do we want the background to be? +$HTML_BGCOLOR = '#000080'; + +# What colour do we want text? +$HTML_TEXT = '#000000'; + +# 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 = 'E Z Mailing List Manager'; + +# --------------------------------------------------------------------------- + +# 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 => ['Archived', + 'Ezmlm will archive new messages'], + b => ['Block archive', + 'Only moderators are allowed to access the archive'], +# c => config. This is implicity called, so is not defined here + d => ['Digest', + 'Set up a digest list to disseminate digest of the list messages'], +# e => edit. Also implicity called, so not defined here + f => ['Prefix', + 'Outgoing subject will be prefixed with the list name'], + g => ['Guard Archive', + 'Archive access requests from unrecognized SENDERs will be rejected'], + h => ['Help subscription', + 'Subscriptions do not require confirmation'], + i => ['Indexed', + 'Indexed for WWW archive access'], + j => ['Jump off', + 'Unsubscribe does not require confirmation'], + k => ['Kill', + 'Posts from addresses in dir/deny/ are rejected'], + l => ['Subscriber List', + 'Remote administrators can request a subscriber list'], + m => ['Message Moderation', + 'All incoming messages are moderated'], + n => ['Text Editing', + 'Allow remote administrators to edit files in dir/text/'], + o => ['Others rejected', + 'Posts from addresses other than moderators are rejected'], + p => ['Public', + 'List will respond to administrative requests and archive retrieval'], + q => ['Service Request Address', + 'Process commands sent in the subject to local-request@host'], + r => ['Remote Admin', + 'Enable remote adminstration of the list'], + s => ['Subscription Moderation', + 'Subscriptions to the main list and digest will be moderated'], + t => ['Trailer', + 'Add a trailer to outgoing messages'], + u => ['User Posts Only', + 'Posts from unrecognized SENDER addresses will be rejected'], +# v => version. I doubt you will really need this ;-) + w => ['Remove Warn', + 'Remove the ezmlm-warn(1) invocations from the list setup. It is assumed that ezmlm-warn(1) is run by other means'], + x => ['Extra', + 'Strip certain mimetypes, etc'], +# y => not used +# z => not used + +# These all take an extra argument, which is the default value to use + + 0 => ['Sublist', + 'Make the list a sublist of list mainlist@host', + 'mainlist@host'], +# 1 => not used +# 2 => not used + 3 => ['From Address', + 'Replace the "From:" header of the message with "From: fromarg"', + 'fromarg'], + 4 => ['Digest Options', + 'Switches for ezmlm-tstdig(1)', + '-t24 -m30 -k64'], + 5 => ['List Owner', + 'The email address of the list owner', + ''], + 6 => ['SQL Database', + 'SQL database connect information. Requires SQL support', + 'host:port:user:password:datab:table'], + 7 => ['Message Moderation Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/some/full/path'], + 8 => ['Subscription Moderation Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/some/full/path'], + 9 => ['Remote Admin Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/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 => 'You may enter any RFC822 compliant email address here, including the comment part. For example; J Random User ', + addaddressfile => 'or you may enter the filename of a plain text file containing multiple RFC822 email addresses, one per line', + moderator => 'Moderators: people who control who may subscribe or post to a list', + deny => 'Deny: A list of addresses that are _never_ allowed to mail the list', + allow => 'Allow: A list of address that are allowed to mail the list even if the configuration otherwise restricts it', + digest => 'Digest: People who will recieve a digest of all messages on the list', + webarch => 'View the web based archive of this list', + config => 'This lets you alter the way the list is set up', + listname => 'This is the name of the list as displayed on the Select Lists screen. It is also the name of the subdirectory that contains the list', + listadd => 'This is the email address of the list. Note that the defaults come from your qmail config. You should just update the local part (before the @)', + webusers => 'NB! At this stage, any users specified here must exist. User creation may be added in future versions', + prefix => 'Text to add to the subject line of all outgoing messages', + headerremove => 'This is a list of headers to remove from all outgoing mail', + headeradd => 'This is a list of headers to add to all outging mail', + mimeremove => 'All messages whose Content-Type matches these mime types will be bounced back to sender', + allowedit => 'Comma separated list of usernames, or ALL (all valid users)', + mysqlcreate => 'This will create the necessary MySQL tables if the list configuration above requires it' + +); + +# 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 => 'Create', + createlist => 'Create List', + edit => 'Edit', + delete => 'Delete', + deleteaddress => 'Delete Address', + addaddress => 'Add Address', + moderators => 'Moderators', + denylist => 'Deny List', + allowlist => 'Allow List', + digestsubscribers => 'Digest Subscribers', + configuration => 'Configuration', + yes => 'Yes', + no => 'No', + updateconfiguration => 'Update Configuration', + edittexts => 'Edit Texts', + editfile => 'Edit File', + savefile => 'Save File', + webarchive => 'Web Archive', + selectlist => 'Select List', + subscribers => 'Subscribers', + cancel => 'Cancel', + resetform => 'Reset Form', + +); + +# 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 => 'Action not yet implemented', + chooselistinfo => "

  • Choose a mailing list from the selection box or click on [$BUTTON{'create'}].
  • Click on the [$BUTTON{'edit'}] button if you want to edit the selected list.
  • Click on the [$BUTTON{'delete'}] button if you want to delete the selected list.
", + confirmdelete => 'Confirm deletion of', # list name + subscribersto => 'Subscribers to', # list name + subscribers => 'subscribers', + additionalparts => 'Additional list parts', + posting => 'Posting', + subscription => 'Subscription', + remoteadmin => 'Remote Admin', + for => 'for', # as in; moderators for blahlist + createnew => 'Create a New List', + listname => 'List Name', + listaddress => 'List Address', + listoptions => 'List Options', + allowedtoedit => 'Users allowed to edit this list', + editconfiguration => 'Edit the List Configuration', + prefix => 'Subject prefex for outgoing messages', + headerremove => 'Headers to strip from all outgoing mail', + headeradd => 'Headers to add to all outgoing mail', + mimeremove => 'Mime types to strip from all outgoing mail', + edittextinfo => "The box on the left contains a list of files available in the
DIR/text directory. These files are sent out in response to specfic user request, or as part of all outgoing messages

To edit a file, select its name from the box. Then click on the [$BUTTON{'editfile'}] button.

Press [$BUTTON{'cancel'}] when you have finished editing.", + editingfile => 'Editing File', + editfileinfo => 'ezmlm-manage
<#l#> The list name
<#A#> The subscription address
<#R#> The address a subscriber must reply to

ezmlm-store
<#l#> The list name
<#A#> The acceptance address
<#R#> The rejection address', + mysqlcreate => 'Create the MySQL database tables if necessary', + +); + +# === Configuration file ends === diff --git a/ezmlm-web-2.1/htaccess.sample b/ezmlm-web-2.1/htaccess.sample new file mode 100644 index 0000000..b381a14 --- /dev/null +++ b/ezmlm-web-2.1/htaccess.sample @@ -0,0 +1,9 @@ +#$Id: htaccess.sample,v 1.1 2000/01/29 11:35:40 guy Exp $ +# +#order deny,allow +#deny from all +#allow from .ru.ac.za +AuthName "EZ Mailing List Manager +AuthType Basic +AuthUserFile /etc/ezmlm/.htusers +require valid-user diff --git a/ezmlm-web-2.1/index.c b/ezmlm-web-2.1/index.c new file mode 100644 index 0000000..3ba9cc1 --- /dev/null +++ b/ezmlm-web-2.1/index.c @@ -0,0 +1,25 @@ +/* $Id: index.c,v 1.2 2000/09/25 18:14:12 guy Exp $ */ + +#include + +/* C wrapper to allow ezmlm-web.cgi to run suid */ +/* Copyright (C) 1999/2000, Guy Antony Halse, All Rights Reserved */ +/* See the README file in this distribution for copyright information */ + +int main(void) { + /* Change this path to wherever you decided to put ezmlm-web.cgi */ + execv("/usr/local/bin/ezmlm-web.cgi"); + + /* Note that you could also use the following to allow a specific user + to store their mailing lists in a different directory defined by + /tmp/ezmlm-web-demo ... This over-rides the default . */ + + /* Look at the exec(3) man page if you don't understand how the arguments + list below works */ + + /* + char *switches[] = { "ezmlm-web.cgi", "-d", "/tmp/ezmlm-web-demo", NULL }; + execv("/usr/local/bin/ezmlm-web.cgi", switches); + */ + +} diff --git a/ezmlm-web-2.1/webusers.sample b/ezmlm-web-2.1/webusers.sample new file mode 100644 index 0000000..f383eb2 --- /dev/null +++ b/ezmlm-web-2.1/webusers.sample @@ -0,0 +1,4 @@ +comm: guy, arb +users: arb +members: ALL +ALL: root diff --git a/ezmlm-web-2.2.tar.gz b/ezmlm-web-2.2.tar.gz new file mode 100644 index 0000000..24341b9 Binary files /dev/null and b/ezmlm-web-2.2.tar.gz differ diff --git a/ezmlm-web-2.2/CHANGES b/ezmlm-web-2.2/CHANGES new file mode 100644 index 0000000..5de2a93 --- /dev/null +++ b/ezmlm-web-2.2/CHANGES @@ -0,0 +1,91 @@ +$Id: CHANGES,v 1.2 2000/09/25 17:54:06 guy Exp $ + +REVISION HISTORY - ezmlm-web.cgi +================================ + +Version 0.1 - 10/04/98 (Not Released) +* University Vac - I was bored and started to play. The first version just + let people play with the subscribers list. No moderators, no nothing. + +Version 0.2 - 13/04/98 (Not Released) +* Allow list creation +* Allowed users to edit moderators + +Version 0.3 - 15/04/98 +* Allow list deletion (for balin@moria.org) +* Made changes to allow it to run on RedHat 4.2 as well as FreeBSD 3.0 +* Fixed some minor bugs (cosmetic irritaions really) that people noticed +* Sorted subscribers list into alphabetical order. +* Added command line switch to change list directory (for nxsy@moria.org) +* Wrote some documentation ... + +Version 0.4 - 28/04/98 +* Fixed up virtual domain (inlocal) stuff as spotted by bryan@rucus +* Allowed the list directory to be automatically created if necessary. + +Version 0.5 - 12/05/98 (Not Released) +* More bug fixes. Mainly for mathew@graham. + +Version 1.0 - 01/08/98 +* Complete re-write to convert to perl5 and CGI.pm +* Removed a lot of dependancy on the OS. Use builtin functions instead :) +* Added support for ezmlm-idx +* Added a lot more command line option support (-adfgiklmnpqsrstux5) +* Added support for digests and digest subscribers +* Added support for blacklists +* Allowed users to edit the config of existing lists +* Allowed the user to edit headeradd and headerremove as well as mimeremove +* Allowed user to edit any of the files in DIR/text +* Revised interface to make it more user-friendly and ergonomic. +* Changed the background colour for Kether (clb@rucus) *gryn* +* Removed a big bug in the delete_list function that had gone unnoticed. + +Version 1.0.1 - 10/08/98 +* Fixed a bug in the way 1.0 re-configured virtual hosts (bryan@rucus) +* Made the script read the /var/qmail/control files instead of explicitly + setting variables (for david@summersoft) + +Version 1.0.2 - 28/08/98 +* Fixed the bug introduced in v1.0.1 :( (keith@rucus) +* Fixed the way we recreate config files (noticed by Glen Stewart) +* Made the script check return values of system calls properly +* Fixed some of the taint checking stuff ... reports less in the logs now. + +Version 1.0.3 - 03/10/98 +* Fixed the alias-alias-alias-list bug in inlocal (bryan@rucus) +* Added a bit of online help +* Fixed the & in list owner (bryan@rucus) +* Added multi-level access to lists (based on idea by Glen Stewart) + +Version 2.0 - 01/01/00 +* Rewrote most of the code to take advantage of Mail::Ezmlm +* Made the webuser file more functional (users can alter it) +* Now handles all current, and future command line options +* Changed the colours :) +* Added support for ezmlm-cgi web archives +* Made it -w and use strict clean +* Moved all user config to a separate file +* Fixed the way we worked out list config - now complete +* Allowed a user specific config over-ride ``ezmlmwebrc'' +* Allowed the printing of `nice' usernames (for Rhodes CS Dept) +* Took account of non-standard paths for moderators +* Removed all system() and `` calls from ezmlm-web.cgi +* Made `look and feel' virtually all user configurable +* Added a lot more context sensitive help +* Made ezmlm-web 99% language configurable - but no other templates yet :( +* Added support for creating databases + +Version 2.1 - 25/09/00 +* Fixed the multiple delete thing - finally! +* Fixed the '-' in username problem - The '-' in hostnames problem is fixed + in the new version of Mail::Ezmlm +* Fixed the '_' in list names problem +* Added support for file uploads of email addresses (multiple subscribe) +* Made error handling more friendly + +Version 2.2 - 26/01/02005 +* German translation of the web interface - more translations can be added easily +* changed "ALT"-tags to "TITLE" - most browsers will display the tooltip texts now +* fixed security problems (permissions were not thoroughly check) +* user-based permission for creating lists (can be set in webusersrc) +* the location of the webusers file is now an option in ezmlmwebrc diff --git a/ezmlm-web-2.2/INSTALL b/ezmlm-web-2.2/INSTALL new file mode 100644 index 0000000..11f2651 --- /dev/null +++ b/ezmlm-web-2.2/INSTALL @@ -0,0 +1,97 @@ +The following notes will guide you through the installation of ezmlm-web: + +0. IMPORTANT: you need the perl module Mail::Ezmlm and others to use + ezmlm-web! The file README contains the list of necessary modules. + +1. Get ezmlm-web and extract the archive: + tar xzf ezmlm-web-2.2.tar.gz + +2. Copy ezmlm-web.cgi to some publically readable directory. It does not + have to be in a path accessible to your web server, but any user with a + mailing list must be able to run it (Check the read and execute rights + on both the file and directory). We put our copy in "/usr/local/bin". + + At the top of ezmlm-web.gi you can will probably have to change the + $ENV{'PATH'} variable. Be careful about what you set as the path. Too + much is a security risk and too little will cause the script to + malfunction. Version 2.0 requires that the following programs be + accessible in your path: mv, rm + +3. Edit the ezmlmwebrc file and alter the variables to suit your + particular system. + + Be careful about the $LIST_DIR variable. This script assumes that all + users store their mailing lists in the same sub directory of the home + directory (eg ~/lists). You can override this for an individual user + by recompiling the C wrapper to call ezmlm-web.cgi with a -d option. + + Other configurable options are documented in the ezmlmwebrc file + itself. I have tried to keep the amount of information that you need to + supply to a minimum and also make reasonable guesses about default + values. + + Finally, copy the ezmlmwebrc file and the "lang" directory to one of + the following places: + - /etc/ezmlm + - the home directory of the user that runs ezmlm-web.cgi + - the directory, that contains your ezmlm-web.cgi file + +4. Edit the index.c file and change the path to the path of your copy + of ezmlm-web.cgi. Then compile this file. You can do this by issuing + the command; gcc -o index.cgi index.c + +5. For every user/virtual host that needs to manage mailing lists, you + need to create a SUID (user not root!!) copy of index.cgi (see + chmod(1) for details). These need to reside somewhere accessible by + the web server. I suggest that you put them in a sub directory (see + about security) of each user/virtual host's home directory (eg + /home/luser/public_html/ezmlm for Apache on Redhat). + + The copies don't actually have to be called index.cgi, but it is nice + for web servers that can resolve a cgi script as an index page (see the + srm.conf file in Apache). It is important to make sure that whichever + directory you choose to put them can i: Execute CGI Scripts and ii: Be + access controlled (here I mean both web and user access) by some method + (eg .htaccess, access.conf for Apache). + +6. Install some method of securing access to the page. The following + information is applicable to Apache web servers ... Detailed + information on user authentication can be obtained from the Apache + documentation (http://www.apache.org) and ApacheWeek + (http://www.apacheweek.com/features/userauth) + +6.1 Ensure that your Apache setup will allow .htaccess file to control + access in the directory that contains. This is controlled by the + AllowOverride tag in access.conf. (Also ensure you have the + necessary Apache modules installed) + +6.2 Create a htpasswd file. This is done using the htpasswd command that + comes with Apache. Its command line syntax is; + htpasswd [-c] passwordfile username + + You need to put the passwordfile somewhere that is not accessible by + people through the web, and create an entry for each user you want + to have access ... See the ApacheWeek article for more details. + +6.3 Create a .htaccess file in the directory that contains index.cgi. + Note that using Apache's built in access control, you can only control + access to directories, not individual files, hence the need for a + sub-directory in step 5. + + The format of the .htaccess file should be along the lines of this; + + AuthName EZ Mailing List Manager + AuthType Basic + AuthUserFile /path/to/passwordfile + require valid-user # or require user username + + Again, see the ApacheWeek article for details. + +7. Test the installation through the web. You should be asked for a + username and password (supplied in 6.2) and then be presented with a + screen entitled EZ Mailing List Manger. You can then try to create and + edit mailing lists ... Have Fun :) + +If you have any problems, then you can: +- take a look at https://systemausfall.org/toolforge/ezmlm-web +- send me an email: ezmlm-web@sumpfralle.de diff --git a/ezmlm-web-2.2/README b/ezmlm-web-2.2/README new file mode 100644 index 0000000..89fbfa7 --- /dev/null +++ b/ezmlm-web-2.2/README @@ -0,0 +1,270 @@ +$Id: README,v 1.2 2000/09/25 17:57:21 guy Exp $ + +================= +| ezmlm-web-2.2 | +================= + +If you only want to know how to install ezmlm-web, then you should +read INSTALL. + +Contents +======== + I. Copyright Stuff + II. Some Background + III. Requirements + IV. Files + V. Notes + VI. Multi-level list access + VII. Language Portability +VIII. Bugs && Bug Reports + XI. Acknowledgements + X. Availability + + +I. Copyright Stuff - essentially the FreeBSD licence ... +================== +ezmlm-web - version 2.2 - 26/01/02005 + +Copyright (C) 1998, 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. + +II. Some Background +=================== +The need for ezmlm-web arose from the fact that we host many student +societies on our system. These societies usually have a virtual host for web +and email, which is administered by a computer rep from the society. These +computer reps often have little or no knowledge of Unix and so we needed a +user friendly system that would let the create and maintain mailing lists +(such as members@foo.soc.ru.ac.za, committee@foo.soc.ru.ac.za, etc). + +Since I am never keen to re-invent the wheel, I had a look at Steve Peterson's +script (http://virtation.com/qmail/ml-sub), which allows people to subscribe +and unsubscribe from mailing lists using a form->email gateway. This is fine +for putting on a web page saying "here come and join our mailing list", but +doesn't really allow you to administrate a list. + +Security of mailing lists was a concern, as we really didn't want +unauthorised people to be able to alter some users list. Ezmlm-web itself +implements no security checks (apart from un-tainting input) and so relies +on the web server to do this (re-inventing the wheel again :). We use an +Apache webserver, so one can control access to a directory using a .htaccess +file or in the access.conf file. ApacheWeek have a good article on doing +this at http://www.apacheweek.com/features/userauth. I also give examples +later in this document. + +This version of ezmlm-web is based to a large extent on previous +versions that I have developed. It has however been totally re-written to +make use of the Mail::Ezmlm perl module I wrote. At the same time it was +updated and extended to include the new features of ezmlm-idx. It includes +many new features that have been suggested to me over the last few months, +and hopefully is now useful to a much larger group of people. + +Since 02005 ezmlm-web is maintained by Lars Kruse (ezmlm-web@sumpfralle.de). +Only minor improvements had to be implemented to keep the already fully +functional ezmlm-web up to date. + +III. Requirements +================= +This version of ezmlm-web requires the following; + +* qmail v1.03 +* ezmlm v0.53 (idx v0.40) +* Perl v5.004 and the following modules; + + Mail::Ezmlm v0.03 + + Mail::Address v1.15 + + CGI v2.6 + + CGI::Carp v1.06 + + DB_File v1.65 + + Getopt::Std v4.1 + + File::Find v? + + File::Copy v2.02 + +The version number indicates the version of the module that ezmlm-web was +developed with. Earlier versions may work, but then they haven't been +tested. Have a look on http://www.CPAN.org/, http://www.qmail.org/, and +http://www.ezmlm.org/ for anything you are missing. + +IV. Files +========= +In this distribution you should find 8 files; + +README This file. Provides some background information. + Not needed to run ezmlm-web. + +INSTALL Notes on installation. Not needed to run ezmlm-web. + +CHANGES The change history. Not needed to run ezmlm-web + +TODO This file is a list of things I intend doing in future + versions of ezmlm-web. Not needed to run ezmlm-web. + +ezmlm-web.cgi The ezmlm-web script proper. This program requires that + you have perl5 installed on your machine and that your web + server is capable of running CGI scripts. + +index.c A C wrapper to allow ezmlm-web.cgi to run suid. Not + strictly necessary if your setup allows perl scripts to + run suid, but I prefer using wrappers anyway. It needs to + be edited and compiled to suit your system. Not needed to + run ezmlm-web. + +ezmlmwebrc This is the configuration file for ezmlm-web. All options + are explained in this example file. You will need this + file to run ezmlm-web. + +htaccess.sample A sample Apache .htaccess file for controlling access to + the mailing lists. If you use another web server, you will + have to work this bit out for yourself. + +webusers.sample A sample webusers file for multi-level access control. + +The directory "lang" contains the language files. You will need at least the +one, that you have choosen in "ezmlmwebrc" by the option "HTML_LANGUAGE". + +V. Notes +========= +* There is a function to delete mailing lists, but I really don't like the + idea. The only reason I put it in is that bvi@rucus asked for it. + If you set $UNSAFE_RD = 0 (the default) in the config section, the + ezmlm-web won't actually delete the list. In this case it moves the + to . and all the associated .qmail files to a sub-directory called + deleted.qmail/ (In the users home directory. This is by far a safer way + (since you can restore lists) and therefore I recommend it. + +* The HTML interface has been tested using Nutscrape, Internet Exploder, and + Lynx. If anyone uses anything else and has problems, please let me know. + +* I suggest that you make use of custom ezmlmwebrc files rather than using + the -d command line switches - it makes fault diagnosis easier ... + +* Please see the section on languages below. + +VI. Multi-Level Access +======================= +Ezmlm-web has a multi-level access system. This depends on a file called +webusers being present in $LIST_DIR. If the file is not present, then any +valid user has access to all lists. If, however, this file exists a number +of constraints come into place. + +- The webusers file is scanned for either the list name (case insensitive) or + an ALL (case sensitive) entry. +- The list entry (or ALL) is scanned for the current user (as set in + $REMOTE_USER) or an ALL entry. +- If any valid match is made, then the user is allowed to edit the list. + Otherwise the user is politely told to go away ;-) + +If list creation is allowed and the webusers file exists, then the person who +creates the list is the default owner. As of yet there is no way to create users +through the web interface, but I intend to do this eventually. + +The format of a webusers file is as follows; + +list1: user1, user2, user3 +ALL: user1, user2 +list2: ALL + +ie; listname colon (:) and a comma (,) separated list of users. Spaces are +ignored but each list must appear on a new line. + +Once this file exists, the ezmlm-web script will allow the list users to +configure their access lists along with any other options. + +You can permit some users to create lists by adding a line similar to the +following to your webusers file: + +ALLOW_CREATE: user2, user3 + +If there is no line starting with "ALLOW_CREATE:" in the webusers file, then +no one will be allowed to create lists. This behaviour is new for ezmlm-web +since version 2.2. To stay compatible to old installations, the commandline +option "-c" for ezmlm-web.cgi will still allow everyone to create lists. The +use of this option is deprecated, since the line "ALLOW_CREATE: ALL" provides +the same effect in a cleaner way. + +VII. Language Portablity +========================= +One of the great new features of version 2.0 is that it is essentially +language independant (okay, not quite, but is 99% of the way there). Most of +the fixed strings, help, etc is defined in the files of lang directory. +Of course you can change them or create a new translation. + +The language can be selected in ezmlmwebrc with the "HTML_LANGUAGE" option. + +If anyone gets round to writing full templates for languages I would +appreciate it if you would do two things; + +Firstly, make them public and announce them on the ezmlm@lists.cr.yp.to +mailing list so that others may benefit. + +Secondly, please mail me a copy (ezmlm-web@sumpfralle.de) so that I may use +them in any future releases of ezmlm-web. + + +VIII. Bugs && Bug Reports +======================= +I don't know of any bugs, but then this is a rewrite and a first release. It +has been tested reasonably well, but not exhaustively. I know it works on +FreeBSD 4.0-STABLE, FreeBSD 3.4-RELEASE, RedHat 5.1 and Redhat 6.0 all using +an Apache web server, but I would be interested to know whether it works on +other OSs and with other web servers. This version is far less dependent on +the OS than previous versions so I don't see any reason why it shouldn't. + +Please mail bug reports and comments to ezmlm-web@sumpfralle.de. + +IX. Acknowledgements +=================== +* Guy Antony Halse (guy-ezmlm@rucus.ru.ac.za) - He created ezmlm-web, + maintained it till 02005 and wrote nearly every line of code! +* Keith Burdis (keith@rucus.ru.ac.za) - For constantly bugging me and + ensuring that I actually got round to writing some code :) +* Bryan Kilian (bryan@rucus.ru.ac.za) and the administrators of the + Litestep mailing list - For helping beta test and putting up with me + pestering them. +* Several societies at Rhodes. For switching to my web interface and so + unknowingly helping to beta test it. +* Barry Irwin (bvi@moria.org) - For trusting me and moving the Grahamstown + Foundation over to qmail and ezmlm - yet another beta tester :-) +* David Summers (david@summersoft.fay.ar.us) - For some ideas. And for + offering to make up an RPM version. I hope the offer still exists for + version 2.0 :-) +* Glen Stewart (glen_stewart@associate.com) - For a multitude of ideas. +* Fred Lindberg (lindberg@id.wustl.edu) for his useful posts to the + mailing list, suggestions, help, etc +* Galen Johnson (gjohnson@totalsports.net) - For some ideas on bugfixes. + +X. Availability +================= +More information on ezmlm-web and developments to ezmlm-web can be found at: +https://systemausfall.org/toolforge/ezmlm-web + +The website of Guy Antony Halse (the author of ezmlm-web) is still at: +http://rucus.ru.ac.za/~guy/ezmlm/ + +The old ftp-archive of ezmlm-web is still available on: +ftp://rucus.ru.ac.za/pub/mail/ezmlm/ diff --git a/ezmlm-web-2.2/TODO b/ezmlm-web-2.2/TODO new file mode 100644 index 0000000..a09d11f --- /dev/null +++ b/ezmlm-web-2.2/TODO @@ -0,0 +1,8 @@ +$Id: TODO,v 1.3 2000/09/25 19:58:02 guy Exp $ + +TODO - ezmlm-web 2.2 + +- More Documentation +- Some nice install method. But then I use FreeBSD and ported it + so that might just count as my nice install method :) +- Option for a css-stylesheet diff --git a/ezmlm-web-2.2/UPGRADING b/ezmlm-web-2.2/UPGRADING new file mode 100644 index 0000000..7abe744 --- /dev/null +++ b/ezmlm-web-2.2/UPGRADING @@ -0,0 +1,39 @@ +$Id: UPGRADING,v 1.1 2000/09/25 19:24:20 guy Exp $ + +UPGRADING ezmlm-web 2.1 to ezmlm-web 2.2 + +1) Creating of new lists is now controlled by a line in the webusers file instead +of a commandline switch for ezmlm-web.cgi. + +necessary changes: + - optional: remove switch "-c" when calling ezmlm-web.cgi (take a look at index.c) + - optional: add a line like "ALLOW_CREATE: john, myra" to the webusers file + +2) The location of the webusers file is now defined in ezmlmwebrc. (default: $LIST_DIR/webusers) + +necessary changes: + - optional: add a line like "$WEBUSERS_FILE = /home/ml/webusers" to ezmlmwebrc + +3) A german translation is available. + + - optional: include "lang/de.pm" in ezmlmwebrc (there you can also remove the english definitions) + or copy the new ezmlmwebrc :) + +------------------------------------------------------------------------------ + +UPGRADING ezmlm-web 2.0 to ezmlm-web 2.1 + +There are no major changes that need to be made in order to upgrade. All +that is necessary is to add two new lines to your ezmlmwebrc ... In the top +section of the file add + +$FILE_UPLOAD = 1; + +and in the %HELPER section, you need to add + +addaddressfile => 'or you may enter the filename of a plain text file containing multiple RFC822 email addresses, one per line', + +(or just copy the new ezmlmwebrc :) + +Have a look for these two lines in the new ezmlmwebrc included in this +distribution if you are unsure of how/where to put these. diff --git a/ezmlm-web-2.2/ezmlm-web.cgi b/ezmlm-web-2.2/ezmlm-web.cgi new file mode 100755 index 0000000..aaf1a8f --- /dev/null +++ b/ezmlm-web-2.2/ezmlm-web.cgi @@ -0,0 +1,1131 @@ +#!/usr/bin/perl -T +#=========================================================================== +# ezmlm-web.cgi - version 2.2 - 26/01/02005 +# $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 $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 $WEBUSERS_FILE]; + +# 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.\/]+)$/); +} + +# If WEBUSERS_FILE is not defined in ezmlmwebrc (as before version 2.2), then use former default value for compatibility +if (!defined($WEBUSERS_FILE)) { + $WEBUSERS_FILE = $LIST_DIR . '/webusers' +} + +# 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', '-Content-Type'=>'text/html; charset=utf-8'); +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; + +# check permissions +&check_permission_for_action == 0 || die 'Error: you are not allowed to do this!'; + +# 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 perform 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; + } 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; + + } elsif ($Q::action eq "[$BUTTON{'addaddress'}]") { # Add a subscriber ... + &add_address($list); + &display_list; + + } elsif ($Q::action eq "[$BUTTON{'moderators'}]") { # Edit the moderators ... + &part_subscribers('mod'); + + } 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; + + } 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; + } + +} 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; + + } elsif ($Q::action eq "[$BUTTON{'edittexts'}]") { # Edit DIR/text ... + &list_text; + + } else { # Cancel - Return to list editing screen ... + &display_list; + } + +} 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; + +} 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") { + $lists[$#lists + 1] = $files[$i] if (&webauth($files[$i]) == 0); + } + } + + # 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 ((&webauth_create_allowed == 0) || (!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 $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); + + # 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; + + # 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=>\@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'), '
'; + print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), '
' 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'}]"), ' ' if ($list->ismodpost || $list->ismodsub || $list->isremote); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'denylist'}]"), ' ' if ($list->isdeny); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'allowlist'}]"), ' ' if ($list->isallow); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'digestsubscribers'}]"), ' ' if ($list->isdigest); + print '

'; + print $q->submit(-name=>'action', -value=>"[$BUTTON{'webarchive'}]"), ' ' if(&ezmlmcgirc); + print $q->submit(-name=>'action', -value=>"[$BUTTON{'configuration'}]"), '   '; + 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 check_permission_for_action { + # test if the user is allowed to modify the choosen list or to create an new one + # the user would still be allowed to fill out the create-form (however he got there), + # but the final creation is omitted + + my $ret; + if ($Q::state eq 'create') { + $ret = &webauth_create_allowed(); + } elsif (defined($Q::list)) { + $ret = &webauth($Q::list); + } else { + $ret = 0; + } + return $ret; + +} + +# ------------------------------------------------------------------------ + +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 .= '' if ($postpath); + $moderated .= '' if ($subpath); + $moderated .= " [$LANGUAGE{'subscription'}]" if($list->ismodsub); + $moderated .= '' if ($subpath); + $moderated .= '' if ($remotepath); + $moderated .= " [$LANGUAGE{'remoteadmin'}]" if($list->isremote); + $moderated .= '' 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'), '
'; + print $q->filefield(-name=>'addfile', -size=>20, -maxlength=>100), '
' 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'), '

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

'; + + 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 ' '; + + } + + print '

', $LANGUAGE{'allowedtoedit'}, ': ', + $q->textfield(-name=>'webusers', -value=>$ENV{'REMOTE_USER'}||'ALL', -size=>'30'), ' ', + '
', $HELPER{'allowedit'}, '' + if(-e "$WEBUSERS_FILE"); + + 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(); + } + } + + &update_webusers(); + + 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), ' ' if defined($prefix); + print '

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

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

', $LANGUAGE{'mimeremove'}, ':
', $q->textarea(-name=>'mimeremove', -default=>$mimeremove, -rows=>5, -columns=>70) if defined($mimeremove); + + if(open(WEBUSER, "<$WEBUSERS_FILE")) { + 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{'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')); + + &update_webusers(); +} + +# ------------------------------------------------------------------------ + +sub update_webusers { + # replace existing webusers-line or add a new one + + if($Q::webusers) { + # Back up web users file + open(TMP, ">/tmp/ezmlm-web.$$"); + open(WU, "<$WEBUSERS_FILE"); + while() { print TMP; } + close TMP; close WU; + + open(TMP, "$WEBUSERS_FILE"); + 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 { + + # Check if webusers file exists - if not, then access is granted + return 0 if (! -e "$WEBUSERS_FILE"); + + # Read authentication level from webusers file. Format of this file is + # somewhat similar to the unix groups file + my($listname) = @_; + open (USERS, "<$WEBUSERS_FILE") || die "Unable to read webusers file ($WEBUSERS_FILE): $!"; + while() { + if (/^($listname|ALL)\:/i) { + if (/(\:\s*|,\s+)((?:$ENV{'REMOTE_USER'})|(?:ALL))\s*(,|$)/) { + close USERS; return 0; + } + } + } + close USERS; + return 1; +} + +# --------------------------------------------------------------------------- + +sub webauth_create_allowed { + + # Check if webusers file exists - if not, then access is granted + return 0 if (! -e "$WEBUSERS_FILE"); + + # Read create-permission from webusers file. + # the special listname "ALLOW_CREATE" controls, who is allowed to do it + open (USERS, "<$WEBUSERS_FILE") || die "Unable to read webusers file ($WEBUSERS_FILE): $!"; + while() { + if (/^ALLOW_CREATE:/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 ''; + 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 ''; + print ''; + print $q->textfield(-name=>"$i-value", -value=>$1||$EZMLM_LABELS{$i}[2], -size=>30); + print '
'; + +} + +# --------------------------------------------------------------------------- + +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.2 +# ------------------------------------------------------------------------ +__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> 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) + + https://systemausfall.org/toolforge/ezmlm-web + http://rucus.ru.ac.za/~guy/ezmlm/ + http://www.ezmlm.org/ + http://www.qmail.org/ diff --git a/ezmlm-web-2.2/ezmlmwebrc b/ezmlm-web-2.2/ezmlmwebrc new file mode 100644 index 0000000..301394f --- /dev/null +++ b/ezmlm-web-2.2/ezmlmwebrc @@ -0,0 +1,85 @@ +# $Id: ezmlmwebrc,v 1.5 2000/09/25 18:25:26 guy Exp $ +# Configuration file for ezmlm-web 2.2 +# =========================================================================== + +# 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 ;-) + +# --------------------------------------------------------------------------- + +# Where do we store lists on this server ... Try "$HOME_DIR/lists". +# This directory will automatically be created if needed. +$LIST_DIR = "$HOME_DIR/lists"; + +# Where is the webusers file for access-permissions +# defaults to "$LIST_DIR/webusers" +$WEBUSERS_FILE = "$LIST_DIR/webusers"; + +# 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://some.server.that.has/cgi-bin/ezmlm-cgi'; + +# 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://rucus.ru.ac.za/icons/small/unknown.gif'; + +# Header for every page (.= concatinates) +$HTML_HEADER = '
E Z Mailing List Manager

'; +$HTML_HEADER .= '
'; + +# Footer for every page (.= concatinates) +$HTML_FOOTER = '
'; +$HTML_FOOTER .= '
'; +$HTML_FOOTER .= 'ezmlm-web (v2.2) A web interface to ezmlm
'; + +# What colour do we want the background to be? +$HTML_BGCOLOR = '#000080'; + +# What colour do we want text? +$HTML_TEXT = '#000000'; + +# 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 = 'E Z Mailing List Manager'; + +# choose a language (en|de) +$HTML_LANGUAGE = 'en'; + +# --------------------------------------------------------------------------- +# include language-specific definitions +require('./lang/' . $HTML_LANGUAGE . '.pm'); + diff --git a/ezmlm-web-2.2/htaccess.sample b/ezmlm-web-2.2/htaccess.sample new file mode 100644 index 0000000..b381a14 --- /dev/null +++ b/ezmlm-web-2.2/htaccess.sample @@ -0,0 +1,9 @@ +#$Id: htaccess.sample,v 1.1 2000/01/29 11:35:40 guy Exp $ +# +#order deny,allow +#deny from all +#allow from .ru.ac.za +AuthName "EZ Mailing List Manager +AuthType Basic +AuthUserFile /etc/ezmlm/.htusers +require valid-user diff --git a/ezmlm-web-2.2/index.c b/ezmlm-web-2.2/index.c new file mode 100644 index 0000000..3ba9cc1 --- /dev/null +++ b/ezmlm-web-2.2/index.c @@ -0,0 +1,25 @@ +/* $Id: index.c,v 1.2 2000/09/25 18:14:12 guy Exp $ */ + +#include + +/* C wrapper to allow ezmlm-web.cgi to run suid */ +/* Copyright (C) 1999/2000, Guy Antony Halse, All Rights Reserved */ +/* See the README file in this distribution for copyright information */ + +int main(void) { + /* Change this path to wherever you decided to put ezmlm-web.cgi */ + execv("/usr/local/bin/ezmlm-web.cgi"); + + /* Note that you could also use the following to allow a specific user + to store their mailing lists in a different directory defined by + /tmp/ezmlm-web-demo ... This over-rides the default . */ + + /* Look at the exec(3) man page if you don't understand how the arguments + list below works */ + + /* + char *switches[] = { "ezmlm-web.cgi", "-d", "/tmp/ezmlm-web-demo", NULL }; + execv("/usr/local/bin/ezmlm-web.cgi", switches); + */ + +} diff --git a/ezmlm-web-2.2/lang/de.pm b/ezmlm-web-2.2/lang/de.pm new file mode 100644 index 0000000..468900f --- /dev/null +++ b/ezmlm-web-2.2/lang/de.pm @@ -0,0 +1,187 @@ +# language-specific definitions for ezmlm-web +# in english + +# 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 => ['archivieren', + 'Ezmlm wird neue Nachrichten zum Archiv hinzufügen'], + b => ['Archiv nur für ModeratorInnen', + 'Nur ModeratorInnen haben Zugriff zum Archiv'], +# c => config. This is implicity called, so is not defined here + d => ['Zusammenfassungen', + 'Erstelle eine Mailing-Liste, an die regelmäßige Zusammenfassungen versandt werden'], +# e => edit. Also implicity called, so not defined here + f => ['Listenname als Präfix in Betreff einfügen', + 'In die versandten Mails wird in der Betreff-Zeile ein Präfix eingefügt'], + g => ['Archiv nur für Mitglieder', + 'Nur TeilnehmerInnen der Liste erhalten Zugriff zum Archiv'], + h => ['abonnieren ohne Bestätigung', + 'Das Abonnieren der Liste erfordert keine Bestätigung durch die neue AbonnentIn'], + i => ['Web-Index erstellen', + 'Den Zugriff auf das Archiv per Webinterface erlauben'], + j => ['abmelden ohne Bestätigung', + 'Das Abbestellen der Liste erfordert keine Bestätigung durch die ehemalige AbonnentIn'], + k => ['Beachte Ausschlussliste', + 'Einsendungen von Abonnenten, die inm deny-Verzeichnis enthalten sind, werden abgelehnt'], + l => ['Abonnenten-Auflistung für AdministratorInnen', + 'Die AdministratorInnen können eine Liste aller AbonnentInnen anfordern'], + m => ['Moderation aktivieren', + 'Alle eingehenden Nachrichten müssen durch eine ModeratorIn bestätigt werden'], + n => ['Anpassung der Textbausteine erlauben', + 'Administratoren dürfen die Standard-Textbausteine im Unterverzeichnis text/ verändern'], + o => ['Nur ModeratorInnen dürfen einsenden', + 'Nur eingehende Nachrichten von den ModeratorInnen werden akzeptiert'], + p => ['Öffentlich', + 'Die öffentliche Einschreibung und Archiv-Anforderung ist erlaubt'], + q => ['Verarbeite Anforderungen', + 'Mails an liste-request@domain werden verarbeitet'], + r => ['Administration per Mail erlauben', + 'Die Verwaltung der Liste durch Mails der AdministratorInnen ist erlaubt'], + s => ['Abonnierung durch ModeratorIn bestätigen', + 'Die Einschreibungen in die Liste und die Zusammenfassungs-Liste werden moderiert'], + t => ['Infotext an Mails anhängen', + 'An alle ausgehenden Mails wird ein Anhang angefügt'], + u => ['Nur Abonnenten dürfen einsenden', + 'Einsendungen von nicht-eingeschriebenen Mail-Adressen werden abgewiesen'], +# v => version. I doubt you will really need this ;-) + w => ['Warnung deaktivieren', + 'Entferne den Aufruf von ezmlm-warn aus der Listen-Konfiguration - es wird angenommen, dass ezmlm-warn auf einem anderem Wege gestartet wird'], + x => ['Filtere Anhänge und Kopfzeilen', + 'Mails mit den angegebenen Anhangs-Typen werden abgewiesen - die angegebenen Kopfzeilen werden aus den ausgehenden Mails entfernt'], +# y => not used +# z => not used + +# These all take an extra argument, which is the default value to use + + 0 => ['Unterlisten', + 'Diese Liste soll eine Unterliste einer anderen Hauptliste sein', + 'hauptliste@domain'], +# 1 => not used +# 2 => not used + 3 => ['Absender', + 'Ersetze den Absender der ausgehenden Mails durch diese Adresse', + 'Absender'], + 4 => ['Zusammenfassungseinstellungen', + 'Einstellungen for ezmlm-tstdig (nach "t" Stunden oder "m" Nachrichten oder "k" Kilobyte', + '-t24 -m30 -k64'], + 5 => ['Adresse des Verantwortlichen der Liste', + 'Mail-Adresse des Listen-Eigentümers', + 'name@domain.org'], + 6 => ['SQL-Datenbank', + 'SQL-Datenbank-Zugangsinformationen (erfordert SQL-Unterstützung)', + 'host:port:user:password:datab:table'], + 7 => ['Listen-Moderations-Verzeichnis', + 'Falls die Liste moderiert wird, ist der vollständige Verzeichnispfad zur Moderationsdatenbank erforderlich', + '/absoluter/pfad/zur/moderations/datenbank'], + 8 => ['Einschreibungs-Moderations-Verzeichnis', + 'Falls die Einschreibung in die Liste moderiert wird, ist der vollständige Verzeichnispfad zur Einschreibungs-Moderationsdatenbank erforderlich', + '/absoluter/pfad/zur/abonnenten/moderations/datenbank'], + 9 => ['Administrations-Verzeichnis', + 'Falls die Liste per Mail administriert wird, ist der vollständige Verzeichnispfad zur Administrationsdatenbank erforderlich', + '/absoluter/pfad/zur/administrations/datenbank'], + +); + +# 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 => 'Eine Mail-Adresse - auch in der Form \'Max Meier \'', + addaddressfile => 'alternativ ist auch eine Datei mit je einer Adresse pro Zeile möglich', + moderator => 'ModeratorInnen kontrollen, welche Mails weitegeleitet und welche AbonnentInnen akzeptiert werden', + deny => 'Ausschluss: die Mail-Adressen, die NIE an die Liste schreiben dürfen', + allow => 'Zulassung: die Mail-Adressen, die immer an die Liste schreiben dürfen', + digest => 'Zusammenfassung: diese Leute werden regeläßige Zusammenfassungen der Mailingliste erhalten', + webarch => 'Gehe zum Web-Archiv der Mailingliste', + config => 'Einstellungen zur Mailingliste', + listname => 'Dies ist der eindeutige Name der Mailingliste', + listadd => 'Die Adresse der Mailingliste - nur der lokale Teil kann geändert werden', + webusers => 'unfertig: derzeit können Listen-Administratoren nur manuell festgelegt werden', + prefix => 'Präfix der Betreffzeile', + headerremove => 'Diese Kopfzeilen werden aus den ausgehenden Mails entfernt', + headeradd => 'Diese Kopfzeilen werden zu jeder ausgehenden Mail hinzugefügt', + mimeremove => 'Alle Mails, die die genannten Anhangs-Typen beinhalten, werden abgewiesen', + allowedit => 'Komma-getrennte Liste von (existierenden) Nutzern oder ALL', + mysqlcreate => 'Anlegen der konfigurierten MySQL-Datenbank' + +); + +# 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 => 'Anlegen', + createlist => 'Liste anlegen', + edit => 'Bearbeiten', + delete => 'Entfernen', + deleteaddress => 'Entferne Adresse', + addaddress => 'Füge Adresse hinzu', + moderators => 'ModeratorInnen', + denylist => 'Ausschlussliste', + allowlist => 'Zulassungsliste', + digestsubscribers => 'Abonnenten der Zusammenfassungen', + configuration => 'Konfiguration', + yes => 'Ja', + no => 'Nein', + updateconfiguration => 'Speichere Konfiguration', + edittexts => 'Bearbeite Texte', + editfile => 'Bearbeite Datei', + savefile => 'Speichere Datei', + webarchive => 'Web-Archiv', + selectlist => 'Listenauswahl', + subscribers => 'AbonnentInnen', + cancel => 'Abbruch', + resetform => 'Reset', + +); + +# 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 => 'Diese Funktionalität ist noch nicht umgesetzt worden', + chooselistinfo => "

  • Markiere eine Liste in der Auswahlbox oder klicke auf [$BUTTON{'create'}].
  • Klicke auf den [$BUTTON{'edit'}]-Schalter, falls du die markierte Liste bearbeiten möchtest.
  • Klicke auf den [$BUTTON{'delete'}]-Schalter, falls du die markierte Liste löschen möchtest.
", + confirmdelete => 'Bestätige die Löschung von ', # list name + subscribersto => 'Abonnenten von', # list name + subscribers => 'Abonnenten', + additionalparts => 'Weitere Listen-Bestandteile', + posting => 'Einsendungen', + subscription => 'Einschreibung', + remoteadmin => 'Entfernte AdministratorIn', + for => 'für', # as in; moderators for blahlist + createnew => 'Lege eine neue Liste an', + listname => 'Name der Liste', + listaddress => 'Adresse der Liste', + listoptions => 'Einstellungen der Liste', + allowedtoedit => 'Nutzer, die diese Liste bearbeiten dürfen', + editconfiguration => 'Einstellungen ändern', + prefix => 'Präfix der Betreff-Zeile ausgehender Nachrichten', + headerremove => 'zu entfernende Kopfzeilen', + headeradd => 'einzufügende Kopfzeilen', + mimeremove => 'abzuweisende Anhangs-Typen', + edittextinfo => "Das Auswahlfeld links enthält die Dateien des
Verzeichnisses DIR/text/. Diese Dateien werden als Antwort auf spezifische Nutzer-Anfragen oder als Teil aller ausgehenden Nachrichten versandt.

Um diese Dateien zu verändern, wähle ihren Namen im Auswahlfeld an. Anschlißend klicke auf den [$BUTTON{'editfile'}] Schalter.

Betätige [$BUTTON{'cancel'}] um die Veränderung abzubrechen.", + editingfile => 'Bearbeite Datei', + editfileinfo => 'ezmlm-manage
<#l#> Der Name der Liste
<#A#> Die Anmeldungs-Adresse
<#R#> Die Bestätigungs-Adresse

ezmlm-store
<#l#> Der Name der Liste
<#A#> Die Zusage-Adresse
<#R#> Die Ablehungs-Adresse', + mysqlcreate => 'Lege die MySQL-Datenbank an, falls erforderlich', + +); + +# === Configuration file ends === diff --git a/ezmlm-web-2.2/lang/en.pm b/ezmlm-web-2.2/lang/en.pm new file mode 100644 index 0000000..25bd2b1 --- /dev/null +++ b/ezmlm-web-2.2/lang/en.pm @@ -0,0 +1,187 @@ +# language-specific definitions for ezmlm-web +# in english + +# 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 => ['Archived', + 'Ezmlm will archive new messages'], + b => ['Block archive', + 'Only moderators are allowed to access the archive'], +# c => config. This is implicity called, so is not defined here + d => ['Digest', + 'Set up a digest list to disseminate digest of the list messages'], +# e => edit. Also implicity called, so not defined here + f => ['Prefix', + 'Outgoing subject will be prefixed with the list name'], + g => ['Guard Archive', + 'Archive access requests from unrecognized SENDERs will be rejected'], + h => ['Help subscription', + 'Subscriptions do not require confirmation'], + i => ['Indexed', + 'Indexed for WWW archive access'], + j => ['Jump off', + 'Unsubscribe does not require confirmation'], + k => ['Kill', + 'Posts from addresses in dir/deny/ are rejected'], + l => ['Subscriber List', + 'Remote administrators can request a subscriber list'], + m => ['Message Moderation', + 'All incoming messages are moderated'], + n => ['Text Editing', + 'Allow remote administrators to edit files in dir/text/'], + o => ['Others rejected', + 'Posts from addresses other than moderators are rejected'], + p => ['Public', + 'List will respond to administrative requests and archive retrieval'], + q => ['Service Request Address', + 'Process commands sent in the subject to local-request@host'], + r => ['Remote Admin', + 'Enable remote adminstration of the list'], + s => ['Subscription Moderation', + 'Subscriptions to the main list and digest will be moderated'], + t => ['Trailer', + 'Add a trailer to outgoing messages'], + u => ['User Posts Only', + 'Posts from unrecognized SENDER addresses will be rejected'], +# v => version. I doubt you will really need this ;-) + w => ['Remove Warn', + 'Remove the ezmlm-warn(1) invocations from the list setup. It is assumed that ezmlm-warn(1) is run by other means'], + x => ['Extra', + 'Strip certain mimetypes, etc'], +# y => not used +# z => not used + +# These all take an extra argument, which is the default value to use + + 0 => ['Sublist', + 'Make the list a sublist of list mainlist@host', + 'mainlist@host'], +# 1 => not used +# 2 => not used + 3 => ['From Address', + 'Replace the "From:" header of the message with "From: fromarg"', + 'fromarg'], + 4 => ['Digest Options', + 'Switches for ezmlm-tstdig(1)', + '-t24 -m30 -k64'], + 5 => ['List Owner', + 'The email address of the list owner', + ''], + 6 => ['SQL Database', + 'SQL database connect information. Requires SQL support', + 'host:port:user:password:datab:table'], + 7 => ['Message Moderation Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/some/full/path'], + 8 => ['Subscription Moderation Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/some/full/path'], + 9 => ['Remote Admin Path', + 'Make /path the path to the database for message moderators, if the list is set up for message moderation', + '/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 => 'You may enter any RFC822 compliant email address here, including the comment part. For example; J Random User ', + addaddressfile => 'or you may enter the filename of a plain text file containing multiple RFC822 email addresses, one per line', + moderator => 'Moderators: people who control who may subscribe or post to a list', + deny => 'Deny: A list of addresses that are _never_ allowed to mail the list', + allow => 'Allow: A list of address that are allowed to mail the list even if the configuration otherwise restricts it', + digest => 'Digest: People who will recieve a digest of all messages on the list', + webarch => 'View the web based archive of this list', + config => 'This lets you alter the way the list is set up', + listname => 'This is the name of the list as displayed on the Select Lists screen. It is also the name of the subdirectory that contains the list', + listadd => 'This is the email address of the list. Note that the defaults come from your qmail config. You should just update the local part (before the @)', + webusers => 'NB! At this stage, any users specified here must exist. User creation may be added in future versions', + prefix => 'Text to add to the subject line of all outgoing messages', + headerremove => 'This is a list of headers to remove from all outgoing mail', + headeradd => 'This is a list of headers to add to all outging mail', + mimeremove => 'All messages whose Content-Type matches these mime types will be bounced back to sender', + allowedit => 'Comma separated list of usernames, or ALL (all valid users)', + mysqlcreate => 'This will create the necessary MySQL tables if the list configuration above requires it' + +); + +# 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 => 'Create', + createlist => 'Create List', + edit => 'Edit', + delete => 'Delete', + deleteaddress => 'Delete Address', + addaddress => 'Add Address', + moderators => 'Moderators', + denylist => 'Deny List', + allowlist => 'Allow List', + digestsubscribers => 'Digest Subscribers', + configuration => 'Configuration', + yes => 'Yes', + no => 'No', + updateconfiguration => 'Update Configuration', + edittexts => 'Edit Texts', + editfile => 'Edit File', + savefile => 'Save File', + webarchive => 'Web Archive', + selectlist => 'Select List', + subscribers => 'Subscribers', + cancel => 'Cancel', + resetform => 'Reset Form', + +); + +# 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 => 'Action not yet implemented', + chooselistinfo => "

  • Choose a mailing list from the selection box or click on [$BUTTON{'create'}].
  • Click on the [$BUTTON{'edit'}] button if you want to edit the selected list.
  • Click on the [$BUTTON{'delete'}] button if you want to delete the selected list.
", + confirmdelete => 'Confirm deletion of', # list name + subscribersto => 'Subscribers to', # list name + subscribers => 'subscribers', + additionalparts => 'Additional list parts', + posting => 'Posting', + subscription => 'Subscription', + remoteadmin => 'Remote Admin', + for => 'for', # as in; moderators for blahlist + createnew => 'Create a New List', + listname => 'List Name', + listaddress => 'List Address', + listoptions => 'List Options', + allowedtoedit => 'Users allowed to edit this list', + editconfiguration => 'Edit the List Configuration', + prefix => 'Subject prefex for outgoing messages', + headerremove => 'Headers to strip from all outgoing mail', + headeradd => 'Headers to add to all outgoing mail', + mimeremove => 'Mime types to strip from all outgoing mail', + edittextinfo => "The box on the left contains a list of files available in the
DIR/text directory. These files are sent out in response to specfic user request, or as part of all outgoing messages

To edit a file, select its name from the box. Then click on the [$BUTTON{'editfile'}] button.

Press [$BUTTON{'cancel'}] when you have finished editing.", + editingfile => 'Editing File', + editfileinfo => 'ezmlm-manage
<#l#> The list name
<#A#> The subscription address
<#R#> The address a subscriber must reply to

ezmlm-store
<#l#> The list name
<#A#> The acceptance address
<#R#> The rejection address', + mysqlcreate => 'Create the MySQL database tables if necessary', + +); + +# === Configuration file ends === diff --git a/ezmlm-web-2.2/webusers.sample b/ezmlm-web-2.2/webusers.sample new file mode 100644 index 0000000..b89278f --- /dev/null +++ b/ezmlm-web-2.2/webusers.sample @@ -0,0 +1,5 @@ +comm: guy, arb +users: arb +members: ALL +ALL: root +ALLOW_CREATE: root, guy