diff --git a/cyrus_ldap_quota.pl b/cyrus_ldap_quota.pl new file mode 100644 index 0000000..2fcf052 --- /dev/null +++ b/cyrus_ldap_quota.pl @@ -0,0 +1,127 @@ +#!/usr/bin/perl +use Cyrus::IMAP::Admin; + +# This script was created by Kevin J. Menard, Jr. . +# It requires root privileges to write to a file in /etc. Best use is +# to set this up as cron job. Works for me. Hope it does for you. +# Any questions/complaints/praise/whatever, send 'em to the address +# above. -- 08/16/2001 + + +# These are the variables you might want to tweak. +my $quota_attr = "mailQuota"; +my $mail_attr = "mailRoutingAddress"; +my $user = "cyrus"; +my $passwd = "blah"; + +# These are the ones that you shouldn't have to. +my @entries = (); +my $index = 0; +my $counter = 0; +my $old_timestamp = 0; +my $timestamp = "199412161032Z"; + +# Open the /etc/cyrus_ldap_quota_time file; it's a long name, but +# shouldn't interfere with existing files :) This file contains 1 line, +# the generalized time format of the last time the script ran. This is +# used for the search, so we only update quotas that have been modified +# since then. + +{ + if (-e "/etc/cyrus_ldap_quota_time") + { + open(TIME_FILE, "/etc/cyrus_ldap_quota_time") or die "could not + open the time file: $!\n"; + + while() { $old_timestamp = $_; } + + close(TIME_FILE); + } + + # Now we deal with the case where the file doesn't exist, that is to + # say the first time the script was run. + + unless ($old_timestamp == 0) { $timestamp = $old_timestamp; } + + + # Now that we have that information, we can overwrite the file with + # the new timestamp. Maybe this overkill, but this is only a + # temporary solution anyway. + + open(TIME_FILE, ">/etc/cyrus_ldap_quota_time") or die "could not + create file: $!\n"; + + my @time = (localtime)[0..5]; + + printf TIME_FILE $time[5] + 1900; + printf TIME_FILE "%02d", $time[4] + 1; + for (my $i = 3; $i >= 0; $i--) { printf TIME_FILE "%02d", $time[$i];} + print TIME_FILE 'Z'; + + close(TIME_FILE); +} + + +# This is where we do the search and then parse the results into a +# useable form. In this case, an arry of hash entries. +{ + # Okay, this very ugly line sets up the LDAP search, and the strips + # away the meaningless stuff. This could be prettier, but I didn't + # want to add a dependency for an LDAP module, and everyone should + # have LDAP search. The greps are just to make things simpler. + + (my $query = "ldapsearch -x '(&(modifyTimestamp>=$timestamp)($quota_attr=*))' $quota_attr $mail_attr + | grep -v ^# | grep -v ^dn | grep -v ^version | grep -v ^search | grep -v ^result | grep -v ^\$") =~ s!\n!!; + + # Now actually do the commands in the above line. + my $result = `$query`; + + + # Split the output into an array, one entry per line. + my @output = split(/\n/, $result); + + # Now go through each line . . . + foreach (@output) + { + # Split on the attribute:value boundary. + (my $key, my $value) = split(/: /); + + # Handle mailRoutingAddress; strip away everything after '@'. + if ($value =~ m!@!) + { + ($value, undef) = split (/@/, $value); + } + + # Add each doctored up attribute:value pair to the entries array. + $entries[$index]{$key} = $value; + + # A crude hack to make sure each of the two attributes makes it + # into one of the entries array element. + if ($counter % 2) + { + $index++; + } + + $counter++; + } +} + +# Now here's the actual interaction with Cyrus IMAPd. It's all pretty +# self-explanatory. +{ + my $imap = Cyrus::IMAP::Admin->new('localhost') or die "imap: + cannot connect to server: $!\n"; + + $imap->send(undef, undef, "LOGIN %s %s", $user, $passwd) or die + "could not send user:pass to the server: $!\n"; + + for (my $i = 0; $i <= $#entries; $i++) + { + $imap->setquota("user." . $entries[$i]{$mail_attr}, "STORAGE", + $entries[$i]{$quota_attr}) + or die "imap: could not set quota for + user.$entries[$i]{$mail_attr}: $!\n"; + } + + $imap=undef; +} diff --git a/imapcreate.pl b/imapcreate.pl new file mode 100644 index 0000000..b26af24 --- /dev/null +++ b/imapcreate.pl @@ -0,0 +1,159 @@ +#!/usr/bin/perl -w +# +# imapcreate: create IMAP mailboxes with quotas +# Reads user names from standard input. +# launch without argument for a short help. +# +# originally found on http://cyrus-utils.sourceforge.net +# (could not find any copyright info, thought) +# +# enhanced by Clément "nodens" Hermann +# +# I'd like to consider this as GPL'd (cf www.gnu.org), but won't add any copyright without the original author's consent. +# + +use Getopt::Long; +use Cyrus::IMAP::Admin; +use strict; + + +my $debug; +my $user; +my $pass; +my $quota; +my @part; +my $useunixhierarchy; +my @mailboxes; +my $delete; +my $cyrus; + +sub usage { + print <]] + [-q quota] [-t partition:list] [-s] [-v] + +Options: + -t : the partition to use. Default to the \"default\" partition + -q ; the quota, if a quota is needed. It is normally in KiloBytes, but you can use m,M,g or G suffix to use MB or GB instead, e.g 10k, 2048M or 100g + -m : a comma-separated mailbox list + -u : your cyrus admin user (usually cyrus or cyradm) + -p : your cyrus admin password (if not provided, it will be asked for) + -s : use the unix hierarchy separator (see imapd.conf(1)) + -d : delete mailboxes instead of creating them + -v : run in debug mode, and print information on stdout + +If no password is submitted with -p, we'll prompt for one. +if no mailbox name is specified with -m, read user names from standard input + + examples: + imapcreate -u cyradm -m foo,bar,joe -q 50000 -t p1:p2 mail.testing.umanitoba.ca + cat list.txt | imapcreate -u cyradm -p 'cyruspass' -q 50M mail.testing.umanitoba.ca +EOU + exit 1; +} + +# Create a mailbox... usage : &CreateMailBox(user,partition[,quota]). +# You have to be authentified already. We use "$cyrus" as the connection name. +# partition can be 'default' +sub CreateMailBox { + my $mbuser = $_[0]; + my $mbpart = $_[1]; + my $mbquota = $_[2]; + + print "Creating $mbuser on $mbpart\n" if $debug; + if ($mbpart eq 'default') { + $cyrus->createmailbox($mbuser); + } + else { + $cyrus->createmailbox($mbuser, $mbpart); + } + warn $cyrus->error if $cyrus->error; + + # Set the quota + if ($mbquota) { + print "Setting quota for $mbuser to $mbquota\n" if $debug; + $cyrus->setquota($mbuser, 'STORAGE', $mbquota); + warn $cyrus->error if $cyrus->error; + } +} + +# Delete a mailbox. Usage: $DeleteMailBox($user) +# Assuming we use $user as the admin. +sub DeleteMailBox { + my $mbuser = $_[0]; + my $delacl = "c"; + + print "Deleting $mbuser\n" if $debug; + $cyrus->setaclmailbox($mbuser, $user, $delacl); + $cyrus->deletemailbox($mbuser); + warn $cyrus->error if $cyrus->error; +} + +GetOptions("d|delete" => \$delete, "u|user=s" => \$user, "p|pass=s" => \$pass, "m|mailboxes=s" => \@mailboxes, "q|quota=s" => \$quota, + "t|part=s" => \@part, "s|UnixHierarchy" => \$useunixhierarchy, "v|verbose" => \$debug ); +@part = split(/:/, join(':', @part)); +push @part, 'default' unless @part; +my $pn = 0; +@mailboxes = split(/,/, join(',', @mailboxes)); + +my $server = shift(@ARGV) if (@ARGV); +usage unless $server; + +# quotas formatting: +if ($quota) { + if ($quota =~ /^(\d+)([mk]?)$/i) { + my $numb = $1; + my $letter = $2; + if ($letter =~ /^m$/i) { + $quota = $numb * 1024; + print "debug: quota=$quota\n" if $debug; + } elsif ($letter =~ /^k$/i) { + $quota = $numb; + print "debug: quota=$quota\n" if $debug; + } else { + die "malformed quota: $quota (must be at least one digit eventually followed by m, M, k or K\n"; +# $quota = $numb; +# print "debug: quota=$quota\n" if $debug; + } + } else { + die "malformed quota: $quota (must be at least one digit eventually followed by m, M, k or K\n"; + } +} + +# Authenticate +$cyrus = Cyrus::IMAP::Admin->new($server); +$cyrus->authenticate(-mechanism => 'login', -user => $user, + -password => $pass); +die $cyrus->error if $cyrus->error; + +# if there isn't any mailbox defined yet, get them from standard input +if (! (defined $mailboxes[0])) { + # For all users + while (<>) { + chomp; + my $mbox = $_; + push @mailboxes, $mbox; + } +} + +# create/delete mailboxes for each user +foreach my $mailbox (@mailboxes) { + if ($useunixhierarchy) { + $mailbox = 'user/' . $mailbox; + } else { + $mailbox = 'user.' . $mailbox; + } + + if ($delete) { + &DeleteMailBox($mailbox) + } else { + # Select the partition + my $pt = $part[$pn]; + $pn += 1; + $pn = 0 unless $pn < @part; + &CreateMailBox($mailbox,$pt,$quota) + } +} +