diff --git a/application/config/plugins.php b/application/config/plugins.php index a130e0c2b..181850f7a 100644 --- a/application/config/plugins.php +++ b/application/config/plugins.php @@ -7,8 +7,13 @@ | Plugins Directory |-------------------------------------------------------------------------- | -| Set plugin directory, DO NOT CHANGE! +| Where are the plugins kept? | +| Default: FCPATH . 'plugins/' (/plugins/) */ +// Use plugin_path instead of plugin_dir because that's what is used in +// Plugins_lib.php of upstream. Using 'plugin_dir' is actually a bug in upstream. +$config['plugin_path'] = APPPATH . 'plugins/'; -$config['plugins_dir'] = APPPATH . 'plugins/'; +require_once( APPPATH . 'libraries/abstract.plugins.php' ); +require_once( APPPATH . 'libraries/trait.plugins.php' ); diff --git a/application/controllers/Daemon.php b/application/controllers/Daemon.php index 9c41d0f1f..ac929b2b8 100644 --- a/application/controllers/Daemon.php +++ b/application/controllers/Daemon.php @@ -30,7 +30,7 @@ function __construct() // Commented this for allow access from other machine // if($_SERVER['REMOTE_ADDR']!='127.0.0.1') exit("Access Denied."); parent::__construct(); - $this->load->library('Plugins'); + $this->load->library('Plugins_lib_kalkun'); $this->load->database(); } @@ -63,7 +63,7 @@ function message_routine() if ( ! $is_spam) { // hook for incoming message (before ownership) - $status = do_action('message.incoming.before', $tmp_message); + $status = do_action_kalkun('message.incoming.before', $tmp_message); // message deleted, do not process later part if (isset($status) && $status === 'break') @@ -80,7 +80,7 @@ function message_routine() { // hook for incoming message (after ownership) $tmp_message->msg_user = $msg_user; - $status = do_action('message.incoming.after', $tmp_message); + $status = do_action_kalkun('message.incoming.after', $tmp_message); // message deleted, do not process later part if (isset($status) && $status === 'break') diff --git a/application/controllers/Install.php b/application/controllers/Install.php index 0eac1cb94..ec9e602ad 100644 --- a/application/controllers/Install.php +++ b/application/controllers/Install.php @@ -268,6 +268,16 @@ function _upgrade() } } + // Update SQL schema to version 0.8.3 + if ( ! $this->Kalkun_model->plugins_table_has_status_column()) + { + $error = $this->_execute_kalkun_sql_file('upgrade_kalkun_0.8.3.sql'); + if ($error !== 0) + { + return $error; + } + } + // Update b8 table from v2 (of b8 0.5) to v3 schema (of b8 0.7) $b8_db_version = NULL; if ($this->db->field_exists('count', 'b8_wordlist')) diff --git a/application/controllers/Messages.php b/application/controllers/Messages.php index c5f03745f..e08473ea6 100644 --- a/application/controllers/Messages.php +++ b/application/controllers/Messages.php @@ -37,7 +37,7 @@ function __construct() $param['uid'] = $this->session->userdata('id_user'); $this->load->model('Phonebook_model'); - $this->load->library('Plugins'); + $this->load->library('Plugins_lib_kalkun'); } // -------------------------------------------------------------------- @@ -498,10 +498,10 @@ function compose_process() // hook for outgoing message if (isset($dest)) { - $dest = do_action('message.outgoing', $dest); - $sms = do_action('message.outgoing_all', $data); + $dest = do_action_kalkun('message.outgoing', $dest); + $sms = do_action_kalkun('message.outgoing_all', $data); - $dest_data = do_action('message.outgoing_dest_data', array($dest, $data)); + $dest_data = do_action_kalkun('message.outgoing_dest_data', array($dest, $data)); if (sizeof($dest_data) === 2) { $dest = $dest_data[0]; diff --git a/application/controllers/Phonebook.php b/application/controllers/Phonebook.php index 5bf70e996..03c768fc5 100644 --- a/application/controllers/Phonebook.php +++ b/application/controllers/Phonebook.php @@ -29,7 +29,7 @@ function __construct() { parent::__construct(); $this->load->model('Phonebook_model'); - $this->load->library('Plugins'); + $this->load->library('Plugins_lib_kalkun'); } // -------------------------------------------------------------------- @@ -476,7 +476,7 @@ function get_phonebook($type = NULL) } // hook for contact get - $contact = do_action('phonebook.contact.get'); + $contact = do_action_kalkun('phonebook.contact.get'); if (empty($contact)) { $contact = array(); diff --git a/application/controllers/Pluginss.php b/application/controllers/Pluginss.php index 1e0b5e405..a9026b774 100644 --- a/application/controllers/Pluginss.php +++ b/application/controllers/Pluginss.php @@ -36,8 +36,12 @@ function __construct() redirect('/'); } - $this->load->library('Plugins'); - $this->load->model('Plugin_model'); + $this->load->library('Plugins_lib_kalkun'); + $this->load->model('Plugins_kalkun_model'); + + $this->plugins_lib_kalkun->restore_orphaned_plugins(); + $this->plugins_lib_kalkun->update_all_plugin_headers(); + } // -------------------------------------------------------------------- @@ -59,47 +63,27 @@ function index($type = 'installed') if ($type === 'installed') { $data['title'] .= ' - '.tr_raw('Installed', 'Plural'); - $data['plugins'] = $this->Plugin_model->get_plugins()->result_array(); - foreach ($data['plugins'] as $key => $plugin) + foreach ($this->Plugins_kalkun_model->get_plugins() as $key => $plugin) { - $data['plugins'][$key]['plugin_controller_has_index'] = $this->_plugin_controller_has_index($plugin['plugin_system_name']); + if (intval($plugin->status) === 1) + { + $data['plugins'][$key] = $plugin; + $data['plugins'][$key]->controller_has_index = $this->_plugin_controller_has_index($plugin->system_name); + } } } else { $data['title'] .= ' - '.tr_raw('Available', 'Plural'); - $plugins = $this->plugins->print_plugins(); - $no = 0; - - if ( ! empty($plugins)) + foreach ($this->Plugins_kalkun_model->get_plugins() as $key => $plugin) { - // do cleanup array key - foreach ($plugins as $key => $tmp) - { - $this->plugins->get_plugin_headers($key); - $new_plugin[$no] = array_merge ( - array ('plugin_system_name' => $key), - $this->plugins->plugin_info($key) - ); - $no++; - } - $installed = $this->Plugin_model->get_plugins()->result_array(); - - foreach ($new_plugin as $key => $tmp) + if (intval($plugin->status) !== 1) { - foreach ($installed as $tmp2) - { - if (in_array($tmp['plugin_system_name'], $tmp2)) - { - unset($new_plugin[$key]); - } - } + $data['plugins'][$key] = $plugin; } - $result = $new_plugin; - uasort($result, array($this, '_plugins_cmp_plugin_name')); - $data['plugins'] = $result; } } + uasort($data['plugins'], array($this, '_plugins_cmp_plugin_name')); $this->load->view('main/layout', $data); } @@ -114,7 +98,7 @@ function index($type = 'installed') */ function install($plugin_name) { - $this->plugins->activate_plugin($plugin_name); + $this->plugins_lib_kalkun->enable_plugin($plugin_name); $this->session->set_flashdata('notif', tr_raw('Plugin {0} installed successfully.', NULL, $plugin_name)); redirect('pluginss'); } @@ -130,51 +114,19 @@ function install($plugin_name) */ function uninstall($plugin_name) { - $this->plugins->deactivate_plugin($plugin_name); + $this->plugins_lib_kalkun->disable_plugin($plugin_name); $this->session->set_flashdata('notif', tr_raw('Plugin {0} uninstalled successfully.', NULL, $plugin_name)); redirect('pluginss'); } // -------------------------------------------------------------------- - /** - * Activate - * - * Activated a plugin - * - * @access public - */ - function activate($plugin_name) - { - $data = array('plugin_status' => 'true'); - $this->db->where('plugin_name', $plugin_name); - $this->db->update('plugin', $data); - } - - // -------------------------------------------------------------------- - - /** - * Deactivate - * - * Deactivated a plugin - * - * @access public - */ - function deactivate($plugin_name) - { - $data = array('plugin_status' => 'false'); - $this->db->where('plugin_name', $plugin_name); - $this->db->update('plugin', $data); - } - - // -------------------------------------------------------------------- - /** * Callback function used to order the array of plugins by plugin name */ function _plugins_cmp_plugin_name($p1, $p2) { - return strcasecmp ($p1['plugin_name'], $p2['plugin_name']); + return strcasecmp ($p1->name, $p2->name); } // -------------------------------------------------------------------- diff --git a/application/helpers/plugin_helper.php b/application/helpers/plugin_helper.php new file mode 100755 index 000000000..1ce5aff2c --- /dev/null +++ b/application/helpers/plugin_helper.php @@ -0,0 +1,421 @@ +update_all_plugin_headers(); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('update_plugin_headers')) +{ + /** + * Shortcut to Plugins_lib::update_plugin_headers() + * + * Updates the plugin headers for a specified plugin based on the plugins .php file comments + * + * @param string $plugin Plugin system name + * + * @since 0.1.0 + * @return bool + */ + function update_plugin_headers( $plugin ) + { + return Plugins_lib::$instance->update_plugin_headers( $plugin ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('install_plugin')) +{ + /** + * Shortcut to Plugins_lib::install_plugin() + * + * Executes whatevers in the plugins install method + * + * @param string $plugin Plugin system name + * + * @since 0.1.0 + * @return bool + */ + function install_plugin( $plugin, $data = NULL ) + { + return Plugins_lib::$instance->install_plugin( $plugin, $data ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('enable_plugin')) +{ + /** + * Shortcut to Plugins_lib::enable_plugin() + * + * Enable a specified plugin by setting the database status value to 1 + * + * @param string $plugin Plugin system name + * @param mixed $data Any data that should be handed down to the plugins activation method (optional) + * + * @since 0.1.0 + * @return bool + */ + function enable_plugin( $plugin, $data = NULL ) + { + return Plugins_lib::$instance->enable_plugin( $plugin, $data ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('disable_plugin')) +{ + /** + * Shortcut to Plugins_lib::disable_plugin() + * + * Disable a specified plugin by setting the database status value to 0 + * + * @param string $plugin Plugin system name + * @param mixed $data Any data that should be handed down to the plugins deactivate method (optional) + * + * @since 0.1.0 + * @return bool + */ + function disable_plugin( $plugin, $data = NULL ) + { + return Plugins_lib::$instance->disable_plugin( $plugin, $data ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('plugin_details')) +{ + /** + * Shortcut to Plugins_lib::plugin_details() + * + * Return the details of a plugin from the plugins database table + * + * @param string $plugin Plugin system name + * + * @since 0.1.0 + * @return array + */ + function plugin_details( $plugin ) + { + return Plugins_lib::$instance->plugin_details( $plugin ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('get_messages')) +{ + /** + * Shortcut to Plugins_lib::get_messages() + * + * Gets all the plugin messages thus far (errors, debug messages, warnings) + * + * @param string $type Specific type to retrieve, if NULL, all are returned + * + * @since 0.1.0 + * @return array + */ + function get_messages( $type = NULL ) + { + return Plugins_lib::$instance->get_messages( $type ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('print_messages')) +{ + /** + * Shortcut to Plugins_lib::print_messages() + * + * Displays all the plugin messages thus far (errors, debug messages, warnings) + * + * @param string $type Specific type to retrieve, if NULL, all are printed + * + * @since 0.1.0 + * @return array + */ + function print_messages( $type = NULL ) + { + return Plugins_lib::$instance->print_messages( $type ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('get_orphaned_plugins')) +{ + /** + * Shortcut to Plugins_lib::get_orphaned_plugins() + * + * See if there are any plugins in the plugins directory that arent in the database + * + * @since 0.1.0 + * @return array + */ + function get_orphaned_plugins() + { + return Plugins_lib::$instance->get_orphaned_plugins(); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('add_action')) +{ + /** + * Shortcut to Plugins_lib::add_action() + * + * Add an action - a function that will fire off when a tag/action is executed (NOT + * the same as add_filter - which will return a value + * + * @param string $tag Tag/Action thats being executed + * @param string|array $function Either a single function (string), or a class and method (array) + * @param int $priority Priority of this action + * + * @since 0.1.0 + * @return boolean + */ + function add_action( $tag, $function, $priority = 10 ) + { + return Plugins_lib::$instance->add_action( $tag, $function, $priority ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('add_filter')) +{ + /** + * Shortcut to Plugins_lib::add_filter() + * + * Add a filter - a function that can be used to effect/parse/filter out some content (NOT + * the same as add_action - which will just fire off a function + * + * @param string $tag Tag/Action thats being executed + * @param string|array $function Either a single function (string), or a class and method (array) + * @param int $priority Priority of this action + * + * @since 0.1.0 + * @return boolean + */ + function add_filter( $tag, $function, $priority = 10 ) + { + return Plugins_lib::$instance->add_filter( $tag, $function, $priority ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('get_actions')) +{ + /** + * Shortcut to Plugins_lib::get_actions() + * + * Retrieve all actions/filters that are assigned to actions/tags + * + * @since 0.1.0 + * @return array + */ + function get_actions() + { + return Plugins_lib::$instance->get_actions(); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('retrieve_plugins')) +{ + /** + * Shortcut to Plugins_lib::retrieve_plugins() + * + * Retrieve all plugins + * + * @since 0.1.0 + * @return array + */ + function retrieve_plugins() + { + return Plugins_lib::$instance->retrieve_plugins(); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('do_action')) +{ + /** + * Shortcut to Plugins_lib::do_action() + * + * Execute all plugin functions tied to a specific tag + * + * @param string $tag Tag to execute + * @param mixed $args Arguments to hand to plugin (Can be anything) + * + * @since 0.1.0 + * @return mixed + */ + function do_action( $tag, array $args = NULL ) + { + //log_message('error',"Doing $tag " . ($args ? "With args: " . serialize($args) : "With no args")); + return Plugins_lib::$instance->do_action( $tag, $args ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('remove_action')) +{ + /** + * Shortcut to Plugins_lib::remove_action() + * + * Remove a specific plugin function assigned to execute on a specific tag at a specific priority + * + * @param string $tag Tag to clear actions from + * @param string|array $function Function or object/method to remove from tag + * @param int $priority Priority to clear + * + * @since 0.1.0 + * @return boolean + */ + function remove_action( $tag, $function, $priority = 10 ) + { + return Plugins_lib::$instance->remove_action( $tag, $function, $priority ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('current_action')) +{ + /** + * Shortcut to Plugins_lib::current_action() + * + * Get the current plugin action being executed + * + * @since 0.1.0 + * @return string + */ + function current_action() + { + return Plugins_lib::$instance->current_action(); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('has_run')) +{ + /** + * Shortcut to Plugins_lib::has_run() + * + * See if an action has run or not + * + * @param string $action Tag/action to check + * + * @since 0.1.0 + * @return boolean + */ + function has_run( $action = NULL ) + { + return Plugins_lib::$instance->has_run( $action ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('doing_action')) +{ + /** + * Shortcut to Plugins_lib::doing_action() + * + * If no action is specified, then the current action being executed will be returned, if + * an action is specified, then TRUE/FALSE will be returned based on if the action is + * being executed or not + * + * @oaran string $action Action to check + * @since 0.1.0 + * @return boolean|string + */ + function doing_action( $action = NULL ) + { + return Plugins_lib::$instance->doing_action( $action ); + } +} + +// ------------------------------------------------------------------------ + +if( ! function_exists('did_action')) +{ + /** + * Shortcut to Plugins_lib::did_action() + * + * Check if an action/tag has been executed or not + * + * @param string $tag Tag/action to check + * + * @since 0.1.0 + * @return boolean + */ + function did_action( $tag ) + { + return Plugins_lib::$instance->did_action( $tag ); + } +} diff --git a/application/helpers/plugin_kalkun_helper.php b/application/helpers/plugin_kalkun_helper.php new file mode 100755 index 000000000..c27cec890 --- /dev/null +++ b/application/helpers/plugin_kalkun_helper.php @@ -0,0 +1,38 @@ + GPL-2.0-or-later + * @link https://kalkun.sourceforge.io/ + */ + +# This file includes/requires the original upstream file at the end of the document +# which permits us to override some methods before they are defined by upstream + +if( ! function_exists('do_action_kalkun')) +{ + /** + * Shortcut to Plugins_lib::do_action_kalkun() + * + * Execute all plugin functions tied to a specific tag + * + * @param string $tag Tag to execute + * @param mixed $args Arguments to hand to plugin (Can be anything) + * + * @since 0.1.0 + * @return mixed + */ + function do_action_kalkun( $tag, $args = NULL ) + { + //log_message('error',"Doing $tag " . ($args ? "With args: " . serialize($args) : "With no args")); + return Plugins_lib::$instance->do_action_kalkun( $tag, $args ); + } +} + +require_once('plugin_helper.php'); diff --git a/application/libraries/Plugins.php b/application/libraries/Plugins.php deleted file mode 100644 index 8a7981e59..000000000 --- a/application/libraries/Plugins.php +++ /dev/null @@ -1,794 +0,0 @@ -_ci =& get_instance(); - - $this->_ci->load->database(); - $this->_ci->load->helper('directory'); - $this->_ci->load->helper('file'); - $this->_ci->load->helper('url'); - - // Set the plugins directory if passed via paramater - if (array_key_exists('plugins_dir', $params)) - { - $this->set_plugin_dir($params['plugins_dir']); - } - else // else set to default value - { - $this->_ci->config->load('plugins'); - $this->set_plugin_dir($this->_ci->config->item('plugins_dir')); - } - - // Remove index.php string on the plugins directory if any - $this->plugins_dir = str_replace("index.php", "", $this->plugins_dir); - - // Find all plugins - $this->find_plugins(); - - // Get all activated plugins - $this->get_activated_plugins(); - - // Include plugins - $this->include_plugins(); - - self::$messages = []; // Clear messages - self::$errors = []; // Clear errors - } - - /** - * Set Plugin Dir - * Set the location of where all of the plugins are located - * - * @param mixed $directory - */ - public function set_plugin_dir($directory) - { - if (!empty($directory)) - { - $this->plugins_dir = trim($directory); - } - } - - /** - * Instance - * The instance of this plugin class - * - */ - public static function instance() - { - if (!self::$instance) - { - self::$instance = new Plugins(); - } - - return self::$instance; - } - - - /** - * Find Plugins - * - * Find plugins in the plugins directory. - * - */ - public function find_plugins() - { - $plugins = directory_map($this->plugins_dir, 1); // Find plugins - - if ($plugins != false) - { - foreach ($plugins AS $key => $name) - { - // Since CI3, directory_map returns dirs with trailing '/', so remove them - $name = strtolower(trim(trim($name),'/')); - - // If the plugin hasn't already been added and isn't a file - if (!isset(self::$plugins_pool[$name]) AND !stripos($name, ".")) - { - // Make sure a valid plugin file by the same name as the folder exists - if (file_exists($this->plugins_dir.$name."/".$name.".php")) - { - // Register the plugin - self::$plugins_pool[$name]['plugin'] = $name; - } - else - { - self::$errors[$name][] = "Plugin file ".$name.".php does not exist."; - } - } - } - } - } - - - /** - * Get Activated Plugins - * Get all activated plugins from the database - * - */ - public function get_activated_plugins() - { - // Only plugins in the database are active ones - $plugins = $this->_ci->db->get('plugins'); - - // If we have activated plugins - if ($plugins->num_rows() > 0) - { - // For every plugin, store it - foreach ($plugins->result_array() AS $plugin) - { - $this->get_plugin_headers($plugin['plugin_system_name']); - self::$plugins_active[$plugin['plugin_system_name']] = $plugin['plugin_system_name']; - } - } - else - { - return true; - } - } - - /** - * Include Plugins - * Include all active plugins that are in the database - * - */ - public function include_plugins() - { - if(self::$plugins_active AND !empty(self::$plugins_active)) - { - // Validate and include our found plugins - foreach (self::$plugins_active AS $name => $value) - { - // The plugin information being added to the database - if (array_key_exists($name, self::$plugins_pool)) - { - $data = array( - "plugin_system_name" => $name, - "plugin_name" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_name']), - "plugin_uri" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_uri']), - "plugin_version" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_version']), - "plugin_description" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_description']), - "plugin_author" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_author']), - "plugin_author_uri" => trim(self::$plugins_pool[$name]['plugin_info']['plugin_author_uri']) - ); - } - else - { - $data = array( - "plugin_system_name" => $name, - "plugin_name" => $name . ' (unavailable)', - ); - } - $this->_ci->db->where('plugin_system_name', $name)->update('plugins', $data); - - // If the file was included - if (file_exists($this->plugins_dir.$name."/".$name.".php")) - { - include_once $this->plugins_dir.$name."/".$name.".php"; - } - - // Run the install action for this plugin - $this->trigger_install_plugin($name); - - } - } - } - - - /** - * Get Plugin Headers - * - * Get the header information from all plugins in - * the plugins pool for use later on. - * - * @param mixed $plugin - */ - public function get_plugin_headers($plugin) - { - if (self::$plugins_pool !== false AND !empty(self::$plugins_pool)) - { - $plugin = strtolower(trim($plugin)); // Lowercase and trim the plugin name - - $plugin_file = $this->plugins_dir.$plugin."/".$plugin.".php"; - if ( ! file_exists($plugin_file)) - { - return; - } - $plugin_data = file_get_contents($plugin_file); // Load the plugin we want - - preg_match ('|Plugin Name:(.*)$|mi', $plugin_data, $name); - preg_match ('|Plugin URI:(.*)$|mi', $plugin_data, $uri); - preg_match ('|Version:(.*)|i', $plugin_data, $version); - preg_match ('|Description:(.*)$|mi', $plugin_data, $description); - preg_match ('|Author:(.*)$|mi', $plugin_data, $author_name); - preg_match ('|Author URI:(.*)$|mi', $plugin_data, $author_uri); - - $arr = []; - if (isset($name[1])) - { - $arr['plugin_name'] = trim($name[1]); - } - - if (isset($uri[1])) - { - - $arr['plugin_uri'] = trim($uri[1]); - } - - if (isset($version[1])) - { - $arr['plugin_version'] = trim($version[1]); - } - - if (isset($description[1])) - { - $arr['plugin_description'] = trim($description[1]); - } - - if (isset($author_name[1])) - { - $arr['plugin_author'] = trim($author_name[1]); - } - - if (isset($author_uri[1])) - { - $arr['plugin_author_uri'] = trim($author_uri[1]); - } - - // For every plugin header item - foreach ($arr AS $k => $v) - { - // If the key doesn't exist or the value is not the same, update the array - if (!isset(self::$plugins_pool[$plugin]['plugin_info'][$k]) OR self::$plugins_pool[$plugin]['plugin_info'][$k] != $v) - { - self::$plugins_pool[$plugin]['plugin_info'][$k] = trim($v); - } - else - { - return true; - } - } - } - } - - /** - * Activate Plugin - * - * Activates a plugin only if it exists in the - * plugins_pool. After activating, reload page - * to get the newly activated plugin - * - * @param mixed $name - */ - public function activate_plugin($name) - { - $name = strtolower(trim($name)); // Make sure the name is lowercase and no spaces - - // Okay the plugin exists, push it to the activated array - if (isset(self::$plugins_pool[$name]) AND !isset(self::$plugins_active[$name])) - { - $db = $this->_ci->db->select('plugin_system_name')->where('plugin_system_name', $name)->get('plugins', 1); - - if ($db->num_rows() == 0) - { - $this->_ci->db->insert('plugins', array('plugin_system_name' => $name)); - } - } - } - - /** - * Deactivate Plugin - * - * Deactivates a plugin - * - * @param string $name - */ - public function deactivate_plugin($name) - { - $name = strtolower(trim($name)); // Make sure the name is lowercase and no spaces - - // Okay the plugin exists - if (isset(self::$plugins_active[$name])) - { - $this->_ci->db->where('plugin_system_name', $name)->delete('plugins'); - if (isset(self::$plugins_pool[$name])) - self::$messages[] = "Plugin ".self::$plugins_pool[$name]['plugin_info']['plugin_name']." has been deactivated!"; - } - } - - - /** - * Plugin Info - * - * Get information about a specific plugin - * - * @param mixed $name - */ - public function plugin_info($name) - { - if (isset(self::$plugins_pool[$name])) - { - return self::$plugins_pool[$name]['plugin_info']; - } - else - { - return true; - } - } - - - /** - * Print Plugins - * - * This plugin returns the array of all plugins found - * - */ - public function print_plugins() - { - return self::$plugins_pool; - } - - - /** - * Add Action - * - * Add a new hook trigger action - * - * @param mixed $name - * @param mixed $function - * @param mixed $priority - */ - public function add_action($name, $function, $priority=10) - { - // If we have already registered this action return true - if (isset(self::$actions[$name][$priority][$function])) - { - return true; - } - - /** - * Allows us to iterate through multiple action hooks. - */ - if (is_array($name)) - { - foreach ($name AS $name) - { - // Store the action hook in the $hooks array - self::$actions[$name][$priority][$function] = array("function" => $function); - } - } - else - { - // Store the action hook in the $hooks array - self::$actions[$name][$priority][$function] = array("function" => $function); - } - - return true; - } - - - /** - * Do Action - * - * Trigger an action for a particular action hook - * - * @param mixed $name - * @param mixed $arguments - * @return mixed - */ - public function do_action($name, $arguments = "") - { - // Oh, no you didn't. Are you trying to run an action hook that doesn't exist? - if (!isset(self::$actions[$name])) - { - return $arguments; - } - - // Set the current running hook to this - self::$current_action = $name; - - // Key sort our action hooks - ksort(self::$actions[$name]); - - foreach(self::$actions[$name] AS $priority => $names) - { - if (is_array($names)) - { - foreach($names AS $name) - { - // This line runs our function and stores the result in a variable - $returnargs = call_user_func_array($name['function'], array(&$arguments)); - - if ($returnargs) - { - $arguments = $returnargs; - } - - // Store our run hooks in the hooks history array - self::$run_actions[self::$current_action][$priority] = $names; - } - } - } - - // No hook is running any more - self::$current_action = ''; - - return $arguments; - } - - - /** - * Remove Action - * - * Remove an action hook. No more needs to be said. - * - * @param mixed $name - * @param mixed $function - * @param mixed $priority - */ - public function remove_action($name, $function, $priority=10) - { - // If the action hook doesn't, just return true - if (!isset(self::$actions[$name][$priority][$function])) - { - return true; - } - - // Remove the action hook from our hooks array - unset(self::$actions[$name][$priority][$function]); - } - - - /** - * Current Action - * - * Get the currently running action hook - * - */ - public function current_action() - { - return self::$current_action; - } - - - /** - * Has Run - * - * Check if a particular hook has been run - * - * @param mixed $hook - * @param mixed $priority - */ - public function has_run($action, $priority = 10) - { - if (isset(self::$actions[$action][$priority])) - { - return true; - } - else - { - return false; - } - } - - - /** - * Action Exists - * - * Does a particular action hook even exist? - * - * @param mixed $name - */ - public function action_exists($name) - { - if (isset(self::$actions[$name])) - { - return true; - } - else - { - return false; - } - } - - /** - * Triggers the functionname_activate function when a plugin is activated - * - * @param mixed $name - */ - public function trigger_activate_plugin($name) - { - // Call plugin activate function - if (function_exists($name."_install")) - { - @call_user_func($name."_activate"); - } - } - - /** - * Triggers the functionname_deactivate function when a plugin is deactivated - * - * @param mixed $name - */ - public function trigger_deactivate_plugin($name) - { - // Call our plugin deactivate function - if (function_exists($name."_install")) - { - @call_user_func($name."_deactivate"); - } - } - - /** - * Triggers the functionname_install function when a plugin is first installed - * - * @param mixed $name - */ - public function trigger_install_plugin($name) - { - // Call our plugin deactivate function - if (function_exists($name."_install")) - { - @call_user_func($name."_install"); - } - } - - /** - * Will print our information about all plugins and actions - * neatly presented to the user. - * - */ - public static function debug_class() - { - if (isset(self::$plugins_pool)) - { - echo "

