must pass $args by ref to to plugin function too, if we want the plugin
[squirrelmail.git] / functions / plugin.php
index 4401a06f0f4d5e67ae471b61e6eedcc3d403db1d..20ccf4c39c2c0d196cf189af3e551c3832fa7554 100644 (file)
 function use_plugin ($name) {
     if (file_exists(SM_PATH . "plugins/$name/setup.php")) {
         include_once(SM_PATH . "plugins/$name/setup.php");
-        $function = "squirrelmail_plugin_init_$name";
-        if (function_exists($function)) {
-            $function();
-        }
-    }
-}
 
-/**
- * This function executes a hook.
- * @param string $name Name of hook to fire
- * @return mixed $data
- */
-function do_hook ($name) {
-    global $squirrelmail_plugin_hooks, $currentHookName;
-    $data = func_get_args();
-    $currentHookName = $name;
-
-    if (isset($squirrelmail_plugin_hooks[$name])
-          && is_array($squirrelmail_plugin_hooks[$name])) {
-        foreach ($squirrelmail_plugin_hooks[$name] as $function) {
-            /* Add something to set correct gettext domain for plugin. */
-            if (function_exists($function)) {
-                $function($data);
-            }
-        }
+        /**
+          * As of SM 1.5.2, plugin hook registration is statically
+          * accomplished using the configuration utility (config/conf.pl).
+          * And this code is deprecated (but let's keep it until 
+          * the new registration system is proven).
+          *
+          */
+        //$function = "squirrelmail_plugin_init_$name";
+        //if (function_exists($function)) {
+        //    $function();
+        //}
     }
-
-    $currentHookName = '';
-
-    /* Variable-length argument lists have a slight problem when */
-    /* passing values by reference. Pity. This is a workaround.  */
-    return $data;
 }
 
 /**
- * This function executes a hook and allows for parameters to be passed.
+ * This function executes a plugin hook.
+ *
+ * It includes an arbitrary return value that is managed by
+ * all plugins on the same hook and returned to the core hook
+ * location.
+ *
+ * The desired format of the return value should be defined 
+ * by the context in which the hook is called.
+ *
+ * Note that the master return value for this hook is passed
+ * to each plugin after the main argument(s) value/array as a 
+ * convenience only - to show what the current return value is
+ * even though it is liable to be changed by other plugins.
+ *
+ * If any plugin on this hook wants to modify the $args
+ * plugin parameter, it simply has to use call-by-reference
+ * syntax in the hook function that it has registered for the
+ * current hook.  Note that this is in addition to (entirely
+ * independent of) the return value for this hook.
+ *
+ * @param string $name Name of hook being executed
+ * @param mixed  $args A single value or an array of arguments 
+ *                     that are to be passed to all plugins 
+ *                     operating off the hook being called.  
+ *                     Note that this argument is passed by 
+ *                     reference thus it is liable to be 
+ *                     changed after the hook completes.
+ *
+ * @return mixed The return value that is managed by the plugins
+ *               on the current hook.
  *
- * @param string name the name of the hook
- * @param mixed param the parameters to pass to the hook function
- * @return mixed the return value of the hook function
  */
