diff --git a/ruty/mails/bin/cleandb.sh b/ruty/mails/bin/cleandb.sh
new file mode 100644
index 0000000..711f32b
--- /dev/null
+++ b/ruty/mails/bin/cleandb.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require INSTALL_PATH.'program/include/clisetup.php';
+
+if (!empty($_SERVER['argv'][1])) {
+ $days = intval($_SERVER['argv'][1]);
+}
+else {
+ $days = 7;
+}
+
+rcmail_utils::db_clean($days);
diff --git a/ruty/mails/bin/cssshrink.sh b/ruty/mails/bin/cssshrink.sh
new file mode 100644
index 0000000..4fa5dd4
--- /dev/null
+++ b/ruty/mails/bin/cssshrink.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+set -e
+
+PWD=`dirname "$0"`
+
+do_shrink() {
+ rm -f "$2"
+ csso $1 -o $2 --no-restructure
+}
+
+if which csso > /dev/null 2>&1; then
+ :
+else
+ echo "csso not found. Please install e.g. 'npm install -g csso-cli'."
+ exit 1
+fi
+
+# compress single file from argument
+if [ $# -gt 0 ]; then
+ CSS_FILE="$1"
+
+ echo "Shrinking $CSS_FILE"
+ minfile=`echo $CSS_FILE | sed -e 's/\.css$/\.min\.css/'`
+ do_shrink "$CSS_FILE" "$minfile"
+ exit
+fi
+
+DIRS="$PWD/../skins/* $PWD/../plugins/* $PWD/../plugins/*/skins/* $PWD/../plugins/*/themes/*"
+# default: compress application scripts
+for dir in $DIRS; do
+ for file in $dir/*.css; do
+ if echo "$file" | grep -q -e '.min.css$'; then
+ continue
+ fi
+ if [ ! -f "$file" ]; then
+ continue
+ fi
+
+ echo "Shrinking $file"
+ minfile=`echo $file | sed -e 's/\.css$/\.min\.css/'`
+ do_shrink "$file" "$minfile"
+ done
+done
diff --git a/ruty/mails/bin/decrypt.sh b/ruty/mails/bin/decrypt.sh
new file mode 100644
index 0000000..b684cd6
--- /dev/null
+++ b/ruty/mails/bin/decrypt.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+/**
+ * If http_received_header_encrypt is configured, the IP address and the
+ * host name of the added Received: header is encrypted with 3DES, to
+ * protect information that some could consider sensitive, yet their
+ * availability is a must in some circumstances.
+ *
+ * Such an encrypted Received: header might look like:
+ *
+ * Received: from DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ==
+ * [my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4]
+ * with HTTP/1.1 (POST); Thu, 14 May 2009 19:17:28 +0200
+ *
+ * In this example, the two encrypted components are the sender host name
+ * (DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ==) and the IP
+ * address (my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4).
+ *
+ * Using this tool, they can be decrypted into plain text:
+ *
+ * $ bin/decrypt.sh 'my0nUbjZXKtl7KVBZcsvWOxxtyVFxza4' \
+ * > 'DzgkvJBO5+bw+oje5JACeNIa/uSI4mRw2cy5YoPBba73eyBmjtyHnQ=='
+ * 84.3.187.208
+ * 5403BBD0.catv.pool.telekom.hu
+ * $
+ *
+ * Thus it is known that this particular message was sent by 84.3.187.208,
+ * having, at the time of sending, the name of 5403BBD0.catv.pool.telekom.hu.
+ *
+ * If (most likely binary) junk is shown, then
+ * - either the encryption password has, between the time the mail was sent
+ * and 'now', changed, or
+ * - you are dealing with counterfeit header data.
+ */
+
+define('INSTALL_PATH', realpath(__DIR__ .'/..') . '/');
+
+require INSTALL_PATH . 'program/include/clisetup.php';
+
+if ($argc < 2) {
+ die("Usage: " . basename($argv[0]) . " encrypted-hdr-part [encrypted-hdr-part ...]\n");
+}
+
+$RCMAIL = rcube::get_instance();
+
+for ($i = 1; $i < $argc; $i++) {
+ printf("%s\n", $RCMAIL->decrypt($argv[$i]));
+};
diff --git a/ruty/mails/bin/deluser.sh b/ruty/mails/bin/deluser.sh
new file mode 100644
index 0000000..7dcf944
--- /dev/null
+++ b/ruty/mails/bin/deluser.sh
@@ -0,0 +1,141 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+function print_usage()
+{
+ print "Usage: deluser.sh [--host=HOST][--age=DAYS][--dry-run] [username]\n";
+ print "--host=HOST The IMAP hostname or IP the given user is related to\n";
+ print "--age=DAYS Delete all users who have not logged in for more than X days\n";
+ print "--dry-run List users but do not delete them (for use with --age)\n";
+}
+
+function _die($msg, $usage=false)
+{
+ fwrite(STDERR, $msg . "\n");
+ if ($usage) print_usage();
+ exit(1);
+}
+
+$rcmail = rcube::get_instance();
+
+// get arguments
+$args = rcube_utils::get_opt(['h' => 'host', 'a' => 'age', 'd' => 'dry-run:bool']);
+
+if (!empty($args['age']) && ($age = intval($args['age']))) {
+ $db = $rcmail->get_dbh();
+ $db->db_connect('r');
+
+ $query = $db->query("SELECT `username`, `mail_host` FROM " . $db->table_name('users', true)
+ . " WHERE `last_login` < " . $db->now($age * -1 * 86400)
+ . ($args['host'] ? " AND `mail_host` = " . $db->quote($args['host']) : '')
+ );
+
+ while ($user = $db->fetch_assoc($query)) {
+ if (!empty($args['dry-run'])) {
+ printf("%s (%s)\n", $user['username'], $user['mail_host']);
+ continue;
+ }
+ system(sprintf("php %s/deluser.sh --host=%s %s", INSTALL_PATH . 'bin', escapeshellarg($user['mail_host']), escapeshellarg($user['username'])));
+ }
+ exit(0);
+}
+
+$username = isset($args[0]) ? trim($args[0]) : null;
+if (empty($username)) {
+ _die("Missing required parameters", true);
+}
+
+if (empty($args['host'])) {
+ $hosts = $rcmail->config->get('imap_host', '');
+ if (is_string($hosts)) {
+ $args['host'] = $hosts;
+ }
+ else if (is_array($hosts) && count($hosts) == 1) {
+ $args['host'] = reset($hosts);
+ }
+ else {
+ _die("Specify a host name", true);
+ }
+
+ // host can be a URL like tls://192.168.12.44
+ $host_url = parse_url($args['host']);
+ if ($host_url['host']) {
+ $args['host'] = $host_url['host'];
+ }
+}
+
+// connect to DB
+$db = $rcmail->get_dbh();
+$db->db_connect('w');
+$transaction = false;
+
+if (!$db->is_connected() || $db->is_error()) {
+ _die("No DB connection\n" . $db->is_error());
+}
+
+// find user in local database
+$user = rcube_user::query($username, $args['host']);
+
+if (!$user) {
+ die("User not found.\n");
+}
+
+// inform plugins about approaching user deletion
+$plugin = $rcmail->plugins->exec_hook('user_delete_prepare', ['user' => $user, 'username' => $username, 'host' => $args['host']]);
+
+// let plugins cleanup their own user-related data
+if (!$plugin['abort']) {
+ $transaction = $db->startTransaction();
+ $plugin = $rcmail->plugins->exec_hook('user_delete', $plugin);
+}
+
+if ($plugin['abort']) {
+ unset($plugin['abort']);
+ if ($transaction) {
+ $db->rollbackTransaction();
+ }
+ _die("User deletion aborted by plugin");
+}
+
+$db->query('DELETE FROM ' . $db->table_name('users', true) . ' WHERE `user_id` = ?', $user->ID);
+
+if ($db->is_error()) {
+ $rcmail->plugins->exec_hook('user_delete_rollback', $plugin);
+ _die("DB error occurred: " . $db->is_error());
+}
+else {
+ // inform plugins about executed user deletion
+ $plugin = $rcmail->plugins->exec_hook('user_delete_commit', $plugin);
+
+ if ($plugin['abort']) {
+ unset($plugin['abort']);
+ $db->rollbackTransaction();
+ $rcmail->plugins->exec_hook('user_delete_rollback', $plugin);
+ }
+ else {
+ $db->endTransaction();
+ echo "Successfully deleted user $user->ID\n";
+ }
+}
diff --git a/ruty/mails/bin/gc.sh b/ruty/mails/bin/gc.sh
new file mode 100644
index 0000000..e83d18e
--- /dev/null
+++ b/ruty/mails/bin/gc.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require INSTALL_PATH.'program/include/clisetup.php';
+
+$rcmail = rcube::get_instance();
+
+$session_driver = $rcmail->config->get('session_storage', 'db');
+$session_lifetime = $rcmail->config->get('session_lifetime', 0) * 60 * 2;
+
+// Clean expired SQL sessions
+if ($session_driver == 'db' && $session_lifetime) {
+ $db = $rcmail->get_dbh();
+ $db->query("DELETE FROM " . $db->table_name('session')
+ . " WHERE changed < " . $db->now(-$session_lifetime));
+}
+
+// Clean caches and temp directory
+$rcmail->gc();
diff --git a/ruty/mails/bin/indexcontacts.sh b/ruty/mails/bin/indexcontacts.sh
new file mode 100644
index 0000000..3fcff80
--- /dev/null
+++ b/ruty/mails/bin/indexcontacts.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH.'program/include/clisetup.php';
+ini_set('memory_limit', -1);
+
+rcmail_utils::indexcontacts();
diff --git a/ruty/mails/bin/initdb.sh b/ruty/mails/bin/initdb.sh
new file mode 100644
index 0000000..a98bbf5
--- /dev/null
+++ b/ruty/mails/bin/initdb.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+// get arguments
+$opts = rcube_utils::get_opt([
+ 'd' => 'dir',
+ 'u' => 'update'
+]);
+
+if (empty($opts['dir'])) {
+ rcube::raise_error("Database schema directory not specified (--dir).", false, true);
+}
+
+// Check if directory exists
+if (!file_exists($opts['dir'])) {
+ rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
+}
+
+$db = rcmail_utils::db();
+
+if (!empty($opts['update']) && in_array($db->table_name('system'), (array)$db->list_tables())) {
+ echo "Checking for database schema updates..." . PHP_EOL;
+ rcmail_utils::db_update($opts['dir'], 'roundcube', null, ['errors' => true]);
+} else {
+ rcmail_utils::db_init($opts['dir']);
+}
diff --git a/ruty/mails/bin/installto.sh b/ruty/mails/bin/installto.sh
new file mode 100644
index 0000000..30705d3
--- /dev/null
+++ b/ruty/mails/bin/installto.sh
@@ -0,0 +1,148 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+if (!function_exists('system')) {
+ rcube::raise_error("PHP system() function is required. Check disable_functions in php.ini.", false, true);
+}
+
+$target_dir = unslashify(end($_SERVER['argv']));
+$accept = in_array('-y', $_SERVER['argv']) ? 'y' : null;
+
+if (empty($target_dir) || !is_dir(realpath($target_dir))) {
+ rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh [-y] ", false, true);
+}
+
+// read version from iniset.php
+$iniset = @file_get_contents($target_dir . '/program/include/iniset.php');
+if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z0-9-]*)/', $iniset, $m)) {
+ rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true);
+}
+
+$oldversion = $m[1];
+
+if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>')) {
+ rcube::raise_error("Target installation already in version $oldversion.", false, true);
+}
+
+if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '==')) {
+ echo "Target installation already in version $oldversion. Do you want to update again? (y/N)\n";
+}
+else {
+ echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n";
+}
+
+$input = $accept ?: trim(fgets(STDIN));
+
+if (strtolower($input) == 'y') {
+ echo "Copying files to target location...";
+
+ $adds = [];
+ $dirs = ['bin','SQL','plugins','skins','program'];
+
+ if (is_dir(INSTALL_PATH . 'vendor') && (!is_file("$target_dir/composer.json") || rcmail_install::vendor_dir_untouched($target_dir))) {
+ $dirs[] = 'vendor';
+ }
+ if (file_exists("$target_dir/installer")) {
+ $dirs[] = 'installer';
+ }
+
+ foreach ($dirs as $dir) {
+ // @FIXME: should we use --delete for all directories?
+ $delete = in_array($dir, ['program', 'vendor', 'installer']) ? '--delete ' : '';
+ $command = "rsync -aC --out-format=%n " . $delete . INSTALL_PATH . "$dir/ $target_dir/$dir/";
+
+ if (system($command, $ret) === false || $ret > 0) {
+ rcube::raise_error("Failed to execute command: $command", false, true);
+ }
+ }
+
+ foreach (['index.php','config/defaults.inc.php','composer.json-dist','jsdeps.json','CHANGELOG.md','README.md','UPGRADING','LICENSE','INSTALL'] as $file) {
+ $command = "rsync -a --out-format=%n " . INSTALL_PATH . "$file $target_dir/$file";
+
+ if (file_exists(INSTALL_PATH . $file) && (system($command, $ret) === false || $ret > 0)) {
+ rcube::raise_error("Failed to execute command: $command", false, true);
+ }
+ }
+
+ // Copy .htaccess or .user.ini if needed
+ foreach (['.htaccess','.user.ini'] as $file) {
+ if (file_exists(INSTALL_PATH . $file)) {
+ if (!file_exists("$target_dir/$file") || file_get_contents(INSTALL_PATH . $file) != file_get_contents("$target_dir/$file")) {
+ if (copy(INSTALL_PATH . $file, "$target_dir/$file.new")) {
+ echo "$file.new\n";
+ $adds[] = "NOTICE: New $file file saved as $file.new.";
+ }
+ }
+ }
+ }
+
+ // remove old (<1.0) .htaccess file
+ @unlink("$target_dir/program/.htaccess");
+ echo "done.\n\n";
+
+ if (is_dir("$target_dir/skins/default")) {
+ echo "Removing old default skin...";
+ system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default");
+ foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) {
+ $plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir);
+ if (is_dir("$target_dir/$plugin_skin_dir/classic")) {
+ system("rm -rf $target_dir/$plugin_skin_dir/default");
+ }
+ }
+ echo "done.\n\n";
+ }
+
+ // Warn about situation when using "complete" package to update "custom" installation (#7087)
+ // Note: "Complete" package do not include jsdeps.json nor install-jsdeps.sh
+ if (file_exists("$target_dir/jsdeps.json") && !file_exists(INSTALL_PATH . "jsdeps.json")) {
+ $adds[] = "WARNING: JavaScript dependencies update skipped. New jsdeps.json file not found.";
+ }
+ // check if js-deps are up-to-date
+ else if (file_exists("$target_dir/jsdeps.json") && file_exists("$target_dir/bin/install-jsdeps.sh")) {
+ $jsdeps = json_decode(file_get_contents("$target_dir/jsdeps.json"));
+ $package = $jsdeps->dependencies[0];
+ $dest_file = $target_dir . '/' . $package->dest;
+
+ if (!file_exists($dest_file) || sha1_file($dest_file) !== $package->sha1) {
+ echo "Installing JavaScript dependencies...";
+ system("cd $target_dir && bin/install-jsdeps.sh");
+ echo "done.\n\n";
+ }
+ }
+
+ if (file_exists("$target_dir/installer")) {
+ $adds[] = "NOTICE: The 'installer' directory still exists. You should remove it after the upgrade.";
+ }
+
+ if (!empty($adds)) {
+ echo implode("\n", $adds) . "\n\n";
+ }
+
+ echo "Running update script at target...\n";
+ system("cd $target_dir && php bin/update.sh --version=$oldversion" . ($accept ? ' -y' : ''));
+ echo "All done.\n";
+}
+else {
+ echo "Update cancelled. See ya!\n";
+}
diff --git a/ruty/mails/bin/jsshrink.sh b/ruty/mails/bin/jsshrink.sh
new file mode 100644
index 0000000..ee75399
--- /dev/null
+++ b/ruty/mails/bin/jsshrink.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+set -e
+
+PWD=`dirname "$0"`
+LANG_IN='ECMASCRIPT5'
+
+do_shrink() {
+ rm -f "$2"
+ # copy the first comment block with license information for LibreJS
+ grep -q '@lic' $1 && sed -n '/\/\*/,/\*\// { p; /\*\//q; }' $1 > $2
+ uglifyjs --compress --mangle -- $1 >> $2
+}
+
+if which uglifyjs > /dev/null 2>&1; then
+ :
+else
+ echo "uglifyjs not found. Please install e.g. 'npm install -g uglify-js'."
+ exit 1
+fi
+
+# compress single file from argument
+if [ $# -gt 0 ]; then
+ JS_FILE="$1"
+
+ if [ $# -gt 1 ]; then
+ LANG_IN="$2"
+ fi
+
+ echo "Shrinking $JS_FILE"
+ minfile=`echo $JS_FILE | sed -e 's/\.js$/\.min\.js/'`
+ do_shrink "$JS_FILE" "$minfile" "$LANG_IN"
+ exit
+fi
+
+DIRS="$PWD/../program/js $PWD/../skins/* $PWD/../plugins/* $PWD/../plugins/*/skins/* $PWD/../plugins/managesieve/codemirror/lib"
+# default: compress application scripts
+for dir in $DIRS; do
+ for file in $dir/*.js; do
+ if echo "$file" | grep -q -e '.min.js$'; then
+ continue
+ fi
+ if [ ! -f "$file" ]; then
+ continue
+ fi
+
+ echo "Shrinking $file"
+ minfile=`echo $file | sed -e 's/\.js$/\.min\.js/'`
+ do_shrink "$file" "$minfile" "$LANG_IN"
+ done
+done
diff --git a/ruty/mails/bin/makedoc.sh b/ruty/mails/bin/makedoc.sh
new file mode 100644
index 0000000..2d6ac8a
--- /dev/null
+++ b/ruty/mails/bin/makedoc.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+set -x
+
+BIN_PHPDOC=`/usr/bin/which phpdoc`
+
+if [ ! -x "$BIN_PHPDOC" ]
+then
+ echo "phpdoc not found"
+ exit 1
+fi
+
+INSTALL_PATH="`dirname $0`/.."
+PATH_PROJECT=$INSTALL_PATH/program/include
+PATH_FRAMEWORK=$INSTALL_PATH/program/lib/Roundcube
+PATH_DOCS=$INSTALL_PATH/doc/phpdoc
+TITLE="Roundcube Webmail"
+PACKAGES="Webmail"
+OUTPUTFORMAT=HTML
+TEMPLATE=responsive-twig
+
+# make documentation
+$BIN_PHPDOC -d $PATH_PROJECT,$PATH_FRAMEWORK -t $PATH_DOCS --title "$TITLE" \
+ --defaultpackagename $PACKAGES --template=$TEMPLATE
diff --git a/ruty/mails/bin/moduserprefs.sh b/ruty/mails/bin/moduserprefs.sh
new file mode 100644
index 0000000..b3402df
--- /dev/null
+++ b/ruty/mails/bin/moduserprefs.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH.'program/include/clisetup.php';
+
+function print_usage()
+{
+ print "Usage: moduserprefs.sh [options] pref-name [pref-value]\n";
+ print "Options:\n";
+ print " --user=user-id User ID in local database\n";
+ print " --config=path Location of additional configuration file\n";
+ print " --delete Unset the given preference\n";
+ print " --type=type Pref-value type: int, bool, string\n";
+}
+
+
+// get arguments
+$args = rcube_utils::get_opt([
+ 'u' => 'user',
+ 'd' => 'delete:bool',
+ 't' => 'type',
+ 'c' => 'config',
+]);
+
+if (empty($_SERVER['argv'][1]) || $_SERVER['argv'][1] == 'help') {
+ print_usage();
+ exit;
+}
+else if (empty($args[0]) || (empty($args[1]) && empty($args['delete']))) {
+ print "Missing required parameters.\n";
+ print_usage();
+ exit;
+}
+
+$pref_name = trim($args[0]);
+$pref_value = !empty($args['delete']) ? null : trim($args[1]);
+
+if ($pref_value === null) {
+ $args['type'] = null;
+}
+
+if (!empty($args['config'])) {
+ $rcube = rcube::get_instance();
+ $rcube->config->load_from_file($args['config']);
+}
+
+$type = isset($args['type']) ? $args['type'] : null;
+$user = isset($args['user']) ? $args['user'] : null;
+
+rcmail_utils::mod_pref($pref_name, $pref_value, $user, $type);
diff --git a/ruty/mails/bin/msgexport.sh b/ruty/mails/bin/msgexport.sh
new file mode 100644
index 0000000..42624e5
--- /dev/null
+++ b/ruty/mails/bin/msgexport.sh
@@ -0,0 +1,149 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+ini_set('memory_limit', -1);
+
+require_once INSTALL_PATH.'program/include/clisetup.php';
+
+function print_usage()
+{
+ print "Usage: msgexport.sh -h imap-host -u user-name -m mailbox name\n";
+ print "--host IMAP host\n";
+ print "--user IMAP user name\n";
+ print "--mbox Folder name, set to '*' for all\n";
+ print "--file Output file\n";
+}
+
+function vputs($str)
+{
+ $out = !empty($GLOBALS['args']['file']) ? STDOUT : STDERR;
+ fwrite($out, $str);
+}
+
+function progress_update($pos, $max)
+{
+ $percent = round(100 * $pos / $max);
+ vputs(sprintf("%3d%% [%-51s] %d/%d\033[K\r", $percent, @str_repeat('=', $percent / 2) . '>', $pos, $max));
+}
+
+function export_mailbox($mbox, $filename)
+{
+ global $IMAP;
+
+ $IMAP->set_folder($mbox);
+
+ vputs("Getting message list of {$mbox}...");
+
+ $index = $IMAP->index($mbox, null, 'ASC');
+ $count = $index->count();
+ $index = $index->get();
+
+ vputs("$count messages\n");
+
+ if ($filename) {
+ if (!($out = fopen($filename, 'w'))) {
+ vputs("Cannot write to output file\n");
+ return;
+ }
+ vputs("Writing to $filename\n");
+ }
+ else {
+ $out = STDOUT;
+ }
+
+ for ($i = 0; $i < $count; $i++) {
+ $headers = $IMAP->get_message_headers($index[$i]);
+ $from = current(rcube_mime::decode_address_list($headers->from, 1, false));
+
+ fwrite($out, sprintf("From %s %s UID %d\n", $from['mailto'], $headers->date, $headers->uid));
+ $IMAP->get_raw_body($headers->uid, $out);
+ fwrite($out, "\n\n\n");
+
+ progress_update($i+1, $count);
+ }
+ vputs("\ncomplete.\n");
+
+ if ($filename) {
+ fclose($out);
+ }
+}
+
+// get arguments
+$opts = ['h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file'];
+$args = rcube_utils::get_opt($opts) + ['host' => 'localhost', 'mbox' => 'INBOX'];
+
+if (!isset($_SERVER['argv'][1]) || $_SERVER['argv'][1] == 'help') {
+ print_usage();
+ exit;
+}
+else if (!$args['host']) {
+ vputs("Missing required parameters.\n");
+ print_usage();
+ exit;
+}
+
+// prompt for username if not set
+if (empty($args['user'])) {
+ vputs("IMAP user: ");
+ $args['user'] = trim(fgets(STDIN));
+}
+
+// prompt for password
+$args['pass'] = rcube_utils::prompt_silent("Password: ");
+
+
+// parse $host URL
+$a_host = parse_url($args['host']);
+if (!empty($a_host['host'])) {
+ $host = $a_host['host'];
+ $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], ['ssl','imaps','tls'])) ? TRUE : FALSE;
+ $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
+}
+else {
+ $host = $args['host'];
+ $imap_port = 143;
+ $imap_ssl = false;
+}
+
+// instantiate IMAP class
+$IMAP = new rcube_imap(null);
+
+// try to connect to IMAP server
+if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) {
+ vputs("IMAP login successful.\n");
+
+ $filename = null;
+ $mailboxes = $args['mbox'] == '*' ? $IMAP->list_folders(null) : [$args['mbox']];
+
+ foreach ($mailboxes as $mbox) {
+ if (!empty($args['file'])) {
+ $filename = preg_replace('/\.[a-z0-9]{3,4}$/i', '', $args['file']) . asciiwords($mbox) . '.mbox';
+ }
+ else if ($args['mbox'] == '*') {
+ $filename = asciiwords($mbox) . '.mbox';
+ }
+
+ if ($args['mbox'] == '*' && in_array(strtolower($mbox), ['junk','spam','trash'])) {
+ continue;
+ }
+
+ export_mailbox($mbox, $filename);
+ }
+}
+else {
+ vputs("IMAP login failed.\n");
+}
diff --git a/ruty/mails/bin/msgimport.sh b/ruty/mails/bin/msgimport.sh
new file mode 100644
index 0000000..e7dd5cb
--- /dev/null
+++ b/ruty/mails/bin/msgimport.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+ini_set('memory_limit', -1);
+
+require_once INSTALL_PATH.'program/include/clisetup.php';
+
+function print_usage()
+{
+ print "Usage: msgimport.sh -h imap-host -u user-name -m mailbox -f message-file\n";
+ print "--host IMAP host\n";
+ print "--user IMAP user name\n";
+ print "--mbox Target mailbox\n";
+ print "--file Message file to upload\n";
+}
+
+// get arguments
+$opts = ['h' => 'host', 'u' => 'user', 'p' => 'pass', 'm' => 'mbox', 'f' => 'file'];
+$args = rcube_utils::get_opt($opts) + ['host' => 'localhost', 'mbox' => 'INBOX'];
+
+if (!isset($_SERVER['argv'][1]) || $_SERVER['argv'][1] == 'help') {
+ print_usage();
+ exit;
+}
+else if (empty($args['host']) || empty($args['file'])) {
+ print "Missing required parameters.\n";
+ print_usage();
+ exit;
+}
+else if (!is_file($args['file'])) {
+ rcube::raise_error("Cannot read message file.", false, true);
+}
+
+// prompt for username if not set
+if (empty($args['user'])) {
+ //fwrite(STDOUT, "Please enter your name\n");
+ echo "IMAP user: ";
+ $args['user'] = trim(fgets(STDIN));
+}
+
+// prompt for password
+if (empty($args['pass'])) {
+ $args['pass'] = rcube_utils::prompt_silent("Password: ");
+}
+
+// parse $host URL
+$a_host = parse_url($args['host']);
+if (!empty($a_host['host'])) {
+ $host = $a_host['host'];
+ $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], ['ssl','imaps','tls'])) ? TRUE : FALSE;
+ $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : 143);
+}
+else {
+ $host = $args['host'];
+ $imap_port = 143;
+ $imap_ssl = false;
+}
+
+// instantiate IMAP class
+$IMAP = new rcube_imap(null);
+
+// try to connect to IMAP server
+if ($IMAP->connect($host, $args['user'], $args['pass'], $imap_port, $imap_ssl)) {
+ print "IMAP login successful.\n";
+ print "Uploading messages...\n";
+
+ $count = 0;
+ $message = $lastline = '';
+
+ $fp = fopen($args['file'], 'r');
+ while (($line = fgets($fp)) !== false) {
+ if (preg_match('/^From\s+-/', $line) && $lastline == '') {
+ if (!empty($message)) {
+ if ($IMAP->save_message($args['mbox'], rtrim($message))) {
+ $count++;
+ }
+ else {
+ rcube::raise_error("Failed to save message to {$args['mbox']}", false, true);
+ }
+ $message = '';
+ }
+ continue;
+ }
+
+ $message .= $line;
+ $lastline = rtrim($line);
+ }
+
+ if (!empty($message) && $IMAP->save_message($args['mbox'], rtrim($message))) {
+ $count++;
+ }
+
+ // upload message from file
+ if ($count) {
+ print "$count messages successfully added to {$args['mbox']}.\n";
+ }
+ else {
+ print "Adding messages failed!\n";
+ }
+}
+else {
+ rcube::raise_error("IMAP login failed.", false, true);
+}
diff --git a/ruty/mails/bin/update.sh b/ruty/mails/bin/update.sh
new file mode 100644
index 0000000..13f0846
--- /dev/null
+++ b/ruty/mails/bin/update.sh
@@ -0,0 +1,328 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+// get arguments
+$opts = rcube_utils::get_opt(['v' => 'version', 'y' => 'accept:bool']);
+
+// ask user if no version is specified
+if (empty($opts['version'])) {
+ echo "What version are you upgrading from? Type '?' if you don't know.\n";
+
+ if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z0-9-]*$/', $input)) {
+ $opts['version'] = $input;
+ }
+ else {
+ $opts['version'] = RCMAIL_VERSION;
+ }
+}
+
+$RCI = rcmail_install::get_instance();
+$RCI->load_config();
+
+if ($RCI->configured) {
+ $success = true;
+
+ if (($messages = $RCI->check_config($opts['version'])) || $RCI->legacy_config) {
+ $success = false;
+ $err = 0;
+
+ // list old/replaced config options
+ if (!empty($messages['replaced'])) {
+ echo "WARNING: Replaced config options:\n";
+ echo "(These config options have been replaced or renamed)\n";
+
+ foreach ($messages['replaced'] as $msg) {
+ echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n";
+ $err++;
+ }
+ }
+
+ // list obsolete config options (just a notice)
+ if (!empty($messages['obsolete'])) {
+ echo "NOTICE: Obsolete config options:\n";
+ echo "(You still have some obsolete or inexistent properties set."
+ . " This isn't a problem but should be noticed)\n";
+
+ foreach ($messages['obsolete'] as $msg) {
+ echo "- '" . $msg['prop'] . (!empty($msg['explain']) ? "': " . $msg['explain'] : "'") . "\n";
+ $err++;
+ }
+ }
+
+ if (!$err && $RCI->legacy_config) {
+ echo "WARNING: Your configuration needs to be migrated!\n";
+ echo "We changed the configuration files structure and your two config files "
+ . "main.inc.php and db.inc.php have to be merged into one single file.\n";
+ $err++;
+ }
+
+ // ask user to update config files
+ if ($err) {
+ if (empty($opts['accept'])) {
+ echo "Do you want me to fix your local configuration? (y/N)\n";
+ $input = trim(fgets(STDIN));
+ }
+
+ // positive: merge the local config with the defaults
+ if (!empty($opts['accept']) || strtolower($input) == 'y') {
+ $error = $written = false;
+
+ echo "- backing up the current config file(s)...\n";
+
+ foreach (['config', 'main', 'db'] as $file) {
+ if (file_exists(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php')) {
+ if (!copy(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php', RCMAIL_CONFIG_DIR . '/' . $file . '.old.php')) {
+ $error = true;
+ }
+ }
+ }
+
+ if (!$error) {
+ $RCI->merge_config();
+ echo "- writing " . RCMAIL_CONFIG_DIR . "/config.inc.php...\n";
+ $written = $RCI->save_configfile($RCI->create_config(false));
+ }
+
+ // Success!
+ if ($written) {
+ echo "Done.\n";
+ echo "Your configuration files are now up-to-date!\n";
+
+ if (!empty($messages['missing'])) {
+ echo "But you still need to add the following missing options:\n";
+ foreach ($messages['missing'] as $msg) {
+ echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n";
+ }
+ }
+
+ if ($RCI->legacy_config) {
+ foreach (['main', 'db'] as $file) {
+ @unlink(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php');
+ }
+ }
+ }
+ else {
+ echo "Failed to write config file(s)!\n";
+ echo "Grant write privileges to the current user or update the files manually "
+ . "according to the above messages.\n";
+ }
+ }
+ else {
+ echo "Please update your config files manually according to the above messages.\n";
+ }
+ }
+
+ // list of config options with changed default (just a notice)
+ if (!empty($messages['defaults'])) {
+ echo "WARNING: Changed defaults (These config options have new default values):\n";
+
+ foreach ($messages['defaults'] as $opt) {
+ echo "- '{$opt}'\n";
+ }
+ }
+
+ // check dependencies based on the current configuration
+ if (!empty($messages['dependencies'])) {
+ echo "WARNING: Dependency check failed!\n";
+ echo "(Some of your configuration settings require other options to be configured "
+ . "or additional PHP modules to be installed)\n";
+
+ foreach ($messages['dependencies'] as $msg) {
+ echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n";
+ }
+
+ echo "Please fix your config files and run this script again!\n";
+ echo "See ya.\n";
+ }
+ }
+
+ // check file type detection
+ if ($RCI->check_mime_detection()) {
+ echo "WARNING: File type detection doesn't work properly!\n";
+ echo "Please check the 'mime_magic' config option or the finfo functions of PHP and run this script again.\n";
+ }
+ if ($RCI->check_mime_extensions()) {
+ echo "WARNING: Mimetype to file extension mapping doesn't work properly!\n";
+ echo "Please check the 'mime_types' config option and run this script again.\n";
+ }
+
+ // check database schema
+ if (!empty($RCI->config['db_dsnw'])) {
+ echo "Executing database schema update.\n";
+ $success = rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $opts['version'], ['errors' => true]);
+ }
+
+ // update composer dependencies
+ if (is_file(INSTALL_PATH . 'composer.json') && is_readable(INSTALL_PATH . 'composer.json-dist')) {
+ $composer_data = json_decode(file_get_contents(INSTALL_PATH . 'composer.json'), true);
+ $composer_template = json_decode(file_get_contents(INSTALL_PATH . 'composer.json-dist'), true);
+ $composer_json = null;
+
+ // update the require section with the new dependencies
+ if (!empty($composer_data['require']) && !empty($composer_template['require'])) {
+ $composer_data['require'] = array_merge($composer_data['require'], $composer_template['require']);
+
+ // remove obsolete packages
+ $old_packages = [
+ 'pear-pear.php.net/net_socket',
+ 'pear-pear.php.net/auth_sasl',
+ 'pear-pear.php.net/net_idna2',
+ 'pear-pear.php.net/mail_mime',
+ 'pear-pear.php.net/net_smtp',
+ 'pear-pear.php.net/crypt_gpg',
+ 'pear-pear.php.net/net_sieve',
+ 'pear/mail_mime-decode',
+ 'roundcube/net_sieve',
+ 'endroid/qrcode',
+ 'endroid/qr-code',
+ ];
+
+ foreach ($old_packages as $pkg) {
+ if (array_key_exists($pkg, $composer_data['require'])) {
+ unset($composer_data['require'][$pkg]);
+ }
+ }
+ }
+
+ // update the repositories section with the new dependencies
+ if (!empty($composer_template['repositories'])) {
+ if (empty($composer_data['repositories'])) {
+ $composer_data['repositories'] = [];
+ }
+
+ foreach ($composer_template['repositories'] as $repo) {
+ $rkey = repo_key($repo);
+ $existing = false;
+
+ foreach ($composer_data['repositories'] as $k => $_repo) {
+ if ($rkey == repo_key($_repo)) {
+ // switch to https://
+ if (isset($_repo['url']) && strpos($_repo['url'], 'http://') === 0) {
+ $composer_data['repositories'][$k]['url'] = 'https:' . substr($_repo['url'], 5);
+ }
+
+ $existing = true;
+ break;
+ }
+
+ // remove old repos
+ if (isset($_repo['url']) && strpos($_repo['url'], 'git://git.kolab.org') === 0) {
+ unset($composer_data['repositories'][$k]);
+ }
+ else if (
+ $_repo['type'] == 'package'
+ && !empty($_repo['package']['name'])
+ && $_repo['package']['name'] == 'Net_SMTP'
+ ) {
+ unset($composer_data['repositories'][$k]);
+ }
+ }
+
+ if (!$existing) {
+ $composer_data['repositories'][] = $repo;
+ }
+ }
+
+ $composer_data['repositories'] = array_values($composer_data['repositories']);
+ }
+
+ $composer_json = json_encode($composer_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+
+ // write updated composer.json back to disk
+ if ($composer_json && is_writeable(INSTALL_PATH . 'composer.json')) {
+ $success &= (bool)file_put_contents(INSTALL_PATH . 'composer.json', $composer_json);
+ }
+ else {
+ echo "WARNING: unable to update composer.json!\n";
+ echo "Please replace the 'require' section in your composer.json with the following:\n";
+
+ $require_json = '';
+ foreach ($composer_data['require'] as $pkg => $ver) {
+ $require_json .= sprintf(' "%s": "%s",'."\n", $pkg, $ver);
+ }
+
+ echo ' "require": {'."\n";
+ echo rtrim($require_json, ",\n");
+ echo "\n }\n\n";
+ }
+
+ if (!rcmail_install::vendor_dir_untouched(INSTALL_PATH)) {
+ $exit_code = 1;
+ if ($composer_bin = find_composer()) {
+ echo "Executing " . $composer_bin . " to update dependencies...\n";
+ echo system("$composer_bin update -d " . escapeshellarg(INSTALL_PATH) . " --no-dev", $exit_code);
+ }
+ if ($exit_code != 0) {
+ echo "-----------------------------------------------------------------------------\n";
+ echo "ATTENTION: Update dependencies by running `php composer.phar update --no-dev`\n";
+ echo "-----------------------------------------------------------------------------\n";
+ }
+ }
+ }
+
+ // index contacts for fulltext searching
+ if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) {
+ rcmail_utils::indexcontacts();
+ }
+
+ if ($success) {
+ echo "This instance of Roundcube is up-to-date.\n";
+ echo "Have fun!\n";
+ }
+}
+else {
+ echo "This instance of Roundcube is not yet configured!\n";
+ echo "Open http://url-to-roundcube/installer/ in your browser and follow the instructions.\n";
+}
+
+function repo_key($repo)
+{
+ $key = $repo['type'];
+
+ if (!empty($repo['url'])) {
+ $key .= preg_replace('/^https?:/', '', $repo['url']);
+ }
+
+ if (!empty($repo['package']['name'])) {
+ $key .= $repo['package']['name'];
+ }
+
+ return $key;
+}
+
+function find_composer()
+{
+ if (is_file(INSTALL_PATH . 'composer.phar')) {
+ return 'php composer.phar';
+ }
+
+ foreach (['composer', 'composer.phar'] as $check_file) {
+ $which = trim(system("which $check_file"));
+ if (!empty($which)) {
+ return $which;
+ }
+ }
+
+ return null;
+}
diff --git a/ruty/mails/bin/updatecss.sh b/ruty/mails/bin/updatecss.sh
new file mode 100644
index 0000000..cac7201
--- /dev/null
+++ b/ruty/mails/bin/updatecss.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+// get arguments
+$opts = rcube_utils::get_opt(['d' => 'dir']);
+
+if (empty($opts['dir'])) {
+ print "Skin directory not specified (--dir). Using skins/ and plugins/*/skins/.\n";
+
+ $dir = INSTALL_PATH . 'skins';
+ $dir_p = INSTALL_PATH . 'plugins';
+ $skins = glob("$dir/*", GLOB_ONLYDIR);
+ $skins_p = glob("$dir_p/*/skins/*", GLOB_ONLYDIR);
+
+ $dirs = array_merge($skins, $skins_p);
+}
+// Check if directory exists
+else if (!file_exists($opts['dir'])) {
+ rcube::raise_error("Specified directory doesn't exist.", false, true);
+}
+else {
+ $dirs = [$opts['dir']];
+}
+
+foreach ($dirs as $dir) {
+ $img_dir = $dir . '/images';
+ if (!file_exists($img_dir)) {
+ continue;
+ }
+
+ $files = get_files($dir);
+ $images = get_images($img_dir);
+ $find = [];
+ $replace = [];
+
+ // build regexps array
+ foreach ($images as $path => $sum) {
+ $path_ex = str_replace('.', '\\.', $path);
+ $find[] = "#url\(['\"]?images/$path_ex(\?v=[a-f0-9-\.]+)?['\"]?\)#";
+ $replace[] = "url(images/$path?v=$sum)";
+ }
+
+ foreach ($files as $file) {
+ $file = $dir . '/' . $file;
+ print "File: $file\n";
+ $content = file_get_contents($file);
+ $content = preg_replace($find, $replace, $content, -1, $count);
+ if ($count) {
+ file_put_contents($file, $content);
+ }
+ }
+}
+
+
+function get_images($dir)
+{
+ $images = [];
+ $dh = opendir($dir);
+
+ while ($file = readdir($dh)) {
+ if (preg_match('/^(.+)\.(gif|ico|png|jpg|jpeg)$/', $file, $m)) {
+ $filepath = "$dir/$file";
+ $images[$file] = substr(md5_file($filepath), 0, 4) . '.' . filesize($filepath);
+ print "Image: $filepath ({$images[$file]})\n";
+ }
+ else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) {
+ foreach (get_images($dir . '/' . $file) as $img => $sum) {
+ $images[$file . '/' . $img] = $sum;
+ }
+ }
+ }
+
+ closedir($dh);
+
+ return $images;
+}
+
+function get_files($dir)
+{
+ $files = [];
+ $dh = opendir($dir);
+
+ while ($file = readdir($dh)) {
+ if (preg_match('/^(.+)\.(css|html)$/', $file, $m)) {
+ $files[] = $file;
+ }
+ else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) {
+ foreach (get_files($dir . '/' . $file) as $f) {
+ $files[] = $file . '/' . $f;
+ }
+ }
+ }
+
+ closedir($dh);
+
+ return $files;
+}
diff --git a/ruty/mails/bin/updatedb.sh b/ruty/mails/bin/updatedb.sh
new file mode 100644
index 0000000..133d4a4
--- /dev/null
+++ b/ruty/mails/bin/updatedb.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env php
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' );
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+// get arguments
+$opts = rcube_utils::get_opt([
+ 'v' => 'version',
+ 'd' => 'dir',
+ 'p' => 'package',
+]);
+
+if (empty($opts['dir'])) {
+ rcube::raise_error("Database schema directory not specified (--dir).", false, true);
+}
+if (empty($opts['package'])) {
+ rcube::raise_error("Database schema package name not specified (--package).", false, true);
+}
+
+rcmail_utils::db_update($opts['dir'], $opts['package'], $opts['version'] ?? null, ['errors' => true]);
diff --git a/ruty/mails/config/.htaccess b/ruty/mails/config/.htaccess
new file mode 100644
index 0000000..43e24ed
--- /dev/null
+++ b/ruty/mails/config/.htaccess
@@ -0,0 +1,7 @@
+# deny webserver access to this directory
+
+ Require all denied
+
+
+ Deny from all
+
diff --git a/ruty/mails/config/config.inc.php b/ruty/mails/config/config.inc.php
new file mode 100644
index 0000000..bf6db10
--- /dev/null
+++ b/ruty/mails/config/config.inc.php
@@ -0,0 +1,89 @@
+ 'r',
+// 'cache_index' => 'r',
+// 'cache_thread' => 'r',
+// 'cache_messages' => 'r',
+];
+
+// It is possible to specify database variable values e.g. some limits here.
+// Use them if your server is not MySQL or for better performance.
+// For example Roundcube uses max_allowed_packet value (in bytes)
+// which limits query size for database cache operations.
+$config['db_max_allowed_packet'] = null;
+
+
+// ----------------------------------
+// LOGGING/DEBUGGING
+// ----------------------------------
+
+// log driver: 'syslog', 'stdout' or 'file'.
+$config['log_driver'] = 'file';
+
+// date format for log entries
+// (read http://php.net/manual/en/function.date.php for all format characters)
+$config['log_date_format'] = 'd-M-Y H:i:s O';
+
+// length of the session ID to prepend each log line with
+// set to 0 to avoid session IDs being logged.
+$config['log_session_id'] = 8;
+
+// Default extension used for log file name
+$config['log_file_ext'] = '.log';
+
+// Syslog ident string to use, if using the 'syslog' log driver.
+$config['syslog_id'] = 'roundcube';
+
+// Syslog facility to use, if using the 'syslog' log driver.
+// For possible values see installer or http://php.net/manual/en/function.openlog.php
+$config['syslog_facility'] = LOG_USER;
+
+// Activate this option if logs should be written to per-user directories.
+// Data will only be logged if a directory // exists and is writable.
+$config['per_user_logging'] = false;
+
+// Log sent messages to /sendmail.log or to syslog
+$config['smtp_log'] = true;
+
+// Log successful/failed logins to /userlogins.log or to syslog
+$config['log_logins'] = false;
+
+// Log session debug information/authentication errors to /session.log or to syslog
+$config['session_debug'] = false;
+
+// Log SQL queries to /sql.log or to syslog
+$config['sql_debug'] = false;
+
+// Log IMAP conversation to /imap.log or to syslog
+$config['imap_debug'] = false;
+
+// Log LDAP conversation to /ldap.log or to syslog
+$config['ldap_debug'] = false;
+
+// Log SMTP conversation to /smtp.log or to syslog
+$config['smtp_debug'] = false;
+
+// Log Memcache conversation to /memcache.log or to syslog
+$config['memcache_debug'] = false;
+
+// Log APC conversation to /apc.log or to syslog
+$config['apc_debug'] = false;
+
+// Log Redis conversation to /redis.log or to syslog
+$config['redis_debug'] = false;
+
+
+// ----------------------------------
+// IMAP
+// ----------------------------------
+
+// The IMAP host (and optionally port number) chosen to perform the log-in.
+// Leave blank to show a textbox at login, give a list of hosts
+// to display a pulldown menu or set one host as string.
+// Enter hostname with prefix ssl:// to use Implicit TLS, or use
+// prefix tls:// to use STARTTLS.
+// If port number is omitted it will be set to 993 (for ssl://) or 143 otherwise.
+// Supported replacement variables:
+// %n - hostname ($_SERVER['SERVER_NAME'])
+// %t - hostname without the first part
+// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
+// %s - domain name after the '@' from e-mail address provided at login screen
+// For example %n = mail.domain.tld, %t = domain.tld
+// WARNING: After hostname change update of mail_host column in users table is
+// required to match old user data records with the new host.
+$config['imap_host'] = 'localhost:143';
+
+// IMAP authentication method (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null).
+// Use 'IMAP' to authenticate with IMAP LOGIN command.
+// By default the most secure method (from supported) will be selected.
+$config['imap_auth_type'] = null;
+
+// IMAP socket context options
+// See http://php.net/manual/en/context.ssl.php
+// The example below enables server certificate validation
+//$config['imap_conn_options'] = [
+// 'ssl' => [
+// 'verify_peer' => true,
+// 'verify_depth' => 3,
+// 'cafile' => '/etc/openssl/certs/ca.crt',
+// ],
+// ];
+// Note: These can be also specified as an array of options indexed by hostname
+$config['imap_conn_options'] = null;
+
+// IMAP connection timeout, in seconds. Default: 0 (use default_socket_timeout)
+$config['imap_timeout'] = 0;
+
+// Optional IMAP authentication identifier to be used as authorization proxy
+$config['imap_auth_cid'] = null;
+
+// Optional IMAP authentication password to be used for imap_auth_cid
+$config['imap_auth_pw'] = null;
+
+// If you know your imap's folder delimiter, you can specify it here.
+// Otherwise it will be determined automatically
+$config['imap_delimiter'] = null;
+
+// If you know your imap's folder vendor, you can specify it here.
+// Otherwise it will be determined automatically. Use lower-case
+// identifiers, e.g. 'dovecot', 'cyrus', 'gimap', 'hmail', 'uw-imap'.
+$config['imap_vendor'] = null;
+
+// If IMAP server doesn't support NAMESPACE extension, but you're
+// using shared folders or personal root folder is non-empty, you'll need to
+// set these options. All can be strings or arrays of strings.
+// Note: Folders need to be ended with directory separator, e.g. "INBOX."
+// (special directory "~" is an exception to this rule)
+// Note: These can be used also to overwrite server's namespaces
+// Note: Set these to FALSE to disable access to specified namespace
+$config['imap_ns_personal'] = null;
+$config['imap_ns_other'] = null;
+$config['imap_ns_shared'] = null;
+
+// By default IMAP capabilities are read after connection to IMAP server
+// In some cases, e.g. when using IMAP proxy, there's a need to refresh the list
+// after login. Set to True if you've got this case.
+$config['imap_force_caps'] = false;
+
+// By default list of subscribed folders is determined using LIST-EXTENDED
+// extension if available. Some servers (dovecot 1.x) returns wrong results
+// for shared namespaces in this case. https://github.com/roundcube/roundcubemail/issues/2474
+// Enable this option to force LSUB command usage instead.
+// Deprecated: Use imap_disabled_caps = ['LIST-EXTENDED']
+$config['imap_force_lsub'] = false;
+
+// Some server configurations (e.g. Courier) doesn't list folders in all namespaces
+// Enable this option to force listing of folders in all namespaces
+$config['imap_force_ns'] = false;
+
+// Some servers return hidden folders (name starting with a dot)
+// from user home directory. IMAP RFC does not forbid that.
+// Enable this option to hide them and disable possibility to create such.
+$config['imap_skip_hidden_folders'] = false;
+
+// Some servers do not support folders with both folders and messages inside
+// If your server supports that use true, if it does not, use false.
+// By default it will be determined automatically (once per user session).
+$config['imap_dual_use_folders'] = null;
+
+// List of disabled imap extensions.
+// Use if your IMAP server has broken implementation of some feature
+// and you can't remove it from CAPABILITY string on server-side.
+// For example UW-IMAP server has broken ESEARCH.
+// Note: Because the list is cached, re-login is required after change.
+$config['imap_disabled_caps'] = [];
+
+// Log IMAP session identifiers after each IMAP login.
+// This is used to relate IMAP session with Roundcube user sessions
+$config['imap_log_session'] = false;
+
+// Type of IMAP indexes cache. Supported values: 'db', 'apc' and 'memcache' or 'memcached'.
+$config['imap_cache'] = null;
+
+// Enables messages cache. Only 'db' cache is supported.
+// This requires an IMAP server that supports QRESYNC and CONDSTORE
+// extensions (RFC7162). See synchronize() in program/lib/Roundcube/rcube_imap_cache.php
+// for further info, or if you experience syncing problems.
+$config['messages_cache'] = false;
+
+// Lifetime of IMAP indexes cache. Possible units: s, m, h, d, w
+$config['imap_cache_ttl'] = '10d';
+
+// Lifetime of messages cache. Possible units: s, m, h, d, w
+$config['messages_cache_ttl'] = '10d';
+
+// Maximum cached message size in kilobytes.
+// Note: On MySQL this should be less than (max_allowed_packet - 30%)
+$config['messages_cache_threshold'] = 50;
+
+
+// ----------------------------------
+// SMTP
+// ----------------------------------
+
+// SMTP server host (and optional port number) for sending mails.
+// Enter hostname with prefix ssl:// to use Implicit TLS, or use
+// prefix tls:// to use STARTTLS.
+// If port number is omitted it will be set to 465 (for ssl://) or 587 otherwise.
+// Supported replacement variables:
+// %h - user's IMAP hostname
+// %n - hostname ($_SERVER['SERVER_NAME'])
+// %t - hostname without the first part
+// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
+// %z - IMAP domain (IMAP hostname without the first part)
+// For example %n = mail.domain.tld, %t = domain.tld
+// To specify different SMTP servers for different IMAP hosts provide an array
+// of IMAP host (no prefix or port) and SMTP server e.g. ['imap.example.com' => 'smtp.example.net']
+$config['smtp_host'] = 'localhost:587';
+
+// SMTP username (if required) if you use %u as the username Roundcube
+// will use the current username for login
+$config['smtp_user'] = '%u';
+
+// SMTP password (if required) if you use %p as the password Roundcube
+// will use the current user's password for login
+$config['smtp_pass'] = '%p';
+
+// SMTP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or empty to use
+// best server supported one)
+$config['smtp_auth_type'] = null;
+
+// Optional SMTP authentication identifier to be used as authorization proxy
+$config['smtp_auth_cid'] = null;
+
+// Optional SMTP authentication password to be used for smtp_auth_cid
+$config['smtp_auth_pw'] = null;
+
+// Pass the username (XCLIENT LOGIN) to the server
+$config['smtp_xclient_login'] = false;
+
+// Pass the remote IP (XCLIENT ADDR) to the server
+$config['smtp_xclient_addr'] = false;
+
+
+// SMTP HELO host
+// Hostname to give to the remote server for SMTP 'HELO' or 'EHLO' messages
+// Leave this blank and you will get the server variable 'server_name' or
+// localhost if that isn't defined.
+$config['smtp_helo_host'] = '';
+
+// SMTP connection timeout, in seconds. Default: 0 (use default_socket_timeout)
+// Note: There's a known issue where using ssl connection with
+// timeout > 0 causes connection errors (https://bugs.php.net/bug.php?id=54511)
+$config['smtp_timeout'] = 0;
+
+// SMTP socket context options
+// See http://php.net/manual/en/context.ssl.php
+// The example below enables server certificate validation, and
+// requires 'smtp_timeout' to be non zero.
+// $config['smtp_conn_options'] = [
+// 'ssl' => [
+// 'verify_peer' => true,
+// 'verify_depth' => 3,
+// 'cafile' => '/etc/openssl/certs/ca.crt',
+// ],
+// ];
+// Note: These can be also specified as an array of options indexed by hostname
+$config['smtp_conn_options'] = null;
+
+
+// ----------------------------------
+// OAuth
+// ----------------------------------
+
+// Enable OAuth2 by defining a provider. Use 'generic' here
+$config['oauth_provider'] = null;
+
+// Provider name to be displayed on the login button
+$config['oauth_provider_name'] = 'Google';
+
+// Mandatory: OAuth client ID for your Roundcube installation
+$config['oauth_client_id'] = null;
+
+// Mandatory: OAuth client secret
+$config['oauth_client_secret'] = null;
+
+// Mandatory: URI for OAuth user authentication (redirect)
+$config['oauth_auth_uri'] = null;
+
+// Mandatory: Endpoint for OAuth authentication requests (server-to-server)
+$config['oauth_token_uri'] = null;
+
+// Optional: Endpoint to query user identity if not provided in auth response
+$config['oauth_identity_uri'] = null;
+
+// Optional: disable SSL certificate check on HTTP requests to OAuth server
+// See http://docs.guzzlephp.org/en/stable/request-options.html#verify for possible values
+$config['oauth_verify_peer'] = true;
+
+// Mandatory: OAuth scopes to request (space-separated string)
+$config['oauth_scope'] = null;
+
+// Optional: additional query parameters to send with login request (hash array)
+$config['oauth_auth_parameters'] = [];
+
+// Optional: array of field names used to resolve the username within the identity information
+$config['oauth_identity_fields'] = null;
+
+// Boolean: automatically redirect to OAuth login when opening Roundcube without a valid session
+$config['oauth_login_redirect'] = false;
+
+///// Example config for Gmail
+
+// Register your service at https://console.developers.google.com/
+// - use https:///index.php/login/oauth as redirect URL
+
+// $config['default_host'] = 'ssl://imap.gmail.com';
+// $config['oauth_provider'] = 'google';
+// $config['oauth_provider_name'] = 'Google';
+// $config['oauth_client_id'] = "";
+// $config['oauth_client_secret'] = "";
+// $config['oauth_auth_uri'] = "https://accounts.google.com/o/oauth2/auth";
+// $config['oauth_token_uri'] = "https://oauth2.googleapis.com/token";
+// $config['oauth_identity_uri'] = 'https://www.googleapis.com/oauth2/v1/userinfo';
+// $config['oauth_scope'] = "email profile openid https://mail.google.com/";
+// $config['oauth_auth_parameters'] = ['access_type' => 'offline', 'prompt' => 'consent'];
+
+///// Example config for Outlook.com (Office 365)
+
+// Register your OAuth client at https://portal.azure.com
+// - use https:///index.php/login/oauth as redirect URL
+// - grant permissions to Microsoft Graph API "IMAP.AccessAsUser.All", "SMTP.Send", "User.Read" and "offline_access"
+
+// $config['imap_host'] = 'ssl://outlook.office365.com';
+// $config['smtp_host'] = 'ssl://smtp.office365.com';
+
+// $config['oauth_provider'] = 'outlook';
+// $config['oauth_provider_name'] = 'Outlook.com';
+// $config['oauth_client_id'] = "";
+// $config['oauth_client_secret'] = "";
+// $config['oauth_auth_uri'] = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
+// $config['oauth_token_uri'] = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
+// $config['oauth_identity_uri'] = "https://graph.microsoft.com/v1.0/me";
+// $config['oauth_identity_fields'] = ['email', 'userPrincipalName'];
+// $config['oauth_scope'] = "https://outlook.office365.com/IMAP.AccessAsUser.All https://outlook.office365.com/SMTP.Send User.Read offline_access";
+// $config['oauth_auth_parameters'] = ['nonce' => mt_rand()];
+
+// ----------------------------------
+// LDAP
+// ----------------------------------
+
+// Type of LDAP cache. Supported values: 'db', 'apc' and 'memcache' or 'memcached'.
+$config['ldap_cache'] = 'db';
+
+// Lifetime of LDAP cache. Possible units: s, m, h, d, w
+$config['ldap_cache_ttl'] = '10m';
+
+
+// ----------------------------------
+// CACHE(S)
+// ----------------------------------
+
+// Use these hosts for accessing memcached
+// Define any number of hosts in the form of hostname:port or unix:///path/to/socket.file
+// Example: ['localhost:11211', '192.168.1.12:11211', 'unix:///var/tmp/memcached.sock'];
+$config['memcache_hosts'] = null;
+
+// Controls the use of a persistent connections to memcache servers
+// See http://php.net/manual/en/memcache.addserver.php
+$config['memcache_pconnect'] = true;
+
+// Value in seconds which will be used for connecting to the daemon
+// See http://php.net/manual/en/memcache.addserver.php
+$config['memcache_timeout'] = 1;
+
+// Controls how often a failed server will be retried (value in seconds).
+// Setting this parameter to -1 disables automatic retry.
+// See http://php.net/manual/en/memcache.addserver.php
+$config['memcache_retry_interval'] = 15;
+
+// Use these hosts for accessing Redis.
+// Currently only one host is supported. Cluster support may come in a future release.
+// You can pass 4 fields, host, port (optional), database (optional) and password (optional).
+// Unset fields will be set to the default values host=127.0.0.1, port=6379.
+// Examples:
+// ['localhost:6379'];
+// ['192.168.1.1:6379:1:secret'];
+// ['unix:///var/run/redis/redis-server.sock:1:secret'];
+$config['redis_hosts'] = null;
+
+// Maximum size of an object in memcache (in bytes). Default: 2MB
+$config['memcache_max_allowed_packet'] = '2M';
+
+// Maximum size of an object in APC cache (in bytes). Default: 2MB
+$config['apc_max_allowed_packet'] = '2M';
+
+// Maximum size of an object in Redis cache (in bytes). Default: 2MB
+$config['redis_max_allowed_packet'] = '2M';
+
+
+// ----------------------------------
+// SYSTEM
+// ----------------------------------
+
+// THIS OPTION WILL ALLOW THE INSTALLER TO RUN AND CAN EXPOSE SENSITIVE CONFIG DATA.
+// ONLY ENABLE IT IF YOU'RE REALLY SURE WHAT YOU'RE DOING!
+$config['enable_installer'] = false;
+
+// don't allow these settings to be overridden by the user
+$config['dont_override'] = [];
+
+// List of disabled UI elements/actions
+$config['disabled_actions'] = [];
+
+// define which settings should be listed under the 'advanced' block
+// which is hidden by default
+$config['advanced_prefs'] = [];
+
+// provide an URL where a user can get support for this Roundcube installation
+// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
+$config['support_url'] = '';
+
+// Location of the blank (watermark) frame page. By default it is the watermark.html
+// file from the currently selected skin. Prepend name/path with a slash to use
+// current skin folder. Remove the slash to point to a file in the Roundcube
+// root directory. It can be also a full URL.
+$config['blankpage_url'] = '/watermark.html';
+
+// Logo image replacement. Specifies location of the image as:
+// - URL relative to the document root of this Roundcube installation
+// - full URL with http:// or https:// prefix
+// - URL relative to the current skin folder (when starts with a '/')
+//
+// An array can be used to specify different logos for specific template files
+// The array key specifies the place(s) the logo should be applied to and
+// is made up of (up to) 3 parts:
+// - skin name prefix (always with colon, can be replaced with *)
+// - template name (or * for all templates)
+// - logo type - it is used for logos used on multiple templates and the available types include:
+// '[favicon]' for favicon
+// '[print]' for logo on all print templates (e.g. messageprint, contactprint)
+// '[small]' for small screen logo in supported skins
+// '[dark]' and '[small-dark]' for dark mode logo in supported skins
+// '[link]' for adding a URL link to the logo image
+//
+// Example config for skin_logo
+/*
+ [
+ // show the image /images/logo_login_small.png for the Login screen in the Elastic skin on small screens
+ "elastic:login[small]" => "/images/logo_login_small.png",
+ // show the image /images/logo_login.png for the Login screen in the Elastic skin
+ "elastic:login" => "/images/logo_login.png",
+ // add a link to the logo on the Login screen in the Elastic skin
+ "elastic:login[link]" => "https://www.example.com",
+ // add a link to the logo on all screens in the Elastic skin
+ "elastic:*[link]" => "https://www.example.com",
+ // add a link to the logo on all screens for all skins
+ "[link]" => "https://www.example.com",
+ // show the image /images/logo_small.png in the Elastic skin
+ "elastic:*[small]" => "/images/logo_small.png",
+ // show the image /images/larry.png in the Larry skin
+ "larry:*" => "/images/larry.png",
+ // show the image /images/logo_login.png on the login template in all skins
+ "login" => "/images/logo_login.png",
+ // show the image /images/logo_print.png for all print type logos in all skins
+ "[print]" => "/images/logo_print.png",
+ ];
+*/
+$config['skin_logo'] = null;
+
+// Automatically register user in Roundcube database on successful (IMAP) logon.
+// Set to false if only registered users should be allowed to the webmail.
+// Note: If disabled you have to create records in Roundcube users table by yourself.
+// Note: Roundcube does not manage/create users on a mail server.
+$config['auto_create_user'] = true;
+
+// Enables possibility to log in using email address from user identities
+$config['user_aliases'] = false;
+
+// use this folder to store log files
+// must be writeable for the user who runs PHP process (Apache user if mod_php is being used)
+// This is used by the 'file' log driver.
+$config['log_dir'] = RCUBE_INSTALL_PATH . 'logs/';
+
+// Location of temporary saved files such as attachments and cache files
+// must be writeable for the user who runs PHP process (Apache user if mod_php is being used)
+$config['temp_dir'] = RCUBE_INSTALL_PATH . 'temp/';
+
+// expire files in temp_dir after 48 hours
+// possible units: s, m, h, d, w
+$config['temp_dir_ttl'] = '48h';
+
+// Enforce connections over https
+// With this option enabled, all non-secure connections will be redirected.
+// It can be also a port number, hostname or hostname:port if they are
+// different than default HTTP_HOST:443
+$config['force_https'] = false;
+
+// tell PHP that it should work as under secure connection
+// even if it doesn't recognize it as secure ($_SERVER['HTTPS'] is not set)
+// e.g. when you're running Roundcube behind a https proxy
+// this option is mutually exclusive to 'force_https' and only either one of them should be set to true.
+$config['use_https'] = false;
+
+// Allow browser-autocompletion on login form.
+// 0 - disabled, 1 - username and host only, 2 - username, host, password
+$config['login_autocomplete'] = 0;
+
+// Forces conversion of logins to lower case.
+// 0 - disabled, 1 - only domain part, 2 - domain and local part.
+// If users authentication is case-insensitive this must be enabled.
+// Note: After enabling it all user records need to be updated, e.g. with query:
+// UPDATE users SET username = LOWER(username);
+$config['login_lc'] = 2;
+
+// Maximum length (in bytes) of logon username and password.
+$config['login_username_maxlen'] = 1024;
+$config['login_password_maxlen'] = 1024;
+
+// Logon username filter. Regular expression for use with preg_match().
+// Use special value 'email' if you accept only full email addresses as user logins.
+// Example: '/^[a-z0-9_@.-]+$/'
+$config['login_username_filter'] = null;
+
+// Brute-force attacks prevention.
+// The value specifies maximum number of failed logon attempts per minute.
+$config['login_rate_limit'] = 3;
+
+// Includes should be interpreted as PHP files
+$config['skin_include_php'] = false;
+
+// display product name and software version on login screen
+// 0 - hide product name and version number, 1 - show product name only, 2 - show product name and version number
+$config['display_product_info'] = 1;
+
+// Session lifetime in minutes
+$config['session_lifetime'] = 30;
+
+// Session domain: .example.org
+$config['session_domain'] = '';
+
+// Session name. Default: 'roundcube_sessid'
+$config['session_name'] = null;
+
+// Session authentication cookie name. Default: 'roundcube_sessauth'
+$config['session_auth_name'] = null;
+
+// Session path. Defaults to PHP session.cookie_path setting.
+$config['session_path'] = null;
+
+// Session samesite. Defaults to PHP session.cookie_samesite setting.
+// Requires PHP >= 7.3.0, see https://wiki.php.net/rfc/same-site-cookie for more info
+// Possible values: null (default), 'Lax', or 'Strict'
+$config['session_samesite'] = null;
+
+// Backend to use for session storage. Can either be 'db' (default), 'redis', 'memcache', or 'php'
+//
+// If set to 'memcache' or 'memcached', a list of servers need to be specified in 'memcache_hosts'
+// Make sure the Memcache extension (https://pecl.php.net/package/memcache) version >= 2.0.0
+// or the Memcached extension (https://pecl.php.net/package/memcached) version >= 2.0.0 is installed.
+//
+// If set to 'redis', a server needs to be specified in 'redis_hosts'
+// Make sure the Redis extension (https://pecl.php.net/package/redis) version >= 2.0.0 is installed.
+//
+// Setting this value to 'php' will use the default session save handler configured in PHP
+$config['session_storage'] = 'db';
+
+// List of trusted proxies
+// X_FORWARDED_* and X_REAL_IP headers are only accepted from these IPs
+$config['proxy_whitelist'] = [];
+
+// List of trusted host names
+// Attackers can modify Host header of the HTTP request causing $_SERVER['SERVER_NAME']
+// or $_SERVER['HTTP_HOST'] variables pointing to a different host, that could be used
+// to collect user names and passwords. Some server configurations prevent that, but not all.
+// An empty list accepts any host name. The list can contain host names
+// or PCRE patterns (without // delimiters, that will be added automatically).
+$config['trusted_host_patterns'] = [];
+
+// check client IP in session authorization
+$config['ip_check'] = false;
+
+// X-Frame-Options HTTP header value sent to prevent from Clickjacking.
+// Possible values: sameorigin|deny|allow-from .
+// Set to false in order to disable sending the header.
+$config['x_frame_options'] = 'sameorigin';
+
+// This key is used for encrypting purposes, like storing of imap password
+// in the session. For historical reasons it's called DES_key, but it's used
+// with any configured cipher_method (see below).
+// For the default cipher_method a required key length is 24 characters.
+$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
+
+// Encryption algorithm. You can use any method supported by OpenSSL.
+// Default is set for backward compatibility to DES-EDE3-CBC,
+// but you can choose e.g. AES-256-CBC which we consider a better choice.
+$config['cipher_method'] = 'DES-EDE3-CBC';
+
+// Automatically add this domain to user names for login
+// Only for IMAP servers that require full e-mail addresses for login
+// Specify an array with 'host' => 'domain' values to support multiple hosts
+// Supported replacement variables:
+// %h - user's IMAP hostname
+// %n - hostname ($_SERVER['SERVER_NAME'])
+// %t - hostname without the first part
+// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
+// %z - IMAP domain (IMAP hostname without the first part)
+// For example %n = mail.domain.tld, %t = domain.tld
+$config['username_domain'] = '';
+
+// Force domain configured in username_domain to be used for login.
+// Any domain in username will be replaced by username_domain.
+$config['username_domain_forced'] = false;
+
+// This domain will be used to form e-mail addresses of new users
+// Specify an array with 'host' => 'domain' values to support multiple hosts
+// Supported replacement variables:
+// %h - user's IMAP hostname
+// %n - http hostname ($_SERVER['SERVER_NAME'])
+// %d - domain (http hostname without the first part)
+// %z - IMAP domain (IMAP hostname without the first part)
+// For example %n = mail.domain.tld, %t = domain.tld
+$config['mail_domain'] = '';
+
+// Password character set, to change the password for user
+// authentication or for password change operations
+$config['password_charset'] = 'UTF-8';
+
+// How many seconds must pass between emails sent by a user
+$config['sendmail_delay'] = 0;
+
+// Message size limit. Note that SMTP server(s) may use a different value.
+// This limit is verified when user attaches files to a composed message.
+// Size in bytes (possible unit suffix: K, M, G)
+$config['max_message_size'] = '100M';
+
+// Maximum number of recipients per message (including To, Cc, Bcc).
+// Default: 0 (no limit)
+$config['max_recipients'] = 0;
+
+// Maximum number of recipients per message excluding Bcc header.
+// This is a soft limit, which means we only display a warning to the user.
+// Default: 5
+$config['max_disclosed_recipients'] = 5;
+
+// Maximum allowed number of members of an address group. Default: 0 (no limit)
+// If 'max_recipients' is set this value should be less or equal
+$config['max_group_members'] = 0;
+
+// Name your service. This is displayed on the login screen and in the window title
+$config['product_name'] = 'Roundcube Webmail';
+
+// Add this user-agent to message headers when sending. Default: not set.
+$config['useragent'] = null;
+
+// try to load host-specific configuration
+// see https://github.com/roundcube/roundcubemail/wiki/Configuration:-Multi-Domain-Setup
+// for more details
+$config['include_host_config'] = false;
+
+// path to a text file which will be added to each sent message
+// paths are relative to the Roundcube root folder
+$config['generic_message_footer'] = '';
+
+// path to a text file which will be added to each sent HTML message
+// paths are relative to the Roundcube root folder
+$config['generic_message_footer_html'] = '';
+
+// add a received header to outgoing mails containing the creators IP and hostname
+$config['http_received_header'] = false;
+
+// Whether or not to encrypt the IP address and the host name
+// these could, in some circles, be considered as sensitive information;
+// however, for the administrator, these could be invaluable help
+// when tracking down issues.
+$config['http_received_header_encrypt'] = false;
+
+// number of chars allowed for line when wrapping text.
+// text wrapping is done when composing/sending messages
+$config['line_length'] = 72;
+
+// send plaintext messages as format=flowed
+$config['send_format_flowed'] = true;
+
+// According to RFC2298, return receipt envelope sender address must be empty.
+// If this option is true, Roundcube will use user's identity as envelope sender for MDN responses.
+$config['mdn_use_from'] = false;
+
+// Set identities access level:
+// 0 - many identities with possibility to edit all params
+// 1 - many identities with possibility to edit all params but not email address
+// 2 - one identity with possibility to edit all params
+// 3 - one identity with possibility to edit all params but not email address
+// 4 - one identity with possibility to edit only signature
+$config['identities_level'] = 0;
+
+// Maximum size of uploaded image (in kilobytes) for HTML identities.
+// Images (in html signatures) are stored in database as data URIs.
+$config['identity_image_size'] = 64;
+
+// Maximum size of uploaded image (in kilobytes) for HTML responses.
+// Images (in html responses) are stored in database as data URIs.
+$config['response_image_size'] = 64;
+
+// Mimetypes supported by the browser.
+// Attachments of these types will open in a preview window.
+// Either a comma-separated list or an array. Default list includes:
+// text/plain,text/html,
+// image/jpeg,image/gif,image/png,image/bmp,image/tiff,image/webp,
+// application/x-javascript,application/pdf,application/x-shockwave-flash
+$config['client_mimetypes'] = null;
+
+// Path to a local mime magic database file for PHPs finfo extension.
+// Set to null if the default path should be used.
+$config['mime_magic'] = null;
+
+// Absolute path to a local mime.types mapping table file.
+// This is used to derive mime-types from the filename extension or vice versa.
+// Such a file is usually part of the apache webserver. If you don't find a file named mime.types on your system,
+// download it from http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
+$config['mime_types'] = null;
+
+// path to imagemagick identify binary (if not set we'll use Imagick or GD extensions)
+$config['im_identify_path'] = null;
+
+// path to imagemagick convert binary (if not set we'll use Imagick or GD extensions)
+$config['im_convert_path'] = null;
+
+// Size of thumbnails from image attachments displayed below the message content.
+// Note: whether images are displayed at all depends on the 'inline_images' option.
+// Set to 0 to display images in full size.
+$config['image_thumbnail_size'] = 240;
+
+// maximum size of uploaded contact photos in pixel
+$config['contact_photo_size'] = 160;
+
+// Enable DNS checking for e-mail address validation
+$config['email_dns_check'] = false;
+
+// Disables saving sent messages in Sent folder (like gmail) (Default: false)
+// Note: useful when SMTP server stores sent mail in user mailbox
+$config['no_save_sent_messages'] = false;
+
+// Improve system security by using special URL with security token.
+// This can be set to a number defining token length. Default: 16.
+// Warning: This requires http server configuration. Sample:
+// RewriteRule ^/roundcubemail/[a-zA-Z0-9]{16}/(.*) /roundcubemail/$1 [PT]
+// Alias /roundcubemail /var/www/roundcubemail/
+// Warning: This feature does NOT work with request_path = 'SCRIPT_NAME'
+// Note: Use assets_path to not prevent the browser from caching assets
+$config['use_secure_urls'] = false;
+
+// Specifies the full path of the original HTTP request, either as a real path or
+// $_SERVER field name. This might be useful when Roundcube runs behind a reverse
+// proxy using a subpath. This is a path part of the URL, not the full URL!
+// The reverse proxy config can specify a custom header (e.g. X-Forwarded-Path) containing
+// the path under which Roundcube is exposed to the outside world (e.g. /rcube/).
+// This header value is then available in PHP with $_SERVER['HTTP_X_FORWARDED_PATH'].
+// By default the path comes from 'REDIRECT_SCRIPT_URL', 'SCRIPT_NAME' or 'REQUEST_URI',
+// whichever is set (in this order).
+$config['request_path'] = null;
+
+// Allows to define separate server/path for image/js/css files
+// Warning: If the domain is different cross-domain access to some
+// resources need to be allowed
+// Sample:
+//
+// Header set Access-Control-Allow-Origin "*"
+//
+$config['assets_path'] = '';
+
+// While assets_path is for the browser, assets_dir informs
+// PHP code about the location of asset files in filesystem
+$config['assets_dir'] = '';
+
+// Options passed when creating Guzzle HTTP client, used to fetch remote content
+// For example:
+// [
+// 'timeout' => 10,
+// 'proxy' => 'tcp://localhost:8125',
+// ]
+$config['http_client'] = [];
+
+// List of supported subject prefixes for a message reply
+// This list is used to clean the subject when replying or sorting messages
+$config['subject_reply_prefixes'] = ['Re:'];
+
+// List of supported subject prefixes for a message forward
+// This list is used to clean the subject when forwarding or sorting messages
+$config['subject_forward_prefixes'] = ['Fwd:', 'Fw:'];
+
+// Prefix to use in subject when replying to a message
+$config['response_prefix'] = 'Re:';
+
+// Prefix to use in subject when forwarding a message
+$config['forward_prefix'] = 'Fwd:';
+
+// ----------------------------------
+// PLUGINS
+// ----------------------------------
+
+// List of active plugins (in plugins/ directory)
+$config['plugins'] = [];
+
+// ----------------------------------
+// USER INTERFACE
+// ----------------------------------
+
+// default messages sort column. Use empty value for default server's sorting,
+// or 'arrival', 'date', 'subject', 'from', 'to', 'fromto', 'size', 'cc'
+$config['message_sort_col'] = '';
+
+// default messages sort order
+$config['message_sort_order'] = 'DESC';
+
+// These cols are shown in the message list. Available cols are:
+// subject, from, to, fromto, cc, replyto, date, size, status, flag, attachment, priority
+$config['list_cols'] = ['subject', 'status', 'fromto', 'date', 'size', 'flag', 'attachment'];
+
+// the default locale setting (leave empty for auto-detection)
+// RFC1766 formatted language name like en_US, de_DE, de_CH, fr_FR, pt_BR
+$config['language'] = null;
+
+// use this format for date display (PHP DateTime format)
+$config['date_format'] = 'Y-m-d';
+
+// give this choice of date formats to the user to select from
+// Note: do not use ambiguous formats like m/d/Y
+$config['date_formats'] = ['Y-m-d', 'Y/m/d', 'Y.m.d', 'd-m-Y', 'd/m/Y', 'd.m.Y', 'j.n.Y'];
+
+// use this format for time display (PHP DateTime format)
+$config['time_format'] = 'H:i';
+
+// give this choice of time formats to the user to select from
+$config['time_formats'] = ['G:i', 'H:i', 'g:i a', 'h:i A'];
+
+// use this format for short date display (derived from date_format and time_format)
+$config['date_short'] = 'D H:i';
+
+// use this format for detailed date/time formatting (derived from date_format and time_format)
+$config['date_long'] = 'Y-m-d H:i';
+
+// store draft message is this mailbox
+// leave blank if draft messages should not be stored
+// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
+$config['drafts_mbox'] = 'Drafts';
+
+// store spam messages in this mailbox
+// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
+$config['junk_mbox'] = 'Junk';
+
+// store sent message is this mailbox
+// leave blank if sent messages should not be stored
+// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
+$config['sent_mbox'] = 'Sent';
+
+// move messages to this folder when deleting them
+// leave blank if they should be deleted directly
+// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
+$config['trash_mbox'] = 'Trash';
+
+// automatically create the above listed default folders on user login
+$config['create_default_folders'] = false;
+
+// protect the default folders from renames, deletes, and subscription changes
+$config['protect_default_folders'] = true;
+
+// Disable localization of the default folder names listed above
+$config['show_real_foldernames'] = false;
+
+// if in your system 0 quota means no limit set this option to true
+$config['quota_zero_as_unlimited'] = false;
+
+// Make use of the built-in spell checker.
+$config['enable_spellcheck'] = false;
+
+// Enables spellchecker exceptions dictionary.
+// Setting it to 'shared' will make the dictionary shared by all users.
+$config['spellcheck_dictionary'] = false;
+
+// Set the spell checking engine. Possible values:
+// - 'googie' - the default (also used for connecting to Nox Spell Server, see 'spellcheck_uri' setting)
+// - 'pspell' - requires the PHP Pspell module and aspell installed
+// - 'enchant' - requires the PHP Enchant module
+// - 'atd' - install your own After the Deadline server or check with the people at http://www.afterthedeadline.com before using their API
+// Since Google shut down their public spell checking service, the default settings
+// connect to http://spell.roundcube.net which is a hosted service provided by Roundcube.
+// You can connect to any other googie-compliant service by setting 'spellcheck_uri' accordingly.
+$config['spellcheck_engine'] = 'googie';
+
+// For locally installed Nox Spell Server or After the Deadline services,
+// please specify the URI to call it.
+// Get Nox Spell Server from http://orangoo.com/labs/?page_id=72 or
+// the After the Deadline package from http://www.afterthedeadline.com.
+// Leave empty to use the public API of service.afterthedeadline.com
+$config['spellcheck_uri'] = '';
+
+// These languages can be selected for spell checking.
+// Configure as a PHP style hash array: ['en'=>'English', 'de'=>'Deutsch'];
+// Leave empty for default set of available language.
+$config['spellcheck_languages'] = null;
+
+// Makes that words with all letters capitalized will be ignored (e.g. GOOGLE)
+$config['spellcheck_ignore_caps'] = false;
+
+// Makes that words with numbers will be ignored (e.g. g00gle)
+$config['spellcheck_ignore_nums'] = false;
+
+// Makes that words with symbols will be ignored (e.g. g@@gle)
+$config['spellcheck_ignore_syms'] = false;
+
+// Number of lines at the end of a message considered to contain the signature.
+// Increase this value if signatures are not properly detected and colored
+$config['sig_max_lines'] = 15;
+
+// don't let users set pagesize to more than this value if set
+$config['max_pagesize'] = 200;
+
+// Minimal value of user's 'refresh_interval' setting (in seconds)
+$config['min_refresh_interval'] = 60;
+
+// Specifies for how many seconds the Undo button will be available
+// after object delete action. Currently used with supporting address book sources.
+// Setting it to 0, disables the feature.
+$config['undo_timeout'] = 0;
+
+// A static list of canned responses which are immutable for the user
+$config['compose_responses_static'] = [
+// ['name' => 'Canned Response 1', 'text' => 'Static Response One'],
+// ['name' => 'Canned Response 2', 'text' => 'Static Response Two'],
+];
+
+// List of HKP key servers for PGP public key lookups in Enigma/Mailvelope
+// Note: Lookup is client-side, so the server must support Cross-Origin Resource Sharing
+$config['keyservers'] = ['keys.openpgp.org'];
+
+// Enables use of the Main Keyring in Mailvelope? If disabled, a per-site keyring
+// will be used. This is set to false for backwards compatibility.
+$config['mailvelope_main_keyring'] = false;
+
+// Mailvelope RSA bit size for newly generated keys, either 2048 or 4096.
+// It maybe desirable to use 2048 for sites with many mobile users.
+$config['mailvelope_keysize'] = 4096;
+
+// Html2Text link handling options:
+// 0 - links will be removed
+// 1 - a list of link URLs should be listed at the end of the text (default)
+// 2 - link should be displayed to the original point in the text they appeared
+$config['html2text_links'] = 1;
+
+// Html2Text text width. Maximum width of the formatted text, in columns. Default: 75.
+$config['html2text_width'] = 75;
+
+// ----------------------------------
+// ADDRESSBOOK SETTINGS
+// ----------------------------------
+
+// This indicates which type of address book to use. Possible choices:
+// 'sql' - built-in sql addressbook enabled (default),
+// '' - built-in sql addressbook disabled.
+// Still LDAP or plugin-added addressbooks will be available.
+// BC Note: The value can actually be anything except 'sql', it does not matter.
+$config['address_book_type'] = 'sql';
+
+// In order to enable public ldap search, configure an array like the Verisign
+// example further below. if you would like to test, simply uncomment the example.
+// Array key must contain only safe characters, ie. a-zA-Z0-9_
+$config['ldap_public'] = [];
+
+// If you are going to use LDAP for individual address books, you will need to
+// set 'user_specific' to true and use the variables to generate the appropriate DNs to access it.
+//
+// The recommended directory structure for LDAP is to store all the address book entries
+// under the users main entry, e.g.:
+//
+// o=root
+// ou=people
+// uid=user@domain
+// mail=contact@contactdomain
+//
+// So the base_dn would be uid=%fu,ou=people,o=root
+// The bind_dn would be the same as based_dn or some super user login.
+/*
+ * example config for Verisign directory
+ *
+$config['ldap_public']['Verisign'] = [
+ 'name' => 'Verisign.com',
+ // Replacement variables supported in host names:
+ // %h - user's IMAP hostname
+ // %n - hostname ($_SERVER['SERVER_NAME'])
+ // %t - hostname without the first part
+ // %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
+ // %z - IMAP domain (IMAP hostname without the first part)
+ // For example %n = mail.domain.tld, %t = domain.tld
+ // Note: Host can also be a full URI e.g. ldaps://hostname.local:636 (for SSL)
+ // Note: If port number is omitted, it will be set to 636 (for ldaps://) or 389 otherwise.
+ // Note: To enable TLS use tls:// prefix
+ 'hosts' => array('directory.verisign.com:389'),
+ 'ldap_version' => 3, // using LDAPv3
+ 'network_timeout' => 10, // The timeout (in seconds) for connect + bind attempts. This is only supported in PHP >= 5.3.0 with OpenLDAP 2.x
+ 'user_specific' => false, // If true the base_dn, bind_dn and bind_pass default to the user's IMAP login.
+ // When 'user_specific' is enabled following variables can be used in base_dn/bind_dn config:
+ // %fu - The full username provided, assumes the username is an email
+ // address, uses the username_domain value if not an email address.
+ // %u - The username prior to the '@'.
+ // %d - The domain name after the '@'.
+ // %dc - The domain name hierarchal string e.g. "dc=test,dc=domain,dc=com"
+ // %dn - DN found by ldap search when search_filter/search_base_dn are used
+ 'base_dn' => '',
+ 'bind_dn' => '',
+ 'bind_pass' => '',
+ // It's possible to bind for an individual address book
+ // The login name is used to search for the DN to bind with
+ 'search_base_dn' => '',
+ 'search_filter' => '', // e.g. '(&(objectClass=posixAccount)(uid=%u))'
+ // DN and password to bind as before searching for bind DN, if anonymous search is not allowed
+ 'search_bind_dn' => '',
+ 'search_bind_pw' => '',
+ // Base DN and filter used for resolving the user's domain root DN which feeds the %dc variables
+ // Leave empty to skip this lookup and derive the root DN from the username domain
+ 'domain_base_dn' => '',
+ 'domain_filter' => '',
+ // Optional map of replacement strings => attributes used when binding for an individual address book
+ 'search_bind_attrib' => [], // e.g. ['%udc' => 'ou']
+ // Default for %dn variable if search doesn't return DN value
+ 'search_dn_default' => '',
+ // Optional authentication identifier to be used as SASL authorization proxy
+ // bind_dn need to be empty
+ 'auth_cid' => '',
+ // SASL authentication method (for proxy auth), e.g. DIGEST-MD5
+ 'auth_method' => '',
+ // Indicates if the addressbook shall be hidden from the list.
+ // With this option enabled you can still search/view contacts.
+ 'hidden' => false,
+ // Indicates if the addressbook shall not list contacts but only allows searching.
+ 'searchonly' => false,
+ // Indicates if we can write to the LDAP directory or not.
+ // If writable is true then these fields need to be populated:
+ // LDAP_Object_Classes, required_fields, LDAP_rdn
+ 'writable' => false,
+ // To create a new contact these are the object classes to specify
+ // (or any other classes you wish to use).
+ 'LDAP_Object_Classes' => ['top', 'inetOrgPerson'],
+ // The RDN field that is used for new entries, this field needs
+ // to be one of the search_fields, the base of base_dn is appended
+ // to the RDN to insert into the LDAP directory.
+ 'LDAP_rdn' => 'cn',
+ // The required attributes needed to build a new contact as required by
+ // the object classes (can include additional fields not required by the object classes).
+ 'required_fields' => ['cn', 'sn', 'mail'],
+ // The attributes used when searching with "All fields" option
+ // If empty, attributes for name, surname, firstname and email fields will be used
+ 'search_fields' => ['mail', 'cn'],
+ // mapping of contact fields to directory attributes
+ // 1. for every attribute one can specify the number of values (limit) allowed.
+ // default is 1, a wildcard * means unlimited
+ // 2. another possible parameter is separator character for composite fields
+ // 3. it's possible to define field format for write operations, e.g. for date fields
+ // example: 'birthday:date[YmdHis\\Z]'
+ 'fieldmap' => [
+ // Roundcube => LDAP:limit
+ 'name' => 'cn',
+ 'surname' => 'sn',
+ 'firstname' => 'givenName',
+ 'jobtitle' => 'title',
+ 'email' => 'mail:*',
+ 'phone:home' => 'homePhone',
+ 'phone:work' => 'telephoneNumber',
+ 'phone:mobile' => 'mobile',
+ 'phone:pager' => 'pager',
+ 'phone:workfax' => 'facsimileTelephoneNumber',
+ 'street' => 'street',
+ 'zipcode' => 'postalCode',
+ 'region' => 'st',
+ 'locality' => 'l',
+ // if you country is a complex object, you need to configure 'sub_fields' below
+ 'country' => 'c',
+ 'organization' => 'o',
+ 'department' => 'ou',
+ 'jobtitle' => 'title',
+ 'notes' => 'description',
+ 'photo' => 'jpegPhoto',
+ // these currently don't work:
+ // 'manager' => 'manager',
+ // 'assistant' => 'secretary',
+ ],
+ // Map of contact sub-objects (attribute name => objectClass(es)), e.g. 'c' => 'country'
+ 'sub_fields' => [],
+ // Generate values for the following LDAP attributes automatically when creating a new record
+ 'autovalues' => [
+ // 'uid' => 'md5(microtime())', // You may specify PHP code snippets which are then eval'ed
+ // 'mail' => '{givenname}.{sn}@mydomain.com', // or composite strings with placeholders for existing attributes
+ ],
+ 'sort' => 'cn', // The field to sort the listing by.
+ 'scope' => 'sub', // search mode: sub|base|list
+ 'filter' => '(objectClass=inetOrgPerson)', // used for basic listing (if not empty) and will be &'d with search queries. example: status=act
+ 'fuzzy_search' => true, // server allows wildcard search
+ 'vlv' => false, // Enable Virtual List View to more efficiently fetch paginated data (if server supports it)
+ 'vlv_search' => false, // Use Virtual List View functions for autocompletion searches (if server supports it)
+ 'numsub_filter' => '(objectClass=organizationalUnit)', // with VLV, we also use numSubOrdinates to query the total number of records. Set this filter to get all numSubOrdinates attributes for counting
+ 'config_root_dn' => 'cn=config', // Root DN to search config entries (e.g. vlv indexes)
+ 'sizelimit' => '0', // Enables you to limit the count of entries fetched. Setting this to 0 means no limit.
+ 'timelimit' => '0', // Sets the number of seconds how long is spend on the search. Setting this to 0 means no limit.
+ 'referrals' => false, // Sets the LDAP_OPT_REFERRALS option. Mostly used in multi-domain Active Directory setups
+ 'dereference' => 0, // Sets the LDAP_OPT_DEREF option. One of: LDAP_DEREF_NEVER, LDAP_DEREF_SEARCHING, LDAP_DEREF_FINDING, LDAP_DEREF_ALWAYS
+ // Used where addressbook contains aliases to objects elsewhere in the LDAP tree.
+
+ // definition for contact groups (uncomment if no groups are supported)
+ // for the groups base_dn, the user replacements %fu, %u, %d and %dc work as for base_dn (see above)
+ // if the groups base_dn is empty, the contact base_dn is used for the groups as well
+ // -> in this case, assure that groups and contacts are separated due to the concerning filters!
+ 'groups' => [
+ 'base_dn' => '',
+ 'scope' => 'sub', // Search mode: sub|base|list
+ 'filter' => '(objectClass=groupOfNames)',
+ 'object_classes' => ['top', 'groupOfNames'], // Object classes to be assigned to new groups
+ 'member_attr' => 'member', // Name of the default member attribute, e.g. uniqueMember
+ 'name_attr' => 'cn', // Attribute to be used as group name
+ 'email_attr' => 'mail', // Group email address attribute (e.g. for mailing lists)
+ 'member_filter' => '(objectclass=*)', // Optional filter to use when querying for group members
+ 'vlv' => false, // Use VLV controls to list groups
+ 'class_member_attr' => [ // Mapping of group object class to member attribute used in these objects
+ 'groupofnames' => 'member',
+ 'groupofuniquenames' => 'uniquemember'
+ ],
+ ],
+ // this configuration replaces the regular groups listing in the directory tree with
+ // a hard-coded list of groups, each listing entries with the configured base DN and filter.
+ // if the 'groups' option from above is set, it'll be shown as the first entry with the name 'Groups'
+ 'group_filters' => [
+ 'departments' => [
+ 'name' => 'Company Departments',
+ 'scope' => 'list',
+ 'base_dn' => 'ou=Groups,dc=mydomain,dc=com',
+ 'filter' => '(|(objectclass=groupofuniquenames)(objectclass=groupofurls))',
+ 'name_attr' => 'cn',
+ ],
+ 'customers' => [
+ 'name' => 'Customers',
+ 'scope' => 'sub',
+ 'base_dn' => 'ou=Customers,dc=mydomain,dc=com',
+ 'filter' => '(objectClass=inetOrgPerson)',
+ 'name_attr' => 'sn',
+ ],
+ ],
+];
+*/
+
+// An ordered array of the ids of the addressbooks that should be searched
+// when populating address autocomplete fields server-side. ex: ['sql','Verisign'];
+$config['autocomplete_addressbooks'] = ['sql'];
+
+// The minimum number of characters required to be typed in an autocomplete field
+// before address books will be searched. Most useful for LDAP directories that
+// may need to do lengthy results building given overly-broad searches
+$config['autocomplete_min_length'] = 1;
+
+// Number of parallel autocomplete requests.
+// If there's more than one address book, n parallel (async) requests will be created,
+// where each request will search in one address book. By default (0), all address
+// books are searched in one request.
+$config['autocomplete_threads'] = 0;
+
+// Max. number of entries in autocomplete popup. Default: 15.
+$config['autocomplete_max'] = 15;
+
+// show address fields in this order
+// available placeholders: {street}, {locality}, {zipcode}, {country}, {region}
+$config['address_template'] = '{street} {locality} {zipcode} {country} {region}';
+
+// Matching mode for addressbook search (including autocompletion)
+// 0 - partial (*abc*), default
+// 1 - strict (abc)
+// 2 - prefix (abc*)
+// Note: For LDAP sources fuzzy_search must be enabled to use 'partial' or 'prefix' mode
+$config['addressbook_search_mode'] = 0;
+
+// List of fields used on contacts list and for autocompletion searches
+// Warning: These are field names not LDAP attributes (see 'fieldmap' setting)!
+$config['contactlist_fields'] = ['name', 'firstname', 'surname', 'email'];
+
+// Template of contact entry on the autocompletion list.
+// You can use contact fields as: name, email, organization, department, etc.
+// See program/actions/contacts/index.php for a list
+$config['contact_search_name'] = '{name} <{email}>';
+
+// Contact mode. If your contacts are mostly business, switch it to 'business'.
+// This will prioritize form fields related to 'work' (instead of 'home').
+// Default: 'private'.
+$config['contact_form_mode'] = 'private';
+
+// The addressbook source to store automatically collected recipients in.
+// Default: true (the built-in "Collected recipients" addressbook, source id = '1')
+// Note: It can be set to any writeable addressbook, e.g. 'sql'
+$config['collected_recipients'] = true;
+
+// The addressbook source to store trusted senders in.
+// Default: true (the built-in "Trusted senders" addressbook, source id = '2')
+// Note: It can be set to any writeable addressbook, e.g. 'sql'
+$config['collected_senders'] = true;
+
+
+// ----------------------------------
+// USER PREFERENCES
+// ----------------------------------
+
+// Use this charset as fallback for message decoding
+$config['default_charset'] = 'ISO-8859-1';
+
+// Skin name: folder from skins/
+$config['skin'] = 'elastic';
+
+// Limit skins available for the user.
+// Note: When not empty, it should include the default skin set in 'skin' option.
+$config['skins_allowed'] = [];
+
+// Enables using standard browser windows (that can be handled as tabs)
+// instead of popup windows
+$config['standard_windows'] = false;
+
+// show up to X items in messages list view
+$config['mail_pagesize'] = 50;
+
+// show up to X items in contacts list view
+$config['addressbook_pagesize'] = 50;
+
+// sort contacts by this col (preferably either one of name, firstname, surname)
+$config['addressbook_sort_col'] = 'surname';
+
+// The way how contact names are displayed in the list.
+// 0: prefix firstname middlename surname suffix (only if display name is not set)
+// 1: firstname middlename surname
+// 2: surname firstname middlename
+// 3: surname, firstname middlename
+$config['addressbook_name_listing'] = 0;
+
+// use this timezone to display date/time
+// valid timezone identifiers are listed here: php.net/manual/en/timezones.php
+// 'auto' will use the browser's timezone settings
+$config['timezone'] = 'auto';
+
+// prefer displaying HTML messages
+$config['prefer_html'] = true;
+
+// Display remote resources (inline images, styles) in HTML messages. Default: 0.
+// 0 - Never, always ask
+// 1 - Allow from my contacts (all writeable addressbooks + collected senders and recipients)
+// 2 - Always allow
+// 3 - Allow from trusted senders only
+$config['show_images'] = 0;
+
+// open messages in new window
+$config['message_extwin'] = false;
+
+// open message compose form in new window
+$config['compose_extwin'] = false;
+
+// compose html formatted messages by default
+// 0 - never,
+// 1 - always,
+// 2 - on reply to HTML message,
+// 3 - on forward or reply to HTML message
+// 4 - always, except when replying to plain text message
+$config['htmleditor'] = 0;
+
+// save copies of compose messages in the browser's local storage
+// for recovery in case of browser crashes and session timeout.
+$config['compose_save_localstorage'] = true;
+
+// show pretty dates as standard
+$config['prettydate'] = true;
+
+// save compose message every 300 seconds (5min)
+$config['draft_autosave'] = 300;
+
+// Interface layout. Default: 'widescreen'.
+// 'widescreen' - three columns
+// 'desktop' - two columns, preview on bottom
+// 'list' - two columns, no preview
+$config['layout'] = 'widescreen';
+
+// Mark as read when viewing a message (delay in seconds)
+// Set to -1 if messages should not be marked as read
+$config['mail_read_time'] = 0;
+
+// Clear Trash on logout. Remove all messages or only older than N days.
+// Supported values: false, true, 30, 60, 90. Default: false.
+$config['logout_purge'] = false;
+
+// Compact INBOX on logout
+$config['logout_expunge'] = false;
+
+// Display attached images below the message body
+$config['inline_images'] = true;
+
+// Encoding of long/non-ascii attachment names:
+// 0 - Full RFC 2231 compatible
+// 1 - RFC 2047 for 'name' and RFC 2231 for 'filename' parameter (Thunderbird's default)
+// 2 - Full 2047 compatible
+$config['mime_param_folding'] = 1;
+
+// Set true if deleted messages should not be displayed
+// This will make the application run slower
+$config['skip_deleted'] = false;
+
+// Set true to Mark deleted messages as read as well as deleted
+// False means that a message's read status is not affected by marking it as deleted
+$config['read_when_deleted'] = true;
+
+// Set to true to never delete messages immediately
+// Use 'Purge' to remove messages marked as deleted
+$config['flag_for_deletion'] = false;
+
+// Default interval for auto-refresh requests (in seconds)
+// These are requests for system state updates e.g. checking for new messages, etc.
+// Setting it to 0 disables the feature.
+$config['refresh_interval'] = 60;
+
+// If true all folders will be checked for recent messages
+$config['check_all_folders'] = false;
+
+// If true, after message/contact delete/move, the next message/contact will be displayed
+$config['display_next'] = true;
+
+// Default messages listing mode. One of 'threads' or 'list'.
+$config['default_list_mode'] = 'list';
+
+// 0 - Do not expand threads
+// 1 - Expand all threads automatically
+// 2 - Expand only threads with unread messages
+$config['autoexpand_threads'] = 0;
+
+// When replying:
+// -1 - don't cite the original message
+// 0 - place cursor below the original message
+// 1 - place cursor above original message (top posting)
+// 2 - place cursor above original message (top posting), but do not indent the quote
+$config['reply_mode'] = 0;
+
+// When replying strip original signature from message
+$config['strip_existing_sig'] = true;
+
+// Show signature:
+// 0 - Never
+// 1 - Always
+// 2 - New messages only
+// 3 - Forwards and Replies only
+$config['show_sig'] = 1;
+
+// By default the signature is placed depending on cursor position (reply_mode).
+// Sometimes it might be convenient to start the reply on top but keep
+// the signature below the quoted text (sig_below = true).
+$config['sig_below'] = false;
+
+// Enables adding of standard separator to the signature
+$config['sig_separator'] = true;
+
+// Use MIME encoding (quoted-printable) for 8bit characters in message body
+$config['force_7bit'] = false;
+
+// Default fields configuration for mail search.
+// The array can contain a per-folder list of header fields which should be considered when searching
+// The entry with key '*' stands for all folders which do not have a specific list set.
+// Supported fields: subject, from, to, cc, bcc, replyto, followupto, body, text.
+// Please note that folder names should to be in sync with $config['*_mbox'] options
+$config['search_mods'] = null; // Example: ['*' => ['subject'=>1, 'from'=>1], 'Sent' => ['subject'=>1, 'to'=>1]];
+
+// Defaults of the addressbook search field configuration.
+$config['addressbook_search_mods'] = null; // Example: ['name'=>1, 'firstname'=>1, 'surname'=>1, 'email'=>1, '*'=>1];
+
+// Directly delete messages in Junk instead of moving to Trash
+$config['delete_junk'] = false;
+
+// Behavior if a received message requests a message delivery notification (read receipt)
+// 0 = ask the user,
+// 1 = send automatically,
+// 2 = ignore (never send or ask)
+// 3 = send automatically if sender is in my contacts, otherwise ask the user
+// 4 = send automatically if sender is in my contacts, otherwise ignore
+// 5 = send automatically if sender is a trusted sender, otherwise ask the user
+// 6 = send automatically if sender is a trusted sender, otherwise ignore
+$config['mdn_requests'] = 0;
+
+// Return receipt checkbox default state
+$config['mdn_default'] = 0;
+
+// Delivery Status Notification checkbox default state
+$config['dsn_default'] = 0;
+
+// Place replies in the folder of the message being replied to
+$config['reply_same_folder'] = false;
+
+// Sets default mode of Forward feature to "forward as attachment"
+$config['forward_attachment'] = false;
+
+// Defines address book (internal index) to which new contacts will be added
+// By default it is the first writeable addressbook.
+// Note: Use '0' for built-in address book.
+$config['default_addressbook'] = null;
+
+// Enables spell checking before sending a message.
+$config['spellcheck_before_send'] = false;
+
+// Skip alternative email addresses in autocompletion (show one address per contact)
+$config['autocomplete_single'] = false;
+
+// Default font for composed HTML message.
+// Supported values: Andale Mono, Arial, Arial Black, Book Antiqua, Courier New,
+// Georgia, Helvetica, Impact, Tahoma, Terminal, Times New Roman, Trebuchet MS, Verdana
+$config['default_font'] = 'Verdana';
+
+// Default font size for composed HTML message.
+// Supported sizes: 8pt, 10pt, 12pt, 14pt, 18pt, 24pt, 36pt
+$config['default_font_size'] = '10pt';
+
+// Enables display of email address with name instead of a name (and address in title)
+$config['message_show_email'] = false;
+
+// Default behavior of Reply-All button:
+// 0 - Reply-All always
+// 1 - Reply-List if mailing list is detected
+$config['reply_all_mode'] = 0;
diff --git a/ruty/mails/config/mimetypes.php b/ruty/mails/config/mimetypes.php
new file mode 100644
index 0000000..efb4698
--- /dev/null
+++ b/ruty/mails/config/mimetypes.php
@@ -0,0 +1,56 @@
+ 'application/vnd.ms-excel',
+ 'xlm' => 'application/vnd.ms-excel',
+ 'xla' => 'application/vnd.ms-excel',
+ 'xlc' => 'application/vnd.ms-excel',
+ 'xlt' => 'application/vnd.ms-excel',
+ 'xlw' => 'application/vnd.ms-excel',
+ 'pdf' => 'application/pdf',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pps' => 'application/vnd.ms-powerpoint',
+ 'pot' => 'application/vnd.ms-powerpoint',
+ 'doc' => 'application/msword',
+ 'dot' => 'application/msword',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'otf' => 'application/vnd.oasis.opendocument.formula-template',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'otm' => 'application/vnd.oasis.opendocument.text-master',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xps' => 'application/vnd.ms-xpsdocument',
+ 'rar' => 'application/x-rar-compressed',
+ '7z' => 'application/x-7z-compressed',
+ 's7z' => 'application/x-7z-compressed',
+ 'vcf' => 'text/vcard',
+ 'ics' => 'text/calendar',
+];
diff --git a/ruty/mails/installer/check.php b/ruty/mails/installer/check.php
new file mode 100644
index 0000000..e7c941d
--- /dev/null
+++ b/ruty/mails/installer/check.php
@@ -0,0 +1,290 @@
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+if (!class_exists('rcmail_install', false) || !isset($RCI)) {
+ die("Not allowed! Please open installer/index.php instead.");
+}
+
+$required_php_exts = [
+ 'PCRE' => 'pcre',
+ 'DOM' => 'dom',
+ 'Session' => 'session',
+ 'XML' => 'xml',
+ 'Intl' => 'intl',
+ 'JSON' => 'json',
+ 'PDO' => 'PDO',
+ 'Multibyte' => 'mbstring',
+ 'OpenSSL' => 'openssl',
+ 'Filter' => 'filter',
+ 'Ctype' => 'ctype',
+];
+
+$optional_php_exts = [
+ 'cURL' => 'curl',
+ 'FileInfo' => 'fileinfo',
+ 'Exif' => 'exif',
+ 'Iconv' => 'iconv',
+ 'LDAP' => 'ldap',
+ 'GD' => 'gd',
+ 'Imagick' => 'imagick',
+ 'XMLWriter' => 'xmlwriter',
+ 'Zip' => 'zip',
+];
+
+$required_libs = [
+ 'PEAR' => 'pear.php.net',
+ 'Auth_SASL' => 'pear.php.net',
+ 'Net_SMTP' => 'pear.php.net',
+ 'Mail_mime' => 'pear.php.net',
+ 'GuzzleHttp\Client' => 'github.com/guzzle/guzzle',
+];
+
+$optional_libs = [
+ 'Net_LDAP3' => 'git.kolab.org',
+];
+
+$ini_checks = [
+ 'file_uploads' => 1,
+ 'session.auto_start' => 0,
+ 'mbstring.func_overload' => 0,
+ 'suhosin.session.encrypt' => 0,
+];
+
+$optional_checks = [
+ 'date.timezone' => '-VALID-',
+];
+
+$source_urls = [
+ 'cURL' => 'https://www.php.net/manual/en/book.curl.php',
+ 'Sockets' => 'https://www.php.net/manual/en/book.sockets.php',
+ 'Session' => 'https://www.php.net/manual/en/book.session.php',
+ 'PCRE' => 'https://www.php.net/manual/en/book.pcre.php',
+ 'FileInfo' => 'https://www.php.net/manual/en/book.fileinfo.php',
+ 'Multibyte' => 'https://www.php.net/manual/en/book.mbstring.php',
+ 'OpenSSL' => 'https://www.php.net/manual/en/book.openssl.php',
+ 'JSON' => 'https://www.php.net/manual/en/book.json.php',
+ 'DOM' => 'https://www.php.net/manual/en/book.dom.php',
+ 'Iconv' => 'https://www.php.net/manual/en/book.iconv.php',
+ 'Intl' => 'https://www.php.net/manual/en/book.intl.php',
+ 'Exif' => 'https://www.php.net/manual/en/book.exif.php',
+ 'oci8' => 'https://www.php.net/manual/en/book.oci8.php',
+ 'PDO' => 'https://www.php.net/manual/en/book.pdo.php',
+ 'LDAP' => 'https://www.php.net/manual/en/book.ldap.php',
+ 'GD' => 'https://www.php.net/manual/en/book.image.php',
+ 'Imagick' => 'https://www.php.net/manual/en/book.imagick.php',
+ 'XML' => 'https://www.php.net/manual/en/book.xml.php',
+ 'XMLWriter' => 'https://www.php.net/manual/en/book.xmlwriter.php',
+ 'Zip' => 'https://www.php.net/manual/en/book.zip.php',
+ 'Filter' => 'https://www.php.net/manual/en/book.filter.php',
+ 'Ctype' => 'https://www.php.net/manual/en/book.ctype.php',
+ 'pdo_mysql' => 'https://www.php.net/manual/en/ref.pdo-mysql.php',
+ 'pdo_pgsql' => 'https://www.php.net/manual/en/ref.pdo-pgsql.php',
+ 'pdo_sqlite' => 'https://www.php.net/manual/en/ref.pdo-sqlite.php',
+ 'pdo_sqlite2' => 'https://www.php.net/manual/en/ref.pdo-sqlite.php',
+ 'pdo_sqlsrv' => 'https://www.php.net/manual/en/ref.pdo-sqlsrv.php',
+ 'pdo_dblib' => 'https://www.php.net/manual/en/ref.pdo-dblib.php',
+ 'PEAR' => 'https://pear.php.net',
+ 'Net_SMTP' => 'https://pear.php.net/package/Net_SMTP',
+ 'Mail_mime' => 'https://pear.php.net/package/Mail_mime',
+ 'Net_LDAP3' => 'https://git.kolab.org/diffusion/PNL',
+];
+
+?>
+
diff --git a/ruty/mails/installer/client.js b/ruty/mails/installer/client.js
new file mode 100644
index 0000000..e08ce22
--- /dev/null
+++ b/ruty/mails/installer/client.js
@@ -0,0 +1,48 @@
+/*
+ +-----------------------------------------------------------------------+
+ | Roundcube installer client function |
+ | |
+ | 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. |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli |
+ +-----------------------------------------------------------------------+
+*/
+
+function toggleblock(id, link)
+{
+ var block = document.getElementById(id);
+
+ return false;
+}
+
+
+function addhostfield()
+{
+ var container = document.getElementById('defaulthostlist');
+ var row = document.createElement('div');
+ var input = document.createElement('input');
+ var link = document.createElement('a');
+
+ input.name = '_imap_host[]';
+ input.size = '30';
+ link.href = '#';
+ link.onclick = function() { removehostfield(this.parentNode); return false };
+ link.className = 'removelink';
+ link.innerHTML = 'remove';
+
+ row.appendChild(input);
+ row.appendChild(link);
+ container.appendChild(row);
+}
+
+
+function removehostfield(row)
+{
+ var container = document.getElementById('defaulthostlist');
+ container.removeChild(row);
+}
diff --git a/ruty/mails/installer/config.php b/ruty/mails/installer/config.php
new file mode 100644
index 0000000..3deeac5
--- /dev/null
+++ b/ruty/mails/installer/config.php
@@ -0,0 +1,647 @@
+ |
+ +-----------------------------------------------------------------------+
+*/
+
+if (!class_exists('rcmail_install', false) || !isset($RCI)) {
+ die("Not allowed! Please open installer/index.php instead.");
+}
+
+// allow the current user to get to the next step
+$_SESSION['allowinstaller'] = true;
+
+if (!empty($_POST['submit'])) {
+ $_SESSION['config'] = $RCI->create_config();
+
+ if ($RCI->save_configfile($_SESSION['config'])) {
+ echo '
The config file was saved successfully into'
+ . ' '.RCMAIL_CONFIG_DIR.' directory of your Roundcube installation.';
+
+ if ($RCI->legacy_config) {
+ echo '
Afterwards, please remove the old configuration files'
+ . ' main.inc.php and db.inc.php from the config directory.';
+ }
+
+ echo '
Copy or download the following configuration and save it';
+ echo ' as config.inc.php within the '.RCUBE_CONFIG_DIR.' directory of your Roundcube installation. ';
+ echo ' Make sure that there are no characters before the <?php bracket when saving the file.';
+ echo ' ';
+ echo $save_button;
+
+ if ($RCI->legacy_config) {
+ echo '
Afterwards, please remove the old configuration files'
+ . ' main.inc.php and db.inc.php from the config directory.';
+ }
+
+ echo '