Merge branch 'dev-elastic'

pull/5874/merge
Aleksander Machniak 7 years ago
commit c6b2d8bead

@ -30,7 +30,7 @@ if (window.rcmail) {
rcmail.enable_command('acl-delete', 'acl-edit', false);
if (rcmail.env.acl_advanced)
$('#acl-switch').addClass('selected');
$('#acl-switch').addClass('selected').find('input').prop('checked', true);
});
}
@ -54,13 +54,14 @@ rcube_webmail.prototype.acl_delete = function()
{
var users = this.acl_get_usernames();
if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) {
this.http_post('settings/plugin.acl', {
if (users && users.length) {
this.confirm_dialog(this.get_label('acl.deleteconfirm'), 'delete', function(e, ref) {
ref.http_post('settings/plugin.acl', {
_act: 'delete',
_user: users.join(','),
_mbox: this.env.mailbox
},
this.set_busy(true, 'acl.deleting'));
_mbox: rcmail.env.mailbox
}, ref.set_busy(true, 'acl.deleting'));
});
}
}
@ -80,11 +81,11 @@ rcube_webmail.prototype.acl_save = function()
}
if (!user) {
alert(this.get_label('acl.nouser'));
this.alert_dialog(this.get_label('acl.nouser'));
return;
}
if (!rights) {
alert(this.get_label('acl.norights'));
this.alert_dialog(this.get_label('acl.norights'));
return;
}
@ -245,7 +246,7 @@ rcube_webmail.prototype.acl_add_row = function(o, sel)
if (cl == 'user')
td.addClass(cl).append($('<a>').text(o.username));
else
td.addClass(this.className + ' ' + rcmail.acl_class(o.acl, cl)).text('');
td.addClass(this.className + ' ' + rcmail.acl_class(o.acl, cl)).html('<span/>');
$(this).replaceWith(td);
});
@ -350,7 +351,7 @@ rcube_webmail.prototype.acl_init_form = function(id)
id ? this.get_label('acl.editperms') : this.get_label('acl.newuser'),
buttons,
{
button_classes: ['mainaction submit'],
button_classes: ['mainaction submit', 'cancel'],
modal: true,
closeOnEscape: true,
close: function(e, ui) {

@ -177,7 +177,7 @@ class acl extends rcube_plugin
$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');
$this->include_stylesheet($this->local_skin_path() . '/acl.css', true);
// add Info fieldset if it doesn't exist
if (!isset($args['form']['props']['fieldsets']['info']))
@ -318,8 +318,9 @@ class acl extends rcube_plugin
$textfield = new html_inputfield($attrib);
$fields['user'] = html::label(array('for' => $attrib['id']), $this->gettext('username'))
. ' ' . $textfield->show();
$fields['user'] = html::div('input-group',
html::label(array('for' => $attrib['id'], 'class' => 'input-group-addon'), $this->gettext('username'))
. ' ' . $textfield->show());
// Add special entries
if (!empty($this->specials)) {
@ -452,7 +453,7 @@ class acl extends rcube_plugin
case 1: $class = 'partial'; break;
default: $class = 'disabled'; break;
}
$table->add('acl' . $key . ' ' . $class, '');
$table->add('acl' . $key . ' ' . $class, '<span></span>');
}
$js_table[$userid] = implode($userrights);

@ -20,6 +20,7 @@ $labels['sharing'] = 'Sharing';
$labels['myrights'] = 'Access Rights';
$labels['username'] = 'User:';
$labels['advanced'] = 'Advanced mode';
$labels['add'] = 'Add';
$labels['newuser'] = 'Add entry';
$labels['editperms'] = 'Edit permissions';
$labels['actions'] = 'Access right actions...';

@ -0,0 +1,37 @@
<div id="acllist-container" class="table-widget">
<div id="acllist-content" class="content">
<h2 class="voice" id="aria-label-acltable"><roundcube:label name="acl.ariasummaryacltable" /></h2>
<roundcube:object name="acltable" id="acltable" class="records-table options-table" aria-labelledby="aria-label-acltable" role="listbox" />
</div>
<div id="acllist-footer" class="footer toolbar">
<roundcube:button command="acl-create" type="link"
label="acl.add" title="acl.newuser"
class="button create disabled" classAct="button create" innerClass="inner" />
<roundcube:button name="aclmenulink" type="link"
label="actions" title="acl.actions" href="#acl-actions"
class="button actions" innerClass="inner" data-popup="acl-menu" />
</div>
</div>
<div id="acl-menu" class="popupmenu" aria-hidden="true" data-align="bottom">
<h3 id="aria-label-aclactions" class="voice"><roundcube:label name="acl.arialabelaclactions" /></h3>
<ul class="toolbarmenu listing iconized" role="menu" aria-labelledby="aria-label-aclactions">
<roundcube:button command="acl-edit" label="edit" type="link-menuitem" class="edit" classAct="edit active" />
<roundcube:button command="acl-delete" label="delete" type="link-menuitem" class="delete" classAct="delete active" />
<roundcube:if condition="!in_array('acl_advanced_mode', (array)config:dont_override)" />
<li role="menuitem" class="checkbox"><label id="acl-switch"><input type="checkbox" onchange="rcmail.command('acl-mode-switch')" /><roundcube:label name="acl.advanced" /></label></li>
<roundcube:endif />
</ul>
</div>
<div id="aclform" class="popupmenu propform" aria-labelledby="aria-label-aclform" role="form">
<h3 id="aria-label-aclform" class="voice"><roundcube:label name="acl.arialabelaclform" /></h3>
<div class="row form-group">
<label class="col-sm-4 col-form-label"><roundcube:label name="acl.identifier" /></label>
<roundcube:object name="acluser" id="acluser" class="proplist col-sm-8" />
</div>
<div class="row form-group">
<label class="col-sm-4 col-form-label"><roundcube:label name="acl.myrights" /></label>
<roundcube:object name="aclrights" class="proplist col-sm-8" />
</div>
</div>

@ -57,7 +57,24 @@ if (window.rcmail) {
// set css style for archive folder
var li;
if (rcmail.env.archive_folder && (li = rcmail.get_folder_li(rcmail.env.archive_folder, '', true)))
$(li).addClass('archive');
if (rcmail.env.archive_folder) {
// in Settings > Folders
if (rcmail.subscription_list)
li = rcmail.subscription_list.get_item(rcmail.env.archive_folder);
// in folders list
else
li = rcmail.get_folder_li(rcmail.env.archive_folder, '', true);
if (li) {
$(li).addClass('archive');
// in folder selector popup
rcmail.addEventListener('menu-open', function(p) {
if (p.name == 'folder-selector') {
$('a[rel="' + $('a', li).attr('rel') + '"]', p.obj).parent().addClass('archive');
}
});
}
}
});
}

@ -22,14 +22,10 @@ class archive extends rcube_plugin
// register special folder type
rcube_storage::$folder_types[] = 'archive';
if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show')
&& ($archive_folder = $rcmail->config->get('archive_mbox'))
) {
$skin_path = $this->local_skin_path();
if (is_file($this->home . "/$skin_path/archive.css")) {
$this->include_stylesheet("$skin_path/archive.css");
}
$archive_folder = $rcmail->config->get('archive_mbox');
if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show') && $archive_folder) {
$this->include_stylesheet($this->local_skin_path() . '/archive.css', true);
$this->include_script('archive.js');
$this->add_texts('localization', true);
$this->add_button(
@ -61,6 +57,13 @@ class archive extends rcube_plugin
else if ($rcmail->task == 'settings') {
$this->add_hook('preferences_list', array($this, 'prefs_table'));
$this->add_hook('preferences_save', array($this, 'save_prefs'));
if ($rcmail->action == 'folders' && $archive_folder) {
$this->include_stylesheet($this->local_skin_path() . '/archive.css', true);
$this->include_script('archive.js');
// set env variables for client
$rcmail->output->set_env('archive_folder', $archive_folder);
}
}
}

@ -3,7 +3,7 @@
"type": "roundcube-plugin",
"description": "This adds a button to move the selected messages to an archive folder. The folder (and the optional structure of subfolders) can be selected in the settings panel.",
"license": "GPLv3+",
"version": "3.2",
"version": "3.3",
"authors": [
{
"name": "Thomas Bruederli",

@ -145,7 +145,7 @@ class emoticons extends rcube_plugin
$checkbox = new html_checkbox(array('name' => '_' . $field_id, 'id' => $field_id, 'value' => 1));
$args['blocks']['main']['options']['emoticons_display'] = array(
'title' => $this->gettext('emoticonsdisplay'),
'title' => html::label($field_id, $this->gettext('emoticonsdisplay')),
'content' => $checkbox->show(intval($rcube->config->get('emoticons_display', false)))
);
}
@ -157,7 +157,7 @@ class emoticons extends rcube_plugin
$checkbox = new html_checkbox(array('name' => '_' . $field_id, 'id' => $field_id, 'value' => 1));
$args['blocks']['main']['options']['emoticons_compose'] = array(
'title' => $this->gettext('emoticonscompose'),
'title' => html::label($field_id, $this->gettext('emoticonscompose')),
'content' => $checkbox->show(intval($rcube->config->get('emoticons_compose', true)))
);
}

@ -4,7 +4,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
if (rcmail.env.task == 'settings') {
if (rcmail.gui_objects.keyslist) {
rcmail.keys_list = new rcube_list_widget(rcmail.gui_objects.keyslist,
{multiselect:true, draggable:false, keyboard:false});
{multiselect:true, draggable:false, keyboard:true});
rcmail.keys_list
.addEventListener('select', function(o) { rcmail.enigma_keylist_select(o); })
.addEventListener('keypress', function(o) { rcmail.enigma_keylist_keypress(o); })
@ -27,6 +27,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
rcmail.register_command('plugin.enigma-key-export', function() { rcmail.enigma_export(); });
rcmail.register_command('plugin.enigma-key-export-selected', function() { rcmail.enigma_export(true); });
rcmail.register_command('plugin.enigma-key-import', function() { rcmail.enigma_key_import(); }, true);
rcmail.register_command('plugin.enigma-key-import-search', function() { rcmail.enigma_key_import_search(); }, true);
rcmail.register_command('plugin.enigma-key-delete', function(props) { return rcmail.enigma_delete(); });
rcmail.register_command('plugin.enigma-key-create', function(props) { return rcmail.enigma_key_create(); }, true);
rcmail.register_command('plugin.enigma-key-save', function(props) { return rcmail.enigma_key_create_save(); }, true);
@ -44,8 +45,6 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
return false;
}
});
$('input[type="button"]:first').focus();
}
}
}
@ -81,13 +80,45 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
// Display key(s) import form
rcube_webmail.prototype.enigma_key_import = function()
{
this.enigma_loadframe('&_action=plugin.enigmakeys&_a=import');
var dialog = $('<iframe>').attr('src', this.url('plugin.enigmakeys', {_a: 'import', _framed: 1})),
import_func = function(e) {
var win = dialog[0].contentWindow;
win.rcmail.enigma_import();
};
this.enigma_import_dialog = this.simple_dialog(dialog, this.gettext('enigma.importkeys'), import_func, {
button: 'import',
width: 500,
height: 150
});
};
// Display key(s) search/import form
rcube_webmail.prototype.enigma_key_import_search = function()
{
var dialog = $('<iframe>').attr('src', this.url('plugin.enigmakeys', {_a: 'import-search', _framed: 1})),
search_func = function() {
var win = dialog[0].contentWindow;
win.rcmail.enigma_import_search();
};
this.enigma_import_dialog = this.simple_dialog(dialog, this.gettext('enigma.keyimportsearchlabel'), search_func, {
button: 'search',
width: 500,
height: 150
});
};
rcube_webmail.prototype.enigma_import_success = function()
{
var dialog = this.enigma_import_dialog || parent.rcmail.enigma_import_dialog;
dialog.dialog('destroy');
};
// Display key(s) generation form
rcube_webmail.prototype.enigma_key_create = function()
{
this.enigma_loadframe('&_action=plugin.enigmakeys&_a=create');
this.enigma_loadframe('&_action=plugin.enigmakeys&_a=create&_nav=hide');
};
// Generate key(s) and submit them
@ -103,14 +134,20 @@ rcube_webmail.prototype.enigma_key_create_save = function()
});
// validate the form
if (!password || !confirm)
return alert(this.get_label('enigma.formerror'));
if (!password || !confirm) {
this.alert_dialog(this.get_label('enigma.formerror'));
return;
}
if (password != confirm)
return alert(this.get_label('enigma.passwordsdiffer'));
if (password != confirm) {
this.alert_dialog(this.get_label('enigma.passwordsdiffer'));
return;
}
if (!users.length)
return alert(this.get_label('enigma.noidentselected'));
if (!users.length) {
this.alert_dialog(this.get_label('enigma.noidentselected'));
return;
}
// generate keys
// use OpenPGP.js if browser supports required features
@ -151,14 +188,16 @@ rcube_webmail.prototype.enigma_delete = function()
{
var keys = this.keys_list.get_selection();
if (!keys.length || !confirm(this.get_label('enigma.keyremoveconfirm')))
if (!keys.length)
return;
var lock = this.display_message(this.get_label('enigma.keyremoving'), 'loading'),
post = {_a: 'delete', _keys: keys};
this.confirm_dialog(this.get_label('enigma.keyremoveconfirm'), 'delete', function(e, ref) {
var lock = ref.display_message(ref.get_label('enigma.keyremoving'), 'loading'),
post = {_a: 'delete', _keys: keys};
// send request to server
this.http_post('plugin.enigmakeys', post, lock);
// send request to server
ref.http_post('plugin.enigmakeys', post, lock);
});
};
// Export key(s)
@ -232,20 +271,20 @@ rcube_webmail.prototype.enigma_export_submit = function(data)
rcube_webmail.prototype.enigma_import = function()
{
var form, file, lock,
id = 'keyexport-' + new Date().getTime(),
iframe = $('<iframe>').attr({name: id, style: 'display:none'});
id = 'keyimport-' + new Date().getTime();
if (form = this.gui_objects.importform) {
file = document.getElementById('rcmimportfile');
if (file && !file.value) {
alert(this.get_label('selectimportfile'));
this.alert_dialog(this.get_label('selectimportfile'));
return;
}
lock = this.set_busy(true, 'importwait');
iframe.appendTo(document.body);
$(form).attr({target: id, action: this.add_url(form.action, '_unlock', lock)})
.submit();
$('<iframe>').attr({name: id, style: 'display:none'}).appendTo(document.body);
$(form).attr({target: id, action: this.add_url(form.action, '_unlock', lock)}).submit();
return true;
}
};
@ -402,16 +441,15 @@ rcube_webmail.prototype.enigma_add_list_row = function(r)
tbody = this.gui_objects.keyslist.tBodies[0],
rowcount = tbody.rows.length,
even = rowcount%2,
css_class = 'message'
+ (even ? ' even' : ' odd'),
// for performance use DOM instead of jQuery here
row = document.createElement('tr'),
col = document.createElement('td');
row.id = 'rcmrow' + r.id;
row.className = css_class;
row.className = 'message';
if (r.flags) $(row).data('flags', r.flags);
col.className = 'name';
col.innerHTML = r.name;
row.appendChild(col);
list.insert_row(row);
@ -500,7 +538,7 @@ rcube_webmail.prototype.enigma_password_request = function(data)
this.show_popup_dialog(myprompt, this.get_label('enigma.enterkeypasstitle'),
[{
text: this.get_label('save'),
'class': 'mainaction save',
'class': 'mainaction save unlock',
click: function(e) {
e.stopPropagation();

@ -59,6 +59,10 @@ class enigma_ui
$this->key_import();
break;
case 'import-search':
$this->key_import_search();
break;
case 'export':
$this->key_export();
break;
@ -121,7 +125,7 @@ class enigma_ui
}
$skin_path = $this->enigma->local_skin_path();
$this->enigma->include_stylesheet("$skin_path/enigma.css");
$this->enigma->include_stylesheet("$skin_path/enigma.css", true);
$this->css_loaded = true;
}
@ -225,7 +229,9 @@ class enigma_ui
// add some labels to client
$this->rc->output->add_label('enigma.keyremoveconfirm', 'enigma.keyremoving',
'enigma.keyexportprompt', 'enigma.withprivkeys', 'enigma.onlypubkeys', 'enigma.exportkeys'
'enigma.keyexportprompt', 'enigma.withprivkeys', 'enigma.onlypubkeys',
'enigma.exportkeys', 'enigma.importkeys', 'enigma.keyimportsearchlabel',
'import', 'search'
);
return $out;
@ -366,11 +372,11 @@ class enigma_ui
$table = new html_table(array('cols' => 2));
// Key user ID
$table->add('title', $this->enigma->gettext('keyuserid'));
$table->add('title', html::label(null, $this->enigma->gettext('keyuserid')));
$table->add(null, rcube::Q($this->data->name));
// Key ID
$table->add('title', $this->enigma->gettext('keyid'));
$table->add('title', html::label(null, $this->enigma->gettext('keyid')));
$table->add(null, $this->data->subkeys[0]->get_short_id());
// Key type
@ -381,11 +387,11 @@ class enigma_ui
else if ($keytype == enigma_key::TYPE_PUBLIC) {
$type = $this->enigma->gettext('typepublickey');
}
$table->add('title', $this->enigma->gettext('keytype'));
$table->add('title', html::label(null, $this->enigma->gettext('keytype')));
$table->add(null, $type);
// Key fingerprint
$table->add('title', $this->enigma->gettext('fingerprint'));
$table->add('title', html::label(null, $this->enigma->gettext('fingerprint')));
$table->add(null, $this->data->subkeys[0]->get_fingerprint());
$out .= html::tag('fieldset', null,
@ -557,12 +563,11 @@ class enigma_ui
if ($result['imported']) {
$this->rc->output->command('parent.enigma_list', 1);
}
else {
$this->rc->output->command('parent.enigma_loadframe');
}
$this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation',
array('new' => $result['imported'], 'old' => $result['unchanged']));
$this->rc->output->command('parent.enigma_import_success');
}
else if ($result instanceof enigma_error && $result->getCode() == enigma_error::BADPASS) {
$this->password_prompt($result);
@ -570,7 +575,6 @@ class enigma_ui
else {
$this->rc->output->show_message('enigma.keysimportfailed', 'error');
}
$this->rc->output->send('iframe');
}
else if ($err = $_FILES['_file']['error']) {
@ -588,10 +592,21 @@ class enigma_ui
'importform' => array($this, 'tpl_key_import_form'),
));
$this->rc->output->set_pagetitle($this->enigma->gettext('keyimport'));
$this->rc->output->send('enigma.keyimport');
}
/**
* Key import-search (page) handler
*/
private function key_import_search()
{
$this->rc->output->add_handlers(array(
'importform' => array($this, 'tpl_key_import_form'),
));
$this->rc->output->send('enigma.keysearch');
}
/**
* Template object for key import (upload) form
*/
@ -599,46 +614,62 @@ class enigma_ui
{
$attrib += array('id' => 'rcmKeyImportForm');
$upload = new html_inputfield(array('type' => 'file', 'name' => '_file',
'id' => 'rcmimportfile', 'size' => 30));
$search = new html_inputfield(array('type' => 'text', 'name' => '_search',
'id' => 'rcmimportsearch', 'size' => 30));
if (empty($attrib['part']) || $attrib['part'] == 'import') {
$title = $this->enigma->gettext('keyimportlabel');
$upload = new html_inputfield(array('type' => 'file', 'name' => '_file',
'id' => 'rcmimportfile', 'size' => 30));
$upload_button = new html_inputfield(array(
'type' => 'button',
'value' => $this->rc->gettext('import'),
'class' => 'button',
'onclick' => "return rcmail.command('plugin.enigma-import','',this,event)",
));
$upload_button = new html_button(array(
'class' => 'button import',
'onclick' => "return rcmail.command('plugin.enigma-import','',this,event)",
));
$search_button = new html_inputfield(array(
'type' => 'button',
'value' => $this->rc->gettext('search'),
'class' => 'button',
'onclick' => "return rcmail.command('plugin.enigma-import-search','',this,event)",
));
$form = html::div(null,
rcube::Q($this->enigma->gettext('keyimporttext'), 'show')
. html::br() . html::br() . $upload->show()
. (empty($attrib['part']) ? html::br() . html::br() . $upload_button->show($this->rc->gettext('import')) : '')
);
$upload_form = html::div(null,
rcube::Q($this->enigma->gettext('keyimporttext'), 'show')
. html::br() . html::br() . $upload->show()
. html::br() . html::br() . $upload_button->show()
);
if (empty($attrib['part'])) {
$form = html::tag('fieldset', '', html::tag('legend', null, $title) . $form);
}
else {
$this->rc->output->set_pagetitle($title);
}
}
$search_form = html::div(null,
rcube::Q($this->enigma->gettext('keyimportsearchtext'), 'show')
. html::br() . html::br() . $search->show()
. html::br() . html::br() . $search_button->show()
);
if (empty($attrib['part']) || $attrib['part'] == 'search') {
$title = $this->enigma->gettext('keyimportsearchlabel');
$search = new html_inputfield(array('type' => 'text', 'name' => '_search',
'id' => 'rcmimportsearch', 'size' => 30));
$search_button = new html_button(array(
'class' => 'button search',
'onclick' => "return rcmail.command('plugin.enigma-import-search','',this,event)",
));
$form = html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportlabel')) . $upload_form)
. html::tag('fieldset', '', html::tag('legend', null, $this->enigma->gettext('keyimportsearchlabel')) . $search_form);
$form = html::div(null,
rcube::Q($this->enigma->gettext('keyimportsearchtext'), 'show')
. html::br() . html::br() . $search->show()
. (empty($attrib['part']) ? html::br() . html::br() . $search_button->show($this->rc->gettext('search')) : '')
);
if (empty($attrib['part'])) {
$form = html::tag('fieldset', '', html::tag('legend', null, $title) . $form);
}
else {
$this->rc->output->set_pagetitle($title);
}
$this->rc->output->include_script('publickey.js');
}
$this->rc->output->add_label('selectimportfile', 'importwait', 'nopubkeyfor', 'nopubkeyforsender',
'encryptnoattachments','encryptedsendialog','searchpubkeyservers', 'importpubkeys',
'encryptpubkeysfound', 'search', 'close', 'import', 'keyid', 'keylength', 'keyexpired',
'keyrevoked', 'keyimportsuccess', 'keyservererror');
$this->rc->output->add_gui_object('importform', $attrib['id']);
$this->rc->output->include_script('publickey.js');
$out = $this->rc->output->form_tag(array(
'action' => $this->rc->url(array('action' => $this->rc->action, 'a' => 'import')),
@ -723,11 +754,11 @@ class enigma_ui
$checkbox = new html_checkbox(array('name' => 'identity[]'));
foreach ((array) $identities as $idx => $ident) {
$name = empty($ident['name']) ? ($ident['email']) : $ident['ident'];
$identities[$idx] = html::label(null, $checkbox->show($name, array('value' => $name)) . rcube::Q($name));
$identities[$idx] = html::tag('li', null, html::label(null, $checkbox->show($name, array('value' => $name)) . rcube::Q($name)));
}
$table->add('title', html::label('key-name', rcube::Q($this->enigma->gettext('newkeyident'))));
$table->add(null, implode($identities, "\n"));
$table->add(null, html::tag('ul', 'proplist', implode($identities, "\n")));
// Key size
$select = new html_select(array('name' => 'size', 'id' => 'key-size'));
@ -783,59 +814,81 @@ class enigma_ui
private function compose_ui()
{
$this->add_css();
$this->rc->output->add_label('enigma.sendunencrypted');
// Options menu button
$this->enigma->add_button(array(
'type' => 'link',
'command' => 'plugin.enigma',
'onclick' => "rcmail.command('menu-open', 'enigmamenu', event.target, event)",
'class' => 'button enigma',
'title' => 'encryptionoptions',
'label' => 'encryption',
'domain' => $this->enigma->ID,
'width' => 32,
'height' => 32,
'aria-owns' => 'enigmamenu',
'aria-haspopup' => 'true',
'aria-expanded' => 'false',
), 'toolbar');
// Elastic skin (or a skin based on it)
if (array_key_exists('elastic', (array) $this->rc->output->skins)) {
$this->enigma->api->add_content($this->compose_ui_options(), 'composeoptions');
}
// other skins
else {
// Options menu button
$this->enigma->add_button(array(
'type' => 'link',
'command' => 'plugin.enigma',
'onclick' => "rcmail.command('menu-open', 'enigmamenu', event.target, event)",
'class' => 'button enigma',
'title' => 'encryptionoptions',
'label' => 'encryption',
'domain' => $this->enigma->ID,
'width' => 32,
'height' => 32,
'aria-owns' => 'enigmamenu',
'aria-haspopup' => 'true',
'aria-expanded' => 'false',
), 'toolbar');
// Options menu contents
$this->rc->output->add_footer($this->compose_ui_options(true));
}
}
/**
* Init compose UI (add task button and the menu)
*/
private function compose_ui_options($wrap = false)
{
$locks = (array) $this->rc->config->get('enigma_options_lock');
$menu = new html_table(array('cols' => 2));
$chbox = new html_checkbox(array('value' => 1));
$menu->add(null, html::label(array('for' => 'enigmasignopt'),
rcube::Q($this->enigma->gettext('signmsg'))));
$menu->add(null, $chbox->show($this->rc->config->get('enigma_sign_all') ? 1 : 0,
array(
'name' => '_enigma_sign',
'id' => 'enigmasignopt',
'disabled' => in_array('sign', $locks),
)));
$menu->add(null, html::label(array('for' => 'enigmaencryptopt'),
rcube::Q($this->enigma->gettext('encryptmsg'))));
$menu->add(null, $chbox->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0,
array(
'name' => '_enigma_encrypt',
'id' => 'enigmaencryptopt',
'disabled' => in_array('encrypt', $locks),
)));
$menu->add(null, html::label(array('for' => 'enigmaattachpubkeyopt'),
rcube::Q($this->enigma->gettext('attachpubkeymsg'))));
$menu->add(null, $chbox->show($this->rc->config->get('enigma_attach_pubkey') ? 1 : 0,
array(
'name' => '_enigma_attachpubkey',
'id' => 'enigmaattachpubkeyopt',
'disabled' => in_array('pubkey', $locks),
)));
$menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), $menu->show());
// Options menu contents
$this->rc->output->add_footer($menu);
$this->rc->output->add_label('enigma.sendunencrypted');
$out = html::div('form-group form-check row',
html::label(array('for' => 'enigmasignopt', 'class' => 'col-form-label col-6'),
rcube::Q($this->enigma->gettext('signmsg')))
. html::div('form-check col-6',
$chbox->show($this->rc->config->get('enigma_sign_all') ? 1 : 0, array(
'name' => '_enigma_sign',
'id' => 'enigmasignopt',
'class' => 'form-check-input',
'disabled' => in_array('sign', $locks),
))));
$out .= html::div('form-group form-check row',
html::label(array('for' => 'enigmaencryptopt', 'class' => 'col-form-label col-6'),
rcube::Q($this->enigma->gettext('encryptmsg')))
. html::div('form-check col-6',
$chbox->show($this->rc->config->get('enigma_encrypt_all') ? 1 : 0, array(
'name' => '_enigma_encrypt',
'id' => 'enigmaencryptopt',
'class' => 'form-check-input',
'disabled' => in_array('encrypt', $locks),
))));
$out .= html::div('form-group form-check row',
html::label(array('for' => 'enigmaattachpubkeyopt', 'class' => 'col-form-label col-6'),
rcube::Q($this->enigma->gettext('attachpubkeymsg')))
. html::div('form-check col-6',
$chbox->show($this->rc->config->get('enigma_attach_pubkey') ? 1 : 0, array(
'name' => '_enigma_attachpubkey',
'id' => 'enigmaattachpubkeyopt',
'class' => 'form-check-input',
'disabled' => in_array('pubkey', $locks),
))));
if (!$wrap) {
return $out;
}
return html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), $out);
}
/**

@ -27,6 +27,7 @@ $labels['keyuserid'] = 'User ID';
$labels['keytype'] = 'Key type';
$labels['fingerprint'] = 'Fingerprint';
$labels['subkeys'] = 'Subkeys';
$labels['keyprops'] = 'Key properties';
$labels['basicinfo'] = 'Basic Information';
$labels['userids'] = 'Additional Users';
$labels['typepublickey'] = 'public key';
@ -68,10 +69,10 @@ $labels['keyrevoke'] = 'Revoke';
$labels['keysend'] = 'Send public key in a message';
$labels['keychpass'] = 'Change password';
$labels['newkeyident'] = 'Identity:';
$labels['newkeypass'] = 'Password:';
$labels['newkeypassconfirm'] = 'Confirm password:';
$labels['newkeysize'] = 'Key size:';
$labels['newkeyident'] = 'Identity';
$labels['newkeypass'] = 'Password';
$labels['newkeypassconfirm'] = 'Confirm password';
$labels['newkeysize'] = 'Key size';
$labels['key2048'] = '2048 bits - default';
$labels['key4096'] = '4096 bits - more secure';
$labels['keygenerating'] = 'Generating keys...';

@ -73,6 +73,26 @@ p.enigmaattachment a
background: url(enigma.png) 0 0 no-repeat;
}
#enigmamenu div.row {
display: table-row;
}
#enigmamenu div.row > label {
display: table-cell;
width: 99%;
padding: 3px;
}
#enigmamenu div.row > div {
display: table-cell;
width: 1%;
padding: 3px;
}
#enigmamenu input {
vertical-align: middle;
}
/***** Keys/Certs Management *****/
#mainscreen.enigma
@ -224,3 +244,11 @@ div.enigmascreen
width: 5px;
background-position: -166px 0;
}
#keystoolbar a.search {
background: url(../../../../skins/classic/images/abook_toolbar.png) -170px 0 no-repeat transparent;
}
#keystoolbar a.searchSel {
background: url(../../../../skins/classic/images/abook_toolbar.png) -170px -32px no-repeat transparent;
}

@ -6,10 +6,8 @@
</head>
<body class="iframe">
<div id="keyimport-title" class="boxtitle"><roundcube:label name="enigma.importkeys" /></div>
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" id="keyimportform" />
<roundcube:object name="importform" id="keyimportform" part="import" />
</div>
</body>

