implemented simplified subscription/posting/archive rules

improved some interface templates
fixed and added some language strings
implemented 'reply-to-self' setting
This commit is contained in:
lars 2007-04-04 14:56:21 +00:00
parent becff599cd
commit 1f1cd133ae
18 changed files with 251 additions and 86 deletions

2
TODO
View File

@ -1,7 +1,5 @@
Reply-To-Option
Listen-Auswahl fuer Einsende/Mod/...-Modi (moderiert & offen / newsletter / ...)
Infos fuer Massen-Hosting:
http://www.fbis.ch/index-de.php?page=14&frameset=4

View File

@ -7,6 +7,7 @@ Version 3.2 - 04/14/02006
* support for listing of subscription log
* a prefix for the local part of mailing list addresses is now configurable
* user-specific interface selection (easy/default/expert)
* simplified rules for subscribing, posting and archive access
* support for more ezmlm-idx: 'headerkeep', 'mimekeep' and 'copylines'
* script for creating binary suid wrappers added
* handling of empty settings for ezmlm-idx 5.0 fixed (closes #21)

View File

@ -842,8 +842,12 @@ sub set_pagedata_misc_configfiles {
# Get the contents of some important files
$item = $list->getpart('prefix');
$pagedata->setValue("Data.List.Prefix", "$item");
# check reply_to setting
$item = $list->getpart('headeradd');
$pagedata->setValue("Data.List.HeaderAdd", "$item");
$pagedata->setValue("Data.List.Options.special_replytoself", 1)
if (&is_reply_to_self("$item"));
# 'headerremove' is ignored if 'headerkeep' exists (since ezmlm-idx v5)
if ((Mail::Ezmlm->get_version() >= 5.1) &&(-e $list->thislist() . "/headerkeep")) {
@ -1003,7 +1007,10 @@ sub set_pagedata4options {
while ($key =~ m/\w/) {
# scan the first part of the options string for lower case letters
$state = ($options =~ /^\w*$key\w*\s*/);
# set the lower case option
$pagedata->setValue("Data.List.Options." . $key , ($state)? 1 : 0);
# also set the reverse value - see cs macro "check_active_selection"
$pagedata->setValue("Data.List.Options." . uc($key) , ($state)? 0 : 1);
$i++;
$key = lc(substr($options,$i,1));
}
@ -1609,6 +1616,8 @@ sub extract_options_from_params {
################ options ################
$i = 0;
$old_key = substr($old_options,$i,1);
# some special selections
my @avail_selections = ('archive', 'subscribe', 'posting');
# 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
@ -1624,7 +1633,17 @@ sub extract_options_from_params {
} else {
$options .= 'X';
}
} elsif (defined($q->param('available_option_' . uc($old_key)))) {
# inverted checkbox
my $form_var_name = "option_" . uc($old_key);
# this option was visible for the user
if (defined($q->param($form_var_name))) {
$options .= uc($old_key);
} else {
$options .= lc($old_key);
}
} elsif (defined($q->param('available_option_' . lc($old_key)))) {
# non inverted checkbox
my $form_var_name = "option_" . lc($old_key);
# this option was visible for the user
if (defined($q->param($form_var_name))) {
@ -1632,6 +1651,12 @@ sub extract_options_from_params {
} else {
$options .= uc($old_key);
}
} elsif (&is_option_in_selections(lc($old_key))) {
# enabled due to some special selection
$options .= lc($old_key);
} elsif (&is_option_in_selections(uc($old_key))) {
# disabled due to some special selection
$options .= uc($old_key);
} elsif ("cevz" =~ m/$old_key/i) {
# ignore invalid settings (the output of "getconfig" is really weird!)
} else {
@ -1914,6 +1939,7 @@ sub update_config {
# update trailing text
if (defined($q->param('trailing_text'))) {
if (defined($q->param('option_t'))) {
# TODO: the trailer _must_ be followed by a newline
$list->set_text_content('trailer', $q->param('trailing_text'));
} else {
# ezmlm-make automatically removes this file
@ -1948,8 +1974,30 @@ sub update_config {
if (defined($q->param('mimereject')));
# Update headeradd if this option is visible
$list->setpart('headeradd', $q->param('headeradd'))
if (defined($q->param('headeradd')));
# afterwards we will care about a single 'options_special_replytoself'
if (defined($q->param('headeradd'))
|| defined($q->param('available_option_special_replytoself'))) {
my $headers;
if (defined($q->param('headeradd'))) {
$headers = $q->param('headeradd');
} else {
$headers = $list->getpart('headeradd');
}
chomp($headers);
if (defined($q->param('available_option_special_replytoself'))) {
if (!defined($q->param('option_special_replytoself'))
&& (&is_reply_to_self("$headers"))) {
# remove the header line
$headers =~ s/^Reply-To:\s+.*$//m;
} elsif (defined($q->param('option_special_replytoself'))
&& (!&is_reply_to_self("$headers"))) {
# add the header line
chomp($headers);
$headers .= "\nReply-To: <#l#>@<#h#>";
}
}
$list->setpart('headeradd', "$headers");
}
# update headerremove/keep
if ($q->param('headerfilter_action') eq "remove") {
@ -2025,6 +2073,34 @@ sub update_config {
# ------------------------------------------------------------------------
sub is_reply_to_self {
# check if the header lines of the list contain a reply-to-self line
my ($header_lines) = @_;
return (0==0) if ($header_lines =~ m/^Reply-To:\s+<#l#>@<#h#>/m);
return (1==0);
}
# ------------------------------------------------------------------------
sub is_option_in_selections {
# check if the given 'key' is defined in any of the special selection
# form fields ('archive', 'subscribe', 'posting'). Case for key matters!
my $key = shift;
my @avail_selections = ('archive', 'subscribe', 'posting');
my $one_selection;
foreach $one_selection (@avail_selections) {
my $form_name = "selection_$one_selection";
return (0==0) if (defined($q->param($form_name))
&& ($q->param($form_name) =~ m/$key/));
}
return (1==0);
}
# ------------------------------------------------------------------------
sub update_webusers {
# replace existing webusers-line or add a new one

View File

@ -25,10 +25,10 @@ Lang {
ListSelect = Auswahl einer Liste
Properties = Eigenschaften von
Language = Sprache
Interface = Interface
Interface = Oberfläche
Help = Hilfe (extern)
SubscribeLog = Einschreibungen
DomainSelect = Choose a domain
DomainSelect = Auswahl einer Domain
}
Title {
ConfigMain = Listeneinstellungen
@ -52,9 +52,9 @@ Lang {
GnupgConvert = Verschlüsselung
GnupgPublic = Öffentliche Schlüssel
GnupgSecret = Private Schlüssel
GnupgGenerate = Erzeugen eines Schlüssels
GnupgGenerateKey = Erzeugen eines Schlüssels
GnupgOptions = Verschlüsselungseinstellungen
DomainSelect = Choose a domain
DomainSelect = Auswahl einer Domain
}
Buttons {
Create = Erzeuge die Liste
@ -148,7 +148,7 @@ Lang {
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
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
@ -163,11 +163,39 @@ Lang {
t = Hänge eine Signatur an jede versandte Nachricht
u = Nur Einsendungen von AbonnentInnen werden akzeptiert (für moderierte Listen: akzeptiere alle Einsendungen von AbonnentInnen)
w = Entferne den Aufruf von ezmlm-warn aus den Verarbeitungsregeln (für sehr spezielle Konfigurationen)
x = Reset the list of to be stripped mime types to its default value
x = Setze die Liste der zu entfernenden MIME-Typen auf den Startwert zurück
y = Fordere eine Bestätigung für jede eingesandte Nachricht an
gnupg_plain_without_key = Sende Nachrichten im Klartext an Empfänger ohne Schlüssel
gnupg_sign_messages = Signiere ausgehende Nachrichten mit dem Listenschlüssel
}
Selections {
archive = Das Archiv ist zugänglich für
archive {
bg = AdministratorInnen
Bg = AbonnentInnen und AdministratorInnen
BG = jede/r
}
subscribe = Öffentliche Einschreibung ist
subscribe {
pS = offen
ps = moderiert
P = nicht erlaubt
}
posting = Einsendungen sind
posting {
MOU = offen für jede/n
mOU = moderiert für jede/n
mOu = offen für AbonnentInnen und moderiert für alle anderen
MOu = offen für AbonnentInnen
moU = offen nur für ModeratorInnen
}
confirmation = Bestätigungsmails werden benötigt für
confirmation {
H = Einschreibung
J = Austragung
y = Einsendung
}
}
Settings {
0 = Diese Liste ist die Unterliste einer anderen
3 = Definiere die Absender-Adresse ausgehender Mails
@ -186,15 +214,15 @@ Lang {
ListName = Name der Liste
ListAddress = Addresse der Liste
ListOptions = Grundlegende Einstellungen
AllowedToEdit = Users allowed to edit this list via web interface
HeaderFiltering = Header filtering
HeaderRemove = strip these header lines
HeaderKeep = keep only these header lines
AllowedToEdit = Nutzer, die diese Liste per Web-Interface konfigurieren dürfen
HeaderFiltering = Kopfzeilen-Filterung
HeaderRemove = entferne die folgenden Kopfzeilen
HeaderKeep = behalte nur die folgenden Kopfzeilen
HeaderAdd = hinzuzufügende Kopfzeilen
MimeTypeExamples = Show some example mime types
MimeFiltering = Mime type filtering (for multipart mails)
MimeRemove = strip these from all messages
MimeKeep = keep only these in messages
MimeTypeExamples = Zeige einige Beispiel-MIME-Typen
MimeFiltering = MIME-Typ-Filterung (für mehrteilige Mails)
MimeRemove = entferne diese von allen Nachrichten
MimeKeep = erhalte nur diese in den Nachrichten
MimeReject = Nachrichten, die einen der folgenden Datentypen enthalten, werden abgewiesen
EditFileInfo {
CommonTags = allgemeine Platzhalter
@ -234,13 +262,13 @@ Lang {
GnupgKeySize = Schlüssellänge (in Bytes)
GnupgKeyExpires = Verfallsdatum (in Jahren)
Never = nie
NoDomainsAvailable = No domains are available.
CopyLinesEnabled = Add some lines of every original message to automatic replies
CopyLinesNumber = number of lines
NoDomainsAvailable = Es sind keine Domains vorhanden.
CopyLinesEnabled = Hänge ein paar Zeilen der Original-Nachricht an jede automatische Antwort
CopyLinesNumber = Anzahl von Zeilen
Interfaces {
easy = basic
normal = default
expert = expert
easy = einfach
normal = normal
expert = erweitert
}
}
Introduction {
@ -263,6 +291,8 @@ Lang {
GnupgConvert = Du kannst eine normale Mailingliste in eine verschlüsselte umwandeln und umgekehrt.
GnupgGenerateKey = Um eine verschlüsselte Mailingliste verwenden zu können, ist es erforderlich, einen Schlüssel für die Liste zu erzeugen (oder zu importieren). Nachdem du das folgende Formular ausgefüllt und abgeschickt hast, wird es eine Weile (bis zu mehreren Minuten) dauern, bis der Schlüssel fertig ist. Sei also bitte geduldig.
GnupgOptions = Konfiguriere die Einstellungen der verschlüsselten Mailingliste.
GnupgSecret = Every every mailing list needs a secret key to decrypt incoming. You should take care that the secret key is kept safe. Otherwise the security of your mailing list is broken.
GnupgPublic = There should be a public key for every subscriber of the mailing list. Additionally there is the key of the mailing list, which should be distributed to all subscribers. It is safe to openly publish public keys.
}
Legend {
ConfigAdmin = Fern-Administrations-Rechte
@ -292,6 +322,6 @@ Lang {
GnupgKeyImport = Schlüssel importieren
GnupgGenerateKey = Schlüssel der Liste erzeugen
GnupgOptions = Verschlüsselungseinstellungen
AvailableDomains = Available domains
AvailableDomains = Verfügbare Domains
}
}

View File

@ -56,7 +56,7 @@ Lang {
GnupgConvert = Encryption
GnupgPublic = Public keys
GnupgSecret = Secret keys
GnupgGenerate = Generate a new keypair
GnupgGenerateKey = Generate a new keypair
GnupgOptions = Encryption settings
DomainSelect = Choose a domain
}
@ -179,11 +179,34 @@ Lang {
w = Remove the ezmlm-warn invocations from the list setup (rarely useful)
x = Reset the list of to be stripped mime types to its default value
y = Request a confirmation mail for every posted message
special_replytoself = Redirect replies to the list
gnupg_plain_without_key = Send plaintext to the subscribers which have no key
gnupg_sign_messages = Sign outgoing messages with the list's key
}
Selections {
archive = Access to the archive is granted for
archive.bg = administrators
archive.Bg = subscribers and administrators
archive.BG = everyone
subscribe = Public subscription is
subscribe.pS = open
subscribe.ps = moderated
subscribe.P = not allowed
posting = Posting is
posting.MOU = allowed for everyone
posting.mOU = moderated for everyone
posting.mOu = allowed for subscribers and moderated for others
posting.MOu = allowed for subscribers
posting.moU = allowed only for moderators
confirmation = Confirmation mails are required for
confirmation.H = subscription
confirmation.J = unsubscription
confirmation.y = posting
}
Settings {
0 = Make the list a sublist of another list
3 = Set a custom "From:" header for outgoing messsages
@ -282,6 +305,8 @@ Lang {
GnupgConvert = You can convert a normal mailinglist to an encrypted list and vice versa.
GnupgGenerateKey = Every encrypted mailing list needs a secret key. You can import this key or create it using the form below. After submitting the form, you have to be patient, as it takes some time (up to several minutes) to create a key.
GnupgOptions = Configure some useful settings of the encrypted mailing list.
GnupgSecret = Every every mailing list needs a secret key to decrypt incoming. You should take care that the secret key is kept safe. Otherwise the security of your mailing list is broken.
GnupgPublic = There should be a public key for every subscriber of the mailing list. Additionally there is the key of the mailing list, which should be distributed to all subscribers. It is safe to openly publish public keys.
}
Legend {

View File

@ -1,3 +1,7 @@
#!/bin/sh
# TODO: remove this header as soon as the demo-uml has python
exit
#!/usr/bin/env python
#-*- coding: utf-8 -*-
#

View File

@ -0,0 +1,3 @@
<!-- REMOVE --><?cs include:TemplateDir + '/macros.cs' ?>
<!-- configure archive access -->
<?cs call:selection_list("archive") ?>

View File

@ -0,0 +1,3 @@
<!-- REMOVE --><?cs include:TemplateDir + '/macros.cs' ?>
<!-- configure confirmation requirements -->
<?cs call:selection_checkboxes("confirmation") ?>

View File

@ -8,8 +8,8 @@
<select name="list_language" id="list_language">
<?cs each:item = Data.List.AvailableLanguages ?>
<option <?cs if:(item == Data.List.Language)
?>selected="selected"<?cs /if ?>><?cs var:item ?></option>
<?cs /each ?>
?>selected="selected"<?cs /if ?>><?cs var:item
?></option><?cs /each ?>
</select><?cs /if ?>
<?cs else ?>
<?cs if:subcount(Data.AvailableLanguages) > 0 ?>
@ -18,8 +18,8 @@
<select name="list_language" id="list_language">
<?cs each:item = Data.AvailableLanguages ?>
<option <?cs if:item == "default"
?>selected="selected"<?cs /if ?>><?cs var:item ?></option>
<?cs /each ?>
?>selected="selected"<?cs /if ?>><?cs var:item
?></option><?cs /each ?>
</select><?cs /if ?>
<?cs /if ?>
<?cs /if ?>

View File

@ -0,0 +1,3 @@
<!-- REMOVE --><?cs include:TemplateDir + '/macros.cs' ?>
<!-- posting rules -->
<?cs call:selection_list("posting") ?>

View File

@ -0,0 +1,3 @@
<!-- REMOVE --><?cs include:TemplateDir + '/macros.cs' ?>
<!-- Gnupg: sign outgoing messages -->
<?cs call:checkbox("special_replytoself") ?>

View File

@ -0,0 +1,3 @@
<!-- REMOVE --><?cs include:TemplateDir + '/macros.cs' ?>
<!-- subscription rules -->
<?cs call:selection_list("subscribe") ?>

View File

@ -1,4 +1,4 @@
<!-- allows the user to change the interface language (not of the list!) -->
<!-- allows the user to change the interface style -->
<?cs if:subcount(Config.UI.Interfaces) > 0 ?>
<?cs call:form_header("select_interface", "template") ?>

View File

@ -1,9 +1,10 @@
<?cs def:checkbox(option)
?><?cs if:Lang.Options[option]
?><input type="checkbox" name="option_<?cs var:option ?>" id="option_<?cs
var:option ?>" value="selected" <?cs
if:(Data.List.Options[option] == 1) ?>checked="checked"<?cs
/if ?> /> <label for="option_<?cs var:option ?>"><?cs
?><input type="checkbox" name="option_<?cs var:option
?>" id="option_<?cs var:option ?>" value="selected" <?cs
if:(Data.List.Options[option] == 1) ?>checked="checked" <?cs
/if ?>/>
<label for="option_<?cs var:option ?>"><?cs
var:html_escape(Lang.Options[option])
?></label>
<input type="hidden" name="available_option_<?cs
@ -15,8 +16,9 @@ def:setting(setting)
?><?cs if:Lang.Settings[setting]
?><input type="checkbox" name="setting_state_<?cs var:setting
?>" id="setting_state_<?cs var:setting ?>" value="selected" <?cs
if:(Data.List.Settings[setting].state == 1) ?>checked="checked"<?cs /if
?> /> <label for="setting_state_<?cs var:setting ?>"><?cs
if:(Data.List.Settings[setting].state == 1) ?>checked="checked"<?cs
/if ?> />
<label for="setting_state_<?cs var:setting ?>"><?cs
var:html_escape(Lang.Settings[setting])
?></label><ul><li><input type="text" name="setting_value_<?cs var:setting
?>" id="setting_value_<?cs var:setting ?>" value="<?cs
@ -124,5 +126,47 @@ def:form_header(form_name, ignore_attr)
def:form_header_upload(form_name, ignore_attr)
?><?cs call:form_header_generic(form_name, ignore_attr,
"multipart/form-data") ?><?cs
/def ?>
/def ?><?cs
def:check_active_selection(input)
?><?cs set:selection=input
?><?cs set:match_ok = 1 ?><?cs
set:slen = string.length(selection) ?><?cs
loop: sindex = #0, slen-1, #1 ?><?cs
set:selection_char = string.slice(selection, sindex, sindex+1) ?><?cs
if:(Data.List.Options[selection_char] != "1") ?><?cs
set:match_ok = 0 ?><?cs /if ?><?cs
/loop ?><?cs if:match_ok == 1 ?> checked="checked" <?cs /if ?><?cs
/def ?><?cs
def:selection_list(sel_name)
?><?cs var:html_escape(Lang.Selections[sel_name])
?>:<br/>
<ul><?cs each:item = Lang.Selections[sel_name] ?>
<li><input type="radio" name="selection_<?cs var:sel_name
?>" value="<?cs var:name(item) ?>" id="selection_<?cs
var:sel_name + '_' + name(item) ?>" <?cs
call:check_active_selection(name(item)) ?> />
<label for="selection_<?csvar:sel_name + '_' + name(item)
?>"><?cs var:html_escape(item) ?></label></li><?cs /each ?>
</ul>
<?cs /def ?><?cs
def:selection_checkboxes(sel_name)
?><?cs var:html_escape(Lang.Selections[sel_name]) ?>:
<ul><?cs each:item = Lang.Selections[sel_name] ?>
<li><input type="checkbox" value="enabled" name="option_<?cs
var:name(item) ?>" id="selection_<?cs
var:sel_name + '_' + name(item) ?>" <?cs
call:check_active_selection(name(item)) ?> />
<input type="hidden" name="available_option_<?cs
var:name(item) ?>" value="enabled" />
<label for="selection_<?cs var:sel_name + '_' + name(item)
?>"><?cs var:html_escape(item) ?></label></li>
<?cs /each ?>
</ul>
<?cs /def ?>

View File

@ -96,7 +96,9 @@
</select></li>
<li><?cs var:subcount(Data.List.Subscribers) ?> <?cs var:html_escape(Lang.Misc.Subscribers) ?></li>
<li><input type="hidden" name="action" value="address_del" />
<button type="submit" name="send" value="do"><?cs var:html_escape(Lang.Buttons.DeleteAddress) ?></button></form></li>
<button type="submit" name="send" value="do"><?cs var:html_escape(Lang.Buttons.DeleteAddress) ?></button></li>
</ul></form>
<ul>
<li><?cs call:form_header("download_subscribers", "") ?>
<input type="hidden" name="action" value="download_subscribers" />
<?cs if:Data.List.PartType ?>

View File

@ -7,12 +7,11 @@ UI {
Subscribers {
Subscribers = 1
Allow = 1
Moderators = 1
}
Config {
Main = 1
Subscription = 1
Posting = 1
Processing = 1
}
@ -54,23 +53,15 @@ UI {
Config {
Main {
Language = lang_select
SubscribeRules = subscribe_selection
PostingRules = posting_selection
Owner = owner_address
WebUsers = webusers
}
Subscription {
Public = public
ConfirmSub = confirm_sub
ConfirmUnsub = confirm_unsub
}
Posting {
BlockOthers = block_others_post
SizeMax = msgsize_max
}
Processing {
Prefix = prefix
ReplyToSelf = reply_to_self
Trailer = trailer
From = from_address
}

View File

@ -89,6 +89,7 @@ UI {
Language = lang_select
Charset = charset_select
Owner = owner_address
Confirm = confirm_selection
MainList = mainlist
MailmanRequests = mailman_requests
RemoveWarn = warn_remove
@ -97,24 +98,17 @@ UI {
}
Archive {
Enabled {
Self = archive_enabled
Public = public
ModOnly = archive_mod_only
Guard = archive_deny_unknown
}
Enabled = archive_enabled
Access = archive_access
RemovePrivateHeader = archive_remove_private_header
}
Subscription {
Public = public
Rules = subscribe_selection
ConfirmSub = confirm_sub
ConfirmUnsub = confirm_unsub
ModSub {
Self = mod_sub
Path = mod_sub_path
}
}
Admin {
Enabled {
@ -126,17 +120,13 @@ UI {
}
Posting {
Rules = posting_selection
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
MimeReject = mimereject
Path = mod_post_path
}
GnupgOptions {
@ -146,6 +136,7 @@ UI {
Processing {
Prefix = prefix
ReplyToSelf = reply_to_self
Trailer = trailer
From = from_address
MimeFilter = mimefilter

View File

@ -81,29 +81,20 @@ UI {
Config {
Main {
Language = lang_select
Charset = charset_select
Owner = owner_address
MainList = mainlist
WebUsers = webusers
}
Archive {
Enabled {
Self = archive_enabled
Public = public
ModOnly = archive_mod_only
Guard = archive_deny_unknown
}
Enabled = archive_enabled
Access = archive_access
RemovePrivateHeader = archive_remove_private_header
}
Subscription {
Public = public
Rules = subscribe_selection
ConfirmSub = confirm_sub
ConfirmUnsub = confirm_unsub
ModSub {
Self = mod_sub
}
}
Admin {
@ -115,13 +106,9 @@ UI {
}
Posting {
Moderate = posting_selection
UseDeny = block_deny
BlockOthers = block_others_post
Confirm = confirm_post
Moderate {
Self = mod_post
NonMod = block_nonmod_post
}
SizeMax = msgsize_max
SizeMin = msgsize_min
MimeReject = mimereject
@ -134,6 +121,7 @@ UI {
Processing {
Prefix = prefix
ReplyToSelf = reply_to_self
Trailer = trailer
From = from_address
MimeFilter = mimefilter