From c321a955a7b0f6d6b13ffaebf040a6c7091037ae Mon Sep 17 00:00:00 2001 From: thomascube <thomas@roundcube.net> Date: Mon, 16 Jan 2012 10:14:41 -0500 Subject: [PATCH] Merged devel-framework branch (r5746:5779) back into trunk --- program/include/rcmail.php | 537 ++++++++++++++++++++++++++++++++++++----------------------- 1 files changed, 327 insertions(+), 210 deletions(-) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index fe2d994..7c01edf 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -6,6 +6,7 @@ | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2011, Kolab Systems AG | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -85,11 +86,11 @@ public $smtp; /** - * Instance of rcube_imap class. + * Instance of rcube_storage class. * - * @var rcube_imap + * @var rcube_storage */ - public $imap; + public $storage; /** * Instance of rcube_template class. @@ -124,6 +125,7 @@ private $address_books = array(); private $caches = array(); private $action_map = array(); + private $shutdown_functions = array(); /** @@ -157,8 +159,6 @@ /** * Initial startup function * to register session, create database and imap connections - * - * @todo Remove global vars $DB, $USER */ private function startup() { @@ -170,7 +170,7 @@ } // connect to database - $GLOBALS['DB'] = $this->get_dbh(); + $this->get_dbh(); // start session $this->session_init(); @@ -238,7 +238,6 @@ { if (is_object($user)) { $this->user = $user; - $GLOBALS['USER'] = $this->user; // overwrite config with user preferences $this->config->set_user_prefs((array)$this->user->get_prefs()); @@ -318,8 +317,8 @@ return $this->db; } - - + + /** * Get global handle for memcache access * @@ -335,20 +334,41 @@ } $this->memcache = new Memcache; - $mc_available = 0; + $this->mc_available = 0; + + // add alll configured hosts to pool + $pconnect = $this->config->get('memcache_pconnect', true); foreach ($this->config->get('memcache_hosts', array()) as $host) { list($host, $port) = explode(':', $host); if (!$port) $port = 11211; - // add server and attempt to connect if not already done yet - if ($this->memcache->addServer($host, $port) && !$mc_available) - $mc_available += intval($this->memcache->connect($host, $port)); + $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure'))); } + + // test connection and failover (will result in $this->mc_available == 0 on complete failure) + $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist - if (!$mc_available) + if (!$this->mc_available) $this->memcache = false; } return $this->memcache; + } + + /** + * Callback for memcache failure + */ + public function memcache_failure($host, $port) + { + static $seen = array(); + + // only report once + if (!$seen["$host:$port"]++) { + $this->mc_available--; + raise_error(array('code' => 604, 'type' => 'db', + 'line' => __LINE__, 'file' => __FILE__, + 'message' => "Memcache failure on host $host:$port"), + true, false); + } } @@ -377,6 +397,7 @@ * * @param string Address book identifier * @param boolean True if the address book needs to be writeable + * * @return rcube_contacts Address book object */ public function get_address_book($id, $writeable = false) @@ -385,12 +406,19 @@ $ldap_config = (array)$this->config->get('ldap_public'); $abook_type = strtolower($this->config->get('address_book_type')); + // 'sql' is the alias for '0' used by autocomplete + if ($id == 'sql') + $id = '0'; + // use existing instance - if (isset($this->address_books[$id]) && is_a($this->address_books[$id], 'rcube_addressbook') && (!$writeable || !$this->address_books[$id]->readonly)) { + if (isset($this->address_books[$id]) && is_object($this->address_books[$id]) + && is_a($this->address_books[$id], 'rcube_addressbook') + && (!$writeable || !$this->address_books[$id]->readonly) + ) { $contacts = $this->address_books[$id]; } else if ($id && $ldap_config[$id]) { - $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); + $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['storage_host'])); } else if ($id === '0') { $contacts = new rcube_contacts($this->db, $this->user->ID); @@ -402,23 +430,27 @@ if ($plugin['instance'] instanceof rcube_addressbook) { $contacts = $plugin['instance']; } - else if ($abook_type == 'ldap') { - // Use the first writable LDAP address book. - foreach ($ldap_config as $id => $prop) { - if (!$writeable || $prop['writable']) { - $contacts = new rcube_ldap($prop, $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); - break; - } + // get first source from the list + else if (!$id) { + $source = reset($this->get_address_sources($writeable)); + if (!empty($source)) { + $contacts = $this->get_address_book($source['id']); + if ($contacts) + $id = $source['id']; } - } - else { // $id == 'sql' - $contacts = new rcube_contacts($this->db, $this->user->ID); } } + if (!$contacts) { + raise_error(array( + 'code' => 700, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Addressbook source ($id) not found!"), + true, true); + } + // add to the 'books' array for shutdown function - if (!isset($this->address_books[$id])) - $this->address_books[$id] = $contacts; + $this->address_books[$id] = $contacts; return $contacts; } @@ -428,6 +460,7 @@ * Return address books list * * @param boolean True if the address book needs to be writeable + * * @return array Address books array */ public function get_address_sources($writeable = false) @@ -442,11 +475,12 @@ if (!isset($this->address_books['0'])) $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID); $list['0'] = array( - 'id' => '0', - 'name' => rcube_label('personaladrbook'), - 'groups' => $this->address_books['0']->groups, + 'id' => '0', + 'name' => rcube_label('personaladrbook'), + 'groups' => $this->address_books['0']->groups, 'readonly' => $this->address_books['0']->readonly, - 'autocomplete' => in_array('sql', $autocomplete) + 'autocomplete' => in_array('sql', $autocomplete), + 'undelete' => $this->address_books['0']->undelete && $this->config->get('undo_timeout'), ); } @@ -454,11 +488,12 @@ $ldap_config = (array) $ldap_config; foreach ($ldap_config as $id => $prop) $list[$id] = array( - 'id' => $id, - 'name' => $prop['name'], - 'groups' => is_array($prop['groups']), + 'id' => $id, + 'name' => $prop['name'], + 'groups' => is_array($prop['groups']), 'readonly' => !$prop['writable'], - 'autocomplete' => in_array('sql', $autocomplete) + 'hidden' => $prop['hidden'], + 'autocomplete' => in_array($id, $autocomplete) ); } @@ -543,87 +578,145 @@ /** - * Create global IMAP object and connect to server + * Initialize and get storage object * - * @param boolean True if connection should be established - * @todo Remove global $IMAP + * @return rcube_storage Storage object */ - public function imap_init($connect = false) + public function get_storage() { // already initialized - if (is_object($this->imap)) - return; - - $this->imap = new rcube_imap(); - $this->imap->debug_level = $this->config->get('debug_level'); - $this->imap->skip_deleted = $this->config->get('skip_deleted'); - - // enable caching of imap data - $imap_cache = $this->config->get('imap_cache'); - $messages_cache = $this->config->get('messages_cache'); - // for backward compatybility - if ($imap_cache === null && $messages_cache === null && $this->config->get('enable_caching')) { - $imap_cache = 'db'; - $messages_cache = true; + if (!is_object($this->storage)) { + $this->storage_init(); } - if ($imap_cache) - $this->imap->set_caching($imap_cache); - if ($messages_cache) - $this->imap->set_messages_caching(true); - // set pagesize from config - $this->imap->set_pagesize($this->config->get('pagesize', 50)); - - // Setting root and delimiter before establishing the connection - // can save time detecting them using NAMESPACE and LIST - $options = array( - 'auth_method' => $this->config->get('imap_auth_type', 'check'), - 'auth_cid' => $this->config->get('imap_auth_cid'), - 'auth_pw' => $this->config->get('imap_auth_pw'), - 'debug' => (bool) $this->config->get('imap_debug', 0), - 'force_caps' => (bool) $this->config->get('imap_force_caps'), - 'timeout' => (int) $this->config->get('imap_timeout', 0), - ); - - $this->imap->set_options($options); - - // set global object for backward compatibility - $GLOBALS['IMAP'] = $this->imap; - - $hook = $this->plugins->exec_hook('imap_init', array('fetch_headers' => $this->imap->fetch_add_headers)); - if ($hook['fetch_headers']) - $this->imap->fetch_add_headers = $hook['fetch_headers']; - - // support this parameter for backward compatibility but log warning - if ($connect) { - $this->imap_connect(); - raise_error(array( - 'code' => 800, 'type' => 'imap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "rcube::imap_init(true) is deprecated, use rcube::imap_connect() instead"), - true, false); - } + return $this->storage; } /** - * Connect to IMAP server with stored session data + * Connect to the IMAP server with stored session data. * - * @return bool True on success, false on error + * @return bool True on success, False on error + * @deprecated */ public function imap_connect() { - if (!$this->imap) - $this->imap_init(); + return $this->storage_connect(); + } - if ($_SESSION['imap_host'] && !$this->imap->conn->connected()) { - if (!$this->imap->connect($_SESSION['imap_host'], $_SESSION['username'], $this->decrypt($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl'])) { + + /** + * Initialize IMAP object. + * + * @deprecated + */ + public function imap_init() + { + $this->storage_init(); + } + + + /** + * Initialize storage object + */ + public function storage_init() + { + // already initialized + if (is_object($this->storage)) { + return; + } + + $driver = $this->config->get('storage_driver', 'imap'); + $driver_class = "rcube_{$driver}"; + + if (!class_exists($driver_class)) { + raise_error(array( + 'code' => 700, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Storage driver class ($driver) not found!"), + true, true); + } + + // Initialize storage object + $this->storage = new $driver_class; + + // for backward compat. (deprecated, will be removed) + $this->imap = $this->storage; + + // enable caching of mail data + $storage_cache = $this->config->get("{$driver}_cache"); + $messages_cache = $this->config->get('messages_cache'); + // for backward compatybility + if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) { + $storage_cache = 'db'; + $messages_cache = true; + } + + if ($storage_cache) + $this->storage->set_caching($storage_cache); + if ($messages_cache) + $this->storage->set_messages_caching(true); + + // set pagesize from config + $pagesize = $this->config->get('mail_pagesize'); + if (!$pagesize) { + $pagesize = $this->config->get('pagesize', 50); + } + $this->storage->set_pagesize($pagesize); + + // set class options + $options = array( + 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'), + 'auth_cid' => $this->config->get("{$driver}_auth_cid"), + 'auth_pw' => $this->config->get("{$driver}_auth_pw"), + 'debug' => (bool) $this->config->get("{$driver}_debug"), + 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), + 'timeout' => (int) $this->config->get("{$driver}_timeout"), + 'skip_deleted' => (bool) $this->config->get('skip_deleted'), + 'driver' => $driver, + ); + + if (!empty($_SESSION['storage_host'])) { + $options['host'] = $_SESSION['storage_host']; + $options['user'] = $_SESSION['username']; + $options['port'] = $_SESSION['storage_port']; + $options['ssl'] = $_SESSION['storage_ssl']; + $options['password'] = $this->decrypt($_SESSION['password']); + } + + $options = $this->plugins->exec_hook("storage_init", $options); + + // for backward compat. (deprecated, to be removed) + $options = $this->plugins->exec_hook("imap_init", $options); + + $this->storage->set_options($options); + $this->set_storage_prop(); + } + + + /** + * Connect to the mail storage server with stored session data + * + * @return bool True on success, False on error + */ + public function storage_connect() + { + $storage = $this->get_storage(); + + if ($_SESSION['storage_host'] && !$storage->is_connected()) { + $host = $_SESSION['storage_host']; + $user = $_SESSION['username']; + $port = $_SESSION['storage_port']; + $ssl = $_SESSION['storage_ssl']; + $pass = $this->decrypt($_SESSION['password']); + + if (!$storage->connect($host, $user, $pass, $port, $ssl)) { if ($this->output) - $this->output->show_message($this->imap->get_error_code() == -1 ? 'imaperror' : 'sessionerror', 'error'); + $this->output->show_message($storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror', 'error'); } else { - $this->set_imap_prop(); - return $this->imap->conn; + $this->set_storage_prop(); + return $storage->is_connected(); } } @@ -640,18 +733,21 @@ if (session_id()) return; + $sess_name = $this->config->get('session_name'); + $sess_domain = $this->config->get('session_domain'); + $lifetime = $this->config->get('session_lifetime', 0) * 60; + // set session domain - if ($domain = $this->config->get('session_domain')) { - ini_set('session.cookie_domain', $domain); + if ($sess_domain) { + ini_set('session.cookie_domain', $sess_domain); } // set session garbage collecting time according to session_lifetime - $lifetime = $this->config->get('session_lifetime', 0) * 60; if ($lifetime) { ini_set('session.gc_maxlifetime', $lifetime * 2); } ini_set('session.cookie_secure', rcube_https_check()); - ini_set('session.name', 'roundcube_sessid'); + ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid'); ini_set('session.use_cookies', 1); ini_set('session.use_only_cookies', 1); ini_set('session.serialize_handler', 'php'); @@ -691,24 +787,28 @@ $keep_alive = max(60, $keep_alive); $this->session->set_keep_alive($keep_alive); } - + $this->session->set_secret($this->config->get('des_key') . $_SERVER['HTTP_USER_AGENT']); $this->session->set_ip_check($this->config->get('ip_check')); } /** - * Perfom login to the IMAP server and to the webmail service. + * Perfom login to the mail server and to the webmail service. * This will also create a new user entry if auto_create_user is configured. * - * @param string IMAP user name - * @param string IMAP password - * @param string IMAP host + * @param string Mail storage (IMAP) user name + * @param string Mail storage (IMAP) password + * @param string Mail storage (IMAP) host + * * @return boolean True on success, False on failure */ function login($username, $pass, $host=NULL) { - $user = NULL; + if (empty($username)) { + return false; + } + $config = $this->config->all(); if (!$host) @@ -735,14 +835,16 @@ $a_host = parse_url($host); if ($a_host['host']) { $host = $a_host['host']; - $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; + $ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? $a_host['scheme'] : null; if (!empty($a_host['port'])) - $imap_port = $a_host['port']; - else if ($imap_ssl && $imap_ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) - $imap_port = 993; + $port = $a_host['port']; + else if ($ssl && $ssl != 'tls' && (!$config['default_port'] || $config['default_port'] == 143)) + $port = 993; } - $imap_port = $imap_port ? $imap_port : $config['default_port']; + if (!$port) { + $port = $config['default_port']; + } /* Modify username with domain if required Inspired by Marco <P0L0_notspam_binware.org> @@ -755,7 +857,7 @@ $username .= '@'.rcube_parse_host($config['username_domain'], $host); } - // Convert username to lowercase. If IMAP backend + // Convert username to lowercase. If storage backend // is case-insensitive we need to store always the same username (#1487113) if ($config['login_lc']) { $username = mb_strtolower($username); @@ -780,11 +882,11 @@ if ($user = rcube_user::query($username, $host)) $username = $user->data['username']; - if (!$this->imap) - $this->imap_init(); + if (!$this->storage) + $this->storage_init(); - // try IMAP login - if (!($imap_login = $this->imap->connect($host, $username, $pass, $imap_port, $imap_ssl))) { + // try to log in + if (!($login = $this->storage->connect($host, $username, $pass, $port, $ssl))) { // try with lowercase $username_lc = mb_strtolower($username); if ($username_lc != $username) { @@ -792,25 +894,18 @@ if (!$user && ($user = rcube_user::query($username_lc, $host))) $username_lc = $user->data['username']; - if ($imap_login = $this->imap->connect($host, $username_lc, $pass, $imap_port, $imap_ssl)) + if ($login = $this->storage->connect($host, $username_lc, $pass, $port, $ssl)) $username = $username_lc; } } - // exit if IMAP login failed - if (!$imap_login) + // exit if login failed + if (!$login) { return false; - - $this->set_imap_prop(); + } // user already registered -> update user's record if (is_object($user)) { - // fix some old settings according to namespace prefix - $this->fix_namespace_settings($user); - - // create default folders on first login - if (!$user->data['last_login'] && $config['create_default_folders']) - $this->imap->create_default_folders(); // update last login timestamp $user->touch(); } @@ -818,13 +913,10 @@ else if ($config['auto_create_user']) { if ($created = rcube_user::create($username, $host)) { $user = $created; - // create default folders on first login - if ($config['create_default_folders']) - $this->imap->create_default_folders(); } else { raise_error(array( - 'code' => 600, 'type' => 'php', + 'code' => 620, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Failed to create a user record. Maybe aborted by a plugin?" ), true, false); @@ -832,31 +924,43 @@ } else { raise_error(array( - 'code' => 600, 'type' => 'php', + 'code' => 621, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Acces denied for new user $username. 'auto_create_user' is disabled" + 'message' => "Access denied for new user $username. 'auto_create_user' is disabled" ), true, false); } // login succeeded if (is_object($user) && $user->ID) { + // Configure environment $this->set_user($user); + $this->set_storage_prop(); $this->session_configure(); + // fix some old settings according to namespace prefix + $this->fix_namespace_settings($user); + + // create default folders on first login + if ($config['create_default_folders'] && (!empty($created) || empty($user->data['last_login']))) { + $this->storage->create_default_folders(); + } + // set session vars - $_SESSION['user_id'] = $user->ID; - $_SESSION['username'] = $user->data['username']; - $_SESSION['imap_host'] = $host; - $_SESSION['imap_port'] = $imap_port; - $_SESSION['imap_ssl'] = $imap_ssl; - $_SESSION['password'] = $this->encrypt($pass); - $_SESSION['login_time'] = mktime(); - + $_SESSION['user_id'] = $user->ID; + $_SESSION['username'] = $user->data['username']; + $_SESSION['storage_host'] = $host; + $_SESSION['storage_port'] = $port; + $_SESSION['storage_ssl'] = $ssl; + $_SESSION['password'] = $this->encrypt($pass); + $_SESSION['login_time'] = mktime(); + if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_') $_SESSION['timezone'] = floatval($_REQUEST['_timezone']); + if (isset($_REQUEST['_dstactive']) && $_REQUEST['_dstactive'] != '_default_') + $_SESSION['dst_active'] = intval($_REQUEST['_dstactive']); // force reloading complete list of subscribed mailboxes - $this->imap->clear_cache('mailboxes', true); + $this->storage->clear_cache('mailboxes', true); return true; } @@ -866,21 +970,23 @@ /** - * Set root dir and last stored mailbox + * Set storage parameters. * This must be done AFTER connecting to the server! */ - public function set_imap_prop() + private function set_storage_prop() { - $this->imap->set_charset($this->config->get('default_charset', RCMAIL_CHARSET)); + $storage = $this->get_storage(); - if ($default_folders = $this->config->get('default_imap_folders')) { - $this->imap->set_default_mailboxes($default_folders); + $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET)); + + if ($default_folders = $this->config->get('default_folders')) { + $storage->set_default_folders($default_folders); } if (isset($_SESSION['mbox'])) { - $this->imap->set_mailbox($_SESSION['mbox']); + $storage->set_folder($_SESSION['mbox']); } if (isset($_SESSION['page'])) { - $this->imap->set_page($_SESSION['page']); + $storage->set_page($_SESSION['page']); } } @@ -906,9 +1012,9 @@ // try to select host by mail domain list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST)); if (!empty($domain)) { - foreach ($default_host as $imap_host => $mail_domains) { + foreach ($default_host as $storage_host => $mail_domains) { if (is_array($mail_domains) && in_array($domain, $mail_domains)) { - $host = $imap_host; + $host = $storage_host; break; } } @@ -932,7 +1038,9 @@ /** * Get localized text in the desired language * - * @param mixed Named parameters array or label name + * @param mixed $attrib Named parameters array or label name + * @param string $domain Label domain (plugin) name + * * @return string Localized text */ public function gettext($attrib, $domain=null) @@ -945,43 +1053,18 @@ if (is_string($attrib)) $attrib = array('name' => $attrib); - $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1; $name = $attrib['name'] ? $attrib['name'] : ''; - + // attrib contain text values: use them from now if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us'])) $this->texts[$name] = $setval; // check for text with domain - if ($domain && ($text_item = $this->texts[$domain.'.'.$name])) + if ($domain && ($text = $this->texts[$domain.'.'.$name])) ; // text does not exist - else if (!($text_item = $this->texts[$name])) { + else if (!($text = $this->texts[$name])) { return "[$name]"; - } - - // make text item array - $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item); - - // decide which text to use - if ($nr == 1) { - $text = $a_text_item['single']; - } - else if ($nr > 0) { - $text = $a_text_item['multiple']; - } - else if ($nr == 0) { - if ($a_text_item['none']) - $text = $a_text_item['none']; - else if ($a_text_item['single']) - $text = $a_text_item['single']; - else if ($a_text_item['multiple']) - $text = $a_text_item['multiple']; - } - - // default text is single - if ($text == '') { - $text = $a_text_item['single']; } // replace vars in text @@ -998,24 +1081,45 @@ else if ($attrib['lowercase']) return mb_strtolower($text); - return $text; + return strtr($text, array('\n' => "\n")); } /** - * Check if the given text lable exists + * Check if the given text label exists * - * @param string Label name + * @param string $name Label name + * @param string $domain Label domain (plugin) name or '*' for all domains + * @param string $ref_domain Sets domain name if label is found + * * @return boolean True if text exists (either in the current language or in en_US) */ - public function text_exists($name, $domain=null) + public function text_exists($name, $domain = null, &$ref_domain = null) { // load localization files if not done yet if (empty($this->texts)) $this->load_language(); - // check for text with domain first - return ($domain && isset($this->texts[$domain.'.'.$name])) || isset($this->texts[$name]); + if (isset($this->texts[$name])) { + $ref_domain = ''; + return true; + } + + // any of loaded domains (plugins) + if ($domain == '*') { + foreach ($this->plugins->loaded_plugins() as $domain) + if (isset($this->texts[$domain.'.'.$name])) { + $ref_domain = $domain; + return true; + } + } + // specified domain + else if ($domain) { + $ref_domain = $domain; + return isset($this->texts[$domain.'.'.$name]); + } + + return false; } /** @@ -1118,15 +1222,15 @@ if (!$this->session->check_auth()) return; - $this->imap_connect(); + $this->storage_connect(); } if ($config['logout_purge'] && !empty($config['trash_mbox'])) { - $this->imap->clear_mailbox($config['trash_mbox']); + $this->storage->clear_folder($config['trash_mbox']); } if ($config['logout_expunge']) { - $this->imap->expunge('INBOX'); + $this->storage->expunge_folder('INBOX'); } // Try to save unsaved user preferences @@ -1142,13 +1246,14 @@ */ public function shutdown() { + foreach ($this->shutdown_functions as $function) + call_user_func($function); + if (is_object($this->smtp)) $this->smtp->disconnect(); foreach ($this->address_books as $book) { - if (!is_object($book)) // maybe an address book instance wasn't fetched using get_address_book() yet - $book = $this->get_address_book($book['id']); - if (is_a($book, 'rcube_addressbook')) + if (is_object($book) && is_a($book, 'rcube_addressbook')) $book->close(); } @@ -1157,12 +1262,11 @@ $cache->close(); } - if (is_object($this->imap)) - $this->imap->close(); + if (is_object($this->storage)) + $this->storage->close(); // before closing the database connection, write session data - if ($_SERVER['REMOTE_ADDR']) { - $this->session->cleanup(); + if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { session_write_close(); } @@ -1183,6 +1287,19 @@ /** + * Registers shutdown function to be executed on shutdown. + * The functions will be executed before destroying any + * objects like smtp, imap, session, etc. + * + * @param callback Function callback + */ + public function add_shutdown_function($function) + { + $this->shutdown_functions[] = $function; + } + + + /** * Generate a unique token to be used in a form request * * @return string The request token @@ -1191,7 +1308,7 @@ { $sess_id = $_COOKIE[ini_get('session.name')]; if (!$sess_id) $sess_id = session_id(); - $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->task . $this->config->get('des_key') . $sess_id))); + $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->user->ID . $this->config->get('des_key') . $sess_id))); return $plugin['value']; } @@ -1485,7 +1602,7 @@ // use strtr behaviour of going through source string once $cmd = strtr($cmd, $replacements); - + return (string)shell_exec($cmd); } @@ -1521,7 +1638,7 @@ } } } - + /** * Returns current action filename * @@ -1545,18 +1662,18 @@ */ private function fix_namespace_settings($user) { - $prefix = $this->imap->get_namespace('prefix'); + $prefix = $this->storage->get_namespace('prefix'); $prefix_len = strlen($prefix); if (!$prefix_len) return; - $prefs = $user->get_prefs(); - if (empty($prefs) || $prefs['namespace_fixed']) + $prefs = $this->config->all(); + if (!empty($prefs['namespace_fixed'])) return; // Build namespace prefix regexp - $ns = $this->imap->get_namespace(); + $ns = $this->storage->get_namespace(); $regexp = array(); foreach ($ns as $entry) { @@ -1580,10 +1697,10 @@ } } - if (!empty($prefs['default_imap_folders'])) { - foreach ($prefs['default_imap_folders'] as $idx => $name) { + if (!empty($prefs['default_folders'])) { + foreach ($prefs['default_folders'] as $idx => $name) { if ($name != 'INBOX' && !preg_match($regexp, $name)) { - $prefs['default_imap_folders'][$idx] = $prefix.$name; + $prefs['default_folders'][$idx] = $prefix.$name; } } } @@ -1633,7 +1750,7 @@ // save updated preferences and reset imap settings (default folders) $user->save_prefs($prefs); - $this->set_imap_prop(); + $this->set_storage_prop(); } } -- Gitblit v1.9.1