@ -21,6 +21,7 @@
<div id="keystoolbar">
<roundcube:button command="plugin.enigma-key-create" type="link" class="buttonPas create" classAct="button create" classSel="button createSel" title="enigma.createkeys" content=" " />
<roundcube:button command="plugin.enigma-key-import" type="link" class="buttonPas import" classAct="button import" classSel="button importSel" title="enigma.importkeys" content=" " />
<roundcube:button command="plugin.enigma-key-import-search" type="link" class="buttonPas search" classAct="button search" classSel="button searchSel" title="enigma.keyimportsearchlabel" content=" " />
<span class="dropbutton">
<roundcube:button command="plugin.enigma-key-export" type="link" class="buttonPas export" classAct="button export" classSel="button exportSel" title="enigma.exportkeys" content=" " />
<span id="exportmenulink" onclick="rcmail_ui.show_popup('exportmenu');return false"></span>

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe">
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" id="keyimportform" part="search" />
</div>
</body>
</html>

@ -0,0 +1,13 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="enigma.createkeys" /></h1>
<div class="formcontent">
<roundcube:object name="keyform" class="propform" textarearows="6" />
</div>
<div class="formbuttons">
<roundcube:button command="plugin.enigma-key-save" class="btn btn-primary submit" label="save" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,9 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="enigma.importkeys" /></h1>
<div class="formcontent">
<roundcube:object name="importform" class="propform" part="import" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,9 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="enigma.keyprops" /></h1>
<div class="formcontent">
<roundcube:object name="keydata" class="propform" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,82 @@
<roundcube:include file="includes/layout.html" />
<roundcube:include file="includes/menu.html" />
<roundcube:include file="includes/settings-menu.html" />
<h1 class="voice"><roundcube:label name="settings" /> : <roundcube:label name="enigma.enigmakeys" /></h1>
<!-- keys list -->
<div class="list listbox selected" aria-labelledby="aria-label-enigmakeyslist">
<div class="header">
<a class="button icon menu-button" href="#menu"><span class="inner"><roundcube:label name="menu" /></span></a>
<a class="button icon back-sidebar-button" href="#sidebar"><span class="inner"><roundcube:label name="settings" /></span></a>
<span id="aria-label-enigmakeyslist" class="header-title"><roundcube:label name="enigma.enigmakeys" /></span>
<roundcube:object name="searchform" id="keysearch" wrapper="searchbar toolbar"
label="keysearchform" buttontitle="findkeys" ariatag="h2" />
<a class="button icon toolbar-menu-button" href="#list-menu"><span class="inner"><roundcube:label name="menu" /></span></a>
</div>
<div class="pagenav toolbar" role="toolbar">
<roundcube:button command="firstpage" type="link"
class="button firstpage disabled" classAct="button firstpage"
title="firstpage" label="first" innerclass="inner" />
<roundcube:button command="previouspage" type="link"
class="button prevpage disabled" classAct="button prevpage"
title="previouspage" label="previous" innerclass="inner" />
<span class="pagenav-text" aria-live="polite" aria-relevant="text">
<roundcube:object name="countdisplay" />
</span>
<roundcube:endif />
<roundcube:button command="nextpage" type="link"
class="button nextpage disabled" classAct="button nextpage"
title="nextpage" label="next" innerclass="inner" />
<roundcube:button command="lastpage" type="link"
class="button lastpage disabled" classAct="button lastpage"
title="lastpage" label="last" innerclass="inner" />
</div>
<div class="scroller">
<roundcube:object name="keyslist" id="keys-table" class="listing" role="listbox" noheader="true" data-list="keys_list" />
</div>
</div>
<!-- key info frame -->
<div class="content" role="main">
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
<div class="header" role="toolbar" aria-labelledby="aria-label-toolbar">
<a class="button icon back-list-button" href="#back"><span class="inner"><roundcube:label name="back" /></span></a>
<span class="header-title"></span>
<!-- toolbar -->
<div id="folderstoolbar" class="toolbar">
<roundcube:button command="plugin.enigma-key-create" type="link"
class="button create disabled" classAct="button create"
label="create" title="enigma.createkeys" innerClass="inner" />
<roundcube:button command="plugin.enigma-key-delete" type="link"
class="button delete disabled" classAct="button delete"
label="delete" title="enigma.keyremove" innerClass="inner" />
<span class="spacer"></span>
<roundcube:button command="plugin.enigma-key-import-search" type="link"
class="button search disabled" classAct="button search"
label="search" title="enigma.keyimportsearchlabel" innerClass="inner" />
<roundcube:button command="plugin.enigma-key-import" type="link"
class="button import disabled" classAct="button import"
label="import" title="enigma.importkeys" innerClass="inner" />
<span class="dropbutton">
<roundcube:button command="plugin.enigma-key-export" type="link"
class="button export disabled" classAct="button export"
label="export" title="enigma.exportkeys" innerclass="inner" />
<a href="#export" class="button dropdown" data-popup="export-menu">
<span class="inner"><roundcube:label name="enigma.arialabelkeyexportoptions" /></span>
</a>
</span>
</div>
</div>
<roundcube:object name="keyframe" id="keyframe" src="/watermark.html" />
</div>
<div id="export-menu" class="popupmenu">
<h3 id="aria-label-exportmenu" class="voice"><roundcube:label name="enigma.arialabelkeyexportoptions" /></h3>
<ul class="toolbarmenu listing" role="menu" aria-labelledby="aria-label-export-menu">
<roundcube:button type="link-menuitem" command="plugin.enigma-key-export" label="exportall" prop="sub" class="export all" classAct="export all active" />
<roundcube:button type="link-menuitem" command="plugin.enigma-key-export-selected" label="exportsel" prop="sub" class="export selection" classAct="export selection active" />
</ul>
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,9 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="enigma.keyimportsearchlabel" /></h1>
<div class="formcontent">
<roundcube:object name="importform" class="propform" part="search" />
</div>
<roundcube:include file="includes/footer.html" />

@ -73,6 +73,21 @@ p.enigmaattachment a {
padding: 2px 5px;
}
#enigmamenu div.row {
display: table-row;
}
#enigmamenu div.row > label {
display: table-cell;
width: 99%;
padding: 3px;
}
#enigmamenu div.row > div {
display: table-cell;
width: 1%;
padding: 3px;
}
/***** Keys/Certs Management *****/
@ -161,15 +176,10 @@ p.enigmaattachment a {
z-index: 10;
}
#keystoolbar a.button
{
background: url(enigma_icons.png) 0 0 no-repeat transparent;
}
#keystoolbar a.import {
background-position: center 0;
background: url(enigma_icons.png) center 0 no-repeat transparent;
}
#keystoolbar a.export {
background-position: center -40px;
background: url(enigma_icons.png) center -40px no-repeat transparent;
}

@ -4,12 +4,12 @@
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe">
<body class="iframe fullheight">
<h1 class="boxtitle"><roundcube:label name="enigma.importkeys" /></h1>
<h1 class="voice"><roundcube:label name="enigma.importkeys" /></h1>
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" class="propform" id="keyimportform" />
<roundcube:object name="importform" class="propform" id="keyimportform" part="import" />
</div>
<roundcube:include file="/includes/footer.html" />

@ -14,6 +14,7 @@
<!-- toolbar -->
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
<div id="keystoolbar" class="toolbar" role="toolbar" aria-labelledby="aria-label-toolbar">
<roundcube:button command="plugin.enigma-key-import-search" type="link" class="button search disabled" classAct="button search" classSel="button search pressed" label="search" title="enigma.keyimportsearchlabel" />
<roundcube:button command="plugin.enigma-key-import" type="link" class="button import disabled" classAct="button import" classSel="button import pressed" label="import" title="enigma.importkeys" />
<span class="dropbutton">
<roundcube:button command="plugin.enigma-key-export" type="link" class="button export disabled" classAct="button export" classSel="button export pressed" label="export" title="enigma.exportkeys" />
@ -34,7 +35,7 @@
<label for="quicksearchbox" class="voice"><roundcube:label name="arialabelmailquicksearchbox" /></label>
<roundcube:object name="searchform" id="quicksearchbox" />
<a id="searchmenulink" class="iconbutton searchicon" > </a>
<roundcube:button command="reset-search" id="searchreset" class="iconbutton reset" title="resetsearch" label="resetsearch" />
<roundcube:button command="reset-search" id="searchreset" type="link" class="iconbutton reset" title="resetsearch" label="resetsearch" />
</div>
<roundcube:include file="/includes/settingstabs.html" />
@ -70,7 +71,7 @@
<div id="keyoptions" class="popupmenu">
<ul class="toolbarmenu">
<li><roundcube:button class="deletelink" command="plugin.enigma-key-delete" label="enigma.keyremove" target="_blank" classAct="deletelink active" /></li>
<li><roundcube:button class="deletelink" type="link" command="plugin.enigma-key-delete" label="enigma.keyremove" target="_blank" classAct="deletelink active" /></li>
<!--
<li><roundcube:button class="disablelink" command="enigma.key-disable" label="enigma.keydisable" target="_blank" classAct="disablelink active" /></li>
<li><roundcube:button class="revokelink" command="enigma.key-revoke" label="enigma.keyrevoke" classAct="revokelink active" /></li>

@ -0,0 +1,18 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe fullheight">
<h1 class="voice"><roundcube:label name="enigma.importkeys" /></h1>
<div id="import-form" class="boxcontent">
<roundcube:object name="importform" class="propform" id="keyimportform" part="search" />
</div>
<roundcube:include file="/includes/footer.html" />
</body>
</html>

@ -1,4 +1,3 @@
<div id="helplicense" class="readtext">
<h2 style="text-align: center;">GNU GENERAL PUBLIC LICENSE</h2>
<p style="text-align: center;">Version 3, 29 June 2007</p>
@ -685,5 +684,3 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
&lt;<a href="http://www.gnu.org/philosophy/why-not-lgpl.html">http://www.gnu.org/philosophy/why-not-lgpl.html</a>&gt;.</p>
</div>

@ -33,6 +33,55 @@ if (window.rcmail) {
}
return false;
}
});
}
});
rcmail.addEventListener('init', function(prop) {
if (rcmail.env.contentframe && rcmail.task == 'help') {
$('#' + rcmail.env.contentframe).on('load error', function(e) {
// Unlock UI
rcmail.set_busy(false, null, rcmail.env.frame_lock);
rcmail.env.frame_lock = null;
// Select menu item
if (e.type == 'load') {
$(rcmail.env.help_action_item).parents('ul').children().removeClass('selected');
$(rcmail.env.help_action_item).parent().addClass('selected');
}
});
try {
var win = rcmail.get_frame_window(rcmail.env.contentframe);
if (win && win.location.href.indexOf(rcmail.env.blankpage) >= 0) {
show_help_content(rcmail.env.action);
}
}
catch (e) { /* ignore */}
}
});
}
function show_help_content(action, event)
{
var win, target = window,
url = rcmail.env.help_links[action];
if (win = rcmail.get_frame_window(rcmail.env.contentframe)) {
target = win;
url += (url.indexOf('?') > -1 ? '&' : '?') + '_framed=1';
}
if (rcmail.env.extwin) {
url += (url.indexOf('?') > -1 ? '&' : '?') + '_extwin=1';
}
if (/^self/.test(url)) {
url = url.substr(4) + '&_content=1&_task=help&_action=' + action;
}
rcmail.env.help_action_item = event ? event.target : $('[rel="' + action + '"]');
rcmail.show_contentframe(true);
rcmail.location_href(url, target, true);
return false;
}

@ -17,8 +17,6 @@ class help extends rcube_plugin
public $task = '?(?!login|logout).*';
// we've got no ajax handlers
public $noajax = true;
// skip frames
public $noframe = true;
function init()
{
@ -41,44 +39,62 @@ class help extends rcube_plugin
{
$rcmail = rcmail::get_instance();
// add taskbar button
$this->add_button(array(
'command' => 'help',
'class' => 'button-help',
'classsel' => 'button-help button-selected',
'innerclass' => 'button-inner',
'label' => 'help.help',
'type' => 'link',
), 'taskbar');
$this->include_script('help.js');
$rcmail->output->set_env('help_open_extwin', $rcmail->config->get('help_open_extwin', false), true);
if (!$rcmail->output->framed) {
// add taskbar button
$this->add_button(array(
'command' => 'help',
'class' => 'button-help',
'classsel' => 'button-help button-selected',
'innerclass' => 'button-inner',
'label' => 'help.help',
'type' => 'link',
), 'taskbar');
$this->include_script('help.js');
$rcmail->output->set_env('help_open_extwin', $rcmail->config->get('help_open_extwin', false), true);
}
// add style for taskbar button (must be here) and Help UI
$skin_path = $this->local_skin_path();
if (is_file($this->home . "/$skin_path/help.css")) {
$this->include_stylesheet("$skin_path/help.css");
}
$this->include_stylesheet($this->local_skin_path() . '/help.css', true);
}
function action()
{
$rcmail = rcmail::get_instance();
if ($rcmail->action == 'about') {
$rcmail->output->set_pagetitle($this->gettext('about'));
}
else if ($rcmail->action == 'license') {
$rcmail->output->set_pagetitle($this->gettext('license'));
}
else {
$rcmail->output->set_pagetitle($this->gettext('help'));
}
// register UI objects
$rcmail->output->add_handlers(array(
'helpcontent' => array($this, 'content'),
'tablink' => array($this, 'tablink'),
'contentframe' => array($this, 'content_frame'),
'helpcontent' => array($this, 'help_content'),
'tablink' => array($this, 'tablink'),
));
if ($rcmail->action == 'about')
$rcmail->output->set_pagetitle($this->gettext('about'));
else if ($rcmail->action == 'license')
$rcmail->output->set_pagetitle($this->gettext('license'));
else
$rcmail->output->set_pagetitle($this->gettext('help'));
$rcmail->output->send(!empty($_GET['_content']) ? 'help.content' : 'help.help');
}
$rcmail->output->send('help.help');
function help_content($attrib)
{
$rcmail = rcmail::get_instance();
// $rcmail->output->set_env('content', $content);
if (!empty($_GET['_content'])) {
if ($rcmail->action == 'about') {
return file_get_contents($this->home . '/content/about.html');
}
else if ($rcmail->action == 'license') {
return file_get_contents($this->home . '/content/license.html');
}
}
}
function tablink($attrib)
@ -87,59 +103,69 @@ class help extends rcube_plugin
$attrib['name'] = 'helplink' . $attrib['action'];
$attrib['href'] = $rcmail->url(array('_action' => $attrib['action'], '_extwin' => !empty($_REQUEST['_extwin']) ? 1 : null));
$attrib['rel'] = $attrib['action'];
// title might be already translated here, so revert to it's initial value
// so button() will translate it correctly
$attrib['title'] = $attrib['label'];
$attrib['onclick'] = sprintf("return show_help_content('%s', event)", $attrib['action']);
return $rcmail->output->button($attrib);
}
function content($attrib)
function content_frame($attrib)
{
$rcmail = rcmail::get_instance();
$rcmail = rcmail::get_instance();
$content = $this->help_metadata();
$src = $content[$rcmail->action] ?: $content['index'];
switch ($rcmail->action) {
case 'about':
if (is_readable($this->home . '/content/about.html')) {
return @file_get_contents($this->home . '/content/about.html');
}
$default = $rcmail->url(array('_task' => 'settings', '_action' => 'about', '_framed' => 1));
$src = $rcmail->config->get('help_about_url', $default);
break;
case 'license':
if (is_readable($this->home . '/content/license.html')) {
return @file_get_contents($this->home . '/content/license.html');
}
$src = $rcmail->config->get('help_license_url', 'http://www.gnu.org/licenses/gpl-3.0-standalone.html');
break;
default:
$src = $rcmail->config->get('help_source');
// resolve task/action for depp linking
$index_map = $rcmail->config->get('help_index_map', array());
$rel = $_REQUEST['_rel'];
list($task,$action) = explode('/', $rel);
if ($add = $index_map[$rel])
$src .= $add;
else if ($add = $index_map[$task])
$src .= $add;
break;
$rcmail->output->set_env('help_links', $content);
return $rcmail->output->frame($attrib, true);
}
function help_metadata()
{
$rcmail = rcmail::get_instance();
$content = array();
// About
if (is_readable($this->home . '/content/about.html')) {
$content['about'] = 'self';
}
else {
$default = $rcmail->url(array('_task' => 'settings', '_action' => 'about', '_framed' => 1));
$content['about'] = $rcmail->config->get('help_about_url', $default);
$content['about'] = $this->resolve_language($content['about']);
}
// default content: iframe
if (!empty($src)) {
$attrib['src'] = $this->resolve_language($src);
// License
if (is_readable($this->home . '/content/license.html')) {
$content['license'] = 'self';
}
else {
$content['license'] = $rcmail->config->get('help_license_url', 'http://www.gnu.org/licenses/gpl-3.0-standalone.html');
$content['license'] = $this->resolve_language($content['license']);
}
if (empty($attrib['id']))
$attrib['id'] = 'rcmailhelpcontent';
// Help Index
$src = $rcmail->config->get('help_source', 'http://docs.roundcube.net/doc/help/1.1/%l/');
$index_map = $rcmail->config->get('help_index_map', array());
// resolve task/action for deep linking
$rel = $_REQUEST['_rel'];
list($task, $action) = explode('/', $rel);
if ($add = $index_map[$rel]) {
$src .= $add;
}
else if ($add = $index_map[$task]) {
$src .= $add;
}
$attrib['name'] = $attrib['id'];
$content['index'] = $this->resolve_language($src);
return $rcmail->output->frame($attrib);
return $content;
}
function error_page($args)

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
<script type="text/javascript" src="/functions.js"></script>
</head>
<body class="iframe" style="margin-top:0">
<div id="help-<roundcube:var name="env:action" />" class="boxcontent">
<roundcube:object name="helpcontent" />
</div>
</body>
</html>

@ -12,6 +12,13 @@ function help_init_settings_tabs()
tab = '#helptab' + (action ? action : 'index');
}
$(tab).addClass('tablink-selected');
$('#' + rcmail.env.contentframe).on('load error', function(e) {
if (e.type == 'load') {
$(rcmail.env.help_action_item).parents('#tabsbar').children().removeClass('tablink-selected');
$(rcmail.env.help_action_item).parent().addClass('tablink-selected');
}
});
}
</script>
</head>
@ -34,7 +41,7 @@ function help_init_settings_tabs()
</div>
<div id="mainscreen" class="box help-box">
<roundcube:object name="helpcontent" id="helpcontentframe" width="100%" height="100%" frameborder="0" src="/watermark.html" />
<roundcube:object name="contentframe" id="helpcontentframe" width="100%" height="100%" frameborder="0" src="/watermark.html" />
</div>
</body>

@ -0,0 +1,9 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:object name="steptitle" /></h1>
<div id="help-<roundcube:var name="env:action" />" class="content frame-content">
<roundcube:object name="helpcontent" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,29 @@
<roundcube:include file="includes/layout.html" />
<roundcube:include file="includes/menu.html" />
<div id="sidebar" class="sidebar listbox" role="navigation" aria-labelledby="aria-label-helpnav">
<div class="header">
<a class="button icon menu-button" href="#menu"><span class="inner"><roundcube:label name="menu" /></span></a>
<span id="aria-label-helpnav" class="header-title"><roundcube:label name="help.help" /></span>
</div>
<div class="scroller">
<ul class="listing iconized" data-menu="toolbar-small">
<roundcube:object name="tablink" action="index" type="link-menuitem" label="help.help" class="help" />
<roundcube:object name="tablink" action="about" type="link-menuitem" label="help.about" class="about" />
<roundcube:object name="tablink" action="license" type="link-menuitem" label="help.license" class="license" />
<roundcube:container name="helptabs" id="helptabsbar" />
</ul>
</div>
</div>
<h1 class="voice"><roundcube:label name="help.help" /></h1>
<div id="content" class="content selected" role="main">
<div class="header">
<a class="button icon menu-button" href="#menu"><span class="inner"><roundcube:label name="menu" /></span></a>
<span class="header-title"><roundcube:label name="help.help" /></span>
</div>
<roundcube:object name="contentframe" id="helpcontentframe" src="/watermark.html" title="arialabelhelpcontent" />
</div>
<roundcube:include file="includes/footer.html" />

@ -38,7 +38,3 @@
.toolbar a.button.license {
background: url(help.png) center -130px no-repeat;
}
.iframebox.help_license {
overflow: auto;
}

@ -0,0 +1,16 @@
<roundcube:object name="doctype" value="html5" />
<html>
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="iframe fullheight">
<div id="help-<roundcube:var name="env:action" />" class="boxcontent">
<roundcube:object name="helpcontent" />
</div>
<roundcube:include file="/includes/footer.html" />
</body>
</html>

@ -19,7 +19,7 @@
<div id="pluginbody" class="uibox offset">
<div class="iframebox help_<roundcube:var name='env:action' />">
<roundcube:object name="helpcontent" id="helpcontentframe" style="width:100%; height:100%" frameborder="0" src="/watermark.html" />
<roundcube:object name="contentframe" id="helpcontentframe" style="width:100%; height:100%" frameborder="0" src="/watermark.html" />
</div>
</div>

@ -49,7 +49,7 @@ function hide_blockquote()
var t = $(this), parent = t.data('parent'), visible = parent.is(':visible');
t.text(rcmail.get_label(visible ? 'hide' : 'show', 'hide_blockquote'))
.detach().appendTo(visible ? q : parent);
.detach().appendTo(visible ? q : parent).toggleClass('collapsed');
parent[visible ? 'hide' : 'show']();
q[visible ? 'show' : 'hide']();

