1
0
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:
Artem Shinkarov 2013-08-18 03:55:20 +01:00
parent ffb565a16a
commit 705a946882
8 changed files with 214 additions and 3 deletions

View File

@ -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 \

View File

@ -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"

View 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

View 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
View 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
View 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

View File

@ -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);
}
}

View File

@ -24,7 +24,8 @@
#define PLUGINS_H
typedef enum {
PYTHON
PYTHON,
C
} lang_t;
typedef struct prof_plugin_t {