From e7620812b01f3eda31ccf21f9dc5b1f17ba6ce57 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sun, 12 Apr 2015 03:24:25 -0400
Subject: [PATCH] Installer: Remove system() function use (#1490139)

---
 CHANGELOG                          |    1 
 bin/indexcontacts.sh               |   27 --
 bin/update.sh                      |    8 
 bin/cleandb.sh                     |   49 ---
 program/include/rcmail_install.php |    8 
 bin/moduserprefs.sh                |   35 --
 program/include/rcmail_utils.php   |  362 ++++++++++++++++++++++++++++++
 bin/initdb.sh                      |   35 --
 bin/updatedb.sh                    |  138 -----------
 9 files changed, 375 insertions(+), 288 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 3096b6e..6c584fc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Installer: Remove system() function use (#1490139)
 - Password plugin: Added 'kpasswd' driver by Peter Allgeyer
 - Add initdb.sh to create database from initial.sql script with prefix support (#1490188)
 - Plugin API: Added message_part_body hook
diff --git a/bin/cleandb.sh b/bin/cleandb.sh
index d811c8d..0bf71ea 100755
--- a/bin/cleandb.sh
+++ b/bin/cleandb.sh
@@ -5,7 +5,7 @@
  | bin/cleandb.sh                                                        |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2010, The Roundcube Dev Team                            |
+ | Copyright (C) 2010-2015, The Roundcube Dev Team                       |
  |                                                                       |
  | Licensed under the GNU General Public License version 3 or            |
  | any later version with exceptions for skins & plugins.                |
@@ -23,56 +23,11 @@
 
 require INSTALL_PATH.'program/include/clisetup.php';
 
-// mapping for table name => primary key
-$primary_keys = array(
-    'contacts' => "contact_id",
-    'contactgroups' => "contactgroup_id",
-);
-
-// connect to DB
-$RCMAIL = rcube::get_instance();
-$db = $RCMAIL->get_dbh();
-$db->db_connect('w');
-
-if (!$db->is_connected() || $db->is_error()) {
-    rcube::raise_error("No DB connection", false, true);
-}
-
 if (!empty($_SERVER['argv'][1]))
     $days = intval($_SERVER['argv'][1]);
 else
     $days = 7;
 
-// remove all deleted records older than two days
-$threshold = date('Y-m-d 00:00:00', time() - $days * 86400);
-
-foreach (array('contacts','contactgroups','identities') as $table) {
-
-    $sqltable = $db->table_name($table, true);
-
-    // also delete linked records
-    // could be skipped for databases which respect foreign key constraints
-    if ($db->db_provider == 'sqlite'
-        && ($table == 'contacts' || $table == 'contactgroups')
-    ) {
-        $pk = $primary_keys[$table];
-        $memberstable = $db->table_name('contactgroupmembers');
-
-        $db->query(
-            "DELETE FROM " . $db->quote_identifier($memberstable).
-            " WHERE `$pk` IN (".
-                "SELECT `$pk` FROM $sqltable".
-                " WHERE `del` = 1 AND `changed` < ?".
-            ")",
-            $threshold);
-
-        echo $db->affected_rows() . " records deleted from '$memberstable'\n";
-    }
-
-    // delete outdated records
-    $db->query("DELETE FROM $sqltable WHERE `del` = 1 AND `changed` < ?", $threshold);
-
-    echo $db->affected_rows() . " records deleted from '$table'\n";
-}
+rcmail_utils::db_clean($days);
 
 ?>
diff --git a/bin/indexcontacts.sh b/bin/indexcontacts.sh
index 2844742..760e537 100755
--- a/bin/indexcontacts.sh
+++ b/bin/indexcontacts.sh
@@ -24,31 +24,6 @@
 require_once INSTALL_PATH.'program/include/clisetup.php';
 ini_set('memory_limit', -1);
 
-// connect to DB
-$RCMAIL = rcube::get_instance();
-
-$db = $RCMAIL->get_dbh();
-$db->db_connect('w');
-
-if (!$db->is_connected() || $db->is_error()) {
-    rcube::raise_error("No DB connection", false, true);
-}
-
-// iterate over all users
-$sql_result = $db->query("SELECT `user_id` FROM " . $db->table_name('users', true) . " ORDER BY `user_id`");
-while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
-    echo "Indexing contacts for user " . $sql_arr['user_id'] . "...";
-
-    $contacts = new rcube_contacts($db, $sql_arr['user_id']);
-    $contacts->set_pagesize(9999);
-
-    $result = $contacts->list_records();
-    while ($result->count && ($row = $result->next())) {
-        unset($row['words']);
-        $contacts->update($row['ID'], $row);
-    }
-
-    echo "done.\n";
-}
+rcmail_utils::indexcontacts();
 
 ?>
diff --git a/bin/initdb.sh b/bin/initdb.sh
index bf32448..fd22007 100755
--- a/bin/initdb.sh
+++ b/bin/initdb.sh
@@ -37,39 +37,6 @@
     rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
 }
 
-$RC = rcube::get_instance();
-$DB = rcube_db::factory($RC->config->get('db_dsnw'));
-
-$DB->set_debug((bool)$RC->config->get('sql_debug'));
-
-// Connect to database
-$DB->db_connect('w');
-if (!$DB->is_connected()) {
-    rcube::raise_error("Error connecting to database: " . $DB->is_error(), false, true);
-}
-
-$file = $opts['dir'] . '/' . $DB->db_provider . '.initial.sql';
-if (!file_exists($file)) {
-    rcube::raise_error("DDL file $file not found", false, true);
-}
-
-echo "Creating database schema... ";
-
-if ($sql = file_get_contents($file)) {
-    if (!$DB->exec_script($sql)) {
-        $error = $DB->is_error();
-    }
-}
-else {
-    $error = "Unable to read file $file or it is empty";
-}
-
-if ($error) {
-    echo "[FAILED]\n";
-    rcube::raise_error($error, false, true);
-}
-else {
-    echo "[OK]\n";
-}
+rcmail_utils::db_init($opts['dir']);
 
 ?>
diff --git a/bin/moduserprefs.sh b/bin/moduserprefs.sh
index 3d46baa..09f7398 100755
--- a/bin/moduserprefs.sh
+++ b/bin/moduserprefs.sh
@@ -5,7 +5,7 @@
  | bin/moduserprefs.sh                                                   |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2012, The Roundcube Dev Team                            |
+ | Copyright (C) 2012-2015, The Roundcube Dev Team                       |
  |                                                                       |
  | Licensed under the GNU General Public License version 3 or            |
  | any later version with exceptions for skins & plugins.                |
@@ -46,37 +46,6 @@
 $pref_name  = trim($args[0]);
 $pref_value = $args['delete'] ? null : trim($args[1]);
 
-// connect to DB
-$rcmail = rcube::get_instance();
-
-$db = $rcmail->get_dbh();
-$db->db_connect('w');
-
-if (!$db->is_connected() || $db->is_error())
-	die("No DB connection\n" . $db->is_error());
-
-$query = '1=1';
-
-if ($args['user'])
-	$query = '`user_id` = ' . intval($args['user']);
-
-// iterate over all users
-$sql_result = $db->query("SELECT * FROM " . $db->table_name('users', true) . " WHERE $query");
-while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
-	echo "Updating prefs for user " . $sql_arr['user_id'] . "...";
-
-	$user = new rcube_user($sql_arr['user_id'], $sql_arr);
-	$prefs = $old_prefs = $user->get_prefs();
-
-	$prefs[$pref_name] = $pref_value;
-
-	if ($prefs != $old_prefs) {
-		$user->save_prefs($prefs);
-		echo "saved.\n";
-	}
-	else {
-		echo "nothing changed.\n";
-	}
-}
+rcmail_utils::mod_pref($pref_name, $pref_value, $args['user']);
 
 ?>
