diff --git a/CHANGES b/CHANGES index 9e6e97f..ff6733f 100644 --- a/CHANGES +++ b/CHANGES @@ -95,3 +95,12 @@ Version 2.3 - 10/06/02005 * file upload typo fixed * update of webusers file fixed * moderator unsubscribe fixed + +Version 3.0 - 12/25/02005 +* complete interface rewritten for enhanced usability +* suppurt for msgsize, mimereject, trailer +* fixed insecure writing of webusers data +* define a default MAIL_DOMAIN +* changed directory for safely removed mailinglists +* requires the clearsilver template engine + diff --git a/INSTALL b/INSTALL index 7272462..2efc335 100644 --- a/INSTALL +++ b/INSTALL @@ -8,7 +8,8 @@ OVERVIEW: 4 - compile cgi wrapper 5 - install cgi wrapper 6 - (optional) configure access control (http authentication) - 7 - final test + 7 - css stylesheet file + 8 - final test ------------------------------------------------------------------------------ @@ -18,9 +19,11 @@ OVERVIEW: ezmlm-web! The file README contains the complete list of necessary modules. + Additionally (since v3.0) you have to install clearsilver (a templating + engine). See INSTALL.clearsilver for details. 1. Get ezmlm-web and extract the archive: - tar xzf ezmlm-web-2.x.tar.gz + tar xzf ezmlm-web-3.x.tar.gz 2. Copy ezmlm-web.cgi to some publically readable directory. It does not @@ -53,12 +56,16 @@ OVERVIEW: mkdir -p /usr/local/share/ezmlm-web cp -r lang /usr/local/share/ezmlm-web You can change this default location in the ezmlmwebrc file. + Do the same with the template directory (e.g copy it + to /usr/local/share/ezmlm-web/template). Then you also have to + set the appropriate location in the ezmlmwebrc file. Finally, copy the ezmlmwebrc file 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 + 1) the home directory of the user that runs ezmlm-web.cgi + 2) the directory, that contains your ezmlm-web.cgi file + 3) /etc/ezmlm + (ezmlm-web will look for it in these places in the given order) 4. Edit the index.c file and change the path to the path of your copy @@ -81,15 +88,6 @@ OVERVIEW: access controlled (here I mean both web and user access) by some method (eg .htaccess, access.conf for Apache). - You should also copy the stylesheet file (css/default.css) to a location - of your choice. Now you may have to change the "HTML_CSS_FILE" setting - in your ezmlmwebrc file. - - Optional: it would be nice if you could download the small picture - whose URL you can find in the ezmlmwebrc file as "HELP_ICON_URL". - Then you should change this URL. - This helps to reduce the load on our server. - 6. Install some method of securing access to the page. The following information is applicable to Apache web servers ... Detailed @@ -122,15 +120,30 @@ OVERVIEW: AuthUserFile /path/to/passwordfile require valid-user # or require user username - Again, see the ApacheWeek article for details. + 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 :) +7. You should copy the stylesheet file (css/default.css) to a location + of your choice. It has to be accessible by an URL - maybe a place like + "/var/www/ezmlm-web.css" could be appropriate. + Now you may have to change the "HTML_CSS_FILE" setting in your + ezmlmwebrc file. This value is a URL - not the local filename. + + +8. Test the installation with your favourite web browser. 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 do not see a colorful screen, then you did not set the HTML_CSS_FILE + option correctly in ezmlmwebrc. Check it again. + + If anything failes - take a look at the web server's error log + (e.g /var/log/apache/error.log). 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 +- subscribe to the mailinglist: ezmlm-web-subscribe@lists.systemausfall.org +- report a bug at https://systemausfall.org/trac/ezmlm-web diff --git a/INSTALL.clearsilver b/INSTALL.clearsilver new file mode 100644 index 0000000..484bfe0 --- /dev/null +++ b/INSTALL.clearsilver @@ -0,0 +1,34 @@ +Short notes on how to install clearsilver for perl: +(you should read it, as step 4 is quite unusual) + +1) download & untar + http://clearsilver.net + + +2) configure + +The following configure options should be sufficient: + ./configure --enable-perl \ + --disable-python \ + --disable-ruby \ + --disable-java \ + --disable-csharp \ + --disable-apache \ + --disable-gettext \ + --disable-remote-debugger + +3) make + + +4) the tricky part :) + +As the installation directory of clearsilver-perl is configured incorrectly, +you should replace the existing SITEPREFIX line in perl/Makefile with the following: + SITEPREFIX = $(PREFIX) +(without the leading white space) + + +5) make install + + +6) done diff --git a/README b/README index 4d14bd6..fad9033 100644 --- a/README +++ b/README @@ -1,5 +1,5 @@ ================= -| ezmlm-web-2.3 | +| ezmlm-web-3.0 | ================= If you only want to know how to install ezmlm-web, then you should @@ -21,10 +21,11 @@ VIII. Bugs && Bug Reports I. Copyright Stuff - essentially the FreeBSD licence ... ================== -ezmlm-web - version 2.3 - 10/06/02005 +ezmlm-web - version 3.0 - 12/22/02005 Copyright (C) 1998, Guy Antony Halse, All Rights Reserved. -Please send bug reports and comments to guy-ezmlm@rucus.ru.ac.za + +Please send bug reports and comments to ezmlm-web@sumpfralle.de Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -55,6 +56,7 @@ POSSIBILITY OF SUCH DAMAGE. II. Some Background =================== +[this text was written by Guy Antony Halse - the original author of ezmlm-web] 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 @@ -94,7 +96,8 @@ III. Requirements This version of ezmlm-web requires the following; * qmail v1.03 -* ezmlm v0.53 (idx v0.40) +* ezmlm v0.53 (or ezmlm-idx v0.40) +* clearsilver v0.10.2 (only perl support is necessary) * Perl v5.004 and the following modules; + Mail::Ezmlm v0.03 + Mail::Address v1.15 @@ -108,48 +111,65 @@ This version of ezmlm-web requires the following; 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. +http://www.ezmlm.org/ for anything you are missing. Of course, newer +versions are expected to work as well. To install perl modules you may use the cpan command line interface. Just run "cpan" and type something like "install Mail::Ezmlm". +You can download clearsilver (a templating engine - it is required since +ezmlm-web v3.0) from http://clearsilver.net. + IV. Files ========= -In this distribution you should find eight files; +In this distribution you should find the following files; -README This file. Provides some background information. - Not needed to run ezmlm-web. +README (optional) This file. Provides some background information. -INSTALL Notes on installation. Not needed to run ezmlm-web. +INSTALL (optional) Notes on installation. -CHANGES The change history. Not needed to run ezmlm-web +INSTALL.clearsilver (optional) Notes on the installation of clearsilver. -TODO This file is a list of things I intend doing in future - versions of ezmlm-web. Not needed to run ezmlm-web. +CHANGES (optional) The change history. -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. +UPGRADING (optional) Notes on upgrading ezmlm-web from a previous version. -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. +TODO (optional) This file is a list of things I intend doing in future + versions of 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. +ezmlm-web.cgi (required) The ezmlm-web cgi script in perl. You will need it :) -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. +index.c (recommended) 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. -webusers.sample A sample webusers file for multi-level access control. +ezmlmwebrc (required) 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. -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". +htaccess.sample (recommended) 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 (recommended) A sample webusers file for multi-level access control. + +lang (directory, required) It contains the language files. You will need + at least the one, that you have choosen in "ezmlmwebrc" by + the option "HTML_LANGUAGE". + +css (directory, recommended) Here you find available css stylesheet files. + Pick the one you like (for now, there is only one choice :)) and + set it up by pointing the "HTML_CSS_FILE" setting in your + "ezmlmwebrc" to an appropriate URL. + +template (directory, required) The clearsilver template files in this + directory defined the layout of the web interface. You should be able + to adapt them to your needs, if you like. + +spec (directory, optional) Some development specific information. V. Notes @@ -181,30 +201,27 @@ 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. + $REMOTE_USER) or an ALL (user) 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. +creates the list is the default owner. There is no way to create users +through the web interface, as this depends on your authentication system. The format of a webusers file is as follows; -list1: user1, user2, user3 -ALL: user1, user2 +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 +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 @@ -217,9 +234,9 @@ 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. +language independant. All 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. @@ -237,26 +254,27 @@ 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. +FreeBSD 4.0-STABLE, FreeBSD 3.4-RELEASE, RedHat 5.1, Redhat 6.0 and Debian +3.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. Please mail bug reports and comments to ezmlm-web@sumpfralle.de. +Or (even better) submit a bug report at https://systemausfall.org/trac/ezmlm-web. +Or subscribe to the ezmlm-web mailinglist: ezmlm-web-subscribe@lists.systemausfall.org. 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 +* Guy Antony Halse (guy-ezmlm@rucus.ru.ac.za) - he created ezmlm-web + and maintained it till 02005 +* Keith Burdis (keith@rucus.ru.ac.za) - For constantly bugging me (Guy) 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 + Litestep mailing list - For helping beta test and putting up with me (Guy) 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 +* Barry Irwin (bvi@moria.org) - For trusting me (Guy) 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 @@ -265,6 +283,9 @@ IX. Acknowledgements * 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. +* Reinin Ooyama (lenin@hasiru.net) - a japanese translation and bugixes for v2.3 +* Henning Rieger (age@systemausfall.org) - he designed most of the new + interface for v3.0 X. Availability @@ -272,6 +293,9 @@ X. Availability More information on ezmlm-web and developments to ezmlm-web can be found at: https://systemausfall.org/toolforge/ezmlm-web +The public subversion repository is at: +https://svn.systemausfall.org/svn/ezmlm-web + The website of Guy Antony Halse (the author of ezmlm-web) is still at: http://rucus.ru.ac.za/~guy/ezmlm/ diff --git a/TODO b/TODO index b6b7f64..ed45e42 100644 --- a/TODO +++ b/TODO @@ -1 +1,12 @@ -remove old language file dependencies +"cancel" button during text editing + +restore user input after failed list_create (especially options) + +support for: + * charset + * show log + +allow dynamic addition of user-made config templates (seperate directory, ...) + +language switch support +choose basic/expert to disable questions diff --git a/UPGRADING b/UPGRADING index 2055ce9..b33f3e6 100644 --- a/UPGRADING +++ b/UPGRADING @@ -2,9 +2,27 @@ This file contains some useful hints for upgrading from a previous version of ez ############################################################################## +UPGRADING ezmlm-web 2.3 to ezmlm-web 3.0 + +1) install clearsilver (see INSTALL for details) + +2) copy the "template" directory somewhere (see INSTALL again) + +3) set "TEMPLATE_DIR" in your ezmlmwebrc file to this directory + +4) copy the languga directory somewehre and adjust the "LANGUAGE_DIR" setting + +4) maybe you want to define "MAIL_DOMAIN" in your ezmlmwebrc + +5) the search order for ezmlmwebrc has changed +from HOME -> SYSTEM -> CGI_DIR +to HOME -> CGI_DIR -> SYSTEM + +------------------------------------------------------------------------------ + UPGRADING ezmlm-web 2.2 to ezmlm-web 2.3 -there are no known issues +1) set the location (URL) of the css file in ezmlmwebrc ------------------------------------------------------------------------------ diff --git a/css/default.css b/css/default.css index 66e6ba9..ca149dd 100644 --- a/css/default.css +++ b/css/default.css @@ -1,199 +1,325 @@ -body { - background-color: #000080; +body { + margin: 0; + padding: 0; + font: normal 100% sans-serif; + color: #606760; + } + +font.ez { + font-style: italic; + color: #505050; + } + +font.hint { + font-size: 85%; + } + +font.feature { + font-weight: bold; + } + +#nav_bar { + float: left; + width: 20%; + margin-left: 1%; + margin-right: 1%; + margin-bottom: 1%; + margin-top: 5px; + padding-left: 0.5%; + padding-right: 0.5%; + padding-top: 1.5%; + padding-bottom: 1.5%; + background-color: #c0c0b0; + } + +.nav_group { + margin-top: 1%; + padding-bottom: 1%; + } + +#nav_bar ul { + color: #af8060; + margin: 0; + padding-left: 15px; + list-style: none; + } + +#nav_bar ul li { + margin-top: 0; + /* small space between highest level entries */ + margin-bottom: 5px; + } + +#nav_bar ul li ul li { + /* no space between lower level entries */ + margin-bottom: 0; + } + +#nav_bar li a.nav_active { + color: #fff; + } + +#nav_bar font.no_link { + color: #2f4860; + font-style: italic; + } + +#nav_bar a { + color: #2f4860; + text-decoration: none; + } + +#nav_bar a:hover { + background-color: #d8d8d8; + color: #2f4860; + } + +#main_content { + margin-left: 22%; + padding-left: 3%; + padding-right: 1%; + min-height: 440px; + } + +#main_content li { + list-style: none; + } + +#main_content button { + margin-top: 12px; + } + +#main_content ul { + line-height: 1.8em; + list-style: none; + } + +#main_content ul li ul { + font-size: 85%; + } + +#main_content fieldset { + margin-top: 0.5%; + margin-bottom: 1%; + padding-top: 1%; + padding-bottom: 1.5%; + } + +#main_content fieldset.form form ul { + padding-left: 1%; + } + +#main_content fieldset.form form ul li ul { + padding-left: 3%; + } + +#main_content table.list_select { + table-layout: fixed; + width: 100%; + text-align: left; + line-height: 1.2em; + border-width: 0px; + padding-left: 2%; + padding-right: 0px; + } + +div.formfield { + font-style: normal; + } + +#news { + background: #e8947c; color: #000000; + margin: 1%; + padding: 5px; + width: 30%; + float: right; + font-size: 80%; } -h1 { - text-align: center; +#news font.title { + font-style: italic; + font-size: 110%; } -h2 { - text-align: center; - } - -a { - color: #3333ff; +#news ul.changes { + font-size: 90%; + margin-top: 0px; } a:visited { - color: #8888ff; + color: #005040; } - -/*********************** general ************************** - -used classes for containers: - title - heading of most pages (except main) - list - list of subscribers/mailinglists/moderators/... - add_remove - buttons and fields to manipulate such lists - info - explanations - question - buttons to answer a question - options - various possibilities (buttons) - input - group of form fields - container - includes all other containers on a page - -low-level classes (for "span"): - button - formfield - checkbox - help - -and a special div: - error - -************************************************************/ - -div.container { - margin-left: auto; - margin-right: auto; +#oben { + background-color: #2f4860; } - -div.add_remove span.button { - width: auto; - margin-top: 0px; - margin-right: auto; - } - -div.add_remove span.formfield { - width: auto; - margin: 0px; - margin-right: auto; - padding: 0px; - } - -div.list { - margin: 1%; - margin-right: 3%; - width: 30%; - text-align: center; - float: left; - margin-bottom: auto; - } - -div.question { - text-align: center; - } - -p.warning { - text-decoration: blink; - color: #ff0000; - text-align: center; - } - -span.help { - font-size: small; - } - -span.button { - margin-left: 3px; - margin-right: 3px; - } - -span.formfield { - margin-right: auto; - } - -/************************ main page *********************** -name of container: main -available classes: list info add_remove -**********************************************************/ - - - - - -/******************* confirm delete page ******************* -name of container: delete -available classes: title button -***********************************************************/ - - - - - -/************************* edit page *********************** -name of container: edit -available classes: title list add_remove options -***********************************************************/ - - - - - -/********* allow/deny/moderators/digests page ************** -name of container: parts -available classes: title info list add_remove -***********************************************************/ - - - - - -/******************* create list page ********************** -name of container: create -available classes: title input question -***********************************************************/ - -#create div.input span.formfield { - font-weight: bold; - font-size: large; - margin-left: 0px; - margin-right: auto; - } - - - -/********************* config page ************************* -name of container: config -available classes: title info input question -***********************************************************/ - -#config div.info { - font-size: large; - font-weight: bold; - } - -#config div.input span.formfield { - font-weight: bold; - margin-left: 0px; - margin-right: auto; - } - - -/******************** textfiles **************************** -name of container: textfiles -available classes: list info question -***********************************************************/ - - - - - -/******************** edittext ***************************** -name of container: edittext -available classes: title input info question -***********************************************************/ - -#edittext div.input { - float:left; - } - - - -/**************** error messages **************************/ - -div.error { - width: 99%; + +h1.oben { + text-align: left; + border-bottom: solid 2px #ffffff; padding: 5px; - text-align: center; - background-color: #e0e0ff; - } - -div.error h2 { - color: #ff0000; - } - -div.error p.msg { font-weight: bold; + letter-spacing: -1px; + color: #ffffff; + margin: 0; } +#perm_nav { + float: right; + padding-right: 5px; + font-size: 100%; + color: #ffd7f0; + background-color: inherit; + } + +#perm_nav a { + font-weight: bold; + color: #ffffff; + padding-left: 2px; + padding-right: 2px; + text-decoration: none; + } + +#perm_nav a:hover { + color: #ffcc00; + } + +table.subscribers { + border-width: 0; + margin: 0; + padding: 1%; + width: 100%; + } + +tr, td { + margin: 0; + padding: 0; + } + +button { + color: #5e5e5e; + background-color: #d8d8d8; + border: 1px dotted #5e5e5e; + font-size: 90%; + cursor: pointer; + } + +button:hover { + color: #505050; + background-color: #d0d0d0; + border: 1px dotted #ACE149; + font-size: 90%; + cursor: pointer; + } + +.lid { + margin: 0; + padding: 3px; + border-bottom: solid 1px #606070; + background-color: #c0c0b0; + font: bold 100% sans-serif; + letter-spacing: -1px; + color: #ffffff; + } + +#content { + position: absolute; + right: 0px; + width: 85%; + font: normal 82% sans-serif; + background-color: #ffffff; + padding: 2px; + } + +#content h2 { + margin-left: 5px; + margin-right: 5px; + margin-top: 10px; + font-weight: normal; + letter-spacing: -1px; + color: #2f4860; + } + +.push { + margin: 5px; + padding: 0; + } + +.push p { + text-align: justify; + } + +#info_title { + text-align: center; + background-color: #c0c0b0; + margin-top: 5px; + margin-left: 0%; + margin-right: 1%; + margin-bottom: 0.2%; + color: #ffffff; + font-size: 125%; + font-style: italic; + } + +#header { + text-align: right; + background-color: #2f4860; + font-size: 90%; + color: #ffffff; + margin: 0; + top: 0; + width: 100%; + } + +#footer { + text-align: center; + background-color: #2f4860; + font-size: 90%; + color: #ffffff; + margin: 0px; + padding: 3px; + } + +#footer a { + color: #a0d0b0; + } + +#footer a:visited { + color: #a0d0b0; + } + +#main_content div.introduction { + font-size: 80%; + } + +#main_content div.warning, div.error, div.success { + margin-left: 10%; + margin-right: 10%; + margin-top: 2%; + margin-bottom: 3%; + padding: 2%; + text-align: center; + font-style: italic; + font-size: 90%; + } + +#main_content div.success { + background-color: #40d070; + color: #202020; + } + +#main_content div.warning { + background-color: #e0a0a0; + color: #202020; + } + +#main_content div.error { + background-color: #d05050; + color: #202020; + } + +.mail { + font-style: italic; + color: #2f4860; + } diff --git a/ezmlm-web.cgi b/ezmlm-web.cgi index 3b7a131..b09cb81 100755 --- a/ezmlm-web.cgi +++ b/ezmlm-web.cgi @@ -37,19 +37,26 @@ # POD documentation is at the end of this file # ========================================================================== +package ezmlm_web; + # Modules to include use strict; use Getopt::Std; use ClearSilver; use Mail::Ezmlm; use Mail::Address; +use File::Copy; use DB_File; use CGI; +use IO::File; +use POSIX qw(tmpnam); +use Encode qw/ from_to /; # add by ooyama for char convert # 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]; @@ -60,32 +67,36 @@ $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]; +my @tmp = getpwuid($>); use vars qw[$USER]; $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]; -use vars qw[$HTML_CSS_FILE $TEMPLATE_DIR $LANGUAGE_DIR]; +use vars qw[$DEFAULT_OPTIONS $UNSAFE_RM $ALIAS_USER $LIST_DIR]; +use vars qw[$QMAIL_BASE $PRETTY_NAMES]; +use vars qw[$FILE_UPLOAD $WEBUSERS_FILE $MAIL_DOMAIN $HTML_TITLE]; +use vars qw[$HTML_CSS_FILE $TEMPLATE_DIR $LANGUAGE_DIR $HTML_LANGUAGE]; + +# set default TEXT_ENCODE +use vars qw[$TEXT_ENCODE]; $TEXT_ENCODE='us-ascii'; # by ooyama for multibyte convert support # pagedata contains the hdf tree for clearsilver # pagename refers to the template file that should be used -use vars qw[$pagedata $pagename]; +use vars qw[$DEFAULT_HOST]; +use vars qw[$pagedata $pagename $error $customError $warning $customWarning $success]; # Get user configuration stuff if(defined($opt_C)) { - require "$opt_C"; # Command Line + $opt_C =~ /^([-\w.\/]+)$/; # security check by ooyama + require "$1"; # 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 +} elsif(-e "/etc/ezmlm/ezmlmwebrc") { + require "/etc/ezmlm/ezmlmwebrc"; # System } else { - die "Unable to read config file"; + &fatal_error("Unable to read config file"); } # Allow suid wrapper to over-ride default list directory ... @@ -98,160 +109,172 @@ 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; +# check optional stylesheet +$HTML_CSS_FILE = '' unless defined($HTML_CSS_FILE); + +# check template directory +$TEMPLATE_DIR = 'template' unless defined($TEMPLATE_DIR); + +if (defined($MAIL_DOMAIN) && ($MAIL_DOMAIN ne '')) { + $DEFAULT_HOST = $MAIL_DOMAIN; +} else { + # Work out default domain name from qmail (for David Summers) + open (GETHOST, "<$QMAIL_BASE/defaultdomain") || open (GETHOST, "<$QMAIL_BASE/me") || &fatal_error("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; -} - my $pagedata = load_hdf(); +my $action = $q->param('action'); # check permissions -&check_permission_for_action == 0 || &error_die('Error: you are not allowed to do this!'); - +unless (&check_permission_for_action) { + $pagename = 'list_select'; + $error = 'Forbidden'; +} # 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 $pagedata->getValue("Lang.Buttons.Create","unknown button")) { # Create a new list ... - &allow_create_list; - } elsif (defined($Q::list)) { - if ($Q::action eq $pagedata->getValue("Lang.Buttons.Edit","unknown button")) { # Edit an existing list ... - &display_list; - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.Delete","unknown button")) { # 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 $pagedata->getValue("Lang.Buttons.DeleteAddress","unknown button")) { # Delete a subscriber ... - &delete_address($list); - &display_list; - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.AddAddress","unknown button")) { # Add a subscriber ... - &add_address($list); - &display_list; - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.Moderators","unknown button")) { # Edit the moderators ... - &part_subscribers('mod'); - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.DenyList","unknown button")) { # Edit the deny list ... - &part_subscribers('deny'); - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.AllowList","unknown button")) { # edit the allow list ... - &part_subscribers('allow'); - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.DigestSubscribers","unknown button")) { # Edit the digest subscribers ... - &part_subscribers('digest'); - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.Configuration","unknown button")) { # 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 $pagedata->getValue("Lang.Buttons.DeleteAddress","unknown button")) { # Delete a subscriber ... - &delete_address("$LIST_DIR/$Q::list", $part); - &part_subscribers($part); - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.AddAddress","unknown button")) { # 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 $pagedata->getValue("Lang.Buttons.Yes","unknown button")); # Do it ... - $q->delete_all; - &select_list(); - -} elsif ($Q::state eq 'create') { - # User wants to create a list ... - - if ($Q::action eq $pagedata->getValue("Lang.Buttons.CreateList","unknown button")) { - 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 $pagedata->getValue("Lang.Buttons.UpdateConfiguration","unknown button")) { # Save current settings ... - &update_config; - &display_list; - - } elsif ($Q::action eq $pagedata->getValue("Lang.Buttons.EditTexts","unknown button")) { # 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 $pagedata->getValue("Lang.Buttons.EditFile","unknown button")) { - &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 $pagedata->getValue("Lang.Buttons.SaveFile","unknown button")); - &list_text; - +# TODO: unify all these "is list param set?" checks ... +elsif ($action eq '' || $action eq 'list_select') { + # Default action. Present a list of available lists to the user ... + $pagename = 'list_select'; +} elsif ($action eq 'subscribers') { + # display list (or part list) subscribers + if (defined($q->param('list'))) { + $pagename = 'subscribers'; + } else { + $pagename = 'list_select'; + $error = 'ParameterMissing'; + } +} elsif ($action eq 'address_del') { + # Delete a subscriber ... + if (defined($q->param('list'))) { + $success = 'DeleteAddress' if (&delete_address()); + $pagename = 'subscribers'; + } else { + $error = 'ParameterMissing'; + $pagename = 'list_select'; + } +} elsif ($action eq 'address_add') { + # Add a subscriber ... + # no selected addresses -> no error + if (defined($q->param('list'))) { + $success = 'AddAddress' if (&add_address()); + $pagename = 'subscribers'; + } else { + $error = 'ParameterMissing'; + $pagename = 'list_select'; + } +} elsif ($action eq 'list_delete_ask') { + # Confirm list removal + if (defined($q->param('list'))) { + $pagename = 'list_delete'; + } else { + $pagename = 'list_select'; + $error = 'ParameterMissing'; + } +} elsif ($action eq 'list_delete_do') { + # User really wants to delete a list ... + warn "do it"; + if (defined($q->param('list'))) { + $success = 'DeleteList' if (&delete_list()); + } else { + $error = 'ParameterMissing'; + } + $pagename = 'list_select'; +} elsif ($action eq 'list_create_ask') { + # User wants to create a list ... + $pagename = 'list_create'; +} elsif ($action eq 'list_create_do') { + # create the new list + # Message if list creation is unsuccessful ... + if (&create_list()) { + $success = 'CreateList'; + $pagename = 'subscribers'; + } else { + $pagename = 'list_create'; + } +} elsif (($action eq 'config_ask') || ($action eq 'config_do')) { + # User wants to see/change the configuration ... + my $subset = $q->param('config_subset'); + if (defined($q->param('list')) && ($subset ne '')) { + if ($subset =~ m/^RESERVED-([\w_-]*)$/) { + $pagename = $1 + } elsif (($subset =~ /^[\w]*$/) && (-e "$TEMPLATE_DIR/config_$subset" . ".cs")) { + $pagename = 'config_' . $subset; + } else { + $pagename = ''; + } + if ($pagename ne '') { + $success = 'UpdateConfig' if (($action eq 'config_do') && &update_config()); + } else { + $error = 'UnknownConfigPage'; + warn "missing config page: $subset"; + $pagename = 'list_select'; + } + } else { + $error = 'ParameterMissing'; + $pagename = 'list_select'; + } +} elsif ($action eq 'textfiles') { + # Edit DIR/text ... + if (defined($q->param('list'))) { + $pagename = 'textfiles'; + } else { + $error = 'ParameterMissing'; + $pagename = 'list_select'; + } +} elsif ($action eq 'textfile_edit') { + # edit the content of a text file + if (defined($q->param('list')) && defined($q->param('file'))) { + if (! &check_filename($q->param('file'))) { + $error = 'InvalidFileName'; + $pagename = 'textfiles'; + } else { + $pagename = 'textfile_edit'; + } + } else { + $error = 'ParameterMissing'; + $pagename = 'list_select'; + } +} elsif ($action eq 'textfile_save') { + # User wants to save a new version of something in DIR/text ... + if (defined($q->param('list')) && defined($q->param('file')) && defined($q->param('content'))) { + if (! &check_filename($q->param('file'))) { + $error = 'InvalidFileName'; + $pagename = 'textfiles'; + } elsif (&save_text()) { + $pagename = 'textfiles'; + $success = 'SaveFile'; + } else { + $warning = 'SaveFile'; + $pagename = 'textfile_edit'; + } + } else { + $error = 'ParameterMissing'; + if ($q->param('list')) { + $pagename = 'textfiles'; + } else { + $pagename = 'list_select'; + } + } } else { - $pagedata->setValue("Data.Action", $q->param('action')); - $pagedata->setValue("Data.Status", "unknown action"); - $pagename = 'select_list'; -} + $pagename = 'list_select'; + $error = 'UnknownAction'; +} + +# read the current state (after the changes are done) +&set_pagedata(); + +# set default action, if there is no list available and the user is +# allowed to create a new one +if (($action eq '') && (&webauth_create_allowed()) && ($pagedata->getValue('Data.Lists.0','') eq '')) { + $pagename = 'list_create'; +} # Print page and exit :) ... &output_page; @@ -264,15 +287,16 @@ sub load_hdf { # initialize the data for clearsilver my $hdf = ClearSilver::HDF->new(); - # TODO: respect LANGUAGE_DIR and LANGUAGE - $hdf->readFile($LANGUAGE_DIR . "/en.hdf"); + $hdf->readFile($LANGUAGE_DIR . '/' . $HTML_LANGUAGE . '.hdf'); # TODO: check for existence + &fatal_error("Template dir ($TEMPLATE_DIR) not found!") unless (-e $TEMPLATE_DIR); $hdf->setValue("TemplateDir", "$TEMPLATE_DIR/"); + &fatal_error("Language data dir ($LANGUAGE_DIR) not found!") unless (-e $LANGUAGE_DIR); $hdf->setValue("LanguageDir", "$LANGUAGE_DIR/"); $hdf->setValue("ScriptName", $ENV{'SCRIPT_NAME'}); $hdf->setValue("Stylesheet", "$HTML_CSS_FILE"); - $hdf->setValue("HelpIconURL", "$HELP_ICON_URL"); + $hdf->setValue("Config.PageTitle", "$HTML_TITLE"); return $hdf; } @@ -281,144 +305,342 @@ sub load_hdf { sub output_page { # Print the page - my $pagefile = $TEMPLATE_DIR . "/" . $pagename . ".cs"; - die "template ($pagefile) not found!" unless (-e "$pagefile"); + $pagedata->setValue('Data.Success', "$success") if (defined($success)); + $pagedata->setValue('Data.Error', "$error") if (defined($error)); + $pagedata->setValue('Data.Warning', "$warning") if (defined($warning)); + $pagedata->setValue('Data.CustomError', "$customError") if (defined($customError)); + $pagedata->setValue('Data.CustomWarning', "$customWarning") if (defined($customWarning)); + + $pagedata->setValue('Data.Action', "$pagename"); + + my $pagefile = $TEMPLATE_DIR . "/main.cs"; + &fatal_error("main template ($pagefile) not found!") unless (-e "$pagefile"); + &fatal_error("sub template ($TEMPLATE_DIR/$pagename.cs) not found!") unless (-e "$TEMPLATE_DIR/$pagename.cs"); # print http header - print "Content-Type: text/html\n\n"; + print "Content-Type: text/html; charset=utf-8\n\n"; my $cs = ClearSilver::CS->new($pagedata); - $cs->parseFile($TEMPLATE_DIR . '/macros.cs'); - $cs->parseFile($TEMPLATE_DIR . '/header.cs'); - $cs->parseFile($TEMPLATE_DIR . '/' . $pagename . '.cs'); - $cs->parseFile($TEMPLATE_DIR . '/footer.cs'); + + $cs->parseFile($pagefile); print $cs->render(); } +# --------------------------------------------------------------------------- -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. +sub set_pagedata_list_of_lists() +{ + my (@files, $i, $num); - my (@lists, @files, $i, $scrollsize); + # Read the list directory for mailing lists. + return (0==0) unless (opendir DIR, $LIST_DIR); - $pagename = 'select_list'; + @files = sort grep !/^\./, readdir DIR; + closedir DIR; - # Read the list directory for mailing lists. - opendir DIR, $LIST_DIR || &error_die("Unable to read $LIST_DIR: $!"); - @files = grep !/^\./, readdir DIR; - closedir DIR; - - # Check that they actually are lists ... - my $num = 0; - foreach $i (0 .. $#files) { - if ((-e "$LIST_DIR/$files[$i]/lock") && (&webauth($files[$i]) == 0)) { - $num++; - $pagedata->setValue("Data.Lists." . $num, "$files[$i]"); - } - } - $pagedata->setValue("Data.ListsCount", "$num"); - - # TODO: ACL an einer Stelle zentral bestimmen lassen - $pagedata->setValue("Data.Permissions.Create", (&webauth_create_allowed == 0)? 1 : 0 ); - + $num = 0; + # Check that they actually are lists and add good ones to pagedata ... + foreach $i (0 .. $#files) { + if ((-e "$LIST_DIR/$files[$i]/lock") && (&webauth($files[$i]))) { + $pagedata->setValue("Data.Lists." . $num, "$files[$i]"); + $num++; + } + } } -# ------------------------------------------------------------------------ +# --------------------------------------------------------------------------- -sub confirm_delete { - # Make sure that the user really does want to delete the list! +sub set_pagedata() +{ + my ($hostname, $username); - $pagedata->setValue("Data.ListName", $q->param('list')); - $pagename = 'confirm_delete'; -} + # read available list of lists + &set_pagedata_list_of_lists(); -# ------------------------------------------------------------------------ + # username and hostname + # 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; + } + $pagedata->setValue("Data.UserName", "$username"); + $pagedata->setValue("Data.HostName", "$hostname"); -sub display_list { - # Show a list of subscribers to the user ... - my ($list); + # modules + # TODO: someone should test, if the mysql support works + $pagedata->setValue("Data.Modules.MySQL", ($Mail::Ezmlm::MYSQL_BASE)? 1 : 0); - # Work out the address of this list ... - $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); - $pagename = 'display_list'; + # permissions + $pagedata->setValue("Data.Permissions.Create", (&webauth_create_allowed)? 1 : 0 ); + $pagedata->setValue("Data.Permissions.FileUpload", ($FILE_UPLOAD)? 1 : 0); - $pagedata->setValue("Data.ListName", $q->param('list')); - $pagedata->setValue("Data.ListAddress", &this_listaddress); - my $i = 0; - my $one_subs; - # TODO: use "pretty" output style for visible mail address - foreach $one_subs ($list->subscribers) { - $pagedata->setValue("Data.Subscribers." . $i, "$one_subs"); - $i++; - } - $pagedata->setValue("Data.SubscribersCount", "$i"); - - $pagedata->setValue("Data.ConfigAvail.Extras", 1) if($list->ismodpost || $list->ismodsub || $list->isremote || $list->isdeny || $list->isallow || $list->isdigest); - $pagedata->setValue("Data.ConfigAvail.Moderation", 1) if ($list->ismodpost || $list->ismodsub || $list->isremote); - $pagedata->setValue("Data.ConfigAvail.DenyList", 1) if ($list->isdeny); - $pagedata->setValue("Data.ConfigAvail.AllowList", 1) if ($list->isallow); - $pagedata->setValue("Data.ConfigAvail.Digest", 1) if ($list->isdigest); - $pagedata->setValue("Data.ConfigAvail.WebArch", 1) if(&ezmlmcgirc); + # display webuser textfield? + $pagedata->setValue("Data.WebUser.show", (-e "$WEBUSERS_FILE")? 1 : 0); + # default username for webuser file + $pagedata->setValue("Data.WebUser.UserName", $ENV{'REMOTE_USER'}||'ALL'); + # list specific configuration + if ($q->param('list') ne '' ) + { + &set_pagedata4list(&get_list_part()); + } else { + &set_pagedata4options($DEFAULT_OPTIONS); + } } -# ------------------------------------------------------------------------ +# --------------------------------------------------------------------------- + +sub set_pagedata4list +{ + my $part_type = shift; + my ($list, $listname, $webusers); + my ($i, $item, @files); + my ($address, $addr_name, %pretty); + + $listname = $q->param('list'); + + if (! -e "$LIST_DIR/$listname/lock" ) { + $warning = 'ListDoesNotExist' if ($warning eq ''); + return; + } + + # Work out the address of this list ... + $list = new Mail::Ezmlm("$LIST_DIR/$listname"); + + $pagedata->setValue("Data.List.Name", "$listname"); + $pagedata->setValue("Data.List.Address", &this_listaddress); + + &set_pagedata4part_list($part_type) if ($part_type ne ''); + + $i = 0; + tie %pretty, "DB_File", "$LIST_DIR/$listname/webnames" if ($PRETTY_NAMES); + foreach $address (sort $list->subscribers($part_type)) { + if ($address ne '') { + $pagedata->setValue("Data.List.Subscribers." . $i . '.address', "$address"); + $addr_name = ($PRETTY_NAMES)? $pretty{$address} : ''; + $pagedata->setValue("Data.List.Subscribers." . $i . '.name', $addr_name); + } + $i++; + } + untie %pretty if ($PRETTY_NAMES); + + $pagedata->setValue("Data.List.hasDenyList", 1) if ($list->isdeny); + $pagedata->setValue("Data.List.hasAllowList", 1) if ($list->isallow); + $pagedata->setValue("Data.List.hasDigestList", 1) if ($list->isdigest); + + # Get the contents of some important files + $item = $list->getpart('prefix'); + $pagedata->setValue("Data.List.Prefix", "$item"); + $item = $list->getpart('headeradd'); + $pagedata->setValue("Data.List.HeaderAdd", "$item"); + $item = $list->getpart('headerremove'); + $pagedata->setValue("Data.List.HeaderRemove", "$item"); + $item = $list->getpart('mimeremove'); + $pagedata->setValue("Data.List.MimeRemove", "$item"); + $item = $list->getpart('mimereject'); + $pagedata->setValue("Data.List.MimeReject", "$item"); + $item = $list->getpart('text/trailer'); + $pagedata->setValue("Data.List.TrailingText", "$item"); + + # read message size limits + $list->getpart('msgsize') =~ m/^\s*(\d+)\s*:\s*(\d+)\s*$/; + $pagedata->setValue("Data.List.MsgSize.Max", "$1"); + $pagedata->setValue("Data.List.MsgSize.Min", "$2"); + + # TODO: this is definitely ugly - create a new sub! + if(open(WEBUSER, "<$WEBUSERS_FILE")) { + while() { + last if (($webusers) = m{^$listname\s*\:\s*(.+)$}); + } + close WEBUSER; + } + # set default if there was no list definition + $webusers ||= $ENV{'REMOTE_USER'} || 'ALL'; + + $pagedata->setValue("Data.List.WebUsers", "$webusers"); + + # get the names of the textfiles of this list + { + my($listDir); + $listDir = $LIST_DIR . '/' . $q->param('list'); + + # Read the list directory for text ... + if (opendir DIR, "$listDir/text") { + @files = grep !/^\./, readdir DIR; + closedir DIR; + $i = 0; + foreach $item (@files) { + $pagedata->setValue("Data.List.Files." . $i, "$item"); + $i++; + } + } else { + $warning = 'TextDirAccessDenied' if ($warning eq '') + } + + # text file specified? + if (($q->param('file') ne '') && ($q->param('file') =~ m/^[\w-]*$/)) { + my ($content); + $content = $list->getpart("text/" . $q->param('file')); + from_to($content,$TEXT_ENCODE,'utf8'); # by ooyama for multibyte + $pagedata->setValue("Data.List.File.Name", $q->param('file')); + $pagedata->setValue("Data.List.File.Content", "$content"); + } + } + &set_pagedata4options($list->getconfig); +} + +# --------------------------------------------------------------------------- + +sub set_pagedata4options { + my($options) = shift; + my($i, $key, $state, $value, $dir_of_list); + + $dir_of_list = $LIST_DIR . '/' . $q->param('list'); + + $i = 0; + $key = lc(substr($options,$i,1)); + # parse the first part of the options string + while ($key =~ m/\w/) { + # scan the first part of the options string for lower case letters + $state = ($options =~ /^\w*$key\w*\s*/); + $pagedata->setValue("Data.List.Options." . $key , ($state)? 1 : 0); + $i++; + $key = lc(substr($options,$i,1)); + } + + # the options "t", "p" and "x" are only used to create a default value + # they have no meaning, so we should adapt them to reality + $pagedata->setValue("Data.List.Options.t" , 1) + if (-e "$dir_of_list/text/trailer"); + $pagedata->setValue("Data.List.Options.f" , 1) + if (-e "$dir_of_list/prefix"); + $pagedata->setValue("Data.List.Options.x" , 1) + if ((-e "$dir_of_list/mimeremove") || (-e "$dir_of_list/mimereject")); + + for ($i=0; $i<9; $i++) { + unless (($i eq 1) || ($i eq 2)) { + $state = ($options =~ /$i (?:'(.+?)')/); + unless ($state) { + if ($i eq 0) { + $value = 'mainlist@' . $DEFAULT_HOST; + } elsif ($i eq 3) { + $value = 'from_address@domain.org'; + } elsif ($i eq 4) { + $value = '-t24 -m30 -k64'; + } elsif ($i eq 5) { + $value = 'owner_address@domain.org'; + } elsif ($i eq 6) { + $value = 'host:port:user:password:database:table'; + } elsif ($i eq 7) { + $value = "$dir_of_list/mod"; + } elsif ($i eq 8) { + $value = "$dir_of_list/mod"; + } + } else { + # use the configured value (extracted by the pattern matching for 'state') + $value = $1; + } + $pagedata->setValue("Data.List.Settings." . $i . ".value", $value); + $pagedata->setValue("Data.List.Settings." . $i . ".state", $state ? 1 : 0); + } + } +} + +# --------------------------------------------------------------------------- + +sub check_filename() +{ + my $filename = shift; + return ($filename =~ m/[^\w-]/) ? (1==0) : (0==0); +} + +# --------------------------------------------------------------------------- + +sub get_list_part +# return the name of the part list (deny, allow, mod, digest or '') +{ + $q->param('part') =~ m/^(allow|deny|digest|mod)$/; + return $1; +} + +# --------------------------------------------------------------------------- sub delete_list { - # Delete a 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 :) + # 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->param('list')); + if ($listadd = $list->getpart('outlocal')) { + chomp($listadd); + } else { + $listadd = $q->param('list'); + } + $listaddress = $1 if ($listadd =~ /-?(\w+)$/); - use File::Copy; + 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/she be in the mood :) - 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"); + my $SAFE_DIR = "$LIST_DIR/_deleted_lists"; + mkdir "$SAFE_DIR", 0700 if (! -e "$SAFE_DIR"); - 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/")) { - error_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")) { - error_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) { - &error_die("Unable to delete .qmail files: $!"); - } - warn "List '$list->thislist()' deleted"; - } + # look for an unused directory name + my $i = 0; + while (-e "$SAFE_DIR/" . $q->param('list') . "-$i") { $i++; } + + $SAFE_DIR .= '/' . $q->param('list') . "-$i"; + + my ($oldfile); $oldfile = "$LIST_DIR/" . $q->param('list'); + unless (move($oldfile, $SAFE_DIR)) { + $warning = 'SafeRemoveRenameDirFailed'; + return (1==0); + } + + unless (opendir(DIR, "$HOME_DIR")) { + $warning = 'DotQmailDirAccessDenied'; + return (1==0); + } + # TODO: this could possibly move some qmail files of other lists - improve it! + my @files = map { "$HOME_DIR/$1" if m{^(\.qmail.+)$} } grep { /^\.qmail-$listaddress/ } readdir DIR; + closedir DIR; + foreach (@files) { + unless (move($_, "$SAFE_DIR")) { + $warning = 'SafeRemoveMoveDotQmailFailed'; + return (1==0); + } + } + 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 ... + unless (rmtree("$LIST_DIR/" . $q->param('list'))) { + $warning = 'UnsafeRemoveListDirFailed'; + return (1==0); + } + opendir(DIR, "$HOME_DIR") or &fatal_error("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) { + $warning = 'UnsafeRemoveDotQmailFailed'; + return (1==0); + } + warn "List '$list->thislist()' deleted"; + } + $q->param(-name=>'list', -values=>''); } # ------------------------------------------------------------------------ @@ -434,10 +656,10 @@ sub untaint { foreach $i (0 .. $#params) { my(@values); - next if($params[$i] eq 'addfile'); + next if($params[$i] eq 'mailaddressfile'); foreach $param ($q->param($params[$i])) { next if $param eq ''; - if ($param =~ /^([#-\@\w\.\/\[\]\:\n\r\>\< ]+)$/) { + if ($param =~ /^([#-\@\w\.\/\[\]\:\n\r\>\< _"']+)$/) { push @values, $1; } else { warn "Tainted input in '$params[$i]': " . $q->param($params[$i]); @@ -445,7 +667,15 @@ sub untaint { $q->param(-name=>$params[$i], -values=>\@values); } } - $q->import_names('Q'); + + # special stuff + + # check the list name + if (($q->param('list') =~ /[^\w-]/) && ($q->param('action') !~ /^list_create_(do|ask)$/)) { + $warning = 'InvalidListName' if ($warning eq ''); + $q->param(-name=>'list', -values=>''); + } + } # ------------------------------------------------------------------------ @@ -456,12 +686,12 @@ sub check_permission_for_action { # but the final creation is omitted my $ret; - if ($Q::state eq 'create') { + if ($action eq 'list_create_ask' || $action eq 'list_create_do') { $ret = &webauth_create_allowed(); - } elsif (defined($Q::list)) { - $ret = &webauth($Q::list); + } elsif (defined($q->param('list'))) { + $ret = &webauth($q->param('list')); } else { - $ret = 0; + $ret = (0==0); } return $ret; } @@ -469,60 +699,76 @@ sub check_permission_for_action { # ------------------------------------------------------------------------ sub add_address { - # Add an address to a list .. + # Add an address to a list .. - my ($address, $list, @addresses, $count); my ($listname, $part) = @_; - $list = new Mail::Ezmlm($listname); + my ($address, $list, $part, @addresses, $fail_count); + $list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); + $part = &get_list_part(); - if (($q->param('addfile')) && ($FILE_UPLOAD)) { + $fail_count = 0; - # Sanity check - &error_die("File upload must be of type text/*") unless($q->uploadInfo($q->param('addfile'))->{'Content-Type'} =~ m{^text/}); + if (($q->param('mailaddressfile')) && ($FILE_UPLOAD)) { + # Sanity check + my $fileinfo = $q->uploadInfo($q->param('mailaddressfile')); + my $filetype = $fileinfo->{'Content-Type'}; + unless($filetype =~ m{^text/}) { + $warning = 'InvalidFileFormat'; + return (1==0); + } - # Handle file uploads of addresses - my($fh) = $q->param('addfile'); - return unless (defined($fh)); - while (<$fh>) { - next if (/^\s*$/ or /^#/); # blank, comments - next unless ( /(\w[\-\w_\.]*)@(\w[\-\w_\.]+)/ ); # email address ... - chomp(); - push @addresses, "$_"; - } - - } + # Handle file uploads of addresses + my($fh) = $q->param('mailaddressfile'); + while (<$fh>) { + next if (/^\s*$/ or /^#/); # blank, comments + if ( /(\w[\-\w_\.]*)@(\w[\-\w_\.]+)/ ) { + chomp(); + push @addresses, "$_"; + } else { + $fail_count++; + } + } + } # User typed in an address - if ($q->param('addsubscriber') ne '') { + if ($q->param('mailaddress_add') ne '') { - $address = $q->param('addsubscriber'); - $address .= $DEFAULT_HOST if ($q->param('addsubscriber') =~ /\@$/); + $address = $q->param('mailaddress_add'); + $address .= $DEFAULT_HOST if ($q->param('mailaddress_add') =~ /\@$/); # untaint - if ($address =~ /(\w[\-\w_\.]*)@(\w[\-\w_\.]+)/) { - push @addresses, "$1\@$2"; + if ($address =~ m/(\w[\-\w_\.]*)@(\w[\-\w_\.]+)/) { + push @addresses, "$address"; } else { - warn "this address ($address) is not valid!"; + warn "invalid address to add: $address to $part"; + $warning = 'AddAddress'; + return (1==0); } } - foreach $address (@addresses) { + my %pretty; + my $add; + tie %pretty, "DB_File", "$LIST_DIR/" . $q->param('list') . "/webnames" if ($PRETTY_NAMES); + 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) { - &error_die("Unable to subscribe to list: $!"); - } - $count++; - } - - $q->delete('addsubscriber'); + ($add) = Mail::Address->parse($address); + if (($add->address() =~ /^\w[\w_-]*\@/) && !($list->issub($add->address(), $part))) { + # it seems, that we cannot trust the return value of "$list->sub" + $list->sub($add->address(), $part); + if(defined($add->name()) && $PRETTY_NAMES) { + $pretty{$add->address()} = $add->name(); + } + } else { + $fail_count++; + } + } + untie %pretty if ($PRETTY_NAMES); + if ($fail_count gt 0) { + $warning = 'AddAddress'; + return (1==0); + } else { + return (0==0); + } } # ------------------------------------------------------------------------ @@ -530,284 +776,327 @@ sub add_address { 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 ''); + my ($list, @address); + $list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); + my $part = &get_list_part(); + return (1==0) if ($q->param('mailaddress_del') eq ''); - @address = $q->param('delsubscriber'); + @address = $q->param('mailaddress_del'); if ($list->unsub(@address, $part) != 1) { - &error_die("Unable to unsubscribe from list $list: $!"); + $warning = 'DeleteAddress'; + return (1==0); } if($PRETTY_NAMES) { my(%pretty, $add); - tie %pretty, "DB_File", "$LIST_DIR/$Q::list/webnames"; + tie %pretty, "DB_File", "$LIST_DIR/" . $q->param('list') . "/webnames"; foreach $add (@address) { delete $pretty{$add}; } untie %pretty; } - $q->delete('delsubscriber'); } # ------------------------------------------------------------------------ -sub part_subscribers { +sub set_pagedata4part_list { my($part) = @_; # Deal with list parts .... - my ($i, $list, $listaddress, @subscribers, $moderated, $scrollsize, $type); - - $pagename = "config_list"; + my ($i, $list, $listaddress,); # Work out the address of this list ... - $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + $list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); $listaddress = &this_listaddress(); - if($part eq 'mod') { - # Lets know what is moderated :) + $pagedata->setValue("Data.List.PartType", "$part"); - $pagedata->setValue("Data.isModerated",1); - + if($part eq 'mod') { # do we store things in different directories? my $config = $list->getconfig; + # empty values represent default settings - everything else is considered as evil :) my($postpath) = $config =~ m{7\s*'([^']+)'}; my($subpath) = $config =~ m{8\s*'([^']+)'}; my($remotepath) = $config =~ m{9\s*'([^']+)'}; - $pagedata->setValue("Data.isPostMod", ($list->ismodpost)? 1 : 0); - $pagedata->setValue("Data.PostModPath", "$postpath"); + $pagedata->setValue("Data.List.hasPostMod", ($list->ismodpost)? 1 : 0); + $pagedata->setValue("Data.List.PostModPath", "$postpath"); - $pagedata->setValue("Data.isSubMod", ($list->ismodsub)? 1 : 0); - $pagedata->setValue("Data.SubModPath", "$subpath"); + $pagedata->setValue("Data.List.hasSubMod", ($list->ismodsub)? 1 : 0); + $pagedata->setValue("Data.List.SubModPath", "$subpath"); - $pagedata->setValue("Data.isRemote", ($list->isremote)? 1 : 0); - $pagedata->setValue("Data.RemotePath", "$remotepath"); + $pagedata->setValue("Data.List.hasRemoteAdmin", ($list->isremote)? 1 : 0); + $pagedata->setValue("Data.List.RemoteAdminPath", "$remotepath"); } - - # What type of sublist is this? - ($type) = $Q::action =~ m/^\[(.+)\]$/; - - my $i = 0; - my $one_subs; - # TODO: use "pretty" output style for visible mail address - foreach $one_subs ($list->subscribers($part)) { - $pagedata->setValue("Data.List." . $i, "$one_subs"); - $i++; - } - $pagedata->setValue("Data.ListCount", "$i"); - - $pagedata->setValue("Data.ListName", $q->param('list')); - $pagedata->setValue("Data.ListAddress", "$listaddress"); - - $pagedata->setValue("Data.Form.State", $q->param('part')); - - $pagedata->setValue("Data.FileUploadAllowed", ($FILE_UPLOAD)? 1 : 0); -} - -# ------------------------------------------------------------------------ - -sub allow_create_list { - # Let the user select options for list creation ... - - my($username, $hostname, %labels, $j); - # TODO: klaeren wofuer %labels da ist - - $pagename = 'create_list'; - - # 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; - } - - $pagedata->setValue("Data.UserName", "$username"); - $pagedata->setValue("Data.HostName", "$hostname"); - - # TODO: migrate to cs - &display_options($DEFAULT_OPTIONS); - - $pagedata->setValue("Data.mysqlModule", ($Mail::Ezmlm::MYSQL_BASE)? 1 : 0); - - $pagedata->setValue("Data.WebUser.show", (-e "$WEBUSERS_FILE")? 1 : 0); - $pagedata->setValue("Data.WebUser.UserName", $ENV{'REMOTE_USER'}||'ALL'); } # ------------------------------------------------------------------------ sub create_list { - # Create a list according to user selections ... + # Create a list according 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; - } + # Check if the list directory exists and create if necessary ... + unless ((-e $LIST_DIR) || (mkdir $LIST_DIR, 0700)) { + warn "Unable to create directory ($LIST_DIR): $!"; + $warning = 'ListDirAccessDenied'; + return (1==0); + } + + my ($qmail, $listname, $options, $i); + + # Some taint checking ... + $qmail = $1 if $q->param('inlocal') =~ /(?:$USER-)?([^\<\>\\\/\s]+)$/; + $listname = $q->param('list'); + if ($listname =~ m/[^\w\.-]/) { + $warning = 'InvalidListName'; + return (1==0); + } + + # Sanity Checks ... + if ($listname eq '') { + $warning = 'EmptyListName'; + return (1==0); + } + if (($listname =~ m/^ALL$/i) || ($listname =~ m/^ALLOW_CREATE$/i)) { + $warning = 'ReservedListName'; + return (1==0); + } + if ($qmail eq '') { + $warning = 'InvalidLocalPart'; + return (1==0); + } + if (-e "$LIST_DIR/$listname/lock") { + $warning = 'ListNameAlreadyExists'; + return (1==0); + } + if (-e "$HOME_DIR/.qmail-$qmail") { + $warning = 'ListAddressAlreadyExists'; + return (1==0); + } + + $options = &extract_options_from_params(); + + 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) + ) { + # fatal error + $customWarning = $list->errmsg(); + return (1==0); + } + + # handle MySQL stuff + if(defined($q->param('setting_state_6')) && $options =~ m/-6\s+/) { + $customWarning = $list->errmsg() unless($list->createsql()); + } - 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 + # no error returned - just a warning + $warning = 'WebUsersUpdate' unless (&update_webusers()); - # Sanity Checks ... - return 1 if ($listname eq '' || $qmail eq ''); - if(-e ("$LIST_DIR/$listname/lock") || -e ("$HOME_DIR/.qmail-$qmail")) { - &error_die("Can't create list '$listname', as it already exists"); - # TODO: create a language string for this message - 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) - ) { - &error_die('List creation failed' , $list->errmsg()); - } - - # handle MySQL stuff - if($q->param('sql') && $options =~ m/-6\s+/) { - unless($list->createsql()) { - error_die('SQL table creation failed: ' , $list->errmsg()); - } - } - - &update_webusers(); - - return 0; + return (0==0); } # ------------------------------------------------------------------------ -sub list_config { - # Allow user to alter the list configuration ... +sub extract_options_from_params() +{ + # Work out the command line options ... + my ($options, $avail_options, $settings, $avail_settings, $i); + my ($listname, $list, $old_options, $state, $old_key); - my ($list, $listname); + # NOTE: we have to define _every_ (even unchanged) setting + # as ezmlm-make removes any undefined value - $pagename = "list_config"; - - # Store some variables before we delete them ... - $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); - $listname = $q->param('list'); + $listname = $q->param('list'); + $list = new Mail::Ezmlm("$LIST_DIR/$listname"); + $old_options = $list->getconfig(); - $pagedata->setValue("Data.ListName", "$listname"); - $pagedata->setValue("Data.ListAddress", &this_listaddress); + ################ options ################ + $i = 0; + $old_key = substr($old_options,$i,1); + $avail_options = $q->param('options_available'); + # parse the first part of the options string + while ($old_key =~ m/\w/) { + # scan the first part of the options string for lower case letters + if ($avail_options =~ m/$old_key/i) { + my $form_var_name = "option_" . lc($old_key); + # this option was visible for the user + if (defined($q->param($form_var_name))) { + $options .= lc($old_key); + } else { + $options .= uc($old_key); + } + } elsif ("cevz" =~ m/$old_key/i) { + # ignore invalid settings (the output of "getconfig" is really weird!) + } else { + # import the previous set option + $options .= $old_key; + } + $i++; + $old_key = substr($old_options,$i,1); + } - # TODO: migrate - # 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 - $pagedata->setValue("Data.List.Prefix", $list->getpart('prefix')); - # TODO: die folgenden Zeilen enden in einem Hash anstelle des Inhalts - my $temp = $list->getpart('headeradd'); - $pagedata->setValue("Data.List.HeaderAdd", "$temp"); - $temp = $list->getpart('headerremove'); - $pagedata->setValue("Data.List.HeaderRemove", "$temp"); - $temp = $list->getpart('mimeremove'); - $pagedata->setValue("Data.List.MimeRemove", "$temp"); + ############### settings ################ + $avail_settings = $q->param('settings_available'); + for ($i=0; $i<9; $i++) { + if ($avail_settings =~ m/$i/) { + # this setting was visible for the user + $options .= " -$i '" . $q->param("setting_value_$i") . "'" + if (defined($q->param("setting_state_$i"))); + } else { + # import the previous setting + $state = ($old_options =~ /$i (?:'(.+?)')/); + $options .= " -$i '$1'" if ($state); + } + } - # TODO: this is definitely ugly - create a new sub! - if(open(WEBUSER, "<$WEBUSERS_FILE")) { - my($webusers); - while() { - last if (($webusers) = m{^$listname\s*\:\s*(.+)$}); - } - close WEBUSER; - $webusers ||= $ENV{'REMOTE_USER'} || 'ALL'; - - $pagedata->setValue("Data.List.WebUsers", "$webusers"); - } + return $options; } # ------------------------------------------------------------------------ sub update_config { - # Save the new user entered config ... + # Save the new user entered config ... - my ($list, $options, $i, @inlocal, @inhost); - $list = new Mail::Ezmlm("$LIST_DIR/$Q::list"); + my ($list, $options, @inlocal, @inhost, $dir_of_list); + my ($old_msgsize); - # Work out the command line options ... - foreach $i (grep {/\D/} keys %EZMLM_LABELS) { - if (defined($q->param($i))) { - $options .= $i; - } else { - $options .= uc($i); - } - } + $list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); + $dir_of_list = $LIST_DIR . '/' . $q->param('list'); - foreach $i (grep {/\d/} keys %EZMLM_LABELS) { - if (defined($q->param($i))) { - $options .= " -$i '" . $q->param("$i-value") . "'"; - } - } + $options = &extract_options_from_params(); - # Actually update the list ... - unless($list->update($options)) { - die "List update failed"; - } + # save the settings, that are generally overwritten by ezmlm-make :((( + # good candidates are: msgsize, inhost, inlocal and outhost + # maybe there are some others? + $old_msgsize = $list->getpart('msgsize'); - # 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')); + # Actually update the list ... + unless($list->update($options)) { + $warning = 'UpdateConfig'; + return (1==0); + } - &update_webusers(); + # update trailing text + # remove old one if the checkbox was not active + if (defined($q->param('trailing_text'))) { + if (defined($q->param('option_t'))) { + $list->setpart('text/trailer', $q->param('trailing_text')); + } else { + unlink("$dir_of_list/text/trailer"); + } + } + + # update prefix text + # remove old one if the checkbox was not active + if (defined($q->param('prefix'))) { + if (defined($q->param('option_f'))) { + $list->setpart('prefix', $q->param('prefix')) + } else { + unlink("$dir_of_list/prefix"); + } + } + + # update mimeremove + # remove old one if the checkbox was not active + if (defined($q->param('mimeremove'))) { + if (defined($q->param('option_x'))) { + $list->setpart('mimeremove', $q->param('mimeremove')) + } else { + unlink("$dir_of_list/mimeremove"); + } + } + + # update mimereject + # remove old one if the checkbox was not active + if (defined($q->param('mimereject'))) { + if (defined($q->param('option_x'))) { + $list->setpart('mimereject', $q->param('mimereject')) + } else { + unlink("$dir_of_list/mimereject"); + } + } + + # Update headeradd and headerremove if these options were visible + $list->setpart('headeradd', $q->param('headeradd')) + if (defined($q->param('headeradd'))); + $list->setpart('headerremove', $q->param('headerremove')) + if (defined($q->param('headerremove'))); + + if (defined($q->param('msgsize_max_value')) && defined($q->param('msgsize_min_value'))) { + my ($minsize, $maxsize); + $maxsize = (defined($q->param('msgsize_max_state'))) ? + $q->param('msgsize_max_value') : 0; + $minsize = (defined($q->param('msgsize_min_state'))) ? + $q->param('msgsize_min_value') : 0; + $list->setpart('msgsize', "$maxsize:$minsize"); + } else { + # restore the original value, as ezmlm-make always overrides these values :((( + $list->setpart('msgsize', "$old_msgsize"); + } + + unless (&update_webusers()) { + $warning = 'WebUsersUpdate'; + return (1==0); + } + + return (0==0); } # ------------------------------------------------------------------------ sub update_webusers { - # replace existing webusers-line or add a new one + # 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() { - print WU unless (/^$Q::list\s*:/); + # return if there is no webusers entry + return (0==0) unless defined($q->param('webusers')); + + # Back up web users file + my $temp_file; + my $fh; + # generate a temporary filename (as suggested by the Perl Cookbook) + do { $temp_file = tmpnam() } + until $fh = IO::File->new($temp_file, O_RDWR|O_CREAT|O_EXCL); + close $fh; + unless (open(TMP, ">$temp_file")) { + warn "could not open a temporary file"; + return (1==0);; } - print WU "$Q::list\: $Q::webusers\n"; - close TMP; close WU; - unlink "/tmp/ezmlm-web.$$"; - } + open(WU, "<$WEBUSERS_FILE"); + while() { print TMP; } + close WU; close TMP; + my $matched = 0; + my $listname = $q->param('list'); + my $webusers_filtered = $q->param('webusers'); + # remove any insecure characters (e.g. a line break :)) + $webusers_filtered =~ s/[^\w_,-]/ /gs; + open(TMP, "<$temp_file"); + unless (open(WU, ">$WEBUSERS_FILE")) { + warn "the webusers file ($WEBUSERS_FILE) is not writable"; + return (0==1); + } + while() { + if ($_ =~ m/^$listname\s*:/i) { + print WU $listname . ': ' . $webusers_filtered . "\n" if ($matched == 0); + $matched = 1; + } else { + print WU $_; + } + } + # append the line, if there was no matching line found before + print WU $listname . ': ' . $webusers_filtered . "\n" if ($matched == 0); + + close TMP; close WU; + unlink "$temp_file"; } # ------------------------------------------------------------------------ @@ -816,7 +1105,7 @@ 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"); + $list = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); chomp($listaddress = $list->getpart('outlocal')); $listaddress .= '@'; chomp($listaddress .= $list->getpart('outhost')); @@ -825,163 +1114,90 @@ sub this_listaddress { # ------------------------------------------------------------------------ -sub list_text { - # Show a listing of what is in DIR/text ... - - $pagename = 'list_textfiles'; - - my(@files, $list); - $list = $LIST_DIR . '/' . $q->param('list'); - - # Read the list directory for text ... - opendir DIR, "$list/text" || &error_die("Unable to read DIR/text: $!"); - @files = grep !/^\./, readdir DIR; - closedir DIR; - - $pagedata->setValue("Data.ListName", $q->param('list')); - - # TODO: find a better way to set a list ... - my $i = 0; - my $one_file; - foreach $one_file (@files) { - $pagedata->setValue("Data.Files." . $i, "$one_file"); - $i++; - } - $pagedata->setValue("Data.FilesCount", "$i"); -} - -# ------------------------------------------------------------------------ - -sub edit_text { - # Allow user to edit the contents of DIR/text ... - - $pagename = 'edit_text'; - - my ($content); - my($list) = new Mail::Ezmlm("$LIST_DIR/$Q::list"); - $content = $list->getpart("text/$Q::file"); - - $pagedata->setValue("Data.ListName", $q->param('list')); - # TODO: file wird nurals hash interpretiert - $pagedata->setValue("Data.File.Name", $q->param('file')); - $pagedata->setValue("Data.File.Content", "$content"); -} - -# ------------------------------------------------------------------------ - 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')); - + my ($list) = new Mail::Ezmlm("$LIST_DIR/" . $q->param('list')); + my ($content) = $q->param('content'); + from_to($content,'utf8',$TEXT_ENCODE); # by ooyama for multibyte + unless ($list->setpart("text/" . $q->param('file'), $content)) { + $warning = 'SaveFile'; + return (1==0); + } } # ------------------------------------------------------------------------ sub webauth { + my $listname = shift; - # Check if webusers file exists - if not, then access is granted - return 0 if (! -e "$WEBUSERS_FILE"); + # Check if webusers file exists - if not, then access is granted + return (0==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; + # if there was no user authentication, then everything is allowed + return (0==0) if ($ENV{'REMOTE_USER'} eq ''); + + # Read authentication level from webusers file. Format of this file is + # somewhat similar to the unix groups file + unless (open (USERS, "<$WEBUSERS_FILE")) { + warn "Unable to read webusers file ($WEBUSERS_FILE): $!"; + $warning = 'WebUsersRead'; + return (1==0); + } + + # TODO: check, why "directly after creating a new list" this does not + # work without the "m" switch for the regexp - very weird! + # the same goes for webauth_create_allowed + # maybe the creating action changed some file access defaults? + while() { + if (/^($listname|ALL):/im) { + # the following line should be synchronized with the webauth_create_allowed sub + if (/^[^:]*:(|.*[\s,])($ENV{'REMOTE_USER'}|ALL)(,|\s|$)/m) { + close USERS; + return (0==0); + } + } + } + close USERS; + return (1==0); } # --------------------------------------------------------------------------- sub webauth_create_allowed { - # Check if we were called with the deprecated argument "-c" (allow to create lists) - return 0 if (defined($opt_c)); + # Check if we were called with the deprecated argument "-c" (allow to create lists) + return (0==0) if (defined($opt_c)); - # Check if webusers file exists - if not, then access is granted - return 0 if (! -e "$WEBUSERS_FILE"); + # if there was no user authentication, then everything is allowed + return (0==0) if ($ENV{'REMOTE_USER'} eq ''); - # 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; + # Check if webusers file exists - if not, then access is granted + return (0==0) if (! -e "$WEBUSERS_FILE"); + + # Read create-permission from webusers file. + # the special listname "ALLOW_CREATE" controls, who is allowed to do it + unless (open (USERS, "<$WEBUSERS_FILE")) { + warn "Unable to read webusers file ($WEBUSERS_FILE): $!"; + $warning = 'WebUsersRead'; + return (1==0); + } + + while() { + if (/^ALLOW_CREATE:/im) { + # the following line should be synchronized with the webauth sub + if (/[:\s,]($ENV{'REMOTE_USER'}|(ALL))(,|\s|$)/m) { + close USERS; + return (0==0); + } + } + } + close USERS; + return (1==0); } # --------------------------------------------------------------------------- -sub display_options { - my($opts) = shift; - my($i, $j); - - # TODO: remove when migration to cs is done - $j = 0; - # convert EZMLM_LABELS to hdf-language values - foreach $i (grep {/\D/} keys %EZMLM_LABELS) { - $pagedata->setValue("Data.ListOptions." . $i . ".name", "$i"); - $pagedata->setValue("Data.ListOptions." . $i . ".short", "$EZMLM_LABELS{$i}[0]"); - $pagedata->setValue("Data.ListOptions." . $i . ".long", "$EZMLM_LABELS{$i}[1]"); - $pagedata->setValue("Data.ListOptions." . $i . ".state", ($opts =~ /^\w*$i\w*\s*/)? 1 : 0); - $j++; - } - $pagedata->setValue("Data.ListOptionsCount", "$j"); - - $j = 0; - # convert EZMLM_LABELS to hdf-language values - foreach $i (grep {/\d/} keys %EZMLM_LABELS) { - $pagedata->setValue("Data.ListSettings." . $i . ".name", "$i"); - $pagedata->setValue("Data.ListSettings." . $i . ".short", "$EZMLM_LABELS{$i}[0]"); - $pagedata->setValue("Data.ListSettings." . $i . ".long", "$EZMLM_LABELS{$i}[1]"); - $pagedata->setValue("Data.ListSettings." . $i . ".state", ($opts =~ /$i (?:'(.+?)')/)? 1 : 0); - $pagedata->setValue("Data.ListSettings." . $i . ".value", $1||$EZMLM_LABELS{$i}[2]); - $j++; - } - $pagedata->setValue("Data.ListSettingsCount", "$j"); - -} - -# --------------------------------------------------------------------------- - -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 :) @@ -1002,34 +1218,19 @@ sub rmtree { # ------------------------------------------------------------------------ -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 - } - - sub error_die { - my $msg = @_; - $pagedata->setValue("Data.ErrorMessage", "$msg"); - # TODO: besser waere eine Warnung in header.cs - $pagename = 'error'; - &output_page; - die; - } +sub fatal_error() { + my $text = shift; + print "Content-Type: text/html; charset=utf-8\n\n"; + print "\n"; + print "ezmlm-web\n"; + print "

a fatal error occoured!

\n"; + print "

$text

\n"; + print "

check the error log of your web server for details

\n"; + print "\n"; + die "$text"; } - + # ------------------------------------------------------------------------ # End of ezmlm-web.cgi v2.3 # ------------------------------------------------------------------------ diff --git a/ezmlmwebrc b/ezmlmwebrc index a68fca6..7f6d6ac 100644 --- a/ezmlmwebrc +++ b/ezmlmwebrc @@ -25,21 +25,18 @@ $LANGUAGE_DIR = "/usr/local/share/ezmlm-web/lang"; $TEMPLATE_DIR = "/usr/local/share/ezmlm-web/template"; # Safe list deletion? -# 0 = move list to .list and the .qmails to deleted.qmail/. Recoverable :) +# 0 = move list to $LIST_DIR/_deleted_lists -> 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 ;) +# Who is the qmail 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'; +# default mailing list domain name (optional) +#$MAIL_DOMAIN = 'lists.someserver.org'; # Do we want to allow ``pretty'' names - ie more human readable ones # This will slow ezmlm-web down a bit for large lists @@ -54,34 +51,13 @@ $FILE_UPLOAD = 1; # 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://systemausfall.org/misc/ezmlm-web-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.3) A web interface to ezmlm
'; - -# NEW: -# html properties (e.g. color, background-color) can be defined in a -# stylesheet (see HTML_CSS_FILE) since version 2.3 - # What is the title of this document? -$HTML_TITLE = 'E Z Mailing List Manager'; +$HTML_TITLE = "ezmlm-web - a mailinglists' administration interface"; # Optional: use a cascading style sheet (css) -$HTML_CSS_FILE = "css/default.css"; +# this is a URL - you have to copy the css file to the right location before +$HTML_CSS_FILE = "/ezmlm-web.css"; # choose a language (en|de) $HTML_LANGUAGE = 'en'; -# --------------------------------------------------------------------------- -# include language-specific definitions -require($LANGUAGE_DIR . '/' . $HTML_LANGUAGE . '.pm'); - diff --git a/htaccess.sample b/htaccess.sample index b381a14..0599b5b 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -1,9 +1,7 @@ -#$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 +AuthName "EZ Mailing List Manager" +AuthType Basic +AuthUserFile /etc/ezmlm/.htusers +require valid-user diff --git a/lang/de.hdf b/lang/de.hdf new file mode 100644 index 0000000..2b4b714 --- /dev/null +++ b/lang/de.hdf @@ -0,0 +1,224 @@ +LanguageID = de + +LanguageName = Deutsch + +Lang { + + Menue { + ListCreate = Neue Liste anlegen + ListDelete = Liste löschen + Subscribers = AbonnentInnen + AllowList = Zulassungsliste + DenyList = Ablehnungsliste + DigestList = Zusammenfassung + ModList = ModeratorInnen + ConfigMain = Einstellungen + ConfigSub = Einschreibung + ConfigPost = Einsendung + ConfigAdmin = Administration + ConfigArchive = Archivierung + ConfigProcess = Verarbeitung + ConfigAll = Übersicht + TextFiles = Texte + ListSelect = Auswahl einer Liste + Properties = Eigenschaften von + Help = Hilfe (extern) + } + + + Title { + ConfigMain = Listeneinstellungen + ConfigSub = Einschreibungsregeln + ConfigPosting = Einsendungsregeln + ConfigAdmin = Fern-Administration der Liste + ConfigArchive = Archivierung der Liste + ConfigProcess = Nachrichtenverarbeitung + ConfigAll = Einstellungen im Überblick + SubscriberList = AbonnentInnen der Liste + AllowList = Zugelassene Nutzer + DenyList = Abzuweisende Nutzer + DigestList = EmpfängerInnen von Zusammenfassungen + ModList = ModeratorInnen der Liste + ListCreate = Anlegen einer neuen Liste + ListSelect = Auswählen einer Liste + ListDelete = Löschung von + FileSelect = Auswählen eines Textbausteins + FileEdit = Bearbeitung des Textbausteins + } + + + Buttons { + Create = Erzeuge die Liste + ConfirmDeletion = Lösche die Liste + DeleteAddress = Adresse(n) entfernen + AddAddress = Adresse(n) hinzufügen + UpdateConfiguration = Einstellungen speichern + EditFile = Datei bearbeiten + SaveFile = Datei speichern + } + + + ErrorMessage { + UnknownAction = Diese Aktion ist undefiniert! + ParameterMissing = Diese Aktion benätigt weitere Parameter! + Forbidden = Fehler: dir fehlen die notwendigen Rechte für diese Aktion + InvalidFileName = Der Dateiname ist nicht zulässig. + UnknownConfigPage = Die gähle Konfigurations-Seite existiert nicht! + } + + + WarningMessage { + AddAddress = Mindestens eine Mailadresse konnte nicht hinzugefügt werden! + DeleteAddress = Mindestens eine der angegebenen Adressen konnte nicht entfernt werden! + CreateList = Fehler beim Anlegen der neuen Liste! + DeleteList = Die Löschung der Mailingliste schlug fehl! + UpdateConfig = Beim Speichern der Einstellungen trat ein Fehler auf! + SaveFile = Die Datei konnte nicht gespeichert werden! + ListNameAlreadyExists = Es gibt bereits eine Liste mit diesem Namen. + ListAddressAlreadyExists = Es gibt bereits eine Liste mit dieser Adresse. + ListDoesNotExist = Eine Liste dieses Namens existiert nicht. + ListDirAccessDenied = Fehler beim Zugriff auf das Verzeichnis der Liste + TextDirAccessDenied = Beim Zugriff auf das Text-Verzeichnis der Liste trat ein Fehler auf. + SafeRemoveRenameDirFailed = Das Verschieben der Liste schlug fehl. + DotQmailDirAccessDenied = Fehler beim Zugriff auf das Nutzerverzeichnis des Listenverwalters + SafeRemoveMoveDotQmailFailed = Beim Verschieben der .qmail-Dateien trat ein Fehler auf! + UnsafeRemoveListDirFailed = Fehler beim sicheren Löschen der Mailingliste + UnsafeRemoveDotQmailFailed = Fehler beim Löschen der .qmail-Dateien + InvalidFileFormat = Die gewählte Datei konnte nicht als Textdatei erkannt werden. + WebUsersUpdate = Fehler beim Aktualisieren der Nutzerverwaltungsdatei + WebUsersRead = Fehler beim Lesen der Nutzerverwaltungsdatei + InvalidListName = Der gewählte Listenname enthält unzulässige Zeichen + ReservedListName = Dieser Listenname ist ein reserviertes Wort und kann nicht benutzt werden + EmptyListName = Es wurde kein Name für die Listen angegeben. + InvalidLocalPart = Die gewählte untergeordnete Liste ist ungültig. + } + + + SuccessMessage { + AddAddress = Einschreibung erfolgreich + DeleteAddress = Austragung erfolgreich abgeschlossen + CreateList = Die neue Liste wurde erfolgreich angelegt. + DeleteList = Die Mailingliste wurde gelöscht. + UpdateConfig = Die neuen Einstellungen wurden erfolgreich gespeichert. + SaveFile = Die Datei wurde gespeichert. + } + + + Options { + a = Archiviere Mailinglisten-Mails + b = Nur Moderatoren dürfen auf das Archiv zugreifen + d = Aktiviere die Zusammenfassungsliste + f = Füge ein Präfix zum Betreff der ausgehenden Mails hinzu + g = Verweigere unbekannten NutzerInnen den Zugriff auf das Archiv + h = Bei der Einschreibung in die Liste ist keine Bestätigungsmail erforderlich + i = Indiziere die Nachrichten zur Veröffentlichung im Internet (z.B. mit ezmlm-www) + j = Beim Austragen aus der Liste ist keine Bestätigungsmail erforderlich + k = Beachte die Ablehnungsliste bei der Verarbeitung von Mails + l = Fern-AdministratorInnen (ModeratorInnen) dürfen eine Liste der AbonnentInnen anfordern + m = Alle eingehenden Nachrichten werden moderiert + n = Fern-AdministratorInnen (ModeratorInnen) dürfen Textbausteine per Mail verändern + o = Nur ModeratorInnen dürfen Nachrichten einsenden + p = Die Einschreibung und der Zugriff auf das Archiv sind öffentlich zugänglich + q = Verarbeite auch Anfragen im Mailman-Stil (Kompatibilität) + r = Erlaube die Fern-Administration der Liste (für ModeratorInnen) + s = Die Einschreibung in die Liste und für die Zusammenfassungen wird moderiert + t = Hänge eine Signatur an jede versandte Nachricht + u = Einsendungen von AbonnentInnen werden immer akzeptiert (dies gilt auch für moderierte Listen) + w = Entferne den Aufruf von ezmlm-warn aus den Verarbeitungsregeln (für sehr spezielle Konfigurationen) + x = Prüfe die MIME-Typen der Anhänge eingehender Nachrichten + y = Fordere eine Bestätigung für jede eingesandte Nachricht an + } + + + Settings { + 0 = Diese Liste is nur eine Unterliste + 3 = Definiere die Absender-Adresse ausgehender Mails + 4 = Eigene Einstellungen zum Versand von Zusammenfassungsmails (ezmlm-tstdig) + 5 = Lege die Mailadresse des Verantwortlichen für diese Liste fest + 6 = Verwende eine SQL-Datenbank + 7 = Die Datenbank der Nachrichten-ModeratorInnen befindet sich in einem alternativen Verzeichnis + 8 = Die Datenbank der Einschreibe-ModeratorInnen (und Fern-AdministratorInnen) befindet sich in einem alternativen Verzeichnis + # 9 => not used - it is only an alternative to (8) + } + + + Misc { + HelpLink = Das online-Handbuch von ezmlm-idx + Subscription = Einschreibung + Subscribers = AbonnentInnen + RemoteAdmin = Fern-AdministratorIn + ListName = Name der Liste + ListAddress = Addresse der Liste + ListOptions = Grundlegende Einstellungen + AllowedToEdit = Nutzer, die diese Liste per Web-Interface konfigurieren dürfen: + HeaderRemove = zu entfernende Kopfzeilen + HeaderAdd = hinzuzufügende Kopfzeilen + MimeRemove = Nachrichtenbestandteile dieses Typs werden entfernt + MimeReject = Nachrichten, die einen der folgenden Datentypen enthalten, werden abgewiesen + EditFileInfo { + CommonTags = allgemeine Platzhalter + ListNameLocal = der lokale Teil (vor dem "@") der Listenadresse + ListNameHost = die Domain der Mailadresse + MessageNumber = die Nummer der jeweiligen Nachricht + SubAddress = die Einschribe-Adresse + SubReplyAddress = die Bestätigungsadresse + AcceptanceAddress = die Zustimmungsadresse + RejectionAddress = die Ablehnungsadresse + } + SuggestDefaultPath = Ansonsten musst du diese Mitglieder per Hand verwalten. + PostModPathWarn = Die Nachrichten-ModeratorInnen werden nicht an ihrem üblichen Ort gespeichert. + SubModPathWarn = Die Einschreibe-ModeratorInnen werden nicht an ihrem üblichen Ort gespeichert. + RemoteAdminPathWarn = Die Fern-AdministratorInnen werden nicht an ihrem üblichen Ort gespeichert. + MessageSize.Max = Verweigere die Annahme von Nachrichten, die eine gewisse Größe überschreiten + MessageSize.Min = Verweigere die Annahme von Nachrichten, die eine gewisse Größe unterschreiten + MessageSize.Unit = Bytes + NoFiles = Es befinden sich keine Dateien im Text-Verzeichnis der Mailingliste. + AddSubscriberAddress = Füge eine neue Mailadresse hinzu: + AddSubscriberFile = Importiere eine Datei, die Mailadressen enthält: + SuggestDefaultPath = Es wird empfohlen, das Standard-Verzeichnis zu verwenden. Andernfalls kannst du die ModeratorInnen-Liste nicht mit ezmlm-web verwalten. + FooterText = eine Web-Oberfläche für + NoListsAvailable = Es sind keine passenden Listen vorhanden. + ConfirmDelete = Willst du wirklich diese Liste vollständig löschen? + } + + + Introduction { + ConfigAdmin = Fern-AdministratorInnen sind (per Voreinstellung) auch ModeratorInnen für die Einschreibung und für eingesandte Mails. Sie können berechtigt sein, per Mail Nutzer ein- und auszutragen, sowie Textbausteine zu verändern. + ConfigArchive = Das Mailinglisten-Archiv ist per Mail verfügbar. Außerdem benötigst du ein Archiv, falls du vergangene Mails im Internet zur Verfügung stellen möchtest (z.B. mit ezmlm-www). + ConfigProcess = Die folgenden Regeln werden auf alle Mails angewandt, bevor sie an die AbonnentInnen verteilt werden. + ConfigMain = Hier findest du ein paar allgemeine Einstellungen der Mailingliste, die sich nicht in den themenorientierten Rubriken unterbringen ließen. + ConfigPosting = Die Einsende-Konfiguration bestimmt, wer Nachrichten einsenden darf und welchen Bedingungen die Mails genügen müssen. + ConfigSub = Hier kannst du festlegen, wer sich als Abonnent selbständig eintragen darf und wie der Einschreibungsprozess abläuft. + ConfigAll = Diese Seite enthält alle verfügbaren Optionen auf einen Blick. + ListDelete = Die Mailingliste und alle damit verbundenen Daten werden hiermit vollständig entfernt. + AllowList = An die Adressen der Zulassungsliste werden keine Mails verschickt. Einsendungen von diesen Adressen werden so behandelt, als kämen sie von AbonnentInnen. Üblicherweise solltest du Aliase von AbonnentInnen in die Zulassungsliste eintragen. + DenyList = Falls du Mails von bestimmte Mailadressen verweigern möchtest, dann füge sie einfach zur Ablehnungsliste hinzu Dies kann nützlich sein, um unbeliebte Nutzer auszuschließen oder um störende Abwesenheitsbenachrichtigungen zu verhindern. + DigestList = Einige AbonnentInnen deiner Mailingliste sind möglicherweise nicht an jeder einzelnen Nachricht interessiert, sondern ziehen es vor, stattdessen regelmäßig automatisch erstellte Zusammenfassungen zu erhalten. + ModList = ModeratorInnen (für die Einschreibung von AbonnentInnen und die Einsendungen an die Liste) und Fern-AdministratorInnen können die Kontrolle über viele wichtige Aspekte der Liste übernehmen (falls du sie dementsprechend konfigurierst). + SubscriberList = Die AbonnentInnen der Mailingliste empfangen alle versandten Nachrigten der Liste. Zudem kann es ihnen gestattet sein, Nachrichten direkt oder indirekt zur weiteren Verteilung an die Liste zu senden. Oft ist es anonymen Nutzern gestattet, sich selbständig in die Mailingliste einzuschreiben, ohne die Hilfe eines Administrators in Anspruch nehmen zu müssen. + TextFiles = Das Auswahlfeld beinhaltet die Liste aller verfügbaren Textbausteine im Texte-Verzeichnis der Liste. Diese Textbasuteine werden zur Erstellung der automatischen Antworten der Mailingliste benutzt. + EditTextFile = Passe den Textbaustein an die Erfordernisse der Liste an. Eventuell möchtest du dafür auch einige der reservierten Platzhalter verwenden, die am Ende dieser Seite aufgeführt sind. + } + + Legend { + ConfigAdmin = Fern-Administrations-Rechte + ConfigArchve = Archivierungseinstellungen + ConfigPosting = Einsende-Regeln + ConfigSub = Einschreibungsdetails + ConfigMain = Allgemeine Listen-Einstellungen + ConfigProcess = Verarbeitungsregeln + ConfigAll = Einstellungen + ListCreate = Eigenschaften der neuen Liste + ListDelete = Löschung der Mailingliste + RelevantOptions = Relevante Optionen + MembersList = AbonnentInnen-Verwaltung + MembersAllow = Verwaltung der zulässigen Adressen + MembersDeny = Verwaltung der abzulehnenden Adressen + MembersDigest = Verwaltung der AbonnentInnen der Zusammenfassungen + MembersMod = Verwaltung der ModeratorInnen / AdministratorInnen + TextFiles = Verfügbare Textbausteine + TextFileEdit = Bearbeite einen Textbaustein + TextFileInfo = Nützliche Platzhalter + AvailableLists = Verfügbare Listen + } +} diff --git a/lang/de.pm b/lang/de.pm deleted file mode 100644 index f8d8cee..0000000 --- a/lang/de.pm +++ /dev/null @@ -1,187 +0,0 @@ -# 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 hinzufuegen'], - b => ['Archiv nur fuer 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 regelmaessige Zusammenfassungen versandt werden'], -# e => edit. Also implicity called, so not defined here - f => ['Listenname als Praefix in Betreff einfuegen', - 'In die versandten Mails wird in der Betreff-Zeile ein Praefix eingefuegt'], - g => ['Archiv nur fuer Mitglieder', - 'Nur TeilnehmerInnen der Liste erhalten Zugriff zum Archiv'], - h => ['einschreiben ohne Bestaetigung', - 'Das Abonnieren der Liste erfordert keine Bestaetigung durch die neue AbonnentIn'], - i => ['Web-Index erstellen', - 'Den Zugriff auf das Archiv per Webinterface erlauben'], - j => ['abmelden ohne Bestaetigung', - 'Das Abbestellen der Liste erfordert keine Bestaetigung durch die ehemalige AbonnentIn'], - k => ['Beachte Ausschlussliste', - 'Einsendungen von AbonnentInnen, die inm deny-Verzeichnis enthalten sind, werden abgelehnt'], - l => ['AbonnentInnen-Auflistung fuer AdministratorInnen', - 'Die AdministratorInnen koennen eine Liste aller AbonnentInnen anfordern'], - m => ['Moderation aktivieren', - 'Alle eingehenden Nachrichten muessen durch eine ModeratorIn bestaetigt werden'], - n => ['Anpassung der Textbausteine erlauben', - 'AdministratorInnen duerfen die Standard-Textbausteine per Mail veraendern'], - o => ['Nur ModeratorInnen duerfen einsenden', - 'Nur eingehende Nachrichten von den ModeratorInnen werden akzeptiert'], - p => ['oeffentlich', - 'Die oeffentliche 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 => ['Einschreibung durch ModeratorIn bestaetigen', - 'Die Einschreibungen in die Liste und die Zusammenfassungs-Liste werden moderiert'], - t => ['Infotext an Mails anhaengen', - 'An alle ausgehenden Mails wird ein Anhang angefuegt (siehe Datei "text/trailer")'], - u => ['Nur AbonnentInnen duerfen 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 Anhaenge 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 => ['AbsenderIn', - 'Ersetze die AbsenderIn 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 der Verantwortlichen der Liste', - 'Mail-Adresse der Listen-EigentuemerIn', - 'name@domain.org'], - 6 => ['SQL-Datenbank', - 'SQL-Datenbank-Zugangsinformationen (erfordert SQL-Unterstuetzung)', - 'host:port:user:password:datab:table'], - 7 => ['Listen-Moderations-Verzeichnis', - 'alternatives Verzeichnis zur Moderationsdatenbank', - '/absoluter/pfad/zur/moderations/datenbank'], - 8 => ['Einschreibungs-Moderations-Verzeichnis', - 'alternatives Verzeichnis zur Einschreibungs-Moderationsdatenbank', - '/absoluter/pfad/zur/abonnenten/moderations/datenbank'], - 9 => ['Administrations-Verzeichnis', - 'alternatives Verzeichnis zur Administrationsdatenbank', - '/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 moeglich', - moderator => 'ModeratorInnen kontrollieren, welche Mails weitegeleitet und welche AbonnentInnen akzeptiert werden', - deny => 'Ausschluss: die Mail-Adressen, die NIE an die Liste schreiben duerfen', - allow => 'Zulassung: die Mail-Adressen, die immer an die Liste schreiben duerfen', - digest => 'Zusammenfassung: diese Leute werden regelmaessige 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 geaendert werden', - webusers => 'unfertig: derzeit koennen Listen-AdministratorInnen nur manuell festgelegt werden', - prefix => 'Praefix der Betreffzeile', - headerremove => 'Diese Kopfzeilen werden aus den ausgehenden Mails entfernt', - headeradd => 'Diese Kopfzeilen werden zu jeder ausgehenden Mail hinzugefuegt', - mimeremove => 'Alle Mails, die die genannten Anhangs-Typen beinhalten, werden abgewiesen', - allowedit => 'Komma-getrennte Liste von (existierenden) NutzerInnen 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 => 'Fuege Adresse hinzu', - moderators => 'ModeratorInnen', - denylist => 'Ausschlussliste', - allowlist => 'Zulassungsliste', - digestsubscribers => 'AbonnentInnen 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 Funktionalitaet 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 moechtest.
  • Klicke auf den [$BUTTON{'delete'}]-Schalter, falls du die markierte Liste loeschen moechtest.
