compatibility/0000755000000000000000000000000011307010230012410 5ustar rootrootcompatibility/functions.php0000644000000000000000000007362311307006647015165 0ustar rootroot * Licensed under the GNU GPL. For full terms see the file COPYING. * * SquirrelMail developers, see below under "SQUIRRELMAIL DEVELOPER * NOTES" for information about how the include files are maintained * * @package plugins * @subpackage compatibility * */ // change this to TRUE to disable plugin config test functionality // which will increase performance (minimally) // $disable_config_check = FALSE; // --------------------------------------- global $compatibility_sm_path, $compatibility_disable_config_check; $compatibility_disable_config_check = $disable_config_check; // we don't want to do any defining constants ourselves to stay // as non-intrusive as possible, so just our own variable // if (defined('SM_PATH')) $compatibility_sm_path = SM_PATH; else $compatibility_sm_path = '../'; // Some uses of this plugin (such as vlogin) were somehow calling the // functions here before having included the functions in global.php, // resulting in fatal errors when called below. Thus, the need for // the following includes // // we also need to include the validate file first // thing so we don't lose the ability to display themes, // but we cannot include this file unless we are being // called from a plugin request, thus this if statement // /* if ( strpos(getcwd(), 'plugins') ) { if (file_exists($compatibility_sm_path . 'include/validate.php')) include_once($compatibility_sm_path . 'include/validate.php'); else if (file_exists($compatibility_sm_path . 'src/validate.php')) include_once($compatibility_sm_path . 'src/validate.php'); } include_once($compatibility_sm_path . 'functions/strings.php'); if (file_exists($compatibility_sm_path . 'functions/global.php')) include_once($compatibility_sm_path . 'functions/global.php'); else if (file_exists($compatibility_sm_path . 'src/global.php')) include_once($compatibility_sm_path . 'src/global.php'); */ // legacy support for previous versions of compatibility plugin // //see below // function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0') // { return check_sm_version($a, $b, $c); } function compatibility_check_php_version ($a = '0', $b = '0', $c = '0') { return check_php_version($a, $b, $c); } function compatibility_sqsession_register ($var, $name) { sqsession_register ($var, $name); } function compatibility_sqsession_unregister ($name) { sqsession_unregister($name); } function compatibility_sqsession_is_active() { sqsession_is_active(); } function compatibility_sqsession_is_registered ($name) { return sqsession_is_registered($name); } function compatibility_sqextractGlobalVar ($name) { global $$name; sqgetGlobalVar($name, $$name); } // now include everything that current SM version is missing // load_legacy_support(); /** * Checks SquirrelMail version, returns TRUE if SquirrelMail * version is at least a.b.c. * * @param $a int Major version number * @param $b int Minor version number * @param $c int Revision number * * @return boolean TRUE if SquirrelMail version matches at * least a.b.c, FALSE otherwise. * */ function compatibility_check_sm_version ($a = '0', $b = '0', $c = '0') { if (function_exists('check_sm_version')) return check_sm_version($a, $b, $c); if (defined('SM_VERSION')) $version = SM_VERSION; else global $version; list($aa, $bb, $cc) = preg_split('/\./', $version, 3); $cc = intval($cc); if(!is_numeric($cc)) list($cc, $info) = explode(' ', $cc, 2); return ($aa > $a) || (($aa == $a) && ($bb > $b)) || (($aa == $a) && ($bb == $b) && ($cc >= $c)); } /** * Includes needed files with updated API for legacy * SquirrelMail installations * */ function load_legacy_support() { global $compatibility_sm_path; // SQUIRRELMAIL DEVELOPER NOTES // // The array below should be updated with every release of // SquirrelMail, along with adding needed directories in the // includes for this plugin. // // Code that was added as of a certain version should be put // in the include file in the directory corresponding to that // same version number in order to make it available to older // versions. When including files here, that file will be // included for all versions prior. // // If some code was added to the newest codebase for two different // release series, for example, a function called "sq_new_function()" // that was added in both 1.4.10 as well as 1.5.2, please add // the function to only the higher version (1.5.2 in this case), // and add additional logic to the way it is included: // // if ((!compatibility_check_sm_version(1, 4, 10) // || (compatibility_check_sm_version(1, 5, 0) // && !compatibility_check_sm_version(1, 5, 2))) // && !function_exists('sq_new_function')) // { // function sq_new_function() // { // echo "HELLO WORLD"; // } // } // // NOTE: In-between version includes should simply be put in the // lowest version include file for the new release series // (e.g., anything in the 1.5.0 include file will be loaded // for all 1.4.x versions, and of course, not for 1.5.0). // The following in-between include file system is thus not // needed, but leaving code and documentation about how it // works just for edification: // // In-between include directories should be named as such: // "1.4.x-to-1.5.0" where the latter version string must // correspond to a real SquirrelMail version and the versions // must be separated by the string "-to-" // // Order in this array is significant, please keep newest releases // at top of this list, ordered downward from there... // // These have to be hard-coded since there is no way to know if this // plugin is being used in series 1.2.x, 1.3.x, 1.4.x, 1.5.x, etc. // $compatibility_versions = array( '1.5.2', '1.5.1', '1.5.0', // in-between includes not needed: //'1.4.x-to-1.5.0', '1.4.20', '1.4.19', '1.4.18', '1.4.17', '1.4.16', '1.4.15', '1.4.14', '1.4.13', '1.4.12', '1.4.11', '1.4.10', '1.4.9', '1.4.8', '1.4.7', '1.4.6', '1.4.5', '1.4.4', '1.4.3', '1.4.2', '1.4.1', '1.4.0', // skipping 1.3.x, not supported for now // in-between includes not needed: //'1.2.x-to-1.4.0', '1.2.11', '1.2.10', '1.2.9', '1.2.8', '1.2.7', // if you are running anything older than this, I feel really, really sorry for you ); // loop through all versions in our list, including files // for all versions newer than the one being run here and now // $last_csv_version_string = ''; $last_version_string = ''; for ($count = 0; !empty($compatibility_versions[$count]); $count++) { $version_string = $compatibility_versions[$count]; /* ----- see above; in-between includes not needed... // in-between version files: set version string to the higher // version so that all versions in the release series below // it will see it // if (($pos = strpos($version_string, '-to-')) !== FALSE) $csv_version_string = str_replace('.', ', ', substr($version_string, $pos + 4)); // normal conversion to CSV values // else ----- */ // note that we could split $version_string by '.' instead and not use eval below $csv_version_string = str_replace('.', ', ', $version_string); if ($count == 0) { if (eval('if (compatibility_check_sm_version(' . $csv_version_string . ')) return TRUE; else return FALSE;')) return; $last_csv_version_string = $csv_version_string; $last_version_string = $version_string; continue; } if (eval('if (file_exists($compatibility_sm_path . \'plugins/compatibility/includes/' . $last_version_string . '/global.php\')) include_once($compatibility_sm_path . \'plugins/compatibility/includes/' . $last_version_string . '/global.php\'); if (compatibility_check_sm_version(' . $csv_version_string . ')) return TRUE;')) return; $last_csv_version_string = $csv_version_string; $last_version_string = $version_string; } } /** * Allows a plugin to push itself (or another plugin) to the top * or bottom of the plugin order for a certain hook. It also * allows for positioning immediately before or after another * plugin. * * NOTE that this function will only be useful when called from * certain points in the code context, such as from a very early * hook like 'config_override' (which has been changed to * 'prefs_backend'), and may not work reliably for reordering * hooks that are already in execution. * * @param string $plugin_name The name of the plugin to reposition. * @param string $hook_name The name of the hook wherein the * repositioning happens. * @param boolean $before If the repositioning should be at the * top of the plugin list (or before the * $relative_plugin plugin). When FALSE, * repositioning goes to the bottom of * the plugin list or after $relative_plugin * (OPTIONAL; default is TRUE). * @param string $relative_plugin The name of a plugin that the repositioning * should be relative to. If not given, * the target plugin is just moved to the * extreme front or back of the whole plugin * list (OPTIONAL; default not used). * * @return boolean TRUE when repositioning succeeds, FALSE otherwise * (for instance, it might fail if the target plugin * is not already registered on the target hook, or * $relative_plugin is not also found on the target hook). * */ function reposition_plugin_on_hook($plugin_name, $hook_name, $before=TRUE, $relative_plugin='') { global $squirrelmail_plugin_hooks, $plugins; // make sure plugin is already registered on the target hook // if (is_array($squirrelmail_plugin_hooks[$hook_name]) && !empty($squirrelmail_plugin_hooks[$hook_name][$plugin_name])) { // move relative to another plugin? // $relative_plugin_function = FALSE; if (!empty($relative_plugin)) { if (empty($squirrelmail_plugin_hooks[$hook_name][$relative_plugin])) return FALSE; $relative_plugin_function = $squirrelmail_plugin_hooks[$hook_name][$relative_plugin]; } // grab target plugin's function callback for this hook // $plugin_function = $squirrelmail_plugin_hooks[$hook_name][$plugin_name]; // reordering an associative array can only be done // by rebuilding by hand as far as I know // $new_hook_array = array(); if ($before && !$relative_plugin_function) $new_hook_array[$plugin_name] = $plugin_function; foreach ($squirrelmail_plugin_hooks[$hook_name] as $plugin => $function) { if ($plugin == $plugin_name) continue; // move relative to another plugin? // if ($plugin == $relative_plugin && !empty($relative_plugin)) { if ($before) { $new_hook_array[$plugin_name] = $plugin_function; $new_hook_array[$relative_plugin] = $relative_plugin_function; } else { $new_hook_array[$relative_plugin] = $relative_plugin_function; $new_hook_array[$plugin_name] = $plugin_function; } continue; } $new_hook_array[$plugin] = $function; } if (!$before && !$relative_plugin_function) $new_hook_array[$plugin_name] = $plugin_function; // now replace the plugins for the target hook // $squirrelmail_plugin_hooks[$hook_name] = $new_hook_array; return TRUE; } // plugin not found on target hook // return FALSE; } /** * Dynamically enables a plugin to the SquirrelMail environment. * * @param string $plugin_name The name of the plugin to add. * @param mixed $args The current plugin function argument, * which must be exactly as received by * the plugin function that is calling * this code (OPTIONAL; default empty). * @param boolean $dont_execute When adding plugins that are registered * on the same hook that is currently being * executed, the registered function for * the new plugins will be manually run, * however, setting this flag to TRUE will * prevent that from happening (plugins * will be registered, but never executed) * (OPTIONAL; default is FALSE). * */ function add_plugin($plugin_name, $args='', $dont_execute=FALSE) { global $squirrelmail_plugin_hooks, $plugins; // changing the hook function array whilst in the // middle of iterating thru it for the same hook // doesn't always work, so we'll see if the hook // currently being executed has had its function // list changed; if so, we will execute the added // hook functions ourselves // $hook_name = get_current_hook_name($args); // used below for determining if any plugins // were added to currently running hook // if (!empty($hook_name) && !empty($squirrelmail_plugin_hooks[$hook_name]) && is_array($squirrelmail_plugin_hooks[$hook_name])) $original_hook_functions = $squirrelmail_plugin_hooks[$hook_name]; else $original_hook_functions = array(); // add plugin to global plugin array // $plugins[] = $plugin_name; // enable plugin -- emulate code from use_plugin() function // in SquirrelMail core, because in 1.5.2, it no longer // called "squirrelmail_plugin_init_", which // NEEDS to be called here. // if (file_exists(SM_PATH . "plugins/$plugin_name/setup.php")) { include_once(SM_PATH . "plugins/$plugin_name/setup.php"); $function = "squirrelmail_plugin_init_$plugin_name"; if (function_exists($function)) $function(); } // now get any new plugins for the current hook // and run their hooks // if (!$dont_execute && !empty($hook_name)) { if (!empty($squirrelmail_plugin_hooks[$hook_name]) && is_array($squirrelmail_plugin_hooks[$hook_name])) $new_hook_functions = array_diff($squirrelmail_plugin_hooks[$hook_name], $original_hook_functions); else $new_hook_functions = array(); foreach ($new_hook_functions as $function) if (function_exists($function)) //FIXME: is $args always how plugins are called, even in 1.4.x? $function($args); } } /** * Dynamically disables a plugin from the SquirrelMail environment. * * @param string $plugin_name The name of the plugin to remove. * */ function remove_plugin($plugin_name) { global $squirrelmail_plugin_hooks, $plugins; $plugin_key = array_search($plugin_name, $plugins); if (!is_null($plugin_key) && $plugin_key !== FALSE) { unset($plugins[$plugin_key]); if (is_array($squirrelmail_plugin_hooks)) foreach (array_keys($squirrelmail_plugin_hooks) as $hookName) { unset($squirrelmail_plugin_hooks[$hookName][$plugin_name]); } } } /** * Determines what plugin hook is currently executing, * if any, in a SquirrelMail version-independent fashion. * * @param mixed $args The current plugin function argument, * which must be exactly as received by * the plugin function that is calling * this code. * * @return string The name of the currently executing plugin * hook, or an empty string if either no hook * is running or the hook name could not be * determined. * */ function get_current_hook_name($args='') { if (check_sm_version(1, 5, 1)) { global $currentHookName; if (!empty($currentHookName)) return $currentHookName; } //TODO: should we ALWAYS backtrace instead of assuming that $args[0] is the hook name? if (!empty($args[0]) && is_string($args[0])) return $args[0]; else { // plugin args not given or didn't have a hook // name in them, so try backtracing instead // $backtrace = debug_backtrace(); foreach ($backtrace as $trace) if ($trace['function'] == 'do_hook' || $trace['function'] == 'do_hook_function' || $trace['function'] == 'concat_hook_function' || $trace['function'] == 'boolean_hook_function') return $trace['args'][0]; // nothing found at all // return ''; } } /** * Load configuration file * * Convenience function for plugins that loads a configuration * file (or files). If the file(s) is(are) not found, an error * is displayed and execution stops (function won't return). * If multiple configuration files are given, ALL of them are * included (unless $load_only_one is TRUE), if they exist, in * the order given. Only one of them needs to be found to avert * triggering an error. * * Note that configuration files are loaded in the order given, * so the caller should place the file that should have the * final overrides as the LAST in the given list, unless using * $load_only_one, in which case the most important configuration * file should probably come first. * * Non-functional on login_before hook. TODO - re-verify that the above is true * * @param string $plugin_name The name of the plugin as * it is known to SquirrelMail, * that is, it is the name * of the plugin directory * @param mixed $config_files An array of files that will * be included IN THE ORDER that * they are given in the * array. Can also be given as * a string if only one config * file is being loaded. Files * should be specified relative * to the calling plugin's * directory, such as: * 'config.php' * or: * '../../config/my_plugin_config.php' * or: * array('data/config.php', 'data/admins.php') * It is also possible to give a * full/direct path to a * configuration file by placing * a forward slash at the * beginning of the file: * array('/var/lib/squirrelmail/config/myplugin.conf') * @param boolean $return_errors When TRUE, any errors encountered * will cause this function to return * FALSE; otherwise, errors are * handled herein by showing an error * to the user and exiting (OPTIONAL; * default is FALSE). * @param boolean $load_only_one When TRUE, this function will stop * after it has successfully loaded * one configuration file, starting * with the first one given for * $config_files. When FALSE, all * configuration files will be loaded * such that the last one can override * all others ("cascading") (OPTIONAL; * default is FALSE). * * @return mixed If no errors are found, TRUE is returned; if an error * was found and $return_errors is TRUE, FALSE is returned. * If $return_errors is FALSE and an error is found, this * function will never return. * */ function load_config($plugin_name, $config_files, $return_errors=FALSE, $load_only_one=FALSE) { global $compatibility_sm_path; // if only one config file given as string // if (!is_array($config_files)) $config_files = array($config_files); // loop through files, attempting to include them // $file_count = 1; foreach ($config_files as $file) { if (strpos($file, '/') === 0) $plugin_path = $file; else $plugin_path = $compatibility_sm_path . 'plugins/' . $plugin_name . '/' . $file; // store inclusion results to be checked below // ${'config' . $file_count} = @include_once($plugin_path); // if we only need one configuration file, stop // here if we successfully loaded this config file // if ($load_only_one && ${'config' . $file_count}) return TRUE; $file_count++; } // now check to see if we got at least one successful inclusion // $success = FALSE; for ($i = 1; $i < $file_count; $i++) if (${'config' . $i}) { $success = TRUE; break; } // error... // if (!$success) { if ($return_errors) return FALSE; // 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 sq_change_text_domain('compatibility'); $error_msg = _("Administrative error:") . '
' . sprintf(_("The plugin %s has not been set up correctly."), '"' . $plugin_name . '"') . '
' . _("Please read the README or INSTALL files that came with the plugin."); sq_change_text_domain('squirrelmail'); include_once($compatibility_sm_path . 'functions/display_messages.php'); global $color; plain_error_message($error_msg, $color); exit; } return TRUE; } /** * Validate Plugin Setup Utility * * Checks a plugin to see if the user has installed it * correctly by checking for the existence of the given * files (all relative from the plugin's directory) * * @param string $pluginName The name of the plugin as * it is known to SquirrelMail, * that is, it is the name * of the plugin directory. * @param array $configFiles An array of any files that the * user should have set up for * this plugin, for example: * array('config.php') * or: * array('data/config.php', 'data/admins.php') * where all files will be * referenced from the plugin's * main directory. * It is also possible to give a * full/direct path to a * configuration file by placing * a forward slash at the * beginning of the file: * array('/var/lib/squirrelmail/config/myplugin.conf') * @param boolean $return_errors When true, any errors encountered * will cause this function to return * either FALSE or a string describing * the error; otherwise, errors are * handled herein by showing an error * to the user and exiting (OPTIONAL; * default is FALSE). * * @return mixed If no errors are found, TRUE is returned; if an error * was found and $return_errors is TRUE, either FALSE or * a string describing the error is returned. If $return_errors * is FALSE and an error is found, this function will never * return. * */ function check_plugin_setup($pluginName, $configFiles, $return_errors=FALSE) { global $compatibility_disable_config_check; if ($compatibility_disable_config_check) return; global $compatibility_sm_path; // check one at a time... // foreach ($configFiles as $configFile) { if (strpos($configFile, '/') === 0) $plugin_path = $configFile; else $plugin_path = $compatibility_sm_path . 'plugins/' . $pluginName . '/' . $configFile; if (!file_exists($plugin_path)) { //if ($return_errors) return FALSE; sq_change_text_domain('compatibility'); if ($return_errors) { $error_msg = sprintf(_("The file %s is missing from plugin %s."), '"' . $configFile . '"', '"' . $pluginName . '"'); sq_change_text_domain('squirrelmail'); return $error_msg; } $error_msg = _("Administrative error:") . '
' . sprintf(_("The plugin %s has not been set up correctly."), '"' . $pluginName . '"') . '
' . sprintf(_("The file %s is missing."), '"' . $configFile . '"') . '
' . _("Please read the README or INSTALL files that came with the plugin."); sq_change_text_domain('squirrelmail'); include_once($compatibility_sm_path . 'functions/display_messages.php'); global $color; plain_error_message($error_msg, $color); exit; } } return TRUE; } /** * Test if a given file contains a given string. * * This can be used, for example, by plugins during the configtest hook * that want to verify if a certain patch to the SquirrelMail core has * been applied or not. * * The string is searched for using a regular expression to allow for * more complex searches than direct string comparision. The $string * parameter may contain regular expression syntax if desired. * * @param string $file The file to search (usually a full path). * @param string $string The string to search for (can include regular * expression syntax if desired - any special * regular expression meta characters need to * be escaped unless they are being used as such). * @param boolean $quiet When TRUE and $file cannot be found or opened, * this function returns FALSE, otherwise it * will complain and exit (never return) (OPTIONAL; * default is FALSE). * * @return boolean TRUE when $string was found or FALSE when it was not. * When $quiet is TRUE, FALSE is also returned if the * target file could not be located, opened or read. * */ function check_file_contents($file, $string, $quiet=FALSE) { if (check_php_version(4, 3, 0)) { $contents = file_get_contents($file); if (!$contents) if ($quiet) return FALSE; else { echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!'; exit; } } else { $temp_contents = file($file); if (!$temp_contents || !is_array($temp_contents)) if ($quiet) return FALSE; else { echo 'FATAL ERROR: ' . $file . ' cannot be found or opened!'; exit; } $contents = ''; foreach ($temp_contents as $line) $contents .= $line; } return preg_match('/' . $string . '/', $contents); } /** * Returns the difference in times. Some small * amount of precision might be lost in the + * operations, but nothing serious. * * This is only a convenience function for plugin * authors fine tuning performance and may not * work on some operating systems. * * @param string $start The microtime() results for * the start point. * @param string $end The microtime() results for * the end point (OPTIONAL; * if empty defaults to the * time NOW). * * @return float The difference between start and * end points. * */ function sm_microtime_diff($start, $end=0) { if (empty($end)) $end = microtime(); return (substr($end, 11) - substr($start, 11)) + (substr($end, 0, 9) - substr($start, 0, 9)); } compatibility/docs/0000755000000000000000000000000011307010223013342 5ustar rootrootcompatibility/docs/index.php0000644000000000000000000000072711273232034015200 0ustar rootroot Description =========== This plugin allows any other plugin access to the functions and special variables needed to make it backward (and forward) compatible with most versions of SM in wide use. This eliminates the need for duplication of certain functions throughout many plugins. It also provides functionality that helps check that plugins have been installed and set up correctly. License ======= This plugin is released under the GNU General Public License (see the file COPYING for details). Donations ========= If you or your company make regular use of this software, please consider supporting Open Source development by donating to the authors or inquire about hiring them to consult on other projects. Donation/ wish list links for the author(s) are as follows: Paul Lesniewski: https://sourceforge.net/donate/index.php?user_id=508228 Requirements ============ * None Troubleshooting =============== * If you experience errors that look similar to the following: Fatal error: Call to undefined function php_self() in .../compatibility/includes/1.5.0/global.php on line 25 You have a plugin installed that requires version 1.x of the Compatibility plugin. There is a list of plugins that have this requirement here: http://www.squirrelmail.org/wiki/CompatibilityDependencies Note that you generally cannot use plugins that require Compatibility 1.x with ones that require Compatibility 2.x. The best approach to solving this problem is to contact the plugin author of the outdated plugin and work with them to update that code. Help Requests ============= Before looking for help elsewhere, please try to help yourself: * Read the Troubleshooting section herein. * Look to see if others have already asked about the same issue. There are tips and links for the best places to do this in the SquirrelMail mailing list posting guidelines: http://squirrelmail.org/wiki/MailingListPostingGuidelines You should also try Google or some other search engine. * If you cannot find any information about your issue, please first mail your help request to the squirrelmail-plugins mailing list. Information about it can be found here: http://lists.sourceforge.net/mailman/listinfo/squirrelmail-plugins You MUST read the mailing list posting guidelines (see above) and include as much information about your issue (and your system) as possible. Including configtest output, any debug output, the plugin configuration settings you've made and anything else you can think of to make it easier to diagnose your problem will get you the most useful responses. Inquiries that do not comply with the posting guidelines are liable to be ignored. * If you don't get any replies on the mailing list, you are welcome to send a help request to the authors' personal address(es), but please be patient with the mailing list. Usage (Plugin Authors' Guide) ============================= As of version 2.0 of this plugin, no special action is required on the part of plugin developers to make their plugin backward compatible via the Compatibility Plugin. However, any custom pages (such as option pages) provided by a plugin should always start with the following code: // set up SquirrelMail environment // if (file_exists('../../include/init.php')) include_once('../../include/init.php'); else if (file_exists('../../include/validate.php')) { define('SM_PATH', '../../'); include_once(SM_PATH . 'include/validate.php'); } else { chdir('..'); define('SM_PATH', '../'); include_once(SM_PATH . 'src/validate.php'); } // make sure plugin is activated! // global $plugins; if (!in_array('plugin_name', $plugins)) exit; Otherwise, developers should just use the most up-to-date SquirrelMail API and expect that their plugins will in most cases work with most versions of SquirrelMail as long as users of older versions have downloaded this plugin and applied its patch if necessary. If a function is found that a certain plugin uses that is not included in the Compatibility Plugin, please ask to have it added. Authors who want to avoid getting support requests for simple setup problems (such as when the person installing the plugin neglects to create a configuration file) can use one of these functionalities: load_config('my_plugin', array('config.php')); check_plugin_setup('my_plugin', array('config.php')); The first of these functions will load (include) any and all configuration files given (in the order given) and will trigger an error (that is a bit more helpful for novice administrators who can't find or understand PHP errors) if none of them are found. The second function checks for the existence of any configuration files you specify (it does not load (include) them, however - this function is only intended as a configuration test. It can be handy in combination with the "configtest" hook which is available in SquirrelMail 1.4.10 and above and 1.5.2 and above. The first parameter for both of these functions is the name of the plugin as it is known to SquirrelMail (the plugin's directory name). The second parameter is an array of any number of files, relative to the plugin's directory (or a full path, if it starts with a forward slash, such as "/var/lib/squirrelmail/config/myplugin.conf"). Any number of files may be named here. Another example for each: load_config('my_plugin', array('data/config-default.php', 'data/config.php')); check_plugin_setup('my_plugin', array('data/config.php', 'data/admins.php')); Note that load_config() is designed to allow you to do things such as include a default configuration in case the administrator did not create her own configuration file, or to include a full set of default configuration settings, and another file that contains just a sub-set thereof, etc. Keep in mind that files are loaded/included in the order given. Note that check_plugin_setup() is best placed somewhere where it will not run frequently, since it is only really needed once (thus, in SquirrelMail versions 1.4.10 and 1.5.2 and above, use it with the "configtest" hook). You may turn off that function by changing the $disable_config_check at the top of the functions.php file in the Compatibility Plugin. A function called check_file_contents() is also available for plugins that would like to check if the SquirrelMail source code has been properly patched if needed by that plugin. See that function's documentation in the functions.php file for more information if needed. There are also some advanced utility functions for use by plugins needing to add, remove or re-order other plugins (or themselves) called add_plugin(), remove_plugin(), get_current_hook_name() and reposition_plugin_on_hook(). Plugin authors needing to use these should read the function documentation in the functions.php file in the Compatibility plugin directory. TODO ==== * sqsetcookie probably will break some plugins, since I'm not sure where the flush is happening in 1.5.1 and if it's being backported correctly. should fix this or make sure it's not a problem (hrmph, seems to work fine for multilogin, sooo....) * Add broader functionality to help plugins diagnose other setup/install issues? such as what? checking certain variables in the config files?... * Add functionality to auto-define SM_PATH? I have run into real sticky issues with this and prefer to leave it out of this plugin... too many variables... but would be nice to remove this responsibilty from plugin authors Possible algorightm: - globalize and check if $compatibility_sm_path is already available - if so, use it, define SM_PATH with it if not done already - iterate through getcwd contents, taking off chunks until one of the known SM directories is found (plugins, src, functions, include, class, etc) - define SM_PATH and $compatibility_sm_path - chdir to plugins or SM_PATH dir??? (see below) Come to think of it, why doesn't validate.php just take care of this? Not sure it is appropriate there, but maybe a plugin config file would be good (that's almost what this is becoming... which is handy but not sure if all the extra work and abstraction is worth it, at least from a performance angle - all we gain is allowing plugin authors to be dumber. and are they that dumb?!? ;> * Add functionality to auto-chdir if needed? we are trying to avoid this altogether (and in fact in SM 1.3 and up we have, unless a plugin is really whacked) so this is only useful for 1.2... hmmm... thing is that I ran into some weird situations with plugins clashing with one another (address_add was one very problematic one) unless some chdir'ing was done. again, it'd be nice to pull all this out of plugin author hands so it'll actually work, but it could be a little messy, and might need to be version dependent code (esp 1.2?) The address_add thing is a good example of how messy things can be... it is called by code executing somewhere in the src directory, so chdir'ing at that time can be disasterous * Checking for config files and whatnot should be moved to the configuration-time code in new SquirrelMail versions; it is pointless to do this every time the plugin is used Change Log ========== v2.0.16 2009/12/06 Paul Lesniewski * Added security token functions sm_get_user_security_tokens(), sm_generate_security_token(), and sm_validate_security_token() v2.0.15 2009/10/31 Paul Lesniewski * Updated check_plugin_dependencies() * Updated minor change in sq_call_function_suppress_errors() v2.0.14 2009/01/01 Paul Lesniewski * Added is_ssl_secured_connection() * Added sq_is_writable() * Added sq_create_tempfile() * Added get_process_owner_info() * Update with changes in sqsetcookie() and that it was added to 1.4.16 v2.0.13 2008/07/26 Paul Lesniewski * Synchronized sq_send_mail() and sqauth_save_password() with changes in SquirrelMail * Synchronized get_plugin_requirement() with changes in SquirrelMail v2.0.12 2008/05/21 Paul Lesniewski * Added set_uri_vars() * Added check_file_contents() * Added $load_only_one to load_config() * Added include directories for 1.4.15 and 1.4.16 * Added lame-duck stand-in for ngettext() when needed under SquirrelMail versions less than 1.5.1 that are not running at least PHP 4.2.0 with the gettext extension v2.0.11 2008/02/29 Paul Lesniewski * Moved sq_send_mail(), since it was added to SM core * Added debug constants from 1.5.2 v2.0.10 2008/01/12 Paul Lesniewski * Note that SquirrelMail 1.4.13+ (as well as 1.5.1+) no longer requires a source patch. * Added sq_call_function_suppress_errors() * Added get_secured_config_value() * Added get_smtp_user() * Added sq_send_mail() v2.0.9 2007/07/12 Paul Lesniewski * Synchronize with addition of sqauth_read_password() to SM 1.4.11 * Improve get_current_hook_name() function in SM 1.5.1+ (no need to upgrade except for use with SM 1.5.1+) * Removed sq_popen() and family v2.0.8 2007/04/17 * Fix mistyped function call, which should not have shown up unless using old or broken setups. Thanks to Yoshinori Mamoto. * Fixed sqm_baseuri() location change that creates bug for versions 1.4.5 and below * Added sq_popen() and family * Added list_files() v2.0.7 2007/04/05 * Added sqauth_save_password() and sqauth_read_password() from 1.5.1 to compatibility library * Added documentation note that plugin authors should not use checkForJavascript() under 1.4.x * Added get_plugin_version(), updated check_plugin_version() * Added sq_htmlspecialchars() * Added sq_change_text_domain() * Added get_plugin_requirement() * Added get_plugin_dependencies(), check_plugin_dependencies() * Changed internal legacy inclusion mechanism for better organization and easier maintenance * Adjusted for new SM_VERSION constant in SM 1.5.2 v2.0.6 2007/01/17 * Fixed issues from the last release: eval code return bug that showed only under 1.5.1 and PHP notice issue when used with the Multilogin plugin under 1.4.x. v2.0.5 2007/01/14 * Revamped legacy mechanism; cleaned up include files and included functions (as mentioned in the README, if plugin authors find functions they need for better compatibility, please get in touch) * Added missing include in the case of errors in load_config * Added get_current_hook_name(), add_plugin(), remove_plugin() and reposition_plugin_on_hook() functions * Remove use of SM_PATH in functions file in case it is not available * load_config() and check_plugin_setup() can now also return after an error to allow the caller to handle the error * Added patches through SquirrelMail version 1.4.9 and 1.5.0 (Compatibility plugin is natively loaded in 1.5.1 and up) v2.0.4 2005/11/11 * Sorry, folks. Changed the location of the compatibility patch again. When upgrading to this version, you *MUST* remove the patch from version 2.0.3 (to do so, just re-run the patch for that version *BEFORE* you unpack and install this version). As with before, patches from version 2.0.2 or previous will do no harm if left in place. If you are using version 2.0.3, upgrade is especially recommended. v2.0.3 2005/10/24 * Changed the location of the compatibility patch. Everyone upgrading to this version will need to re-run the patch! The old compatibility patch becomes obsolete, but it does not hurt anything to be left in place. v2.0.2 2005/10/19 * Added load_config function for use by other plugins * Added new sqsetcookie and sqsession_start functions to includes * Added new checkForJavascript function to includes v2.0.1 2005/07/14 * Documentation change (plugins *never* need to include Compatibility directly) * Added 1.4.6 includes directory * Added is_plugin_enabled() up to 1.4.5 and 1.5.0 v2.0 2005/06/16 * Reorganized code so that plugin authors do not need to specifically use "compatibility_" functions. * Changed compatibility_check_plugin_setup() to check_plugin_setup() 1.3 - Paul Lesniewski * Added compatibility_check_plugin_setup() that helps verify that a plugin has been installed and set up correctly * Added new $compatibility_sm_path variable for easier plugin coding... * Updated for compatibility (!) with new version reporting API 1.2 - Paul Lesniewski * Fix for theme problem with plugins under SM 1.4 1.1 - Paul Lesniewski * Some applications of this plugin were experiencing unusual include order, so added includes of the global.php and strings.php files to be safe. * Even though older versions of SquirrelMail have some of the functions that this plugin duplicates, because they have session issues, the compatibility version of those functions now takes precedence over older SquirrelMail core code. 1.0 - Paul Lesniewski * Initial release compatibility/index.php0000644000000000000000000000072211127344440014246 0ustar rootroot SquirrelMail Compatibility Plugin Translation File # Copyright (c) 2005 The Squirrelmail Development Team # This file is distributed under the same license as the SquirrelMail package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: compatibility\n" "Report-Msgid-Bugs-To: SquirrelMail Internationalization \n" "POT-Creation-Date: 2008-02-27 23:15-0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "Administrative error:" msgstr "" #, php-format msgid "The plugin %s has not been set up correctly." msgstr "" msgid "Please read the README or INSTALL files that came with the plugin." msgstr "" #, php-format msgid "The file %s is missing from plugin %s." msgstr "" #, php-format msgid "The file %s is missing." msgstr "" compatibility/locale/.htaccess0000644000000000000000000000001611273232034015454 0ustar rootrootDeny from All compatibility/locale/getpot0000744000000000000000000000063311035054125015110 0ustar rootroot#!/bin/sh XGETTEXT_OPTIONS="--keyword=_ -keyword=N_ --default-domain=compatibility --no-wrap --no-location --add-comments=i18n" # Allows controlling language option # (gettext v.0.10.40 = -C, gettext 0.11+ = -L php). if [ $SM_OLD_GETTEXT ] ; then XGETTEXT_OPTIONS="${XGETTEXT_OPTIONS} -C"; else XGETTEXT_OPTIONS="${XGETTEXT_OPTIONS} -L php"; fi xgettext ${XGETTEXT_OPTIONS} *.php --output=compatibility.pot compatibility/version0000644000000000000000000000002511307010230014015 0ustar rootrootCompatibility 2.0.16 compatibility/patches.old/0000755000000000000000000000000011273232052014626 5ustar rootrootcompatibility/patches.old/index.php0000644000000000000000000000072210730633404016452 0ustar rootroot * Licensed under the GNU GPL. For full terms see the file COPYING. * * @package plugins * @subpackage compatibility * */ /** * Returns info about this plugin * */ function compatibility_info() { return array( 'english_name' => 'Compatibility', 'authors' => array( 'Paul Lesniewski' => array( 'email' => 'paul@squirrelmail.org', 'sm_site_username' => 'pdontthink', ), ), 'version' => '2.0.16', 'required_sm_version' => '1.0', 'requires_configuration' => 0, 'requires_source_patch' => 2, 'required_plugins' => array(), 'per_version_requirements' => array( '1.5.1' => array( 'requires_source_patch' => 0, ), '1.5.0' => array( 'requires_source_patch' => 1, ), '1.4.13' => array( 'requires_source_patch' => 0, ), '1.0.0' => array( 'requires_source_patch' => 1, ), ), 'summary' => 'Allows plugins to remain compatible with all versions of SquirrelMail.', 'details' => 'This plugin allows any other plugin access to the functions and special variables needed to make it backward (and forward) compatible with most versions of SM in wide use. This eliminates the need for duplication of certain functions throughout many plugins. It also provides functionality that helps check that plugins have been installed and set up correctly.', ); } /** * Returns version info about this plugin * */ function compatibility_version() { $info = compatibility_info(); return $info['version']; } compatibility/README0000644000000000000000000000006511273231027013304 0ustar rootrootPlease see all documentation in the docs/ directory. compatibility/make_release.sh0000744000000000000000000001345011273232032015375 0ustar rootroot#!/bin/sh # Generic shell script for building SquirrelMail plugin release # # Copyright (c) 2004-2009 Paul Lesniewski # Licensed under the GNU GPL. For full terms see the file COPYING. # ####################################################### # # CONFIGURATION # # Relative paths to any and all configuration files # for this plugin: these files will NOT be included # in the release package built by this script; they # should be given as relative paths and filenames from # the plugin's own directory - for example, if you # have a config.php file in the main plugin directory # and a special_config.php file in a "data" subdirectory, # this should be set as follows: # # CONFIG_FILES=( config.php data/special_config.php ) # # Note that you can also use this setting to exclude # entire subdirectories while creating the release # package. Here is an example that skips any files # inside a subdirectory called "cache_files" and # completely removes a subdirectory called "tmp", as # well as the standard config.php file: # # CONFIG_FILES=( config.php tmp cache_files/* ) # # CONFIG_FILES=( ) # # END CONFIGURATION # ####################################################### # avoid all kinds of potential problems; only allow # this to be run from directory where it resides # if [ "$0" != "./make_release.sh" ]; then echo echo "Please do not run from remote directory" echo exit 1 fi # grab name of package being built from directory name # # PACKAGE=`echo "$PWD" | sed s/.*\\\///` # get "pretty name" from version file # if [ ! -e version ]; then echo echo "No version file found. Please create before making release" echo exit 2 fi PRETTY_NAME=`head -1 version` # announce ourselves # echo echo "Creating Release Package for $PRETTY_NAME" echo # grab old version number straight from the php code # OLD_VERSION=`echo "" | php -q` REQ_SM_VERSION=`echo "" | php -q` # check for the standard files... # if [ ! -e README ]; then echo echo "No README file found. Please create before making release" echo exit 3 fi if [ ! -e docs/README ]; then echo echo "No docs/README file found. Please create before making release" echo exit 3 fi if [ ! -e docs/INSTALL ]; then echo echo "No docs/INSTALL file found. Please create before making release" echo exit 4 fi if [ ! -e locale/getpot ]; then echo echo "No locale/getpot file found. Please create before making release" echo exit 5 fi if [ ! -e locale/$PACKAGE.pot ]; then echo echo "No locale/$PACKAGE.pot file found. Please create before making release" echo exit 5 fi # just copy index.php and COPYING automatically if not found # if [ ! -e docs/COPYING ]; then echo "No docs/COPYING file found. Grabbing one from ../../" cp ../../COPYING ./docs/ fi if [ ! -e index.php ]; then echo "No index.php file found. Grabbing one from ../" cp ../index.php . fi if [ ! -e docs/index.php ]; then echo "No docs/index.php file found. Grabbing one from ../" cp ../index.php ./docs/ fi if [ ! -e locale/index.php ]; then echo "No locale/index.php file found. Grabbing one from ../" cp ../index.php ./locale/ fi # Make our own docs/.htaccess and locale/.htaccess if needed # if [ ! -e docs/.htaccess ]; then echo "No docs/.htaccess file found. Creating..." echo "Deny from All" > ./docs/.htaccess fi if [ ! -e locale/.htaccess ]; then echo "No locale/.htaccess file found. Creating..." echo "Deny from All" > ./locale/.htaccess fi # remove any previous tarballs # while test 1; do echo echo -n "Remove all .tar.gz files? (y/[n]): " read REPLY if test -z $REPLY; then REPLY="n" break fi if test $REPLY = "y"; then break fi if test $REPLY = "n"; then break fi done if [ "$REPLY" = "y" ]; then rm -f *.tar.gz fi # get new version number if needed # if [ ! -z "$REQ_SM_VERSION" ] ; then OLD_FULL_VERSION=$OLD_VERSION-$REQ_SM_VERSION else OLD_FULL_VERSION=$OLD_VERSION fi echo read -p "Enter Version Number [$OLD_VERSION]: " VERSION if [ -z "$VERSION" ] ; then VERSION=$OLD_VERSION; # VERSION=$OLD_FULL_VERSION; fi PURE_VERSION=`echo "$VERSION" | sed 's/-.*//'` if [ ! -z "$REQ_SM_VERSION" ] ; then FINAL_VERSION="$PURE_VERSION-$REQ_SM_VERSION" else FINAL_VERSION="$PURE_VERSION" fi # remove tarball we are building if present # echo echo "Removing $PACKAGE-$FINAL_VERSION.tar.gz" rm -f $PACKAGE-$FINAL_VERSION.tar.gz # replace version number in info function in setup.php # NOTE that this requires specific syntax in setup.php # for the _info() function which should be # a line that looks like: # 'version' => '', # if test -e setup.php; then echo "Replacing version in setup.php (info function)" sed -e "s/'version' => '$OLD_VERSION',/'version' => '$PURE_VERSION',/" setup.php > setup.php.tmp mv setup.php.tmp setup.php fi # update version number in version file too # echo "Replacing version in version file" echo "$PRETTY_NAME" > version echo $PURE_VERSION >> version # Build tar command; exclude config and other irrelevant files # TAR_COMMAND="tar -c -z -v --exclude CVS --exclude .svn" J=0 while [ "$J" -lt ${#CONFIG_FILES[@]} ]; do echo "Excluding ${CONFIG_FILES[$J]}" TAR_COMMAND="$TAR_COMMAND --exclude ${CONFIG_FILES[$J]}" J=`expr $J + 1` done TAR_COMMAND="$TAR_COMMAND -f $PACKAGE-$FINAL_VERSION.tar.gz $PACKAGE" # make tarball # echo "Creating $PACKAGE-$FINAL_VERSION.tar.gz" cd ../ $TAR_COMMAND mv $PACKAGE-$FINAL_VERSION.tar.gz $PACKAGE cd $PACKAGE echo echo "Finished" echo compatibility/includes/0000755000000000000000000000000011307006666014240 5ustar rootrootcompatibility/includes/1.2.11/0000755000000000000000000000000010730633423014754 5ustar rootrootcompatibility/includes/1.2.11/index.php0000644000000000000000000000072210730633423016575 0ustar rootroot $files, 'DIRECTORIES' => $directories); return $files; } } // // taken from functions/plugin.php on 2007/04/05 // since 1.5.2 // if (!function_exists('get_plugin_version')) { function get_plugin_version($plugin_name, $force_inclusion = FALSE, $do_parse = FALSE) { $info_function = $plugin_name . '_info'; $version_function = $plugin_name . '_version'; $plugin_info = array(); $plugin_version = FALSE; // first attempt to find the plugin info function, wherein // the plugin version should be available // if (function_exists($info_function)) $plugin_info = $info_function(); else if ($force_inclusion && file_exists(SM_PATH . 'plugins/' . $plugin_name . '/setup.php')) { /* --- Old code, keeping just in case... problem with it is, for example, if it is used, but later we are checking if the same plugin is activated (because it SHOULD be), this code having run will possibly create a false positive. include_once(SM_PATH . 'plugins/' . $plugin_name . '/setup.php'); if (function_exists($info_function)) $plugin_info = $info_function(); --- */ // so what we need to do is process this plugin without // it polluting our environment // // we *could* just use the above code, which is more of a // sure thing than some regular expressions, and then test // the contents of the $plugins array to see if this plugin // is actually activated, and that might be good enough, but // for now, we'll use the following approach, because of two // concerns: other plugins and other templates might force // the inclusion of a plugin (which SHOULD also add it to // the $plugins array, but am not 100% sure at this time (FIXME)), // and because the regexps below should work just fine with // any resonably formatted plugin setup file. // // read the target plugin's setup.php file into a string, // then use a regular expression to try to find the version... // this of course can break if plugin authors do funny things // with their file formatting // $setup_file = ''; $file_contents = file(SM_PATH . 'plugins/' . $plugin_name . '/setup.php'); foreach ($file_contents as $line) $setup_file .= $line; // this regexp grabs a version number from a standard // _info() function // if (preg_match('/[\'"]version[\'"]\s*=>\s*[\'"](.+?)[\'"]/is', $setup_file, $matches)) $plugin_info = array('version' => $matches[1]); // this regexp grabs a version number from a standard // (deprecated) _version() function // else if (preg_match('/function\s+.*?' . $plugin_name . '_version.*?\(.*?\).*?\{.*?return\s+[\'"](.+?)[\'"]/is', $setup_file, $matches)) $plugin_info = array('version' => $matches[1]); } if (!empty($plugin_info['version'])) $plugin_version = $plugin_info['version']; // otherwise, look for older version function // if (!$plugin_version && function_exists($version_function)) $plugin_version = $version_function(); if ($plugin_version && $do_parse) { // massage version number into something we understand // // the first regexp strips everything and anything that follows // the first occurance of a non-digit (or non decimal point), so // beware that putting letters in the middle of a version string // will effectively truncate the version string right there (but // this also just helps remove the SquirrelMail version part off // of versions such as "1.2.3-1.4.4") // // the second regexp just strips out non-digits/non-decimal points // (and might be redundant(?)) // // the regexps are wrapped in a trim that makes sure the version // does not start or end with a decimal point // $plugin_version = trim(preg_replace(array('/[^0-9.]+.*$/', '/[^0-9.]/'), '', $plugin_version), '.'); } return $plugin_version; } } // // taken from functions/plugin.php on 2007/04/05 // since 1.5.2 // if (!function_exists('check_plugin_version')) { function check_plugin_version($plugin_name, $a = 0, $b = 0, $c = 0, $force_inclusion = FALSE) { $plugin_version = get_plugin_version($plugin_name, $force_inclusion, TRUE); if (!$plugin_version) return FALSE; // split the version string into sections delimited by // decimal points, and make sure we have three sections // $plugin_version = explode('.', $plugin_version); if (!isset($plugin_version[0])) $plugin_version[0] = 0; if (!isset($plugin_version[1])) $plugin_version[1] = 0; if (!isset($plugin_version[2])) $plugin_version[2] = 0; // sm_print_r($plugin_version); // now test the version number // if ($plugin_version[0] < $a || ($plugin_version[0] == $a && $plugin_version[1] < $b) || ($plugin_version[0] == $a && $plugin_version[1] == $b && $plugin_version[2] < $c)) return FALSE; return TRUE; } } // // taken from functions/plugin.php on 2008/07/22 // since 1.5.2 // if (!function_exists('get_plugin_requirement')) { function get_plugin_requirement($plugin_name, $requirement, $ignore_incompatible = TRUE, $force_inclusion = FALSE) { $info_function = $plugin_name . '_info'; $plugin_info = array(); $requirement_value = NULL; // first attempt to find the plugin info function, wherein // the plugin requirements should be available // if (function_exists($info_function)) $plugin_info = $info_function(); else if ($force_inclusion && file_exists(SM_PATH . 'plugins/' . $plugin_name . '/setup.php')) { /* --- Old code, keeping just in case... problem with it is, for example, if it is used, but later we are checking if the same plugin is activated (because it SHOULD be), this code having run will possibly create a false positive. include_once(SM_PATH . 'plugins/' . $plugin_name . '/setup.php'); if (function_exists($info_function)) $plugin_info = $info_function(); --- */ // so what we need to do is process this plugin without // it polluting our environment // // we *could* just use the above code, which is more of a // sure thing than a regular expression, and then test // the contents of the $plugins array to see if this plugin // is actually activated, and that might be good enough, but // for now, we'll use the following approach, because of two // concerns: other plugins and other templates might force // the inclusion of a plugin (which SHOULD also add it to // the $plugins array, but am not 100% sure at this time (FIXME)), // and because the regexp below should work just fine with // any resonably formatted plugin setup file. // // read the target plugin's setup.php file into a string, // then use a regular expression to try to find the needed // requirement information... // this of course can break if plugin authors do funny things // with their file formatting // $setup_file = ''; $file_contents = file(SM_PATH . 'plugins/' . $plugin_name . '/setup.php'); foreach ($file_contents as $line) $setup_file .= $line; // this regexp grabs the full plugin info array from a standard // _info() function... determining the end of the info // array can fail, but if authors end the array with ");\n" // (without quotes), then it should work well, especially because // newlines shouldn't be found inside the array after any ");" // (without quotes) // if (preg_match('/function\s+.*?' . $plugin_name . '_info.*?\(.*?\).*?\{.*?(array.+?\)\s*;)\s*' . "\n" . '/is', $setup_file, $matches)) eval('$plugin_info = ' . $matches[1]); } // attempt to get the requirement from the "global" scope // of the plugin information array // if (isset($plugin_info[$requirement]) && !is_null($plugin_info[$requirement])) $requirement_value = $plugin_info[$requirement]; // now, if there is a series of per-version requirements, // check there too // if (!empty($plugin_info['per_version_requirements']) && is_array($plugin_info['per_version_requirements'])) { // iterate through requirements, where keys are version // numbers -- tricky part is knowing the difference between // more than one version for which the current SM installation // passes the check_sm_version() test... we want the highest one // $requirement_value_override = NULL; $highest_version_array = array(); foreach ($plugin_info['per_version_requirements'] as $version => $requirement_overrides) { $version_array = explode('.', $version); if (sizeof($version_array) != 3) continue; $a = $version_array[0]; $b = $version_array[1]; $c = $version_array[2]; // complicated way to say we are interested in these overrides // if the version is applicable to us and if the overrides include // the requirement we are looking for, or if the plugin is not // compatible with this version of SquirrelMail (unless we are // told to ignore such) // if (check_sm_version($a, $b, $c) && ((!$ignore_incompatible && (!empty($requirement_overrides[SQ_INCOMPATIBLE]) || $requirement_overrides === SQ_INCOMPATIBLE)) || (is_array($requirement_overrides) && isset($requirement_overrides[$requirement]) && !is_null($requirement_overrides[$requirement])))) { if (empty($highest_version_array) || $highest_version_array[0] < $a || ($highest_version_array[0] == $a && $highest_version_array[1] < $b) || ($highest_version_array[0] == $a && $highest_version_array[1] == $b && $highest_version_array[2] < $c)) { $highest_version_array = $version_array; if (!empty($requirement_overrides[SQ_INCOMPATIBLE]) || $requirement_overrides === SQ_INCOMPATIBLE) $requirement_value_override = SQ_INCOMPATIBLE; else $requirement_value_override = $requirement_overrides[$requirement]; } } } // now grab override if one is available // if (!is_null($requirement_value_override)) $requirement_value = $requirement_value_override; } return $requirement_value; } } // // taken from functions/plugin.php on 2007/06/29 // since 1.5.2 // if (!function_exists('get_plugin_dependencies')) { function get_plugin_dependencies($plugin_name, $force_inclusion = FALSE, $do_parse = TRUE) { $plugin_dependencies = get_plugin_requirement($plugin_name, 'required_plugins', $force_inclusion); // the plugin is simply incompatible, no need to continue here // if ($plugin_dependencies === SQ_INCOMPATIBLE) return $plugin_dependencies; // not an array of requirements? wrong format, just return FALSE // if (!is_array($plugin_dependencies)) return FALSE; // make sure everything is in order... // if (!empty($plugin_dependencies)) { $new_plugin_dependencies = array(); foreach ($plugin_dependencies as $plugin_name => $plugin_requirements) { // if $plugin_requirements isn't an array, this is old-style, // where only the version number was given... // if (is_string($plugin_requirements)) $plugin_requirements = array('version' => $plugin_requirements, 'activate' => FALSE); // trap badly formatted requirements arrays that don't have // needed info // if (!is_array($plugin_requirements) || !isset($plugin_requirements['version'])) continue; if (!isset($plugin_requirements['activate'])) $plugin_requirements['activate'] = FALSE; // parse version into something we understand? // if ($do_parse) { // massage version number into something we understand // // the first regexp strips everything and anything that follows // the first occurance of a non-digit (or non decimal point), so // beware that putting letters in the middle of a version string // will effectively truncate the version string right there (but // this also just helps remove the SquirrelMail version part off // of versions such as "1.2.3-1.4.4") // // the second regexp just strips out non-digits/non-decimal points // (and might be redundant(?)) // // the regexps are wrapped in a trim that makes sure the version // does not start or end with a decimal point // $plugin_requirements['version'] = trim(preg_replace(array('/[^0-9.]+.*$/', '/[^0-9.]/'), '', $plugin_requirements['version']), '.'); } $new_plugin_dependencies[$plugin_name] = $plugin_requirements; } $plugin_dependencies = $new_plugin_dependencies; } return $plugin_dependencies; } } // // taken from functions/plugin.php on 2007/06/29 // since 1.5.2 // if (!function_exists('check_plugin_dependencies')) { function check_plugin_dependencies($plugin_name, $force_inclusion = FALSE) { $dependencies = get_plugin_dependencies($plugin_name, $force_inclusion); if (!$dependencies) return TRUE; if ($dependencies === SQ_INCOMPATIBLE) return $dependencies; $missing_or_bad = array(); foreach ($dependencies as $depend_name => $depend_requirements) { // check for core plugins first // if (strpos(strtoupper($depend_requirements['version']), 'CORE') === 0) { // see if the plugin is in the core (just check if the directory exists) // if (!file_exists(SM_PATH . 'plugins/' . $depend_name)) $missing_or_bad[$depend_name] = $depend_requirements; // check if it is activated if need be // else if ($depend_requirements['activate'] && !is_plugin_enabled($depend_name)) $missing_or_bad[$depend_name] = $depend_requirements; // check if this is the right core version if one is given // (note this is pretty useless - a plugin should specify // whether or not it itself is compatible with this version // of SM in the first place) // else if (strpos($depend_requirements['version'], ':') !== FALSE) { $version = explode('.', substr($depend_requirements['version'], strpos($depend_requirements['version'], ':') + 1), 3); $version[0] = intval($version[0]); if (isset($version[1])) $version[1] = intval($version[1]); else $version[1] = 0; if (isset($version[2])) $version[2] = intval($version[2]); else $version[2] = 0; if (!check_sm_version($version[0], $version[1], $version[2])) $missing_or_bad[$depend_name] = $depend_requirements; } continue; } // if the plugin is actually incompatible; check that it // is not activated // if ($depend_requirements['version'] == SQ_INCOMPATIBLE) { if (is_plugin_enabled($depend_name)) $missing_or_bad[$depend_name] = $depend_requirements; continue; } // check for normal plugins // $version = explode('.', $depend_requirements['version'], 3); $version[0] = intval($version[0]); if (isset($version[1])) $version[1] = intval($version[1]); else $version[1] = 0; if (isset($version[2])) $version[2] = intval($version[2]); else $version[2] = 0; $force_dependency_inclusion = !$depend_requirements['activate']; if (!check_plugin_version($depend_name, $version[0], $version[1], $version[2], $force_dependency_inclusion)) $missing_or_bad[$depend_name] = $depend_requirements; } if (empty($missing_or_bad)) return TRUE; // get non-parsed required versions // $non_parsed_dependencies = get_plugin_dependencies($plugin_name, $force_inclusion, FALSE); $return_array = array(); foreach ($missing_or_bad as $depend_name => $ignore) $return_array[$depend_name] = $non_parsed_dependencies[$depend_name]; return $return_array; } } // // taken from functions/plugin.php on 2006/09/21 // since 1.5.2 // if (!function_exists('sqm_array_merge')) { function sqm_array_merge($a, $b, $concat_strings=true) { $ret = array(); if (is_array($a)) { $ret = $a; } else { if (is_string($a) && is_string($b) && $concat_strings) { return $a . $b; } $ret[] = $a; } if (is_array($b)) { foreach ($b as $key => $value) { if (isset($ret[$key])) { $ret[$key] = sqm_array_merge($ret[$key], $value, $concat_strings); } else { $ret[$key] = $value; } } } else { $ret[] = $b; } return $ret; } } // // taken from functions/global.php on 2007/01/14 // since 1.5.2 // if (!function_exists('sqGetGlobalVarMultiple')) { function sqGetGlobalVarMultiple($name, &$value, $indicator_field, $search = SQ_INORDER, $fallback_no_suffix=TRUE, $default=NULL, $typecast=FALSE) { // Set arbitrary max limit -- should be much lower except on the // search results page, if there are many (50 or more?) mailboxes // shown, this may not be high enough. Is there some way we should // automate this value? // $max_form_search = 100; for ($i = 1; $i <= $max_form_search; $i++) { if (sqGetGlobalVar($indicator_field . '_' . $i, $temp, $search)) { return sqGetGlobalVar($name . '_' . $i, $value, $search, $default, $typecast); } } // no indicator field found; just try without suffix if allowed // if ($fallback_no_suffix) { return sqGetGlobalVar($name, $value, $search, $default, $typecast); } // no dice, set default and return FALSE // if (!is_null($default)) { $value = $default; } return FALSE; } } // // taken from functions/global.php on 2007/02/05 // since 1.5.2 // if (!function_exists('sq_htmlspecialchars')) { function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { if ($quote_style === FALSE) $quote_style = ENT_QUOTES; // array? go recursive... // if (is_array($value)) { $return_array = array(); foreach ($value as $key => $val) { $return_array[sq_htmlspecialchars($key, $quote_style)] = sq_htmlspecialchars($val, $quote_style); } return $return_array; // sanitize strings only // } else if (is_string($value)) { if ($quote_style === TRUE) return str_replace(array('\'', '"'), array(''', '"'), $value); else return htmlspecialchars($value, $quote_style); } // anything else gets returned with no changes // return $value; } } // // taken from 1.4.10-svn functions/i18n.php on 2007/03/30 // since 1.5.2 and 1.4.10 // // This code was taken from 1.4.10, because it has code that // is needed in the 1.4.x series but will still work (albiet // a spec more inefficient) in 1.5.x. If you are running 1.5.x // you should be running 1.5.2+, where this function is natively // included anyway. // if ((!compatibility_check_sm_version(1, 4, 10) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('sq_change_text_domain')) { function sq_change_text_domain($domain_name, $directory='') { global $use_gettext; static $domains_already_seen = array(); $return_value = textdomain(NULL); // empty domain defaults to "squirrelmail" // if (empty($domain_name)) $domain_name = 'squirrelmail'; // only need to call bindtextdomain() once unless // $use_gettext is turned on // if (!$use_gettext && in_array($domain_name, $domains_already_seen)) { textdomain($domain_name); return $return_value; } $domains_already_seen[] = $domain_name; if (empty($directory)) $directory = SM_PATH . 'locale/'; sq_bindtextdomain($domain_name, $directory); textdomain($domain_name); return $return_value; } } // // taken from 1.4.12-svn functions/global.php on 2007/12/17 // since 1.5.2 and 1.4.12 // // This code was taken from 1.4.12, because the 1.5.2 version // of this function has constants that are not defined in the // 1.4.x series. If you are running 1.5.x, you should be // running 1.5.2+, where this function is natively included // anyway. // if ((!compatibility_check_sm_version(1, 4, 12) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('sq_call_function_suppress_errors')) { function sq_call_function_suppress_errors($function, $args=array()) { $display_errors = ini_get('display_errors'); ini_set('display_errors', '0'); $ret = call_user_func_array($function, $args); ini_set('display_errors', $display_errors); return $ret; } } // // taken from functions/global.php on 2008/01/12 // since 1.5.2 // if (!function_exists('get_secured_config_value')) { function get_secured_config_value($var_name) { static $return_values = array(); // if we can avoid it, return values that have // already been retrieved (so we don't have to // include the config file yet again) // if (isset($return_values[$var_name])) { return $return_values[$var_name]; } // load site configuration // require(SM_PATH . 'config/config.php'); // load local configuration overrides // if (file_exists(SM_PATH . 'config/config_local.php')) { require(SM_PATH . 'config/config_local.php'); } // if SM isn't in "secured configuration" mode, // just return the desired value from the global scope // if (!$secured_config) { global $$var_name; $return_values[$var_name] = $$var_name; return $$var_name; } // else we return what we got from the config file // $return_values[$var_name] = $$var_name; return $$var_name; } } // // taken from functions/compose.php on 2008/02/29 // since 1.5.2 // if (!function_exists('sq_send_mail')) { function sq_send_mail($to, $subject, $body, $from, $cc='', $bcc='', $message='') { require_once(SM_PATH . 'functions/mime.php'); require_once(SM_PATH . 'class/mime.class.php'); if (empty($message)) { $message = new Message(); $header = new Rfc822Header(); $message->setBody($body); $content_type = new ContentType('text/plain'); global $special_encoding, $default_charset; if ($special_encoding) $rfc822_header->encoding = $special_encoding; else $rfc822_header->encoding = '8bit'; if ($default_charset) $content_type->properties['charset']=$default_charset; $header->content_type = $content_type; $header->parseField('To', $to); $header->parseField('Cc', $cc); $header->parseField('Bcc', $bcc); $header->parseField('From', $from); $header->parseField('Subject', $subject); $message->rfc822_header = $header; } //sm_print_r($message);exit; global $useSendmail; // ripped from src/compose.php - based on both 1.5.2 and 1.4.14 // if (!$useSendmail) { require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php'); $deliver = new Deliver_SMTP(); global $smtpServerAddress, $smtpPort, $pop_before_smtp, $domain, $pop_before_smtp_host; $authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false; if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress; $user = ''; $pass = ''; get_smtp_user($user, $pass); $stream = $deliver->initStream($message,$domain,0, $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host); } else { require_once(SM_PATH . 'class/deliver/Deliver_SendMail.class.php'); global $sendmail_path, $sendmail_args; // Check for outdated configuration if (!isset($sendmail_args)) { if ($sendmail_path=='/var/qmail/bin/qmail-inject') { $sendmail_args = ''; } else { $sendmail_args = '-i -t'; } } $deliver = new Deliver_SendMail(array('sendmail_args'=>$sendmail_args)); $stream = $deliver->initStream($message,$sendmail_path); } $success = false; $message_id = ''; if ($stream) { $deliver->mail($message, $stream); if (!empty($message->rfc822_header->message_id)) { $message_id = $message->rfc822_header->message_id; } $success = $deliver->finalizeStream($stream); } return array($success, $message_id); } } // // taken from functions/html.php on 2008/05/21 // since 1.5.2 // if (!function_exists('set_uri_vars')) { function set_uri_vars($uri, $values, $sanitize=TRUE) { foreach ($values as $key => $value) if (is_array($value)) { $i = 0; foreach ($value as $val) $uri = set_url_var($uri, $key . '[' . $i++ . ']', $val, $sanitize); } else $uri = set_url_var($uri, $key, $value, $sanitize); return $uri; } } // // taken from 1.5.2-svn functions/global.php on 2008/11/26 // since 1.5.2 and 1.4.17 // if ((!compatibility_check_sm_version(1, 4, 17) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('is_ssl_secured_connection')) { function is_ssl_secured_connection() { global $sq_ignore_http_x_forwarded_headers, $sq_https_port; $https_env_var = getenv('HTTPS'); if ($sq_ignore_http_x_forwarded_headers || !sqgetGlobalVar('HTTP_X_FORWARDED_PROTO', $forwarded_proto, SQ_SERVER)) $forwarded_proto = ''; if (empty($sq_https_port)) // won't work with port 0 (zero) $sq_https_port = 443; if ((isset($https_env_var) && strcasecmp($https_env_var, 'on') === 0) || (sqgetGlobalVar('HTTPS', $https, SQ_SERVER) && !empty($https) && strcasecmp($https, 'off') !== 0) || (strcasecmp($forwarded_proto, 'https') === 0) || (sqgetGlobalVar('SERVER_PORT', $server_port, SQ_SERVER) && $server_port == $sq_https_port)) return TRUE; return FALSE; } global $is_secure_connection; $is_secure_connection = is_ssl_secured_connection(); } // // taken from 1.5.2-svn functions/files.php on 2008/11/26 // since 1.5.2 // if (!function_exists('sq_is_writable')) { global $server_os; if (DIRECTORY_SEPARATOR == '\\') $server_os = 'windows'; else $server_os = '*nix'; function sq_is_writable($path) { global $server_os; // under *nix with safe_mode off, use the native is_writable() // if ($server_os == '*nix' && !(bool)ini_get('safe_mode')) return is_writable($path); // if it's a directory, that means we have to create a temporary // file therein // $delete_temp_file = FALSE; if (@is_dir($path) && ($temp_filename = @sq_create_tempfile($path))) { $path .= DIRECTORY_SEPARATOR . $temp_filename; $delete_temp_file = TRUE; } // try to open the file for writing (without trying to create it) // if (!@is_dir($path) && ($FILE = @fopen($path, 'r+'))) { @fclose($FILE); // delete temp file if needed // if ($delete_temp_file) @unlink($path); return TRUE; } // delete temp file if needed // if ($delete_temp_file) @unlink($path); return FALSE; } } // // taken from 1.5.2-svn functions/files.php on 2008/11/26 // since 1.5.2 // if (!function_exists('sq_create_tempfile')) { function sq_create_tempfile($directory) { // give up after 1000 tries $maximum_tries = 1000; // using PHP >= 4.3.2 we can be truly atomic here $filemods = check_php_version(4, 3, 2) ? 'x' : 'w'; for ($try = 0; $try < $maximum_tries; ++$try) { $localfilename = GenerateRandomString(32, '', 7); $full_localfilename = $directory . DIRECTORY_SEPARATOR . $localfilename; // filename collision. try again if ( file_exists($full_localfilename) ) { continue; } // try to open for (binary) writing $fp = @fopen( $full_localfilename, $filemods); if ($fp !== FALSE) { // success! make sure it's not readable, close and return filename chmod($full_localfilename, 0600); fclose($fp); return $localfilename; } } // we tried as many times as we could but didn't succeed. return FALSE; } } // // taken from 1.5.2-svn functions/global.php on 2008/12/04 // since 1.5.2 // if (!function_exists('get_process_owner_info')) { function get_process_owner_info() { if (!function_exists('posix_getuid')) return FALSE; $process_info['uid'] = posix_getuid(); $process_info['euid'] = posix_geteuid(); $process_info['gid'] = posix_getgid(); $process_info['egid'] = posix_getegid(); $user_info = posix_getpwuid($process_info['uid']); $euser_info = posix_getpwuid($process_info['euid']); $group_info = posix_getgrgid($process_info['gid']); $egroup_info = posix_getgrgid($process_info['egid']); $process_info['name'] = $user_info['name']; $process_info['ename'] = $euser_info['name']; $process_info['group'] = $user_info['name']; $process_info['egroup'] = $euser_info['name']; return $process_info; } } // // taken from 1.5.2-svn/1.4.20-svn (code is identical) // functions/strings.php on 2009/12/06 // since 1.5.2 and 1.4.20-RC 1 // if ((!compatibility_check_sm_version(1, 4, 20) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('sm_get_user_security_tokens')) { function sm_get_user_security_tokens($purge_old=TRUE) { global $data_dir, $username, $max_token_age_days; $tokens = getPref($data_dir, $username, 'security_tokens', ''); if (($tokens = unserialize($tokens)) === FALSE || !is_array($tokens)) $tokens = array(); // purge old tokens if necessary // if ($purge_old) { if (empty($max_token_age_days)) $max_token_age_days = 30; $now = time(); $discard_token_date = $now - ($max_token_age_days * 86400); $cleaned_tokens = array(); foreach ($tokens as $token => $timestamp) if ($timestamp >= $discard_token_date) $cleaned_tokens[$token] = $timestamp; $tokens = $cleaned_tokens; } return $tokens; } } // // taken from 1.5.2-svn/1.4.20-svn (code is identical) // functions/strings.php on 2009/12/06 // since 1.5.2 and 1.4.20-RC 1 // if ((!compatibility_check_sm_version(1, 4, 20) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('sm_generate_security_token')) { function sm_generate_security_token() { global $data_dir, $username, $disable_security_tokens; $max_generation_tries = 1000; $tokens = sm_get_user_security_tokens(); $new_token = GenerateRandomString(12, '', 7); $count = 0; while (isset($tokens[$new_token])) { $new_token = GenerateRandomString(12, '', 7); if (++$count > $max_generation_tries) { logout_error(_("Fatal token generation error; please contact your system administrator or the SquirrelMail Team")); exit; } } // is the token system enabled? CAREFUL! // if (!$disable_security_tokens) { $tokens[$new_token] = time(); setPref($data_dir, $username, 'security_tokens', serialize($tokens)); } return $new_token; } } // // taken from 1.5.2-svn/1.4.20-svn (code is identical) // functions/strings.php on 2009/12/06 // since 1.5.2 and 1.4.20-RC 1 // if ((!compatibility_check_sm_version(1, 4, 20) || (compatibility_check_sm_version(1, 5, 0) && !compatibility_check_sm_version(1, 5, 2))) && !function_exists('sm_validate_security_token')) { function sm_validate_security_token($token, $validity_period=0, $show_error=FALSE) { global $data_dir, $username, $max_token_age_days, $disable_security_tokens; // bypass token validation? CAREFUL! // if ($disable_security_tokens) return TRUE; // don't purge old tokens here because we already // do it when generating tokens // $tokens = sm_get_user_security_tokens(FALSE); // token not found? // if (empty($tokens[$token])) { if (!$show_error) return FALSE; logout_error(_("This page request could not be verified and appears to have expired.")); exit; } $now = time(); $timestamp = $tokens[$token]; // whether valid or not, we want to remove it from // user prefs if it's old enough // if ($timestamp < $now - $validity_period) { unset($tokens[$token]); setPref($data_dir, $username, 'security_tokens', serialize($tokens)); } // reject tokens that are too old // if (empty($max_token_age_days)) $max_token_age_days = 30; $old_token_date = $now - ($max_token_age_days * 86400); if ($timestamp < $old_token_date) { if (!$show_error) return FALSE; logout_error(_("The current page request appears to have originated from an untrusted source.")); exit; } // token OK! // return TRUE; } } compatibility/includes/1.5.1/0000755000000000000000000000000011273230374014677 5ustar rootrootcompatibility/includes/1.5.1/index.php0000644000000000000000000000072210730633450016517 0ustar rootroot