Found plugins

"; - echo "

All plugins found in the plugins directory.

"; - echo "
";
-            print_r(self::$plugins_pool);
-            echo "
"; - echo "
"; - echo "
"; - } - - if (isset(self::$plugins_active)) - { - echo "

Activated plugins

"; - echo "

Activated plugins that have already been included and are usable.

"; - echo "
";
-            print_r(self::$plugins_active);
-            echo "
"; - echo "
"; - echo "
"; - } - - if (isset(self::$actions)) - { - echo "

Register action hooks

"; - echo "

Action hooks that have been registered by the application and can be called via plugin files.

"; - echo "
";
-            print_r(self::$actions);
-            echo "
"; - echo "
"; - echo "
"; - } - - if (isset(self::$run_actions)) - { - echo "

Previously run action hooks

"; - echo "

Hooks that have been called previously.

"; - echo "
";
-            print_r(self::$run_actions);
-            echo "
"; - echo "
"; - echo "
"; - } - } -} - -/** -* Add a new action hook -* -* @param mixed $name -* @param mixed $function -* @param mixed $priority -*/ -function add_action($name, $function, $priority=10) -{ - return Plugins::instance()->add_action($name, $function, $priority); -} - -/** -* Run an action -* -* @param mixed $name -* @param mixed $arguments -* @return mixed -*/ -function do_action($name, $arguments = "") -{ - return Plugins::instance()->do_action($name, $arguments); -} - -/** -* Remove an action -* -* @param mixed $name -* @param mixed $function -* @param mixed $priority -*/ -function remove_action($name, $function, $priority=10) -{ - return Plugins::instance()->remove_action($name, $function, $priority); -} - -/** -* Check if an action actually exists -* -* @param mixed $name -*/ -function action_exists($name) -{ - return Plugins::instance()->action_exists($name); -} - -/** -* Set the location of where our plugins are located -* -* @param mixed $directory -*/ -function set_plugin_dir($directory) -{ - Plugins::instance()->set_plugin_dir($directory); -} - -/** -* Activate a specific plugin -* -* @param mixed $name -*/ -function activate($name) -{ - return Plugins::instance()->activate_plugin($name); -} - -/** -* Deactivate a specific plugin -* -* @param mixed $name -*/ -function deactivate($name) -{ - return Plugins::instance()->deactivate_plugin($name); -} - -/** -* Print Plugins -* Returns the list of plugins -* -*/ -function print_plugins() -{ - return Plugins::instance()->print_plugins(); -} - -/** -* Return the number of plugins found -* -*/ -function count_found_plugins() -{ - return count(Plugins::$plugins_pool); -} - -/** -* Return number of plugins activated -* -*/ -function count_activated_plugins() -{ - return count(Plugins::$plugins_active); -} - -/** -* Debug function will return all plugins registered and hooks -* -*/ -function debug_class() -{ - Plugins::debug_class(); -} - -/** -* Return all errors -* -*/ -function plugin_errors() -{ - if (is_array(Plugins::$errors)) - { - foreach (Plugins::$errors AS $k => $error) - { - echo $error."\n\r"; - } - } - else - { - return true; - } -} - -/** -* Return all messages -* -*/ -function plugin_messages() -{ - if (is_array(Plugins::$messages)) - { - foreach (Plugins::$messages AS $k => $message) - { - echo $message."\n\r"; - } - } - else - { - return true; - } -} diff --git a/application/libraries/Plugins_lib.php b/application/libraries/Plugins_lib.php new file mode 100755 index 000000000..50f2656e8 --- /dev/null +++ b/application/libraries/Plugins_lib.php @@ -0,0 +1,1049 @@ +load->model('Plugins_kalkun_model'); + + // Load the plugins helper + static::$CI->load->helper('plugin_kalkun'); + + // Set a shorter handle for the plugins model + static::$PM = static::$CI->Plugins_kalkun_model; + + static::$messages = array( + 'error' => [], + 'debug' => [], + 'warn' => [] + ); + // Set plugin path + $this->set_plugin_dir(); + + // Get all activated plugins + $this->get_plugins(); + + // Include plugins + $this->include_enabled_plugins(); + + // Load them + $this->load_enabled_plugins(); + } + + // ------------------------------------------------------------------------ + + /** + * Set Plugin Directory + * + * Set the plugins directory that contains all the plugin folders, at the local + * private property: static::$plugin_path + * + * @param str $dir Directory, an ending slash is appended if not found, and any + * accidental double slashes are replaced with single slashes + * @access private + */ + protected function set_plugin_dir() + { + if($path = static::$CI->config->item('plugin_path')) + { + $this->_debug("Plugin path set to {$path} via config setting"); + } + elseif(defined('PLUGIN_DIR')) + { + $this->_debug("Plugin path set to ".PLUGIN_DIR."via constant PLUGIN_DIR"); + + $path = PLUGIN_DIR; + } + else + { + $path = FCPATH . 'plugins/'; + + $this->_debug("Plugin path defaulted to {$path}"); + + $this->_warn("No plugin path specified in CI settings or PLUGIN_DIR constant, defaulting to {$path}"); + } + + // Make sure it ends in / + if( preg_match('%/$%', $path) === FALSE ) + { + $path = "{$path}/"; + } + + static::$plugin_path = str_replace('//','/',$path); + } + + // ------------------------------------------------------------------------ + + /** + * View Controller + * + * View the controller from the plugin. + * + * @param string $plugin Systen name of plugin + * @param mixed $plugin_data Any data to hand down to the plugin (Anything + * processed from the controller, etc) + * @access public + * @since 0.1.0 + * @return string Whatever content is returned from the plugins controller (which + * is usually HTML from the settings form) + */ + public function view_controller($plugin, $plugin_data = NULL) + { + if( ! isset(static::$plugins[$plugin])) + { + log_message('error',"The plugin {$plugin} was not found"); + + return FALSE; + } + elseif( ! method_exists(static::$plugins[$plugin]['handler'], 'controller')) + { + $this->_error('error','Plugin Error',"The plugin {$plugin} does not have a controller", TRUE); + + return FALSE; + } + + return call_user_func(array(static::$plugins[$plugin]['handler'], 'controller'), $plugin_data); + } + + // ------------------------------------------------------------------------ + + /** + * Plugin Error Collector + * + * Push an error message into the messages array + * + * @param string $message Message to push + * @access private + */ + protected function _error($message) + { + //log_message('error', 'PLUGIN-ERROR: ' . $message); + + array_push(static::$messages['error'], $message); + } + + // ------------------------------------------------------------------------ + + /** + * Plugin Debug Collector + * + * Push a debug message into the messages array + * + * @param string $message Message to push + * @access private + */ + protected function _debug($message) + { + //log_message('debug', 'PLUGIN-DEBUG: ' . $message); + + array_push(static::$messages['debug'], $message); + } + + // ------------------------------------------------------------------------ + + /** + * Plugin Warn Collector + * + * Push a warn message into the messages array + * + * @param string $message Message to push + * @access private + */ + protected function _warn($message) + { + //log_message('error', 'PLUGIN-WARN: ' . $message); + + array_push(static::$messages['warn'], $message); + } + + // ------------------------------------------------------------------------ + + /** + * Enable Plugin + * + * Enable a plugin by setting the plugins.status to 1 in the plugins table + * + * @oaram string $plugin Plugin Name + * @param mixed $data Any data that should be handed down to the plugins deactivate method (optional) + * @access public + * @since 0.1.0 + * @return bool + */ + public function enable_plugin($plugin, $data = NULL) + { + // Run the plugins activation method to run anything required by the plugin + call_user_func(array(static::$plugins[$plugin]['handler'], 'activate'), $data); + + // Enable it in the database + return static::$PM->set_status($plugin, 1); + } + + // ------------------------------------------------------------------------ + + /** + * Disable Plugin + * + * Disable a plugin by setting the plugins.status to 0 in the plugins table + * + * @oaram string $plugin Plugin Name + * @param mixed $data Any data that should be handed down to the plugins activate method (optional) + * @access public + * @since 0.1.0 + * @return bool + */ + public function disable_plugin($plugin, $data = NULL) + { + // Run the plugins deactivation method to run anything required by the plugin + call_user_func(array(static::$plugins[$plugin]['handler'], 'deactivate'), $data); + + // Disable it in the database + return static::$PM->set_status($plugin, 0); + } + + // ------------------------------------------------------------------------ + + /** + * Install Plugin + * + * Install a plugin by adding it to the database and executing any installation code thats in + * the plugins install method + * + * @param string $plugin Plugins system name (Folder name) + * @access public + * @param boolean + */ + public function install_plugin($plugin, $data = NULL) + { + // System name for folder and file + $system_name = strtolower($plugin); + + // Class name is just system name with ucfirst + $class_name = $this->plugin_class_name($system_name); + + // Path to plugins main file + $plugin_path = static::$plugin_path . "{$system_name}/{$system_name}.php"; + + // If the plugins class hasnt been loaded... + if( ! class_exists($class_name)) + { + // Make sure a valid plugin file by the same name as the folder exists + if (file_exists($plugin_path)) + { + if( ! include_once $plugin_path) + { + $this->_error("Failed to install {$plugin}, there was an error loading the plugin file {$plugin_path}, is it readable?"); + } + else + { + $this->_debug("Successfully loaded the plugin file {$plugin_path}"); + } + } + else + { + $this->_error("Failed to install {$plugin}, unable to find the file {$plugin_path}"); + } + } + + // Execute the plugin installation + return call_user_func("{$class_name}::install", $data); + } + + // ------------------------------------------------------------------------ + + /** + * Plugin Details + * + * Retrieve the details of a plugin from the database + * + * @param string $plugin Plugin system name + * @access public + * @since 0.1.0 + * @return object|bool + */ + public function plugin_details($plugin) + { + return static::$PM->get_plugin($plugin); + } + + // ------------------------------------------------------------------------ + + /** + * Get Enabled Plugins + * + * Retrieve the enabled plugins from the database and load them into the enabled_plugins + * array. This does not initiate the plugins, thats done in a different method + * + * @access private + */ + protected function get_plugins() + { + // Fetch all plugins + if( ! $plugins = static::$PM->get_plugins()) + { + return FALSE; + } + + // Load the plugins + foreach($plugins as $p) + { + if( ! isset( static::$plugins[ $p->system_name ] ) ) + { + $this->_debug( "Adding plugin {$p->system_name}" ); + + static::$plugins[$p->system_name] = array( + 'data' => $p->data + ); + + // If its enabled, add it to $enabled_plugins referencing the plugin in $plugins + if($p->status == '1') + { + $this->_debug( "Enabling plugin {$p->system_name}" ); + + static::$enabled_plugins[ $p->system_name ] = &static::$plugins[$p->system_name]; + } + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Print Plugins + * + * Retrieve all plugin information from the database + * + * @access public + * @since 0.1.0 + * @return array + */ + public function retrieve_plugins() + { + return static::$PM->get_plugins(); + } + + // ------------------------------------------------------------------------ + + /** + * Include Enabled Plugins + * + * Iterate through the enabled_plugins property array and include the actual plugin files + * + * @access private + */ + protected function include_enabled_plugins() + { + if(empty(static::$enabled_plugins)) + { + $this->_error("Unable to include enabled plugin files, enabled plugins not retrieved"); + + return FALSE; + } + + foreach(static::$enabled_plugins as $name => $p) + { + $plugin_path = static::$plugin_path . "{$name}/{$name}.php"; + + // Make sure a valid plugin file by the same name as the folder exists + if (file_exists($plugin_path)) + { + if( ! include_once $plugin_path) + { + $this->_error("There was an error loading the plugin file {$plugin_path}"); + } + else + { + $this->_debug("Successfully loaded the plugin file {$plugin_path}"); + } + } + else + { + $this->_error("Failed to include the plugin {$name}, unable to find the file {$plugin_path}"); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Load Enabled Plugins + * + * Load the enabled plugins into objects, store the objects into the loaded plugins array + * + * @access private + */ + protected function load_enabled_plugins() + { + if(static::$enabled_plugins) + { + foreach( static::$enabled_plugins as $name => $p ) + { + $class_name = $this->plugin_class_name($name); + new $class_name; + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Add Action + * + * Assign a function to be executed by a certain tag. An action will just fire off a function + * when the tag is called, a filter will parse data and return the modified data + * + * @param string $tag Tag to add filter to + * @param string|array $function Either a string (function), or an array (Object, method) + * @param integer $priority Priority + * @param string $type Either action or filter + * @access public + * @since 0.1.0 + * @return boolean + */ + public function add_action($tag, $function, $priority = 10, $type = 'action') + { + if(is_array($function)) + { + if(count($function) < 2) + { + // If its an array of one element, then just add the first element + $function = $function[0]; + } + elseif( ! is_object($function[0])) + { + $this->_error("Failing to add method '" . implode('::', $function) . "'' as {$type} to tag {$tag}, an array was given, first element was not an object"); + + return FALSE; + } + elseif( ! method_exists($function[0], $function[1])) + { + $this->_error("Failing to add method '" . get_class($function[0]) . "::{$function[1]}' as {$type} to tag {$tag}, the method does not exist"); + + return FALSE; + } + } + + // Execute is_array again, since the above could have converted it to an array + if( ! is_array($function)) + { + if( ! function_exists($function)) + { + $this->_error("Failing to add function {$function} as {$type} to tag {$tag}, the function does not exist"); + + return FALSE; + } + } + + if( ! in_array($type, ['action','filter'])) + { + $this->_error("Unknown type '{$type}', must be 'filter' or 'action'"); + + return FALSE; + } + + static::$actions[$tag][$priority][] = array( + 'function' => $function, + 'type' => $type + ); + + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Add Filter + * + * Just a wrapper for add_function except adds it as type 'filter'. Filters will + * take in data and perform an action on it, then return it, actions will just + * fire off a function + * + * @param string $tag Tag to add filter to + * @param string|array $function Either a string (function), or an array (Object, method) + * @param integer $priority Priority + * @access public + * @since 0.1.0 + * @return boolean + */ + public function add_filter($tag, $function, $priority = 10) + { + return $this->add_action($tag, $function, $priority, 'filter'); + } + + // ------------------------------------------------------------------------ + + /** + * Get Actions + * + * Get actions.... + * + * @access public + * @since 0.1.0 + * @return array + */ + public function get_actions() + { + foreach(static::$actions as $k => $a) + ksort(static::$actions[$k]); + + return static::$actions; + } + + // ------------------------------------------------------------------------ + + /** + * Do Action + * + * Execute a specific action, pass optional arguments to it + * @param string $tag Tag to execute + * @param null $args Arguments to hand to functions assigned to tag + * @access public + * @since 0.1.0 + * @return mixed Returns whatever the type of $args is + */ + public function do_action($tag, array $args = NULL) + { + static::$current_action = $tag; + + array_push(static::$run_actions, $tag); + + if( ! isset(static::$actions[$tag])) + { + $this->_debug("No actions found for tag {$tag}"); + + return $args; + } + + ksort(static::$actions[$tag]); + + //die('
' . print_r(static::$actions, TRUE));
+
+        foreach(static::$actions[$tag] as $actions)
+        {
+            foreach($actions as $a)
+            {
+                // Make sure the function or method exists
+                if(is_array($a['function']))
+                {
+                    // Methods are setup as an array, [0] is the object/class, [1] is the method
+                    if( ! method_exists($a['function'][0], $a['function'][1]))
+                    {
+                        $this->_error("Unable to execute method '" . get_class($a['function'][0]) . "::{$a['function'][1]}' for action {$tag}, the method doesn't exist");
+
+                        return $args;
+                    }
+                }
+                else
+                {
+                    // Strings are just functions
+                    if( ! function_exists($a['function']))
+                    {
+                        $this->_error("Unable to execute function '{$a['function']}' for action {$tag}, the function doesn't exist");
+
+                        return $args;
+                    }
+                }
+
+                // Actions
+                if($a['type'] == 'action')
+                {
+                    // No arguments/null
+                    if( ! $args)
+                    {
+                        call_user_func( $a['function'] );
+                    }
+                    else
+                    {
+                        call_user_func_array( $a['function'], $args );
+                    }
+                }
+                // Filters
+                else
+                {
+                    // No arguments/null
+                    if( ! $args)
+                    {
+                        $args = call_user_func( $a['function'] );
+                    }
+                    else
+                    {
+                        $args = call_user_func_array( $a['function'], $args );
+                    }
+                }
+            }
+        }
+
+        static::$current_action = NULL;
+
+        // Be polite, return it as you found it
+        settype($args, gettype($args));
+
+        return $args;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Remove Action
+     *
+     * Remove a function from an action
+     *
+     * @param   string  $tag Tag to check in
+     * @param   mixed   $function Function to be removed
+     * @param   integer $priority Priority to check for function
+     * @access  public
+     * @since   0.1.0
+     * @return  boolean
+     */
+    public function remove_action($tag, $function, $priority = 10)
+    {
+        if (isset(static::$actions[$tag][$priority][$function]))
+        {
+            // Remove the action hook from our hooks array
+            unset(static::$actions[$tag][$priority][$function]);
+        }
+
+        return TRUE;
+
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Current Action
+     *
+     * Set the currently running action
+     *
+     * @access public
+     * @since   0.1.0
+     * @return string
+     */
+    public function current_action()
+    {
+        return static::$current_action;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Has Run
+     *
+     * See if a particular action has ran yet
+     *
+     * @param  string  $action  Action to check for
+     * @access public
+     * @since   0.1.0
+     * @return boolean
+     */
+    public function has_run($action)
+    {
+        if (isset(static::$run_actions[$action]))
+        {
+            return true;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Update Plugin Headers
+     *
+     * Parse a given plugins PHP file for the header information in the comments, and update the database info
+     * accordingly
+     *
+     * @param   string  $plugin Plugin System Name to check
+     * @access  public
+     * @todo    Try to retrieve only the top X lines of the file, not the whole file
+     * @since   0.1.0
+     * @return  TRUE Always true
+     */
+    public function update_plugin_headers($plugin)
+    {
+        if (isset(static::$plugins[$plugin]))
+        {
+            $arr = array();
+
+            $plugin_data = file_get_contents(static::$plugin_path.$plugin."/".$plugin.".php"); // Load the plugin we want
+
+            preg_match ('|Plugin Name:(.*)$|mi', $plugin_data, $name);
+            preg_match ('|Plugin URI:(.*)$|mi', $plugin_data, $uri);
+            preg_match ('|Version:(.*)|i', $plugin_data, $version);
+            preg_match ('|Description:(.*)$|mi', $plugin_data, $description);
+            preg_match ('|Author:(.*)$|mi', $plugin_data, $author_name);
+            preg_match ('|Author URI:(.*)$|mi', $plugin_data, $author_uri);
+
+            if (isset($name[1]))
+            {
+                $arr['name'] = trim($name[1]);
+            }
+
+            if (isset($uri[1]))
+            {
+                $arr['uri'] = trim($uri[1]);
+            }
+
+            if (isset($version[1]))
+            {
+                $arr['version'] = trim($version[1]);
+            }
+
+            if (isset($description[1]))
+            {
+                $arr['description'] = trim($description[1]);
+            }
+
+            if (isset($author_name[1]))
+            {
+                $arr['author'] = trim($author_name[1]);
+            }
+
+            if (isset($author_uri[1]))
+            {
+                $arr['author_uri'] = trim($author_uri[1]);
+            }
+
+            if(empty($arr))
+            {
+                $this->_warn("Skipping header update for {$plugin}, no headers matched");
+            }
+            elseif(self::$PM->update_plugin_info($plugin, $arr))
+            {
+                $this->_debug("Updated plugin headers for {$plugin}: " . serialize($arr));
+            }
+            else
+            {
+                $this->_error("Failed to update plugin headers for {$plugin}: " . serialize($arr));
+            }
+        }
+
+        return TRUE;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Update All Plugin Headers
+     *
+     * Execute self::update_plugin_headers for each plugin found in static::$plugins
+     *
+     * @access public
+     * @since   0.1.0
+     * @return boolean
+     */
+    public function update_all_plugin_headers()
+    {
+        if(empty(static::$plugins))
+        {
+            $this->_warn("No plugins to update headers for");
+
+            return TRUE;
+        }
+
+        foreach(static::$plugins as $name => $plugin)
+        {
+            $this->_debug("Updating plugin headers for {$name}");
+
+            if( ! $this->update_plugin_headers($name))
+            {
+                return FALSE;
+            }
+        }
+
+        return TRUE;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Doing Action
+     *
+     * If the param is NULL, then this will return what action is being executed,
+     * if an action is supplied, then it will return boolean based on if that action
+     * is being executed or not
+     *
+     * @param null $action  Action to check for
+     */
+    public function doing_action($action = NULL)
+    {
+        if(is_null($action))
+        {
+            return static::$current_action;
+        }
+        else
+        {
+            return $action === static::$current_action;
+        }
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Did Action
+     *
+     * Returns if a tag has been fired or not
+     *
+     * @param $tag
+     */
+    public function did_action($tag)
+    {
+        return in_array($tag, static::$run_actions);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Get Orphaned Plugins
+     *
+     * Look in the plugin directory for any folders that do not have an associated entry
+     * in the plugins table
+     *
+     * @access public
+     * @since   0.1.0
+     * @return array|bool   If no orphaned plugins are found, return false
+     */
+    public function get_orphaned_plugins()
+    {
+        $files = scandir(static::$plugin_path);
+
+        $plugins = static::$PM->get_plugins();
+
+        $orphaned = array();
+
+        foreach($files as $f)
+        {
+            // Skip directories
+            if(in_array($f, ['.','..'])) continue;
+
+            if( ! isset($plugins[$f]))
+            {
+                array_push($orphaned, $f);
+            }
+        }
+
+        return (count($orphaned) > 0 ? $orphaned : FALSE);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Get Messages
+     *
+     * Get all messages, or a specific type of message
+     *
+     * @param   string  $type   Type of error to retrieve (error, debug, warn)
+     * @access  public
+     * @since   0.1.0
+     * @return  array|bool
+     */
+    public function get_messages($type = NULL)
+    {
+        if( ! $type)
+        {
+            return static::$messages;
+        }
+        elseif( ! isset(static::$messages[ strtolower($type) ]))
+        {
+            $this->_error("Failed to retrieve error type '{$type}', no such type found. Use 'error', 'warn' or 'debug'");
+
+            return FALSE;
+        }
+
+        return static::$messages[strtolower($type)];
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Print Messages
+     *
+     * Print all messages, or messages of a certain type
+     *
+     * @param   string  $type   Type of error to display (error, debug, warn)
+     * @access  public
+     * @since   0.1.0
+     * @return  array|bool
+     */
+    public function print_messages($type = NULL)
+    {
+        if($type)
+        {
+            if(@empty(static::$messages[ strtolower($type) ]) || ! isset(static::$messages[ strtolower($type) ]))
+            {
+                echo "{$type} IS EMPTY\n";
+                return TRUE;
+            }
+
+            echo "

Plugin Messages - " . ucfirst($type) . "

\n"; + + echo "
    \n"; + + foreach(static::$messages[ strtolower($type) ] as $m) + { + echo "
  1. $m
  2. \n"; + } + + echo "
\n\n"; + + return TRUE; + } + + foreach(static::$messages as $type => $messages) + { + if(@empty($messages)) + { + echo "{$type} IS EMPTY\n"; + continue; + } + + echo "

Plugin Messages - " . ucfirst($type) . "

\n"; + + echo "
    \n"; + + foreach($messages as $m) + { + echo "
  1. $m
  2. \n"; + } + + echo "
\n\n"; + } + + return TRUE; + } + + protected function plugin_class_name($system_name = '') { + return ucfirst($system_name); + } +} diff --git a/application/libraries/Plugins_lib_kalkun.php b/application/libraries/Plugins_lib_kalkun.php new file mode 100644 index 000000000..1e4ddb6af --- /dev/null +++ b/application/libraries/Plugins_lib_kalkun.php @@ -0,0 +1,363 @@ +config->load('plugins'); + parent::set_plugin_dir(); + } + + private function create_plugin_instance($name) + { + include_once static::$plugin_path."{$name}/{$name}.php"; + + $c = $this->plugin_class_name($name); + $plugin_instance = new $c; + } + + // ------------------------------------------------------------------------ + + /** + * Enable Plugin + * + * Enable a plugin by setting the plugins.status to 1 in the plugins table + * + * There is an issue in upstream where they want to access the 'handler' + * key with $plugins[$plugin]['handler'] but this key is only there if the plugin + * object is actually instatiated. So this cannot work. We have to instantiate the + * object before. + * + * @oaram string $plugin Plugin Name + * @param mixed $data Any data that should be handed down to the plugins deactivate method (optional) + * @access public + * @since 0.1.0 + * @return bool + */ + public function enable_plugin($plugin, $data = NULL) + { + if (! array_key_exists('handler', static::$plugins[$plugin])) + { + $this->create_plugin_instance($plugin); + } + parent::enable_plugin($plugin, $data); + } + + public function install_plugin($plugin, $data = NULL) + { + $this->insert_plugin_headers($plugin); + + $ret = parent::install_plugin($plugin, $data); + + if ($ret !== TRUE) { + return $ret; + } + + } + + // ------------------------------------------------------------------------ + + /** + * Insert Plugin Headers in a minimal fashion + * + * Parse a given plugins PHP file for the header information in the comments, and update the database info + * accordingly + * + * @param string $plugin Plugin System Name to insert + * @access private + * @return TRUE Always true + */ + private function insert_plugin_headers_minimal($plugin) + { + $arr = array(); + + if ( ! isset(static::$plugins[$plugin])) + { + $arr['system_name'] = $plugin; + $arr['name'] = $plugin; + $arr['status'] = 0; + if (self::$PM->insert_plugin($plugin, $arr)) + { + $this->_debug("Inserted plugin for {$plugin}: " . serialize($arr)); + // Insert an element for that plugin into static::$plugins array + // so that it gets filled by update_plugin_headers($plugin) + static::$plugins[$plugin] = $plugin; + } + else + { + $this->_error("Failed to insert plugin for {$plugin}: " . serialize($arr)); + } + } + + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Insert All Plugin Headers + * + * Insert all plugin headers + * + * @param string $plugin Plugin System Name to insert + * @access private + * @return TRUE Always true + */ + public function insert_plugin_headers($plugin) + { + // Insert the minimal plugin headers + $this->insert_plugin_headers_minimal($plugin); + + // Now update the other headers for that plugin + $this->update_plugin_headers($plugin); + + // Update static::$plugins[$plugin] of that object to have same content + // as if it were filled by get_plugins() + $resultObject = static::$PM->get_plugin($plugin); + if( ! empty($resultObject->data)) { + $resultObject->data = unserialize($resultObject->data); + } + static::$plugins[$plugin] = array('data' => $resultObject->data);; + + // By default, when inserting a new plugin, it is disabled, so we + // don't have to update $enabled_plugins, and neither to load them into an object. + + + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Get Orphaned Plugins + * + * Look in the plugin directory for any folders that do not have an associated entry + * in the plugins table + * + * Upstream bug here it that it doesn't check only for folders, but also for files. + * So we have to skip the loop for files. + * + * @access public + * @since 0.1.0 + * @return array|bool If no orphaned plugins are found, return false + */ + public function get_orphaned_plugins() + { + $files = scandir(static::$plugin_path); + + $plugins = static::$PM->get_plugins(); + + $orphaned = array(); + + foreach($files as $f) + { + // Skip directories + if (in_array($f, ['.', '..'])) + { + continue; + } + if ( ! is_dir(static::$plugin_path . "/" . $f)) + { + continue; + } + + if( ! isset($plugins[$f])) + { + array_push($orphaned, $f); + } + } + + return (count($orphaned) > 0 ? $orphaned : FALSE); + } + + public function restore_orphaned_plugins() { + // Insert orphaned plugins to plugins table & install the plugin to the DB + $orphaned_plugins = $this->get_orphaned_plugins(); + if ($orphaned_plugins) + { + foreach ($orphaned_plugins as $op) + { + $this->install_plugin($op); + } + } + } + + /* + * method to return static member of the function. + * Required for php 5.6 because using $this->plugins_lib_kalkun::$enabled_plugins + * would not be a valid call. + */ + public static function get_enabled_plugins() + { + return self::$enabled_plugins; + } + + public function do_action($tag, $args = NULL) + { + die("Call to do_action forbidden, call do_action_kalkun instead."); + } + + /** + * Do Action. + * + * Override upstream's do_action because the call to call_user_func_array + * was missing the array(&$args) + * + * Moreover, in kalkun, we need to pass an Object as argument. So the do_action function + * which requires an arrays doesn't fit. + * + * Execute a specific action, pass optional arguments to it + * @param string $tag Tag to execute + * @param null $args Arguments to hand to functions assigned to tag + * @access public + * @since 0.1.0 + * @return mixed Returns whatever the type of $args is + */ + public function do_action_kalkun($tag, $args = NULL) + { + static::$current_action = $tag; + + array_push(static::$run_actions, $tag); + + if( ! isset(static::$actions[$tag])) + { + $this->_debug("No actions found for tag {$tag}"); + + return $args; + } + + ksort(static::$actions[$tag]); + + //die('
' . print_r(static::$actions, TRUE));
+
+        foreach(static::$actions[$tag] as $actions)
+        {
+            foreach($actions as $a)
+            {
+                // Make sure the function or method exists
+                if(is_array($a['function']))
+                {
+                    // Methods are setup as an array, [0] is the object/class, [1] is the method
+                    if( ! method_exists($a['function'][0], $a['function'][1]))
+                    {
+                        $this->_error("Unable to execute method '" . get_class($a['function'][0]) . "::{$a['function'][1]}' for action {$tag}, the method doesn't exist");
+
+                        return $args;
+                    }
+                }
+                else
+                {
+                    // Strings are just functions
+                    if( ! function_exists($a['function']))
+                    {
+                        $this->_error("Unable to execute function '{$a['function']}' for action {$tag}, the function doesn't exist");
+
+                        return $args;
+                    }
+                }
+
+                // Actions
+                if($a['type'] == 'action')
+                {
+                    // No arguments/null
+                    if( ! $args)
+                    {
+                        call_user_func( $a['function'] );
+                    }
+                    else
+                    {
+                        call_user_func_array( $a['function'], array(&$args) );
+                    }
+                }
+                // Filters
+                else
+                {
+                    // No arguments/null
+                    if( ! $args)
+                    {
+                        $args = call_user_func( $a['function'] );
+                    }
+                    else
+                    {
+                        $args = call_user_func_array( $a['function'], array(&$args) );
+                    }
+                }
+            }
+        }
+
+        static::$current_action = NULL;
+
+        // Be polite, return it as you found it
+        settype($args, gettype($args));
+
+        return $args;
+    }
+
+	protected function plugin_class_name($system_name = '') {
+		return ucfirst($system_name).'_plugin';
+	}
+
+
+}
\ No newline at end of file
diff --git a/application/libraries/abstract.plugins.php b/application/libraries/abstract.plugins.php
new file mode 100755
index 000000000..cf0a9c02c
--- /dev/null
+++ b/application/libraries/abstract.plugins.php
@@ -0,0 +1,133 @@
+input->get($index, $xss_clean);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Fetch an item from the POST array
+     *
+     * Shortcut to Loader::post()
+     *
+     * @param	mixed	    $index		Index for item to be fetched from $_POST
+     * @param	bool	    $xss_clean	Whether to apply XSS filtering
+     * @access  protected
+     * @since   0.1.0
+     * @return	mixed
+     */
+    protected function post($index = NULL, $xss_clean = NULL)
+    {
+        return parent::$CI->input->post($index, $xss_clean);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Fetch an item from POST data with fallback to GET
+     *
+     * Shortcut to Loader::post_get()
+     *
+     * @param	string	    $index		Index for item to be fetched from $_POST or $_GET
+     * @param	bool	    $xss_clean	Whether to apply XSS filtering
+     * @access  protected
+     * @since   0.1.0
+     * @return	mixed
+     */
+    protected function post_get($index, $xss_clean = NULL)
+    {
+        return parent::$CI->input->post_get($index, $xss_clean);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Fetch an item from GET data with fallback to POST
+     *
+     * Shortcut to Loader::get_post()
+     *
+     * @param	string	    $index		Index for item to be fetched from $_GET or $_POST
+     * @param	bool	    $xss_clean	Whether to apply XSS filtering
+     * @access  protected
+     * @since   0.1.0
+     * @return	mixed
+     */
+    protected function get_post($index, $xss_clean = NULL)
+    {
+        return parent::$CI->input->get_post($index, $xss_clean);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Plugin View
+     *
+     * Load a plugin view via Loader::plugin_view()
+     *
+     * @param   str         $view       Plugin view to load, must exist in the /views/ folder of the plugins root directory
+     * @param   array       $data       Data to load into view.
+     * @access  protected
+     * @since   0.1.0
+     * @return  str         String value of processed view
+     */
+    protected function view($view, array $data = array())
+    {
+        $backtrace = debug_backtrace();
+
+        if( ! isset($backtrace[1]['class']))
+        {
+            return FALSE;
+        }
+
+        // The strtolower version of the class name should be the plugin folder name
+        $class = strtolower($backtrace[1]['class']);
+
+        return parent::$CI->load->plugin_view($class, $view, $data, TRUE);
+    }
+}
diff --git a/application/models/Kalkun_model.php b/application/models/Kalkun_model.php
index 334cdcfff..3fe4c23c3 100644
--- a/application/models/Kalkun_model.php
+++ b/application/models/Kalkun_model.php
@@ -694,4 +694,9 @@ function _phone_number_validation($phone)
 			show_error($result, 400);
 		}
 	}
+
+	function plugins_table_has_status_column()
+	{
+		return $this->db->field_exists('status', 'plugins');
+	}
 }
diff --git a/application/models/Plugin_model.php b/application/models/Plugin_model.php
deleted file mode 100644
index 698ecdd9e..000000000
--- a/application/models/Plugin_model.php
+++ /dev/null
@@ -1,31 +0,0 @@
-db->from('plugins');
-		$this->db->order_by('plugin_name', 'ASC');
-		return $this->db->get();
-	}
-}
diff --git a/application/models/Plugins_kalkun_model.php b/application/models/Plugins_kalkun_model.php
new file mode 100755
index 000000000..113b39d1d
--- /dev/null
+++ b/application/models/Plugins_kalkun_model.php
@@ -0,0 +1,44 @@
+where('system_name', $plugin)->insert('plugins', $settings);
+    }
+}
diff --git a/application/models/Plugins_model.php b/application/models/Plugins_model.php
new file mode 100644
index 000000000..322025fb0
--- /dev/null
+++ b/application/models/Plugins_model.php
@@ -0,0 +1,175 @@
+load->database();
+        static::$db = static::$CI->db;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Get Plugins
+     *
+     * Get all plugins, return an array of the plugins from the database, with the system_name
+     * as the keys
+     *
+     * @access public
+     * @since   0.1.0
+     * @return array|bool
+     */
+    public function get_plugins()
+    {
+        $query = static::$db->get('plugins');
+
+        if( ! $result = $query->result())
+        {
+            log_message('error','Error retrieving plugins from database');
+
+            return FALSE;
+        }
+
+        $return = array();
+
+        foreach($result as $r)
+        {
+            if( ! empty($r->data))
+            {
+                $r->data = unserialize($r->data);
+            }
+
+            $return[$r->system_name] = $r;
+        }
+
+        return $return;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Update Plugin Info
+     *
+     * Update the plugin information in the database. This is typically executed by the
+     * Plugins_lib::update_headers() which parses the comments of the plugin for the info
+     *
+     * @param   str     $plugin     The system_name of the plugin
+     * @param   array   $settings   New settings for plugin
+     * @access  public
+     * @since   0.1.0
+     * @return  bool
+     */
+    public function update_plugin_info($plugin, array $settings)
+    {
+        return static::$db->where('system_name', $plugin)->update('plugins', $settings);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Set Status
+     *
+     * Enable/Disable plugin
+     *
+     * @param   string  $plugin     Plugin system name
+     * @param   bool    $status     Status to set plugin as
+     * @access  public
+     * @since   0.1.0
+     * @return  bool
+     */
+    public function set_status($plugin, $status)
+    {
+        log_message("error","PLUGIN: $plugin; STATUS: $status");
+
+        if( ! static::$db
+            ->where('system_name', $plugin)
+            ->update('plugins', ['status' => $status]))
+        {
+            return FALSE;
+        }
+
+        return TRUE;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Get Plugin
+     *
+     * Retrieve the data from the database for a single plugin by the plugin system name
+     *
+     * @param  string   $plugin  Plugin System Name
+     * @access public
+     * @since   0.1.0
+     * @return bool|object
+     */
+    public function get_plugin($plugin)
+    {
+        $query = static::$db->get_where('plugins', ['system_name' => $plugin]);
+
+        $result = $query->result();
+
+        return ( ! @empty($result[0]) ? $result[0] : FALSE);
+    }
+}
diff --git a/application/plugins/Plugin_controller.php b/application/plugins/Plugin_controller.php
index d43e9803f..fb5c2aff3 100644
--- a/application/plugins/Plugin_controller.php
+++ b/application/plugins/Plugin_controller.php
@@ -52,8 +52,8 @@ function __construct($login = TRUE)
 
 		// Check if plugin is active
 		$CI = &get_instance();
-		$check = $CI->db->where('plugin_system_name', $this->plugin_name)->get('plugins');
-		if ($check->num_rows() !== 1)
+		$this->load->library('Plugins_lib_kalkun');
+		if (!isset($this->plugins_lib_kalkun->get_enabled_plugins()[$this->plugin_name]))
 		{
 			$message = tr_raw('Plugin {0} is not installed.', NULL, $this->plugin_name);
 			$this->session->set_flashdata('notif', $message);
diff --git a/application/plugins/blacklist_number/blacklist_number.php b/application/plugins/blacklist_number/blacklist_number.php
index c1c0aab19..96a06a447 100644
--- a/application/plugins/blacklist_number/blacklist_number.php
+++ b/application/plugins/blacklist_number/blacklist_number.php
@@ -8,48 +8,34 @@
 * Author URI: http://azhari.harahap.us
 */
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'blacklist_number_incoming', 10);
+class Blacklist_number_plugin extends CI3_plugin_system {
 
-// Add hook for outgoing message
-add_action('message.outgoing', 'blacklist_number_outgoing', 10);
+    use plugin_trait;
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function blacklist_number_activate()
-{
-	return TRUE;
-}
+    public function __construct()
+    {
+        parent::__construct();
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function blacklist_number_deactivate()
-{
-	return TRUE;
-}
+		// Add hook for incoming message
+		add_action('message.incoming.before', array($this, 'blacklist_number_incoming'), 10);
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function blacklist_number_install()
-{
+		// Add hook for outgoing message
+		add_action('message.outgoing', array($this, 'blacklist_number_outgoing'), 10);
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -60,10 +46,10 @@ function blacklist_number_install()
 		execute_sql(APPPATH.'plugins/blacklist_number/media/'.$db_prop['file'].'_blacklist_number.sql');
 	}
 	return TRUE;
-}
+	}
 
-function blacklist_number_incoming($sms)
-{
+	function blacklist_number_incoming($sms)
+	{
 	$CI = &get_instance();
 	$CI->load->model('blacklist_number/blacklist_number_model', 'blacklist_number_model');
 	$evil = array();
@@ -81,10 +67,10 @@ function blacklist_number_incoming($sms)
 		$CI->db->where('ID', $sms->ID)->delete('inbox');
 		return 'break';
 	}
-}
+	}
 
-function blacklist_number_outgoing($numbers = array())
-{
+	function blacklist_number_outgoing($numbers = array())
+	{
 	$CI = &get_instance();
 	$CI->load->model('blacklist_number/blacklist_number_model', 'blacklist_number_model');
 	$evil = array();
@@ -105,4 +91,5 @@ function blacklist_number_outgoing($numbers = array())
 		}
 	}
 	return $numbers;
+	}
 }
diff --git a/application/plugins/external_script/external_script.php b/application/plugins/external_script/external_script.php
index b3f81c604..80844e7ed 100644
--- a/application/plugins/external_script/external_script.php
+++ b/application/plugins/external_script/external_script.php
@@ -12,50 +12,19 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'external_script', 12);
+class External_script_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function external_script_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function external_script_deactivate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function external_script_install()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'external_script'), 12);
+	}
 
-function external_script($sms)
-{
+	function external_script($sms)
+	{
 	$scripts = Plugin_helper::get_plugin_config('external_script')['external_script'];
 	$phone = $sms->SenderNumber;
 	$content = $sms->TextDecoded;
@@ -123,10 +92,10 @@ function external_script($sms)
 			exec(escapeshellcmd($intepreter_path.' '.$script_path.' '.$parameter));
 		}
 	}
-}
+	}
 
-function is_equal($subject, $matched)
-{
+	function is_equal($subject, $matched)
+	{
 	if ($subject === $matched)
 	{
 		return TRUE;
@@ -135,10 +104,10 @@ function is_equal($subject, $matched)
 	{
 		return FALSE;
 	}
-}
+	}
 
-function is_contain($subject, $matched)
-{
+	function is_contain($subject, $matched)
+	{
 	if ( ! strstr($matched, $subject))
 	{
 		return FALSE;
@@ -147,10 +116,10 @@ function is_contain($subject, $matched)
 	{
 		return TRUE;
 	}
-}
+	}
 
-function is_preg_match($pattern, $subject)
-{
+	function is_preg_match($pattern, $subject)
+	{
 	$ret = preg_match($pattern, $subject, $matches, PREG_UNMATCHED_AS_NULL);
 	if ($ret === 1)
 	{
@@ -160,4 +129,5 @@ function is_preg_match($pattern, $subject)
 	{
 		return array(FALSE, NULL);
 	}
+	}
 }
diff --git a/application/plugins/jsonrpc/jsonrpc.php b/application/plugins/jsonrpc/jsonrpc.php
index 742f9aa5e..b1ce16e49 100644
--- a/application/plugins/jsonrpc/jsonrpc.php
+++ b/application/plugins/jsonrpc/jsonrpc.php
@@ -8,42 +8,7 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Jsonrpc_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function jsonrpc_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function jsonrpc_deactivate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function jsonrpc_install()
-{
-	return TRUE;
+    use plugin_trait;
 }
diff --git a/application/plugins/phonebook_ldap/phonebook_ldap.php b/application/plugins/phonebook_ldap/phonebook_ldap.php
index 34d4a4548..c241aeaf7 100644
--- a/application/plugins/phonebook_ldap/phonebook_ldap.php
+++ b/application/plugins/phonebook_ldap/phonebook_ldap.php
@@ -11,56 +11,25 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for contact menu
-add_action('phonebook.contact.get', 'phonebook_ldap', 10);
+class Phonebook_ldap_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function phonebook_ldap_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function phonebook_ldap_deactivate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function phonebook_ldap_install()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for contact menu
+		add_filter('phonebook.contact.get', array($this, 'phonebook_ldap'), 10);
+	}
 
-/**
-* Some of code is based on
-* http://www.newitperson.com/2010/11/simple-phonebook-list-ldap-codeigniter-datatables/
-* with modification
-*
-*/
-function phonebook_ldap($number)
-{
+	/**
+	 * Some of code is based on
+	 * http://www.newitperson.com/2010/11/simple-phonebook-list-ldap-codeigniter-datatables/
+	 * with modification
+	 *
+	 */
+	function phonebook_ldap($number)
+	{
 	if ( ! extension_loaded('ldap'))
 	{
 		show_error('phonebook_ldap: PHP extension "ldap" is missing. Install it if you want to use phonebook_ldap plugin.', 500, '500 Internal Server Error');
@@ -123,4 +92,5 @@ function phonebook_ldap($number)
 	}
 	ldap_close($conn);
 	return $users;
+	}
 }
diff --git a/application/plugins/phonebook_lookup/phonebook_lookup.php b/application/plugins/phonebook_lookup/phonebook_lookup.php
index 3449e207a..ee629ad68 100644
--- a/application/plugins/phonebook_lookup/phonebook_lookup.php
+++ b/application/plugins/phonebook_lookup/phonebook_lookup.php
@@ -11,53 +11,23 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for contact menu
-add_action('phonebook.contact.menu', 'phonebook_lookup', 10);
+class Phonebook_lookup_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function phonebook_lookup_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function phonebook_lookup_deactivate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function phonebook_lookup_install()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for contact menu
+		add_filter('phonebook.contact.menu', array($this, 'phonebook_lookup'), 10);
+	}
 
-function phonebook_lookup($number)
-{
+	function phonebook_lookup($number)
+	{
 	$config = Plugin_helper::get_plugin_config('phonebook_lookup');
 	Plugin_helper::load_lang('phonebook_lookup');
 	$lookup['url'] = str_replace('#phonenumber#', $number->Number, $config['url']);
 	$lookup['title'] = tr('Lookup Number');
 	return $lookup;
+	}
 }
diff --git a/application/plugins/rest_api/rest_api.php b/application/plugins/rest_api/rest_api.php
index 06ca12fe3..d66c380de 100644
--- a/application/plugins/rest_api/rest_api.php
+++ b/application/plugins/rest_api/rest_api.php
@@ -8,42 +8,7 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Rest_api_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function rest_api_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function rest_api_deactivate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function rest_api_install()
-{
-	return TRUE;
+    use plugin_trait;
 }
diff --git a/application/plugins/server_alert/server_alert.php b/application/plugins/server_alert/server_alert.php
index d72d4f470..91183ef5c 100644
--- a/application/plugins/server_alert/server_alert.php
+++ b/application/plugins/server_alert/server_alert.php
@@ -8,43 +8,23 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Server_alert_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function server_alert_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function server_alert_deactivate()
-{
-	return TRUE;
-}
+// ------------------------------------------------------------------------
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function server_alert_install()
-{
+	/**
+	 * Install Plugin
+	 *
+	 * Anything that needs to happen when this plugin gets installed
+	 *
+	 * @access public
+	 * @since   0.1.0
+	 * @return bool    TRUE by default
+	 */
+	public static function install($data = NULL)
+ {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -55,4 +35,5 @@ function server_alert_install()
 		execute_sql(APPPATH.'plugins/server_alert/media/'.$db_prop['file'].'_server_alert.sql');
 	}
 	return TRUE;
+    }
 }
