From: Gunnar Wrobel Date: Thu, 22 Jul 2010 14:59:38 +0000 (+0200) Subject: Working Incoming test. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=0d8fd2880aeda33139a0bc84a9e61b2c6c2224c5;p=horde.git Working Incoming test. --- diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter.php index 674ce72ee..fcfd9ab0c 100644 --- a/framework/Kolab_Filter/lib/Horde/Kolab/Filter.php +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter.php @@ -31,19 +31,32 @@ require_once 'Horde/Autoloader/Default.php'; */ class Horde_Kolab_Filter { + /** + * The injector providing the dependencies for this application. + * + * @var Horde_Injector + */ + private $_injector; + public function __construct(Horde_Injector $injector = null) { if ($injector === null) { - $this->injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $this->_injector = new Horde_Injector(new Horde_Injector_TopLevel()); - $this->injector->bindFactory( + $this->_injector->bindFactory( 'Horde_Log_Logger', 'Horde_Kolab_Filter_Factory', 'getLogger' ); - $this->injector->bindImplementation( + $this->_injector->bindFactory( + 'Horde_Kolab_Server_Composite', 'Horde_Kolab_Filter_Factory', 'getUserDb' + ); + $this->_injector->bindImplementation( 'Horde_Kolab_Filter_Temporary', 'Horde_Kolab_Filter_Temporary_File' ); + $this->_injector->setInstance( + 'Horde_Kolab_Filter', $this + ); } else { - $this->injector = $injector; + $this->_injector = $injector; } } @@ -55,12 +68,22 @@ class Horde_Kolab_Filter public function main($type, $inh = STDIN, $transport = null) { /** Setup all configuration information */ - /* $configuration = $this->injector->getInstance('Horde_Kolab_Filter_Configuration'); */ + /* $configuration = $this->_injector->getInstance('Horde_Kolab_Filter_Configuration'); */ /* $configuration->init(); */ /** Now run the filter */ - $filter = $this->injector->getInstance('Horde_Kolab_Filter_' . $type); + $filter = $this->_injector->getInstance('Horde_Kolab_Filter_' . $type); $filter->init(); $filter->parse($inh, $transport); } + + /** + * Return the connection to the user database. + * + * @return Horde_Kolab_Server_Composite The user DB handle. + */ + public function getUserDb() + { + return $this->_injector->getInstance('Horde_Kolab_Server_Composite'); + } } \ No newline at end of file diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Base.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Base.php index 2f8930306..826093dbd 100644 --- a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Base.php +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Base.php @@ -1,19 +1,29 @@ + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Filter */ /** * A basic definition for a PHP based postfix filter. * - * Copyright 2004-2008 Klarälvdalens Datakonsult AB + * Copyright 2004-2010 Klarälvdalens Datakonsult AB * * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. * - * @author Steffen Hansen - * @author Gunnar Wrobel - * @package Kolab_Filter + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Filter */ class Horde_Kolab_Filter_Base { @@ -28,14 +38,18 @@ class Horde_Kolab_Filter_Base * Configuration. * * @param Horde_Kolab_Filter_Configuration + * + * @todo Make private */ - private $_config; + protected $_config; /** * The log backend that needs to implement the debug(), info() and err() * methods. * * @param Horde_Kolab_Filter_Logger + * + * @todo Make private/decorator */ protected $_logger; diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Configuration.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Configuration.php index 0e9485fc4..2d04d4672 100644 --- a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Configuration.php +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Configuration.php @@ -118,16 +118,19 @@ class Horde_Kolab_Filter_Configuration } /* This is used as the default domain for unqualified adresses */ - if (!array_key_exists('SERVER_NAME', $_SERVER)) { - $_SERVER['SERVER_NAME'] = $conf['kolab']['imap']['server']; - } - - if (!array_key_exists('REMOTE_ADDR', $_SERVER)) { - $_SERVER['REMOTE_ADDR'] = $conf['kolab']['imap']['server']; - } - - if (!array_key_exists('REMOTE_HOST', $_SERVER)) { - $_SERVER['REMOTE_HOST'] = $conf['kolab']['imap']['server']; + /* @todo: What do we need this for? Which libraries grab these infos from global scope? MIME? */ + if (isset($conf['kolab']['imap']['server'])) { + if (!array_key_exists('SERVER_NAME', $_SERVER)) { + $_SERVER['SERVER_NAME'] = $conf['kolab']['imap']['server']; + } + + if (!array_key_exists('REMOTE_ADDR', $_SERVER)) { + $_SERVER['REMOTE_ADDR'] = $conf['kolab']['imap']['server']; + } + + if (!array_key_exists('REMOTE_HOST', $_SERVER)) { + $_SERVER['REMOTE_HOST'] = $conf['kolab']['imap']['server']; + } } /* Always display all possible problems */ diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Exception/Temporary.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Exception/Temporary.php new file mode 100644 index 000000000..5b1cf5f55 --- /dev/null +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Exception/Temporary.php @@ -0,0 +1,48 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Filter + */ + +/** + * This class provides an error thrown when a potentially temporary failure + * occured. + * + * Copyright 2010 Klarälvdalens Datakonsult AB + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Filter + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Filter + */ +class Horde_Kolab_Filter_Exception_Temporary +extends Horde_Kolab_Filter_Exception +{ + /** + * Construct the exception + * + * @param string $msg + * @param Exception $previous + */ + public function __construct($msg = '', Exception $previous = null) + { + parent::__construct( + $msg, + Horde_Kolab_Filter_Exception::OUT_STDOUT | + Horde_Kolab_Filter_Exception::EX_TEMPFAIL, + $previous + ); + } +} diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Factory.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Factory.php index 01cd29b85..7318b664f 100644 --- a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Factory.php +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Factory.php @@ -95,4 +95,29 @@ class Horde_Kolab_Filter_Factory $handler->addFilter(constant('Horde_Log::' . $conf['log']['priority'])); return new Horde_Log_Logger($handler); } + + /** + * Creates the connection to the user database. + * + * @param Horde_Injector $injector The injector provides the required + * configuration. + * + * @return Horde_Kolab_Server_Composite The connection to the user DB. + */ + public function getUserDb(Horde_Injector $injector) + { + $configuration = $injector->getInstance('Horde_Kolab_Filter_Configuration'); + + $conf = $configuration->getConf(); + + $factory = new Horde_Kolab_Server_Factory(); + + return new Horde_Kolab_Server_Composite( + $factory->getServer($conf['server']), + new Horde_Kolab_Server_Objects_Base(), + new Horde_Kolab_Server_Structure_Kolab(), + new Horde_Kolab_Server_Search_Base(), + new Horde_Kolab_Server_Schema_Base() + ); + } } \ No newline at end of file diff --git a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Incoming.php b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Incoming.php index 279e3069b..45631d24c 100644 --- a/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Incoming.php +++ b/framework/Kolab_Filter/lib/Horde/Kolab/Filter/Incoming.php @@ -25,6 +25,13 @@ require_once dirname(__FILE__) . '/Transport.php'; class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base { /** + * The application. + * + * @param Horde_Kolab_Filter + */ + private $_application; + + /** * A temporary storage place for incoming messages. * * @param Horde_Kolab_Filter_Temporary @@ -41,18 +48,21 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base /** * Constructor. * - * @param Horde_Kolab_Filter_Configuration $config The configuration. - * @param Horde_Kolab_Filter_Temporary $temporaray Temporary storage - * location. - * @param Horde_Kolab_Filter_Logger $logger The logging backend. + * @param Horde_Kolab_Filter_Configuration $config The configuration. + * @param Horde_Kolab_Filter_Temporary $temporary Temporary storage + * location. + * @param Horde_Kolab_Filter_Logger $logger The logging backend. + * @param Horde_Kolab_Filter $application Main application. */ public function __construct( Horde_Kolab_Filter_Configuration $config, Horde_Kolab_Filter_Temporary $temporary, - Horde_Log_Logger $logger + Horde_Log_Logger $logger, + Horde_Kolab_Filter $application ) { parent::__construct($config, $logger); $this->_temporary = $temporary; + $this->_application = $application; } /** @@ -154,10 +164,12 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base OUT_LOG | EX_IOERR); } + $recipients = $this->_config->getRecipients(); + if ($ical) { require_once 'Horde/Kolab/Resource.php'; $newrecips = array(); - foreach ($this->_recipients as $recip) { + foreach ($recipients as $recip) { if (strpos($recip, '+')) { list($local, $rest) = explode('+', $recip, 2); list($rest, $domain) = explode('@', $recip, 2); @@ -184,24 +196,24 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base $newrecips[] = $resource; } } - $this->_recipients = $newrecips; + $recipients = $newrecips; $this->_add_headers[] = 'X-Kolab-Scheduling-Message: TRUE'; } else { $this->_add_headers[] = 'X-Kolab-Scheduling-Message: FALSE'; } /* Check if we still have recipients */ - if (empty($this->_recipients)) { - $this->_logger->debug("No recipients left.", 'DEBUG'); + if (empty($recipients)) { + $this->_logger->debug('No recipients left.'); return; } else { - $result = $this->_deliver($transport); + $result = $this->_deliver($transport, $recipients); if (is_a($result, 'PEAR_Error')) { return $result; } } - $this->_logger->debug("Filter_Incoming successfully completed.", 'DEBUG'); + $this->_logger->debug('Filter_Incoming successfully completed.'); } private function _transportItipReply(Horde_Kolab_Resource_Reply $reply) @@ -249,7 +261,7 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base * * @return mixed A PEAR_Error in case of an error, nothing otherwise. */ - function _deliver($transport) + function _deliver($transport, $recipients) { global $conf; @@ -264,17 +276,11 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base $port = 2003; } - /* Load the LDAP library */ - require_once 'Horde/Kolab/Server.php'; - - $server = &Horde_Kolab_Server::singleton(); - if (is_a($server, 'PEAR_Error')) { - $server->code = OUT_LOG | EX_TEMPFAIL; - return $server; - } + // @todo: extract as separate (optional) class + $userDb = $this->_application->getUserDb(); $hosts = array(); - foreach ($this->_recipients as $recipient) { + foreach ($recipients as $recipient) { if (strpos($recipient, '+')) { list($local, $rest) = explode('+', $recipient, 2); list($rest, $domain) = explode('@', $recipient, 2); @@ -282,25 +288,30 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base } else { $real_recipient = $recipient; } - $dn = $server->uidForIdOrMail($real_recipient); - if (is_a($dn, 'PEAR_Error')) { - return $dn; - } - if (!$dn) { - Horde::logMessage(sprintf('User %s does not exist!', $real_recipient), 'DEBUG'); - } try { - $user = $server->fetch($dn, 'Horde_Kolab_Server_Object_Kolab_User'); + //@todo: fix anonymous binding in Kolab_Server. The method name should be explicit. + $userDb->server->connectGuid(); + $guid = $userDb->search->searchGuidForUidOrMail($real_recipient); + if (empty($guid)) { + throw new Horde_Kolab_Filter_Exception_Temporary( + sprintf('User %s does not exist!', $real_recipient) + ); + } + $imapserver = $userDb->objects->fetch( + $guid, 'Horde_Kolab_Server_Object_Kolab_User' + )->getSingle('kolabHomeServer'); } catch (Horde_Kolab_Server_Exception $e) { - Horde::logMessage(sprintf('Failed fetching user object %s. Error was:', - $dn, $e->getMessage()), 'DEBUG'); - $user->code = OUT_LOG | EX_TEMPFAIL; - return $user; - } - $imapserver = $user->get(Horde_Kolab_Server_Object_Kolab_User::ATTRIBUTE_IMAPHOST); - if (is_a($imapserver, 'PEAR_Error')) { - $imapserver->code = OUT_LOG | EX_TEMPFAIL; - return $imapserver; + //@todo: If a message made it till here than we shouldn't fail + // because the LDAP lookup fails. The safer alternative is to try the local + // delivery. LMTP should deny anyway in case the user is unknown + // (despite the initial postfix checks). + throw new Horde_Kolab_Filter_Exception_Temporary( + sprintf( + 'Failed identifying IMAP host of user %s. Error was: %s', + $real_recipient, $e->getMessage() + ), + $e + ); } if (!empty($imapserver)) { $uhost = $imapserver; @@ -326,7 +337,7 @@ class Horde_Kolab_Filter_Incoming extends Horde_Kolab_Filter_Base OUT_LOG | EX_IOERR); } - $result = $transport->start($this->_sender, $hosts[$imap_host]); + $result = $transport->start($this->_config->getSender(), $hosts[$imap_host]); if (is_a($result, 'PEAR_Error')) { return $result; } diff --git a/framework/Kolab_Filter/package.xml b/framework/Kolab_Filter/package.xml index 00fe5aa54..77c29937d 100644 --- a/framework/Kolab_Filter/package.xml +++ b/framework/Kolab_Filter/package.xml @@ -85,6 +85,7 @@ http://pear.php.net/dtd/package-2.0.xsd"> + @@ -268,6 +269,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + diff --git a/framework/Kolab_Filter/test/Horde/Kolab/Filter/StoryTestCase.php b/framework/Kolab_Filter/test/Horde/Kolab/Filter/StoryTestCase.php index d6fa53caf..b7592c58e 100644 --- a/framework/Kolab_Filter/test/Horde/Kolab/Filter/StoryTestCase.php +++ b/framework/Kolab_Filter/test/Horde/Kolab/Filter/StoryTestCase.php @@ -96,6 +96,10 @@ extends PHPUnit_Extensions_Story_TestCase { switch($action) { case 'handling the message': + global $conf; + $conf['server']['mock'] = true; + //@todo: Fix guid => dn here + $conf['server']['data'] = array('dn=example' => array('dn' => 'dn=example', 'data' => array('mail' => array('me@example.org'), 'kolabHomeServer' => array('localhost'), 'objectClass' => array('kolabInetOrgPerson'), 'guid' => 'dn=example'))); $_SERVER['argv'] = $this->_prepareArguments($world); $filter = new Horde_Kolab_Filter(); ob_start(); diff --git a/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php b/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php new file mode 100644 index 000000000..969192863 --- /dev/null +++ b/framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php @@ -0,0 +1,165 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ + +/** + * A based Horde_Kolab_Server:: factory. + * + * Copyright 2008-2010 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (LGPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. + * + * @category Kolab + * @package Kolab_Server + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=Kolab_Server + */ +class Horde_Kolab_Server_Factory +{ + /** + * Return the suggested interface bindings for the Kolab Server components. + * + * @return array The bindings. + */ + public function getBindings() + { + return array( + array( + 'Horde_Kolab_Server_Objects_Interface', + 'Horde_Kolab_Server_Objects_Base' + ), + array( + 'Horde_Kolab_Server_Search_Interface', + 'Horde_Kolab_Server_Search_Base' + ), + array( + 'Horde_Kolab_Server_Schema_Interface', + 'Horde_Kolab_Server_Schema_Base' + ), + ); + } + + /** + * Setup the machinery to create a Horde_Kolab_Server_Structure handler. + * + * @param array $configuration The configuration parameters for the + * connection. (@todo: describe parameters) + * + * @return Horde_Kolab_Server_Structure_Interface + */ + private function getStructure(array $configuration) + { + if (!isset($configuration['driver'])) { + $driver = 'Horde_Kolab_Server_Structure_Kolab'; + } else { + $driver = $configuration['driver']; + } + return new $driver(); + } + + /** + * Return the server connection that should be used. + * + * @param array $configuration The configuration parameters for the + * connection. (@todo: describe parameters) + * + * @return Horde_Kolab_Server_Connection The connection to the server. + */ + public function getConnection(array $configuration) + { + if (empty($configuration['mock'])) { + if (!isset($configuration['basedn'])) { + throw new Horde_Exception('The parameter \'basedn\' is missing in the Kolab server configuration!'); + } + + $ldap_read = new Horde_Ldap($configuration); + if (isset($configuration['host_master'])) { + $configuration['host'] = $configuration['host_master']; + $ldap_write = new Horde_Ldap($configuration); + $connection = new Horde_Kolab_Server_Connection_Splittedldap( + $ldap_read, $ldap_write + ); + } else { + $connection = new Horde_Kolab_Server_Connection_Simpleldap( + $ldap_read + ); + } + return $connection; + } else { + if (isset($configuration['data'])) { + $data = $configuration['data']; + } else { + $data = array(); + } + $connection = new Horde_Kolab_Server_Connection_Mock( + new Horde_Kolab_Server_Connection_Mock_Ldap( + $configuration, $data + ) + ); + return $connection; + } + } + + /** + * Return the server connection that should be used. + * + * @param array $configuration The configuration parameters for the + * server. (@todo: describe parameters) + * @param mixed $logger The logger (@todo: which methods need to be provided?) + * + * @return Horde_Kolab_Server_Interface The Horde_Kolab_Server connection. + */ + public function getServer(array $configuration, $logger) + { + $connection = $this->getConnection($configuration); + + if (!isset($configuration['filter'])) { + $server = new Horde_Kolab_Server_Ldap_Standard( + $connection, + $configuration['basedn'] + ); + } else { + $server = new Horde_Kolab_Server_Ldap_Filtered( + $connection, + $configuration['basedn'], + $configuration['filter'] + ); + } + + if (isset($configuration['map'])) { + $server = new Horde_Kolab_Server_Decorator_Map( + $server, $configuration['map'] + ); + } + + if (isset($configuration['debug']) || isset($configuration['log'])) { + $server = new Horde_Kolab_Server_Decorator_Log( + $server, $logger + ); + } + + if (isset($configuration['debug']) || isset($configuration['count'])) { + $server = new Horde_Kolab_Server_Decorator_Count( + $server, $logger + ); + } + + if (!empty($configuration['cleanup'])) { + $server = new Horde_Kolab_Server_Decorator_Clean( + $server + ); + } + return $server; + } +} \ No newline at end of file