Page MenuHomePhorge

No OneTemporary

diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 6ed095062..06f50a13f 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -1,972 +1,979 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcmail.php |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2008-2009, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Application class providing core functions and holding |
| instances of all 'global' objects like db- and imap-connections |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id: rcmail.php 328 2006-08-30 17:41:21Z thomasb $
*/
/**
* Application class of RoundCube Webmail
* implemented as singleton
*
* @package Core
*/
class rcmail
{
static public $main_tasks = array('mail','settings','addressbook','login','logout');
static private $instance;
public $config;
public $user;
public $db;
public $imap;
public $output;
public $plugins;
public $task = 'mail';
public $action = '';
public $comm_path = './';
private $texts;
/**
* This implements the 'singleton' design pattern
*
* @return object rcmail The one and only instance
*/
static function get_instance()
{
if (!self::$instance) {
self::$instance = new rcmail();
self::$instance->startup(); // init AFTER object was linked with self::$instance
}
return self::$instance;
}
/**
* Private constructor
*/
private function __construct()
{
// load configuration
$this->config = new rcube_config();
register_shutdown_function(array($this, 'shutdown'));
}
/**
* Initial startup function
* to register session, create database and imap connections
*
* @todo Remove global vars $DB, $USER
*/
private function startup()
{
$config_all = $this->config->all();
// initialize syslog
if ($this->config->get('log_driver') == 'syslog') {
$syslog_id = $this->config->get('syslog_id', 'roundcube');
$syslog_facility = $this->config->get('syslog_facility', LOG_USER);
openlog($syslog_id, LOG_ODELAY, $syslog_facility);
}
// set task and action properties
$this->set_task(get_input_value('_task', RCUBE_INPUT_GPC));
$this->action = asciiwords(get_input_value('_action', RCUBE_INPUT_GPC));
// connect to database
$GLOBALS['DB'] = $this->get_dbh();
// use database for storing session data
include_once('include/session.inc');
// set session domain
if (!empty($config_all['session_domain'])) {
ini_set('session.cookie_domain', $config_all['session_domain']);
}
// set session garbage collecting time according to session_lifetime
if (!empty($config_all['session_lifetime'])) {
ini_set('session.gc_maxlifetime', ($config_all['session_lifetime']) * 120);
}
// start PHP session (if not in CLI mode)
if ($_SERVER['REMOTE_ADDR'])
session_start();
// set initial session vars
if (!isset($_SESSION['auth_time'])) {
$_SESSION['auth_time'] = time();
$_SESSION['temp'] = true;
}
// create user object
$this->set_user(new rcube_user($_SESSION['user_id']));
// reset some session parameters when changing task
if ($_SESSION['task'] != $this->task)
rcube_sess_unset('page');
// set current task to session
$_SESSION['task'] = $this->task;
// create IMAP object
if ($this->task == 'mail')
$this->imap_init();
// create plugin API and load plugins
$this->plugins = rcube_plugin_api::get_instance();
}
/**
* Setter for application task
*
* @param string Task to set
*/
public function set_task($task)
{
$task = asciiwords($task);
$this->task = $task ? $task : 'mail';
$this->comm_path = $this->url(array('task' => $this->task));
if ($this->output)
$this->output->set_env('task', $this->task);
}
/**
* Setter for system user object
*
* @param object rcube_user Current user instance
*/
public function set_user($user)
{
if (is_object($user)) {
$this->user = $user;
$GLOBALS['USER'] = $this->user;
// overwrite config with user preferences
$this->config->merge((array)$this->user->get_prefs());
}
$_SESSION['language'] = $this->user->language = $this->language_prop($this->config->get('language', $_SESSION['language']));
// set localization
setlocale(LC_ALL, $_SESSION['language'] . '.utf8', 'en_US.utf8');
// workaround for http://bugs.php.net/bug.php?id=18556
if (in_array($_SESSION['language'], array('tr_TR', 'ku', 'az_AZ')))
setlocale(LC_CTYPE, 'en_US' . '.utf8');
}
/**
* Check the given string and return a valid language code
*
* @param string Language code
* @return string Valid language code
*/
private function language_prop($lang)
{
static $rcube_languages, $rcube_language_aliases;
// user HTTP_ACCEPT_LANGUAGE if no language is specified
if (empty($lang) || $lang == 'auto') {
$accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$lang = str_replace('-', '_', $accept_langs[0]);
}
if (empty($rcube_languages)) {
@include(INSTALL_PATH . 'program/localization/index.inc');
}
// check if we have an alias for that language
if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) {
$lang = $rcube_language_aliases[$lang];
}
// try the first two chars
else if (!isset($rcube_languages[$lang])) {
$short = substr($lang, 0, 2);
// check if we have an alias for the short language code
if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) {
$lang = $rcube_language_aliases[$short];
}
// expand 'nn' to 'nn_NN'
else if (!isset($rcube_languages[$short])) {
$lang = $short.'_'.strtoupper($short);
}
}
if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
$lang = 'en_US';
}
return $lang;
}
/**
* Get the current database connection
*
* @return object rcube_mdb2 Database connection object
*/
public function get_dbh()
{
if (!$this->db) {
$config_all = $this->config->all();
$this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']);
$this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql';
$this->db->set_debug((bool)$config_all['sql_debug']);
$this->db->db_connect('w');
}
return $this->db;
}
/**
* Return instance of the internal address book class
*
* @param boolean True if the address book needs to be writeable
* @return object rcube_contacts Address book object
*/
public function get_address_book($id, $writeable = false)
{
$contacts = null;
$ldap_config = (array)$this->config->get('ldap_public');
$abook_type = strtolower($this->config->get('address_book_type'));
$plugin = $this->plugins->exec_hook('get_address_book', array('id' => $id, 'writeable' => $writeable));
// plugin returned instance of a rcube_addressbook
if ($plugin['instance'] instanceof rcube_addressbook) {
$contacts = $plugin['instance'];
}
else if ($id && $ldap_config[$id]) {
$contacts = new rcube_ldap($ldap_config[$id]);
}
else if ($id === '0') {
$contacts = new rcube_contacts($this->db, $this->user->ID);
}
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);
break;
}
}
}
else {
$contacts = new rcube_contacts($this->db, $this->user->ID);
}
return $contacts;
}
/**
* Init output object for GUI and add common scripts.
* This will instantiate a rcmail_template object and set
* environment vars according to the current session and configuration
*
* @param boolean True if this request is loaded in a (i)frame
* @return object rcube_template Reference to HTML output object
*/
public function load_gui($framed = false)
{
// init output page
if (!($this->output instanceof rcube_template))
$this->output = new rcube_template($this->task, $framed);
foreach (array('flag_for_deletion','read_when_deleted') as $js_config_var) {
$this->output->set_env($js_config_var, $this->config->get($js_config_var));
}
// set keep-alive/check-recent interval
if ($keep_alive = $this->config->get('keep_alive')) {
// be sure that it's less than session lifetime
if ($session_lifetime = $this->config->get('session_lifetime'))
$keep_alive = min($keep_alive, $session_lifetime * 60 - 30);
$this->output->set_env('keep_alive', max(60, $keep_alive));
}
if ($framed) {
$this->comm_path .= '&_framed=1';
$this->output->set_env('framed', true);
}
$this->output->set_env('task', $this->task);
$this->output->set_env('action', $this->action);
$this->output->set_env('comm_path', $this->comm_path);
$this->output->set_charset($this->config->get('charset', RCMAIL_CHARSET));
// add some basic label to client
$this->output->add_label('loading');
return $this->output;
}
/**
* Create an output object for JSON responses
*
* @return object rcube_json_output Reference to JSON output object
*/
public function init_json()
{
if (!($this->output instanceof rcube_json_output))
$this->output = new rcube_json_output($this->task);
return $this->output;
}
/**
* Create global IMAP object and connect to server
*
* @param boolean True if connection should be established
* @todo Remove global $IMAP
*/
public function imap_init($connect = false)
{
$this->imap = new rcube_imap($this->db);
$this->imap->debug_level = $this->config->get('debug_level');
$this->imap->skip_deleted = $this->config->get('skip_deleted');
// enable caching of imap data
if ($this->config->get('enable_caching')) {
$this->imap->set_caching(true);
}
// set pagesize from config
$this->imap->set_pagesize($this->config->get('pagesize', 50));
// Setting root and delimiter before iil_Connect can save time detecting them
// using NAMESPACE and LIST
$options = array(
'imap' => $this->config->get('imap_auth_type', 'check'),
'delimiter' => isset($_SESSION['imap_delimiter']) ? $_SESSION['imap_delimiter'] : $this->config->get('imap_delimiter'),
'rootdir' => isset($_SESSION['imap_root']) ? $_SESSION['imap_root'] : $this->config->get('imap_root'),
);
$this->imap->set_options($options);
// set global object for backward compatibility
$GLOBALS['IMAP'] = $this->imap;
if ($connect)
$this->imap_connect();
}
/**
* Connect to IMAP server with stored session data
*
* @return bool True on success, false on error
*/
public function imap_connect()
{
$conn = false;
if ($_SESSION['imap_host'] && !$this->imap->conn) {
if (!($conn = $this->imap->connect($_SESSION['imap_host'], $_SESSION['username'], $this->decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']))) {
if ($this->output)
$this->output->show_message($this->imap->error_code == -1 ? 'imaperror' : 'sessionerror', 'error');
}
$this->set_imap_prop();
}
return $conn;
}
/**
* Perfom login to the IMAP 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
* @return boolean True on success, False on failure
*/
function login($username, $pass, $host=NULL)
{
$user = NULL;
$config = $this->config->all();
if (!$host)
$host = $config['default_host'];
// Validate that selected host is in the list of configured hosts
if (is_array($config['default_host'])) {
$allowed = false;
foreach ($config['default_host'] as $key => $host_allowed) {
if (!is_numeric($key))
$host_allowed = $key;
if ($host == $host_allowed) {
$allowed = true;
break;
}
}
if (!$allowed)
return false;
}
else if (!empty($config['default_host']) && $host != $config['default_host'])
return false;
// parse $host URL
$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;
if(!empty($a_host['port']))
$imap_port = $a_host['port'];
else if ($imap_ssl && $imap_ssl != 'tls')
$imap_port = 993;
}
$imap_port = $imap_port ? $imap_port : $config['default_port'];
/* Modify username with domain if required
Inspired by Marco <P0L0_notspam_binware.org>
*/
// Check if we need to add domain
if (!empty($config['username_domain']) && !strpos($username, '@')) {
if (is_array($config['username_domain']) && isset($config['username_domain'][$host]))
$username .= '@'.$config['username_domain'][$host];
else if (is_string($config['username_domain']))
$username .= '@'.$config['username_domain'];
}
// try to resolve email address from virtuser table
if (strpos($username, '@'))
if ($virtuser = rcube_user::email2user($username))
$username = $virtuser;
// lowercase username if it's an e-mail address (#1484473)
if (strpos($username, '@'))
$username = rc_strtolower($username);
// user already registered -> overwrite username
if ($user = rcube_user::query($username, $host))
$username = $user->data['username'];
// exit if IMAP login failed
if (!($imap_login = $this->imap->connect($host, $username, $pass, $imap_port, $imap_ssl)))
return false;
// user already registered -> update user's record
if (is_object($user)) {
$user->touch();
}
// create new system user
else if ($config['auto_create_user']) {
if ($created = rcube_user::create($username, $host)) {
$user = $created;
// get existing mailboxes (but why?)
// $a_mailboxes = $this->imap->list_mailboxes();
}
+ else {
+ raise_error(array(
+ 'code' => 600,
+ 'type' => 'php',
+ 'message' => "Failed to create a user record. Maybe aborted by a plugin?"
+ ), true, false);
+ }
}
else {
raise_error(array(
'code' => 600,
'type' => 'php',
'file' => RCMAIL_CONFIG_DIR."/main.inc.php",
'message' => "Acces denied for new user $username. 'auto_create_user' is disabled"
), true, false);
}
// login succeeded
if (is_object($user) && $user->ID) {
$this->set_user($user);
// 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_passwd($pass);
$_SESSION['login_time'] = mktime();
if ($_REQUEST['_timezone'] != '_default_')
$_SESSION['timezone'] = floatval($_REQUEST['_timezone']);
// force reloading complete list of subscribed mailboxes
$this->set_imap_prop();
$this->imap->clear_cache('mailboxes');
if ($config['create_default_folders'])
$this->imap->create_default_folders();
return true;
}
return false;
}
/**
* Set root dir and last stored mailbox
* This must be done AFTER connecting to the server!
*/
public function set_imap_prop()
{
$this->imap->set_charset($this->config->get('default_charset', RCMAIL_CHARSET));
if ($default_folders = $this->config->get('default_imap_folders')) {
$this->imap->set_default_mailboxes($default_folders);
}
if (!empty($_SESSION['mbox'])) {
$this->imap->set_mailbox($_SESSION['mbox']);
}
if (isset($_SESSION['page'])) {
$this->imap->set_page($_SESSION['page']);
}
// cache IMAP root and delimiter in session for performance reasons
$_SESSION['imap_root'] = $this->imap->root_dir;
$_SESSION['imap_delimiter'] = $this->imap->delimiter;
}
/**
* Auto-select IMAP host based on the posted login information
*
* @return string Selected IMAP host
*/
public function autoselect_host()
{
$default_host = $this->config->get('default_host');
$host = null;
if (is_array($default_host)) {
$post_host = get_input_value('_host', RCUBE_INPUT_POST);
// direct match in default_host array
if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) {
$host = $post_host;
}
// 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) {
if (is_array($mail_domains) && in_array($domain, $mail_domains)) {
$host = $imap_host;
break;
}
}
}
// take the first entry if $host is still an array
if (empty($host)) {
$host = array_shift($default_host);
}
}
else if (empty($default_host)) {
$host = get_input_value('_host', RCUBE_INPUT_POST);
}
else
$host = $default_host;
return $host;
}
/**
* Get localized text in the desired language
*
* @param mixed Named parameters array or label name
* @return string Localized text
*/
public function gettext($attrib, $domain=null)
{
// load localization files if not done yet
if (empty($this->texts))
$this->load_language();
// extract attributes
if (is_string($attrib))
$attrib = array('name' => $attrib);
$nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
$vars = isset($attrib['vars']) ? $attrib['vars'] : '';
$command_name = !empty($attrib['command']) ? $attrib['command'] : NULL;
$alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
// check for text with domain
if ($domain && ($text_item = $this->texts[$domain.'.'.$alias]))
;
// text does not exist
else if (!($text_item = $this->texts[$alias])) {
/*
raise_error(array(
'code' => 500,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Missing localized text for '$alias' in '$sess_user_lang'"), TRUE, FALSE);
*/
return "[$alias]";
}
// 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
if (is_array($attrib['vars'])) {
foreach ($attrib['vars'] as $var_key => $var_value)
$a_replace_vars[$var_key{0}=='$' ? substr($var_key, 1) : $var_key] = $var_value;
}
if ($a_replace_vars)
$text = preg_replace('/\$\{?([_a-z]{1}[_a-z0-9]*)\}?/ei', '$a_replace_vars["\1"]', $text);
// format output
if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
return ucfirst($text);
else if ($attrib['uppercase'])
return strtoupper($text);
else if ($attrib['lowercase'])
return strtolower($text);
return $text;
}
/**
* Load a localization package
*
* @param string Language ID
*/
public function load_language($lang = null, $add = array())
{
$lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));
// load localized texts
if (empty($this->texts) || $lang != $_SESSION['language']) {
$this->texts = array();
// get english labels (these should be complete)
@include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
@include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
if (is_array($labels))
$this->texts = $labels;
if (is_array($messages))
$this->texts = array_merge($this->texts, $messages);
// include user language files
if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
if (is_array($labels))
$this->texts = array_merge($this->texts, $labels);
if (is_array($messages))
$this->texts = array_merge($this->texts, $messages);
}
$_SESSION['language'] = $lang;
}
// append additional texts (from plugin)
if (is_array($add) && !empty($add))
$this->texts += $add;
}
/**
* Read directory program/localization and return a list of available languages
*
* @return array List of available localizations
*/
public function list_languages()
{
static $sa_languages = array();
if (!sizeof($sa_languages)) {
@include(INSTALL_PATH . 'program/localization/index.inc');
if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {
while (($name = readdir($dh)) !== false) {
if ($name{0}=='.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name))
continue;
if ($label = $rcube_languages[$name])
$sa_languages[$name] = $label ? $label : $name;
}
closedir($dh);
}
}
return $sa_languages;
}
/**
* Check the auth hash sent by the client against the local session credentials
*
* @return boolean True if valid, False if not
*/
function authenticate_session()
{
global $SESS_CLIENT_IP, $SESS_CHANGED;
// advanced session authentication
if ($this->config->get('double_auth')) {
$now = time();
$valid = ($_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['auth_time']) ||
$_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['last_auth']));
// renew auth cookie every 5 minutes (only for GET requests)
if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now - $_SESSION['auth_time'] > 300)) {
$_SESSION['last_auth'] = $_SESSION['auth_time'];
$_SESSION['auth_time'] = $now;
rcmail::setcookie('sessauth', $this->get_auth_hash(session_id(), $now), 0);
}
}
else {
$valid = $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true;
}
// check session filetime
$lifetime = $this->config->get('session_lifetime');
if (!empty($lifetime) && isset($SESS_CHANGED) && $SESS_CHANGED + $lifetime*60 < time()) {
$valid = false;
}
return $valid;
}
/**
* Destroy session data and remove cookie
*/
public function kill_session()
{
rcube_sess_unset();
$_SESSION = array('language' => $this->user->language, 'auth_time' => time(), 'temp' => true);
rcmail::setcookie('sessauth', '-del-', time() - 60);
$this->user->reset();
}
/**
* Do server side actions on logout
*/
public function logout_actions()
{
$config = $this->config->all();
// on logout action we're not connected to imap server
if (($config['logout_purge'] && !empty($config['trash_mbox'])) || $config['logout_expunge']) {
if (!$this->authenticate_session())
return;
$this->imap_init(true);
}
if ($config['logout_purge'] && !empty($config['trash_mbox'])) {
$this->imap->clear_mailbox($config['trash_mbox']);
}
if ($config['logout_expunge']) {
$this->imap->expunge('INBOX');
}
}
/**
* Function to be executed in script shutdown
* Registered with register_shutdown_function()
*/
public function shutdown()
{
if (is_object($this->imap)) {
$this->imap->close();
$this->imap->write_cache();
}
if (is_object($this->contacts))
$this->contacts->close();
// before closing the database connection, write session data
if ($_SERVER['REMOTE_ADDR'])
session_write_close();
}
/**
* Create unique authorization hash
*
* @param string Session ID
* @param int Timestamp
* @return string The generated auth hash
*/
private function get_auth_hash($sess_id, $ts)
{
$auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s',
$sess_id,
$ts,
$this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***',
$_SERVER['HTTP_USER_AGENT']);
if (function_exists('sha1'))
return sha1($auth_string);
else
return md5($auth_string);
}
/**
* Encrypt IMAP password using DES encryption
*
* @param string Password to encrypt
* @return string Encryprted string
*/
public function encrypt_passwd($pass)
{
if (function_exists('mcrypt_module_open') && ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_ECB, ""))) {
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $this->config->get_des_key(), $iv);
$cypher = mcrypt_generic($td, $pass);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
else if (function_exists('des')) {
$cypher = des($this->config->get_des_key(), $pass, 1, 0, NULL);
}
else {
$cypher = $pass;
raise_error(array(
'code' => 500,
'type' => 'php',
'file' => __FILE__,
'message' => "Could not convert encrypt password. Make sure Mcrypt is installed or lib/des.inc is available"
), true, false);
}
return base64_encode($cypher);
}
/**
* Decrypt IMAP password using DES encryption
*
* @param string Encrypted password
* @return string Plain password
*/
public function decrypt_passwd($cypher)
{
if (function_exists('mcrypt_module_open') && ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_ECB, ""))) {
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $this->config->get_des_key(), $iv);
$pass = mdecrypt_generic($td, base64_decode($cypher));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
}
else if (function_exists('des')) {
$pass = des($this->config->get_des_key(), base64_decode($cypher), 0, 0, NULL);
}
else {
$pass = base64_decode($cypher);
}
return preg_replace('/\x00/', '', $pass);
}
/**
* Build a valid URL to this instance of RoundCube
*
* @param mixed Either a string with the action or url parameters as key-value pairs
* @return string Valid application URL
*/
public function url($p)
{
if (!is_array($p))
$p = array('_action' => @func_get_arg(0));
$task = $p['_task'] ? $p['_task'] : ($p['task'] ? $p['task'] : $this->task);
$p['_task'] = $task;
unset($p['task']);
$url = './';
$delm = '?';
foreach (array_reverse($p) as $key => $val)
{
if (!empty($val)) {
$par = $key[0] == '_' ? $key : '_'.$key;
$url .= $delm.urlencode($par).'='.urlencode($val);
$delm = '&';
}
}
return $url;
}
/**
* Helper method to set a cookie with the current path and host settings
*
* @param string Cookie name
* @param string Cookie value
* @param string Expiration time
*/
public static function setcookie($name, $value, $exp = 0)
{
$cookie = session_get_cookie_params();
setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'],
($_SERVER['HTTPS'] && ($_SERVER['HTTPS'] != 'off')));
}
}
diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php
index 79721d51b..da819c7c0 100644
--- a/program/include/rcube_user.php
+++ b/program/include/rcube_user.php
@@ -1,517 +1,530 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcube_user.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2009, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| This class represents a system user linked and provides access |
| to the related database records. |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id: rcube_user.inc 933 2007-11-29 14:17:32Z thomasb $
*/
/**
* Class representing a system user
*
* @package Core
* @author Thomas Bruederli <roundcube@gmail.com>
*/
class rcube_user
{
public $ID = null;
public $data = null;
public $language = null;
private $db = null;
/**
* Object constructor
*
* @param object DB Database connection
*/
function __construct($id = null, $sql_arr = null)
{
$this->db = rcmail::get_instance()->get_dbh();
if ($id && !$sql_arr)
{
$sql_result = $this->db->query("SELECT * FROM ".get_table_name('users')." WHERE user_id=?", $id);
$sql_arr = $this->db->fetch_assoc($sql_result);
}
if (!empty($sql_arr))
{
$this->ID = $sql_arr['user_id'];
$this->data = $sql_arr;
$this->language = $sql_arr['language'];
}
}
/**
* Build a user name string (as e-mail address)
*
* @return string Full user name
*/
function get_username()
{
return $this->data['username'] ? $this->data['username'] . (!strpos($this->data['username'], '@') ? '@'.$this->data['mail_host'] : '') : false;
}
/**
* Get the preferences saved for this user
*
* @return array Hash array with prefs
*/
function get_prefs()
{
if (!empty($this->language))
$prefs = array('language' => $this->language);
if ($this->ID && $this->data['preferences'])
$prefs += (array)unserialize($this->data['preferences']);
return $prefs;
}
/**
* Write the given user prefs to the user's record
*
* @param array User prefs to save
* @return boolean True on success, False on failure
*/
function save_prefs($a_user_prefs)
{
if (!$this->ID)
return false;
$config = rcmail::get_instance()->config;
$old_prefs = (array)$this->get_prefs();
// merge (partial) prefs array with existing settings
$save_prefs = $a_user_prefs + $old_prefs;
unset($save_prefs['language']);
// don't save prefs with default values if they haven't been changed yet
foreach ($a_user_prefs as $key => $value) {
if (!isset($old_prefs[$key]) && ($value == $config->get($key)))
unset($save_prefs[$key]);
}
$this->db->query(
"UPDATE ".get_table_name('users')."
SET preferences=?,
language=?
WHERE user_id=?",
serialize($save_prefs),
$_SESSION['language'],
$this->ID);
$this->language = $_SESSION['language'];
if ($this->db->affected_rows()) {
$config->merge($a_user_prefs);
return true;
}
return false;
}
/**
* Get default identity of this user
*
* @param int Identity ID. If empty, the default identity is returned
* @return array Hash array with all cols of the
*/
function get_identity($id = null)
{
$sql_result = $this->list_identities($id ? sprintf('AND identity_id=%d', $id) : '');
return $this->db->fetch_assoc($sql_result);
}
/**
* Return a list of all identities linked with this user
*
* @return array List of identities
*/
function list_identities($sql_add = '')
{
// get contacts from DB
$sql_result = $this->db->query(
"SELECT * FROM ".get_table_name('identities')."
WHERE del<>1
AND user_id=?
$sql_add
ORDER BY ".$this->db->quoteIdentifier('standard')." DESC, name ASC, identity_id ASC",
$this->ID);
return $sql_result;
}
/**
* Update a specific identity record
*
* @param int Identity ID
* @param array Hash array with col->value pairs to save
* @return boolean True if saved successfully, false if nothing changed
*/
function update_identity($iid, $data)
{
if (!$this->ID)
return false;
$write_sql = array();
foreach ((array)$data as $col => $value)
{
$write_sql[] = sprintf("%s=%s",
$this->db->quoteIdentifier($col),
$this->db->quote($value));
}
$this->db->query(
"UPDATE ".get_table_name('identities')."
SET ".join(', ', $write_sql)."
WHERE identity_id=?
AND user_id=?
AND del<>1",
$iid,
$this->ID);
return $this->db->affected_rows();
}
/**
* Create a new identity record linked with this user
*
* @param array Hash array with col->value pairs to save
* @return int The inserted identity ID or false on error
*/
function insert_identity($data)
{
if (!$this->ID)
return false;
$insert_cols = $insert_values = array();
foreach ((array)$data as $col => $value)
{
$insert_cols[] = $this->db->quoteIdentifier($col);
$insert_values[] = $this->db->quote($value);
}
$this->db->query(
"INSERT INTO ".get_table_name('identities')."
(user_id, ".join(', ', $insert_cols).")
VALUES (?, ".join(', ', $insert_values).")",
$this->ID);
return $this->db->insert_id(get_sequence_name('identities'));
}
/**
* Mark the given identity as deleted
*
* @param int Identity ID
* @return boolean True if deleted successfully, false if nothing changed
*/
function delete_identity($iid)
{
if (!$this->ID)
return false;
if (!$this->ID || $this->ID == '')
return false;
$sql_result = $this->db->query("SELECT count(*) AS ident_count FROM " .
get_table_name('identities') .
" WHERE user_id = ? AND del <> 1",
$this->ID);
$sql_arr = $this->db->fetch_assoc($sql_result);
if ($sql_arr['ident_count'] <= 1)
return false;
$this->db->query(
"UPDATE ".get_table_name('identities')."
SET del=1
WHERE user_id=?
AND identity_id=?",
$this->ID,
$iid);
return $this->db->affected_rows();
}
/**
* Make this identity the default one for this user
*
* @param int The identity ID
*/
function set_default($iid)
{
if ($this->ID && $iid)
{
$this->db->query(
"UPDATE ".get_table_name('identities')."
SET ".$this->db->quoteIdentifier('standard')."='0'
WHERE user_id=?
AND identity_id<>?
AND del<>1",
$this->ID,
$iid);
}
}
/**
* Update user's last_login timestamp
*/
function touch()
{
if ($this->ID)
{
$this->db->query(
"UPDATE ".get_table_name('users')."
SET last_login=".$this->db->now()."
WHERE user_id=?",
$this->ID);
}
}
/**
* Clear the saved object state
*/
function reset()
{
$this->ID = null;
$this->data = null;
}
/**
* Find a user record matching the given name and host
*
* @param string IMAP user name
* @param string IMAP host name
* @return object rcube_user New user instance
*/
static function query($user, $host)
{
$dbh = rcmail::get_instance()->get_dbh();
// query for matching user name
$query = "SELECT * FROM ".get_table_name('users')." WHERE mail_host=? AND %s=?";
$sql_result = $dbh->query(sprintf($query, 'username'), $host, $user);
// query for matching alias
if (!($sql_arr = $dbh->fetch_assoc($sql_result))) {
$sql_result = $dbh->query(sprintf($query, 'alias'), $host, $user);
$sql_arr = $dbh->fetch_assoc($sql_result);
}
// user already registered -> overwrite username
if ($sql_arr)
return new rcube_user($sql_arr['user_id'], $sql_arr);
else
return false;
}
/**
* Create a new user record and return a rcube_user instance
*
* @param string IMAP user name
* @param string IMAP host
* @return object rcube_user New user instance
*/
static function create($user, $host)
{
$user_name = '';
$user_email = '';
$rcmail = rcmail::get_instance();
$data = $rcmail->plugins->exec_hook('create_user', array('user'=>$user, 'user_name'=>$user_name, 'user_email'=>$user_email));
$user_name = $data['user_name'];
$user_email = $data['user_email'];
+
+ // plugin aborted this operation
+ if ($data['abort'])
+ return false;
$dbh = $rcmail->get_dbh();
// try to resolve user in virtuser table and file
if ($user_email != '' && !strpos($user, '@')) {
if ($email_list = self::user2email($user, false))
$user_email = $email_list[0];
}
$dbh->query(
"INSERT INTO ".get_table_name('users')."
(created, last_login, username, mail_host, alias, language)
VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?, ?)",
strip_newlines($user),
strip_newlines($host),
strip_newlines($data['alias'] ? $data['alias'] : $user_email),
$_SESSION['language']);
if ($user_id = $dbh->insert_id(get_sequence_name('users')))
{
$mail_domain = $rcmail->config->mail_domain($host);
if ($user_email=='')
$user_email = strpos($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain);
if ($user_name == '') {
$user_name = $user != $user_email ? $user : '';
}
if (empty($email_list))
$email_list[] = strip_newlines($user_email);
// identities_level check
if (count($email_list) > 1 && $rcmail->config->get('identities_level', 0) > 1)
$email_list = array($email_list[0]);
// create new identities records
$standard = 1;
foreach ($email_list as $email) {
- $dbh->query(
- "INSERT INTO ".get_table_name('identities')."
- (user_id, del, standard, name, email)
- VALUES (?, 0, ?, ?, ?)",
- $user_id,
- $standard,
- strip_newlines($user_name),
- preg_replace('/^@/', $user . '@', $email));
+ $plugin = $RCMAIL->plugins->exec_hook('create_identity', array('record' => array(
+ 'login' => true,
+ 'user_id' => $user_id,
+ 'name' => strip_newlines($user_name),
+ 'email' => $email,
+ 'standard' => $standard)));
+
+ if (!$plugin['abort'] && $plugin['record']['name'] && $plugin['record']['email']) {
+ $dbh->query(
+ "INSERT INTO ".get_table_name('identities')."
+ (user_id, del, standard, name, email)
+ VALUES (?, 0, ?, ?, ?)",
+ $user_id,
+ $plugin['record']['standard'],
+ $plugin['record']['name'],
+ $plugin['record']['email']);
+ }
$standard = 0;
}
}
else
{
raise_error(array(
'code' => 500,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Failed to create new user"), true, false);
}
return $user_id ? new rcube_user($user_id) : false;
}
/**
* Resolve username using a virtuser file
*
* @param string E-mail address to resolve
* @return string Resolved IMAP username
*/
static function email2user($email)
{
$r = self::findinvirtual('/^' . preg_quote($email, '/') . '\s/');
for ($i=0; $i<count($r); $i++)
{
$data = trim($r[$i]);
$arr = preg_split('/\s+/', $data);
if (count($arr) > 0)
return trim($arr[count($arr)-1]);
}
return NULL;
}
/**
* Resolve e-mail address from virtuser file/table
*
* @param string User name
* @param boolean If true returns first found entry
* @return mixed Resolved e-mail address string or array of strings
*/
static function user2email($user, $first=true)
{
$result = array();
$rcmail = rcmail::get_instance();
$dbh = $rcmail->get_dbh();
// SQL lookup
if ($virtuser_query = $rcmail->config->get('virtuser_query')) {
$sql_result = $dbh->query(preg_replace('/%u/', $dbh->escapeSimple($user), $virtuser_query));
while ($sql_arr = $dbh->fetch_array($sql_result))
if (strpos($sql_arr[0], '@')) {
$result[] = $sql_arr[0];
if ($first)
return $result[0];
}
}
// File lookup
$r = self::findinvirtual('/\s' . preg_quote($user, '/') . '\s*$/');
for ($i=0; $i<count($r); $i++)
{
$data = $r[$i];
$arr = preg_split('/\s+/', $data);
if (count($arr) > 0 && strpos($arr[0], '@'))
{
$result[] = trim(str_replace('\\@', '@', $arr[0]));
if ($first)
return $result[0];
}
}
return empty($result) ? NULL : $result;
}
/**
* Find matches of the given pattern in virtuser file
*
* @param string Regular expression to search for
* @return array Matching entries
*/
private static function findinvirtual($pattern)
{
$result = array();
$virtual = null;
if ($virtuser_file = rcmail::get_instance()->config->get('virtuser_file'))
$virtual = file($virtuser_file);
if (empty($virtual))
return $result;
// check each line for matches
foreach ($virtual as $line)
{
$line = trim($line);
if (empty($line) || $line{0}=='#')
continue;
if (preg_match($pattern, $line))
$result[] = $line;
}
return $result;
}
}
diff --git a/program/steps/settings/save_identity.inc b/program/steps/settings/save_identity.inc
index 754e86c55..900c2d3d9 100644
--- a/program/steps/settings/save_identity.inc
+++ b/program/steps/settings/save_identity.inc
@@ -1,126 +1,126 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/settings/save_identity.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Save an identity record or to add a new one |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
define('IDENTITIES_LEVEL', intval($RCMAIL->config->get('identities_level', 0)));
$a_save_cols = array('name', 'email', 'organization', 'reply-to', 'bcc', 'standard', 'signature', 'html_signature');
$a_html_cols = array('signature');
$a_boolean_cols = array('standard', 'html_signature');
$updated = $default_id = false;
// check input
if (empty($_POST['_name']) || (empty($_POST['_email']) && IDENTITIES_LEVEL != 1 && IDENTITIES_LEVEL != 3))
{
$OUTPUT->show_message('formincomplete', 'warning');
rcmail_overwrite_action('edit-identity');
return;
}
$save_data = array();
foreach ($a_save_cols as $col)
{
$fname = '_'.$col;
if (isset($_POST[$fname]))
$save_data[$col] = get_input_value($fname, RCUBE_INPUT_POST, in_array($col, $a_html_cols));
}
// set "off" values for checkboxes that were not checked, and therefore
// not included in the POST body.
foreach ($a_boolean_cols as $col)
{
$fname = '_' . $col;
if (!isset($_POST[$fname]))
$save_data[$col] = 0;
}
// unset email address if user has no rights to change it
if (IDENTITIES_LEVEL == 1 || IDENTITIES_LEVEL == 3)
unset($save_data['email']);
// update an existing contact
if ($_POST['_iid'])
{
$iid = get_input_value('_iid', RCUBE_INPUT_POST);
$plugin = $RCMAIL->plugins->exec_hook('save_identity', array('id' => $iid, 'record' => $save_data));
$save_data = $plugin['record'];
if (!$plugin['abort'] && ($updated = $USER->update_identity($iid, $save_data)))
{
$OUTPUT->show_message('successfullysaved', 'confirmation');
if (!empty($_POST['_standard']))
$default_id = get_input_value('_iid', RCUBE_INPUT_POST);
if ($_POST['_framed'])
{
// update the changed col in list
// ...
}
}
else if ($plugin['abort'] || $DB->is_error())
{
// show error message
$OUTPUT->show_message('errorsaving', 'error', null, false);
rcmail_overwrite_action('edit-identity');
return;
}
}
// insert a new identity record
else if (IDENTITIES_LEVEL < 2)
{
if (IDENTITIES_LEVEL == 1)
$save_data['email'] = $RCMAIL->user->get_username();
- $plugin = $RCMAIL->plugins->exec_hook('create_identity', array('id' => $iid, 'record' => $save_data));
+ $plugin = $RCMAIL->plugins->exec_hook('create_identity', array('record' => $save_data));
$save_data = $plugin['record'];
if (!$plugin['abort'] && $save_data['email'] && ($insert_id = $USER->insert_identity($save_data)))
{
$OUTPUT->show_message('successfullysaved', 'confirmation', null, false);
$_GET['_iid'] = $insert_id;
if (!empty($_POST['_standard']))
$default_id = $insert_id;
}
else
{
// show error message
$OUTPUT->show_message('errorsaving', 'error', null, false);
rcmail_overwrite_action('edit-identity');
return;
}
}
else
$OUTPUT->show_message('opnotpermitted', 'error');
// mark all other identities as 'not-default'
if ($default_id)
$USER->set_default($default_id);
// go to next step
rcmail_overwrite_action('identities');
?>

File Metadata

Mime Type
text/x-diff
Expires
Sat, Mar 1, 2:17 PM (23 m, 47 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
167238
Default Alt Text
(48 KB)

Event Timeline