diff --git a/plugins/kolab_activesync/kolab_activesync_ui.php b/plugins/kolab_activesync/kolab_activesync_ui.php index 53134240..1b2c1c17 100644 --- a/plugins/kolab_activesync/kolab_activesync_ui.php +++ b/plugins/kolab_activesync/kolab_activesync_ui.php @@ -1,301 +1,301 @@ * @author Aleksander Machniak * * Copyright (C) 2011-2013, Kolab Systems AG * * 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 . */ class kolab_activesync_ui { private $rc; private $plugin; public $device = array(); const SETUP_URL = 'https://kb.kolabenterprise.com/documentation/setting-up-an-activesync-client'; public function __construct($plugin) { $this->plugin = $plugin; $this->rc = rcube::get_instance(); $skin_path = $this->plugin->local_skin_path() . '/'; $this->skin_path = 'plugins/kolab_activesync/' . $skin_path; $this->plugin->include_stylesheet($skin_path . 'config.css'); } public function device_list($attrib = array()) { $attrib += array('id' => 'devices-list'); $devices = $this->plugin->list_devices(); $table = new html_table(); foreach ($devices as $id => $device) { $name = $device['ALIAS'] ? $device['ALIAS'] : $id; $table->add_row(array('id' => 'rcmrow' . $id)); $table->add(null, html::span('devicealias', rcube::Q($name)) . ' ' . html::span('devicetype secondary', rcube::Q($device['TYPE']))); } $this->rc->output->add_gui_object('devicelist', $attrib['id']); $this->rc->output->set_env('devicecount', count($devices)); $this->rc->output->include_script('list.js'); return $table->show($attrib); } public function device_config_form($attrib = array()) { $table = new html_table(array('cols' => 2)); $field_id = 'config-device-alias'; $input = new html_inputfield(array('name' => 'devicealias', 'id' => $field_id, 'size' => 40)); $table->add('title', html::label($field_id, $this->plugin->gettext('devicealias'))); $table->add(null, $input->show($this->device['ALIAS'] ? $this->device['ALIAS'] : $this->device['_id'])); // read-only device information $info = $this->plugin->device_info($this->device['ID']); if (!empty($info)) { foreach ($info as $key => $value) { if ($value) { $table->add('title', html::label(null, rcube::Q($this->plugin->gettext($key)))); $table->add(null, rcube::Q($value)); } } } if ($attrib['form']) { $this->rc->output->add_gui_object('editform', $attrib['form']); } return $table->show($attrib); } public function folder_subscriptions($attrib = array()) { if (!$attrib['id']) { $attrib['id'] = 'foldersubscriptions'; } // group folders by type (show only known types) $folder_groups = array('mail' => array(), 'contact' => array(), 'event' => array(), 'task' => array(), 'note' => array()); $folder_types = kolab_storage::folders_typedata(); $use_fieldsets = rcube_utils::get_boolean($attrib['use-fieldsets']); $imei = $this->device['_id']; $subscribed = array(); if ($imei) { $folder_meta = $this->plugin->folder_meta(); } foreach ($this->plugin->list_folders() as $folder) { if ($folder_types[$folder]) { list($type, ) = explode('.', $folder_types[$folder]); } else { $type = 'mail'; } if (is_array($folder_groups[$type])) { $folder_groups[$type][] = $folder; if (!empty($folder_meta) && ($meta = $folder_meta[$folder]) && $meta['FOLDER'] && $meta['FOLDER'][$imei]['S'] ) { $subscribed[$folder] = intval($meta['FOLDER'][$imei]['S']); } } } // build block for every folder type foreach ($folder_groups as $type => $group) { if (empty($group)) { continue; } $attrib['type'] = $type; $table = $this->folder_subscriptions_block($group, $attrib, $subscribed); $label = $this->plugin->gettext($type); if ($use_fieldsets) { $html .= html::tag('fieldset', 'subscriptionblock', html::tag('legend', $type, $label) . $table); } else { $html .= html::div('subscriptionblock', html::tag('h3', $type, $label) . $table); } } $this->rc->output->add_gui_object('subscriptionslist', $attrib['id']); return html::div($attrib, $html); } public function folder_subscriptions_block($a_folders, $attrib, $subscribed) { $alarms = ($attrib['type'] == 'event' || $attrib['type'] == 'task'); $table = new html_table(array('cellspacing' => 0, 'class' => 'table-striped')); $table->add_header(array( 'class' => 'subscription checkbox-cell', 'title' => $this->plugin->gettext('synchronize'), 'tabindex' => 0 ), $attrib['syncicon'] ? html::img(array('src' => $this->skin_path . $attrib['syncicon'])) : $this->plugin->gettext('synchronize') ); if ($alarms) { $table->add_header(array( 'class' => 'alarm checkbox-cell', 'title' => $this->plugin->gettext('withalarms'), 'tabindex' => 0 ), $attrib['alarmicon'] ? html::img(array('src' => $this->skin_path . $attrib['alarmicon'])) : $this->plugin->gettext('withalarms') ); } $table->add_header('foldername', $this->plugin->gettext('folder')); $checkbox_sync = new html_checkbox(array('name' => 'subscribed[]', 'class' => 'subscription')); $checkbox_alarm = new html_checkbox(array('name' => 'alarm[]', 'class' => 'alarm')); $names = array(); foreach ($a_folders as $folder) { - $foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_prettyname($folder)); + $foldername = $origname = kolab_storage::object_prettyname($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; } } $folder_id = 'rcmf' . rcube_utils::html_identifier($folder); $names[] = $origname; $classes = array('mailbox'); if ($folder_class = $this->rc->folder_classname($folder)) { if ($this->rc->text_exists($folder_class)) { $foldername = html::quote($this->rc->gettext($folder_class)); } $classes[] = $folder_class; } $table->add_row(); $table->add('subscription checkbox-cell', $checkbox_sync->show( !empty($subscribed[$folder]) ? $folder : null, array('value' => $folder, 'id' => $folder_id))); if ($alarms) { $table->add('alarm checkbox-cell', $checkbox_alarm->show( intval($subscribed[$folder]) > 1 ? $folder : null, array('value' => $folder, 'id' => $folder_id.'_alarm'))); } $table->add(join(' ', $classes), html::label($folder_id, $foldername)); } return $table->show(); } public function folder_options_table($folder_name, $devices, $type) { $alarms = $type == 'event' || $type == 'task'; $meta = $this->plugin->folder_meta(); $folder_data = (array) ($meta[$folder_name] ? $meta[$folder_name]['FOLDER'] : null); $table = new html_table(array('cellspacing' => 0, 'id' => 'folder-sync-options', 'class' => 'records-table')); // table header $table->add_header(array('class' => 'device'), $this->plugin->gettext('devicealias')); $table->add_header(array('class' => 'subscription'), $this->plugin->gettext('synchronize')); if ($alarms) { $table->add_header(array('class' => 'alarm'), $this->plugin->gettext('withalarms')); } // table records foreach ($devices as $id => $device) { $info = $this->plugin->device_info($device['ID']); $name = $id; $title = ''; $checkbox = new html_checkbox(array('name' => "_subscriptions[$id]", 'value' => 1, 'onchange' => 'return activesync_object.update_sync_data(this)')); if (!empty($info)) { $_name = trim($info['friendlyname'] . ' ' . $info['os']); $title = $info['useragent']; if ($_name) { $name .= " ($_name)"; } } $table->add_row(); $table->add(array('class' => 'device', 'title' => $title), $name); $table->add('subscription checkbox-cell', $checkbox->show(!empty($folder_data[$id]['S']) ? 1 : 0)); if ($alarms) { $checkbox_alarm = new html_checkbox(array('name' => "_alarms[$id]", 'value' => 1, 'onchange' => 'return activesync_object.update_sync_data(this)')); $table->add('alarm checkbox-cell', $checkbox_alarm->show($folder_data[$id]['S'] > 1 ? 1 : 0)); } } return $table->show(); } /** * Displays initial page (when no devices are registered) */ function init_message() { $this->plugin->load_config(); $this->rc->output->add_handlers(array( 'initmessage' => array($this, 'init_message_content') )); $this->rc->output->send('kolab_activesync.configempty'); } /** * Handler for initmessage template object */ function init_message_content() { $url = $this->rc->config->get('activesync_setup_url', self::SETUP_URL); $vars = array('url' => $url); $msg = $this->plugin->gettext(array('name' => 'nodevices', 'vars' => $vars)); return $msg; } } diff --git a/plugins/kolab_delegation/kolab_delegation.php b/plugins/kolab_delegation/kolab_delegation.php index af37744c..0b074774 100644 --- a/plugins/kolab_delegation/kolab_delegation.php +++ b/plugins/kolab_delegation/kolab_delegation.php @@ -1,603 +1,603 @@ * @author Thomas Bruederli * * Copyright (C) 2011-2012, Kolab Systems AG * * 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 . */ class kolab_delegation extends rcube_plugin { public $task = 'login|mail|settings|calendar|tasks'; private $rc; private $engine; /** * Plugin initialization. */ public function init() { $this->rc = rcube::get_instance(); $this->require_plugin('libkolab'); $this->require_plugin('kolab_auth'); // 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')); // on-message-send delegation support $this->add_hook('message_before_send', array($this, 'message_before_send')); // delegation support in Calendar and Tasklist plugins $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')); $this->add_hook('tasklist_list_filter', array($this, 'tasklist_list_filter')); // delegation support in kolab_auth plugin $this->add_hook('kolab_auth_emails', array($this, 'kolab_auth_emails')); // delegation support in Enigma plugin $this->add_hook('enigma_user_identities', array($this, 'user_identities')); 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')); $this->register_action('plugin.delegation-autocomplete', array($this, 'controller_action')); $this->add_hook('settings_actions', array($this, 'settings_actions')); if ($this->rc->output->type == 'html' && ($this->rc->action == 'plugin.delegation' || empty($_REQUEST['_framed'])) ) { $this->add_texts('localization/', array('deleteconfirm', 'savingdata', 'yes', 'no')); if ($this->rc->action == 'plugin.delegation') { $this->include_script('kolab_delegation.js'); } $this->skin_path = $this->local_skin_path(); $this->include_stylesheet($this->skin_path . '/style.css'); } } // Calendar/Tasklist plugin UI bindings else if (($this->rc->task == 'calendar' || $this->rc->task == 'tasks') && empty($_REQUEST['_framed']) ) { if ($this->rc->output->type == 'html') { $this->calendar_ui(); } } } /** * Adds Delegation section in Settings */ function settings_actions($args) { $args['actions'][] = array( 'action' => 'plugin.delegation', 'class' => 'delegation', 'label' => 'tabtitle', 'domain' => 'kolab_delegation', 'title' => 'delegationtitle', ); return $args; } /** * 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) { // Manage (create) identities for delegator's email addresses // and subscribe to delegator's folders. Also remove identities // after delegation is removed $engine = $this->engine(); $engine->delegation_init(); 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['delegators'])) { return $args; } $storage = $this->rc->get_storage(); $other_ns = $storage->get_namespace('other'); $folders = $storage->list_folders_subscribed('', '*', 'mail'); 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'])) { $args['folders'][] = $folder; } } } return $args; } /** * Mail send action */ public function message_before_send($args) { // Checking headers of email being send, we'll add // Sender: header if mail is send on behalf of someone else if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $engine->delegator_delivery_filter($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? // skip invalid messages or Kolab objects (for better performance) if (empty($args['object']->headers) || $args['object']->headers->get('x-kolab-type', false)) { return $args; } $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 if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $engine->delegator_emails_filter($args); } 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 if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $engine->delegator_folder_filter($args, 'calendars'); } return $args; } /** * tasklist_driver::get_lists() handler */ public function tasklist_list_filter($args) { // In delegator context we'll use delegator's folders // instead of current user folders if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $engine->delegator_folder_filter($args, 'tasklists'); } 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 if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $engine->delegator_identity_filter($args); } return $args; } /** * Delegation support in Calendar/Tasks plugin UI */ public function calendar_ui() { // Initialize handling of delegators' identities in event form if (!empty($_SESSION['delegators'])) { $engine = $this->engine(); $this->rc->output->set_env('namespace', $engine->namespace_js()); $this->rc->output->set_env('delegators', $engine->list_delegators_js()); $this->include_script('kolab_delegation.js'); } } /** * Delegation support in kolab_auth plugin */ public function kolab_auth_emails($args) { // Add delegators addresses to address selector in user identity form if (!empty($_SESSION['delegators'])) { // @TODO: Consider not adding all delegator addresses to the list. // Instead add only address of currently edited identity foreach ($_SESSION['delegators'] as $emails) { $args['emails'] = array_merge($args['emails'], $emails); } $args['emails'] = array_unique($args['emails']); sort($args['emails']); } return $args; } /** * Delegation support in Enigma plugin */ public function user_identities($args) { // Remove delegators' identities from the key generation form if (!empty($_SESSION['delegators'])) { $args['identities'] = array_filter($args['identities'], function($ident) { foreach ($_SESSION['delegators'] as $emails) { if (in_array($ident['email'], $emails)) { return false; } } return true; }); } 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/'); $engine = $this->engine(); // Delegate delete if ($this->rc->action == 'plugin.delegation-delete') { $id = rcube_utils::get_input_value('id', rcube_utils::INPUT_GPC); $error = $engine->delegate_delete($id, (bool) rcube_utils::get_input_value('acl', rcube_utils::INPUT_GPC)); if (!$error) { $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($error), 'error'); } } // Delegate add/update else if ($this->rc->action == 'plugin.delegation-save') { $id = rcube_utils::get_input_value('id', rcube_utils::INPUT_GPC); $acl = rcube_utils::get_input_value('folders', rcube_utils::INPUT_GPC); // update if ($id) { $delegate = $engine->delegate_get($id); $error = $engine->delegate_acl_update($delegate['uid'], $acl); if (!$error) { $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($error), 'error'); } } // new else { $login = rcube_utils::get_input_value('newid', rcube_utils::INPUT_GPC); $delegate = $engine->delegate_get_by_name($login); $error = $engine->delegate_add($delegate, $acl); if (!$error) { $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($error), 'error'); } } } // Delegate autocompletion else if ($this->rc->action == 'plugin.delegation-autocomplete') { $search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true); $reqid = rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC); $users = $engine->list_users($search); $this->rc->output->command('ksearch_query_results', $users, $search, $reqid); } $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) { $table->add_row(array('id' => 'rcmrow' . $id)); $table->add(null, rcube::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 = rcube_utils::get_input_value('_id', rcube_utils::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 = rcube::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 = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC); if ($id) { $delegate = $engine->delegate_get($id); } $folder_data = $engine->list_folders($delegate['uid']); $use_fieldsets = rcube_utils::get_boolean($attrib['use-fieldsets']); $rights = 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; $table = $this->delegate_folders_block($group, $attrib, $rights); $label = $this->gettext($type); if ($use_fieldsets) { $html .= html::tag('fieldset', 'foldersblock', html::tag('legend', $type, $label) . $table); } else { $html .= html::div('foldersblock', html::tag('h3', $type, $label) . $table); } } $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) { $path = 'plugins/kolab_delegation/' . $this->skin_path . '/'; $read_ico = $attrib['readicon'] ? html::img(array('src' => $path . $attrib['readicon'], 'title' => $this->gettext('read'))) : ''; $write_ico = $attrib['writeicon'] ? html::img(array('src' => $path . $attrib['writeicon'], 'title' => $this->gettext('write'))) : ''; $table = new html_table(array('cellspacing' => 0, 'class' => 'table-striped')); $table->add_header(array('class' => 'read checkbox-cell', 'title' => $this->gettext('read'), 'tabindex' => 0), $read_ico); $table->add_header(array('class' => 'write checkbox-cell', 'title' => $this->gettext('write'), 'tabindex' => 0), $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_prettyname($folder)); + $foldername = $origname = kolab_storage::object_prettyname($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; } } $folder_id = 'rcmf' . rcube_utils::html_identifier($folder); $names[] = $origname; $classes = array('mailbox'); if ($folder_class = $this->rc->folder_classname($folder)) { if ($this->rc->text_exists($folder_class)) { $foldername = html::quote($this->rc->gettext($folder_class)); } $classes[] = $folder_class; } $table->add_row(); $table->add('read checkbox-cell', $checkbox_read->show( $rights[$folder] >= kolab_delegation_engine::ACL_READ ? $folder : null, array('value' => $folder))); $table->add('write checkbox-cell', $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, $foldername)); } return $table->show(); } }