@ -26,7 +26,7 @@ class hide_blockquote extends rcube_plugin
&& ($limit = $rcmail->config->get('hide_blockquote_limit'))
) {
// include styles
$this->include_stylesheet($this->local_skin_path() . "/style.css");
$this->include_stylesheet($this->local_skin_path() . "/style.css", true);
// Script and localization
$this->include_script('hide_blockquote.js');
@ -58,7 +58,7 @@ class hide_blockquote extends rcube_plugin
$input = new html_inputfield(array('name' => '_'.$field_id, 'id' => $field_id, 'size' => 5));
$args['blocks']['main']['options']['hide_blockquote_limit'] = array(
'title' => $this->gettext('quotelimit'),
'title' => html::label($field_id, $this->gettext('quotelimit')),
'content' => $input->show($limit ?: '')
);

@ -94,9 +94,12 @@ class jqueryui extends rcube_plugin
$css = "plugins/jqueryui/themes/larry/jquery.minicolors.css";
}
$colors_theme = $rcube->config->get('jquery_ui_colors_theme', 'default');
$conf = rcube_output::json_serialize(array('theme' => $colors_theme));
$rcube->output->include_css($css);
$rcube->output->add_header(html::tag('script', array('type' => "text/javascript", 'src' => $script)));
$rcube->output->add_script('$.fn.miniColors = $.fn.minicolors; $("input.colors").minicolors()', 'docready');
$rcube->output->add_script('$.fn.miniColors = $.fn.minicolors; $("input.colors").minicolors(' . $conf . ')', 'docready');
}
public static function tagedit()

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,272 @@
.minicolors {
position: relative;
}
.minicolors-sprite {
background-image: url(images/jquery.minicolors.png);
}
.minicolors-swatch {
position: absolute;
vertical-align: middle;
background-position: -80px 0;
cursor: text;
padding: 0;
margin: 0;
display: inline-block;
}
.minicolors-swatch-color {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.minicolors input[type=hidden] + .minicolors-swatch {
width: 28px;
position: static;
cursor: pointer;
}
.minicolors input[type=hidden][disabled] + .minicolors-swatch {
cursor: default;
}
/* Panel */
.minicolors-panel {
position: absolute;
width: 173px;
background: white;
z-index: 99999;
box-sizing: content-box;
display: none;
}
.minicolors-panel.minicolors-visible {
display: block;
}
/* Panel positioning */
.minicolors-position-top .minicolors-panel {
top: -154px;
}
.minicolors-position-right .minicolors-panel {
right: 0;
}
.minicolors-position-bottom .minicolors-panel {
top: auto;
}
.minicolors-position-left .minicolors-panel {
left: 0;
}
.minicolors-with-opacity .minicolors-panel {
width: 194px;
}
.minicolors .minicolors-grid {
position: relative;
top: 1px;
left: 1px;
width: 150px;
height: 150px;
background-position: -120px 0;
cursor: crosshair;
}
.minicolors .minicolors-grid-inner {
position: absolute;
top: 0;
left: 0;
width: 150px;
height: 150px;
}
.minicolors-slider-saturation .minicolors-grid {
background-position: -420px 0;
}
.minicolors-slider-saturation .minicolors-grid-inner {
background-position: -270px 0;
background-image: inherit;
}
.minicolors-slider-brightness .minicolors-grid {
background-position: -570px 0;
}
.minicolors-slider-brightness .minicolors-grid-inner {
background-color: black;
}
.minicolors-slider-wheel .minicolors-grid {
background-position: -720px 0;
}
.minicolors-slider,
.minicolors-opacity-slider {
position: absolute;
top: 2px;
left: 153px;
width: 20px;
height: 150px;
background-color: white;
background-position: 0 0;
cursor: row-resize;
}
.minicolors-slider-saturation .minicolors-slider {
background-position: -60px 0;
}
.minicolors-slider-brightness .minicolors-slider {
background-position: -20px 0;
}
.minicolors-slider-wheel .minicolors-slider {
background-position: -20px 0;
}
.minicolors-opacity-slider {
left: 173px;
background-position: -40px 0;
display: none;
}
.minicolors-with-opacity .minicolors-opacity-slider {
display: block;
}
/* Pickers */
.minicolors-grid .minicolors-picker {
position: absolute;
top: 70px;
left: 70px;
width: 12px;
height: 12px;
border: solid 1px black;
border-radius: 10px;
margin-top: -6px;
margin-left: -6px;
background: none;
}
.minicolors-grid .minicolors-picker > div {
position: absolute;
top: 0;
left: 0;
width: 8px;
height: 8px;
border-radius: 8px;
border: solid 2px white;
box-sizing: content-box;
}
.minicolors-picker {
position: absolute;
top: 0;
left: 0;
width: 18px;
height: 2px;
background: white;
border: solid 1px black;
margin-top: -2px;
box-sizing: content-box;
}
/* Swatches */
.minicolors-swatches,
.minicolors-swatches li {
margin: 5px 0 3px 5px;
padding: 0;
list-style: none;
overflow: hidden;
}
.minicolors-swatches .minicolors-swatch {
position: relative;
float: left;
cursor: pointer;
margin:0 4px 0 0;
}
.minicolors-with-opacity .minicolors-swatches .minicolors-swatch {
margin-right: 7px;
}
.minicolors-swatch.selected {
border-color: #000;
}
/* Inline controls */
.minicolors-inline {
display: inline-block;
}
.minicolors-inline .minicolors-input {
display: none !important;
}
.minicolors-inline .minicolors-panel {
position: relative;
top: auto;
left: auto;
box-shadow: none;
z-index: auto;
display: inline-block;
}
/* Bootstrap theme */
.minicolors-theme-bootstrap .minicolors-swatch {
z-index: 2;
top: 4px;
left: 4px;
width: 26px;
height: 26px;
border-radius: .3rem;
}
.minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {
margin-bottom: 2px;
top: 0;
left: 0;
width: 20px;
height: 20px;
}
.minicolors-theme-bootstrap .minicolors-swatch-color {
border-radius: inherit;
}
.minicolors-theme-bootstrap.minicolors-position-right > .minicolors-swatch {
left: auto;
right: 3px;
}
.minicolors-theme-bootstrap .minicolors-input {
padding-left: 34px;
}
.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {
padding-right: 34px;
padding-left: 12px;
}
.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {
top: 4px;
left: 4px;
width: 37px;
height: 37px;
border-radius: 5px;
}
.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch {
width: 24px;
height: 24px;
}
.minicolors-theme-bootstrap .minicolors-input.input-xs + .minicolors-swatch {
width: 18px;
height: 18px;
}
.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

@ -0,0 +1,319 @@
.minicolors {
position: relative;
}
.minicolors-sprite {
background-image: url(images/jquery.minicolors.png);
}
.minicolors-swatch {
position: absolute;
vertical-align: middle;
background-position: -80px 0;
border: solid 1px #ccc;
cursor: text;
padding: 0;
margin: 0;
display: inline-block;
}
.minicolors-swatch-color {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.minicolors input[type=hidden] + .minicolors-swatch {
width: 28px;
position: static;
cursor: pointer;
}
.minicolors input[type=hidden][disabled] + .minicolors-swatch {
cursor: default;
}
/* Panel */
.minicolors-panel {
position: absolute;
width: 173px;
background: white;
border: solid 1px #CCC;
box-shadow: 0 0 20px rgba(0, 0, 0, .2);
z-index: 99999;
box-sizing: content-box;
display: none;
}
.minicolors-panel.minicolors-visible {
display: block;
}
/* Panel positioning */
.minicolors-position-top .minicolors-panel {
top: -154px;
}
.minicolors-position-right .minicolors-panel {
right: 0;
}
.minicolors-position-bottom .minicolors-panel {
top: auto;
}
.minicolors-position-left .minicolors-panel {
left: 0;
}
.minicolors-with-opacity .minicolors-panel {
width: 194px;
}
.minicolors .minicolors-grid {
position: relative;
top: 1px;
left: 1px;
width: 150px;
height: 150px;
background-position: -120px 0;
cursor: crosshair;
}
.minicolors .minicolors-grid-inner {
position: absolute;
top: 0;
left: 0;
width: 150px;
height: 150px;
}
.minicolors-slider-saturation .minicolors-grid {
background-position: -420px 0;
}
.minicolors-slider-saturation .minicolors-grid-inner {
background-position: -270px 0;
background-image: inherit;
}
.minicolors-slider-brightness .minicolors-grid {
background-position: -570px 0;
}
.minicolors-slider-brightness .minicolors-grid-inner {
background-color: black;
}
.minicolors-slider-wheel .minicolors-grid {
background-position: -720px 0;
}
.minicolors-slider,
.minicolors-opacity-slider {
position: absolute;
top: 1px;
left: 152px;
width: 20px;
height: 150px;
background-color: white;
background-position: 0 0;
cursor: row-resize;
}
.minicolors-slider-saturation .minicolors-slider {
background-position: -60px 0;
}
.minicolors-slider-brightness .minicolors-slider {
background-position: -20px 0;
}
.minicolors-slider-wheel .minicolors-slider {
background-position: -20px 0;
}
.minicolors-opacity-slider {
left: 173px;
background-position: -40px 0;
display: none;
}
.minicolors-with-opacity .minicolors-opacity-slider {
display: block;
}
/* Pickers */
.minicolors-grid .minicolors-picker {
position: absolute;
top: 70px;
left: 70px;
width: 12px;
height: 12px;
border: solid 1px black;
border-radius: 10px;
margin-top: -6px;
margin-left: -6px;
background: none;
}
.minicolors-grid .minicolors-picker > div {
position: absolute;
top: 0;
left: 0;
width: 8px;
height: 8px;
border-radius: 8px;
border: solid 2px white;
box-sizing: content-box;
}
.minicolors-picker {
position: absolute;
top: 0;
left: 0;
width: 18px;
height: 2px;
background: white;
border: solid 1px black;
margin-top: -2px;
box-sizing: content-box;
}
/* Swatches */
.minicolors-swatches,
.minicolors-swatches li {
margin: 5px 0 3px 5px;
padding: 0;
list-style: none;
overflow: hidden;
}
.minicolors-swatches .minicolors-swatch {
position: relative;
float: left;
cursor: pointer;
margin:0 4px 0 0;
}
.minicolors-with-opacity .minicolors-swatches .minicolors-swatch {
margin-right: 7px;
}
.minicolors-swatch.selected {
border-color: #000;
}
/* Inline controls */
.minicolors-inline {
display: inline-block;
}
.minicolors-inline .minicolors-input {
display: none !important;
}
.minicolors-inline .minicolors-panel {
position: relative;
top: auto;
left: auto;
box-shadow: none;
z-index: auto;
display: inline-block;
}
/* Default theme */
.minicolors-theme-default .minicolors-swatch {
top: 5px;
left: 5px;
width: 18px;
height: 18px;
}
.minicolors-theme-default .minicolors-swatches .minicolors-swatch {
margin-bottom: 2px;
top: 0;
left: 0;
width: 18px;
height: 18px;
}
.minicolors-theme-default.minicolors-position-right .minicolors-swatch {
left: auto;
right: 5px;
}
.minicolors-theme-default.minicolors {
width: auto;
display: inline-block;
}
.minicolors-theme-default .minicolors-input {
height: 20px;
width: auto;
display: inline-block;
padding-left: 26px;
}
.minicolors-theme-default.minicolors-position-right .minicolors-input {
padding-right: 26px;
padding-left: inherit;
}
/* Bootstrap theme */
.minicolors-theme-bootstrap .minicolors-swatch {
z-index: 2;
top: 3px;
left: 3px;
width: 28px;
height: 28px;
border-radius: 3px;
}
.minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {
margin-bottom: 2px;
top: 0;
left: 0;
width: 20px;
height: 20px;
}
.minicolors-theme-bootstrap .minicolors-swatch-color {
border-radius: inherit;
}
.minicolors-theme-bootstrap.minicolors-position-right > .minicolors-swatch {
left: auto;
right: 3px;
}
.minicolors-theme-bootstrap .minicolors-input {
float: none;
padding-left: 44px;
}
.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {
padding-right: 44px;
padding-left: 12px;
}
.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {
top: 4px;
left: 4px;
width: 37px;
height: 37px;
border-radius: 5px;
}
.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch {
width: 24px;
height: 24px;
}
.minicolors-theme-bootstrap .minicolors-input.input-xs + .minicolors-swatch {
width: 18px;
height: 18px;
}
.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* Semantic Ui theme */
.minicolors-theme-semanticui .minicolors-swatch {
top: 0;
left: 0;
padding: 18px;
}
.minicolors-theme-semanticui input {
text-indent: 30px;
}

@ -0,0 +1,105 @@
/**
* Styles of the tagedit inputsforms
*/
.tagedit-list {
width: 100%;
margin: 0;
padding: 4px 4px 0 5px;
overflow: auto;
min-height: 26px;
background: #fff;
border: 1px solid #b2b2b2;
border-radius: 4px;
box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
-moz-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
-webkit-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
-o-box-shadow: inset 0 0 2px 1px rgba(0,0,0, 0.1);
}
.tagedit-list li.tagedit-listelement {
list-style-type: none;
float: left;
margin: 0 4px 4px 0;
padding: 0;
}
/* New Item input */
.tagedit-list li.tagedit-listelement-new input {
border: 0;
height: 100%;
padding: 4px 1px;
width: 15px;
background: #fff;
border-radius: 0;
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-o-box-shadow: none;
}
.tagedit-list li.tagedit-listelement-new input:focus {
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
-o-box-shadow: none;
outline: none;
}
.tagedit-list li.tagedit-listelement-new input.tagedit-input-disabled {
display: none;
}
/* Item that is put to the List */
.tagedit span.tag-element,
.tagedit-list li.tagedit-listelement-old {
padding: 3px 6px 1px 6px;
background: #ddeef5;
background: -moz-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#edf6fa), color-stop(100%,#d6e9f3));
background: -o-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%);
background: -ms-linear-gradient(top, #edf6fa 0%, #d6e9f3 100%);
background: linear-gradient(top, #edf6fa 0%, #d6e9f3 100%);
border: 1px solid #c2dae5;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
color: #0d5165;
line-height: 1.3em;
}
.tagedit-list li.tagedit-listelement-focus {
border-color: #4787b1;
-moz-box-shadow: 0 0 3px 1px rgba(71,135,177, 0.8);
-webkit-box-shadow: 0 0 3px 1px rgba(71,135,177, 0.8);
-o-box-shadow: 0 0 3px 1px rgba(71,135,177, 0.8);
box-shadow: 0 0 3px 1px rgba(71,135,177, 0.8);
}
.tagedit span.tag-element {
margin-right: 0.6em;
padding: 2px 6px;
/* cursor: pointer; */
}
.tagedit span.tag-element.inherit {
color: #666;
background: #f2f2f2;
border-color: #ddd;
}
.tagedit-list li.tagedit-listelement-old a.tagedit-close,
.tagedit-list li.tagedit-listelement-old a.tagedit-break,
.tagedit-list li.tagedit-listelement-old a.tagedit-delete,
.tagedit-list li.tagedit-listelement-old a.tagedit-save {
text-indent: -2000px;
display: inline-block;
position: relative;
top: -1px;
width: 16px;
height: 16px;
margin: 0 -4px 0 6px;
background: url('data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAOCAYAAAD0f5bSAAAAgUlEQVQoz2NgQAKzdxwWAOIEIG5AwiC+AAM2AJQIAOL3QPwfCwaJB6BrSMChGB0nwDQYwATP3nn4f+Ge4ygKQXyQOJKYAUjTepjAm09fwBimEUTDxJA0rWdANxWmaMXB0xiGwDADurthGkEAmwbqaCLFeWQFBOlBTlbkkp2MSE2wAA8R50rWvqeRAAAAAElFTkSuQmCC') left 1px no-repeat;
cursor: pointer;
}
.tagedit-list li.tagedit-listelement-old span {
display: inline-block;
height: 15px;
}

@ -454,7 +454,7 @@ class rcube_sieve_engine
else if ($action == 'ruleadd') {
$rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_POST);
$id = $this->genid();
$content = $this->rule_div($fid, $id, false);
$content = $this->rule_div($fid, $id, false, $_SESSION['managesieve-compact-form']);
$this->rc->output->command('managesieve_rulefill', $content, $id, $rid);
}
@ -1339,18 +1339,16 @@ class rcube_sieve_engine
function filterset_form($attrib)
{
if (!$attrib['id'])
if (!$attrib['id']) {
$attrib['id'] = 'rcmfiltersetform';
}
$out = '<form name="filtersetform" action="./" method="post" enctype="multipart/form-data">'."\n";
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
$hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $this->rc->task));
$hiddenfields->add(array('name' => '_action', 'value' => 'plugin.managesieve-save'));
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
$hiddenfields->add(array('name' => '_newset', 'value' => 1));
$out .= $hiddenfields->show();
$name = rcube_utils::get_input_value('_name', rcube_utils::INPUT_POST);
$copy = rcube_utils::get_input_value('_copy', rcube_utils::INPUT_POST);
$selected = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST);
@ -1359,18 +1357,17 @@ class rcube_sieve_engine
$input_name = new html_inputfield(array('name' => '_name', 'id' => '_name', 'size' => 30,
'class' => ($this->errors['name'] ? 'error' : '')));
$out .= sprintf('<label for="%s"><b>%s:</b></label> %s<br><br>',
'_name', rcube::Q($this->plugin->gettext('filtersetname')), $input_name->show($name));
$table->add('title', html::label('_name', rcube::Q($this->plugin->gettext('filtersetname'))));
$table->add(null, $input_name->show($name));
$out .="\n<fieldset class=\"itemlist\"><legend>" . $this->plugin->gettext('filters') . ":</legend>\n";
$out .= html::tag('input', array(
$filters = '<ul class="proplist">';
$filters .= '<li>' . html::label('from_none', html::tag('input', array(
'type' => 'radio',
'id' => 'from_none',
'name' => '_from',
'value' => 'none',
'checked' => !$selected || $selected == 'none'
));
$out .= html::label('from_none', rcube::Q($this->plugin->gettext('none')));
)) . rcube::Q($this->plugin->gettext('none'))) . '</li>';
// filters set list
$list = $this->list_scripts();
@ -1386,33 +1383,34 @@ class rcube_sieve_engine
$select->add($set, $set);
}
$out .= '<br>';
$out .= html::tag('input', array(
$filters .= '<li>' . html::label('from_set', html::tag('input', array(
'type' => 'radio',
'id' => 'from_set',
'name' => '_from',
'value' => 'set',
'checked' => $selected == 'set',
));
$out .= html::label('from_set', rcube::Q($this->plugin->gettext('fromset')));
$out .= $select->show($copy);
)) . rcube::Q($this->plugin->gettext('fromset')) . ' ' . $select->show($copy)) . '</li>';
}
// script upload box
$upload = new html_inputfield(array('name' => '_file', 'id' => '_file', 'size' => 30,
'type' => 'file', 'class' => ($this->errors['file'] ? 'error' : '')));
$out .= '<br>';
$out .= html::tag('input', array(
$filters .= '<li>' . html::label('from_file', html::tag('input', array(
'type' => 'radio',
'id' => 'from_file',
'name' => '_from',
'value' => 'file',
'checked' => $selected == 'file',
));
$out .= html::label('from_file', rcube::Q($this->plugin->gettext('fromfile')));
$out .= $upload->show();
$out .= '</fieldset>';
)) . rcube::Q($this->plugin->gettext('fromfile')) . ' ' . $upload->show()) . '</li>';
$filters .= '</ul>';
$table->add('title', html::label('from_none', rcube::Q($this->plugin->gettext('filters'))));
$table->add('', $filters);
$out = '<form name="filtersetform" action="./" method="post" enctype="multipart/form-data">'
. "\n" . $hiddenfields->show() . "\n" . $table->show();
$this->rc->output->add_gui_object('sieveform', 'filtersetform');
@ -1429,11 +1427,15 @@ class rcube_sieve_engine
function filter_form($attrib)
{
if (!$attrib['id'])
if (!$attrib['id']) {
$attrib['id'] = 'rcmfilterform';
}
$fid = rcube_utils::get_input_value('_fid', rcube_utils::INPUT_GPC);
$scr = isset($this->form) ? $this->form : $this->script[$fid];
$fid = rcube_utils::get_input_value('_fid', rcube_utils::INPUT_GPC);
$scr = isset($this->form) ? $this->form : $this->script[$fid];
$compact = !empty($attrib['compact-form']);
$_SESSION['managesieve-compact-form'] = $compact;
// do not allow creation of new rules
if ($fid == null && in_array('new_rule', $this->disabled_actions)) {
@ -1446,8 +1448,7 @@ class rcube_sieve_engine
$hiddenfields->add(array('name' => '_framed', 'value' => ($_POST['_framed'] || $_GET['_framed'] ? 1 : 0)));
$hiddenfields->add(array('name' => '_fid', 'value' => $fid));
$out = '<form name="filterform" action="./" method="post">'."\n";
$out .= $hiddenfields->show();
$out = $hiddenfields->show();
// 'any' flag
if ((!isset($this->form) && empty($scr['tests']) && !empty($scr))
@ -1457,72 +1458,105 @@ class rcube_sieve_engine
}
// filter name input
$field_id = '_name';
$input_name = new html_inputfield(array('name' => '_name', 'id' => $field_id, 'size' => 30,
'class' => ($this->errors['name'] ? 'error' : '')));
$input_name = new html_inputfield(array(
'name' => '_name',
'id' => '_name',
'size' => 30,
'class' => ($this->errors['name'] ? ' error' : '')
));
if ($this->errors['name'])
$this->add_tip($field_id, $this->errors['name'], true);
$this->add_tip('_name', $this->errors['name'], true);
if (isset($scr))
$input_name = $input_name->show($scr['name']);
else
$input_name = $input_name->show();
$input_name = $input_name->show(isset($scr) ? $scr['name'] : '');
$out .= sprintf("\n<label for=\"%s\"><b>%s:</b></label> %s\n",
$field_id, rcube::Q($this->plugin->gettext('filtername')), $input_name);
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="_name" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
rcube::Q($this->plugin->gettext('filtername')), $input_name);
// filter set selector
if ($this->rc->task == 'mail') {
$out .= sprintf("\n&nbsp;<label for=\"%s\"><b>%s:</b></label> %s\n",
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="%s" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
$field_id, rcube::Q($this->plugin->gettext('filterset')),
$this->filtersets_list(array('id' => 'sievescriptname'), true));
}
else if ($compact) {
$out .= sprintf("\n" . '<div class="form-group row form-check">'
. '<label for="disabled" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8 form-check"><input type="checkbox" id="disabled" name="_disabled" value="1" /></div></div>',
rcube::Q($this->plugin->gettext('filterdisabled')));
}
$out .= '<br><br><fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesrules')) . "</legend>\n";
if ($compact) {
$select = new html_select(array('name' => '_join', 'id' => '_join' . $id,
'onchange' => 'rule_join_radio(this.value)'));
foreach (array('allof', 'anyof', 'any') as $val) {
$select->add($this->plugin->gettext('filter' . $val), $val);
}
$join = $any ? 'any' : 'allof';
if (isset($scr) && !$any) {
$join = $scr['join'] ? 'allof' : 'anyof';
}
// any, allof, anyof radio buttons
$field_id = '_allof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof',
'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio'));
$out .= sprintf("\n" . '<div class="form-group row">'
. '<label for="_join" class="col-sm-4 col-form-label">%s</label>'
. '<div class="col-sm-8">%s</div></div>',
rcube::Q($this->plugin->gettext('scope')), $select->show($join));
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? 'allof' : '');
else
$input_join = $input_join->show();
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
$out .= "\n<fieldset><legend>" . rcube::Q($this->plugin->gettext('rules')) . "</legend>\n";
}
else {
$out .= '<br><fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesrules')) . "</legend>\n";
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterallof')));
// any, allof, anyof radio buttons
$field_id = '_allof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'allof',
'onclick' => 'rule_join_radio(\'allof\')', 'class' => 'radio'));
$field_id = '_anyof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof',
'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio'));
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? 'allof' : '');
else
$input_join = $input_join->show();
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? '' : 'anyof');
else
$input_join = $input_join->show('anyof'); // default
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterallof')));
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filteranyof')));
$field_id = '_anyof';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'anyof',
'onclick' => 'rule_join_radio(\'anyof\')', 'class' => 'radio'));
$field_id = '_any';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any',
'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio'));
if (isset($scr) && !$any)
$input_join = $input_join->show($scr['join'] ? '' : 'anyof');
else
$input_join = $input_join->show('anyof'); // default
$input_join = $input_join->show($any ? 'any' : '');
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filteranyof')));
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterany')));
$field_id = '_any';
$input_join = new html_radiobutton(array('name' => '_join', 'id' => $field_id, 'value' => 'any',
'onclick' => 'rule_join_radio(\'any\')', 'class' => 'radio'));
$rows_num = !empty($scr['tests']) ? count($scr['tests']) : 1;
$input_join = $input_join->show($any ? 'any' : '');
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
for ($x=0; $x<$rows_num; $x++)
$out .= $this->rule_div($fid, $x);
$out .= "</div>\n";
$out .= $input_join . html::label($field_id, rcube::Q($this->plugin->gettext('filterany')));
$out .= '<div id="rules"'.($any ? ' style="display: none"' : '').'>';
}
$out .= "</fieldset>\n";
$rows_num = !empty($scr['tests']) ? count($scr['tests']) : 1;
for ($x=0; $x<$rows_num; $x++) {
$out .= $this->rule_div($fid, $x, true, $compact);
}
$out .= $compact ? "</fieldset>\n</div>\n" : "</div>\n</fieldset>\n";
// actions
$out .= '<fieldset><legend>' . rcube::Q($this->plugin->gettext('messagesactions')) . "</legend>\n";
$label = $this->plugin->gettext($compact ? 'actions' : 'messagesactions');
$out .= '<fieldset><legend>' . rcube::Q($label) . "</legend>\n";
$rows_num = isset($scr) ? count($scr['actions']) : 1;
@ -1544,10 +1578,14 @@ class rcube_sieve_engine
);
$this->rc->output->add_gui_object('sieveform', 'filterform');
return $out;
$attrib['name'] = 'filterform';
$attrib['action'] = './';
$attrib['method'] = 'post';
return html::tag('form', $attrib, $out, array('name', 'action', 'method', 'class'));
}
function rule_div($fid, $id, $div=true)
function rule_div($fid, $id, $div = true, $compact = false)
{
$rule = isset($this->form) ? $this->form['tests'][$id] : $this->script[$fid]['tests'][$id];
$rows_num = isset($this->form) ? count($this->form['tests']) : count($this->script[$fid]['tests']);
@ -1604,6 +1642,7 @@ class rcube_sieve_engine
}
}
$tout = '<div class="flexbox">';
$aout = $select_header->show($test);
// custom headers input
@ -1626,11 +1665,11 @@ class rcube_sieve_engine
}
}
// custom variable input
$tout = $this->list_input($id, 'custom_header', $custom, isset($custom),
// custom header and variable inputs
$aout .= $this->list_input($id, 'custom_header', $custom, isset($custom),
$this->error_class($id, 'test', 'header', 'custom_header'), 15) . "\n";
$tout .= $this->list_input($id, 'custom_var', $customv, isset($customv),
$aout .= $this->list_input($id, 'custom_var', $customv, isset($customv),
$this->error_class($id, 'test', 'header', 'custom_var'), 15) . "\n";
// matching type select (operator)
@ -1699,7 +1738,7 @@ class rcube_sieve_engine
$select_dp->add(rcube::Q($this->plugin->gettext($part)), $part);
}
$tout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : '');
$aout .= $select_dp->show($rule['test'] == 'currentdate' || $rule['test'] == 'date' ? $rule['part'] : '');
}
// message test select (e.g. duplicate)
@ -1720,11 +1759,16 @@ class rcube_sieve_engine
$rule['test'] != 'size' && $rule['test'] != 'exists' && $rule['test'] != 'duplicate',
$this->error_class($id, 'test', 'target', 'rule_target')) . "\n";
$select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id));
$select_size_op = new html_select(array('name' => "_rule_size_op[]", 'id' => 'rule_size_op'.$id, 'class' => 'input-group-addon'));
$select_size_op->add(rcube::Q($this->plugin->gettext('filterover')), 'over');
$select_size_op->add(rcube::Q($this->plugin->gettext('filterunder')), 'under');
$tout .= '<div id="rule_size' .$id. '" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
$select_size_item = new html_select(array('name' => "_rule_size_item[]", 'id' => 'rule_size_item'.$id, 'class' => 'input-group-addon'));
foreach (array('', 'K', 'M', 'G') as $unit) {
$select_size_item->add($this->plugin->gettext($unit . 'B'), $unit);
}
$tout .= '<div id="rule_size' .$id. '" class="input-group" style="display:' . ($rule['test']=='size' ? 'inline' : 'none') .'">';
$tout .= $select_size_op->show($rule['test']=='size' ? $rule['type'] : '');
$tout .= html::tag('input', array(
'type' => 'text',
@ -1734,15 +1778,8 @@ class rcube_sieve_engine
'size' => 10,
'class' => $this->error_class($id, 'test', 'sizetarget', 'rule_size_i'),
));
foreach (array('', 'K', 'M', 'G') as $unit) {
$tout .= html::label(null, html::tag('input', array(
'type' => 'radio',
'name' => '_rule_size_item['.$id.']',
'value' => $unit,
'checked' => $sizeitem == $unit,
'class' => 'radio',
)) . $this->rc->gettext($unit . 'B'));
}
$tout .= "\n" . $select_size_item->show($sizeitem);
$tout .= '</div>';
$tout .= '</div>';
// Advanced modifiers (address, envelope)
@ -1764,14 +1801,14 @@ class rcube_sieve_engine
}
$need_mod = !in_array($rule['test'], array('size', 'body', 'date', 'currentdate', 'duplicate', 'string'));
$mout = '<div id="rule_mod' .$id. '" class="adv"' . (!$need_mod ? ' style="display:none"' : '') . '>';
$mout .= ' <span class="label">' . rcube::Q($this->plugin->gettext('modifier')) . ' </span>';
$mout = '<div id="rule_mod' .$id. '" class="adv input-group"' . (!$need_mod ? ' style="display:none"' : '') . '>';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('modifier')) . ' </span>';
$mout .= $select_mod->show($rule['test']);
$mout .= ' <span id="rule_mod_type' . $id . '"';
$mout .= ' style="display:' . (in_array($rule['test'], array('address', 'envelope')) ? 'inline' : 'none') .'">';
$mout .= rcube::Q($this->plugin->gettext('modtype')) . ' ';
$mout .= '</div>';
$mout .= '<div id="rule_mod_type' . $id . '" class="adv input-group"';
$mout .= (!in_array($rule['test'], array('address', 'envelope')) ? ' style="display:none' : '') . '">';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('modtype')) . ' </span>';
$mout .= $select_type->show($rule['part']);
$mout .= '</span>';
$mout .= '</div>';
// Advanced modifiers (body transformations)
@ -1781,8 +1818,8 @@ class rcube_sieve_engine
$select_mod->add(rcube::Q($this->plugin->gettext('undecoded')), 'raw');
$select_mod->add(rcube::Q($this->plugin->gettext('contenttype')), 'content');
$mout .= '<div id="rule_trans' .$id. '" class="adv"' . ($rule['test'] != 'body' ? ' style="display:none"' : '') . '>';
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('modifier')) . '</span>';
$mout .= '<div id="rule_trans' .$id. '" class="adv input-group"' . ($rule['test'] != 'body' ? ' style="display:none"' : '') . '>';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('modifier')) . '</span>';
$mout .= $select_mod->show($rule['part']);
$mout .= html::tag('input', array(
'type' => 'text',
@ -1806,15 +1843,15 @@ class rcube_sieve_engine
// Comparators
$need_comp = $rule['test'] != 'size' && $rule['test'] != 'duplicate';
$mout .= '<div id="rule_comp' .$id. '" class="adv"' . (!$need_comp ? ' style="display:none"' : '') . '>';
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('comparator')) . '</span>';
$mout .= '<div id="rule_comp' .$id. '" class="adv input-group"' . (!$need_comp ? ' style="display:none"' : '') . '>';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('comparator')) . '</span>';
$mout .= $select_comp->show($rule['comparator']);
$mout .= '</div>';
// Date header
if (in_array('date', $this->exts)) {
$mout .= '<div id="rule_date_header_div' .$id. '" class="adv"'. ($rule['test'] != 'date' ? ' style="display:none"' : '') .'>';
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('dateheader')) . '</span>';
$mout .= '<div id="rule_date_header_div' .$id. '" class="adv input-group"'. ($rule['test'] != 'date' ? ' style="display:none"' : '') .'>';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('dateheader')) . '</span>';
$mout .= html::tag('input', array(
'type' => 'text',
'name' => '_rule_date_header[]',
@ -1829,8 +1866,8 @@ class rcube_sieve_engine
// Index
if (in_array('index', $this->exts)) {
$need_index = in_array($rule['test'], array('header', ', address', 'date'));
$mout .= '<div id="rule_index_div' .$id. '" class="adv"'. (!$need_index ? ' style="display:none"' : '') .'>';
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('index')) . '</span>';
$mout .= '<div id="rule_index_div' .$id. '" class="adv input-group"'. (!$need_index ? ' style="display:none"' : '') .'>';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('index')) . '</span>';
$mout .= html::tag('input', array(
'type' => 'text',
'name' => '_rule_index[]',
@ -1839,14 +1876,14 @@ class rcube_sieve_engine
'size' => 3,
'class' => $this->error_class($id, 'test', 'index', 'rule_index'),
));
$mout .= '&nbsp;' . html::tag('input', array(
'type' => 'checkbox',
'name' => '_rule_index_last[]',
'id' => 'rule_index_last' . $id,
'value' => 1,
'checked' => !empty($rule['last']),
))
. html::label('rule_index_last' . $id, rcube::Q($this->plugin->gettext('indexlast')));
$mout .= html::label(array('class' => 'input-group-addon'),
html::tag('input', array(
'type' => 'checkbox',
'name' => '_rule_index_last[]',
'id' => 'rule_index_last' . $id,
'value' => 1,
'checked' => !empty($rule['last']),
)) . rcube::Q($this->plugin->gettext('indexlast')));
$mout .= '</div>';
}
@ -1856,7 +1893,8 @@ class rcube_sieve_engine
$mout .= '<div id="rule_duplicate_div' .$id. '" class="adv"'. (!$need_duplicate ? ' style="display:none"' : '') .'>';
foreach (array('handle', 'header', 'uniqueid') as $unit) {
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('duplicate.handle')) . '</span>';
$mout .= '<div class="input-group">';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('duplicate.' . $unit)) . '</span>';
$mout .= html::tag('input', array(
'type' => 'text',
'name' => '_rule_duplicate_' . $unit . '[]',
@ -1865,10 +1903,11 @@ class rcube_sieve_engine
'size' => 30,
'class' => $this->error_class($id, 'test', 'duplicate_' . $unit, 'rule_duplicate_' . $unit),
));
$mout .= '<br>';
$mout .= '</div>';
}
$mout .= '<span class="label">' . rcube::Q($this->plugin->gettext('duplicate.seconds')) . '</span>';
$mout .= '<div class="input-group">';
$mout .= '<span class="label input-group-addon">' . rcube::Q($this->plugin->gettext('duplicate.seconds')) . '</span>';
$mout .= html::tag('input', array(
'type' => 'text',
'name' => '_rule_duplicate_seconds[]',
@ -1877,38 +1916,49 @@ class rcube_sieve_engine
'size' => 6,
'class' => $this->error_class($id, 'test', 'duplicate_seconds', 'rule_duplicate_seconds'),
));
$mout .= '&nbsp;' . html::tag('input', array(
$mout .= html::label(array('class' => 'input-group-addon'),
html::tag('input', array(
'type' => 'checkbox',
'name' => '_rule_duplicate_last[' . $id . ']',
'id' => 'rule_duplicate_last' . $id,
'value' => 1,
'checked' => !empty($rule['last']),
));
$mout .= html::label('rule_duplicate_last' . $id, rcube::Q($this->plugin->gettext('duplicate.last')));
)) . rcube::Q($this->plugin->gettext('duplicate.last')));
$mout .= '</div>';
$mout .= '</div>';
}
$add_title = rcube::Q($this->plugin->gettext('add'));
$del_title = rcube::Q($this->plugin->gettext('del'));
$adv_title = rcube::Q($this->plugin->gettext('advancedopts'));
// Build output table
$out = $div ? '<div class="rulerow" id="rulerow' .$id .'">'."\n" : '';
$out .= '<table><tr>';
$out .= '<td class="advbutton">';
$out .= '<a href="#" id="ruleadv' . $id .'" title="'. rcube::Q($this->plugin->gettext('advancedopts')). '"
onclick="rule_adv_switch(' . $id .', this)" class="show">&nbsp;&nbsp;</a>';
$out .= '</td>';
$out .= '<td class="rowactions">' . $aout . '</td>';
$out .= '<table class="compact-table"><tr>';
if (!$compact) {
$out .= '<td class="advbutton">';
$out .= sprintf('<a href="#" id="ruleadv%s" title="%s" onclick="rule_adv_switch(%s, this)" class="show">'
. '<span class="inner">%s</span></a>', $id, $adv_title, $id, $adv_title);
$out .= '</td>';
}
$out .= '<td class="rowactions"><div class="flexbox">' . $aout . '</div></td>';
$out .= '<td class="rowtargets">' . $tout . "\n";
$out .= '<div id="rule_advanced' .$id. '" style="display:none">' . $mout . '</div>';
$out .= '<div id="rule_advanced' .$id. '" style="display:none" class="advanced">' . $mout . '</div>';
$out .= '</td>';
// add/del buttons
$out .= '<td class="rowbuttons">';
$out .= '<a href="#" id="ruleadd' . $id .'" title="'. rcube::Q($this->plugin->gettext('add')). '"
onclick="rcmail.managesieve_ruleadd(' . $id .')" class="button add"></a>';
$out .= '<a href="#" id="ruledel' . $id .'" title="'. rcube::Q($this->plugin->gettext('del')). '"
onclick="rcmail.managesieve_ruledel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>';
if ($compact) {
$out .= sprintf('<a href="#" id="ruleadv%s" title="%s" onclick="rule_adv_switch(%s, this)" class="advanced show">'
. '<span class="inner">%s</span></a>', $id, $adv_title, $id, $adv_title);
}
$out .= sprintf('<a href="#" id="ruleadd%s" title="%s" onclick="rcmail.managesieve_ruleadd(\'%s\')" class="button create add">'
. '<span class="inner">%s</span></a>', $id, $add_title, $id, $add_title);
$out .= sprintf('<a href="#" id="ruledel%s" title="%s" onclick="rcmail.managesieve_ruledel(\'%s\')" class="button delete del%s">'
. '<span class="inner">%s</span></a>', $id, $del_title, $id, ($rows_num < 2 ? ' disabled' : ''), $del_title);
$out .= '</td>';
$out .= '</tr></table>';
$out .= '</tr></table>';
$out .= $div ? "</div>\n" : '';
return $out;
@ -1958,7 +2008,7 @@ class rcube_sieve_engine
$out = $div ? '<div class="actionrow" id="actionrow' .$id .'">'."\n" : '';
$out .= '<table><tr><td class="rowactions">';
$out .= '<table class="compact-table"><tr><td class="rowactions">';
// action select
$select_action = new html_select(array('name' => "_action_type[$id]", 'id' => 'action_type'.$id,
@ -2090,8 +2140,8 @@ class rcube_sieve_engine
$this->error_class($id, 'action', 'addresses', 'action_addresses'), 30)
. html::a(array('href' => '#', 'onclick' => rcmail_output::JS_OBJECT_NAME . ".managesieve_vacation_addresses($id)"),
rcube::Q($this->plugin->gettext('filladdresses')));
$out .= '<br><span class="label">' . rcube::Q($this->plugin->gettext($vsec ? 'vacationinterval' : 'vacationdays')) . '</span><br>';
$out .= html::tag('input', array(
$out .= '<br><span class="label">' . rcube::Q($this->plugin->gettext('vacationinterval')) . '</span><br>';
$out .= '<div class="input-group">' . html::tag('input', array(
'type' => 'text',
'name' => '_action_interval[' . $id . ']',
'id' => 'action_interval' . $id,
@ -2100,18 +2150,15 @@ class rcube_sieve_engine
'class' => $this->error_class($id, 'action', 'interval', 'action_interval'),
));
if ($vsec) {
foreach (array('days', 'seconds') as $unit) {
$out .= '&nbsp;' . html::label(null, html::tag('input', array(
'type' => 'radio',
'name' => '_action_interval_type[' . $id . ']',
'value' => $unit,
'checked' => ($unit == 'seconds' && isset($action['seconds'])
|| $unit == 'deys' && !isset($action['seconds'])),
'class' => 'radio',
)) . $this->plugin->gettext($unit));
}
$interval_select = new html_select(array('name' => '_action_interval_type[' . $id . ']', 'class' => 'input-group-addon'));
$interval_select->add($this->plugin->gettext('days'), 'days');
$interval_select->add($this->plugin->gettext('seconds'), 'seconds');
$out .= $interval_select->show(isset($action['seconds']) ? 'seconds' : 'days');
}
$out .= '</div>';
else {
$out .= "\n" . html::span('input-group-addon', $this->plugin->gettext('days'));
}
$out .= '</div></div>';
// flags
$flags = array(
@ -2125,18 +2172,18 @@ class rcube_sieve_engine
$flout = '';
foreach ($flags as $fidx => $flag) {
$flout .= html::tag('input', array(
$flout .= html::label(null, html::tag('input', array(
'type' => 'checkbox',
'name' => '_action_flags[' .$id .'][]',
'value' => $flag,
'checked' => in_array_nocase($flag, $flags_target),
))
. rcube::Q($this->plugin->gettext('flag'.$fidx)) .'<br>';
. rcube::Q($this->plugin->gettext('flag'.$fidx))) . '<br>';
}
$out .= html::div(array(
'id' => 'action_flags' . $id,
'style' => 'display:' . (preg_match('/^(set|add|remove)flag$/', $action['type']) ? 'inline' : 'none'),
'class' => $this->error_class($id, 'action', 'flags', 'action_flags'),
'class' => trim('checklist ' . $this->error_class($id, 'action', 'flags', 'action_flags')),
), $flout);
// set variable
@ -2194,7 +2241,7 @@ class rcube_sieve_engine
$select_method = new html_select(array(
'name' => "_action_notifymethod[$id]",
'id' => "_action_notifymethod$id",
'class' => $this->error_class($id, 'action', 'method', 'action_notifymethod'),
'class' => 'input-group-addon ' . $this->error_class($id, 'action', 'method', 'action_notifymethod'),
));
foreach ($notify_methods as $m_n) {
$select_method->add(rcube::Q($this->rc->text_exists('managesieve.notifymethod'.$m_n) ? $this->plugin->gettext('managesieve.notifymethod'.$m_n) : $m_n), $m_n);
@ -2212,6 +2259,7 @@ class rcube_sieve_engine
// @TODO: nice UI for mailto: (other methods too) URI parameters
$out .= '<div id="action_notify' .$id.'" style="display:' .($action['type'] == 'notify' ? 'inline' : 'none') .'">';
$out .= '<span class="label">' .rcube::Q($this->plugin->gettext('notifytarget')) . '</span><br>';
$out .= '<div class="input-group">';
$out .= $select_method->show($method);
$out .= html::tag('input', array(
'type' => 'text',
@ -2221,6 +2269,7 @@ class rcube_sieve_engine
'size' => 25,
'class' => $this->error_class($id, 'action', 'target', 'action_notifytarget'),
));
$out .= '</div>';
$out .= '<br><span class="label">'. rcube::Q($this->plugin->gettext('notifymessage')) .'</span><br>';
$out .= html::tag('textarea', array(
'name' => '_action_notifymessage[' . $id . ']',
@ -2270,11 +2319,13 @@ class rcube_sieve_engine
$out .= '</td>';
// add/del buttons
$add_label = rcube::Q($this->plugin->gettext('add'));
$del_label = rcube::Q($this->plugin->gettext('del'));
$out .= '<td class="rowbuttons">';
$out .= '<a href="#" id="actionadd' . $id .'" title="'. rcube::Q($this->plugin->gettext('add')). '"
onclick="rcmail.managesieve_actionadd(' . $id .')" class="button add"></a>';
$out .= '<a href="#" id="actiondel' . $id .'" title="'. rcube::Q($this->plugin->gettext('del')). '"
onclick="rcmail.managesieve_actiondel(' . $id .')" class="button del' . ($rows_num<2 ? ' disabled' : '') .'"></a>';
$out .= sprintf('<a href="#" id="actionadd%s" title="%s" onclick="rcmail.managesieve_actionadd(%s)" class="button create add">'
. '<span class="inner">%s</span></a>', $id, $add_label, $id, $add_label);
$out .= sprintf('<a href="#" id="actiondel%s" title="%s" onclick="rcmail.managesieve_actiondel(%s)" class="button delete del%s">'
. '<span class="inner">%s</span></a>', $id, $del_label, $id, ($rows_num < 2 ? ' disabled' : ''), $del_label);
$out .= '</td>';
$out .= '</tr></table>';
@ -2326,10 +2377,10 @@ class rcube_sieve_engine
protected function add_tip($id, $str, $error=false)
{
if ($error) {
$str = html::span('sieve error', $str);
$class = 'sieve error';
}
$this->tips[] = array($id, $str);
$this->tips[] = array($id, $class ?: '', $str);
}
protected function print_tips()

@ -392,10 +392,10 @@ class rcube_sieve_vacation extends rcube_sieve_engine
$interval_select = new html_select(array('name' => 'vacation_interval_type'));
$interval_select->add($this->plugin->gettext('days'), 'days');
$interval_select->add($this->plugin->gettext('seconds'), 'seconds');
$interval_txt .= '&nbsp;' . $interval_select->show(isset($this->vacation['seconds']) ? 'seconds' : 'days');
$interval_txt .= $interval_select->show(isset($this->vacation['seconds']) ? 'seconds' : 'days');
}
else {
$interval_txt .= '&nbsp;' . $this->plugin->gettext('days');
$interval_txt .= "\n" . html::span('input-group-addon', $this->plugin->gettext('days'));
}
if ($date_extension || $regex_extension) {
@ -495,7 +495,7 @@ class rcube_sieve_vacation extends rcube_sieve_engine
$table->add('title', html::label('vacation_addresses', $this->plugin->gettext('vacation.addresses')));
$table->add(null, $addresses . $addresses_link->show($this->plugin->gettext('filladdresses')));
$table->add('title', html::label('vacation_interval', $this->plugin->gettext('vacation.interval')));
$table->add(null, $interval_txt);
$table->add('input-group', $interval_txt);
if ($after) {
$table->add('title', html::label('vacation_after', $this->plugin->gettext('vacation.after')));

@ -23,6 +23,9 @@ $labels['filtername'] = 'Filter name';
$labels['newfilter'] = 'New filter';
$labels['filteradd'] = 'Add filter';
$labels['filterdel'] = 'Delete filter';
$labels['rules'] = 'Rules';
$labels['actions'] = 'Actions';
$labels['scope'] = 'Scope';
$labels['moveup'] = 'Move up';
$labels['movedown'] = 'Move down';
$labels['filterallof'] = 'matching all of the following rules';
@ -69,10 +72,11 @@ $labels['enable'] = 'Enable/Disable';
$labels['filterset'] = 'Filters set';
$labels['filtersets'] = 'Filter sets';
$labels['filtersetadd'] = 'Add filters set';
$labels['filtersetdel'] = 'Delete current filters set';
$labels['filtersetdel'] = 'Delete filters set';
$labels['filtersetact'] = 'Activate current filters set';
$labels['filtersetdeact'] = 'Deactivate current filters set';
$labels['filterseteditraw'] = 'Edit filter set';
$labels['filtersetswitch'] = 'Enable/disable filters set';
$labels['filterdef'] = 'Filter definition';
$labels['filtersetname'] = 'Filters set name';
$labels['newfilterset'] = 'New filters set';

@ -84,6 +84,7 @@ if (window.rcmail) {
rcmail.filtersets_list.init().focus();
if (set != null) {
$('#filterset-name').text(set);
set = rcmail.managesieve_setid(set);
rcmail.filtersets_list.select(set);
}
@ -114,17 +115,18 @@ if (window.rcmail) {
rcube_webmail.prototype.managesieve_add = function()
{
this.load_managesieveframe('', true);
this.load_managesieveframe('_nav=hide', true);
};
rcube_webmail.prototype.managesieve_del = function()
{
var id = this.filters_list.get_single_selection();
if (confirm(this.get_label('managesieve.filterdeleteconfirm'))) {
var lock = this.set_busy(true, 'loading');
this.http_post('plugin.managesieve-action',
'_act=delete&_fid='+this.filters_list.rows[id].uid, lock);
}
this.confirm_dialog(this.get_label('managesieve.filterdeleteconfirm'), 'delete', function(e, ref) {
var id = ref.filters_list.get_single_selection(),
post = '_act=delete&_fid=' + ref.filters_list.rows[id].uid,
lock = ref.set_busy(true, 'loading');
ref.http_post('plugin.managesieve-action', post, lock);
});
};
rcube_webmail.prototype.managesieve_act = function()
@ -163,8 +165,10 @@ rcube_webmail.prototype.managesieve_setselect = function(list)
this.enable_command('plugin.managesieve-seteditraw', list.rowcount > 0 && this.env.raw_sieve_editor);
var id = list.get_single_selection();
if (id != null)
if (id != null) {
this.managesieve_list(this.env.filtersets[id]);
$('#filterset-name').text(this.env.filtersets[id]);
}
};
rcube_webmail.prototype.managesieve_rowid = function(id)
@ -215,14 +219,13 @@ rcube_webmail.prototype.managesieve_setact = function()
// Set delete request
rcube_webmail.prototype.managesieve_setdel = function()
{
if (!confirm(this.get_label('managesieve.setdeleteconfirm')))
return false;
this.confirm_dialog(this.get_label('managesieve.setdeleteconfirm'), 'delete', function(e, ref) {
var id = ref.filtersets_list.get_single_selection(),
script = ref.env.filtersets[id],
lock = ref.set_busy(true, 'loading');
var id = this.filtersets_list.get_single_selection(),
lock = this.set_busy(true, 'loading'),
script = this.env.filtersets[id];
this.http_post('plugin.managesieve-action', '_act=setdel&_set='+urlencode(script), lock);
ref.http_post('plugin.managesieve-action', '_act=setdel&_set=' + urlencode(script), lock);
});
};
// Set edit raw request
@ -231,13 +234,13 @@ rcube_webmail.prototype.managesieve_seteditraw = function()
var id = this.filtersets_list.get_single_selection(),
script = this.env.filtersets[id];
this.load_managesieveframe('_seteditraw=1&_set=' + urlencode(script), true);
}
this.load_managesieveframe('_nav=hide&_seteditraw=1&_set=' + urlencode(script), true);
};
// Set add request
rcube_webmail.prototype.managesieve_setadd = function()
{
this.load_managesieveframe('_newset=1', true);
this.load_managesieveframe('_nav=hide&_newset=1', true);
};
rcube_webmail.prototype.managesieve_updatelist = function(action, o)
@ -355,13 +358,13 @@ rcube_webmail.prototype.managesieve_updatelist = function(action, o)
case 'setdel':
var id = this.managesieve_setid(o.name);
this.filtersets_list.remove_row(id);
this.filters_list.clear();
this.show_contentframe(false);
this.enable_command('plugin.managesieve-setdel', 'plugin.managesieve-setact', 'plugin.managesieve-setget', false);
this.enable_command('plugin.managesieve-setdel', 'plugin.managesieve-setact',
'plugin.managesieve-setget', 'plugin.managesieve-seteditraw', false);
this.filtersets_list.remove_row(id, true);
delete this.env.filtersets[id];
break;
// Create set row
@ -515,14 +518,11 @@ rcube_webmail.prototype.managesieve_rulefill = function(content, id, after)
{
if (content != '') {
// create new element
var div = document.getElementById('rules'),
row = document.createElement('div');
var div = $('#rules')[0],
row = $('<div>').attr({'class': 'rulerow', id: 'rulerow'+id})
.html(content);
this.managesieve_insertrow(div, row, after);
// fill row after inserting (for IE)
row.setAttribute('id', 'rulerow'+id);
row.className = 'rulerow';
row.innerHTML = content;
// initialize smart list inputs
$('textarea[data-type="list"]', row).each(function() {
@ -538,11 +538,11 @@ rcube_webmail.prototype.managesieve_ruledel = function(id)
if ($('#ruledel'+id).hasClass('disabled'))
return;
if (confirm(this.get_label('managesieve.ruledeleteconfirm'))) {
var row = document.getElementById('rulerow'+id);
row.parentNode.removeChild(row);
this.managesieve_formbuttons(document.getElementById('rules'));
}
this.confirm_dialog(this.get_label('managesieve.ruledeleteconfirm'), 'delete', function(e, ref) {
var row = document.getElementById('rulerow'+id);
row.parentNode.removeChild(row);
ref.managesieve_formbuttons(document.getElementById('rules'));
});
};
rcube_webmail.prototype.managesieve_actionadd = function(id)
@ -553,14 +553,11 @@ rcube_webmail.prototype.managesieve_actionadd = function(id)
rcube_webmail.prototype.managesieve_actionfill = function(content, id, after)
{
if (content != '') {
var div = document.getElementById('actions'),
row = document.createElement('div');
var div = $('#actions')[0],
row = $('<div>').attr({'class': 'actionrow', id: 'actionrow'+id})
.html(content);
this.managesieve_insertrow(div, row, after);
// fill row after inserting (for IE)
row.className = 'actionrow';
row.setAttribute('id', 'actionrow'+id);
row.innerHTML = content;
// initialize smart list inputs
$('textarea[data-type="list"]', row).each(function() {
@ -576,53 +573,34 @@ rcube_webmail.prototype.managesieve_actiondel = function(id)
if ($('#actiondel'+id).hasClass('disabled'))
return;
if (confirm(this.get_label('managesieve.actiondeleteconfirm'))) {
var row = document.getElementById('actionrow'+id);
row.parentNode.removeChild(row);
this.managesieve_formbuttons(document.getElementById('actions'));
}
this.confirm_dialog(this.get_label('managesieve.actiondeleteconfirm'), 'delete', function(e, ref) {
var row = document.getElementById('actionrow'+id);
row.parentNode.removeChild(row);
ref.managesieve_formbuttons(document.getElementById('actions'));
});
};
// insert rule/action row in specified place on the list
rcube_webmail.prototype.managesieve_insertrow = function(div, row, after)
{
for (var i=0; i<div.childNodes.length; i++) {
if (div.childNodes[i].id == (div.id == 'rules' ? 'rulerow' : 'actionrow') + after)
break;
}
var node = $('#' + ($(div).attr('id') == 'rules' ? 'rulerow' : 'actionrow') + after)[0];
if (div.childNodes[i+1])
div.insertBefore(row, div.childNodes[i+1]);
if (node)
$(row).insertAfter(node);
else
div.appendChild(row);
$(div).append(row);
this.triggerEvent('managesieve.insertrow', {obj: row});
};
// update Delete buttons status
rcube_webmail.prototype.managesieve_formbuttons = function(div)
{
var i, button, buttons = [];
var buttons = $('a.delete', div);
// count and get buttons
for (i=0; i<div.childNodes.length; i++) {
if (div.id == 'rules' && div.childNodes[i].id) {
if (/rulerow/.test(div.childNodes[i].id))
buttons.push('ruledel' + div.childNodes[i].id.replace(/rulerow/, ''));
}
else if (div.childNodes[i].id) {
if (/actionrow/.test(div.childNodes[i].id))
buttons.push( 'actiondel' + div.childNodes[i].id.replace(/actionrow/, ''));
}
}
for (i=0; i<buttons.length; i++) {
button = document.getElementById(buttons[i]);
if (i>0 || buttons.length>1) {
$(button).removeClass('disabled');
}
else {
$(button).addClass('disabled');
}
}
buttons.removeClass('disabled');
if (buttons.length == 1)
buttons.addClass('disabled');
};
// update vacation addresses field with user identities
@ -659,22 +637,22 @@ function rule_header_select(id)
if (h == 'size') {
if (msg) set.push(msg);
$.each(set, function() { this.style.display = 'none'; });
size.style.display = 'inline';
size.style.display = '';
}
else if (h == 'message' && msg) {
$.each(set, function() { this.style.display = 'none'; });
msg.style.display = 'inline';
msg.style.display = '';
}
else {
header.style.display = h != '...' ? 'none' : 'inline-block';
custstr.style.display = h != 'string' ? 'none' : 'inline-block';
header.style.display = h != '...' ? 'none' : '';
custstr.style.display = h != 'string' ? 'none' : '';
size.style.display = 'none';
op.style.display = 'inline';
op.style.display = '';
comp.style.display = '';
mod.style.display = h == 'body' || h == 'currentdate' || h == 'date' || h == 'string' ? 'none' : 'block';
trans.style.display = h == 'body' ? 'block' : 'none';
mod.style.display = h == 'body' || h == 'currentdate' || h == 'date' || h == 'string' ? 'none' : '';
trans.style.display = h == 'body' ? '' : 'none';
if (msg)
msg.style.display = h == 'message' ? 'block' : 'none';
msg.style.display = h == 'message' ? '' : 'none';
}
if (datepart)
@ -699,7 +677,7 @@ function rule_op_select(obj, id, header)
if (!header)
header = document.getElementById('header' + id).value;
target.style.display = obj.value.match(/^(exists|notexists)$/) || header.match(/^(size|message)$/) ? 'none' : 'inline-block';
target.style.display = obj.value.match(/^(exists|notexists)$/) || header.match(/^(size|message)$/) ? 'none' : '';
};
function rule_trans_select(id)
@ -720,7 +698,7 @@ function rule_mod_select(id, header)
if (!header)
header = document.getElementById('header' + id).value;
target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : 'inline';
target.style.display = obj.value != 'address' && obj.value != 'envelope' ? 'none' : '';
if (index)
index.style.display = !header.match(/^(body|currentdate|size|message|string)$/) && obj.value != 'envelope' ? '' : 'none';
@ -739,14 +717,14 @@ function rule_adv_switch(id, elem)
var elem = $(elem), enabled = elem.hasClass('hide'), adv = $('#rule_advanced'+id);
if (enabled) {
adv.hide();
adv.get(0).style.display = 'none';
elem.removeClass('hide').addClass('show');
}
else {
adv.show();
adv.get(0).style.display = '';
elem.removeClass('show').addClass('hide');
}
}
};
function action_type_select(id)
{
@ -799,6 +777,9 @@ function vacation_action_select()
// Inititalizes smart list input
function smart_field_init(field)
{
if (window.UI && UI.smart_field_init)
return UI.smart_field_init(field);
var id = field.id + '_list',
area = $('<span class="listarea"></span>'),
list = field.value ? field.value.split("\n") : [''];
@ -824,7 +805,7 @@ function smart_field_init(field)
if (field.hasClass('error')) {
area.addClass('error');
rcmail.managesieve_tip_register([[id, field.data('tip')]]);
rcmail.managesieve_tip_register([[id, field.data('tip-class'), field.data('tip-msg')]]);
}
};
@ -884,6 +865,9 @@ function smart_field_row(value, name, idx, size)
// Reset and fill the smart list input with new data
function smart_field_reset(field, data)
{
if (window.UI && UI.smart_field_reset)
return UI.smart_field_reset(field, data);
var id = field.id + '_list',
list = data.length ? data : [''];
area = $('#' + id);
@ -899,19 +883,24 @@ function smart_field_reset(field, data)
// Register onmouse(leave/enter) events for tips on specified form element
rcube_webmail.prototype.managesieve_tip_register = function(tips)
{
if (window.UI && UI.form_errors)
return UI.form_errors(tips);
var n, framed = parent.rcmail,
tip = framed ? parent.rcmail.env.ms_tip_layer : rcmail.env.ms_tip_layer;
for (n in tips) {
$('#'+tips[n][0])
.data('tip', tips[n][1])
.data('tip-class', tips[n][1])
.data('tip-msg', tips[n][2])
.mouseleave(function(e) { tip.hide(); })
.mouseenter(function(e) {
var elem = $(this),
offset = elem.offset(),
left = offset.left,
top = offset.top - 12,
minwidth = elem.width();
minwidth = elem.width(),
span = $('<span>').addClass(elem.data('tip-class')).text(elem.data('tip-msg'));
if (framed) {
offset = $((rcmail.env.task == 'mail' ? '#sievefilterform > iframe' : '#filter-box'), parent.document).offset();
@ -919,7 +908,7 @@ rcube_webmail.prototype.managesieve_tip_register = function(tips)
left += offset.left;
}
tip.html(elem.data('tip'));
tip.html('').append(span);
top -= tip.height();
tip.css({left: left, top: top, minWidth: (minwidth-2) + 'px'}).show();
@ -1097,29 +1086,34 @@ rcube_webmail.prototype.managesieve_create = function(force)
if (!this.env.sieve_headers || !this.env.sieve_headers.length)
return;
var i, html, buttons = {}, dialog = $("#sievefilterform");
var i, buttons = {},
title = this.get_label('managesieve.newfilter'),
dialog = $('<div id="sievefilterform" class="propform"></div>'),
props = {minWidth: 600, minHeight: 250, height: 300};
// create dialog window
if (!dialog.length) {
dialog = $('<div id="sievefilterform"></div>');
$('body').append(dialog);
}
// build dialog window content
html = '<fieldset><legend>'+this.get_label('managesieve.usedata')+'</legend><ul>';
for (i in this.env.sieve_headers)
html += '<li><input type="checkbox" name="headers[]" id="sievehdr'+i+'" value="'+i+'" checked="checked" />'
+'<label for="sievehdr'+i+'">'+this.env.sieve_headers[i][0]+':</label> '+this.env.sieve_headers[i][1]+'</li>';
html += '</ul></fieldset>';
dialog.html(html);
dialog.append($('<fieldset>')
.append($('<legend>').text(this.get_label('managesieve.usedata')))
.append($('<ul class="proplist">'))
);
$.each(this.env.sieve_headers, function(i, v) {
var attr = {type: 'checkbox', name: 'headers[]', id: 'sievehdr' + i, value: i, checked: true},
label = rcmail.env.sieve_headers[i][0] + ': ' + rcmail.env.sieve_headers[i][1];
$('ul', dialog).append($('<li>')
.append($('<input>').attr(attr))
.append($('<label>').attr('for', 'sievehdr' + i).text(label))
);
});
// [Next Step] button action
buttons[this.get_label('managesieve.nextstep')] = function () {
// check if there's at least one checkbox checked
var hdrs = $('input[name="headers[]"]:checked', dialog);
if (!hdrs.length) {
alert(rcmail.get_label('managesieve.nodata'));
rcmail.alert_dialog(rcmail.get_label('managesieve.nodata'));
return;
}
@ -1134,41 +1128,32 @@ rcube_webmail.prototype.managesieve_create = function(force)
});
// load form in the iframe
var frame = $('<iframe>').attr({src: url, frameborder: 0})
dialog.empty().append(frame).dialog('widget').resize();
var buttons = {}, iframe = $('<iframe>').attr({src: url, frameborder: 0});
// Change [Next Step] button with [Save] button
buttons = {};
buttons[rcmail.get_label('save')] = function() {
var win = $('iframe', dialog).get(0).contentWindow;
win.rcmail.managesieve_save();
};
dialog.dialog('option', 'buttons', buttons);
buttons[rcmail.get_label('cancel')] = function() { $(this).dialog('destroy'); };
dialog.dialog('destroy');
rcmail.env.managesieve_dialog = dialog = rcmail.show_popup_dialog(
iframe, title, buttons, $.extend(props, {button_classes: ['mainaction save', 'cancel']})
);
};
// show dialog window
dialog.dialog({
modal: false,
resizable: true,
closeOnEscape: true,
title: this.get_label('managesieve.newfilter'),
close: function() { rcmail.managesieve_dialog_close(); },
buttons: buttons,
minWidth: 600,
minHeight: 300,
height: 250
}).show();
this.env.managesieve_dialog = dialog;
buttons[this.get_label('cancel')] = function() { $(this).dialog('destroy'); };
this.env.managesieve_dialog = dialog = this.show_popup_dialog(
dialog, title, buttons, $.extend(props, {button_classes: ['mainaction next', 'cancel']})
);
}
rcube_webmail.prototype.managesieve_dialog_close = function()
{
var dialog = this.env.managesieve_dialog;
// BUG(?): if we don't remove the iframe first, it will be reloaded
dialog.html('');
dialog.dialog('destroy').hide();
this.env.managesieve_dialog.dialog('destroy');
}
rcube_webmail.prototype.managesieve_dialog_resize = function(o)
@ -1179,5 +1164,8 @@ rcube_webmail.prototype.managesieve_dialog_resize = function(o)
height = form.height(),
w = win.width(), h = win.height();
if (height < 100)
return;
dialog.dialog('option', { height: Math.min(h-20, height+120), width: Math.min(w-20, width+65) });
}

@ -85,10 +85,10 @@ class managesieve extends rcube_plugin
// include styles
$skin_path = $this->local_skin_path();
if ($sieve_action || ($this->rc->task == 'settings' && empty($_REQUEST['_framed']))) {
$this->include_stylesheet("$skin_path/managesieve.css");
$this->include_stylesheet("$skin_path/managesieve.css", true);
}
else if ($this->rc->task == 'mail') {
$this->include_stylesheet("$skin_path/managesieve_mail.css");
$this->include_stylesheet("$skin_path/managesieve_mail.css", true);
}
$this->ui_initialized = true;

@ -117,6 +117,20 @@ body.iframe
color: #666666;
}
filter-form .col-form-label {
display: inline-block;
min-width: 75px;
line-height: 2.5;
}
#filter-form .col-form-label + div {
display: inline;
}
#filter-form div.flexbox {
margin: 0;
}
#rules, #actions
{
margin-top: 5px;
@ -161,19 +175,23 @@ td.advbutton a
{
display: block;
padding-top: 14px;
height: 6px;
height: 14px;
width: 12px;
text-decoration: none;
}
td.advbutton a span {
display: none;
}
td.advbutton a.show
{
background: url(images/down_small.gif?v=8629.106) center no-repeat;
background: url(images/down_small.gif) center no-repeat;
}
td.advbutton a.hide
{
background: url(images/up_small.gif?v=c56c.106) center no-repeat;
background: url(images/up_small.gif) center no-repeat;
}
td.rowbuttons
@ -305,9 +323,13 @@ span.sieve.error
color: red;
}
#filter-form a.button span {
display: none;
}
a.button.add
{
background: url(images/add.png?v=a165.280) no-repeat;
background: url(images/add.png) no-repeat;
width: 30px;
height: 20px;
margin-right: 4px;
@ -316,7 +338,7 @@ a.button.add
a.button.del
{
background: url(images/del.png?v=3c27.247) no-repeat;
background: url(images/del.png) no-repeat;
width: 30px;
height: 20px;
display: inline-block;
@ -370,7 +392,7 @@ td.rowtargets > span.listarea
.listarea.error .listelement
{
background-color: #FFFFC4;
background-color: #FFFF88;
}
.listelement:first-child
@ -402,7 +424,7 @@ td.rowtargets > span.listarea
display: inline-block;
width: 16px;
height: 16px;
background: url(images/erase.png?v=3052.453) -1px 0 no-repeat #eee;
background: url(images/erase.png) -1px 0 no-repeat #eee;
cursor: pointer;
}

@ -1,5 +1,5 @@
#messagemenu li a.filterlink {
background-image: url(images/filter.png?v=b0fe.547);
background-image: url(images/filter.png);
background-position: 7px 1px;
}

@ -0,0 +1,17 @@
<roundcube:include file="includes/layout.html" />
<roundcube:if condition="env:task != 'mail'" />
<h1 class="voice"><roundcube:label name="managesieve.filterdef" /></h1>
<roundcube:endif />
<div class="formcontent">
<roundcube:object name="filterform" id="filter-form" class="propform" compact-form="true" />
</div>
<roundcube:if condition="env:task != 'mail'" />
<div class="formbuttons">
<roundcube:button command="plugin.managesieve-save" class="btn btn-primary submit" label="save" />
</div>
<roundcube:endif />
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,73 @@
<roundcube:include file="includes/layout.html" />
<roundcube:include file="includes/menu.html" />
<roundcube:include file="includes/settings-menu.html" />
<h1 class="voice"><roundcube:label name="settings" /> : <roundcube:label name="managesieve.filters" /></h1>
<!-- filters list -->
<div class="list listbox selected">
<div class="header">
<a class="button icon menu-button" href="#menu"><span class="inner"><roundcube:label name="menu" /></span></a>
<a class="button icon back-sidebar-button" href="#sidebar"><span class="inner"><roundcube:label name="settings" /></span></a>
<span id="aria-label-filterslist" class="header-title"><roundcube:label name="managesieve.filters" /></span>
<a class="button icon toolbar-menu-button" href="#list-menu"><span class="inner"><roundcube:label name="menu" /></span></a>
</div>
<roundcube:if condition="!env:managesieve_no_set_list" />
<div class="pagenav pagenav-list toolbar" onclick="UI.switch_nav_list(this)">
<a class="button icon expand" href="#filtersetslistbox"><span class="inner"></span></a>
<span id="filterset-name" class="pagenav-text"></span>
<h2 class="voice" id="aria-label-filtersets"><roundcube:label name="managesieve.filtersets" /></h2>
</div>
<div id="filtersetslistbox" class="navlist scroller" aria-labelledby="aria-label-filtersets">
<roundcube:object name="filtersetslist" id="filtersetslist" class="listing"
summary="managesieve.ariasummaryfiltersetslist" type="list" noheader="true" role="listbox" />
</div>
<roundcube:endif />
<div class="scroller" aria-labelledby="aria-label-filterslist">
<roundcube:object name="filterslist" id="filterslist" class="listing" noheader="true"
role="listbox" data-list="filters_list" />
</div>
<roundcube:if condition="!env:managesieve_no_set_list" />
<div class="footer toolbar">
<roundcube:button name="filtersetactions" type="link" title="managesieve.arialabelfiltersetactions" label="actions"
class="button actions" innerclass="inner" data-popup="filterset-menu" />
</div>
<roundcube:endif />
</div>
<!-- filter details frame -->
<div class="content" role="main">
<h2 id="aria-label-toolbar" class="voice"><roundcube:label name="arialabeltoolbar" /></h2>
<div class="header" role="toolbar" aria-labelledby="aria-label-toolbar">
<a class="button icon back-list-button" href="#back"><span class="inner"><roundcube:label name="back" /></span></a>
<span class="header-title"></span>
<!-- toolbar -->
<div id="responsestoolbar" class="toolbar">
<roundcube:button command="plugin.managesieve-add" type="link"
label="create" title="managesieve.filteradd" innerClass="inner"
class="button create disabled" classAct="button create" />
<roundcube:button command="plugin.managesieve-del" type="link"
label="delete" title="delete" innerClass="inner"
class="button delete disabled" classAct="button delete" />
</div>
</div>
<h2 id="aria-label-filterframe" class="voice"><roundcube:label name="managesieve.arialabelfilterform" /></h2>
<roundcube:object name="filterframe" id="filter-box" src="/watermark.html" title="managesieve.arialabelfilterform"
aria-labelledby="aria-label-filterform" />
</div>
<div id="filterset-menu" class="popupmenu">
<h3 id="aria-label-setactions" class="voice"><roundcube:label name="managesieve.arialabelfiltersetactions" /></h3>
<ul class="toolbarmenu listing" id="filtersetmenu-menu" role="menu" aria-labelledby="aria-label-setactions">
<roundcube:button type="link-menuitem" command="plugin.managesieve-setadd" label="managesieve.filtersetadd" class="create" classAct="create active" />
<roundcube:if condition="env:raw_sieve_editor != false" />
<roundcube:button type="link-menuitem" command="plugin.managesieve-seteditraw" label="managesieve.filterseteditraw" class="edit" classAct="edit active" data-hidden="small" />
<roundcube:endif />
<roundcube:button type="link-menuitem" command="plugin.managesieve-setact" label="managesieve.filtersetswitch" class="status" classAct="status active" />
<roundcube:button type="link-menuitem" command="plugin.managesieve-setdel" label="managesieve.filtersetdel" class="delete" classAct="delete active" />
<roundcube:button type="link-menuitem" command="plugin.managesieve-setget" label="download" class="download" classAct="download active" />
<roundcube:container name="filtersetoptions" id="filtersetmenu-menu" />
</ul>
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,13 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="managesieve.newfilterset" /></h1>
<div class="formcontent">
<roundcube:object name="filtersetform" class="propform" />
</div>
<div class="formbuttons">
<roundcube:button command="plugin.managesieve-save" class="btn btn-primary submit" label="save" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,13 @@
<roundcube:include file="includes/layout.html" />
<h1 class="voice"><roundcube:label name="managesieve.filterseteditraw" /></h1>
<div class="formcontent">
<roundcube:object name="filterseteditraw" class="propform" />
</div>
<div class="formbuttons">
<roundcube:button command="plugin.managesieve-save" class="btn btn-primary submit" label="save" />
</div>
<roundcube:include file="includes/footer.html" />

@ -0,0 +1,23 @@
<roundcube:include file="includes/layout.html" />
<roundcube:include file="includes/menu.html" />
<roundcube:include file="includes/settings-menu.html" />
<h1 class="voice"><roundcube:label name="managesieve.vacation" /></h1>
<div class="content selected" role="main">
<div class="header">
<a class="button icon back-list-button" href="#back"><span class="inner"><roundcube:label name="back" /></span></a>
<span class="header-title"></span>
</div>
<div class="formcontainer scroller" aria-labelledby="aria-label-vacationform">
<div class="formcontent">
<h2 class="voice" id="aria-label-vacationform"><roundcube:label name="managesieve.vacation" /></h2>
<roundcube:object name="vacationform" id="vacationform" class="propform" />
</div>
<div class="formbuttons">
<roundcube:button command="plugin.managesieve-save" class="btn btn-primary submit" label="save" />
</div>
</div>
</div>
<roundcube:include file="includes/footer.html" />

@ -101,6 +101,20 @@ body.iframe
vertical-align: middle;
}
#filter-form li {
border: none;
}
#filter-form .col-form-label {
display: inline-block;
min-width: 75px;
line-height: 2.5;
}
#filter-form .col-form-label + div {
display: inline;
}
#rules, #actions
{
margin-top: 5px;
@ -134,28 +148,38 @@ div.rulerow table, div.actionrow table
vertical-align: top;
}
#filter-form div.flexbox {
margin: 0;
}
td.advbutton
{
width: 1%;
overflow: hidden;
}
td.advbutton a
{
display: block;
padding-top: 14px;
padding-top: 16px;
height: 6px;
width: 12px;
text-decoration: none;
}
td.advbutton a span
{
display: none;
}
td.advbutton a.show
{
background: url(images/down_small.gif?v=8629.106) center no-repeat;
background: url(images/down_small.gif) center no-repeat;
}
td.advbutton a.hide
{
background: url(images/up_small.gif?v=c56c.106) center no-repeat;
background: url(images/up_small.gif) center no-repeat;
}
td.rowbuttons
@ -292,9 +316,14 @@ span.sieve.error
border-radius: 0;
}
#filter-form a.button span
{
display: none;
}
#filter-form a.button.add
{
background: url(images/add.png?v=a165.280) no-repeat;
background: url(images/add.png) no-repeat;
width: 30px;
height: 20px;
margin-right: 4px;
@ -303,7 +332,7 @@ span.sieve.error
#filter-form a.button.del
{
background: url(images/del.png?v=3c27.247) no-repeat;
background: url(images/del.png) no-repeat;
width: 30px;
height: 20px;
display: inline-block;
@ -414,7 +443,7 @@ td.rowtargets > span.listarea
display: inline-block;
width: 16px;
height: 16px;
background: url(images/erase.png?v=3052.453) -1px -1px no-repeat #eee;
background: url(images/erase.png) -1px -1px no-repeat #eee;
cursor: pointer;
}
@ -435,7 +464,7 @@ body.iframe.mail #filter-form
/* vacation form */
#settings-sections .vacation a {
background-image: url(images/vacation_icons.png?v=e738.767);
background-image: url(images/vacation_icons.png);
background-repeat: no-repeat;
background-position: 7px 1px;
}

@ -21,23 +21,19 @@ class markasjunk extends rcube_plugin
$this->add_hook('storage_init', array($this, 'storage_init'));
if ($rcmail->action == '' || $rcmail->action == 'show') {
$skin_path = $this->local_skin_path();
$this->add_texts('localization', true);
$this->include_script('markasjunk.js');
if (is_file($this->home . "/$skin_path/markasjunk.css")) {
$this->include_stylesheet("$skin_path/markasjunk.css");
}
$this->include_stylesheet($this->local_skin_path() . '/markasjunk.css', true);
$this->add_button(array(
'type' => 'link',
'label' => 'buttontext',
'command' => 'plugin.markasjunk',
'class' => 'button buttonPas junk disabled',
'classact' => 'button junk',
'title' => 'buttontitle',
'domain' => 'markasjunk'
'type' => 'link',
'label' => 'buttontext',
'command' => 'plugin.markasjunk',
'title' => 'buttontitle',
'domain' => 'markasjunk',
'class' => 'button buttonPas junk disabled',
'classact' => 'button junk',
'innerclass' => 'inner',
),'toolbar');
}
}

@ -3,7 +3,7 @@
"type": "roundcube-plugin",
"description": "When a new user is created, this plugin checks the default identity and sets a session flag in case it is incomplete. An overlay box will appear on the screen until the user has reviewed/completed his identity.",
"license": "GPLv3+",
"version": "2.1",
"version": "2.2",
"authors": [
{
"name": "Thomas Bruederli",

@ -53,73 +53,82 @@ class new_user_dialog extends rcube_plugin
$identities_level = intval($rcmail->config->get('identities_level', 0));
// compose user-identity dialog
$table = new html_table(array('cols' => 2));
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
$table->add('title', $this->gettext('name'));
$table->add('title', html::label('newuserdialog-name', $this->gettext('name')));
$table->add(null, html::tag('input', array(
'id' => 'newuserdialog-name',
'type' => 'text',
'name' => '_name',
'value' => $identity['name'],
'disabled' => $identities_level == 4
)));
$table->add('title', $this->gettext('email'));
$table->add('title', html::label('newuserdialog-email', $this->gettext('email')));
$table->add(null, html::tag('input', array(
'id' => 'newuserdialog-email',
'type' => 'text',
'name' => '_email',
'value' => rcube_utils::idn_to_utf8($identity['email']),
'disabled' => in_array($identities_level, array(1, 3, 4))
)));
$table->add('title', $this->gettext('organization'));
$table->add('title', html::label('newuserdialog-org', $this->gettext('organization')));
$table->add(null, html::tag('input', array(
'id' => 'newuserdialog-org',
'type' => 'text',
'name' => '_organization',
'value' => $identity['organization'],
'disabled' => $identities_level == 4
)));
$table->add('title', $this->gettext('signature'));
$table->add('title', html::label('newuserdialog-sig', $this->gettext('signature')));
$table->add(null, html::tag('textarea', array(
'id' => 'newuserdialog-sig',
'name' => '_signature',
'rows' => '3',
'rows' => '5',
),
$identity['signature']
));
// add overlay input box to html page
$rcmail->output->add_footer(html::tag('form', array(
'id' => 'newuserdialog',
'id' => 'newuserdialog',
'action' => $rcmail->url('plugin.newusersave'),
'method' => 'post'
'method' => 'post',
'class' => 'formcontent',
'style' => 'display: none',
),
html::p('hint', rcube::Q($this->gettext('identitydialoghint'))) .
$table->show() .
html::p(array('class' => 'formbuttons'),
html::tag('input', array('type' => 'submit',
'class' => 'button mainaction', 'value' => $this->gettext('save'))))
html::p('hint', rcube::Q($this->gettext('identitydialoghint'))) . $table->show()
));
$title = rcube::JQ($this->gettext('identitydialogtitle'));
$script = "
$('#newuserdialog').show()
.dialog({modal:true, resizable:false, closeOnEscape:false, width:450, title:'$title'})
.submit(function() {
var i, request = {}, form = $(this).serializeArray();
for (i in form)
request[form[i].name] = form[i].value;
var newuserdialog = rcmail.show_popup_dialog($('#newuserdialog'), '$title', [{
text: rcmail.get_label('save'),
'class': 'mainaction save',
click: function() {
var request = {};
$.each($('form', this).serializeArray(), function() {
request[this.name] = this.value;
});
rcmail.http_post('plugin.newusersave', request, true);
return false;
});
$('input[name=_name]').focus();
rcube_webmail.prototype.new_user_dialog_close = function() { $('#newuserdialog').dialog('close'); }
}
}],
{
resizable: false,
closeOnEscape: false,
width: 500,
open: function() { $('#newuserdialog').show(); $('#newuserdialog-name').focus(); },
beforeClose: function() { return false; }
}
);
rcube_webmail.prototype.new_user_dialog_close = function() { newuserdialog.dialog('destroy'); };
";
// disable keyboard events for messages list (#1486726)
$rcmail->output->add_script($script, 'docready');
$this->include_stylesheet('newuserdialog.css');
}
}

@ -1,39 +0,0 @@
/** Styles for the new-user-dialog box */
#newuserdialog {
display: none;
}
#newuserdialog h3 {
color: #333;
font-size: normal;
margin-top: 0;
margin-bottom: 0;
}
#newuserdialog p.hint {
margin-top: 0.5em;
margin-bottom: 1em;
font-style: italic;
}
#newuserdialog table td.title {
color: #666;
text-align: right;
padding-right: 1em;
white-space: nowrap;
}
#newuserdialog table td input,
#newuserdialog table td textarea {
width: 20em;
}
#newuserdialog .formbuttons {
margin-top: 1.5em;
text-align: center;
}
.ui-dialog-titlebar-close {
display: none;
}