", - confirmdelete => 'Bestaetige die Loeschung von ', # list name - subscribersto => 'AbonnentInnen von', # list name - subscribers => 'AbonnentInnen', - additionalparts => 'Weitere Optionen', - posting => 'Einsendungen', - subscription => 'Einschreibung', - remoteadmin => 'Entfernte AdministratorIn', - for => 'fuer', # as in; moderators for blahlist - createnew => 'Lege eine neue Liste an', - listname => 'Name der Liste', - listaddress => 'Adresse der Liste', - listoptions => 'Einstellungen der Liste', - allowedtoedit => 'NutzerInnen, die diese Liste bearbeiten duerfen', - editconfiguration => 'Einstellungen aendern', - prefix => 'Praefix der Betreff-Zeile ausgehender Nachrichten', - headerremove => 'zu entfernende Kopfzeilen', - headeradd => 'einzufuegende Kopfzeilen', - mimeremove => 'abzuweisende Anhangs-Typen', - edittextinfo => "Das Auswahlfeld links enthaelt 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 veraendern, waehle ihren Namen im Auswahlfeld an. Anschliessend klicke auf den [$BUTTON{'editfile'}] Schalter.

BetäAege [$BUTTON{'cancel'}] um die Veraenderung zu beenden.", - editingfile => 'Bearbeite Datei', - editfileinfo => 'ezmlm-manage
<#l#> Der Name der Liste
<#A#> Die Anmeldungs-Adresse
<#R#> Die Bestaetigungs-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/lang/en.hdf b/lang/en.hdf index f722215..42926e1 100644 --- a/lang/en.hdf +++ b/lang/en.hdf @@ -1,168 +1,224 @@ -Language = en - -PageTitle = ezmlm-web - a mailinglists' administration interface +LanguageID = en +LanguageName = English Lang { - Buttons { - Create = [Create List] - Edit = [Edit] - Delete = [Delete] - Yes = [Yes] - No = [No] - Cancel = [Cancel] - DeleteAddress = [Delete Address] - AddAddress = [Add Address] - Moderators = [Moderators] - DenyList = [Deny List] - AllowList = [Allow List] - DigestSubscribers = [Digest Subscribers] - Configuration = [Configuration] - UpdateConfiguration = [Update Configuration] - EditTexts = [Edit Texts] - EditFile = [Edit File] - SaveFile = [Save File] - WebArchive = [Web Archive] - SelectList = [Select List] - Subscribers = [Subscribers] - ResetForm = [Reset Form] - } - - Options { - a.short = Archived - a.long = Ezmlm will archive new messages - b.short = Block archive - b.long = Only moderators are allowed to access the archive -# c => config. This is implicity called, so is not defined here - d.short = Digest - d.long = Set up a digest list to disseminate digest of the list messages -# e => edit. Also implicity called, so not defined here - f.short = Prefix - f.long = Outgoing subject will be prefixed with the list name - g.short = Guard Archive - g.long = Archive access requests from unrecognized SENDERs will be rejected - h.short = Help subscription - h.long = Subscriptions do not require confirmation - i.short = Indexed - i.long = Indexed for WWW archive access - j.short = Jump off - j.long = Unsubscribe does not require confirmation - k.short = Kill - k.long = Posts from addresses in dir/deny/ are rejected - l.short = Subscriber List - l.long = Remote administrators can request a subscriber list - m.short = Message Moderation - m.long = All incoming messages are moderated - n.short = Text Editing - n.long = Allow remote administrators to edit files in dir/text/ - o.short = Others rejected - o.long = Posts from addresses other than moderators are rejected - p.short = Public - p.long = List will respond to administrative requests and archive retrieval - q.short = Service Request Address - q.long = Process commands sent in the subject to local-request@host - r.short = Remote Admin - r.long = Enable remote adminstration of the list - s.short = Subscription Moderation - s.long = Subscriptions to the main list and digest will be moderated - t.short = Trailer - t.long = Add a trailer to outgoing messages - u.short = User Posts Only - u.long = Posts from unrecognized SENDER addresses will be rejected -# v => version. I doubt you will really need this ;-) - w.short = Remove Warn - w.long = Remove the ezmlm-warn(1) invocations from the list setup. It is assumed that ezmlm-warn(1) is run by other means - x.short = Extra - x.long = Strip certain mimetypes, etc -# y => not used -# z => not used - } - - Settings { - 0.short = Sublist - 0.long = Make the list a sublist of list mainlist@host - 0.default = mainlist@host -# 1 => not used -# 2 => not used - 3.short = From Address - 3.long = Replace the "From:" header of the message with "From: fromarg" - 3.default = fromarg - 4.short = Digest Options - 4.long = Switches for ezmlm-tstdig(1) - 4.default = -t24 -m30 -k64 - 5.short = List Owner - 5.default = The email address of the list owner - 6.short = SQL Database - 6.long = SQL database connect information. Requires SQL support - 6.default = host:port:user:password:datab:table - 7.short = Message Moderation Path - 7.long = Make /path the path to the database for message moderators, if the list is set up for message moderation - 7.default = /some/full/path - 8.short = Subscription Moderation Path - 8.long = Make /path the path to the database for message moderators, if the list is set up for message moderation - 8.default = /some/full/path - 9.short = Remote Admin Path - 9.long = Make /path the path to the database for message moderators, if the list is set up for message moderation - 9.default = /some/full/path - } - - - Helper { - 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 - SelectList = Go back to list selection - } - - - Misc { - ListSelectDescription { - 1 = choose a mailing list from the selection box or click on [Create List] - 2 = click on the [Edit] button if you want to edit the selected list - 3 = click on the [Delete] button if you want to delete the selected list + Menue { + ListCreate = Create new list + ListDelete = Delete list + Subscribers = Subscribers + AllowList = allow list + DenyList = deny list + DigestList = digest list + ModList = moderators + ConfigMain = Options + ConfigSub = subscription + ConfigPost = posting + ConfigAdmin = administration + ConfigArchive = archive + ConfigProcess = processing + ConfigAll = overview + TextFiles = Text files + ListSelect = Choose a list + Properties = Properties of + Help = Help (external) } - UnknownAction = Action not yet implemented - ConfirmDelete = Confirm deletion of - SubscribersTo = Subscribers to - Subscribers = subscribers - AdditionalParts = Additional list parts - Posting = Posting - Subscription = Subscription - RemoteAdmin = Remote Admin - For = for - # as in; "moderators for ..." - 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 [Edit File] button. Press [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 - SuggestEdit = You will have to edit them manually. - PostModPathWarn = Posting Moderators are stored in a non-standard location - SubModPathWarn = Subscriber Moderators are stored in a non-standard location - RemotePathWarn = Remote Administrators are stored in a non-standard location + + + Title { + ConfigMain = List configuration + ConfigSub = Subscription options + ConfigPosting = Posting options + ConfigAdmin = Remote administration + ConfigArchive = Archive options + ConfigProcess = Message processing + ConfigAll = Complete configuration + SubscriberList = Subscribers of the list + AllowList = Allowed users + DenyList = Blocked users + DigestList = Digest subscribers + ModList = Moderators of the mailinglist + ListCreate = Create a new list + ListSelect = Choose a list + ListDelete = Delete list + FileSelect = Choose a file for editing + FileEdit = Editing file + } + + + Buttons { + Create = Create list + ConfirmDeletion = Delete the list + DeleteAddress = Delete address(es) + AddAddress = Add address(es) + UpdateConfiguration = Update configuration + EditFile = Edit file + SaveFile = Save File + } + + + ErrorMessage { + UnknownAction = this action is undefined + ParameterMissing = this action needs one or more parameters + Forbidden = Error: you are not allowed to do this! + InvalidFileName = The name of the file is invalid! + UnknownConfigPage = The chosen config page is invalid! + } + + + WarningMessage { + AddAddress = Adding of at least one mail address failed! + DeleteAddress = Removal of at least one mail address failed! + CreateList = Creation of new mailing list failed! + DeleteList = Removal of mailing list failed! + UpdateConfig = Update of configuration failed! + SaveFile = The file could not be saved! + ListNameAlreadyExists = There is already a list with this name! + ListAddressAlreadyExists = There is already a list with this address! + ListDoesNotExist = A list with this name does not exist! + ListDirAccessDenied = Unable to access the list's directory + TextDirAccessDenied = Unable to access the list's directory of text files + SafeRemoveRenameDirFailed = Unable to rename list for safe removal + DotQmailDirAccessDenied = Unable to read the mail user's home directory for .qmail files + SafeRemoveMoveDotQmailFailed = Unable to move .qmail files + UnsafeRemoveListDirFailed = Unable to delete list + UnsafeRemoveDotQmailFailed = Unable to delete .qmail files + InvalidFileFormat = The uploaded file must be a text file + WebUsersUpdate = Could not update the webusers file + WebUsersRead = Could not read the webusers file + InvalidListName = The name of the list contains invalid characters + ReservedListName = This listname may not be used as it is reserved for internal purposes + EmptyListName = The name of the list may not be empty + InvalidLocalPart = The local part of the list address is not valid + } + + + SuccessMessage { + AddAddress = The address was added to the list. + DeleteAddress = The address was removed from the list. + CreateList = The new mailing list was successfully created. + DeleteList = The mailing list was successfully removed. + UpdateConfig = The mailing list's configuration was successfully changed. + SaveFile = The file was saved. + } + + + Options { + a = Archive mailing list messages + b = Only moderators are allowed to access the archive + d = Activate the digest list + f = Add a prefix to the subject line of outgoing messages + g = Archive requests from unrecogniced senders are denied + h = Subscriptions do not require confirmation by the user + i = Index mailing list messages for WWW archive access + j = Unsubscribe does not require confirmation + k = Use deny list to prevent some users from posting + l = Remote administrators (moderators) may request a subscriber list + m = All incoming messages are moderated + n = Remote administrators (moderators) may edit text files in DIR/text + o = Only moderators may post + p = Allow subscription and archive retrieval for everyone + q = Process mailman-style requests (to local-request@domain) + r = Enable remote administration of the list (for moderators) + s = Subscriptions to the main list and the digest list will be moderated + t = Add a trailing text to every message + u = Subscribed users may always post messages (even ignoring moderation) + w = Remove the ezmlm-warn invocations from the list setup (rarely useful) + x = Remove or reject specific mime types in messages + y = Request a confirmation mail for every posted message + } + + + Settings { + 0 = Make the list a sublist of list mainlist@host + 3 = Set a custom "From:" header for outgoing messsages + 4 = Define customized setting for digest creation (ezmlm-tstdig) + 5 = Define the email address of the list owner + 6 = Use a SQL database + 7 = Define a custom path to the database for posting moderators + 8 = Define a custom path to the database for remote administrators and subscription moderators + # 9 => not used - it is only an alternative to (8) } + + + Misc { + HelpLink = The manual page of ezmlm-idx + Subscription = Subscription + Subscribers = subscribers + RemoteAdmin = Remote Admin + ListName = List Name + ListAddress = List Address + ListOptions = Basic List Options + AllowedToEdit = Users allowed to edit this list via web interface: + HeaderRemove = Headers to strip from every outgoing mail + HeaderAdd = Headers to add to all outgoing mail + MimeRemove = Mime types to strip from all outgoing mail + MimeReject = Messages containing any of these mime type will be rejected + EditFileInfo { + CommonTags = common tags + ListNameLocal = The local part of the list name + ListNameHost = The host name of the list name + MessageNumber = Number of the respective message + SubAddress = The subscription address + SubReplyAddress = The address a subscriber must reply to + AcceptanceAddress = The acceptance address + RejectionAddress = The rejection address + } + SuggestDefaultPath = You will have to manage them manually. + PostModPathWarn = Posting moderators are stored in a non-standard location + SubModPathWarn = Subscription moderators are stored in a non-standard location + RemoteAdminPathWarn = Remote administrators are stored in a non-standard location + MessageSize.Max = Reject messages exceeding a specified value + MessageSize.Min = Reject messages smaller than a specified value + MessageSize.Unit = bytes + NoFiles = There are no files in the text directory of the mailinglist. + AddSubscriberAddress = Add a new mail address: + AddSubscriberFile = Upload a file containing mail addresses to be added: + SuggestDefaultPath = It is recommended to use the default path for the moderation database. Otherwise you cannot manage the moderators' list with ezmlm-web. + FooterText = a web interface for + NoListsAvailable = I could not find any accessible list for you. + ConfirmDelete = Do you really want to remove this list completely? + } + + + Introduction { + ConfigAdmin = Remote administrators are (by default) also moderators for subscription and for posting. They may have the permission to (un)subscribe users and to change the text files of the list by sending emails to the mailing list software. + ConfigArchive = The mailing list archive can be accessed by mail. Additionally you will want to create a list archive, if you plan to publish it (e.g. with ezmlm-www). + ConfigProcess = Modify some message properties, before they are distributed to the subscribers. + ConfigMain = Here you find some settings, that did not fit into any other category. + ConfigPosting = The posting configuration determines, who is allowed to send messages to the list and how these mails will be processed. + ConfigSub = Here you may define, who is allowed to subscribe to the list and you can set some details of the subscription process. + ConfigAll = This is the complete list of all available properties of the list. Usually it should be easier to use the topic-based configuration pages, but - of course - this is your choice. + ListDelete = This mailinglist and everything inside of it will be removed completely. + AllowList = Members of the allow list will not receive outgoing mails, but they have the same rights, as normal subscribers. Usually the allow list will contain mail aliases of subscribers. + DenyList = If you want to prevent specific mail addresses from using this list (subscription, posting, ...), then you should add them to the deny list and activate it. This can be useful for annoying people and even for notorious vacation reply users. But since it is fairly easy to fake an mail address, this will not really improve security. + DigestList = Some users of your mailing list may prefer to receive a regular digest instead of all mailing list messages. They will usually not take part in discussions, but aret somehow interested anyway. + ModList = Moderators (for posting or subscription) and remote administrators can be allowed to manage the most important parts of mailing list administration: moderating subscription and posting, changing filtering rules, and managing users. Moderators may even be configured to be the only ones, who are allowed to send mails to the mailing list. + SubscriberList = Subscribers of a mailing list will receive all outgoing message of the list. They may also be allowed to post messages directly or moderated. Usually anonymous users are able to subscribe and unsubscribe without the help of an administrator - but of course, you may configure this to suit your needs. + TextFiles = The selection box contains a list of files available in the DIR/text directory. These files are sent out in response to specfic user requests or as part of all outgoing messages. Edit them as necessary. + EditTextFile = Change this text according to your needs. Maybe you would like to use some of the reserved tags, that are described at the bottom of this page. + } + + Legend { + ConfigAdmin = Remote administrator's permissions + ConfigArchve = Archive configuration + ConfigPosting = Posting rules + ConfigSub = Subscription details + ConfigMain = General list configuration + ConfigProcess = Processing rules + ConfigAll = Available properties + ListCreate = Properties of the new list + ListDelete = Remove this mailinglist + RelevantOptions = Useful settings + MembersList = Manage subscribers + MembersAllow = Manage allowed users + MembersDeny = Manage blocked users + MembersDigest = Manage digest subscribers + MembersMod = Manage moderators and administrators + TextFiles = Available text files + TextFileEdit = Edit content of text file + TextFileInfo = Useful placeholders + AvailableLists = Available lists + } } diff --git a/lang/en.pm b/lang/en.pm deleted file mode 100644 index 25bd2b1..0000000 --- a/lang/en.pm +++ /dev/null @@ -1,187 +0,0 @@ -# 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/lang/jp.pm b/lang/jp.pm new file mode 100644 index 0000000..522fbad --- /dev/null +++ b/lang/jp.pm @@ -0,0 +1,187 @@ +# language-specific definitions for ezmlm-web +# in Japanese + +# 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 => ['アーカイブ保存', + 'メッセージをアーカイブする'], + b => ['アーカイブブロック', + 'モデレータのみアーカイブにアクセス可能'], +# c => config. This is implicity called, so is not defined here + d => ['ダイジェスト作成', + 'メッセージのダイジェストリストをセットアップする'], +# e => edit. Also implicity called, so not defined here + f => ['件名にPrefixを付加する', + '件名に指定したPrefix文字を付加する'], + g => ['アーカイブ制限', + '送信者が未登録の場合アーカイブのアクセスを拒否する'], + h => ['登録確認をしない', + 'メールによる登録時に確認メールを送らない'], + i => ['インデックス作成', + 'WWW アーカイブアクセス用インデックスの作成'], + j => ['登録解除確認をしない', + 'メールによる登録解除時に確認メールを送らない'], + k => ['拒否リスト有効', + '拒否リストに登録されたアドレスを拒否する'], + l => ['登録者リスト取出', + '遠隔管理者に登録者リストを送る'], + m => ['投稿の審査', + '全ての投稿メッセージを審査する'], + n => ['テキスト編集', + '遠隔管理者にテキスト編集を許可する'], + o => ['モデレータのみ投稿可', + 'モデレータ以外の投稿を拒否する'], + p => ['公開する', + 'メールによる登録、登録解除などを有効にする'], + q => ['リクエスト形式有効', + 'local-request@host のメールを処理する'], + r => ['遠隔管理', + '遠隔管理を有効にする'], + s => ['登録の審査', + '登録を審査する'], + t => ['Trailerを付加する', + 'メッセージの末尾にTrailerを付加する'], + u => ['登録者のみ投稿可', + '登録者の投稿のみを受け付ける'], +# v => version. I doubt you will really need this ;-) + w => ['警告を出さない', + 'ezmlm-warn(1) の挙動を抑止する'], + x => ['指定mime typeの削除', + '指定したmime typeの貼付ファイルを削除する'], +# y => not used +# z => not used + +# These all take an extra argument, which is the default value to use + + 0 => ['サブリストにする', + '指定したメインリストのサブリストにする', + 'mainlist@host'], +# 1 => not used +# 2 => not used + 3 => ['送信者アドレス固定', + '指定した Fromアドレスに固定する', + 'fromarg'], + 4 => ['ダイジェストオプション', + 'ezmlm-tstdig(1) のオプションを指定する', + '-t24 -m30 -k64'], + 5 => ['オーナーアドレス', + 'リストオーナーのアドレスを指定する', + ''], + 6 => ['SQLデータベース', + 'SQLデータベースへの接続情報', + 'host:port:user:password:datab:table'], + 7 => ['メッセージモデレータのデータベース', + 'メッセージモデレータのデータベースへのフルパス', + '/some/full/path'], + 8 => ['登録モデレータのデータベース', + '登録モデレータのデータベースへのフルパス', + '/some/full/path'], + 9 => ['遠隔管理者データベース', + '遠隔管理者のデータベースへのフルパス', + '/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 => 'RFC822 に準拠したメールアドレスを入れます 例; J Random User ', + addaddressfile => 'または RFC822 に準拠したアドレスを、1行毎に含むテキストファイルを選択します', + moderator => 'モデレータ: 登録や投稿を審査する人のリスト', + deny => '拒絶リスト: メーリングリストへの参加を拒絶する人のリスト', + allow => '許可リスト: メーリングリストへの参加を特に許可する人のリスト', + digest => 'ダイジェストリスト: 全てのメッセージのダイジェストの受け取りを許可された人のリスト', + webarch => 'ウェブベースのアーカイブリストの閲覧', + config => 'メーリングリストの設定の変更', + listname => 'リスト選択時に表示される名前.また、実際に作成されるサブディレクトリの名前.', + listadd => 'メーリングリストの投稿に使用されるアドレス.特殊な場合を除き、- 以前は変更削除しないこと', + webusers => 'NB! 現在は、ここで指定できるユーザーは実在のユーザーに限る. ユーザーの追加は将来の追加課題', + prefix => '件名の先頭に付加される文字列 #で、メッセージ番号がつきます', + headerremove => 'メッセージから取り除くヘッダーを指定する', + headeradd => 'メッセージに追加するヘッダーを指定する', + mimeremove => '指定した mime type の貼付ファイルをメッセージから削除する', + allowedit => 'ユーザー名のカンマ区切りリストまたは、ALL (有効な全てのユーザー)', + mysqlcreate => 'MySQLに必要なテーブルを作成する' + +); + +# 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 => '作成', + createlist => 'リスト作成', + edit => '編集', + delete => '削除', + deleteaddress => 'アドレス削除', + addaddress => 'アドレス追加', + moderators => 'モデレータ', + denylist => '拒絶リスト', + allowlist => '許可リスト', + digestsubscribers => 'ダイジェスト登録者', + configuration => '設定', + yes => 'はい', + no => 'いいえ', + updateconfiguration => '設定更新', + edittexts => 'テキスト編集', + editfile => 'ファイル編集', + savefile => 'ファイル保存', + webarchive => 'ウェブアーカイブ', + selectlist => 'リスト選択', + subscribers => '登録者編集', + cancel => 'キャンセル', + resetform => 'リセット', + +); + +# 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 => "

  • メーリングリストを選択するか、または、 [$BUTTON{'create'}] ボタンを押して作成してください.
  • 変更する場合は、選択して、 [$BUTTON{'edit'}] ボタンを押してください.
  • 削除する場合は、選択して、 [$BUTTON{'delete'}] ボタンを押してください.
