Thomas Bruederli
2012-11-17 6ddb16d181e285d4f0ef0ef55bdd0ba787f1b583
commit | author | age
cc97ea 1 <?php
T 2
3 /*
4  +-----------------------------------------------------------------------+
5  | program/include/rcube_plugin.php                                      |
6  |                                                                       |
e019f2 7  | This file is part of the Roundcube Webmail client                     |
f5e7b3 8  | Copyright (C) 2008-2009, The Roundcube Dev Team                       |
7fe381 9  |                                                                       |
T 10  | Licensed under the GNU General Public License version 3 or            |
11  | any later version with exceptions for skins & plugins.                |
12  | See the README file for a full license statement.                     |
cc97ea 13  |                                                                       |
T 14  | PURPOSE:                                                              |
15  |  Abstract plugins interface/class                                     |
16  |  All plugins need to extend this class                                |
17  +-----------------------------------------------------------------------+
18  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
19  +-----------------------------------------------------------------------+
20 */
21
22 /**
23  * Plugin interface class
24  *
9ab346 25  * @package    Framework
AM 26  * @subpackage PluginAPI
cc97ea 27  */
T 28 abstract class rcube_plugin
29 {
2cd443 30   /**
A 31    * Class name of the plugin instance
32    *
33    * @var string
34    */
cc97ea 35   public $ID;
5c461b 36
A 37   /**
2cd443 38    * Instance of Plugin API
5c461b 39    *
A 40    * @var rcube_plugin_api
41    */
cc97ea 42   public $api;
2cd443 43
A 44   /**
45    * Regular expression defining task(s) to bind with 
46    *
47    * @var string
48    */
cc97ea 49   public $task;
2cd443 50
A 51   /**
52    * Disables plugin in AJAX requests
53    *
54    * @var boolean
55    */
56   public $noajax = false;
57
58   /**
59    * Disables plugin in framed mode
60    *
61    * @var boolean
62    */
63   public $noframe = false;
64
cc97ea 65   protected $home;
T 66   protected $urlbase;
05a631 67   private $mytask;
cc97ea 68
2cd443 69
cc97ea 70   /**
T 71    * Default constructor.
5c461b 72    *
A 73    * @param rcube_plugin_api $api Plugin API
cc97ea 74    */
T 75   public function __construct($api)
76   {
77     $this->ID = get_class($this);
78     $this->api = $api;
cdf1ae 79     $this->home = $api->dir . $this->ID;
cc97ea 80     $this->urlbase = $api->url . $this->ID . '/';
T 81   }
479af9 82
cc97ea 83   /**
T 84    * Initialization method, needs to be implemented by the plugin itself
85    */
86   abstract function init();
0501b6 87
T 88
89   /**
90    * Attempt to load the given plugin which is required for the current plugin
91    *
92    * @param string Plugin name
93    * @return boolean True on success, false on failure
94    */
95   public function require_plugin($plugin_name)
96   {
97     return $this->api->load_plugin($plugin_name);
98   }
99
100
c73b19 101   /**
T 102    * Load local config file from plugins directory.
103    * The loaded values are patched over the global configuration.
104    *
5c461b 105    * @param string $fname Config file name relative to the plugin's folder
029c2f 106    * @return boolean True on success, false on failure
c73b19 107    */
T 108   public function load_config($fname = 'config.inc.php')
109   {
110     $fpath = $this->home.'/'.$fname;
be98df 111     $rcube = rcube::get_instance();
A 112     if (is_file($fpath) && !$rcube->config->load_from_file($fpath)) {
0c2596 113       rcube::raise_error(array(
A 114         'code' => 527, 'type' => 'php',
10eedb 115         'file' => __FILE__, 'line' => __LINE__,
A 116         'message' => "Failed to load config from $fpath"), true, false);
029c2f 117       return false;
T 118     }
479af9 119
029c2f 120     return true;
c73b19 121   }
cc97ea 122
T 123   /**
124    * Register a callback function for a specific (server-side) hook
125    *
5c461b 126    * @param string $hook Hook name
A 127    * @param mixed  $callback Callback function as string or array with object reference and method name
cc97ea 128    */
T 129   public function add_hook($hook, $callback)
130   {
131     $this->api->register_hook($hook, $callback);
132   }
479af9 133
A 134   /**
135    * Unregister a callback function for a specific (server-side) hook.
136    *
137    * @param string $hook Hook name
138    * @param mixed  $callback Callback function as string or array with object reference and method name
139    */
140   public function remove_hook($hook, $callback)
141   {
142     $this->api->unregister_hook($hook, $callback);
143   }
144
cc97ea 145   /**
T 146    * Load localized texts from the plugins dir
147    *
5c461b 148    * @param string $dir Directory to search in
A 149    * @param mixed  $add2client Make texts also available on the client (array with list or true for all)
cc97ea 150    */
T 151   public function add_texts($dir, $add2client = false)
152   {
153     $domain = $this->ID;
59041f 154     $lang   = $_SESSION['language'];
AM 155     $langs  = array_unique(array('en_US', $lang));
cc97ea 156     $locdir = slashify(realpath(slashify($this->home) . $dir));
59041f 157     $texts  = array();
AM 158
159     // Language aliases used to find localization in similar lang, see below
160     $aliases = array(
161         'de_CH' => 'de_DE',
162         'es_AR' => 'es_ES',
163         'fa_AF' => 'fa_IR',
164         'nl_BE' => 'nl_NL',
165         'pt_BR' => 'pt_PT',
166         'zh_CN' => 'zh_TW',
167     );
7c9850 168
A 169     // use buffering to handle empty lines/spaces after closing PHP tag
170     ob_start();
171
59041f 172     foreach ($langs as $lng) {
aecadc 173       $fpath = $locdir . $lng . '.inc';
A 174       if (is_file($fpath) && is_readable($fpath)) {
59041f 175         include $fpath;
aecadc 176         $texts = (array)$labels + (array)$messages + (array)$texts;
A 177       }
59041f 178       else if ($lng != 'en_US') {
AM 179         // Find localization in similar language (#1488401)
180         $alias = null;
181         if (!empty($aliases[$lng])) {
182           $alias = $aliases[$lng];
183         }
184         else if ($key = array_search($lng, $aliases)) {
185           $alias = $key;
186         }
187
188         if (!empty($alias)) {
189           $fpath = $locdir . $alias . '.inc';
190           if (is_file($fpath) && is_readable($fpath)) {
191             include $fpath;
192             $texts = (array)$labels + (array)$messages + (array)$texts;
193           }
194         }
195       }
cc97ea 196     }
T 197
7c9850 198     ob_end_clean();
A 199
cc97ea 200     // prepend domain to text keys and add to the application texts repository
T 201     if (!empty($texts)) {
202       $add = array();
203       foreach ($texts as $key => $value)
204         $add[$domain.'.'.$key] = $value;
205
38b6aa 206       $rcmail = rcube::get_instance();
cc97ea 207       $rcmail->load_language($lang, $add);
479af9 208
cc97ea 209       // add labels to client
T 210       if ($add2client) {
211         $js_labels = is_array($add2client) ? array_map(array($this, 'label_map_callback'), $add2client) : array_keys($add);
212         $rcmail->output->add_label($js_labels);
213       }
214     }
215   }
479af9 216
cc97ea 217   /**
T 218    * Wrapper for rcmail::gettext() adding the plugin ID as domain
219    *
5c461b 220    * @param string $p Message identifier
cc97ea 221    * @return string Localized text
T 222    * @see rcmail::gettext()
223    */
1c932d 224   public function gettext($p)
cc97ea 225   {
0c2596 226     return rcube::get_instance()->gettext($p, $this->ID);
cc97ea 227   }
1c932d 228
T 229   /**
230    * Register this plugin to be responsible for a specific task
231    *
5c461b 232    * @param string $task Task name (only characters [a-z0-9_.-] are allowed)
1c932d 233    */
T 234   public function register_task($task)
235   {
05a631 236     if ($this->api->register_task($task, $this->ID))
T 237       $this->mytask = $task;
1c932d 238   }
T 239
cc97ea 240   /**
T 241     * Register a handler for a specific client-request action
242     *
243     * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction
244     *
5c461b 245     * @param string $action  Action name (should be unique)
A 246     * @param mixed $callback Callback function as string or array with object reference and method name
cc97ea 247    */
T 248   public function register_action($action, $callback)
249   {
05a631 250     $this->api->register_action($action, $this->ID, $callback, $this->mytask);
cc97ea 251   }
T 252
253   /**
254    * Register a handler function for a template object
255    *
256    * When parsing a template for display, tags like <roundcube:object name="plugin.myobject" />
257    * will be replaced by the return value if the registered callback function.
258    *
5c461b 259    * @param string $name Object name (should be unique and start with 'plugin.')
A 260    * @param mixed  $callback Callback function as string or array with object reference and method name
cc97ea 261    */
T 262   public function register_handler($name, $callback)
263   {
264     $this->api->register_handler($name, $this->ID, $callback);
265   }
266
267   /**
268    * Make this javascipt file available on the client
269    *
5c461b 270    * @param string $fn File path; absolute or relative to the plugin directory
cc97ea 271    */
T 272   public function include_script($fn)
273   {
eb6f19 274     $this->api->include_script($this->resource_url($fn));
cc97ea 275   }
T 276
277   /**
278    * Make this stylesheet available on the client
279    *
5c461b 280    * @param string $fn File path; absolute or relative to the plugin directory
cc97ea 281    */
T 282   public function include_stylesheet($fn)
283   {
eb6f19 284     $this->api->include_stylesheet($this->resource_url($fn));
cc97ea 285   }
479af9 286
cc97ea 287   /**
T 288    * Append a button to a certain container
289    *
5c461b 290    * @param array $p Hash array with named parameters (as used in skin templates)
A 291    * @param string $container Container name where the buttons should be added to
cc97ea 292    * @see rcube_remplate::button()
T 293    */
294   public function add_button($p, $container)
295   {
296     if ($this->api->output->type == 'html') {
297       // fix relative paths
298       foreach (array('imagepas', 'imageact', 'imagesel') as $key)
299         if ($p[$key])
eb6f19 300           $p[$key] = $this->api->url . $this->resource_url($p[$key]);
479af9 301
cc97ea 302       $this->api->add_content($this->api->output->button($p), $container);
T 303     }
304   }
479af9 305
24e219 306   /**
T 307    * Generate an absolute URL to the given resource within the current
308    * plugin directory
309    *
5c461b 310    * @param string $fn The file name
24e219 311    * @return string Absolute URL to the given resource
T 312    */
313   public function url($fn)
314   {
315       return $this->api->url . $this->resource_url($fn);
316   }
cc97ea 317
T 318   /**
319    * Make the given file name link into the plugin directory
5c461b 320    *
A 321    * @param string $fn Filename
cc97ea 322    */
eb6f19 323   private function resource_url($fn)
cc97ea 324   {
23a2ee 325     if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn))
cc97ea 326       return $this->ID . '/' . $fn;
T 327     else
328       return $fn;
329   }
715a1b 330
01acca 331   /**
T 332    * Provide path to the currently selected skin folder within the plugin directory
333    * with a fallback to the default skin folder.
334    *
335    * @return string Skin path relative to plugins directory
336    */
715a1b 337   public function local_skin_path()
01acca 338   {
0c2596 339     $rcmail = rcube::get_instance();
b2631b 340     foreach (array($rcmail->config->get('skin'), 'larry') as $skin) {
9f1652 341       $skin_path = 'skins/' . $skin;
TB 342       if (is_dir(realpath(slashify($this->home) . $skin_path)))
343         break;
344     }
345
01acca 346     return $skin_path;
T 347   }
cc97ea 348
T 349   /**
350    * Callback function for array_map
5c461b 351    *
A 352    * @param string $key Array key.
353    * @return string
cc97ea 354    */
T 355   private function label_map_callback($key)
356   {
357     return $this->ID.'.'.$key;
358   }
359
360 }