7b086a80 |
1 | <?php |
2 | |
35586184 |
3 | /** |
4 | * plugin.php |
5 | * |
35586184 |
6 | * This file provides the framework for a plugin architecture. |
7 | * |
8 | * Documentation on how to write plugins might show up some time. |
9 | * |
47ccfad4 |
10 | * @copyright © 1999-2006 The SquirrelMail Project Team |
4b4abf93 |
11 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
31841a9e |
12 | * @version $Id$ |
d6c32258 |
13 | * @package squirrelmail |
35586184 |
14 | */ |
15 | |
d6c32258 |
16 | /** |
17 | * This function adds a plugin. |
18 | * @param string $name Internal plugin name (ie. delete_move_next) |
19 | * @return void |
20 | */ |
0606ca1f |
21 | function use_plugin ($name) { |
bd9c880b |
22 | if (file_exists(SM_PATH . "plugins/$name/setup.php")) { |
23 | include_once(SM_PATH . "plugins/$name/setup.php"); |
8b56e282 |
24 | |
25 | /** |
26 | * As of SM 1.5.2, plugin hook registration is statically |
27 | * accomplished using the configuration utility (config/conf.pl). |
28 | * And this code is deprecated (but let's keep it until |
29 | * the new registration system is proven). |
30 | * |
31 | */ |
32 | //$function = "squirrelmail_plugin_init_$name"; |
33 | //if (function_exists($function)) { |
34 | // $function(); |
35 | //} |
2d367c68 |
36 | } |
0606ca1f |
37 | } |
2d367c68 |
38 | |
d6c32258 |
39 | /** |
d849b570 |
40 | * This function executes a plugin hook. |
41 | * |
42 | * It includes an arbitrary return value that is managed by |
43 | * all plugins on the same hook and returned to the core hook |
44 | * location. |
45 | * |
46 | * The desired format of the return value should be defined |
47 | * by the context in which the hook is called. |
48 | * |
49 | * Note that the master return value for this hook is passed |
50 | * to each plugin after the main argument(s) value/array as a |
51 | * convenience only - to show what the current return value is |
52 | * even though it is liable to be changed by other plugins. |
53 | * |
54 | * If any plugin on this hook wants to modify the $args |
55 | * plugin parameter, it simply has to use call-by-reference |
56 | * syntax in the hook function that it has registered for the |
57 | * current hook. Note that this is in addition to (entirely |
58 | * independent of) the return value for this hook. |
59 | * |
60 | * @param string $name Name of hook being executed |
61 | * @param mixed $args A single value or an array of arguments |
62 | * that are to be passed to all plugins |
63 | * operating off the hook being called. |
64 | * Note that this argument is passed by |
65 | * reference thus it is liable to be |
66 | * changed after the hook completes. |
67 | * |
68 | * @return mixed The return value that is managed by the plugins |
69 | * on the current hook. |
8b096f0a |
70 | * |
8b096f0a |
71 | */ |
d849b570 |
72 | function do_hook($name, &$args) { |
73 | |
eb1f02bc |
74 | global $squirrelmail_plugin_hooks, $currentHookName; |
eb1f02bc |
75 | $currentHookName = $name; |
d849b570 |
76 | $ret = NULL; |
31524bcd |
77 | |
78 | if (isset($squirrelmail_plugin_hooks[$name]) |
79 | && is_array($squirrelmail_plugin_hooks[$name])) { |
8b56e282 |
80 | foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) { |
81 | use_plugin($plugin_name); |
31524bcd |
82 | if (function_exists($function)) { |
0fe6826d |
83 | $ret = $function($args, $ret); |
dd389be5 |
84 | } |
2d367c68 |
85 | } |
2d367c68 |
86 | } |
7b086a80 |
87 | |
eb1f02bc |
88 | $currentHookName = ''; |
2586d588 |
89 | return $ret; |
d849b570 |
90 | |
0606ca1f |
91 | } |
7b086a80 |
92 | |
8b096f0a |
93 | /** |
d849b570 |
94 | * This function executes a hook that allows for an arbitrary |
95 | * return value from each plugin that will be merged into one |
96 | * array (or one string if all return values are strings) and |
97 | * returned to the core hook location. |
7edd8ad6 |
98 | * |
99 | * Note that unlike PHP's array_merge function, matching array keys |
100 | * will not overwrite each other, instead, values under such keys |
101 | * will be concatenated if they are both strings, or merged if they |
102 | * are arrays (in the same (non-overwrite) manner recursively). |
103 | * |
104 | * Plugins returning non-arrays (strings, objects, etc) will have |
105 | * their output added to the end of the ultimate return array, |
106 | * unless ALL values returned are strings, in which case one string |
0db60ced |
107 | * with all returned strings concatenated together is returned |
108 | * (unless $force_array is TRUE). |
8b096f0a |
109 | * |
d849b570 |
110 | * If any plugin on this hook wants to modify the $args |
111 | * plugin parameter, it simply has to use call-by-reference |
112 | * syntax in the hook function that it has registered for the |
113 | * current hook. Note that this is in addition to (entirely |
114 | * independent of) the return value for this hook. |
115 | * |
0db60ced |
116 | * @param string $name Name of hook being executed |
117 | * @param mixed $args A single value or an array of arguments |
118 | * that are to be passed to all plugins |
119 | * operating off the hook being called. |
120 | * Note that this argument is passed by |
121 | * reference thus it is liable to be |
122 | * changed after the hook completes. |
123 | * @param boolean $force_array When TRUE, guarantees the return |
124 | * value will ALWAYS be an array, |
125 | * (simple strings will be forced |
126 | * into a one-element array). |
127 | * When FALSE, behavior is as |
128 | * described above (OPTIONAL; |
129 | * default behavior is to return |
130 | * mixed - array or string). |
7edd8ad6 |
131 | * |
132 | * @return mixed the merged return arrays or strings of each |
d849b570 |
133 | * plugin on this hook. |
7edd8ad6 |
134 | * |
8b096f0a |
135 | */ |
0db60ced |
136 | function concat_hook_function($name, &$args, $force_array=FALSE) { |
d849b570 |
137 | |
eb1f02bc |
138 | global $squirrelmail_plugin_hooks, $currentHookName; |
eb1f02bc |
139 | $currentHookName = $name; |
d849b570 |
140 | $ret = ''; |
31524bcd |
141 | |
09ac2863 |
142 | if (isset($squirrelmail_plugin_hooks[$name]) |
143 | && is_array($squirrelmail_plugin_hooks[$name])) { |
8b56e282 |
144 | foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) { |
145 | use_plugin($plugin_name); |
09ac2863 |
146 | if (function_exists($function)) { |
d849b570 |
147 | $plugin_ret = $function($args); |
5fba72db |
148 | if (!empty($plugin_ret)) { |
149 | $ret = sqm_array_merge($ret, $plugin_ret); |
150 | } |
09ac2863 |
151 | } |
152 | } |
153 | } |
154 | |
0db60ced |
155 | if ($force_array && is_string($ret)) { |
156 | $ret = array($ret); |
157 | } |
158 | |
eb1f02bc |
159 | $currentHookName = ''; |
09ac2863 |
160 | return $ret; |
d849b570 |
161 | |
09ac2863 |
162 | } |
cd7fc9e6 |
163 | |
5576644b |
164 | /** |
165 | * This function is used for hooks which are to return true or |
166 | * false. If $priority is > 0, any one or more trues will override |
167 | * any falses. If $priority < 0, then one or more falses will |
168 | * override any trues. |
8b096f0a |
169 | * Priority 0 means majority rules. Ties will be broken with $tie |
170 | * |
d849b570 |
171 | * If any plugin on this hook wants to modify the $args |
172 | * plugin parameter, it simply has to use call-by-reference |
173 | * syntax in the hook function that it has registered for the |
174 | * current hook. Note that this is in addition to (entirely |
175 | * independent of) the return value for this hook. |
176 | * |
177 | * @param string $name The hook name |
178 | * @param mixed $args A single value or an array of arguments |
179 | * that are to be passed to all plugins |
180 | * operating off the hook being called. |
181 | * Note that this argument is passed by |
182 | * reference thus it is liable to be |
183 | * changed after the hook completes. |
184 | * @param int $priority See explanation above |
185 | * @param boolean $tie See explanation above |
186 | * |
187 | * @return boolean The result of the function |
188 | * |
8b096f0a |
189 | */ |
d849b570 |
190 | function boolean_hook_function($name, &$args, $priority=0, $tie=false) { |
191 | |
eb1f02bc |
192 | global $squirrelmail_plugin_hooks, $currentHookName; |
5576644b |
193 | $yea = 0; |
194 | $nay = 0; |
195 | $ret = $tie; |
196 | |
197 | if (isset($squirrelmail_plugin_hooks[$name]) && |
198 | is_array($squirrelmail_plugin_hooks[$name])) { |
199 | |
200 | /* Loop over the plugins that registered the hook */ |
eb1f02bc |
201 | $currentHookName = $name; |
8b56e282 |
202 | foreach ($squirrelmail_plugin_hooks[$name] as $plugin_name => $function) { |
203 | use_plugin($plugin_name); |
5576644b |
204 | if (function_exists($function)) { |
d849b570 |
205 | $ret = $function($args); |
5576644b |
206 | if ($ret) { |
207 | $yea++; |
208 | } else { |
209 | $nay++; |
210 | } |
211 | } |
212 | } |
eb1f02bc |
213 | $currentHookName = ''; |
5576644b |
214 | |
215 | /* Examine the aftermath and assign the return value appropriately */ |
216 | if (($priority > 0) && ($yea)) { |
217 | $ret = true; |
218 | } elseif (($priority < 0) && ($nay)) { |
219 | $ret = false; |
220 | } elseif ($yea > $nay) { |
221 | $ret = true; |
222 | } elseif ($nay > $yea) { |
223 | $ret = false; |
224 | } else { |
225 | // There's a tie, no action needed. |
226 | } |
227 | return $ret; |
228 | } |
229 | // If the code gets here, there was a problem - no hooks, etc. |
230 | return NULL; |
d849b570 |
231 | |
5576644b |
232 | } |
233 | |
cd7fc9e6 |
234 | /** |
141105fc |
235 | * Do not use, use checkForJavascript() instead. |
236 | * |
cd7fc9e6 |
237 | * This function checks whether the user's USER_AGENT is known to |
238 | * be broken. If so, returns true and the plugin is invisible to the |
239 | * offending browser. |
7349fa12 |
240 | * *** THIS IS A TEST FOR JAVASCRIPT SUPPORT *** |
8b096f0a |
241 | * |
242 | * @return bool whether this browser properly supports JavaScript |
ccacde36 |
243 | * @deprecated use checkForJavascript() since 1.5.1 |
cd7fc9e6 |
244 | */ |
245 | function soupNazi(){ |
7349fa12 |
246 | return !checkForJavascript(); |
cd7fc9e6 |
247 | } |
fe0aa536 |
248 | |
249 | /** |
250 | * Check if plugin is enabled |
251 | * @param string $plugin_name plugin name |
252 | * @since 1.5.1 |
253 | * @return boolean |
254 | */ |
255 | function is_plugin_enabled($plugin_name) { |
256 | global $plugins; |
257 | |
e83cfcef |
258 | /** |
202bcbcc |
259 | * check if variable is empty. if var is not set, php empty |
e495bd68 |
260 | * returns true without error notice. |
261 | * |
262 | * then check if it is an array |
e83cfcef |
263 | */ |
e495bd68 |
264 | if (empty($plugins) || ! is_array($plugins)) |
fe0aa536 |
265 | return false; |
266 | |
267 | if ( in_array($plugin_name,$plugins) ) { |
268 | return true; |
269 | } else { |
270 | return false; |
271 | } |
272 | } |
d99b6c56 |
273 | |
274 | /** |
275 | * Check a plugin's version. |
276 | * |
277 | * Returns TRUE if the given plugin is installed, |
278 | * activated and is at minimum version $a.$b.$c. |
279 | * If any one of those conditions fails, FALSE |
280 | * will be returned (careful of plugins that are |
281 | * sufficiently versioned but are not activated). |
282 | * |
283 | * By overriding the default value of $force_inclusion, |
284 | * this function will attempt to grab versioning |
285 | * information from the given plugin even if it |
286 | * is not activated (plugin still has to be |
287 | * unpackaged and set in place in the plugins |
288 | * directory). Use with care - some plugins |
289 | * might break SquirrelMail when this is used. |
290 | * |
291 | * Note that this function assumes plugin |
292 | * versioning is consistently applied in the same |
293 | * fashion that SquirrelMail versions are, with the |
294 | * exception that an applicable SquirrelMail |
295 | * version may be appended to the version number |
296 | * (which will be ignored herein). That is, plugin |
297 | * version number schemes are expected in the following |
298 | * format: 1.2.3, or 1.2.3-1.4.0. |
299 | * |
300 | * Any characters after the third number are discarded, |
301 | * so formats such as the following will also work, |
302 | * although extra information about beta versions can |
303 | * possibly confuse the desired results of the version |
304 | * check: 1.2.3-beta4, 1.2.3.RC2, and so forth. |
305 | * |
b2a6a14c |
306 | * @since 1.5.2 |
d99b6c56 |
307 | * |
308 | * @param string plugin_name name of the plugin to |
309 | * check; must precisely |
310 | * match the plugin |
311 | * directory name |
312 | * @param int a major version number |
313 | * @param int b minor version number |
314 | * @param int c release number |
315 | * @param bool force_inclusion try to get version info |
316 | * for plugins not activated? |
317 | * (default FALSE) |
318 | * |
319 | * @return bool |
320 | * |
321 | */ |
322 | function check_plugin_version($plugin_name, |
323 | $a = 0, $b = 0, $c = 0, |
324 | $force_inclusion = FALSE) |
325 | { |
326 | |
6b6bcf00 |
327 | $info_function = $plugin_name . '_info'; |
d99b6c56 |
328 | $version_function = $plugin_name . '_version'; |
6b6bcf00 |
329 | $plugin_info = array(); |
d99b6c56 |
330 | $plugin_version = FALSE; |
331 | |
332 | |
6b6bcf00 |
333 | // first attempt to find the plugin info function, wherein |
334 | // the plugin version should be available |
d99b6c56 |
335 | // |
6b6bcf00 |
336 | if (function_exists($info_function)) |
337 | $plugin_info = $info_function(); |
d99b6c56 |
338 | else if ($force_inclusion |
339 | && file_exists(SM_PATH . 'plugins/' . $plugin_name . '/setup.php')) |
340 | { |
341 | include_once(SM_PATH . 'plugins/' . $plugin_name . '/setup.php'); |
6b6bcf00 |
342 | if (function_exists($info_function)) |
343 | $plugin_info = $info_function(); |
d99b6c56 |
344 | } |
6b6bcf00 |
345 | if (!empty($plugin_info['version'])) |
346 | $plugin_version = $plugin_info['version']; |
347 | |
348 | |
349 | // otherwise, look for older version function |
350 | // |
351 | if (!$plugin_version && function_exists($version_function)) |
352 | $plugin_version = $version_function(); |
353 | |
d99b6c56 |
354 | |
355 | if (!$plugin_version) return FALSE; |
356 | |
357 | |
358 | // now massage version number into something we understand |
359 | // |
360 | $plugin_version = trim(preg_replace(array('/[^0-9.]+.*$/', '/[^0-9.]/'), |
361 | '', $plugin_version), |
362 | '.'); |
363 | $plugin_version = explode('.', $plugin_version); |
364 | if (!isset($plugin_version[0])) $plugin_version[0] = 0; |
365 | if (!isset($plugin_version[1])) $plugin_version[1] = 0; |
366 | if (!isset($plugin_version[2])) $plugin_version[2] = 0; |
367 | // sm_print_r($plugin_version); |
368 | |
369 | |
370 | // now test the version number |
371 | // |
372 | if ($plugin_version[0] < $a || |
373 | ($plugin_version[0] == $a && $plugin_version[1] < $b) || |
374 | ($plugin_version[0] == $a && $plugin_version[1] == $b && $plugin_version[2] < $c)) |
375 | return FALSE; |
376 | |
377 | |
378 | return TRUE; |
379 | |
380 | } |
381 | |