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