Import Ruty

This commit is contained in:
2024-03-11 00:58:34 +01:00
parent 34a31bb184
commit 985f1ab418
618 changed files with 225414 additions and 0 deletions
@@ -0,0 +1,147 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| Copyright (C) Kolab Systems AG |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Display license information about program and enabled plugins |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_about extends rcmail_action
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($rcmail->gettext('about'));
$rcmail->output->add_handlers([
'supportlink' => [$this, 'supportlink'],
'pluginlist' => [$this, 'plugins_list'],
'copyright' => function() {
return 'Copyright &copy; 2005-2022, The Roundcube Dev Team';
},
'license' => function() {
return 'This program is free software; you can redistribute it and/or modify it under the terms '
. 'of the <a href="http://www.gnu.org/licenses/gpl.html" target="_blank">GNU General Public License</a> '
. 'as published by the Free Software Foundation, either version 3 of the License, '
. 'or (at your option) any later version.<br/>'
. 'Some <a href="https://roundcube.net/license" target="_blank">exceptions</a> '
. 'for skins &amp; plugins apply.';
},
]);
$rcmail->output->send('about');
}
public static function supportlink($attrib)
{
$rcmail = rcmail::get_instance();
if ($url = $rcmail->config->get('support_url')) {
$label = !empty($attrib['label']) ? $attrib['label'] : 'support';
$attrib['href'] = $url;
return html::a($attrib, $rcmail->gettext($label));
}
}
public static function plugins_list($attrib)
{
$rcmail = rcmail::get_instance();
if (empty($attrib['id'])) {
$attrib['id'] = 'rcmpluginlist';
}
$plugins = array_filter($rcmail->plugins->active_plugins);
$plugin_info = [];
foreach ($plugins as $name) {
if ($info = $rcmail->plugins->get_info($name)) {
$plugin_info[$name] = $info;
}
}
// load info from required plugins, too
foreach ($plugin_info as $name => $info) {
if (!empty($info['require']) && is_array($info['require'])) {
foreach ($info['require'] as $req_name) {
if (!isset($plugin_info[$req_name]) && ($req_info = $rcmail->plugins->get_info($req_name))) {
$plugin_info[$req_name] = $req_info;
}
}
}
}
if (empty($plugin_info)) {
return '';
}
ksort($plugin_info, SORT_LOCALE_STRING);
$table = new html_table($attrib);
// add table header
$table->add_header('name', $rcmail->gettext('plugin'));
$table->add_header('version', $rcmail->gettext('version'));
$table->add_header('license', $rcmail->gettext('license'));
$table->add_header('source', $rcmail->gettext('source'));
foreach ($plugin_info as $name => $data) {
$uri = !empty($data['src_uri']) ? $data['src_uri'] : ($data['uri'] ?? '');
if ($uri && stripos($uri, 'http') !== 0) {
$uri = 'http://' . $uri;
}
if ($uri) {
$uri = html::a([
'target' => '_blank',
'href' => rcube::Q($uri)
],
rcube::Q($rcmail->gettext('download'))
);
}
$license = isset($data['license']) ? $data['license'] : '';
if (!empty($data['license_uri'])) {
$license = html::a([
'target' => '_blank',
'href' => rcube::Q($data['license_uri'])
],
rcube::Q($data['license'])
);
}
else {
$license = rcube::Q($license);
}
$table->add_row();
$table->add('name', rcube::Q(!empty($data['name']) ? $data['name'] : $name));
$table->add('version', !empty($data['version']) ? rcube::Q($data['version']) : '');
$table->add('license', $license);
$table->add('source', $uri);
}
return $table->show();
}
}
@@ -0,0 +1,22 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality to create a folder |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_create extends rcmail_action_settings_folder_edit
{
}
@@ -0,0 +1,66 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality to delete a folder |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_delete extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$mbox = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$plugin = $rcmail->plugins->exec_hook('folder_delete', ['name' => $mbox]);
if (empty($plugin['abort'])) {
$deleted = $storage->delete_folder($plugin['name']);
}
else {
$deleted = $plugin['result'];
}
// #1488692: update session
if ($deleted && isset($_SESSION['mbox']) && $_SESSION['mbox'] === $mbox) {
$rcmail->session->remove('mbox');
}
}
if (!empty($deleted)) {
// Remove folder and subfolders rows
$rcmail->output->command('remove_folder_row', $mbox);
$rcmail->output->show_message('folderdeleted', 'confirmation');
// Clear content frame
$rcmail->output->command('subscription_select');
$rcmail->output->command('set_quota', self::quota_content());
}
else {
self::display_server_error('errorsaving');
}
$rcmail->output->send();
}
}
@@ -0,0 +1,347 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality to edit a folder |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_edit extends rcmail_action_settings_folders
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$rcmail->output->add_handlers([
'folderdetails' => [$this, 'folder_form'],
]);
$rcmail->output->add_label('nonamewarning');
$rcmail->output->send('folderedit');
}
public static function folder_form($attrib)
{
// WARNING: folder names in UI are encoded with RCUBE_CHARSET
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
// edited folder name (empty in create-folder mode)
$mbox = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_GPC, true);
// predefined path for new folder
$parent = rcube_utils::get_input_string('_path', rcube_utils::INPUT_GPC, true);
$threading_supported = $storage->get_capability('THREAD');
$dual_use_supported = $storage->get_capability(rcube_storage::DUAL_USE_FOLDERS);
$delimiter = $storage->get_hierarchy_delimiter();
// Get mailbox parameters
if (strlen($mbox)) {
$options = self::folder_options($mbox);
$namespace = $storage->get_namespace();
$path = explode($delimiter, $mbox);
$folder = array_pop($path);
$path = implode($delimiter, $path);
$folder = rcube_charset::convert($folder, 'UTF7-IMAP');
$hidden_fields = ['name' => '_mbox', 'value' => $mbox];
}
else {
$options = [];
$path = $parent;
$folder = '';
$hidden_fields = [];
// allow creating subfolders of INBOX folder
if ($path == 'INBOX') {
$path = $storage->mod_folder($path, 'in');
}
}
// remove personal namespace prefix
$path_id = null;
if (strlen($path)) {
$path_id = $path;
$path = $storage->mod_folder($path . $delimiter);
if (($path[strlen($path)-1] ?? '') == $delimiter) {
$path = substr($path, 0, -1);
}
}
$form = [];
// General tab
$form['props'] = [
'name' => $rcmail->gettext('properties'),
];
// Location (name)
if (!empty($options['protected'])) {
$foldername = str_replace($delimiter, ' &raquo; ', rcube::Q(self::localize_foldername($mbox, false, true)));
}
else if (!empty($options['norename'])) {
$foldername = rcube::Q($folder);
}
else {
if (isset($_POST['_name'])) {
$folder = trim(rcube_utils::get_input_string('_name', rcube_utils::INPUT_POST, true));
}
$foldername = new html_inputfield(['name' => '_name', 'id' => '_name', 'size' => 30, 'class' => 'form-control']);
$foldername = '<span class="input-group">' . $foldername->show($folder);
if (!empty($options['special']) && ($sname = self::localize_foldername($mbox, false, true)) != $folder) {
$foldername .= ' <span class="input-group-append"><span class="input-group-text">(' . rcube::Q($sname) .')</span></span>';
}
$foldername .= '</span>';
}
$form['props']['fieldsets']['location'] = [
'name' => $rcmail->gettext('location'),
'content' => [
'name' => [
'label' => $rcmail->gettext('foldername'),
'value' => $foldername,
],
],
];
if (!empty($options) && (!empty($options['norename']) || !empty($options['protected']))) {
// prevent user from moving folder
$hidden_path = new html_hiddenfield(['name' => '_parent', 'value' => $path]);
$form['props']['fieldsets']['location']['content']['name']['value'] .= $hidden_path->show();
}
else {
$selected = $_POST['_parent'] ?? $path_id;
$exceptions = [$mbox];
// Exclude 'prefix' namespace from parent folders list (#1488349)
// If INBOX. namespace exists, folders created as INBOX subfolders
// will be listed at the same level - selecting INBOX as a parent does nothing
if ($prefix = $storage->get_namespace('prefix')) {
$exceptions[] = substr($prefix, 0, -1);
}
$select = self::folder_selector([
'id' => '_parent',
'name' => '_parent',
'noselection' => '---',
'maxlength' => 150,
'unsubscribed' => true,
'skip_noinferiors' => true,
'exceptions' => $exceptions,
'additional' => is_string($selected) && strlen($selected) ? [$selected] : null,
]);
$form['props']['fieldsets']['location']['content']['parent'] = [
'label' => $rcmail->gettext('parentfolder'),
'value' => $select->show($selected),
];
}
// Settings
$form['props']['fieldsets']['settings'] = [
'name' => $rcmail->gettext('settings'),
];
// For servers that do not support both sub-folders and messages in a folder
if (!$dual_use_supported) {
if (!strlen($mbox)) {
$select = new html_select(['name' => '_type', 'id' => '_type']);
$select->add($rcmail->gettext('dualusemail'), 'mail');
$select->add($rcmail->gettext('dualusefolder'), 'folder');
$value = rcube_utils::get_input_string('_type', rcube_utils::INPUT_POST);
$value = $select->show($value ?: 'mail');
}
else {
$value = $options['noselect'] ? 'folder' : 'mail';
$value = $rcmail->gettext('dualuse' . $value);
}
$form['props']['fieldsets']['settings']['content']['type'] = [
'label' => $rcmail->gettext('dualuselabel'),
'value' => $value,
];
}
// Settings: threading
if ($threading_supported && ($mbox == 'INBOX' || (empty($options['noselect']) && empty($options['is_root'])))) {
$value = 0;
$select = new html_select(['name' => '_viewmode', 'id' => '_viewmode']);
$select->add($rcmail->gettext('list'), 0);
$select->add($rcmail->gettext('threads'), 1);
if (isset($_POST['_viewmode'])) {
$value = (int) $_POST['_viewmode'];
}
else if (strlen($mbox)) {
$a_threaded = $rcmail->config->get('message_threading', []);
$default_mode = $rcmail->config->get('default_list_mode', 'list');
$value = (int) ($a_threaded[$mbox] ?? $default_mode == 'threads');
}
$form['props']['fieldsets']['settings']['content']['viewmode'] = [
'label' => $rcmail->gettext('listmode'),
'value' => $select->show($value),
];
}
$msgcount = 0;
// Information (count, size) - Edit mode
if (strlen($mbox)) {
// Number of messages
$form['props']['fieldsets']['info'] = [
'name' => $rcmail->gettext('info'),
'content' => []
];
if ((!$options['noselect'] && !$options['is_root']) || $mbox == 'INBOX') {
$msgcount = (int) $storage->count($mbox, 'ALL', true, false);
if ($msgcount) {
// Get the size on servers with supposed-to-be-fast method for that
if ($storage->get_capability('STATUS=SIZE')) {
$size = $storage->folder_size($mbox);
if ($size !== false) {
$size = self::show_bytes($size);
}
}
// create link with folder-size command
if (!isset($size) || $size === false) {
$onclick = sprintf("return %s.command('folder-size', '%s', this)",
rcmail_output::JS_OBJECT_NAME, rcube::JQ($mbox));
$attr = ['href' => '#', 'onclick' => $onclick, 'id' => 'folder-size'];
$size = html::a($attr, $rcmail->gettext('getfoldersize'));
}
}
else {
// no messages -> zero size
$size = 0;
}
$form['props']['fieldsets']['info']['content']['count'] = [
'label' => $rcmail->gettext('messagecount'),
'value' => $msgcount
];
$form['props']['fieldsets']['info']['content']['size'] = [
'label' => $rcmail->gettext('size'),
'value' => $size,
];
}
// show folder type only if we have non-private namespaces
if (!empty($namespace['shared']) || !empty($namespace['others'])) {
$form['props']['fieldsets']['info']['content']['foldertype'] = [
'label' => $rcmail->gettext('foldertype'),
'value' => $rcmail->gettext($options['namespace'] . 'folder')
];
}
}
// Allow plugins to modify folder form content
$plugin = $rcmail->plugins->exec_hook('folder_form', [
'form' => $form,
'options' => $options,
'name' => $mbox,
'parent_name' => $parent
]);
$form = $plugin['form'];
// Set form tags and hidden fields
list($form_start, $form_end) = self::get_form_tags($attrib, 'save-folder', null, $hidden_fields);
unset($attrib['form'], $attrib['id']);
// return the complete edit form as table
$out = "$form_start\n";
// Create form output
foreach ($form as $idx => $tab) {
if (!empty($tab['fieldsets']) && is_array($tab['fieldsets'])) {
$content = '';
foreach ($tab['fieldsets'] as $fieldset) {
$subcontent = self::get_form_part($fieldset, $attrib);
if ($subcontent) {
$subcontent = html::tag('legend', null, rcube::Q($fieldset['name'])) . $subcontent;
$content .= html::tag('fieldset', null, $subcontent) ."\n";
}
}
}
else {
$content = self::get_form_part($tab, $attrib);
}
if ($idx != 'props') {
$out .= html::tag('fieldset', null, html::tag('legend', null, rcube::Q($tab['name'])) . $content) ."\n";
}
else {
$out .= $content ."\n";
}
}
$out .= "\n$form_end";
$rcmail->output->set_env('messagecount', $msgcount);
$rcmail->output->set_env('folder', $mbox);
if ($mbox !== null && empty($_POST)) {
$rcmail->output->command('parent.set_quota', self::quota_content(null, $mbox));
}
return $out;
}
public static function get_form_part($form, $attrib = [])
{
$rcmail = rcmail::get_instance();
$content = '';
if (!empty($form['content']) && is_array($form['content'])) {
$table = new html_table(['cols' => 2]);
foreach ($form['content'] as $col => $colprop) {
$colprop['id'] = '_' . $col;
$label = !empty($colprop['label']) ? $colprop['label'] : $rcmail->gettext($col);
$table->add('title', html::label($colprop['id'], rcube::Q($label)));
$table->add(null, $colprop['value']);
}
$content = $table->show($attrib);
}
else if (isset($form['content'])) {
$content = $form['content'];
}
return $content;
}
}
@@ -0,0 +1,70 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality of folder purge |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_purge extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$mbox = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
$delimiter = $storage->get_hierarchy_delimiter();
$trash_mbox = $rcmail->config->get('trash_mbox');
$trash_regexp = '/^' . preg_quote($trash_mbox . $delimiter, '/') . '/';
// we should only be purging trash (or their subfolders)
if (!strlen($trash_mbox) || $mbox === $trash_mbox || preg_match($trash_regexp, $mbox)) {
$success = $storage->delete_message('*', $mbox);
$delete = true;
}
// move to Trash
else {
$success = $storage->move_message('1:*', $trash_mbox, $mbox);
$delete = false;
}
if (!empty($success)) {
$rcmail->output->set_env('messagecount', 0);
if ($delete) {
$rcmail->output->show_message('folderpurged', 'confirmation');
$rcmail->output->command('set_quota', self::quota_content(null, $mbox));
}
else {
$rcmail->output->show_message('messagemoved', 'confirmation');
}
$_SESSION['unseen_count'][$mbox] = 0;
$rcmail->output->command('show_folder', $mbox, null, true);
}
else {
self::display_server_error('errorsaving');
}
$rcmail->output->send();
}
}
@@ -0,0 +1,94 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality of folder rename |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_rename extends rcmail_action_settings_folders
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$name = trim(rcube_utils::get_input_string('_folder_newname', rcube_utils::INPUT_POST, true));
$oldname = rcube_utils::get_input_string('_folder_oldname', rcube_utils::INPUT_POST, true);
if (strlen($name) && strlen($oldname)) {
$rename = self::rename_folder($oldname, $name);
}
if (!empty($rename)) {
self::update_folder_row($name, $oldname);
}
else {
self::display_server_error('errorsaving');
}
$rcmail->output->send();
}
public static function rename_folder($oldname, $newname)
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$plugin = $rcmail->plugins->exec_hook('folder_rename', [
'oldname' => $oldname, 'newname' => $newname]);
if (empty($plugin['abort'])) {
$renamed = $storage->rename_folder($oldname, $newname);
}
else {
$renamed = $plugin['result'];
}
// update per-folder options for modified folder and its subfolders
if ($renamed) {
$delimiter = $storage->get_hierarchy_delimiter();
$a_threaded = (array) $rcmail->config->get('message_threading', []);
$oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/';
foreach ($a_threaded as $key => $val) {
if ($key == $oldname) {
unset($a_threaded[$key]);
$a_threaded[$newname] = $val;
}
else if (preg_match($oldprefix, $key)) {
unset($a_threaded[$key]);
$a_threaded[preg_replace($oldprefix, $newname . $delimiter, $key)] = $val;
}
}
$rcmail->user->save_prefs(['message_threading' => $a_threaded]);
// #1488692: update session
if (isset($_SESSION['mbox']) && $_SESSION['mbox'] === $oldname) {
$_SESSION['mbox'] = $newname;
}
return true;
}
return false;
}
}
@@ -0,0 +1,235 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Handler for saving the create/edit folder form |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_save extends rcmail_action_settings_folder_edit
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
// WARNING: folder names in UI are encoded with RCUBE_CHARSET
$name = trim(rcube_utils::get_input_string('_name', rcube_utils::INPUT_POST, true));
$path = rcube_utils::get_input_string('_parent', rcube_utils::INPUT_POST, true);
$old_imap = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
$type = rcube_utils::get_input_string('_type', rcube_utils::INPUT_POST);
$name_imap = rcube_charset::convert($name, RCUBE_CHARSET, 'UTF7-IMAP');
// $path is in UTF7-IMAP already
// init IMAP connection
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$delimiter = $storage->get_hierarchy_delimiter();
$options = strlen($old_imap) ? self::folder_options($old_imap) : [];
$char = null;
// Folder name checks
if (!empty($options['protected']) || !empty($options['norename'])) {
// do nothing
}
else if (!strlen($name)) {
$error = $rcmail->gettext('namecannotbeempty');
}
else if (mb_strlen($name) > 128) {
$error = $rcmail->gettext('nametoolong');
}
else if ($name[0] == '.' && $rcmail->config->get('imap_skip_hidden_folders')) {
$error = $rcmail->gettext('namedotforbidden');
}
else if (!$storage->folder_validate($name, $char)) {
$error = $rcmail->gettext('forbiddencharacter') . " ($char)";
}
if (!empty($error)) {
$rcmail->output->command('display_message', $error, 'error');
}
else {
if (!empty($options['protected']) || !empty($options['norename'])) {
$name_imap = $old_imap;
}
else if (strlen($path)) {
$name_imap = $path . $delimiter . $name_imap;
}
else {
$name_imap = $storage->mod_folder($name_imap, 'in');
}
}
$dual_use_supported = $storage->get_capability(rcube_storage::DUAL_USE_FOLDERS);
$acl_supported = $storage->get_capability('ACL');
// Check access rights to the parent folder
if (empty($error) && $acl_supported && strlen($path) && (!strlen($old_imap) || $old_imap != $name_imap)) {
$parent_opts = $storage->folder_info($path);
if ($parent_opts['namespace'] != 'personal'
&& (empty($parent_opts['rights']) || !preg_match('/[ck]/', implode($parent_opts['rights'])))
) {
$error = $rcmail->gettext('parentnotwritable');
}
}
if (!empty($error)) {
$rcmail->output->command('display_message', $error, 'error');
$folder = null;
}
else {
$folder = [
'name' => $name_imap,
'oldname' => $old_imap,
'class' => '',
'options' => $options,
'settings' => [
// List view mode: 0-list, 1-threads
'view_mode' => (int) rcube_utils::get_input_string('_viewmode', rcube_utils::INPUT_POST),
'sort_column' => rcube_utils::get_input_string('_sortcol', rcube_utils::INPUT_POST),
'sort_order' => rcube_utils::get_input_string('_sortord', rcube_utils::INPUT_POST),
],
'subscribe' => false,
'noselect' => false,
];
}
// create a new mailbox
if (empty($error) && !strlen($old_imap)) {
$folder['subscribe'] = true;
// Server does not support both sub-folders and messages in a folder
// For folders that are supposed to contain other folders we will:
// - disable subscription
// - add a separator at the end to make them \NoSelect
if (!$dual_use_supported && $type == 'folder') {
$folder['subscribe'] = false;
$folder['noselect'] = true;
}
$plugin = $rcmail->plugins->exec_hook('folder_create', ['record' => $folder]);
$folder = $plugin['record'];
if (!$plugin['abort']) {
$created = $storage->create_folder($folder['name'], $folder['subscribe'], null, $folder['noselect']);
}
else {
$created = $plugin['result'];
}
if ($created) {
// Save folder settings
if (isset($_POST['_viewmode'])) {
$a_threaded = (array) $rcmail->config->get('message_threading', []);
$a_threaded[$folder['name']] = (bool) $_POST['_viewmode'];
$rcmail->user->save_prefs(['message_threading' => $a_threaded]);
}
self::update_folder_row($folder['name'], null, $folder['subscribe'], $folder['class']);
$rcmail->output->show_message('foldercreated', 'confirmation');
// reset folder preview frame
$rcmail->output->command('subscription_select');
$rcmail->output->send('iframe');
}
else {
// show error message
if (!empty($plugin['message'])) {
$rcmail->output->show_message($plugin['message'], 'error', null, false);
}
else {
self::display_server_error('errorsaving');
}
}
}
// update a mailbox
else if (empty($error)) {
$plugin = $rcmail->plugins->exec_hook('folder_update', ['record' => $folder]);
$folder = $plugin['record'];
$rename = $folder['oldname'] != $folder['name'];
if (!$plugin['abort']) {
if ($rename) {
$updated = $storage->rename_folder($folder['oldname'], $folder['name']);
}
else {
$updated = true;
}
}
else {
$updated = $plugin['result'];
}
if ($updated) {
// Update folder settings,
if (isset($_POST['_viewmode'])) {
$a_threaded = (array) $rcmail->config->get('message_threading', []);
// In case of name change update names of children in settings
if ($rename) {
$oldprefix = '/^' . preg_quote($folder['oldname'] . $delimiter, '/') . '/';
foreach ($a_threaded as $key => $val) {
if ($key == $folder['oldname']) {
unset($a_threaded[$key]);
}
else if (preg_match($oldprefix, $key)) {
unset($a_threaded[$key]);
$a_threaded[preg_replace($oldprefix, $folder['name'].$delimiter, $key)] = $val;
}
}
}
$a_threaded[$folder['name']] = (bool) $_POST['_viewmode'];
$rcmail->user->save_prefs(['message_threading' => $a_threaded]);
}
$rcmail->output->show_message('folderupdated', 'confirmation');
$rcmail->output->set_env('folder', $folder['name']);
if ($rename) {
// #1488692: update session
if (isset($_SESSION['mbox']) && $_SESSION['mbox'] === $folder['oldname']) {
$_SESSION['mbox'] = $folder['name'];
}
self::update_folder_row($folder['name'], $folder['oldname'], $folder['subscribe'], $folder['class']);
$rcmail->output->send('iframe');
}
else if (!empty($folder['class'])) {
self::update_folder_row($folder['name'], $folder['oldname'], $folder['subscribe'], $folder['class']);
}
}
else {
// show error message
if (!empty($plugin['message'])) {
$rcmail->output->show_message($plugin['message'], 'error', null, false);
}
else {
self::display_server_error('errorsaving');
}
}
}
$rcmail->overwrite_action('edit-folder');
}
}
@@ -0,0 +1,49 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality of getting folder size |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_size extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$name = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
$size = $storage->folder_size($name);
// @TODO: check quota and show percentage usage of specified mailbox?
if ($size !== false) {
$rcmail->output->command('folder_size_update', self::show_bytes($size));
}
else {
self::display_server_error();
}
$rcmail->output->send();
}
}
@@ -0,0 +1,67 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Handler for folder subscribe action |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_subscribe extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$mbox = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$result = $storage->subscribe([$mbox]);
// Handle virtual (non-existing) folders
if (
!$result
&& $storage->get_error_code() == -1
&& $storage->get_response_code() == rcube_storage::TRYCREATE
) {
$result = $storage->create_folder($mbox, true);
if ($result) {
// @TODO: remove 'virtual' class of folder's row
}
}
}
if (!empty($result)) {
// Handle subscription of protected folder (#1487656)
if ($rcmail->config->get('protect_default_folders') && $storage->is_special_folder($mbox)) {
$rcmail->output->command('disable_subscription', $mbox);
}
$rcmail->output->show_message('foldersubscribed', 'confirmation');
}
else {
self::display_server_error('errorsaving');
$rcmail->output->command('reset_subscription', $mbox, false);
}
$rcmail->output->send();
}
}
@@ -0,0 +1,50 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Handler for folder unsubscribe action |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folder_unsubscribe extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$mbox = rcube_utils::get_input_string('_mbox', rcube_utils::INPUT_POST, true);
if (strlen($mbox)) {
$result = $storage->unsubscribe([$mbox]);
}
if (!empty($result)) {
$rcmail->output->show_message('folderunsubscribed', 'confirmation');
}
else {
self::display_server_error('errorsaving');
$rcmail->output->command('reset_subscription', $mbox, true);
}
$rcmail->output->send();
}
}
@@ -0,0 +1,377 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality of folders listing |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_folders extends rcmail_action_settings_index
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$rcmail->output->set_pagetitle($rcmail->gettext('folders'));
$rcmail->output->set_env('prefix_ns', $storage->get_namespace('prefix'));
$rcmail->output->set_env('quota', (bool) $storage->get_capability('QUOTA'));
$rcmail->output->include_script('treelist.js');
// add some labels to client
$rcmail->output->add_label('deletefolderconfirm', 'purgefolderconfirm', 'movefolderconfirm',
'folderdeleting', 'foldermoving', 'foldersubscribing', 'folderunsubscribing',
'move', 'quota');
// register UI objects
$rcmail->output->add_handlers([
'foldersubscription' => [$this, 'folder_subscriptions'],
'folderfilter' => [$this, 'folder_filter'],
'quotadisplay' => [$rcmail, 'quota_display'],
'searchform' => [$rcmail->output, 'search_form'],
]);
$rcmail->output->send('folders');
}
// build table with all folders listed by server
public static function folder_subscriptions($attrib)
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
if (empty($attrib['id'])) {
$attrib['id'] = 'rcmSubscriptionlist';
}
// get folders from server
$storage->clear_cache('mailboxes', true);
$a_unsubscribed = $storage->list_folders();
$a_subscribed = $storage->list_folders_subscribed('', '*', null, null, true); // unsorted
$delimiter = $storage->get_hierarchy_delimiter();
$namespace = $storage->get_namespace();
$special_folders = array_flip(array_merge(['inbox' => 'INBOX'], $storage->get_special_folders()));
$protect_default = $rcmail->config->get('protect_default_folders');
$seen = [];
$list_folders = [];
// pre-process folders list
foreach ($a_unsubscribed as $i => $folder) {
$folder_id = $folder;
$folder = $storage->mod_folder($folder);
$foldersplit = explode($delimiter, $folder);
$name = rcube_charset::convert(array_pop($foldersplit), 'UTF7-IMAP');
$is_special = isset($special_folders[$folder_id]);
$parent_folder = $is_special ? '' : join($delimiter, $foldersplit);
$level = $is_special ? 0 : count($foldersplit);
// add any necessary "virtual" parent folders
if ($parent_folder && empty($seen[$parent_folder])) {
for ($i = 1; $i <= $level; $i++) {
$ancestor_folder = join($delimiter, array_slice($foldersplit, 0, $i));
if ($ancestor_folder) {
if (empty($seen[$ancestor_folder])) {
$seen[$ancestor_folder] = true;
$ancestor_name = rcube_charset::convert($foldersplit[$i-1], 'UTF7-IMAP');
$list_folders[] = [
'id' => $ancestor_folder,
'name' => $ancestor_name,
'level' => $i-1,
'virtual' => true,
];
}
}
}
}
// Handle properly INBOX.INBOX situation
if (isset($seen[$folder])) {
continue;
}
$seen[$folder] = true;
$list_folders[] = [
'id' => $folder_id,
'name' => $name,
'level' => $level,
];
}
unset($seen);
$checkbox_subscribe = new html_checkbox([
'name' => '_subscribed[]',
'title' => $rcmail->gettext('changesubscription'),
'onclick' => rcmail_output::JS_OBJECT_NAME.".command(this.checked?'subscribe':'unsubscribe',this.value)",
]);
$js_folders = [];
$folders = [];
$collapsed = (string) $rcmail->config->get('collapsed_folders');
// create list of available folders
foreach ($list_folders as $i => $folder) {
$sub_key = array_search($folder['id'], $a_subscribed);
$is_subscribed = $sub_key !== false;
$is_special = isset($special_folders[$folder['id']]);
$is_protected = $folder['id'] == 'INBOX' || ($protect_default && $is_special);
$noselect = false;
$classes = [];
$folder_utf8 = rcube_charset::convert($folder['id'], 'UTF7-IMAP');
$display_folder = rcube::Q($is_special ? self::localize_foldername($folder['id'], false, true) : $folder['name']);
if (!empty($folder['virtual'])) {
$classes[] = 'virtual';
}
// Check \Noselect flag (of existing folder)
if (!$is_protected && in_array($folder['id'], $a_unsubscribed)) {
$attrs = $storage->folder_attributes($folder['id']);
$noselect = in_array_nocase('\\Noselect', $attrs);
}
$is_disabled = (($is_protected && $is_subscribed) || $noselect);
// Below we will disable subscription option for "virtual" folders
// according to namespaces, but only if they aren't already subscribed.
// User should be able to unsubscribe from the folder
// even if it doesn't exists or is not accessible (OTRS:1000059)
if (!$is_subscribed && !$is_disabled && !empty($namespace) && !empty($folder['virtual'])) {
// check if the folder is a namespace prefix, then disable subscription option on it
if (!$is_disabled && $folder['level'] == 0) {
$fname = $folder['id'] . $delimiter;
foreach ($namespace as $ns) {
if (is_array($ns)) {
foreach ($ns as $item) {
if ($item[0] === $fname) {
$is_disabled = true;
break 2;
}
}
}
}
}
// check if the folder is an other users virtual-root folder, then disable subscription option on it
if (!$is_disabled && $folder['level'] == 1 && !empty($namespace['other'])) {
$parts = explode($delimiter, $folder['id']);
$fname = $parts[0] . $delimiter;
foreach ($namespace['other'] as $item) {
if ($item[0] === $fname) {
$is_disabled = true;
break;
}
}
}
// check if the folder is shared, then disable subscription option on it (if not subscribed already)
if (!$is_disabled) {
$tmp_ns = array_merge((array)$namespace['other'], (array)$namespace['shared']);
foreach ($tmp_ns as $item) {
if (strlen($item[0]) && strpos($folder['id'], $item[0]) === 0) {
$is_disabled = true;
break;
}
}
}
}
$is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
$folder_id = rcube_utils::html_identifier($folder['id'], true);
if ($folder_class = self::folder_classname($folder['id'])) {
$classes[] = $folder_class;
}
$folders[$folder['id']] = [
'idx' => $folder_id,
'folder_imap' => $folder['id'],
'folder' => $folder_utf8,
'display' => $display_folder,
'protected' => $is_protected || !empty($folder['virtual']),
'class' => join(' ', $classes),
'subscribed' => $is_subscribed,
'level' => $folder['level'],
'collapsed' => $is_collapsed,
'content' => html::a(['href' => '#'], $display_folder)
. $checkbox_subscribe->show(($is_subscribed ? $folder['id'] : ''),
['value' => $folder['id'], 'disabled' => $is_disabled ? 'disabled' : ''])
];
}
$plugin = $rcmail->plugins->exec_hook('folders_list', ['list' => $folders]);
// add drop-target representing 'root'
$root = [
'idx' => rcube_utils::html_identifier('*', true),
'folder_imap' => '*',
'folder' => '',
'display' => '',
'protected' => true,
'class' => 'root',
'content' => '<span>&nbsp;</span>',
];
$folders = [];
$plugin['list'] = array_values($plugin['list']);
array_unshift($plugin['list'], $root);
for ($i = 0, $length = count($plugin['list']); $i<$length; $i++) {
$folders[] = self::folder_tree_element($plugin['list'], $i, $js_folders);
}
$rcmail->output->add_gui_object('subscriptionlist', $attrib['id']);
$rcmail->output->set_env('subscriptionrows', $js_folders);
$rcmail->output->set_env('defaultfolders', array_keys($special_folders));
$rcmail->output->set_env('collapsed_folders', $collapsed);
$rcmail->output->set_env('delimiter', $delimiter);
return html::tag('ul', $attrib, implode('', $folders), html::$common_attrib);
}
public static function folder_tree_element($folders, &$key, &$js_folders)
{
$data = $folders[$key];
$idx = 'rcmli' . $data['idx'];
$js_folders[$data['folder_imap']] = [$data['folder'], $data['display'], $data['protected']];
$content = $data['content'];
$attribs = [
'id' => $idx,
'class' => trim($data['class'] . ' mailbox')
];
if (!isset($data['level'])) {
$data['level'] = 0;
}
$children = [];
while (!empty($folders[$key+1]) && ($folders[$key+1]['level'] > $data['level'])) {
$key++;
$children[] = self::folder_tree_element($folders, $key, $js_folders);
}
if (!empty($children)) {
$content .= html::div('treetoggle ' . (!empty($data['collapsed']) ? 'collapsed' : 'expanded'), '&nbsp;')
. html::tag('ul', ['style' => !empty($data['collapsed']) ? "display:none" : null],
implode("\n", $children));
}
return html::tag('li', $attribs, $content);
}
public static function folder_filter($attrib)
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$namespace = $storage->get_namespace();
if (empty($namespace['personal']) && empty($namespace['shared']) && empty($namespace['other'])) {
return '';
}
if (empty($attrib['id'])) {
$attrib['id'] = 'rcmfolderfilter';
}
if (!self::get_bool_attr($attrib, 'noevent')) {
$attrib['onchange'] = rcmail_output::JS_OBJECT_NAME . '.folder_filter(this.value)';
}
$roots = [];
$select = new html_select($attrib);
$select->add($rcmail->gettext('all'), '---');
foreach (array_keys($namespace) as $type) {
foreach ((array)$namespace[$type] as $ns) {
$root = rtrim($ns[0], $ns[1]);
$label = $rcmail->gettext('namespace.' . $type);
if (count($namespace[$type]) > 1) {
$label .= ' (' . rcube_charset::convert($root, 'UTF7-IMAP', RCUBE_CHARSET) . ')';
}
$select->add($label, $root);
if (strlen($root)) {
$roots[] = $root;
}
}
}
$rcmail->output->add_gui_object('foldersfilter', $attrib['id']);
$rcmail->output->set_env('ns_roots', $roots);
return $select->show();
}
public static function folder_options($mailbox)
{
$rcmail = rcmail::get_instance();
$options = $rcmail->get_storage()->folder_info($mailbox);
$options['protected'] = !empty($options['is_root'])
|| strtoupper($mailbox) === 'INBOX'
|| (!empty($options['special']) && $rcmail->config->get('protect_default_folders'));
return $options;
}
/**
* Updates (or creates) folder row in the subscriptions table
*
* @param string $name Folder name
* @param string $oldname Old folder name (for update)
* @param bool $subscribe Checks subscription checkbox
* @param string $class CSS class name for folder row
*/
public static function update_folder_row($name, $oldname = null, $subscribe = false, $class_name = null)
{
$rcmail = rcmail::get_instance();
$storage = $rcmail->get_storage();
$delimiter = $storage->get_hierarchy_delimiter();
$options = self::folder_options($name);
$name_utf8 = rcube_charset::convert($name, 'UTF7-IMAP');
$foldersplit = explode($delimiter, $storage->mod_folder($name));
$level = count($foldersplit) - 1;
$class_name = trim($class_name . ' mailbox');
if (!empty($options['protected'])) {
$display_name = self::localize_foldername($name);
}
else {
$display_name = rcube_charset::convert($foldersplit[$level], 'UTF7-IMAP');
}
$protected = !empty($options['protected']) || !empty($options['noselect']);
if ($oldname === null) {
$rcmail->output->command('add_folder_row', $name, $name_utf8, $display_name,
$protected, $subscribe, $class_name);
}
else {
$rcmail->output->command('replace_folder_row', $oldname, $name, $name_utf8, $display_name,
$protected, $class_name);
}
}
}
@@ -0,0 +1,73 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Manage identities of a user account |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_identities extends rcmail_action
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($rcmail->gettext('identities'));
$rcmail->output->include_script('list.js');
$rcmail->output->set_env('identities_level', (int) $rcmail->config->get('identities_level', 0));
$rcmail->output->add_label('deleteidentityconfirm');
$rcmail->output->add_handlers([
'identitieslist' => [$this, 'identities_list'],
]);
$rcmail->output->send('identities');
}
public static function identities_list($attrib)
{
$rcmail = rcmail::get_instance();
// add id to message list table if not specified
if (empty($attrib['id'])) {
$attrib['id'] = 'rcmIdentitiesList';
}
// get identities list and define 'mail' column
$list = $rcmail->user->list_emails();
foreach ($list as $idx => $row) {
$list[$idx]['mail'] = trim($row['name'] . ' <' . rcube_utils::idn_to_utf8($row['email']) . '>');
}
// get all identities from DB and define list of cols to be displayed
$plugin = $rcmail->plugins->exec_hook('identities_list', [
'list' => $list,
'cols' => ['mail']
]);
// @TODO: use <UL> instead of <TABLE> for identities list
$out = self::table_output($attrib, $plugin['list'], $plugin['cols'], 'identity_id');
// set client env
$rcmail->output->add_gui_object('identitieslist', $attrib['id']);
return $out;
}
}
@@ -0,0 +1,22 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide identity create form |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_identity_create extends rcmail_action_settings_identity_edit
{
}
@@ -0,0 +1,52 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| A handler for identity delete action |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_identity_delete extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$iid = rcube_utils::get_input_string('_iid', rcube_utils::INPUT_POST);
$deleted = 0;
if ($iid && preg_match('/^[0-9]+(,[0-9]+)*$/', $iid)) {
$plugin = $rcmail->plugins->exec_hook('identity_delete', ['id' => $iid]);
$deleted = !$plugin['abort'] ? $rcmail->user->delete_identity($iid) : $plugin['result'];
}
if ($deleted > 0 && $deleted !== false) {
$rcmail->output->show_message('deletedsuccessfully', 'confirmation', null, false);
$rcmail->output->command('remove_identity', $iid);
}
else {
$msg = !empty($plugin['message']) ? $plugin['message'] : ($deleted < 0 ? 'nodeletelastidentity' : 'errorsaving');
$rcmail->output->show_message($msg, 'error', null, false);
}
$rcmail->output->send();
}
}
@@ -0,0 +1,240 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Show edit form for an identity record |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_identity_edit extends rcmail_action
{
protected static $mode = self::MODE_HTTP;
protected static $record;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$IDENTITIES_LEVEL = intval($rcmail->config->get('identities_level', 0));
// edit-identity
if ($rcmail->action == 'edit-identity'
&& ($id = rcube_utils::get_input_string('_iid', rcube_utils::INPUT_GPC))
) {
self::$record = $rcmail->user->get_identity($id);
if (!is_array(self::$record)) {
$rcmail->output->show_message('dberror', 'error');
$rcmail->output->send('iframe');
}
$rcmail->output->set_env('iid', self::$record['identity_id']);
$rcmail->output->set_env('mailvelope_main_keyring', $rcmail->config->get('mailvelope_main_keyring'));
$rcmail->output->set_env('mailvelope_keysize', $rcmail->config->get('mailvelope_keysize'));
}
// add-identity
else {
if ($IDENTITIES_LEVEL > 1) {
$rcmail->output->show_message('opnotpermitted', 'error');
// go to identities page
$rcmail->overwrite_action('identities');
return;
}
if ($IDENTITIES_LEVEL == 1) {
self::$record['email'] = $rcmail->get_user_email();
}
}
$rcmail->output->add_handler('identityform', [$this, 'identity_form']);
$rcmail->output->set_env('identities_level', $IDENTITIES_LEVEL);
$rcmail->output->add_label('deleteidentityconfirm', 'generate',
'encryptioncreatekey', 'openmailvelopesettings', 'encryptionprivkeysinmailvelope',
'encryptionnoprivkeysinmailvelope', 'keypaircreatesuccess');
$rcmail->output->set_pagetitle($rcmail->gettext(($rcmail->action == 'add-identity' ? 'addidentity' : 'editidentity')));
if ($rcmail->action == 'add-identity' && $rcmail->output->template_exists('identityadd')) {
$rcmail->output->send('identityadd');
}
$rcmail->output->send('identityedit');
}
public static function identity_form($attrib)
{
$rcmail = rcmail::get_instance();
$IDENTITIES_LEVEL = intval($rcmail->config->get('identities_level', 0));
// Add HTML editor script(s)
self::html_editor('identity', 'rcmfd_signature');
// add some labels to client
$rcmail->output->add_label('noemailwarning', 'converting', 'editorwarning');
$i_size = !empty($attrib['size']) ? $attrib['size'] : 40;
$t_rows = !empty($attrib['textarearows']) ? $attrib['textarearows'] : 6;
$t_cols = !empty($attrib['textareacols']) ? $attrib['textareacols'] : 40;
// list of available cols
$form = [
'addressing' => [
'name' => $rcmail->gettext('settings'),
'content' => [
'name' => ['type' => 'text', 'size' => $i_size],
'email' => ['type' => 'text', 'size' => $i_size],
'organization' => ['type' => 'text', 'size' => $i_size],
'reply-to' => ['type' => 'text', 'size' => $i_size],
'bcc' => ['type' => 'text', 'size' => $i_size],
'standard' => ['type' => 'checkbox', 'label' => $rcmail->gettext('setdefault')],
]
],
'signature' => [
'name' => $rcmail->gettext('signature'),
'content' => [
'signature' => [
'type' => 'textarea',
'size' => $t_cols,
'rows' => $t_rows,
'spellcheck' => true,
'data-html-editor' => true
],
'html_signature' => [
'type' => 'checkbox',
'label' => $rcmail->gettext('htmlsignature'),
'onclick' => "return rcmail.command('toggle-editor', {id: 'rcmfd_signature', html: this.checked}, '', event)"
],
]
],
'encryption' => [
'name' => $rcmail->gettext('identityencryption'),
'attrs' => ['class' => 'identity-encryption', 'style' => 'display:none'],
'content' => html::div('identity-encryption-block', '')
]
];
// Enable TinyMCE editor
if (!empty(self::$record['html_signature'])) {
$form['signature']['content']['signature']['class'] = 'mce_editor';
$form['signature']['content']['signature']['is_escaped'] = true;
// Correctly handle HTML entities in HTML editor (#1488483)
self::$record['signature'] = htmlspecialchars(self::$record['signature'], ENT_NOQUOTES, RCUBE_CHARSET);
}
// hide "default" checkbox if only one identity is allowed
if ($IDENTITIES_LEVEL > 1) {
unset($form['addressing']['content']['standard']);
}
// disable some field according to access level
if ($IDENTITIES_LEVEL == 1 || $IDENTITIES_LEVEL == 3) {
$form['addressing']['content']['email']['disabled'] = true;
$form['addressing']['content']['email']['class'] = 'disabled';
}
if ($IDENTITIES_LEVEL == 4) {
foreach ($form['addressing']['content'] as $formfield => $value){
$form['addressing']['content'][$formfield]['disabled'] = true;
$form['addressing']['content'][$formfield]['class'] = 'disabled';
}
}
if (!empty(self::$record['email'])) {
self::$record['email'] = rcube_utils::idn_to_utf8(self::$record['email']);
}
// Allow plugins to modify identity form content
$plugin = $rcmail->plugins->exec_hook('identity_form', [
'form' => $form,
'record' => self::$record
]);
$form = $plugin['form'];
self::$record = $plugin['record'];
// Set form tags and hidden fields
list($form_start, $form_end) = self::get_form_tags($attrib, 'save-identity',
intval(self::$record['identity_id'] ?? 0),
['name' => '_iid', 'value' => self::$record['identity_id'] ?? 0]
);
unset($plugin);
unset($attrib['form'], $attrib['id']);
// return the complete edit form as table
$out = "$form_start\n";
foreach ($form as $fieldset) {
if (empty($fieldset['content'])) {
continue;
}
$content = '';
if (is_array($fieldset['content'])) {
$table = new html_table(['cols' => 2]);
foreach ($fieldset['content'] as $col => $colprop) {
$colprop['id'] = 'rcmfd_'.$col;
if (!empty($colprop['label'])) {
$label = $colprop['label'];
}
else {
$label = $rcmail->gettext(str_replace('-', '', $col));
}
if (!empty($colprop['value'])) {
$value = $colprop['value'];
}
else {
$val = self::$record[$col] ?? '';
$value = rcube_output::get_edit_field($col, $val, $colprop, $colprop['type']);
}
$table->add('title', html::label($colprop['id'], rcube::Q($label)));
$table->add(null, $value);
}
$content = $table->show($attrib);
}
else {
$content = $fieldset['content'];
}
$content = html::tag('legend', null, rcube::Q($fieldset['name'])) . $content;
$out .= html::tag('fieldset', !empty($fieldset['attrs']) ? $fieldset['attrs'] : [], $content) . "\n";
}
$out .= $form_end;
// add image upload form
$max_size = self::upload_init($rcmail->config->get('identity_image_size', 64) * 1024);
$form_id = 'identityImageUpload';
$out .= '<form id="' . $form_id . '" style="display: none">'
. html::div('hint', $rcmail->gettext(['name' => 'maxuploadsize', 'vars' => ['size' => $max_size]]))
. '</form>';
$rcmail->output->add_gui_object('uploadform', $form_id);
return $out;
}
}
@@ -0,0 +1,212 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Save an identity record or to add a new one |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_identity_save extends rcmail_action_settings_index
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$IDENTITIES_LEVEL = intval($rcmail->config->get('identities_level', 0));
$a_save_cols = ['name', 'email', 'organization', 'reply-to', 'bcc', 'standard', 'signature', 'html_signature'];
$a_bool_cols = ['standard', 'html_signature'];
$updated = false;
// check input
if (empty($_POST['_email']) && ($IDENTITIES_LEVEL == 0 || $IDENTITIES_LEVEL == 2)) {
$rcmail->output->show_message('noemailwarning', 'warning');
$rcmail->overwrite_action('edit-identity');
return;
}
$save_data = [];
foreach ($a_save_cols as $col) {
$fname = '_'.$col;
if (isset($_POST[$fname])) {
$save_data[$col] = rcube_utils::get_input_string($fname, rcube_utils::INPUT_POST, true);
}
}
// set "off" values for checkboxes that were not checked, and therefore
// not included in the POST body.
foreach ($a_bool_cols as $col) {
$fname = '_' . $col;
if (!isset($_POST[$fname])) {
$save_data[$col] = 0;
}
}
// make the identity a "default" if only one identity is allowed
if ($IDENTITIES_LEVEL > 1) {
$save_data['standard'] = 1;
}
// unset email address if user has no rights to change it
if ($IDENTITIES_LEVEL == 1 || $IDENTITIES_LEVEL == 3) {
unset($save_data['email']);
}
// unset all fields except signature
else if ($IDENTITIES_LEVEL == 4) {
foreach ($save_data as $idx => $value) {
if ($idx != 'signature' && $idx != 'html_signature') {
unset($save_data[$idx]);
}
}
}
// Validate e-mail addresses
$email_checks = !empty($save_data['email']) ? [rcube_utils::idn_to_ascii($save_data['email'])] : [];
foreach (['reply-to', 'bcc'] as $item) {
if (!empty($save_data[$item])) {
foreach (rcube_mime::decode_address_list($save_data[$item], null, false) as $rcpt) {
$email_checks[] = rcube_utils::idn_to_ascii($rcpt['mailto']);
}
}
}
foreach ($email_checks as $email) {
if ($email && !rcube_utils::check_email($email)) {
// show error message
$rcmail->output->show_message('emailformaterror', 'error', ['email' => rcube_utils::idn_to_utf8($email)], false);
$rcmail->overwrite_action('edit-identity');
return;
}
}
if (!empty($save_data['signature']) && !empty($save_data['html_signature'])) {
// replace uploaded images with data URIs
$save_data['signature'] = self::attach_images($save_data['signature'], 'identity');
// XSS protection in HTML signature (#1489251)
$save_data['signature'] = self::wash_html($save_data['signature']);
// clear POST data of signature, we want to use safe content
// when the form is displayed again
unset($_POST['_signature']);
}
// update an existing identity
if (!empty($_POST['_iid'])) {
$iid = rcube_utils::get_input_string('_iid', rcube_utils::INPUT_POST);
if (in_array($IDENTITIES_LEVEL, [1, 3, 4])) {
// merge with old identity data, fixes #1488834
$identity = $rcmail->user->get_identity($iid);
$save_data = array_merge($identity, $save_data);
unset($save_data['changed'], $save_data['del'], $save_data['user_id'], $save_data['identity_id']);
}
$plugin = $rcmail->plugins->exec_hook('identity_update', ['id' => $iid, 'record' => $save_data]);
$save_data = $plugin['record'];
if ($save_data['email']) {
$save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']);
}
if (!$plugin['abort']) {
$updated = $rcmail->user->update_identity($iid, $save_data);
}
else {
$updated = $plugin['result'];
}
if ($updated) {
$rcmail->output->show_message('successfullysaved', 'confirmation');
if (!empty($save_data['standard'])) {
$default_id = $iid;
}
// update the changed col in list
$name = $save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>';
$rcmail->output->command('parent.update_identity_row', $iid, rcube::Q(trim($name)));
}
else {
// show error message
$error = !empty($plugin['message']) ? $plugin['message'] : 'errorsaving';
$rcmail->output->show_message($error, 'error', null, false);
$rcmail->overwrite_action('edit-identity');
return;
}
}
// insert a new identity record
else if ($IDENTITIES_LEVEL < 2) {
if ($IDENTITIES_LEVEL == 1) {
$save_data['email'] = $rcmail->get_user_email();
}
$plugin = $rcmail->plugins->exec_hook('identity_create', ['record' => $save_data]);
$save_data = $plugin['record'];
if ($save_data['email']) {
$save_data['email'] = rcube_utils::idn_to_ascii($save_data['email']);
}
if (!$plugin['abort']) {
$insert_id = $save_data['email'] ? $rcmail->user->insert_identity($save_data) : null;
}
else {
$insert_id = $plugin['result'];
}
if ($insert_id) {
$rcmail->plugins->exec_hook('identity_create_after', ['id' => $insert_id, 'record' => $save_data]);
$rcmail->output->show_message('successfullysaved', 'confirmation', null, false);
$_GET['_iid'] = $insert_id;
if (!empty($save_data['standard'])) {
$default_id = $insert_id;
}
// add a new row to the list
$name = $save_data['name'] . ' <' . rcube_utils::idn_to_utf8($save_data['email']) .'>';
$rcmail->output->command('parent.update_identity_row', $insert_id, rcube::Q(trim($name)), true);
}
else {
// show error message
$error = !empty($plugin['message']) ? $plugin['message'] : 'errorsaving';
$rcmail->output->show_message($error, 'error', null, false);
$rcmail->overwrite_action('edit-identity');
return;
}
}
else {
$rcmail->output->show_message('opnotpermitted', 'error');
}
// mark all other identities as 'not-default'
if (!empty($default_id)) {
$rcmail->user->set_default($default_id);
}
// go to next step
$rcmail->overwrite_action('edit-identity');
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,96 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Provide functionality for user's settings & preferences |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_prefs_edit extends rcmail_action_settings_index
{
protected static $mode = self::MODE_HTTP;
protected static $section;
protected static $sections;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($rcmail->gettext('preferences'));
self::$section = rcube_utils::get_input_string('_section', rcube_utils::INPUT_GPC);
list(self::$sections,) = self::user_prefs(self::$section);
// register UI objects
$rcmail->output->add_handlers([
'userprefs' => [$this, 'user_prefs_form'],
'sectionname' => [$this, 'prefs_section_name'],
]);
$rcmail->output->send('settingsedit');
}
public static function user_prefs_form($attrib)
{
$rcmail = rcmail::get_instance();
// add some labels to client
$rcmail->output->add_label('nopagesizewarning', 'nosupporterror');
unset($attrib['form']);
$hidden = ['name' => '_section', 'value' => self::$section];
list($form_start, $form_end) = self::get_form_tags($attrib, 'save-prefs', null, $hidden);
$out = $form_start;
if (!empty(self::$sections[self::$section]['header'])) {
$div_attr = ['id' => 'preferences-header', 'class' =>'boxcontent'];
$out .= html::div($div_attr, self::$sections[self::$section]['header']);
}
foreach (self::$sections[self::$section]['blocks'] as $class => $block) {
if (!empty($block['options'])) {
$table = new html_table(['cols' => 2]);
foreach ($block['options'] as $option) {
if (isset($option['title'])) {
$table->add('title', $option['title']);
$table->add(null, $option['content']);
}
else {
$table->add(['colspan' => 2], $option['content']);
}
}
$out .= html::tag('fieldset', $class, html::tag('legend', null, $block['name']) . $table->show($attrib));
}
else if (!empty($block['content'])) {
$out .= html::tag('fieldset', null, html::tag('legend', null, $block['name']) . $block['content']);
}
}
return $out . $form_end;
}
public static function prefs_section_name()
{
return self::$sections[self::$section]['section'];
}
}
@@ -0,0 +1,298 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Save user preferences to DB and to the current session |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_prefs_save extends rcmail_action
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$CURR_SECTION = rcube_utils::get_input_string('_section', rcube_utils::INPUT_POST);
$dont_override = (array) $rcmail->config->get('dont_override');
$a_user_prefs = [];
// set options for specified section
switch ($CURR_SECTION) {
case 'general':
$a_user_prefs = [
'language' => self::prefs_input('language', '/^[a-zA-Z0-9_-]+$/'),
'timezone' => self::prefs_input('timezone', '/^[a-zA-Z_\/-]+$/'),
'date_format' => self::prefs_input('date_format', '/^[a-zA-Z_.\/ -]+$/'),
'time_format' => self::prefs_input('time_format', '/^[a-zA-Z0-9: ]+$/'),
'prettydate' => isset($_POST['_pretty_date']),
'display_next' => isset($_POST['_display_next']),
'refresh_interval' => self::prefs_input_int('refresh_interval') * 60,
'standard_windows' => isset($_POST['_standard_windows']),
'skin' => self::prefs_input('skin', '/^[a-zA-Z0-9_.-]+$/'),
];
// compose derived date/time format strings
if (
(isset($_POST['_date_format']) || isset($_POST['_time_format']))
&& !empty($a_user_prefs['date_format'])
&& !empty($a_user_prefs['time_format'])
) {
$a_user_prefs['date_short'] = 'D ' . $a_user_prefs['time_format'];
$a_user_prefs['date_long'] = $a_user_prefs['date_format'] . ' ' . $a_user_prefs['time_format'];
}
break;
case 'mailbox':
$a_user_prefs = [
'layout' => self::prefs_input('layout', '/^[a-z]+$/'),
'mail_read_time' => self::prefs_input_int('mail_read_time'),
'autoexpand_threads' => self::prefs_input_int('autoexpand_threads'),
'check_all_folders' => isset($_POST['_check_all_folders']),
'mail_pagesize' => max(2, self::prefs_input_int('mail_pagesize')),
];
break;
case 'mailview':
$a_user_prefs = [
'message_extwin' => self::prefs_input_int('message_extwin'),
'message_show_email' => isset($_POST['_message_show_email']),
'prefer_html' => isset($_POST['_prefer_html']),
'inline_images' => isset($_POST['_inline_images']),
'show_images' => self::prefs_input_int('show_images'),
'mdn_requests' => self::prefs_input_int('mdn_requests'),
'default_charset' => self::prefs_input('default_charset', '/^[a-zA-Z0-9-]+$/'),
];
break;
case 'compose':
$a_user_prefs = [
'compose_extwin' => self::prefs_input_int('compose_extwin'),
'htmleditor' => self::prefs_input_int('htmleditor'),
'draft_autosave' => self::prefs_input_int('draft_autosave'),
'mime_param_folding' => self::prefs_input_int('mime_param_folding'),
'force_7bit' => isset($_POST['_force_7bit']),
'mdn_default' => isset($_POST['_mdn_default']),
'dsn_default' => isset($_POST['_dsn_default']),
'reply_same_folder' => isset($_POST['_reply_same_folder']),
'spellcheck_before_send' => isset($_POST['_spellcheck_before_send']),
'spellcheck_ignore_syms' => isset($_POST['_spellcheck_ignore_syms']),
'spellcheck_ignore_nums' => isset($_POST['_spellcheck_ignore_nums']),
'spellcheck_ignore_caps' => isset($_POST['_spellcheck_ignore_caps']),
'show_sig' => self::prefs_input_int('show_sig'),
'reply_mode' => self::prefs_input_int('reply_mode'),
'sig_below' => isset($_POST['_sig_below']),
'strip_existing_sig' => isset($_POST['_strip_existing_sig']),
'sig_separator' => isset($_POST['_sig_separator']),
'default_font' => self::prefs_input('default_font', '/^[a-zA-Z ]+$/'),
'default_font_size' => self::prefs_input('default_font_size', '/^[0-9]+pt$/'),
'reply_all_mode' => self::prefs_input_int('reply_all_mode'),
'forward_attachment' => !empty($_POST['_forward_attachment']),
'compose_save_localstorage' => self::prefs_input_int('compose_save_localstorage'),
];
break;
case 'addressbook':
$a_user_prefs = [
'default_addressbook' => rcube_utils::get_input_string('_default_addressbook', rcube_utils::INPUT_POST, true),
'collected_recipients' => rcube_utils::get_input_string('_collected_recipients', rcube_utils::INPUT_POST, true),
'collected_senders' => rcube_utils::get_input_string('_collected_senders', rcube_utils::INPUT_POST, true),
'autocomplete_single' => isset($_POST['_autocomplete_single']),
'addressbook_sort_col' => self::prefs_input('addressbook_sort_col', '/^[a-z_]+$/'),
'addressbook_name_listing' => self::prefs_input_int('addressbook_name_listing'),
'addressbook_pagesize' => max(2, self::prefs_input_int('addressbook_pagesize')),
'contact_form_mode' => self::prefs_input('contact_form_mode', '/^(private|business)$/'),
];
break;
case 'server':
$a_user_prefs = [
'read_when_deleted' => isset($_POST['_read_when_deleted']),
'skip_deleted' => isset($_POST['_skip_deleted']),
'flag_for_deletion' => isset($_POST['_flag_for_deletion']),
'delete_junk' => isset($_POST['_delete_junk']),
'logout_purge' => self::prefs_input('logout_purge', '/^(all|never|30|60|90)$/'),
'logout_expunge' => isset($_POST['_logout_expunge']),
];
break;
case 'folders':
$a_user_prefs = [
'show_real_foldernames' => isset($_POST['_show_real_foldernames']),
// stop using SPECIAL-USE (#4782)
'lock_special_folders' => !in_array('lock_special_folders', $dont_override),
];
foreach (rcube_storage::$folder_types as $type) {
$a_user_prefs[$type . '_mbox'] = rcube_utils::get_input_string('_' . $type . '_mbox', rcube_utils::INPUT_POST, true);
};
break;
case 'encryption':
$a_user_prefs = [
'mailvelope_main_keyring' => isset($_POST['_mailvelope_main_keyring']),
];
break;
}
$plugin = rcmail::get_instance()->plugins->exec_hook('preferences_save',
['prefs' => $a_user_prefs, 'section' => $CURR_SECTION]);
$a_user_prefs = $plugin['prefs'];
// don't override these parameters
foreach ($dont_override as $p) {
$a_user_prefs[$p] = $rcmail->config->get($p);
}
// verify some options
switch ($CURR_SECTION) {
case 'general':
// switch UI language
if (isset($_POST['_language']) && $a_user_prefs['language'] != $_SESSION['language']) {
$rcmail->load_language($a_user_prefs['language']);
$rcmail->output->command('reload', 500);
}
// switch skin (if valid, otherwise unset the pref and fall back to default)
if (!empty($a_user_prefs['skin'])) {
if (!$rcmail->output->check_skin($a_user_prefs['skin'])) {
unset($a_user_prefs['skin']);
}
else if ($rcmail->config->get('skin') != $a_user_prefs['skin']) {
$rcmail->output->command('reload', 500);
}
}
$a_user_prefs['timezone'] = (string) $a_user_prefs['timezone'];
$min_refresh_interval = (int) $rcmail->config->get('min_refresh_interval');
if (!empty($a_user_prefs['refresh_interval']) && $min_refresh_interval) {
if ($a_user_prefs['refresh_interval'] < $min_refresh_interval) {
$a_user_prefs['refresh_interval'] = $min_refresh_interval;
}
}
break;
case 'mailbox':
// force min size
if ($a_user_prefs['mail_pagesize'] < 1) {
$a_user_prefs['mail_pagesize'] = 10;
}
$max_pagesize = (int) $rcmail->config->get('max_pagesize');
if ($max_pagesize && ($a_user_prefs['mail_pagesize'] > $max_pagesize)) {
$a_user_prefs['mail_pagesize'] = $max_pagesize;
}
break;
case 'addressbook':
// force min size
if ($a_user_prefs['addressbook_pagesize'] < 1) {
$a_user_prefs['addressbook_pagesize'] = 10;
}
$max_pagesize = (int) $rcmail->config->get('max_pagesize');
if ($max_pagesize && ($a_user_prefs['addressbook_pagesize'] > $max_pagesize)) {
$a_user_prefs['addressbook_pagesize'] = $max_pagesize;
}
break;
case 'folders':
$storage = $rcmail->get_storage();
$specials = [];
foreach (rcube_storage::$folder_types as $type) {
$specials[$type] = $a_user_prefs[$type . '_mbox'];
}
$storage->set_special_folders($specials);
break;
case 'server':
if (isset($a_user_prefs['logout_purge']) && !is_numeric($a_user_prefs['logout_purge'])) {
$a_user_prefs['logout_purge'] = $a_user_prefs['logout_purge'] !== 'never';
}
break;
}
// Save preferences
if (empty($plugin['abort'])) {
$saved = $rcmail->user->save_prefs($a_user_prefs);
}
else {
$saved = $plugin['result'];
}
if ($saved) {
$rcmail->output->show_message('successfullysaved', 'confirmation');
}
else {
$rcmail->output->show_message(!empty($plugin['message']) ? $plugin['message'] : 'errorsaving', 'error');
}
// display the form again
$rcmail->overwrite_action('edit-prefs');
}
/**
* Get option value from POST and validate with a regex
*/
public static function prefs_input($name, $regex)
{
$rcmail = rcmail::get_instance();
$value = rcube_utils::get_input_value('_' . $name, rcube_utils::INPUT_POST);
if (!is_string($value)) {
$value = null;
}
if ($value !== null && strlen($value) && !preg_match($regex, $value)) {
$value = $rcmail->config->get($name);
}
return $value;
}
/**
* Get integer option value from POST
*/
public static function prefs_input_int($name)
{
$rcmail = rcmail::get_instance();
$value = rcube_utils::get_input_value('_' . $name, rcube_utils::INPUT_POST);
return (int) $value;
}
}
@@ -0,0 +1,22 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Show edit form for a canned response creation |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_response_create extends rcmail_action_settings_response_edit
{
}
@@ -0,0 +1,50 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| A handler for canned response deletion |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_response_delete extends rcmail_action
{
static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
if ($id = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GP)) {
$plugin = $rcmail->plugins->exec_hook('response_delete', ['id' => $id]);
$deleted = !$plugin['abort'] ? $rcmail->user->delete_response($id) : $plugin['result'];
if (!empty($deleted)) {
$rcmail->output->command('display_message', $rcmail->gettext('deletedsuccessfully'), 'confirmation');
$rcmail->output->command('remove_response', $id);
}
else {
$msg = !empty($plugin['message']) ? $plugin['message'] : 'errorsaving';
$rcmail->output->show_message($msg, 'error');
}
}
$rcmail->output->send();
}
}
@@ -0,0 +1,124 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Show edit form for a canned response record |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_response_edit extends rcmail_action_settings_responses
{
protected static $mode = self::MODE_HTTP;
protected static $response;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$title = $rcmail->gettext($rcmail->action == 'add-response' ? 'addresponse' : 'editresponse');
if (!empty($args['post'])) {
self::$response = $args['post'];
}
else if ($id = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GP)) {
self::$response = $rcmail->get_compose_response($id);
if (!is_array(self::$response)) {
$rcmail->output->show_message('dberror', 'error');
$rcmail->output->send('iframe');
}
}
$rcmail->output->set_pagetitle($title);
$rcmail->output->set_env('readonly', !empty(self::$response['static']));
$rcmail->output->add_handler('responseform', [$this, 'response_form']);
$rcmail->output->send('responseedit');
}
/**
* Get content of a response editing/adding form
*
* @param array $attrib Template object attributes
*
* @return string HTML content
*/
public static function response_form($attrib)
{
$rcmail = rcmail::get_instance();
// add some labels to client
$rcmail->output->add_label('converting', 'editorwarning');
// Set form tags and hidden fields
$readonly = !empty(self::$response['static']);
$is_html = self::$response['is_html'] ?? false;
$id = self::$response['id'] ?? '';
$hidden = ['name' => '_id', 'value' => $id];
list($form_start, $form_end) = self::get_form_tags($attrib, 'save-response', $id, $hidden);
unset($attrib['form'], $attrib['id']);
$name_attr = [
'id' => 'ffname',
'size' => $attrib['size'] ?? null,
'readonly' => $readonly,
'required' => true,
];
$text_attr = [
'id' => 'fftext',
'size' => $attrib['textareacols'] ?? null,
'rows' => $attrib['textarearows'] ?? null,
'readonly' => $readonly,
'spellcheck' => true,
'data-html-editor' => true
];
$chk_attr = [
'id' => 'ffis_html',
'disabled' => $readonly,
'onclick' => "return rcmail.command('toggle-editor', {id: 'fftext', html: this.checked}, '', event)"
];
// Add HTML editor script(s)
self::html_editor('response', 'fftext');
// Enable TinyMCE editor
if ($is_html) {
$text_attr['class'] = 'mce_editor';
$text_attr['is_escaped'] = true;
// Correctly handle HTML entities in HTML editor (#1488483)
self::$response['data'] = htmlspecialchars(self::$response['data'], ENT_NOQUOTES, RCUBE_CHARSET);
}
$table = new html_table(['cols' => 2]);
$table->add('title', html::label('ffname', rcube::Q($rcmail->gettext('responsename'))));
$table->add(null, rcube_output::get_edit_field('name', self::$response['name'] ?? '', $name_attr, 'text'));
$table->add('title', html::label('fftext', rcube::Q($rcmail->gettext('responsetext'))));
$table->add(null, rcube_output::get_edit_field('text', self::$response['data'] ?? '', $text_attr, 'textarea'));
$table->add('title', html::label('ffis_html', rcube::Q($rcmail->gettext('htmltoggle'))));
$table->add(null, rcube_output::get_edit_field('is_html', $is_html, $chk_attr, 'checkbox'));
// return the complete edit form as table
return "$form_start\n" . $table->show($attrib) . $form_end;
}
}
@@ -0,0 +1,59 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| A handler for fetching a canned response content |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_response_get extends rcmail_action
{
static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$id = rcube_utils::get_input_string('_id', rcube_utils::INPUT_GET);
if ($id && ($response = $rcmail->get_compose_response($id))) {
$is_html = (bool) rcube_utils::get_input_string('_is_html', rcube_utils::INPUT_GET);
if ($is_html && empty($response['is_html'])) {
$converter = new rcube_text2html($response['data'], false, ['wrap' => true]);
$response['data'] = $converter->get_html();
$response['is_html'] = true;
}
else if (!$is_html && !empty($response['is_html'])) {
$params = [
'width' => $rcmail->config->get('line_length', 72),
'links' => false,
];
$response['data'] = $rcmail->html2text($response['data'], $params);
$response['is_html'] = false;
}
$rcmail->output->command('insert_response', $response);
}
$rcmail->output->send();
}
}
@@ -0,0 +1,112 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| A handler for saving a canned response record |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_response_save extends rcmail_action_settings_index
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$id = trim(rcube_utils::get_input_string('_id', rcube_utils::INPUT_POST));
$name = trim(rcube_utils::get_input_string('_name', rcube_utils::INPUT_POST));
$text = trim(rcube_utils::get_input_string('_text', rcube_utils::INPUT_POST, true));
$is_html = (bool) rcube_utils::get_input_string('_is_html', rcube_utils::INPUT_POST);
$response = [
'id' => $id,
'name' => $name,
'data' => $text,
'is_html' => $is_html,
];
if (!empty($text) && $is_html) {
// replace uploaded images with data URIs
$text = self::attach_images($text, 'response');
// XSS protection in HTML signature (#1489251)
$text = self::wash_html($text);
$response['data'] = $text;
}
if (empty($name) || empty($text)) {
// TODO: error
$rcmail->output->show_message('formincomplete', 'error');
$rcmail->overwrite_action('edit-response', ['post' => $response]);
return;
}
if (!empty($id) && is_numeric($id)) {
$plugin = $rcmail->plugins->exec_hook('response_update', ['id' => $id, 'record' => $response]);
$response = $plugin['record'];
if (!$plugin['abort']) {
$updated = $rcmail->user->update_response($id, $response);
}
else {
$updated = $plugin['result'];
}
if ($updated) {
$rcmail->output->show_message('successfullysaved', 'confirmation');
$rcmail->output->command('parent.update_response_row', $id, rcube::Q($response['name']));
}
else {
// show error message
$error = !empty($plugin['message']) ? $plugin['message'] : 'errorsaving';
$rcmail->output->show_message($error, 'error', null, false);
}
}
else {
$plugin = $rcmail->plugins->exec_hook('response_create', ['record' => $response]);
$response = $plugin['record'];
if (!$plugin['abort']) {
$insert_id = $rcmail->user->insert_response($response);
}
else {
$insert_id = $plugin['result'];
}
if ($insert_id) {
$rcmail->output->show_message('successfullysaved', 'confirmation');
$response['id'] = $_GET['_id'] = $insert_id;
// add a new row to the list
$rcmail->output->command('parent.update_response_row', $insert_id, rcube::Q($response['name']), true);
}
else {
$error = !empty($plugin['message']) ? $plugin['message'] : 'errorsaving';
$rcmail->output->show_message($error, 'error', null, false);
$rcmail->overwrite_action('add-response');
return;
}
}
// display the form again
$rcmail->overwrite_action('edit-response', ['post' => $response]);
}
}
@@ -0,0 +1,73 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Listing of canned responses, and quick insert action handler |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_responses extends rcmail_action_settings_index
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($rcmail->gettext('responses'));
$rcmail->output->include_script('list.js');
$rcmail->output->add_label('deleteresponseconfirm');
$rcmail->output->add_handlers(['responseslist' => [$this, 'responses_list']]);
$rcmail->output->send('responses');
}
/**
* Create template object 'responseslist'
*
* @param array $attrib Object attributes
*
* @return string HTML table output
*/
public static function responses_list($attrib)
{
$rcmail = rcmail::get_instance();
$attrib += ['id' => 'rcmresponseslist', 'tagname' => 'table'];
$plugin = $rcmail->plugins->exec_hook('responses_list', [
'list' => $rcmail->get_compose_responses(),
'cols' => ['name']
]);
$out = self::table_output($attrib, $plugin['list'], $plugin['cols'], 'id');
$readonly_responses = [];
foreach ($plugin['list'] as $item) {
if (!empty($item['static'])) {
$readonly_responses[] = $item['id'];
}
}
// set client env
$rcmail->output->add_gui_object('responseslist', $attrib['id']);
$rcmail->output->set_env('readonly_responses', $readonly_responses);
return $out;
}
}
@@ -0,0 +1,122 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Handles image uploads |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_upload extends rcmail_action
{
protected static $mode = self::MODE_AJAX;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$rcmail = rcmail::get_instance();
$from = rcube_utils::get_input_string('_from', rcube_utils::INPUT_GET);
$type = preg_replace('/(add|edit)-/', '', $from);
// Plugins in Settings may use this file for some uploads (#5694)
// Make sure it does not contain a dot, which is a special character
// when using rcube_session::append() below
$type = str_replace('.', '-', $type);
// Supported image format types
$IMAGE_TYPES = explode(',', 'jpeg,jpg,jp2,tiff,tif,bmp,eps,gif,png,png8,png24,png32,svg,ico');
// clear all stored output properties (like scripts and env vars)
$rcmail->output->reset();
$max_size = $rcmail->config->get($type . '_image_size', 64) * 1024;
$uploadid = rcube_utils::get_input_string('_uploadid', rcube_utils::INPUT_GET);
if (!empty($_FILES['_file']['tmp_name']) && is_array($_FILES['_file']['tmp_name'])) {
$multiple = count($_FILES['_file']['tmp_name']) > 1;
foreach ($_FILES['_file']['tmp_name'] as $i => $filepath) {
$err = $_FILES['_file']['error'][$i];
$imageprop = null;
$attachment = null;
// Process uploaded attachment if there is no error
if (!$err) {
if ($max_size < $_FILES['_file']['size'][$i]) {
$err = 'size_error';
}
// check image file type
else {
$image = new rcube_image($filepath);
$imageprop = $image->props();
if (!in_array(strtolower($imageprop['type']), $IMAGE_TYPES)) {
$err = 'type_error';
}
}
}
// save uploaded image in storage backend
if (!empty($imageprop)) {
$attachment = $rcmail->plugins->exec_hook('attachment_upload', [
'path' => $filepath,
'size' => $_FILES['_file']['size'][$i],
'name' => $_FILES['_file']['name'][$i],
'mimetype' => 'image/' . $imageprop['type'],
'group' => $type,
]);
}
if (!$err && !empty($attachment['status']) && empty($attachment['abort'])) {
$id = $attachment['id'];
// store new file in session
unset($attachment['status'], $attachment['abort']);
$rcmail->session->append($type . '.files', $id, $attachment);
$content = rcube::Q($attachment['name']);
$rcmail->output->command('add2attachment_list', "rcmfile$id", [
'html' => $content,
'name' => $attachment['name'],
'mimetype' => $attachment['mimetype'],
'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']),
'complete' => true
],
$uploadid
);
}
else {
$error_label = null;
if ($err == 'type_error') {
$error_label = 'invalidimageformat';
}
else if ($err == 'size_error') {
$error_label = ['name' => 'filesizeerror', 'vars' => ['size' => self::show_bytes($max_size)]];
}
self::upload_error($err, $attachment, $error_label);
}
}
}
else if (self::upload_failure()) {
$rcmail->output->command('remove_from_attachment_list', $uploadid);
}
$rcmail->output->send('iframe');
}
}
@@ -0,0 +1,49 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| |
| Copyright (C) The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Displaying uploaded images |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
*/
class rcmail_action_settings_upload_display extends rcmail_action
{
protected static $mode = self::MODE_HTTP;
/**
* Request handler.
*
* @param array $args Arguments from the previous step(s)
*/
public function run($args = [])
{
$from = rcube_utils::get_input_string('_from', rcube_utils::INPUT_GET);
$type = preg_replace('/(add|edit)-/', '', $from);
// Plugins in Settings may use this file for some uploads (#5694)
// Make sure it does not contain a dot, which is a special character
// when using rcube_session::append() below
$type = str_replace('.', '-', $type);
$id = 'undefined';
if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs)) {
$id = $regs[1];
}
self::display_uploaded_file($_SESSION[$type]['files'][$id]);
exit;
}
}