alecpl
2012-04-13 0c259682f65eaaf23ea4ccb56a706d6baf3007e4
commit | author | age
197601 1 <?php
T 2
3 /*
4  +-----------------------------------------------------------------------+
5  | program/include/rcube_config.php                                      |
6  |                                                                       |
e019f2 7  | This file is part of the Roundcube Webmail client                     |
0ac416 8  | Copyright (C) 2008-2012, The Roundcube Dev Team                       |
7fe381 9  |                                                                       |
T 10  | Licensed under the GNU General Public License version 3 or            |
11  | any later version with exceptions for skins & plugins.                |
12  | See the README file for a full license statement.                     |
197601 13  |                                                                       |
T 14  | PURPOSE:                                                              |
15  |   Class to read configuration settings                                |
16  |                                                                       |
17  +-----------------------------------------------------------------------+
18  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
19  +-----------------------------------------------------------------------+
20
1d786c 21  $Id$
197601 22
T 23 */
24
25 /**
e019f2 26  * Configuration class for Roundcube
197601 27  *
T 28  * @package Core
29  */
30 class rcube_config
31 {
2eb794 32     private $prop = array();
A 33     private $errors = array();
34     private $userprefs = array();
0ac416 35
A 36     /**
37      * Renamed options
38      *
39      * @var array
40      */
41     private $legacy_props = array(
42         // new name => old name
43         'default_folders'      => 'default_imap_folders',
44         'mail_pagesize'        => 'pagesize',
45         'addressbook_pagesize' => 'pagesize',
46     );
197601 47
T 48
2eb794 49     /**
A 50      * Object constructor
51      */
52     public function __construct()
2471d3 53     {
2eb794 54         $this->load();
2471d3 55     }
2eb794 56
A 57
58     /**
59      * Load config from local config file
60      *
61      * @todo Remove global $CONFIG
62      */
63     private function load()
2471d3 64     {
2eb794 65         // load main config file
A 66         if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/main.inc.php'))
67             $this->errors[] = 'main.inc.php was not found.';
68
69         // load database config
70         if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/db.inc.php'))
71             $this->errors[] = 'db.inc.php was not found.';
f52c4f 72
2eb794 73         // load host-specific configuration
A 74         $this->load_host_config();
75
76         // set skin (with fallback to old 'skin_path' property)
77         if (empty($this->prop['skin']) && !empty($this->prop['skin_path']))
78             $this->prop['skin'] = str_replace('skins/', '', unslashify($this->prop['skin_path']));
79         else if (empty($this->prop['skin']))
80             $this->prop['skin'] = 'default';
81
82         // fix paths
83         $this->prop['log_dir'] = $this->prop['log_dir'] ? realpath(unslashify($this->prop['log_dir'])) : INSTALL_PATH . 'logs';
84         $this->prop['temp_dir'] = $this->prop['temp_dir'] ? realpath(unslashify($this->prop['temp_dir'])) : INSTALL_PATH . 'temp';
f52c4f 85
2eb794 86         // fix default imap folders encoding
A 87         foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
0c2596 88             $this->prop[$folder] = rcube_charset::convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');
2eb794 89
c321a9 90         if (!empty($this->prop['default_folders']))
T 91             foreach ($this->prop['default_folders'] as $n => $folder)
0c2596 92                 $this->prop['default_folders'][$n] = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
2eb794 93
A 94         // set PHP error logging according to config
95         if ($this->prop['debug_level'] & 1) {
96             ini_set('log_errors', 1);
97
98             if ($this->prop['log_driver'] == 'syslog') {
99                 ini_set('error_log', 'syslog');
100             }
101             else {
102                 ini_set('error_log', $this->prop['log_dir'].'/errors');
103             }
104         }
23b495 105
A 106         // enable display_errors in 'show' level, but not for ajax requests
107         ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4)));
0829b7 108
65082b 109         // set timezone auto settings values
T 110         if ($this->prop['timezone'] == 'auto') {
5879c0 111           $this->prop['_timezone_value'] = $this->client_timezone();
0829b7 112         }
5879c0 113         else if (is_numeric($this->prop['timezone'])) {
T 114           $this->prop['timezone'] = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0);
65082b 115         }
5879c0 116
T 117         // remove deprecated properties
118         unset($this->prop['dst_active']);
2eb794 119
A 120         // export config data
121         $GLOBALS['CONFIG'] = &$this->prop;
2471d3 122     }
1854c4 123
2eb794 124     /**
A 125      * Load a host-specific config file if configured
126      * This will merge the host specific configuration with the given one
127      */
128     private function load_host_config()
129     {
130         $fname = null;
10eedb 131
2eb794 132         if (is_array($this->prop['include_host_config'])) {
A 133             $fname = $this->prop['include_host_config'][$_SERVER['HTTP_HOST']];
134         }
135         else if (!empty($this->prop['include_host_config'])) {
136             $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php';
137         }
2471d3 138
2eb794 139         if ($fname) {
A 140             $this->load_from_file(RCMAIL_CONFIG_DIR . '/' . $fname);
141         }
83a763 142     }
T 143
2eb794 144
A 145     /**
146      * Read configuration from a file
147      * and merge with the already stored config values
148      *
5c461b 149      * @param string $fpath Full path to the config file to be loaded
2eb794 150      * @return booelan True on success, false on failure
A 151      */
152     public function load_from_file($fpath)
153     {
154         if (is_file($fpath) && is_readable($fpath)) {
7c9850 155             // use output buffering, we don't need any output here 
A 156             ob_start();
2eb794 157             include($fpath);
7c9850 158             ob_end_clean();
A 159
2eb794 160             if (is_array($rcmail_config)) {
A 161                 $this->prop = array_merge($this->prop, $rcmail_config, $this->userprefs);
162                 return true;
163             }
164         }
165
166         return false;
167     }
168
169
170     /**
171      * Getter for a specific config parameter
172      *
5c461b 173      * @param  string $name Parameter name
A 174      * @param  mixed  $def  Default value if not set
2eb794 175      * @return mixed  The requested config value
A 176      */
177     public function get($name, $def = null)
178     {
0ac416 179         if (isset($this->prop[$name])) {
A 180             $result = $this->prop[$name];
181         }
e65c36 182         else if (isset($this->legacy_props[$name])) {
T 183             return $this->get($this->legacy_props[$name], $def);
0ac416 184         }
A 185         else {
186             $result = $def;
187         }
188
0c2596 189         $rcmail = rcube::get_instance();
0ac416 190
801b69 191         if ($name == 'timezone' && isset($this->prop['_timezone_value']))
T 192             $result = $this->prop['_timezone_value'];
183717 193
A 194         if (is_object($rcmail->plugins)) {
195             $plugin = $rcmail->plugins->exec_hook('config_get', array(
196                 'name' => $name, 'default' => $def, 'result' => $result));
197
198             return $plugin['result'];
199         }
200
201         return $result;
2eb794 202     }
A 203
204
205     /**
206      * Setter for a config parameter
207      *
5c461b 208      * @param string $name  Parameter name
A 209      * @param mixed  $value Parameter value
2eb794 210      */
A 211     public function set($name, $value)
212     {
213         $this->prop[$name] = $value;
214     }
215
216
217     /**
218      * Override config options with the given values (eg. user prefs)
219      *
5c461b 220      * @param array $prefs Hash array with config props to merge over
2eb794 221      */
A 222     public function merge($prefs)
223     {
224         $this->prop = array_merge($this->prop, $prefs, $this->userprefs);
225     }
226
227
228     /**
229      * Merge the given prefs over the current config
230      * and make sure that they survive further merging.
231      *
5c461b 232      * @param array $prefs Hash array with user prefs
2eb794 233      */
A 234     public function set_user_prefs($prefs)
235     {
bfb7d6 236         // Honor the dont_override setting for any existing user preferences
A 237         $dont_override = $this->get('dont_override');
238         if (is_array($dont_override) && !empty($dont_override)) {
239             foreach ($prefs as $key => $pref) {
240                 if (in_array($key, $dont_override)) {
241                     unset($prefs[$key]);
242                 }
243             }
244         }
245
c21d7f 246         // convert user's timezone into the new format
A 247         if (is_numeric($prefs['timezone'])) {
248             $prefs['timezone'] = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0);
249         }
250
2eb794 251         $this->userprefs = $prefs;
bfb7d6 252         $this->prop      = array_merge($this->prop, $prefs);
65082b 253
T 254         // override timezone settings with client values
801b69 255         if ($this->prop['timezone'] == 'auto') {
5879c0 256             $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $this->client_timezone() : $this->prop['_timezone_value'];
65082b 257         }
985e41 258         else if (isset($this->prop['_timezone_value']))
T 259            unset($this->prop['_timezone_value']);
2eb794 260     }
A 261
262
263     /**
264      * Getter for all config options
265      *
266      * @return array  Hash array containg all config properties
267      */
268     public function all()
269     {
270         return $this->prop;
271     }
272
da7178 273     /**
65082b 274      * Special getter for user's timezone offset including DST
T 275      *
276      * @return float  Timezone offset (in hours)
5879c0 277      * @deprecated
da7178 278      */
T 279     public function get_timezone()
280     {
e86a21 281       if ($tz = $this->get('timezone')) {
A 282         try {
283           $tz = new DateTimeZone($tz);
284           return $tz->getOffset(new DateTime('now')) / 3600;
285         }
286         catch (Exception $e) {
287         }
5879c0 288       }
T 289
290       return 0;
da7178 291     }
2eb794 292
A 293     /**
294      * Return requested DES crypto key.
295      *
5c461b 296      * @param string $key Crypto key name
2eb794 297      * @return string Crypto key
A 298      */
299     public function get_crypto_key($key)
300     {
301         // Bomb out if the requested key does not exist
302         if (!array_key_exists($key, $this->prop)) {
0c2596 303             rcube::raise_error(array(
2eb794 304                 'code' => 500, 'type' => 'php',
A 305                 'file' => __FILE__, 'line' => __LINE__,
306                 'message' => "Request for unconfigured crypto key \"$key\""
307             ), true, true);
308         }
309
310         $key = $this->prop[$key];
311
312         // Bomb out if the configured key is not exactly 24 bytes long
313         if (strlen($key) != 24) {
0c2596 314             rcube::raise_error(array(
2eb794 315                 'code' => 500, 'type' => 'php',
A 316                 'file' => __FILE__, 'line' => __LINE__,
317                 'message' => "Configured crypto key '$key' is not exactly 24 bytes long"
318             ), true, true);
319         }
320
321         return $key;
322     }
323
324
325     /**
326      * Try to autodetect operating system and find the correct line endings
327      *
328      * @return string The appropriate mail header delimiter
329      */
330     public function header_delimiter()
331     {
332         // use the configured delimiter for headers
086767 333         if (!empty($this->prop['mail_header_delimiter'])) {
A 334             $delim = $this->prop['mail_header_delimiter'];
335             if ($delim == "\n" || $delim == "\r\n")
336                 return $delim;
337             else
0c2596 338                 rcube::raise_error(array(
086767 339                     'code' => 500, 'type' => 'php',
A 340                     'file' => __FILE__, 'line' => __LINE__,
341                     'message' => "Invalid mail_header_delimiter setting"
342                 ), true, false);
343         }
2eb794 344
A 345         $php_os = strtolower(substr(PHP_OS, 0, 3));
346
347         if ($php_os == 'win')
348             return "\r\n";
349
350         if ($php_os == 'mac')
351             return "\r\n";
352
353         return "\n";
354     }
355
356
357     /**
358      * Return the mail domain configured for the given host
359      *
5c461b 360      * @param string  $host   IMAP host
A 361      * @param boolean $encode If true, domain name will be converted to IDN ASCII
2eb794 362      * @return string Resolved SMTP host
A 363      */
e99991 364     public function mail_domain($host, $encode=true)
2eb794 365     {
A 366         $domain = $host;
367
368         if (is_array($this->prop['mail_domain'])) {
369             if (isset($this->prop['mail_domain'][$host]))
370                 $domain = $this->prop['mail_domain'][$host];
371         }
372         else if (!empty($this->prop['mail_domain']))
0c2596 373             $domain = rcmail::parse_host($this->prop['mail_domain']);
bb8721 374
e99991 375         if ($encode)
e8d5bd 376             $domain = rcube_idn_to_ascii($domain);
e99991 377
2eb794 378         return $domain;
A 379     }
bb8721 380
A 381
2eb794 382     /**
A 383      * Getter for error state
384      *
385      * @return mixed Error message on error, False if no errors
386      */
387     public function get_error()
388     {
389         return empty($this->errors) ? false : join("\n", $this->errors);
390     }
83a763 391
5879c0 392
T 393     /**
394      * Internal getter for client's (browser) timezone identifier
395      */
396     private function client_timezone()
397     {
398         return isset($_SESSION['timezone']) ? timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0) : date_default_timezone_get();
399     }
400
197601 401 }