Page MenuHomePhorge

No OneTemporary

Size
28 KB
Referenced Files
None
Subscribers
None
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

Mime Type
text/x-diff
Expires
Mon, Aug 17, 9:23 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1261638
Default Alt Text
(28 KB)

Event Timeline