Fixing variable not parsed through PHP. Thanks to Scott Venier for the patch.
[squirrelmail.git] / src / configtest.php
1 <?php
2
3 /**
4 * SquirrelMail configtest script
5 *
6 * @copyright &copy; 2003-2007 The SquirrelMail Project Team
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
8 * @version $Id$
9 * @package squirrelmail
10 * @subpackage config
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
18 /** This is the configtest page */
19 define('PAGE_NAME', 'configtest');
20
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
24 /** force verbose error reporting and turn on display of errors */
25 error_reporting(E_ALL);
26 ini_set('display_errors',1);
27
28 /** Blockcopy from init.php. Cleans globals. */
29 if ((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 */
71 function do_err($str, $fatal = TRUE) {
72 global $IND, $warnings;
73 $level = $fatal ? 'FATAL ERROR:' : 'WARNING:';
74 echo '<p>'.$IND.'<font color="red"><b>' . $level . '</b></font> ' .$str. "</p>\n";
75 if($fatal) {
76 echo '</body></html>';
77 exit;
78 } else {
79 $warnings++;
80 }
81 }
82
83 ob_implicit_flush();
84 /** @ignore */
85 define('SM_PATH', '../');
86 /** load minimal function set */
87 require(SM_PATH . 'include/constants.php');
88 require(SM_PATH . 'functions/global.php');
89 require(SM_PATH . 'functions/strings.php');
90 $SQM_INTERNAL_VERSION = explode('.', SM_VERSION, 3);
91 $SQM_INTERNAL_VERSION[2] = intval($SQM_INTERNAL_VERSION[2]);
92
93 /** set default value in order to block remote access */
94 $allow_remote_configtest=false;
95
96 /** Load all configuration files before output begins */
97
98 /* load default configuration */
99 require(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 */
111 if (file_exists(SM_PATH . 'config/config.php')) {
112 require(SM_PATH . 'config/config.php');
113 }
114 /* load local configuration overrides */
115 if (file_exists(SM_PATH . 'config/config_local.php')) {
116 require(SM_PATH . 'config/config_local.php');
117 }
118
119 /** Load plugins */
120 global $disable_plugins;
121 $squirrelmail_plugin_hooks = array();
122 if (!$disable_plugins && file_exists(SM_PATH . 'config/plugin_hooks.php')) {
123 require(SM_PATH . 'config/plugin_hooks.php');
124 }
125
126 /** Warning counter */
127 $warnings = 0;
128
129 /** indent */
130 $IND = str_repeat('&nbsp;',4);
131
132 /**
133 * get_location starts session and must be run before output is started.
134 */
135 $test_location = get_location();
136
137 ?><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
138 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
139 <html>
140 <head>
141 <meta name="robots" content="noindex,nofollow">
142 <title>SquirrelMail configtest</title>
143 </head>
144 <body>
145 <h1>SquirrelMail configtest</h1>
146
147 <p>This script will try to check some aspects of your SquirrelMail configuration
148 and point you to errors whereever it can find them. You need to go run <tt>conf.pl</tt>
149 in the <tt>config/</tt> directory first before you run this script.</p>
150
151 <?php
152
153 $included = array_map('basename', get_included_files() );
154 if(!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 />'.
157 'You need to run <tt>conf.pl</tt> first.');
158 }
159 do_err('Could not read '.SM_PATH.'config/config.php! Check file permissions.');
160 }
161 if(!in_array('strings.php', $included)) {
162 do_err('Could not include '.SM_PATH.'functions/strings.php!<br />'.
163 'Check permissions on that file.');
164 }
165
166 /* Block remote use of script */
167 if (! $allow_remote_configtest) {
168 sqGetGlobalVar('REMOTE_ADDR',$client_ip,SQ_SERVER);
169 sqGetGlobalVar('SERVER_ADDR',$server_ip,SQ_SERVER);
170
171 if ((! isset($client_ip) || $client_ip!='127.0.0.1') &&
172 (! isset($client_ip) || ! isset($server_ip) || $client_ip!=$server_ip)) {
173 do_err('Enable "Allow remote configtest" option in squirrelmail configuration in order to use this script.');
174 }
175 }
176
177 echo "<p><table>\n<tr><td>SquirrelMail version:</td><td><b>" . SM_VERSION . "</b></td></tr>\n" .
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";
182
183 /* check $config_version */
184 if ($config_version!='1.5.0') {
185 do_err('Configuration file version does not match required version. Please update your configuration file.');
186 }
187
188
189 /* checking PHP specs */
190
191 echo "Checking PHP configuration...<br />\n";
192
193 if(!check_php_version(4,1,0)) {
194 do_err('Insufficient PHP version: '. PHP_VERSION . '! Minimum required: 4.1.0');
195 }
196
197 echo $IND . 'PHP version ' . PHP_VERSION . ' OK. (You have: ' . phpversion() . ". Minimum: 4.1.0)<br />\n";
198
199 echo $IND . 'display_errors: ' . ini_get('display_errors') . "<br />\n";
200
201 echo $IND . 'error_reporting: ' . ini_get('error_reporting') . "<br />\n";
202
203 $safe_mode = ini_get('safe_mode');
204 if ($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>)';
208 if (!empty($addrbook_dsn) || !empty($prefs_dsn) || !empty($addrbook_global_dsn))
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
215 /* register_globals check: test for boolean false and any string that is not equal to 'off' */
216
217 if ((bool) ini_get('register_globals') &&
218 strtolower(ini_get('register_globals'))!='off') {
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);
220 }
221
222
223 /* variables_order check */
224
225 // FIXME(?): Hmm, how do we distinguish between when an ini setting is
226 // not available (ini_set() returns empty string) and when
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)
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'));
234 if (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);
236 else if (strpos($variables_order, 'G') === FALSE
237 || strpos($variables_order, 'P') === FALSE
238 || strpos($variables_order, 'C') === FALSE
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);
241 } else {
242 echo $IND . "variables_order OK: $variables_order.<br />\n";
243 }
244
245
246 /* gpc_order check (removed from PHP as of v5.0) */
247
248 if (!check_php_version(5)) {
249 // FIXME(?): Hmm, how do we distinguish between when an ini setting is
250 // not available (ini_set() returns empty string) and when
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 }
267 }
268
269
270 /* check PHP extensions */
271
272 $php_exts = array('session','pcre');
273 $diff = array_diff($php_exts, get_loaded_extensions());
274 if(count($diff)) {
275 do_err('Required PHP extensions missing: '.implode(', ',$diff) );
276 }
277
278 echo $IND . "PHP extensions OK. Dynamic loading is ";
279
280 if (!(bool)ini_get('enable_dl') || (bool)ini_get('safe_mode')) {
281 echo "disabled.<br />\n";
282 } else {
283 echo "enabled.<br />\n";
284 }
285
286
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
291 * scripts analyze 8bit strings byte after byte or use 8bit strings in regexp tests.
292 * Setting can be controlled in php.ini (php 4.2.0), webserver config (php 4.2.0)
293 * and .htaccess files (php 4.3.5).
294 */
295 if (function_exists('mb_internal_encoding') &&
296 check_php_version(4,2,0) &&
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 }
302
303 /**
304 * Do not use SquirrelMail with magic_quotes_* on.
305 */
306 if ( (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime()) ||
307 (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) ||
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
318 if (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 }
329
330 /* checking paths */
331
332 echo "Checking paths...<br />\n";
333
334 if(!file_exists($data_dir)) {
335 // data_dir is not that important in db_setups.
336 if (!empty($prefs_dsn)) {
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 }
342 }
343 // don't check if errors
344 if(!isset($data_dir_error) && !is_dir($data_dir)) {
345 if (!empty($prefs_dsn)) {
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 }
351 }
352 // datadir should be executable - but no clean way to test on that
353 if(!isset($data_dir_error) && !is_writable($data_dir)) {
354 if (!empty($prefs_dsn)) {
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 }
360 }
361
362 if (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 }
368
369 if($data_dir == $attachment_dir) {
370 echo $IND . "Attachment dir is the same as data dir.<br />\n";
371 if (isset($data_dir_error)) {
372 do_err($data_dir_error);
373 }
374 } else {
375 if(!file_exists($attachment_dir)) {
376 do_err("Attachment dir ($attachment_dir) does not exist!");
377 }
378 if (!is_dir($attachment_dir)) {
379 do_err("Attachment dir ($attachment_dir) is not a directory!");
380 }
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
388 echo "Checking plugins...<br />\n";
389
390 /* check plugins and themes */
391 //FIXME: check requirements given in plugin _info() function, such
392 // as required PHP extensions, Pear packages, other plugins, SM version, etc
393 // see development docs for list of returned info from that function
394 $bad_plugins = array(
395 'attachment_common', // Integrated into SquirrelMail 1.2 core
396 'auto_prune_sent', // Obsolete: See Proon Automatic Folder Pruning plugin
397 'compose_new_window', // Integrated into SquirrelMail 1.4 core
398 'delete_move_next', // Integrated into SquirrelMail 1.5 core
399 'disk_quota', // Obsolete: See Check Quota plugin
400 'email_priority', // Integrated into SquirrelMail 1.2 core
401 'emoticons', // Obsolete: See HTML Mail plugin
402 'focus_change', // Integrated into SquirrelMail 1.2 core
403 'folder_settings', // Integrated into SquirrelMail 1.5.1 core
404 'global_sql_addressbook', // Integrated into SquirrelMail 1.4 core
405 'hancock', // Not Working: See Random Signature Taglines plugin
406 'msg_flags', // Integrated into SquirrelMail 1.5.1 core
407 'message_source', // Added to SquirrelMail 1.4 Core Plugins (message_details)
408 'motd', // Integrated into SquirrelMail 1.2 core
409 'paginator', // Integrated into SquirrelMail 1.2 core
410 'printer_friendly', // Integrated into SquirrelMail 1.2 core
411 'procfilter', // Obsolete: See Server Side Filter plugin
412 'redhat_php_cgi_fix', // Integrated into SquirrelMail 1.1.1 core
413 'send_to_semicolon', // Integrated into SquirrelMail 1.4.1 core
414 'spamassassin', // Not working beyond SquirrelMail 1.2.7: See Spamassassin SpamFilter (Frontend) v2 plugin
415 'sqcalendar', // Added to SquirrelMail 1.2 Core Plugins (calendar)
416 'sqclock', // Integrated into SquirrelMail 1.2 core
417 'sql_squirrel_logger', // Obsolete: See Squirrel Logger plugin
418 'tmda', // Obsolete: See TMDA Tools plugin
419 'vacation', // Obsolete: See Vacation Local plugin
420 'view_as_html', // Integrated into SquirrelMail 1.5.1 core
421 'xmailer' // Integrated into SquirrelMail 1.2 core
422 );
423
424 if (isset($plugins[0])) {
425 foreach($plugins as $plugin) {
426 if(!file_exists(SM_PATH .'plugins/'.$plugin)) {
427 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot find it.', FALSE);
428 } elseif (!is_readable(SM_PATH .'plugins/'.$plugin.'/setup.php')) {
429 do_err('You have enabled the <i>'.$plugin.'</i> plugin, but I cannot read its setup.php file.', FALSE);
430 } elseif (in_array($plugin, $bad_plugins)) {
431 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);
432 }
433 }
434 // load plugin functions
435 include_once(SM_PATH . 'functions/plugin.php');
436 // turn on output buffering in order to prevent output of new lines
437 ob_start();
438 foreach ($plugins as $name) {
439 use_plugin($name);
440 }
441 // get output and remove whitespace
442 $output = trim(ob_get_contents());
443 ob_end_clean();
444 // if plugins output more than newlines and spacing, stop script execution.
445 if (!empty($output)) {
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);
447 do_err($plugin_load_error);
448 }
449 /**
450 * Print plugin versions
451 */
452 echo $IND . "Plugin versions...<br />\n";
453 foreach ($plugins as $name) {
454 $plugin_version = get_plugin_version($name);
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";
457
458 // check if this plugin has any other plugin
459 // dependencies and if they are satisfied
460 //
461 $failed_dependencies = check_plugin_dependencies($name);
462 if ($failed_dependencies === SQ_INCOMPATIBLE) {
463 do_err($name . ' is NOT COMPATIBLE with this version of SquirrelMail', FALSE);
464 }
465 else if (is_array($failed_dependencies)) {
466 $missing_plugins = '';
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') . ')';
469 }
470 do_err($name . ' is missing some dependencies: ' . trim($missing_plugins, ', '), FALSE);
471 }
472
473 }
474 /**
475 * This hook was added in 1.5.2 and 1.4.10. Each plugins should print an error
476 * message and return TRUE if there are any errors in its setup/configuration.
477 */
478 $plugin_err = boolean_hook_function('configtest', $null, 1);
479 if($plugin_err) {
480 do_err('Some plugin tests failed.');
481 } else {
482 echo $IND . "Plugins OK.<br />\n";
483 }
484 } else {
485 echo $IND . "Plugins are not enabled in config.<br />\n";
486 }
487 foreach($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
495 echo $IND . "Themes OK.<br />\n";
496
497 if ( $squirrelmail_default_language != 'en_US' ) {
498 $loc_path = SM_PATH .'locale/'.$squirrelmail_default_language.'/LC_MESSAGES/squirrelmail.mo';
499 if( ! file_exists( $loc_path ) ) {
500 do_err('You have set <i>' . $squirrelmail_default_language .
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);
504 } elseif ( ! is_readable( $loc_path ) ) {
505 do_err('You have set <i>' . $squirrelmail_default_language .
506 '</i> as your default language, but I cannot read this translation (file '.
507 'in <tt>' . $loc_path . '</tt> unreadable).', FALSE);
508 } else {
509 echo $IND . "Default language OK.<br />\n";
510 }
511 } else {
512 echo $IND . "Default language OK.<br />\n";
513 }
514
515 echo $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";
518
519 /* check minimal requirements for other security options */
520
521 /* imaps or ssmtp */
522 if($use_smtp_tls == 1 || $use_imap_tls == 1) {
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 }
530 /* starttls extensions */
531 if($use_smtp_tls === 2 || $use_imap_tls === 2) {
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 */
537 if ($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 */
544
545 echo "Checking outgoing mail service....<br />\n";
546
547 if($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)!");
551 }
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 {
558 $stream = fsockopen( ($use_smtp_tls==1?'tls://':'').$smtpServerAddress, $smtpPort,
559 $errorNumber, $errorString);
560 if(!$stream) {
561 do_err("Error connecting to SMTP server \"$smtpServerAddress:$smtpPort\".".
562 "Server error: ($errorNumber) ".htmlspecialchars($errorString));
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) {
568 do_err("Error connecting to SMTP server. Server error: ".
569 htmlspecialchars($smtpline));
570 }
571
572 /* smtp starttls checks */
573 if ($use_smtp_tls===2) {
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)||
583 preg_match("/^250(-|\s)(\S*)\s+/",$line,$match)) {
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 {
596 //
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
622 fputs($stream, 'QUIT');
623 fclose($stream);
624 echo $IND . 'SMTP server OK (<tt><small>'.
625 trim(htmlspecialchars($smtpline))."</small></tt>)<br />\n";
626
627 /* POP before SMTP */
628 if($pop_before_smtp) {
629 $stream = fsockopen($smtpServerAddress, 110, $err_no, $err_str);
630 if (!$stream) {
631 do_err("Error connecting to POP Server ($smtpServerAddress:110) "
632 . $err_no . ' : ' . htmlspecialchars($err_str));
633 }
634
635 $tmp = fgets($stream, 1024);
636 if (substr($tmp, 0, 3) != '+OK') {
637 do_err("Error connecting to POP Server ($smtpServerAddress:110)"
638 . ' '.htmlspecialchars($tmp));
639 }
640 fputs($stream, 'QUIT');
641 fclose($stream);
642 echo $IND . "POP-before-SMTP OK.<br />\n";
643 }
644 }
645
646 /**
647 * Check the IMAP server
648 */
649 echo "Checking IMAP service....<br />\n";
650
651 /** Can we open a connection? */
652 $stream = fsockopen( ($use_imap_tls==1?'tls://':'').$imapServerAddress, $imapPort,
653 $errorNumber, $errorString);
654 if(!$stream) {
655 do_err("Error connecting to IMAP server \"$imapServerAddress:$imapPort\".".
656 "Server error: ($errorNumber) ".
657 htmlspecialchars($errorString));
658 }
659
660 /** Is the first response 'OK'? */
661 $imapline = fgets($stream, 1024);
662 if(substr($imapline, 0,4) != '* OK') {
663 do_err('Error connecting to IMAP server. Server error: '.
664 htmlspecialchars($imapline));
665 }
666
667 echo $IND . 'IMAP server ready (<tt><small>'.
668 htmlspecialchars(trim($imapline))."</small></tt>)<br />\n";
669
670 /** Check capabilities */
671 fputs($stream, "A001 CAPABILITY\r\n");
672 $capline = '';
673 while ($line=fgets($stream, 1024)){
674 if (preg_match("/A001.*/",$line)) {
675 break;
676 } else {
677 $capline.=$line;
678 }
679 }
680
681 /* don't display capabilities before STARTTLS */
682 if ($use_imap_tls===2 && stristr($capline, 'STARTTLS') === false) {
683 do_err('Your server doesn\'t support STARTTLS.');
684 } elseif($use_imap_tls===2) {
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: '
690 .htmlspecialchars($starttls_line);
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 }
709
710 echo $IND . 'Capabilities: <tt>'.htmlspecialchars($capline)."</tt><br />\n";
711
712 if($imap_auth_mech == 'login' && stristr($capline, 'LOGINDISABLED') !== FALSE) {
713 do_err('Your server doesn\'t allow plaintext logins. '.
714 'Try enabling another authentication mechanism like CRAM-MD5, DIGEST-MD5 or TLS-encryption '.
715 'in the SquirrelMail configuration.', FALSE);
716 }
717
718 if (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
730 /* add warning about IMAP delivery */
731 if (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
739 /** OK, close connection */
740 fputs($stream, "A004 LOGOUT\r\n");
741 fclose($stream);
742
743 echo "Checking internationalization (i18n) settings...<br />\n";
744 echo "$IND gettext - ";
745 if (function_exists('gettext')) {
746 echo 'Gettext functions are available.'
747 .' On some systems you must have appropriate system locales compiled.'
748 ."<br />\n";
749
750 /* optional setlocale() tests. Should work only on glibc systems. */
751 if (sqgetGlobalVar('testlocales',$testlocales,SQ_GET)) {
752 include_once(SM_PATH . 'include/languages.php');
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 */
795 } else {
796 echo 'Gettext functions are unavailable.'
797 .' SquirrelMail will use slower internal gettext functions.'
798 ."<br />\n";
799 }
800 echo "$IND mbstring - ";
801 if (function_exists('mb_detect_encoding')) {
802 echo "Mbstring functions are available.<br />\n";
803 } else {
804 echo 'Mbstring functions are unavailable.'
805 ." Japanese translation won't work.<br />\n";
806 }
807 echo "$IND recode - ";
808 if (function_exists('recode')) {
809 echo "Recode functions are available.<br />\n";
810 } elseif (isset($use_php_recode) && $use_php_recode) {
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 }
816 echo "$IND iconv - ";
817 if (function_exists('iconv')) {
818 echo "Iconv functions are available.<br />\n";
819 } elseif (isset($use_php_iconv) && $use_php_iconv) {
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 }
825 // same test as in include/init.php + date_default_timezone_set check
826 echo "$IND timezone - ";
827 if ( (!ini_get('safe_mode')) || function_exists('date_default_timezone_set') ||
828 !strcmp(ini_get('safe_mode_allowed_env_vars'),'') ||
829 preg_match('/^([\w_]+,)*TZ/', ini_get('safe_mode_allowed_env_vars')) ) {
830 echo "Webmail users can change their time zone settings. \n";
831 } else {
832 echo "Webmail users can't change their time zone settings. \n";
833 }
834 if (isset($_ENV['TZ'])) {
835 echo 'Default time zone is '.htmlspecialchars($_ENV['TZ']);
836 } else {
837 echo 'Current time zone is '.date('T');
838 }
839 echo ".<br />\n";
840
841 // Pear DB tests
842 echo "Checking database functions...<br />\n";
843 if($addrbook_dsn || $prefs_dsn || $addrbook_global_dsn) {
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(
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 );
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) {
875 $aDsn = explode(':', $dsn);
876 $dbtype = array_shift($aDsn);
877
878 if(isset($db_functions[$dbtype]) && function_exists($db_functions[$dbtype])) {
879 echo "$IND$dbtype database support present.<br />\n";
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 }
888
889
890 // now, test this interface:
891
892 $dbh = DB::connect($dsn, true);
893 if (DB::isError($dbh)) {
894 do_err('Database error: '. htmlspecialchars(DB::errorMessage($dbh)) .
895 ' in ' .$type .' DSN.');
896 }
897 $dbh->disconnect();
898 echo "$IND$type database connect successful.<br />\n";
899 }
900 } else {
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>?'
903 .' The include path is now: "<tt>' . ini_get('include_path') . '</tt>".';
904 do_err($db_error);
905 }
906 } else {
907 echo $IND."not using database functionality.<br />\n";
908 }
909
910 // LDAP DB tests
911 echo "Checking LDAP functions...<br />\n";
912 if( empty($ldap_server) ) {
913 echo $IND."not using LDAP functionality.<br />\n";
914 } else {
915 if ( !function_exists('ldap_connect') ) {
916 do_err('Required LDAP support is not available.');
917 } else {
918 echo "$IND LDAP support present.<br />\n";
919 foreach ( $ldap_server as $param ) {
920
921 $linkid = @ldap_connect($param['host'], (empty($param['port']) ? 389 : $param['port']) );
922
923 if ( $linkid ) {
924 echo "$IND LDAP connect to ".$param['host']." successful: ".$linkid."<br />\n";
925
926 if ( !empty($param['protocol']) &&
927 !ldap_set_option($linkid, LDAP_OPT_PROTOCOL_VERSION, $param['protocol']) ) {
928 do_err('Unable to set LDAP protocol');
929 }
930
931 if ( empty($param['binddn']) ) {
932 $bind = @ldap_bind($linkid);
933 } else {
934 $bind = @ldap_bind($param['binddn'], $param['bindpw']);
935 }
936
937 if ( $bind ) {
938 echo "$IND LDAP Bind Successful <br />";
939 } else {
940 do_err('Unable to Bind to LDAP Server');
941 }
942
943 @ldap_close($linkid);
944 } else {
945 do_err('Connection to LDAP failed');
946 }
947 }
948 }
949 }
950
951 echo '<hr width="75%" align="center">';
952 echo '<h2 align="center">Summary</h2>';
953 $footer = '<hr width="75%" align="center">';
954 if ($warnings) {
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;
957 } else {
958 print <<< EOF
959 <p>Congratulations, your SquirrelMail setup looks fine to me!</p>
960
961 <p><a href="login.php">Login now</a></p>
962
963 </body>
964 </html>
965 EOF;
966 echo $footer;
967 }