Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F223001
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/plugins/acl/acl.js b/plugins/acl/acl.js
index acea60a4c..d82725c8b 100644
--- a/plugins/acl/acl.js
+++ b/plugins/acl/acl.js
@@ -1,380 +1,388 @@
/**
* ACL plugin script
*
* @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*/
if (window.rcmail) {
rcmail.addEventListener('init', function() {
if (rcmail.gui_objects.acltable) {
rcmail.acl_list_init();
// enable autocomplete on user input
if (rcmail.env.acl_users_source) {
var inst = rcmail.is_framed() ? parent.rcmail : rcmail;
inst.init_address_input_events($('#acluser'), {action:'settings/plugin.acl-autocomplete'});
// pass config settings and localized texts to autocomplete context
inst.set_env({ autocomplete_max:rcmail.env.autocomplete_max, autocomplete_min_length:rcmail.env.autocomplete_min_length });
inst.add_label('autocompletechars', rcmail.labels.autocompletechars);
inst.add_label('autocompletemore', rcmail.labels.autocompletemore);
// fix inserted value
inst.addEventListener('autocomplete_insert', function(e) {
if (e.field.id != 'acluser')
return;
var value = e.insert;
// get UID from the entry value
if (value.match(/\s*\(([^)]+)\)[, ]*$/))
value = RegExp.$1;
e.field.value = value;
});
}
}
rcmail.enable_command('acl-create', 'acl-save', 'acl-cancel', 'acl-mode-switch', true);
rcmail.enable_command('acl-delete', 'acl-edit', false);
if (rcmail.env.acl_advanced)
$('#acl-switch').addClass('selected');
});
}
// Display new-entry form
rcube_webmail.prototype.acl_create = function()
{
this.acl_init_form();
}
// Display ACL edit form
rcube_webmail.prototype.acl_edit = function()
{
// @TODO: multi-row edition
var id = this.acl_list.get_single_selection();
if (id)
this.acl_init_form(id);
}
// ACL entry delete
rcube_webmail.prototype.acl_delete = function()
{
var users = this.acl_get_usernames();
if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) {
this.http_request('settings/plugin.acl', '_act=delete&_user='+urlencode(users.join(','))
+ '&_mbox='+urlencode(this.env.mailbox),
this.set_busy(true, 'acl.deleting'));
}
}
// Save ACL data
rcube_webmail.prototype.acl_save = function()
{
var user = $('#acluser', this.acl_form).val(), rights = '', type;
$((this.env.acl_advanced ? '#advancedrights :checkbox' : '#simplerights :checkbox'), this.acl_form).map(function() {
if (this.checked)
rights += this.value;
});
if (type = $('input:checked[name=usertype]', this.acl_form).val()) {
if (type != 'user')
user = type;
}
if (!user) {
alert(this.get_label('acl.nouser'));
return;
}
if (!rights) {
alert(this.get_label('acl.norights'));
return;
}
this.http_request('settings/plugin.acl', '_act=save'
+ '&_user='+urlencode(user)
+ '&_acl=' +rights
+ '&_mbox='+urlencode(this.env.mailbox)
+ (this.acl_id ? '&_old='+this.acl_id : ''),
this.set_busy(true, 'acl.saving'));
}
// Cancel/Hide form
rcube_webmail.prototype.acl_cancel = function()
{
this.ksearch_blur();
this.acl_popup.dialog('close');
}
// Update data after save (and hide form)
rcube_webmail.prototype.acl_update = function(o)
{
// delete old row
if (o.old)
this.acl_remove_row(o.old);
// make sure the same ID doesn't exist
else if (this.env.acl[o.id])
this.acl_remove_row(o.id);
// add new row
this.acl_add_row(o, true);
// hide autocomplete popup
this.ksearch_blur();
// hide form
this.acl_popup.dialog('close');
}
// Switch table display mode
rcube_webmail.prototype.acl_mode_switch = function(elem)
{
this.env.acl_advanced = !this.env.acl_advanced;
this.enable_command('acl-delete', 'acl-edit', false);
this.http_request('settings/plugin.acl', '_act=list'
+ '&_mode='+(this.env.acl_advanced ? 'advanced' : 'simple')
+ '&_mbox='+urlencode(this.env.mailbox),
this.set_busy(true, 'loading'));
}
// ACL table initialization
rcube_webmail.prototype.acl_list_init = function()
{
var method = this.env.acl_advanced ? 'addClass' : 'removeClass';
+
$('#acl-switch')[method]('selected');
$(this.gui_objects.acltable)[method]('advanced');
this.acl_list = new rcube_list_widget(this.gui_objects.acltable,
- {multiselect:true, draggable:false, keyboard:true, toggleselect:true});
- this.acl_list.addEventListener('select', function(o) { rcmail.acl_list_select(o); });
- this.acl_list.addEventListener('dblclick', function(o) { rcmail.acl_list_dblclick(o); });
- this.acl_list.addEventListener('keypress', function(o) { rcmail.acl_list_keypress(o); });
- this.acl_list.init();
+ {multiselect: true, draggable: false, keyboard: true});
+ this.acl_list.addEventListener('select', function(o) { rcmail.acl_list_select(o); })
+ .addEventListener('dblclick', function(o) { rcmail.acl_list_dblclick(o); })
+ .addEventListener('keypress', function(o) { rcmail.acl_list_keypress(o); })
+ .init();
}
// ACL table row selection handler
rcube_webmail.prototype.acl_list_select = function(list)
{
rcmail.enable_command('acl-delete', list.selection.length > 0);
rcmail.enable_command('acl-edit', list.selection.length == 1);
list.focus();
}
// ACL table double-click handler
rcube_webmail.prototype.acl_list_dblclick = function(list)
{
this.acl_edit();
}
// ACL table keypress handler
rcube_webmail.prototype.acl_list_keypress = function(list)
{
if (list.key_pressed == list.ENTER_KEY)
this.command('acl-edit');
else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY)
if (!this.acl_form || !this.acl_form.is(':visible'))
this.command('acl-delete');
}
// Reloads ACL table
rcube_webmail.prototype.acl_list_update = function(html)
{
$(this.gui_objects.acltable).html(html);
this.acl_list_init();
}
// Returns names of users in selected rows
rcube_webmail.prototype.acl_get_usernames = function()
{
var users = [], n, len, cell, row,
list = this.acl_list,
selection = list.get_selection();
for (n=0, len=selection.length; n<len; n++) {
if (this.env.acl_specials.length && $.inArray(selection[n], this.env.acl_specials) >= 0) {
users.push(selection[n]);
}
else if (row = list.rows[selection[n]]) {
cell = $('td.user', row.obj);
if (cell.length == 1)
users.push(cell.text());
}
}
return users;
}
// Removes ACL table row
rcube_webmail.prototype.acl_remove_row = function(id)
{
var list = this.acl_list;
list.remove_row(id);
list.clear_selection();
// we don't need it anymore (remove id conflict)
$('#rcmrow'+id).remove();
this.env.acl[id] = null;
this.enable_command('acl-delete', list.selection.length > 0);
this.enable_command('acl-edit', list.selection.length == 1);
}
// Adds ACL table row
rcube_webmail.prototype.acl_add_row = function(o, sel)
{
var n, len, ids = [], spec = [], id = o.id, list = this.acl_list,
items = this.env.acl_advanced ? [] : this.env.acl_items,
table = this.gui_objects.acltable,
row = $('thead > tr', table).clone();
// Update new row
- $('td', row).map(function() {
- var r, cl = this.className.replace(/^acl/, '');
+ $('th', row).map(function() {
+ var td = $('<td>'),
+ title = $(this).attr('title'),
+ cl = this.className.replace(/^acl/, '');
+
+ if (title)
+ td.attr('title', title);
if (items && items[cl])
cl = items[cl];
if (cl == 'user')
- $(this).text(o.username);
+ td.addClass(cl).append($('<a>').text(o.username));
else
- $(this).addClass(rcmail.acl_class(o.acl, cl)).text('');
+ td.addClass(this.className + ' ' + rcmail.acl_class(o.acl, cl)).text('');
+
+ $(this).replaceWith(td);
});
row.attr('id', 'rcmrow'+id);
row = row.get(0);
this.env.acl[id] = o.acl;
// sorting... (create an array of user identifiers, then sort it)
for (n in this.env.acl) {
if (this.env.acl[n]) {
if (this.env.acl_specials.length && $.inArray(n, this.env.acl_specials) >= 0)
spec.push(n);
else
ids.push(n);
}
}
ids.sort();
// specials on the top
ids = spec.concat(ids);
// find current id
for (n=0, len=ids.length; n<len; n++)
if (ids[n] == id)
break;
// add row
if (n && n < len) {
$('#rcmrow'+ids[n-1]).after(row);
list.init_row(row);
list.rowcount++;
}
else
list.insert_row(row);
if (sel)
list.select_row(o.id);
}
// Initializes and shows ACL create/edit form
rcube_webmail.prototype.acl_init_form = function(id)
{
var ul, row, td, val = '', type = 'user', li_elements, body = $('body'),
adv_ul = $('#advancedrights'), sim_ul = $('#simplerights'),
- name_input = $('#acluser');
+ name_input = $('#acluser'), type_list = $('#usertype');
if (!this.acl_form) {
- var fn = function () { $('input[value=user]').prop('checked', true); };
+ var fn = function () { $('input[value="user"]').prop('checked', true); };
name_input.click(fn).keypress(fn);
}
this.acl_form = $('#aclform');
// Hide unused items
if (this.env.acl_advanced) {
adv_ul.show();
sim_ul.hide();
ul = adv_ul;
}
else {
sim_ul.show();
adv_ul.hide();
ul = sim_ul;
}
// initialize form fields
li_elements = $(':checkbox', ul);
li_elements.attr('checked', false);
if (id && (row = this.acl_list.rows[id])) {
row = row.obj;
li_elements.map(function() {
td = $('td.'+this.id, row);
if (td.length && td.hasClass('enabled'))
this.checked = true;
});
if (!this.env.acl_specials.length || $.inArray(id, this.env.acl_specials) < 0)
val = $('td.user', row).text();
else
type = id;
}
// mark read (lrs) rights by default
else {
li_elements.filter(function() { return this.id.match(/^acl([lrs]|read)$/); }).prop('checked', true);
}
name_input.val(val);
$('input[value='+type+']').prop('checked', true);
this.acl_id = id;
- var me = this, inst = window.rcmail, body = document.body;
- var buttons = {};
- buttons[rcmail.gettext('save')] = function(e) { inst.command('acl-save'); };
- buttons[rcmail.gettext('cancel')] = function(e) { inst.command('acl-cancel'); };
+ var buttons = {}, me = this, body = document.body;
+
+ buttons[this.gettext('save')] = function(e) { me.command('acl-save'); };
+ buttons[this.gettext('cancel')] = function(e) { me.command('acl-cancel'); };
// display it as popup
- this.acl_popup = rcmail.show_popup_dialog(
+ this.acl_popup = this.show_popup_dialog(
'<div style="width:480px;height:280px"> </div>',
- id ? rcmail.gettext('acl.editperms') : rcmail.gettext('acl.newuser'),
+ id ? this.gettext('acl.editperms') : this.gettext('acl.newuser'),
buttons,
{
modal: true,
- closeOnEscape: false,
+ closeOnEscape: true,
close: function(e, ui) {
- (rcmail.is_framed() ? parent.rcmail : rcmail).ksearch_hide();
+ (me.is_framed() ? parent.rcmail : me).ksearch_hide();
me.acl_form.appendTo(body).hide();
$(this).remove();
+ window.focus(); // focus iframe
}
}
);
this.acl_form.appendTo(this.acl_popup).show();
if (type == 'user')
name_input.focus();
-
- // unfocus the list, make backspace key in name input field working
- this.acl_list.blur();
+ else
+ $('input:checked', type_list).focus();
}
// Returns class name according to ACL comparision result
rcube_webmail.prototype.acl_class = function(acl1, acl2)
{
var i, len, found = 0;
acl1 = String(acl1);
acl2 = String(acl2);
for (i=0, len=acl2.length; i<len; i++)
if (acl1.indexOf(acl2[i]) > -1)
found++;
if (found == len)
return 'enabled';
else if (found)
return 'partial';
return 'disabled';
}
diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php
index d7e50f978..95d4eda62 100644
--- a/plugins/acl/acl.php
+++ b/plugins/acl/acl.php
@@ -1,731 +1,731 @@
<?php
/**
* Folders Access Control Lists Management (RFC4314, RFC2086)
*
* @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*
*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
class acl extends rcube_plugin
{
public $task = 'settings|addressbook|calendar';
private $rc;
private $supported = null;
private $mbox;
private $ldap;
private $specials = array('anyone', 'anonymous');
/**
* Plugin initialization
*/
function init()
{
$this->rc = rcmail::get_instance();
// Register hooks
$this->add_hook('folder_form', array($this, 'folder_form'));
// kolab_addressbook plugin
$this->add_hook('addressbook_form', array($this, 'folder_form'));
$this->add_hook('calendar_form_kolab', array($this, 'folder_form'));
// Plugin actions
$this->register_action('plugin.acl', array($this, 'acl_actions'));
$this->register_action('plugin.acl-autocomplete', array($this, 'acl_autocomplete'));
}
/**
* Handler for plugin actions (AJAX)
*/
function acl_actions()
{
$action = trim(rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC));
// Connect to IMAP
$this->rc->storage_init();
// Load localization and configuration
$this->add_texts('localization/');
$this->load_config();
if ($action == 'save') {
$this->action_save();
}
else if ($action == 'delete') {
$this->action_delete();
}
else if ($action == 'list') {
$this->action_list();
}
// Only AJAX actions
$this->rc->output->send();
}
/**
* Handler for user login autocomplete request
*/
function acl_autocomplete()
{
$this->load_config();
$search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true);
$reqid = rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC);
$users = array();
if ($this->init_ldap()) {
$max = (int) $this->rc->config->get('autocomplete_max', 15);
$mode = (int) $this->rc->config->get('addressbook_search_mode');
$this->ldap->set_pagesize($max);
$result = $this->ldap->search('*', $search, $mode);
foreach ($result->records as $record) {
$user = $record['uid'];
if (is_array($user)) {
$user = array_filter($user);
$user = $user[0];
}
if ($user) {
if ($record['name'])
$user = $record['name'] . ' (' . $user . ')';
$users[] = $user;
}
}
}
sort($users, SORT_LOCALE_STRING);
$this->rc->output->command('ksearch_query_results', $users, $search, $reqid);
$this->rc->output->send();
}
/**
* Handler for 'folder_form' hook
*
* @param array $args Hook arguments array (form data)
*
* @return array Hook arguments array
*/
function folder_form($args)
{
$mbox_imap = $args['options']['name'];
$myrights = $args['options']['rights'];
// Edited folder name (empty in create-folder mode)
if (!strlen($mbox_imap)) {
return $args;
}
/*
// Do nothing on protected folders (?)
if ($args['options']['protected']) {
return $args;
}
*/
// Get MYRIGHTS
if (empty($myrights)) {
return $args;
}
// Load localization and include scripts
$this->load_config();
$this->specials = $this->rc->config->get('acl_specials', $this->specials);
$this->add_texts('localization/', array('deleteconfirm', 'norights',
'nouser', 'deleting', 'saving', 'newuser', 'editperms'));
$this->rc->output->add_label('save', 'cancel');
$this->include_script('acl.js');
$this->rc->output->include_script('list.js');
$this->include_stylesheet($this->local_skin_path().'/acl.css');
// add Info fieldset if it doesn't exist
if (!isset($args['form']['props']['fieldsets']['info']))
$args['form']['props']['fieldsets']['info'] = array(
'name' => $this->rc->gettext('info'),
'content' => array());
// Display folder rights to 'Info' fieldset
$args['form']['props']['fieldsets']['info']['content']['myrights'] = array(
'label' => rcube::Q($this->gettext('myrights')),
'value' => $this->acl2text($myrights)
);
// Return if not folder admin
if (!in_array('a', $myrights)) {
return $args;
}
// The 'Sharing' tab
$this->mbox = $mbox_imap;
$this->rc->output->set_env('acl_users_source', (bool) $this->rc->config->get('acl_users_source'));
$this->rc->output->set_env('mailbox', $mbox_imap);
$this->rc->output->add_handlers(array(
'acltable' => array($this, 'templ_table'),
'acluser' => array($this, 'templ_user'),
'aclrights' => array($this, 'templ_rights'),
));
$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');
$args['form']['sharing'] = array(
'name' => rcube::Q($this->gettext('sharing')),
'content' => $this->rc->output->parse('acl.table', false, false),
);
return $args;
}
/**
* Creates ACL rights table
*
* @param array $attrib Template object attributes
*
* @return string HTML Content
*/
function templ_table($attrib)
{
if (empty($attrib['id']))
$attrib['id'] = 'acl-table';
$out = $this->list_rights($attrib);
$this->rc->output->add_gui_object('acltable', $attrib['id']);
return $out;
}
/**
* Creates ACL rights form (rights list part)
*
* @param array $attrib Template object attributes
*
* @return string HTML Content
*/
function templ_rights($attrib)
{
// Get supported rights
$supported = $this->rights_supported();
// depending on server capability either use 'te' or 'd' for deleting msgs
$deleteright = implode(array_intersect(str_split('ted'), $supported));
$out = '';
$ul = '';
$input = new html_checkbox();
// Advanced rights
$attrib['id'] = 'advancedrights';
foreach ($supported as $key => $val) {
$id = "acl$val";
$ul .= html::tag('li', null,
$input->show('', array(
'name' => "acl[$val]", 'value' => $val, 'id' => $id))
. html::label(array('for' => $id, 'title' => $this->gettext('longacl'.$val)),
$this->gettext('acl'.$val)));
}
$out = html::tag('ul', $attrib, $ul, html::$common_attrib);
// Simple rights
$ul = '';
$attrib['id'] = 'simplerights';
$items = array(
'read' => 'lrs',
'write' => 'wi',
'delete' => $deleteright,
'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)),
);
foreach ($items as $key => $val) {
$id = "acl$key";
$ul .= html::tag('li', null,
$input->show('', array(
'name' => "acl[$val]", 'value' => $val, 'id' => $id))
. html::label(array('for' => $id, 'title' => $this->gettext('longacl'.$key)),
$this->gettext('acl'.$key)));
}
$out .= "\n" . html::tag('ul', $attrib, $ul, html::$common_attrib);
$this->rc->output->set_env('acl_items', $items);
return $out;
}
/**
* Creates ACL rights form (user part)
*
* @param array $attrib Template object attributes
*
* @return string HTML Content
*/
function templ_user($attrib)
{
// Create username input
$attrib['name'] = 'acluser';
$textfield = new html_inputfield($attrib);
- $fields['user'] = html::label(array('for' => 'iduser'), $this->gettext('username'))
+ $fields['user'] = html::label(array('for' => $attrib['id']), $this->gettext('username'))
. ' ' . $textfield->show();
// Add special entries
if (!empty($this->specials)) {
foreach ($this->specials as $key) {
$fields[$key] = html::label(array('for' => 'id'.$key), $this->gettext($key));
}
}
$this->rc->output->set_env('acl_specials', $this->specials);
// Create list with radio buttons
if (count($fields) > 1) {
$ul = '';
$radio = new html_radiobutton(array('name' => 'usertype'));
foreach ($fields as $key => $val) {
$ul .= html::tag('li', null, $radio->show($key == 'user' ? 'user' : '',
array('value' => $key, 'id' => 'id'.$key))
. $val);
}
$out = html::tag('ul', array('id' => 'usertype', 'class' => $attrib['class']), $ul, html::$common_attrib);
}
// Display text input alone
else {
$out = $fields['user'];
}
return $out;
}
/**
* Creates ACL rights table
*
* @param array $attrib Template object attributes
*
* @return string HTML Content
*/
private function list_rights($attrib=array())
{
// Get ACL for the folder
$acl = $this->rc->storage->get_acl($this->mbox);
if (!is_array($acl)) {
$acl = array();
}
// Keep special entries (anyone/anonymous) on top of the list
if (!empty($this->specials) && !empty($acl)) {
foreach ($this->specials as $key) {
if (isset($acl[$key])) {
$acl_special[$key] = $acl[$key];
unset($acl[$key]);
}
}
}
// Sort the list by username
uksort($acl, 'strnatcasecmp');
if (!empty($acl_special)) {
$acl = array_merge($acl_special, $acl);
}
// Get supported rights and build column names
$supported = $this->rights_supported();
// depending on server capability either use 'te' or 'd' for deleting msgs
$deleteright = implode(array_intersect(str_split('ted'), $supported));
// Use advanced or simple (grouped) rights
$advanced = $this->rc->config->get('acl_advanced_mode');
if ($advanced) {
$items = array();
foreach ($supported as $sup) {
$items[$sup] = $sup;
}
}
else {
$items = array(
'read' => 'lrs',
'write' => 'wi',
'delete' => $deleteright,
'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)),
);
}
// Create the table
$attrib['noheader'] = true;
$table = new html_table($attrib);
// Create table header
$table->add_header('user', $this->gettext('identifier'));
foreach (array_keys($items) as $key) {
$label = $this->gettext('shortacl'.$key);
$table->add_header(array('class' => 'acl'.$key, 'title' => $label), $label);
}
$js_table = array();
foreach ($acl as $user => $rights) {
if ($this->rc->storage->conn->user == $user) {
continue;
}
// filter out virtual rights (c or d) the server may return
$userrights = array_intersect($rights, $supported);
$userid = rcube_utils::html_identifier($user);
if (!empty($this->specials) && in_array($user, $this->specials)) {
$user = $this->gettext($user);
}
$table->add_row(array('id' => 'rcmrow'.$userid));
- $table->add('user', rcube::Q($user));
+ $table->add('user', html::a(array('id' => 'rcmlinkrow'.$userid), rcube::Q($user)));
foreach ($items as $key => $right) {
$in = $this->acl_compare($userrights, $right);
switch ($in) {
case 2: $class = 'enabled'; break;
case 1: $class = 'partial'; break;
default: $class = 'disabled'; break;
}
$table->add('acl' . $key . ' ' . $class, '');
}
$js_table[$userid] = implode($userrights);
}
$this->rc->output->set_env('acl', $js_table);
$this->rc->output->set_env('acl_advanced', $advanced);
$out = $table->show();
return $out;
}
/**
* Handler for ACL update/create action
*/
private function action_save()
{
$mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP
$user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC));
$acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_GPC));
$oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_GPC));
$acl = array_intersect(str_split($acl), $this->rights_supported());
$users = $oldid ? array($user) : explode(',', $user);
$result = 0;
foreach ($users as $user) {
$user = trim($user);
if (!empty($this->specials) && in_array($user, $this->specials)) {
$username = $this->gettext($user);
}
else if (!empty($user)) {
if (!strpos($user, '@') && ($realm = $this->get_realm())) {
$user .= '@' . rcube_utils::idn_to_ascii(preg_replace('/^@/', '', $realm));
}
$username = $user;
}
if (!$acl || !$user || !strlen($mbox)) {
continue;
}
$user = $this->mod_login($user);
$username = $this->mod_login($username);
if ($user != $_SESSION['username'] && $username != $_SESSION['username']) {
if ($this->rc->storage->set_acl($mbox, $user, $acl)) {
$ret = array('id' => rcube_utils::html_identifier($user),
'username' => $username, 'acl' => implode($acl), 'old' => $oldid);
$this->rc->output->command('acl_update', $ret);
$result++;
}
}
}
if ($result) {
$this->rc->output->show_message($oldid ? 'acl.updatesuccess' : 'acl.createsuccess', 'confirmation');
}
else {
$this->rc->output->show_message($oldid ? 'acl.updateerror' : 'acl.createerror', 'error');
}
}
/**
* Handler for ACL delete action
*/
private function action_delete()
{
$mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); //UTF7-IMAP
$user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC));
$user = explode(',', $user);
foreach ($user as $u) {
$u = trim($u);
if ($this->rc->storage->delete_acl($mbox, $u)) {
$this->rc->output->command('acl_remove_row', rcube_utils::html_identifier($u));
}
else {
$error = true;
}
}
if (!$error) {
$this->rc->output->show_message('acl.deletesuccess', 'confirmation');
}
else {
$this->rc->output->show_message('acl.deleteerror', 'error');
}
}
/**
* Handler for ACL list update action (with display mode change)
*/
private function action_list()
{
if (in_array('acl_advanced_mode', (array)$this->rc->config->get('dont_override'))) {
return;
}
$this->mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP
$advanced = trim(rcube_utils::get_input_value('_mode', rcube_utils::INPUT_GPC));
$advanced = $advanced == 'advanced' ? true : false;
// Save state in user preferences
$this->rc->user->save_prefs(array('acl_advanced_mode' => $advanced));
$out = $this->list_rights();
$out = preg_replace(array('/^<table[^>]+>/', '/<\/table>$/'), '', $out);
$this->rc->output->command('acl_list_update', $out);
}
/**
* Creates <UL> list with descriptive access rights
*
* @param array $rights MYRIGHTS result
*
* @return string HTML content
*/
function acl2text($rights)
{
if (empty($rights)) {
return '';
}
$supported = $this->rights_supported();
$list = array();
$attrib = array(
'name' => 'rcmyrights',
'style' => 'margin:0; padding:0 15px;',
);
foreach ($supported as $right) {
if (in_array($right, $rights)) {
$list[] = html::tag('li', null, rcube::Q($this->gettext('acl' . $right)));
}
}
if (count($list) == count($supported))
return rcube::Q($this->gettext('aclfull'));
return html::tag('ul', $attrib, implode("\n", $list));
}
/**
* Compares two ACLs (according to supported rights)
*
* @param array $acl1 ACL rights array (or string)
* @param array $acl2 ACL rights array (or string)
*
* @param int Comparision result, 2 - full match, 1 - partial match, 0 - no match
*/
function acl_compare($acl1, $acl2)
{
if (!is_array($acl1)) $acl1 = str_split($acl1);
if (!is_array($acl2)) $acl2 = str_split($acl2);
$rights = $this->rights_supported();
$acl1 = array_intersect($acl1, $rights);
$acl2 = array_intersect($acl2, $rights);
$res = array_intersect($acl1, $acl2);
$cnt1 = count($res);
$cnt2 = count($acl2);
if ($cnt1 == $cnt2)
return 2;
else if ($cnt1)
return 1;
else
return 0;
}
/**
* Get list of supported access rights (according to RIGHTS capability)
*
* @return array List of supported access rights abbreviations
*/
function rights_supported()
{
if ($this->supported !== null) {
return $this->supported;
}
$capa = $this->rc->storage->get_capability('RIGHTS');
if (is_array($capa)) {
$rights = strtolower($capa[0]);
}
else {
$rights = 'cd';
}
return $this->supported = str_split('lrswi' . $rights . 'pa');
}
/**
* Username realm detection.
*
* @return string Username realm (domain)
*/
private function get_realm()
{
// When user enters a username without domain part, realm
// allows to add it to the username (and display correct username in the table)
if (isset($_SESSION['acl_username_realm'])) {
return $_SESSION['acl_username_realm'];
}
// find realm in username of logged user (?)
list($name, $domain) = explode('@', $_SESSION['username']);
// Use (always existent) ACL entry on the INBOX for the user to determine
// whether or not the user ID in ACL entries need to be qualified and how
// they would need to be qualified.
if (empty($domain)) {
$acl = $this->rc->storage->get_acl('INBOX');
if (is_array($acl)) {
$regexp = '/^' . preg_quote($_SESSION['username'], '/') . '@(.*)$/';
foreach (array_keys($acl) as $name) {
if (preg_match($regexp, $name, $matches)) {
$domain = $matches[1];
break;
}
}
}
}
return $_SESSION['acl_username_realm'] = $domain;
}
/**
* Initializes autocomplete LDAP backend
*/
private function init_ldap()
{
if ($this->ldap)
return $this->ldap->ready;
// get LDAP config
$config = $this->rc->config->get('acl_users_source');
if (empty($config)) {
return false;
}
// not an array, use configured ldap_public source
if (!is_array($config)) {
$ldap_config = (array) $this->rc->config->get('ldap_public');
$config = $ldap_config[$config];
}
$uid_field = $this->rc->config->get('acl_users_field', 'mail');
$filter = $this->rc->config->get('acl_users_filter');
if (empty($uid_field) || empty($config)) {
return false;
}
// get name attribute
if (!empty($config['fieldmap'])) {
$name_field = $config['fieldmap']['name'];
}
// ... no fieldmap, use the old method
if (empty($name_field)) {
$name_field = $config['name_field'];
}
// add UID field to fieldmap, so it will be returned in a record with name
$config['fieldmap'] = array(
'name' => $name_field,
'uid' => $uid_field,
);
// search in UID and name fields
$config['search_fields'] = array_values($config['fieldmap']);
$config['required_fields'] = array($uid_field);
// set search filter
if ($filter)
$config['filter'] = $filter;
// disable vlv
$config['vlv'] = false;
// Initialize LDAP connection
$this->ldap = new rcube_ldap($config,
$this->rc->config->get('ldap_debug'),
$this->rc->config->mail_domain($_SESSION['imap_host']));
return $this->ldap->ready;
}
/**
* Modify user login according to 'login_lc' setting
*/
protected function mod_login($user)
{
$login_lc = $this->rc->config->get('login_lc');
if ($login_lc === true || $login_lc == 2) {
$user = mb_strtolower($user);
}
// lowercase domain name
else if ($login_lc && strpos($user, '@')) {
list($local, $domain) = explode('@', $user);
$user = $local . '@' . mb_strtolower($domain);
}
return $user;
}
}
diff --git a/plugins/acl/localization/en_US.inc b/plugins/acl/localization/en_US.inc
index 23501dafe..ff8dde76c 100644
--- a/plugins/acl/localization/en_US.inc
+++ b/plugins/acl/localization/en_US.inc
@@ -1,103 +1,108 @@
<?php
/*
+-----------------------------------------------------------------------+
| plugins/acl/localization/<lang>.inc |
| |
| Localization file of the Roundcube Webmail ACL plugin |
| Copyright (C) 2012-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
+-----------------------------------------------------------------------+
For translation see https://www.transifex.com/projects/p/roundcube-webmail/resource/plugin-acl/
*/
$labels['sharing'] = 'Sharing';
$labels['myrights'] = 'Access Rights';
$labels['username'] = 'User:';
$labels['advanced'] = 'Advanced mode';
$labels['newuser'] = 'Add entry';
$labels['editperms'] = 'Edit permissions';
$labels['actions'] = 'Access right actions...';
$labels['anyone'] = 'All users (anyone)';
$labels['anonymous'] = 'Guests (anonymous)';
$labels['identifier'] = 'Identifier';
$labels['acll'] = 'Lookup';
$labels['aclr'] = 'Read messages';
$labels['acls'] = 'Keep Seen state';
$labels['aclw'] = 'Write flags';
$labels['acli'] = 'Insert (Copy into)';
$labels['aclp'] = 'Post';
$labels['aclc'] = 'Create subfolders';
$labels['aclk'] = 'Create subfolders';
$labels['acld'] = 'Delete messages';
$labels['aclt'] = 'Delete messages';
$labels['acle'] = 'Expunge';
$labels['aclx'] = 'Delete folder';
$labels['acla'] = 'Administer';
$labels['acln'] = 'Annotate messages';
$labels['aclfull'] = 'Full control';
$labels['aclother'] = 'Other';
$labels['aclread'] = 'Read';
$labels['aclwrite'] = 'Write';
$labels['acldelete'] = 'Delete';
$labels['shortacll'] = 'Lookup';
$labels['shortaclr'] = 'Read';
$labels['shortacls'] = 'Keep';
$labels['shortaclw'] = 'Write';
$labels['shortacli'] = 'Insert';
$labels['shortaclp'] = 'Post';
$labels['shortaclc'] = 'Create';
$labels['shortaclk'] = 'Create';
$labels['shortacld'] = 'Delete';
$labels['shortaclt'] = 'Delete';
$labels['shortacle'] = 'Expunge';
$labels['shortaclx'] = 'Folder delete';
$labels['shortacla'] = 'Administer';
$labels['shortacln'] = 'Annotate';
$labels['shortaclother'] = 'Other';
$labels['shortaclread'] = 'Read';
$labels['shortaclwrite'] = 'Write';
$labels['shortacldelete'] = 'Delete';
$labels['longacll'] = 'The folder is visible on lists and can be subscribed to';
$labels['longaclr'] = 'The folder can be opened for reading';
$labels['longacls'] = 'Messages Seen flag can be changed';
$labels['longaclw'] = 'Messages flags and keywords can be changed, except Seen and Deleted';
$labels['longacli'] = 'Messages can be written or copied to the folder';
$labels['longaclp'] = 'Messages can be posted to this folder';
$labels['longaclc'] = 'Folders can be created (or renamed) directly under this folder';
$labels['longaclk'] = 'Folders can be created (or renamed) directly under this folder';
$labels['longacld'] = 'Messages Delete flag can be changed';
$labels['longaclt'] = 'Messages Delete flag can be changed';
$labels['longacle'] = 'Messages can be expunged';
$labels['longaclx'] = 'The folder can be deleted or renamed';
$labels['longacla'] = 'The folder access rights can be changed';
$labels['longacln'] = 'Messages shared metadata (annotations) can be changed';
$labels['longaclfull'] = 'Full control including folder administration';
$labels['longaclread'] = 'The folder can be opened for reading';
$labels['longaclwrite'] = 'Messages can be marked, written or copied to the folder';
$labels['longacldelete'] = 'Messages can be deleted';
+$labels['longaclother'] = 'Other access rights';
+
+$labels['ariasummaryacltable'] = 'List of access rights';
+$labels['arialabelaclactions'] = 'List actions';
+$labels['arialabelaclform'] = 'Access rights form';
$messages['deleting'] = 'Deleting access rights...';
$messages['saving'] = 'Saving access rights...';
$messages['updatesuccess'] = 'Successfully changed access rights';
$messages['deletesuccess'] = 'Successfully deleted access rights';
$messages['createsuccess'] = 'Successfully added access rights';
$messages['updateerror'] = 'Unable to update access rights';
$messages['deleteerror'] = 'Unable to delete access rights';
$messages['createerror'] = 'Unable to add access rights';
$messages['deleteconfirm'] = 'Are you sure, you want to remove access rights of selected user(s)?';
$messages['norights'] = 'No rights has been specified!';
$messages['nouser'] = 'No username has been specified!';
?>
diff --git a/plugins/acl/skins/larry/acl.css b/plugins/acl/skins/larry/acl.css
index 96c1092a0..bd72b3c85 100644
--- a/plugins/acl/skins/larry/acl.css
+++ b/plugins/acl/skins/larry/acl.css
@@ -1,129 +1,124 @@
#aclcontainer
{
overflow-x: auto;
border: 1px solid #CCDDE4;
background-color: #D9ECF4;
height: 272px;
box-shadow: none;
}
#acllist-content
{
position: relative;
height: 230px;
background-color: white;
}
#acllist-footer
{
position: relative;
}
#acltable
{
width: 100%;
border-collapse: collapse;
border: none;
}
+#acltable th,
#acltable td
{
white-space: nowrap;
text-align: center;
}
-#acltable thead tr td
+#acltable thead tr th
{
- border-left: #BBD3DA dotted 1px;
font-size: 11px;
font-weight: bold;
- width: auto;
}
#acltable tbody td
{
- border-bottom: #DDDDDD 1px solid;
text-align: center;
height: 16px;
cursor: default;
}
-#acltable thead td.user
+#acltable thead tr > .user
{
width: 30%;
+ border-left: none;
}
-#acltable.advanced thead td.user {
- width: 25%;
+#acltable.advanced thead tr > .user {
+ width: 25%;
}
#acltable tbody td.user
{
text-align: left;
- overflow: hidden;
- text-overflow: ellipsis;
- -o-text-overflow: ellipsis;
- border-left: none;
}
#acltable tbody td.partial
{
background-image: url(images/partial.png);
background-position: center;
background-repeat: no-repeat;
}
#acltable tbody td.enabled
{
background-image: url(images/enabled.png);
background-position: center;
background-repeat: no-repeat;
}
#acltable tbody tr.selected td.partial
{
background-color: #019bc6;
background-image: url(images/partial.png), -moz-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/partial.png), -webkit-gradient(linear, left top, left bottom, color-stop(0%,#019bc6), color-stop(100%,#017cb4));
background-image: url(images/partial.png), -o-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/partial.png), -ms-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/partial.png), linear-gradient(top, #019bc6 0%, #017cb4 100%);
}
#acltable tbody tr.selected td.enabled
{
background-color: #019bc6;
background-image: url(images/enabled.png), -moz-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/enabled.png), -webkit-gradient(linear, left top, left bottom, color-stop(0%,#019bc6), color-stop(100%,#017cb4));
background-image: url(images/enabled.png), -o-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/enabled.png), -ms-linear-gradient(top, #019bc6 0%, #017cb4 100%);
background-image: url(images/enabled.png), linear-gradient(top, #019bc6 0%, #017cb4 100%);
}
#aclform
{
display: none;
}
#aclform div
{
padding: 0;
text-align: center;
clear: both;
}
#aclform ul
{
list-style: none;
margin: 0.2em;
padding: 0;
}
#aclform ul li label
{
margin-left: 0.5em;
}
ul.toolbarmenu li span.delete {
background-position: 0 -1509px;
}
diff --git a/plugins/acl/skins/larry/templates/table.html b/plugins/acl/skins/larry/templates/table.html
index c0b8329c6..3f203e44d 100644
--- a/plugins/acl/skins/larry/templates/table.html
+++ b/plugins/acl/skins/larry/templates/table.html
@@ -1,27 +1,30 @@
<div id="aclcontainer" class="uibox listbox">
-<div id="acllist-content" class="scroller withfooter">
- <roundcube:object name="acltable" id="acltable" class="records-table" />
+<div id="acllist-content" class="scroller withfooter" aria-labelledby="aria-label-acltable">
+ <h2 class="boxtitle" id="aria-label-acltable"><roundcube:label name="acl.ariasummaryacltable" /></h2>
+ <roundcube:object name="acltable" id="acltable" class="records-table" summary="acl.ariasummaryacltable" role="listbox" />
</div>
<div id="acllist-footer" class="boxfooter">
- <roundcube:button command="acl-create" id="aclcreatelink" type="link" title="acl.newuser" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="aclmenulink" id="aclmenulink" type="link" title="acl.actions" class="listbutton groupactions"onclick="UI.show_popup('aclmenu', undefined, {above:1});return false" innerClass="inner" content="⚙" />
+ <roundcube:button command="acl-create" id="aclcreatelink" type="link" title="acl.newuser" class="listbutton add disabled" classAct="listbutton add" innerClass="inner" content="+" /><roundcube:button name="aclmenulink" id="aclmenulink" type="link" title="acl.actions" class="listbutton groupactions" onclick="return UI.toggle_popup('aclmenu', event)" innerClass="inner" content="⚙" aria-haspopup="true" aria-expanded="false" aria-owns="aclmenu-menu" />
</div>
</div>
-<div id="aclmenu" class="popupmenu">
- <ul class="toolbarmenu selectable iconized">
- <li><roundcube:button command="acl-edit" label="edit" class="icon" classAct="icon active" innerclass="icon edit" /></li>
- <li><roundcube:button command="acl-delete" label="delete" class="icon" classAct="icon active" innerclass="icon delete" /></li>
+<div id="aclmenu" class="popupmenu" aria-hidden="true" data-align="bottom">
+ <h3 id="aria-label-aclactions" class="voice"><roundcube:label name="acl.arialabelaclactions" /></h3>
+ <ul id="aclmenu-menu" class="toolbarmenu selectable iconized" role="menu" aria-labelledby="aria-label-aclactions">
+ <li role="menuitem"><roundcube:button command="acl-edit" label="edit" class="icon" classAct="icon active" innerclass="icon edit" /></li>
+ <li role="menuitem"><roundcube:button command="acl-delete" label="delete" class="icon" classAct="icon active" innerclass="icon delete" /></li>
<roundcube:if condition="!in_array('acl_advanced_mode', (array)config:dont_override)" />
- <li><roundcube:button name="acl-switch" id="acl-switch" label="acl.advanced" onclick="rcmail.command('acl-mode-switch');return false" class="active" /></li>
+ <li role="menuitem"><roundcube:button name="acl-switch" id="acl-switch" label="acl.advanced" onclick="rcmail.command('acl-mode-switch');return false" class="active" /></li>
<roundcube:endif />
</ul>
</div>
-<div id="aclform" class="propform" style="position:absolute; width:480px; top:0; left:0; padding:8px">
+<div id="aclform" class="propform" style="position:absolute; width:480px; top:0; left:0; padding:8px" aria-labelledby="aria-label-aclform" aria-hidden="true" role="dialog">
+ <h3 id="aria-label-aclform" class="voice"><roundcube:label name="acl.arialabelaclform" /></h3>
<fieldset class="thinbordered"><legend><roundcube:label name="acl.identifier" /></legend>
<roundcube:object name="acluser" id="acluser" size="35" class="proplist" />
</fieldset>
<fieldset class="thinbordered"><legend><roundcube:label name="acl.myrights" /></legend>
<roundcube:object name="aclrights" class="proplist" />
</fieldset>
</div>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Mar 1, 12:54 AM (1 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
165287
Default Alt Text
(48 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment