1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-11-03 19:37:16 -05:00

Added plugin load list as preference, moved python hooks

This commit is contained in:
James Booth 2013-08-17 22:42:44 +01:00
parent 140a2ad0e3
commit 580b14ab68
8 changed files with 245 additions and 99 deletions

View File

@ -24,7 +24,8 @@ profanity_SOURCES = \
src/config/theme.c src/config/theme.h \
src/plugins/plugins.h src/plugins/plugins.c \
src/plugins/api.h src/plugins/api.c \
src/plugins/callbacks.h src/plugins/callbacks.c
src/plugins/callbacks.h src/plugins/callbacks.c \
src/plugins/python_plugins.h src/plugins/python_plugins.c
TESTS = tests/testsuite
check_PROGRAMS = tests/testsuite

View File

@ -257,6 +257,19 @@ prefs_set_autoaway_time(gint value)
_save_prefs();
}
gchar **
prefs_get_plugins(void)
{
if (!g_key_file_has_group(prefs, "plugins")) {
return NULL;
}
if (!g_key_file_has_key(prefs, "plugins", "load", NULL)) {
return NULL;
}
return g_key_file_get_string_list(prefs, "plugins", "load", NULL, NULL);
}
static void
_save_prefs(void)
{

View File

@ -84,6 +84,8 @@ gint prefs_get_autoping(void);
gint prefs_get_autoaway_time(void);
void prefs_set_autoaway_time(gint value);
gchar** prefs_get_plugins(void);
void prefs_add_login(const char *jid);
gboolean prefs_get_boolean(preference_t pref);

View File

@ -134,7 +134,7 @@ api_send_line(PyObject *self, PyObject *args)
}
static PyObject *
api_get_current_recipient(void)
api_get_current_recipient(PyObject *self, PyObject *args)
{
win_type_t win_type = ui_current_win_type();
if (win_type == WIN_CHAT) {

View File

@ -22,74 +22,104 @@
#include <Python.h>
#include "config/preferences.h"
#include "plugins/api.h"
#include "plugins/callbacks.h"
#include "plugins/plugins.h"
#include "plugins/python_plugins.h"
#include "ui/ui.h"
static GSList* _get_module_names(void);
static void _run_plugins(const char * const function, PyObject *p_args);
static GSList* plugins;
static void
_check_error(void)
{
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}
void
plugins_init(void)
{
plugins = NULL;
PyObject *p_module;
GSList *module_names = _get_module_names();
// initialse python and path
Py_Initialize();
_check_error();
python_check_error();
api_init();
_check_error();
python_check_error();
// TODO change to use XDG spec
GString *path = g_string_new(Py_GetPath());
g_string_append(path, ":./plugins/");
PySys_SetPath(path->str);
_check_error();
python_check_error();
g_string_free(path, TRUE);
if (module_names != NULL) {
cons_show("Loading plugins...");
GSList *module_name = module_names;
while (module_name != NULL) {
p_module = PyImport_ImportModule(module_name->data);
_check_error();
if (p_module != NULL) {
cons_show("Loaded plugin: %s", module_name->data);
plugins = g_slist_append(plugins, p_module);
// load plugins
gchar **plugins_load = prefs_get_plugins();
if (plugins_load != NULL) {
int i;
for (i = 0; i < g_strv_length(plugins_load); i++)
{
gchar *filename = plugins_load[i];
if (g_str_has_suffix(filename, ".py")) {
gchar *module_name = g_strndup(filename, strlen(filename) - 3);
p_module = PyImport_ImportModule(module_name);
python_check_error();
if (p_module != NULL) {
cons_show("Loaded plugin: %s", module_name);
ProfPlugin *plugin = malloc(sizeof(ProfPlugin));
plugin->name = module_name;
plugin->lang = PYTHON;
plugin->module = p_module;
plugin->init_func = python_init_hook;
plugin->on_start_func = python_on_start_hook;
plugin->on_connect_func = python_on_connect_hook;
plugin->on_message_func = python_on_message_hook;
plugins = g_slist_append(plugins, plugin);
}
g_free(module_name);
}
module_name = g_slist_next(module_name);
}
PyObject *p_args = Py_BuildValue("ss", PACKAGE_VERSION, PACKAGE_STATUS);
_run_plugins("prof_init", p_args);
Py_XDECREF(p_args);
_check_error();
// initialise plugins
GSList *curr = plugins;
while (curr != NULL) {
ProfPlugin *plugin = curr->data;
plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS);
python_check_error();
curr = g_slist_next(curr);
}
}
return;
}
void
plugins_on_start(void)
{
_run_plugins("prof_on_start", NULL);
_check_error();
GSList *curr = plugins;
while (curr != NULL) {
ProfPlugin *plugin = curr->data;
plugin->on_start_func(plugin);
curr = g_slist_next(curr);
}
}
void
plugins_on_connect(void)
{
GSList *curr = plugins;
while (curr != NULL) {
ProfPlugin *plugin = curr->data;
plugin->on_connect_func(plugin);
curr = g_slist_next(curr);
}
}
void
plugins_on_message(const char * const jid, const char * const message)
{
GSList *curr = plugins;
while (curr != NULL) {
ProfPlugin *plugin = curr->data;
plugin->on_message_func(plugin, jid, message);
curr = g_slist_next(curr);
}
}
void
@ -97,63 +127,3 @@ plugins_shutdown(void)
{
Py_Finalize();
}
void
plugins_on_connect(void)
{
_run_plugins("prof_on_connect", NULL);
}
void
plugins_on_message(const char * const jid, const char * const message)
{
PyObject *p_args = Py_BuildValue("ss", jid, message);
_run_plugins("prof_on_message", p_args);
Py_XDECREF(p_args);
}
static GSList *
_get_module_names(void)
{
GSList *result = NULL;
// TODO change to use XDG
GDir *plugins_dir = g_dir_open("./plugins", 0, NULL);
if (plugins_dir != NULL) {
const gchar *file = g_dir_read_name(plugins_dir);
while (file != NULL) {
if (g_str_has_suffix(file, ".py")) {
gchar *module_name = g_strndup(file, strlen(file) - 3);
result = g_slist_append(result, module_name);
}
file = g_dir_read_name(plugins_dir);
}
g_dir_close(plugins_dir);
return result;
} else {
return NULL;
}
}
static void
_run_plugins(const char * const function, PyObject *p_args)
{
GSList *plugin = plugins;
PyObject *p_function;
while (plugin != NULL) {
PyObject *p_module = plugin->data;
if (PyObject_HasAttrString(p_module, function)) {
p_function = PyObject_GetAttrString(p_module, function);
_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, p_args);
_check_error();
Py_XDECREF(p_function);
}
}
plugin = g_slist_next(plugin);
}
}

View File

@ -23,6 +23,22 @@
#ifndef PLUGINS_H
#define PLUGINS_H
typedef enum {
PYTHON
} lang_t;
typedef struct prof_plugin_t {
char *name;
lang_t lang;
void *module;
void (*init_func)(struct prof_plugin_t* plugin, const char * const version,
const char * const status);
void (*on_start_func)(struct prof_plugin_t* plugin);
void (*on_connect_func)(struct prof_plugin_t* plugin);
void (*on_message_func)(struct prof_plugin_t* plugin,
const char * const jid, const char * const message);
} ProfPlugin;
void plugins_init(void);
void plugins_on_start(void);
void plugins_on_connect(void);

View File

@ -0,0 +1,109 @@
/*
* python_plugins.c
*
* Copyright (C) 2012, 2013 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <Python.h>
#include "config/preferences.h"
#include "plugins/api.h"
#include "plugins/callbacks.h"
#include "plugins/plugins.h"
#include "plugins/python_plugins.h"
#include "ui/ui.h"
void
python_init_hook(ProfPlugin *plugin, const char * const version, const char * const status)
{
PyObject *p_args = Py_BuildValue("ss", version, status);
PyObject *p_function;
PyObject *p_module = plugin->module;
if (PyObject_HasAttrString(p_module, "prof_init")) {
p_function = PyObject_GetAttrString(p_module, "prof_init");
python_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, p_args);
python_check_error();
Py_XDECREF(p_function);
}
}
}
void
python_on_start_hook(ProfPlugin *plugin)
{
PyObject *p_function;
PyObject *p_module = plugin->module;
if (PyObject_HasAttrString(p_module, "prof_on_start")) {
p_function = PyObject_GetAttrString(p_module, "prof_on_start");
python_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, NULL);
python_check_error();
Py_XDECREF(p_function);
}
}
}
void
python_on_connect_hook(ProfPlugin *plugin)
{
PyObject *p_function;
PyObject *p_module = plugin->module;
if (PyObject_HasAttrString(p_module, "prof_on_connect")) {
p_function = PyObject_GetAttrString(p_module, "prof_on_connect");
python_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, NULL);
python_check_error();
Py_XDECREF(p_function);
}
}
}
void
python_on_message_hook(ProfPlugin *plugin, const char * const jid, const char * const message)
{
PyObject *p_args = Py_BuildValue("ss", jid, message);
PyObject *p_function;
PyObject *p_module = plugin->module;
if (PyObject_HasAttrString(p_module, "prof_on_message")) {
p_function = PyObject_GetAttrString(p_module, "prof_on_message");
python_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, p_args);
python_check_error();
Py_XDECREF(p_function);
}
}
}
void
python_check_error(void)
{
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}

View File

@ -0,0 +1,35 @@
/*
* python_plugins.h
*
* Copyright (C) 2012, 2013 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PYTHON_PLUGINS_H
#define PYTHON_PLUGINS_H
#include "plugins/plugins.h"
void python_init_hook(ProfPlugin *plugin, const char * const version, const char * const status);
void python_on_start_hook(ProfPlugin *plugin);
void python_on_connect_hook(ProfPlugin *plugin);
void python_on_message_hook(ProfPlugin *plugin, const char * const jid, const char * const message);
void python_check_error(void);
#endif