Mercurial > hg > rc2
annotate program/lib/Roundcube/rcube_plugin.php @ 19:b6a96bdd6b29
More cleaning up php8 Warnings/deprecations
| author | Charlie Root |
|---|---|
| date | Wed, 08 Oct 2025 08:50:44 -0400 |
| parents | dd5ed6ef69c9 |
| children |
| rev | line source |
|---|---|
| 0 | 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(); | |
|
17
dd5ed6ef69c9
Slowly cleaning up more php8 Warnings/deprecations
Charlie Root
parents:
5
diff
changeset
|
207 $messages = null; |
| 0 | 208 |
| 209 // Language aliases used to find localization in similar lang, see below | |
| 210 $aliases = array( | |
| 211 'de_CH' => 'de_DE', | |
| 212 'es_AR' => 'es_ES', | |
| 213 'fa_AF' => 'fa_IR', | |
| 214 'nl_BE' => 'nl_NL', | |
| 215 'pt_BR' => 'pt_PT', | |
| 216 'zh_CN' => 'zh_TW', | |
| 217 ); | |
| 218 | |
| 219 // use buffering to handle empty lines/spaces after closing PHP tag | |
| 220 ob_start(); | |
| 221 | |
| 222 foreach ($langs as $lng) { | |
| 223 $fpath = $locdir . $lng . '.inc'; | |
| 224 if (is_file($fpath) && is_readable($fpath)) { | |
| 225 include $fpath; | |
| 226 $texts = (array)$labels + (array)$messages + (array)$texts; | |
| 227 } | |
| 228 else if ($lng != 'en_US') { | |
| 229 // Find localization in similar language (#1488401) | |
| 230 $alias = null; | |
| 231 if (!empty($aliases[$lng])) { | |
| 232 $alias = $aliases[$lng]; | |
| 233 } | |
| 234 else if ($key = array_search($lng, $aliases)) { | |
| 235 $alias = $key; | |
| 236 } | |
| 237 | |
| 238 if (!empty($alias)) { | |
| 239 $fpath = $locdir . $alias . '.inc'; | |
| 240 if (is_file($fpath) && is_readable($fpath)) { | |
| 241 include $fpath; | |
| 242 $texts = (array)$labels + (array)$messages + (array)$texts; | |
| 243 } | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 ob_end_clean(); | |
| 249 | |
| 250 // prepend domain to text keys and add to the application texts repository | |
| 251 if (!empty($texts)) { | |
| 252 $add = array(); | |
| 253 foreach ($texts as $key => $value) { | |
| 254 $add[$domain.'.'.$key] = $value; | |
| 255 } | |
| 256 | |
| 257 $rcube = rcube::get_instance(); | |
| 258 $rcube->load_language($lang, $add); | |
| 259 | |
| 260 // add labels to client | |
| 261 if ($add2client && method_exists($rcube->output, 'add_label')) { | |
| 262 if (is_array($add2client)) { | |
| 263 $js_labels = array_map(array($this, 'label_map_callback'), $add2client); | |
| 264 } | |
| 265 else { | |
| 266 $js_labels = array_keys($add); | |
| 267 } | |
| 268 $rcube->output->add_label($js_labels); | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 /** | |
| 274 * Wrapper for add_label() adding the plugin ID as domain | |
| 275 */ | |
| 276 public function add_label() | |
| 277 { | |
| 278 $rcube = rcube::get_instance(); | |
| 279 | |
| 280 if (method_exists($rcube->output, 'add_label')) { | |
| 281 $args = func_get_args(); | |
| 282 if (count($args) == 1 && is_array($args[0])) { | |
| 283 $args = $args[0]; | |
| 284 } | |
| 285 | |
| 286 $args = array_map(array($this, 'label_map_callback'), $args); | |
| 287 $rcube->output->add_label($args); | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 /** | |
| 292 * Wrapper for rcube::gettext() adding the plugin ID as domain | |
| 293 * | |
| 294 * @param string $p Message identifier | |
| 295 * | |
| 296 * @return string Localized text | |
| 297 * @see rcube::gettext() | |
| 298 */ | |
| 299 public function gettext($p) | |
| 300 { | |
| 5 | 301 #rcube::write_log('lab',"gtxt: $p |".$this->ID."|"); |
| 0 | 302 return rcube::get_instance()->gettext($p, $this->ID); |
| 303 } | |
| 304 | |
| 305 /** | |
| 306 * Register this plugin to be responsible for a specific task | |
| 307 * | |
| 308 * @param string $task Task name (only characters [a-z0-9_-] are allowed) | |
| 309 */ | |
| 310 public function register_task($task) | |
| 311 { | |
| 312 if ($this->api->register_task($task, $this->ID)) { | |
| 313 $this->mytask = $task; | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 /** | |
| 318 * Register a handler for a specific client-request action | |
| 319 * | |
| 320 * The callback will be executed upon a request like /?_task=mail&_action=plugin.myaction | |
| 321 * | |
| 322 * @param string $action Action name (should be unique) | |
| 323 * @param mixed $callback Callback function as string | |
| 324 * or array with object reference and method name | |
| 325 */ | |
| 326 public function register_action($action, $callback) | |
| 327 { | |
| 328 $this->api->register_action($action, $this->ID, $callback, $this->mytask); | |
| 329 } | |
| 330 | |
| 331 /** | |
| 332 * Register a handler function for a template object | |
| 333 * | |
| 334 * When parsing a template for display, tags like <roundcube:object name="plugin.myobject" /> | |
| 335 * will be replaced by the return value if the registered callback function. | |
| 336 * | |
| 337 * @param string $name Object name (should be unique and start with 'plugin.') | |
| 338 * @param mixed $callback Callback function as string or array with object reference | |
| 339 * and method name | |
| 340 */ | |
| 341 public function register_handler($name, $callback) | |
| 342 { | |
| 343 $this->api->register_handler($name, $this->ID, $callback); | |
| 344 } | |
| 345 | |
| 346 /** | |
| 347 * Make this javascipt file available on the client | |
| 348 * | |
| 349 * @param string $fn File path; absolute or relative to the plugin directory | |
| 350 */ | |
| 351 public function include_script($fn) | |
| 352 { | |
| 353 $this->api->include_script($this->resource_url($fn)); | |
| 354 } | |
| 355 | |
| 356 /** | |
| 357 * Make this stylesheet available on the client | |
| 358 * | |
| 359 * @param string $fn File path; absolute or relative to the plugin directory | |
| 360 */ | |
| 361 public function include_stylesheet($fn) | |
| 362 { | |
| 363 $this->api->include_stylesheet($this->resource_url($fn)); | |
| 364 } | |
| 365 | |
| 366 /** | |
| 367 * Append a button to a certain container | |
| 368 * | |
| 369 * @param array $p Hash array with named parameters (as used in skin templates) | |
| 370 * @param string $container Container name where the buttons should be added to | |
| 371 * | |
| 372 * @see rcube_remplate::button() | |
| 373 */ | |
| 374 public function add_button($p, $container) | |
| 375 { | |
| 376 if ($this->api->output->type == 'html') { | |
| 377 // fix relative paths | |
| 378 foreach (array('imagepas', 'imageact', 'imagesel') as $key) { | |
| 19 | 379 if ($p[$key]??null) { |
| 0 | 380 $p[$key] = $this->api->url . $this->resource_url($p[$key]); |
| 381 } | |
| 382 } | |
| 383 | |
| 384 $this->api->add_content($this->api->output->button($p), $container); | |
| 385 } | |
| 386 } | |
| 387 | |
| 388 /** | |
| 389 * Generate an absolute URL to the given resource within the current | |
| 390 * plugin directory | |
| 391 * | |
| 392 * @param string $fn The file name | |
| 393 * | |
| 394 * @return string Absolute URL to the given resource | |
| 395 */ | |
| 396 public function url($fn) | |
| 397 { | |
| 398 return $this->api->url . $this->resource_url($fn); | |
| 399 } | |
| 400 | |
| 401 /** | |
| 402 * Make the given file name link into the plugin directory | |
| 403 * | |
| 404 * @param string $fn Filename | |
| 405 */ | |
| 406 private function resource_url($fn) | |
| 407 { | |
| 408 if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn)) { | |
| 409 return $this->ID . '/' . $fn; | |
| 410 } | |
| 411 else { | |
| 412 return $fn; | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 /** | |
| 417 * Provide path to the currently selected skin folder within the plugin directory | |
| 418 * with a fallback to the default skin folder. | |
| 419 * | |
| 420 * @return string Skin path relative to plugins directory | |
| 421 */ | |
| 422 public function local_skin_path() | |
| 423 { | |
| 424 $rcube = rcube::get_instance(); | |
| 425 $skins = array_keys((array)$rcube->output->skins); | |
| 426 if (empty($skins)) { | |
| 427 $skins = (array) $rcube->config->get('skin'); | |
| 428 } | |
| 429 foreach ($skins as $skin) { | |
| 430 $skin_path = 'skins/' . $skin; | |
| 431 if (is_dir(realpath(slashify($this->home) . $skin_path))) { | |
| 432 break; | |
| 433 } | |
| 434 } | |
| 435 | |
| 436 return $skin_path; | |
| 437 } | |
| 438 | |
| 439 /** | |
| 440 * Callback function for array_map | |
| 441 * | |
| 442 * @param string $key Array key. | |
| 443 * @return string | |
| 444 */ | |
| 445 private function label_map_callback($key) | |
| 446 { | |
| 447 if (strpos($key, $this->ID.'.') === 0) { | |
| 448 return $key; | |
| 449 } | |
| 450 | |
| 451 return $this->ID.'.'.$key; | |
| 452 } | |
| 453 } |
