golden hour
/home/doctorbruno/public_html/doctorbruno.info/taeionline/support/include
⬆️ Go Up
Upload
File/Folder
Size
Actions
.MANIFEST
194.97 KB
Del
OK
.htaccess
14 B
Del
OK
JSON.php
33.13 KB
Del
OK
PasswordHash.php
6.92 KB
Del
OK
Spyc.php
31.74 KB
Del
OK
UniversalClassLoader.php
8.61 KB
Del
OK
ajax.admin.php
7.29 KB
Del
OK
ajax.config.php
4.61 KB
Del
OK
ajax.content.php
9.76 KB
Del
OK
ajax.draft.php
13.03 KB
Del
OK
ajax.email.php
2.33 KB
Del
OK
ajax.export.php
1006 B
Del
OK
ajax.filter.php
874 B
Del
OK
ajax.forms.php
13.84 KB
Del
OK
ajax.i18n.php
5.1 KB
Del
OK
ajax.kbase.php
2.93 KB
Del
OK
ajax.note.php
2.05 KB
Del
OK
ajax.orgs.php
11.73 KB
Del
OK
ajax.plugins.php
2.15 KB
Del
OK
ajax.schedule.php
4.29 KB
Del
OK
ajax.search.php
12.72 KB
Del
OK
ajax.sequence.php
3.2 KB
Del
OK
ajax.staff.php
11.62 KB
Del
OK
ajax.tasks.php
33.87 KB
Del
OK
ajax.thread.php
8.81 KB
Del
OK
ajax.tickets.php
79.7 KB
Del
OK
ajax.tips.php
1.66 KB
Del
OK
ajax.upgrader.php
2.24 KB
Del
OK
ajax.users.php
18.33 KB
Del
OK
api.cron.php
1.06 KB
Del
OK
api.tickets.php
10.36 KB
Del
OK
class.2fa.php
7.76 KB
Del
OK
class.ajax.php
1.45 KB
Del
OK
class.api.php
15.31 KB
Del
OK
class.app.php
1.49 KB
Del
OK
class.attachment.php
6.95 KB
Del
OK
class.auth.php
50.73 KB
Del
OK
class.avatar.php
6.44 KB
Del
OK
class.banlist.php
2.58 KB
Del
OK
class.base32.php
4.07 KB
Del
OK
class.businesshours.php
7.08 KB
Del
OK
class.canned.php
9.05 KB
Del
OK
class.captcha.php
1.73 KB
Del
OK
class.category.php
11.14 KB
Del
OK
class.charset.php
3.41 KB
Del
OK
class.cli.php
9.48 KB
Del
OK
class.client.php
15.39 KB
Del
OK
class.collaborator.php
5.65 KB
Del
OK
class.company.php
2.65 KB
Del
OK
class.config.php
60.36 KB
Del
OK
class.controller.php
1.15 KB
Del
OK
class.cron.php
3.6 KB
Del
OK
class.crypto.php
18.92 KB
Del
OK
class.csrf.php
2.38 KB
Del
OK
class.dept.php
33.21 KB
Del
OK
class.dispatcher.php
7.12 KB
Del
OK
class.draft.php
6.23 KB
Del
OK
class.dynamic_forms.php
64.98 KB
Del
OK
class.email.php
49 KB
Del
OK
class.error.php
1.69 KB
Del
OK
class.export.php
32.92 KB
Del
OK
class.faq.php
15.05 KB
Del
OK
class.file.php
34.59 KB
Del
OK
class.filter.php
31.9 KB
Del
OK
class.filter_action.php
23.67 KB
Del
OK
class.format.php
44.3 KB
Del
OK
class.forms.php
195.58 KB
Del
OK
class.http.php
7.16 KB
Del
OK
class.i18n.php
24.28 KB
Del
OK
class.import.php
6.9 KB
Del
OK
class.json.php
2.71 KB
Del
OK
class.knowledgebase.php
5.8 KB
Del
OK
class.list.php
42 KB
Del
OK
class.lock.php
4.05 KB
Del
OK
class.log.php
1.55 KB
Del
OK
class.mail.php
35.76 KB
Del
OK
class.mailer.php
25.75 KB
Del
OK
class.mailfetch.php
9.72 KB
Del
OK
class.mailparse.php
30.99 KB
Del
OK
class.message.php
6.42 KB
Del
OK
class.migrater.php
5.2 KB
Del
OK
class.misc.php
7.5 KB
Del
OK
class.model.php
2.3 KB
Del
OK
class.nav.php
14.15 KB
Del
OK
class.note.php
2.39 KB
Del
OK
class.oauth2.php
4.04 KB
Del
OK
class.organization.php
22.45 KB
Del
OK
class.orm.php
120.9 KB
Del
OK
class.osticket.php
20.64 KB
Del
OK
class.ostsession.php
21.86 KB
Del
OK
class.page.php
10.59 KB
Del
OK
class.pagenate.php
5.53 KB
Del
OK
class.passwd.php
1.21 KB
Del
OK
class.pdf.php
3.83 KB
Del
OK
class.plugin.php
36.13 KB
Del
OK
class.priority.php
1.81 KB
Del
OK
class.queue.php
103.51 KB
Del
OK
class.report.php
11.76 KB
Del
OK
class.role.php
11.27 KB
Del
OK
class.schedule.php
46.28 KB
Del
OK
class.search.php
61.66 KB
Del
OK
class.sequence.php
7.27 KB
Del
OK
class.session.php
19.25 KB
Del
OK
class.setup.php
3.55 KB
Del
OK
class.signal.php
4.16 KB
Del
OK
class.sla.php
9.11 KB
Del
OK
class.staff.php
60.21 KB
Del
OK
class.task.php
56.21 KB
Del
OK
class.team.php
12.31 KB
Del
OK
class.template.php
23.45 KB
Del
OK
class.thread.php
108.96 KB
Del
OK
class.thread_actions.php
17.08 KB
Del
OK
class.ticket.php
167.39 KB
Del
OK
class.timezone.php
21.94 KB
Del
OK
class.topic.php
20.06 KB
Del
OK
class.translation.php
34.79 KB
Del
OK
class.upgrader.php
13.76 KB
Del
OK
class.user.php
43.4 KB
Del
OK
class.usersession.php
7.55 KB
Del
OK
class.util.php
10.07 KB
Del
OK
class.validator.php
12.94 KB
Del
OK
class.variable.php
11.93 KB
Del
OK
class.xml.php
3.23 KB
Del
OK
class.yaml.php
1.15 KB
Del
OK
cli
-
Del
OK
client
-
Del
OK
config
-
Del
OK
fpdf
-
Del
OK
htmLawed.php
53.53 KB
Del
OK
html2text.php
33.71 KB
Del
OK
i18n
-
Del
OK
index.php
37 B
Del
OK
laminas-mail
-
Del
OK
mpdf
-
Del
OK
mysqli.php
9.55 KB
Del
OK
ost-config.php
5.63 KB
Del
OK
ost-sampleconfig.php
6.24 KB
Del
OK
pear
-
Del
OK
plugins
-
Del
OK
staff
-
Del
OK
tnef_decoder.php
19.82 KB
Del
OK
upgrader
-
Del
OK
Edit: class.plugin.php
<?php require_once(INCLUDE_DIR.'/class.config.php'); /* * PluginConfig * * Base class for plugin configs * */ abstract class PluginConfig extends Config { var $table = CONFIG_TABLE; var $instance; var $form; var $_config = []; function __construct($namespace, $defaults=[]) { // Use parent constructor to place configurable information into the // central config table with $namespace parent::__construct($namespace, $defaults); // Cache decoded config $this->_config = []; foreach ($this->getOptions() as $name => $field) { if ($this->exists($name)) { $val = $this->get($name); $this->_config[$name] = $field->to_php($val); } elseif (($default = $field->get('default'))) $this->_config[$name] = $default; } } function getId() { if ($this->instance) return sprintf('p%di%d', $this->instance->getPluginId(), $this->instance->getId()); } function getName() { if ($this->instance) return $this->instance->getName(); } function get($key, $default=null) { if (isset($this->_config[$key])) return $this->_config[$key]; return parent::get($key, $default); } function getOptions() { return array(); } // getFields is same as getOptions but can be used downstream to filter // or modify fields based on settings function getFields() { return $this->getOptions(); } // Returns form options like title and notices as accepted by SimpleForm function getFormOptions() { return array(); } function getInfo() { return array_merge(parent::getInfo(), $this->_config); } function getInstance() { return $this->instance; } function setInstance(PluginInstance $i=null) { $this->instance = $i; } function hasCustomConfig() { return $this instanceof PluginCustomConfig; } /** * Retreive a Form instance for the configurable options offered in * ::getOptions */ function getForm($vars=[]) { if (!isset($this->form)) { $this->form = new SimpleForm($this->getFields(), null, $this->getFormOptions()); // set data if any if ($_SERVER['REQUEST_METHOD'] != 'POST') { // defaults + current info $this->form->data(array_merge($vars ?: [], $this->getInfo())); } elseif ($vars) { // set possible defaults $this->form->data($vars); } } return $this->form; } /** * store * * Used in the POST request of the configuration process. The * ::getForm() method should be used to retrieve a configuration form * for this plugin. That form should be submitted via a POST request, * and this method should be called in that request. The data from the * POST request will be interpreted and will adjust the configuration of * this field * * Parameters: * form - plugin confirm form * errors - (OUT array) receives validation errors of the parsed * configuration form * * returns (true | false) * */ function store(SimpleForm $form = null, &$errors=array()) { try { if ($this->hasCustomConfig()) return $this->saveConfig($form, $errors); $form = $form ?: $this->getForm(); if (($clean=$form->getClean()) && $this->pre_save($clean, $errors) && count($errors) === 0 && ($data=$form->to_db($clean))) return $this->updateAll($data); } catch (Throwable $t) { if (!isset($errors['err'])) $errors['err'] = $t->getMessage(); } return false; } /** * Pre-save hook to check configuration for errors (other than obvious * validation errors) prior to saving. Can be also used to encrypt the * data if necessary. * * Add an error to the errors list * or return boolean FALSE if the config commit should be aborted. */ function pre_save(&$config, &$errors) { return true; } /** * Remove all configuration for this plugin -- used when the plugin is * uninstalled / deleted. * Plugin */ function purge() { return $this->destroy(); } } /** * Interface: PluginCustomConfig * * Allows a plugin to specify custom configuration pages. If the * configuration cannot be suited by a single page, single form, then * the plugin can use the ::renderConfig() method to trigger * rendering the page, and use ::saveConfig() to trigger * validating and saving the custom configuration. */ interface PluginCustomConfig { function renderConfig(); function saveConfig(); } class PluginManager { const VERIFIED = 1; // Thumbs up const VERIFY_EXT_MISSING = 2; // PHP extension missing const VERIFY_FAILED = 3; // Bad signature data const VERIFY_ERROR = 4; // Unable to verify (unexpected error) const VERIFY_NO_KEY = 5; // Public key missing const VERIFY_DNS_PASS = 6; // DNS check passes, cannot verify sig static private $verify_domain = 'updates.osticket.com'; static private $plugin_info = array(); static private $plugin_list = array(); /** * boostrap * * Used to bootstrap the plugin subsystem and initialize all the plugins * currently enabled. */ function bootstrap() { foreach ($this->allInstalled() as $p) { if (!$p->isCompatible()) continue; // Init plugin even when disabled $p->init(); // If the plugin is active then boostrap active instances if ($p->isActive()) { foreach($p->getActiveInstances() as $i) $i->bootstrap(); } // Clear any side loaded config $p->config = null; } } /** * allInstalled * * Scans the plugin registry to find all installed and active plugins. * Those plugins are included, instanciated, and cached in a list. * * Returns: * Array<Plugin> a cached list of instanciated plugins for all installed * and active plugins */ static function allInstalled() { if (static::$plugin_list) return static::$plugin_list; foreach (Plugin::objects() as $p) { $a = $p->getImpl() ?: $p; static::$plugin_list[$p->getInstallPath()] = &$a; unset($a); } return static::$plugin_list; } static function getPluginByName($name, $active=false) { $sql = sprintf('SELECT * FROM %s WHERE name="%s"', PLUGIN_TABLE, $name); if ($active) $sql = sprintf('%s AND isactive = true', $sql); if (!($res = db_query($sql))) return false; $ht = db_fetch_array($res); return $ht['name']; } static function auditPlugin() { global $ost; if (!$ost || $ost->isUpgradePending()) return false; return self::getPluginByName('Help Desk Audit', true); } static function allActive() { $plugins = array(); foreach (static::allInstalled() as $p) if ($p instanceof Plugin && $p->isActive()) $plugins[] = $p; return $plugins; } static function throwException($errno, $errstr) { throw new RuntimeException($errstr); } /** * allInfos * * Scans the plugin folders for installed plugins. For each one, the * plugin.php file is included and the info array returned in added to * the list returned. * * Returns: * Information about all available plugins. The registry will have to be * queried to determine if the plugin is installed */ static function allInfos() { foreach (glob(INCLUDE_DIR . 'plugins/*', GLOB_NOSORT) as $p) { $is_phar = false; if (substr($p, strlen($p) - 5) == '.phar' && class_exists('Phar') && Phar::isValidPharFilename($p)) { try { // When public key is invalid, openssl throws a // 'supplied key param cannot be coerced into a public key' warning // and phar ignores sig verification. // We need to protect from that by catching the warning // Thanks, https://github.com/koto/phar-util set_error_handler(array('self', 'throwException')); $ph = new Phar($p); restore_error_handler(); // Verify the signature $ph->getSignature(); $p = 'phar://' . $p; $is_phar = true; } catch (UnexpectedValueException $e) { // Cannot find signature file } catch (RuntimeException $e) { // Invalid signature file } } if (!is_file($p . '/plugin.php')) // Invalid plugin -- must define "/plugin.php" continue; // Cache the info into static::$plugin_info static::getInfoForPath($p, $is_phar); } return static::$plugin_info; } static function getInfoForPath($path, $is_phar=false) { static $defaults = array( 'include' => 'include/', 'stream' => false, ); $install_path = str_replace(INCLUDE_DIR, '', $path); $install_path = str_replace('phar://', '', $install_path); if ($is_phar && substr($path, 0, 7) != 'phar://') $path = 'phar://' . $path; if (!isset(static::$plugin_info[$install_path])) { // plugin.php is require to return an array of informaiton about // the plugin. if (!file_exists($path . '/plugin.php')) return false; $info = array_merge($defaults, (@include $path . '/plugin.php')); $info['install_path'] = $install_path; // XXX: Ensure 'id' key isset static::$plugin_info[$install_path] = $info; } return static::$plugin_info[$install_path]; } static function getInstance($path) { static $instances = array(); if (!isset($instances[$path]) && ($ps = static::allInstalled()) && ($ht = $ps[$path])) { $info = static::getInfoForPath($path); // $ht may be the plugin instance if ($ht instanceof Plugin) return $ht; // Usually this happens when the plugin is being enabled list($path, $class) = explode(':', $info['plugin']); if (!$class) $class = $path; else require_once(INCLUDE_DIR . $info['install_path'] . '/' . $path); $instances[$path] = new $class($ht['id']); } return $instances[$path]; } static function lookup($id) { if (!($p=Plugin::lookup( (int) $id))) return null; return $p->getImpl() ?: $p; } /** * install * * Used to install a plugin that is in-place on the filesystem, but not * registered in the plugin registry -- the %plugin table. */ function install($path) { // Fixup $path to ensure we are only installing from the plugin dir $path = 'plugins/' . basename($path); $is_phar = substr($path, strlen($path) - 5) == '.phar'; if (!($info = $this->getInfoForPath(INCLUDE_DIR . $path, $is_phar))) return false; if (isset($info['ost_version']) && !self::isCompatible($info['ost_version'])) return false; $vars = [ 'name' => $info['name'], 'isphar' => $is_phar, 'version' => $info['version'] ?: '', 'install_path' => $path ]; $p = Plugin::create($vars); if ($p->save(true)) { // TODO: Trigger enable() for the plugin (for now) $p->getImpl()->enable(); static::clearCache(); return $p; } } static function clearCache() { static::$plugin_list = array(); static::$plugin_info = array(); } /** * Function: isCompatible * * Check if provided plugin (info) is compatible with the current version * of osTicket. * * Compatibility is only checked aganist osTicket major version by * default because full version is only available on packaged * versions and not git repo clones. * */ static function isCompatible($version, $ost_version=null) { // Assume compatible if specific osTicket version is not required. if (!$version) return true; $matches = array(); if (!$ost_version && preg_match_all('/\./', $version, $matches, PREG_OFFSET_CAPTURE) == 2) $version = substr($version, 0, $matches[0][1][1]); return version_compare($ost_version ?: MAJOR_VERSION, $version, '>='); } /** * Function: isVerified * * This will help verify the content, integrity, oversight, and origin * of plugins, language packs and other modules distributed for * osTicket. * * This idea is that the signature of the PHAR file will be registered * in DNS, for instance, * `7afc8bf80b0555bed88823306744258d6030f0d9.updates.osticket.com`, for * a PHAR file with a SHA1 signature of * `7afc8bf80b0555bed88823306744258d6030f0d9 `, which will resolve to a * string like the following: * ``` * "v=1; i=storage:s3; s=MEUCIFw6A489eX4Oq17BflxCZ8+MH6miNjtcpScUoKDjmb * lsAiEAjiBo9FzYtV3WQtW6sbhPlJXcoPpDfYyQB+BFVBMps4c=; V=0.1;" * ``` * Which is a simple semicolon separated key-value pair string with the * following keys * * Key | Description * :----|:--------------------------------------------------- * v | Algorithm version * i | Plugin 'id' registered in plugin.php['id'] * V | Plugin 'version' registered in plugin.php['version'] * s | OpenSSL signature of the PHAR SHA1 signature using a * | private key (specified on the command line) * * The public key, which will be distributed with osTicket, can be used * to verify the signature of the PHAR file from the data received from * DNS. * * Parameters: * $phar - (string) filename of phar file to verify * * Returns: * (int) - * PluginManager::VERIFIED upon success * PluginManager::VERIFY_DNS_PASS if found in DNS but cannot verify sig * PluginManager::VERIFY_NO_KEY if public key not found in include/plugins * PluginManager::VERIFY_FAILED if the plugin fails validation * PluginManager::VERIFY_EXT_MISSING if a PHP extension is required * Plugin::VERIFY_ERROR if an unexpected error occurred */ static function isVerified($phar) { static $pubkey = null; if (!class_exists('Phar') || !extension_loaded('openssl')) return self::VERIFY_EXT_MISSING; elseif (!file_exists(INCLUDE_DIR . '/plugins/updates.pem')) return self::VERIFY_NO_KEY; if (!isset($pubkey)) { $pubkey = openssl_pkey_get_public( file_get_contents(INCLUDE_DIR . 'plugins/updates.pem')); } if (!$pubkey) { return self::VERIFY_ERROR; } $P = new Phar($phar); $sig = $P->getSignature(); $info = array(); $ignored = null; if ($r = dns_get_record($sig['hash'].'.'.self::$verify_domain.'.', DNS_TXT)) { foreach ($r as $rec) { foreach (explode(';', $rec['txt']) as $kv) { list($k, $v) = explode('=', trim($kv)); $info[$k] = trim($v); } if ($info['v'] && $info['s']) break; } } if (is_array($info) && isset($info['v'])) { switch ($info['v']) { case '1': if (!($signature = base64_decode($info['s']))) return self::VERIFY_FAILED; elseif (!function_exists('openssl_verify')) return self::VERIFY_DNS_PASS; $codes = array( -1 => self::VERIFY_ERROR, 0 => self::VERIFY_FAILED, 1 => self::VERIFIED, ); $result = openssl_verify($sig['hash'], $signature, $pubkey, OPENSSL_ALGO_SHA1); return $codes[$result]; } } return self::VERIFY_FAILED; } static function showVerificationBadge($phar) { switch (self::isVerified($phar)) { case self::VERIFIED: $show_lock = true; case self::VERIFY_DNS_PASS: ?> <span class="label label-verified" title="<?php if ($show_lock) echo sprintf(__('Verified by %s'), self::$verify_domain); ?>"> <?php if ($show_lock) echo '<i class="icon icon-lock"></i>'; ?> <?php echo $show_lock ? __('Verified') : __('Registered'); ?></span> <?php break; case self::VERIFY_FAILED: ?> <span class="label label-danger" title="<?php echo __('The originator of this extension cannot be verified'); ?>"><i class="icon icon-warning-sign"></i></span> <?php break; } } } class Plugin extends VerySimpleModel { static $meta = array( 'table' => PLUGIN_TABLE, 'ordering' => array('name'), 'pk' => array('id'), 'joins' => array( 'instances' => array( 'reverse' => 'PluginInstance.plugin', ), ), ); /** * Configuration manager for the plugin. Should be the name of a class * that inherits from PluginConfig. This is abstract and must be defined * by the plugin subclass. */ var $config_class = null; // plugin subclass impl var $_impl; // config instance var $config; // active instances var $active_instances; // var $info; var $form; var $defunct; /** * init * * Used to initialize the plugin as part of bootstrapping process */ function init() { //noop } function __onload() { $this->info = PluginManager::getInfoForPath(INCLUDE_DIR.$this->ht['install_path'], $this->isPhar()); // Auto upgrade / downgrade plugins on-load - if we have version // mismatch. See upgrade routine for more information if ($this->info['version'] && $this->getVersion() != $this->info['verion']) $this->upgrade(); } /* * useModalConfig * * Plugin instance can be configured via a dialog modal or inline page. * A modal is suitable for plugins with short or no configuration, * whereas inline page caters for more complex / larger configuration */ function useModalConfig() { return false; } /* * canAddInstance * * Multi-instance plugins can add unlimited instances, otherwise only * one plugin instance is allowed. * */ function canAddInstance() { // No instances yet if (!$this->getNumInstances()) return true; // We have at least one instance already. if (!$this->isMultiInstance()) return false; // Some Plugins DO Not or SHOULDN'T support multiple instances due // design issues or simply because of the fact that it doesn't make // sense to do so. // TODO: The Black List is to be removed down the road once plugins // are forced to declare core osTicket version and if it supports // multiple instances. $blackList =[ // 2FA Plugin up to v0.3 cannot handle multiple instances 'Auth2FAPlugin' => 0.3, // It doesn't make sense for Audit Plugin to have // multiple instances 'AuditPlugin' => '*', // File storage plugins don't currently support multiple instances 'S3StoragePlugin' => '*', 'FsStoragePlugin' => '*', ]; foreach ($blackList as $c => $v) { if (is_a($this, $c) && ($v == '*' || $this->getVersion() <= $v)) return false; } // Yes, let's make instances - Genesis 9:7 return true; } /* * Get Namespace of the instance otherwise return plugin's namespace * */ function getNamespace() { if (($c=$this->getConfig()) && ($i=$c->getInstance())) return $i->getNamespace(); return sprintf('plugin.%d', $this->getId()); } /* * * isMultiInstance * * Indicates if the plugin supports multiple instances * Default is true unless overwritten downstream. * */ function isMultiInstance() { return true; } /* * getNewInstanceOptions * * Plugin can return new instance options if it supports different types * of instances. */ public function getNewInstanceOptions() { return false; } /* * getNewInstanceDefaults * * Plugin can return new instance options if it supports different types * of instances. */ public function getNewInstanceDefaults($options) { return []; } /* * getImpl * * Returns plugin subclass impl if any */ function getImpl() { if (!isset($this->_impl) && $this->info['plugin']) { // TODO: if if the class is already cached in PluginManager list($file, $class) = explode(':', $this->info['plugin']); $path = INCLUDE_DIR . $this->getInstallPath(); if ($this->isPhar()) $path = 'phar://' . $path; $file = "$path/$file"; if (file_exists($file)) { // Register possible plugin namespace before init osTicket::register_namespace(dirname($file).'/lib'); @include_once $file; if (class_exists($class)) $this->_impl = $class::lookup($this->getId()); } } $this->defunct = !isset($this->_impl); return $this->_impl; } function getId() { return $this->get('id'); } function getName() { return $this->__($this->get('name', $this->info['name'])); } function isActive() { return ($this->get('isactive')); } function isPhar() { return $this->get('isphar'); } function getVersion() { return $this->get('version', $this->info['version']); } function getosTicketVersion() { return $this->info['ost_version']; } function getAuthor() { return $this->info['author']; } function getInstallDate() { return $this->get('installed'); } function getInstallPath() { return $this->get('install_path'); } function getNotes() { return $this->get('notes') ?: $this->info['description']; } function getStatus() { return __($this->isActive() ? 'Active' : 'Disabled'); } function getNumInstances() { return $this->getInstances()->count(); } function getInstances() { return $this->instances; } function getActiveInstances() { if (!isset($this->active_instances)) { $instances = clone $this->instances; $this->active_instances = $instances->filter( ['flags__hasbit' => PluginInstance::FLAG_ENABLED]); } return $this->active_instances; } function getInstance($id) { return $this->instances->findFirst(['id' => (int) $id]); } function getIncludePath() { return realpath(INCLUDE_DIR . $this->info['install_path'] . '/' . $this->info['include_path']) . '/'; } function isDefunct() { if (!isset($this->defunct)) { $this->defunct = false; if (!$this->info['plugin'] || !$this->getImpl()) $this->defunct = true; } return $this->defunct; } function isCompatible() { if (!($v=$this->getosTicketVersion())) return true; return PluginManager::isCompatible($v); } function update($vars, &$errors) { $this->isactive = $vars['isactive']; $this->notes = $vars['notes']; return $this->save(true); } function getConfigClass() { return $this->config_class; } function getConfig(PluginInstance $instance = null, $defaults = []) { if ((!isset($this->config) || $instance) && ($class=$this->getConfigClass())) { // We cache instance config for side loading purposes on // plugin instantace boostrapping if ($instance) // Config for an instance. $this->config = $instance->getConfig($defaults); else // New instance config $this->config = new $class(null, $defaults); } return $this->config; } function getConfigForm($vars=null) { if (!isset($this->form) || $vars) $this->form = $this->getConfig(null, $vars)->getForm($vars); return $this->form; } function isInstanceUnique($vars, $id=0) { $criteria = array(); // Make sure name is unique $criteria = ['name' => $vars['name']]; $i = $this->instances->findFirst($criteria); return !($i && $i->getId() != $id); } function addInstance($vars, &$errors) { $form = $this->getConfigForm($vars); if (!$vars['name']) $errors['name']= __('Name Required'); elseif (!$this->isInstanceUnique($vars)) $errors['name']= __('Name already in use'); if ($form->isValid() && !$errors) { // Basic info required to create instance $info = [ 'name' => $vars['name'], 'plugin_id' => $this->getId(), 'flags' => 0]; if (($i=PluginInstance::create($info)) && $i->save()) { // clear temp config $this->config = null; // update newly created instance... $i->update($vars, $errors); return $i; } } return false; } function delete() { foreach ($this->getInstances() as $i) $i->delete(); parent::delete(); } /** * upgrade * * Plugins can implement upgrade / downgrade process downsteam as needed. * */ function upgrade(&$errors=[]) { if ($this->pre_upgrade($errors) === false) return false; // For now we're just updating the version if we have a mismatch // The true version is what is packaged with the plugin if ($this->getVersion() != $this->info['version']) $this->version = $this->info['version']; $this->save(); return true; } /** * pre_upgrade * * Hook function to veto the upgrade request. Return boolean * FALSE if the upgrade operation should be aborted. */ function pre_upgrade(&$errors) { return true; } /** * uninstall * * Removes the plugin from the plugin registry. The files remain on the * filesystem which would allow the plugin to be reinstalled. The * configuration for the plugin is also removed. If the plugin is * reinstalled, it will have to be reconfigured. */ function uninstall(&$errors) { if ($this->pre_uninstall($errors) === false) return false; $this->delete(); PluginManager::clearCache(); return true; } /** * pre_uninstall * * Hook function to veto the uninstallation request. Return boolean * FALSE if the uninstall operation should be aborted. */ function pre_uninstall(&$errors) { return true; } function enable() { return true; } /** * Function: __ * * Translate a single string (without plural alternatives) from the * langauge pack installed in this plugin. The domain is auto-configured * and detected from the plugin install path. */ function __($msgid) { if (!isset($this->translation)) { // Detect the domain from the plugin install-path $groups = array(); preg_match('`plugins/(\w+)(?:.phar)?`', $this->getInstallPath(), $groups); $domain = $groups[1]; if (!$domain) return $msgid; $this->translation = self::translate($domain); } list($__, $_N) = $this->translation; return $__($msgid); } // Domain-specific translations (plugins) /** * Function: translate * * Convenience function to setup translation functions for other * domains. This is of greatest benefit for plugins. This will return * two functions to perform the translations. The first will translate a * single string, the second will translate a plural string. * * Parameters: * $domain - (string) text domain. The location of the MO.php file * will be (path)/LC_MESSAGES/(locale)/(domain).mo.php. The (path) * can be set via the $options parameter * $options - (array<string:mixed>) Extra options for the setup * "path" - (string) path to the folder containing the LC_MESSAGES * folder. The (locale) setting is set externally respective to * the user. If this is not set, the directory of the caller is * assumed, plus '/i18n'. This is geared for plugins to be * built with i18n content inside the '/i18n/' folder. * * Returns: * Translation utility functions which mimic the __() and _N() * functions. Note that two functions are returned. Capture them with a * PHP list() construct. * * Caveats: * When desiging plugins which might be installed in versions of * osTicket which don't provide this function, use this compatibility * interface: * * // Provide compatibility function for versions of osTicket prior to * // translation support (v1.9.4) * function translate($domain) { * if (!method_exists('Plugin', 'translate')) { * return array( * function($x) { return $x; }, * function($x, $y, $n) { return $n != 1 ? $y : $x; }, * ); * } * return Plugin::translate($domain); * } */ static function translate($domain, $options=array()) { // Configure the path for the domain. If no $path = @$options['path']; if (!$path) { # Fetch the working path of the caller $bt = debug_backtrace(false); $path = dirname($bt[0]["file"]) . '/i18n'; } $path = rtrim($path, '/') . '/'; $D = TextDomain::lookup($domain); $D->setPath($path); $trans = $D->getTranslation(); return array( // __() function($msgid) use ($trans) { return $trans->translate($msgid); }, // _N() function($singular, $plural, $n) use ($trans) { return $trans->ngettext($singular, $plural, $n); }, ); } static function create($vars=false) { $p = new Static($vars); $p->installed = SqlFunction::NOW(); return $p; } } /** * Represents an instance of a plugin * */ class PluginInstance extends VerySimpleModel { static $meta = array( 'table' => PLUGIN_INSTANCE_TABLE, 'pk' => array('id'), 'ordering' => array('name'), 'joins' => array( 'plugin' => array( 'null' => false, 'constraint' => array('plugin_id' => 'Plugin.id'), ), ), ); // Config class that plugin can set. private $config_class = null; // Plugin Config for the instance var $_config; var $_form; var $_data; const FLAG_ENABLED = 0x0001; protected function hasFlag($flag) { return ($this->get('flags') & $flag) !== 0; } protected function clearFlag($flag) { return $this->set('flags', $this->get('flags') & ~$flag); } protected function setFlag($flag, $val) { if ($val) $this->flags |= $flag; else $this->flags &= ~$flag; } function getId() { return $this->get('id'); } function getName() { return $this->get('name'); } function getCreateDate() { return $this->get('created'); } function getUpdateDate() { return $this->get('updated'); } function getPluginId() { return $this->plugin_id; } function getPlugin() { return $this->plugin->getImpl(); } function isEnabled() { return $this->hasFlag(self::FLAG_ENABLED); } function setStatus($status) { $this->setFlag(self::FLAG_ENABLED, $status); } function setConfigClass($class) { $this->config_class = $class; // Clear current config so it can be reloaded $this->_config = null; } function getConfigClass() { return $this->config_class ?: $this->getPlugin()->getConfigClass(); } function getConfig($defaults=[]) { $class = $this->getConfigClass(); if (!isset($this->_config) && $class) { $this->_config = new $class($this->getNamespace(), $defaults); $this->_config->setInstance($this); } return $this->_config; } function getForm($vars=null) { if (!isset($this->_form) || $vars) $this->_form = $this->getConfig()->getForm($vars); return $this->_form; } function getSignature() { // get Config $config = $this->getConfiguration() ?: []; // Key sort to normalize config - key order matters with md5 ksort($config); // Json encode and md5 return md5(json_encode($config)); } function getNamespace() { return sprintf('plugin.%d.instance.%d', $this->getPluginId(), $this->getId() ?: 0); } function getConfiguration() { return $this->getConfig()->getInfo(); } function saveConfiguration($form, &$errors) { return $this->getConfig()->store($form, $errors); } function getInfo() { $ht = array_intersect_key($this->ht, array_flip(['name', 'notes'])); $ht['isactive'] = $this->isEnabled() ? 1 : 0; return $ht; } function isNameUnique($name) { return $this->plugin->isInstanceUnique(['name' => Format::htmlchars($name)], $this->getId()); } function update($vars, &$errors) { if (!$vars['name']) $errors['name'] = __('Name Required'); elseif (!$this->isNameUnique($vars['name'])) $errors['name'] = __('Name already in-use'); $form = $this->getForm($vars); if ($form->isValid() && $this->saveConfiguration($form, $errors) && !$errors) { $this->setFlag(self::FLAG_ENABLED, ($vars['isactive'])); $this->name = Format::htmlchars($vars['name']); $this->notes = Format::sanitize($vars['notes']); $this->updated = SqlFunction::NOW(); return $this->save(); } return false; } /** * boostrap plugin instance. * */ function bootstrap() { if ($this->isEnabled() && ($plugin = $this->getPlugin()) // Side load this instance config && ($plugin->getConfig($this))) return $plugin->bootstrap(); } function delete() { $this->getConfig()->purge(); parent::delete(); } static function create($vars=false) { $i = new Static($vars); $i->created = SqlFunction::NOW(); return $i; } } class DefunctPlugin extends Plugin { function bootstrap() {} function enable() { return false; } } ?>
Save