-function do_hook_function($name,$parm=NULL) {
+function do_hook($name, &$args) {
+
     global $squirrelmail_plugin_hooks, $currentHookName;
-    $ret = '';
     $currentHookName = $name;
+    $ret = NULL;
 
     if (isset($squirrelmail_plugin_hooks[$name])
           && is_array($squirrelmail_plugin_hooks[$name])) {
-        foreach ($squirrelmail_plugin_hooks[$name] as $function) {
-            /* Add something to set correct gettext domain for plugin. */
+        foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) {
+            use_plugin($plugin_name);
             if (function_exists($function)) {
-                $ret = $function($parm);
+                $ret = $function(&$args, $ret);
             }
         }
     }
 
     $currentHookName = '';
-
-    /* Variable-length argument lists have a slight problem when */
-    /* passing values by reference. Pity. This is a workaround.  */
     return $ret;
+
 }
 
 /**
- * This function executes a hook, concatenating the results of each
- * plugin that has the hook defined.
+ * This function executes a hook that allows for an arbitrary
+ * return value from each plugin that will be merged into one
+ * array (or one string if all return values are strings) and
+ * returned to the core hook location.
+ *
+ * Note that unlike PHP's array_merge function, matching array keys
+ * will not overwrite each other, instead, values under such keys
+ * will be concatenated if they are both strings, or merged if they
+ * are arrays (in the same (non-overwrite) manner recursively).
+ *
+ * Plugins returning non-arrays (strings, objects, etc) will have 
+ * their output added to the end of the ultimate return array, 
+ * unless ALL values returned are strings, in which case one string
+ * with all returned strings concatenated together is returned.
+ *
+ * If any plugin on this hook wants to modify the $args
+ * plugin parameter, it simply has to use call-by-reference
+ * syntax in the hook function that it has registered for the
+ * current hook.  Note that this is in addition to (entirely
+ * independent of) the return value for this hook.
+ *
+ * @param string $name Name of hook being executed
+ * @param mixed  $args A single value or an array of arguments 
+ *                     that are to be passed to all plugins 
+ *                     operating off the hook being called.  
+ *                     Note that this argument is passed by 
+ *                     reference thus it is liable to be 
+ *                     changed after the hook completes.
+ *
+ * @return mixed the merged return arrays or strings of each
+ *               plugin on this hook.
  *
- * @param string name the name of the hook
- * @param mixed parm optional hook function parameters
- * @return string a concatenation of the results of each plugin function
  */
-function concat_hook_function($name,$parm=NULL) {
+function concat_hook_function($name, &$args) {
+
     global $squirrelmail_plugin_hooks, $currentHookName;
-    $ret = '';
     $currentHookName = $name;
+    $ret = '';
 
     if (isset($squirrelmail_plugin_hooks[$name])
           && is_array($squirrelmail_plugin_hooks[$name])) {
-        foreach ($squirrelmail_plugin_hooks[$name] as $function) {
-            /* Concatenate results from hook. */
+        foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) {
+            use_plugin($plugin_name);
             if (function_exists($function)) {
-                $ret .= $function($parm);
+                $plugin_ret = $function($args);
+                if (!empty($plugin_ret)) {
+                    $ret = sqm_array_merge($ret, $plugin_ret);
+                }
             }
         }
     }
 
     $currentHookName = '';
-
-    /* Variable-length argument lists have a slight problem when */
-    /* passing values by reference. Pity. This is a workaround.  */
     return $ret;
+
 }
 
 /**
@@ -121,13 +155,27 @@ function concat_hook_function($name,$parm=NULL) {
  * override any trues.
  * Priority 0 means majority rules.  Ties will be broken with $tie
  *
- * @param string name the hook name
- * @param mixed parm the parameters for the hook function
- * @param int priority
- * @param bool tie
- * @return bool the result of the function
+ * If any plugin on this hook wants to modify the $args
+ * plugin parameter, it simply has to use call-by-reference
+ * syntax in the hook function that it has registered for the
+ * current hook.  Note that this is in addition to (entirely
+ * independent of) the return value for this hook.
+ *
+ * @param string  $name     The hook name
+ * @param mixed   $args     A single value or an array of arguments 
+ *                          that are to be passed to all plugins 
+ *                          operating off the hook being called.  
+ *                          Note that this argument is passed by 
+ *                          reference thus it is liable to be 
+ *                          changed after the hook completes.
+ * @param int     $priority See explanation above
+ * @param boolean $tie      See explanation above
+ *
+ * @return boolean The result of the function
+ *
  */
-function boolean_hook_function($name,$parm=NULL,$priority=0,$tie=false) {
+function boolean_hook_function($name, &$args, $priority=0, $tie=false) {
+
     global $squirrelmail_plugin_hooks, $currentHookName;
     $yea = 0;
     $nay = 0;
@@ -138,9 +186,10 @@ function boolean_hook_function($name,$parm=NULL,$priority=0,$tie=false) {
 
         /* Loop over the plugins that registered the hook */
         $currentHookName = $name;
-        foreach ($squirrelmail_plugin_hooks[$name] as $function) {
+        foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) {
+            use_plugin($plugin_name);
             if (function_exists($function)) {
-                $ret = $function($parm);
+                $ret = $function($args);
                 if ($ret) {
                     $yea++;
                 } else {
@@ -166,14 +215,16 @@ function boolean_hook_function($name,$parm=NULL,$priority=0,$tie=false) {
     }
     // If the code gets here, there was a problem - no hooks, etc.
     return NULL;
+
 }
 
 /**
+ * Do not use, use checkForJavascript() instead.
+ *
  * This function checks whether the user's USER_AGENT is known to
  * be broken. If so, returns true and the plugin is invisible to the
  * offending browser.
  * *** THIS IS A TEST FOR JAVASCRIPT SUPPORT ***
- * FIXME: This function needs to have its name changed!
  *
  * @return bool whether this browser properly supports JavaScript
  * @deprecated use checkForJavascript() since 1.5.1