ql-web: init
This commit is contained in:
parent
47cce4a660
commit
8c46c822d3
13 changed files with 981 additions and 0 deletions
325
ql-web/trunk/css/default.css
Normal file
325
ql-web/trunk/css/default.css
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#news font.title {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#news ul.changes {
|
||||||
|
font-size: 90%;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #005040;
|
||||||
|
}
|
||||||
|
|
||||||
|
#oben {
|
||||||
|
background-color: #2f4860;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.oben {
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: solid 2px #ffffff;
|
||||||
|
padding: 5px;
|
||||||
|
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;
|
||||||
|
}
|
85
ql-web/trunk/lang/de.hdf
Normal file
85
ql-web/trunk/lang/de.hdf
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
LanguageID = de
|
||||||
|
|
||||||
|
LanguageName = Deutsch
|
||||||
|
|
||||||
|
Lang {
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
Overview = Ueberblick
|
||||||
|
Password = Passwort
|
||||||
|
Forward = Weiterleitung
|
||||||
|
Filter = Spam-Filter
|
||||||
|
Vacation = Abwesenheit
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Title {
|
||||||
|
Overview = Ueberblick
|
||||||
|
Password = Passwortaenderung
|
||||||
|
Forward = Weiterleitungen konfigurieren
|
||||||
|
Filter = Spam-Filter konfigurieren
|
||||||
|
Vacation = Abwesenheitsbenachrichtigung
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Buttons {
|
||||||
|
Password = Passwort aendern
|
||||||
|
AddForward = Weiterleitung hinzufuegen
|
||||||
|
DelForward = Weiterleitung entfernen
|
||||||
|
Filter = Einstellung speichern
|
||||||
|
Vacation = Einstellung speichern
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Options {
|
||||||
|
filter_on = Aktiviere den Spam-Filter
|
||||||
|
spam_move = Verschiebe Spam in ein eigenes Verzeichnis
|
||||||
|
vacation_on = Aktivieren Abwesenheits-Benachrichtigung
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Misc {
|
||||||
|
NewForwardAddress = Neue Weiterleitungsadresse
|
||||||
|
VacationText = Benachrichtigungstext
|
||||||
|
Password = Mailaccount-Passwort
|
||||||
|
OldPassword = Altes Passwort
|
||||||
|
NewPassword = Neues Passwort
|
||||||
|
NewPasswordAgain = Neues Passwort wiederholen
|
||||||
|
FooterText = eine Web-Oberflaeche fuer
|
||||||
|
Filter_None = keine Spam-Kontrolle
|
||||||
|
Filter_Mark = markiere Spam-Nachrichten
|
||||||
|
Filter_Move = Verschiebe Spam-Nachrichten
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorMessage {
|
||||||
|
UnknownAction = Diese Aktion ist undefiniert!
|
||||||
|
ParameterMissing = Diese Aktion benoetigt weitere Parameter!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WarningMessage {
|
||||||
|
FilterConnfig = Die Filterungseinstellungen konnten nicht gespeichert werden!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SuccessMessage {
|
||||||
|
UpdatePassword = Das Passwort wurde erfolgreich geaendert.
|
||||||
|
AddForward = Die Weiterleitung wurde hinzugefuegt.
|
||||||
|
DelForward = Die Weiterleitung wurde entfernt.
|
||||||
|
UpdateFilter = Die Spam-Filter-Einstellungen wurden gespeichert.
|
||||||
|
UpdateVacation = Die Abwesenheits-Einstellungen wurden gespeichert.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Introduction {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Legend {
|
||||||
|
Password = Passwort aendern
|
||||||
|
Forward = Weiterleitungen verwalten
|
||||||
|
Filter = Spam-Filterung einrichten
|
||||||
|
Vacation = Abwesenheitsbenachrichtigung einrichten
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
18
ql-web/trunk/ql-web.conf
Normal file
18
ql-web/trunk/ql-web.conf
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
$CSS_URL = '/ql-web/css/default.css';
|
||||||
|
|
||||||
|
$HTML_TITLE = 'QL-Web - Entwicklung';
|
||||||
|
|
||||||
|
$QL_WEB_DIR = '/home/lars/subversion/admin-tools/ql-web/trunk';
|
||||||
|
$TEMPLATE_DIR = "$QL_WEB_DIR/template";
|
||||||
|
$LANGUAGE_DIR = "$QL_WEB_DIR/lang";
|
||||||
|
|
||||||
|
$HTML_LANGUAGE = 'de';
|
||||||
|
|
||||||
|
$LDAP_HOST = 'ldap.sao';
|
||||||
|
|
||||||
|
# the string '_USERNAME_' will be replaced by the real username
|
||||||
|
$LDAP_USER_DN = "cn=_USERNAME_,ou=People,o=neofaxe,dc=systemausfall,dc=org";
|
||||||
|
|
||||||
|
$LDAP_SPAM_MOVE = "| ifspam spam-_USERNAME_ || true";
|
||||||
|
$LDAP_SPAM_MARK = "| ifspam spam-_USERNAME_";
|
||||||
|
|
353
ql-web/trunk/ql-web.pl
Executable file
353
ql-web/trunk/ql-web.pl
Executable file
|
@ -0,0 +1,353 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
#===========================================================================
|
||||||
|
# ql-web v0.1
|
||||||
|
# ==========================================================================
|
||||||
|
|
||||||
|
package ql_web;
|
||||||
|
|
||||||
|
# Modules to include
|
||||||
|
use strict;
|
||||||
|
use ClearSilver;
|
||||||
|
use Mail::Address;
|
||||||
|
use CGI;
|
||||||
|
use IO::File;
|
||||||
|
use Net::LDAP;
|
||||||
|
|
||||||
|
my $q = new CGI;
|
||||||
|
$q->import_names('Q');
|
||||||
|
|
||||||
|
# Suid stuff requires a secure path.
|
||||||
|
$ENV{'PATH'} = '/bin';
|
||||||
|
|
||||||
|
# use strict is a good thing++
|
||||||
|
|
||||||
|
# We run suid so we can't use $ENV{'HOME'} and $ENV{'USER'} to determine the user
|
||||||
|
my @tmp = getpwuid($>);
|
||||||
|
|
||||||
|
use vars qw[$HOME_DIR]; $HOME_DIR=$tmp[7];
|
||||||
|
use vars qw[$HTML_TITLE];
|
||||||
|
use vars qw[$CSS_URL $TEMPLATE_DIR $LANGUAGE_DIR $HTML_LANGUAGE];
|
||||||
|
use vars qw[$LDAP_HOST $LDAP_USER_DN $LDAP_SPAM_MOVE $LDAP_SPAM_MARK];
|
||||||
|
|
||||||
|
# set default TEXT_ENCODE
|
||||||
|
use vars qw[$TEXT_ENCODE]; $TEXT_ENCODE='us-ascii';
|
||||||
|
|
||||||
|
# pagedata contains the hdf tree for clearsilver
|
||||||
|
# pagename refers to the template file that should be used
|
||||||
|
use vars qw[$pagedata $pagename $error $customError $warning $customWarning $success];
|
||||||
|
use vars qw[$mail_user];
|
||||||
|
|
||||||
|
# Get user configuration stuff
|
||||||
|
if(-e "$HOME_DIR/.ql-web.conf") {
|
||||||
|
require "$HOME_DIR/.ql-web.conf"; # User
|
||||||
|
} elsif(-e "./ql-web.conf") {
|
||||||
|
require "./ql-web.conf"; # Install
|
||||||
|
} elsif(-e "/etc/ql-web/ql-web.conf") {
|
||||||
|
require "/etc/ql-web/ql-web.conf"; # System (new style)
|
||||||
|
} else {
|
||||||
|
&fatal_error("Unable to read config file");
|
||||||
|
}
|
||||||
|
|
||||||
|
# check optional stylesheet
|
||||||
|
$CSS_URL = '' unless defined($CSS_URL);
|
||||||
|
|
||||||
|
# check template directory
|
||||||
|
$TEMPLATE_DIR = 'template' unless defined($TEMPLATE_DIR);
|
||||||
|
|
||||||
|
# Untaint form input ...
|
||||||
|
&untaint;
|
||||||
|
|
||||||
|
$mail_user = $ENV{'REMOTE_USER'};
|
||||||
|
|
||||||
|
my $pagedata = load_hdf();
|
||||||
|
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 ...
|
||||||
|
if ($action eq '' || $action eq 'overview') {
|
||||||
|
# Default action - display the current mail account configuration
|
||||||
|
$pagename = 'overview';
|
||||||
|
} elsif ($action eq 'password_form') {
|
||||||
|
# display password change dialog
|
||||||
|
$pagename = 'password_form';
|
||||||
|
} elsif ($action eq 'password_update') {
|
||||||
|
$success = 'UpdatePassword' if (&update_password());
|
||||||
|
} elsif ($action eq 'forward_form') {
|
||||||
|
$pagename = 'forward_form';
|
||||||
|
} elsif ($action eq 'forward_add') {
|
||||||
|
# add a forwarding address
|
||||||
|
if (defined($q->param('options_forward_add_address'))) {
|
||||||
|
$success = 'AddForward' if (&add_forward());
|
||||||
|
$pagename = 'forward_form';
|
||||||
|
} else {
|
||||||
|
$error = 'ParameterMissing';
|
||||||
|
$pagename = 'forward_form';
|
||||||
|
}
|
||||||
|
} elsif ($action eq 'forward_del') {
|
||||||
|
# remove a forwarding address
|
||||||
|
# no selected address -> no error
|
||||||
|
if (defined($q->param('options_forward_del_address'))) {
|
||||||
|
$success = 'DelForward' if (&del_forward());
|
||||||
|
$pagename = 'forward_form';
|
||||||
|
} else {
|
||||||
|
$error = 'ParameterMissing';
|
||||||
|
$pagename = 'forward_form';
|
||||||
|
}
|
||||||
|
} elsif ($action eq 'filter_form') {
|
||||||
|
$pagename = 'filter_form';
|
||||||
|
} elsif ($action eq 'filter_update') {
|
||||||
|
# update filtering setting
|
||||||
|
$success = 'UpdateFilter' if (&update_filter());
|
||||||
|
$pagename = 'filter_form';
|
||||||
|
} elsif ($action eq 'vacation_form') {
|
||||||
|
$pagename = 'vacation_form';
|
||||||
|
} elsif ($action eq 'vacation_update') {
|
||||||
|
# update vacation reply setting
|
||||||
|
$success = 'UpdateVacation' if (&update_vacation());
|
||||||
|
$pagename = 'vacation_form';
|
||||||
|
} else {
|
||||||
|
$pagename = 'overview';
|
||||||
|
$error = 'UnknownAction';
|
||||||
|
}
|
||||||
|
|
||||||
|
# read the current state (after the changes are done)
|
||||||
|
&set_pagedata();
|
||||||
|
|
||||||
|
# Print page and exit :) ...
|
||||||
|
&output_page;
|
||||||
|
exit;
|
||||||
|
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
sub set_pagedata {
|
||||||
|
$pagedata->setValue('Data.isSpamMove', &is_spam_move()? 1 : 0);
|
||||||
|
$pagedata->setValue('Data.isSpamMark', &is_spam_mark()? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub update_filter {
|
||||||
|
|
||||||
|
my $ldif;
|
||||||
|
my $password = $q->param('pw');
|
||||||
|
my $result;
|
||||||
|
my $ldap;
|
||||||
|
my $user_dn = $LDAP_USER_DN;
|
||||||
|
$user_dn =~ s/_USERNAME_/$mail_user/g;
|
||||||
|
|
||||||
|
$ldap = Net::LDAP->new($LDAP_HOST);
|
||||||
|
$result = $ldap->bind($mail_user, password => $password);
|
||||||
|
if ($result->is_error) {
|
||||||
|
$warning = 'WrongPassword';
|
||||||
|
return (0==1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($q->param('filter_type') eq 'none') {
|
||||||
|
if (&is_spam_mark() || &is_spam_move()) {
|
||||||
|
$result = $ldap->modify($user_dn, delete => ['deliveryProgramPath']);
|
||||||
|
}
|
||||||
|
} elsif ($q->param('filter_type') eq 'move') {
|
||||||
|
if (!&is_spam_move()) {
|
||||||
|
$ldif = $LDAP_SPAM_MOVE;
|
||||||
|
$ldif =~ s/_USERNAME_/$mail_user/g;
|
||||||
|
$ldap->modify($user_dn, delete => [ 'deliveryProgramPath' ])
|
||||||
|
if (&is_spam_mark());
|
||||||
|
$result = $ldap->modify($user_dn, add => { deliveryProgramPath => $ldif });
|
||||||
|
}
|
||||||
|
} elsif ($q->param('filter_type') eq 'mark') {
|
||||||
|
if (!&is_spam_mark()) {
|
||||||
|
$ldif = $LDAP_SPAM_MARK;
|
||||||
|
$ldif =~ s/_USERNAME_/$mail_user/g;
|
||||||
|
$ldap->modify($user_dn, delete => [ 'deliveryProgramPath' ])
|
||||||
|
if (&is_spam_move());
|
||||||
|
$result = $ldap->modify($user_dn, add => { deliveryProgramPath => $ldif });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'ParameterMissing';
|
||||||
|
warn "unknown filter_type: " . $q->param('filter_type');
|
||||||
|
}
|
||||||
|
$ldap->unbind;
|
||||||
|
|
||||||
|
if ($result->is_error) {
|
||||||
|
$warning = 'FilterConfig';
|
||||||
|
return (0==1);
|
||||||
|
} else {
|
||||||
|
return (0==0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub is_spam_move {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
sub is_spam_mark {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub load_hdf {
|
||||||
|
# initialize the data for clearsilver
|
||||||
|
my $hdf = ClearSilver::HDF->new();
|
||||||
|
|
||||||
|
$hdf->readFile($LANGUAGE_DIR . '/' . $HTML_LANGUAGE . '.hdf');
|
||||||
|
|
||||||
|
&fatal_error("Template dir ($TEMPLATE_DIR) not found!") unless (-e $TEMPLATE_DIR);
|
||||||
|
$hdf->setValue("Config.TemplateDir", "$TEMPLATE_DIR/");
|
||||||
|
&fatal_error("Language data dir ($LANGUAGE_DIR) not found!") unless (-e $LANGUAGE_DIR);
|
||||||
|
$hdf->setValue("Config.LanguageDir", "$LANGUAGE_DIR/");
|
||||||
|
$hdf->setValue("Config.ScriptName", $ENV{'SCRIPT_NAME'});
|
||||||
|
$hdf->setValue("Config.Stylesheet", "$CSS_URL");
|
||||||
|
$hdf->setValue("Config.PageTitle", "$HTML_TITLE");
|
||||||
|
|
||||||
|
return $hdf;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub output_page {
|
||||||
|
# Print the page
|
||||||
|
|
||||||
|
$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; charset=utf-8\n\n";
|
||||||
|
|
||||||
|
my $cs = ClearSilver::CS->new($pagedata);
|
||||||
|
|
||||||
|
$cs->parseFile($pagefile);
|
||||||
|
|
||||||
|
print $cs->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub untaint {
|
||||||
|
|
||||||
|
# Go through all the CGI input and make sure it is not tainted. Log any
|
||||||
|
# tainted data that we come accross ... See the perlsec(1) man page ...
|
||||||
|
|
||||||
|
my (@params, $i, $param);
|
||||||
|
@params = $q->param;
|
||||||
|
|
||||||
|
foreach $i (0 .. $#params) {
|
||||||
|
my(@values);
|
||||||
|
foreach $param ($q->param($params[$i])) {
|
||||||
|
next if $param eq '';
|
||||||
|
if ($param =~ /^([#-\@\w\.\/\[\]\:\n\r\>\< _"']+)$/) {
|
||||||
|
push @values, $1;
|
||||||
|
} else {
|
||||||
|
warn "Tainted input in '$params[$i]': " . $q->param($params[$i]);
|
||||||
|
}
|
||||||
|
$q->param(-name=>$params[$i], -values=>\@values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub check_language {
|
||||||
|
my ($list, $lang) = @_;
|
||||||
|
my $found = 0;
|
||||||
|
my $item;
|
||||||
|
foreach $item ($list->get_available_languages()) {
|
||||||
|
$found++ if ($item eq $q->param('list_language'));
|
||||||
|
}
|
||||||
|
return ($found > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
sub fatal_error() {
|
||||||
|
my $text = shift;
|
||||||
|
|
||||||
|
print "Content-Type: text/html; charset=utf-8\n\n";
|
||||||
|
print "<html><head>\n";
|
||||||
|
print "<title>ezmlm-web</title></head>\n";
|
||||||
|
print "<body><h1>a fatal error occoured!</h1>\n";
|
||||||
|
print "<p><strong><big>$text</big></strong></p>\n";
|
||||||
|
print "<p>check the error log of your web server for details</p>\n";
|
||||||
|
print "</body></html>\n";
|
||||||
|
die "$text";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
# End of ql-web.pl
|
||||||
|
# ------------------------------------------------------------------------
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
ezmlm-web - A web configuration interface to ezmlm mailing lists
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
ezmlm-web [B<-c>] [B<-C> E<lt>F<config file>E<gt>] [B<-d> E<lt>F<list directory>E<gt>]
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item B<-C> Specify an alternate configuration file given as F<config file>
|
||||||
|
If not specified, ezmlm-web checks first in the users home directory, then in
|
||||||
|
F</etc/ezmlm> and then the current directory
|
||||||
|
|
||||||
|
=item B<-d> Specify an alternate directory where lists live. This is now
|
||||||
|
depreciated in favour of using a custom ezmlmwebrc, but is left for backward
|
||||||
|
compatibility.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 SUID WRAPPER
|
||||||
|
|
||||||
|
C<#include stdio.h>
|
||||||
|
|
||||||
|
C<void main (void) {>
|
||||||
|
C</* call ezmlm-web */>
|
||||||
|
C<system("/path/to/ezmlm-web.cgi");>
|
||||||
|
C<}>
|
||||||
|
|
||||||
|
|
||||||
|
=head1 DOCUMENTATION/CONFIGURATION
|
||||||
|
|
||||||
|
Please refer to the example ezmlmwebrc which is well commented, and
|
||||||
|
to the README file in this distribution.
|
||||||
|
|
||||||
|
=head1 FILES
|
||||||
|
|
||||||
|
F<~/.ezmlmwebrc>
|
||||||
|
F</etc/ezmlm/ezmlmwebrc>
|
||||||
|
F<./ezmlmwebrc>
|
||||||
|
|
||||||
|
=head1 AUTHOR
|
||||||
|
|
||||||
|
Guy Antony Halse <guy-ezmlm@rucus.ru.ac.za>
|
||||||
|
Lars Kruse <ezmlm-web@sumpfralle.de>
|
||||||
|
|
||||||
|
=head1 BUGS
|
||||||
|
|
||||||
|
None known yet. Please report bugs to the author.
|
||||||
|
|
||||||
|
=head1 S<SEE ALSO>
|
||||||
|
|
||||||
|
ezmlm(5), ezmlm-cgi(1), Mail::Ezmlm(3)
|
||||||
|
|
||||||
|
https://systemausfall.org/toolforge/ezmlm-web
|
||||||
|
http://rucus.ru.ac.za/~guy/ezmlm/
|
||||||
|
http://www.ezmlm.org/
|
||||||
|
http://www.qmail.org/
|
23
ql-web/trunk/template/filter_form.cs
Normal file
23
ql-web/trunk/template/filter_form.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<div class="title">
|
||||||
|
<h1><?cs var:html_escape(Lang.Title.Filter) ?></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="form">
|
||||||
|
<legend><?cs var:html_escape(Lang.Legend.Filter) ?> </legend>
|
||||||
|
|
||||||
|
<form method="post" action="<?cs var:Config.ScriptName ?>" enctype="application/x-www-form-urlencoded">
|
||||||
|
<ul>
|
||||||
|
<li><select name="filter_type">
|
||||||
|
<option value="none"><?cs var:Lang.Misc.Filter_None ?></option>
|
||||||
|
<option value="mark"><?cs var:Lang.Misc.Filter_Mark ?></option>
|
||||||
|
<option value="move"><?cs var:Lang.Misc.Filter_Move ?></option>
|
||||||
|
</select></li>
|
||||||
|
<li><label for="pw"><?cs var:html_escape(Lang.Misc.Password) ?>:</label>
|
||||||
|
<input type="password" name="pw" id="pw" size="20"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<input type="hidden" name="action" value="filter_update" />
|
||||||
|
<button type="submit" name="send" value="do"><?cs var:html_escape(Lang.Buttons.Filter) ?></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</fieldset>
|
8
ql-web/trunk/template/footer.cs
Normal file
8
ql-web/trunk/template/footer.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
<div id="footer">
|
||||||
|
<a href="https://systemausfall.org/toolforge/ql-web">ql-web</a> (v0.1) - <?cs var:html_escape(Lang.Misc.FooterText) ?> <a href="http://www.qmail-ldap.org/" target="_blank">qmail-ldap</a>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
22
ql-web/trunk/template/forward_form.cs
Normal file
22
ql-web/trunk/template/forward_form.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<div class="title">
|
||||||
|
<h1><?cs var:html_escape(Lang.Title.Forward) ?></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="form">
|
||||||
|
<legend><?cs var:html_escape(Lang.Legend.Forward) ?> </legend>
|
||||||
|
|
||||||
|
<form method="post" action="<?cs var:Config.ScriptName ?>" enctype="application/x-www-form-urlencoded">
|
||||||
|
<ul>
|
||||||
|
<li>not yet implemented</li>
|
||||||
|
<!--
|
||||||
|
<li><label for="oldpw"><?cs var:html_escape(Lang.Misc.OldPassword) ?>:</label>
|
||||||
|
<input type="password" name="oldpassword" id="oldpw" size="20"></li>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<input type="hidden" name="action" value="forward_update" />
|
||||||
|
<button type="submit" name="send" value="do"><?cs var:html_escape(Lang.Buttons.Forward) ?></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</fieldset>
|
25
ql-web/trunk/template/header.cs
Normal file
25
ql-web/trunk/template/header.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<!DOCTYPE html
|
||||||
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title><?cs var:Config.PageTitle ?></title>
|
||||||
|
<meta http-equiv="pragma" content="no-cache" /> <!-- for browsers -->
|
||||||
|
<meta http-equiv="cache-control" content="no-cache" /> <!-- for proxys -->
|
||||||
|
<meta http-equiv="content-language" content="<?cs var:html_escape(Config.Language) ?>" />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="Author" content="devel[at]sumpfralle.de" />
|
||||||
|
<meta http-equiv="expire" content="-1d" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?cs var:Config.Stylesheet ?>" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="oben">
|
||||||
|
<div id="perm_nav">
|
||||||
|
<?cs var:Config.PageTitle ?>
|
||||||
|
</div>
|
||||||
|
<h1 class="oben">ql-web</h1>
|
||||||
|
</div>
|
||||||
|
|
52
ql-web/trunk/template/macros.cs
Normal file
52
ql-web/trunk/template/macros.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?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 var:html_escape(Lang.Options[option])
|
||||||
|
?></label><?cs
|
||||||
|
else ?>unknown option (<?cs var:option ?>)<?cs /if ?><?cs
|
||||||
|
/def ?>
|
||||||
|
|
||||||
|
<?cs 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
|
||||||
|
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
|
||||||
|
var:html_escape(Data.List.Settings[setting].value) ?>" size="30" /></li></ul><?cs
|
||||||
|
else ?>unknown setting (<?cs var:setting ?>)<?cs /if ?><?cs
|
||||||
|
/def ?>
|
||||||
|
|
||||||
|
<?cs def:warning(warntext)
|
||||||
|
?><div class="warning">
|
||||||
|
<?cs alt:warntext ?>unknown warning message (<?cs
|
||||||
|
var:Data.Warning ?>)<?cs /alt ?>
|
||||||
|
</div><?cs
|
||||||
|
/def ?>
|
||||||
|
|
||||||
|
<?cs def:error(errtext)
|
||||||
|
?><div class="error">
|
||||||
|
<?cs alt:errtext ?>unknown error message (<?cs
|
||||||
|
var:Data.Error ?>)<?cs /alt ?>
|
||||||
|
</div><?cs
|
||||||
|
/def ?>
|
||||||
|
|
||||||
|
<?cs def:success(succtext)
|
||||||
|
?><div class="success">
|
||||||
|
<?cs alt:succtext ?>unknown success message (<?cs
|
||||||
|
var:Data.Success ?>)<?cs /alt ?>
|
||||||
|
</div><?cs
|
||||||
|
/def ?>
|
||||||
|
|
||||||
|
<?cs def:limit_string_len(text,limit)
|
||||||
|
?><?cs set:text2 = text ?><?cs set:len = string.length(text2) ?><?cs
|
||||||
|
if:len > limit ?><?cs
|
||||||
|
var:string.slice(text,0,limit / #2 + limit % #2 - 1) ?>...<?cs
|
||||||
|
var:string.slice(text,len - limit / #2 + #3 - #1, len) ?><?cs
|
||||||
|
else ?><?cs var:text ?><?cs /if ?><?cs
|
||||||
|
/def ?>
|
||||||
|
|
17
ql-web/trunk/template/main.cs
Normal file
17
ql-web/trunk/template/main.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?cs include:Config.TemplateDir + '/macros.cs' ?>
|
||||||
|
<?cs include:Config.TemplateDir + '/header.cs' ?>
|
||||||
|
|
||||||
|
<!-- this ql-web template follows: <?cs var:Data.Action ?> -->
|
||||||
|
|
||||||
|
<?cs include:Config.TemplateDir + '/nav.cs' ?>
|
||||||
|
<div id="main_content">
|
||||||
|
<?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 ?>
|
||||||
|
<?cs if:Data.customWarning ?><?cs call:warning(Data.customWarning) ?><?cs /if ?>
|
||||||
|
<?cs if:Data.Success ?><?cs call:success(Lang.SuccessMessage[Data.Success]) ?><?cs /if ?>
|
||||||
|
<?cs include:Config.TemplateDir + '/' + Data.Action + '.cs' ?>
|
||||||
|
</div> <!-- end of main_content -->
|
||||||
|
|
||||||
|
<?cs include:Config.TemplateDir + '/footer.cs' ?>
|
||||||
|
|
28
ql-web/trunk/template/nav.cs
Normal file
28
ql-web/trunk/template/nav.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<div id="nav_bar">
|
||||||
|
<ul><li><a <?cs if:(Data.Action == "overview") ?> class="nav_active"<?cs /if ?>
|
||||||
|
href="<?cs var:Config.ScriptName ?>?action=overview"
|
||||||
|
title="<?cs var:html_escape(Lang.Menu.Overview) ?>"><?cs
|
||||||
|
var:html_escape(Lang.Menu.Overview) ?></a>
|
||||||
|
<ul>
|
||||||
|
<li><a <?cs if:(Data.Action == "password_form") ?> class="nav_active"<?cs /if ?>
|
||||||
|
href="<?cs var:Config.ScriptName ?>?action=password_form"
|
||||||
|
title="<?cs var:html_escape(Lang.Menu.Password) ?>"><?cs
|
||||||
|
var:html_escape(Lang.Menu.Password) ?></a></li>
|
||||||
|
<li><a <?cs if:(Data.Action == "forward_form") ?> class="nav_active"<?cs /if ?>
|
||||||
|
href="<?cs var:Config.ScriptName ?>?action=forward_form"
|
||||||
|
title="<?cs var:html_escape(Lang.Menu.Forward) ?>"><?cs
|
||||||
|
var:html_escape(Lang.Menu.Forward) ?></a></li>
|
||||||
|
<li><a <?cs if:(Data.Action == "filter_form") ?> class="nav_active"<?cs /if ?>
|
||||||
|
href="<?cs var:Config.ScriptName ?>?action=filter_form"
|
||||||
|
title="<?cs var:html_escape(Lang.Menu.Filter) ?>"><?cs
|
||||||
|
var:html_escape(Lang.Menu.Filter) ?></a></li>
|
||||||
|
<li><a <?cs if:(Data.Action == "vacation_form") ?> class="nav_active"<?cs /if ?>
|
||||||
|
href="<?cs var:Config.ScriptName ?>?action=vacation_form"
|
||||||
|
title="<?cs var:html_escape(Lang.Menu.Vacation) ?>"><?cs
|
||||||
|
var:html_escape(Lang.Menu.Vacation) ?></a></li>
|
||||||
|
</ul></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- end of navbar div -->
|
||||||
|
</div>
|
||||||
|
|
1
ql-web/trunk/template/overview.cs
Normal file
1
ql-web/trunk/template/overview.cs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
mainly empty
|
24
ql-web/trunk/template/password_form.cs
Normal file
24
ql-web/trunk/template/password_form.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<div class="title">
|
||||||
|
<h1><?cs var:html_escape(Lang.Title.Password) ?></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="form">
|
||||||
|
<legend><?cs var:html_escape(Lang.Legend.Password) ?> </legend>
|
||||||
|
|
||||||
|
<form method="post" action="<?cs var:Config.ScriptName ?>" enctype="application/x-www-form-urlencoded">
|
||||||
|
<ul>
|
||||||
|
<li><label for="oldpw"><?cs var:html_escape(Lang.Misc.OldPassword) ?>:</label>
|
||||||
|
<input type="password" name="oldpassword" id="oldpw" size="20"></li>
|
||||||
|
<li><label for="newpw"><?cs var:html_escape(Lang.Misc.NewPassword) ?>:</label>
|
||||||
|
<input type="password" id="newpw" name="newpassword" size="20"></li>
|
||||||
|
<li><label for="newpw2"><?cs var:html_escape(Lang.Misc.NewPasswordAgain) ?>:</label>
|
||||||
|
<input type="password" id="newpw2" name="newpassword2" size="20"></li>
|
||||||
|
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<input type="hidden" name="action" value="password_update" />
|
||||||
|
<button type="submit" name="send" value="do"><?cs var:html_escape(Lang.Buttons.Password) ?></button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</fieldset>
|
Loading…
Reference in a new issue