forked from extern/egroupware
b29610c2b9
because of not set "mail" attribute, UCS only set "mailPrimaryAddress", changed our code to also use just that attribute
815 lines
25 KiB
PHP
815 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* EGroupware EMailAdmin: generic base class for SMTP configuration via LDAP
|
|
*
|
|
* @link http://www.stylite.de
|
|
* @package emailadmin
|
|
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
|
* @copyright (c) 2010-15 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @version $Id$
|
|
*/
|
|
|
|
/**
|
|
* Generic base class for SMTP configuration via LDAP
|
|
*
|
|
* This class uses just inetOrgPerson schema to store primary mail address and aliases
|
|
*
|
|
* Aliases are stored as aditional mail Attributes. The primary mail address is the first one.
|
|
* This schema does NOT support forwarding or disabling of an account for mail.
|
|
*
|
|
* Aliases, forwards, forward-only and quota attribute can be stored in same multivalued attribute
|
|
* with different prefixes.
|
|
*
|
|
* Please do NOT copy this class! Extend it and set the constants different.
|
|
*
|
|
* Please note: schema names muse use correct case (eg. "inetOrgPerson"),
|
|
* while attribute name muse use lowercase, as LDAP returns them as keys in lowercase!
|
|
*/
|
|
class emailadmin_smtp_ldap extends emailadmin_smtp
|
|
{
|
|
/**
|
|
* Name of schema, has to be in the right case!
|
|
*/
|
|
const SCHEMA = 'inetOrgPerson';
|
|
|
|
/**
|
|
* Filter for users
|
|
*/
|
|
const USER_FILTER = '(objectClass=posixAccount)';
|
|
|
|
/**
|
|
* Name of schema for groups, has to be in the right case!
|
|
*/
|
|
const GROUP_SCHEMA = 'posixGroup';
|
|
|
|
/**
|
|
* Attribute with mail address(es)
|
|
*/
|
|
const MAIL_ATTR = 'mail';
|
|
|
|
/**
|
|
* Attribute to enable mail for an account, OR false if existence of ALIAS_ATTR is enough for mail delivery
|
|
*/
|
|
const MAIL_ENABLE_ATTR = false;
|
|
|
|
/**
|
|
* Value for MAIL_ENABLED to use local mail address
|
|
*/
|
|
const MAIL_ENABLED_USE_MAIL = '@mail';
|
|
|
|
/**
|
|
* Attribute for aliases OR false to use mail
|
|
*/
|
|
const ALIAS_ATTR = false;
|
|
|
|
/**
|
|
* Caseinsensitive prefix for aliases (eg. "smtp:"), aliases get added with it and only aliases with it are reported
|
|
*/
|
|
const ALIAS_PREFIX = '';
|
|
|
|
/**
|
|
* Primary mail address required as an alias too: true or false
|
|
*/
|
|
const REQUIRE_MAIL_AS_ALIAS = false;
|
|
|
|
/**
|
|
* Attribute for forwards OR false if not possible
|
|
*/
|
|
const FORWARD_ATTR = false;
|
|
|
|
/**
|
|
* Caseinsensitive prefix for forwards (eg. "forward:"), forwards get added with it and only forwards with it are reported
|
|
*/
|
|
const FORWARD_PREFIX = '';
|
|
|
|
/**
|
|
* Attribute to only forward mail, OR false if not available
|
|
*/
|
|
const FORWARD_ONLY_ATTR = false;
|
|
|
|
/**
|
|
* Value of forward-only attribute, if empty any value will switch forward only on (checked with =*)
|
|
*/
|
|
const FORWARD_ONLY = 'forwardOnly';
|
|
|
|
/**
|
|
* Attribute for mailbox, to which mail gets delivered OR false if not supported
|
|
*/
|
|
const MAILBOX_ATTR = false;
|
|
|
|
/**
|
|
* Attribute for quota limit of user in MB
|
|
*/
|
|
const QUOTA_ATTR = false;
|
|
|
|
/**
|
|
* Caseinsensitive prefix for quota (eg. "quota:"), quota get added with it and only quota with it are reported
|
|
*/
|
|
const QUOTA_PREFIX = '';
|
|
|
|
/**
|
|
* Internal quota in MB is multiplicated with this factor before stored in LDAP
|
|
*/
|
|
const QUOTA_FACTOR = 1048576;
|
|
|
|
/**
|
|
* Attribute for user name
|
|
*/
|
|
const USER_ATTR = 'uid';
|
|
|
|
/**
|
|
* Attribute for numeric user id (optional)
|
|
*/
|
|
const USERID_ATTR = 'uidnumber';
|
|
|
|
/**
|
|
* Base for all searches, defaults to $GLOBALS['egw_info']['server']['ldap_context'] and can be set via setBase($base)
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $search_base;
|
|
|
|
/**
|
|
* Special search filter for getUserData only
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $search_filter;
|
|
|
|
/**
|
|
* Log all LDAP writes / actions to error_log
|
|
*/
|
|
var $debug = false;
|
|
|
|
/**
|
|
* from here on implementation, please do NOT copy but extend it!
|
|
*/
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param string $defaultDomain =null
|
|
*/
|
|
function __construct($defaultDomain=null)
|
|
{
|
|
parent::__construct($defaultDomain);
|
|
|
|
if (empty($this->search_base))
|
|
{
|
|
$this->setBase($GLOBALS['egw_info']['server']['ldap_context']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return description for EMailAdmin
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function description()
|
|
{
|
|
return 'LDAP ('.static::SCHEMA.')';
|
|
}
|
|
|
|
/**
|
|
* Set ldap search filter for aliases and forwards (getUserData)
|
|
*
|
|
* @param string $filter
|
|
*/
|
|
function setFilter($filter)
|
|
{
|
|
$this->search_filter = $filter;
|
|
}
|
|
|
|
/**
|
|
* Set ldap search base, default $GLOBALS['egw_info']['server']['ldap_context']
|
|
*
|
|
* @param string $base
|
|
*/
|
|
function setBase($base)
|
|
{
|
|
$this->search_base = $base;
|
|
}
|
|
|
|
/**
|
|
* Hook called on account creation
|
|
*
|
|
* @param array $_hookValues values for keys 'account_email', 'account_firstname', 'account_lastname', 'account_lid'
|
|
* @return boolean true on success, false on error writing to ldap
|
|
*/
|
|
function addAccount($_hookValues)
|
|
{
|
|
$mailLocalAddress = $_hookValues['account_email'] ? $_hookValues['account_email'] :
|
|
common::email_address($_hookValues['account_firstname'],
|
|
$_hookValues['account_lastname'],$_hookValues['account_lid'],$this->defaultDomain);
|
|
|
|
$ds = $this->getLdapConnection();
|
|
|
|
$filter = static::USER_ATTR."=".ldap::quote($_hookValues['account_lid']);
|
|
|
|
if (!($sri = @ldap_search($ds, $this->search_base, $filter)))
|
|
{
|
|
return false;
|
|
}
|
|
$allValues = ldap_get_entries($ds, $sri);
|
|
$accountDN = $allValues[0]['dn'];
|
|
$objectClasses = $allValues[0]['objectclass'];
|
|
unset($objectClasses['count']);
|
|
|
|
// add our mail schema, if not already set
|
|
if(!in_array(static::SCHEMA,$objectClasses) && !in_array(strtolower(static::SCHEMA),$objectClasses))
|
|
{
|
|
$objectClasses[] = static::SCHEMA;
|
|
}
|
|
// the new code for postfix+cyrus+ldap
|
|
$newData = array(
|
|
static::MAIL_ATTR => $mailLocalAddress,
|
|
'objectclass' => $objectClasses
|
|
);
|
|
// does schema have explicit alias attribute AND require mail added as alias too
|
|
if (static::ALIAS_ATTR && static::REQUIRE_MAIL_AS_ALIAS)
|
|
{
|
|
$newData[static::ALIAS_ATTR] = static::ALIAS_PREFIX.$mailLocalAddress;
|
|
}
|
|
// does schema support enabling/disabling mail via attribute
|
|
if (static::MAIL_ENABLE_ATTR)
|
|
{
|
|
$newData[static::MAIL_ENABLE_ATTR] = static::MAIL_ENABLED == self::MAIL_ENABLED_USE_MAIL ?
|
|
$mailLocalAddress : static::MAIL_ENABLE_ATTR;
|
|
}
|
|
// does schema support an explicit mailbox name --> set it
|
|
if (static::MAILBOX_ATTR)
|
|
{
|
|
$newData[static::MAILBOX_ATTR] = self::mailbox_addr($_hookValues);
|
|
}
|
|
|
|
// allow extending classes to add extra data
|
|
$this->addAccountExtra($_hookValues, $allValues[0], $newData);
|
|
|
|
if (!($ret = ldap_mod_replace($ds, $accountDN, $newData)) || $this->debug)
|
|
{
|
|
error_log(__METHOD__.'('.array2string(func_get_args()).") --> ldap_mod_replace(,'$accountDN',".
|
|
array2string($newData).') returning '.array2string($ret).
|
|
(!$ret?' ('.ldap_error($ds).')':''));
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Add additional values to addAccount and setUserData ($_hookValues['location'])
|
|
*
|
|
* @param array $_hookValues
|
|
* @param array $allValues existing data of account as returned by ldap query
|
|
* @param array $newData data to update
|
|
*/
|
|
function addAccountExtra(array $_hookValues, array $allValues, array &$newData)
|
|
{
|
|
unset($_hookValues, $allValues, $newData); // not used, but required by function signature
|
|
}
|
|
|
|
/**
|
|
* Get all email addresses of an account
|
|
*
|
|
* @param string $_accountName
|
|
* @return array
|
|
*/
|
|
function getAccountEmailAddress($_accountName)
|
|
{
|
|
$emailAddresses = array();
|
|
$ds = $this->getLdapConnection();
|
|
$filter = '(&'.static::USER_FILTER.'('.static::USER_ATTR.'='.ldap::quote($_accountName).'))';
|
|
$attributes = array('dn', static::MAIL_ATTR, static::ALIAS_ATTR);
|
|
$sri = @ldap_search($ds, $this->search_base, $filter, $attributes);
|
|
|
|
if ($sri)
|
|
{
|
|
$realName = trim($GLOBALS['egw_info']['user']['account_firstname'] . (!empty($GLOBALS['egw_info']['user']['account_firstname']) ? ' ' : '') . $GLOBALS['egw_info']['user']['account_lastname']);
|
|
$allValues = ldap_get_entries($ds, $sri);
|
|
|
|
if(isset($allValues[0][static::MAIL_ATTR]))
|
|
{
|
|
foreach($allValues[0][static::MAIL_ATTR] as $key => $value)
|
|
{
|
|
if ($key === 'count') continue;
|
|
|
|
$emailAddresses[] = array (
|
|
'name' => $realName,
|
|
'address' => $value,
|
|
'type' => !$key ? 'default' : 'alternate',
|
|
);
|
|
}
|
|
}
|
|
if (static::ALIAS_ATTR && isset($allValues[0][static::ALIAS_ATTR]))
|
|
{
|
|
foreach(self::getAttributePrefix($allValues[0][static::ALIAS_ATTR], static::ALIAS_PREFIX) as $value)
|
|
{
|
|
$emailAddresses[] = array(
|
|
'name' => $realName,
|
|
'address' => $value,
|
|
'type' => 'alternate'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
if ($this->debug) error_log(__METHOD__."('$_accountName') returning ".array2string($emailAddresses));
|
|
|
|
return $emailAddresses;
|
|
}
|
|
|
|
/**
|
|
* Get the data of a given user
|
|
*
|
|
* Multiple accounts may match, if an email address is specified.
|
|
* In that case only mail routing fields "uid", "mailbox" and "forward" contain values
|
|
* from all accounts!
|
|
*
|
|
* @param int|string $user numerical account-id, account-name or email address
|
|
* @param boolean $match_uid_at_domain =true true: uid@domain matches, false only an email or alias address matches
|
|
* @return array with values for keys 'mailLocalAddress', 'mailAlternateAddress' (array), 'mailForwardingAddress' (array),
|
|
* 'accountStatus' ("active"), 'quotaLimit' and 'deliveryMode' ("forwardOnly")
|
|
*/
|
|
function getUserData($user, $match_uid_at_domain=false)
|
|
{
|
|
$userData = array(
|
|
'mailbox' => array(),
|
|
'forward' => array(),
|
|
|
|
);
|
|
|
|
$ldap = $this->getLdapConnection();
|
|
|
|
if (is_numeric($user) && static::USERID_ATTR)
|
|
{
|
|
$filter = '('.static::USERID_ATTR.'='.(int)$user.')';
|
|
}
|
|
elseif (strpos($user, '@') === false)
|
|
{
|
|
if (is_numeric($user)) $user = $GLOBALS['egw']->accounts->id2name($user);
|
|
$filter = '(&'.static::USER_FILTER.'('.static::USER_ATTR.'='.ldap::quote($user).'))';
|
|
}
|
|
else // email address --> build filter by attributes defined in config
|
|
{
|
|
list($namepart, $domain) = explode('@', $user);
|
|
if (!empty($this->search_filter))
|
|
{
|
|
$filter = strtr($this->search_filter, array(
|
|
'%s' => ldap::quote($user),
|
|
'%u' => ldap::quote($namepart),
|
|
'%d' => ldap::quote($domain),
|
|
));
|
|
}
|
|
else
|
|
{
|
|
$to_or = array('('.static::MAIL_ATTR.'='.ldap::quote($user).')');
|
|
if ($match_uid_at_domain) $to_or[] = '('.static::USER_ATTR.'='.ldap::quote($namepart).')';
|
|
if (static::ALIAS_ATTR)
|
|
{
|
|
$to_or[] = '('.static::ALIAS_ATTR.'='.static::ALIAS_PREFIX.ldap::quote($user).')';
|
|
}
|
|
$filter = count($to_or) > 1 ? '(|'.explode('', $to_or).')' : $to_or[0];
|
|
|
|
// if an enable attribute is set, only return enabled accounts
|
|
if (static::MAIL_ENABLE_ATTR)
|
|
{
|
|
$filter = '(&('.static::MAIL_ENABLE_ATTR.'='.
|
|
(static::MAIL_ENABLED ? static::MAIL_ENABLED : '*').")$filter)";
|
|
}
|
|
}
|
|
}
|
|
$attributes = array_values(array_diff(array(
|
|
static::MAIL_ATTR, 'objectclass', static::USER_ATTR, static::MAIL_ENABLE_ATTR, static::ALIAS_ATTR,
|
|
static::MAILBOX_ATTR, static::FORWARD_ATTR, static::FORWARD_ONLY_ATTR, static::QUOTA_ATTR,
|
|
), array(false, '')));
|
|
|
|
$sri = ldap_search($ldap, $this->search_base, $filter, $attributes);
|
|
|
|
if ($sri)
|
|
{
|
|
$allValues = ldap_get_entries($ldap, $sri);
|
|
if ($this->debug) error_log(__METHOD__."('$user') --> ldap_search(, '$this->search_base', '$filter') --> ldap_get_entries=".array2string($allValues[0]));
|
|
|
|
foreach($allValues as $key => $values)
|
|
{
|
|
if ($key === 'count') continue;
|
|
|
|
// groups are always active (if they have an email) and allways forwardOnly
|
|
if (in_array(static::GROUP_SCHEMA, $values['objectclass']))
|
|
{
|
|
$accountStatus = emailadmin_smtp::MAIL_ENABLED;
|
|
$deliveryMode = emailadmin_smtp::FORWARD_ONLY;
|
|
}
|
|
else // for users we have to check the attributes
|
|
{
|
|
if (static::MAIL_ENABLE_ATTR)
|
|
{
|
|
$accountStatus = isset($values[static::MAIL_ENABLE_ATTR]) &&
|
|
(static::MAIL_ENABLED === self::MAIL_ENABLED_USE_MAIL && !empty($values[static::MAIL_ENABLE_ATTR][0]) ||
|
|
static::MAIL_ENABLED && !strcasecmp($values[static::MAIL_ENABLE_ATTR][0], static::MAIL_ENABLED) ||
|
|
!static::MAIL_ENABLED && $values[static::ALIAS_ATTR ? static::ALIAS_ATTR : static::MAIL_ATTR]['count'] > 0) ?
|
|
emailadmin_smtp::MAIL_ENABLED : '';
|
|
}
|
|
else
|
|
{
|
|
$accountStatus = $values[static::ALIAS_ATTR ? static::ALIAS_ATTR : static::MAIL_ATTR]['count'] > 0 ?
|
|
emailadmin_smtp::MAIL_ENABLED : '';
|
|
}
|
|
if (static::FORWARD_ONLY_ATTR)
|
|
{
|
|
if (static::FORWARD_ONLY) // check caseinsensitiv for existence of that value
|
|
{
|
|
$deliveryMode = self::getAttributePrefix($values[static::FORWARD_ONLY_ATTR], static::FORWARD_ONLY) ?
|
|
emailadmin_smtp::FORWARD_ONLY : '';
|
|
}
|
|
else // check for existence of any value
|
|
{
|
|
$deliveryMode = $values[static::FORWARD_ONLY_ATTR]['count'] > 0 ?
|
|
emailadmin_smtp::FORWARD_ONLY : '';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$deliveryMode = '';
|
|
}
|
|
}
|
|
|
|
// collect mail routing data (can be from multiple (active) accounts and groups!)
|
|
if ($accountStatus)
|
|
{
|
|
// groups never have a mailbox, accounts can have a deliveryMode of "forwardOnly"
|
|
if ($deliveryMode != emailadmin_smtp::FORWARD_ONLY)
|
|
{
|
|
$userData[static::USER_ATTR][] = $values[static::USER_ATTR][0];
|
|
if (static::MAILBOX_ATTR && isset($values[static::MAILBOX_ATTR]))
|
|
{
|
|
$userData['mailbox'][] = $values[static::MAILBOX_ATTR][0];
|
|
}
|
|
}
|
|
if (static::FORWARD_ATTR && $values[static::FORWARD_ATTR])
|
|
{
|
|
$userData['forward'] = array_merge($userData['forward'],
|
|
self::getAttributePrefix($values[static::FORWARD_ATTR], static::FORWARD_PREFIX, false));
|
|
}
|
|
}
|
|
|
|
// regular user-data can only be from users, NOT groups
|
|
if (in_array(static::GROUP_SCHEMA, $values['objectclass'])) continue;
|
|
|
|
$userData['mailLocalAddress'] = $values[static::MAIL_ATTR][0];
|
|
$userData['accountStatus'] = $accountStatus;
|
|
|
|
if (static::ALIAS_ATTR)
|
|
{
|
|
$userData['mailAlternateAddress'] = self::getAttributePrefix($values[static::ALIAS_ATTR], static::ALIAS_PREFIX);
|
|
}
|
|
else
|
|
{
|
|
$userData['mailAlternateAddress'] = (array)$values[static::MAIL_ATTR];
|
|
unset($userData['mailAlternateAddress']['count']);
|
|
unset($userData['mailAlternateAddress'][0]);
|
|
$userData['mailAlternateAddress'] = array_values($userData['mailAlternateAddress']);
|
|
}
|
|
|
|
if (static::FORWARD_ATTR)
|
|
{
|
|
$userData['mailForwardingAddress'] = self::getAttributePrefix($values[static::FORWARD_ATTR], static::FORWARD_PREFIX);
|
|
}
|
|
|
|
if (static::MAILBOX_ATTR) $userData['mailMessageStore'] = $values[static::MAILBOX_ATTR][0];
|
|
|
|
$userData['deliveryMode'] = $deliveryMode;
|
|
|
|
// eg. suse stores all email addresses as aliases
|
|
if (static::REQUIRE_MAIL_AS_ALIAS &&
|
|
($k = array_search($userData['mailLocalAddress'],$userData['mailAlternateAddress'])) !== false)
|
|
{
|
|
unset($userData['mailAlternateAddress'][$k]);
|
|
}
|
|
|
|
if (static::QUOTA_ATTR && isset($values[static::QUOTA_ATTR]))
|
|
{
|
|
$userData['quotaLimit'] = self::getAttributePrefix($values[static::QUOTA_ATTR], static::QUOTA_PREFIX);
|
|
$userData['quotaLimit'] = array_shift($userData['quotaLimit']);
|
|
$userData['quotaLimit'] = $userData['quotaLimit'] ? $userData['quotaLimit'] / static::QUOTA_FACTOR : null;
|
|
}
|
|
}
|
|
}
|
|
if ($this->debug) error_log(__METHOD__."('$user') returning ".array2string($userData));
|
|
|
|
return $userData;
|
|
}
|
|
|
|
/**
|
|
* Set the data of a given user
|
|
*
|
|
* @param int $_uidnumber numerical user-id
|
|
* @param array $_mailAlternateAddress
|
|
* @param array $_mailForwardingAddress
|
|
* @param string $_deliveryMode
|
|
* @param string $_accountStatus
|
|
* @param string $_mailLocalAddress
|
|
* @param int $_quota in MB
|
|
* @param boolean $_forwarding_only =false not used as we have our own addAccount method
|
|
* @param string $_setMailbox =null used only for account migration
|
|
* @return boolean true on success, false on error writing to ldap
|
|
*/
|
|
function setUserData($_uidnumber, array $_mailAlternateAddress, array $_mailForwardingAddress, $_deliveryMode,
|
|
$_accountStatus, $_mailLocalAddress, $_quota, $_forwarding_only=false, $_setMailbox=null)
|
|
{
|
|
unset($_forwarding_only); // not used
|
|
|
|
if (static::USERID_ATTR)
|
|
{
|
|
$filter = static::USERID_ATTR.'='.(int)$_uidnumber;
|
|
}
|
|
else
|
|
{
|
|
$uid = $GLOBALS['egw']->accounts->id2name($_uidnumber);
|
|
$filter = static::USER_ATTR.'='.ldap::quote($uid);
|
|
}
|
|
$ldap = $this->getLdapConnection();
|
|
|
|
if (!($sri = @ldap_search($ldap, $this->search_base, $filter)))
|
|
{
|
|
return false;
|
|
}
|
|
$allValues = ldap_get_entries($ldap, $sri);
|
|
|
|
$accountDN = $allValues[0]['dn'];
|
|
$uid = $allValues[0][static::USER_ATTR][0];
|
|
$objectClasses = $allValues[0]['objectclass'];
|
|
|
|
unset($objectClasses['count']);
|
|
|
|
if(!in_array(static::SCHEMA,$objectClasses) && !in_array(strtolower(static::SCHEMA),$objectClasses))
|
|
{
|
|
$objectClasses[] = static::SCHEMA;
|
|
$newData['objectclass'] = $objectClasses;
|
|
}
|
|
|
|
sort($_mailAlternateAddress);
|
|
sort($_mailForwardingAddress);
|
|
|
|
$newData[static::MAIL_ATTR] = $_mailLocalAddress;
|
|
// does schema have explicit alias attribute
|
|
if (static::ALIAS_ATTR)
|
|
{
|
|
self::setAttributePrefix($newData[static::ALIAS_ATTR], $_mailAlternateAddress, static::ALIAS_PREFIX);
|
|
|
|
// all email must be stored as alias for suse
|
|
if (static::REQUIRE_MAIL_AS_ALIAS && !in_array($_mailLocalAddress,(array)$_mailAlternateAddress))
|
|
{
|
|
self::setAttributePrefix($newData[static::ALIAS_ATTR], $_mailLocalAddress, static::ALIAS_PREFIX);
|
|
}
|
|
}
|
|
// or de we add them - if existing - to mail attr
|
|
elseif ($_mailAlternateAddress)
|
|
{
|
|
self::setAttributePrefix($newData[static::MAIL_ATTR], $_mailAlternateAddress, static::ALIAS_PREFIX);
|
|
}
|
|
// does schema support to store forwards
|
|
if (static::FORWARD_ATTR)
|
|
{
|
|
self::setAttributePrefix($newData[static::FORWARD_ATTR], $_mailForwardingAddress, static::FORWARD_PREFIX);
|
|
}
|
|
// does schema support only forwarding incomming mail
|
|
if (static::FORWARD_ONLY_ATTR)
|
|
{
|
|
self::setAttributePrefix($newData[static::FORWARD_ONLY_ATTR],
|
|
$_deliveryMode ? (static::FORWARD_ONLY ? static::FORWARD_ONLY : 'forwardOnly') : array());
|
|
}
|
|
// does schema support an explicit mailbox name --> set it with $uid@$domain
|
|
if (static::MAILBOX_ATTR && empty($allValues[0][static::MAILBOX_ATTR][0]))
|
|
{
|
|
$newData[static::MAILBOX_ATTR] = $this->mailbox_addr(array(
|
|
'account_id' => $_uidnumber,
|
|
'account_lid' => $uid,
|
|
'account_email' => $_mailLocalAddress,
|
|
));
|
|
}
|
|
if (static::QUOTA_ATTR)
|
|
{
|
|
self::setAttributePrefix($newData[static::QUOTA_ATTR],
|
|
(int)$_quota > 0 ? (int)$_quota*static::QUOTA_FACTOR : array(), static::QUOTA_PREFIX);
|
|
}
|
|
// does schema support enabling/disabling mail via attribute
|
|
if (static::MAIL_ENABLE_ATTR)
|
|
{
|
|
$newData[static::MAIL_ENABLE_ATTR] = $_accountStatus ?
|
|
(static::MAIL_ENABLED == self::MAIL_ENABLED_USE_MAIL ? $_mailLocalAddress : static::MAIL_ENABLED) : array();
|
|
}
|
|
// if we have no mail-enabled attribute, but require primary mail in aliases-attr
|
|
// we do NOT write aliases, if mail is not enabled
|
|
if (!$_accountStatus && !static::MAIL_ENABLE_ATTR && static::REQUIRE_MAIL_AS_ALIAS)
|
|
{
|
|
$newData[static::ALIAS_ATTR] = array();
|
|
}
|
|
// does schema support an explicit mailbox name --> set it, $_setMailbox is given
|
|
if (static::MAILBOX_ATTR && $_setMailbox)
|
|
{
|
|
$newData[static::MAILBOX_ATTR] = $_setMailbox;
|
|
}
|
|
|
|
$this->addAccountExtra(array('location' => 'setUserData'), $allValues[0], $newData);
|
|
|
|
if ($this->debug) error_log(__METHOD__.'('.array2string(func_get_args()).") --> ldap_mod_replace(,'$accountDN',".array2string($newData).')');
|
|
|
|
return ldap_mod_replace($ldap, $accountDN, $newData);
|
|
}
|
|
|
|
/**
|
|
* Saves the forwarding information
|
|
*
|
|
* @param int $_accountID
|
|
* @param string $_forwardingAddress
|
|
* @param string $_keepLocalCopy 'yes'
|
|
* @return boolean true on success, false on error writing to ldap
|
|
*/
|
|
function saveSMTPForwarding($_accountID, $_forwardingAddress, $_keepLocalCopy)
|
|
{
|
|
$ds = $this->getLdapConnection();
|
|
if (static::USERID_ATTR)
|
|
{
|
|
$filter = '(&'.static::USER_FILTER.'('.static::USERID_ATTR.'='.(int)$_accountID.'))';
|
|
}
|
|
else
|
|
{
|
|
$uid = $GLOBALS['egw']->accounts->id2name($_accountID);
|
|
$filter = '(&'.static::USER_FILTER.'('.static::USER_ATTR.'='.ldap::quote($uid).'))';
|
|
}
|
|
$attributes = array('dn', static::FORWARD_ATTR, 'objectclass');
|
|
if (static::FORWARD_ONLY_ATTR)
|
|
{
|
|
$attributes[] = static::FORWARD_ONLY_ATTR;
|
|
}
|
|
$sri = ldap_search($ds, $this->search_base, $filter, $attributes);
|
|
|
|
if ($sri)
|
|
{
|
|
$newData = array();
|
|
$allValues = ldap_get_entries($ds, $sri);
|
|
$objectClasses = $allValues[0]['objectclass'];
|
|
$newData['objectclass'] = $allValues[0]['objectclass'];
|
|
|
|
unset($newData['objectclass']['count']);
|
|
|
|
if(!in_array(static::SCHEMA,$objectClasses))
|
|
{
|
|
$newData['objectclass'][] = static::SCHEMA;
|
|
}
|
|
if (static::FORWARD_ATTR)
|
|
{
|
|
// copy all non-forward data (different prefix) to newData, all existing forwards to $forwards
|
|
$newData[static::FORWARD_ATTR] = $allValues[0][static::FORWARD_ATTR];
|
|
$forwards = self::getAttributePrefix($newData[static::FORWARD_ATTR], static::FORWARD_PREFIX);
|
|
|
|
if(!empty($_forwardingAddress))
|
|
{
|
|
if($forwards)
|
|
{
|
|
if (!is_array($_forwardingAddress))
|
|
{
|
|
// replace the first forwarding address (old behavior)
|
|
$forwards[0] = $_forwardingAddress;
|
|
}
|
|
else
|
|
{
|
|
// replace all forwarding Addresses
|
|
$forwards = $_forwardingAddress;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$forwards = (array)$_forwardingAddress;
|
|
}
|
|
if (static::FORWARD_ONLY_ATTR)
|
|
{
|
|
self::getAttributePrefix($newData[static::FORWARD_ONLY_ATTR], static::FORWARD_ONLY);
|
|
self::setAttributePrefix($newData[static::FORWARD_ONLY_ATTR],
|
|
$_keepLocalCopy == 'yes' ? array() : static::FORWARD_ONLY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$forwards = array();
|
|
}
|
|
// merge in again all new set forwards incl. opt. prefix
|
|
self::getAttributePrefix($newData[static::FORWARD_ATTR], $forwards, static::FORWARD_PREFIX);
|
|
}
|
|
if ($this->debug) error_log(__METHOD__.'('.array2string(func_get_args()).") --> ldap_mod_replace(,'{$allValues[0]['dn']}',".array2string($newData).')');
|
|
|
|
return ldap_modify ($ds, $allValues[0]['dn'], $newData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get configured mailboxes of a domain
|
|
*
|
|
* @param boolean $return_inactive return mailboxes NOT marked as accountStatus=active too
|
|
* @return array uid => name-part of mailMessageStore
|
|
*/
|
|
function getMailboxes($return_inactive)
|
|
{
|
|
$ds = $this->getLdapConnection();
|
|
$filter = array('('.static::MAIL_ATTR.'=*)');
|
|
$attrs = array(static::USER_ATTR, static::MAIL_ATTR);
|
|
if (static::MAILBOX_ATTR)
|
|
{
|
|
$filter[] = '('.static::MAILBOX_ATTR.'=*)';
|
|
$attrs[] = static::MAILBOX_ATTR;
|
|
}
|
|
if (!$return_inactive && static::MAIL_ENABLE_ATTR)
|
|
{
|
|
$filter[] = '('.static::MAIL_ENABLE_ATTR.'='.static::MAIL_ENABLED.')';
|
|
}
|
|
if (count($filter) > 1)
|
|
{
|
|
$filter = '(&'.implode('', $filter).')';
|
|
}
|
|
else
|
|
{
|
|
$filter = $filter[0];
|
|
}
|
|
if (!($sr = @ldap_search($ds, $this->search_base, $filter, $attrs)))
|
|
{
|
|
//error_log("Error ldap_search(\$ds, '$base', '$filter')!");
|
|
return array();
|
|
}
|
|
$entries = ldap_get_entries($ds, $sr);
|
|
|
|
unset($entries['count']);
|
|
|
|
$mailboxes = array();
|
|
foreach($entries as $entry)
|
|
{
|
|
if ($entry[static::USER_ATTR][0] == 'anonymous') continue; // anonymous is never a mail-user!
|
|
list($mailbox) = explode('@', $entry[static::MAILBOX_ATTR ? static::MAILBOX_ATTR : static::MAIL_ATTR][0]);
|
|
$mailboxes[$entry[static::USER_ATTR][0]] = $mailbox;
|
|
}
|
|
return $mailboxes;
|
|
}
|
|
|
|
/**
|
|
* Set values in a given LDAP attribute using an optional prefix
|
|
*
|
|
* @param array &$attribute on return array with values set and existing values preseved
|
|
* @param string|array $values value(s) to set
|
|
* @param string $prefix ='' prefix to use or ''
|
|
*/
|
|
protected static function setAttributePrefix(&$attribute, $values, $prefix='')
|
|
{
|
|
//$attribute_in = $attribute;
|
|
if (!isset($attribute)) $attribute = array();
|
|
if (!is_array($attribute)) $attribute = array($attribute);
|
|
|
|
foreach((array)$values as $value)
|
|
{
|
|
$attribute[] = $prefix.$value;
|
|
}
|
|
//error_log(__METHOD__."(".array2string($attribute_in).", ".array2string($values).", '$prefix') attribute=".array2string($attribute));
|
|
}
|
|
|
|
/**
|
|
* Get values having an optional prefix from a given LDAP attribute
|
|
*
|
|
* @param array &$attribute only "count" and prefixed values get removed, get's reindexed, if values have been removed
|
|
* @param string $prefix ='' prefix to use or ''
|
|
* @param boolean $remove =true remove returned values from $attribute
|
|
* @return array with values (prefix removed) or array() if nothing found
|
|
*/
|
|
protected static function getAttributePrefix(&$attribute, $prefix='', $remove=true)
|
|
{
|
|
//$attribute_in = $attribute;
|
|
$values = array();
|
|
|
|
if (isset($attribute))
|
|
{
|
|
unset($attribute['count']);
|
|
|
|
foreach($attribute as $key => $value)
|
|
{
|
|
if (!$prefix || stripos($value, $prefix) === 0)
|
|
{
|
|
if ($remove) unset($attribute[$key]);
|
|
$values[] = substr($value, strlen($prefix));
|
|
}
|
|
}
|
|
// reindex $attribute, if neccessary
|
|
if ($values && $attribute) $attribute = array_values($attribute);
|
|
}
|
|
//error_log(__METHOD__."(".array2string($attribute_in).", '$prefix', $remove) attribute=".array2string($attribute).' returning '.array2string($values));
|
|
return $values;
|
|
}
|
|
|
|
/**
|
|
* Return LDAP connection
|
|
*/
|
|
protected function getLdapConnection()
|
|
{
|
|
static $ldap=null;
|
|
|
|
if (is_null($ldap)) $ldap = $GLOBALS['egw']->ldap->ldapConnect();
|
|
|
|
return $ldap;
|
|
}
|
|
}
|