diff --git a/application/plugins/simple_autoreply/simple_autoreply.php b/application/plugins/simple_autoreply/simple_autoreply.php
index 007450374..7a40b8d6f 100644
--- a/application/plugins/simple_autoreply/simple_autoreply.php
+++ b/application/plugins/simple_autoreply/simple_autoreply.php
@@ -11,50 +11,19 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'simple_autoreply', 11);
+class Simple_autoreply_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function simple_autoreply_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function simple_autoreply_deactivate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function simple_autoreply_install()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'simple_autoreply'), 11);
+	}
 
-function simple_autoreply($sms)
-{
+	function simple_autoreply($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('simple_autoreply');
 	$CI = &get_instance();
 	$CI->load->model('Message_model');
@@ -65,4 +34,5 @@ function simple_autoreply($sms)
 	$data['delivery_report'] = 'default';
 	$data['uid'] = $config['uid'];
 	$CI->Message_model->send_messages($data);
+	}
 }
diff --git a/application/plugins/sms_credit/sms_credit.php b/application/plugins/sms_credit/sms_credit.php
index 18f0d4ebe..a6901f8a6 100644
--- a/application/plugins/sms_credit/sms_credit.php
+++ b/application/plugins/sms_credit/sms_credit.php
@@ -11,45 +11,30 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for outgoing message
-add_action('message.outgoing_all', 'sms_credit', 10);
+class Sms_credit_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_credit_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_credit_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for outgoing message
+		add_filter('message.outgoing_all', array($this, 'sms_credit'), 10);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_credit_install()
-{
+	// ------------------------------------------------------------------------
+
+	/**
+	 * Install Plugin
+	 *
+	 * Anything that needs to happen when this plugin gets installed
+	 *
+	 * @access public
+	 * @since   0.1.0
+	 * @return bool    TRUE by default
+	 */
+	public static function install($data = NULL)
+	{
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -60,10 +45,10 @@ function sms_credit_install()
 		execute_sql(APPPATH.'plugins/sms_credit/media/'.$db_prop['file'].'_sms_credit.sql');
 	}
 	return TRUE;
-}
+    }
 
