Mercurial > hg > rc2
comparison program/lib/Roundcube/rcube_plugin.php @ 0:4681f974d28b
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:52:31 -0500 |
parents | |
children | 3a5f959af5ae |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4681f974d28b |
---|---|
1 <?php | |
2 | |
3 /** | |
4 +-----------------------------------------------------------------------+ | |
5 | This file is part of the Roundcube Webmail client | | |
6 | Copyright (C) 2008-2014, The Roundcube Dev Team | | |
7 | | | |
8 | Licensed under the GNU General Public License version 3 or | | |
9 | any later version with exceptions for skins & plugins. | | |
10 | See the README file for a full license statement. | | |
11 | | | |
12 | PURPOSE: | | |
13 | Abstract plugins interface/class | | |
14 | All plugins need to extend this class | | |
15 +-----------------------------------------------------------------------+ | |
16 | Author: Thomas Bruederli <roundcube@gmail.com> | | |
17 +-----------------------------------------------------------------------+ | |
18 */ | |
19 | |
20 /** | |
21 * Plugin interface class | |
22 * | |
23 * @package Framework | |
24 * @subpackage PluginAPI | |
25 */ | |
26 abstract class rcube_plugin | |
27 { | |
28 /** | |
29 * Class name of the plugin instance | |
30 * | |
31 * @var string | |
32 */ | |
33 public $ID; | |
34 | |
35 /** | |
36 * Instance of Plugin API | |
37 * | |
38 * @var rcube_plugin_api | |
39 */ | |
40 public $api; | |
41 | |
42 /** | |
43 * Regular expression defining task(s) to bind with | |
44 * | |
45 * @var string | |
46 */ | |
47 public $task; | |
48 | |
49 /** | |
50 * Disables plugin in AJAX requests | |
51 * | |
52 * @var boolean | |
53 */ | |
54 public $noajax = false; | |
55 | |
56 /** | |
57 * Disables plugin in framed mode | |
58 * | |
59 * @var boolean | |
60 */ | |
61 public $noframe = false; | |
62 | |
63 /** | |
64 * A list of config option names that can be modified | |
65 * by the user via user interface (with save-prefs command) | |
66 * | |
67 * @var array | |
68 */ | |
69 public $allowed_prefs; | |
70 | |
71 protected $home; | |
72 protected $urlbase; | |
73 private $mytask; | |
74 private $loaded_config = array(); | |
75 | |
76 | |
77 /** | |
78 * Default constructor. | |
79 * | |
80 * @param rcube_plugin_api $api Plugin API | |
81 */ | |
82 public function __construct($api) | |
83 { | |
84 $this->ID = get_class($this); | |
85 $this->api = $api; | |
86 $this->home = $api->dir . $this->ID; | |
87 $this->urlbase = $api->url . $this->ID . '/'; | |
88 } | |
89 | |
90 /** | |
91 * Initialization method, needs to be implemented by the plugin itself | |
92 */ | |
93 abstract function init(); | |
94 | |
95 /** | |
96 * Provide information about this | |
97 * | |
98 * @return array Meta information about a plugin or false if not implemented: | |
99 * As hash array with the following keys: | |
100 * name: The plugin name | |
101 * vendor: Name of the plugin developer | |
102 * version: Plugin version name | |
103 * license: License name (short form according to http://spdx.org/licenses/) | |
104 * uri: The URL to the plugin homepage or source repository | |
105 * src_uri: Direct download URL to the source code of this plugin | |
106 * require: List of plugins required for this one (as array of plugin names) | |
107 */ | |
108 public static function info() | |
109 { | |
110 return false; | |
111 } | |
112 | |
113 /** | |
114 * Attempt to load the given plugin which is required for the current plugin | |
115 * | |
116 * @param string Plugin name | |
117 * @return boolean True on success, false on failure | |
118 */ | |
119 public function require_plugin($plugin_name) | |
120 { | |
121 return $this->api->load_plugin($plugin_name, true); | |
122 } | |
123 | |
124 /** | |
125 * Attempt to load the given plugin which is optional for the current plugin | |
126 * | |
127 * @param string Plugin name | |
128 * @return boolean True on success, false on failure | |
129 */ | |
130 public function include_plugin($plugin_name) | |
131 { | |
132 return $this->api->load_plugin($plugin_name, true, false); | |
133 } | |
134 | |
135 /** | |
136 * Load local config file from plugins directory. | |
137 * The loaded values are patched over the global configuration. | |
138 * | |
139 * @param string $fname Config file name relative to the plugin's folder | |
140 * | |
141 * @return boolean True on success, false on failure | |
142 */ | |
143 public function load_config($fname = 'config.inc.php') | |
144 { | |
145 if (in_array($fname, $this->loaded_config)) { | |
146 return true; | |
147 } | |
148 | |
149 $this->loaded_config[] = $fname; | |
150 | |
151 $fpath = $this->home.'/'.$fname; | |
152 $rcube = rcube::get_instance(); | |
153 | |
154 if (($is_local = is_file($fpath)) && !$rcube->config->load_from_file($fpath)) { | |
155 rcube::raise_error(array( | |
156 'code' => 527, 'type' => 'php', | |
157 'file' => __FILE__, 'line' => __LINE__, | |
158 'message' => "Failed to load config from $fpath"), true, false); | |
159 return false; | |
160 } | |
161 else if (!$is_local) { | |
162 // Search plugin_name.inc.php file in any configured path | |
163 return $rcube->config->load_from_file($this->ID . '.inc.php'); | |
164 } | |
165 | |
166 return true; | |
167 } | |
168 | |
169 /** | |
170 * Register a callback function for a specific (server-side) hook | |
171 * | |
172 * @param string $hook Hook name | |
173 * @param mixed $callback Callback function as string or array | |
174 * with object reference and method name | |
175 */ | |
176 public function add_hook($hook, $callback) | |
177 { | |
178 $this->api->register_hook($hook, $callback); | |
179 } | |
180 | |
181 /** | |
182 * Unregister a callback function for a specific (server-side) hook. | |
183 * | |
184 * @param string $hook Hook name | |
185 * @param mixed $callback Callback function as string or array | |
186 * with object reference and method name | |
187 */ | |
188 public function remove_hook($hook, $callback) | |
189 { | |
190 $this->api->unregister_hook($hook, $callback); | |
191 } | |
192 | |
193 /** | |
194 * Load localized texts from the plugins dir | |
195 * | |
196 * @param string $dir Directory to search in | |
197 * @param mixed $add2client Make texts also available on the client | |
198 * (array with list or true for all) | |
199 */ | |
200 public function add_texts($dir, $add2client = false) | |
201 { | |
202 $domain = $this->ID; | |
203 $lang = $_SESSION['language']; | |
204 $langs = array_unique(array('en_US', $lang)); | |
205 $locdir = slashify(realpath(slashify($this->home) . $dir)); | |
206 $texts = array(); | |
207 | |
208 // Language aliases used to find localization in similar lang, see below | |
209 $aliases = array( | |
210 'de_CH' => 'de_DE', | |
211 'es_AR' => 'es_ES', | |
212 'fa_AF' => 'fa_IR', | |
213 'nl_BE' => 'nl_NL', | |
214 'pt_BR' => 'pt_PT', | |
215 'zh_CN' => 'zh_TW', | |
216 ); | |
217 | |
218 // use buffering to handle empty lines/spaces after closing PHP tag | |
219 ob_start(); | |
220 | |
221 foreach ($langs as $lng) { | |
222 $fpath = $locdir . $lng . '.inc'; | |
223 if (is_file($fpath) && is_readable($fpath)) { | |
224 include $fpath; | |
225 $texts = (array)$labels + (array)$messages + (array)$texts; | |
226 } | |
227 else if ($lng != 'en_US') { | |
228 // Find localization in similar language (#1488401) | |
229 $alias = null; | |
230 if (!empty($aliases[$lng])) { | |
231 $alias = $aliases[$lng]; | |
232 } | |
233 else if ($key = array_search($lng, $aliases)) { | |
234 $alias = $key; | |
235 } | |
236 | |
237 if (!empty($alias)) { | |
238 $fpath = $locdir . $alias . '.inc'; | |
239 if (is_file($fpath) && is_readable($fpath)) { | |
240 include $fpath; | |
241 $texts = (array)$labels + (array)$messages + (array)$texts; | |
242 } | |
243 } | |
244 } | |
245 } | |
246 | |
247 ob_end_clean(); | |
248 | |
249 // prepend domain to text keys and add to the application texts repository | |
250 if (!empty($texts)) { | |
251 $add = array(); | |
252 foreach ($texts as $key => $value) { | |
253 $add[$domain.'.'.$key] = $value; | |
254 } | |
255 | |
256 $rcube = rcube::get_instance(); | |
257 $rcube->load_language($lang, $add); | |
258 | |
259 // add labels to client | |
260 if ($add2client && method_exists($rcube->output, 'add_label')) { | |
261 if (is_array($add2client)) { | |
262 $js_labels = array_map(array($this, 'label_map_callback'), $add2client); | |
263 } | |
264 else { | |
265 $js_labels = array_keys($add); | |
266 } | |
267 $rcube->output->add_label($js_labels); | |
268 } | |
269 } | |
270 } | |
271 | |
272 /** | |
273 * Wrapper for add_label() adding the plugin ID as domain | |
274 */ | |
275 public function add_label() | |
276 { | |
277 $rcube = rcube::get_instance(); | |
278 | |
279 if (method_exists($rcube->output, 'add_label')) { | |
280 $args = func_get_args(); | |
281 if (count($args) == 1 && is_array($args[0])) { | |
282 $args = $args[0]; | |
283 } | |
284 | |
285 $args = array_map(array($this, 'label_map_callback'), $args); | |
286 $rcube->output->add_label($args); | |
287 } | |
288 } | |
289 | |
290 /** | |
291 * Wrapper for rcube::gettext() adding the plugin ID as domain | |
292 * | |
293 * @param string $p Message identifier | |
294 * | |
295 * @return string Localized text | |
296 * @see rcube::gettext() | |
297 */ | |
298 public function gettext($p) | |
299 { | |
300 return rcube::get_instance()->gettext($p, $this->ID); | |
301 } | |
302 | |
303 /** | |
304 * Register this plugin to be responsible for a specific task | |
305 * | |
306 * @param string $task Task name (only characters [a-z0-9_-] are allowed) | |
307 */ | |
308 public function register_task($task) | |
309 { | |
310 if ($this->api->register_task($task, $this->ID)) { | |
311 $this->mytask = $task; | |
312 } | |
313 } | |
314 | |
315 /** | |
316 * Register a handler for a specific client-request action | |
317 * | |
318 * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction | |
319 * | |
320 * @param string $action Action name (should be unique) | |
321 * @param mixed $callback Callback function as string | |
322 * or array with object reference and method name | |
323 */ | |
324 public function register_action($action, $callback) | |
325 { | |
326 $this->api->register_action($action, $this->ID, $callback, $this->mytask); | |
327 } | |
328 | |
329 /** | |
330 * Register a handler function for a template object | |
331 * | |
332 * When parsing a template for display, tags like <roundcube:object name="plugin.myobject" /> | |
333 * will be replaced by the return value if the registered callback function. | |
334 * | |
335 * @param string $name Object name (should be unique and start with 'plugin.') | |
336 * @param mixed $callback Callback function as string or array with object reference | |
337 * and method name | |
338 */ | |
339 public function register_handler($name, $callback) | |
340 { | |
341 $this->api->register_handler($name, $this->ID, $callback); | |
342 } | |
343 | |
344 /** | |
345 * Make this javascipt file available on the client | |
346 * | |
347 * @param string $fn File path; absolute or relative to the plugin directory | |
348 */ | |
349 public function include_script($fn) | |
350 { | |
351 $this->api->include_script($this->resource_url($fn)); | |
352 } | |
353 | |
354 /** | |
355 * Make this stylesheet available on the client | |
356 * | |
357 * @param string $fn File path; absolute or relative to the plugin directory | |
358 */ | |
359 public function include_stylesheet($fn) | |
360 { | |
361 $this->api->include_stylesheet($this->resource_url($fn)); | |
362 } | |
363 | |
364 /** | |
365 * Append a button to a certain container | |
366 * | |
367 * @param array $p Hash array with named parameters (as used in skin templates) | |
368 * @param string $container Container name where the buttons should be added to | |
369 * | |
370 * @see rcube_remplate::button() | |
371 */ | |
372 public function add_button($p, $container) | |
373 { | |
374 if ($this->api->output->type == 'html') { | |
375 // fix relative paths | |
376 foreach (array('imagepas', 'imageact', 'imagesel') as $key) { | |
377 if ($p[$key]) { | |
378 $p[$key] = $this->api->url . $this->resource_url($p[$key]); | |
379 } | |
380 } | |
381 | |
382 $this->api->add_content($this->api->output->button($p), $container); | |
383 } | |
384 } | |
385 | |
386 /** | |
387 * Generate an absolute URL to the given resource within the current | |
388 * plugin directory | |
389 * | |
390 * @param string $fn The file name | |
391 * | |
392 * @return string Absolute URL to the given resource | |
393 */ | |
394 public function url($fn) | |
395 { | |
396 return $this->api->url . $this->resource_url($fn); | |
397 } | |
398 | |
399 /** | |
400 * Make the given file name link into the plugin directory | |
401 * | |
402 * @param string $fn Filename | |
403 */ | |
404 private function resource_url($fn) | |
405 { | |
406 if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) { | |
407 return $this->ID . '/' . $fn; | |
408 } | |
409 else { | |
410 return $fn; | |
411 } | |
412 } | |
413 | |
414 /** | |
415 * Provide path to the currently selected skin folder within the plugin directory | |
416 * with a fallback to the default skin folder. | |
417 * | |
418 * @return string Skin path relative to plugins directory | |
419 */ | |
420 public function local_skin_path() | |
421 { | |
422 $rcube = rcube::get_instance(); | |
423 $skins = array_keys((array)$rcube->output->skins); | |
424 if (empty($skins)) { | |
425 $skins = (array) $rcube->config->get('skin'); | |
426 } | |
427 foreach ($skins as $skin) { | |
428 $skin_path = 'skins/' . $skin; | |
429 if (is_dir(realpath(slashify($this->home) . $skin_path))) { | |
430 break; | |
431 } | |
432 } | |
433 | |
434 return $skin_path; | |
435 } | |
436 | |
437 /** | |
438 * Callback function for array_map | |
439 * | |
440 * @param string $key Array key. | |
441 * @return string | |
442 */ | |
443 private function label_map_callback($key) | |
444 { | |
445 if (strpos($key, $this->ID.'.') === 0) { | |
446 return $key; | |
447 } | |
448 | |
449 return $this->ID.'.'.$key; | |
450 } | |
451 } |