egroupware_official/emailadmin/inc/class.emailadmin_dovecot.inc.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;
}
}