mirror of
https://github.com/profanity-im/profanity.git
synced 2024-12-04 14:46:46 -05:00
Adding plugin interface for C files.
Implementation of hooks using C interface basedon dlfcn. Added test plugin and makefile to build it. In order to test it add the followin into your profrc: [plugins] load=test-c-plugin.so and execute profanity piping stderr to some file. The file should contain all entries whenever the plugin function is triggered. It seem to be workin but some parts are missing.
This commit is contained in:
parent
ffb565a16a
commit
705a946882
@ -26,6 +26,7 @@ profanity_SOURCES = \
|
||||
src/plugins/api.h src/plugins/api.c \
|
||||
src/plugins/callbacks.h src/plugins/callbacks.c \
|
||||
src/plugins/python_plugins.h src/plugins/python_plugins.c \
|
||||
src/plugins/c_plugins.h src/plugins/c_plugins.c \
|
||||
src/plugins/python_api.h src/plugins/python_api.c
|
||||
|
||||
TESTS = tests/testsuite
|
||||
@ -57,6 +58,7 @@ tests_testsuite_SOURCES = \
|
||||
src/plugins/api.h src/plugins/api.c \
|
||||
src/plugins/callbacks.h src/plugins/callbacks.c \
|
||||
src/plugins/python_plugins.h src/plugins/python_plugins.c \
|
||||
src/plugins/c_plugins.h src/plugins/c_plugins.c \
|
||||
src/plugins/python_api.h src/plugins/python_api.c \
|
||||
tests/test_roster.c tests/test_common.c tests/test_history.c \
|
||||
tests/test_autocomplete.c tests/testsuite.c tests/test_parser.c \
|
||||
|
@ -88,7 +88,7 @@ if test "x$enable_notifications" != xno; then
|
||||
fi
|
||||
|
||||
# Default parameters
|
||||
AM_CFLAGS="-Wall -I/usr/include/python2.7 -I/usr/include/python2.7 -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -L/usr/lib/python2.7/config -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions"
|
||||
AM_CFLAGS="-Wall -I/usr/include/python2.7 -I/usr/include/python2.7 -fno-strict-aliasing -DNDEBUG -g -fwrapv -O0 -Wall -Wstrict-prototypes -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -L/usr/lib/python2.7/config -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions"
|
||||
if test "x$PACKAGE_STATUS" = xdevelopment; then
|
||||
# AM_CFLAGS="$AM_CFLAGS -Wunused -Werror"
|
||||
AM_CFLAGS="$AM_CFLAGS -Wunused"
|
||||
|
12
plugins/test-c-plugin/Makefile
Normal file
12
plugins/test-c-plugin/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
all: test-c-plugin.so
|
||||
|
||||
%.so:%.o
|
||||
$(CC) -shared -fpic -o $@ $^
|
||||
|
||||
%.o:%.c
|
||||
$(CC) $(INCLUDE) -D_GNU_SOURCE -D_BSD_SOURCE -fpic -O3 -std=c99 \
|
||||
-Wall -Wextra -pedantic -c -o $@ $<
|
||||
|
||||
clean:
|
||||
$(RM) test-c-plugin.so
|
31
plugins/test-c-plugin/test-c-plugin.c
Normal file
31
plugins/test-c-plugin/test-c-plugin.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static FILE * f = NULL;
|
||||
|
||||
void
|
||||
prof_init (const char * const version, const char * const status)
|
||||
{
|
||||
fprintf (stderr, "called %s with args=<%s, %s>\n", __func__, version, status);
|
||||
}
|
||||
|
||||
void
|
||||
prof_on_start (void)
|
||||
{
|
||||
fprintf (stderr, "called %s with no args\n", __func__);
|
||||
}
|
||||
|
||||
void
|
||||
prof_on_connect (void)
|
||||
{
|
||||
fprintf (stderr, "called %s with no args\n", __func__);
|
||||
}
|
||||
|
||||
void
|
||||
c_on_message_received (const char * const jid, const char * const message)
|
||||
{
|
||||
fprintf (stderr, "called %s with args=<%s, %s>\n", __func__, jid, message);
|
||||
}
|
||||
|
||||
|
123
src/plugins/c_plugins.c
Normal file
123
src/plugins/c_plugins.c
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
#include "config/preferences.h"
|
||||
#include "plugins/api.h"
|
||||
#include "plugins/callbacks.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/c_plugins.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
// FIXME on windows this might be a different header
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
ProfPlugin *
|
||||
c_plugin_create(const char * const filename)
|
||||
{
|
||||
ProfPlugin *plugin;
|
||||
void * handle = NULL;
|
||||
char * path = NULL;
|
||||
|
||||
// FIXME so where is the right path for the plugin dir?
|
||||
if (-1 == asprintf (&path, "./plugins/%s", filename)) {
|
||||
log_warning ("asprintf failed, plugin %s not loaded", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
handle = dlopen (path, RTLD_NOW | RTLD_GLOBAL);
|
||||
|
||||
if (!handle) {
|
||||
log_warning ("dlopen failed to open `%s', %s", filename, dlerror ());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin = malloc(sizeof(ProfPlugin));
|
||||
plugin->name = g_strdup(filename);
|
||||
plugin->lang = C;
|
||||
plugin->module = handle;
|
||||
plugin->init_func = c_init_hook;
|
||||
plugin->on_start_func = c_on_start_hook;
|
||||
plugin->on_connect_func = c_on_connect_hook;
|
||||
plugin->on_message_received_func = c_on_message_received_hook;
|
||||
|
||||
if (!path)
|
||||
free (path);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void
|
||||
c_init_hook(ProfPlugin *plugin, const char * const version, const char * const status)
|
||||
{
|
||||
void * f = NULL;
|
||||
void (*func)(const char * const __version, const char * const __status);
|
||||
|
||||
assert (plugin && plugin->module);
|
||||
|
||||
if (NULL == (f = dlsym (plugin->module, "prof_init"))) {
|
||||
log_warning ("warning: %s does not have init function", plugin->name);
|
||||
return ;
|
||||
}
|
||||
|
||||
func = (void (*)(const char * const, const char * const))f;
|
||||
|
||||
// FIXME maybe we want to make it boolean to see if it succeeded or not?
|
||||
func (version, status);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
c_on_start_hook (ProfPlugin *plugin)
|
||||
{
|
||||
void * f = NULL;
|
||||
void (*func)(void);
|
||||
assert (plugin && plugin->module);
|
||||
|
||||
if (NULL == (f = dlsym (plugin->module, "prof_on_start")))
|
||||
return ;
|
||||
|
||||
func = (void (*)(void)) f;
|
||||
func ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
c_on_connect_hook (ProfPlugin *plugin)
|
||||
{
|
||||
void * f = NULL;
|
||||
void (*func)(void);
|
||||
assert (plugin && plugin->module);
|
||||
|
||||
if (NULL == (f = dlsym (plugin->module, "prof_on_connect")))
|
||||
return ;
|
||||
|
||||
func = (void (*)(void)) f;
|
||||
func ();
|
||||
}
|
||||
|
||||
|
||||
// FIXME wooow, if the message is cosntant, then how could I possibly fiddle around with it?
|
||||
void
|
||||
c_on_message_received_hook(ProfPlugin *plugin, const char * const jid, const char * const message)
|
||||
{
|
||||
void * f = NULL;
|
||||
void (*func)(const char * const __jid, const char * const __message);
|
||||
assert (plugin && plugin->module);
|
||||
|
||||
if (NULL == (f = dlsym (plugin->module, "prof_on_message_received")))
|
||||
return;
|
||||
|
||||
func = (void (*)(const char * const, const char * const)) f;
|
||||
func (jid, message);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
c_close_library (ProfPlugin * plugin)
|
||||
{
|
||||
assert (plugin && plugin->module);
|
||||
|
||||
if (dlclose (plugin->module))
|
||||
log_warning ("dlclose failed to close `%s' with `%s'", plugin->name, dlerror ());
|
||||
}
|
14
src/plugins/c_plugins.h
Normal file
14
src/plugins/c_plugins.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef C_PLUGINS_H
|
||||
#define C_PLUGINS_H
|
||||
|
||||
#include "plugins/plugins.h"
|
||||
|
||||
ProfPlugin* c_plugin_create(const char * const filename);
|
||||
|
||||
void c_init_hook(ProfPlugin *plugin, const char * const version, const char * const status);
|
||||
void c_on_start_hook (ProfPlugin *plugin);
|
||||
void c_on_connect_hook (ProfPlugin *plugin);
|
||||
void c_on_message_received_hook(ProfPlugin *plugin, const char * const jid, const char * const message);
|
||||
void c_close_library (ProfPlugin * plugin);
|
||||
|
||||
#endif
|
@ -25,8 +25,11 @@
|
||||
#include "plugins/plugins.h"
|
||||
#include "plugins/python_api.h"
|
||||
#include "plugins/python_plugins.h"
|
||||
#include "plugins/c_plugins.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
|
||||
|
||||
static GSList* plugins;
|
||||
|
||||
void
|
||||
@ -47,7 +50,16 @@ plugins_init(void)
|
||||
ProfPlugin *plugin = python_plugin_create(filename);
|
||||
if (plugin != NULL) {
|
||||
plugins = g_slist_append(plugins, plugin);
|
||||
cons_show("Loaded plugin: %s", filename);
|
||||
cons_show("Loaded python plugin: %s", filename);
|
||||
}
|
||||
// TODO include configure option to vary on windows and
|
||||
// unix i.e. so, dll, or maybe we can come up with unified
|
||||
// shared library plugin name... dunno...
|
||||
} else if (g_str_has_suffix(filename, ".so")) {
|
||||
ProfPlugin *plugin = c_plugin_create(filename);
|
||||
if (plugin != NULL) {
|
||||
plugins = g_slist_append(plugins, plugin);
|
||||
cons_show("Loaded C plugin: %s", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,7 +68,9 @@ plugins_init(void)
|
||||
GSList *curr = plugins;
|
||||
while (curr != NULL) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
|
||||
plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS);
|
||||
// TODO well, it should be more of a generic check error here
|
||||
python_check_error();
|
||||
curr = g_slist_next(curr);
|
||||
}
|
||||
@ -101,5 +115,19 @@ plugins_on_message_received(const char * const jid, const char * const message)
|
||||
void
|
||||
plugins_shutdown(void)
|
||||
{
|
||||
GSList *curr = plugins;
|
||||
|
||||
python_shutdown();
|
||||
|
||||
//FIXME do we need to clean the plugins list?
|
||||
//for the time being I'll just call dlclose for
|
||||
//every C plugin.
|
||||
|
||||
while (curr != NULL) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
if (plugin->lang == C)
|
||||
c_close_library (plugin);
|
||||
|
||||
curr = g_slist_next(curr);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,8 @@
|
||||
#define PLUGINS_H
|
||||
|
||||
typedef enum {
|
||||
PYTHON
|
||||
PYTHON,
|
||||
C
|
||||
} lang_t;
|
||||
|
||||
typedef struct prof_plugin_t {
|
||||
|
Loading…
Reference in New Issue
Block a user