Delegation support in calendar event invitations handling

This commit is contained in:
Aleksander Machniak 2012-12-13 13:10:07 +01:00
parent a24ad50619
commit 3be3065941
6 changed files with 261 additions and 16 deletions

View file

@ -209,9 +209,13 @@ class calendar extends rcube_plugin
{ {
if (!$this->itip) { if (!$this->itip) {
require_once($this->home . '/lib/calendar_itip.php'); 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; return $this->itip;
} }
@ -727,7 +731,7 @@ class calendar extends rcube_plugin
if ($numcals <= 1) if ($numcals <= 1)
$calendar_select = null; $calendar_select = null;
} }
if ($status == 'unknown') { if ($status == 'unknown') {
$html = html::div('rsvp-status', $this->gettext('notanattendee')); $html = html::div('rsvp-status', $this->gettext('notanattendee'));
$action = 'import'; $action = 'import';
@ -738,7 +742,7 @@ class calendar extends rcube_plugin
$action = ''; // nothing to do here $action = ''; // nothing to do here
} }
} }
$default_calendar = $calendar_select ? $this->get_default_calendar(true) : null; $default_calendar = $calendar_select ? $this->get_default_calendar(true) : null;
$this->rc->output->command('plugin.update_event_rsvp_status', array( $this->rc->output->command('plugin.update_event_rsvp_status', array(
'uid' => $event['uid'], 'uid' => $event['uid'],
@ -1974,7 +1978,15 @@ class calendar extends rcube_plugin
*/ */
private function get_user_emails() 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) foreach ($this->rc->user->list_identities() as $identity)
$emails[] = $identity['email']; $emails[] = $identity['email'];

View file

@ -147,6 +147,16 @@ class kolab_driver extends calendar_driver
protected function filter_calendars($writable = false, $active = false, $personal = false) protected function filter_calendars($writable = false, $active = false, $personal = false)
{ {
$calendars = array(); $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) { foreach ($this->calendars as $cal) {
if (!$cal->ready) { if (!$cal->ready) {
continue; continue;

View file

@ -28,14 +28,14 @@ class calendar_itip
{ {
private $rc; private $rc;
private $cal; private $cal;
private $event; private $sender;
private $itip_send = false; private $itip_send = false;
function __construct($cal) function __construct($cal, $identity = null)
{ {
$this->cal = $cal; $this->cal = $cal;
$this->rc = $cal->rc; $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')); $this->cal->add_hook('smtp_connect', array($this, 'smtp_connect_hook'));
} }

View file

@ -22,6 +22,14 @@
*/ */
window.rcmail && rcmail.addEventListener('init', function(evt) { 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 // add Delegation section to the list
var tab = $('<span>').attr('id', 'settingstabplugindelegation').addClass('tablink'), var tab = $('<span>').attr('id', 'settingstabplugindelegation').addClass('tablink'),
button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.delegation') 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); 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;
};

View file

@ -25,7 +25,7 @@
class kolab_delegation extends rcube_plugin class kolab_delegation extends rcube_plugin
{ {
public $task = 'login|mail|settings'; public $task = 'login|mail|settings|calendar';
private $rc; private $rc;
private $engine; private $engine;
@ -41,10 +41,19 @@ class kolab_delegation extends rcube_plugin
$this->require_plugin('libkolab'); $this->require_plugin('libkolab');
$this->require_plugin('kolab_auth'); $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')); $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') { if ($this->rc->task == 'settings') {
// delegation management interface
$this->register_action('plugin.delegation', array($this, 'controller_ui')); $this->register_action('plugin.delegation', array($this, 'controller_ui'));
$this->register_action('plugin.delegation-delete', array($this, 'controller_action')); $this->register_action('plugin.delegation-delete', array($this, 'controller_action'));
$this->register_action('plugin.delegation-save', 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; return $args;
} }
if (empty($_SESSION['delegator_uids'])) { if (empty($_SESSION['delegators'])) {
return $args; return $args;
} }
@ -113,7 +122,7 @@ class kolab_delegation extends rcube_plugin
$other_ns = $storage->get_namespace('other'); $other_ns = $storage->get_namespace('other');
$folders = $storage->list_folders_subscribed('', '*', 'mail'); $folders = $storage->list_folders_subscribed('', '*', 'mail');
foreach ($_SESSION['delegator_uids'] as $uid) { foreach (array_keys($_SESSION['delegators']) as $uid) {
foreach ($other_ns as $ns) { foreach ($other_ns as $ns) {
$folder = $ns[0] . $uid; $folder = $ns[0] . $uid;
if (in_array($folder, $folders) && !in_array($folder, $args['folders'])) { if (in_array($folder, $folders) && !in_array($folder, $args['folders'])) {
@ -125,6 +134,79 @@ class kolab_delegation extends rcube_plugin
return $args; return $args;
} }
/**
* 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 * Delegation UI handler
*/ */

View file

@ -25,6 +25,8 @@
class kolab_delegation_engine class kolab_delegation_engine
{ {
public $context;
private $rc; private $rc;
private $ldap_filter; private $ldap_filter;
private $ldap_delegate_field; private $ldap_delegate_field;
@ -532,9 +534,8 @@ class kolab_delegation_engine
// for every delegator... // for every delegator...
foreach ($delegators as $delegator) { foreach ($delegators as $delegator) {
$uids[] = $delegator['imap_uid']; $uids[$delegator['imap_uid']] = $email_arr = $delegator['email'];
$email_arr = $delegator['email']; $diff = array_intersect($emails, $email_arr);
$diff = array_intersect($emails, $email_arr);
// identity with delegator's email already exist, do nothing // identity with delegator's email already exist, do nothing
if (count($diff)) { if (count($diff)) {
@ -545,6 +546,8 @@ class kolab_delegation_engine
// create identities for delegator emails // create identities for delegator emails
foreach ($email_arr as $email) { foreach ($email_arr as $email) {
$default['email'] = $email; $default['email'] = $email;
// @TODO: "Username" or "Delegatorname" or "Username on behalf of Delegatorname"
//$default['name'] = $delegator['email'];
$this->rc->user->insert_identity($default); $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;
} }
/** /**