", + confirmdelete => '削除確認', # list name + subscribersto => '登録者編集', # list name + subscribers => '登録者', + additionalparts => 'リスト付加情報', + posting => '投稿', + subscription => '登録', + remoteadmin => '遠隔管理', + for => 'for', # as in; moderators for blahlist + createnew => '新規リスト作成', + listname => 'リスト名', + listaddress => 'リストアドレス', + listoptions => 'リストオプション', + allowedtoedit => 'リスト編集許可者', + editconfiguration => 'リスト設定編集', + prefix => '件名に付加する文字 prefix', + headerremove => '削除するヘッダー情報', + headeradd => '追加するヘッダー情報', + mimeremove => '削除する貼付ファイルのmime type', + edittextinfo => "左側にある一覧は、DIR/text の中にあるテキストファイルです.
これらのファイルは、ユーザーのリクエストに対する返信内容,または、配信されるメールに付加される内容です.

このファイルを編集するには, 左の一覧から選択して、 [$BUTTON{'editfile'}] ボタンを押します.

終了または、中止するときは、[$BUTTON{'cancel'}] ボタンを押します.", + editingfile => 'ファイル編集', + editfileinfo => 'マネージ用
<#l#> リスト名
<#A#> 投稿者アドレス
<#R#> 投稿者が返信するアドレス

