Hi Folks,
Sorry to dredge this thread up from the dead, but I've put together something that folks might find handy.
First, many thanks to whomever put together the RCPFA patches, and of course to the entire RC team.
I was excited when I saw this, as vacations and forwarding are operations I found myself needing to implement for our users. However, my setup doesn't really have room for PostFix Admin; I'm using Postfix and Dovecot with LDAP as a back-end for authentication and storage of things like forwarding addresses and vacation messages.
To that end, utilizing the extra functionality provided by RCPFA and based on the object/function calls in pfa_*.inc, I wrote a quick-n-dirty "PFA" class that can be dropped in to func.inc to provide LDAP interaction.
Please excuse the messy code; I'm sure some of this could be tightened up significantly. I'm more of a perl hacker than a PHP one.
// Define a class called 'pfa' to handle vacations and forwards
class pfa {
var $ldaprdn = 'cn=admin,dc=domain,dc=com';
var $ldappass = 'secret';
var $ldapbase = 'ou=mail,dc=domain,dc=com';
function update_vacation($u, $a, $s, $t) {
if ($a == 1) { $a = "TRUE"; } else { $a = "FALSE"; }
$ldap = ldap_connect("localhost")
or die("could not connect to ldap server");
if ($ldap) {
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $this->ldaprdn, $this->ldappass);
$sr = ldap_search($ldap, $this->ldapbase, "(&(objectClass=VirtualMailAccount)(mail=$u))");
$ent = ldap_get_entries($ldap, $sr);
$dn = $ent[0]["dn"];
$userdata = array();
$userdata["vacationActive"] = $a;
$userdata["vacationInfo"] = $t;
ldap_modify($ldap, $dn, $userdata) or die("Unable to modify:" . ldap_error($ldap));
ldap_close($ldap);
return true;
} else {
return false;
}
}
function get_vacation($u) {
// Fetch current values from LDAP
$ldap = ldap_connect("localhost") or die ("No LDAP connect");
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $this->ldaprdn, $this->ldappass);
$filter = "(&(objectClass=VirtualMailAccount)(mail=$u))";
$results = array("vacationActive", "vacationInfo");
$sr = ldap_search($ldap, $this->ldapbase, $filter, $results);
$entries = ldap_get_entries($ldap, $sr);
$active = $entries[0]["vacationactive"][0];
$text = $entries[0]["vacationinfo"][0];
if ($active == "TRUE") { $active = 1; } else { $active = 0; }
$retval['active'] = $active;
$retval['subject'] = ''; // Subject not implemented in my LDAP
$retval['body'] = $text;
ldap_unbind($ldap);
return $retval;
}
function update_forwarding($u, $alias, $local) {
$alias = rtrim($alias);
// $alias will be a string with \ns. If it is empty, set forwardActive to false.
// otherwise set forwardActive=true.
// if Local is true, be sure to tack on their local mail address to the
// array when it goes into LDAP.
// If $alias is empty we need to disable forwarding; likewise if it is non-empty
// we need to ensure forwarding is enabled.
if (strlen($alias) < 5) {
$forwarding = "FALSE";
} else {
$forwarding = "TRUE";
}
$fwds = explode("\n", $alias);
// If we get 'true' for $local, then we need to tack on the user's email address.
if ($local == "true") {
$fwds[] = $u;
}
$ldap = ldap_connect("localhost")
or die("could not connect to ldap server");
if ($ldap) {
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $this->ldaprdn, $this->ldappass);
$sr = ldap_search($ldap, $this->ldapbase, "(&(objectClass=VirtualMailAccount)(mail=$u))");
$ent = ldap_get_entries($ldap, $sr);
$dn = $ent[0]["dn"];
$userdata = array();
if ($forwarding == "TRUE") { $userdata["mailForward"] = $fwds; }
$userdata["forwardActive"] = $forwarding;
ldap_modify($ldap, $dn, $userdata) or die("Unable to modify:" . ldap_error($ldap));
ldap_close($ldap);
return true;
} else {
return false;
}
}
function get_forwarding($u) {
// LDAP fetching for forwarding stuff
$ldap = ldap_connect("localhost") or die ("No LDAP connect");
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapbind = ldap_bind($ldap, $this->ldaprdn, $this->ldappass);
$filter = "(&(objectClass=VirtualMailAccount)(mail=$u))";
$results = array("mailForward", "forwardActive");
$sr = ldap_search($ldap, $this->ldapbase, $filter, $results);
$entries = ldap_get_entries($ldap, $sr);
$local = false;
$fwds = "";
if ($entries[0]["forwardactive"][0] == "FALSE") {
$retval['aliases'] = '';
$retval['local'] = true;
ldap_unbind($ldap);
return $retval;
}
foreach ($entries[0]["mailforward"] as $address) {
if ($address == $u) {
$local = true;
}
elseif (is_int($address)) { continue; }
else {
$fwds .= $address . "\n";
}
}
// Kill any lingering \ns at the end
$fwds = rtrim($fwds);
ldap_unbind($ldap);
$retval['aliases'] = $fwds;
$retval['local'] = $local;
return $retval;
}
}
And for reference, here's what a record in my LDAP schema would look like:
accountActive: TRUE
cn: jrandom
delete: FALSE
gidNumber: 100
mail: jrandomhacker@local.domain
mailbox: jrandomhacker
uid: jrandomhacker@local.domain
uidNumber: 1234
userPassword:: {SSHA}foobarbaz
username: jrandomhacker
objectClass: VirtualMailAccount
objectClass: top
objectClass: shadowAccount
objectClass: posixAccount
gecos: J. Random Hacker
vacationActive: FALSE
vacationInfo: Not here, go away.
mailForward: username@remote.domain
forwardActive: FALSE
As you can see from the LDAP record and the code, I store whether or not vacation/forwarding is active with a pair of binary records, which Postfix then uses - along with the values of mailForward - to either redirect the email or send it to gnarwl for an auto-respond.
I haven't implemented password changing as there is another tool our users are meant to use for that, but you can see how it would be relatively easy to add.
Anyway, if anyone has any suggestions or questions, please let me know.