1<?php
2
3/**
4  * SquirrelMail Compatibility Plugin
5  * Copyright (c) 2004-2009 Paul Lesniewski <paul@squirrelmail.org>
6  * Licensed under the GNU GPL. For full terms see the file COPYING.
7  *
8  * SquirrelMail developers, see below under "SQUIRRELMAIL DEVELOPER
9  * NOTES" for information about how the include files are maintained
10  *
11  * @package plugins
12  * @subpackage compatibility
13  *
14  */
15
16
17
18   // change this to TRUE to disable plugin config test functionality
19   // which will increase performance (minimally)
20   //
21   $disable_config_check = FALSE;
22
23
24   // ---------------------------------------
25
26
27   global $compatibility_sm_path, $compatibility_disable_config_check;
28   $compatibility_disable_config_check = $disable_config_check;
29
30
31   // we don't want to do any defining constants ourselves to stay
32   // as non-intrusive as possible, so just our own variable
33   //
34   if (defined('SM_PATH'))
35      $compatibility_sm_path = SM_PATH;
36   else
37      $compatibility_sm_path = '../';
38
39
40   // Some uses of this plugin (such as vlogin) were somehow calling the
41   // functions here before having included the functions in global.php,
42   // resulting in fatal errors when called below.  Thus, the need for
43   // the following includes
44   //
45
46   // we also need to include the validate file first
47   // thing so we don't lose the ability to display themes,
48   // but we cannot include this file unless we are being
49   // called from a plugin request, thus this if statement
50   //
51/*
52   if ( strpos(getcwd(), 'plugins') )
53   {
54      if (file_exists($compatibility_sm_path . 'include/validate.php'))
55         include_once($compatibility_sm_path . 'include/validate.php');
56      else if (file_exists($compatibility_sm_path . 'src/validate.php'))
57         include_once($compatibility_sm_path . 'src/validate.php');
58   }
59
60
61   include_once($compatibility_sm_path . 'functions/strings.php');
62
63
64   if (file_exists($compatibility_sm_path . 'functions/global.php'))
65      include_once($compatibility_sm_path . 'functions/global.php');
66   else if (file_exists($compatibility_sm_path . 'src/global.php'))
67      include_once($compatibility_sm_path . 'src/global.php');
68*/
69
70
71
72   // legacy support for previous versions of compatibility plugin
73   //
74//see below
75//   function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0')
76//   { return check_sm_version($a, $b, $c); }
77   function compatibility_check_php_version ($a = '0', $b = '0', $c = '0')
78   { return check_php_version($a, $b, $c); }
79   function compatibility_sqsession_register ($var, $name)
80   { sqsession_register ($var, $name); }
81   function compatibility_sqsession_unregister ($name)
82   { sqsession_unregister($name); }
83   function compatibility_sqsession_is_active()
84   { sqsession_is_active(); }
85   function compatibility_sqsession_is_registered ($name)
86   { return sqsession_is_registered($name); }
87   function compatibility_sqextractGlobalVar ($name)
88   { global $$name; sqgetGlobalVar($name, $$name); }
89
90
91
92   // now include everything that current SM version is missing
93   //
94   load_legacy_support();
95
96
97
98
99   /**
100     * Checks SquirrelMail version, returns TRUE if SquirrelMail
101     * version is at least a.b.c.
102     *
103     * @param $a int Major version number
104     * @param $b int Minor version number
105     * @param $c int Revision number
106     *
107     * @return boolean TRUE if SquirrelMail version matches at
108     *                 least a.b.c, FALSE otherwise.
109     *
110     */
111   function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0')
112   {
113      if (function_exists('check_sm_version'))
114         return check_sm_version($a, $b, $c);
115
116      if (defined('SM_VERSION'))
117         $version = SM_VERSION;
118      else
119         global $version;
120
121      list($aa, $bb, $cc) = preg_split('/\./', $version, 3);
122      $cc = intval($cc);
123
124      if(!is_numeric($cc))
125         list($cc, $info) = explode(' ', $cc, 2);
126
127      return ($aa > $a)
128          || (($aa == $a) && ($bb > $b))
129          || (($aa == $a) && ($bb == $b) && ($cc >= $c));
130   }
131
132
133
134   /**
135     * Includes needed files with updated API for legacy
136     * SquirrelMail installations
137     *
138     */
139   function load_legacy_support()
140   {
141
142      global $compatibility_sm_path;
143
144      // SQUIRRELMAIL DEVELOPER NOTES
145      //
146      // The array below should be updated with every release of
147      // SquirrelMail, along with adding needed directories in the
148      // includes for this plugin.
149      //
150      // Code that was added as of a certain version should be put
151      // in the include file in the directory corresponding to that
152      // same version number in order to make it available to older
153      // versions.  When including files here, that file will be
154      // included for all versions prior.
155      //
156      // If some code was added to the newest codebase for two different
157      // release series, for example, a function called "sq_new_function()"
158      // that was added in both 1.4.10 as well as 1.5.2, please add
159      // the function to only the higher version (1.5.2 in this case),
160      // and add additional logic to the way it is included:
161      //
162      //    if ((!compatibility_check_sm_version(1, 4, 10)
163      //      || (compatibility_check_sm_version(1, 5, 0)
164      //     && !compatibility_check_sm_version(1, 5, 2)))
165      //     && !function_exists('sq_new_function'))
166      //    {
167      //    function sq_new_function()
168      //    {
169      //       echo "HELLO WORLD";
170      //    }
171      //    }
172      //
173      // NOTE: In-between version includes should simply be put in the
174      //       lowest version include file for the new release series
175      //       (e.g., anything in the 1.5.0 include file will be loaded
176      //       for all 1.4.x versions, and of course, not for 1.5.0).
177      //       The following in-between include file system is thus not
178      //       needed, but leaving code and documentation about how it
179      //       works just for edification:
180      //
181      // In-between include directories should be named as such:
182      // "1.4.x-to-1.5.0" where the latter version string must
183      // correspond to a real SquirrelMail version and the versions
184      // must be separated by the string "-to-"
185      //
186      // Order in this array is significant, please keep newest releases
187      // at top of this list, ordered downward from there...
188      //
189      // These have to be hard-coded since there is no way to know if this
190      // plugin is being used in series 1.2.x, 1.3.x, 1.4.x, 1.5.x, etc.
191      //
192      $compatibility_versions = array(
193         '1.5.2', '1.5.1', '1.5.0',
194         // in-between includes not needed:
195         //'1.4.x-to-1.5.0',
196         '1.4.20', '1.4.19', '1.4.18', '1.4.17', '1.4.16', '1.4.15', '1.4.14',
197         '1.4.13', '1.4.12', '1.4.11', '1.4.10', '1.4.9', '1.4.8', '1.4.7',
198         '1.4.6', '1.4.5', '1.4.4', '1.4.3', '1.4.2', '1.4.1', '1.4.0',
199         // skipping 1.3.x, not supported for now
200         // in-between includes not needed:
201         //'1.2.x-to-1.4.0',
202         '1.2.11', '1.2.10', '1.2.9', '1.2.8', '1.2.7',
203         // if you are running anything older than this, I feel really, really sorry for you
204                                     );
205
206
207      // loop through all versions in our list, including files
208      // for all versions newer than the one being run here and now
209      //
210      $last_csv_version_string = '';
211      $last_version_string = '';
212      for ($count = 0; !empty($compatibility_versions[$count]); $count++)
213      {
214
215         $version_string = $compatibility_versions[$count];
216
217
218/* ----- see above; in-between includes not needed...
219         // in-between version files: set version string to the higher
220         // version so that all versions in the release series below
221         // it will see it
222         //
223         if (($pos = strpos($version_string, '-to-')) !== FALSE)
224            $csv_version_string = str_replace('.', ', ', substr($version_string, $pos + 4));
225
226
227         // normal conversion to CSV values
228         //
229         else
230----- */
231            // note that we could split $version_string by '.' instead and not use eval below
232            $csv_version_string = str_replace('.', ', ', $version_string);
233
234
235         if ($count == 0)
236         {
237            if (eval('if (compatibility_check_sm_version(' . $csv_version_string . ')) return TRUE; else return FALSE;'))
238               return;
239            $last_csv_version_string = $csv_version_string;
240            $last_version_string = $version_string;
241            continue;
242         }
243
244
245         if (eval('if (file_exists($compatibility_sm_path . \'plugins/compatibility/includes/'
246              . $last_version_string . '/global.php\')) include_once($compatibility_sm_path . \'plugins/compatibility/includes/'
247              . $last_version_string . '/global.php\'); if (compatibility_check_sm_version('
248              . $csv_version_string . ')) return TRUE;'))
249            return;
250
251         $last_csv_version_string = $csv_version_string;
252         $last_version_string = $version_string;
253
254      }
255
256   }
257
258
259
260/**
261  * Allows a plugin to push itself (or another plugin) to the top
262  * or bottom of the plugin order for a certain hook.  It also
263  * allows for positioning immediately before or after another
264  * plugin.
265  *
266  * NOTE that this function will only be useful when called from
267  * certain points in the code context, such as from a very early
268  * hook like 'config_override' (which has been changed to
269  * 'prefs_backend'), and may not work reliably for reordering
270  * hooks that are already in execution.
271  *
272  * @param string  $plugin_name     The name of the plugin to reposition.
273  * @param string  $hook_name       The name of the hook wherein the
274  *                                 repositioning happens.
275  * @param boolean $before          If the repositioning should be at the
276  *                                 top of the plugin list (or before the
277  *                                 $relative_plugin plugin).  When FALSE,
278  *                                 repositioning goes to the bottom of
279  *                                 the plugin list or after $relative_plugin
280  *                                 (OPTIONAL; default is TRUE).
281  * @param string  $relative_plugin The name of a plugin that the repositioning
282  *                                 should be relative to.  If not given,
283  *                                 the target plugin is just moved to the
284  *                                 extreme front or back of the whole plugin
285  *                                 list (OPTIONAL; default not used).
286  *
287  * @return boolean TRUE when repositioning succeeds, FALSE otherwise
288  *                 (for instance, it might fail if the target plugin
289  *                 is not already registered on the target hook, or
290  *                 $relative_plugin is not also found on the target hook).
291  *
292  */
293function reposition_plugin_on_hook($plugin_name, $hook_name, $before=TRUE,
294                                   $relative_plugin='')
295{
296
297   global $squirrelmail_plugin_hooks, $plugins;
298
299
300   // make sure plugin is already registered on the target hook
301   //
302   if (is_array($squirrelmail_plugin_hooks[$hook_name])
303    && !empty($squirrelmail_plugin_hooks[$hook_name][$plugin_name]))
304   {
305
306      // move relative to another plugin?
307      //
308      $relative_plugin_function = FALSE;
309      if (!empty($relative_plugin))
310      {
311         if (empty($squirrelmail_plugin_hooks[$hook_name][$relative_plugin]))
312            return FALSE;
313
314         $relative_plugin_function = $squirrelmail_plugin_hooks[$hook_name][$relative_plugin];
315      }
316
317
318      // grab target plugin's function callback for this hook
319      //
320      $plugin_function = $squirrelmail_plugin_hooks[$hook_name][$plugin_name];
321
322
323      // reordering an associative array can only be done
324      // by rebuilding by hand as far as I know
325      //
326      $new_hook_array = array();
327      if ($before && !$relative_plugin_function)
328         $new_hook_array[$plugin_name] = $plugin_function;
329      foreach ($squirrelmail_plugin_hooks[$hook_name] as $plugin => $function)
330      {
331
332         if ($plugin == $plugin_name)
333            continue;
334
335         // move relative to another plugin?
336         //
337         if ($plugin == $relative_plugin && !empty($relative_plugin))
338         {
339            if ($before)
340            {
341               $new_hook_array[$plugin_name] = $plugin_function;
342               $new_hook_array[$relative_plugin] = $relative_plugin_function;
343            }
344            else
345            {
346               $new_hook_array[$relative_plugin] = $relative_plugin_function;
347               $new_hook_array[$plugin_name] = $plugin_function;
348            }
349            continue;
350         }
351
352         $new_hook_array[$plugin] = $function;
353
354      }
355      if (!$before && !$relative_plugin_function)
356         $new_hook_array[$plugin_name] = $plugin_function;
357
358
359
360      // now replace the plugins for the target hook
361      //
362      $squirrelmail_plugin_hooks[$hook_name] = $new_hook_array;
363
364      return TRUE;
365
366   }
367
368
369   // plugin not found on target hook
370   //
371   return FALSE;
372
373}
374
375
376
377/**
378  * Dynamically enables a plugin to the SquirrelMail environment.
379  *
380  * @param string  $plugin_name  The name of the plugin to add.
381  * @param mixed   $args         The current plugin function argument,
382  *                              which must be exactly as received by
383  *                              the plugin function that is calling
384  *                              this code (OPTIONAL; default empty).
385  * @param boolean $dont_execute When adding plugins that are registered
386  *                              on the same hook that is currently being
387  *                              executed, the registered function for
388  *                              the new plugins will be manually run,
389  *                              however, setting this flag to TRUE will
390  *                              prevent that from happening (plugins
391  *                              will be registered, but never executed)
392  *                              (OPTIONAL; default is FALSE).
393  *
394  */
395function add_plugin($plugin_name, $args='', $dont_execute=FALSE)
396{
397
398   global $squirrelmail_plugin_hooks, $plugins;
399
400   // changing the hook function array whilst in the
401   // middle of iterating thru it for the same hook
402   // doesn't always work, so we'll see if the hook
403   // currently being executed has had its function
404   // list changed; if so, we will execute the added
405   // hook functions ourselves
406   //
407   $hook_name = get_current_hook_name($args);
408
409
410   // used below for determining if any plugins
411   // were added to currently running hook
412   //
413   if (!empty($hook_name)
414    && !empty($squirrelmail_plugin_hooks[$hook_name])
415    && is_array($squirrelmail_plugin_hooks[$hook_name]))
416      $original_hook_functions = $squirrelmail_plugin_hooks[$hook_name];
417   else
418      $original_hook_functions = array();
419
420
421   // add plugin to global plugin array
422   //
423   $plugins[] = $plugin_name;
424
425
426   // enable plugin -- emulate code from use_plugin() function
427   // in SquirrelMail core, because in 1.5.2, it no longer
428   // called "squirrelmail_plugin_init_<plugin_name>", which
429   // NEEDS to be called here.
430   //
431   if (file_exists(SM_PATH . "plugins/$plugin_name/setup.php"))
432   {
433
434      include_once(SM_PATH . "plugins/$plugin_name/setup.php");
435
436      $function = "squirrelmail_plugin_init_$plugin_name";
437      if (function_exists($function))
438         $function();
439
440   }
441
442
443   // now get any new plugins for the current hook
444   // and run their hooks
445   //
446   if (!$dont_execute && !empty($hook_name))
447   {
448
449      if (!empty($squirrelmail_plugin_hooks[$hook_name])
450       && is_array($squirrelmail_plugin_hooks[$hook_name]))
451         $new_hook_functions = array_diff($squirrelmail_plugin_hooks[$hook_name],
452                                          $original_hook_functions);
453      else
454         $new_hook_functions = array();
455
456      foreach ($new_hook_functions as $function)
457         if (function_exists($function))
458//FIXME: is $args always how plugins are called, even in 1.4.x?
459            $function($args);
460
461   }
462
463}
464
465
466
467/**
468  * Dynamically disables a plugin from the SquirrelMail environment.
469  *
470  * @param string $plugin_name The name of the plugin to remove.
471  *
472  */
473function remove_plugin($plugin_name)
474{
475
476   global $squirrelmail_plugin_hooks, $plugins;
477
478   $plugin_key = array_search($plugin_name, $plugins);
479   if (!is_null($plugin_key) && $plugin_key !== FALSE)
480   {
481      unset($plugins[$plugin_key]);
482      if (is_array($squirrelmail_plugin_hooks))
483         foreach (array_keys($squirrelmail_plugin_hooks) as $hookName)
484         {
485            unset($squirrelmail_plugin_hooks[$hookName][$plugin_name]);
486         }
487   }
488
489}
490
491
492
493/**
494  * Determines what plugin hook is currently executing,
495  * if any, in a SquirrelMail version-independent fashion.
496  *
497  * @param mixed $args The current plugin function argument,
498  *                    which must be exactly as received by
499  *                    the plugin function that is calling
500  *                    this code.
501  *
502  * @return string The name of the currently executing plugin
503  *                hook, or an empty string if either no hook
504  *                is running or the hook name could not be
505  *                determined.
506  *
507  */
508function get_current_hook_name($args='')
509{
510
511   if (check_sm_version(1, 5, 1))
512   {
513      global $currentHookName;
514      if (!empty($currentHookName))
515         return $currentHookName;
516   }
517
518
519//TODO: should we ALWAYS backtrace instead of assuming that $args[0] is the hook name?
520   if (!empty($args[0]) && is_string($args[0]))
521      return $args[0];
522   else
523   {
524
525      // plugin args not given or didn't have a hook
526      // name in them, so try backtracing instead
527      //
528      $backtrace = debug_backtrace();
529      foreach ($backtrace as $trace)
530         if ($trace['function'] == 'do_hook'
531          || $trace['function'] == 'do_hook_function'
532          || $trace['function'] == 'concat_hook_function'
533          || $trace['function'] == 'boolean_hook_function')
534            return $trace['args'][0];
535
536      // nothing found at all
537      //
538      return '';
539
540   }
541
542}
543
544
545
546/**
547  * Load configuration file
548  *
549  * Convenience function for plugins that loads a configuration
550  * file (or files).  If the file(s) is(are) not found, an error
551  * is displayed and execution stops (function won't return).
552  * If multiple configuration files are given, ALL of them are
553  * included (unless $load_only_one is TRUE), if they exist, in
554  * the order given.  Only one of them needs to be found to avert
555  * triggering an error.
556  *
557  * Note that configuration files are loaded in the order given,
558  * so the caller should place the file that should have the
559  * final overrides as the LAST in the given list, unless using
560  * $load_only_one, in which case the most important configuration
561  * file should probably come first.
562  *
563  * Non-functional on login_before hook.
564TODO - re-verify that the above is true
565  *
566  * @param string $plugin_name    The name of the plugin as
567  *                               it is known to SquirrelMail,
568  *                               that is, it is the name
569  *                               of the plugin directory
570  * @param mixed $config_files    An array of files that will
571  *                               be included IN THE ORDER that
572  *                               they are given in the
573  *                               array.  Can also be given as
574  *                               a string if only one config
575  *                               file is being loaded.  Files
576  *                               should be specified relative
577  *                               to the calling plugin's
578  *                               directory, such as:
579  *                                 'config.php'
580  *                               or:
581  *                                 '../../config/my_plugin_config.php'
582  *                               or:
583  *                                 array('data/config.php', 'data/admins.php')
584  *                               It is also possible to give a
585  *                               full/direct path to a
586  *                               configuration file by placing
587  *                               a forward slash at the
588  *                               beginning of the file:
589  *                               array('/var/lib/squirrelmail/config/myplugin.conf')
590  * @param boolean $return_errors When TRUE, any errors encountered
591  *                               will cause this function to return
592  *                               FALSE; otherwise, errors are
593  *                               handled herein by showing an error
594  *                               to the user and exiting (OPTIONAL;
595  *                               default is FALSE).
596  * @param boolean $load_only_one When TRUE, this function will stop
597  *                               after it has successfully loaded
598  *                               one configuration file, starting
599  *                               with the first one given for
600  *                               $config_files.  When FALSE, all
601  *                               configuration files will be loaded
602  *                               such that the last one can override
603  *                               all others ("cascading") (OPTIONAL;
604  *                               default is FALSE).
605  *
606  * @return mixed If no errors are found, TRUE is returned; if an error
607  *               was found and $return_errors is TRUE, FALSE is returned.
608  *               If $return_errors is FALSE and an error is found, this
609  *               function will never return.
610  *
611  */
612function load_config($plugin_name, $config_files,
613                     $return_errors=FALSE, $load_only_one=FALSE)
614{
615
616   global $compatibility_sm_path;
617
618
619   // if only one config file given as string
620   //
621   if (!is_array($config_files)) $config_files = array($config_files);
622
623
624   // loop through files, attempting to include them
625   //
626   $file_count = 1;
627   foreach ($config_files as $file)
628   {
629
630      if (strpos($file, '/') === 0)
631         $plugin_path = $file;
632      else
633         $plugin_path = $compatibility_sm_path . 'plugins/' . $plugin_name . '/' . $file;
634
635      // store inclusion results to be checked below
636      //
637      ${'config' . $file_count} = @include_once($plugin_path);
638
639      // if we only need one configuration file, stop
640      // here if we successfully loaded this config file
641      //
642      if ($load_only_one && ${'config' . $file_count})
643         return TRUE;
644
645      $file_count++;
646
647   }
648
649
650   // now check to see if we got at least one successful inclusion
651   //
652   $success = FALSE;
653   for ($i = 1; $i < $file_count; $i++)
654      if (${'config' . $i})
655      {
656         $success = TRUE;
657         break;
658      }
659
660
661   // error...
662   //
663   if (!$success)
664   {
665
666      if ($return_errors) return FALSE;
667
668// TODO: when used in configtest hook (and others??), this function (sq_change_text_domain()) is not known yet... but usually $return_errors should be turned on for that hook
669      sq_change_text_domain('compatibility');
670      $error_msg = _("Administrative error:") . '<br />'
671                 . sprintf(_("The plugin %s has not been set up correctly."),
672                           '&quot;<strong>' . $plugin_name . '</strong>&quot;')
673                 . '<br />'
674                 . _("Please read the README or INSTALL files that came with the plugin.");
675      sq_change_text_domain('squirrelmail');
676      include_once($compatibility_sm_path . 'functions/display_messages.php');
677      global $color;
678      plain_error_message($error_msg, $color);
679      exit;
680   }
681
682   return TRUE;
683
684}
685
686
687
688/**
689  * Validate Plugin Setup Utility
690  *
691  * Checks a plugin to see if the user has installed it
692  * correctly by checking for the existence of the given
693  * files (all relative from the plugin's directory)
694  *
695  * @param string $pluginName The name of the plugin as
696  *                           it is known to SquirrelMail,
697  *                           that is, it is the name
698  *                           of the plugin directory.
699  * @param array $configFiles An array of any files that the
700  *                           user should have set up for
701  *                           this plugin, for example:
702  *                             array('config.php')
703  *                           or:
704  *                             array('data/config.php', 'data/admins.php')
705  *                           where all files will be
706  *                           referenced from the plugin's
707  *                           main directory.
708  *                           It is also possible to give a
709  *                           full/direct path to a
710  *                           configuration file by placing
711  *                           a forward slash at the
712  *                           beginning of the file:
713  *                             array('/var/lib/squirrelmail/config/myplugin.conf')
714  * @param boolean $return_errors When true, any errors encountered
715  *                               will cause this function to return
716  *                               either FALSE or a string describing
717  *                               the error; otherwise, errors are
718  *                               handled herein by showing an error
719  *                               to the user and exiting (OPTIONAL;
720  *                               default is FALSE).
721  *
722  * @return mixed If no errors are found, TRUE is returned; if an error
723  *               was found and $return_errors is TRUE, either FALSE or
724  *               a string describing the error is returned.  If $return_errors
725  *               is FALSE and an error is found, this function will never
726  *               return.
727  *
728  */
729function check_plugin_setup($pluginName, $configFiles, $return_errors=FALSE)
730{
731
732   global $compatibility_disable_config_check;
733   if ($compatibility_disable_config_check) return;
734
735
736   global $compatibility_sm_path;
737
738
739   // check one at a time...
740   //
741   foreach ($configFiles as $configFile)
742   {
743
744      if (strpos($configFile, '/') === 0)
745         $plugin_path = $configFile;
746      else
747         $plugin_path = $compatibility_sm_path . 'plugins/' . $pluginName . '/' . $configFile;
748
749      if (!file_exists($plugin_path))
750      {
751
752         //if ($return_errors) return FALSE;
753
754         sq_change_text_domain('compatibility');
755
756         if ($return_errors)
757         {
758            $error_msg = sprintf(_("The file %s is missing from plugin %s."),
759                                 '&quot;<strong>' . $configFile . '</strong>&quot;',
760                                 '&quot;<strong>' . $pluginName . '</strong>&quot;');
761            sq_change_text_domain('squirrelmail');
762            return $error_msg;
763         }
764
765         $error_msg = _("Administrative error:") . '<br />'
766                    . sprintf(_("The plugin %s has not been set up correctly."),
767                              '&quot;<strong>' . $pluginName . '</strong>&quot;')
768                    . '<br />'
769                    . sprintf(_("The file %s is missing."),
770                              '&quot;<strong>' . $configFile . '</strong>&quot;')
771                    . '<br />'
772                    . _("Please read the README or INSTALL files that came with the plugin.");
773         sq_change_text_domain('squirrelmail');
774         include_once($compatibility_sm_path . 'functions/display_messages.php');
775         global $color;
776         plain_error_message($error_msg, $color);
777         exit;
778
779      }
780
781   }
782
783   return TRUE;
784
785}
786
787
788
789/**
790  * Test if a given file contains a given string.
791  *
792  * This can be used, for example, by plugins during the configtest hook
793  * that want to verify if a certain patch to the SquirrelMail core has
794  * been applied or not.
795  *
796  * The string is searched for using a regular expression to allow for
797  * more complex searches than direct string comparision.  The $string
798  * parameter may contain regular expression syntax if desired.
799  *
800  * @param string  $file   The file to search (usually a full path).
801  * @param string  $string The string to search for (can include regular
802  *                        expression syntax if desired - any special
803  *                        regular expression meta characters need to
804  *                        be escaped unless they are being used as such).
805  * @param boolean $quiet  When TRUE and $file cannot be found or opened,
806  *                        this function returns FALSE, otherwise it
807  *                        will complain and exit (never return) (OPTIONAL;
808  *                        default is FALSE).
809  *
810  * @return boolean TRUE when $string was found or FALSE when it was not.
811  *                 When $quiet is TRUE, FALSE is also returned if the
812  *                 target file could not be located, opened or read.
813  *
814  */
815function check_file_contents($file, $string, $quiet=FALSE)
816{
817
818   if (check_php_version(4, 3, 0))
819   {
820      $contents = file_get_contents($file);
821      if (!$contents)
822         if ($quiet) return FALSE;
823         else
824         {
825            echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!';
826            exit;
827         }
828   }
829   else
830   {
831      $temp_contents = file($file);
832      if (!$temp_contents || !is_array($temp_contents))
833         if ($quiet) return FALSE;
834         else
835         {
836            echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!';
837            exit;
838         }
839      $contents = '';
840      foreach ($temp_contents as $line)
841         $contents .= $line;
842   }
843
844
845   return preg_match('/' . $string . '/', $contents);
846
847}
848
849
850
851/**
852  * Returns the difference in times.  Some small
853  * amount of precision might be lost in the +
854  * operations, but nothing serious.
855  *
856  * This is only a convenience function for plugin
857  * authors fine tuning performance and may not
858  * work on some operating systems.
859  *
860  * @param string $start The microtime() results for
861  *                      the start point.
862  * @param string $end   The microtime() results for
863  *                      the end point (OPTIONAL;
864  *                      if empty defaults to the
865  *                      time NOW).
866  *
867  * @return float The difference between start and
868  *               end points.
869  *
870  */
871function sm_microtime_diff($start, $end=0)
872{
873
874   if (empty($end)) $end = microtime();
875
876   return (substr($end, 11) - substr($start, 11))
877        + (substr($end, 0, 9) - substr($start, 0, 9));
878
879}
880
881
882
883