2011-05-19 12:40:46 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type-aware folder management/listing for Kolab
|
|
|
|
*
|
|
|
|
* @author Aleksander Machniak <machniak@kolabsys.com>
|
|
|
|
*
|
2017-06-12 10:28:07 +00:00
|
|
|
* Copyright (C) 2011-2017, Kolab Systems AG <contact@kolabsys.com>
|
2011-05-19 12:40:46 +02:00
|
|
|
*
|
2011-10-27 10:20:46 +02:00
|
|
|
* 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.
|
2011-05-19 12:40:46 +02:00
|
|
|
*
|
|
|
|
* 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
|
2011-10-27 10:20:46 +02:00
|
|
|
* GNU Affero General Public License for more details.
|
2011-05-19 12:40:46 +02:00
|
|
|
*
|
2011-10-27 10:20:46 +02:00
|
|
|
* 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/>.
|
2011-05-19 12:40:46 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
class kolab_folders extends rcube_plugin
|
|
|
|
{
|
2011-07-07 15:52:29 +02:00
|
|
|
public $task = '?(?!login).*';
|
|
|
|
|
2013-10-29 16:04:02 +01:00
|
|
|
public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact', 'configuration', 'file', 'freebusy');
|
2014-09-23 11:37:45 +02:00
|
|
|
public $subtypes = array(
|
|
|
|
'mail' => array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail'),
|
2015-03-25 15:09:04 +01:00
|
|
|
'event' => array('default', 'confidential', 'private'),
|
|
|
|
'task' => array('default', 'confidential', 'private'),
|
2014-09-23 11:37:45 +02:00
|
|
|
'journal' => array('default'),
|
|
|
|
'note' => array('default'),
|
|
|
|
'contact' => array('default'),
|
|
|
|
'configuration' => array('default'),
|
|
|
|
'file' => array('default'),
|
|
|
|
'freebusy' => array('default'),
|
|
|
|
);
|
2013-10-29 16:04:02 +01:00
|
|
|
public $act_types = array('event', 'task');
|
2012-09-20 08:51:38 +02:00
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
private $rc;
|
2012-09-20 08:51:38 +02:00
|
|
|
private static $instance;
|
2017-06-12 10:28:07 +00:00
|
|
|
private $expire_annotation = '/shared/vendor/cmu/cyrus-imapd/expire';
|
2011-05-19 12:40:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Plugin initialization.
|
|
|
|
*/
|
|
|
|
function init()
|
|
|
|
{
|
2012-09-20 08:51:38 +02:00
|
|
|
self::$instance = $this;
|
2012-10-17 11:54:25 +02:00
|
|
|
$this->rc = rcube::get_instance();
|
2011-05-19 12:40:46 +02:00
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
// load required plugin
|
|
|
|
$this->require_plugin('libkolab');
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
// Folder listing hooks
|
2012-01-23 10:16:30 +01:00
|
|
|
$this->add_hook('storage_folders', array($this, 'mailboxes_list'));
|
2011-05-19 12:40:46 +02:00
|
|
|
|
|
|
|
// Folder manager hooks
|
|
|
|
$this->add_hook('folder_form', array($this, 'folder_form'));
|
|
|
|
$this->add_hook('folder_update', array($this, 'folder_save'));
|
|
|
|
$this->add_hook('folder_create', array($this, 'folder_save'));
|
2011-07-10 20:21:53 +02:00
|
|
|
$this->add_hook('folder_delete', array($this, 'folder_save'));
|
|
|
|
$this->add_hook('folder_rename', array($this, 'folder_save'));
|
2011-06-15 15:28:13 +02:00
|
|
|
$this->add_hook('folders_list', array($this, 'folders_list'));
|
2013-04-10 13:56:04 +02:00
|
|
|
|
|
|
|
// Special folders setting
|
|
|
|
$this->add_hook('preferences_save', array($this, 'prefs_save'));
|
2015-03-12 14:55:04 +01:00
|
|
|
|
|
|
|
// ACL plugin hooks
|
|
|
|
$this->add_hook('acl_rights_simple', array($this, 'acl_rights_simple'));
|
|
|
|
$this->add_hook('acl_rights_supported', array($this, 'acl_rights_supported'));
|
2019-06-13 13:33:35 +00:00
|
|
|
|
|
|
|
// Resolving other user folder names
|
|
|
|
$this->add_hook('render_mailboxlist', array($this, 'render_folderlist'));
|
|
|
|
$this->add_hook('render_folder_selector', array($this, 'render_folderlist'));
|
|
|
|
$this->add_hook('folders_list', array($this, 'render_folderlist'));
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for mailboxes_list hook. Enables type-aware lists filtering.
|
|
|
|
*/
|
|
|
|
function mailboxes_list($args)
|
|
|
|
{
|
2012-05-14 13:04:24 +02:00
|
|
|
// infinite loop prevention
|
|
|
|
if ($this->is_processing) {
|
2011-05-19 12:40:46 +02:00
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
if (!$this->metadata_support()) {
|
2011-05-19 12:40:46 +02:00
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
$this->is_processing = true;
|
2011-05-19 12:40:46 +02:00
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
// get folders
|
2012-06-26 11:01:22 +02:00
|
|
|
$folders = kolab_storage::list_folders($args['root'], $args['name'], $args['filter'], $args['mode'] == 'LSUB', $folderdata);
|
2011-05-19 12:40:46 +02:00
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
$this->is_processing = false;
|
2011-05-19 12:40:46 +02:00
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
if (!is_array($folders)) {
|
2011-05-19 12:40:46 +02:00
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
// Create default folders
|
|
|
|
if ($args['root'] == '' && $args['name'] = '*') {
|
2013-10-29 16:04:02 +01:00
|
|
|
$this->create_default_folders($folders, $args['filter'], $folderdata, $args['mode'] == 'LSUB');
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
2012-05-14 13:04:24 +02:00
|
|
|
$args['folders'] = $folders;
|
2011-05-19 12:40:46 +02:00
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2011-06-15 15:28:13 +02:00
|
|
|
/**
|
|
|
|
* Handler for folders_list hook. Add css classes to folder rows.
|
|
|
|
*/
|
|
|
|
function folders_list($args)
|
|
|
|
{
|
|
|
|
if (!$this->metadata_support()) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2014-08-11 18:55:50 +02:00
|
|
|
// load translations
|
|
|
|
$this->add_texts('localization/', false);
|
|
|
|
|
|
|
|
// Add javascript script to the client
|
|
|
|
$this->include_script('kolab_folders.js');
|
|
|
|
|
|
|
|
$this->add_label('folderctype');
|
|
|
|
foreach ($this->types as $type) {
|
|
|
|
$this->add_label('foldertype' . $type);
|
|
|
|
}
|
|
|
|
|
2014-08-13 18:13:09 +02:00
|
|
|
$skip_namespace = $this->rc->config->get('kolab_skip_namespace');
|
2014-08-11 18:55:50 +02:00
|
|
|
$skip_roots = array();
|
|
|
|
|
|
|
|
if (!empty($skip_namespace)) {
|
|
|
|
$storage = $this->rc->get_storage();
|
2014-08-13 18:13:09 +02:00
|
|
|
foreach ((array)$skip_namespace as $ns) {
|
2014-08-11 18:55:50 +02:00
|
|
|
foreach((array)$storage->get_namespace($ns) as $root) {
|
|
|
|
$skip_roots[] = rtrim($root[0], $root[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->rc->output->set_env('skip_roots', $skip_roots);
|
|
|
|
$this->rc->output->set_env('foldertypes', $this->types);
|
|
|
|
|
2011-06-15 15:28:13 +02:00
|
|
|
// get folders types
|
2013-07-09 15:24:01 +02:00
|
|
|
$folderdata = kolab_storage::folders_typedata();
|
2011-06-15 15:28:13 +02:00
|
|
|
|
|
|
|
if (!is_array($folderdata)) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add type-based style for table rows
|
|
|
|
// See kolab_folders::folder_class_name()
|
2014-07-03 11:21:01 +02:00
|
|
|
if ($table = $args['table']) {
|
|
|
|
for ($i=1, $cnt=$table->size(); $i<=$cnt; $i++) {
|
|
|
|
$attrib = $table->get_row_attribs($i);
|
|
|
|
$folder = $attrib['foldername']; // UTF7-IMAP
|
|
|
|
$type = $folderdata[$folder];
|
|
|
|
|
|
|
|
if (!$type) {
|
|
|
|
$type = 'mail';
|
|
|
|
}
|
|
|
|
|
|
|
|
$class_name = self::folder_class_name($type);
|
|
|
|
$attrib['class'] = trim($attrib['class'] . ' ' . $class_name);
|
|
|
|
$table->set_row_attribs($attrib, $i);
|
2013-07-09 15:16:15 +02:00
|
|
|
}
|
2014-07-03 11:21:01 +02:00
|
|
|
}
|
2011-06-15 15:42:58 +02:00
|
|
|
|
2014-07-03 11:21:01 +02:00
|
|
|
// Add type-based class for list items
|
|
|
|
if (is_array($args['list'])) {
|
|
|
|
foreach ((array)$args['list'] as $k => $item) {
|
|
|
|
$folder = $item['folder_imap']; // UTF7-IMAP
|
|
|
|
$type = $folderdata[$folder];
|
2011-06-15 15:42:58 +02:00
|
|
|
|
2014-07-03 11:21:01 +02:00
|
|
|
if (!$type) {
|
|
|
|
$type = 'mail';
|
|
|
|
}
|
|
|
|
|
|
|
|
$class_name = self::folder_class_name($type);
|
|
|
|
$args['list'][$k]['class'] = trim($item['class'] . ' ' . $class_name);
|
|
|
|
}
|
2011-06-15 15:28:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
/**
|
|
|
|
* Handler for folder info/edit form (folder_form hook).
|
|
|
|
* Adds folder type selector.
|
|
|
|
*/
|
|
|
|
function folder_form($args)
|
|
|
|
{
|
|
|
|
if (!$this->metadata_support()) {
|
|
|
|
return $args;
|
|
|
|
}
|
2011-07-07 19:39:34 +02:00
|
|
|
// load translations
|
|
|
|
$this->add_texts('localization/', false);
|
|
|
|
|
|
|
|
// INBOX folder is of type mail.inbox and this cannot be changed
|
|
|
|
if ($args['name'] == 'INBOX') {
|
|
|
|
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
|
|
|
|
'label' => $this->gettext('folderctype'),
|
|
|
|
'value' => sprintf('%s (%s)', $this->gettext('foldertypemail'), $this->gettext('inbox')),
|
|
|
|
);
|
|
|
|
|
2017-06-12 10:28:07 +00:00
|
|
|
$this->add_expire_input($args['form'], 'INBOX');
|
|
|
|
|
2011-07-07 19:39:34 +02:00
|
|
|
return $args;
|
|
|
|
}
|
2011-05-19 12:40:46 +02:00
|
|
|
|
2011-10-04 13:19:46 +02:00
|
|
|
if ($args['options']['is_root']) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
$mbox = strlen($args['name']) ? $args['name'] : $args['parent_name'];
|
2011-07-07 19:39:34 +02:00
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
if (isset($_POST['_ctype'])) {
|
2014-10-06 09:19:26 +02:00
|
|
|
$new_ctype = trim(rcube_utils::get_input_value('_ctype', rcube_utils::INPUT_POST));
|
|
|
|
$new_subtype = trim(rcube_utils::get_input_value('_subtype', rcube_utils::INPUT_POST));
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get type of the folder or the parent
|
|
|
|
if (strlen($mbox)) {
|
|
|
|
list($ctype, $subtype) = $this->get_folder_type($mbox);
|
2011-07-07 15:50:50 +02:00
|
|
|
if (strlen($args['parent_name']) && $subtype == 'default')
|
|
|
|
$subtype = ''; // there can be only one
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$ctype) {
|
|
|
|
$ctype = 'mail';
|
|
|
|
}
|
|
|
|
|
2012-01-23 10:16:30 +01:00
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
|
2011-08-19 10:13:14 +02:00
|
|
|
// Don't allow changing type of shared folder, according to ACL
|
|
|
|
if (strlen($mbox)) {
|
2012-01-23 10:16:30 +01:00
|
|
|
$options = $storage->folder_info($mbox);
|
2013-04-09 18:50:47 +02:00
|
|
|
if ($options['namespace'] != 'personal' && !in_array('a', (array)$options['rights'])) {
|
2012-01-23 10:16:30 +01:00
|
|
|
if (in_array($ctype, $this->types)) {
|
2011-08-19 10:13:14 +02:00
|
|
|
$value = $this->gettext('foldertype'.$ctype);
|
2012-01-23 10:16:30 +01:00
|
|
|
}
|
|
|
|
else {
|
2011-08-19 10:13:14 +02:00
|
|
|
$value = $ctype;
|
2012-01-23 10:16:30 +01:00
|
|
|
}
|
|
|
|
if ($subtype) {
|
2011-08-19 10:13:14 +02:00
|
|
|
$value .= ' ('. ($subtype == 'default' ? $this->gettext('default') : $subtype) .')';
|
2012-01-23 10:16:30 +01:00
|
|
|
}
|
2011-08-19 10:13:14 +02:00
|
|
|
|
|
|
|
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
|
|
|
|
'label' => $this->gettext('folderctype'),
|
|
|
|
'value' => $value,
|
|
|
|
);
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:39:34 +02:00
|
|
|
// Add javascript script to the client
|
2011-05-19 12:40:46 +02:00
|
|
|
$this->include_script('kolab_folders.js');
|
|
|
|
|
|
|
|
// build type SELECT fields
|
2017-10-30 11:30:02 +01:00
|
|
|
$type_select = new html_select(array('name' => '_ctype', 'id' => '_folderctype',
|
2017-06-12 10:28:07 +00:00
|
|
|
'onchange' => "\$('[name=\"_expire\"]').attr('disabled', \$(this).val() != 'mail')"
|
|
|
|
));
|
2011-05-19 12:40:46 +02:00
|
|
|
$sub_select = new html_select(array('name' => '_subtype', 'id' => '_subtype'));
|
2014-09-23 11:37:45 +02:00
|
|
|
$sub_select->add('', '');
|
2011-05-19 12:40:46 +02:00
|
|
|
|
|
|
|
foreach ($this->types as $type) {
|
|
|
|
$type_select->add($this->gettext('foldertype'.$type), $type);
|
|
|
|
}
|
|
|
|
// add non-supported type
|
|
|
|
if (!in_array($ctype, $this->types)) {
|
|
|
|
$type_select->add($ctype, $ctype);
|
|
|
|
}
|
|
|
|
|
2014-09-23 11:37:45 +02:00
|
|
|
$sub_types = array();
|
|
|
|
foreach ($this->subtypes as $ftype => $subtypes) {
|
|
|
|
$sub_types[$ftype] = array_combine($subtypes, array_map(array($this, 'gettext'), $subtypes));
|
|
|
|
|
|
|
|
// fill options for the current folder type
|
|
|
|
if ($ftype == $ctype || $ftype == $new_ctype) {
|
|
|
|
$sub_select->add(array_values($sub_types[$ftype]), $subtypes);
|
|
|
|
}
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
2017-10-30 11:30:02 +01:00
|
|
|
$args['form']['props']['fieldsets']['settings']['content']['folderctype'] = array(
|
2011-05-19 12:40:46 +02:00
|
|
|
'label' => $this->gettext('folderctype'),
|
2017-10-30 11:30:02 +01:00
|
|
|
'value' => html::div('input-group',
|
|
|
|
$type_select->show(isset($new_ctype) ? $new_ctype : $ctype)
|
|
|
|
. $sub_select->show(isset($new_subtype) ? $new_subtype : $subtype)
|
|
|
|
),
|
2011-05-19 12:40:46 +02:00
|
|
|
);
|
|
|
|
|
2014-09-23 11:37:45 +02:00
|
|
|
$this->rc->output->set_env('kolab_folder_subtypes', $sub_types);
|
|
|
|
$this->rc->output->set_env('kolab_folder_subtype', isset($new_subtype) ? $new_subtype : $subtype);
|
|
|
|
|
2017-06-12 10:28:07 +00:00
|
|
|
$this->add_expire_input($args['form'], $args['name'], $ctype);
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for folder update/create action (folder_update/folder_create hook).
|
|
|
|
*/
|
|
|
|
function folder_save($args)
|
|
|
|
{
|
2011-07-10 20:21:53 +02:00
|
|
|
// Folder actions from folders list
|
|
|
|
if (empty($args['record'])) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Folder create/update with form
|
2014-10-06 09:19:26 +02:00
|
|
|
$ctype = trim(rcube_utils::get_input_value('_ctype', rcube_utils::INPUT_POST));
|
|
|
|
$subtype = trim(rcube_utils::get_input_value('_subtype', rcube_utils::INPUT_POST));
|
2011-06-15 15:28:13 +02:00
|
|
|
$mbox = $args['record']['name'];
|
|
|
|
$old_mbox = $args['record']['oldname'];
|
|
|
|
$subscribe = $args['record']['subscribe'];
|
2011-05-19 12:40:46 +02:00
|
|
|
|
|
|
|
if (empty($ctype)) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2011-07-07 15:50:50 +02:00
|
|
|
// load translations
|
|
|
|
$this->add_texts('localization/', false);
|
|
|
|
|
|
|
|
// Skip folder creation/rename in core
|
|
|
|
// @TODO: Maybe we should provide folder_create_after and folder_update_after hooks?
|
|
|
|
// Using create_mailbox/rename_mailbox here looks bad
|
|
|
|
$args['abort'] = true;
|
|
|
|
|
|
|
|
// There can be only one default folder of specified type
|
2011-05-19 12:40:46 +02:00
|
|
|
if ($subtype == 'default') {
|
2011-07-07 15:50:50 +02:00
|
|
|
$default = $this->get_default_folder($ctype);
|
|
|
|
|
|
|
|
if ($default !== null && $old_mbox != $default) {
|
|
|
|
$args['result'] = false;
|
|
|
|
$args['message'] = $this->gettext('defaultfolderexists');
|
|
|
|
return $args;
|
|
|
|
}
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
// Subtype sanity-checks
|
2014-09-23 11:37:45 +02:00
|
|
|
else if ($subtype && (!($subtypes = $this->subtypes[$ctype]) || !in_array($subtype, $subtypes))) {
|
2011-05-19 12:40:46 +02:00
|
|
|
$subtype = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
$ctype .= $subtype ? '.'.$subtype : '';
|
|
|
|
|
2012-01-23 10:16:30 +01:00
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
// Create folder
|
|
|
|
if (!strlen($old_mbox)) {
|
2011-06-15 15:28:13 +02:00
|
|
|
// By default don't subscribe to non-mail folders
|
|
|
|
if ($subscribe)
|
2011-06-15 15:42:58 +02:00
|
|
|
$subscribe = (bool) preg_match('/^mail/', $ctype);
|
2011-06-15 15:28:13 +02:00
|
|
|
|
2012-01-23 10:16:30 +01:00
|
|
|
$result = $storage->create_folder($mbox, $subscribe);
|
2011-05-19 12:40:46 +02:00
|
|
|
// Set folder type
|
|
|
|
if ($result) {
|
|
|
|
$this->set_folder_type($mbox, $ctype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Rename folder
|
|
|
|
else {
|
|
|
|
if ($old_mbox != $mbox) {
|
2012-01-23 10:16:30 +01:00
|
|
|
$result = $storage->rename_folder($old_mbox, $mbox);
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
$result = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($result) {
|
|
|
|
list($oldtype, $oldsubtype) = $this->get_folder_type($mbox);
|
|
|
|
$oldtype .= $oldsubtype ? '.'.$oldsubtype : '';
|
|
|
|
|
|
|
|
if ($ctype != $oldtype) {
|
|
|
|
$this->set_folder_type($mbox, $ctype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 10:28:07 +00:00
|
|
|
// Set messages expiration in days
|
|
|
|
if ($result && isset($_POST['_expire'])) {
|
|
|
|
$expire = trim(rcube_utils::get_input_value('_expire', rcube_utils::INPUT_POST));
|
|
|
|
$expire = intval($expire) && preg_match('/^mail/', $ctype) ? intval($expire) : null;
|
|
|
|
|
|
|
|
$storage->set_metadata($mbox, array($this->expire_annotation => $expire));
|
|
|
|
}
|
|
|
|
|
|
|
|
$args['record']['class'] = self::folder_class_name($ctype);
|
2011-06-15 15:28:13 +02:00
|
|
|
$args['record']['subscribe'] = $subscribe;
|
2011-05-19 12:40:46 +02:00
|
|
|
$args['result'] = $result;
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2013-04-10 13:56:04 +02:00
|
|
|
/**
|
|
|
|
* Handler for user preferences save (preferences_save hook)
|
|
|
|
*
|
|
|
|
* @param array $args Hash array with hook parameters
|
|
|
|
*
|
|
|
|
* @return array Hash array with modified hook parameters
|
|
|
|
*/
|
|
|
|
public function prefs_save($args)
|
|
|
|
{
|
|
|
|
if ($args['section'] != 'folders') {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2014-04-03 09:59:23 +02:00
|
|
|
$dont_override = (array) $this->rc->config->get('dont_override', array());
|
2013-04-10 13:56:04 +02:00
|
|
|
|
|
|
|
// map config option name to kolab folder type annotation
|
|
|
|
$opts = array(
|
|
|
|
'drafts_mbox' => 'mail.drafts',
|
|
|
|
'sent_mbox' => 'mail.sentitems',
|
|
|
|
'junk_mbox' => 'mail.junkemail',
|
|
|
|
'trash_mbox' => 'mail.wastebasket',
|
|
|
|
);
|
|
|
|
|
|
|
|
// check if any of special folders has been changed
|
|
|
|
foreach ($opts as $opt_name => $type) {
|
|
|
|
$new = $args['prefs'][$opt_name];
|
|
|
|
$old = $this->rc->config->get($opt_name);
|
2014-04-03 09:59:23 +02:00
|
|
|
if (!strlen($new) || $new === $old || in_array($opt_name, $dont_override)) {
|
2013-04-10 13:56:04 +02:00
|
|
|
unset($opts[$opt_name]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($opts)) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2013-07-09 15:24:01 +02:00
|
|
|
$folderdata = kolab_storage::folders_typedata();
|
2013-04-10 13:56:04 +02:00
|
|
|
|
|
|
|
if (!is_array($folderdata)) {
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($opts as $opt_name => $type) {
|
|
|
|
$foldername = $args['prefs'][$opt_name];
|
|
|
|
|
2014-04-03 09:59:23 +02:00
|
|
|
// get all folders of specified type
|
|
|
|
$folders = array_intersect($folderdata, array($type));
|
2013-04-10 13:56:04 +02:00
|
|
|
|
2014-04-03 09:59:23 +02:00
|
|
|
// folder already annotated with specified type
|
|
|
|
if (!empty($folders[$foldername])) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-10 13:56:04 +02:00
|
|
|
|
2014-04-03 09:59:23 +02:00
|
|
|
// set type to the new folder
|
|
|
|
$this->set_folder_type($foldername, $type);
|
2013-04-10 13:56:04 +02:00
|
|
|
|
2014-04-03 09:59:23 +02:00
|
|
|
// unset old folder(s) type annotation
|
|
|
|
list($maintype, $subtype) = explode('.', $type);
|
|
|
|
foreach (array_keys($folders) as $folder) {
|
|
|
|
$this->set_folder_type($folder, $maintype);
|
2013-04-10 13:56:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2015-03-12 14:55:04 +01:00
|
|
|
/**
|
|
|
|
* Handler for ACL permissions listing (acl_rights_simple hook)
|
|
|
|
*
|
|
|
|
* This shall combine the write and delete permissions into one item for
|
|
|
|
* groupware folders as updating groupware objects is an insert + delete operation.
|
|
|
|
*
|
|
|
|
* @param array $args Hash array with hook parameters
|
|
|
|
*
|
|
|
|
* @return array Hash array with modified hook parameters
|
|
|
|
*/
|
|
|
|
public function acl_rights_simple($args)
|
|
|
|
{
|
|
|
|
if ($args['folder']) {
|
|
|
|
list($type,) = $this->get_folder_type($args['folder']);
|
|
|
|
|
|
|
|
// we're dealing with a groupware folder here...
|
|
|
|
if ($type && $type !== 'mail') {
|
|
|
|
if ($args['rights']['write'] && $args['rights']['delete']) {
|
2016-06-10 05:14:46 -04:00
|
|
|
$write_perms = $args['rights']['write'] . $args['rights']['delete'];
|
|
|
|
$rw_perms = $write_perms . $args['rights']['read'];
|
|
|
|
|
|
|
|
$args['rights']['write'] = $write_perms;
|
|
|
|
$args['rights']['other'] = preg_replace("/[$rw_perms]/", '', $args['rights']['other']);
|
2015-03-12 14:55:04 +01:00
|
|
|
|
|
|
|
// add localized labels and titles for the altered items
|
|
|
|
$args['labels'] = array(
|
|
|
|
'other' => $this->rc->gettext('shortacla','acl'),
|
|
|
|
);
|
|
|
|
$args['titles'] = array(
|
|
|
|
'other' => $this->rc->gettext('longaclother','acl'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for ACL permissions listing (acl_rights_supported hook)
|
|
|
|
*
|
|
|
|
* @param array $args Hash array with hook parameters
|
|
|
|
*
|
|
|
|
* @return array Hash array with modified hook parameters
|
|
|
|
*/
|
|
|
|
public function acl_rights_supported($args)
|
|
|
|
{
|
|
|
|
if ($args['folder']) {
|
|
|
|
list($type,) = $this->get_folder_type($args['folder']);
|
|
|
|
|
|
|
|
// we're dealing with a groupware folder here...
|
|
|
|
if ($type && $type !== 'mail') {
|
|
|
|
// remove some irrelevant (for groupware objects) rights
|
2016-06-10 05:14:46 -04:00
|
|
|
$args['rights'] = str_split(preg_replace('/[p]/', '', join('', $args['rights'])));
|
2015-03-12 14:55:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
|
|
|
|
2011-05-19 12:40:46 +02:00
|
|
|
/**
|
|
|
|
* Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
|
|
|
|
*
|
2012-05-14 13:04:24 +02:00
|
|
|
* @return boolean
|
2011-05-19 12:40:46 +02:00
|
|
|
*/
|
|
|
|
function metadata_support()
|
|
|
|
{
|
2012-01-23 10:16:30 +01:00
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
|
|
|
|
return $storage->get_capability('METADATA') ||
|
|
|
|
$storage->get_capability('ANNOTATEMORE') ||
|
|
|
|
$storage->get_capability('ANNOTATEMORE2');
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
|
|
|
|
*
|
|
|
|
* @param string $folder Folder name
|
|
|
|
*
|
|
|
|
* @return array Folder content-type
|
|
|
|
*/
|
|
|
|
function get_folder_type($folder)
|
|
|
|
{
|
2012-10-17 12:12:45 +02:00
|
|
|
return explode('.', (string)kolab_storage::folder_type($folder));
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets folder content-type.
|
|
|
|
*
|
|
|
|
* @param string $folder Folder name
|
|
|
|
* @param string $type Content type
|
|
|
|
*
|
|
|
|
* @return boolean True on success
|
|
|
|
*/
|
2012-10-26 13:44:57 +02:00
|
|
|
function set_folder_type($folder, $type = 'mail')
|
2011-05-19 12:40:46 +02:00
|
|
|
{
|
2012-10-17 11:46:26 +02:00
|
|
|
return kolab_storage::set_folder_type($folder, $type);
|
2011-05-19 12:40:46 +02:00
|
|
|
}
|
|
|
|
|
2011-07-07 15:50:50 +02:00
|
|
|
/**
|
|
|
|
* Returns the name of default folder
|
|
|
|
*
|
|
|
|
* @param string $type Folder type
|
|
|
|
*
|
|
|
|
* @return string Folder name
|
|
|
|
*/
|
|
|
|
function get_default_folder($type)
|
|
|
|
{
|
2013-07-09 15:24:01 +02:00
|
|
|
$folderdata = kolab_storage::folders_typedata();
|
2011-07-07 15:50:50 +02:00
|
|
|
|
|
|
|
if (!is_array($folderdata)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-10-27 18:24:04 +02:00
|
|
|
// get all folders of specified type
|
2012-10-25 15:20:33 +02:00
|
|
|
$folderdata = array_intersect($folderdata, array($type.'.default'));
|
2011-07-07 15:50:50 +02:00
|
|
|
|
2012-10-25 15:20:33 +02:00
|
|
|
return key($folderdata);
|
2011-07-07 15:50:50 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 15:28:13 +02:00
|
|
|
/**
|
|
|
|
* Returns CSS class name for specified folder type
|
|
|
|
*
|
|
|
|
* @param string $type Folder type
|
|
|
|
*
|
|
|
|
* @return string Class name
|
|
|
|
*/
|
|
|
|
static function folder_class_name($type)
|
|
|
|
{
|
|
|
|
list($ctype, $subtype) = explode('.', $type);
|
|
|
|
|
|
|
|
$class[] = 'type-' . ($ctype ? $ctype : 'mail');
|
|
|
|
|
2011-06-15 15:31:29 +02:00
|
|
|
if ($subtype)
|
|
|
|
$class[] = 'subtype-' . $subtype;
|
2011-06-15 15:28:13 +02:00
|
|
|
|
|
|
|
return implode(' ', $class);
|
|
|
|
}
|
2011-07-10 20:21:53 +02:00
|
|
|
|
2011-10-27 18:24:04 +02:00
|
|
|
/**
|
|
|
|
* Creates default folders if they doesn't exist
|
|
|
|
*/
|
2013-10-29 16:04:02 +01:00
|
|
|
private function create_default_folders(&$folders, $filter, $folderdata = null, $lsub = false)
|
2011-10-27 18:24:04 +02:00
|
|
|
{
|
2012-01-23 10:16:30 +01:00
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
$namespace = $storage->get_namespace();
|
2011-10-27 18:24:04 +02:00
|
|
|
$defaults = array();
|
2012-10-26 13:44:57 +02:00
|
|
|
$prefix = '';
|
2012-05-14 13:04:24 +02:00
|
|
|
|
2011-10-27 18:24:04 +02:00
|
|
|
// Find personal namespace prefix
|
|
|
|
if (is_array($namespace['personal']) && count($namespace['personal']) == 1) {
|
|
|
|
$prefix = $namespace['personal'][0][0];
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->load_config();
|
|
|
|
|
|
|
|
// get configured defaults
|
|
|
|
foreach ($this->types as $type) {
|
2014-09-24 17:08:29 +02:00
|
|
|
foreach ((array)$this->subtypes[$type] as $subtype) {
|
2011-10-27 18:24:04 +02:00
|
|
|
$opt_name = 'kolab_folders_' . $type . '_' . $subtype;
|
|
|
|
if ($folder = $this->rc->config->get($opt_name)) {
|
|
|
|
// convert configuration value to UTF7-IMAP charset
|
2012-12-07 11:03:33 +01:00
|
|
|
$folder = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP');
|
2011-10-27 18:24:04 +02:00
|
|
|
// and namespace prefix if needed
|
|
|
|
if ($prefix && strpos($folder, $prefix) === false && $folder != 'INBOX') {
|
|
|
|
$folder = $prefix . $folder;
|
|
|
|
}
|
|
|
|
$defaults[$type . '.' . $subtype] = $folder;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-26 13:44:57 +02:00
|
|
|
if (empty($defaults)) {
|
|
|
|
return;
|
|
|
|
}
|
2011-10-27 18:24:04 +02:00
|
|
|
|
2013-07-09 15:16:15 +02:00
|
|
|
if ($folderdata === null) {
|
2013-07-09 15:24:01 +02:00
|
|
|
$folderdata = kolab_storage::folders_typedata();
|
2013-07-09 15:16:15 +02:00
|
|
|
}
|
2011-10-27 18:24:04 +02:00
|
|
|
|
2013-07-09 15:16:15 +02:00
|
|
|
if (!is_array($folderdata)) {
|
|
|
|
return;
|
2012-10-26 13:44:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// find default folders
|
|
|
|
foreach ($defaults as $type => $foldername) {
|
2011-10-27 18:24:04 +02:00
|
|
|
// get all folders of specified type
|
2012-10-26 13:44:57 +02:00
|
|
|
$_folders = array_intersect($folderdata, array($type));
|
2011-10-27 18:24:04 +02:00
|
|
|
|
2012-10-26 13:44:57 +02:00
|
|
|
// default folder found
|
|
|
|
if (!empty($_folders)) {
|
|
|
|
continue;
|
2011-10-27 18:24:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
list($type1, $type2) = explode('.', $type);
|
2013-10-29 16:04:02 +01:00
|
|
|
|
|
|
|
$activate = in_array($type1, $this->act_types);
|
|
|
|
$exists = false;
|
|
|
|
$result = false;
|
|
|
|
|
|
|
|
// check if folder exists
|
|
|
|
if (!empty($folderdata[$foldername]) || $foldername == 'INBOX') {
|
|
|
|
$exists = true;
|
|
|
|
}
|
|
|
|
else if ((!$filter || $filter == $type1) && in_array($foldername, $folders)) {
|
|
|
|
// this assumes also that subscribed folder exists
|
|
|
|
$exists = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$exists = $storage->folder_exists($foldername);
|
|
|
|
}
|
2011-10-27 18:24:04 +02:00
|
|
|
|
|
|
|
// create folder
|
2013-10-29 16:04:02 +01:00
|
|
|
if (!$exists) {
|
|
|
|
$exists = $storage->create_folder($foldername);
|
2011-10-27 18:24:04 +02:00
|
|
|
}
|
|
|
|
|
2013-10-29 16:04:02 +01:00
|
|
|
// set type + subscribe + activate
|
|
|
|
if ($exists) {
|
|
|
|
if ($result = kolab_storage::set_folder_type($foldername, $type)) {
|
|
|
|
// check if folder is subscribed
|
|
|
|
if ((!$filter || $filter == $type1) && $lsub && in_array($foldername, $folders)) {
|
|
|
|
// already subscribed
|
|
|
|
$subscribed = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$subscribed = $storage->subscribe($foldername);
|
|
|
|
}
|
|
|
|
|
|
|
|
// activate folder
|
|
|
|
if ($activate) {
|
2013-11-18 10:21:21 +01:00
|
|
|
kolab_storage::folder_activate($foldername, true);
|
2013-10-29 16:04:02 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-10-27 18:24:04 +02:00
|
|
|
|
|
|
|
// add new folder to the result
|
2013-10-29 16:04:02 +01:00
|
|
|
if ($result && (!$filter || $filter == $type1) && (!$lsub || $subscribed)) {
|
2012-05-14 13:04:24 +02:00
|
|
|
$folders[] = $foldername;
|
2011-10-27 18:24:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-23 10:16:30 +01:00
|
|
|
|
2012-09-20 08:51:38 +02:00
|
|
|
/**
|
|
|
|
* Static getter for default folder of the given type
|
|
|
|
*
|
|
|
|
* @param string $type Folder type
|
2019-06-13 13:33:35 +00:00
|
|
|
*
|
2012-09-20 08:51:38 +02:00
|
|
|
* @return string Folder name
|
|
|
|
*/
|
|
|
|
public static function default_folder($type)
|
|
|
|
{
|
|
|
|
return self::$instance->get_default_folder($type);
|
|
|
|
}
|
2017-06-12 10:28:07 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get /shared/vendor/cmu/cyrus-imapd/expire value
|
|
|
|
*
|
|
|
|
* @param string $folder IMAP folder name
|
|
|
|
*
|
|
|
|
* @return int|false The annotation value or False if not supported
|
|
|
|
*/
|
|
|
|
private function get_expire_annotation($folder)
|
|
|
|
{
|
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
|
|
|
|
if ($storage->get_vendor() != 'cyrus') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strlen($folder)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$value = $storage->get_metadata($folder, $this->expire_annotation);
|
|
|
|
|
|
|
|
if (is_array($value)) {
|
|
|
|
return $value[$folder] ? intval($value[$folder][$this->expire_annotation]) : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add expiration time input to the form if supported
|
|
|
|
*/
|
|
|
|
private function add_expire_input(&$form, $folder, $type = null)
|
|
|
|
{
|
|
|
|
if (($expire = $this->get_expire_annotation($folder)) !== false) {
|
|
|
|
$post = trim(rcube_utils::get_input_value('_expire', rcube_utils::INPUT_POST));
|
|
|
|
$is_mail = empty($type) || preg_match('/^mail/i', $type);
|
2017-10-30 11:30:02 +01:00
|
|
|
$label = $this->gettext('xdays');
|
|
|
|
$input = new html_inputfield(array(
|
|
|
|
'id' => '_kolabexpire',
|
|
|
|
'name' => '_expire',
|
|
|
|
'size' => 3,
|
|
|
|
'disabled' => !$is_mail
|
|
|
|
));
|
2017-06-12 10:28:07 +00:00
|
|
|
|
|
|
|
if ($post && $is_mail) {
|
|
|
|
$expire = (int) $post;
|
|
|
|
}
|
|
|
|
|
2017-10-30 11:30:02 +01:00
|
|
|
if (strpos($label, '$') === 0) {
|
|
|
|
$label = str_replace('$x', '', $label);
|
2018-01-24 10:12:49 +01:00
|
|
|
$html = $input->show($expire ?: '')
|
|
|
|
. html::span('input-group-append', html::span('input-group-text', rcube::Q($label)));
|
2017-10-30 11:30:02 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
$label = str_replace('$x', '', $label);
|
2018-01-24 10:12:49 +01:00
|
|
|
$html = html::span('input-group-prepend', html::span('input-group-text', rcube::Q($label)))
|
|
|
|
. $input->show($expire ?: '');
|
2017-10-30 11:30:02 +01:00
|
|
|
}
|
|
|
|
|
2017-06-12 10:28:07 +00:00
|
|
|
$form['props']['fieldsets']['settings']['content']['kolabexpire'] = array(
|
|
|
|
'label' => $this->gettext('folderexpire'),
|
2017-10-30 11:30:02 +01:00
|
|
|
'value' => html::div('input-group', $html),
|
2017-06-12 10:28:07 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2019-06-13 13:33:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Handler for various folders list widgets (hooks)
|
|
|
|
*
|
|
|
|
* @param array $args Hash array with hook parameters
|
|
|
|
*
|
|
|
|
* @return array Hash array with modified hook parameters
|
|
|
|
*/
|
|
|
|
public function render_folderlist($args)
|
|
|
|
{
|
|
|
|
$storage = $this->rc->get_storage();
|
|
|
|
$ns_other = $storage->get_namespace('other');
|
|
|
|
$is_fl = $this->rc->plugins->is_processing('folders_list');
|
|
|
|
|
|
|
|
foreach ((array) $ns_other as $root) {
|
|
|
|
$delim = $root[1];
|
|
|
|
$prefix = rtrim($root[0], $delim);
|
|
|
|
$length = strlen($prefix);
|
|
|
|
|
|
|
|
if (!$length) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// folders_list hook mode
|
|
|
|
if ($is_fl) {
|
|
|
|
foreach ((array) $args['list'] as $folder_name => $folder) {
|
|
|
|
if (strpos($folder_name, $root[0]) === 0 && !substr_count($folder_name, $root[1], $length+1)) {
|
2019-06-20 12:53:36 +00:00
|
|
|
if ($name = kolab_storage::folder_id2user(substr($folder_name, $length+1), true)) {
|
2019-06-13 13:33:35 +00:00
|
|
|
$old = $args['list'][$folder_name]['display'];
|
|
|
|
$content = $args['list'][$folder_name]['content'];
|
|
|
|
|
|
|
|
$name = rcube::Q($name);
|
|
|
|
$content = str_replace(">$old<", ">$name<", $content);
|
|
|
|
|
|
|
|
$args['list'][$folder_name]['display'] = $name;
|
|
|
|
$args['list'][$folder_name]['content'] = $content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Re-sort the list
|
|
|
|
}
|
|
|
|
// render_* hooks mode
|
|
|
|
else if (!empty($args['list'][$prefix]) && !empty($args['list'][$prefix]['folders'])) {
|
|
|
|
$map = array();
|
|
|
|
foreach ($args['list'][$prefix]['folders'] as $folder_name => $folder) {
|
2019-06-20 12:53:36 +00:00
|
|
|
if ($name = kolab_storage::folder_id2user($folder_name, true)) {
|
2019-06-13 13:33:35 +00:00
|
|
|
$args['list'][$prefix]['folders'][$folder_name]['name'] = $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
$map[$folder_name] = $name ?: $args['list'][$prefix]['folders'][$folder_name]['name'];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-sort the list
|
|
|
|
uasort($map, 'strcoll');
|
|
|
|
$args['list'][$prefix]['folders'] = array_replace($map, $args['list'][$prefix]['folders']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $args;
|
|
|
|
}
|
2011-06-15 15:28:13 +02:00
|
|
|
}
|