added multi-domain support

error checking after config loading
fixed language selection behaviour
removed obsolete ui_set directories
This commit is contained in:
lars 2007-03-30 15:24:18 +00:00
parent 4b78064a81
commit 3958224115
15 changed files with 218 additions and 287 deletions

32
INSTALL
View file

@ -9,10 +9,11 @@ OVERVIEW:
3 - configuration file
4 - create a suid cgi wrapper
5 - [optional] configure access control (http authentication)
6 - css stylesheet file
7 - final test
8 - troubleshooting
9 - report problems
6 - [optional] configure multi domain support
7 - css stylesheet file
8 - final test
9 - troubleshooting
10 - report problems
------------------------------------------------------------------------------
@ -123,14 +124,29 @@ OVERVIEW:
Again, see the ApacheWeek article for details.
6. Copy the stylesheet file (/usr/local/share/ezmlm-web/css/default.css)
6. You may skip this step if you manage only one directory containing mailing
lists. For more than one domain or multiple user directories you should
follow the instructions below. BEWARE: this is an advanced setting.
1) copy examples/multidomain.conf.dist to /etc/ezmlm-web/multidomain.conf
2) add your mailing list parent directories to this file
3) uncomment the respective line in your ezmlmwebrc file
The web interface should now show a "Change domain" link in the navigation
bar to the left.
Direct links to a specifc domain use the following format:
http://BASE_URL/ezmlm-web?domain=foo
7. Copy the stylesheet file (/usr/local/share/ezmlm-web/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.
7. Test the installation with your favourite web browser. You should be
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 :)
@ -139,11 +155,11 @@ OVERVIEW:
option correctly in ezmlmwebrc. Check it again.
8. If anything failes - take a look at the web server's error log
9. If anything failes - take a look at the web server's error log
(e.g. /var/log/apache/error.log).
9. If the error log of your web server did not help you to solve your problem:
10. If the error log of your web server did not help you to solve your problem:
- 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

View file