メッセージ埋め込み用
<#l#> リスト名
<#A#> 受け取りアドレス
<#R#> 拒絶アドレス', + mysqlcreate => '必要ならば MySQL データベースを作成', + +); + +# === Configuration file ends === diff --git a/spec/actions-spec.txt b/spec/actions-spec.txt new file mode 100644 index 0000000..f5066c9 --- /dev/null +++ b/spec/actions-spec.txt @@ -0,0 +1,40 @@ +subscribers + list + [part] +address_add + list + [part] + [mailaddress_add] + [mailaddressfile] +address_del + list + [part] + mailaddress_del +list_select +list_delete_ask + list +list_delete_do + list +list_create_ask +list_create_do + list + inlocal + inhost + [options] + [sql] +config_ask + list + [config_subset] +config_do + list + [config_subset] + [options] +textfiles + list +textfile_edit + list + file +textfile_save + list + file + content diff --git a/spec/check_languages.sh b/spec/check_languages.sh new file mode 100755 index 0000000..502dbe9 --- /dev/null +++ b/spec/check_languages.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# +# compare the defined fields of a language file with the english translation +# +# nice for finding unavailable definitions +# +# Parameter: LANGUAGE +# (e.g. "de") +# + +set -u + +LANG_DIR=$(dirname $0)/../lang +DEFAULT_LANG=en +TMP_FILE1=/tmp/$(basename $0)-$$-1 +TMP_FILE2=/tmp/$(basename $0)-$$-2 + +[ $# -ne 1 ] && echo -e "Syntax: $(basename $0) LANGUAGE\n" >&2 && exit 1 + +grep "=" "$LANG_DIR/${DEFAULT_LANG}.hdf" | grep -v "^[[:space:]]*#" | cut -f 1 -d "=" >"$TMP_FILE1" +grep "=" "$LANG_DIR/${1}.hdf" | grep -v "^[[:space:]]*#" | cut -f 1 -d "=" >"$TMP_FILE2" + +diff -wu "$TMP_FILE1" "$TMP_FILE2" + +rm "$TMP_FILE1" "$TMP_FILE2" + diff --git a/spec/hdf-spec.txt b/spec/hdf-spec.txt new file mode 100644 index 0000000..fc2f4e6 --- /dev/null +++ b/spec/hdf-spec.txt @@ -0,0 +1,47 @@ +ScriptName +TemplateDir +LanguageDir +Stylesheet +HelpIconURL +Config.Title + +Data.Action +Data.ErrorMessage +Data.List.Address +Data.List.File.Name +Data.List.File.Content +Data.List.Files.* +Data.List.hasAllowList +Data.List.hasDenyList +Data.List.hasDigestList +Data.List.hasPostMod +Data.List.hasRemoteAdmin +Data.List.hasSubMod +Data.List.HeaderAdd +Data.List.HeaderRemove +Data.List.MimeRemove +Data.List.MimeReject +Data.List.MsgSize.Max +Data.List.MsgSize.Min +Data.List.Name +Data.List.PartType +Data.List.PostModPath +Data.List.Options +Data.List.Options.[0-9] +Data.List.Prefix +Data.List.RemoteAdminPath +Data.List.Settings.[0-9].value +Data.List.Settings.[0-9].state +Data.List.SubModPath +Data.List.Subscribers.* +Data.List.TrailingText +Data.List.WebUsers +Data.Lists.[0-9]+ +Data.ListsCount +Data.HostName +Data.Modules.MySQL +Data.Permissions.Create +Data.Permissions.FileUpload +Data.UserName +Data.WebUser.show +Data.WebUser.UserName diff --git a/template/config_admin.cs b/template/config_admin.cs new file mode 100644 index 0000000..4827808 --- /dev/null +++ b/template/config_admin.cs @@ -0,0 +1,39 @@ +

