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