diff --git a/bin/update.sh b/bin/update.sh
index 1dfaa96..bfb2148 100755
--- a/bin/update.sh
+++ b/bin/update.sh
@@ -156,10 +156,8 @@
   // check database schema
   if ($RCI->config['db_dsnw']) {
     echo "Executing database schema update.\n";
-    system("php " . INSTALL_PATH . "bin/updatedb.sh --package=roundcube --version=" . $opts['version']
-      . " --dir=" . INSTALL_PATH . "SQL", $res);
-
-    $success = !$res;
+    $success = rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $opts['version'],
+        array('errors' => true));
   }
 
   // update composer dependencies
@@ -239,7 +237,7 @@
 
   // index contacts for fulltext searching
   if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) {
-    system("php " . INSTALL_PATH . 'bin/indexcontacts.sh');
+    rcmail_utils::indexcontacts();
   }
 
   if ($success) {
diff --git a/bin/updatedb.sh b/bin/updatedb.sh
index ffeac0b..7e4f0f5 100755
--- a/bin/updatedb.sh
+++ b/bin/updatedb.sh
@@ -37,142 +37,6 @@
     rcube::raise_error("Database schema package name not specified (--package).", false, true);
 }
 
-// Check if directory exists
-if (!file_exists($opts['dir'])) {
-    rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
-}
-
-$RC = rcube::get_instance();
-$DB = rcube_db::factory($RC->config->get('db_dsnw'));
-
-$DB->set_debug((bool)$RC->config->get('sql_debug'));
-
-// Connect to database
-$DB->db_connect('w');
-if (!$DB->is_connected()) {
-    rcube::raise_error("Error connecting to database: " . $DB->is_error(), false, true);
-}
-
-// Read DB schema version from database (if 'system' table exists)
-if (in_array($DB->table_name('system'), (array)$DB->list_tables())) {
-    $DB->query("SELECT `value`"
-        ." FROM " . $DB->table_name('system', true)
-        ." WHERE `name` = ?",
-        $opts['package'] . '-version');
-
-    $row     = $DB->fetch_array();
-    $version = preg_replace('/[^0-9]/', '', $row[0]);
-}
-
-// DB version not found, but release version is specified
-if (!$version && $opts['version']) {
-    // Map old release version string to DB schema version
-    // Note: This is for backward compat. only, do not need to be updated
-    $map = array(
-        '0.1-stable' => 1,
-        '0.1.1'      => 2008030300,
-        '0.2-alpha'  => 2008040500,
-        '0.2-beta'   => 2008060900,
-        '0.2-stable' => 2008092100,
-        '0.2.1'      => 2008092100,
-        '0.2.2'      => 2008092100,
-        '0.3-stable' => 2008092100,
-        '0.3.1'      => 2009090400,
-        '0.4-beta'   => 2009103100,
-        '0.4'        => 2010042300,
-        '0.4.1'      => 2010042300,
-        '0.4.2'      => 2010042300,
-        '0.5-beta'   => 2010100600,
-        '0.5'        => 2010100600,
-        '0.5.1'      => 2010100600,
-        '0.5.2'      => 2010100600,
-        '0.5.3'      => 2010100600,
-        '0.5.4'      => 2010100600,
-        '0.6-beta'   => 2011011200,
-        '0.6'        => 2011011200,
-        '0.7-beta'   => 2011092800,
-        '0.7'        => 2011111600,
-        '0.7.1'      => 2011111600,
-        '0.7.2'      => 2011111600,
-        '0.7.3'      => 2011111600,
-        '0.7.4'      => 2011111600,
-        '0.8-beta'   => 2011121400,
-        '0.8-rc'     => 2011121400,
-        '0.8.0'      => 2011121400,
-        '0.8.1'      => 2011121400,
-        '0.8.2'      => 2011121400,
-        '0.8.3'      => 2011121400,
-        '0.8.4'      => 2011121400,
-        '0.8.5'      => 2011121400,
-        '0.8.6'      => 2011121400,
-        '0.9-beta'   => 2012080700,
-    );
-
-    $version = $map[$opts['version']];
-}
-
-// Assume last version before the 'system' table was added
-if (empty($version)) {
-    $version = 2012080700;
-}
-
-$dir = $opts['dir'] . '/' . $DB->db_provider;
-if (!file_exists($dir)) {
-    rcube::raise_error("DDL Upgrade files for " . $DB->db_provider . " driver not found.", false, true);
-}
-
-$dh     = opendir($dir);
-$result = array();
-
-while ($file = readdir($dh)) {
-    if (preg_match('/^([0-9]+)\.sql$/', $file, $m) && $m[1] > $version) {
-        $result[] = $m[1];
-    }
-}
-sort($result, SORT_NUMERIC);
-
-foreach ($result as $v) {
-    echo "Updating database schema ($v)... ";
-    $error = update_db_schema($opts['package'], $v, "$dir/$v.sql");
-
-    if ($error) {
-        echo "[FAILED]\n";
-        rcube::raise_error("Error in DDL upgrade $v: $error", false, true);
-    }
-    echo "[OK]\n";
-}
-
-
-function update_db_schema($package, $version, $file)
-{
-    global $DB;
-
-    // read DDL file
-    if ($sql = file_get_contents($file)) {
-        if (!$DB->exec_script($sql)) {
-            return $DB->is_error();
-        }
-    }
-
-    // escape if 'system' table does not exist
-    if ($version < 2013011000) {
-        return;
-    }
-
-    $system_table = $DB->table_name('system', true);
-
-    $DB->query("UPDATE " . $system_table
-        ." SET `value` = ?"
-        ." WHERE `name` = ?",
-        $version, $package . '-version');
-
-    if (!$DB->is_error() && !$DB->affected_rows()) {
-        $DB->query("INSERT INTO " . $system_table
-            ." (`name`, `value`) VALUES (?, ?)",
-            $package . '-version', $version);
-    }
-
-    return $DB->is_error();
-}
+rcmail_utils::db_update($opts['dir'], $opts['package'], $opts['version'], array('errors' => true));
 
 ?>