@ -1,12 +1,13 @@
Version 3.2 - 04/14/02006
* support for encrypted mailing lists
(https://systemausfall.org/toolforge/gpgpy-ezmlm/)
* support for multi-domain setups
* detect preferred interface language
* user-specific interface language selection
* handling of empty settings for ezmlm-idx 5.0 fixed (closes #21)
* script for creating binary suid wrappers added
* bug in MySQL support fixed
* treatment of the special character "dot" in listname and list address fixed
* handling of the special character "dot" in listname and list address fixed
* the formerly required module "Encode" is now optional
* support for listing of subscription log

View file

@ -13,6 +13,17 @@
# BEWARE: the (resulting) path MUST be absolute (starting with a slash)!
$LIST_DIR = "$HOME_DIR/lists";
# Multi-Domain-Support
# This is a quite advanced setting for special installations.
# Most people should just ignore it.
# Anyway - if you want to control more than one directory containing
# different lists, then you should:
# 1) copy examples/multidomain.conf.dist to /etc/ezmlm-web/multidomain.conf
# 2) adjust /etc/ezmlm-web/multidomain.conf to your setup
# 3) uncomment the following line
# 4) make sure that your multi domain settings are not overriden below
#warn "multidomain.conf failed" unless (defined do "/etc/ezmlm-web/multidomain.conf");
# Where do we store the dotqmail files of this user?
# (defaults to the home directory of the executing user)
# You will have to change this value, if you use a multi domain

View file

@ -0,0 +1,55 @@
# This is a configuration file for ezmlm-web setups with more than one
# mailing list directory.
#
# If you want to use multi-domain support, then you should somehow know
# what you are doing. You have been warned! ;)
#
# Usually you just need to adjust the $DOMAIN setting below.
# Use the existing example as a template.
#
# If your setup is a little bit more exotic, then you can change the code, too.
# In the end, the setting $LIST_DIR should either be an empty string or
# the path of a mailing list directory. You may also want to take care for the
# $DOTQMAIL_DIR and $MAILDOMAIN settings.
#
# BEWARE: you may not define new variables as - otherwise they could collide
# with the names of variables of the ezmlm-web program.
#
{
# we do not want to spoil our namespace - but we need CGI input
use CGI ();
$CURRENT_DOMAIN = new CGI->param('domain');
};
# domain names may not contain any special characters
# you must define at least "name" and "list_dir" for each domain
%DOMAINS = (
foo => {
name => "Example Domain Foo",
list_dir => "/data/lists/foo",
dot_dir => "/data/lists/foo",
mail_domain => "lists.foo.org",
},
bar => {
name => "Example Domain Bar",
list_dir => "/data/lists/bar",
dot_dir => "/data/lists/bar",
mail_domain => "lists.bar.org",
},
);
# this simple code defines $LIST_DIR and $DOTQMAILDIR in a sane way
if (defined($CURRENT_DOMAIN) && defined($DOMAINS{$CURRENT_DOMAIN})) {
$LIST_DIR = $DOMAINS{$CURRENT_DOMAIN}{'list_dir'}
if (defined $DOMAINS{$CURRENT_DOMAIN}{'list_dir'});
$DOTQMAIL_DIR = $DOMAINS{$CURRENT_DOMAIN}{'dot_dir'}
if (defined $DOMAINS{$CURRENT_DOMAIN}{'dot_dir'});
$MAIL_DOMAIN = $DOMAINS{$CURRENT_DOMAIN}{'mail_domain'}
if (defined $DOMAINS{$CURRENT_DOMAIN}{'mail_domain'});
} else {
$LIST_DIR = '';
}

View file

@ -22,7 +22,8 @@ use CGI;
use IO::File;
use POSIX;
use English;
use Time::localtime;
# TODO: uncomment it later
use Time::localtime ();
# gettext support is optional
my $GETTEXT_SUPPORT = 1;
@ -79,6 +80,8 @@ use vars qw[$HTML_CSS_FILE $TEMPLATE_DIR $LANGUAGE_DIR $HTML_LANGUAGE];
use vars qw[$DEFAULT_HOST];
# some settings for encrypted mailing lists
use vars qw[$GPG_SUPPORT];
# settings for multi-domain setups
use vars qw[%DOMAINS $CURRENT_DOMAIN];
# some deprecated configuration settings - they have to be announced
# otherwise old configuration files would break
@ -106,7 +109,15 @@ if (defined($opt_C)) {
} else {
&fatal_error("Unable to find config file");
}
do $config_file;
unless (my $return = do $config_file) {
if ($@) {
&fatal_error("Failed to parse the config file ($config_file): $@");
} elsif (!defined $return) {
&fatal_error("Failed to read the config file ($config_file): $!");
} else {
# the last statement of the config file return False -> this is ok
}
}
####### validate configuration and apply some default settings ##########
@ -162,8 +173,13 @@ my $action = $q->param('action');
# This is where we decide what to do, depending on the form state and the
# users chosen course of action ...
# TODO: unify all these "is list param set?" checks ...
# check permissions
unless (&check_permission_for_action()) {
if (%DOMAINS && (!defined($CURRENT_DOMAIN) || ($CURRENT_DOMAIN eq '')
|| ($action eq 'domain_select'))) {
# domain support is enabled, but no domain is selected
$pagename = 'domain_select';
# undef the currently selected domain
undef $CURRENT_DOMAIN;
} elsif (!&check_permission_for_action()) {
$pagename = 'list_select';
$error = 'Forbidden';
} elsif ($action eq '' || $action eq 'list_select') {
@ -423,6 +439,8 @@ unless (&check_permission_for_action()) {
# set default action, if there is no list available and the user is
# allowed to create a new one
if (((!defined($action)) || ($action eq ''))
&& ((%DOMAINS && defined($CURRENT_DOMAIN) and ($CURRENT_DOMAIN ne ''))
|| (!%DOMAINS))
&& (&webauth_create_allowed())
&& ($pagedata->getValue('Data.Lists.0','') eq '')) {
$pagename = 'list_create';
@ -524,7 +542,7 @@ sub load_interface_language {
unless (&check_interface_language($HTML_LANGUAGE));
# first: load default language - in case some translations are incomplete
$data->readFile("$LANGUAGE_DIR/$HTML_LANGUAGE" . ".hdf");
$data->readFile("$LANGUAGE_DIR/$config_language" . ".hdf");
# check for preferred browser language, if the box was not initialized yet
my $prefLang = &get_browser_language();
@ -583,10 +601,38 @@ sub get_browser_language {
# ---------------------------------------------------------------------------
sub set_pagedata_domains {
my ($domain_name);
# multi-domain setup?
if (defined($CURRENT_DOMAIN)) {
$pagedata->setValue("Config.UI.LinkAttrs.domain", $CURRENT_DOMAIN);
$pagedata->setValue("Data.CurrentDomain", $CURRENT_DOMAIN);
$pagedata->setValue("Data.CurrentDomain.Description",
$DOMAINS{$CURRENT_DOMAIN}{name});
}
foreach $domain_name (keys %DOMAINS) {
$pagedata->setValue("Data.Domains.$domain_name",
$DOMAINS{$domain_name}{'name'});
}
}
# ---------------------------------------------------------------------------
sub set_pagedata_list_of_lists {
my (@files, $i, $num);
# for a multi-domain setup there are no lists available if no domain
# is selected
return (0==0) if (%DOMAINS &&
(!defined($CURRENT_DOMAIN) || ($CURRENT_DOMAIN eq '')));
# undefined $LIST_DIR?
return (0==0) if (!defined($LIST_DIR) || ($LIST_DIR eq ''));
# Read the list directory for mailing lists.
return (0==0) unless (opendir DIR, $LIST_DIR);
@ -612,6 +658,9 @@ sub set_pagedata {
# read available list of lists
&set_pagedata_list_of_lists();
# multi domain support?
&set_pagedata_domains() if (%DOMAINS);
# username and hostname
# Work out if this user has a virtual host and set input accordingly ...
if (-e "$QMAIL_BASE/virtualdomains") {
@ -2002,6 +2051,11 @@ sub webauth {
sub webauth_create_allowed {
# for a multi-domain setup we disallow list creation until a domain
# is selected
return (1==0) if (%DOMAINS &&
(!defined($CURRENT_DOMAIN) || ($CURRENT_DOMAIN eq '')));
# Check if we were called with the deprecated argument "-c" (allow to create lists)
return (0==0) if (defined($opt_c));

View file

@ -26,7 +26,8 @@ Lang {
Properties = Eigenschaften von
Language = Sprache
Help = Hilfe (extern)
SubscribeLog = Subscriber's log
SubscribeLog = Einschreibungen
DomainSelect = Choose a domain
}
Title {
ConfigMain = Listeneinstellungen
@ -46,12 +47,13 @@ Lang {
ListDelete = Liste löschen
FileSelect = Auswählen eines Textbausteins
FileEdit = Bearbeitung des Textbausteins
SubscribeLog = Subscription events
SubscribeLog = Einschreibungsereignisse
GnupgConvert = Verschlüsselung
GnupgPublic = Öffentliche Schlüssel
GnupgSecret = Private Schlüssel
GnupgGenerate = Erzeugen eines Schlüssels
GnupgOptions = Verschlüsselungseinstellungen
DomainSelect = Choose a domain
}
Buttons {
Create = Erzeuge die Liste
@ -112,7 +114,7 @@ Lang {
RequiresIDX5 = Diese Aktion erfordert ezmlm-idx in der Version 5.0
ResetFileIsDefault = Dieser Textbaustein ist keine angepasste Variante und kann somit nicht zurückgesetzt werden.
ResetFile = Der angepasste Textbaustein konnte nicht entfernt werden.
LogFile = Reading of log file failed.
LogFile = Das Lesen der Protokoll-Datei schlug fehl.
GnupgNoKeyFile = Es wurde keine Datei zum Hochladen ausgewählt!
GnupgDelKey = Mindestens ein Schlüssel konnte nicht gelöscht werden!
GnupgNoKeySelected = Es wurde kein Schlüssel ausgewählt!
@ -225,6 +227,7 @@ Lang {
GnupgKeySize = Schlüssellänge (in Bytes)
GnupgKeyExpires = Verfallsdatum (in Jahren)
Never = nie
NoDomainsAvailable = No domains are available.
}
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.
@ -268,12 +271,13 @@ Lang {
TextFileReset = Auf die Vorgabe zurücksetzen
TextFileInfo = Nützliche Platzhalter
AvailableLists = Verfügbare Listen
SubscribeLog = Events
SubscribeLog = Ereignisse
GnupgConvert = Verschlüsselungsunterstützung
GnupgPublicKeys = Öffentliche Schlüssel dieser Liste
GnupgSecretKeys = Private Schlüssel dieser Liste
GnupgKeyImport = Schlüssel importieren
GnupgGenerateKey = Schlüssel der Liste erzeugen
GnupgOptions = Verschlüsselungseinstellungen
AvailableDomains = Available domains
}
}

View file

@ -29,6 +29,7 @@ Lang {
Language = Language
Help = Help (external)
SubscribeLog = Subscriber's log
DomainSelect = Choose a domain
}
@ -56,6 +57,7 @@ Lang {
GnupgSecret = Secret keys
GnupgGenerate = Generate a new keypair
GnupgOptions = Encryption settings
DomainSelect = Choose a domain
}
@ -242,6 +244,7 @@ Lang {
GnupgKeySize = Length of the key (bytes)
GnupgKeyExpires = Expiration time (years)
Never = never
NoDomainsAvailable = No domains are available.
}
@ -295,5 +298,7 @@ Lang {
GnupgKeyImport = Import a key
GnupgGenerateKey = Generate the key for this list
GnupgOptions = Encryption settings
AvailableDomains = Available domains
}
}

22
template/domain_select.cs Normal file
View file

@ -0,0 +1,22 @@
<div class="title">
<h1><?cs var:html_escape(Lang.Title.DomainSelect) ?></h1>
</div>
<fieldset>
<legend>
<?cs var:html_escape(Lang.Legend.AvailableDomains) ?>
</legend>
<?cs if:subcount(Data.Domains) > 0 ?>
<ul>
<?cs each:domain = Data.Domains
?><li><a href="<?cs call:link('domain',name(domain),'','','','')
?>"><?cs var:html_escape(domain) ?></a></li>
<?cs /each ?>
</ul>
<?cs else ?>
<p><?cs var:html_escape(Lang.Misc.NoDomainsAvailable) ?></p>
<?cs /if ?>
</fieldset>

View file

@ -4,10 +4,11 @@
<form class="select" method="post" action="<?cs call:link("","","","","","") ?>" enctype="application/x-www-form-urlencoded">
<?cs if:Data.List.Name ?><input type="hidden" name="list" value="<?cs
var:Data.List.Name ?>" /><?cs /if ?>
var:Data.List.Name ?>" />
<input type="hidden" name="action" value="subscribers" /><?cs /if ?>
<?cs if:Data.CurrentDomain ?><input type="hidden" name="domain" value="<?cs
var:Data.CurrentDomain ?>" /><?cs /if ?>
<input type="hidden" name="action" value="show_page" />
<input type="hidden" name="pagename" value="<?cs var:Data.Action ?>" />
<font class="no_link"><?cs
var:html_escape(Lang.Menue.Language) ?>:</font><br/>
<select name="web_lang" size="0">

View file

@ -7,8 +7,11 @@
<?cs include:TemplateDir + '/nav.cs' ?>
<div id="main_content">
<?cs if:Data.List.Name ?><div id="info_title"><?cs var:Data.List.Name ?> - <?cs
var:Data.List.Address ?></div><?cs /if ?>
<?cs if:Data.List.Name ?><div id="info_title"><?cs
if:Data.CurrentDomain ?><?cs
var:html_escape(Data.CurrentDomain.Description) ?> - <?cs /if
?><?cs var:html_escape(Data.List.Name) ?> - <?cs
var:html_escape(Data.List.Address) ?></div><?cs /if ?>
<?cs if:Data.Error ?><?cs call:error(Lang.ErrorMessage[Data.Error]) ?><?cs /if ?>
<?cs if:Data.customError ?><?cs call:error(Data.customError) ?><?cs /if ?>
<?cs if:Data.Warning ?><?cs call:warning(Lang.WarningMessage[Data.Warning]) ?><?cs /if ?>

View file

@ -1,8 +1,16 @@
<!-- $Id$ -->
<div id="nav_bar">
<ul>
<?cs if:(subcount(Data.Lists) > 0) && (UI.Navigation.ListSelect == 1) ?>
<?cs if:(subcount(Data.Domains) > 0) && (UI.Navigation.DomainSelect == 1) ?>
<li><a <?cs if:(Data.Action == "domain_select") ?> class="nav_active"<?cs /if ?>
href="<?cs call:link('action','domain_select','','','','') ?>"
title="<?cs var:html_escape(Lang.Menue.DomainSelect) ?>"><?cs
var:html_escape(Lang.Menue.DomainSelect) ?></a>
</li>
<?cs /if ?>
<?cs if:(subcount(Data.Lists) > 0) && (UI.Navigation.ListSelect == 1) ?>
<li><a <?cs if:(Data.Action == "list_select") ?> class="nav_active"<?cs /if ?>
href="<?cs call:link("action","list_select","","","","") ?>"
title="<?cs var:html_escape(Lang.Menue.ListSelect) ?>"><?cs var:html_escape(Lang.Menue.ListSelect) ?></a>

View file

@ -5,14 +5,18 @@
<fieldset class="form">
<legend><?cs var:html_escape(Lang.Legend.SubscribeLog) ?> </legend>
<table>
<?cs each:x = Data.List.SubscribeLog ?>
<tr>
<td><?cs var:html_escape(x.address) ?></td>
<td><?cs var:html_escape(x.text) ?></td>
<td><?cs var:html_escape(x.date) ?></td>
</tr>
<?cs /each ?>
</table>
<?cs if:subcount(Data.List.SubscribeLog) > 0 ?>
<table>
<?cs each:x = Data.List.SubscribeLog ?>
<tr>
<td><?cs var:html_escape(x.address) ?></td>
<td><?cs var:html_escape(x.text) ?></td>
<td><?cs var:html_escape(x.date) ?></td>
</tr>
<?cs /each ?>
</table>
<?cs else ?>
<?cs var:html_escape(Lang.WarningMessage.EmptyList) ?>
<?cs /if ?>
</fieldset>

View file

@ -1,197 +0,0 @@
UI {
Navigation {
ListSelect = 1
ListCreate = 1
Subscribers {
Subscribers = 1
Digest = 1
Allow = 1
Deny = 1
Moderators = 1
}
Config {
Main = 1
Subscription = 1
Posting = 1
Processing = 1
Archive = 1
Admin = 1
All = 1
}
Gnupg {
PublicKeys = 1
SecretKeys = 1
GenerateKey = 1
}
TextEdit = 1
ListDelete = 1
GnupgConvert = 1
Language = 1
Interface = 1
Help = 1
}
Options {
Create {
Listname = create_listname
Listaddress = create_listaddress
Listlanguage = lang_select
Mysql = mysql
Webuser = webusers
}
Subscribers {
Subscribers = {}
Digest {
Enabled = digest_enabled
Settings = digest_settings
}
Deny {
Enabled = block_deny
}
Moderators {
Posting {
Self = mod_post
Path = mod_post_path
}
Subscription {
Self = mod_sub
Path = mod_sub_path
}
Administration {
Self = admin_enabled
Path = admin_path
}
}
}
Config {
Main {
Language = lang_select
Charset = charset_select
Owner = owner_address
MainList = mainlist
MailmanRequests = mailman_requests
RemoveWarn = warn_remove
SQL = mysql
WebUsers = webusers
}
Archive {
Enabled {
Self = archive_enabled
Public = public
ModOnly = archive_mod_only
Guard = archive_deny_unknown
}
RemovePrivateHeader = archive_remove_private_header
}
Subscription {
Public = public
ConfirmSub = confirm_sub
ConfirmUnsub = confirm_unsub
ModSub {
Self = mod_sub
Path = mod_sub_path
}
}
Admin {
Enabled {
Self = admin_enabled
RequestSubscribers = admin_get_subscribers
EditText = admin_edit_text
Path = admin_path
}
}
Posting {
UseDeny = block_deny
BlockOthers = block_others_post
Confirm = confirm_post
Moderate {
Self = mod_post
NonMod = block_nonmod_post
Path = mod_post_path
}
SizeMax = msgsize_max
SizeMin = msgsize_min
MimeCheck {
Self = mimecheck
MimeReject = mimereject
}
}
Processing {
Prefix = prefix
Trailer = trailer
From = from_address
MimeCheck {
Self = mimecheck
MimeRemove = mimeremove
}
HeaderRemove = headerremove
HeaderAdd = headeradd
}
Overview {
Public = public
ConfirmSub = confirm_sub
ConfirmUnsub = confirm_unsub
ModSubEnable = mod_sub
UseDeny = block_deny
BlockOthers = block_others_post
ConfirmPosting = confirm_post
ModPosting = mod_post
NonModPosting = block_nonmod_post
MailmanRequests = mailman_requests
RemoveWarn = warn_remove
DigestEnabled = digest_enabled
DigestSettings = digest_settings
ArchiveEnabled = archive_enabled
ArchiveModOnly = archive_mod_only
ArchiveGuard = archive_deny_unknown
RemovePrivateHeader = archive_remove_private_header
AdminEnabled = admin_enabled
AdminRequestSubscribers = admin_get_subscribers
AdminEditText = admin_edit_text
FromAddress = from_address
Owner = owner_address
SQL = mysql
MainList = mainlist
ModPostPath = mod_post_path
ModSubPath = mod_sub_path
AdminPath = admin_path
Prefix = prefix
Trailer = trailer
SizeMax = msgsize_max
SizeMin = msgsize_min
MimeCheck {
Self = mimecheck
MimeRemove = mimeremove
MimeReject = mimereject
}
HeaderRemove = headerremove
HeaderAdd = headeradd
Language = lang_select
Charset = charset_select
WebUsers = webusers
}
}
}
}

View file

@ -1,57 +0,0 @@
UI {
Navigation {
ListSelect = 1
ListCreate = 1
Subscribers {
Subscribers = 1
}
Config {
Main = 1
}
Gnupg {
PublicKeys = 1
SecretKeys = 1
GenerateKey = 1
}
TextEdit = 1
ListDelete = 1
Language = 1
Interface = 1
Help = 1
}
Options {
GenerateKey {
KeyName = gnupg_keyname
KeyComment = gnupg_keycomment
KeySize = gnupg_keysize
KeyExpiration = gnupg_keyexpires
}
Config {
Main {
#Language = lang_select
#Charset = charset_select
SignMessages = gnupg_sign_messages
EncryptToAll = gnupg_encrypt_to_all
AllowKeySubmission = gnupg_allow_key_submission
NokeyNocrypt = gnupg_nokey_nocrypt
VerifiedKeyReq = gnupg_verified_key_required
RequireSub = gnupg_require_subscriber
requireSigs = gnupg_require_sigs
WebUsers = webusers
}
}
}
}

View file

@ -1,6 +1,7 @@
UI {
Navigation {
DomainSelect = 1
ListSelect = 1
ListCreate = 1
Subscribers {