source: subversion/branches/devel-vnext/program/include/main.inc @ 631

Last change on this file since 631 was 631, checked in by till, 6 years ago

+ addressbook plugin

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