diff --git a/program/include/rcmail_install.php b/program/include/rcmail_install.php
index 0d5fbc5..e161779 100644
--- a/program/include/rcmail_install.php
+++ b/program/include/rcmail_install.php
@@ -773,12 +773,8 @@
    */
   function update_db($version)
   {
-    system(INSTALL_PATH . "bin/updatedb.sh --package=roundcube"
-      . " --version=" . escapeshellarg($version)
-      . " --dir=" . INSTALL_PATH . "SQL"
-      . " 2>&1", $result);
-
-    return !$result;
+    return rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $version,
+        array('quiet' => true));
   }
 
 
diff --git a/program/include/rcmail_utils.php b/program/include/rcmail_utils.php
new file mode 100644
index 0000000..50700b0
--- /dev/null
+++ b/program/include/rcmail_utils.php
@@ -0,0 +1,362 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcmail_utils.php                                      |
+ |                                                                       |
+ | This file is part of the Roundcube PHP suite                          |
+ | Copyright (C) 2005-2015 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.                     |
+ |                                                                       |
+ | CONTENTS:                                                             |
+ |   Roundcube utilities                                                 |
+ |                                                                       |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com>                        |
+ | Author: Aleksander Machniak <alec@alec.pl>                            |
+ +-----------------------------------------------------------------------+
+*/
+
+/**
+ * Roundcube utilities
+ *
+ * @package Webmail
+ * @subpackage Utils
+ */
+class rcmail_utils
+{
+    public static $db;
+
+    /**
+     * Initialize database object and connect
+     *
+     * @return rcube_db Database instance
+     */
+    public static function db()
+    {
+        if (self::$db === null) {
+            $rc = rcube::get_instance();
+            $db = rcube_db::factory($rc->config->get('db_dsnw'));
+
+            $db->set_debug((bool)$rc->config->get('sql_debug'));
+
+            // Connect to database
+            $db->db_connect('w');
+
+            if (!$db->is_connected()) {
+                rcube::raise_error("Error connecting to database: " . $db->is_error(), false, true);
+            }
+
+            self::$db = $db;
+        }
+
+        return self::$db;
+    }
+
+    /**
+     * Initialize database schema
+     *
+     * @param string Directory with sql files
+     */
+    public static function db_init($dir)
+    {
+        $db = self::db();
+
+        $file = $dir . '/' . $db->db_provider . '.initial.sql';
+        if (!file_exists($file)) {
+            rcube::raise_error("DDL file $file not found", false, true);
+        }
+
+        echo "Creating database schema... ";
+
+        if ($sql = file_get_contents($file)) {
+            if (!$db->exec_script($sql)) {
+                $error = $db->is_error();
+            }
+        }
+        else {
+            $error = "Unable to read file $file or it is empty";
+        }
+
+        if ($error) {
+            echo "[FAILED]\n";
+            rcube::raise_error($error, false, true);
+        }
+        else {
+            echo "[OK]\n";
+        }
+    }
+
+    /**
+     * Update database schema
+     *
+     * @param string Directory with sql files
+     * @param string Component name
+     * @param string Optional current version number
+     * @param array  Parameters (errors, quiet)
+     *
+     * @return True on success, False on failure
+     */
+    public static function db_update($dir, $package, $ver = null, $opts = array())
+    {
+        // Check if directory exists
+        if (!file_exists($dir)) {
+            if ($opts['errors']) {
+                rcube::raise_error("Specified database schema directory doesn't exist.", false, true);
+            }
+            return false;
+        }
+
+        $db = self::db();
+
+        // Read DB schema version from database (if 'system' table exists)
+        if (in_array($db->table_name('system'), (array)$db->list_tables())) {
+            $db->query("SELECT `value`"
+                . " FROM " . $db->table_name('system', true)
+                . " WHERE `name` = ?",
+                $package . '-version');
+
+            $row     = $db->fetch_array();
+            $version = preg_replace('/[^0-9]/', '', $row[0]);
+        }
+
+        // DB version not found, but release version is specified
+        if (!$version && $ver) {
+            // Map old release version string to DB schema version
+            // Note: This is for backward compat. only, do not need to be updated
+            $map = array(
+                '0.1-stable' => 1,
+                '0.1.1'      => 2008030300,
+                '0.2-alpha'  => 2008040500,
+                '0.2-beta'   => 2008060900,
+                '0.2-stable' => 2008092100,
+                '0.2.1'      => 2008092100,
+                '0.2.2'      => 2008092100,
+                '0.3-stable' => 2008092100,
+                '0.3.1'      => 2009090400,
+                '0.4-beta'   => 2009103100,
+                '0.4'        => 2010042300,
+                '0.4.1'      => 2010042300,
+                '0.4.2'      => 2010042300,
+                '0.5-beta'   => 2010100600,
+                '0.5'        => 2010100600,
+                '0.5.1'      => 2010100600,
+                '0.5.2'      => 2010100600,
+                '0.5.3'      => 2010100600,
+                '0.5.4'      => 2010100600,
+                '0.6-beta'   => 2011011200,
+                '0.6'        => 2011011200,
+                '0.7-beta'   => 2011092800,
+                '0.7'        => 2011111600,
+                '0.7.1'      => 2011111600,
+                '0.7.2'      => 2011111600,
+                '0.7.3'      => 2011111600,
+                '0.7.4'      => 2011111600,
+                '0.8-beta'   => 2011121400,
+                '0.8-rc'     => 2011121400,
+                '0.8.0'      => 2011121400,
+                '0.8.1'      => 2011121400,
+                '0.8.2'      => 2011121400,
+                '0.8.3'      => 2011121400,
+                '0.8.4'      => 2011121400,
+                '0.8.5'      => 2011121400,
+                '0.8.6'      => 2011121400,
+                '0.9-beta'   => 2012080700,
+            );
+
+            $version = $map[$ver];
+        }
+
+        // Assume last version before the 'system' table was added
+        if (empty($version)) {
+            $version = 2012080700;
+        }
+
+        $dir .= '/' . $db->db_provider;
+        if (!file_exists($dir)) {
+            if ($opts['errors']) {
+                rcube::raise_error("DDL Upgrade files for " . $db->db_provider . " driver not found.", false, true);
+            }
+            return false;
+        }
+
+        $dh     = opendir($dir);
+        $result = array();
+
+        while ($file = readdir($dh)) {
+            if (preg_match('/^([0-9]+)\.sql$/', $file, $m) && $m[1] > $version) {
+                $result[] = $m[1];
+            }
+        }
+        sort($result, SORT_NUMERIC);
+
+        foreach ($result as $v) {
+            if (!$opts['quiet']) {
+                echo "Updating database schema ($v)... ";
+            }
+
+            $error = self::db_update_schema($package, $v, "$dir/$v.sql");
+
+            if ($error) {
+                if (!$opts['quiet']) {
+                    echo "[FAILED]\n";
+                }
+                if ($opts['errors']) {
+                    rcube::raise_error("Error in DDL upgrade $v: $error", false, true);
+                }
+                return false;
+            }
+            else if (!$opts['quiet']) {
+                echo "[OK]\n";
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Run database update from a single sql file
+     */
+    protected static function db_update_schema($package, $version, $file)
+    {
+        $db = self::db();
+
+        // read DDL file
+        if ($sql = file_get_contents($file)) {
+            if (!$db->exec_script($sql)) {
+                return $db->is_error();
+            }
+        }
+
+        // escape if 'system' table does not exist
+        if ($version < 2013011000) {
+            return;
+        }
+
+        $system_table = $db->table_name('system', true);
+
+        $db->query("UPDATE " . $system_table
+            . " SET `value` = ?"
+            . " WHERE `name` = ?",
+            $version, $package . '-version');
+
+        if (!$db->is_error() && !$db->affected_rows()) {
+            $db->query("INSERT INTO " . $system_table
+                ." (`name`, `value`) VALUES (?, ?)",
+                $package . '-version', $version);
+        }
+
+        return $db->is_error();
+    }
+
+    /**
+     * Removes all deleted records older than X days
+     *
+     * @param int Number of days
+     */
+    public static function db_clean($days)
+    {
+        // mapping for table name => primary key
+        $primary_keys = array(
+            'contacts'      => 'contact_id',
+            'contactgroups' => 'contactgroup_id',
+        );
+
+        $db = self::db();
+
+        $threshold = date('Y-m-d 00:00:00', time() - $days * 86400);
+
+        foreach (array('contacts','contactgroups','identities') as $table) {
+            $sqltable = $db->table_name($table, true);
+
+            // also delete linked records
+            // could be skipped for databases which respect foreign key constraints
+            if ($db->db_provider == 'sqlite' && ($table == 'contacts' || $table == 'contactgroups')) {
+                $pk           = $primary_keys[$table];
+                $memberstable = $db->table_name('contactgroupmembers');
+
+                $db->query(
+                    "DELETE FROM " . $db->quote_identifier($memberstable)
+                    . " WHERE `$pk` IN ("
+                        . "SELECT `$pk` FROM $sqltable"
+                        . " WHERE `del` = 1 AND `changed` < ?"
+                    . ")",
+                    $threshold);
+
+                echo $db->affected_rows() . " records deleted from '$memberstable'\n";
+            }
+
+            // delete outdated records
+            $db->query("DELETE FROM $sqltable WHERE `del` = 1 AND `changed` < ?", $threshold);
+
+            echo $db->affected_rows() . " records deleted from '$table'\n";
+        }
+    }
+
+    /**
+     * Reindex contacts
+     */
+    public static function indexcontacts()
+    {
+        $db = self::db();
+
+        // iterate over all users
+        $sql_result = $db->query("SELECT `user_id` FROM " . $db->table_name('users', true) . " ORDER BY `user_id`");
+        while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
+            echo "Indexing contacts for user " . $sql_arr['user_id'] . "...\n";
+
+            $contacts = new rcube_contacts($db, $sql_arr['user_id']);
+            $contacts->set_pagesize(9999);
+
+            $result = $contacts->list_records();
+            while ($result->count && ($row = $result->next())) {
+                unset($row['words']);
+                $contacts->update($row['ID'], $row);
+            }
+        }
+
+        echo "done.\n";
+    }
+
+    /**
+     * Modify user preferences
+     *
+     * @param string Option name
+     * @param string Option value
+     * @param int    Optional user identifier
+     */
+    public static function mod_pref($name, $value, $userid = null)
+    {
+        $db = self::db();
+
+        if ($userid) {
+            $query = '`user_id` = ' . intval($userid);
+        }
+        else {
+            $query = '1=1';
+        }
+
+        // iterate over all users
+        $sql_result = $db->query("SELECT * FROM " . $db->table_name('users', true) . " WHERE $query");
+
+        while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
+            echo "Updating prefs for user " . $sql_arr['user_id'] . "...";
+
+            $user  = new rcube_user($sql_arr['user_id'], $sql_arr);
+            $prefs = $old_prefs = $user->get_prefs();
+
+            $prefs[$name] = $value;
+
+            if ($prefs != $old_prefs) {
+                $user->save_prefs($prefs);
+                echo "saved.\n";
+            }
+            else {
+                echo "nothing changed.\n";
+            }
+        }
+    }
+}

--
Gitblit v1.9.1