453 lines
16 KiB
PHP
453 lines
16 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Delegation configuration utility for Kolab accounts
|
|
*
|
|
* @version @package_version@
|
|
* @author Aleksander Machniak <machniak@kolabsys.com>
|
|
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
|
*
|
|
* Copyright (C) 2011-2012, Kolab Systems AG <contact@kolabsys.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
class kolab_delegation extends rcube_plugin
|
|
{
|
|
public $task = 'login|mail|settings';
|
|
|
|
private $rc;
|
|
private $engine;
|
|
|
|
|
|
/**
|
|
* Plugin initialization.
|
|
*/
|
|
public function init()
|
|
{
|
|
$this->rc = rcube::get_instance();
|
|
|
|
$this->require_plugin('libkolab');
|
|
$this->require_plugin('kolab_auth');
|
|
|
|
$this->add_hook('login_after', array($this, 'login_hook'));
|
|
$this->add_hook('check_recent', array($this, 'check_recent_hook'));
|
|
|
|
if ($this->rc->task == 'settings') {
|
|
$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'));
|
|
$this->register_action('plugin.delegation-autocomplete', array($this, 'controller_action'));
|
|
|
|
if ($this->rc->action == 'plugin.delegation' || empty($_REQUEST['_framed'])) {
|
|
$this->add_texts('localization/', array('tabtitle', 'deleteconfirm', 'savingdata', 'yes', 'no'));
|
|
$this->include_script('kolab_delegation.js');
|
|
$skin_path = $this->local_skin_path();
|
|
$this->include_stylesheet("$skin_path/style.css");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Engine object getter
|
|
*/
|
|
private function engine()
|
|
{
|
|
if (!$this->engine) {
|
|
require_once $this->home . '/kolab_delegation_engine.php';
|
|
|
|
$this->load_config();
|
|
$this->engine = new kolab_delegation_engine();
|
|
}
|
|
|
|
return $this->engine;
|
|
}
|
|
|
|
/**
|
|
* On-login action
|
|
*/
|
|
public function login_hook($args)
|
|
{
|
|
// Fetch all delegators from LDAP who assigned the
|
|
// current user as their delegate and create identities
|
|
// a) if identity with delegator's email exists, continue
|
|
// b) create identity ($delegate on behalf of $delegator
|
|
// <$delegator-email>) for new delegators
|
|
// c) remove all other identities which do not match the user's primary
|
|
// or alias email if 'kolab_delegation_purge_identities' is set.
|
|
|
|
$engine = $this->engine();
|
|
$storage = $this->rc->get_storage();
|
|
$delegators = $engine->list_delegators();
|
|
$other_ns = $storage->get_namespace('other');
|
|
$folders = $storage->list_folders();
|
|
$identities = $this->rc->user->list_identities();
|
|
$emails = array();
|
|
$uids = array();
|
|
|
|
// convert identities to simpler format for faster access
|
|
foreach ($identities as $idx => $ident) {
|
|
// get user name from default identity
|
|
if (!$idx) {
|
|
$default = array(
|
|
'name' => $ident['name'],
|
|
// 'organization' => $ident['organization'],
|
|
// 'signature' => $ident['signature'],
|
|
// 'html_signature' => $ident['html_signature'],
|
|
);
|
|
}
|
|
$emails[$ident['identity_id']] = $ident['email'];
|
|
}
|
|
|
|
// for every delegator...
|
|
foreach ($delegators as $delegator) {
|
|
$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)) {
|
|
$emails = array_diff($emails, $email_arr);
|
|
continue;
|
|
}
|
|
|
|
// create identities for delegator emails
|
|
foreach ($email_arr as $email) {
|
|
$default['email'] = $email;
|
|
$this->rc->user->insert_identity($default);
|
|
}
|
|
|
|
// IMAP folders shared by new delegators shall be subscribed on login,
|
|
// as well as existing subscriptions of previously shared folders shall
|
|
// be removed. I suppose the latter one is already done in Roundcube.
|
|
|
|
// for every accessible folder...
|
|
foreach ($folders as $folder) {
|
|
// for every 'other' namespace root...
|
|
foreach ($other_ns as $ns) {
|
|
$prefix = $ns[0] . $delegator['imap_uid'];
|
|
// subscribe delegator's folder
|
|
if ($folder === $prefix || strpos($folder, $prefix . substr($ns[0], -1)) === 0) {
|
|
$storage->subscribe($folder);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove identities that "do not belong" to user nor delegators
|
|
if ($this->rc->config->get('kolab_delegation_purge_identities')) {
|
|
$user = $engine->user(true);
|
|
$emails = array_diff($emails, $user['email']);
|
|
|
|
foreach (array_keys($emails) as $idx) {
|
|
$this->rc->user->delete_identity($idx);
|
|
}
|
|
}
|
|
|
|
$_SESSION['delegator_uids'] = $uids;
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Check-recent action
|
|
*/
|
|
public function check_recent_hook($args)
|
|
{
|
|
// Checking for new messages shall be extended to Inbox folders of all
|
|
// delegators if 'check_all_folders' is set to false.
|
|
|
|
if ($this->rc->task != 'mail') {
|
|
return $args;
|
|
}
|
|
|
|
if (!empty($args['all'])) {
|
|
return $args;
|
|
}
|
|
|
|
if (empty($_SESSION['delegator_uids'])) {
|
|
return $args;
|
|
}
|
|
|
|
$storage = $this->rc->get_storage();
|
|
$other_ns = $storage->get_namespace('other');
|
|
$folders = $storage->list_folders_subscribed('', '*', 'mail');
|
|
|
|
foreach ($_SESSION['delegator_uids'] as $uid) {
|
|
foreach ($other_ns as $ns) {
|
|
$folder = $ns[0] . $uid;
|
|
if (in_array($folder, $folders) && !in_array($folder, $args['folders'])) {
|
|
$args['folders'][] = $folder;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Delegation UI handler
|
|
*/
|
|
public function controller_ui()
|
|
{
|
|
// main interface (delegates list)
|
|
if (empty($_REQUEST['_framed'])) {
|
|
$this->register_handler('plugin.delegatelist', array($this, 'delegate_list'));
|
|
|
|
$this->rc->output->include_script('list.js');
|
|
$this->rc->output->send('kolab_delegation.settings');
|
|
}
|
|
// delegate frame
|
|
else {
|
|
$this->register_handler('plugin.delegateform', array($this, 'delegate_form'));
|
|
$this->register_handler('plugin.delegatefolders', array($this, 'delegate_folders'));
|
|
|
|
$this->rc->output->set_env('autocomplete_max', (int)$this->rc->config->get('autocomplete_max', 15));
|
|
$this->rc->output->set_env('autocomplete_min_length', $this->rc->config->get('autocomplete_min_length'));
|
|
$this->rc->output->add_label('autocompletechars', 'autocompletemore');
|
|
|
|
$this->rc->output->send('kolab_delegation.editform');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delegation action handler
|
|
*/
|
|
public function controller_action()
|
|
{
|
|
$this->add_texts('localization/', true);
|
|
|
|
$engine = $this->engine();
|
|
|
|
// Delegate delete
|
|
if ($this->rc->action == 'plugin.delegation-delete') {
|
|
$id = get_input_value('id', RCUBE_INPUT_GPC);
|
|
$success = $engine->delegate_delete($id, (bool) get_input_value('acl', RCUBE_INPUT_GPC));
|
|
|
|
if ($success) {
|
|
$this->rc->output->show_message($this->gettext('deletesuccess'), 'confirmation');
|
|
$this->rc->output->command('plugin.delegate_save_complete', array('deleted' => $id));
|
|
}
|
|
else {
|
|
$this->rc->output->show_message($this->gettext('deleteerror'), 'error');
|
|
}
|
|
}
|
|
// Delegate add/update
|
|
else if ($this->rc->action == 'plugin.delegation-save') {
|
|
$id = get_input_value('id', RCUBE_INPUT_GPC);
|
|
$acl = get_input_value('folders', RCUBE_INPUT_GPC);
|
|
|
|
// update
|
|
if ($id) {
|
|
$delegate = $engine->delegate_get($id);
|
|
$success = $engine->delegate_acl_update($delegate['uid'], $acl);
|
|
|
|
if ($success) {
|
|
$this->rc->output->show_message($this->gettext('updatesuccess'), 'confirmation');
|
|
$this->rc->output->command('plugin.delegate_save_complete', array('updated' => $id));
|
|
}
|
|
else {
|
|
$this->rc->output->show_message($this->gettext('updateerror'), 'error');
|
|
}
|
|
}
|
|
// new
|
|
else {
|
|
$login = get_input_value('newid', RCUBE_INPUT_GPC);
|
|
$delegate = $engine->delegate_get_by_name($login);
|
|
$success = $engine->delegate_add($delegate, $acl);
|
|
|
|
if ($success) {
|
|
$this->rc->output->show_message($this->gettext('createsuccess'), 'confirmation');
|
|
$this->rc->output->command('plugin.delegate_save_complete', array(
|
|
'created' => $delegate['ID'],
|
|
'name' => $delegate['name'],
|
|
));
|
|
}
|
|
else {
|
|
$this->rc->output->show_message($this->gettext('createerror'), 'error');
|
|
}
|
|
}
|
|
}
|
|
// Delegate autocompletion
|
|
else if ($this->rc->action == 'plugin.delegation-autocomplete') {
|
|
$search = get_input_value('_search', RCUBE_INPUT_GPC, true);
|
|
$sid = get_input_value('_id', RCUBE_INPUT_GPC);
|
|
$users = $engine->list_users($search);
|
|
|
|
$this->rc->output->command('ksearch_query_results', $users, $search, $sid);
|
|
}
|
|
|
|
$this->rc->output->send();
|
|
}
|
|
|
|
/**
|
|
* Template object of delegates list
|
|
*/
|
|
public function delegate_list($attrib = array())
|
|
{
|
|
$attrib += array('id' => 'delegate-list');
|
|
|
|
$engine = $this->engine();
|
|
$list = $engine->list_delegates();
|
|
$table = new html_table();
|
|
|
|
// sort delegates list
|
|
asort($list, SORT_LOCALE_STRING);
|
|
|
|
foreach ($list as $id => $delegate) {
|
|
$name = $id;
|
|
$table->add_row(array('id' => 'rcmrow' . $id));
|
|
$table->add(null, Q($delegate));
|
|
}
|
|
|
|
$this->rc->output->add_gui_object('delegatelist', $attrib['id']);
|
|
$this->rc->output->set_env('delegatecount', count($list));
|
|
|
|
return $table->show($attrib);
|
|
}
|
|
|
|
/**
|
|
* Template object of delegate form
|
|
*/
|
|
public function delegate_form($attrib = array())
|
|
{
|
|
$engine = $this->engine();
|
|
$table = new html_table(array('cols' => 2));
|
|
$id = get_input_value('_id', RCUBE_INPUT_GPC);
|
|
$field_id = 'delegate';
|
|
|
|
if ($id) {
|
|
$delegate = $engine->delegate_get($id);
|
|
}
|
|
|
|
if ($delegate) {
|
|
$input = new html_hiddenfield(array('name' => $field_id, 'id' => $field_id, 'size' => 40));
|
|
$input = Q($delegate['name']) . $input->show($id);
|
|
|
|
$this->rc->output->set_env('active_delegate', $id);
|
|
$this->rc->output->command('parent.enable_command','delegate-delete', true);
|
|
}
|
|
else {
|
|
$input = new html_inputfield(array('name' => $field_id, 'id' => $field_id, 'size' => 40));
|
|
$input = $input->show();
|
|
}
|
|
|
|
$table->add('title', html::label($field_id, $this->gettext('delegate')));
|
|
$table->add(null, $input);
|
|
|
|
if ($attrib['form']) {
|
|
$this->rc->output->add_gui_object('editform', $attrib['form']);
|
|
}
|
|
|
|
return $table->show($attrib);
|
|
}
|
|
|
|
/**
|
|
* Template object of folders list
|
|
*/
|
|
public function delegate_folders($attrib = array())
|
|
{
|
|
if (!$attrib['id']) {
|
|
$attrib['id'] = 'delegatefolders';
|
|
}
|
|
|
|
$engine = $this->engine();
|
|
$id = get_input_value('_id', RCUBE_INPUT_GPC);
|
|
|
|
if ($id) {
|
|
$delegate = $engine->delegate_get($id);
|
|
}
|
|
|
|
$folder_data = $engine->list_folders($delegate['uid']);
|
|
$rights = array();
|
|
$folders = array();
|
|
$folder_groups = array();
|
|
|
|
foreach ($folder_data as $folder_name => $folder) {
|
|
$folder_groups[$folder['type']][] = $folder_name;
|
|
$rights[$folder_name] = $folder['rights'];
|
|
}
|
|
|
|
// build block for every folder type
|
|
foreach ($folder_groups as $type => $group) {
|
|
if (empty($group)) {
|
|
continue;
|
|
}
|
|
$attrib['type'] = $type;
|
|
$html .= html::div('foldersblock',
|
|
html::tag('h3', $type, $this->gettext($type)) .
|
|
$this->delegate_folders_block($group, $attrib, $rights));
|
|
}
|
|
|
|
$this->rc->output->add_gui_object('folderslist', $attrib['id']);
|
|
|
|
return html::div($attrib, $html);
|
|
}
|
|
|
|
/**
|
|
* List of folders in specified group
|
|
*/
|
|
private function delegate_folders_block($a_folders, $attrib, $rights)
|
|
{
|
|
$read_ico = $attrib['readicon'] ? html::img(array('src' => $this->skin_path . $attrib['readicon'], 'title' => $this->gettext('read'))) : '';
|
|
$write_ico = $attrib['writeicon'] ? html::img(array('src' => $this->skin_path . $attrib['writeicon'], 'title' => $this->gettext('write'))) : '';
|
|
|
|
$table = new html_table(array('cellspacing' => 0));
|
|
$table->add_header('read', $read_ico);
|
|
$table->add_header('write', $write_ico);
|
|
$table->add_header('foldername', $this->rc->gettext('folder'));
|
|
|
|
$checkbox_read = new html_checkbox(array('name' => 'read[]', 'class' => 'read'));
|
|
$checkbox_write = new html_checkbox(array('name' => 'write[]', 'class' => 'write'));
|
|
|
|
$names = array();
|
|
foreach ($a_folders as $folder) {
|
|
$foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_name($folder));
|
|
|
|
// find folder prefix to truncate (the same code as in kolab_addressbook plugin)
|
|
for ($i = count($names)-1; $i >= 0; $i--) {
|
|
if (strpos($foldername, $names[$i].' » ') === 0) {
|
|
$length = strlen($names[$i].' » ');
|
|
$prefix = substr($foldername, 0, $length);
|
|
$count = count(explode(' » ', $prefix));
|
|
$foldername = str_repeat(' ', $count-1) . '» ' . substr($foldername, $length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
$names[] = $origname;
|
|
$classes = array('mailbox');
|
|
|
|
if ($folder_class = $this->rc->folder_classname($folder)) {
|
|
$foldername = html::quote($this->rc->gettext($folder_class));
|
|
$classes[] = $folder_class;
|
|
}
|
|
|
|
$folder_id = 'rcmf' . html_identifier($folder);
|
|
$padding = str_repeat(' ', $level);
|
|
|
|
$table->add_row();
|
|
$table->add('read', $checkbox_read->show(
|
|
$rights[$folder] >= kolab_delegation_engine::ACL_READ ? $folder : null,
|
|
array('value' => $folder)));
|
|
$table->add('write', $checkbox_write->show(
|
|
$rights[$folder] >= kolab_delegation_engine::ACL_WRITE ? $folder : null,
|
|
array('value' => $folder, 'id' => $folder_id)));
|
|
|
|
$table->add(join(' ', $classes), html::label($folder_id, $padding . $foldername));
|
|
}
|
|
|
|
return $table->show();
|
|
}
|
|
}
|