Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F9785776
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/plugins/kolab_folders/kolab_folders.js b/plugins/kolab_folders/kolab_folders.js
index ac50543d..b9d92258 100644
--- a/plugins/kolab_folders/kolab_folders.js
+++ b/plugins/kolab_folders/kolab_folders.js
@@ -1,149 +1,125 @@
/**
* Client script for the Kolab folder management/listing extension
*
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (C) 2011, 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/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*/
window.rcmail && rcmail.env.action == 'folders' && rcmail.addEventListener('init', function() {
var filter = $(rcmail.gui_objects.foldersfilter),
optgroup = $('<optgroup>').attr('label', rcmail.gettext('kolab_folders.folderctype'));
// remove disabled namespaces
filter.children('option').each(function(i, opt) {
$.each(rcmail.env.skip_roots || [], function() {
if (opt.value == this) {
$(opt).remove();
}
});
});
// add type options to the filter
$.each(rcmail.env.foldertypes, function() {
optgroup.append($('<option>').attr('value', 'type-' + this).text(rcmail.gettext('kolab_folders.foldertype' + this)));
});
// overwrite default onchange handler
filter.attr('onchange', '')
.on('change', function() { return kolab_folders_filter(this.value); })
.append(optgroup);
});
window.rcmail && rcmail.env.action != 'folders' && $(document).ready(function() {
- // IE doesn't allow setting OPTION's display/visibility
- // We'll need to remove SELECT's options, see below
- if (bw.ie) {
- rcmail.env.subtype_html = $('#_subtype').html();
- }
-
// Add onchange handler for folder type SELECT, and call it on form init
$('#_ctype').change(function() {
var type = $(this).val(),
sub = $('#_subtype'),
- subtype = sub.val();
+ subtypes = rcmail.env.kolab_folder_subtypes[type] || {};
- // For IE we need to revert the whole SELECT to the original state
- if (bw.ie) {
- sub.html(rcmail.env.subtype_html).val(subtype);
- }
+ // reset subtype selector
+ sub.html('<option value=""></option>');
- // For non-mail folders we must hide mail-specific subtypes
- $('option', sub).each(function() {
- var opt = $(this), val = opt.val();
- if (val == '')
- return;
- // there's no mail.default
- if (val == 'default' && type != 'mail') {
- opt.show();
- return;
- };
-
- if (type == 'mail' && val != 'default')
- opt.show();
- else if (bw.ie)
- opt.remove();
- else
- opt.hide();
+ // append available subtypes for the given folder type
+ $.each(subtypes, function(val, label) {
+ $('<option>').attr('value', val).text(label).appendTo(sub);
});
// And re-set subtype
- if (type != 'mail' && subtype != '' && subtype != 'default') {
- sub.val('');
- }
- }).change();
+ sub.val(rcmail.env.kolab_folder_subtype);
+ });
});
function kolab_folders_filter(filter)
{
var type = filter.match(/^type-([a-z]+)$/) ? RegExp.$1 : null;
rcmail.subscription_list.reset_search();
if (!type) {
// clear type filter
if (rcmail.folder_filter_type) {
$('li', rcmail.subscription_list.container).removeData('filtered').show();
rcmail.folder_filter_type = null;
}
// apply namespace filter
rcmail.folder_filter(filter);
}
else {
rcmail.folder_filter_type = type;
rcmail.subscription_list.container.children('li').each(function() {
kolab_folder_filter_match(this, type);
});
}
return false;
}
function kolab_folder_filter_match(elem, type)
{
var found = 0, cl = elem.className || '',
$elem = $(elem),
children = $('ul', elem).children('li');
// subfolders...
children.each(function() {
found += kolab_folder_filter_match(this, type);
});
if (found || cl.match(new RegExp('type-' + type))
|| (type == 'mail' && !children.length && !cl.match(/(^| )type-([a-z]+)/))
) {
if (found || !$elem.is('.virtual')) {
found++;
}
}
if (found) {
$elem.removeData('filtered').show();
}
else {
$elem.data('filtered', true).hide();
}
return found;
}
diff --git a/plugins/kolab_folders/kolab_folders.php b/plugins/kolab_folders/kolab_folders.php
index 510388c7..fbffa345 100644
--- a/plugins/kolab_folders/kolab_folders.php
+++ b/plugins/kolab_folders/kolab_folders.php
@@ -1,621 +1,639 @@
<?php
/**
* Type-aware folder management/listing for Kolab
*
* @version @package_version@
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2011, 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_folders extends rcube_plugin
{
public $task = '?(?!login).*';
public $types = array('mail', 'event', 'journal', 'task', 'note', 'contact', 'configuration', 'file', 'freebusy');
- public $mail_types = array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail');
+ public $subtypes = array(
+ 'mail' => array('inbox', 'drafts', 'sentitems', 'outbox', 'wastebasket', 'junkemail'),
+ 'event' => array('default', 'confidential'),
+ 'task' => array('default', 'confidential'),
+ 'journal' => array('default'),
+ 'note' => array('default'),
+ 'contact' => array('default'),
+ 'configuration' => array('default'),
+ 'file' => array('default'),
+ 'freebusy' => array('default'),
+ );
public $act_types = array('event', 'task');
private $rc;
private static $instance;
/**
* Plugin initialization.
*/
function init()
{
self::$instance = $this;
$this->rc = rcube::get_instance();
// load required plugin
$this->require_plugin('libkolab');
// Folder listing hooks
$this->add_hook('storage_folders', array($this, 'mailboxes_list'));
// 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'));
$this->add_hook('folder_delete', array($this, 'folder_save'));
$this->add_hook('folder_rename', array($this, 'folder_save'));
$this->add_hook('folders_list', array($this, 'folders_list'));
// Special folders setting
$this->add_hook('preferences_save', array($this, 'prefs_save'));
}
/**
* Handler for mailboxes_list hook. Enables type-aware lists filtering.
*/
function mailboxes_list($args)
{
// infinite loop prevention
if ($this->is_processing) {
return $args;
}
if (!$this->metadata_support()) {
return $args;
}
$this->is_processing = true;
// get folders
$folders = kolab_storage::list_folders($args['root'], $args['name'], $args['filter'], $args['mode'] == 'LSUB', $folderdata);
$this->is_processing = false;
if (!is_array($folders)) {
return $args;
}
// Create default folders
if ($args['root'] == '' && $args['name'] = '*') {
$this->create_default_folders($folders, $args['filter'], $folderdata, $args['mode'] == 'LSUB');
}
$args['folders'] = $folders;
return $args;
}
/**
* Handler for folders_list hook. Add css classes to folder rows.
*/
function folders_list($args)
{
if (!$this->metadata_support()) {
return $args;
}
// 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);
}
$skip_namespace = $this->rc->config->get('kolab_skip_namespace');
$skip_roots = array();
if (!empty($skip_namespace)) {
$storage = $this->rc->get_storage();
foreach ((array)$skip_namespace as $ns) {
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);
// get folders types
$folderdata = kolab_storage::folders_typedata();
if (!is_array($folderdata)) {
return $args;
}
// Add type-based style for table rows
// See kolab_folders::folder_class_name()
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);
}
}
// 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];
if (!$type) {
$type = 'mail';
}
$class_name = self::folder_class_name($type);
$args['list'][$k]['class'] = trim($item['class'] . ' ' . $class_name);
}
}
return $args;
}
/**
* Handler for folder info/edit form (folder_form hook).
* Adds folder type selector.
*/
function folder_form($args)
{
if (!$this->metadata_support()) {
return $args;
}
// 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')),
);
return $args;
}
if ($args['options']['is_root']) {
return $args;
}
$mbox = strlen($args['name']) ? $args['name'] : $args['parent_name'];
if (isset($_POST['_ctype'])) {
$new_ctype = trim(get_input_value('_ctype', RCUBE_INPUT_POST));
$new_subtype = trim(get_input_value('_subtype', RCUBE_INPUT_POST));
}
// Get type of the folder or the parent
if (strlen($mbox)) {
list($ctype, $subtype) = $this->get_folder_type($mbox);
if (strlen($args['parent_name']) && $subtype == 'default')
$subtype = ''; // there can be only one
}
if (!$ctype) {
$ctype = 'mail';
}
$storage = $this->rc->get_storage();
// Don't allow changing type of shared folder, according to ACL
if (strlen($mbox)) {
$options = $storage->folder_info($mbox);
if ($options['namespace'] != 'personal' && !in_array('a', (array)$options['rights'])) {
if (in_array($ctype, $this->types)) {
$value = $this->gettext('foldertype'.$ctype);
}
else {
$value = $ctype;
}
if ($subtype) {
$value .= ' ('. ($subtype == 'default' ? $this->gettext('default') : $subtype) .')';
}
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
'label' => $this->gettext('folderctype'),
'value' => $value,
);
return $args;
}
}
// Add javascript script to the client
$this->include_script('kolab_folders.js');
// build type SELECT fields
$type_select = new html_select(array('name' => '_ctype', 'id' => '_ctype'));
$sub_select = new html_select(array('name' => '_subtype', 'id' => '_subtype'));
+ $sub_select->add('', '');
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);
}
- $sub_select->add('', '');
- $sub_select->add($this->gettext('default'), 'default');
- foreach ($this->mail_types as $type) {
- $sub_select->add($this->gettext($type), $type);
+ $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);
+ }
}
$args['form']['props']['fieldsets']['settings']['content']['foldertype'] = array(
'label' => $this->gettext('folderctype'),
'value' => $type_select->show(isset($new_ctype) ? $new_ctype : $ctype)
. $sub_select->show(isset($new_subtype) ? $new_subtype : $subtype),
);
+ $this->rc->output->set_env('kolab_folder_subtypes', $sub_types);
+ $this->rc->output->set_env('kolab_folder_subtype', isset($new_subtype) ? $new_subtype : $subtype);
+
return $args;
}
/**
* Handler for folder update/create action (folder_update/folder_create hook).
*/
function folder_save($args)
{
// Folder actions from folders list
if (empty($args['record'])) {
return $args;
}
// Folder create/update with form
$ctype = trim(get_input_value('_ctype', RCUBE_INPUT_POST));
$subtype = trim(get_input_value('_subtype', RCUBE_INPUT_POST));
$mbox = $args['record']['name'];
$old_mbox = $args['record']['oldname'];
$subscribe = $args['record']['subscribe'];
if (empty($ctype)) {
return $args;
}
// 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
if ($subtype == 'default') {
$default = $this->get_default_folder($ctype);
if ($default !== null && $old_mbox != $default) {
$args['result'] = false;
$args['message'] = $this->gettext('defaultfolderexists');
return $args;
}
}
// Subtype sanity-checks
- else if ($subtype && ($ctype != 'mail' || !in_array($subtype, $this->mail_types))) {
+ else if ($subtype && (!($subtypes = $this->subtypes[$ctype]) || !in_array($subtype, $subtypes))) {
$subtype = '';
}
$ctype .= $subtype ? '.'.$subtype : '';
$storage = $this->rc->get_storage();
// Create folder
if (!strlen($old_mbox)) {
// By default don't subscribe to non-mail folders
if ($subscribe)
$subscribe = (bool) preg_match('/^mail/', $ctype);
$result = $storage->create_folder($mbox, $subscribe);
// Set folder type
if ($result) {
$this->set_folder_type($mbox, $ctype);
}
}
// Rename folder
else {
if ($old_mbox != $mbox) {
$result = $storage->rename_folder($old_mbox, $mbox);
}
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);
}
}
}
$args['record']['class'] = self::folder_class_name($ctype);
$args['record']['subscribe'] = $subscribe;
$args['result'] = $result;
return $args;
}
/**
* 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;
}
$dont_override = (array) $this->rc->config->get('dont_override', array());
// 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);
if (!strlen($new) || $new === $old || in_array($opt_name, $dont_override)) {
unset($opts[$opt_name]);
}
}
if (empty($opts)) {
return $args;
}
$folderdata = kolab_storage::folders_typedata();
if (!is_array($folderdata)) {
return $args;
}
foreach ($opts as $opt_name => $type) {
$foldername = $args['prefs'][$opt_name];
// get all folders of specified type
$folders = array_intersect($folderdata, array($type));
// folder already annotated with specified type
if (!empty($folders[$foldername])) {
continue;
}
// set type to the new folder
$this->set_folder_type($foldername, $type);
// unset old folder(s) type annotation
list($maintype, $subtype) = explode('.', $type);
foreach (array_keys($folders) as $folder) {
$this->set_folder_type($folder, $maintype);
}
}
return $args;
}
/**
* Checks if IMAP server supports any of METADATA, ANNOTATEMORE, ANNOTATEMORE2
*
* @return boolean
*/
function metadata_support()
{
$storage = $this->rc->get_storage();
return $storage->get_capability('METADATA') ||
$storage->get_capability('ANNOTATEMORE') ||
$storage->get_capability('ANNOTATEMORE2');
}
/**
* 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)
{
return explode('.', (string)kolab_storage::folder_type($folder));
}
/**
* Sets folder content-type.
*
* @param string $folder Folder name
* @param string $type Content type
*
* @return boolean True on success
*/
function set_folder_type($folder, $type = 'mail')
{
return kolab_storage::set_folder_type($folder, $type);
}
/**
* Returns the name of default folder
*
* @param string $type Folder type
*
* @return string Folder name
*/
function get_default_folder($type)
{
$folderdata = kolab_storage::folders_typedata();
if (!is_array($folderdata)) {
return null;
}
// get all folders of specified type
$folderdata = array_intersect($folderdata, array($type.'.default'));
return key($folderdata);
}
/**
* 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');
if ($subtype)
$class[] = 'subtype-' . $subtype;
return implode(' ', $class);
}
/**
* Creates default folders if they doesn't exist
*/
private function create_default_folders(&$folders, $filter, $folderdata = null, $lsub = false)
{
$storage = $this->rc->get_storage();
$namespace = $storage->get_namespace();
$defaults = array();
$prefix = '';
// 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) {
$subtypes = $type == 'mail' ? $this->mail_types : array('default');
foreach ($subtypes as $subtype) {
$opt_name = 'kolab_folders_' . $type . '_' . $subtype;
if ($folder = $this->rc->config->get($opt_name)) {
// convert configuration value to UTF7-IMAP charset
$folder = rcube_charset::convert($folder, RCUBE_CHARSET, 'UTF7-IMAP');
// and namespace prefix if needed
if ($prefix && strpos($folder, $prefix) === false && $folder != 'INBOX') {
$folder = $prefix . $folder;
}
$defaults[$type . '.' . $subtype] = $folder;
}
}
}
if (empty($defaults)) {
return;
}
if ($folderdata === null) {
$folderdata = kolab_storage::folders_typedata();
}
if (!is_array($folderdata)) {
return;
}
// find default folders
foreach ($defaults as $type => $foldername) {
// get all folders of specified type
$_folders = array_intersect($folderdata, array($type));
// default folder found
if (!empty($_folders)) {
continue;
}
list($type1, $type2) = explode('.', $type);
$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);
}
// create folder
if (!$exists) {
$exists = $storage->create_folder($foldername);
}
// 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) {
kolab_storage::folder_activate($foldername, true);
}
}
}
// add new folder to the result
if ($result && (!$filter || $filter == $type1) && (!$lsub || $subscribed)) {
$folders[] = $foldername;
}
}
}
/**
* Static getter for default folder of the given type
*
* @param string $type Folder type
* @return string Folder name
*/
public static function default_folder($type)
{
return self::$instance->get_default_folder($type);
}
}
diff --git a/plugins/kolab_folders/localization/en_US.inc b/plugins/kolab_folders/localization/en_US.inc
index 0d8d86c1..0910d9d8 100644
--- a/plugins/kolab_folders/localization/en_US.inc
+++ b/plugins/kolab_folders/localization/en_US.inc
@@ -1,34 +1,35 @@
<?php
/**
* Localizations for the Kolab Folders plugin
*
* Copyright (C) 2014, Kolab Systems AG
*
* For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_folders/
*/
$labels = array();
$labels['folderctype'] = 'Content type';
$labels['foldertypemail'] = 'Mail';
$labels['foldertypeevent'] = 'Calendar';
$labels['foldertypejournal'] = 'Journal';
$labels['foldertypetask'] = 'Tasks';
$labels['foldertypenote'] = 'Notes';
$labels['foldertypecontact'] = 'Contacts';
$labels['foldertypeconfiguration'] = 'Configuration';
$labels['foldertypefile'] = 'Files';
$labels['foldertypefreebusy'] = 'Free-Busy';
$labels['default'] = 'Default';
$labels['inbox'] = 'Inbox';
$labels['drafts'] = 'Drafts';
$labels['sentitems'] = 'Sent';
$labels['outbox'] = 'Outbox';
$labels['wastebasket'] = 'Trash';
$labels['junkemail'] = 'Junk';
+$labels['confidential'] = 'Confidential';
$messages['defaultfolderexists'] = 'There is already default folder of specified type';
?>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Aug 17, 9:23 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1261638
Default Alt Text
(28 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment