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

Last change on this file since 954 was 954, checked in by till, 5 years ago

# bugfix (thanks Ivan Kurmanov)

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