Working Incoming test.
authorGunnar Wrobel <p@rdus.de>
Thu, 22 Jul 2010 14:59:38 +0000 (16:59 +0200)
committerGunnar Wrobel <p@rdus.de>
Wed, 25 Aug 2010 17:21:38 +0000 (19:21 +0200)
framework/Kolab_Filter/lib/Horde/Kolab/Filter.php
framework/Kolab_Filter/lib/Horde/Kolab/Filter/Base.php
framework/Kolab_Filter/lib/Horde/Kolab/Filter/Configuration.php
framework/Kolab_Filter/lib/Horde/Kolab/Filter/Exception/Temporary.php [new file with mode: 0644]
framework/Kolab_Filter/lib/Horde/Kolab/Filter/Factory.php
framework/Kolab_Filter/lib/Horde/Kolab/Filter/Incoming.php
framework/Kolab_Filter/package.xml
framework/Kolab_Filter/test/Horde/Kolab/Filter/StoryTestCase.php
framework/Kolab_Server/lib/Horde/Kolab/Server/Factory.php [new file with mode: 0644]

index 674ce72..fcfd9ab 100644 (file)
@@ -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
index 2f89303..826093d 100644 (file)
@@ -1,19 +1,29 @@
 <?php
 /**
- * @package Kolab_Filter
+ * A basic definition for a PHP based postfix filter.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <steffen@klaralvdalens-datakonsult.se>
- * @author  Gunnar Wrobel <wrobel@pardus.de>
- * @package Kolab_Filter
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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;
 
index 0e9485f..2d04d46 100644 (file)
@@ -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 (file)
index 0000000..5b1cf5f
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**
+ * This class provides an error thrown when a potentially temporary failure
+ * occured.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Kolab_Filter
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <wrobel@pardus.de>
+ * @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
+        );
+    }
+}
index 01cd29b..7318b66 100644 (file)
@@ -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
index 279e306..45631d2 100644 (file)
@@ -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;
             }
index 00fe5aa..77c2993 100644 (file)
@@ -85,6 +85,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
        <file name="Exception.php" role="php" />
        <dir name="Exception">
         <file name="IoError.php" role="php" />
+        <file name="Temporary.php" role="php" />
         <file name="Usage.php" role="php" />
        </dir> <!-- /lib/Horde/Kolab/Filter/Exception -->
        <file name="Factory.php" role="php" />
@@ -268,6 +269,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
    <install name="lib/Horde/Kolab/Filter/Content.php" as="Horde/Kolab/Filter/Content.php" />
    <install name="lib/Horde/Kolab/Filter/Base.php" as="Horde/Kolab/Filter/Base.php" />
    <install name="lib/Horde/Kolab/Filter/Exception.php" as="Horde/Kolab/Filter/Exception.php" />
+   <install name="lib/Horde/Kolab/Filter/Exception/IoError.php" as="Horde/Kolab/Filter/Exception/IoError.php" />
+   <install name="lib/Horde/Kolab/Filter/Exception/Temporary.php" as="Horde/Kolab/Filter/Exception/Temporary.php" />
    <install name="lib/Horde/Kolab/Filter/Exception/Usage.php" as="Horde/Kolab/Filter/Exception/Usage.php" />
    <install name="lib/Horde/Kolab/Filter/Factory.php" as="Horde/Kolab/Filter/Factory.php" />
    <install name="lib/Horde/Kolab/Filter/Incoming.php" as="Horde/Kolab/Filter/Incoming.php" />
index d6fa53c..b7592c5 100644 (file)
@@ -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 (file)
index 0000000..9691928
--- /dev/null
@@ -0,0 +1,165 @@
+<?php
+/**
+ * A Horde_Kolab_Server:: factory.
+ *
+ * PHP version 5
+ *
+ * @category Kolab
+ * @package  Kolab_Server
+ * @author   Gunnar Wrobel <wrobel@pardus.de>
+ * @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 <wrobel@pardus.de>
+ * @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