-function sms_credit($sms)
-{
+	function sms_credit($sms)
+	{
 	$CI = &get_instance();
 	$CI->load->model('Kalkun_model');
 	$CI->load->model('sms_credit/sms_credit_model', 'sms_credit_model');
@@ -90,4 +75,5 @@ function sms_credit($sms)
 		echo 'Sorry, your sms credit limit exceeded.';
 		exit;
 	}
+	}
 }
diff --git a/application/plugins/sms_member/sms_member.php b/application/plugins/sms_member/sms_member.php
index 161e04611..5f6aa43db 100644
--- a/application/plugins/sms_member/sms_member.php
+++ b/application/plugins/sms_member/sms_member.php
@@ -11,45 +11,30 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'sms_member', 13);
+class Sms_member_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_member_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_member_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'sms_member'), 13);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_member_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -60,10 +45,10 @@ function sms_member_install()
 		execute_sql(APPPATH.'plugins/sms_member/media/'.$db_prop['file'].'_sms_member.sql');
 	}
 	return TRUE;
-}
+	}
 
-function sms_member($sms)
-{
+	function sms_member($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('sms_member');
 	$message = $sms->TextDecoded;
 	$number = $sms->SenderNumber;
@@ -82,17 +67,17 @@ function sms_member($sms)
 			unregister_member($number);
 		}
 	}
