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