+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • +
      + +
    • + + +
    • + + +
    • +
  • + +
  • + + + +
  • +
+ +
+
+ diff --git a/template/config_all.cs b/template/config_all.cs new file mode 100644 index 0000000..938950d --- /dev/null +++ b/template/config_all.cs @@ -0,0 +1,163 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • + + + +
  • + + +
  • + + +
  • + + +
  • + + +
  • +
    • +
  • + + +
  • + + +
    • +
  • + + +
  • 0 ?>checked="checked" /> + +
  • +
  • 0 ?>checked="checked" /> + +
  • + + +
  • +
      + +
    • :
      +
    • +
    • :
      +
    • +
  • + + +
  • :
    +
  • + + +
  • :
    +
  • + + + +
  • +

    • +
  • + +
  • + + + +
  • +
+ +
+
+ diff --git a/template/config_archive.cs b/template/config_archive.cs new file mode 100644 index 0000000..4cc588b --- /dev/null +++ b/template/config_archive.cs @@ -0,0 +1,42 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • +
      + +
    • + + +
    • + + +
    • +
  • + + +
  • + +
  • + + + +
  • +
+ +
+
+ diff --git a/template/config_list.cs b/template/config_list.cs deleted file mode 100644 index eae79df..0000000 --- a/template/config_list.cs +++ /dev/null @@ -1,58 +0,0 @@ -
-
- -

