plugins/calendar plugins/kolab_delegation

Aleksander Machniak machniak at kolabsys.com
Thu Dec 13 13:12:17 CET 2012


 plugins/calendar/calendar.php                        |   22 ++-
 plugins/calendar/drivers/kolab/kolab_driver.php      |   10 +
 plugins/calendar/lib/calendar_itip.php               |    6 
 plugins/kolab_delegation/kolab_delegation.js         |   21 +++
 plugins/kolab_delegation/kolab_delegation.php        |   90 ++++++++++++-
 plugins/kolab_delegation/kolab_delegation_engine.php |  128 ++++++++++++++++++-
 6 files changed, 261 insertions(+), 16 deletions(-)

New commits:
commit 3be3065941f993df74d4112a6c3aeb9f03dbe780
Author: Aleksander Machniak <machniak at kolabsys.com>
Date:   Thu Dec 13 13:10:07 2012 +0100

    Delegation support in calendar event invitations handling

diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php
index 24d929a..eafb015 100644
--- a/plugins/calendar/calendar.php
+++ b/plugins/calendar/calendar.php
@@ -209,9 +209,13 @@ class calendar extends rcube_plugin
   {
     if (!$this->itip) {
       require_once($this->home . '/lib/calendar_itip.php');
-      $this->itip = new calendar_itip($this);
+
+      $plugin = $this->rc->plugins->exec_hook('calendar_load_itip',
+        array('identity' => null));
+
+      $this->itip = new calendar_itip($this, $plugin['identity']);
     }
-    
+
     return $this->itip;
   }
 
@@ -727,7 +731,7 @@ class calendar extends rcube_plugin
           if ($numcals <= 1)
             $calendar_select = null;
         }
-        
+
         if ($status == 'unknown') {
           $html = html::div('rsvp-status', $this->gettext('notanattendee'));
           $action = 'import';
@@ -738,7 +742,7 @@ class calendar extends rcube_plugin
             $action = '';  // nothing to do here
          }
         }
