--- a/Common.pm Wed Nov 23 13:05:59 2011 +0100
+++ b/Common.pm Thu Nov 24 11:57:31 2011 +0100
@@ -28,9 +28,12 @@
# * account *
default_domain => { ARGS => "=s", DEFAULT => "" },
imap_server => { ARGS => "=s", DEFAULT => "localhost" },
+ imap_port => { ARGS => "=s", DEFAULT => "143" },
imap_admin => { ARGS => "=s", DEFAULT => $ENV{USER} },
imap_password =>{ ARGS => "=s" },
- imap_quota => { ARGS => "=i", DEFAULT => 300, ALIAS => "quota" },
+ imap_quota => { ARGS => "=i", DEFAULT => 300 * 1024 * 1024, ALIAS => "quota" },
+ # dovecots mail_location (%1, %u & %d supported)
+ imap_mail_location => { ARGS => "=s", DEFAULT => '/var/vmail/users/%d/%1/%u' },
mbox => { ARGS => "!", DEFAULT => 1 },
password => { ARGS => "=s" },
@@ -63,6 +66,7 @@
ldap_at_address => { ARGS => "=s", DEFAULT => "XXXmailAddress" },
ldap_at_group => { ARGS => "=s", DEFAULT => "XXXmailGroup" },
+ ldap_at_quota => { ARGS => "=s", DEFAULT => "XXXmailQuota" },
ldap_at_forwardingaddress =>
{ ARGS => "=s", DEFAULT => "XXXmailForwardingAddress" },
ldap_at_primaryaddress =>
--- a/account.pm Wed Nov 23 13:05:59 2011 +0100
+++ b/account.pm Thu Nov 24 11:57:31 2011 +0100
@@ -8,14 +8,14 @@
use Net::LDAP;
use Net::LDAP::Constant qw(LDAP_ALREADY_EXISTS LDAP_NO_SUCH_OBJECT LDAP_TYPE_OR_VALUE_EXISTS);
use Net::LDAP::Entry;
-use Cyrus::IMAP::Admin;
+use Mail::IMAPTalk;
use Text::Wrap;
use password;
my $Cf;
my ($ldap, $ubase, $abase);
-my ($imap);
+my ($imap, $imap_password);
END { $imap and $imap = undef; };
@@ -33,6 +33,7 @@
sub AT_ADDRESS();
sub AT_GROUP();
sub AT_FORWARDINGADDRESS();
+sub AT_QUOTA();
sub import(@) {
$Cf = shift;
@@ -45,6 +46,7 @@
import constant AT_ADDRESS => $Cf->ldap_at_address;
import constant AT_GROUP => $Cf->ldap_at_group;
import constant AT_FORWARDINGADDRESS => $Cf->ldap_at_forwardingaddress;
+ import constant AT_QUOTA => $Cf->ldap_at_quota;
$ubase = OU_ACCOUNTS . "," . $Cf->ldap_base;
$abase = OU_ALIASES . "," . $Cf->ldap_base;
@@ -57,11 +59,9 @@
password => $Cf->ldap_password || $ENV{LDAP_PASS} || password::ask("LDAP (". $Cf->ldap_bind_dn .") password: "));
die $r->error, "\n" if $r->code;
- $imap = new Cyrus::IMAP::Admin or die $@;
- $imap->authenticate(-server => $Cf->imap_server, -user => $Cf->imap_admin,
- -password => $Cf->imap_password || $ENV{IMAP_PASS} || password::ask("IMAP (". $Cf->imap_admin .") password: "))
- or die $@;
-
+ $imap = Mail::IMAPTalk->new(Server => $Cf->imap_server, Port => $Cf->imap_port)
+ or die "Can't connect to IMAP Server '", $Cf->imap_server, "', Port '", $Cf->imap_port, "': ", $@;
+ $imap_password = $Cf->imap_password || $ENV{IMAP_PASS} || password::ask("IMAP (". $Cf->imap_admin .") password: ");
if ($Cf->list) { _list() }
elsif ($Cf->add) { _add() }
@@ -88,12 +88,19 @@
my $mailAddress = [$user, split /,/, $Cf->other || ""]; # ditto
$user =~ s/!$//; # jetzt können wir ! nicht mehr brauchn
- my $mbox = "user/$user";
my $cn = $Cf->fullname || $user;
my $sn = (reverse split " ", $cn)[0];
my $mailGroup = [split /,/, $Cf->group || ""];
my $mailForwardingAddress = [split /,/, $Cf->forward || ""];
my $pw = _mkpw($Cf->password || "{pwgen}");
+ # assuming usernames of the form localpart@domain
+ $user =~ /@(.+)$/;
+ my $escapes;
+ die "Invalid username '$user'" unless $escapes->{'%u'} = $user
+ and $escapes->{'%1'} = substr $user, 0, 1
+ and $escapes->{'%d'} = $1;
+ my $mbox = $Cf->imap_mail_location;
+ $mbox =~ s/$_/$escapes->{$_}/ for keys %{$escapes};
if ($mailPrimaryAddress !~ /@/) {
$mailPrimaryAddress .= "@" . $Cf->default_domain;
@@ -139,9 +146,10 @@
$e->add((AT_ADDRESS) => $mailAddress);
$e->add((AT_PRIMARYADDRESS) => $mailPrimaryAddress);
- $e->add(userPassword => $pw);
+ $e->add(userPassword => "{plain}$pw");
$e->add((AT_GROUP) => $mailGroup) if @$mailGroup;
$e->add((AT_FORWARDINGADDRESS) => $mailForwardingAddress) if @$mailForwardingAddress;
+ $e->add((AT_QUOTA) => $Cf->imap_quota);
# $e->add(iusRestrictedMail => $Cf->internal) if $Cf->internal ne ":";
@@ -152,22 +160,24 @@
$r = $e->update($ldap);
die $r->error if $r->code;
- verbose("ok");
+ verbose('ok');
verbose(" Password: $pw") if not $Cf->password or $Cf->password eq "{pwgen}";
}
if($Cf->mbox) {
verbose("\n\t$mbox...");
- if ($imap->list($mbox)) { verbose("exists") }
+ if (-d $mbox) { verbose('exists') }
else {
- $imap->create($mbox) and verbose("ok") or die $@;
- $imap->setacl($mbox, $Cf->imap_admin => "lrswipcda") or die $@;
- $imap->setquota($mbox, STORAGE => 1024 * $Cf->imap_quota) or die $@;
+
+ $imap->login($user, $pw) or die $@;
+ # 'list' seems to trigger acl file (and thus the maildir) creation with dovecot
+ $imap->list('', '*') or die $@;
+ verbose('ok');
}
+
}
-
verbose("\n");
}
@@ -187,7 +197,6 @@
my $user = $e->get_value("uid");
my $dn = $e->dn;
- my $mbox = "user/$user";
my $modified = 0;
verbose "$user:";
@@ -296,8 +305,8 @@
# FIXME: Wenn keine Mailbox existiert, gibt es hier ein Problem
if (defined $Cf->imap_quota) {
- $imap->setquota($mbox, STORAGE => $Cf->imap_quota * 1024)
- or die $@;
+# $imap->setquota($mbox, STORAGE => $Cf->imap_quota * 1024)
+# or die $@;
}
verbose "ok\n";
@@ -322,7 +331,6 @@
foreach (@ARGV) {
my $user = $_;
my $dn = "uid=$user,$ubase";
- my $mbox = "user/$user";
verbose("$user:\n");
@@ -352,9 +360,11 @@
verbose("\n");
if ($Cf->mbox) {
- verbose("\tdeleting mbox $mbox...");
- $imap->delete($mbox) and verbose("ok")
- or verbose($imap->error);
+ verbose("\tdeleting mbox for $user...");
+ my $m = user_dovecot( 'LOGIN' )->{'home'};
+ if (not (defined $m and $m)) { verbose("can't determine mbox location - not deleting it"); }
+ elsif (not unlink $m) { verbose("Can't unlink $m: $!"); }
+ else { verbose('ok'); }
}
verbose("\n");
@@ -384,7 +394,6 @@
my $ml = join(", ", $e->get_value(AT_ADDRESS)) || ""; # ??
my $mg = join(", ", $e->get_value(AT_GROUP)) || ""; # ??
my $forw = join (", ", $e->get_value(AT_FORWARDINGADDRESS)) || "";
- my $mbox = "user/$uid";
print "$uid: $cn <$mr>";
@@ -392,13 +401,15 @@
#print " INTERNAL";
#}
+ $imap->login("$uid*" . $Cf->imap_admin, $imap_password ) or die $@;
+
MBOX: {
- if (!$imap->list($mbox)) {
+ if (!$imap->list()) {
print ", no mbox";
last MBOX;
}
print ", mbox";
- my %q = $imap->listquota($mbox);
+ my %q = $imap->listquota();
my ($used, $max) = map { int($_ / 1024) } @{$q{STORAGE}};
if (!$max) {
--- a/ma Wed Nov 23 13:05:59 2011 +0100
+++ b/ma Thu Nov 24 11:57:31 2011 +0100
@@ -52,7 +52,6 @@
use warnings;
use IO::File;
-use Cyrus::IMAP::Admin;
use AppConfig qw(:expand);
use File::Basename;
use FindBin;
--- a/ma.conf.ex Wed Nov 23 13:05:59 2011 +0100
+++ b/ma.conf.ex Thu Nov 24 11:57:31 2011 +0100
@@ -18,7 +18,10 @@
at_forwardingaddress = XXXMailForwardingAddress
at_primaryaddress = XXXMailPrimaryAddress
at_group = XXXMailGroup
+at_quota = XXXMailQuotaBytes
[imap]
admin = cyrus
password = SECRET
+server = localhost
+port = 143