-

-
-
- - - - - - - -
- - -
- - - # TODO: the same as of "display_list.cs" - # list of moderators/administrators - 0 ?> - - 25) ?> - - - - - - - - -
- - 0) ?> - - - - - - - - - - - - -
- - -
diff --git a/template/config_main.cs b/template/config_main.cs new file mode 100644 index 0000000..af700f3 --- /dev/null +++ b/template/config_main.cs @@ -0,0 +1,50 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • + + +
  • + + +
  • + + +
  • + + + +
  • + + + +
  • +

    • +
  • + +
  • + + + +
  • +
+ +
+ +
diff --git a/template/config_posting.cs b/template/config_posting.cs new file mode 100644 index 0000000..b57740b --- /dev/null +++ b/template/config_posting.cs @@ -0,0 +1,73 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • + + +
  • + + +
  • + + +
  • +
      + +
    • + + +
    • +
  • + + +
  • 0 ?>checked="checked" /> + +
  • +
  • 0 ?>checked="checked" /> + +
  • + + +
  • +
      + +
    • :
      +
    • +
  • + +
  • + + + +
  • +
+ +
+ +
diff --git a/template/config_processing.cs b/template/config_processing.cs new file mode 100644 index 0000000..a888187 --- /dev/null +++ b/template/config_processing.cs @@ -0,0 +1,65 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • +
    • +
  • + + +
  • + + +
    • +
  • + + +
  • + + +
  • +
      + +
    • :
      +
    • +
  • + + +
  • :
    +
  • + + +
  • :
    +
  • + +
  • + + + +
  • + +