@ -30,20 +30,28 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
input_confpasswd = rcube_find_object('_confpasswd');
if (input_curpasswd && input_curpasswd.value == '') {
alert(rcmail.get_label('nocurpassword', 'password'));
input_curpasswd.focus();
rcmail.alert_dialog(rcmail.get_label('nocurpassword', 'password'), function() {
input_curpasswd.focus();
return true;
});
}
else if (input_newpasswd && input_newpasswd.value == '') {
alert(rcmail.get_label('nopassword', 'password'));
input_newpasswd.focus();
rcmail.alert_dialog(rcmail.get_label('nopassword', 'password'), function() {
input_newpasswd.focus();
return true;
});
}
else if (input_confpasswd && input_confpasswd.value == '') {
alert(rcmail.get_label('nopassword', 'password'));
input_confpasswd.focus();
rcmail.alert_dialog(rcmail.get_label('nopassword', 'password'), function() {
input_confpasswd.focus();
return true;
});
}
else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) {
alert(rcmail.get_label('passwordinconsistency', 'password'));
input_newpasswd.focus();
rcmail.alert_dialog(rcmail.get_label('passwordinconsistency', 'password'), function() {
input_newpasswd.focus();
return true;
});
}
else {
rcmail.gui_objects.passform.submit();

@ -213,7 +213,7 @@ class password extends rcube_plugin
$rcmail->output->set_env('product_name', $rcmail->config->get('product_name'));
$rcmail->output->set_env('password_disabled', !empty($form_disabled));
$table = new html_table(array('cols' => 2));
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
if ($rcmail->config->get('password_confirm_current')) {
// show current password selection
@ -279,26 +279,26 @@ class password extends rcube_plugin
$submit_button = $rcmail->output->button(array(
'command' => 'plugin.password-save',
'class' => 'button mainaction save',
'class' => 'button mainaction submit',
'label' => 'save',
));
$form_buttons = html::p(array('class' => 'formbuttons'), $submit_button);
$out = html::div(array('class' => 'box'),
html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd'))
. html::div(array('class' => 'boxcontent'),
$disabled_msg . $table->show() . $rules . $form_buttons));
$form_buttons = html::p(array('class' => 'formbuttons footerleft'), $submit_button);
$rcmail->output->add_gui_object('passform', 'password-form');
$this->include_script('password.js');
return $rcmail->output->form_tag(array(
$form = $rcmail->output->form_tag(array(
'id' => 'password-form',
'name' => 'password-form',
'method' => 'post',
'action' => './?_task=settings&_action=plugin.password-save',
), $out);
), $disabled_msg . $table->show() . $rules);
return html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd'))
. html::div(array('class' => 'box formcontainer scroller'),
html::div(array('class' => 'boxcontent formcontent'), $form)
. $form_buttons);
}
private function _save($curpass, $passwd)

@ -3,7 +3,7 @@
"type": "roundcube-plugin",
"description": "Sample plugin that adds a new tab to the settings section to display some information about the current user.",
"license": "GPLv3+",
"version": "1.0",
"version": "1.1",
"authors": [
{
"name": "Thomas Bruederli",

@ -1,18 +0,0 @@
/* Show user-info plugin script */
if (window.rcmail) {
rcmail.addEventListener('init', function() {
// <span id="settingstabdefault" class="tablink"><roundcube:button command="preferences" type="link" label="preferences" title="editpreferences" /></span>
var tab = $('<span>').attr('id', 'settingstabpluginuserinfo').addClass('tablink');
$('<a>').attr('href', rcmail.env.comm_path + '&_action=plugin.userinfo')
.text(rcmail.get_label('userinfo', 'userinfo'))
.click(function(e) { return rcmail.command('plugin.userinfo', '', this, e); })
.appendTo(tab);
// add button and register command
rcmail.add_element(tab, 'tabs');
rcmail.register_command('plugin.userinfo', function() { rcmail.goto_url('plugin.userinfo') }, true);
})
}

@ -13,14 +13,29 @@ class userinfo extends rcube_plugin
function init()
{
$this->add_texts('localization/', array('userinfo'));
$this->add_hook('settings_actions', array($this, 'settings_actions'));
$this->register_action('plugin.userinfo', array($this, 'infostep'));
$this->include_script('userinfo.js');
}
function settings_actions($args)
{
$args['actions'][] = array(
'action' => 'plugin.userinfo',
'class' => 'userinfo',
'label' => 'userinfo',
'domain' => 'userinfo',
);
return $args;
}
function infostep()
{
$this->register_handler('plugin.body', array($this, 'infohtml'));
rcmail::get_instance()->output->send('plugin');
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($this->gettext('userinfo'));
$rcmail->output->send('plugin');
}
function infohtml()
@ -29,26 +44,31 @@ class userinfo extends rcube_plugin
$user = $rcmail->user;
$identity = $user->get_identity();
$table = new html_table(array('cols' => 2, 'cellpadding' => 3));
$table = new html_table(array('cols' => 2, 'class' => 'propform'));
$table->add('title', 'ID');
$table->add('title', html::label('', 'ID'));
$table->add('', rcube::Q($user->ID));
$table->add('title', rcube::Q($this->gettext('username')));
$table->add('title', html::label('', rcube::Q($this->gettext('username'))));
$table->add('', rcube::Q($user->data['username']));
$table->add('title', rcube::Q($this->gettext('server')));
$table->add('title', html::label('', rcube::Q($this->gettext('server'))));
$table->add('', rcube::Q($user->data['mail_host']));
$table->add('title', rcube::Q($this->gettext('created')));
$table->add('title', html::label('', rcube::Q($this->gettext('created'))));
$table->add('', rcube::Q($user->data['created']));
$table->add('title', rcube::Q($this->gettext('lastlogin')));
$table->add('title', html::label('', rcube::Q($this->gettext('lastlogin'))));
$table->add('', rcube::Q($user->data['last_login']));
$table->add('title', rcube::Q($this->gettext('defaultidentity')));
$table->add('title', html::label('', rcube::Q($this->gettext('defaultidentity'))));
$table->add('', rcube::Q($identity['name'] . ' <' . $identity['email'] . '>'));
return html::tag('h4', null, rcube::Q('Infos for ' . $user->get_username())) . $table->show();
$legend = rcube::Q('Infos for ' . $user->get_username());
$out = html::tag('fieldset', '', html::tag('legend', '', $legend) . $table->show());
return html::div(array('class' => 'box formcontent'),
html::div(array('class' => 'boxtitle'), $this->gettext('userinfo'))
. html::div(array('class' => 'boxcontent'), $out));
}
}

@ -3,7 +3,7 @@
"type": "roundcube-plugin",
"description": "Detects vCard attachments and allows to add them to address book. Also allows to attach vCards of your contacts to composed messages",
"license": "GPLv3+",
"version": "4.0",
"version": "4.1",
"authors": [
{
"name": "Thomas Bruederli",

@ -2,18 +2,26 @@
p.vcardattachment {
margin: 0.5em 1em;
border: 1px solid #999;
border-radius:4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
width: auto;
position: relative;
}
p.vcardattachment a {
p.vcardattachment span {
display: block;
background: url(vcard_add_contact.png) 4px 0px no-repeat;
padding: 0.7em 0.5em 0.3em 42px;
height: 22px;
line-height: 32px;
padding: 0 60px 0 46px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
p.vcardattachment button {
position: absolute;
right: 0;
top: 0;
margin: 6px;
}
#abookactions a.vcard span {
@ -27,3 +35,7 @@ p.vcardattachment a {
#abookactions a.vcard.disabled span {
opacity: 0.5;
}
.messagelist tr .attachment span.attachment.vcard {
background: url(vcard.png) 0 center no-repeat;
}

@ -5,15 +5,31 @@ p.vcardattachment {
background: #f9f9f9;
border: 1px solid #d3d3d3;
border-radius: 4px;
position: relative;
}
p.vcardattachment a {
p.vcardattachment span {
display: block;
background: url(vcard_add_contact.png) 6px 2px no-repeat;
padding: 1.2em 0.5em 0.7em 46px;
line-height: 32px;
padding: 0 60px 0 46px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
p.vcardattachment button {
position: absolute;
right: 0;
top: 0;
margin: 5px;
}
a.listbutton.vcard .inner
{
background-position: center -2107px;
}
.messagelist tbody tr .attachment span.attachment.vcard {
background: url(vcard.png) 0 center no-repeat;
}

@ -21,6 +21,7 @@ class vcard_attachments extends rcube_plugin
if ($rcmail->action == 'show' || $rcmail->action == 'preview') {
$this->add_hook('message_load', array($this, 'message_load'));
$this->add_hook('message_objects', array($this, 'message_objects'));
$this->add_hook('template_object_messagebody', array($this, 'html_output'));
}
else if ($rcmail->action == 'upload') {
@ -31,7 +32,7 @@ class vcard_attachments extends rcube_plugin
$btn_class = strpos($skin_path, 'classic') ? 'button' : 'listbutton';
$this->add_texts('localization', true);
$this->include_stylesheet($skin_path . '/style.css');
$this->include_stylesheet($skin_path . '/style.css', true);
$this->include_script('vcardattach.js');
$this->add_button(
array(
@ -46,8 +47,8 @@ class vcard_attachments extends rcube_plugin
'compose-contacts-toolbar');
}
else if (!$rcmail->output->framed && (!$rcmail->action || $rcmail->action == 'list')) {
$icon = 'plugins/vcard_attachments/' .$this->local_skin_path(). '/vcard.png';
$rcmail->output->set_env('vcard_icon', $icon);
$skin_path = $this->local_skin_path();
$this->include_stylesheet($skin_path . '/style.css', true);
$this->include_script('vcardattach.js');
}
@ -81,12 +82,13 @@ class vcard_attachments extends rcube_plugin
}
/**
* This callback function adds a box below the message content
* This callback function adds a box above the message content
* if there is a vcard attachment available
*/
function html_output($p)
function message_objects($p)
{
$attach_script = false;
$rcmail = rcmail::get_instance();
foreach ($this->vcard_parts as $part) {
$vcards = rcube_vcard::import($this->message->get_part_content($part, null, true));
@ -96,11 +98,6 @@ class vcard_attachments extends rcube_plugin
continue;
}
// remove part's body
if (in_array($part, $this->vcard_bodies)) {
$p['content'] = '';
}
foreach ($vcards as $idx => $vcard) {
// skip invalid vCards
if (empty($vcard->email) || empty($vcard->email[0])) {
@ -108,15 +105,16 @@ class vcard_attachments extends rcube_plugin
}
$display = $vcard->displayname . ' <'.$vcard->email[0].'>';
$vid = rcube::JQ($part.':'.$idx);
// add box below message body
$p['content'] .= html::p(array('class' => 'vcardattachment'),
html::a(array(
'href' => "#",
'onclick' => "return plugin_vcard_save_contact('" . rcube::JQ($part.':'.$idx) . "')",
'title' => $this->gettext('addvcardmsg'),
),
html::span(null, rcube::Q($display)))
$p['content'][] = html::p(array('class' => 'vcardattachment aligned-buttons'),
html::span(null, rcube::Q($display)) .
html::tag('button', array(
'onclick' => "return plugin_vcard_save_contact('$vid')",
'title' => $this->gettext('addvcardmsg'),
'class' => 'import',
), rcube::Q($rcmail->gettext('import')))
);
}
@ -125,7 +123,23 @@ class vcard_attachments extends rcube_plugin
if ($attach_script) {
$this->include_script('vcardattach.js');
$this->include_stylesheet($this->local_skin_path() . '/style.css');
$this->include_stylesheet($this->local_skin_path() . '/style.css', true);
}
return $p;
}
/**
* This callback function removes message part's content
* for parts that are vcards
*/
function html_output($p)
{
foreach ($this->vcard_parts as $part) {
// remove part's body
if (in_array($part, $this->vcard_bodies)) {
$p['content'] = '';
}
}
return $p;

@ -4,7 +4,7 @@
* @licstart The following is the entire license notice for the
* JavaScript code in this file.
*
* Copyright (c) 2012-2016, The Roundcube Dev Team
* Copyright (c) 2012-2017, The Roundcube Dev Team
*
* The JavaScript code in this page is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
@ -25,11 +25,8 @@ function plugin_vcard_save_contact(mime_id)
function plugin_vcard_insertrow(data)
{
var ctype = data.row.ctype;
if (ctype == 'text/vcard' || ctype == 'text/x-vcard' || ctype == 'text/directory') {
$('#rcmrow' + rcmail.html_identifier(data.uid, true) + ' > td.attachment')
.html('<img src="' + rcmail.env.vcard_icon + '" alt="" />');
if (data.row.ctype.match(/^(text\/vcard|text\/x-vcard|text\/directory)$/i)) {
$(data.row.obj).find('.attachment > .attachment').addClass('vcard');
}
}

@ -86,7 +86,7 @@ class zipdownload extends rcube_plugin
break;
}
$this->include_stylesheet($this->local_skin_path() . '/zipdownload.css');
$this->include_stylesheet($this->local_skin_path() . '/zipdownload.css', true);
}
return $p;
@ -111,7 +111,8 @@ class zipdownload extends rcube_plugin
$menu[] = html::tag('li', null, $rcmail->output->button(array(
'command' => "download-$type",
'label' => "zipdownload.download$type",
'classact' => 'active',
'class' => "download $type",
'classact' => "download $type active",
'type' => 'link',
)));
}

@ -455,7 +455,7 @@ class rcmail extends rcube
// add some basic labels to client
$this->output->add_label('loading', 'servererror', 'connerror', 'requesttimedout',
'refreshing', 'windowopenerror', 'uploadingmany', 'close', 'save', 'cancel');
'refreshing', 'windowopenerror', 'uploadingmany', 'close', 'save', 'cancel', 'alerttitle', 'confirmationtitle', 'delete', 'continue', 'ok');
return $this->output;
}

@ -1210,7 +1210,7 @@ EOF;
$content = html::quote($ver);
}
else if ($object == 'steptitle') {
$content = html::quote($this->get_pagetitle());
$content = html::quote($this->get_pagetitle());
}
else if ($object == 'pagetitle') {
if ($this->devel_mode && !empty($_SESSION['username']))
@ -1484,7 +1484,7 @@ EOF;
}
else if ($attrib['type'] == 'link') {
$btn_content = isset($attrib['content']) ? $attrib['content'] : ($attrib['label'] ? $attrib['label'] : $attrib['command']);
$link_attrib = array_merge(html::$common_attrib, array('href', 'onclick', 'tabindex', 'target'));
$link_attrib = array_merge(html::$common_attrib, array('href', 'onclick', 'tabindex', 'target', 'rel'));
if ($attrib['innerclass'])
$btn_content = html::span($attrib['innerclass'], $btn_content);
}

@ -1195,7 +1195,11 @@ class rcmail_sendmail
$hiddenfields->add(array('name' => '_id', 'value' => $this->data['id']));
$hiddenfields->add(array('name' => '_attachments'));
$form_start = empty($attrib['form']) ? $this->rcmail->output->form_tag(array('name' => "form", 'method' => "post")) : '';
if (empty($attrib['form'])) {
$form_attr = array('name' => "form", 'method' => "post", 'class' => $attrib['class']);
$form_start = $this->rcmail->output->form_tag($form_attr);
}
$form_start .= $hiddenfields->show();
}

@ -63,7 +63,8 @@ function rcube_webmail()
recipients_separator: ',', // @deprecated
recipients_delimiter: ', ', // @deprecated
popup_width: 1150,
popup_width_small: 900
popup_width_small: 900,
thread_padding: '15px'
};
// create protected reference to myself
@ -115,7 +116,7 @@ function rcube_webmail()
this.buttons[command].push(button_prop);
if (this.loaded)
init_button(command, button_prop);
this.init_button(command, button_prop);
};
// register a specific gui object
@ -282,8 +283,7 @@ function rcube_webmail()
}, this.env.mail_read_time * 1000);
if (this.env.blockedobjects) {
if (this.gui_objects.remoteobjectsmsg)
this.gui_objects.remoteobjectsmsg.style.display = 'block';
$(this.gui_objects.remoteobjectsmsg).show();
this.enable_command('load-remote', true);
}
@ -720,14 +720,18 @@ function rcube_webmail()
// check input before leaving compose step
if (this.task == 'mail' && this.env.action == 'compose' && !this.env.server_error && command != 'save-pref'
&& $.inArray(command, this.env.compose_commands) < 0
&& $.inArray(command, this.env.compose_commands) < 0 && !this.compose_skip_unsavedcheck
) {
if (!this.env.is_sent && this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
return false;
if (!this.env.is_sent && this.cmp_hash != this.compose_field_hash()) {
this.confirm_dialog(this.get_label('notsentwarning'), 'discard', function() {
// remove copy from local storage if compose screen is left intentionally
ref.remove_compose_data(ref.env.compose_id);
ref.compose_skip_unsavedcheck = true;
ref.command(command, props, obj, event);
});
// remove copy from local storage if compose screen is left intentionally
this.remove_compose_data(this.env.compose_id);
this.compose_skip_unsavedcheck = true;
return false;
}
}
this.last_command = command;
@ -944,8 +948,9 @@ function rcube_webmail()
if (form) {
// user prefs
if ((input = $("[name='_pagesize']", form)) && input.length && isNaN(parseInt(input.val()))) {
alert(this.get_label('nopagesizewarning'));
input.focus();
this.alert_dialog(this.get_label('nopagesizewarning'), function() {
input.focus();
});
break;
}
// contacts/identities
@ -957,8 +962,9 @@ function rcube_webmail()
else if (this.task == 'settings' && (this.env.identities_level % 2) == 0 &&
(input = $("[name='_email']", form)) && input.length && !rcube_check_email(input.val())
) {
alert(this.get_label('noemailwarning'));
input.focus();
this.alert_dialog(this.get_label('noemailwarning'), function() {
input.focus();
});
break;
}
}
@ -1199,7 +1205,7 @@ function rcube_webmail()
if (!(flag = this.upload_file(props || this.gui_objects.uploadform, 'upload'))) {
if (flag !== false)
alert(this.get_label('selectimportfile'));
this.alert_dialog(this.get_label('selectimportfile'));
aborted = true;
}
break;
@ -1351,7 +1357,7 @@ function rcube_webmail()
if (!(flag = this.upload_file(form, 'import', importlock))) {
this.set_busy(false, null, importlock);
if (flag !== false)
alert(this.get_label('selectimportfile'));
this.alert_dialog(this.get_label('selectimportfile'));
aborted = true;
}
break;
@ -1366,7 +1372,7 @@ function rcube_webmail()
if (form) {
var lock, file = win.$('#rcmimportfile')[0];
if (file && !file.value) {
alert(win.rcmail.get_label('selectimportfile'));
win.rcmail.alert_dialog(win.rcmail.get_label('selectimportfile'));
return;
}
@ -1548,22 +1554,28 @@ function rcube_webmail()
// Add variable to GET string, replace old value if exists
this.add_url = function(url, name, value)
{
var urldata, datax, hash = '';
value = urlencode(value);
if (/(#[a-z0-9_-]+)$/.test(url)) {
hash = RegExp.$1;
url = url.substr(0, url.length - hash.length);
}
if (/(\?.*)$/.test(url)) {
var urldata = RegExp.$1,
datax = RegExp('((\\?|&)'+RegExp.escape(name)+'=[^&]*)');
urldata = RegExp.$1;
datax = RegExp('((\\?|&)'+RegExp.escape(name)+'=[^&]*)');
if (datax.test(urldata)) {
if (datax.test(urldata))
urldata = urldata.replace(datax, RegExp.$2 + name + '=' + value);
}
else
urldata += '&' + name + '=' + value
urldata += '&' + name + '=' + value;
return url.replace(/(\?.*)$/, urldata);
return url.replace(/(\?.*)$/, urldata) + hash;
}
return url + '?' + name + '=' + value;
return url + '?' + name + '=' + value + hash;
};
// append CSRF protection token to the given url
@ -2319,13 +2331,20 @@ function rcube_webmail()
});
if (this.env.threading && message.depth) {
$('td.subject', domrow).attr('style', 'padding-left:' + Math.min(90, message.depth * 15) + 'px !important');
n = this.calculate_thread_padding(message.depth);
$('td.subject', domrow).attr('style', 'padding-left:' + n + ' !important');
$('span.branch', domrow).remove();
}
return domrow;
};
this.calculate_thread_padding = function(level)
{
ref.env.thread_padding.match(/^([0-9.]+)(.+)/);
return (Math.min(6, level) * parseFloat(RegExp.$1)) + RegExp.$2;
};
this.set_list_sorting = function(sort_col, sort_order)
{
var sort_old = this.env.sort_col == 'arrival' ? 'date' : this.env.sort_col,
@ -3142,8 +3161,9 @@ function rcube_webmail()
else {
// if shift was pressed delete it immediately
if ((list && list.modkey == SHIFT_KEY) || (event && rcube_event.get_modifier(event) == SHIFT_KEY)) {
if (confirm(this.get_label('deletemessagesconfirm')))
this.permanently_remove_messages();
this.confirm_dialog(this.get_label('deletemessagesconfirm'), 'delete', function() {
ref.permanently_remove_messages();
});
}
else
this.move_messages(trash);
@ -3522,7 +3542,7 @@ function rcube_webmail()
// go to specified page
var p = parseInt(this.value);
if (p && p != ref.env.current_page && !ref.busy) {
ref.hide_menu('pagejump-selector');
ref.hide_menu('pagejump-selector', e);
ref.list_page(p);
}
});
@ -3691,7 +3711,7 @@ function rcube_webmail()
// notify user about loosing attachments
if (ref.env.attachments && !$.isEmptyObject(ref.env.attachments)) {
alert(ref.get_label('encryptnoattachments'));
ref.alert_dialog(ref.get_label('encryptnoattachments'));
$.each(ref.env.attachments, function(name, attach) {
ref.remove_from_attachment_list(name);
@ -3748,8 +3768,9 @@ function rcube_webmail()
if (!isvalid) {
if (!recipients.length) {
alert(ref.get_label('norecipientwarning'));
$("[name='_to']").focus();
ref.alert_dialog(ref.get_label('norecipientwarning'), function() {
$("[name='_to']").focus();
});
}
return false;
}
@ -3940,11 +3961,10 @@ function rcube_webmail()
});
li.append(ul_);
li.append($('<input>')
.attr('type', 'button')
li.append($('<button>')
.attr('rel', keyrec.keyid)
.attr('value', ref.get_label('import'))
.addClass('button importkey')
.text(ref.get_label('import'))
.addClass('button import importkey')
.prop('disabled', keyrec.revoked || keyrec.disabled || keyrec.expired));
ul.append(li);
@ -3961,7 +3981,7 @@ function rcube_webmail()
);
// delegate handler for import button clicks
ul.on('click', 'input.button.importkey', function() {
ul.on('click', 'button.importkey', function() {
var btn = $(this),
keyid = btn.attr('rel'),
pk = new PublicKey(),
@ -3984,7 +4004,7 @@ function rcube_webmail()
// import to keyring
ref.mailvelope_keyring.importPublicKey(armored).then(function(status) {
if (status === 'REJECTED') {
// alert(ref.get_label('Key import was rejected'));
// ref.alert_dialog(ref.get_label('Key import was rejected'));
}
else {
var $key = keyid.substr(-8).toUpperCase();
@ -4022,19 +4042,20 @@ function rcube_webmail()
this.purge_mailbox = function(mbox)
{
var lock, post_data = {_mbox: mbox};
this.confirm_dialog(this.get_label('purgefolderconfirm'), 'delete', function() {
var lock, post_data = {_mbox: mbox};
if (!confirm(this.get_label('purgefolderconfirm')))
return false;
// lock interface if it's the active mailbox
if (mbox == ref.env.mailbox) {
lock = ref.set_busy(true, 'loading');
post_data._reload = 1;
}
// lock interface if it's the active mailbox
if (mbox == this.env.mailbox) {
lock = this.set_busy(true, 'loading');
post_data._reload = 1;
}
// send request to server
ref.http_post('purge', post_data, lock);
});
// send request to server
this.http_post('purge', post_data, lock);
return false;
};
// test if purge command is allowed
@ -4503,7 +4524,7 @@ function rcube_webmail()
// check if all files has been uploaded
for (key in this.env.attachments) {
if (typeof this.env.attachments[key] === 'object' && !this.env.attachments[key].complete) {
alert(this.get_label('notuploadedwarning'));
this.alert_dialog(this.get_label('notuploadedwarning'));
return false;
}
}
@ -4585,15 +4606,17 @@ function rcube_webmail()
// check sender (if have no identities)
if (input_from.prop('type') == 'text' && !rcube_check_email(input_from.val(), true)) {
alert(this.get_label('nosenderwarning'));
input_from.focus();
this.alert_dialog(this.get_label('nosenderwarning'), function() {
input_from.focus();
});
return false;
}
// check for empty recipient
if (!rcube_check_email(get_recipients([input_to, input_cc, input_bcc]), true)) {
alert(this.get_label('norecipientwarning'));
input_to.focus();
this.alert_dialog(this.get_label('norecipientwarning'), function() {
input_to.focus();
});
return false;
}
@ -4750,8 +4773,10 @@ function rcube_webmail()
}
// submit delete request
if (key && confirm(this.get_label('deleteresponseconfirm'))) {
this.http_post('settings/delete-response', { _key: key }, false);
if (key) {
this.confirm_dialog(this.get_label('deleteresponseconfirm'), 'delete', function() {
ref.http_post('settings/delete-response', { _key: key }, false);
});
}
};
@ -5158,14 +5183,16 @@ function rcube_webmail()
if (!this.gui_objects.attachmentlist)
return false;
var label, indicator, li = $('<li>');
if (!att.complete && this.env.loadingicon)
att.html = '<img src="'+this.env.loadingicon+'" alt="" class="uploading" />' + att.html;
if (!att.complete && att.frame)
att.html = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+name+'\', \''+att.frame+'\');" href="#cancelupload" class="cancelupload">'
+ (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="'+this.get_label('cancel')+'" />' : this.get_label('cancel')) + '</a>' + att.html;
var indicator, li = $('<li>');
if (!att.complete && att.frame) {
label = this.get_label('cancel');
att.html = '<a title="'+label+'" onclick="return rcmail.cancel_attachment_upload(\''+name+'\', \''+att.frame+'\');" href="#cancelupload" class="cancelupload">'
+ (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="'+label+'" />' : '<span class="inner">' + label + '</span>') + '</a>' + att.html;
}
li.attr('id', name)
.addClass(att.classname)
@ -5756,33 +5783,19 @@ function rcube_webmail()
this.ksearch_data.num--;
};
// Getter for input value (with support for non-input content-editable elements)
// returns a string from last comma to current cursor position
// Getter for input value
// returns a string from the last comma to current cursor position
this.ksearch_input_get = function()
{
if (!this.ksearch_input)
return '';
var sel, range, sp, cp = 0, value = '';
var cp = this.get_caret_pos(this.ksearch_input);
if (this.ksearch_input.value === undefined) {
if ((sel = window.getSelection()) && (range = sel.getRangeAt(0))) {
value = $(range.endContainer).text();
cp = range.endOffset;
}
else {
value = $(this.ksearch_input).text();
}
}
else {
cp = this.get_caret_pos(this.ksearch_input);
value = this.ksearch_input.value;
}
return value.substr(0, cp).split(/[,;]/).pop();
return this.ksearch_input.value.substr(0, cp).split(/[,;]/).pop();
};
// Setter for input value (with support for non-input content-editable elements)
// Setter for input value
// replaces 'from' string with 'to' and sets cursor position at the end
this.ksearch_input_replace = function(from, to, input)
{
@ -5792,24 +5805,15 @@ function rcube_webmail()
if (!input)
input = this.ksearch_input;
if (input.value === undefined) {
var node = $(input).contents().filter(function() { return this.nodeType == 3; }).last();
// here we assume there's only one text node
if (node.length) {
$(node)[0].textContent = to;
}
}
else {
var cpos = this.get_caret_pos(input),
p = input.value.lastIndexOf(from, cpos),
pre = input.value.substring(0, p),
end = input.value.substring(p + from.length, input.value.length);
var cpos = this.get_caret_pos(input),
p = input.value.lastIndexOf(from, cpos),
pre = input.value.substring(0, p),
end = input.value.substring(p + from.length, input.value.length);
input.value = pre + to + end;
input.value = pre + to + end;
// set caret to insert pos
this.set_caret_pos(input, p + to.length);
}
// set caret to insert pos
this.set_caret_pos(input, p + to.length);
// run onchange action on the element
$(input).change();
@ -6215,10 +6219,11 @@ function rcube_webmail()
{
var undelete = this.env.source && this.env.address_sources[this.env.source].undelete;
if (!undelete && !confirm(this.get_label('deletecontactconfirm')))
return;
return this._with_selected_contacts('delete');
if (!undelete) {
this.confirm_dialog(this.get_label('deletecontactconfirm'), 'delete', function() {
ref._with_selected_contacts('delete');
});
}
};
this._with_selected_contacts = function(action, post_data)
@ -6400,9 +6405,11 @@ function rcube_webmail()
this.group_delete = function()
{
if (this.env.group && confirm(this.get_label('deletegroupconfirm'))) {
var lock = this.set_busy(true, 'groupdeleting');
this.http_post('group-delete', {_source: this.env.source, _gid: this.env.group}, lock);
if (this.env.group) {
this.confirm_dialog(this.get_label('deletegroupconfirm'), 'delete', function() {
var lock = ref.set_busy(true, 'groupdeleting');
ref.http_post('group-delete', {_source: ref.env.source, _gid: ref.env.group}, lock);
});
}
};
@ -6515,20 +6522,21 @@ function rcube_webmail()
if (!elem)
elem = $('.ff_' + col);
if (label)
if (label && !$('label[for="ff_' + col + '"]').length)
elem.placeholder(label);
};
this.insert_edit_field = function(col, section, menu)
{
// just make pre-defined input field visible
var elem = $('#ff_'+col);
var elem = $('#ff_' + col);
if (elem.length) {
$('label[for="ff_' + col + '"]').parent().show();
elem.show().focus();
$(menu).children('option[value="'+col+'"]').prop('disabled', true);
$(menu).children('option[value="' + col + '"]').prop('disabled', true);
}
else {
var lastelem = $('.ff_'+col),
var lastelem = $('.ff_' + col),
appendcontainer = $('#contactsection'+section+' .contactcontroller'+col);
if (!appendcontainer.length) {
@ -6541,25 +6549,31 @@ function rcube_webmail()
sect.prepend(appendcontainer);
}
if (appendcontainer.length && appendcontainer.get(0).nodeName == 'FIELDSET') {
var input, colprop = this.env.coltypes[col],
if (appendcontainer.get(0).nodeName == 'FIELDSET') {
var label, input,
colprop = this.env.coltypes[col],
name_suffix = colprop.limit != 1 ? '[]' : '',
compact = $(menu).data('compact') ? true : false,
input_id = 'ff_' + col + (colprop.count || 0),
row = $('<div>').addClass('row'),
cell = $('<div>').addClass('contactfieldcontent data'),
label = $('<div>').addClass('contactfieldlabel label');
if (colprop.subtypes_select)
label.html(colprop.subtypes_select);
row = $('<div>').addClass('row input-group'),
cell = $('<div>').addClass('contactfieldcontent ' + colprop.type);
// Field label
if (colprop.subtypes_select) {
label = $(colprop.subtypes_select);
if (!compact)
label = $('<div>').addClass('contactfieldlabel label').append(label);
else
label.addClass('input-group-addon');
}
else
label.html('<label for="' + input_id + '">' + colprop.label + '</label>');
var name_suffix = colprop.limit != 1 ? '[]' : '';
label = $('<label>').addClass('contactfieldlabel label input-group-addon').attr('for', input_id).text(colprop.label);
// Field input
if (colprop.type == 'text' || colprop.type == 'date') {
input = $('<input>')
.addClass('ff_'+col)
.attr({type: 'text', name: '_'+col+name_suffix, size: colprop.size, id: input_id})
.appendTo(cell);
.addClass('form-control ff_' + col)
.attr({type: 'text', name: '_'+col+name_suffix, size: colprop.size, id: input_id});
this.init_edit_field(col, input);
@ -6568,17 +6582,19 @@ function rcube_webmail()
}
else if (colprop.type == 'textarea') {
input = $('<textarea>')
.addClass('ff_'+col)
.attr({ name: '_'+col+name_suffix, cols:colprop.size, rows:colprop.rows, id: input_id })
.appendTo(cell);
.addClass('form-control ff_' + col)
.attr({ name: '_' + col + name_suffix, cols: colprop.size, rows: colprop.rows, id: input_id });
this.init_edit_field(col, input);
}
else if (colprop.type == 'composite') {
var i, childcol, cp, first, templ, cols = [], suffices = [];
var i, childcol, cp, first, templ, cols = [], suffices = [], content = cell;
if (compact)
content = $('<div class="content input-group-addon">');
// read template for composite field order
if ((templ = this.env[col+'_template'])) {
if (templ = this.env[col + '_template']) {
for (i=0; i < templ.length; i++) {
cols.push(templ[i][1]);
suffices.push(templ[i][2]);
@ -6593,42 +6609,61 @@ function rcube_webmail()
childcol = cols[i];
cp = colprop.childs[childcol];
input = $('<input>')
.addClass('ff_'+childcol)
.attr({ type: 'text', name: '_'+childcol+name_suffix, size: cp.size })
.appendTo(cell);
cell.append(suffices[i] || " ");
.addClass('form-control ff_' + childcol)
.attr({ type: 'text', name: '_' + childcol + name_suffix, size: cp.size })
.appendTo(content);
if (!compact)
content.append(suffices[i] || " ");
this.init_edit_field(childcol, input);
if (!first) first = input;
}
input = first; // set focus to the first of this composite fields
if (compact)
input = content;
else
input = first; // set focus to the first of this composite fields
}
else if (colprop.type == 'select') {
input = $('<select>')
.addClass('ff_'+col)
.attr({ 'name': '_'+col+name_suffix, id: input_id })
.appendTo(cell);
.addClass('form-control ff_' + col)
.attr({ name: '_' + col + name_suffix, id: input_id });
var options = input.attr('options');
options[options.length] = new Option('---', '');
if (colprop.options)
$.each(colprop.options, function(i, val){ options[options.length] = new Option(val, i); });
$.each(colprop.options, function(i, val) { options[options.length] = new Option(val, i); });
}
if (input) {
var delbutton = $('<a href="#del"></a>')
.addClass('contactfieldbutton deletebutton')
.addClass('contactfieldbutton deletebutton input-group-addon icon delete')
.attr({title: this.get_label('delete'), rel: col})
.html(this.env.delbutton)
.click(function(){ ref.delete_edit_field(this); return false })
.appendTo(cell);
.click(function() { ref.delete_edit_field(this); return false; });
row.append(label).append(cell).appendTo(appendcontainer.show());
input.first().focus();
row.append(label);
if (!compact) {
if (colprop.type != 'composite')
cell.append(input);
row.append(cell.append(delbutton));
}
else
row.append(input).append(delbutton);
row.appendTo(appendcontainer.show());
if (input.is('div'))
input.find('input:first').focus();
else
input.first().focus();
// disable option if limit reached
if (!colprop.count) colprop.count = 0;
if (++colprop.count == colprop.limit && colprop.limit)
$(menu).children('option[value="'+col+'"]').prop('disabled', true);
$(menu).children('option[value="' + col + '"]').prop('disabled', true);
}
}
}
@ -6643,7 +6678,7 @@ function rcube_webmail()
// just clear input but don't hide the last field
if (--colprop.count <= 0 && colprop.visible)
$(elem).parent().children('input').val('').blur();
$(elem).parent().find('input').val('').blur();
else {
$(elem).parents('div.row').remove();
// hide entire fieldset if no more rows
@ -6821,7 +6856,7 @@ function rcube_webmail()
this.qrcode = function()
{
var title = this.get_label('qrcode'),
options = {button: false, cancel_button: 'close', width: 300, height: 350},
options = {button: false, cancel_button: 'close', width: 300, height: 300},
img = new Image(300, 300);
img.src = this.url('addressbook/qrcode', {_source: this.env.source, _cid: this.env.cid});
@ -6907,8 +6942,11 @@ function rcube_webmail()
id = this.env.iid ? this.env.iid : selection[0];
// submit request with appended token
if (id && confirm(this.get_label('deleteidentityconfirm')))
this.http_post('settings/delete-identity', { _iid: id }, true);
if (id) {
this.confirm_dialog(this.get_label('deleteidentityconfirm'), 'delete', function() {
ref.http_post('settings/delete-identity', { _iid: id }, true);
});
}
};
this.update_identity_row = function(id, name, add)
@ -7071,8 +7109,10 @@ function rcube_webmail()
if (!name)
name = this.env.mailbox;
if (name && confirm(this.get_label('deletefolderconfirm'))) {
this.http_post('delete-folder', {_mbox: name}, this.set_busy(true, 'folderdeleting'));
if (name) {
this.confirm_dialog(this.get_label('deletefolderconfirm'), 'delete', function() {
ref.http_post('delete-folder', {_mbox: name}, ref.set_busy(true, 'folderdeleting'));
});
}
};
@ -7424,7 +7464,7 @@ function rcube_webmail()
/********* GUI functionality *********/
/*********************************************************/
var init_button = function(cmd, prop)
this.init_button = function(cmd, prop)
{
var elm = document.getElementById(prop.id);
if (!elm)
@ -7460,7 +7500,7 @@ function rcube_webmail()
continue;
for (var i=0; i<this.buttons[cmd].length; i++) {
init_button(cmd, this.buttons[cmd][i]);
this.init_button(cmd, this.buttons[cmd][i]);
}
}
};
@ -7785,6 +7825,30 @@ function rcube_webmail()
else
popup.html(content);
// assign special classes to dialog buttons
var i = 0, fn = function(button, classes, idx) {
if (typeof button == 'function') {
button = {
click: button,
text: idx,
'class': classes
};
}
else {
buttons['class'] = classes;
}
return button;
};
if (options && options.button_classes)
$.each(buttons, function(idx, button) {
var cl = options.button_classes[i];
if (cl)
buttons[idx] = fn(button, cl, idx);
i++;
});
options = $.extend({
title: title,
buttons: buttons,
@ -7803,16 +7867,16 @@ function rcube_webmail()
// resize and center popup
var win = $(window), w = win.width(), h = win.height(),
width = popup.width(), height = options.height || (popup[0].scrollHeight + 20);
width = popup.width(),
height = options.height || (popup[0].scrollHeight + 20),
dialog = popup.parent(),
titlebar_height = $('.ui-dialog-titlebar', dialog).outerHeight(),
buttonpane_height = $('.ui-dialog-buttonpane', dialog).outerHeight(),
padding = (parseInt(dialog.css('padding-top')) + parseInt(popup.css('padding-top'))) * 2;
popup.dialog('option', {
height: Math.min(h - 40, height + 28 + (buttons ? 50 : 0)),
width: Math.min(w - 20, width + 28)
});
// assign special classes to dialog buttons
$.each(options.button_classes || [], function(i, v) {
if (v) $($('.ui-dialog-buttonpane button', popup.parent()).get(i)).addClass(v);
height: Math.min(h - 40, height + titlebar_height + buttonpane_height + padding + 2),
width: Math.min(w - 20, width + 24)
});
return popup;
@ -7822,12 +7886,17 @@ function rcube_webmail()
this.simple_dialog = function(content, title, action_func, options)
{
var title = this.get_label(title),
cancel_label = (options || {}).cancel_button || 'cancel',
save_label = (options || {}).button || 'save',
close_func = function(e, ui, dialog) { (ref.is_framed() ? parent.$ : $)(dialog || this).dialog('close'); },
save_class = (options || {}).button_class || save_label.replace(/^[^\.]+\./i, ''),
cancel_label = (options || {}).cancel_button || 'cancel',
cancel_class = (options || {}).cancel_class || cancel_label.replace(/^[^\.]+\./i, ''),
close_func = function(e, ui, dialog) {
(ref.is_framed() ? parent.$ : $)(dialog || this).dialog('close');
if (options && options.cancel_func) options.cancel_func(e, ref);
},
buttons = [{
text: ref.get_label(cancel_label),
'class': 'cancel',
text: this.get_label(cancel_label),
'class': cancel_class.replace(/close/i, 'cancel'),
click: close_func
}];
@ -7836,13 +7905,37 @@ function rcube_webmail()
else
buttons.unshift({
text: this.get_label(save_label),
'class': 'mainaction ' + save_label,
click: function(e, ui) { if (action_func(e)) close_func(e, ui, this); }
'class': 'mainaction ' + save_class,
click: function(e, ui) { if (action_func(e, ref)) close_func(e, ui, this); }
});
return this.show_popup_dialog(content, title, buttons, options);
};
// show_popup_dialog() wrapper for alert() type dialogs
this.alert_dialog = function(content, action, options)
{
options = $.extend(options || {}, {
cancel_button: 'ok',
cancel_class: 'save',
cancel_func: action
});
return this.simple_dialog(content, options.title || 'alerttitle', null, options);
};
// simple_dialog() wrapper for confirm() type dialogs
this.confirm_dialog = function(content, button_label, action, options)
{
var action_func = function(e, ref) { action(e, ref); return true; };
options = $.extend(options || {}, {
button: button_label || 'continue'
});
return this.simple_dialog(content, options.title || 'confirmationtitle', action_func, options);
};
// enable/disable buttons for page shifting
this.set_page_buttons = function()
{
@ -8069,7 +8162,7 @@ function rcube_webmail()
// display fetched raw headers
this.set_headers = function(content)
{
if (this.gui_objects.all_headers_row && this.gui_objects.all_headers_box && content)
if (this.gui_objects.all_headers_box && content)
$(this.gui_objects.all_headers_box).html(content).show();
};
@ -8085,7 +8178,7 @@ function rcube_webmail()
// fetch headers only once
if (!this.gui_objects.all_headers_box.innerHTML) {
this.http_post('headers', {_uid: this.env.uid, _mbox: this.env.mailbox},
this.http_request('headers', {_uid: this.env.uid, _mbox: this.env.mailbox},
this.display_message(this.get_label('loading'), 'loading')
);
}
@ -8122,7 +8215,7 @@ function rcube_webmail()
var n = 0, s = 0,
folder = ref.env.mailboxes[this],
id = folder.id,
a = $(link.cloneNode(false)),
a = $(link.cloneNode(false)).attr('rel', folder.id),
row = $('<li>');
if (folder.virtual)
@ -8159,7 +8252,6 @@ function rcube_webmail()
// register delegate event handler for folder item clicks
container.on('click', 'a.active', function(e) {
container.data('callback')($(this).data('id'));
return false;
});
this.folder_selector_element = container;
@ -8302,8 +8394,7 @@ function rcube_webmail()
this.focused_menu = null;
this.menu_keyboard_active = false;
}
}
};
// position a menu element on the screen in relation to other object
this.element_position = function(element, obj)
@ -8678,11 +8769,20 @@ function rcube_webmail()
if (response.action == 'list' || response.action == 'search') {
// highlight message row when we're back from message page
if (uid) {
if (!list.rows[uid])
if (uid === 'FIRST') {
uid = list.get_first_row();
}
else if (uid === 'LAST') {
uid = list.get_last_row();
}
else if (!list.rows[uid]) {
uid += '-' + this.env.mailbox;
if (list.rows[uid]) {
}
if (uid && list.rows[uid]) {
list.select(uid);
}
delete this.env.list_uid;
}
@ -8700,15 +8800,38 @@ function rcube_webmail()
}
}
else if (this.task == 'addressbook') {
this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
var list = this.contact_list,
uid = this.env.list_uid;
this.enable_command('export', (list && list.rowcount > 0));
if (response.action == 'list' || response.action == 'search') {
this.enable_command('search-create', this.env.source == '');
this.enable_command('search-delete', this.env.search_id);
this.update_group_commands();
if (this.contact_list.rowcount > 0 && !$(document.activeElement).is('input,textarea'))
this.contact_list.focus();
this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount });
if (list && uid) {
if (uid === 'FIRST') {
uid = list.get_first_row();
}
else if (uid === 'LAST') {
uid = list.get_last_row();
}
if (uid && list.rows[uid]) {
list.select(uid);
}
delete this.env.list_uid;
// trigger 'select' so all dependent actions update its state
list.triggerEvent('select');
}
if (list.rowcount > 0 && !$(document.activeElement).is('input,textarea'))
list.focus();
this.triggerEvent('listupdate', { folder:this.env.source, rowcount:list.rowcount });
}
}
break;
@ -8791,6 +8914,9 @@ function rcube_webmail()
// callback when an iframe finished loading
this.iframe_loaded = function(unlock)
{
if (!unlock)
unlock = this.env.frame_lock;
this.set_busy(false, null, unlock);
if (this.submit_timer)
@ -9576,7 +9702,7 @@ rcube_webmail.subject_text = function(elem)
{
var t = $(elem).clone();
t.find('.skip-on-drag,.skip-content,.voice').remove();
return t.text();
return $.trim(t.text());
};
// set event handlers on all iframe elements (and their contents)

@ -283,10 +283,13 @@ cancel: function(evt)
*/
is_keyboard: function(e)
{
return e && (
(e.type && String(e.type).match(/^key/)) // DOM3-compatible
|| (!e.pageX && (e.pageY || 0) <= 0 && !e.clientX && (e.clientY || 0) <= 0) // others
);
if (!e)
return false;
if (e.type)
return !!e.type.match(/^key/); // DOM3-compatible
return !e.pageX && (e.pageY || 0) <= 0 && !e.clientX && (e.clientY || 0) <= 0;
},
/**

@ -139,8 +139,9 @@ this.decorateTextarea = function(id)
this.checkSpellingState();
}
else if (this.report_ta_not_found)
alert('Text area not found');
else if (this.report_ta_not_found) {
rcmail.alert_dialog('Text area not found');
}
};
//////
@ -252,10 +253,12 @@ this.spellCheck = function(ignore)
$.ajax({ type: 'POST', url: this.getUrl(), data: this.createXMLReq(req_text), dataType: 'text',
error: function(o) {
if (ref.custom_ajax_error)
if (ref.custom_ajax_error) {
ref.custom_ajax_error(ref);
else
alert('An error was encountered on the server. Please try again later.');
}
else {
rcmail.alert_dialog('An error was encountered on the server. Please try again later.');
}
if (ref.main_controller) {
$(ref.spell_span).remove();
ref.removeIndicator();
@ -284,10 +287,12 @@ this.learnWord = function(word, id)
$.ajax({ type: 'POST', url: this.getUrl(), data: req_text, dataType: 'text',
error: function(o) {
if (ref.custom_ajax_error)
if (ref.custom_ajax_error) {
ref.custom_ajax_error(ref);
else
alert('An error was encountered on the server. Please try again later.');
}
else {
rcmail.alert_dialog('An error was encountered on the server. Please try again later.');
}
},
success: function(data) {
}

@ -931,7 +931,7 @@ get_first_row: function()
var i, uid, rows = this.tbody.childNodes;
for (i=0; i<rows.length; i++)
if (rows[i].id && (uid = this.get_row_uid(rows[i])))
if (rows[i].id && (uid = this.get_row_uid(rows[i])) && this.rows[uid])
return uid;
}
@ -944,13 +944,29 @@ get_last_row: function()
var i, uid, rows = this.tbody.childNodes;
for (i=rows.length-1; i>=0; i--)
if (rows[i].id && (uid = this.get_row_uid(rows[i])))
if (rows[i].id && (uid = this.get_row_uid(rows[i])) && this.rows[uid])
return uid;
}
return null;
},
get_next: function()
{
var row;
if (row = this.get_next_row()) {
return row.uid;
}
},
get_prev: function()
{
var row;
if (row = this.get_prev_row()) {
return row.uid;
}
},
row_tagname: function()
{
var row_tagnames = { table:'tr', ul:'li', '*':'div' };
@ -1584,7 +1600,7 @@ drag_mouse_move: function(e)
// append subject (of every row up to the limit) to the drag layer
$.each(selection, function(i, uid) {
if (i > limit) {
self.draglayer.append('...');
self.draglayer.append($('<div>').text('...'));
return false;
}

@ -95,6 +95,9 @@ function rcube_treelist_widget(node, p)
this.get_item = get_item;
this.get_node = get_node;
this.get_selection = get_selection;
this.get_next = get_next;
this.get_prev = get_prev;
this.get_single_selection = get_selection;
this.is_search = is_search;
this.reset_search = reset_search;
@ -928,6 +931,44 @@ function rcube_treelist_widget(node, p)
}
function get_next()
{
var node, child;
if (selection && (node = id2dom(selection))) {
child = node.children('ul').children('li:first');
if (child.length) {
return dom2id(child);
}
node = node.next();
if (node.length) {
return dom2id(node);
}
}
}
function get_prev()
{
var node, prev, child;
if (selection && (node = id2dom(selection))) {
prev = node.prev();
child = prev.find('li:last');
if (child.length) {
return dom2id(child);
}
if (prev.length) {
return dom2id(prev);
}
node = node.parent().parent();
if (node.length && node.is('li')) {
return dom2id(node);
}
}
}
///// drag & drop support
/**

@ -574,6 +574,38 @@ class html_checkbox extends html_inputfield
}
}
/**
* Class to create HTML button
*
* @package Framework
* @subpackage View
*/
class html_button extends html_inputfield
{
protected $tagname = 'button';
protected $type = 'button';
/**
* Get HTML code for this object
*
* @param string $content Text Content of the button
* @param array $attrib Additional attributes to override
*
* @return string HTML output
*/
public function show($content = '', $attrib = null)
{
// overwrite object attributes
if (is_array($attrib)) {
$this->attrib = array_merge($this->attrib, $attrib);
}
$this->content = $content;
return parent::show();
}
}
/**
* Class to create an HTML textarea
*
@ -871,26 +903,35 @@ class html_table extends html
$this->attrib = array_merge($this->attrib, $attrib);
}
$thead = $tbody = "";
$thead = '';
$tbody = '';
$col_tagname = $this->_col_tagname();
$row_tagname = $this->_row_tagname();
$head_tagname = $this->_head_tagname();
// include <thead>
if (!empty($this->header)) {
$rowcontent = '';
foreach ($this->header as $c => $col) {
$rowcontent .= self::tag($this->_head_tagname(), $col->attrib, $col->content);
$rowcontent .= self::tag($head_tagname, $col->attrib, $col->content);
}
$thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) :
self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib);
self::tag($row_tagname, array('class' => 'thead'), $rowcontent, parent::$common_attrib);
}
foreach ($this->rows as $r => $row) {
$rowcontent = '';
foreach ($row->cells as $c => $col) {
$rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content);
if ($row_tagname == 'li' && empty($col->attrib) && count($row->cells) == 1) {
$rowcontent .= $col->content;
}
else {
$rowcontent .= self::tag($col_tagname, $col->attrib, $col->content);
}
}
if ($r < $this->rowindex || count($row->cells)) {
$tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib);
$tbody .= self::tag($row_tagname, $row->attrib, $rowcontent, parent::$common_attrib);
}
}

@ -354,11 +354,12 @@ abstract class rcube_plugin
/**
* Make this stylesheet available on the client
*
* @param string $fn File path; absolute or relative to the plugin directory
* @param string $fn File path; absolute or relative to the plugin directory
* @param bool $if_exists Include the file only if exists
*/
public function include_stylesheet($fn)
public function include_stylesheet($fn, $if_exists = false)
{
$this->api->include_stylesheet($this->resource_url($fn));
$this->api->include_stylesheet($this->resource_url($fn), $if_exists);
}
/**

@ -604,11 +604,21 @@ class rcube_plugin_api
/**
* Include a plugin stylesheet in the current HTML page
*
* @param string $fn Path to stylesheet
* @param string $fn Path to stylesheet
* @param bool $if_exists Include stylesheet only if the file exists
*/
public function include_stylesheet($fn)
public function include_stylesheet($fn, $if_exists = false)
{
if (is_object($this->output) && $this->output->type == 'html') {
if ($if_exists && $fn[0] != '/' && !preg_match('|^https?://|i', $fn)) {
$rcube = rcube::get_instance();
$path = unslashify($rcube->config->get('assets_dir') ?: RCUBE_INSTALL_PATH);
if (!is_file("$path/plugins/$fn")) {
return;
}
}
$src = $this->resource_url($fn);
$this->output->include_css($src);
}

@ -361,6 +361,9 @@ $labels['edit'] = 'Edit';
$labels['cancel'] = 'Cancel';
$labels['save'] = 'Save';
$labels['delete'] = 'Delete';
$labels['discard'] = 'Discard';
$labels['continue'] = 'Continue';
$labels['ok'] = 'OK';
$labels['rename'] = 'Rename';
$labels['addphoto'] = 'Add';
$labels['replacephoto'] = 'Replace';

@ -76,6 +76,8 @@ $messages['errormoving'] = 'Could not move the message(s).';
$messages['errorcopying'] = 'Could not copy the message(s).';
$messages['errordeleting'] = 'Could not delete the message(s).';
$messages['errormarking'] = 'Could not mark the message(s).';
$messages['alerttitle'] = 'Attention';
$messages['confirmationtitle'] = 'Are you sure...';
$messages['deletecontactconfirm'] = 'Do you really want to delete the selected contact(s)?';
$messages['deletegroupconfirm'] = 'Do you really want to delete the selected group?';
$messages['deletemessagesconfirm'] = 'Do you really want to delete the selected message(s)?';

@ -164,6 +164,9 @@ $labels['folders-all'] = 'All folders';
$labels['more'] = 'More';
$labels['back'] = 'Back';
$labels['options'] = 'Options';
$labels['composeoptions'] = 'Compose options';
$labels['optionsandattachments'] = 'Options and attachments';
$labels['actions'] = 'Actions';
$labels['first'] = 'First';
$labels['last'] = 'Last';
@ -207,6 +210,7 @@ $labels['listcolumns'] = 'List columns';
$labels['listsorting'] = 'Sorting column';
$labels['listorder'] = 'Sorting order';
$labels['listmode'] = 'List view mode';
$labels['lmode'] = 'List mode';
$labels['layout'] = 'Layout';
$labels['layoutwidescreen'] = 'Widescreen';
$labels['layoutdesktop'] = 'Desktop';
@ -228,6 +232,9 @@ $labels['quotatotal'] = 'Limit';
$labels['quotaused'] = 'Used';
$labels['quotastorage'] = 'Disk space';
$labels['quotamessage'] = 'Messages count';
$labels['shortheaderdate'] = 'On $date';
$labels['shortheaderto'] = 'To $to on $date';
$labels['shortheaderfrom'] = 'From $from on $date';
$labels['quicksearch'] = 'Quick search';
$labels['searchplaceholder'] = 'Search...';
@ -279,6 +286,7 @@ $labels['keylength'] = 'Bits';
$labels['keyexpired'] = 'Expired';
$labels['keyrevoked'] = 'Revoked';
$labels['bccinstead'] = 'Use Bcc';
$labels['addheader'] = 'Add recipient (header)';
$labels['editidents'] = 'Edit identities';
$labels['spellcheck'] = 'Spell';
@ -322,6 +330,8 @@ $labels['alwaysshow'] = 'Always show images from $sender';
$labels['alwaysallow'] = 'Always allow from $sender';
$labels['isdraft'] = 'This is a draft message.';
$labels['andnmore'] = '$nr more...';
$labels['headers'] = 'Headers';
$labels['envelope'] = 'Envelope';
$labels['togglemoreheaders'] = 'Show more message headers';
$labels['togglefullheaders'] = 'Toggle raw message headers';
@ -403,12 +413,16 @@ $labels['contacts'] = 'Contacts';
$labels['contactproperties'] = 'Contact properties';
$labels['contactnameandorg'] = 'Name and Organization';
$labels['personalinfo'] = 'Personal information';
$labels['personal'] = 'Personal';
$labels['contactphoto'] = 'Contact photo';
$labels['edit'] = 'Edit';
$labels['cancel'] = 'Cancel';
$labels['save'] = 'Save';
$labels['delete'] = 'Delete';
$labels['discard'] = 'Discard';
$labels['continue'] = 'Continue';
$labels['ok'] = 'OK';
$labels['rename'] = 'Rename';
$labels['addphoto'] = 'Add';
$labels['replacephoto'] = 'Replace';
@ -676,6 +690,7 @@ $labels['arialabelcomposeoptions'] = 'Composition options';
$labels['arialabelresponsesmenu'] = 'Canned responses menu';
$labels['arialabelattachmentuploadform'] = 'Attachment upload form';
$labels['arialabelattachmentmenu'] = 'Attachment options';
$labels['arialabelmailtomenu'] = 'Email address options';
$labels['arialabelattachmentpreview'] = 'Attachment preview';
$labels['ariasummarycomposecontacts'] = 'List of contacts and groups to select as recipients';
$labels['arialabelcontactexportoptions'] = 'Contact export options';
@ -685,6 +700,7 @@ $labels['arialabelidentityeditfrom'] = 'Identity edit form';
$labels['arialabelresonseeditfrom'] = 'Response edit form';
$labels['arialabelsearchterms'] = 'Search terms';
$labels['arialabeldropactionmenu'] = 'Drag-n-Drop action menu';
$labels['arialabelheadersmenu'] = 'Recipient (header) adding menu';
$labels['helplistnavigation'] = 'List keyboard navigation';
$labels['helplistkeyboardnavigation'] = "Arrows up/down: Move row focus/selection.

@ -78,6 +78,8 @@ $messages['errormoving'] = 'Could not move the message(s).';
$messages['errorcopying'] = 'Could not copy the message(s).';
$messages['errordeleting'] = 'Could not delete the message(s).';
$messages['errormarking'] = 'Could not mark the message(s).';
$messages['alerttitle'] = 'Attention';
$messages['confirmationtitle'] = 'Are you sure...';
$messages['deletecontactconfirm'] = 'Do you really want to delete selected contact(s)?';
$messages['deletegroupconfirm'] = 'Do you really want to delete selected group?';
$messages['deletemessagesconfirm'] = 'Do you really want to delete selected message(s)?';

@ -110,16 +110,17 @@ function rcmail_contact_edithead($attrib)
'head' => array(
'name' => $RCMAIL->gettext('contactnameandorg'),
'content' => array(
'prefix' => array('size' => $i_size),
'firstname' => array('size' => $i_size, 'visible' => true),
'middlename' => array('size' => $i_size),
'surname' => array('size' => $i_size, 'visible' => true),
'suffix' => array('size' => $i_size),
'name' => array('size' => 2*$i_size),
'nickname' => array('size' => 2*$i_size),
'organization' => array('size' => 2*$i_size),
'department' => array('size' => 2*$i_size),
'jobtitle' => array('size' => 2*$i_size),
'source' => array('id' => '_source', 'label' => $RCMAIL->gettext('addressbook')),
'prefix' => array('size' => $i_size),
'firstname' => array('size' => $i_size, 'visible' => true),
'middlename' => array('size' => $i_size),
'surname' => array('size' => $i_size, 'visible' => true),
'suffix' => array('size' => $i_size),
'name' => array('size' => 2*$i_size),
'nickname' => array('size' => 2*$i_size),
'organization' => array('size' => 2*$i_size),
'department' => array('size' => 2*$i_size),
'jobtitle' => array('size' => 2*$i_size),
)
)
);
@ -140,12 +141,14 @@ function rcmail_contact_editform($attrib)
$record = rcmail_get_edit_record();
// copy (parsed) address template to client
if (preg_match_all('/\{([a-z0-9]+)\}([^{]*)/i', $RCMAIL->config->get('address_template', ''), $templ, PREG_SET_ORDER))
$RCMAIL->output->set_env('address_template', $templ);
if (preg_match_all('/\{([a-z0-9]+)\}([^{]*)/i', $RCMAIL->config->get('address_template', ''), $templ, PREG_SET_ORDER)) {
$RCMAIL->output->set_env('address_template', $templ);
}
$i_size = $attrib['size'] ?: 40;
$t_rows = $attrib['textarearows'] ?: 10;
$t_cols = $attrib['textareacols'] ?: 40;
$i_size = $attrib['size'] ?: 40;
$t_rows = $attrib['textarearows'] ?: 10;
$t_cols = $attrib['textareacols'] ?: 40;
$short_labels = rcube_utils::get_boolean($attrib['short-legend-labels']);
$form = array(
'contact' => array(
@ -159,7 +162,7 @@ function rcmail_contact_editform($attrib)
),
),
'personal' => array(
'name' => $RCMAIL->gettext('personalinfo'),
'name' => $RCMAIL->gettext($short_labels ? 'personal' : 'personalinfo'),
'content' => array(
'gender' => array('visible' => true),
'maidenname' => array('size' => $i_size),

@ -522,6 +522,7 @@ function rcmail_contact_form($form, $record, $attrib = null)
// group fields
$head_fields = array(
'source' => array('source'),
'names' => array('prefix','firstname','middlename','surname','suffix'),
'displayname' => array('name'),
'nickname' => array('nickname'),
@ -538,9 +539,18 @@ function rcmail_contact_form($form, $record, $attrib = null)
$record = $plugin['record'];
$head_fields = $plugin['head_fields'];
$edit_mode = $RCMAIL->action != 'show' && $RCMAIL->action != 'print';
$del_button = $attrib['deleteicon'] ? html::img(array('src' => $RCMAIL->output->get_skin_file($attrib['deleteicon']), 'alt' => $RCMAIL->gettext('delete'))) : $RCMAIL->gettext('delete');
$compact = rcube_utils::get_boolean($attrib['compact-form']);
$use_labels = rcube_utils::get_boolean($attrib['use-labels']);
$with_source = rcube_utils::get_boolean($attrib['with-source']);
$out = '';
if ($attrib['deleteicon']) {
$del_button = html::img(array('src' => $RCMAIL->output->get_skin_file($attrib['deleteicon']), 'alt' => $RCMAIL->gettext('delete')));
}
else {
$del_button = html::span('inner', $RCMAIL->gettext('delete'));
}
unset($attrib['deleteicon']);
// get default coltypes
@ -566,7 +576,7 @@ function rcmail_contact_form($form, $record, $attrib = null)
continue;
}
$select_add = new html_select(array('class' => 'addfieldmenu', 'rel' => $section));
$select_add = new html_select(array('class' => 'addfieldmenu', 'rel' => $section, 'data-compact' => $compact ? "true" : null));
$select_add->add($RCMAIL->gettext('addfield'), '');
// render head section with name fields (not a regular list of rows)
@ -579,11 +589,29 @@ function rcmail_contact_form($form, $record, $attrib = null)
}
foreach ($head_fields as $blockname => $colnames) {
$fields = '';
$fields = '';
$block_attr = array('class' => $blockname . (count($colnames) == 1 ? ' row' : ''));
foreach ($colnames as $col) {
if ($col == 'source') {
if (!$with_source || !($source = $RCMAIL->output->get_env('sourcename'))) {
continue;
}
if (!$edit_mode) {
$record['source'] = $RCMAIL->gettext('addressbook') . ': ' . $source;
}
else if ($RCMAIL->action == 'add') {
$record['source'] = $source;
}
else {
continue;
}
}
// skip cols unknown to the backend
if (!$coltypes[$col])
else if (!$coltypes[$col]) {
continue;
}
// skip cols not listed in the form definition
if (is_array($fieldset['content']) && !in_array($col, array_keys($fieldset['content']))) {
@ -591,30 +619,61 @@ function rcmail_contact_form($form, $record, $attrib = null)
}
// only string values are expected here
if (is_array($record[$col]))
if (is_array($record[$col])) {
$record[$col] = join(' ', $record[$col]);
}
if (!$edit_mode) {
if (!empty($record[$col]))
$fields .= html::span('namefield ' . $col, rcube::Q($record[$col])) . " ";
if (!empty($record[$col])) {
$fields .= html::span('namefield ' . $col, rcube::Q($record[$col])) . ' ';
}
}
else {
$colprop = (array)$fieldset['content'][$col] + (array)$coltypes[$col];
$colprop['id'] = 'ff_'.$col;
$visible = true;
if (empty($colprop['id'])) {
$colprop['id'] = 'ff_' . $col;
}
if (empty($record[$col]) && !$colprop['visible']) {
$colprop['style'] = 'display:none';
$visible = false;
$colprop['style'] = $use_labels ? null : 'display:none';
$select_add->add($colprop['label'], $col);
}
$fields .= rcube_output::get_edit_field($col, $record[$col], $colprop, $colprop['type']);
if ($col == 'source') {
$input = rcmail_source_selector(array('id' => $colprop['id']));
}
else {
$input = rcube_output::get_edit_field($col, $record[$col], $colprop, $colprop['type']);
}
if ($use_labels) {
$_content = html::label($colprop['id'], rcube::Q($colprop['label'])) . html::div(null, $input);
if (count($colnames) > 1) {
$fields .= html::div(array('class' => 'row', 'style' => $visible ? null : 'display:none'), $_content);
}
else {
$fields .= $_content;
$block_attr['style'] = $visible ? null : 'display:none';
}
}
else {
$fields .= $input;
}
}
}
$content .= html::div($blockname, $fields);
$content .= html::div($block_attr, $fields);
}
if ($edit_mode)
if ($edit_mode) {
$content .= html::p('addfield', $select_add->show(null));
}
$out .= html::tag('fieldset', $attrib, (!empty($fieldset['name']) ? html::tag('legend', null, rcube::Q($fieldset['name'])) : '') . $content) ."\n";
$legend = !empty($fieldset['name']) ? html::tag('legend', null, rcube::Q($fieldset['name'])) : '';
$out .= html::tag('fieldset', $attrib, $legend . $content, html::$common_attrib) ."\n";
continue;
}
@ -702,11 +761,11 @@ function rcmail_contact_form($form, $record, $attrib = null)
if ($edit_mode) {
if ($colprop['subtypes'] || $colprop['limit'] != 1) $cp['array'] = true;
$composite['{'.$childcol.'}'] = rcube_output::get_edit_field($childcol, $childvalue, $cp, $cp['type']) . " ";
$composite['{'.$childcol.'}'] = rcube_output::get_edit_field($childcol, $childvalue, $cp, $cp['type']) . ' ';
}
else {
$childval = $cp['render_func'] ? call_user_func($cp['render_func'], $childvalue, $childcol) : rcube::Q($childvalue);
$composite['{'.$childcol.'}'] = html::span('data ' . $childcol, $childval) . " ";
$composite['{'.$childcol.'}'] = html::span('data ' . $childcol, $childval) . ' ';
}
$j++;
}
@ -714,58 +773,86 @@ function rcmail_contact_form($form, $record, $attrib = null)
$coltypes[$field] += (array)$colprop;
$coltypes[$field]['count']++;
$val = preg_replace('/\{\w+\}/', '', strtr($template, $composite));
if ($compact) {
$val = html::div('content', str_replace('<br/>', '', $val));
}
}
else if ($edit_mode) {
// call callback to render/format value
if ($colprop['render_func'])
if ($colprop['render_func']) {
$val = call_user_func($colprop['render_func'], $val, $col);
}
$coltypes[$field] = (array)$colprop + $coltypes[$field];
if ($colprop['subtypes'] || $colprop['limit'] != 1)
if ($colprop['subtypes'] || $colprop['limit'] != 1) {
$colprop['array'] = true;
}
// load jquery UI datepicker for date fields
if ($colprop['type'] == 'date') {
$colprop['class'] .= ($colprop['class'] ? ' ' : '') . 'datepicker';
if (!$colprop['render_func'])
if (!$colprop['render_func']) {
$val = rcmail_format_date_col($val);
}
}
$val = rcube_output::get_edit_field($col, $val, $colprop, $colprop['type']);
$coltypes[$field]['count']++;
}
else if ($colprop['render_func'])
else if ($colprop['render_func']) {
$val = call_user_func($colprop['render_func'], $val, $col);
else if (is_array($colprop['options']) && isset($colprop['options'][$val]))
}
else if (is_array($colprop['options']) && isset($colprop['options'][$val])) {
$val = $colprop['options'][$val];
else
}
else {
$val = rcube::Q($val);
}
// use subtype as label
if ($colprop['subtypes'])
if ($colprop['subtypes']) {
$label = rcmail_get_type_label($subtype);
}
$_del_btn = html::a(array('href' => '#del', 'class' => 'contactfieldbutton deletebutton', 'title' => $RCMAIL->gettext('delete'), 'rel' => $col), $del_button);
// add delete button/link
if ($edit_mode && !($colprop['visible'] && $colprop['limit'] == 1))
$val .= html::a(array('href' => '#del', 'class' => 'contactfieldbutton deletebutton', 'title' => $RCMAIL->gettext('delete'), 'rel' => $col), $del_button);
if (!$compact && $edit_mode && !($colprop['visible'] && $colprop['limit'] == 1)) {
$val .= $_del_btn;
}
// display row with label
if ($label) {
if ($RCMAIL->action == 'print') {
$_label = rcube::Q($colprop['label'] . ($label != $colprop['label'] ? ' (' . $label . ')' : ''));
if (!$compact) {
$_label = html::div('contactfieldlabel label', $_label);
}
}
else if ($select_subtype) {
$_label = $select_subtype->show($subtype);
if (!$compact) {
$_label = html::div('contactfieldlabel label', $_label);
}
}
else {
$_label = $select_subtype ? $select_subtype->show($subtype) : html::label($colprop['id'], rcube::Q($label));
$_label = html::label(array('class' => 'contactfieldlabel label', 'for' => $colprop['id']), rcube::Q($label));
}
$rows .= html::div('row',
html::div('contactfieldlabel label', $_label) .
html::div('contactfieldcontent '.$colprop['type'], $val));
if (!$compact) {
$val = html::div('contactfieldcontent ' . $colprop['type'], $val);
}
else {
$val .= $_del_btn;
}
$rows .= html::div('row', $_label . $val);
}
// row without label
else {
$rows .= html::div('row', html::div('contactfield', $val));
$rows .= html::div('row', $compact ? $val : html::div('contactfield', $val));
}
}
@ -787,12 +874,14 @@ function rcmail_contact_form($form, $record, $attrib = null)
}
}
if (!$content && (!$edit_mode || !$select_add->_count))
if (!$content && (!$edit_mode || !$select_add->_count)) {
continue;
}
// also render add-field selector
if ($edit_mode)
if ($edit_mode) {
$content .= html::p('addfield', $select_add->show(null, array('style' => $select_add->_count ? null : 'display:none')));
}
$content = html::div(array('id' => 'contactsection' . $section), $content);
}
@ -800,8 +889,10 @@ function rcmail_contact_form($form, $record, $attrib = null)
$content = $fieldset['content'];
}
if ($content)
$out .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($fieldset['name'])) . $content) ."\n";
if ($content) {
$out .= html::tag('fieldset', array('class' => $attrib['fieldset-class']),
html::tag('legend', null, rcube::Q($fieldset['name'])) . $content) . "\n";
}
}
if ($edit_mode) {

@ -256,7 +256,8 @@ function rcmail_contact_search_form($attrib)
{
global $RCMAIL, $CONTACT_COLTYPES;
$i_size = $attrib['size'] ?: 30;
$i_size = $attrib['size'] ?: 30;
$short_labels = rcube_utils::get_boolean($attrib['short-legend-labels']);
$form = array(
'main' => array(
@ -265,7 +266,7 @@ function rcmail_contact_search_form($attrib)
),
),
'personal' => array(
'name' => $RCMAIL->gettext('personalinfo'),
'name' => $RCMAIL->gettext($short_labels ? 'personal' : 'personalinfo'),
'content' => array(
),
),
@ -285,7 +286,7 @@ function rcmail_contact_search_form($attrib)
if (is_array($CONTACTS->coltypes)) {
$contact_cols = $CONTACTS->coltypes[0] ? array_flip($CONTACTS->coltypes) : $CONTACTS->coltypes;
$coltypes = array_merge($coltypes, $contact_cols);
$coltypes = array_merge($coltypes, $contact_cols);
}
}
@ -295,22 +296,24 @@ function rcmail_contact_search_form($attrib)
}
// build form fields list
foreach ($coltypes as $col => $colprop)
{
if ($colprop['type'] != 'image' && !$colprop['nosearch'])
{
foreach ($coltypes as $col => $colprop) {
if ($colprop['type'] != 'image' && !$colprop['nosearch']) {
$ftype = $colprop['type'] == 'select' ? 'select' : 'text';
$label = isset($colprop['label']) ? $colprop['label'] : $RCMAIL->gettext($col);
$category = $colprop['category'] ?: 'other';
// load jquery UI datepicker for date fields
if ($colprop['type'] == 'date')
if ($colprop['type'] == 'date') {
$colprop['class'] .= ($colprop['class'] ? ' ' : '') . 'datepicker';
else if ($ftype == 'text')
}
else if ($ftype == 'text') {
$colprop['size'] = $i_size;
}
$colprop['id'] = '_search_' . $col;
$content = html::div('row', html::div('contactfieldlabel label', rcube::Q($label))
$content = html::div('row',
html::label(array('class' => 'contactfieldlabel label', 'for' => $colprop['id']), rcube::Q($label))
. html::div('contactfieldcontent', rcube_output::get_edit_field('search_'.$col, '', $colprop, $ftype)));
$form[$category]['content'][] = $content;
@ -321,9 +324,12 @@ function rcmail_contact_search_form($attrib)
$hiddenfields->add(array('name' => '_adv', 'value' => 1));
$out = $RCMAIL->output->request_form(array(
'name' => 'form', 'method' => 'post',
'task' => $RCMAIL->task, 'action' => 'search',
'noclose' => true) + $attrib, $hiddenfields->show());
'name' => 'form',
'method' => 'post',
'task' => $RCMAIL->task,
'action' => 'search',
'noclose' => true,
) + $attrib, $hiddenfields->show());
$RCMAIL->output->add_gui_object('editform', $attrib['id']);

@ -70,6 +70,7 @@ function rcmail_contact_head($attrib)
'head' => array( // section 'head' is magic!
'name' => $RCMAIL->gettext('contactnameandorg'),
'content' => array(
'source' => array('type' => 'text'),
'prefix' => array('type' => 'text'),
'firstname' => array('type' => 'text'),
'middlename' => array('type' => 'text'),
@ -98,7 +99,8 @@ function rcmail_contact_details($attrib)
return false;
}
$i_size = $attrib['size'] ?: 40;
$i_size = $attrib['size'] ?: 40;
$short_labels = rcube_utils::get_boolean($attrib['short-legend-labels']);
$form = array(
'contact' => array(
@ -112,7 +114,7 @@ function rcmail_contact_details($attrib)
),
),
'personal' => array(
'name' => $RCMAIL->gettext('personalinfo'),
'name' => $RCMAIL->gettext($short_labels ? 'personal' : 'personalinfo'),
'content' => array(
'gender' => array('size' => $i_size),
'maidenname' => array('size' => $i_size),
@ -141,7 +143,7 @@ function rcmail_contact_details($attrib)
);
}
return rcmail_contact_form($form, $record);
return rcmail_contact_form($form, $record, $attrib);
}
@ -179,27 +181,32 @@ function rcmail_contact_record_groups($contact_id)
return '';
}
$form_attrs = array(
'name' => 'form',
'method' => 'post',
'task' => $RCMAIL->task,
'action' => 'save',
'request' => 'save.' . intval($contact_id),
'noclose' => true,
);
$list = array();
$members = $CONTACTS->get_record_groups($contact_id);
$table = new html_table(array('cols' => 2, 'cellspacing' => 0, 'border' => 0));
$table = new html_table(array('tagname' => 'ul', 'cols' => 1, 'class' => 'proplist simplelist'));
$checkbox = new html_checkbox(array('name' => '_gid[]',
'class' => 'groupmember', 'disabled' => $CONTACTS->readonly));
foreach ($GROUPS as $group) {
$gid = $group['ID'];
$table->add(null, $checkbox->show($members[$gid] ? $gid : null,
array('value' => $gid, 'id' => 'ff_gid' . $gid)));
$table->add(null, html::label('ff_gid' . $gid, rcube::Q($group['name'])));
$gid = $group['ID'];
$input = $checkbox->show($members[$gid] ? $gid : null, array('value' => $gid));
$table->add(null, html::label(null, $input . rcube::Q($group['name'])));
}
$hiddenfields = new html_hiddenfield(array('name' => '_source', 'value' => rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC)));
$hiddenfields->add(array('name' => '_cid', 'value' => $contact_id));
$form_start = $RCMAIL->output->request_form(array(
'name' => "form", 'method' => "post",
'task' => $RCMAIL->task, 'action' => 'save',
'request' => 'save.'.intval($contact_id),
'noclose' => true), $hiddenfields->show());
$form_end = '</form>';
$form_start = $RCMAIL->output->request_form($form_attrs, $hiddenfields->show());
$form_end = '</form>';
$RCMAIL->output->add_gui_object('editform', 'form');
$RCMAIL->output->add_label('addingmember', 'removingmember');

@ -81,7 +81,7 @@ $OUTPUT->add_label('notuploadedwarning', 'savingmessage',
'selectimportfile', 'messageissent', 'loadingdata', 'nopubkeyfor', 'nopubkeyforsender',
'encryptnoattachments','encryptedsendialog','searchpubkeyservers', 'importpubkeys',
'encryptpubkeysfound', 'search', 'close', 'import', 'keyid', 'keylength', 'keyexpired',
'keyrevoked', 'keyimportsuccess', 'keyservererror', 'attaching', 'namex', 'attachmentrename'
'keyrevoked', 'keyimportsuccess', 'keyservererror', 'attaching', 'namex', 'attachmentrename', 'discard'
);
$OUTPUT->set_pagetitle($RCMAIL->gettext('compose'));
@ -619,8 +619,9 @@ function rcmail_compose_body($attrib)
}
// If desired, set this textarea to be editable by TinyMCE
$attrib['data-html-editor'] = true;
if ($HTML_MODE) {
$attrib['class'] = 'mce_editor';
$attrib['class'] = trim($attrib['class'] . ' mce_editor');
}
$attrib['name'] = '_message';

@ -125,9 +125,6 @@ $OUTPUT->add_handlers(array(
'messagecountdisplay' => 'rcmail_messagecount_display',
'listmenulink' => 'rcmail_options_menu_link',
'mailboxname' => 'rcmail_mailbox_name_display',
'messageheaders' => 'rcmail_message_headers',
'messagefullheaders' => 'rcmail_message_full_headers',
'messagebody' => 'rcmail_message_body',
'messagecontentframe' => 'rcmail_messagecontent_frame',
'messageimportform' => 'rcmail_message_import_form',
'searchfilter' => 'rcmail_search_filter',
@ -667,7 +664,7 @@ function rcmail_options_menu_link($attrib = array())
global $RCMAIL;
$onclick = 'return ' . rcmail_output::JS_OBJECT_NAME . ".command('menu-open', 'messagelistmenu', this, event)";
$inner = $title = $RCMAIL->gettext('listoptions');
$inner = $title = $RCMAIL->gettext($attrib['label'] ?: 'listoptions');
if (is_string($attrib['optionsmenuicon']) && $attrib['optionsmenuicon'] != 'true') {
$inner = html::img(array('src' => $RCMAIL->output->abs_url($attrib['optionsmenuicon'], true), 'alt' => $title));
@ -1041,389 +1038,6 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml)
return $out;
}
/**
* return table with message headers
*/
function rcmail_message_headers($attrib, $headers=null)
{
global $MESSAGE, $PRINT_MODE, $RCMAIL;
static $sa_attrib;
// keep header table attrib
if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) {
$sa_attrib = $attrib;
}
else if (!is_array($attrib) && is_array($sa_attrib)) {
$attrib = $sa_attrib;
}
if (!isset($MESSAGE)) {
return false;
}
// get associative array of headers object
if (!$headers) {
$headers_obj = $MESSAGE->headers;
$headers = get_object_vars($MESSAGE->headers);
}
else if (is_object($headers)) {
$headers_obj = $headers;
$headers = get_object_vars($headers_obj);
}
else {
$headers_obj = rcube_message_header::from_array($headers);
}
// show these headers
$standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto',
'mail-reply-to', 'mail-followup-to', 'date', 'priority');
$exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array();
$output_headers = array();
foreach ($standard_headers as $hkey) {
if ($headers[$hkey])
$value = $headers[$hkey];
else if ($headers['others'][$hkey])
$value = $headers['others'][$hkey];
else if (!$attrib['valueof'])
continue;
if (in_array($hkey, $exclude_headers))
continue;
$ishtml = false;
$header_title = $RCMAIL->gettext(preg_replace('/(^mail-|-)/', '', $hkey));
if ($hkey == 'date') {
if ($PRINT_MODE)
$header_value = $RCMAIL->format_date($value, $RCMAIL->config->get('date_long', 'x'));
else
$header_value = $RCMAIL->format_date($value);
}
else if ($hkey == 'priority') {
if ($value) {
$header_value = html::span('prio' . $value, rcube::Q(rcmail_localized_priority($value)));
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'replyto') {
if ($headers['replyto'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'mail-reply-to') {
if ($headers['mail-replyto'] != $headers['replyto']
&& $headers['replyto'] != $headers['from']
) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'sender') {
if ($headers['sender'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'mail-followup-to') {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if ($hkey == 'subject' && empty($value)) {
$header_value = $RCMAIL->gettext('nosubject');
}
else {
$value = is_array($value) ? implode(' ', $value) : $value;
$header_value = trim(rcube_mime::decode_header($value, $headers['charset']));
}
$output_headers[$hkey] = array(
'title' => $header_title,
'value' => $header_value,
'raw' => $value,
'html' => $ishtml,
);
}
$plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array(
'output' => $output_headers,
'headers' => $headers_obj,
'exclude' => $exclude_headers, // readonly
'folder' => $MESSAGE->folder, // readonly
'uid' => $MESSAGE->uid, // readonly
));
// single header value is requested
if (!empty($attrib['valueof'])) {
$row = $plugin['output'][$attrib['valueof']];
return $row['html'] ? $row['value'] : rcube::Q($row['value']);
}
// compose html table
$table = new html_table(array('cols' => 2));
foreach ($plugin['output'] as $hkey => $row) {
$val = $row['html'] ? $row['value'] : rcube::Q($row['value']);
$table->add(array('class' => 'header-title'), rcube::Q($row['title']));
$table->add(array('class' => 'header '.$hkey), $val);
}
return $table->show($attrib);
}
/**
* Convert Priority header value into a localized string
*/
function rcmail_localized_priority($value)
{
global $RCMAIL;
$labels_map = array(
'1' => 'highest',
'2' => 'high',
'3' => 'normal',
'4' => 'low',
'5' => 'lowest',
);
if ($value && $labels_map[$value]) {
return $RCMAIL->gettext($labels_map[$value]);
}
return '';
}
/**
* return block to show full message headers
*/
function rcmail_message_full_headers($attrib)
{
global $OUTPUT, $RCMAIL;
$html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'), html::div(array('id' => 'headers-source'), ''));
$html .= html::div(array(
'class' => "more-headers show-headers",
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('show-headers','',this)",
'title' => $RCMAIL->gettext('togglefullheaders')
), '');
$OUTPUT->add_gui_object('all_headers_row', 'all-headers');
$OUTPUT->add_gui_object('all_headers_box', 'headers-source');
return html::div($attrib, $html);
}
/**
* Handler for the 'messagebody' GUI object
*
* @param array Named parameters
* @return string HTML content showing the message body
*/
function rcmail_message_body($attrib)
{
global $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS;
if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) {
return '';
}
if (!$attrib['id'])
$attrib['id'] = 'rcmailMsgBody';
$safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']);
$out = '';
$part_no = 0;
$header_attrib = array();
foreach ($attrib as $attr => $value) {
if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) {
$header_attrib[$regs[1]] = $value;
}
}
if (!empty($MESSAGE->parts)) {
foreach ($MESSAGE->parts as $part) {
if ($part->type == 'headers') {
$out .= html::div('message-partheaders', rcmail_message_headers(count($header_attrib) ? $header_attrib : null, $part->headers));
}
else if ($part->type == 'content') {
// unsupported (e.g. encrypted)
if ($part->realtype) {
if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') {
if (!empty($_SESSION['browser_caps']['pgpmime']) && ($pgp_mime_part = $MESSAGE->get_multipart_encrypted_part())) {
$out .= html::span('part-notice', $RCMAIL->gettext('externalmessagedecryption'));
$OUTPUT->set_env('pgp_mime_part', $pgp_mime_part->mime_id);
$OUTPUT->set_env('pgp_mime_container', '#' . $attrib['id']);
$OUTPUT->add_label('loadingdata');
}
if (!$MESSAGE->encrypted_part) {
$out .= html::span('part-notice', $RCMAIL->gettext('encryptedmessage'));
}
}
continue;
}
else if (!$part->size) {
continue;
}
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
else if (!rcube_utils::mem_check($part->size * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
continue;
}
// fetch part body
$body = $MESSAGE->get_part_body($part->mime_id, true);
// message is cached but not exists (#1485443), or other error
if ($body === false) {
rcmail_message_error($MESSAGE->uid);
}
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $part, 'prefix' => ''));
// Set attributes of the part container
$container_class = $part->ctype_secondary == 'html' ? 'message-htmlpart' : 'message-part';
$container_id = $container_class . (++$part_no);
$container_attrib = array('class' => $container_class, 'id' => $container_id);
$body_args = array(
'safe' => $safe_mode,
'plain' => !$RCMAIL->config->get('prefer_html'),
'css_prefix' => 'v' . $part_no,
'body_class' => 'rcmBody',
'container_id' => $container_id,
'container_attrib' => $container_attrib,
);
// Parse the part content for display
$body = rcmail_print_body($body, $part, $body_args);
// check if the message body is PGP encrypted
if (strpos($body, '-----BEGIN PGP MESSAGE-----') !== false) {
$OUTPUT->set_env('is_pgp_content', '#' . $container_id);
}
if ($part->ctype_secondary == 'html') {
$body = rcmail_html4inline($body, $body_args);
}
$out .= html::div($container_attrib, $plugin['prefix'] . $body);
}
}
}
else {
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0'
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
}
else {
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $MESSAGE, 'prefix' => ''));
$out .= html::div('message-part',
$plugin['prefix'] . rcmail_plain_body($MESSAGE->body));
}
}
// list images after mail body
if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) {
$thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
$client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes');
foreach ($MESSAGE->attachments as $attach_prop) {
// skip inline images
if ($attach_prop->content_id && $attach_prop->disposition == 'inline') {
continue;
}
// Content-Type: image/*...
if ($mimetype = rcmail_part_image_type($attach_prop)) {
// display thumbnails
if ($thumbnail_size) {
$supported = in_array($mimetype, $client_mimetypes);
$show_link = array(
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf(
'return %s.command(\'load-attachment\',\'%s\',this)',
rcmail_output::JS_OBJECT_NAME,
$attach_prop->mime_id)
);
$out .= html::p(array('class' => 'image-attachment', 'style' => $supported ? '' : 'display:none'),
html::a($show_link + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)),
html::img(array(
'class' => 'image-thumbnail',
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1',
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
'onload' => $supported ? '' : '$(this).parents(\'p.image-attachment\').show()',
))
) .
html::span('image-filename', rcube::Q($attach_prop->filename)) .
html::span('image-filesize', rcube::Q($RCMAIL->message_part_size($attach_prop))) .
html::span('attachment-links',
($supported ? html::a($show_link, $RCMAIL->gettext('showattachment')) . '&nbsp;' : '') .
html::a($show_link['href'] . '&_download=1', $RCMAIL->gettext('download'))
) .
html::br(array('style' => 'clear:both'))
);
}
else {
$out .= html::tag('fieldset', 'image-attachment',
html::tag('legend', 'image-filename', rcube::Q($attach_prop->filename)) .
html::p(array('align' => 'center'),
html::img(array(
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'),
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
)))
);
}
}
}
}
// tell client that there are blocked remote objects
if ($REMOTE_OBJECTS && !$safe_mode) {
$OUTPUT->set_env('blockedobjects', true);
}
return html::div($attrib, $out);
}
function rcmail_part_image_type($part)
{
$mimetype = strtolower($part->mimetype);

@ -19,7 +19,10 @@
+-----------------------------------------------------------------------+
*/
if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) {
$uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GP);
$inline = $OUTPUT instanceof rcmail_output_html;
if ($uid) {
if ($pos = strpos($uid, '.')) {
$message = new rcube_message($uid);
$source = $message->get_part_body(substr($uid, $pos + 1));
@ -44,13 +47,22 @@ if ($uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST)) {
'<br />'
), $source);
$OUTPUT->command('set_headers', $source);
$OUTPUT->add_handlers(array('dialogcontent' => 'rcmail_headers_output'));
if (!$inline) {
$OUTPUT->command('set_headers', $source);
}
}
else {
else if (!$inline) {
$RCMAIL->output->show_message('messageopenerror', 'error');
}
$OUTPUT->send();
$OUTPUT->send($inline ? 'dialog' : null);
}
exit;
function rcmail_headers_output()
{
global $source;
return $source;
}

@ -62,6 +62,10 @@ if ($uid) {
$RCMAIL->storage->set_charset($MESSAGE->headers->charset);
}
if (!isset($_SESSION['writeable_abook'])) {
$_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false;
}
$OUTPUT->set_pagetitle(abbreviate_string($MESSAGE->subject, 128, '...', true));
// set message environment
@ -72,6 +76,7 @@ if ($uid) {
$OUTPUT->set_env('mailbox', $mbox_name);
$OUTPUT->set_env('username', $RCMAIL->get_user_name());
$OUTPUT->set_env('permaurl', $RCMAIL->url(array('_action' => 'show', '_uid' => $msg_id, '_mbox' => $mbox_name)));
$OUTPUT->set_env('has_writeable_addressbook', $_SESSION['writeable_abook']);
if ($MESSAGE->headers->get('list-post', false)) {
$OUTPUT->set_env('list_post', true);
@ -150,9 +155,13 @@ if ($uid) {
$OUTPUT->add_handlers(array(
'messageattachments' => 'rcmail_message_attachments',
'mailboxname' => 'rcmail_mailbox_name_display',
'messageattachments' => 'rcmail_message_attachments',
'messageobjects' => 'rcmail_message_objects',
'messagesummary' => 'rcmail_message_summary',
'messageheaders' => 'rcmail_message_headers',
'messagefullheaders' => 'rcmail_message_full_headers',
'messagebody' => 'rcmail_message_body',
'contactphoto' => 'rcmail_message_contactphoto',
));
@ -188,36 +197,34 @@ function rcmail_message_attachments($attrib)
foreach ($MESSAGE->attachments as $attach_prop) {
$filename = rcmail_attachment_name($attach_prop, true);
$filesize = $RCMAIL->message_part_size($attach_prop);
if ($PRINT_MODE) {
$ol .= html::tag('li', array('id' => 'attach' . $attach_prop->mime_id),
rcube::Q(sprintf("%s (%s)", $filename, $filesize)));
$mimetype = rcmail_fix_mimetype($attach_prop->mimetype);
$class = rcube_utils::file2class($mimetype, $filename);
$id = 'attach' . $attach_prop->mime_id;
$size = html::span('attachment-size', '(' . rcube::Q($filesize) . ')');
if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) {
$title = $filename;
$filename = abbreviate_string($filename, $attrib['maxlength']);
}
else {
if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) {
$title = $filename;
$filename = abbreviate_string($filename, $attrib['maxlength']);
}
else {
$title = '';
}
$title = '';
}
$item = rcube::Q($filename) . ' ' . $size;
$size = ' ' . html::span('attachment-size', '(' . rcube::Q($filesize) . ')');
$mimetype = rcmail_fix_mimetype($attach_prop->mimetype);
$class = rcube_utils::file2class($mimetype, $filename);
$id = 'attach' . $attach_prop->mime_id;
$link = html::a(array(
if (!$PRINT_MODE) {
$item = html::a(array(
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)',
rcmail_output::JS_OBJECT_NAME, $attach_prop->mime_id),
'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)',
'title' => $title,
), rcube::Q($filename) . $size);
$ol .= html::tag('li', array('class' => $class, 'id' => $id), $link);
), $item);
$attachments[$attach_prop->mime_id] = $mimetype;
}
$ol .= html::tag('li', array('class' => $class, 'id' => $id), $item);
}
$out = html::tag('ul', $attrib, $ol, html::$common_attrib);
@ -237,8 +244,8 @@ function rcmail_remote_objects_msg()
$attrib['class'] = 'notice';
$attrib['style'] = 'display: none';
$msg = rcube::Q($RCMAIL->gettext('blockedresources')) . '&nbsp;';
$msg .= html::a(array(
$msg = html::span('', rcube::Q($RCMAIL->gettext('blockedresources'))) . '&nbsp;'
. html::a(array(
'href' => "#loadremote",
'onclick' => rcmail_output::JS_OBJECT_NAME.".command('load-remote')"
),
@ -267,14 +274,16 @@ function rcmail_message_buttons()
$dbox = $RCMAIL->config->get('drafts_mbox');
// the message is not a draft
if ($MESSAGE->folder != $dbox && strpos($MESSAGE->folder, $dbox.$delim) !== 0) {
if ($MESSAGE->context
|| ($MESSAGE->folder != $dbox && strpos($MESSAGE->folder, $dbox.$delim) !== 0)
) {
return '';
}
$attrib['id'] = 'message-buttons';
$attrib['class'] = 'notice';
$msg = rcube::Q($RCMAIL->gettext('isdraft')) . '&nbsp;';
$msg = html::span('', rcube::Q($RCMAIL->gettext('isdraft'))) . '&nbsp;';
$msg .= html::a(array(
'href' => "#edit",
'onclick' => rcmail_output::JS_OBJECT_NAME.".command('edit')"
@ -335,6 +344,7 @@ function rcmail_message_contactphoto($attrib)
'_task' => 'addressbook',
'_action' => 'photo',
'_email' => $MESSAGE->sender['mailto'],
'_error' => strpos($placeholder, 'blank.gif') === false ? 1 : null,
));
$attrib['onerror'] = "this.src = '$placeholder'; this.onerror = null";
@ -345,3 +355,430 @@ function rcmail_message_contactphoto($attrib)
return html::img(array('src' => $photo_img, 'alt' => $RCMAIL->gettext('contactphoto')) + $attrib);
}
/**
* Returns table with message headers
*/
function rcmail_message_headers($attrib, $headers=null)
{
global $MESSAGE, $PRINT_MODE, $RCMAIL;
static $sa_attrib;
// keep header table attrib
if (is_array($attrib) && !$sa_attrib && !$attrib['valueof']) {
$sa_attrib = $attrib;
}
else if (!is_array($attrib) && is_array($sa_attrib)) {
$attrib = $sa_attrib;
}
if (!isset($MESSAGE)) {
return false;
}
// get associative array of headers object
if (!$headers) {
$headers_obj = $MESSAGE->headers;
$headers = get_object_vars($MESSAGE->headers);
}
else if (is_object($headers)) {
$headers_obj = $headers;
$headers = get_object_vars($headers_obj);
}
else {
$headers_obj = rcube_message_header::from_array($headers);
}
// show these headers
$standard_headers = array('subject', 'from', 'sender', 'to', 'cc', 'bcc', 'replyto',
'mail-reply-to', 'mail-followup-to', 'date', 'priority');
$exclude_headers = $attrib['exclude'] ? explode(',', $attrib['exclude']) : array();
$output_headers = array();
foreach ($standard_headers as $hkey) {
if ($headers[$hkey]) {
$value = $headers[$hkey];
}
else if ($headers['others'][$hkey]) {
$value = $headers['others'][$hkey];
}
else if (!$attrib['valueof']) {
continue;
}
if (in_array($hkey, $exclude_headers)) {
continue;
}
$ishtml = false;
$header_title = $RCMAIL->gettext(preg_replace('/(^mail-|-)/', '', $hkey));
if ($hkey == 'date') {
$header_value = $RCMAIL->format_date($value,
$PRINT_MODE ? $RCMAIL->config->get('date_long', 'x') : null);
}
else if ($hkey == 'priority') {
if ($value) {
$header_value = html::span('prio' . $value, rcube::Q(rcmail_localized_priority($value)));
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'replyto') {
if ($headers['replyto'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'mail-reply-to') {
if ($headers['mail-replyto'] != $headers['replyto']
&& $headers['replyto'] != $headers['from']
) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'sender') {
if ($headers['sender'] != $headers['from']) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else {
continue;
}
}
else if ($hkey == 'mail-followup-to') {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if (in_array($hkey, array('from', 'to', 'cc', 'bcc'))) {
$header_value = rcmail_address_string($value, $attrib['max'], true,
$attrib['addicon'], $headers['charset'], $header_title);
$ishtml = true;
}
else if ($hkey == 'subject' && empty($value)) {
$header_value = $RCMAIL->gettext('nosubject');
}
else {
$value = is_array($value) ? implode(' ', $value) : $value;
$header_value = trim(rcube_mime::decode_header($value, $headers['charset']));
}
$output_headers[$hkey] = array(
'title' => $header_title,
'value' => $header_value,
'raw' => $value,
'html' => $ishtml,
);
}
$plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array(
'output' => $output_headers,
'headers' => $headers_obj,
'exclude' => $exclude_headers, // readonly
'folder' => $MESSAGE->folder, // readonly
'uid' => $MESSAGE->uid, // readonly
));
// single header value is requested
if (!empty($attrib['valueof'])) {
$row = $plugin['output'][$attrib['valueof']];
return $row['html'] ? $row['value'] : rcube::Q($row['value']);
}
// compose html table
$table = new html_table(array('cols' => 2));
foreach ($plugin['output'] as $hkey => $row) {
$val = $row['html'] ? $row['value'] : rcube::Q($row['value']);
$table->add(array('class' => 'header-title'), rcube::Q($row['title']));
$table->add(array('class' => 'header '.$hkey), $val);
}
return $table->show($attrib);
}
/**
* Returns element with "From|To <sender|recipient> on <date>"
*/
function rcmail_message_summary($attrib)
{
global $MESSAGE, $RCMAIL;
if (!isset($MESSAGE) || empty($MESSAGE->headers)) {
return;
}
$header = $MESSAGE->context ? 'from' : rcmail_message_list_smart_column_name();
$label = 'shortheader' . $header;
$date = $RCMAIL->format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long', 'x'));
$user = $MESSAGE->headers->$header;
if (!$user && $header == 'to') {
$user = $MESSAGE->headers->cc;
}
if (!$user && $header == 'to') {
$user = $MESSAGE->headers->bcc;
}
$vars[$header] = rcmail_address_string($user, 1, true, $attrib['addicon'], $MESSAGE->headers->charset);
$vars['date'] = html::span('text-nowrap', $date);
if (empty($user)) {
$label = 'shortheaderdate';
}
$out = html::span(null, $RCMAIL->gettext(array('name' => $label, 'vars' => $vars)));
return html::div($attrib, $out);
}
/**
* Convert Priority header value into a localized string
*/
function rcmail_localized_priority($value)
{
global $RCMAIL;
$labels_map = array(
'1' => 'highest',
'2' => 'high',
'3' => 'normal',
'4' => 'low',
'5' => 'lowest',
);
if ($value && $labels_map[$value]) {
return $RCMAIL->gettext($labels_map[$value]);
}
return '';
}
/**
* Returns block to show full message headers
*/
function rcmail_message_full_headers($attrib)
{
global $OUTPUT, $RCMAIL;
$html = html::div(array('id' => "all-headers", 'class' => "all", 'style' => 'display:none'),
html::div(array('id' => 'headers-source'), ''));
$html .= html::div(array(
'class' => "more-headers show-headers",
'onclick' => "return ".rcmail_output::JS_OBJECT_NAME.".command('show-headers','',this)",
'title' => $RCMAIL->gettext('togglefullheaders')
), '');
$OUTPUT->add_gui_object('all_headers_row', 'all-headers');
$OUTPUT->add_gui_object('all_headers_box', 'headers-source');
return html::div($attrib, $html);
}
/**
* Handler for the 'messagebody' GUI object
*
* @param array Named parameters
* @return string HTML content showing the message body
*/
function rcmail_message_body($attrib)
{
global $OUTPUT, $MESSAGE, $RCMAIL, $REMOTE_OBJECTS;
if (!is_array($MESSAGE->parts) && empty($MESSAGE->body)) {
return '';
}
if (!$attrib['id'])
$attrib['id'] = 'rcmailMsgBody';
$safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']);
$out = '';
$part_no = 0;
$header_attrib = array();
foreach ($attrib as $attr => $value) {
if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs)) {
$header_attrib[$regs[1]] = $value;
}
}
if (!empty($MESSAGE->parts)) {
foreach ($MESSAGE->parts as $part) {
if ($part->type == 'headers') {
$out .= html::div('message-partheaders', rcmail_message_headers(count($header_attrib) ? $header_attrib : null, $part->headers));
}
else if ($part->type == 'content') {
// unsupported (e.g. encrypted)
if ($part->realtype) {
if ($part->realtype == 'multipart/encrypted' || $part->realtype == 'application/pkcs7-mime') {
if (!empty($_SESSION['browser_caps']['pgpmime']) && ($pgp_mime_part = $MESSAGE->get_multipart_encrypted_part())) {
$out .= html::span('part-notice', $RCMAIL->gettext('externalmessagedecryption'));
$OUTPUT->set_env('pgp_mime_part', $pgp_mime_part->mime_id);
$OUTPUT->set_env('pgp_mime_container', '#' . $attrib['id']);
$OUTPUT->add_label('loadingdata');
}
if (!$MESSAGE->encrypted_part) {
$out .= html::span('part-notice', $RCMAIL->gettext('encryptedmessage'));
}
}
continue;
}
else if (!$part->size) {
continue;
}
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
else if (!rcube_utils::mem_check($part->size * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
continue;
}
// fetch part body
$body = $MESSAGE->get_part_body($part->mime_id, true);
// message is cached but not exists (#1485443), or other error
if ($body === false) {
rcmail_message_error($MESSAGE->uid);
}
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $part, 'prefix' => ''));
// Set attributes of the part container
$container_class = $part->ctype_secondary == 'html' ? 'message-htmlpart' : 'message-part';
$container_id = $container_class . (++$part_no);
$container_attrib = array('class' => $container_class, 'id' => $container_id);
$body_args = array(
'safe' => $safe_mode,
'plain' => !$RCMAIL->config->get('prefer_html'),
'css_prefix' => 'v' . $part_no,
'body_class' => 'rcmBody',
'container_id' => $container_id,
'container_attrib' => $container_attrib,
);
// Parse the part content for display
$body = rcmail_print_body($body, $part, $body_args);
// check if the message body is PGP encrypted
if (strpos($body, '-----BEGIN PGP MESSAGE-----') !== false) {
$OUTPUT->set_env('is_pgp_content', '#' . $container_id);
}
if ($part->ctype_secondary == 'html') {
$body = rcmail_html4inline($body, $body_args);
}
$out .= html::div($container_attrib, $plugin['prefix'] . $body);
}
}
}
else {
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) {
$out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0'
.'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')));
}
else {
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $MESSAGE, 'prefix' => ''));
$out .= html::div('message-part',
$plugin['prefix'] . rcmail_plain_body($MESSAGE->body));
}
}
// list images after mail body
if ($RCMAIL->config->get('inline_images', true) && !empty($MESSAGE->attachments)) {
$thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240);
$client_mimetypes = (array)$RCMAIL->config->get('client_mimetypes');
$show_label = rcube::Q($RCMAIL->gettext('showattachment'));
$download_label = rcube::Q($RCMAIL->gettext('download'));
foreach ($MESSAGE->attachments as $attach_prop) {
// skip inline images
if ($attach_prop->content_id && $attach_prop->disposition == 'inline') {
continue;
}
// Content-Type: image/*...
if ($mimetype = rcmail_part_image_type($attach_prop)) {
// display thumbnails
if ($thumbnail_size) {
$supported = in_array($mimetype, $client_mimetypes);
$show_link_attr = array(
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf(
'return %s.command(\'load-attachment\',\'%s\',this)',
rcmail_output::JS_OBJECT_NAME,
$attach_prop->mime_id
)
);
$download_link_attr = array(
'href' => $show_link_attr['href'] . '&_download=1',
);
$show_link = html::a($show_link_attr + array('class' => 'open'), $show_label);
$download_link = html::a($download_link_attr + array('class' => 'download'), $download_label);
$out .= html::p(array('class' => 'image-attachment', 'style' => $supported ? '' : 'display:none'),
html::a($show_link_attr + array('class' => 'image-link', 'style' => sprintf('width:%dpx', $thumbnail_size)),
html::img(array(
'class' => 'image-thumbnail',
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image') . '&_thumb=1',
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
'style' => sprintf('max-width:%dpx; max-height:%dpx', $thumbnail_size, $thumbnail_size),
'onload' => $supported ? '' : '$(this).parents(\'p.image-attachment\').show()',
))
) .
html::span('image-filename', rcube::Q($attach_prop->filename)) .
html::span('image-filesize', rcube::Q($RCMAIL->message_part_size($attach_prop))) .
html::span('attachment-links', ($supported ? $show_link . '&nbsp;' : '') . $download_link) .
html::br(array('style' => 'clear:both'))
);
}
else {
$out .= html::tag('fieldset', 'image-attachment',
html::tag('legend', 'image-filename', rcube::Q($attach_prop->filename)) .
html::p(array('align' => 'center'),
html::img(array(
'src' => $MESSAGE->get_part_url($attach_prop->mime_id, 'image'),
'title' => $attach_prop->filename,
'alt' => $attach_prop->filename,
)))
);
}
}
}
}
// tell client that there are blocked remote objects
if ($REMOTE_OBJECTS && !$safe_mode) {
$OUTPUT->set_env('blockedobjects', true);
}
return html::div($attrib, $out);
}

