mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-27 09:09:07 +01:00
3e40eaf0cb
Trunk commits r42507, r42545, r42556, r42557, r42612, r42630 plugin to support Active Directory to store email configuration (in proxyAddresses attribute, no Exchange schema and support!), also fully autodetecting plugins now in emailadmin/inc directory
259 lines
6.6 KiB
PHP
259 lines
6.6 KiB
PHP
<?php
|
|
/**
|
|
* EGroupware EMailAdmin: Support for Dovecot IMAP
|
|
*
|
|
* @link http://www.stylite.de
|
|
* @package emailadmin
|
|
* @author Ralf Becker <rb@stylite.de>
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @version $Id$
|
|
*/
|
|
|
|
include_once(EGW_SERVER_ROOT."/emailadmin/inc/class.defaultimap.inc.php");
|
|
|
|
/**
|
|
* Manages connection to Dovecot IMAP server
|
|
*
|
|
* Basic differences to cyrusimap:
|
|
* - no real admin user, but master user, whos password can be used to connect instead of real user
|
|
* - mailboxes have to be deleted in filesystem (no IMAP command for that)
|
|
* --> require by webserver writable user_home to be configured, otherwise deleting get ignored like with defaultimap
|
|
* - quota can be read, but not set
|
|
*/
|
|
class emailadmin_dovecot extends defaultimap
|
|
{
|
|
/**
|
|
* Label shown in EMailAdmin
|
|
*/
|
|
const DESCRIPTION = 'Dovecot';
|
|
/**
|
|
* Capabilities of this class (pipe-separated): default, sieve, admin, logintypeemail
|
|
*/
|
|
const CAPABILITIES = 'default|sieve|timedsieve|admin|logintypeemail';
|
|
|
|
/**
|
|
* prefix for groupnames, when using groups in ACL Management
|
|
*/
|
|
const ACL_GROUP_PREFIX = '$';
|
|
|
|
// mailbox delimiter
|
|
var $mailboxDelimiter = '.';
|
|
|
|
// mailbox prefix
|
|
var $mailboxPrefix = '';
|
|
|
|
var $enableCyrusAdmin = false;
|
|
|
|
var $cyrusAdminUsername;
|
|
|
|
var $cyrusAdminPassword;
|
|
|
|
/**
|
|
* To enable deleting of a mailbox user_home has to be set and be writable by webserver
|
|
*
|
|
* Supported placeholders are:
|
|
* - %d domain
|
|
* - %u username part of email
|
|
* - %s email address
|
|
*
|
|
* @var string
|
|
*/
|
|
var $user_home; // = '/var/dovecot/imap/%d/%u';
|
|
|
|
/**
|
|
* Opens a connection to a imap server
|
|
*
|
|
* Reimplemented to prefix adminUsername with real username (separated by an asterisk)
|
|
*
|
|
* @param bool $_adminConnection create admin connection if true
|
|
* @return resource the imap connection
|
|
*/
|
|
function openConnection($_adminConnection=false, $_timeout=20)
|
|
{
|
|
if ($_adminConnection)
|
|
{
|
|
if (($pos = strpos($this->adminUsername, '*')) !== false) // remove evtl. set username
|
|
{
|
|
$this->adminUsername = substr($this->adminUsername, $pos+1);
|
|
}
|
|
$this->adminUsername = $this->loginName.'*'.$this->adminUsername;
|
|
}
|
|
return parent::openConnection($_adminConnection, $_timeout);
|
|
}
|
|
|
|
/**
|
|
* Updates an account
|
|
*
|
|
* @param array $_hookValues only value for key 'account_lid' and 'new_passwd' is used
|
|
*/
|
|
function addAccount($_hookValues)
|
|
{
|
|
return $this->updateAccount($_hookValues);
|
|
}
|
|
|
|
/**
|
|
* Delete an account
|
|
*
|
|
* @param array $_hookValues only value for key 'account_lid' is used
|
|
*/
|
|
function deleteAccount($_hookValues)
|
|
{
|
|
// some precausion to really delete just _one_ account
|
|
if (strpos($_hookValues['account_lid'],'%') !== false ||
|
|
strpos($_hookValues['account_lid'],'*') !== false)
|
|
{
|
|
return false;
|
|
}
|
|
return !!$this->deleteUsers($_hookValues['account_lid']);
|
|
}
|
|
|
|
/**
|
|
* Delete multiple (user-)mailboxes via a wildcard, eg. '%' for whole domain
|
|
*
|
|
* Domain is the configured domain and it uses the Cyrus admin user
|
|
*
|
|
* @return string $username='%' username containing wildcards, default '%' for all users of a domain
|
|
* @return int|boolean number of deleted mailboxes on success or false on error
|
|
*/
|
|
function deleteUsers($username='%')
|
|
{
|
|
if(!$this->enableCyrusAdmin || empty($username))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// dovecot can not delete mailbox, they need to be physically deleted in filesystem (webserver needs write-rights to do so!)
|
|
if (empty($this->user_home))
|
|
{
|
|
return false;
|
|
}
|
|
$replace = array('%d' => $this->domainName, '%u' => $username, '%s' => $username.'@'.$this->domainName);
|
|
|
|
if ($username == '%')
|
|
{
|
|
if (($pos = strpos($this->user_home, '%d')) === false)
|
|
{
|
|
throw new egw_exception_assertion_failed("user_home='$this->user_home' contains no domain-part '%d'!");
|
|
}
|
|
$home = strtr(substr($this->user_home, 0, $pos+2), $replace);
|
|
|
|
$ret = count(scandir($home))-2;
|
|
}
|
|
else
|
|
{
|
|
$home = strtr($this->user_home, $replace);
|
|
|
|
$ret = 1;
|
|
}
|
|
if (!is_writable(dirname($home)) || !self::_rm_recursive($home))
|
|
{
|
|
error_log(__METHOD__."('$username') Failed to delete $home!");
|
|
return false;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Recursively delete a directory (or file)
|
|
*
|
|
* @param string $path
|
|
* @return boolean true on success, false on failure
|
|
*/
|
|
private function _rm_recursive($path)
|
|
{
|
|
if (is_dir($path))
|
|
{
|
|
foreach(scandir($path) as $file)
|
|
{
|
|
if ($file == '.' || $file == '..') continue;
|
|
|
|
if (is_dir($path))
|
|
{
|
|
self::_rm_recursive($path.'/'.$file);
|
|
}
|
|
elseif (!unlink($path.'/'.$file))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (!rmdir($path))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
elseif(!unlink($path))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* returns information about a user
|
|
* currently only supported information is the current quota
|
|
*
|
|
* @param string $_username
|
|
* @return array userdata
|
|
*/
|
|
function getUserData($_username)
|
|
{
|
|
// we need a connection to fetch the namespace to get the users mailbox string
|
|
if($this->_connected === false) $this->openConnection();
|
|
$bufferUsername = $this->username;
|
|
$bufferLoginName = $this->loginName;
|
|
$this->username = $_username;
|
|
$nameSpaces = $this->getNameSpaces();
|
|
$mailBoxName = $this->getUserMailboxString($this->username);
|
|
$this->loginName = str_replace((is_array($nameSpaces)?$nameSpaces['others'][0]['name']:'user/'),'',$mailBoxName); // we need to strip the namespacepart
|
|
// now disconnect to be able to reestablish the connection with the targetUser while we go on
|
|
if($this->_connected === true)
|
|
{
|
|
//error_log(__METHOD__."try to disconnect");
|
|
$this->disconnect();
|
|
}
|
|
|
|
$userData = array();
|
|
// we are authenticated with master but for current user
|
|
if($this->openConnection(true) === true && ($quota = $this->getStorageQuotaRoot('INBOX')) && !PEAR::isError($quota))
|
|
{
|
|
$userData['quotaLimit'] = (int) ($quota['QMAX'] / 1024);
|
|
$userData['quotaUsed'] = (int) ($quota['USED'] / 1024);
|
|
}
|
|
$this->username = $bufferUsername;
|
|
$this->loginName = $bufferLoginName;
|
|
$this->disconnect();
|
|
|
|
return $userData;
|
|
}
|
|
|
|
/**
|
|
* Set information about a user
|
|
* currently only supported information is the current quota
|
|
*
|
|
* Dovecot get's quota from it's user-db, but cant set it --> ignored
|
|
*
|
|
* @param string $_username
|
|
* @param int $_quota
|
|
* @return boolean
|
|
*/
|
|
function setUserData($_username, $_quota)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Updates an account
|
|
*
|
|
* @param array $_hookValues only value for key 'account_lid' and 'new_passwd' is used
|
|
*/
|
|
function updateAccount($_hookValues)
|
|
{
|
|
if(!$this->enableCyrusAdmin)
|
|
{
|
|
return false;
|
|
}
|
|
// mailbox get's automatic created with full rights for user
|
|
return true;
|
|
}
|
|
}
|