+
+
+ + diff --git a/template/config_subscription.cs b/template/config_subscription.cs new file mode 100644 index 0000000..9527f83 --- /dev/null +++ b/template/config_subscription.cs @@ -0,0 +1,42 @@ +
+

+
+ +
+

+
+ +
+ + +
+ + +
    + + +
  • + + +
  • + + +
  • + + +
  • +
      + +
    • +
  • + +
  • + + + +
  • +
+ +
+ +
diff --git a/template/confirm_delete.cs b/template/confirm_delete.cs deleted file mode 100644 index f062fa2..0000000 --- a/template/confirm_delete.cs +++ /dev/null @@ -1,17 +0,0 @@ -
- -
- - -
-

-
- - -
-
-
- -
diff --git a/template/create_list.cs b/template/create_list.cs deleted file mode 100644 index 9819c35..0000000 --- a/template/create_list.cs +++ /dev/null @@ -1,43 +0,0 @@ -
- -
-

-
-
- - -
- -
- : - : - @ - : - - - - - - - - - - : - - # TODO: the following span is quite unusual - - -
- -
- - - -
-
- -
diff --git a/template/display_list.cs b/template/display_list.cs deleted file mode 100644 index 46de0a0..0000000 --- a/template/display_list.cs +++ /dev/null @@ -1,102 +0,0 @@ -
- -
- -

-

-
-
- -
-
- - - - - - 25) ?> - - - - - - - -
- 0) ?> -

- - - -

- -

-

-
-
- - -

:

- -

- - - - - - - - - - - - - - - - - - - - - - - -

- -

- - - - - - - - - - - - -

- -
-
- -
- -
diff --git a/template/display_options.cs b/template/display_options.cs deleted file mode 100644 index dc3a936..0000000 --- a/template/display_options.cs +++ /dev/null @@ -1,23 +0,0 @@ - -

- - -

checked="checked"> -
- -

- -

- -

checked="checked"> - - -
- - -

diff --git a/template/edit_text.cs b/template/edit_text.cs deleted file mode 100644 index 531aa7e..0000000 --- a/template/edit_text.cs +++ /dev/null @@ -1,32 +0,0 @@ -
- -
-

-
- -
- - - - -
- -
- -
- -
- -
- - - -
- -
- -
diff --git a/template/footer.cs b/template/footer.cs index 81bff46..4451b4a 100644 --- a/template/footer.cs +++ b/template/footer.cs @@ -1,9 +1,8 @@ - - -
-ezmlm-web (v2.3) A web interface to ezmlm -
+ diff --git a/template/form_common.cs b/template/form_common.cs new file mode 100644 index 0000000..8b633bc --- /dev/null +++ b/template/form_common.cs @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/template/header.cs b/template/header.cs index 204f502..9c5c0b4 100644 --- a/template/header.cs +++ b/template/header.cs @@ -5,21 +5,21 @@ - <?cs var:PageTitle ?> + <?cs var:Config.PageTitle ?> - + - + - -

-

E Z Mailing List Manager
-

- -
+
+
+ +
+

ezmlm-web

+
diff --git a/template/help_tag_substitution.cs b/template/help_tag_substitution.cs new file mode 100644 index 0000000..4ebd095 --- /dev/null +++ b/template/help_tag_substitution.cs @@ -0,0 +1,21 @@ +
+ + +
    +
    • +
    • <#l#>
    • +
    • <#h#>
    • +
    • <#n#>
    • +
  • +
  • ezmlm-manage
      +
    • <#A#>
    • +
    • <#R#>
    • +
  • +
  • ezmlm-store
      +
    • <#A#>
    • +
    • <#R#>
    • +
  • +
+ +
+ diff --git a/template/list_config.cs b/template/list_config.cs deleted file mode 100644 index a8a3c26..0000000 --- a/template/list_config.cs +++ /dev/null @@ -1,57 +0,0 @@ -
- -
-

-
-
- -
- - -
-

:

-

:

-
- -
-

:

- - - - -
:
- -
: -
-
: -
- -
: -
- - - -
- : - - -
- -
- -
- - - - -
- -
- -
diff --git a/template/list_create.cs b/template/list_create.cs new file mode 100644 index 0000000..56c7281 --- /dev/null +++ b/template/list_create.cs @@ -0,0 +1,40 @@ +
+

+
+ +
+ + +
+
    +
  • +
  • + +
  • + @
  • + + + +
  • + + + +
  • +
  • + + +
+ + + + + + +
+ +
diff --git a/template/list_delete.cs b/template/list_delete.cs new file mode 100644 index 0000000..a8b0773 --- /dev/null +++ b/template/list_delete.cs @@ -0,0 +1,20 @@ +
+

""

+
+ +
+

+
+ +
+ + +

+
+ + + + +
+ +
diff --git a/template/list_select.cs b/template/list_select.cs new file mode 100644 index 0000000..e765f83 --- /dev/null +++ b/template/list_select.cs @@ -0,0 +1,39 @@ +
+

+
+ +
+ + + + + + + + 0 ?> + + + + 0 ?> + + + + + + + + + +
+ + +
+ +

+ + +
+ diff --git a/template/list_textfiles.cs b/template/list_textfiles.cs deleted file mode 100644 index 99298ae..0000000 --- a/template/list_textfiles.cs +++ /dev/null @@ -1,28 +0,0 @@ -
- -
- - - -
- -
- -
- -
- -
- - -
- -
- -
diff --git a/template/macros.cs b/template/macros.cs index 09b9b2d..dbd5c0e 100644 --- a/template/macros.cs +++ b/template/macros.cs @@ -1,11 +1,53 @@ - - - -   - - - +checked="checked" /> + unknown option () - -   - +checked="checked" /> + +
unknown setting () + +
+ unknown warning message () +
+ +
+ unknown error message () +
+ +
+ unknown success message () +
+ + limit ?>... diff --git a/template/main.cs b/template/main.cs new file mode 100644 index 0000000..ecba2c6 --- /dev/null +++ b/template/main.cs @@ -0,0 +1,21 @@ + + + + + + + + +
+
-
+ + + + + + +
+ + + diff --git a/template/modpath_info.cs b/template/modpath_info.cs index 218d76a..a96cbcc 100644 --- a/template/modpath_info.cs +++ b/template/modpath_info.cs @@ -1,30 +1,20 @@ -
- - -

- - (). - -

+ +
+ ().
+
- -

- - (). - -

+ +
+ ().
+
- -

- - (). - -

+ +
+ ().
+
- -
diff --git a/template/nav.cs b/template/nav.cs new file mode 100644 index 0000000..2264db3 --- /dev/null +++ b/template/nav.cs @@ -0,0 +1,73 @@ + + + + diff --git a/template/select_list.cs b/template/select_list.cs deleted file mode 100644 index bdaeac6..0000000 --- a/template/select_list.cs +++ /dev/null @@ -1,60 +0,0 @@ - - - -
-

-

-
- - - - -
-
- - - 0) ?> - -
- - 25) ?> - - - - - -
- - - -
-
    - -
  • - -
-
- - -
- - - - - 0) ?> - - - - -
-
-
- - diff --git a/template/subscribers.cs b/template/subscribers.cs new file mode 100644 index 0000000..7b3c705 --- /dev/null +++ b/template/subscribers.cs @@ -0,0 +1,135 @@ +
+

+ + + + + + +

+
+ +
+

+ + + + + + +

+
+ + + + + + + + + +
+ + +
+ + + +
    + +
  • +
  • + +
  • + +
  • +
  • + + +
  • + + + + + +
  • +
+
+
+ + + + + + +
+ + + + + + + + + + + 0 ?> + + + + +
+ + + + + +
    + + + 15 ?> + + + + +
  • +
  • +
  • +
  • +
+ + + + + +
    + +
  • +
    • +
  • + +
  • +
    • +
  • + + +
  • +
  • +
+
+
+ +
+ + + diff --git a/template/textfile_edit.cs b/template/textfile_edit.cs new file mode 100644 index 0000000..2e183e2 --- /dev/null +++ b/template/textfile_edit.cs @@ -0,0 +1,25 @@ +
+

""

+
+ +
+ +
+ +
+ + +
+ + + +

+ + + +
+ +
+ + diff --git a/template/textfiles.cs b/template/textfiles.cs new file mode 100644 index 0000000..255fb0d --- /dev/null +++ b/template/textfiles.cs @@ -0,0 +1,39 @@ +
+

+
+ +
+ +
+ +
+ + +
+ + +
    + 0 ?> + + + 15 ?> + + + + +
  • + +
  • + + +
  • +
  • +
+ +
+
+ diff --git a/webusers.sample b/webusers.sample index b89278f..268caa8 100644 --- a/webusers.sample +++ b/webusers.sample @@ -1,5 +1,5 @@ -comm: guy, arb +comm: guy arb users: arb members: ALL ALL: root -ALLOW_CREATE: root, guy +ALLOW_CREATE: root guy