-        
+
         $default_calendar = $calendar_select ? $this->get_default_calendar(true) : null;
         $this->rc->output->command('plugin.update_event_rsvp_status', array(
           'uid' => $event['uid'],
@@ -1974,7 +1978,15 @@ class calendar extends rcube_plugin
    */
   private function get_user_emails()
   {
-    $emails = array($this->rc->user->get_username());
+    $emails = array();
+    $plugin = $this->rc->plugins->exec_hook('calendar_user_emails', array('emails' => $emails));
+    $emails = $plugin['emails'];
+
+    if ($plugin['abort']) {
+      return $emails;
+    }
+
+    $emails[] = $this->rc->user->get_username();
     foreach ($this->rc->user->list_identities() as $identity)
       $emails[] = $identity['email'];
     
diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php
index 4787445..0d913a3 100644
--- a/plugins/calendar/drivers/kolab/kolab_driver.php
+++ b/plugins/calendar/drivers/kolab/kolab_driver.php
@@ -147,6 +147,16 @@ class kolab_driver extends calendar_driver
   protected function filter_calendars($writable = false, $active = false, $personal = false)
   {
     $calendars = array();
+
+    $plugin = $this->rc->plugins->exec_hook('calendar_list_filter', array(
+      'list' => $this->calendars, 'calendars' => $calendars,
+      'writable' => $writable, 'active' => $active, 'personal' => $personal,
+    ));
+
+    if ($plugin['abort']) {
+      return $plugin['calendars'];
+    }
+
     foreach ($this->calendars as $cal) {
       if (!$cal->ready) {
         continue;
diff --git a/plugins/calendar/lib/calendar_itip.php b/plugins/calendar/lib/calendar_itip.php
index dc4cfa0..40d9786 100644
--- a/plugins/calendar/lib/calendar_itip.php
+++ b/plugins/calendar/lib/calendar_itip.php
@@ -28,14 +28,14 @@ class calendar_itip
 {
   private $rc;
   private $cal;
-  private $event;
+  private $sender;
   private $itip_send = false;
 
-  function __construct($cal)
+  function __construct($cal, $identity = null)
   {
     $this->cal = $cal;
     $this->rc = $cal->rc;
-    $this->sender = $this->rc->user->get_identity();
+    $this->sender = $identity ? $identity : $this->rc->user->get_identity();
 
     $this->cal->add_hook('smtp_connect', array($this, 'smtp_connect_hook'));
   }
diff --git a/plugins/kolab_delegation/kolab_delegation.js b/plugins/kolab_delegation/kolab_delegation.js
index 2462fa3..75e77b8 100644
--- a/plugins/kolab_delegation/kolab_delegation.js
+++ b/plugins/kolab_delegation/kolab_delegation.js
@@ -22,6 +22,14 @@
  */
 
 window.rcmail && rcmail.addEventListener('init', function(evt) {
+  if (rcmail.env.task == 'mail') {
+    // set delegator context for calendar requests on invitation message
+    rcmail.addEventListener('requestcalendar/event', function(o) { rcmail.event_delegator_request(o); });
+    rcmail.addEventListener('requestcalendar/mailimportevent', function(o) { rcmail.event_delegator_request(o); });
+  }
+  else if (rcmail.env.task != 'settings')
+    return;
+
   // add Delegation section to the list
   var tab = $('<span>').attr('id', 'settingstabplugindelegation').addClass('tablink'),
     button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.delegation')
@@ -218,3 +226,16 @@ rcube_webmail.prototype.delegate_save_complete = function(p)
     this.enable_command('delegate-delete', false);
   }
 };
+
+rcube_webmail.prototype.event_delegator_request = function(data)
+{
+  if (!this.env.delegator_context)
+    return;
+
+  if (typeof data === 'object')
+    data._context = this.env.delegator_context;
+  else
+    data += '&_context=' + this.env.delegator_context;
+
+  return data;
+};
diff --git a/plugins/kolab_delegation/kolab_delegation.php b/plugins/kolab_delegation/kolab_delegation.php
index b7abfd4..6b37e3f 100644
--- a/plugins/kolab_delegation/kolab_delegation.php
+++ b/plugins/kolab_delegation/kolab_delegation.php
@@ -25,7 +25,7 @@
 
 class kolab_delegation extends rcube_plugin
 {
-    public $task = 'login|mail|settings';
+    public $task = 'login|mail|settings|calendar';
 
     private $rc;
     private $engine;
@@ -41,10 +41,19 @@ class kolab_delegation extends rcube_plugin
         $this->require_plugin('libkolab');
         $this->require_plugin('kolab_auth');
 
-        $this->add_hook('login_after',  array($this, 'login_hook'));
+        // on-login delegation initialization
+        $this->add_hook('login_after', array($this, 'login_hook'));
+        // on-check-recent delegation support
         $this->add_hook('check_recent', array($this, 'check_recent_hook'));
 
+        // delegation support in Calendar plugin
+        $this->add_hook('message_load', array($this, 'message_load'));
+        $this->add_hook('calendar_user_emails', array($this, 'calendar_user_emails'));
+        $this->add_hook('calendar_list_filter', array($this, 'calendar_list_filter'));
+        $this->add_hook('calendar_load_itip', array($this, 'calendar_load_itip'));
+
         if ($this->rc->task == 'settings') {
+            // delegation management interface
             $this->register_action('plugin.delegation',              array($this, 'controller_ui'));
             $this->register_action('plugin.delegation-delete',       array($this, 'controller_action'));
             $this->register_action('plugin.delegation-save',         array($this, 'controller_action'));
@@ -105,7 +114,7 @@ class kolab_delegation extends rcube_plugin
             return $args;
         }
 
-        if (empty($_SESSION['delegator_uids'])) {
+        if (empty($_SESSION['delegators'])) {
             return $args;
         }
 
@@ -113,7 +122,7 @@ class kolab_delegation extends rcube_plugin
         $other_ns = $storage->get_namespace('other');
         $folders  = $storage->list_folders_subscribed('', '*', 'mail');
 
-        foreach ($_SESSION['delegator_uids'] as $uid) {
+        foreach (array_keys($_SESSION['delegators']) as $uid) {
             foreach ($other_ns as $ns) {
                 $folder = $ns[0] . $uid;
                 if (in_array($folder, $folders) && !in_array($folder, $args['folders'])) {
@@ -126,6 +135,79 @@ class kolab_delegation extends rcube_plugin
     }
 
     /**
+     * E-mail message loading action
+     */
+    public function message_load($args)
+    {
+        // This is a place where we detect delegate context
+        // So we can handle event invitations on behalf of delegator
+        // @TODO: should we do this only in delegators' folders?
+
+        $engine = $this->engine();
+        $context = $engine->delegator_context_from_message($args['object']);
+
+        if ($context) {
+            $this->rc->output->set_env('delegator_context', $context);
+            $this->include_script('kolab_delegation.js');
+        }
+
+        return $args;
+    }
+
+    /**
+     * calendar::get_user_emails() handler
+     */
+    public function calendar_user_emails($args)
+    {
+        // In delegator context we'll use delegator's addresses
+        // instead of current user addresses
+
+        $engine = $this->engine();
+
+        if ($context = $engine->delegator_context()) {
+            $args['emails'] = $_SESSION['delegators'][$context];
+            $args['abort']  = true;
+        }
+
+        return $args;
+    }
+
+    /**
+     * calendar_driver::list_calendars() handler
+     */
+    public function calendar_list_filter($args)
+    {
+        // In delegator context we'll use delegator's folders
+        // instead of current user folders
+
+        $engine = $this->engine();
+
+        if ($engine->delegator_context()) {
+            $args['calendars'] = $engine->delegator_folder_filter($args);
+            $args['abort']     = true;
+        }
+
+        return $args;
+    }
+
+    /**
+     * calendar::load_itip() handler
+     */
+    public function calendar_load_itip($args)
+    {
+        // In delegator context we'll use delegator's address/name
+        // for invitation responses
+
+        $engine = $this->engine();
+
+        if ($engine->delegator_context()) {
+            $args['identity'] = $engine->delegator_identity();
+        }
+
+        return $args;
+    }
+
+    /**
      * Delegation UI handler
      */
     public function controller_ui()
diff --git a/plugins/kolab_delegation/kolab_delegation_engine.php b/plugins/kolab_delegation/kolab_delegation_engine.php
index 2bb6b70..f2a7125 100644
--- a/plugins/kolab_delegation/kolab_delegation_engine.php
+++ b/plugins/kolab_delegation/kolab_delegation_engine.php
@@ -25,6 +25,8 @@
 
 class kolab_delegation_engine
 {
+    public $context;
+
     private $rc;
     private $ldap_filter;
     private $ldap_delegate_field;
@@ -532,9 +534,8 @@ class kolab_delegation_engine
 
         // for every delegator...
         foreach ($delegators as $delegator) {
-            $uids[]    = $delegator['imap_uid'];
-            $email_arr = $delegator['email'];
-            $diff      = array_intersect($emails, $email_arr);
+            $uids[$delegator['imap_uid']] = $email_arr = $delegator['email'];
+            $diff = array_intersect($emails, $email_arr);
 
             // identity with delegator's email already exist, do nothing
             if (count($diff)) {
@@ -545,6 +546,8 @@ class kolab_delegation_engine
             // create identities for delegator emails
             foreach ($email_arr as $email) {
                 $default['email'] = $email;
+                // @TODO: "Username" or "Delegatorname" or "Username on behalf of Delegatorname"
+                //$default['name']  = $delegator['email'];
                 $this->rc->user->insert_identity($default);
             }
 
@@ -584,7 +587,124 @@ class kolab_delegation_engine
             }
         }
 
-        $_SESSION['delegator_uids'] = $uids;
+        $_SESSION['delegators'] = $uids;
+    }
+
+    /**
+     * Sets delegator context according to email message recipient
+     *
+     * @param rcube_message $message Email message object
+     */
+    public function delegator_context_from_message($message)
+    {
+        if (empty($_SESSION['delegators'])) {
+            return;
+        }
+
+        // Match delegators' addresses with message To: address
+        // @TODO: Is this reliable enough?
+        // Roundcube sends invitations to every attendee separately,
+        // but maybe there's a software which sends with CC header or many addresses in To:
+
+        $emails = $message->get_header('to');
+        $emails = rcube_mime::decode_address_list($emails, null, false);
+
+        foreach ($emails as $email) {
+            foreach ($_SESSION['delegators'] as $uid => $addresses) {
+                if (in_array($email['mailto'], $addresses)) {
+                    return $this->context = $uid;
+                }
+            }
+        }
+    }
+
+    /**
+     * Return (set) current delegator context
+     *
+     * @return string Delegator UID
+     */
+    public function delegator_context()
+    {
+        if (!$this->context && !empty($_SESSION['delegators'])) {
+            $context = rcube_utils::get_input_value('_context', rcube_utils::INPUT_GPC);
+            if ($context && isset($_SESSION['delegators'][$context])) {
+                $this->context = $context;
+            }
+        }
+
+        return $this->context;
+    }
+
+    /**
+     * Return identity of the current delegator
+     *
+     * @return array Identity data (name and email)
+     */
+    public function delegator_identity()
+    {
+        if (!$this->context) {
+            return;
+        }
+
+        $identities = $this->rc->user->list_identities();
+        $emails     = $_SESSION['delegators'][$this->context];
+
+        foreach ($identities as $ident) {
+            if (in_array($ident['email'], $emails)) {
+                return $ident;
+            }
+        }
+    }
+
+    /**
+     * Filters list of calendars according to delegator context
+     *
+     * @param array $args Plugin hook arguments
+     *
+     * @return array List of calendars
+     */
+    public function delegator_folder_filter($args)
+    {
+        if (empty($this->context)) {
+            return;
+        }
+
+        $storage   = $this->rc->get_storage();
+        $other_ns  = $storage->get_namespace('other');
+        $delim     = $storage->get_hierarchy_delimiter();
+        $calendars = array();
+
+        // code parts derived from kolab_driver::filter_calendars()
+        foreach ($args['list'] as $cal) {
+            if (!$cal->ready) {
+                continue;
+            }
+            if ($args['writeable'] && $cal->readonly) {
+                continue;
+            }
+            if ($args['active'] && !$cal->storage->is_active()) {
+                continue;
+            }
+            if ($args['personal']) {
+                $ns   = $cal->get_namespace();
+                $name = $cal->get_realname(); // UTF-7 IMAP folder name
+
+                if ($ns != 'other') {
+                    continue;
+                }
+
+                foreach ($other_ns as $ns) {
+                    $folder = $ns[0] . $this->context . $delim;
+                    if (strpos($name, $folder) !== 0) {
+                        continue;
+                    }
+                }
+            }
+
+            $calendars[$cal->id] = $cal;
+        }
+
+        return $calendars;
     }
 
     /**





More information about the commits mailing list