@ -142,7 +142,7 @@ function rcmail_folder_form($attrib)
'additional' => strlen($selected) ? array($selected) : null,
));
$form['props']['fieldsets']['location']['content']['path'] = array(
$form['props']['fieldsets']['location']['content']['parent'] = array(
'label' => $RCMAIL->gettext('parentfolder'),
'value' => $select->show($selected),
);

@ -93,7 +93,7 @@ function rcube_identity_form($attrib)
'name' => $RCMAIL->gettext('signature'),
'content' => array(
'signature' => array('type' => 'textarea', 'size' => $t_cols, 'rows' => $t_rows,
'spellcheck' => true),
'spellcheck' => true, 'data-html-editor' => true),
'html_signature' => array('type' => 'checkbox',
'label' => $RCMAIL->gettext('htmlsignature'),
'onclick' => 'return rcmail.command(\'toggle-editor\', {id: \'rcmfd_signature\', html: this.checked}, \'\', event)'),

@ -936,8 +936,8 @@ function rcmail_user_prefs($current = null)
$blocks['main']['options']['default_font'] = array(
'title' => html::label($field_id, rcube::Q($RCMAIL->gettext('defaultfont'))),
'content' => $select_default_font->show($RCMAIL->config->get('default_font', 1)) .
$select_default_font_size->show($RCMAIL->config->get('default_font_size', 1))
'content' => html::div('input-group', $select_default_font->show($RCMAIL->config->get('default_font', 1)) .
$select_default_font_size->show($RCMAIL->config->get('default_font_size', 1)))
);
}
@ -1404,9 +1404,10 @@ function rcmail_settings_tabs($attrib)
'attrib' => $attrib,
));
$attrib = $plugin['attrib'];
$tagname = $attrib['tagname'];
$tabs = array();
$selected = $RCMAIL->action ?: 'preferences';
$attrib = $plugin['attrib'];
$tagname = $attrib['tagname'];
$tabs = array();
foreach ($plugin['actions'] as $action) {
$task_action = $action['command'] ? $action['command'] : $action['action'];
@ -1435,7 +1436,7 @@ function rcmail_settings_tabs($attrib)
else if (!empty($cmd)) {
$classnames[] = $cmd;
}
if ($RCMAIL->action == $cmd) {
if ($cmd == $selected) {
$classnames[] = $attrib['selclass'];
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save