aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-04 22:00:19 +0200
committerGuilhem Moulin <guilhem.moulin@fripost.org>2012-09-04 22:00:19 +0200
commite652956aa8dd6160b078f396e3f89157c15294af (patch)
treef5daa06245f0277925d8d5ad7d74c9a097d4dbd8
parente04e3174c1c38e7587df495c19082a864f2373b2 (diff)
Edition of mailboxes, aliases and lists.
-rw-r--r--css/style.css8
-rw-r--r--lib/FPanel/Interface.pm240
-rw-r--r--template/edit-alias.html83
-rw-r--r--template/edit-domain.html41
-rw-r--r--template/edit-list.html71
-rw-r--r--template/edit-mailbox.html111
-rw-r--r--template/list-domains.html2
-rw-r--r--template/list-locals.html4
8 files changed, 503 insertions, 57 deletions
diff --git a/css/style.css b/css/style.css
index b4925da..ac2b6e2 100644
--- a/css/style.css
+++ b/css/style.css
@@ -156,9 +156,15 @@ table.editform td {
div.editform {
text-align: center;
}
-.ack {
+.success {
font-weight: bold;
color: #32CD32;
+ text-align: center;
+}
+.fail {
+ font-weight: bold;
+ color: #FF0040;
+ text-align: center;
}
.description {
text-align: justify;
diff --git a/lib/FPanel/Interface.pm b/lib/FPanel/Interface.pm
index 79e36b5..aa5b554 100644
--- a/lib/FPanel/Interface.pm
+++ b/lib/FPanel/Interface.pm
@@ -42,7 +42,7 @@ sub ListDomains : StartRunmode {
fripostOwner
fripostPostmaster/ ]
);
- die $domains->error if $domains->code;
+ die '403' if $domains->code;
$ldap->unbind;
@@ -53,10 +53,10 @@ sub ListDomains : StartRunmode {
$template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
$template->param( DOMAINS => [
map { { DOMAIN => $_->get_value('fvd')
+ # TODO: do we really want to list the permissions?
, PERMS => &list_perms_long($_, $authzDN)
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
- 1 : 0
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE'
};
}
$domains->sorted('fvd')
@@ -65,7 +65,7 @@ sub ListDomains : StartRunmode {
}
-# This Run Mode lists the known aliases, users and lists in the current
+# This Run Mode lists the known mailboxes, aliases and lists in the current
# domain.
sub ListLocals : Runmode {
my $self = shift;
@@ -91,9 +91,11 @@ sub ListLocals : Runmode {
fripostOwner
fripostPostmaster/ ]
);
- die $domains->error if $domains->code;
- die "Error: Domains not found" unless $domains->count;
- die "Error: Multiple domains found" if $domains->count > 1;
+ die '404' if $domains->code;
+ # The following is not supposed to happen.
+ die "Error: Multible matching entries found." if $domains->count > 1;
+ my $domain = $domains->pop_entry or die '404';
+
# Query the mailboxes under the given domain
my $mailboxes = $ldap->search( base => "fvd=$domainname,$suffix"
@@ -105,6 +107,7 @@ sub ListLocals : Runmode {
fripostOptionalMaildrop
fripostMailboxQuota/ ]
);
+ # We don't return 403 or 404 here, since it's not supposed to crash.
die $mailboxes->error if $mailboxes->code;
# Query the aliases under the given domain
@@ -117,6 +120,7 @@ sub ListLocals : Runmode {
fripostOwner
fripostMaildrop/ ]
);
+ # We don't return 403 or 404 here, since it's not supposed to crash.
die $aliases->error if $aliases->code;
# Query the lists under the given domain
@@ -129,11 +133,14 @@ sub ListLocals : Runmode {
fripostOwner
fripostListManager/ ]
);
+ # We don't return 403 or 404 here, since it's not supposed to crash.
die $lists->error if $lists->code;
$ldap->unbind;
- my $domain = $domains->entry('0');
+ # Get the perms of the autenticated user, so that we know where
+ # should put "add" and "edit" links (the LDAP ACLs back that up
+ # eventually, anyway).
my $perms = &list_perms($domain, $authzDN);
my $template = $self->load_tmpl( 'list-locals.html', cache => 1, utf8 => 1
@@ -146,7 +153,7 @@ sub ListLocals : Runmode {
$template->param( DESCRIPTION =>
join ("\n", $domain->get_value('description')) );
$template->param( ISACTIVE =>
- $domain->get_value('fripostIsStatusActive') eq 'TRUE' ? 1 : 0 );
+ $domain->get_value('fripostIsStatusActive') eq 'TRUE' );
# Can the user edit the domain (change description, toggle
# activation, modify catchalls?)
$template->param( CANEDIT => $perms =~ /[op]/ );
@@ -158,8 +165,7 @@ sub ListLocals : Runmode {
$template->param( MAILBOXES => [
map { { USER => $_->get_value('fvu')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
- 1 : 0
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE'
, FORWARDS => [ map { {FORWARD => $_} }
$_->get_value('fripostOptionalMaildrop') ]
, QUOTA => $_->get_value('fripostMailboxQuota') // ''
@@ -176,8 +182,8 @@ sub ListLocals : Runmode {
$template->param( ALIASES => [
map { { ALIAS => $_->get_value('fva')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
- 1 : 0
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE'
+ # TODO: do we really want to list the owners?
, OWNERS => [ map { {OWNER => &dn2email($_)} }
$_->get_value('fripostOwner') ]
, DESTINATIONS => [ map { {DESTINATION => $_} }
@@ -188,6 +194,7 @@ sub ListLocals : Runmode {
]);
$template->param( CATCHALLS => [ map { {CATCHALL => $_} }
$domain->get_value('fripostOptionalMaildrop') ]
+ # TODO: do we really want to list the owners?
, OWNERS => [ ( map { {OWNER => &dn2email($_)} }
$domain->get_value('fripostOwner') )
, ( map { {OWNER => &dn2email($_)} }
@@ -201,8 +208,8 @@ sub ListLocals : Runmode {
$template->param( LISTS => [
map { { LIST => $_->get_value('fvl')
, DESCRIPTION => join ("\n", $_->get_value('description'))
- , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE' ?
- 1 : 0
+ , ISACTIVE => $_->get_value('fripostIsStatusActive') eq 'TRUE'
+ # TODO: do we really want to list the owners?
, OWNERS => [ map { {OWNER => &dn2email($_)} }
$_->get_value('fripostOwner') ]
, TRANSPORT => $_->get_value('fripostListManager')
@@ -214,7 +221,8 @@ sub ListLocals : Runmode {
}
-# This is the page used to edit domains.
+# In this Run Mode authenticated users can edit the domain description
+# and catchall, and toggle activation (if they have the permission).
sub EditDomain : Runmode {
my $self = shift;
my %CFG = $self->cfg;
@@ -226,24 +234,26 @@ sub EditDomain : Runmode {
my $domainname = (split /\//, $ENV{PATH_INFO}, 3)[1];
- if (defined $self->query->param('submit') or
- defined $self->query->param('active')) {
+ my $error; # Tells wether the change submission has fails.
+ if (defined $self->query->param('submit')) {
# Changes have been submitted: process them
my %changes;
- if (defined $self->query->param('active')) {
- $changes{fripostIsStatusActive} = $self->query->param('active');
+ my $q = $self->query;
+ if (defined $q->param('status')) {
+ $changes{fripostIsStatusActive} = $q->param('status') eq 'active' ?
+ 'TRUE' : 'FALSE';
}
- if (defined $self->query->param('description')) {
+ if (defined $q->param('description')) {
my @desc;
- foreach my $d (split /\n/, $self->query->param('description')) {
+ foreach my $d (split /\n/, $q->param('description')) {
push @desc, $d;
}
$changes{description} = [ @desc ];
}
- if (defined $self->query->param('maildrop')) {
+ if (defined $q->param('maildrop')) {
my @maildrop;
- foreach my $d (split /\n/, $self->query->param('maildrop')) {
- $d =~ s/\s//g;
+ foreach my $d (split /\n/, $q->param('maildrop')) {
+ $d =~ s/\s//g; # lowercase and strip out the spaces
push @maildrop, (lc $d) unless $d =~ /^$/;
}
$changes{fripostOptionalMaildrop} = [ @maildrop ];
@@ -251,16 +261,19 @@ sub EditDomain : Runmode {
my $mesg = $ldap->modify( "fvd=$domainname,$suffix",
replace => \%changes );
- die $mesg->error if $mesg->code;
+ $error = $mesg->error if $mesg->code;
}
- my $answer = $ldap->search( base => "fvd=$domainname,$suffix"
- , scope => 'base'
- , filter => 'objectClass=FripostVirtualDomain'
- , deref => 'never'
- );
- die $answer->error if $answer->code;
- $answer = $answer->entry('0');
+ my $domains = $ldap->search( base => "fvd=$domainname,$suffix"
+ , scope => 'base'
+ , filter => 'objectClass=FripostVirtualDomain'
+ , deref => 'never'
+ );
+ die '404' if $domains->code;
+ # The following is not supposed to happen.
+ die "Error: Multible matching entries found." if $domains->count > 1;
+ my $domain = $domains->pop_entry or die '404';
+
$ldap->unbind;
my $template = $self->load_tmpl( 'edit-domain.html', cache => 1, utf8 => 1
@@ -270,12 +283,165 @@ sub EditDomain : Runmode {
$template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
$template->param( DOMAIN => $domainname );
$template->param( DESCRIPTION =>
- join ("\n",$answer->get_value('description')) );
+ join ("\n",$domain->get_value('description')) );
$template->param( MAILDROP =>
- join ("\n",$answer->get_value('fripostOptionalMaildrop')) );
- $template->param( ISACTIVE => $answer->get_value('fripostIsStatusActive') eq 'TRUE' ?
- 1 : 0 );
+ join ("\n",$domain->get_value('fripostOptionalMaildrop')) );
+ $template->param( ISACTIVE => $domain->get_value('fripostIsStatusActive') eq 'TRUE' );
+ $template->param( NEWCHANGES => defined $self->query->param('submit') );
+ $template->param( ERROR => $error );
+ return $template->output;
+}
+
+
+# In this Run Mode authenticated users can edit the entry (if they have
+# the permission).
+sub EditLocal : Runmode {
+ my $self = shift;
+ my %CFG = $self->cfg;
+ my $suffix = join ',', @{$CFG{ldap_suffix}};
+
+ my ($l,$d) = split /@/, $self->authen->username, 2;
+ my $authzDN = "fvu=$l,fvd=$d,". $suffix;
+ my $ldap = $self->ldap_from_auth_user($authzDN);
+
+ my ($null,$domainname,$localname,$crap) = (split /\//, $ENV{PATH_INFO}, 4);
+
+ my $error; # Tells wether the change submission has fails.
+ if (defined $self->query->param('submit')) {
+ # Changes have been submitted: process them
+ my (%changes, $t2);
+ my $q = $self->query;
+ my $t = lc $q->param('t') // die "Error: Unknown type";
+
+ if ($t eq 'mailbox') {
+ $t2 = 'fvu';
+ if ($q->param('oldpassword') ne '' or
+ $q->param('newpassword') ne '' or
+ $q->param('newpassword2') ne '') {
+ # If the user tries to change the password, we make her
+ # bind first, to prevent an attacker from setting a
+ # custom password and accessing the emails.
+
+ if ($q->param('newpassword') eq $q->param('newpassword2')) {
+ my $ldap2 = Net::LDAP->new( $CFG{ldap_uri} );
+ my $mesg = $ldap2->bind ( "fvu=$l,fvd=$d,$suffix",
+ password => $q->param('oldpassword') );
+ if ($mesg->code) {
+ $error = "Wrong password (for ".$self->authen->username.").";
+ }
+ else {
+ my $pw = $q->param('newpassword');
+ # TODO: hash it.
+ $mesg = $ldap2->modify( "fvu=$localname,fvd=$domainname,$suffix",
+ replace => { userPassword => $pw } );
+ $error = $mesg->error if $mesg->code;
+ }
+ $ldap2->unbind;
+ }
+ else {
+ $error = "Password don't match.";
+ }
+ }
+
+ if (defined $q->param('maildrop')) {
+ my @maildrop;
+ foreach my $d (split /\n/, $q->param('maildrop')) {
+ $d =~ s/\s//g; # lowercase and strip out the spaces
+ push @maildrop, (lc $d) unless $d =~ /^$/;
+ }
+ $changes{fripostOptionalMaildrop} = [ @maildrop ];
+ }
+ }
+
+ elsif ($t eq 'alias') {
+ $t2 = 'fva';
+ if (defined $q->param('maildrop')) {
+ my @maildrop;
+ foreach my $d (split /\n/, $q->param('maildrop')) {
+ $d =~ s/\s//g; # lowercase and strip out the spaces
+ push @maildrop, (lc $d) unless $d =~ /^$/;
+ }
+ $changes{fripostMaildrop} = [ @maildrop ];
+ }
+ }
+
+ elsif ($t eq 'list') {
+ $t2 = 'fvl';
+ }
+
+ else {
+ die "Error: Unknown type";
+ }
+
+ # Global parameters
+ if (defined $q->param('status')) {
+ $changes{fripostIsStatusActive} = $q->param('status') eq 'active' ?
+ 'TRUE' : 'FALSE';
+ }
+ if (defined $q->param('description')) {
+ my @desc;
+ foreach my $d (split /\n/, $q->param('description')) {
+ push @desc, $d;
+ }
+ $changes{description} = [ @desc ];
+ }
+
+ unless (defined $error) {
+ my $mesg = $ldap->modify( "$t2=$localname,fvd=$domainname,$suffix",
+ replace => \%changes );
+ $error = $mesg->error if $mesg->code;
+ }
+ }
+
+ # Query *the* matching mailbox, alias or list.
+ my $locals = $ldap->search( base => "fvd=$domainname,$suffix"
+ , scope => 'one'
+ , filter => "(|(&(objectClass=FripostVirtualMailbox)
+ (fvu=$localname))
+ (&(objectClass=FripostVirtualAlias)
+ (fva=$localname))
+ (&(objectClass=FripostVirtualList)
+ (fvl=$localname))
+ )"
+ , deref => 'never'
+ , attrs => [ qw/fvu description
+ fripostIsStatusActive
+ fripostOptionalMaildrop
+ fripostMailboxQuota
+ fva fripostMaildrop
+ fvl fripostListManager/ ]
+ );
+ die '404' if $locals->code;
+ # The following is not supposed to happen.
+ die "Error: Multible matching entries found." if $locals->count > 1;
+ my $local = $locals->pop_entry or die '404';
+
+ my $template;
+ if ($local->dn =~ /^fvu=/) {
+ $template = $self->load_tmpl( 'edit-mailbox.html', cache => 1, utf8 => 1 );
+ $template->param( MAILBOX => $local->get_value('fvu') );
+ $template->param( MAILDROP =>
+ join ("\n",$local->get_value('fripostOptionalMaildrop')) );
+ }
+ elsif ($local->dn =~ /^fva=/) {
+ $template = $self->load_tmpl( 'edit-alias.html', cache => 1, utf8 => 1 );
+ $template->param( ALIAS => $local->get_value('fva') );
+ $template->param( MAILDROP =>
+ join ("\n",$local->get_value('fripostMaildrop')) );
+ }
+ elsif ($local->dn =~ /^fvl=/) {
+ $template = $self->load_tmpl( 'edit-list.html', cache => 1, utf8 => 1 );
+ $template->param( LIST => $local->get_value('fvl') );
+ }
+
+ $template->param( URL => $self->query->url );
+ $template->param( DOMAIN => $domainname );
+ $template->param( USER_LOCALPART => $l, USER_DOMAINPART => $d);
+ $template->param( DESCRIPTION =>
+ join ("\n",$local->get_value('description')) );
+ $template->param( ISACTIVE => $local->get_value('fripostIsStatusActive') eq 'TRUE' );
$template->param( NEWCHANGES => defined $self->query->param('submit') );
+ $template->param( ERROR => $error );
return $template->output;
}
diff --git a/template/edit-alias.html b/template/edit-alias.html
new file mode 100644
index 0000000..dc046cd
--- /dev/null
+++ b/template/edit-alias.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <title>Edit alias <TMPL_VAR NAME=ALIAS>@<TMPL_VAR NAME=DOMAIN></title>
+ <link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
+ </head>
+ <body>
+ <div id="header">
+ <div class="left column">
+ <a href="<TMPL_VAR NAME=URL>/">Root</a> /
+ <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/"><TMPL_VAR NAME=DOMAIN></a> /
+ <TMPL_VAR NAME=ALIAS> /
+ </div>
+ <div class="right column">
+ Logged as <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=USER_DOMAINPART>/<TMPL_VAR NAME=USER_LOCALPART>/?a=edit"
+ ><TMPL_VAR NAME=USER_LOCALPART>@<TMPL_VAR NAME=USER_DOMAINPART></a>
+ | <a href="<TMPL_VAR NAME=URL>/?a=logout">Log out</a>
+ </div>
+ <br/>
+ </div>
+ <hr/>
+
+ <h1>Edit alias <tt><TMPL_VAR NAME=ALIAS>@<TMPL_VAR NAME=DOMAIN></tt></h1>
+
+ <TMPL_IF NAME=NEWCHANGES>
+ <TMPL_IF NAME=ERROR>
+ <div class="fail">Error: <TMPL_VAR NAME=ERROR></div>
+ <TMPL_ELSE>
+ <div class="success">Your changes have succesfully been submitted.</div>
+ </TMPL_IF>
+ <TMPL_ELSE>
+ </br>
+ </TMPL_IF>
+
+ <br/>
+
+ <form class="editform" name="editform" method="post">
+ <div class="editform">
+ <input type="hidden" name="a" value="edit" />
+ <input type="hidden" name="t" value="alias" />
+
+ <p>
+ <h4 class="label">Status</h4>
+ <select name="status">
+ <option value="active" <TMPL_IF NAME=ISACTIVE>selected</TMPL_IF>>Active</option>
+ <option value="inactive" <TMPL_UNLESS NAME=ISACTIVE>selected</TMPL_UNLESS>>Inactive</option>
+ </select>
+ <div class="help">
+ <b>Warning</b>: emails are <i>not</i> delivered to inactive entries.
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Description</h4>
+ <textarea type="text" name="description" cols="50" rows="3" wrap="soft"><TMPL_VAR NAME=DESCRIPTION></textarea>
+ <div class="help">
+ An optional description. (HTML tags are allowed.)
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Destination(s)</h4>
+ <textarea type="text" name="maildrop" cols="50" rows="10" wrap="hard" ><TMPL_VAR NAME=MAILDROP></textarea>
+ <div class="help">
+ The list of destinations (one e-mail address per line) that
+ will receive mail sent to
+ <tt><TMPL_VAR NAME=ALIAS>@<TMPL_VAR NAME=DOMAIN><tt>.
+ </div>
+ </p>
+
+ <hr/>
+
+ <input type="hidden" name="destination" value="<TMPL_VAR NAME=DESTINATION>" />
+ <input type="submit" name="submit" value="Submit Changes" />
+ </div>
+ </form>
+ </body>
+</html>
diff --git a/template/edit-domain.html b/template/edit-domain.html
index 5be62dd..cac44be 100644
--- a/template/edit-domain.html
+++ b/template/edit-domain.html
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
- <title>Domain names for <TMPL_VAR NAME=USER></title>
+ <title>Edit domain <TMPL_VAR NAME=DOMAIN></title>
<link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
@@ -22,20 +22,15 @@
<h1>Edit domain <tt><TMPL_VAR NAME=DOMAIN></tt></h1>
-
- <table width=90% align=center>
- <tr>
- <td width=30%>
- Status: <b><TMPL_IF NAME=ISACTIVE><span class="active">Active</span><TMPL_ELSE><span class="inactive">Inactive</span></TMPL_IF></b>
- (<a href="./?a=edit&active=<TMPL_IF NAME=ISACTIVE>FALSE<TMPL_ELSE>TRUE</TMPL_IF>">toggle</a>)
- </td>
- <td width=70% align=right>
- <span class="ack">
- <TMPL_IF NAME=NEWCHANGES>Your changes have succesfully been submitted.</TMPL_IF>
- </span>
- </td>
- </tr>
- </table>
+ <TMPL_IF NAME=NEWCHANGES>
+ <TMPL_IF NAME=ERROR>
+ <div class="fail">Error: <TMPL_VAR NAME=ERROR></div>
+ <TMPL_ELSE>
+ <div class="success">Your changes have succesfully been submitted.</div>
+ </TMPL_IF>
+ <TMPL_ELSE>
+ </br>
+ </TMPL_IF>
<br/>
@@ -44,10 +39,24 @@
<input type="hidden" name="a" value="edit" />
<p>
+ <h4 class="label">Status</h4>
+ <select name="status">
+ <option value="active" <TMPL_IF NAME=ISACTIVE>selected</TMPL_IF>>Active</option>
+ <option value="inactive" <TMPL_UNLESS NAME=ISACTIVE>selected</TMPL_UNLESS>>Inactive</option>
+ </select>
+ <div class="help">
+ <b>Warning</b>: emails are <i>not</i> delivered to mailboxes,
+ aliases or lists of inactive domains.
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
<h4 class="label">Description</h4>
<textarea type="text" name="description" cols="50" rows="3" wrap="soft"><TMPL_VAR NAME=DESCRIPTION></textarea>
<div class="help">
- An optional description of your domain.
+ An optional description. (HTML tags are allowed.)
</div>
</p>
diff --git a/template/edit-list.html b/template/edit-list.html
new file mode 100644
index 0000000..bca900f
--- /dev/null
+++ b/template/edit-list.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <title>Edit mailbox <TMPL_VAR NAME=MAILBOX>@<TMPL_VAR NAME=DOMAIN></title>
+ <link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
+ </head>
+ <body>
+ <div id="header">
+ <div class="left column">
+ <a href="<TMPL_VAR NAME=URL>/">Root</a> /
+ <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/"><TMPL_VAR NAME=DOMAIN></a> /
+ <TMPL_VAR NAME=LIST> /
+ </div>
+ <div class="right column">
+ Logged as <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=USER_DOMAINPART>/<TMPL_VAR NAME=USER_LOCALPART>/?a=edit"
+ ><TMPL_VAR NAME=USER_LOCALPART>@<TMPL_VAR NAME=USER_DOMAINPART></a>
+ | <a href="<TMPL_VAR NAME=URL>/?a=logout">Log out</a>
+ </div>
+ <br/>
+ </div>
+ <hr/>
+
+ <h1>Edit list <tt><TMPL_VAR NAME=LIST>@<TMPL_VAR NAME=DOMAIN></tt></h1>
+
+ <TMPL_IF NAME=NEWCHANGES>
+ <TMPL_IF NAME=ERROR>
+ <div class="error"><TMPL_VAR NAME=ERROR></div>
+ <TMPL_ELSE>
+ <div class="success">Your changes have succesfully been submitted.</div>
+ </TMPL_IF>
+ <TMPL_ELSE>
+ </br>
+ </TMPL_IF>
+
+ <br/>
+
+ <form class="editform" name="editform" method="post">
+ <div class="editform">
+ <input type="hidden" name="a" value="edit" />
+ <input type="hidden" name="t" value="list" />
+
+ <p>
+ <h4 class="label">Status</h4>
+ <select name="status">
+ <option value="active" <TMPL_IF NAME=ISACTIVE>selected</TMPL_IF>>Active</option>
+ <option value="inactive" <TMPL_UNLESS NAME=ISACTIVE>selected</TMPL_UNLESS>>Inactive</option>
+ </select>
+ <div class="help">
+ <b>Warning</b>: emails are <i>not</i> delivered to inactive entries.
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Description</h4>
+ <textarea type="text" name="description" cols="50" rows="3" wrap="soft"><TMPL_VAR NAME=DESCRIPTION></textarea>
+ <div class="help">
+ An optional description. (HTML tags are allowed.)
+ </div>
+ </p>
+
+ <hr/>
+
+ <input type="hidden" name="destination" value="<TMPL_VAR NAME=DESTINATION>" />
+ <input type="submit" name="submit" value="Submit Changes" />
+ </div>
+ </form>
+ </body>
+</html>
diff --git a/template/edit-mailbox.html b/template/edit-mailbox.html
new file mode 100644
index 0000000..2a122bd
--- /dev/null
+++ b/template/edit-mailbox.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <title>Edit mailbox <TMPL_VAR NAME=MAILBOX>@<TMPL_VAR NAME=DOMAIN></title>
+ <link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
+ </head>
+ <body>
+ <div id="header">
+ <div class="left column">
+ <a href="<TMPL_VAR NAME=URL>/">Root</a> /
+ <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=DOMAIN>/"><TMPL_VAR NAME=DOMAIN></a> /
+ <TMPL_VAR NAME=MAILBOX> /
+ </div>
+ <div class="right column">
+ Logged as <a href="<TMPL_VAR NAME=URL>/<TMPL_VAR NAME=USER_DOMAINPART>/<TMPL_VAR NAME=USER_LOCALPART>/?a=edit"
+ ><TMPL_VAR NAME=USER_LOCALPART>@<TMPL_VAR NAME=USER_DOMAINPART></a>
+ | <a href="<TMPL_VAR NAME=URL>/?a=logout">Log out</a>
+ </div>
+ <br/>
+ </div>
+ <hr/>
+
+ <h1>Edit mailbox <tt><TMPL_VAR NAME=MAILBOX>@<TMPL_VAR NAME=DOMAIN></tt></h1>
+
+ <TMPL_IF NAME=NEWCHANGES>
+ <TMPL_IF NAME=ERROR>
+ <div class="fail">Error: <TMPL_VAR NAME=ERROR></div>
+ <TMPL_ELSE>
+ <div class="success">Your changes have succesfully been submitted.</div>
+ </TMPL_IF>
+ <TMPL_ELSE>
+ </br>
+ </TMPL_IF>
+
+ <br/>
+
+ <form class="editform" name="editform" method="post">
+ <div class="editform">
+ <input type="hidden" name="a" value="edit" />
+ <input type="hidden" name="t" value="mailbox" />
+
+ <p>
+ <h4 class="label">Status</h4>
+ <select name="status">
+ <option value="active" <TMPL_IF NAME=ISACTIVE>selected</TMPL_IF>>Active</option>
+ <option value="inactive" <TMPL_UNLESS NAME=ISACTIVE>selected</TMPL_UNLESS>>Inactive</option>
+ </select>
+ <div class="help">
+ <b>Warning</b>: emails are <i>not</i> delivered to inactive entries.
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Change password</h4>
+
+ <table class="loginform">
+ <tr>
+ <td class="label">Current password</td>
+ <td><input type="password" name="oldpassword" size="20" /></td>
+ </tr>
+ <tr>
+ <td class="label">New password</td>
+ <td><input type="password" name="newpassword" size="20" /></td>
+ </tr>
+ <tr>
+ <td class="label">Repeat new password</td>
+ <td><input type="password" name="newpassword2" size="20" /></td>
+ </tr>
+ </table>
+
+ <div class="help">
+ <i>Note</i>:
+ You need to enter
+ <tt><TMPL_VAR NAME=USER_LOCALPART>@<TMPL_VAR NAME=USER_DOMAINPART></tt>'s
+ current password first.
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Description</h4>
+ <textarea type="text" name="description" cols="50" rows="3" wrap="soft"><TMPL_VAR NAME=DESCRIPTION></textarea>
+ <div class="help">
+ An optional description. (HTML tags are allowed.)
+ </div>
+ </p>
+
+ <hr/>
+
+ <p>
+ <h4 class="label">Mail forwarding</h4>
+ <textarea type="text" name="maildrop" cols="50" rows="10" wrap="hard" ><TMPL_VAR NAME=MAILDROP></textarea>
+ <div class="help">
+ An optional list of destinations (one e-mail address per line) that
+ will <i>also</i> receive mail sent to
+ <tt><TMPL_VAR NAME=MAILBOX>@<TMPL_VAR NAME=DOMAIN><tt>.
+ </div>
+ </p>
+
+ <hr/>
+
+ <input type="hidden" name="destination" value="<TMPL_VAR NAME=DESTINATION>" />
+ <input type="submit" name="submit" value="Submit Changes" />
+ </div>
+ </form>
+ </body>
+</html>
diff --git a/template/list-domains.html b/template/list-domains.html
index f57d448..baaa705 100644
--- a/template/list-domains.html
+++ b/template/list-domains.html
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
- <title>Domain names for <TMPL_VAR NAME=USER></title>
+ <title>Manage domains</title>
<link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
diff --git a/template/list-locals.html b/template/list-locals.html
index 60d4581..cddfb84 100644
--- a/template/list-locals.html
+++ b/template/list-locals.html
@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
- <title>Domain names for <TMPL_VAR NAME=USER></title>
+ <title>Manage domain <TMPL_VAR NAME=DOMAIN></title>
<link href="/css/style.css" media="all" rel="stylesheet" type="text/css" />
</head>
<body>
@@ -73,7 +73,7 @@
<th>Description</th>
<th>Active</th>
<th>Owner(s)</th>
- <th>Destination</th>
+ <th>Destination(s)</th>
</tr>
</thead>
<tbody>