Allow a different server address for the POP server to be configured when using POP...
[squirrelmail.git] / src / configtest.php
CommitLineData
d1ae9d4c 1<?php
134e4174 2
30967a1e 3/**
d1ae9d4c 4 * SquirrelMail configtest script
5 *
4b5049de 6 * @copyright &copy; 2003-2007 The SquirrelMail Project Team
4b4abf93 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
30967a1e 8 * @version $Id$
9 * @package squirrelmail
10 * @subpackage config
d1ae9d4c 11 */
12
13/************************************************************
14 * NOTE: you do not need to change this script! *
15 * If it throws errors you need to adjust your config. *
16 ************************************************************/
17
ebd2391c 18/** This is the configtest page */
19define('PAGE_NAME', 'configtest');
20
df758744 21// This script could really use some restructuring as it has grown quite rapidly
22// but is not very 'clean'. Feel free to get some structure into this thing.
23
dda39a1a 24/** force verbose error reporting and turn on display of errors */
25error_reporting(E_ALL);
26ini_set('display_errors',1);
27
28/** Blockcopy from init.php. Cleans globals. */
29if ((bool) ini_get('register_globals') &&
30 strtolower(ini_get('register_globals'))!='off') {
31 /**
32 * Remove all globals that are not reserved by PHP
33 * 'value' and 'key' are used by foreach. Don't unset them inside foreach.
34 */
35 foreach ($GLOBALS as $key => $value) {
36 switch($key) {
37 case 'HTTP_POST_VARS':
38 case '_POST':
39 case 'HTTP_GET_VARS':
40 case '_GET':
41 case 'HTTP_COOKIE_VARS':
42 case '_COOKIE':
43 case 'HTTP_SERVER_VARS':
44 case '_SERVER':
45 case 'HTTP_ENV_VARS':
46 case '_ENV':
47 case 'HTTP_POST_FILES':
48 case '_FILES':
49 case '_REQUEST':
50 case 'HTTP_SESSION_VARS':
51 case '_SESSION':
52 case 'GLOBALS':
53 case 'key':
54 case 'value':
55 break;
56 default:
57 unset($GLOBALS[$key]);
58 }
59 }
60 // Unset variables used in foreach
61 unset($GLOBALS['key']);
62 unset($GLOBALS['value']);
63}
64
65
66/**
67 * Displays error messages and warnings
68 * @param string $str message
69 * @param boolean $fatal fatal error or only warning
70 */
3a196538 71function do_err($str, $fatal = TRUE) {
f084f987 72 global $IND, $warnings;
73 $level = $fatal ? 'FATAL ERROR:' : 'WARNING:';
3a196538 74 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
75 if($fatal) {
f084f987 76 echo '</body></html>';
77 exit;
3a196538 78 } else {
f084f987 79 $warnings++;
80 }
5b53b7e0 81}
82
5b53b7e0 83ob_implicit_flush();
30967a1e 84/** @ignore */
5b53b7e0 85define('SM_PATH', '../');
dda39a1a 86/** load minimal function set */
b37e457f 87require(SM_PATH . 'include/constants.php');
dda39a1a 88require(SM_PATH . 'functions/global.php');
89require(SM_PATH . 'functions/strings.php');
a895042a 90$SQM_INTERNAL_VERSION = explode('.', SM_VERSION, 3);
b37e457f 91$SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
5b53b7e0 92
dda39a1a 93/** set default value in order to block remote access */
d0184454 94$allow_remote_configtest=false;
95
dda39a1a 96/** Load all configuration files before output begins */
97
98/* load default configuration */
99require(SM_PATH . 'config/config_default.php');
100/* reset arrays in default configuration */
101$ldap_server = array();
102$plugins = array();
103$fontsets = array();
104$theme = array();
105$theme[0]['PATH'] = SM_PATH . 'themes/default_theme.php';
106$theme[0]['NAME'] = 'Default';
107$aTemplateSet = array();
108$aTemplateSet[0]['ID'] = 'default';
109$aTemplateSet[0]['NAME'] = 'Default';
110/* load site configuration */
5b53b7e0 111if (file_exists(SM_PATH . 'config/config.php')) {
dda39a1a 112 require(SM_PATH . 'config/config.php');
5b53b7e0 113}
dda39a1a 114/* load local configuration overrides */
115if (file_exists(SM_PATH . 'config/config_local.php')) {
116 require(SM_PATH . 'config/config_local.php');
117}
118
1dc63862 119/**
120 * Include Compatibility plugin if available.
121 */
122if (!$disable_plugins && file_exists(SM_PATH . 'plugins/compatibility/functions.php'))
123 include_once(SM_PATH . 'plugins/compatibility/functions.php');
124
8459a9bb 125/** Load plugins */
126global $disable_plugins;
127$squirrelmail_plugin_hooks = array();
128if (!$disable_plugins && file_exists(SM_PATH . 'config/plugin_hooks.php')) {
129 require(SM_PATH . 'config/plugin_hooks.php');
130}
131
dda39a1a 132/** Warning counter */
133$warnings = 0;
134
135/** indent */
136$IND = str_repeat('&nbsp;',4);
c772f125 137
69792446 138/**
139 * get_location starts session and must be run before output is started.
140 */
141$test_location = get_location();
142
151562a7 143?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
144 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
d1ae9d4c 145<html>
146<head>
f084f987 147 <meta name="robots" content="noindex,nofollow">
148 <title>SquirrelMail configtest</title>
d1ae9d4c 149</head>
150<body>
151<h1>SquirrelMail configtest</h1>
152
153<p>This script will try to check some aspects of your SquirrelMail configuration
154and point you to errors whereever it can find them. You need to go run <tt>conf.pl</tt>
d18703d3 155in the <tt>config/</tt> directory first before you run this script.</p>
d1ae9d4c 156
157<?php
158
d1ae9d4c 159$included = array_map('basename', get_included_files() );
160if(!in_array('config.php', $included)) {
161 if(!file_exists(SM_PATH . 'config/config.php')) {
162 do_err('Config file '.SM_PATH . 'config/config.php does not exist!<br />'.
f084f987 163 'You need to run <tt>conf.pl</tt> first.');
d1ae9d4c 164 }
165 do_err('Could not read '.SM_PATH.'config/config.php! Check file permissions.');
166}
167if(!in_array('strings.php', $included)) {
168 do_err('Could not include '.SM_PATH.'functions/strings.php!<br />'.
f084f987 169 'Check permissions on that file.');
d1ae9d4c 170}
171
d0184454 172/* Block remote use of script */
173if (! $allow_remote_configtest) {
174 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER);
a15f9d93 175 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER);
176
177 if ((! isset($client_ip) || $client_ip!='127.0.0.1') &&
f084f987 178 (! isset($client_ip) || ! isset($server_ip) || $client_ip!=$server_ip)) {
f8a1ed5a 179 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
d0184454 180 }
181}
d1ae9d4c 182
b37e457f 183echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . SM_VERSION . "</b></td></tr>\n" .
f084f987 184 '<tr><td>Config file version:</td><td><b>' . $config_version . "</b></td></tr>\n" .
185 '<tr><td>Config file last modified:</td><td><b>' .
186 date ('d F Y H:i:s', filemtime(SM_PATH . 'config/config.php')) .
187 "</b></td></tr>\n</table>\n</p>\n\n";
d1ae9d4c 188
c3da9f50 189/* check $config_version */
65efa982 190if ($config_version!='1.5.0') {
c3da9f50 191 do_err('Configuration file version does not match required version. Please update your configuration file.');
192}
a15f9d93 193
a1912bbc 194
195/* checking PHP specs */
196
d1ae9d4c 197echo "Checking PHP configuration...<br />\n";
198
abd74f7d 199if(!check_php_version(4,1,0)) {
200 do_err('Insufficient PHP version: '. PHP_VERSION . '! Minimum required: 4.1.0');
d1ae9d4c 201}
202
3a196538 203echo $IND . 'PHP version ' . PHP_VERSION . ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
a1912bbc 204
0cc820f9 205echo $IND . 'display_errors: ' . ini_get('display_errors') . "<br />\n";
206
207echo $IND . 'error_reporting: ' . ini_get('error_reporting') . "<br />\n";
208
ccbde363 209$safe_mode = ini_get('safe_mode');
210if ($safe_mode) {
211 echo $IND . 'safe_mode: ' . $safe_mode;
212 if (empty($prefs_dsn) || empty($addrbook_dsn))
213 echo ' (<font color="red">double check data and attachment directory ownership, etc!</font>)';
dc528046 214 if (!empty($addrbook_dsn) || !empty($prefs_dsn) || !empty($addrbook_global_dsn))
ccbde363 215 echo ' (<font color="red">does PHP have access to database interface?</font>)';
216 echo "<br />\n";
217 $safe_mode_exec_dir = ini_get('safe_mode_exec_dir');
218 echo $IND . 'safe_mode_exec_dir: ' . $safe_mode_exec_dir . "<br />\n";
219}
220
a1912bbc 221/* register_globals check: test for boolean false and any string that is not equal to 'off' */
222
dc528046 223if ((bool) ini_get('register_globals') &&
a3b99374 224 strtolower(ini_get('register_globals'))!='off') {
b00dce9b 225 do_err('You have register_globals turned on. This is not an error, but it CAN be a security hazard. Consider turning register_globals off.', false);
c772f125 226}
a1912bbc 227
228
229/* variables_order check */
230
b00dce9b 231// FIXME(?): Hmm, how do we distinguish between when an ini setting is not available (ini_set() returns empty string) and when the administrator set the value to an empty string? The latter is sure to be highly rare, so for now, just assume that empty value means the setting isn't even available (could also check PHP version when this setting was implemented) although, we'll also warn the user if it is empty, with a non-fatal error
47fa8e9b 232$variables_order = strtoupper(ini_get('variables_order'));
233if (empty($variables_order))
b00dce9b 234 do_err('Your variables_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
47fa8e9b 235else if (strpos($variables_order, 'G') === FALSE
a1912bbc 236 || strpos($variables_order, 'P') === FALSE
237 || strpos($variables_order, 'C') === FALSE
47fa8e9b 238 || strpos($variables_order, 'S') === FALSE) {
b00dce9b 239 do_err('Your variables_order setting is insufficient for SquirrelMail to function. It needs at least "GPCS", but you have it set to "' . htmlspecialchars($variables_order) . '"', true);
a1912bbc 240} else {
241 echo $IND . "variables_order OK: $variables_order.<br />\n";
242}
243
244
47fa8e9b 245/* gpc_order check (removed from PHP as of v5.0) */
246
247if (!check_php_version(5)) {
b00dce9b 248 // FIXME(?): Hmm, how do we distinguish between when an ini setting is not available (ini_set() returns empty string) and when the administrator set the value to an empty string? The latter is sure to be highly rare, so for now, just assume that empty value means the setting isn't even available (could also check PHP version when this setting was implemented) although, we'll also warn the user if it is empty, with a non-fatal error
47fa8e9b 249 $gpc_order = strtoupper(ini_get('gpc_order'));
250 if (empty($gpc_order))
b00dce9b 251 do_err('Your gpc_order setting seems to be empty. Make sure it is undefined in any PHP ini files, .htaccess files, etc. and not specifically set to an empty value or SquirrelMail may not function correctly', false);
47fa8e9b 252 else if (strpos($gpc_order, 'G') === FALSE
253 || strpos($gpc_order, 'P') === FALSE
254 || strpos($gpc_order, 'C') === FALSE) {
b00dce9b 255 do_err('Your gpc_order setting is insufficient for SquirrelMail to function. It needs to be set to "GPC", but you have it set to "' . htmlspecialchars($gpc_order) . '"', true);
47fa8e9b 256 } else {
257 echo $IND . "gpc_order OK: $gpc_order.<br />\n";
258 }
a1912bbc 259}
260
261
262/* check PHP extensions */
263
d1ae9d4c 264$php_exts = array('session','pcre');
265$diff = array_diff($php_exts, get_loaded_extensions());
266if(count($diff)) {
267 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
268}
269
d053c206 270echo $IND . "PHP extensions OK. Dynamic loading is ";
271
272if (!(bool)ini_get('enable_dl') || (bool)ini_get('safe_mode')) {
273 echo "disabled.<br />\n";
274} else {
275 echo "enabled.<br />\n";
276}
277
d1ae9d4c 278
8f186a2a 279/* dangerous php settings */
280/**
281 * mbstring.func_overload allows to replace original string and regexp functions
282 * with their equivalents from php mbstring extension. It causes problems when
d0184454 283 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
9211bcef 284 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
8f186a2a 285 * and .htaccess files (php 4.3.5).
286 */
287if (function_exists('mb_internal_encoding') &&
9211bcef 288 check_php_version(4,2,0) &&
8f186a2a 289 (int)ini_get('mbstring.func_overload')!=0) {
290 $mb_error='You have enabled mbstring overloading.'
291 .' It can cause problems with SquirrelMail scripts that rely on single byte string functions.';
292 do_err($mb_error);
293}
d1ae9d4c 294
99c1c0d6 295/**
296 * Do not use SquirrelMail with magic_quotes_* on.
297 */
430a19f3 298if ( (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime()) ||
299 (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) ||
99c1c0d6 300 ( (bool) ini_get('magic_quotes_sybase') && ini_get('magic_quotes_sybase') != 'off' )
301 ) {
302 $magic_quotes_warning='You have enabled any one of <tt>magic_quotes_runtime</tt>, '
303 .'<tt>magic_quotes_gpc</tt> or <tt>magic_quotes_sybase</tt> in your PHP '
304 .'configuration. We recommend all those settings to be off. SquirrelMail '
305 .'may work with them on, but when experiencing stray backslashes in your mail '
306 .'or other strange behaviour, it may be advisable to turn them off.';
307 do_err($magic_quotes_warning,false);
308}
309
dc528046 310if (ini_get('short_open_tag') == 0) {
311 $short_open_tag_warning = 'You have configured PHP not to allow short tags '
312 . '(<tt>short_open_tag=off</tt>). This shouldn\'t be a problem with '
313 . 'SquirrelMail or any plugin coded coded according to the '
314 . 'SquirrelMail Coding Guidelines, but if you experience problems with '
315 . 'PHP code being displayed in some of the pages and changing setting '
316 . 'to "on" solves the problem, please file a bug report against the '
317 . 'failing plugin. The correct contact information is most likely '
318 . 'to be found in the plugin documentation.';
319 do_err($short_open_tag_warning, false);
320}
99c1c0d6 321
d1ae9d4c 322/* checking paths */
323
324echo "Checking paths...<br />\n";
325
326if(!file_exists($data_dir)) {
d0184454 327 // data_dir is not that important in db_setups.
ccbde363 328 if (!empty($prefs_dsn)) {
d0184454 329 $data_dir_error = "Data dir ($data_dir) does not exist!\n";
330 echo $IND .'<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
331 } else {
332 do_err("Data dir ($data_dir) does not exist!");
333 }
91e0dccc 334}
d0184454 335// don't check if errors
336if(!isset($data_dir_error) && !is_dir($data_dir)) {
ccbde363 337 if (!empty($prefs_dsn)) {
d0184454 338 $data_dir_error = "Data dir ($data_dir) is not a directory!\n";
339 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
340 } else {
341 do_err("Data dir ($data_dir) is not a directory!");
342 }
91e0dccc 343}
d4eaadbe 344// datadir should be executable - but no clean way to test on that
d0184454 345if(!isset($data_dir_error) && !is_writable($data_dir)) {
ccbde363 346 if (!empty($prefs_dsn)) {
d0184454 347 $data_dir_error = "Data dir ($data_dir) is not writable!\n";
348 echo $IND . '<font color="red"><b>ERROR:</b></font> ' . $data_dir_error;
349 } else {
350 do_err("Data dir ($data_dir) is not writable!");
351 }
d1ae9d4c 352}
353
d0184454 354if (isset($data_dir_error)) {
355 echo " Some plugins might need access to data directory.<br />\n";
356} else {
357 // todo_ornot: actually write something and read it back.
358 echo $IND . "Data dir OK.<br />\n";
359}
d1ae9d4c 360
361if($data_dir == $attachment_dir) {
362 echo $IND . "Attachment dir is the same as data dir.<br />\n";
d0184454 363 if (isset($data_dir_error)) {
364 do_err($data_dir_error);
365 }
d1ae9d4c 366} else {
367 if(!file_exists($attachment_dir)) {
368 do_err("Attachment dir ($attachment_dir) does not exist!");
91e0dccc 369 }
d1ae9d4c 370 if (!is_dir($attachment_dir)) {
371 do_err("Attachment dir ($attachment_dir) is not a directory!");
91e0dccc 372 }
d1ae9d4c 373 if (!is_writable($attachment_dir)) {
374 do_err("I cannot write to attachment dir ($attachment_dir)!");
375 }
376 echo $IND . "Attachment dir OK.<br />\n";
377}
378
379
646b17e0 380echo "Checking plugins...<br />\n";
381
d1ae9d4c 382/* check plugins and themes */
d17b7894 383//FIXME: check requirements given in plugin _info() function, such as required PHP extensions, Pear packages, other plugins, SM version, etc see development docs for list of returned info from that function
384//FIXME: update this list with most recent contents of the Obsolete category - I think it has changed recently
f084f987 385$bad_plugins = array(
0880efc9 386 'attachment_common', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 387 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
0880efc9 388 'compose_new_window', // Integrated into SquirrelMail 1.4 core
389 'delete_move_next', // Integrated into SquirrelMail 1.5 core
eb7bd9b7 390 'disk_quota', // Obsolete: See Check Quota plugin
0880efc9 391 'email_priority', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 392 'emoticons', // Obsolete: See HTML Mail plugin
0880efc9 393 'focus_change', // Integrated into SquirrelMail 1.2 core
394 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
395 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
eb7bd9b7 396 'hancock', // Not Working: See Random Signature Taglines plugin
0880efc9 397 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
398 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
399 'motd', // Integrated into SquirrelMail 1.2 core
400 'paginator', // Integrated into SquirrelMail 1.2 core
401 'printer_friendly', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 402 'procfilter', // Obsolete: See Server Side Filter plugin
0880efc9 403 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
404 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
405 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
406 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
407 'sqclock', // Integrated into SquirrelMail 1.2 core
eb7bd9b7 408 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
409 'tmda', // Obsolete: See TMDA Tools plugin
410 'vacation', // Obsolete: See Vacation Local plugin
0880efc9 411 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
412 'xmailer' // Integrated into SquirrelMail 1.2 core
f084f987 413 );
3a196538 414
5b53b7e0 415if (isset($plugins[0])) {
416 foreach($plugins as $plugin) {
417 if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
f084f987 418 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
5b53b7e0 419 } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
1dc63862 420 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot locate or read its setup.php file.', FALSE);
f084f987 421 } elseif (in_array($plugin, $bad_plugins)) {
422 do_err('You have enabled the <i>'.$plugin.'</i> plugin, which causes problems with this version of SquirrelMail. Please check the ReleaseNotes or other documentation for more information.', false);
423 }
d1ae9d4c 424 }
1dc63862 425
426
69792446 427 // load plugin functions
428 include_once(SM_PATH . 'functions/plugin.php');
1dc63862 429
69792446 430 // turn on output buffering in order to prevent output of new lines
431 ob_start();
432 foreach ($plugins as $name) {
433 use_plugin($name);
1dc63862 434
435 // get output and remove whitespace
436 $output = trim(ob_get_contents());
437
438 // if plugin outputs more than newlines and spacing, stop script execution.
439 if (!empty($output)) {
440 $plugin_load_error = 'Some output was produced when plugin <i>' . $name . '</i> was loaded. Usually this means there is an error in the plugin\'s setup or configuration file. The output was: '.htmlspecialchars($output);
441 do_err($plugin_load_error);
442 }
69792446 443 }
69792446 444 ob_end_clean();
1dc63862 445
446
447 /**
448 * Check the contents of the static plugin hooks array file against
449 * the plugin setup file, which may have changed in an upgrade, etc.
450 * This helps remind admins to re-run the configuration utility when
451 * a plugin has been changed or upgraded.
452 */
453 $static_squirrelmail_plugin_hooks = $squirrelmail_plugin_hooks;
454 $squirrelmail_plugin_hooks = array();
455 foreach ($plugins as $name) {
456 $function = "squirrelmail_plugin_init_$name";
457 if (function_exists($function)) {
458 $function();
459
460 // now iterate through each hook and make sure the
461 // plugin is registered on the correct ones in the
462 // static plugin configuration file
463 //
464 foreach ($squirrelmail_plugin_hooks as $hook_name => $hooked_plugins)
465 foreach ($hooked_plugins as $hooked_plugin => $hooked_function)
466 if ($hooked_plugin == $name
467 && (empty($static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin])
468 || $static_squirrelmail_plugin_hooks[$hook_name][$hooked_plugin] != $hooked_function))
469 do_err('The plugin <i>' . $name . '</i> is supposed to be registered on the <i>' . $hook_name . '</i> hook, but it is not. You need to re-run the configuration utility and re-save your configuration file.', FALSE);
470 }
69792446 471 }
1dc63862 472 $squirrelmail_plugin_hooks = $static_squirrelmail_plugin_hooks;
473
474
dc528046 475 /**
56f9bb83 476 * Print plugin versions
477 */
56f9bb83 478 echo $IND . "Plugin versions...<br />\n";
479 foreach ($plugins as $name) {
d95b10b3 480 $plugin_version = get_plugin_version($name);
daa0c5b8 481 $english_name = get_plugin_requirement($name, 'english_name');
482 echo $IND . $IND . (empty($english_name) ? $name . ' ' : $english_name . ' (' . $name . ') ') . (empty($plugin_version) ? '??' : $plugin_version) . "<br />\n";
2cbaf68d 483
dc528046 484 // check if this plugin has any other plugin
2cbaf68d 485 // dependencies and if they are satisfied
486 //
487 $failed_dependencies = check_plugin_dependencies($name);
f258865c 488 if ($failed_dependencies === SQ_INCOMPATIBLE) {
03a69f57 489 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
490 }
491 else if (is_array($failed_dependencies)) {
2cbaf68d 492 $missing_plugins = '';
e1a125cd 493 $incompatible_plugins = '';
fc6228e4 494 foreach ($failed_dependencies as $depend_name => $depend_requirements) {
e1a125cd 495 if ($depend_requirements['version'] == SQ_INCOMPATIBLE)
496 $incompatible_plugins .= ', ' . $depend_name;
497 else
498 $missing_plugins .= ', ' . $depend_name . ' (version ' . $depend_requirements['version'] . ', ' . ($depend_requirements['activate'] ? 'must be activated' : 'need not be activated') . ')';
2cbaf68d 499 }
e1a125cd 500 $error_string = (!empty($incompatible_plugins) ? $name . ' cannot be activated at the same time as the following plugins: ' . trim($incompatible_plugins, ', ') : '')
501 . (!empty($missing_plugins) ? (!empty($incompatible_plugins) ? '. ' . $name . ' is also ' : $name . ' is ') . 'missing some dependencies: ' . trim($missing_plugins, ', ') : '');
502 do_err($error_string, FALSE);
2cbaf68d 503 }
504
56f9bb83 505 }
1dc63862 506
507
69792446 508 /**
dc528046 509 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
6e515418 510 * message and return TRUE if there are any errors in its setup/configuration.
69792446 511 */
62fb877b 512 $plugin_err = boolean_hook_function('configtest', $null, 1);
69792446 513 if($plugin_err) {
514 do_err('Some plugin tests failed.');
515 } else {
516 echo $IND . "Plugins OK.<br />\n";
517 }
5b53b7e0 518} else {
519 echo $IND . "Plugins are not enabled in config.<br />\n";
d1ae9d4c 520}
d1ae9d4c 521foreach($theme as $thm) {
522 if(!file_exists($thm['PATH'])) {
523 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot find it ('.$thm['PATH'].').', FALSE);
524 } elseif(!is_readable($thm['PATH'])) {
525 do_err('You have enabled the <i>'.$thm['NAME'].'</i> theme but I cannot read it ('.$thm['PATH'].').', FALSE);
526 }
527}
528
529echo $IND . "Themes OK.<br />\n";
530
07337c9b 531if ( $squirrelmail_default_language != 'en_US' ) {
532 $loc_path = SM_PATH .'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
533 if( ! file_exists( $loc_path ) ) {
f8a1ed5a 534 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 535 '</i> as your default language, but I cannot find this translation (should be '.
536 'in <tt>' . $loc_path . '</tt>). Please note that you have to download translations '.
537 'separately from the main SquirrelMail package.', FALSE);
07337c9b 538 } elseif ( ! is_readable( $loc_path ) ) {
f8a1ed5a 539 do_err('You have set <i>' . $squirrelmail_default_language .
f084f987 540 '</i> as your default language, but I cannot read this translation (file '.
541 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
07337c9b 542 } else {
543 echo $IND . "Default language OK.<br />\n";
544 }
545} else {
546 echo $IND . "Default language OK.<br />\n";
547}
548
74530cf4 549echo $IND . "Base URL detected as: <tt>" . htmlspecialchars($test_location) .
550 "</tt> (location base " . (empty($config_location_base) ? 'autodetected' : 'set to <tt>' .
551 htmlspecialchars($config_location_base)."</tt>") . ")<br />\n";
23649466 552
a15f9d93 553/* check minimal requirements for other security options */
d1ae9d4c 554
a15f9d93 555/* imaps or ssmtp */
556if($use_smtp_tls == 1 || $use_imap_tls == 1) {
d1ae9d4c 557 if(!check_php_version(4,3,0)) {
558 do_err('You need at least PHP 4.3.0 for SMTP/IMAP TLS!');
559 }
560 if(!extension_loaded('openssl')) {
561 do_err('You need the openssl PHP extension to use SMTP/IMAP TLS!');
562 }
563}
a15f9d93 564/* starttls extensions */
1c4f110f 565if($use_smtp_tls === 2 || $use_imap_tls === 2) {
a15f9d93 566 if (! function_exists('stream_socket_enable_crypto')) {
567 do_err('If you want to use STARTTLS extension, you need stream_socket_enable_crypto() function from PHP 5.1.0 and newer.');
568 }
569}
570/* digest-md5 */
571if ($smtp_auth_mech=='digest-md5' || $imap_auth_mech =='digest-md5') {
572 if (!extension_loaded('xml')) {
573 do_err('You need the PHP XML extension to use Digest-MD5 authentication!');
574 }
575}
576
577/* check outgoing mail */
d1ae9d4c 578
579echo "Checking outgoing mail service....<br />\n";
580
581if($useSendmail) {
582 // is_executable also checks for existance, but we want to be as precise as possible with the errors
583 if(!file_exists($sendmail_path)) {
584 do_err("Location of sendmail program incorrect ($sendmail_path)!");
91e0dccc 585 }
d1ae9d4c 586 if(!is_executable($sendmail_path)) {
587 do_err("I cannot execute the sendmail program ($sendmail_path)!");
588 }
589
590 echo $IND . "sendmail OK<br />\n";
591} else {
a15f9d93 592 $stream = fsockopen( ($use_smtp_tls==1?'tls://':'').$smtpServerAddress, $smtpPort,
f084f987 593 $errorNumber, $errorString);
d1ae9d4c 594 if(!$stream) {
595 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
f084f987 596 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
d1ae9d4c 597 }
598
599 // check for SMTP code; should be 2xx to allow us access
600 $smtpline = fgets($stream, 1024);
601 if(((int) $smtpline{0}) > 3) {
9c941728 602 do_err("Error connecting to SMTP server. Server error: ".
f084f987 603 htmlspecialchars($smtpline));
d1ae9d4c 604 }
605
a15f9d93 606 /* smtp starttls checks */
1c4f110f 607 if ($use_smtp_tls===2) {
a15f9d93 608 // if something breaks, script should close smtp connection on exit.
609
610 // say helo
611 fwrite($stream,"EHLO $client_ip\r\n");
612
613 $ehlo=array();
614 $ehlo_error = false;
615 while ($line=fgets($stream, 1024)){
616 if (preg_match("/^250(-|\s)(\S*)\s+(\S.*)/",$line,$match)||
f084f987 617 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
a15f9d93 618 if (!isset($match[3])) {
619 // simple one word extension
620 $ehlo[strtoupper($match[2])]='';
621 } else {
622 // ehlo-keyword + ehlo-param
623 $ehlo[strtoupper($match[2])]=trim($match[3]);
624 }
625 if ($match[1]==' ') {
626 $ret = $line;
627 break;
628 }
629 } else {
dc528046 630 //
a15f9d93 631 $ehlo_error = true;
632 $ehlo[]=$line;
633 break;
634 }
635 }
636 if ($ehlo_error) {
637 do_err('SMTP EHLO failed. You need ESMTP support for SMTP STARTTLS');
638 } elseif (!array_key_exists('STARTTLS',$ehlo)) {
639 do_err('STARTTLS support is not declared by SMTP server.');
640 }
641
642 fwrite($stream,"STARTTLS\r\n");
643 $starttls_response=fgets($stream, 1024);
644 if ($starttls_response[0]!=2) {
645 $starttls_cmd_err = 'SMTP STARTTLS failed. Server replied: '
646 .htmlspecialchars($starttls_response);
647 do_err($starttls_cmd_err);
648 } elseif(! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
649 do_err('Failed to enable encryption on SMTP STARTTLS connection.');
650 } else {
651 echo $IND . "SMTP STARTTLS extension looks OK.<br />\n";
652 }
653 // According to RFC we should second ehlo call here.
654 }
655
d1ae9d4c 656 fputs($stream, 'QUIT');
657 fclose($stream);
9c941728 658 echo $IND . 'SMTP server OK (<tt><small>'.
f084f987 659 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
d1ae9d4c 660
661 /* POP before SMTP */
662 if($pop_before_smtp) {
783e926e 663 if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
664 $stream = fsockopen($pop_before_smtp_host, 110, $err_no, $err_str);
d1ae9d4c 665 if (!$stream) {
783e926e 666 do_err("Error connecting to POP Server ($pop_before_smtp_host:110) "
f084f987 667 . $err_no . ' : ' . htmlspecialchars($err_str));
d1ae9d4c 668 }
669
670 $tmp = fgets($stream, 1024);
671 if (substr($tmp, 0, 3) != '+OK') {
783e926e 672 do_err("Error connecting to POP Server ($pop_before_smtp_host:110)"
f084f987 673 . ' '.htmlspecialchars($tmp));
d1ae9d4c 674 }
675 fputs($stream, 'QUIT');
676 fclose($stream);
677 echo $IND . "POP-before-SMTP OK.<br />\n";
678 }
679}
680
df758744 681/**
682 * Check the IMAP server
683 */
d1ae9d4c 684echo "Checking IMAP service....<br />\n";
685
df758744 686/** Can we open a connection? */
a15f9d93 687$stream = fsockopen( ($use_imap_tls==1?'tls://':'').$imapServerAddress, $imapPort,
f084f987 688 $errorNumber, $errorString);
d1ae9d4c 689if(!$stream) {
70b71161 690 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
f084f987 691 "Server error: ($errorNumber) ".
692 htmlspecialchars($errorString));
d1ae9d4c 693}
694
df758744 695/** Is the first response 'OK'? */
d1ae9d4c 696$imapline = fgets($stream, 1024);
697if(substr($imapline, 0,4) != '* OK') {
f084f987 698 do_err('Error connecting to IMAP server. Server error: '.
699 htmlspecialchars($imapline));
d1ae9d4c 700}
701
df758744 702echo $IND . 'IMAP server ready (<tt><small>'.
9c941728 703 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
d1ae9d4c 704
df758744 705/** Check capabilities */
706fputs($stream, "A001 CAPABILITY\r\n");
a15f9d93 707$capline = '';
708while ($line=fgets($stream, 1024)){
f084f987 709 if (preg_match("/A001.*/",$line)) {
710 break;
711 } else {
712 $capline.=$line;
713 }
a15f9d93 714}
715
716/* don't display capabilities before STARTTLS */
1c4f110f 717if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
a15f9d93 718 do_err('Your server doesn\'t support STARTTLS.');
1c4f110f 719} elseif($use_imap_tls===2) {
a15f9d93 720 /* try starting starttls */
721 fwrite($stream,"A002 STARTTLS\r\n");
722 $starttls_line=fgets($stream, 1024);
723 if (! preg_match("/^A002 OK.*/i",$starttls_line)) {
724 $imap_starttls_err = 'IMAP STARTTLS failed. Server replied: '
f084f987 725 .htmlspecialchars($starttls_line);
a15f9d93 726 do_err($imap_starttls_err);
727 } elseif (! stream_socket_enable_crypto($stream,true,STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
728 do_err('Failed to enable encryption on IMAP connection.');
729 } else {
730 echo $IND . "IMAP STARTTLS extension looks OK.<br />\n";
731 }
732
733 // get new capability line
734 fwrite($stream,"A003 CAPABILITY\r\n");
735 $capline='';
736 while ($line=fgets($stream, 1024)){
737 if (preg_match("/A003.*/",$line)) {
738 break;
739 } else {
740 $capline.=$line;
741 }
742 }
743}
df758744 744
745echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
746
747if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
748 do_err('Your server doesn\'t allow plaintext logins. '.
f084f987 749 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
750 'in the SquirrelMail configuration.', FALSE);
df758744 751}
df758744 752
ceb7ad3c 753if (stristr($capline, 'XMAGICTRASH') !== false) {
754 $magic_trash = 'It looks like IMAP_MOVE_EXPUNGE_TO_TRASH option is turned on '
755 .'in your Courier IMAP configuration. Courier does not provide tools that '
756 .'allow to detect folder used for Trash or commands are not documented. '
757 .'SquirrelMail can\'t detect special trash folder. SquirrelMail manages '
758 .'all message deletion or move operations internally and '
759 .'IMAP_MOVE_EXPUNGE_TO_TRASH option can cause errors in message and '
760 .'folder management operations. Please turn off IMAP_MOVE_EXPUNGE_TO_TRASH '
761 .'option in Courier imapd configuration.';
762 do_err($magic_trash,false);
763}
764
0fa9bde7 765/* add warning about IMAP delivery */
766if (stristr($capline, 'XCOURIEROUTBOX') !== false) {
767 $courier_outbox = 'OUTBOX setting is enabled in your Courier imapd '
768 .'configuration. SquirrelMail uses standard SMTP protocol or sendmail '
769 .'binary to send emails. Courier IMAP delivery method is not supported'
770 .' and can create duplicate email messages.';
771 do_err($courier_outbox,false);
772}
773
df758744 774/** OK, close connection */
a15f9d93 775fputs($stream, "A004 LOGOUT\r\n");
df758744 776fclose($stream);
777
17fca61d 778echo "Checking internationalization (i18n) settings...<br />\n";
0ed3bdc3 779echo "$IND gettext - ";
780if (function_exists('gettext')) {
8f186a2a 781 echo 'Gettext functions are available.'
782 .' On some systems you must have appropriate system locales compiled.'
783 ."<br />\n";
fd72907b 784
785 /* optional setlocale() tests. Should work only on glibc systems. */
786 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET)) {
867fed37 787 include_once(SM_PATH . 'include/languages.php');
fd72907b 788 echo $IND . $IND . 'Testing translations:<br>';
789 foreach ($languages as $lang_code => $lang_data) {
790 /* don't test aliases */
791 if (isset($lang_data['NAME'])) {
792 /* locale can be $lang_code or $lang_data['LOCALE'] */
793 if (isset($lang_data['LOCALE'])) {
794 $setlocale = $lang_data['LOCALE'];
795 } else {
796 $setlocale = $lang_code;
797 }
798 /* prepare information about tested locales */
799 if (is_array($setlocale)) {
800 $display_locale = implode(', ',$setlocale);
801 $locale_count = count($setlocale);
802 } else {
803 $display_locale = $setlocale;
804 $locale_count = 1;
805 }
806 $tested_locales_msg = 'Tested '.htmlspecialchars($display_locale).' '
807 .($locale_count>1 ? 'locales':'locale'). '.';
808
809 echo $IND . $IND .$IND . $lang_data['NAME'].' (' .$lang_code. ') - ';
810 $retlocale = sq_setlocale(LC_ALL,$setlocale);
811 if (is_bool($retlocale)) {
812 echo '<font color="red">unsupported</font>. ';
813 echo $tested_locales_msg;
814 } else {
815 echo 'supported. '
816 .$tested_locales_msg
817 .' setlocale() returned "'.htmlspecialchars($retlocale).'"';
818 }
819 echo "<br />\n";
820 }
821 }
822 echo $IND . $IND . '<a href="configtest.php">Don\'t test translations</a>';
823 } else {
824 echo $IND . $IND . '<a href="configtest.php?testlocales=1">Test translations</a>. '
825 .'This test is not accurate and might work only on some systems.'
826 ."\n";
827 }
828 echo "<br />\n";
829 /* end of translation tests */
0ed3bdc3 830} else {
8f186a2a 831 echo 'Gettext functions are unavailable.'
832 .' SquirrelMail will use slower internal gettext functions.'
833 ."<br />\n";
0ed3bdc3 834}
835echo "$IND mbstring - ";
836if (function_exists('mb_detect_encoding')) {
837 echo "Mbstring functions are available.<br />\n";
838} else {
8f186a2a 839 echo 'Mbstring functions are unavailable.'
840 ." Japanese translation won't work.<br />\n";
0ed3bdc3 841}
842echo "$IND recode - ";
843if (function_exists('recode')) {
844 echo "Recode functions are available.<br />\n";
ba17b6c7 845} elseif (isset($use_php_recode) && $use_php_recode) {
0ed3bdc3 846 echo "Recode functions are unavailable.<br />\n";
847 do_err('Your configuration requires recode support, but recode support is missing.');
848} else {
849 echo "Recode functions are unavailable.<br />\n";
850}
851echo "$IND iconv - ";
852if (function_exists('iconv')) {
853 echo "Iconv functions are available.<br />\n";
ba17b6c7 854} elseif (isset($use_php_iconv) && $use_php_iconv) {
0ed3bdc3 855 echo "Iconv functions are unavailable.<br />\n";
856 do_err('Your configuration requires iconv support, but iconv support is missing.');
857} else {
858 echo "Iconv functions are unavailable.<br />\n";
859}
867fed37 860// same test as in include/init.php + date_default_timezone_set check
0ed3bdc3 861echo "$IND timezone - ";
867fed37 862if ( (!ini_get('safe_mode')) || function_exists('date_default_timezone_set') ||
f084f987 863 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
864 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
fd72907b 865 echo "Webmail users can change their time zone settings. \n";
0ed3bdc3 866} else {
fd72907b 867 echo "Webmail users can't change their time zone settings. \n";
4764a7ff 868}
fd72907b 869if (isset($_ENV['TZ'])) {
870 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
871} else {
872 echo 'Current time zone is '.date('T');
873}
874echo ".<br />\n";
d18703d3 875
4764a7ff 876// Pear DB tests
d18703d3 877echo "Checking database functions...<br />\n";
878if($addrbook_dsn || $prefs_dsn || $addrbook_global_dsn) {
134e4174 879 @include_once('DB.php');
880 if (class_exists('DB')) {
881 echo "$IND PHP Pear DB support is present.<br />\n";
882 $db_functions=array(
f084f987 883 'dbase' => 'dbase_open',
884 'fbsql' => 'fbsql_connect',
885 'interbase' => 'ibase_connect',
886 'informix' => 'ifx_connect',
887 'msql' => 'msql_connect',
888 'mssql' => 'mssql_connect',
889 'mysql' => 'mysql_connect',
890 'mysqli' => 'mysqli_connect',
891 'oci8' => 'ocilogon',
892 'odbc' => 'odbc_connect',
893 'pgsql' => 'pg_connect',
894 'sqlite' => 'sqlite_open',
895 'sybase' => 'sybase_connect'
896 );
134e4174 897
898 $dsns = array();
899 if($prefs_dsn) {
900 $dsns['preferences'] = $prefs_dsn;
901 }
902 if($addrbook_dsn) {
903 $dsns['addressbook'] = $addrbook_dsn;
904 }
905 if($addrbook_global_dsn) {
906 $dsns['global addressbook'] = $addrbook_global_dsn;
907 }
908
909 foreach($dsns as $type => $dsn) {
ba17b6c7 910 $aDsn = explode(':', $dsn);
911 $dbtype = array_shift($aDsn);
d053c206 912
134e4174 913 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
914 echo "$IND$dbtype database support present.<br />\n";
d053c206 915 } elseif(!(bool)ini_get('enable_dl') || (bool)ini_get('safe_mode')) {
916 do_err($dbtype.' database support not present!');
917 } else {
918 // Non-fatal error
919 do_err($dbtype.' database support not present or not configured!
920 Trying to dynamically load '.$dbtype.' extension.
921 Please note that it is advisable to not rely on dynamic loading of extensions.', FALSE);
922 }
134e4174 923
134e4174 924
d053c206 925 // now, test this interface:
134e4174 926
d053c206 927 $dbh = DB::connect($dsn, true);
928 if (DB::isError($dbh)) {
929 do_err('Database error: '. htmlspecialchars(DB::errorMessage($dbh)) .
930 ' in ' .$type .' DSN.');
d18703d3 931 }
d053c206 932 $dbh->disconnect();
933 echo "$IND$type database connect successful.<br />\n";
134e4174 934 }
935 } else {
8f186a2a 936 $db_error='Required PHP PEAR DB support is not available.'
937 .' Is PEAR installed and is the include path set correctly to find <tt>DB.php</tt>?'
dc528046 938 .' The include path is now: "<tt>' . ini_get('include_path') . '</tt>".';
8f186a2a 939 do_err($db_error);
134e4174 940 }
4764a7ff 941} else {
d18703d3 942 echo $IND."not using database functionality.<br />\n";
0ed3bdc3 943}
7562c55b 944
945// LDAP DB tests
946echo "Checking LDAP functions...<br />\n";
947if( empty($ldap_server) ) {
134e4174 948 echo $IND."not using LDAP functionality.<br />\n";
7562c55b 949} else {
d0184454 950 if ( !function_exists('ldap_connect') ) {
7562c55b 951 do_err('Required LDAP support is not available.');
952 } else {
134e4174 953 echo "$IND LDAP support present.<br />\n";
7562c55b 954 foreach ( $ldap_server as $param ) {
955
d0184454 956 $linkid = @ldap_connect($param['host'], (empty($param['port']) ? 389 : $param['port']) );
7562c55b 957
958 if ( $linkid ) {
f084f987 959 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
91e0dccc 960
7562c55b 961 if ( !empty($param['protocol']) &&
f084f987 962 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION, $param['protocol']) ) {
7562c55b 963 do_err('Unable to set LDAP protocol');
91e0dccc 964 }
7562c55b 965
966 if ( empty($param['binddn']) ) {
d0184454 967 $bind = @ldap_bind($linkid);
7562c55b 968 } else {
d0184454 969 $bind = @ldap_bind($param['binddn'], $param['bindpw']);
7562c55b 970 }
971
972 if ( $bind ) {
973 echo "$IND LDAP Bind Successful <br />";
974 } else {
975 do_err('Unable to Bind to LDAP Server');
976 }
91e0dccc 977
d0184454 978 @ldap_close($linkid);
7562c55b 979 } else {
980 do_err('Connection to LDAP failed');
981 }
982 }
983 }
984}
a2b193bc 985
3a196538 986echo '<hr width="75%" align="center">';
987echo '<h2 align="center">Summary</h2>';
988$footer = '<hr width="75%" align="center">';
989if ($warnings) {
b00dce9b 990 echo '<p>No fatal errors were found, but there was at least 1 warning. Please check the flagged issue(s) carefully, as correcting them may prevent erratic, undefined, or incorrect behavior (or flat out breakage).</p>';
f084f987 991 echo $footer;
3a196538 992} else {
f084f987 993 print <<< EOF
d1ae9d4c 994<p>Congratulations, your SquirrelMail setup looks fine to me!</p>
995
13721b47 996<p><a href="login.php">Login now</a></p>
d1ae9d4c 997
998</body>
3a196538 999</html>
1000EOF;
f084f987 1001 echo $footer;
3a196538 1002}