-}
+	}
 
-// --------------------------------------------------------------------
+	// --------------------------------------------------------------------
 
-/**
- * Register member
- *
- * Register member's phone number
- */
-function register_member($number)
-{
+	/**
+	 * Register member
+	 *
+	 * Register member's phone number
+	 */
+	function register_member($number)
+	{
 	$CI = &get_instance();
 	$CI->load->model('sms_member/sms_member_model', 'sms_member_model');
 
@@ -101,17 +86,17 @@ function register_member($number)
 	{
 		$CI->sms_member_model->add_member($number);
 	}
-}
+	}
 
-// --------------------------------------------------------------------
+	// --------------------------------------------------------------------
 
-/**
- * Unregister member
- *
- * Unregister member's phone number
- */
-function unregister_member($number)
-{
+	/**
+	 * Unregister member
+	 *
+	 * Unregister member's phone number
+	 */
+	function unregister_member($number)
+	{
 	$CI = &get_instance();
 	$CI->load->model('sms_member/sms_member_model', 'sms_member_model');
 
@@ -120,4 +105,5 @@ function unregister_member($number)
 	{
 		$CI->sms_member_model->remove_member($number);
 	}
-}
+	}
+}
\ No newline at end of file
diff --git a/application/plugins/sms_to_email/sms_to_email.php b/application/plugins/sms_to_email/sms_to_email.php
index cf1377317..008d90b2d 100644
--- a/application/plugins/sms_to_email/sms_to_email.php
+++ b/application/plugins/sms_to_email/sms_to_email.php
@@ -11,45 +11,30 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.after', 'sms_to_email', 10);
+class Sms_to_email_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_to_email_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_to_email_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.after', array($this, 'sms_to_email'), 10);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_to_email_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -60,11 +45,10 @@ function sms_to_email_install()
 		execute_sql(APPPATH.'plugins/sms_to_email/media/'.$db_prop['file'].'_sms_to_email.sql');
 	}
 	return TRUE;
