source: subversion/branches/devel-vnext/program/include/rcube.php @ 957

Last change on this file since 957 was 957, checked in by tomekp, 5 years ago

first part of devel-vnext to trunk merging process
this broke the devel-vnext branch, we switched to error_reporting(E_ALL|E_STRICT)
more to come shortly

File size: 62.1 KB
Line 
1<?php
2/*
3 +-----------------------------------------------------------------------+
4 | program/include/rcube.php                                             |
5 |                                                                       |
6 | This file is part of the RoundCube Webmail client                     |
7 | Copyright (C) 2005-2007, RoundCube Dev, - Switzerland                 |
8 | Licensed under the GNU GPL                                            |
9 |                                                                       |
10 | PURPOSE:                                                              |
11 |   Provide basic functions for the webmail package                     |
12 |                                                                       |
13 +-----------------------------------------------------------------------+
14 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
15 |         Till Klampaeckel <till@php.net>                               |
16 +-----------------------------------------------------------------------+
17
18 $Id: main.inc 567 2007-05-17 18:41:24Z thomasb $
19
20*/
21
22
23require_once 'lib/des.inc';
24require_once 'lib/utf7.inc';
25require_once 'lib/utf8.class.php';
26
27/**
28 * rcube
29 *
30 * @author   Thomas Bruederli <roundcube@gmail.com>
31 * @author   Till Klampaeckel <till@php.net>
32 * @license  GPL
33 * @category main
34 * @package  roundcube
35 * @todo     Docs, docs, docs!
36 * @todo     Maybe unit tests.
37 * @since    0.1-rc1
38 */
39class rcube {
40    const INPUT_GET  = 0x0101;
41    const INPUT_POST = 0x0102;
42    const INPUT_GPC  = 0x0103;
43   
44   
45    /**
46     * register session and connect to server
47     *
48     * @todo   Remove this include from here. This is not good for bytecode caching.
49     * @todo   Maybe implement autoload
50     * @param  string $task
51     * @return void
52     */
53    static function startup($task = 'mail') {
54        $registry = rcube_registry::get_instance();
55        $registry->set('task', $task, 'core');
56
57        // load configuration
58        $CONFIG = self::load_config();
59
60        // set session garbage collecting time according to session_lifetime
61        if (!empty($CONFIG['session_lifetime'])) {
62            ini_set('session.gc_maxlifetime', ($CONFIG['session_lifetime']) * 120);
63        }
64
65        $DB = new rcube_db($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']);
66        $DB->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql';
67        $DB->db_connect('w');
68
69        $registry->set('DB', $DB, 'core');
70
71        // use database for storing session data
72        include_once 'include/session.inc';
73
74        // init session
75        session_start();
76        $registry->set('sess_id', session_id(), 'core');
77
78        // create session and set session vars
79        if (isset($_SESSION['auth_time']) !== true) {
80            $_SESSION['user_lang'] = rcube::language_prop($CONFIG['locale_string']);
81            $_SESSION['auth_time'] = time();
82            $_SESSION['temp']      = true;
83        }
84
85        // set session vars global
86        $user_lang = rcube::language_prop($_SESSION['user_lang']);
87        $registry->set('user_lang', $user_lang, 'core');
88
89        // overwrite config with user preferences
90        if (is_array($_SESSION['user_prefs'])) {
91            foreach ($_SESSION['user_prefs'] as $key => $prop)
92                $registry->set($key, $prop, 'config');
93           
94            $CONFIG = array_merge($CONFIG, $_SESSION['user_prefs']);
95        }
96        $registry->set('CONFIG', $CONFIG, 'core');
97
98        // reset some session parameters when changing task
99        if ($_SESSION['task'] != $task) {
100            unset($_SESSION['page']);
101        }
102        // set current task to session
103        $_SESSION['task'] = $task;
104
105        // create IMAP object
106        if ($task == 'mail') {
107            self::imap_init();
108        }
109
110        // set localization
111        if ($CONFIG['locale_string']) {
112            setlocale(LC_ALL, $CONFIG['locale_string']);
113        }
114        else if ($user_lang) {
115            setlocale(LC_ALL, $user_lang);
116        }
117       
118        register_shutdown_function(array('rcube', 'shutdown'));
119    }
120
121
122    /**
123     * Load roundcube configuration array
124     *
125     * @return array Named configuration parameters
126     */
127    static function load_config()
128    {
129        // load config file (throw php error if fails)
130        include_once INSTALL_PATH . 'config/main.inc.php';
131        $conf = is_array($rcmail_config) ? $rcmail_config : array();
132
133        // load host-specific configuration
134        $conf = self::load_host_config($conf);
135
136        $conf['skin_path'] = $conf['skin_path'] ? unslashify($conf['skin_path']) : 'skins/default';
137
138        // load db conf
139        include_once INSTALL_PATH . 'config/db.inc.php';
140        $conf = array_merge($conf, $rcmail_config);
141
142        if (empty($conf['log_dir'])) {
143            $conf['log_dir'] = INSTALL_PATH . 'logs';
144        }
145        else {
146            $conf['log_dir'] = unslashify($conf['log_dir']);
147        }
148        // set PHP error logging according to config
149        if ($conf['debug_level'] & 1) {
150            ini_set('log_errors', 1);
151            ini_set('error_log', $conf['log_dir'].'/errors');
152        }
153        if ($conf['debug_level'] & 4) {
154            ini_set('display_errors', 1);
155        }
156        else {
157            ini_set('display_errors', 0);
158        }
159       
160        // copy all config parameters to registry
161        $registry = rcube_registry::get_instance();
162        foreach ($conf as $key => $prop)
163            $registry->set($key, $prop, 'config');
164       
165        return $conf;
166    }
167
168
169    /**
170     * Load a host-specific config file if configured
171     * This will merge the host specific configuration with the given one
172     *
173     * @param array Global configuration parameters
174     */
175    static function load_host_config($config)
176    {
177        $fname = null;
178
179        if (is_array($config['include_host_config'])) {
180            $fname = $config['include_host_config'][$_SERVER['HTTP_HOST']];
181        }
182        else if (!empty($config['include_host_config'])) {
183            $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php';
184        }
185        if ($fname && is_file(INSTALL_PATH . 'config/' . $fname)) {
186            include(INSTALL_PATH . 'config/' . $fname);
187            $config = array_merge($config, $rcmail_config);
188        }
189       
190        return $config;
191    }
192
193
194    /**
195     * Create unique authorization hash
196     *
197     * @param string Session ID
198     * @param int Timestamp
199     * @return string The generated auth hash
200     */
201    static function auth_hash($sess_id, $ts)
202    {
203        $registry = rcube_registry::get_instance();
204        $CONFIG   = $registry->get_all('config');
205
206        $auth_string = sprintf(
207                            'rcmail*sess%sR%s*Chk:%s;%s',
208                            $sess_id,
209                            $ts,
210                            $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***',
211                            $_SERVER['HTTP_USER_AGENT']
212        );
213
214        if (function_exists('sha1')) {
215            return sha1($auth_string);
216        }
217        return md5($auth_string);
218    }
219
220
221    /**
222     * Check the auth hash sent by the client against the local session credentials
223     *
224     * @return boolean True if valid, False if not
225     */
226    static function authenticate_session()
227    {
228        $registry       = rcube_registry::get_instance();
229        $CONFIG         = $registry->get_all('config');
230        $SESS_CLIENT_IP = $registry->get('SESS_CLIENT_IP', 'core');
231        $SESS_CHANGED   = $registry->get('SESS_CHANGED', 'core');
232
233        // advanced session authentication
234        if ($CONFIG['double_auth']) {
235            $now = time();
236            $valid = ($_COOKIE['sessauth'] == self::auth_hash(session_id(), $_SESSION['auth_time']) ||
237                  $_COOKIE['sessauth'] == self::auth_hash(session_id(), $_SESSION['last_auth']));
238
239            // renew auth cookie every 5 minutes (only for GET requests)
240            if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300)) {
241                $_SESSION['last_auth'] = $_SESSION['auth_time'];
242                $_SESSION['auth_time'] = $now;
243                setcookie('sessauth', self::auth_hash(session_id(), $now));
244            }
245        }
246        else {
247            $valid = $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true;
248        }
249        // check session filetime
250        if (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < time()) {
251            $valid = false;
252        }
253        return $valid;
254    }
255
256    /**
257     * create IMAP object and connects to server if param
258     * is set to true.
259     *
260     * @param  bool True if connection should be established
261     * @return void
262     * @uses   rcube_registry::get_instance()
263     */
264    static function imap_init($connect=FALSE)
265    {
266        $registry = rcube_registry::get_instance();
267        $CONFIG   = $registry->get_all('config');
268        $DB       = $registry->get('DB', 'core');
269        $OUTPUT   = $registry->get('OUTPUT', 'core');
270
271        $IMAP = new rcube_imap($DB);
272
273        $IMAP->debug_level  = $CONFIG['debug_level'];
274        $IMAP->skip_deleted = $CONFIG['skip_deleted'];
275
276        // connect with stored session data
277        if ($connect) {
278            $conn = $IMAP->connect(
279                $_SESSION['imap_host'],
280                $_SESSION['username'],
281                self::decrypt_passwd($_SESSION['password']),
282                $_SESSION['imap_port'],
283                $_SESSION['imap_ssl']
284            );
285            $registry->set('IMAP', $IMAP, 'core');
286            if ($conn === false) {
287                $OUTPUT->show_message('imaperror', 'error');
288            }
289            self::set_imap_prop();
290        }
291
292        // enable caching of imap data
293        if ($CONFIG['enable_caching'] === true) {
294            $IMAP->set_caching(true);
295        }
296        // set pagesize from config
297        if (isset($CONFIG['pagesize'])) {
298            $IMAP->set_pagesize($CONFIG['pagesize']);
299        }
300       
301        $registry->set('IMAP', $IMAP, 'core');
302    }
303
304    /**
305     * Set root dir and last stored mailbox
306     * This must be done AFTER connecting to the server!
307     */
308    static function set_imap_prop()
309    {
310        $registry         = rcube_registry::get_instance();
311        $IMAP             = $registry->get('IMAP', 'core');
312        $imap_root        = $registry->get('imap_root', 'config');
313        $default_folders  = $registry->get('default_imap_folders', 'config');
314
315        // set root dir from config
316        if (!empty($imap_root)) {
317            $IMAP->set_rootdir($imap_root);
318        }
319        if (is_array($default_folders)) {
320            $IMAP->set_default_mailboxes($default_folders);
321        }
322        if (!empty($_SESSION['mbox'])) {
323            $IMAP->set_mailbox($_SESSION['mbox']);
324        }
325        if (isset($_SESSION['page'])) {
326            $IMAP->set_page($_SESSION['page']);
327        }
328    }
329
330
331    /**
332     * Do these things on script shutdown
333     */
334    static function shutdown()
335    {
336        $registry = rcube_registry::get_instance();
337        $IMAP     = $registry->get('IMAP', 'core');
338
339        if (is_object($IMAP)) {
340            $IMAP->close();
341            $IMAP->write_cache();
342        }
343
344        // before closing the database connection, write session data
345        session_write_close();
346    }
347
348    /**
349     * Destroy session data and remove cookie
350     */
351    static function kill_session()
352    {
353        // save user preferences
354        $a_user_prefs = $_SESSION['user_prefs'];
355        if (!is_array($a_user_prefs)) {
356            $a_user_prefs = array();
357        }
358        if (
359            (
360                isset($_SESSION['sort_col'])
361                && $_SESSION['sort_col'] != $a_user_prefs['message_sort_col']
362            )
363            ||
364            (
365                isset($_SESSION['sort_order'])
366                && $_SESSION['sort_order'] != $a_user_prefs['message_sort_order']
367            )
368        ) {
369            $a_user_prefs['message_sort_col'] = $_SESSION['sort_col'];
370            $a_user_prefs['message_sort_order'] = $_SESSION['sort_order'];
371            self::save_user_prefs($a_user_prefs);
372        }
373
374        $_SESSION = array(
375                        'user_lang' => $GLOBALS['user_lang'],
376                        'auth_time' => time(),
377                        'temp' => true
378        );
379        setcookie('sessauth', '-del-', time()-60);
380        session_destroy();
381    }
382
383
384    /**
385     * return correct name for a specific database table
386     *
387     * @param  string Table name
388     * @return string Translated table name
389     * @uses   rcube_registry::get_instance()
390     */
391    static function get_table_name($table)
392    {
393        $registry = rcube_registry::get_instance();
394        $CONFIG   = $registry->get_all('config');
395
396        // return table name if configured
397        $config_key = 'db_table_' . $table;
398
399        if (strlen($CONFIG[$config_key])) {
400            return $CONFIG[$config_key];
401        }
402        return $table;
403    }
404
405
406    /**
407     * Return correct name for a specific database sequence
408     * (used for Postres only)
409     *
410     * @param string Secuence name
411     * @return string Translated sequence name
412     */
413    static function get_sequence_name($sequence)
414    {
415        $registry = rcube_registry::get_instance();
416
417        if ($seq = $registry->get('db_sequence_' . $sequence, 'config')) {
418            return $seq;
419        }
420       
421        // return table name if not configured
422        return $table;
423    }
424
425
426    /**
427     * Init output object for GUI and add common scripts.
428     * This will instantiate a rcube_template object and set
429     * environment vars according to the current session and configuration
430     */
431    static function load_gui()
432    {
433        $registry  = rcube_registry::get_instance();
434        $config    = $registry->get_all('config');
435
436        // init output page
437        $OUTPUT = new rcube_template();
438
439        if (is_array($config['javascript_config'])) {
440            foreach ($config['javascript_config'] as $js_config_var) {
441                $OUTPUT->set_env($js_config_var, $config[$js_config_var]);
442            }
443        }
444
445        if (!empty($GLOBALS['_framed'])) {
446            $OUTPUT->set_env('framed', true);
447        }
448
449        // add some basic label to client
450        $OUTPUT->add_label('loading', 'movingmessage');
451       
452        $registry->set('OUTPUT', $OUTPUT, 'core');
453       
454        // set locale setting
455        self::set_locale($registry->get('user_lang', 'core'));
456    }
457   
458   
459    /**
460     * Create an output object for JSON responses
461     * and register it to the global registry
462     */
463    static function init_json()
464    {
465        $registry  = rcube_registry::get_instance();
466       
467        $OUTPUT = new rcube_json_output();
468        $registry->set('OUTPUT', $OUTPUT, 'core');
469       
470        // set locale setting
471        self::set_locale($registry->get('user_lang', 'core'));
472    }
473
474
475    // set localization charset based on the given language
476    static function set_locale($lang)
477    {
478        $registry        = rcube_registry::get_instance();
479        $charset         = $registry->get('charset', 'config', RCMAIL_CHARSET);
480        $OUTPUT          = $registry->get('OUTPUT', 'core');
481        $MBSTRING        = $registry->get('MBSTRING', 'core');
482        $mbstring_loaded = $registry->get('mbstring_loaded', 'core');
483       
484        // settings for mbstring module (by Tadashi Jokagi)
485        if (is_null($mbstring_loaded)) {
486            $MBSTRING = $mbstring_loaded = extension_loaded("mbstring");
487        }
488        else {
489            $MBSTRING = $mbstring_loaded = FALSE;
490        }
491
492        if ($MBSTRING) {
493            mb_internal_encoding($charset);
494        }
495       
496        $registry->set('MBSTRING', $MBSTRING, 'core');
497        $registry->set('mbstring_loaded', $mbstring_loaded, 'core');
498        $registry->set('OUTPUT_CHARSET', $charset, 'core');
499
500        $OUTPUT->set_charset($charset);
501    }
502
503
504    /**
505     * auto-select IMAP host based on the posted login information
506     *
507     * @link   ./index.php
508     * @todo   Remove reference to $_POST superglobal.
509     */
510    static function autoselect_host()
511    {
512        $registry = rcube_registry::get_instance();
513        $default_host = $registry->get('default_host', 'config');
514
515        $host = '';
516        if (isset($_POST['_host']) && empty($_POST['_host']) === false) {
517            $host .= rcube::get_input_value('_host', rcube::INPUT_POST);
518        }
519        else {
520            $host .= $default_host;
521        }
522
523        if (is_array($host)) {
524            list($user, $domain) = explode('@', rcube::get_input_value('_user', rcube::INPUT_POST));
525            if (!empty($domain)) {
526                foreach ($host as $imap_host => $mail_domains) {
527                    if (is_array($mail_domains) && in_array($domain, $mail_domains)) {
528                        $host = $imap_host;
529                        break;
530                    }
531                }
532            }
533
534            // take the first entry if $host is still an array
535            if (is_array($host)) {
536                $host = array_shift($host);
537            }
538        }
539
540        return $host;
541    }
542
543    /**
544     * Perfom login to the IMAP server and to the webmail service.
545     * This will also create a new user entry if auto_create_user is configured.
546     *
547     * @param string IMAP user name
548     * @param string IMAP password
549     * @param string IMAP host
550     * @return boolean True on success, False on failure
551     */
552    static function login($user, $pass, $host=null)
553    {
554        $user_id = null;
555
556        $registry  = rcube_registry::get_instance();
557        $CONFIG    = $registry->get_all('config');
558        $IMAP      = $registry->get('IMAP', 'core');
559        $DB        = $registry->get('DB', 'core');
560        $user_lang = $registry->get('user_lang', 'core');
561
562        if (is_null($host) === true) {
563            $host = $CONFIG['default_host'];
564        }
565        // Validate that selected host is in the list of configured hosts
566        if (is_array($CONFIG['default_host'])) {
567            $allowed = false;
568            foreach ($CONFIG['default_host'] as $key => $host_allowed) {
569                if (!is_numeric($key)) {
570                    $host_allowed = $key;
571                }
572                if ($host == $host_allowed) {
573                    $allowed = true;
574                    break;
575                }
576            }
577            if (!$allowed) {
578                return false;
579            }
580        }
581        else if (!empty($CONFIG['default_host']) && $host != $CONFIG['default_host']) {
582            return false;
583        }
584
585        // parse $host URL
586        $a_host = parse_url($host);
587        if ($a_host['host']) {
588            $host = $a_host['host'];
589            $imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? true : false;
590            $imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : $CONFIG['default_port']);
591        }
592        else {
593            $imap_port = $CONFIG['default_port'];
594        }
595
596        /**
597         * Modify username with domain if required
598         * Inspired by Marco <P0L0_notspam_binware.org>
599         */
600        // Check if we need to add domain
601        //tfk_debug('User #1: ' . $user);
602        //tfk_debug('Host: ' . $CONFIG['username_domain']);
603        if (!empty($CONFIG['username_domain']) && !strstr($user, '@')) {
604            if (is_array($CONFIG['username_domain']) && isset($CONFIG['username_domain'][$host])) {
605                $user .= '@' . $CONFIG['username_domain'][$host];
606            }
607            else if (is_string($CONFIG['username_domain'])) {
608                $user .= '@' . $CONFIG['username_domain'];
609            }
610        }
611        //tfk_debug('User #2: ' . $user);
612
613        // try to resolve email address from virtuser table
614        if (!empty($CONFIG['virtuser_file']) && strstr($user, '@')) {
615            $user = rcube::email2user($user);
616        }
617
618        // query if user already registered
619        $_query = "SELECT user_id, username, language, preferences";
620        $_query.= " FROM " . self::get_table_name('users');
621        $_query.= " WHERE mail_host=?";
622        $_query.= " AND (username=? OR alias=?)";
623
624        $sql_result = $DB->query(
625                            $_query,
626                            $host,
627                            $user,
628                            $user
629        );
630        if ($DB->db_error === true) {
631            return FALSE;
632        }
633        // user already registered -> overwrite username
634        if ($sql_arr = $DB->fetch_assoc($sql_result)) {
635            $user_id = $sql_arr['user_id'];
636            $user    = $sql_arr['username'];
637        }
638
639        // exit if IMAP login failed
640        if (!($imap_login  = $IMAP->connect($host, $user, $pass, $imap_port, $imap_ssl))) {
641            return FALSE;
642        }
643        // user already registered
644        if ($user_id && !empty($sql_arr)) {
645            // get user prefs
646            if (strlen($sql_arr['preferences'])) {
647                $user_prefs = unserialize($sql_arr['preferences']);
648                $_SESSION['user_prefs'] = $user_prefs;
649                array_merge($CONFIG, $user_prefs);
650            }
651
652
653            // set user specific language
654            if (strlen($sql_arr['language'])) {
655                $user_lang = $_SESSION['user_lang'] = $sql_arr['language'];
656            }
657            // update user's record
658            $_query = "UPDATE " . self::get_table_name('users');
659            $_query.= " SET last_login=" . $DB->now();
660            $_query.= " WHERE user_id=?";
661            $DB->query($_query, $user_id);
662        }
663        // create new system user
664        else if ($CONFIG['auto_create_user']) {
665            $user_id = self::create_user($user, $host);
666        }
667
668        //tfk_debug('User id: ' . $user_id);
669
670        if (empty($user_id) === true) {
671            return false;
672        }
673        $_SESSION['user_id']    = $user_id;
674        $_SESSION['imap_host']  = $host;
675        $_SESSION['imap_port']  = $imap_port;
676        $_SESSION['imap_ssl']   = $imap_ssl;
677        $_SESSION['username']   = $user;
678        $_SESSION['user_lang']  = $user_lang;
679        $_SESSION['password']   = self::encrypt_passwd($pass);
680        $_SESSION['login_time'] = mktime();
681
682        /**
683         * If multi-SMTP servers, use correct one
684         * Otherwise, use the general SMTP server
685         * or use phpMail function
686         *
687         * @author Brett Patterson <brett@bpatterson.net>
688         * @author Till Klampaeckel <till@php.net>
689         */
690        if(is_array($CONFIG['smtp_server']) === true) {
691            if (isset($CONFIG['smtp_server'][$host]) === true) {
692                $_SESSION['smtp_server'] = $CONFIG['smtp_server'][$host];
693            }
694            else {
695                $_SESSION['smtp_server'] = 'phpMail';
696            }
697        }
698        else {
699            if (empty($CONFIG['smtp_server']) === false) {
700                $_SESSION['smtp_server'] = $CONFIG['smtp_server'];
701            }
702            else {
703                $_SESSION['smtp_server'] = 'phpMail';
704            }
705        }
706
707        // force reloading complete list of subscribed mailboxes
708        self::set_imap_prop();
709        $IMAP->clear_cache('mailboxes');
710        $IMAP->create_default_folders();
711
712        return TRUE;
713    }
714
715
716    /**
717     * Create new entry in users and identities table
718     *
719     * @param string User name
720     * @param string IMAP host
721     * @return mixed New user ID or False on failure
722     */
723    static function create_user($user, $host)
724    {
725        $registry = rcube_registry::get_instance();
726        $DB       = $registry->get('DB', 'core');
727        $CONFIG   = $registry->get_all('config');
728        $IMAP     = $registry->get('IMAP', 'core');
729
730        $user_email = '';
731
732        // try to resolve user in virtusertable
733        if (!empty($CONFIG['virtuser_file']) && strstr($user, '@') === FALSE) {
734            $user_email = self::user2email($user);
735        }
736        else { // failover
737            $user_email = $user;
738        }
739        $_query = "INSERT INTO " . self::get_table_name('users');
740        $_query.= " (created, last_login, username, mail_host, alias, language)";
741        $_query.= " VALUES (" . $DB->now() . ", " . $DB->now() . ", %s, %s, %s, %s)";
742
743        $_query = sprintf(
744                    $_query,
745                    $DB->quote(strip_newlines($user)),
746                    $DB->quote(strip_newlines($host)),
747                    $DB->quote(strip_newlines($user_email)),
748                    $DB->quote($_SESSION['user_lang'])
749        );
750        rcube::tfk_debug($_query);
751
752
753        $DB->query($_query);
754
755        if ($user_id = $DB->insert_id(self::get_sequence_name('users'))) {
756            $mail_domain = self::mail_domain($host);
757
758            if ($user_email=='') {
759                $user_email = strstr($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain);
760            }
761            $user_name = $user!=$user_email ? $user : '';
762
763            // try to resolve the e-mail address from the virtuser table
764            if (
765                !empty($CONFIG['virtuser_query'])
766                && ($sql_result = $DB->query(preg_replace('/%u/', $user, $CONFIG['virtuser_query'])))
767                && ($DB->num_rows()>0)
768            ) {
769                while ($sql_arr = $DB->fetch_array($sql_result)) {
770                    $_query = "INSERT INTO " . self::get_table_name('identities');
771                    $_query.= " (user_id, del, standard, name, email)";
772                    $_query.= " VALUES (?, 0, 1, ?, ?)";
773                    $DB->query(
774                            $_query,
775                            $user_id,
776                            strip_newlines($user_name),
777                            preg_replace('/^@/', $user . '@', $sql_arr[0])
778                    );
779                }
780            }
781            else {
782                // also create new identity records
783                $_query = "INSERT INTO " . self::get_table_name('identities');
784                $_query.= " (user_id, del, standard, name, email)";
785                $_query.= " VALUES (?, 0, 1, ?, ?)";
786                $DB->query(
787                        $_query,
788                        $user_id,
789                        strip_newlines($user_name),
790                        strip_newlines($user_email)
791                );
792            }
793
794            // get existing mailboxes
795            $a_mailboxes = $IMAP->list_mailboxes();
796        }
797        else {
798            rcube_error::raise(
799                array(
800                    'code' => 500,
801                    'type' => 'php',
802                    'line' => __LINE__,
803                    'file' => __FILE__,
804                    'message' => "Failed to create new user"
805                ),
806                TRUE,
807                FALSE
808            );
809        }
810        return $user_id;
811    }
812
813
814    /**
815     * Load virtuser table in array
816     *
817     * @return array Virtuser table entries
818     */
819    function get_virtualfile()
820    {
821        $registry = rcube_registry::get_instance();
822        $registry->get_all('config');
823        if (empty($CONFIG['virtuser_file']) || !is_file($CONFIG['virtuser_file'])) {
824            return FALSE;
825        }
826        // read file
827        $a_lines = file($CONFIG['virtuser_file']);
828        return $a_lines;
829    }
830
831
832    /**
833     * Find matches of the given pattern in virtuser table
834     *
835     * @param string Regular expression to search for
836     * @return array Matching entries
837     */
838    static function find_in_virtual($pattern)
839    {
840        $result  = array();
841        $virtual = self::get_virtualfile();
842        if ($virtual==FALSE) {
843            return $result;
844        }
845        // check each line for matches
846        foreach ($virtual as $line) {
847            $line = trim($line);
848            if (empty($line) || $line{0}=='#') {
849                continue;
850            }
851            if (eregi($pattern, $line)) {
852                $result[] = $line;
853            }
854        }
855        return $result;
856    }
857
858
859    /**
860     * Resolve username using a virtuser table
861     *
862     * @param string E-mail address to resolve
863     * @return string Resolved IMAP username
864     */
865    static function email2user($email)
866    {
867        $user = $email;
868        $r = self::find_in_virtual("^$email");
869
870        for ($i=0; $i<count($r); $i++) {
871            $data = $r[$i];
872            $arr = preg_split('/\s+/', $data);
873            if (count($arr)>0) {
874                $user = trim($arr[count($arr)-1]);
875                break;
876            }
877        }
878        return $user;
879    }
880
881
882    /**
883     * Resolve e-mail address from virtuser table
884     *
885     * @param string User name
886     * @return string Resolved e-mail address
887     */
888    static function user2email($user)
889    {
890        $email = "";
891        $r = self::find_in_virtual("$user$");
892
893        for ($i=0; $i<count($r); $i++) {
894            $data=$r[$i];
895            $arr = preg_split('/\s+/', $data);
896            if (count($arr)>0) {
897                $email = trim($arr[0]);
898                break;
899            }
900        }
901        return $email;
902    }
903
904
905    /**
906     * Write the given user prefs to the user's record
907     *
908     * @param mixed User prefs to save
909     * @return boolean True on success, False on failure
910     */
911    static function save_user_prefs($a_user_prefs)
912    {
913        $registry       = rcube_registry::get_instance();
914        $DB             = $registry->get('DB', 'core');
915        $CONFIG         = $registry->get_all('config');
916        $user_lang = $registry->get('user_lang', 'core');
917
918        $_query = "UPDATE " . self::get_table_name('users');
919        $_query.= " SET preferences=?,";
920        $_query.= " language=?";
921        $_query.= " WHERE user_id=?";
922        $DB->query(
923            $_query,
924            serialize($a_user_prefs),
925            $user_lang,
926            $_SESSION['user_id']
927        );
928
929        if ($DB->affected_rows()) {
930            $_SESSION['user_prefs'] = $a_user_prefs;
931            foreach ($a_user_prefs as $key => $value)
932                $registry->set($key, $value, 'config');
933            return true;
934        }
935
936        return false;
937    }
938
939
940    /**
941     * Overwrite action variable
942     *
943     * @param string New action value
944     */
945    static function override_action($action)
946    {
947        $registry = rcube_registry::get_instance();
948        $OUTPUT   = $registry->get('OUTPUT', 'core');
949        $GLOBALS['_action'] = $action;
950        $OUTPUT->set_env('action', $action);
951    }
952
953
954    /**
955     * Compose an URL for a specific action
956     *
957     * @param string  Request action
958     * @param array   More URL parameters
959     * @param string  Request task (omit if the same)
960     * @return The application URL
961     */
962    static function url($action, $p=array(), $task=null)
963    {
964        $registry   = rcube_registry::get_instance();
965        $COMM_PATH  = $registry->get('COMM_PATH', 'core');
966        $MAIN_TASKS = $registry->get('MAIN_TASKS', 'core');
967
968        $qstring = '';
969        $base = $COMM_PATH;
970
971        if ($task && in_array($task, $MAIN_TASKS)) {
972            $base = ereg_replace('_task=[a-z]+', '_task='.$task, $COMM_PATH);
973        }
974        if (is_array($p)) {
975            foreach ($p as $key => $val) {
976                $qstring .= '&'.urlencode($key).'='.urlencode($val);
977            }
978        }
979        return $base . ($action ? '&_action='.$action : '') . $qstring;
980    }
981
982
983    /**
984     * Encrypt IMAP password using DES encryption
985     *
986     * @param string Password to encrypt
987     * @return string Encryprted string
988     */
989    static function encrypt_passwd($pass)
990    {
991        $cypher = des(self::get_des_key(), $pass, 1, 0, NULL);
992        return base64_encode($cypher);
993    }
994
995    /**
996     * Decrypt IMAP password using DES encryption
997     *
998     * @param string Encrypted password
999     * @return string Plain password
1000     */
1001    static function decrypt_passwd($cypher)
1002    {
1003        $pass = des(self::get_des_key(), base64_decode($cypher), 0, 0, NULL);
1004        return preg_replace('/\x00/', '', $pass);
1005    }
1006
1007
1008    /**
1009     * Return a 24 byte key for the DES encryption
1010     *
1011     * @return string DES encryption key
1012     */
1013    static function get_des_key()
1014    {
1015        $registry = rcube_registry::get_instance();
1016        $CONFIG   = $registry->get_all('config');
1017        $key = !empty($CONFIG['des_key']) ? $CONFIG['des_key'] : 'rcmail?24BitPwDkeyF**ECB';
1018        $len = strlen($key);
1019
1020        // make sure the key is exactly 24 chars long
1021        if ($len<24) {
1022            $key .= str_repeat('_', 24-$len);
1023        }
1024        else if ($len>24) {
1025            substr($key, 0, 24);
1026        }
1027        return $key;
1028    }
1029
1030
1031    /**
1032     * Garbage collector function for temp files.
1033     * Remove temp files older than two days
1034     */
1035    function temp_gc()
1036    {
1037        $registry = rcube_registry::get_instance();
1038        $CONFIG   = $registry->get_all('config');
1039        $tmp      = unslashify($CONFIG['temp_dir']);
1040        $expire   = mktime() - 172800;  // expire in 48 hours
1041
1042        if (($dir = opendir($tmp)) === false) {
1043            return false;
1044        }
1045        while (($fname = readdir($dir)) !== false) {
1046            if ($fname{0} == '.')
1047                continue;
1048
1049            if (filemtime($tmp.'/'.$fname) < $expire)
1050                @unlink($tmp.'/'.$fname);
1051        }
1052        closedir($dir);
1053    }
1054
1055
1056    /**
1057     * Garbage collector for cache entries.
1058     * Remove all expired message cache records
1059     */
1060    static function message_cache_gc()
1061    {
1062        $registry = rcube_registry::get_instance();
1063        $DB       = $registry->get('DB', 'core');
1064        $CONFIG   = $registry->get_all('config');
1065
1066        // no cache lifetime configured
1067        if (empty($CONFIG['message_cache_lifetime'])) {
1068            return;
1069        }
1070        // get target timestamp
1071        $ts = get_offset_time($CONFIG['message_cache_lifetime'], -1);
1072
1073        $_query = "DELETE FROM " . self::get_table_name('messages');
1074        $_query.= " WHERE created < " . $DB->fromunixtime($ts);
1075        $DB->query($_query);
1076    }
1077
1078
1079    /**
1080     * Check if a specific template exists
1081     *
1082     * @param string Template name
1083     * @return bool True if template exists
1084     */
1085    static function template_exists($name)
1086    {
1087        $registry = rcube_registry::get_instance();
1088        $CONFIG   = $registry->get_all('config');
1089        $skin_path = $CONFIG['skin_path'];
1090
1091        // check template file
1092        return is_file("$skin_path/templates/$name.html");
1093    }
1094
1095
1096    /**
1097     * Wrapper for rcube_template::parse()
1098     *
1099     * @deprecated
1100     */
1101    static function parse_template($name='main', $exit=true)
1102    {
1103        $registry = rcube_registry::get_instance();
1104        $OUTPUT   = $registry->get('OUTPUT', 'core');
1105        $OUTPUT->send($name, $exit);
1106    }
1107
1108    /**
1109     * Create a HTML table based on the given data
1110     *
1111     * @param  array  Named table attributes
1112     * @param  mixed  Table row data. Either a two-dimensional array or a valid SQL result set
1113     * @param  array  List of cols to show
1114     * @param  string Name of the identifier col
1115     * @return string HTML table code
1116     * @uses   rcube_registry::get_instance()
1117     * @uses   Q()
1118     */
1119    static function table_output($attrib, $table_data, $a_show_cols, $id_col)
1120    {
1121        $registry = rcube_registry::get_instance();
1122        $DB       = $registry->get('DB', 'core');
1123        $OUTPUT   = null;
1124
1125        // allow the following attributes to be added to the <table> tag
1126        $attrib_str = rcube::create_attrib_string(
1127                        $attrib,
1128                        array(
1129                            'style',
1130                            'class',
1131                            'id',
1132                            'cellpadding',
1133                            'cellspacing',
1134                            'border',
1135                            'summary'
1136                        )
1137        );
1138        $table = '<table' . $attrib_str . ">\n";
1139
1140        // add table title
1141        $table .= "<thead><tr>\n";
1142
1143        foreach ($a_show_cols as $col) {
1144            $table .= '<td class="'.$col.'">' . Q(rcube::gettext($col)) . "</td>\n";
1145        }
1146        $table .= "</tr></thead>\n<tbody>\n";
1147
1148        $c = 0;
1149        if (!is_array($table_data)) {
1150            while ($table_data && ($sql_arr = $DB->fetch_assoc($table_data))) {
1151                $zebra_class = $c%2 ? 'even' : 'odd';
1152
1153                $table .= sprintf(
1154                            '<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n",
1155                            $sql_arr[$id_col]
1156                );
1157
1158                // format each col
1159                foreach ($a_show_cols as $col) {
1160                    $cont = Q($sql_arr[$col]);
1161                    $table .= '<td class="'.$col.'">' . $cont . "</td>\n";
1162                }
1163
1164                $table .= "</tr>\n";
1165                $c++;
1166            }
1167        }
1168        else {
1169            foreach ($table_data as $row_data) {
1170                $zebra_class = $c%2 ? 'even' : 'odd';
1171
1172                $table .= sprintf(
1173                            '<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n",
1174                            $row_data[$id_col]
1175                );
1176
1177                // format each col
1178                foreach ($a_show_cols as $col) {
1179                    $cont = $row_data[$col];
1180                    if (strstr($cont, '<roundcube')) {
1181                        if (is_null($OUTPUT) === true) {
1182                            $OUTPUT = $registry->get('OUTPUT','core');
1183                        }
1184                        // parse tags/conditions
1185                        $cont = $OUTPUT->just_parse($cont);
1186                        //var_dump($cont); exit;
1187                    }
1188                    else {
1189                        $cont = Q($row_data[$col]);
1190                    }
1191                    $table .= '<td class="' . $col . '">' . $cont . "</td>\n";
1192                }
1193
1194                $table .= "</tr>\n";
1195                $c++;
1196            }
1197        }
1198
1199        // complete message table
1200        $table .= "</tbody></table>\n";
1201
1202        return $table;
1203    }
1204
1205
1206    /**
1207     * Create an edit field for inclusion on a form
1208     *
1209     * @param string col field name
1210     * @param string value field value
1211     * @param array attrib HTML element attributes for field
1212     * @param string type HTML element type (default 'text')
1213     * @return string HTML field definition
1214     */
1215    static function get_edit_field($col, $value, $attrib, $type='text')
1216    {
1217        $fname = '_'.$col;
1218        $attrib['name'] = $fname;
1219
1220        if ($type=='checkbox') {
1221            $attrib['value'] = '1';
1222            $input = new html_checkbox($attrib);
1223        }
1224        else if ($type=='textarea') {
1225            $attrib['cols'] = $attrib['size'];
1226            $input = new html_textarea($attrib);
1227        }
1228        else {
1229            $input = new html_inputfield($attrib);
1230        }
1231        // use value from post
1232        if (!empty($_POST[$fname])) {
1233            $value = $_POST[$fname];
1234        }
1235        $out = $input->show($value);
1236
1237        return $out;
1238    }
1239
1240
1241    /**
1242     * Return the mail domain configured for the given host
1243     *
1244     * @param string IMAP host
1245     * @return string Resolved SMTP host
1246     */
1247    static function mail_domain($host)
1248    {
1249        $registry = rcube_registry::get_instance();
1250        $CONFIG   = $registry->get_all('config');
1251
1252        $domain = $host;
1253        if (is_array($CONFIG['mail_domain'])) {
1254            if (isset($CONFIG['mail_domain'][$host])) {
1255                $domain = $CONFIG['mail_domain'][$host];
1256            }
1257        }
1258        else if (!empty($CONFIG['mail_domain'])) {
1259            $domain = $CONFIG['mail_domain'];
1260        }
1261        return $domain;
1262    }
1263
1264
1265    /**
1266     * Convert the given date to a human readable form
1267     * This uses the date formatting properties from config
1268     *
1269     * @param mixed Date representation (string or timestamp)
1270     * @param string Date format to use
1271     * @return string Formatted date string
1272     */
1273    static function format_date($date, $format=NULL)
1274    {
1275        $registry       = rcube_registry::get_instance();
1276        $CONFIG         = $registry->get_all('config');
1277        $user_lang = $registry->get('user_lang', 'core');
1278
1279        $ts = NULL;
1280
1281        if (is_numeric($date)) {
1282            $ts = $date;
1283        }
1284        else if (!empty($date)) {
1285            $ts = @strtotime($date);
1286        }
1287        if (empty($ts)) {
1288            return '';
1289        }
1290        // get user's timezone
1291        $tz = $CONFIG['timezone'];
1292        if ($CONFIG['dst_active']) {
1293            $tz++;
1294        }
1295        // convert time to user's timezone
1296        $timestamp = $ts - date('Z', $ts) + ($tz * 3600);
1297
1298        // get current timestamp in user's timezone
1299        $now      = time();  // local time
1300        $now     -= (int)date('Z'); // make GMT time
1301        $now     += ($tz * 3600); // user's time
1302        $now_date = getdate($now);
1303
1304        $today_limit = mktime(
1305                        0, 0, 0,
1306                        $now_date['mon'],
1307                        $now_date['mday'],
1308                        $now_date['year']
1309        );
1310        $week_limit  = mktime(
1311                        0, 0, 0,
1312                        $now_date['mon'],
1313                        $now_date['mday']-6,
1314                        $now_date['year']
1315        );
1316
1317        // define date format depending on current time
1318        if (
1319            $CONFIG['prettydate']
1320            && !$format
1321            && $timestamp > $today_limit
1322            && $timestamp < $now
1323        ) {
1324            return sprintf(
1325                    '%s %s',
1326                    rcube::gettext('today'),
1327                    date(
1328                        $CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i',
1329                        $timestamp
1330                    )
1331            );
1332        }
1333        elseif (
1334            $CONFIG['prettydate']
1335            && !$format
1336            && $timestamp > $week_limit
1337            && $timestamp < $now
1338        ) {
1339            $format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i';
1340        }
1341        elseif (!$format) {
1342            $format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i';
1343        }
1344
1345        // parse format string manually in order to provide localized weekday and month names
1346        // an alternative would be to convert the date() format string to fit with strftime()
1347        $out = '';
1348        for($i=0; $i<strlen($format); $i++) {
1349            if ($format{$i}=='\\') {  // skip escape chars
1350                continue;
1351            }
1352            // write char "as-is"
1353            if ($format{$i}==' ' || $format{$i-1}=='\\') {
1354                $out .= $format{$i};
1355            // weekday (short)
1356            }
1357            elseif ($format{$i}=='D') {
1358                $out .= rcube::gettext(strtolower(date('D', $timestamp)));
1359            // weekday long
1360            }
1361            elseif ($format{$i}=='l') {
1362                $out .= rcube::gettext(strtolower(date('l', $timestamp)));
1363            // month name (short)
1364            }
1365            elseif ($format{$i}=='M') {
1366                $out .= rcube::gettext(strtolower(date('M', $timestamp)));
1367            // month name (long)
1368            }
1369            elseif ($format{$i}=='F') {
1370                $out .= rcube::gettext(strtolower(date('F', $timestamp)));
1371            }
1372            else {
1373                $out .= date($format{$i}, $timestamp);
1374            }
1375        }
1376        return $out;
1377    }
1378
1379
1380    /**
1381     * Compose a valid representaion of name and e-mail address
1382     *
1383     * @param string E-mail address
1384     * @param string Person name
1385     * @return string Formatted string
1386     */
1387    static function format_email_recipient($email, $name='')
1388    {
1389        if ($name && $name != $email) {
1390            return sprintf('%s <%s>', strpos($name, ",") ? '"'.$name.'"' : $name, $email);
1391        }
1392        else {
1393            return $email;
1394        }
1395    }
1396   
1397   
1398   
1399    /**
1400     * Check the given string and returns language properties
1401     *
1402     * @param string Language code
1403     * @param string Peropert name
1404     * @return string Property value
1405     */
1406    static function language_prop($lang, $prop='lang')
1407    {
1408        $registry               = rcube_registry::get_instance();
1409        $rcube_languages        = $registry->get('languages', 'core');
1410        $rcube_language_aliases = $registry->get('language_aliases', 'core');
1411        $rcube_charsets         = $registry->get('language_charsets', 'core');
1412
1413        if (empty($rcube_languages)) {
1414            $status = @include(INSTALL_PATH . 'program/localization/index.inc');
1415            if ($status === false) {
1416                self::tfk_debug("Couldn't include localization/index.inc");
1417            }
1418        }
1419        // check if we have an alias for that language
1420        if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang])) {
1421            $lang = $rcube_language_aliases[$lang];
1422        }
1423        // try the first two chars
1424        if (!isset($rcube_languages[$lang]) && strlen($lang)>2) {
1425            $registry->set('rcube_languages', $rcube_languages, 'core');
1426            $registry->set('rcube_language_aliases', $rcube_language_aliases, 'core');
1427            $registry->set('rcube_charsets', $rcube_charsets, 'core');
1428
1429            $lang = substr($lang, 0, 2);
1430            $lang = rcube::language_prop($lang);
1431        }
1432
1433        if (!isset($rcube_languages[$lang])) {
1434            $lang = 'en_US';
1435        }
1436        // language has special charset configured
1437        if (isset($rcube_charsets[$lang])) {
1438            $charset = $rcube_charsets[$lang];
1439        }
1440        else {
1441            $charset = 'UTF-8';
1442        }
1443
1444        // write back to registry
1445        $registry->set('languages', $rcube_languages, 'core');
1446        $registry->set('language_aliases', $rcube_language_aliases, 'core');
1447        $registry->set('language_charsets', $rcube_charsets, 'core');
1448
1449        if ($prop=='charset') {
1450            return $charset;
1451        }
1452
1453        return $lang;
1454    }
1455   
1456   
1457    /**
1458     * Read directory program/localization and return a list of available languages
1459     *
1460     * @return array List of available localizations
1461     */
1462    static function list_languages()
1463    {
1464        $registry      = rcube_registry::get_instance();
1465        $localizations = $registry->get('localizations', 'core');
1466
1467        if (empty($localizations)) {
1468            $localizations = array();
1469            @include(INSTALL_PATH . 'program/localization/index.inc');
1470
1471            if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {
1472                while (($name = readdir($dh)) !== false) {
1473                    if ($name{0}=='.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name))
1474                        continue;
1475
1476                    if ($label = $rcube_languages[$name])
1477                        $localizations[$name] = $label ? $label : $name;
1478                }
1479                closedir($dh);
1480            }
1481            $registry->set('localizations', $localizations, 'core');
1482        }
1483        return $localizations;
1484    }
1485   
1486   
1487    /**
1488     * Get localized text in the desired language
1489     *
1490     * @param mixed Named parameters array or label name
1491     * @return string Localized text
1492     */
1493    static function gettext($attrib)
1494    {
1495        static $sa_text_data, $s_language, $utf8_decode;
1496       
1497        $registry = rcube_registry::get_instance();
1498        $lang     = $registry->get('user_lang', 'core');
1499
1500        // extract attributes
1501        if (is_string($attrib)) {
1502            $attrib = array('name' => $attrib);
1503        }
1504        $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1;
1505        $vars = isset($attrib['vars']) ? $attrib['vars'] : '';
1506
1507        $command_name = !empty($attrib['command']) ? $attrib['command'] : NULL;
1508        $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : '');
1509
1510
1511        // load localized texts
1512        if (!$sa_text_data || $s_language != $lang) {
1513            $sa_text_data = array();
1514
1515            // get english labels (these should be complete)
1516            include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
1517            include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
1518
1519            if (is_array($labels)) {
1520                $sa_text_data = $labels;
1521            }
1522            if (is_array($messages)) {
1523                $sa_text_data = array_merge($sa_text_data, $messages);
1524            }
1525            // include user language files
1526            if (
1527                !empty($lang)
1528                && $lang != 'en'
1529                && is_dir(INSTALL_PATH . 'program/localization/'.$lang)
1530            ) {
1531                include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
1532                include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
1533
1534                if (is_array($labels)) {
1535                    $sa_text_data = array_merge($sa_text_data, $labels);
1536                }
1537                if (is_array($messages)) {
1538                    $sa_text_data = array_merge($sa_text_data, $messages);
1539                }
1540            }
1541            $s_language = $lang;
1542        }
1543
1544        // text does not exist
1545        if (!($text_item = $sa_text_data[$alias])) {
1546            /*
1547            rcube_error::raise(
1548                array(
1549                    'code' => 500,
1550                    'type' => 'php',
1551                    'line' => __LINE__,
1552                    'file' => __FILE__,
1553                    'message' => "Missing localized text for '$alias' in '$lang'"
1554                ),
1555                TRUE,
1556                FALSE
1557            );
1558            */
1559            /**
1560             * We got as far - so let's see if $_SESSION contains what we are
1561             * looking for.
1562             *
1563             * @author Till Klampaeckel <till@php.net>
1564             */
1565            if (substr($alias, 0, 3) == 'RC_') {
1566
1567                $_sess_ident = substr($alias, 3);
1568
1569                if (isset($_SESSION[$_sess_ident]) === true) {
1570                    return $_SESSION[$_sess_ident];
1571                }
1572            }
1573            return "[$alias]";
1574        }
1575
1576        // make text item array
1577        $a_text_item = is_array($text_item) ? $text_item : array('single' => $text_item);
1578
1579        // decide which text to use
1580        if ($nr==1) {
1581            $text = $a_text_item['single'];
1582        }
1583        elseif ($nr>0) {
1584            $text = $a_text_item['multiple'];
1585        }
1586        elseif ($nr==0) {
1587            if ($a_text_item['none']) {
1588                $text = $a_text_item['none'];
1589            }
1590            elseif ($a_text_item['single']) {
1591                $text = $a_text_item['single'];
1592            }
1593            elseif ($a_text_item['multiple']) {
1594                $text = $a_text_item['multiple'];
1595            }
1596        }
1597
1598        // default text is single
1599        if ($text=='')
1600            $text = $a_text_item['single'];
1601
1602        // replace vars in text
1603        if (is_array($attrib['vars'])) {
1604            foreach ($attrib['vars'] as $var_key=>$var_value) {
1605                $a_replace_vars[substr($var_key, 0, 1)=='$' ? substr($var_key, 1) : $var_key] = $var_value;
1606            }
1607        }
1608
1609        if ($a_replace_vars) {
1610            $text = preg_replace('/\${?([_a-z]{1}[_a-z0-9]*)}?/ei', '$a_replace_vars["\1"]', $text);
1611        }
1612
1613        // format output
1614        if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst']) {
1615            return ucfirst($text);
1616        }
1617        elseif ($attrib['uppercase']) {
1618            return strtoupper($text);
1619        }
1620        elseif ($attrib['lowercase']) {
1621            return strtolower($text);
1622        }
1623        return $text;
1624    }
1625   
1626   
1627    /**
1628     * Read input value and convert it for internal use
1629     * Performs stripslashes() and charset conversion if necessary
1630     *
1631     * @param  string   Field name to read
1632     * @param  int      Source to get value from (GPC)
1633     * @param  boolean  Allow HTML tags in field value
1634     * @param  string   Charset to convert into
1635     * @return string   Field value or NULL if not available
1636     */
1637    static function get_input_value($fname, $source, $allow_html=false, $charset=null)
1638    {
1639        try {
1640            $registry = rcube_registry::get_instance();
1641            $output   = $registry->get('OUTPUT', 'core');
1642        }
1643        catch (rcube_registry_exception $e) {
1644            $output = NULL;
1645        }
1646
1647        $value = NULL;
1648
1649        if ($source == rcube::INPUT_GET && isset($_GET[$fname])) {
1650            $value = $_GET[$fname];
1651        }
1652        else if ($source == rcube::INPUT_POST && isset($_POST[$fname])) {
1653            $value = $_POST[$fname];
1654        }
1655        else if ($source == rcube::INPUT_GPC) {
1656            if (isset($_POST[$fname])) {
1657                $value = $_POST[$fname];
1658            }
1659            else if (isset($_GET[$fname])) {
1660                $value = $_GET[$fname];
1661            }
1662            else if (isset($_COOKIE[$fname])) {
1663                $value = $_COOKIE[$fname];
1664            }
1665        }
1666
1667        // strip slashes if magic_quotes enabled
1668        if ((bool)get_magic_quotes_gpc())
1669            $value = stripslashes($value);
1670
1671        // remove HTML tags if not allowed
1672        if (!$allow_html) {
1673            $value = strip_tags($value);
1674        }
1675        // convert to internal charset
1676        if (is_object($output)) {
1677            return self::charset_convert($value, $output->get_charset(), $charset);
1678        }
1679        return $value;
1680    }
1681   
1682   
1683    /**
1684     * Read a specific HTTP request header
1685     *
1686     * @param  string $name Header name
1687     * @return mixed  Header value or null if not available
1688     */
1689    static function get_request_header($name)
1690    {
1691        if (function_exists('getallheaders')) {
1692            $hdrs = getallheaders();
1693            $hdrs = array_change_key_case($hdrs, CASE_UPPER);
1694            $key  = strtoupper($name);
1695        }
1696        else {
1697            $key  = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
1698            $hdrs = array_change_key_case($_SERVER, CASE_UPPER);
1699        }
1700        if (isset($hdrs[$key])) {
1701            return $hdrs[$key];
1702        }
1703        return null;
1704    }
1705   
1706   
1707    /**
1708     * Convert a string from one charset to another.
1709     * Uses mbstring and iconv functions if possible
1710     *
1711     * @param  string Input string
1712     * @param  string Suspected charset of the input string
1713     * @param  string Target charset to convert to; defaults to RCMAIL_CHARSET
1714     * @return Converted string
1715     */
1716    static function charset_convert($str, $from, $to=NULL)
1717    {
1718        $registry = rcube_registry::get_instance();
1719        $MBSTRING = $registry->get('MBSTRING', 'core');
1720
1721        $from = strtoupper($from);
1722        $to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to);
1723
1724        if ($from==$to || $str=='' || empty($from)) {
1725            return $str;
1726        }
1727        // convert charset using mbstring module
1728        if ($MBSTRING) {
1729            $to = $to=="UTF-7" ? "UTF7-IMAP" : $to;
1730            $from = $from=="UTF-7" ? "UTF7-IMAP": $from;
1731
1732            // return if convert succeeded
1733            if (($out = @mb_convert_encoding($str, $to, $from)) != '') {
1734                return $out;
1735            }
1736        }
1737
1738        // convert charset using iconv module
1739        if (function_exists('iconv') && $from!='UTF-7' && $to!='UTF-7')
1740            return iconv($from, $to, $str);
1741
1742        $conv = new utf8();
1743
1744        // convert string to UTF-8
1745        if ($from=='UTF-7') {
1746            $str = utf7_to_utf8($str);
1747        }
1748        else if (($from=='ISO-8859-1') && function_exists('utf8_encode')) {
1749            $str = utf8_encode($str);
1750        }
1751        else if ($from!='UTF-8') {
1752            $conv->loadCharset($from);
1753            $str = $conv->strToUtf8($str);
1754        }
1755
1756        // encode string for output
1757        if ($to=='UTF-7') {
1758            return utf8_to_utf7($str);
1759        }
1760        else if ($to=='ISO-8859-1' && function_exists('utf8_decode')) {
1761            return utf8_decode($str);
1762        }
1763        else if ($to!='UTF-8') {
1764            $conv->loadCharset($to);
1765            return $conv->utf8ToStr($str);
1766        }
1767
1768        // return UTF-8 string
1769        return $str;
1770    }
1771
1772
1773    /**
1774     * Replacing specials characters to a specific encoding type
1775     *
1776     * @param  string  Input string
1777     * @param  string  Encoding type: text|html|xml|js|url
1778     * @param  string  Replace mode for tags: show|replace|remove
1779     * @param  boolean Convert newlines
1780     * @return The quoted string
1781     */
1782    static function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
1783    {
1784        static $html_encode_arr, $js_rep_table, $xml_rep_table;
1785       
1786        $out_charset = rcube_registry::get_instance()->get('OUTPUT_CHARSET', 'core');
1787
1788        if (!$enctype) {
1789            $enctype = $registry->get('OUTPUT_TYPE', 'core');
1790        }
1791
1792        // encode for plaintext
1793        if ($enctype == 'text') {
1794            return str_replace(
1795                "\r\n",
1796                "\n",
1797                $mode=='remove' ? strip_tags($str) : $str
1798            );
1799        }
1800       
1801        // encode for HTML output
1802        if ($enctype == 'html') {
1803            if (empty($html_encode_arr)) {
1804                $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
1805                unset($html_encode_arr['?']);
1806            }
1807
1808            $ltpos = strpos($str, '<');
1809            $encode_arr = $html_encode_arr;
1810
1811            // don't replace quotes and html tags
1812            if (
1813                ($mode == 'show' || $mode == '')
1814                && $ltpos!==false
1815                && strpos($str, '>', $ltpos)!==false
1816            ) {
1817                unset($encode_arr['"']);
1818                unset($encode_arr['<']);
1819                unset($encode_arr['>']);
1820                unset($encode_arr['&']);
1821            }
1822            else if ($mode == 'remove') {
1823                $str = strip_tags($str);
1824            }
1825            // avoid douple quotation of &
1826            $out = preg_replace(
1827                '/&amp;([a-z]{2,5}|#[0-9]{2,4});/',
1828                '&\\1;',
1829                strtr($str, $encode_arr)
1830            );
1831            return $newlines ? nl2br($out) : $out;
1832        }
1833
1834        if ($enctype == 'url') {
1835            return rawurlencode($str);
1836        }
1837       
1838        // if the replace tables for XML and JS are not yet defined
1839        if (empty($js_rep_table)) {
1840            $js_rep_table = $xml_rep_table = array();
1841            $xml_rep_table['&'] = '&amp;';
1842
1843            for ($c=160; $c<256; $c++)  // can be increased to support more charsets
1844            {
1845                $xml_rep_table[Chr($c)] = "&#$c;";
1846
1847                if ($out_charset == 'ISO-8859-1') {
1848                    $js_rep_table[Chr($c)] = sprintf("\\u%04x", $c);
1849                }
1850            }
1851            $xml_rep_table['"'] = '&quot;';
1852        }
1853
1854        // encode for XML
1855        if ($enctype == 'xml') {
1856            return strtr($str, $xml_rep_table);
1857        }
1858       
1859        // encode for javascript use
1860        if ($enctype == 'js') {
1861            if ($out_charset != 'UTF-8') {
1862                $str = self::charset_convert($str, RCMAIL_CHARSET, $out_charset);
1863            }
1864            return preg_replace(
1865                array("/\r?\n/", "/\r/"),
1866                array('\n', '\n'),
1867                addslashes(strtr($str, $js_rep_table))
1868            );
1869        }
1870       
1871        // no encoding given -> return original string
1872        return $str;
1873    }
1874   
1875   
1876    /**
1877     * Compose a valid attribute string for HTML tags
1878     *
1879     * @param array Named tag attributes
1880     * @param array List of allowed attributes
1881     * @return string HTML formatted attribute string
1882     * @uses html::attrib_string
1883     * @deprecated
1884     */
1885    static function create_attrib_string($attrib, $allowed=array('id', 'class', 'style'))
1886    {
1887        return html::attrib_string($attrib, $allowed);
1888    }
1889
1890
1891    /**
1892     * Convert a HTML attribute string attributes to an associative array (name => value)
1893     *
1894     * @param string Input string
1895     * @return array Key-value pairs of parsed attributes
1896     */
1897    function parse_attrib_string($str)
1898    {
1899        $attrib = array();
1900        preg_match_all(
1901            '/\s*([-_a-z]+)=(["\'])([^"]+)\2/Ui',
1902            stripslashes($str),
1903            $regs,
1904            PREG_SET_ORDER
1905        );
1906
1907        // convert attributes to an associative array (name => value)
1908        if ($regs) {
1909            foreach ($regs as $attr) {
1910                $attrib[strtolower($attr[1])] = $attr[3];
1911            }
1912        }
1913        return $attrib;
1914    }
1915   
1916   
1917    /****** debugging functions ********/
1918
1919
1920    /**
1921     * tfk_debug
1922     *
1923     * @param  string $str
1924     * @return void
1925     */
1926    static function tfk_debug($str)
1927    {
1928        $str = "\n\n" . @date('Y-m-d H:i:s') . "\n" . $str;
1929        $fp = @fopen(dirname(__FILE__) . '/../../logs/debug.tfk', 'a');
1930        if ($fp !== false) {
1931            @fwrite($fp, $str);
1932            @fclose($fp);
1933        }
1934        else {
1935            die('Could not open logs/debug.tfk.');
1936        }
1937    }
1938   
1939
1940    /**
1941     * Print or write debug messages
1942     *
1943     * @param mixed Debug message or data
1944     */
1945    function console($msg)
1946    {
1947        $registry = rcube_registry::get_instance();
1948        $CONFIG   = $registry->get_all('config');
1949        if (!is_string($msg)) {
1950            $msg = var_export($msg, true);
1951        }
1952        if (!($CONFIG['debug_level'] & 4)) {
1953            write_log('console', $msg);
1954        }
1955        elseif ($GLOBALS['REMOTE_REQUEST']) {
1956            echo "/*\n $msg \n*/\n";
1957        }
1958        else {
1959            echo '<div style="background:#eee; border:1px solid #ccc; ';
1960            echo 'margin-bottom:3px; padding:6px"><pre>';
1961            echo $msg;
1962            echo "</pre></div>\n";
1963        }
1964    }
1965
1966
1967    /**
1968     * Append a line to a logfile in the logs directory.
1969     * Date will be added automatically to the line.
1970     *
1971     * @param string Name of logfile
1972     * @param string Line to append
1973     */
1974    function write_log($name, $line)
1975    {
1976        $registry = rcube_registry::get_instance();
1977        $log_dir  = $registry->get('log_dir', 'config');
1978
1979        if (!is_string($line)) {
1980            $line = var_export($line, true);
1981        }
1982        $log_entry = sprintf(
1983            "[%s]: %s\n",
1984            date("d-M-Y H:i:s O", mktime()),
1985            $line
1986        );
1987
1988        if (empty($log_dir)) {
1989            $log_dir = INSTALL_PATH . 'logs';
1990        }
1991        // try to open specific log file for writing
1992        if ($fp = @fopen($log_dir . '/' . $name, 'a')) {
1993            fwrite($fp, $log_entry);
1994            fclose($fp);
1995        }
1996    }
1997
1998
1999    static function timer()
2000    {
2001        list($usec, $sec) = explode(" ", microtime());
2002        return ((float)$usec + (float)$sec);
2003    }
2004
2005    static function print_time($timer, $label='Timer')
2006    {
2007        static $print_count = 0;
2008
2009        $print_count++;
2010        $now = rcube_timer();
2011        $diff = $now-$timer;
2012
2013        if (empty($label)) {
2014            $label = 'Timer '.$print_count;
2015        }
2016        rcube::console(sprintf("%s: %0.4f sec", $label, $diff));
2017    }
2018   
2019   
2020}
2021
Note: See TracBrowser for help on using the repository browser.