-}
-
+    }
 
-function sms_to_email($sms)
-{
+	function sms_to_email($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('sms_to_email');
 	$message = $sms->TextDecoded;
 	$from = $sms->SenderNumber;
@@ -100,4 +84,5 @@ function sms_to_email($sms)
 		$CI->email->message($message."\n\n". '- '.$from);
 		$CI->email->send();
 	}
+	}
 }
diff --git a/application/plugins/sms_to_twitter/sms_to_twitter.php b/application/plugins/sms_to_twitter/sms_to_twitter.php
index 37e50e439..0b65dde6a 100644
--- a/application/plugins/sms_to_twitter/sms_to_twitter.php
+++ b/application/plugins/sms_to_twitter/sms_to_twitter.php
@@ -11,45 +11,30 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'sms_to_twitter', 15);
+class Sms_to_twitter_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_to_twitter_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_to_twitter_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'sms_to_twitter'), 15);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_to_twitter_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -60,10 +45,10 @@ function sms_to_twitter_install()
 		execute_sql(APPPATH.'plugins/sms_to_twitter/media/'.$db_prop['file'].'_sms_to_twitter.sql');
 	}
 	return TRUE;
-}
+    }
 
-function sms_to_twitter($sms)
-{
+	function sms_to_twitter($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('sms_to_twitter');
 	$message = $sms->TextDecoded;
 	$number = $sms->SenderNumber;
@@ -88,4 +73,5 @@ function sms_to_twitter($sms)
 			$CI->twitter->call('statuses/update', array('status' => $twitter_msg));
 		}
 	}
-}
+	}
+}
\ No newline at end of file
diff --git a/application/plugins/sms_to_wordpress/sms_to_wordpress.php b/application/plugins/sms_to_wordpress/sms_to_wordpress.php
index c35a2f67e..bd392ba9d 100644
--- a/application/plugins/sms_to_wordpress/sms_to_wordpress.php
+++ b/application/plugins/sms_to_wordpress/sms_to_wordpress.php
@@ -12,45 +12,30 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'sms_to_wordpress', 16);
+class Sms_to_wordpress_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_to_wordpress_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_to_wordpress_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'sms_to_wordpress'), 16);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_to_wordpress_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -61,10 +46,10 @@ function sms_to_wordpress_install()
 		execute_sql(APPPATH.'plugins/sms_to_wordpress/media/'.$db_prop['file'].'_sms_to_wordpress.sql');
 	}
 	return TRUE;
-}
+    }
 
-function sms_to_wordpress($sms)
-{
+	function sms_to_wordpress($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('sms_to_wordpress');
 	$message = $sms->TextDecoded;
 	$number = $sms->SenderNumber;
@@ -108,4 +93,5 @@ function sms_to_wordpress($sms)
 			$res = $client->query('metaWeblog.newPost', '', $wp['wp_username'], $wp_pass, $post);
 		}
 	}
+	}
 }
diff --git a/application/plugins/sms_to_xmpp/sms_to_xmpp.php b/application/plugins/sms_to_xmpp/sms_to_xmpp.php
index 7e6c6dd3b..9ed4a574f 100644
--- a/application/plugins/sms_to_xmpp/sms_to_xmpp.php
+++ b/application/plugins/sms_to_xmpp/sms_to_xmpp.php
@@ -11,46 +11,31 @@
 
 require_once (APPPATH.'plugins/Plugin_helper.php');
 
-// Add hook for incoming message
-add_action('message.incoming.before', 'sms_to_xmpp', 17);
+class Sms_to_xmpp_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function sms_to_xmpp_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function sms_to_xmpp_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for incoming message
+		add_filter('message.incoming.before', array($this, 'sms_to_xmpp'), 17);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function sms_to_xmpp_install()
-{
-	$CI = &get_instance();
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
+ 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
 	if ( ! $CI->db->table_exists('plugin_sms_to_xmpp'))
@@ -60,10 +45,10 @@ function sms_to_xmpp_install()
 		execute_sql(APPPATH.'plugins/sms_to_xmpp/media/'.$db_prop['file'].'_sms_to_xmpp.sql');
 	}
 	return TRUE;
-}
+    }
 
-function sms_to_xmpp($sms)
-{
+	function sms_to_xmpp($sms)
+	{
 	$config = Plugin_helper::get_plugin_config('sms_to_xmpp');
 	$message = $sms->TextDecoded;
 	$number = $sms->SenderNumber;
@@ -91,4 +76,5 @@ function sms_to_xmpp($sms)
 				.$xampp_pass.' '.$xmpp['xmpp_host'].' '.$xmpp['xmpp_server'].' '.$to.' '.$xmpp_message);
 		}
 	}
+	}
 }
diff --git a/application/plugins/soap/soap.php b/application/plugins/soap/soap.php
index cc847f0d2..3f7c823c0 100644
--- a/application/plugins/soap/soap.php
+++ b/application/plugins/soap/soap.php
@@ -8,43 +8,23 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Soap_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function soap_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function soap_deactivate()
-{
-	return TRUE;
-}
+// ------------------------------------------------------------------------
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function soap_install()
-{
+	/**
+	 * Install Plugin
+	 *
+	 * Anything that needs to happen when this plugin gets installed
+	 *
+	 * @access public
+	 * @since   0.1.0
+	 * @return bool    TRUE by default
+	 */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -55,4 +35,5 @@ function soap_install()
 		execute_sql(APPPATH.'plugins/soap/media/'.$db_prop['file'].'_remote_access.sql');
 	}
 	return TRUE;
+    }
 }
diff --git a/application/plugins/stop_manager/stop_manager.php b/application/plugins/stop_manager/stop_manager.php
index d808025dc..59c8d14e4 100644
--- a/application/plugins/stop_manager/stop_manager.php
+++ b/application/plugins/stop_manager/stop_manager.php
@@ -15,38 +15,33 @@
 use Kalkun\Plugins\StopManager\MsgIncoming;
 use Kalkun\Plugins\StopManager\MsgOutgoing;
 
-// Add hook for outgoing message
-add_action('message.outgoing_dest_data', 'stop_manager_cleanup_outgoing', 1);
-add_action('message.incoming.before', 'stop_manager_incoming', 1);
+class Stop_manager_plugin extends CI3_plugin_system {
 
-function stop_manager_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function stop_manager_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for outgoing message
+		//add_action('message.outgoing_dest_data', 'stop_manager_cleanup_outgoing', 1);
+		add_filter('message.outgoing_dest_data', array($this, 'cleanup_outgoing'), 1);
+		//add_action('message.incoming.before', 'stop_manager_incoming', 1);
+		add_action('message.incoming.before', array($this, 'incoming'), 1);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function stop_manager_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exists
@@ -57,19 +52,18 @@ function stop_manager_install()
 		execute_sql(APPPATH.'plugins/stop_manager/media/'.$db_prop['file'].'_stop_manager.sql');
 	}
 	return TRUE;
-}
-
-
-/**
- * Cleanup the outgoing message
- *  - the list of recipient (remove those who have opted out)
- *  - the content (remove the type)
- *
- * @param array $all (an array containing $dest & $data)
- * @return array (an array containing $dest & $data)
- */
-function stop_manager_cleanup_outgoing($all)
-{
+    }
+
+	/**
+	 * Cleanup the outgoing message
+	 *  - the list of recipient (remove those who have opted out)
+	 *  - the content (remove the type)
+	 *
+	 * @param array $all (an array containing $dest & $data)
+	 * @return array (an array containing $dest & $data)
+	 */
+	public function cleanup_outgoing($all)
+	{
 	$stopCfg = Config::getInstance();
 	$stopMsgOutgoing = new MsgOutgoing($all);
 
@@ -103,16 +97,16 @@ function stop_manager_cleanup_outgoing($all)
 	$data['message'] = $stopMsgOutgoing->getCleanedMsg();
 
 	return array($dest, $data);
-}
+	}
 
-/**
- * Analyse an incoming message and store/remove in the Stop_manager database
- *
- * @param
- * @return void
- */
-function stop_manager_incoming($sms)
-{
+	/**
+	 * Analyse an incoming message and store/remove in the Stop_manager database
+	 *
+	 * @param
+	 * @return void
+	 */
+	public function incoming($sms)
+	{
 	// On message reception, if it is a STOP message (eg STOP rappel)
 	// Put it to the STOP table
 
@@ -139,20 +133,20 @@ function stop_manager_incoming($sms)
 		// Send auto reply
 		if ($stopCfg->isAutoreplyInfoEnabled())
 		{
-			autoreply($stopMsgIncoming->getParty(), $stopMsgIncoming->getAutoReplyMsg());
+			$this->autoreply($stopMsgIncoming->getParty(), $stopMsgIncoming->getAutoReplyMsg());
 		}
 	}
 	else
 	{
 		if ($stopCfg->isAutoreplyErrorEnabled())
 		{
-			autoreply($stopMsgIncoming->getParty(), $stopMsgIncoming->getAutoReplyMsg());
+			$this->autoreply($stopMsgIncoming->getParty(), $stopMsgIncoming->getAutoReplyMsg());
 		}
 	}
-}
+	}
 
-function autoreply($tel, $reply_msg)
-{
+	private function autoreply($tel, $reply_msg)
+	{
 	$config = Config::getInstance()->getConfig();
 
 	$ret = NULL;
@@ -175,4 +169,5 @@ function autoreply($tel, $reply_msg)
 		$data['uid'] = '1';
 		$CI->Message_model->send_messages($data);
 	}
+	}
 }
diff --git a/application/plugins/welcome/welcome.php b/application/plugins/welcome/welcome.php
index 14c509d28..2c7e48f85 100644
--- a/application/plugins/welcome/welcome.php
+++ b/application/plugins/welcome/welcome.php
@@ -8,42 +8,61 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Welcome_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function welcome_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function welcome_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hooks here like add_action, or add_filter...
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function welcome_install()
-{
-	return TRUE;
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
+        return TRUE;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Activate Plugin
+     *
+     * Anything that needs to happen when this plugin gets activate
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public function activate($data = NULL)
+    {
+        return TRUE;
+    }
+
+    // ------------------------------------------------------------------------
+
+    /**
+     * Deactivate Plugin
+     *
+     * Anything that needs to happen when this plugin gets deactivate
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public function deactivate($data = NULL)
+    {
+        return TRUE;
+    }
 }
diff --git a/application/plugins/whitelist_number/whitelist_number.php b/application/plugins/whitelist_number/whitelist_number.php
index 390fbb2db..5b791ccaa 100644
--- a/application/plugins/whitelist_number/whitelist_number.php
+++ b/application/plugins/whitelist_number/whitelist_number.php
@@ -8,37 +8,30 @@
 * Author URI: https://bitbucket.org/maxsamael
 */
 
-// Add hook for outgoing message
-add_action('message.outgoing', 'whitelist_number_outgoing', 1);
+class Whitelist_number_plugin extends CI3_plugin_system {
 
-function whitelist_number_activate()
-{
-	return TRUE;
-}
+	use plugin_trait;
 
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function whitelist_number_deactivate()
-{
-	return TRUE;
-}
+	public function __construct()
+	{
+		parent::__construct();
+		// Add hook for outgoing message
+		add_filter('message.outgoing', array($this, 'whitelist_number_outgoing'), 1);
+	}
 
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function whitelist_number_install()
-{
+	// ------------------------------------------------------------------------
+
+    /**
+     * Install Plugin
+     *
+     * Anything that needs to happen when this plugin gets installed
+     *
+     * @access public
+     * @since   0.1.0
+     * @return bool    TRUE by default
+     */
+    public static function install($data = NULL)
+    {
 	$CI = &get_instance();
 	$CI->load->helper('kalkun');
 	// check if table already exist
@@ -49,10 +42,10 @@ function whitelist_number_install()
 		execute_sql(APPPATH.'plugins/whitelist_number/media/'.$db_prop['file'].'_whitelist_number.sql');
 	}
 	return TRUE;
-}
+    }
 
-function whitelist_number_outgoing($numbers = array())
-{
+	function whitelist_number_outgoing($numbers = array())
+	{
 	$CI = &get_instance();
 	$CI->load->model('whitelist_number/whitelist_number_model', 'whitelist_number_model');
 	$heaven = array();
@@ -80,4 +73,5 @@ function whitelist_number_outgoing($numbers = array())
 		}
 	}
 	return $numbers;
+	}
 }
diff --git a/application/plugins/xmlrpc/xmlrpc.php b/application/plugins/xmlrpc/xmlrpc.php
index 083ac77e2..b28305b2d 100644
--- a/application/plugins/xmlrpc/xmlrpc.php
+++ b/application/plugins/xmlrpc/xmlrpc.php
@@ -8,42 +8,7 @@
 * Author URI: http://azhari.harahap.us
 */
 
+class Xmlrpc_plugin extends CI3_plugin_system {
 
-/**
-* Function called when plugin first activated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_activate
-*
-*/
-function xmlrpc_activate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin deactivated
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_deactivate
-*
-*/
-function xmlrpc_deactivate()
-{
-	return TRUE;
-}
-
-/**
-* Function called when plugin first installed into the database
-* Utility function must be prefixed with the plugin name
-* followed by an underscore.
-*
-* Format: pluginname_install
-*
-*/
-function xmlrpc_install()
-{
-	return TRUE;
+	use plugin_trait;
 }
diff --git a/application/sql/mysql/kalkun.sql b/application/sql/mysql/kalkun.sql
index 666762d48..93639c1fa 100644
--- a/application/sql/mysql/kalkun.sql
+++ b/application/sql/mysql/kalkun.sql
@@ -235,16 +235,17 @@ INSERT INTO `b8_wordlist` (`token`, `count_ham`, `count_spam`) VALUES ('b8*texts
 
 CREATE TABLE IF NOT EXISTS `plugins` (
   `plugin_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-  `plugin_system_name` varchar(191) NOT NULL,
-  `plugin_name` varchar(191) NOT NULL,
-  `plugin_uri` varchar(120) DEFAULT NULL,
-  `plugin_version` varchar(30) NOT NULL,
-  `plugin_description` text,
-  `plugin_author` varchar(120) DEFAULT NULL,
-  `plugin_author_uri` varchar(120) DEFAULT NULL,
-  `plugin_data` longtext,
+  `system_name` varchar(191) NOT NULL,
+  `name` varchar(191) NOT NULL,
+  `status` tinyint(1) NOT NULL DEFAULT '1',
+  `uri` varchar(120) DEFAULT NULL,
+  `version` varchar(30) NOT NULL,
+  `description` text,
+  `author` varchar(120) DEFAULT NULL,
+  `author_uri` varchar(120) DEFAULT NULL,
+  `data` longtext,
   PRIMARY KEY (`plugin_id`),
-  UNIQUE KEY `plugin_index` (`plugin_system_name`) USING BTREE
+  UNIQUE KEY `plugin_index` (`system_name`) USING BTREE
 )  DEFAULT CHARSET=utf8mb4;
 
 
diff --git a/application/sql/mysql/upgrade_kalkun_0.8.3.sql b/application/sql/mysql/upgrade_kalkun_0.8.3.sql
new file mode 100644
index 000000000..73d643008
--- /dev/null
+++ b/application/sql/mysql/upgrade_kalkun_0.8.3.sql
@@ -0,0 +1,19 @@
+-- --------------------------------------------------------
+
+--
+-- Upgrade plugins table to conform to the new CI3 plugin system
+--
+
+START TRANSACTION;
+ALTER TABLE `plugins`
+  RENAME COLUMN `plugin_system_name` TO `system_name`,
+  RENAME COLUMN `plugin_name` TO `name`,
+  RENAME COLUMN `plugin_uri` TO `uri`,
+  RENAME COLUMN `plugin_version` TO `version`,
+  RENAME COLUMN `plugin_description` TO `description`,
+  RENAME COLUMN `plugin_author` TO `author`,
+  RENAME COLUMN `plugin_author_uri` TO `author_uri`,
+  RENAME COLUMN `plugin_data` TO `data`,
+  ADD COLUMN `status` tinyint(1) NOT NULL DEFAULT '1'
+  AFTER `name`;
+COMMIT;
diff --git a/application/sql/pgsql/kalkun.sql b/application/sql/pgsql/kalkun.sql
index 9d7238cd3..27e80dbfd 100644
--- a/application/sql/pgsql/kalkun.sql
+++ b/application/sql/pgsql/kalkun.sql
@@ -109,15 +109,16 @@ insert into "b8_wordlist" ("token", "count_ham", "count_spam") values ('b8*texts
 
 CREATE TABLE "plugins" (
   "plugin_id" serial PRIMARY KEY,
-  "plugin_system_name" varchar(255) NOT NULL,
-  "plugin_name" varchar(255) DEFAULT NULL,
-  "plugin_uri" varchar(120) DEFAULT NULL,
-  "plugin_version" varchar(30) DEFAULT NULL,
-  "plugin_description" text,
-  "plugin_author" varchar(120) DEFAULT NULL,
-  "plugin_author_uri" varchar(120) DEFAULT NULL,
-  "plugin_data" text,
-  UNIQUE("plugin_system_name")
+  "system_name" varchar(255) NOT NULL,
+  "name" varchar(255) DEFAULT NULL,
+  "status" smallint NOT NULL DEFAULT 1,
+  "uri" varchar(120) DEFAULT NULL,
+  "version" varchar(30) DEFAULT NULL,
+  "description" text,
+  "author" varchar(120) DEFAULT NULL,
+  "author_uri" varchar(120) DEFAULT NULL,
+  "data" text,
+  UNIQUE("system_name")
 );
 
 CREATE TABLE "user_forgot_password" (
diff --git a/application/sql/pgsql/upgrade_kalkun_0.8.3.sql b/application/sql/pgsql/upgrade_kalkun_0.8.3.sql
new file mode 100644
index 000000000..386b003f1
--- /dev/null
+++ b/application/sql/pgsql/upgrade_kalkun_0.8.3.sql
@@ -0,0 +1,17 @@
+-- --------------------------------------------------------
+
+--
+-- Upgrade plugins table to conform to the new CI3 plugin system
+--
+
+BEGIN;
+ALTER TABLE "plugins" RENAME COLUMN "plugin_system_name" TO "system_name";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_name" TO "name";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_uri" TO "uri";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_version" TO "version";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_description" TO "description";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_author" TO "author";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_author_uri" TO "author_uri";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_data" TO "data";
+ALTER TABLE "plugins" ADD COLUMN "status" smallint NOT NULL DEFAULT 1;
+COMMIT;
diff --git a/application/sql/sqlite/kalkun.sql b/application/sql/sqlite/kalkun.sql
index 2ebafd411..bc3a68d74 100644
--- a/application/sql/sqlite/kalkun.sql
+++ b/application/sql/sqlite/kalkun.sql
@@ -109,14 +109,15 @@ insert into b8_wordlist (token, count_ham, count_spam) values ('b8*texts', 0, 0)
 
 CREATE TABLE "plugins" (
   "plugin_id" INTEGER PRIMARY KEY AUTOINCREMENT,
-  "plugin_system_name" VARCHAR(255) NOT NULL UNIQUE,
-  "plugin_name" VARCHAR(255) NOT NULL,
-  "plugin_uri" VARCHAR(120) DEFAULT NULL,
-  "plugin_version" VARCHAR(30) NOT NULL,
-  "plugin_description" TEXT,
-  "plugin_author" VARCHAR(120) DEFAULT NULL,
-  "plugin_author_uri" VARCHAR(120) DEFAULT NULL,
-  "plugin_data" TEXT
+  "system_name" VARCHAR(255) NOT NULL UNIQUE,
+  "name" VARCHAR(255) NOT NULL,
+  "status" TINYINT(1) NOT NULL DEFAULT '1',
+  "uri" VARCHAR(120) DEFAULT NULL,
+  "version" VARCHAR(30) NOT NULL,
+  "description" TEXT,
+  "author" VARCHAR(120) DEFAULT NULL,
+  "author_uri" VARCHAR(120) DEFAULT NULL,
+  "data" TEXT
 );
 
 CREATE TABLE "user_forgot_password" (
diff --git a/application/sql/sqlite/upgrade_kalkun_0.8.3.sql b/application/sql/sqlite/upgrade_kalkun_0.8.3.sql
new file mode 100644
index 000000000..732c2eafd
--- /dev/null
+++ b/application/sql/sqlite/upgrade_kalkun_0.8.3.sql
@@ -0,0 +1,17 @@
+-- --------------------------------------------------------
+
+--
+-- Upgrade plugins table to conform to the new CI3 plugin system
+--
+
+BEGIN TRANSACTION;
+ALTER TABLE "plugins" RENAME COLUMN "plugin_system_name" TO "system_name";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_name" TO "name";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_uri" TO "uri";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_version" TO "version";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_description" TO "description";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_author" TO "author";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_author_uri" TO "author_uri";
+ALTER TABLE "plugins" RENAME COLUMN "plugin_data" TO "data";
+ALTER TABLE "plugins" ADD COLUMN "status" smallint(1) NOT NULL DEFAULT 1;
+COMMIT;
diff --git a/application/views/main/base.php b/application/views/main/base.php
index c993879fc..5065ad089 100644
--- a/application/views/main/base.php
+++ b/application/views/main/base.php
@@ -62,9 +62,8 @@
 					echo htmlentities($this->agent->browser(), ENT_QUOTES), ' ', htmlentities($this->agent->version(), ENT_QUOTES) ; ?>`
 			
* Plugins: `load->model('Plugin_model'); - $installed_plugins = array_column($this->Plugin_model->get_plugins()->result_array(), 'plugin_system_name'); - echo htmlentities(implode(', ', $installed_plugins), ENT_QUOTES); + $this->load->library('Plugins_lib_kalkun'); + echo htmlentities(implode(', ', array_keys($this->plugins_lib_kalkun->get_enabled_plugins())), ENT_QUOTES); ?>`

diff --git a/application/views/main/phonebook/contact/pbk_list.php b/application/views/main/phonebook/contact/pbk_list.php index 5111cd3f6..34347f082 100644 --- a/application/views/main/phonebook/contact/pbk_list.php +++ b/application/views/main/phonebook/contact/pbk_list.php @@ -24,7 +24,7 @@ '.htmlentities($menu['title'], ENT_QUOTES).' '; diff --git a/application/views/main/plugin/index.php b/application/views/main/plugin/index.php index d08cc498d..28e02a21c 100644 --- a/application/views/main/plugin/index.php +++ b/application/views/main/plugin/index.php @@ -15,31 +15,31 @@ 0) { - foreach ($plugins as $tmp) + foreach ($plugins as $plugin) { if ($type === 'installed' - && file_exists(APPPATH . 'plugins/'.$tmp['plugin_system_name'].'/controllers/'.ucfirst($tmp['plugin_system_name']).'.php') - && $tmp['plugin_controller_has_index'] === TRUE) + && file_exists(APPPATH . 'plugins/'.$plugin->system_name.'/controllers/'.ucfirst($plugin->system_name).'.php') + && $plugin->controller_has_index === TRUE) { - echo '

'.anchor('plugin/'.rawurlencode($tmp['plugin_system_name']), htmlentities($tmp['plugin_name'], ENT_QUOTES)).'

'; + echo '

'.anchor('plugin/'.rawurlencode($plugin->system_name), htmlentities($plugin->name, ENT_QUOTES)).'

'; } else { - echo '

'.htmlentities($tmp['plugin_name'], ENT_QUOTES).'

'; + echo '

'.htmlentities($plugin->name, ENT_QUOTES).'

'; } ?>
- + - +
- :    - : + : version, ENT_QUOTES); ?>   + : author_uri, ENT_QUOTES), htmlentities($plugin->author, ENT_QUOTES)); ?>
-

+

description, ENT_QUOTES); ?>


CodeIgniter extra: - * CI-Plugin-System commit c7c6b6d19b198cff6f1723f6911d317232a97fdd (2013-09-23) + * CI3_Plugin_System, commit 65468cf92ce30e73db1041fb6c0feba347205277 (2015-09-25) * HMVC 5.3.5 commit #2d6d33922276 jQuery 3.7.1 jQuery UI 1.13.2 diff --git a/utils/php-cs-fixer-configs/finder.inc.php b/utils/php-cs-fixer-configs/finder.inc.php index eca546433..c8d4f23fb 100644 --- a/utils/php-cs-fixer-configs/finder.inc.php +++ b/utils/php-cs-fixer-configs/finder.inc.php @@ -27,6 +27,7 @@ //->notPath('config/routes.php') ->notPath('config/smileys.php') ->notPath('config/user_agents.php') + ->notPath('models/Plugins_model.php') ->in('application') //->in(__DIR__) ;