1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-12-04 14:46:46 -05:00

Merge branch 'master' into osx-functional

This commit is contained in:
James Booth 2016-07-13 00:08:39 +01:00
commit 069fe295e2
41 changed files with 1218 additions and 382 deletions

View File

@ -123,6 +123,7 @@ unittest_sources = \
tests/unittests/test_cmd_join.c tests/unittests/test_cmd_join.h \ tests/unittests/test_cmd_join.c tests/unittests/test_cmd_join.h \
tests/unittests/test_cmd_roster.c tests/unittests/test_cmd_roster.h \ tests/unittests/test_cmd_roster.c tests/unittests/test_cmd_roster.h \
tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \
tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \
tests/unittests/unittests.c tests/unittests/unittests.c
functionaltest_sources = \ functionaltest_sources = \

View File

@ -57,6 +57,8 @@
#include "pgp/gpg.h" #include "pgp/gpg.h"
#endif #endif
static char* _complete_filepath(const char *const input, char *const startstr);
static char* _sub_autocomplete(ProfWin *window, const char *const input); static char* _sub_autocomplete(ProfWin *window, const char *const input);
static char* _notify_autocomplete(ProfWin *window, const char *const input); static char* _notify_autocomplete(ProfWin *window, const char *const input);
static char* _theme_autocomplete(ProfWin *window, const char *const input); static char* _theme_autocomplete(ProfWin *window, const char *const input);
@ -185,7 +187,9 @@ static Autocomplete console_msg_ac;
static Autocomplete autoping_ac; static Autocomplete autoping_ac;
static Autocomplete plugins_ac; static Autocomplete plugins_ac;
static Autocomplete plugins_load_ac; static Autocomplete plugins_load_ac;
static Autocomplete sendfile_ac; static Autocomplete plugins_unload_ac;
static Autocomplete plugins_reload_ac;
static Autocomplete filepath_ac;
static Autocomplete blocked_ac; static Autocomplete blocked_ac;
static Autocomplete tray_ac; static Autocomplete tray_ac;
static Autocomplete presence_ac; static Autocomplete presence_ac;
@ -484,6 +488,8 @@ cmd_ac_init(void)
theme_load_ac = NULL; theme_load_ac = NULL;
plugins_load_ac = NULL; plugins_load_ac = NULL;
plugins_unload_ac = NULL;
plugins_reload_ac = NULL;
who_roster_ac = autocomplete_new(); who_roster_ac = autocomplete_new();
autocomplete_add(who_roster_ac, "chat"); autocomplete_add(who_roster_ac, "chat");
@ -701,9 +707,12 @@ cmd_ac_init(void)
autocomplete_add(autoping_ac, "timeout"); autocomplete_add(autoping_ac, "timeout");
plugins_ac = autocomplete_new(); plugins_ac = autocomplete_new();
autocomplete_add(plugins_ac, "install");
autocomplete_add(plugins_ac, "load"); autocomplete_add(plugins_ac, "load");
autocomplete_add(plugins_ac, "unload");
autocomplete_add(plugins_ac, "reload");
sendfile_ac = autocomplete_new(); filepath_ac = autocomplete_new();
blocked_ac = autocomplete_new(); blocked_ac = autocomplete_new();
autocomplete_add(blocked_ac, "add"); autocomplete_add(blocked_ac, "add");
@ -784,6 +793,14 @@ cmd_ac_remove(const char *const value)
} }
} }
void
cmd_ac_remove_help(const char *const value)
{
if (help_ac) {
autocomplete_remove(help_ac, value);
}
}
gboolean gboolean
cmd_ac_exists(char *cmd) cmd_ac_exists(char *cmd)
{ {
@ -889,7 +906,7 @@ cmd_ac_reset(ProfWin *window)
autocomplete_reset(notify_mention_ac); autocomplete_reset(notify_mention_ac);
autocomplete_reset(notify_trigger_ac); autocomplete_reset(notify_trigger_ac);
autocomplete_reset(sub_ac); autocomplete_reset(sub_ac);
autocomplete_reset(sendfile_ac); autocomplete_reset(filepath_ac);
autocomplete_reset(who_room_ac); autocomplete_reset(who_room_ac);
autocomplete_reset(who_roster_ac); autocomplete_reset(who_roster_ac);
@ -909,6 +926,14 @@ cmd_ac_reset(ProfWin *window)
autocomplete_free(plugins_load_ac); autocomplete_free(plugins_load_ac);
plugins_load_ac = NULL; plugins_load_ac = NULL;
} }
if (plugins_unload_ac) {
autocomplete_free(plugins_unload_ac);
plugins_unload_ac = NULL;
}
if (plugins_reload_ac) {
autocomplete_free(plugins_reload_ac);
plugins_reload_ac = NULL;
}
autocomplete_reset(account_ac); autocomplete_reset(account_ac);
autocomplete_reset(account_set_ac); autocomplete_reset(account_set_ac);
autocomplete_reset(account_clear_ac); autocomplete_reset(account_clear_ac);
@ -1087,7 +1112,9 @@ cmd_ac_uninit(void)
autocomplete_free(autoping_ac); autocomplete_free(autoping_ac);
autocomplete_free(plugins_ac); autocomplete_free(plugins_ac);
autocomplete_free(plugins_load_ac); autocomplete_free(plugins_load_ac);
autocomplete_free(sendfile_ac); autocomplete_free(plugins_unload_ac);
autocomplete_free(plugins_reload_ac);
autocomplete_free(filepath_ac);
autocomplete_free(blocked_ac); autocomplete_free(blocked_ac);
autocomplete_free(tray_ac); autocomplete_free(tray_ac);
autocomplete_free(presence_ac); autocomplete_free(presence_ac);
@ -1865,6 +1892,11 @@ static char*
_plugins_autocomplete(ProfWin *window, const char *const input) _plugins_autocomplete(ProfWin *window, const char *const input)
{ {
char *result = NULL; char *result = NULL;
if (strncmp(input, "/plugins install ", 17) == 0) {
return _complete_filepath(input, "/plugins install");
}
if (strncmp(input, "/plugins load ", 14) == 0) { if (strncmp(input, "/plugins load ", 14) == 0) {
if (plugins_load_ac == NULL) { if (plugins_load_ac == NULL) {
plugins_load_ac = autocomplete_new(); plugins_load_ac = autocomplete_new();
@ -1881,6 +1913,41 @@ _plugins_autocomplete(ProfWin *window, const char *const input)
return result; return result;
} }
} }
if (strncmp(input, "/plugins reload ", 16) == 0) {
if (plugins_reload_ac == NULL) {
plugins_reload_ac = autocomplete_new();
GList *plugins = plugins_loaded_list();
GList *curr = plugins;
while (curr) {
autocomplete_add(plugins_reload_ac, curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
}
result = autocomplete_param_with_ac(input, "/plugins reload", plugins_reload_ac, TRUE);
if (result) {
return result;
}
}
if (strncmp(input, "/plugins unload ", 16) == 0) {
if (plugins_unload_ac == NULL) {
plugins_unload_ac = autocomplete_new();
GList *plugins = plugins_loaded_list();
GList *curr = plugins;
while (curr) {
autocomplete_add(plugins_unload_ac, curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
}
result = autocomplete_param_with_ac(input, "/plugins unload", plugins_unload_ac, TRUE);
if (result) {
return result;
}
}
result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE); result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE);
if (result) { if (result) {
return result; return result;
@ -2659,107 +2726,9 @@ _close_autocomplete(ProfWin *window, const char *const input)
static char* static char*
_sendfile_autocomplete(ProfWin *window, const char *const input) _sendfile_autocomplete(ProfWin *window, const char *const input)
{ {
static char* last_directory = NULL; return _complete_filepath(input, "/sendfile");
unsigned int output_off = 0;
char *result = NULL;
char *tmp;
// strip command
char *inpcp = (char*)input + 9;
while (*inpcp == ' ') {
inpcp++;
}
inpcp = strdup(inpcp);
// strip quotes
if (*inpcp == '"') {
tmp = strchr(inpcp+1, '"');
if (tmp) {
*tmp = '\0';
}
tmp = strdup(inpcp+1);
free(inpcp);
inpcp = tmp;
}
// expand ~ to $HOME
if (inpcp[0] == '~' && inpcp[1] == '/') {
if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
return NULL;
}
output_off = strlen(getenv("HOME"))+1;
} else {
if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
return NULL;
}
}
free(inpcp);
inpcp = tmp;
char* inpcp2 = strdup(inpcp);
char* foofile = strdup(basename(inpcp2));
char* directory = strdup(dirname(inpcp));
free(inpcp);
free(inpcp2);
if (!last_directory || strcmp(last_directory, directory) != 0) {
free(last_directory);
last_directory = directory;
autocomplete_reset(sendfile_ac);
struct dirent *dir;
DIR *d = opendir(directory);
if (d) {
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0) {
continue;
} else if (strcmp(dir->d_name, "..") == 0) {
continue;
} else if (*(dir->d_name) == '.' && *foofile != '.') {
// only show hidden files on explicit request
continue;
}
char * acstring;
if (output_off) {
if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
return NULL;
}
if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
return NULL;
}
free(tmp);
} else if (strcmp(directory, "/") == 0) {
if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
return NULL;
}
} else {
if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
return NULL;
}
}
autocomplete_add(sendfile_ac, acstring);
free(acstring);
}
closedir(d);
}
} else {
free(foofile);
free(directory);
}
result = autocomplete_param_with_ac(input, "/sendfile", sendfile_ac, TRUE);
if (result) {
return result;
}
return NULL;
} }
static char* static char*
_subject_autocomplete(ProfWin *window, const char *const input) _subject_autocomplete(ProfWin *window, const char *const input)
{ {
@ -2959,3 +2928,106 @@ _presence_autocomplete(ProfWin *window, const char *const input)
return NULL; return NULL;
} }
static char*
_complete_filepath(const char *const input, char *const startstr)
{
static char* last_directory = NULL;
unsigned int output_off = 0;
char *result = NULL;
char *tmp;
// strip command
char *inpcp = (char*)input + strlen(startstr);
while (*inpcp == ' ') {
inpcp++;
}
inpcp = strdup(inpcp);
// strip quotes
if (*inpcp == '"') {
tmp = strchr(inpcp+1, '"');
if (tmp) {
*tmp = '\0';
}
tmp = strdup(inpcp+1);
free(inpcp);
inpcp = tmp;
}
// expand ~ to $HOME
if (inpcp[0] == '~' && inpcp[1] == '/') {
if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) {
return NULL;
}
output_off = strlen(getenv("HOME"))+1;
} else {
if (asprintf(&tmp, "%sfoo", inpcp) == -1) {
return NULL;
}
}
free(inpcp);
inpcp = tmp;
char* inpcp2 = strdup(inpcp);
char* foofile = strdup(basename(inpcp2));
char* directory = strdup(dirname(inpcp));
free(inpcp);
free(inpcp2);
if (!last_directory || strcmp(last_directory, directory) != 0) {
free(last_directory);
last_directory = directory;
autocomplete_reset(filepath_ac);
struct dirent *dir;
DIR *d = opendir(directory);
if (d) {
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0) {
continue;
} else if (strcmp(dir->d_name, "..") == 0) {
continue;
} else if (*(dir->d_name) == '.' && *foofile != '.') {
// only show hidden files on explicit request
continue;
}
char * acstring;
if (output_off) {
if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) {
return NULL;
}
if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) {
return NULL;
}
free(tmp);
} else if (strcmp(directory, "/") == 0) {
if (asprintf(&acstring, "/%s", dir->d_name) == -1) {
return NULL;
}
} else {
if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) {
return NULL;
}
}
autocomplete_add(filepath_ac, acstring);
free(acstring);
}
closedir(d);
}
} else {
free(foofile);
free(directory);
}
result = autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE);
if (result) {
return result;
}
return NULL;
}

View File

@ -48,6 +48,7 @@ void cmd_ac_add_alias(ProfAlias *alias);
void cmd_ac_add_alias_value(char *value); void cmd_ac_add_alias_value(char *value);
void cmd_ac_remove(const char *const value); void cmd_ac_remove(const char *const value);
void cmd_ac_remove_help(const char *const value);
void cmd_ac_remove_alias_value(char *value); void cmd_ac_remove_alias_value(char *value);
gboolean cmd_ac_exists(char *cmd); gboolean cmd_ac_exists(char *cmd);

View File

@ -1979,13 +1979,22 @@ static struct cmd_t command_defs[] =
CMD_NOTAGS CMD_NOTAGS
CMD_SYN( CMD_SYN(
"/plugins", "/plugins",
"/plugins load <plugin>") "/plugins install <path>",
"/plugins unload <plugin>",
"/plugins load <plugin>",
"/plugins reload [<plugin>]")
CMD_DESC( CMD_DESC(
"Manage plugins. Passing no arguments lists currently loaded plugins.") "Manage plugins. Passing no arguments lists currently loaded plugins.")
CMD_ARGS( CMD_ARGS(
{ "load <plugin>", "Load a plugin." }) { "install <file>", "Install file to plugins directory, and load or reload the plugin." },
{ "load <plugin>", "Load a plugin that already exists in the plugin directory." },
{ "unload <plugin>", "Unload a loaded plugin." },
{ "reload [<plugin>]", "Reload a plugin, passing no argument will reload all plugins" })
CMD_EXAMPLES( CMD_EXAMPLES(
"/plugin load browser.py") "/plugin install /home/steveharris/Downloads/metal.py",
"/plugin load browser.py",
"/plugin unload say.py",
"/plugin reload wikipedia.py")
}, },
{ "/prefs", { "/prefs",

View File

@ -3809,7 +3809,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args)
} else { } else {
mucconfwin_form_help(confwin); mucconfwin_form_help(confwin);
const gchar **help_text = NULL; gchar **help_text = NULL;
Command *command = cmd_get("/form"); Command *command = cmd_get("/form");
if (command) { if (command) {
@ -6025,34 +6025,103 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args)
gboolean gboolean
cmd_plugins(ProfWin *window, const char *const command, gchar **args) cmd_plugins(ProfWin *window, const char *const command, gchar **args)
{ {
if (g_strcmp0(args[0], "load") == 0) { if (g_strcmp0(args[0], "install") == 0) {
char *filename = args[1];
if (filename == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
// expand ~ to $HOME
if (filename[0] == '~' && filename[1] == '/') {
if (asprintf(&filename, "%s/%s", getenv("HOME"), filename+2) == -1) {
return TRUE;
}
} else {
filename = strdup(filename);
}
if (access(filename, R_OK) != 0) {
cons_show("File not found: %s", filename);
free(filename);
return TRUE;
}
if (!is_regular_file(filename)) {
cons_show("Not a file: %s", filename);
free(filename);
return TRUE;
}
if (!g_str_has_suffix(filename, ".py") && !g_str_has_suffix(filename, ".so")) {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
free(filename);
return TRUE;
}
char *plugin_name = basename(filename);
gboolean result = plugins_install(plugin_name, filename);
if (result) {
cons_show("Plugin installed, use '/plugin load %s' to enable the plugin.", plugin_name);
} else {
cons_show("Failed to install plugin: %s", plugin_name);
}
return TRUE;
} else if (g_strcmp0(args[0], "load") == 0) {
if (args[1] == NULL) { if (args[1] == NULL) {
cons_bad_cmd_usage(command); cons_bad_cmd_usage(command);
return TRUE; return TRUE;
} }
gboolean res = plugins_load(args[1]); gboolean res = plugins_load(args[1]);
if (res) { if (res) {
prefs_add_plugin(args[1]);
cons_show("Loaded plugin: %s", args[1]); cons_show("Loaded plugin: %s", args[1]);
} else { } else {
cons_show("Failed to load plugin: %s", args[1]); cons_show("Failed to load plugin: %s", args[1]);
} }
return TRUE; return TRUE;
} else { } else if (g_strcmp0(args[0], "unload") == 0) {
GSList *plugins = plugins_get_list(); if (args[1] == NULL) {
GSList *curr = plugins; cons_bad_cmd_usage(command);
if (curr == NULL) { return TRUE;
cons_show("No plugins installed."); }
gboolean res = plugins_unload(args[1]);
if (res) {
cons_show("Unloaded plugin: %s", args[1]);
} else { } else {
cons_show("Installed plugins:"); cons_show("Failed to unload plugin: %s", args[1]);
while (curr) { }
ProfPlugin *plugin = curr->data;
cons_show(" %s", plugin->name); return TRUE;
curr = g_slist_next(curr); } else if (g_strcmp0(args[0], "reload") == 0) {
if (args[1] == NULL) {
plugins_reload_all();
cons_show("Reloaded all plugins");
} else {
gboolean res = plugins_reload(args[1]);
if (res) {
cons_show("Reloaded plugin: %s", args[1]);
} else {
cons_show("Failed to reload plugin: %s", args[1]);
} }
} }
g_slist_free(curr);
return TRUE;
} else {
GList *plugins = plugins_loaded_list();
if (plugins == NULL) {
cons_show("No plugins installed.");
return TRUE;
}
GList *curr = plugins;
cons_show("Installed plugins:");
while (curr) {
cons_show(" %s", curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
return TRUE; return TRUE;
} }

View File

@ -39,11 +39,11 @@
// Command help strings // Command help strings
typedef struct cmd_help_t { typedef struct cmd_help_t {
const gchar *tags[20]; gchar *tags[20];
const gchar *synopsis[50]; gchar *synopsis[50];
const gchar *desc; gchar *desc;
const gchar *args[128][2]; gchar *args[128][2];
const gchar *examples[20]; gchar *examples[20];
} CommandHelp; } CommandHelp;
/* /*

View File

@ -38,6 +38,7 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -155,6 +156,31 @@ mkdir_recursive(const char *dir)
return result; return result;
} }
gboolean
copy_file(const char *const sourcepath, const char *const targetpath)
{
int ch;
FILE *source = fopen(sourcepath, "rb");
if (source == NULL) {
return FALSE;
}
FILE *target = fopen(targetpath, "wb");
if (target == NULL) {
fclose(source);
return FALSE;
}
while((ch = fgetc(source)) != EOF) {
fputc(ch, target);
}
fclose(source);
fclose(target);
return TRUE;
}
char* char*
str_replace(const char *string, const char *substr, str_replace(const char *string, const char *substr,
const char *replacement) const char *replacement)

View File

@ -102,6 +102,7 @@ gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key);
gboolean create_dir(char *name); gboolean create_dir(char *name);
gboolean mkdir_recursive(const char *dir); gboolean mkdir_recursive(const char *dir);
gboolean copy_file(const char *const src, const char *const target);
char* str_replace(const char *string, const char *substr, const char *replacement); char* str_replace(const char *string, const char *substr, const char *replacement);
int str_contains(const char str[], int size, char ch); int str_contains(const char str[], int size, char ch);
gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg);

View File

@ -64,7 +64,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con
GList *curr = glist; GList *curr = glist;
i = 0; i = 0;
while (curr) { while (curr) {
new_list[i++] = strdup(curr->data); new_list[i++] = curr->data;
curr = g_list_next(curr); curr = g_list_next(curr);
} }
new_list[i] = NULL; new_list[i] = NULL;
@ -73,7 +73,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con
// list not found // list not found
} else { } else {
const gchar* new_list[2]; const gchar* new_list[2];
new_list[0] = strdup(item); new_list[0] = item;
new_list[1] = NULL; new_list[1] = NULL;
g_key_file_set_string_list(keyfile, group, key, new_list, 1); g_key_file_set_string_list(keyfile, group, key, new_list, 1);
} }
@ -114,7 +114,7 @@ conf_string_list_remove(GKeyFile *keyfile, const char *const group, const char *
GList *curr = glist; GList *curr = glist;
i = 0; i = 0;
while (curr) { while (curr) {
new_list[i++] = strdup(curr->data); new_list[i++] = curr->data;
curr = g_list_next(curr); curr = g_list_next(curr);
} }
new_list[i] = NULL; new_list[i] = NULL;

View File

@ -631,6 +631,13 @@ prefs_add_plugin(const char *const name)
_save_prefs(); _save_prefs();
} }
void
prefs_remove_plugin(const char *const name)
{
conf_string_list_remove(prefs, "plugins", "load", name);
_save_prefs();
}
void void
prefs_free_plugins(gchar **plugins) prefs_free_plugins(gchar **plugins)
{ {

View File

@ -191,6 +191,7 @@ void prefs_set_autoxa_time(gint value);
gchar** prefs_get_plugins(void); gchar** prefs_get_plugins(void);
void prefs_free_plugins(gchar **plugins); void prefs_free_plugins(gchar **plugins);
void prefs_add_plugin(const char *const name); void prefs_add_plugin(const char *const name);
void prefs_remove_plugin(const char *const name);
char prefs_get_otr_char(void); char prefs_get_otr_char(void);
void prefs_set_otr_char(char ch); void prefs_set_otr_char(char ch);

View File

@ -106,19 +106,22 @@ api_cons_bad_cmd_usage(const char *const cmd)
} }
void void
api_register_command(const char *command_name, int min_args, int max_args, api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void(*callback_func)(PluginCommand *command, gchar **args)) void *callback, void(*callback_exec)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback))
{ {
PluginCommand *command = malloc(sizeof(PluginCommand)); PluginCommand *command = malloc(sizeof(PluginCommand));
command->command_name = command_name; command->command_name = strdup(command_name);
command->min_args = min_args; command->min_args = min_args;
command->max_args = max_args; command->max_args = max_args;
command->callback = callback; command->callback = callback;
command->callback_func = callback_func; command->callback_exec = callback_exec;
command->callback_destroy = callback_destroy;
CommandHelp *help = malloc(sizeof(CommandHelp)); CommandHelp *help = malloc(sizeof(CommandHelp));
help->tags[0] = NULL;
int i = 0; int i = 0;
for (i = 0; synopsis[i] != NULL; i++) { for (i = 0; synopsis[i] != NULL; i++) {
help->synopsis[i] = strdup(synopsis[i]); help->synopsis[i] = strdup(synopsis[i]);
@ -140,38 +143,39 @@ api_register_command(const char *command_name, int min_args, int max_args,
command->help = help; command->help = help;
callbacks_add_command(command); callbacks_add_command(plugin_name, command);
} }
void void
api_register_timed(void *callback, int interval_seconds, api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
void (*callback_func)(PluginTimedFunction *timed_function)) void (*callback_exec)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback))
{ {
PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction)); PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction));
timed_function->callback = callback; timed_function->callback = callback;
timed_function->callback_func = callback_func; timed_function->callback_exec = callback_exec;
timed_function->callback_destroy = callback_destroy;
timed_function->interval_seconds = interval_seconds; timed_function->interval_seconds = interval_seconds;
timed_function->timer = g_timer_new(); timed_function->timer = g_timer_new();
callbacks_add_timed(timed_function); callbacks_add_timed(plugin_name, timed_function);
} }
void void
api_completer_add(const char *key, char **items) api_completer_add(const char *const plugin_name, const char *key, char **items)
{ {
autocompleters_add(key, items); autocompleters_add(plugin_name, key, items);
} }
void void
api_completer_remove(const char *key, char **items) api_completer_remove(const char *const plugin_name, const char *key, char **items)
{ {
autocompleters_remove(key, items); autocompleters_remove(plugin_name, key, items);
} }
void void
api_completer_clear(const char *key) api_completer_clear(const char *const plugin_name, const char *key)
{ {
autocompleters_clear(key); autocompleters_clear(plugin_name, key);
} }
void void
@ -292,17 +296,24 @@ api_win_exists(const char *tag)
void void
api_win_create( api_win_create(
const char *const plugin_name,
const char *tag, const char *tag,
void *callback, void *callback,
void(*destroy)(void *callback), void(*callback_exec)(PluginWindowCallback *window_callback, const char *tag, const char * const line),
void(*callback_func)(PluginWindowCallback *window_callback, const char *tag, const char * const line)) void(*callback_destroy)(void *callback))
{ {
if (callbacks_win_exists(plugin_name, tag)) {
return;
}
PluginWindowCallback *window = malloc(sizeof(PluginWindowCallback)); PluginWindowCallback *window = malloc(sizeof(PluginWindowCallback));
window->callback = callback; window->callback = callback;
window->callback_func = callback_func; window->callback_exec = callback_exec;
window->destroy = destroy; window->callback_destroy = callback_destroy;
callbacks_add_window_handler(tag, window);
wins_new_plugin(tag); callbacks_add_window_handler(plugin_name, tag, window);
wins_new_plugin(plugin_name, tag);
// set status bar active // set status bar active
ProfPluginWin *pluginwin = wins_get_plugin(tag); ProfPluginWin *pluginwin = wins_get_plugin(tag);

View File

@ -50,15 +50,15 @@ gboolean api_current_win_is_console(void);
char* api_get_current_nick(void); char* api_get_current_nick(void);
char** api_get_current_occupants(void); char** api_get_current_occupants(void);
void api_register_command(const char *command_name, int min_args, int max_args, void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void *callback, void(*callback_func)(PluginCommand *command, gchar **args)); void *callback, void(*callback_func)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback));
void api_register_timed(void *callback, int interval_seconds, void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
void (*callback_func)(PluginTimedFunction *timed_function)); void (*callback_func)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback));
void api_completer_add(const char *key, char **items); void api_completer_add(const char *const plugin_name, const char *key, char **items);
void api_completer_remove(const char *key, char **items); void api_completer_remove(const char *const plugin_name, const char *key, char **items);
void api_completer_clear(const char *key); void api_completer_clear(const char *const plugin_name, const char *key);
void api_log_debug(const char *message); void api_log_debug(const char *message);
void api_log_info(const char *message); void api_log_info(const char *message);
@ -67,10 +67,11 @@ void api_log_error(const char *message);
int api_win_exists(const char *tag); int api_win_exists(const char *tag);
void api_win_create( void api_win_create(
const char *const plugin_name,
const char *tag, const char *tag,
void *callback, void *callback,
void(*destroy)(void *callback), void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line),
void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line)); void(*destroy)(void *callback));
int api_win_focus(const char *tag); int api_win_focus(const char *tag);
int api_win_show(const char *tag, const char *line); int api_win_show(const char *tag, const char *line);
int api_win_show_themed(const char *tag, const char *const group, const char *const key, const char *const def, const char *line); int api_win_show_themed(const char *tag, const char *const group, const char *const key, const char *const def, const char *line);

View File

@ -38,56 +38,71 @@
#include "tools/autocomplete.h" #include "tools/autocomplete.h"
static GHashTable *autocompleters; static GHashTable *plugin_to_acs;
static void
_free_autocompleters(GHashTable *key_to_ac)
{
g_hash_table_destroy(key_to_ac);
}
void void
autocompleters_init(void) autocompleters_init(void)
{ {
autocompleters = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free); plugin_to_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_autocompleters);
} }
void void
autocompleters_add(const char *key, char **items) autocompleters_add(const char *const plugin_name, const char *key, char **items)
{ {
if (g_hash_table_contains(autocompleters, key)) { GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name);
Autocomplete existing_ac = g_hash_table_lookup(autocompleters, key); if (key_to_ac) {
if (g_hash_table_contains(key_to_ac, key)) {
int i = 0; Autocomplete existing_ac = g_hash_table_lookup(key_to_ac, key);
for (i = 0; i < g_strv_length(items); i++) { autocomplete_add_all(existing_ac, items);
autocomplete_add(existing_ac, items[i]); } else {
Autocomplete new_ac = autocomplete_new();
autocomplete_add_all(new_ac, items);
g_hash_table_insert(key_to_ac, strdup(key), new_ac);
} }
} else { } else {
key_to_ac = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free);
Autocomplete new_ac = autocomplete_new(); Autocomplete new_ac = autocomplete_new();
int i = 0; autocomplete_add_all(new_ac, items);
for (i = 0; i < g_strv_length(items); i++) { g_hash_table_insert(key_to_ac, strdup(key), new_ac);
autocomplete_add(new_ac, items[i]); g_hash_table_insert(plugin_to_acs, strdup(plugin_name), key_to_ac);
}
g_hash_table_insert(autocompleters, strdup(key), new_ac);
} }
} }
void void
autocompleters_remove(const char *key, char **items) autocompleters_remove(const char *const plugin_name, const char *key, char **items)
{ {
if (!g_hash_table_contains(autocompleters, key)) { GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name);
if (!key_to_ac) {
return; return;
} }
Autocomplete ac = g_hash_table_lookup(autocompleters, key); if (!g_hash_table_contains(key_to_ac, key)) {
int i = 0; return;
for (i = 0; i < g_strv_length(items); i++) {
autocomplete_remove(ac, items[i]);
} }
Autocomplete ac = g_hash_table_lookup(key_to_ac, key);
autocomplete_remove_all(ac, items);
} }
void void
autocompleters_clear(const char *key) autocompleters_clear(const char *const plugin_name, const char *key)
{ {
if (!g_hash_table_contains(autocompleters, key)) { GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name);
if (!key_to_ac) {
return; return;
} }
Autocomplete ac = g_hash_table_lookup(autocompleters, key); if (!g_hash_table_contains(key_to_ac, key)) {
return;
}
Autocomplete ac = g_hash_table_lookup(key_to_ac, key);
autocomplete_clear(ac); autocomplete_clear(ac);
} }
@ -96,17 +111,26 @@ autocompleters_complete(const char * const input)
{ {
char *result = NULL; char *result = NULL;
GList *keys = g_hash_table_get_keys(autocompleters); GList *ac_hashes = g_hash_table_get_values(plugin_to_acs);
GList *curr = keys; GList *curr_hash = ac_hashes;
while (curr) { while (curr_hash) {
result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(autocompleters, curr->data), TRUE); GHashTable *key_to_ac = curr_hash->data;
if (result) {
g_list_free(keys); GList *keys = g_hash_table_get_keys(key_to_ac);
return result; GList *curr = keys;
while (curr) {
result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(key_to_ac, curr->data), TRUE);
if (result) {
g_list_free(keys);
return result;
}
curr = g_list_next(curr);
} }
curr = g_list_next(curr); g_list_free(keys);
curr_hash = g_list_next(curr_hash);
} }
g_list_free(keys); g_list_free(ac_hashes);
return NULL; return NULL;
} }
@ -114,17 +138,24 @@ autocompleters_complete(const char * const input)
void void
autocompleters_reset(void) autocompleters_reset(void)
{ {
GList *acs = g_hash_table_get_values(autocompleters); GList *ac_hashes = g_hash_table_get_values(plugin_to_acs);
GList *curr = acs; GList *curr_hash = ac_hashes;
while (curr) { while (curr_hash) {
autocomplete_reset(curr->data); GList *acs = g_hash_table_get_values(curr_hash->data);
curr = g_list_next(curr); GList *curr = acs;
while (curr) {
autocomplete_reset(curr->data);
curr = g_list_next(curr);
}
g_list_free(acs);
curr_hash = g_list_next(curr_hash);
} }
g_list_free(acs); g_list_free(ac_hashes);
} }
void autocompleters_destroy(void) void autocompleters_destroy(void)
{ {
g_hash_table_destroy(autocompleters); g_hash_table_destroy(plugin_to_acs);
} }

View File

@ -38,9 +38,9 @@
#include <glib.h> #include <glib.h>
void autocompleters_init(void); void autocompleters_init(void);
void autocompleters_add(const char *key, char **items); void autocompleters_add(const char *const plugin_name, const char *key, char **items);
void autocompleters_remove(const char *key, char **items); void autocompleters_remove(const char *const plugin_name, const char *key, char **items);
void autocompleters_clear(const char *key); void autocompleters_clear(const char *const plugin_name, const char *key);
char* autocompleters_complete(const char * const input); char* autocompleters_complete(const char * const input);
void autocompleters_reset(void); void autocompleters_reset(void);
void autocompleters_destroy(void); void autocompleters_destroy(void);

View File

@ -53,6 +53,8 @@ typedef struct window_wrapper_t {
void(*func)(char *tag, char *line); void(*func)(char *tag, char *line);
} WindowWrapper; } WindowWrapper;
static char* _c_plugin_name(const char *filename);
static void static void
c_api_cons_alert(void) c_api_cons_alert(void)
{ {
@ -78,40 +80,65 @@ c_api_cons_bad_cmd_usage(const char *const cmd)
} }
static void static void
c_api_register_command(const char *command_name, int min_args, int max_args, c_api_register_command(const char *filename, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void(*callback)(char **args)) void(*callback)(char **args))
{ {
char *plugin_name = _c_plugin_name(filename);
log_debug("Register command %s for %s", command_name, plugin_name);
CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); CommandWrapper *wrapper = malloc(sizeof(CommandWrapper));
wrapper->func = callback; wrapper->func = callback;
api_register_command(command_name, min_args, max_args, synopsis, api_register_command(plugin_name, command_name, min_args, max_args, synopsis,
description, arguments, examples, wrapper, c_command_callback); description, arguments, examples, wrapper, c_command_callback, free);
free(plugin_name);
} }
static void static void
c_api_register_timed(void(*callback)(void), int interval_seconds) c_api_register_timed(const char *filename, void(*callback)(void), int interval_seconds)
{ {
char *plugin_name = _c_plugin_name(filename);
log_debug("Register timed for %s", plugin_name);
TimedWrapper *wrapper = malloc(sizeof(TimedWrapper)); TimedWrapper *wrapper = malloc(sizeof(TimedWrapper));
wrapper->func = callback; wrapper->func = callback;
api_register_timed(wrapper, interval_seconds, c_timed_callback); api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback, free);
free(plugin_name);
} }
static void static void
c_api_completer_add(const char *key, char **items) c_api_completer_add(const char *filename, const char *key, char **items)
{ {
api_completer_add(key, items); char *plugin_name = _c_plugin_name(filename);
log_debug("Autocomplete add %s for %s", key, plugin_name);
api_completer_add(plugin_name, key, items);
free(plugin_name);
} }
static void static void
c_api_completer_remove(const char *key, char **items) c_api_completer_remove(const char *filename, const char *key, char **items)
{ {
api_completer_remove(key, items); char *plugin_name = _c_plugin_name(filename);
log_debug("Autocomplete remove %s for %s", key, plugin_name);
api_completer_remove(plugin_name, key, items);
free(plugin_name);
} }
static void static void
c_api_completer_clear(const char *key) c_api_completer_clear(const char *filename, const char *key)
{ {
api_completer_clear(key); char *plugin_name = _c_plugin_name(filename);
log_debug("Autocomplete clear %s for %s", key, plugin_name);
api_completer_clear(plugin_name, key);
free(plugin_name);
} }
static void static void
@ -187,11 +214,16 @@ c_api_win_exists(char *tag)
} }
static void static void
c_api_win_create(char *tag, void(*callback)(char *tag, char *line)) c_api_win_create(const char *filename, char *tag, void(*callback)(char *tag, char *line))
{ {
char *plugin_name = _c_plugin_name(filename);
log_debug("Win create %s for %s", tag, plugin_name);
WindowWrapper *wrapper = malloc(sizeof(WindowWrapper)); WindowWrapper *wrapper = malloc(sizeof(WindowWrapper));
wrapper->func = callback; wrapper->func = callback;
api_win_create(tag, wrapper, free, c_window_callback); api_win_create(plugin_name, tag, wrapper, c_window_callback, free);
free(plugin_name);
} }
static int static int
@ -297,11 +329,12 @@ c_api_init(void)
prof_cons_show = c_api_cons_show; prof_cons_show = c_api_cons_show;
prof_cons_show_themed = c_api_cons_show_themed; prof_cons_show_themed = c_api_cons_show_themed;
prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage; prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage;
prof_register_command = c_api_register_command; _prof_register_command = c_api_register_command;
prof_register_timed = c_api_register_timed; _prof_register_timed = c_api_register_timed;
prof_completer_add = c_api_completer_add; _prof_completer_add = c_api_completer_add;
prof_completer_remove = c_api_completer_remove; _prof_completer_remove = c_api_completer_remove;
prof_completer_clear = c_api_completer_clear; _prof_completer_clear = c_api_completer_clear;
_prof_win_create = c_api_win_create;
prof_notify = c_api_notify; prof_notify = c_api_notify;
prof_send_line = c_api_send_line; prof_send_line = c_api_send_line;
prof_get_current_recipient = c_api_get_current_recipient; prof_get_current_recipient = c_api_get_current_recipient;
@ -314,7 +347,6 @@ c_api_init(void)
prof_log_warning = c_api_log_warning; prof_log_warning = c_api_log_warning;
prof_log_error = c_api_log_error; prof_log_error = c_api_log_error;
prof_win_exists = c_api_win_exists; prof_win_exists = c_api_win_exists;
prof_win_create = c_api_win_create;
prof_win_focus = c_api_win_focus; prof_win_focus = c_api_win_focus;
prof_win_show = c_api_win_show; prof_win_show = c_api_win_show;
prof_win_show_themed = c_api_win_show_themed; prof_win_show_themed = c_api_win_show_themed;
@ -328,3 +360,17 @@ c_api_init(void)
prof_incoming_message = c_api_incoming_message; prof_incoming_message = c_api_incoming_message;
prof_disco_add_feature = c_api_disco_add_feature; prof_disco_add_feature = c_api_disco_add_feature;
} }
static char *
_c_plugin_name(const char *filename)
{
GString *plugin_name_str = g_string_new("");
char *name = strndup(filename, strlen(filename)-1);
g_string_append(plugin_name_str, name);
free(name);
g_string_append(plugin_name_str, "so");
char *result = plugin_name_str->str;
g_string_free(plugin_name_str, FALSE);
return result;
}

View File

@ -81,6 +81,7 @@ c_plugin_create(const char *const filename)
plugin->init_func = c_init_hook; plugin->init_func = c_init_hook;
plugin->on_start_func = c_on_start_hook; plugin->on_start_func = c_on_start_hook;
plugin->on_shutdown_func = c_on_shutdown_hook; plugin->on_shutdown_func = c_on_shutdown_hook;
plugin->on_unload_func = c_on_unload_hook;
plugin->on_connect_func = c_on_connect_hook; plugin->on_connect_func = c_on_connect_hook;
plugin->on_disconnect_func = c_on_disconnect_hook; plugin->on_disconnect_func = c_on_disconnect_hook;
plugin->pre_chat_message_display = c_pre_chat_message_display_hook; plugin->pre_chat_message_display = c_pre_chat_message_display_hook;
@ -161,6 +162,20 @@ c_on_shutdown_hook(ProfPlugin *plugin)
func(); func();
} }
void
c_on_unload_hook(ProfPlugin *plugin)
{
void *f = NULL;
void (*func)(void);
assert(plugin && plugin->module);
if (NULL == (f = dlsym(plugin->module, "prof_on_unload")))
return;
func = (void (*)(void))f;
func();
}
void void
c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid) c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid)
{ {
@ -523,6 +538,8 @@ c_plugin_destroy(ProfPlugin *plugin)
{ {
assert (plugin && plugin->module); assert (plugin && plugin->module);
callbacks_remove(plugin->name);
if (dlclose (plugin->module)) { if (dlclose (plugin->module)) {
log_warning ("dlclose failed to close `%s' with `%s'", plugin->name, dlerror ()); log_warning ("dlclose failed to close `%s' with `%s'", plugin->name, dlerror ());
} }

View File

@ -47,6 +47,7 @@ void c_init_hook(ProfPlugin *plugin, const char *const version, const char *cons
const char *const fulljid); const char *const fulljid);
void c_on_start_hook(ProfPlugin *plugin); void c_on_start_hook(ProfPlugin *plugin);
void c_on_shutdown_hook(ProfPlugin *plugin); void c_on_shutdown_hook(ProfPlugin *plugin);
void c_on_unload_hook(ProfPlugin *plugin);
void c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);
void c_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void c_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);

View File

@ -41,59 +41,227 @@
#include "plugins/plugins.h" #include "plugins/plugins.h"
#include "tools/autocomplete.h" #include "tools/autocomplete.h"
#include "tools/parser.h" #include "tools/parser.h"
#include "window_list.h"
#include "ui/ui.h" #include "ui/ui.h"
static GSList *p_commands = NULL; static GHashTable *p_commands = NULL;
static GSList *p_timed_functions = NULL; static GHashTable *p_timed_functions = NULL;
static GHashTable *p_window_callbacks = NULL; static GHashTable *p_window_callbacks = NULL;
static void static void
_free_window_callback(PluginWindowCallback *window_callback) _free_window_callback(PluginWindowCallback *window_callback)
{ {
if (window_callback->destroy) { if (window_callback->callback_destroy) {
window_callback->destroy(window_callback->callback); window_callback->callback_destroy(window_callback->callback);
} }
free(window_callback); free(window_callback);
} }
static void
_free_window_callbacks(GHashTable *window_callbacks)
{
g_hash_table_destroy(window_callbacks);
}
static void
_free_command_help(CommandHelp *help)
{
int i = 0;
while (help->tags[i] != NULL) {
free(help->tags[i++]);
}
i = 0;
while (help->synopsis[i] != NULL) {
free(help->synopsis[i++]);
}
free(help->desc);
i = 0;
while (help->args[i] != NULL && help->args[i][0] != NULL) {
free(help->args[i][0]);
free(help->args[i][1]);
i++;
}
i = 0;
while (help->examples[i] != NULL) {
free(help->examples[i++]);
}
free(help);
}
static void
_free_command(PluginCommand *command)
{
if (command->callback_destroy) {
command->callback_destroy(command->callback);
}
free(command->command_name);
_free_command_help(command->help);
free(command);
}
static void
_free_command_hash(GHashTable *command_hash)
{
g_hash_table_destroy(command_hash);
}
static void
_free_timed_function(PluginTimedFunction *timed_function)
{
if (timed_function->callback_destroy) {
timed_function->callback_destroy(timed_function->callback);
}
g_timer_destroy(timed_function->timer);
free(timed_function);
}
static void
_free_timed_function_list(GList *timed_functions)
{
g_list_free_full(timed_functions, (GDestroyNotify)_free_timed_function);
}
void void
callbacks_init(void) callbacks_init(void)
{ {
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash);
p_timed_functions = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_timed_function_list);
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callbacks);
}
void
callbacks_remove(const char *const plugin_name)
{
GHashTable *command_hash = g_hash_table_lookup(p_commands, plugin_name);
if (command_hash) {
GList *commands = g_hash_table_get_keys(command_hash);
GList *curr = commands;
while (curr) {
char *command = curr->data;
cmd_ac_remove(command);
cmd_ac_remove_help(&command[1]);
curr = g_list_next(curr);
}
g_list_free(commands);
}
g_hash_table_remove(p_commands, plugin_name);
g_hash_table_remove(p_timed_functions, plugin_name);
GHashTable *tag_to_win_cb_hash = g_hash_table_lookup(p_window_callbacks, plugin_name);
GList *tags = g_hash_table_get_keys(tag_to_win_cb_hash);
GList *curr = tags;
while (curr) {
wins_close_plugin(curr->data);
curr = g_list_next(curr);
}
g_list_free(tags);
g_hash_table_remove(p_window_callbacks, plugin_name);
} }
void void
callbacks_close(void) callbacks_close(void)
{ {
g_hash_table_destroy(p_commands);
g_hash_table_destroy(p_timed_functions);
g_hash_table_destroy(p_window_callbacks); g_hash_table_destroy(p_window_callbacks);
} }
void void
callbacks_add_command(PluginCommand *command) callbacks_add_command(const char *const plugin_name, PluginCommand *command)
{ {
p_commands = g_slist_append(p_commands, command); GHashTable *command_hash = g_hash_table_lookup(p_commands, plugin_name);
if (command_hash) {
g_hash_table_insert(command_hash, strdup(command->command_name), command);
} else {
command_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command);
g_hash_table_insert(command_hash, strdup(command->command_name), command);
g_hash_table_insert(p_commands, strdup(plugin_name), command_hash);
}
cmd_ac_add(command->command_name); cmd_ac_add(command->command_name);
cmd_ac_add_help(&command->command_name[1]); cmd_ac_add_help(&command->command_name[1]);
} }
void void
callbacks_add_timed(PluginTimedFunction *timed_function) callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function)
{ {
p_timed_functions = g_slist_append(p_timed_functions, timed_function); GList *timed_function_list = g_hash_table_lookup(p_timed_functions, plugin_name);
if (timed_function_list) {
timed_function_list = g_list_append(timed_function_list, timed_function);
g_hash_table_replace(p_timed_functions, strdup(plugin_name), timed_function_list);
} else {
timed_function_list = g_list_append(timed_function_list, timed_function);
g_hash_table_insert(p_timed_functions, strdup(plugin_name), timed_function_list);
}
}
gboolean
callbacks_win_exists(const char *const plugin_name, const char *tag)
{
GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name);
if (window_callbacks) {
PluginWindowCallback *cb = g_hash_table_lookup(window_callbacks, tag);
if (cb) {
return TRUE;
}
}
return FALSE;
} }
void void
callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback) callbacks_remove_win(const char *const plugin_name, const char *const tag)
{ {
g_hash_table_insert(p_window_callbacks, strdup(tag), window_callback); GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name);
if (window_callbacks) {
g_hash_table_remove(window_callbacks, tag);
}
}
void
callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback)
{
GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name);
if (window_callbacks) {
g_hash_table_insert(window_callbacks, strdup(tag), window_callback);
} else {
window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback);
g_hash_table_insert(window_callbacks, strdup(tag), window_callback);
g_hash_table_insert(p_window_callbacks, strdup(plugin_name), window_callbacks);
}
} }
void * void *
callbacks_get_window_handler(const char *tag) callbacks_get_window_handler(const char *tag)
{ {
if (p_window_callbacks) { if (p_window_callbacks) {
return g_hash_table_lookup(p_window_callbacks, tag); GList *window_callback_hashes = g_hash_table_get_values(p_window_callbacks);
GList *curr_hash = window_callback_hashes;
while (curr_hash) {
GHashTable *window_callback_hash = curr_hash->data;
PluginWindowCallback *callback = g_hash_table_lookup(window_callback_hash, tag);
if (callback) {
g_list_free(window_callback_hashes);
return callback;
}
curr_hash = g_list_next(curr_hash);
}
g_list_free(window_callback_hashes);
return NULL;
} else { } else {
return NULL; return NULL;
} }
@ -104,25 +272,32 @@ plugins_run_command(const char * const input)
{ {
gchar **split = g_strsplit(input, " ", -1); gchar **split = g_strsplit(input, " ", -1);
GSList *p_command = p_commands; GList *command_hashes = g_hash_table_get_values(p_commands);
while (p_command) { GList *curr_hash = command_hashes;
PluginCommand *command = p_command->data; while (curr_hash) {
if (g_strcmp0(split[0], command->command_name) == 0) { GHashTable *command_hash = curr_hash->data;
PluginCommand *command = g_hash_table_lookup(command_hash, split[0]);
if (command) {
gboolean result; gboolean result;
gchar **args = parse_args_with_freetext(input, command->min_args, command->max_args, &result); gchar **args = parse_args_with_freetext(input, command->min_args, command->max_args, &result);
if (result == FALSE) { if (result == FALSE) {
ui_invalid_command_usage(command->command_name, NULL); ui_invalid_command_usage(command->command_name, NULL);
g_strfreev(split); g_strfreev(split);
g_list_free(command_hashes);
return TRUE; return TRUE;
} else { } else {
command->callback_func(command, args); command->callback_exec(command, args);
g_strfreev(split); g_strfreev(split);
g_strfreev(args); g_strfreev(args);
g_list_free(command_hashes);
return TRUE; return TRUE;
} }
} }
p_command = g_slist_next(p_command);
curr_hash = g_list_next(curr_hash);
} }
g_strfreev(split); g_strfreev(split);
return FALSE; return FALSE;
} }
@ -130,36 +305,50 @@ plugins_run_command(const char * const input)
CommandHelp* CommandHelp*
plugins_get_help(const char *const cmd) plugins_get_help(const char *const cmd)
{ {
GSList *curr = p_commands; GList *command_hashes = g_hash_table_get_values(p_commands);
while (curr) { GList *curr_hash = command_hashes;
PluginCommand *command = curr->data; while (curr_hash) {
if (g_strcmp0(cmd, command->command_name) == 0) { GHashTable *command_hash = curr_hash->data;
PluginCommand *command = g_hash_table_lookup(command_hash, cmd);
if (command) {
g_list_free(command_hashes);
return command->help; return command->help;
} }
curr = g_slist_next(curr); curr_hash = g_list_next(curr_hash);
} }
g_list_free(command_hashes);
return NULL; return NULL;
} }
void void
plugins_run_timed(void) plugins_run_timed(void)
{ {
GSList *p_timed_function = p_timed_functions; GList *timed_functions_lists = g_hash_table_get_values(p_timed_functions);
while (p_timed_function) { GList *curr_list = timed_functions_lists;
PluginTimedFunction *timed_function = p_timed_function->data; while (curr_list) {
gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL); GList *timed_function_list = curr_list->data;
GList *curr = timed_function_list;
while (curr) {
PluginTimedFunction *timed_function = curr->data;
if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) { gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL);
timed_function->callback_func(timed_function);
g_timer_start(timed_function->timer); if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) {
timed_function->callback_exec(timed_function);
g_timer_start(timed_function->timer);
}
curr = g_list_next(curr);
} }
curr_list = g_list_next(curr_list);
p_timed_function = g_slist_next(p_timed_function);
} }
return;
g_list_free(timed_functions_lists);
} }
GList* GList*
@ -167,12 +356,22 @@ plugins_get_command_names(void)
{ {
GList *result = NULL; GList *result = NULL;
GSList *curr = p_commands; GList *command_hashes = g_hash_table_get_values(p_commands);
while (curr) { GList *curr_hash = command_hashes;
PluginCommand *command = curr->data; while (curr_hash) {
result = g_list_append(result, (char*)command->command_name); GHashTable *command_hash = curr_hash->data;
curr = g_slist_next(curr); GList *commands = g_hash_table_get_keys(command_hash);
GList *curr = commands;
while (curr) {
char *command = curr->data;
result = g_list_append(result, command);
curr = g_list_next(curr);
}
g_list_free(commands);
curr_hash = g_list_next(curr_hash);
} }
g_list_free(command_hashes);
return result; return result;
} }

View File

@ -40,33 +40,38 @@
#include "command/cmd_defs.h" #include "command/cmd_defs.h"
typedef struct p_command { typedef struct p_command {
const char *command_name; char *command_name;
int min_args; int min_args;
int max_args; int max_args;
CommandHelp *help; CommandHelp *help;
void *callback; void *callback;
void (*callback_func)(struct p_command *command, gchar **args); void (*callback_exec)(struct p_command *command, gchar **args);
void (*callback_destroy)(void *callback);
} PluginCommand; } PluginCommand;
typedef struct p_timed_function { typedef struct p_timed_function {
void *callback; void *callback;
void (*callback_func)(struct p_timed_function *timed_function); void (*callback_exec)(struct p_timed_function *timed_function);
void (*callback_destroy)(void *callback);
int interval_seconds; int interval_seconds;
GTimer *timer; GTimer *timer;
} PluginTimedFunction; } PluginTimedFunction;
typedef struct p_window_input_callback { typedef struct p_window_input_callback {
void *callback; void *callback;
void (*destroy)(void *callback); void (*callback_exec)(struct p_window_input_callback *window_callback, const char *tag, const char * const line);
void (*callback_func)(struct p_window_input_callback *window_callback, const char *tag, const char * const line); void (*callback_destroy)(void *callback);
} PluginWindowCallback; } PluginWindowCallback;
void callbacks_init(void); void callbacks_init(void);
void callbacks_remove(const char *const plugin_name);
void callbacks_close(void); void callbacks_close(void);
void callbacks_add_command(PluginCommand *command); void callbacks_add_command(const char *const plugin_name, PluginCommand *command);
void callbacks_add_timed(PluginTimedFunction *timed_function); void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function);
void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); gboolean callbacks_win_exists(const char *const plugin_name, const char *tag);
void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback);
void * callbacks_get_window_handler(const char *tag); void * callbacks_get_window_handler(const char *tag);
void callbacks_remove_win(const char *const plugin_name, const char *const tag);
#endif #endif

View File

@ -60,14 +60,18 @@
#include "ui/ui.h" #include "ui/ui.h"
static GSList* plugins; static GHashTable *plugins;
static gchar* _get_plugins_dir(void);
void void
plugins_init(void) plugins_init(void)
{ {
plugins = NULL; plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
callbacks_init(); callbacks_init();
autocompleters_init(); autocompleters_init();
plugin_themes_init();
plugin_settings_init();
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
python_env_init(); python_env_init();
@ -76,9 +80,6 @@ plugins_init(void)
c_env_init(); c_env_init();
#endif #endif
plugin_themes_init();
plugin_settings_init();
// load plugins // load plugins
gchar **plugins_pref = prefs_get_plugins(); gchar **plugins_pref = prefs_get_plugins();
if (plugins_pref) { if (plugins_pref) {
@ -91,7 +92,7 @@ plugins_init(void)
if (g_str_has_suffix(filename, ".py")) { if (g_str_has_suffix(filename, ".py")) {
ProfPlugin *plugin = python_plugin_create(filename); ProfPlugin *plugin = python_plugin_create(filename);
if (plugin) { if (plugin) {
plugins = g_slist_append(plugins, plugin); g_hash_table_insert(plugins, strdup(filename), plugin);
loaded = TRUE; loaded = TRUE;
} }
} }
@ -100,7 +101,7 @@ plugins_init(void)
if (g_str_has_suffix(filename, ".so")) { if (g_str_has_suffix(filename, ".so")) {
ProfPlugin *plugin = c_plugin_create(filename); ProfPlugin *plugin = c_plugin_create(filename);
if (plugin) { if (plugin) {
plugins = g_slist_append(plugins, plugin); g_hash_table_insert(plugins, strdup(filename), plugin);
loaded = TRUE; loaded = TRUE;
} }
} }
@ -113,12 +114,15 @@ plugins_init(void)
} }
// initialise plugins // initialise plugins
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL); plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
prefs_free_plugins(plugins_pref); prefs_free_plugins(plugins_pref);
@ -127,24 +131,38 @@ plugins_init(void)
} }
gboolean gboolean
_find_by_name(gconstpointer pluginp, gconstpointer namep) plugins_install(const char *const plugin_name, const char *const filename)
{ {
char *name = (char*)namep; char *plugins_dir = _get_plugins_dir();
ProfPlugin *plugin = (ProfPlugin*)pluginp; GString *target_path = g_string_new(plugins_dir);
free(plugins_dir);
g_string_append(target_path, "/");
g_string_append(target_path, plugin_name);
return g_strcmp0(name, plugin->name); ProfPlugin *plugin = g_hash_table_lookup(plugins, plugin_name);
if (plugin) {
plugins_unload(plugin_name);
}
gboolean result = copy_file(filename, target_path->str);
g_string_free(target_path, TRUE);
if (result) {
result = plugins_load(plugin_name);
}
return result;
} }
gboolean gboolean
plugins_load(const char *const name) plugins_load(const char *const name)
{ {
GSList *found = g_slist_find_custom(plugins, name, (GCompareFunc)_find_by_name); ProfPlugin *plugin = g_hash_table_lookup(plugins, name);
if (found) { if (plugin) {
log_info("Failed to load plugin: %s, plugin already loaded", name); log_info("Failed to load plugin: %s, plugin already loaded", name);
return FALSE; return FALSE;
} }
ProfPlugin *plugin = NULL;
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
if (g_str_has_suffix(name, ".py")) { if (g_str_has_suffix(name, ".py")) {
plugin = python_plugin_create(name); plugin = python_plugin_create(name);
@ -156,7 +174,7 @@ plugins_load(const char *const name)
} }
#endif #endif
if (plugin) { if (plugin) {
plugins = g_slist_append(plugins, plugin); g_hash_table_insert(plugins, strdup(name), plugin);
if (connection_get_status() == JABBER_CONNECTED) { if (connection_get_status() == JABBER_CONNECTED) {
const char *account_name = session_get_account_name(); const char *account_name = session_get_account_name();
const char *fulljid = connection_get_fulljid(); const char *fulljid = connection_get_fulljid();
@ -165,6 +183,7 @@ plugins_load(const char *const name)
plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL); plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL);
} }
log_info("Loaded plugin: %s", name); log_info("Loaded plugin: %s", name);
prefs_add_plugin(name);
return TRUE; return TRUE;
} else { } else {
log_info("Failed to load plugin: %s", name); log_info("Failed to load plugin: %s", name);
@ -172,10 +191,58 @@ plugins_load(const char *const name)
} }
} }
GSList * gboolean
plugins_get_list(void) plugins_unload(const char *const name)
{ {
return plugins; ProfPlugin *plugin = g_hash_table_lookup(plugins, name);
if (plugin) {
plugin->on_unload_func(plugin);
#ifdef HAVE_PYTHON
if (plugin->lang == LANG_PYTHON) {
python_plugin_destroy(plugin);
}
#endif
#ifdef HAVE_C
if (plugin->lang == LANG_C) {
c_plugin_destroy(plugin);
}
#endif
prefs_remove_plugin(name);
g_hash_table_remove(plugins, name);
}
return TRUE;
}
void
plugins_reload_all(void)
{
GList *plugin_names = g_hash_table_get_keys(plugins);
GList *plugin_names_dup = NULL;
GList *curr = plugin_names;
while (curr) {
plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data));
curr = g_list_next(curr);
}
g_list_free(plugin_names);
curr = plugin_names_dup;
while (curr) {
plugins_reload(curr->data);
curr = g_list_next(curr);
}
g_list_free_full(plugin_names_dup, free);
}
gboolean
plugins_reload(const char *const name)
{
gboolean res = plugins_unload(name);
if (res) {
res = plugins_load(name);
}
return res;
} }
static gchar* static gchar*
@ -198,7 +265,7 @@ _plugins_unloaded_list_dir(const gchar *const dir, GSList **result)
const gchar *plugin = g_dir_read_name(plugins_dir); const gchar *plugin = g_dir_read_name(plugins_dir);
while (plugin) { while (plugin) {
GSList *found = g_slist_find_custom(plugins, plugin, (GCompareFunc)_find_by_name); ProfPlugin *found = g_hash_table_lookup(plugins, plugin);
if ((g_str_has_suffix(plugin, ".so") || g_str_has_suffix(plugin, ".py")) && !found) { if ((g_str_has_suffix(plugin, ".so") || g_str_has_suffix(plugin, ".py")) && !found) {
*result = g_slist_append(*result, strdup(plugin)); *result = g_slist_append(*result, strdup(plugin));
} }
@ -218,6 +285,12 @@ plugins_unloaded_list(void)
return result; return result;
} }
GList*
plugins_loaded_list(void)
{
return g_hash_table_get_keys(plugins);
}
char * char *
plugins_autocomplete(const char * const input) plugins_autocomplete(const char * const input)
{ {
@ -234,51 +307,67 @@ void
plugins_win_process_line(char *win, const char * const line) plugins_win_process_line(char *win, const char * const line)
{ {
PluginWindowCallback *window = callbacks_get_window_handler(win); PluginWindowCallback *window = callbacks_get_window_handler(win);
window->callback_func(window, win, line); if (window) {
window->callback_exec(window, win, line);
}
}
void
plugins_close_win(const char *const plugin_name, const char *const tag)
{
callbacks_remove_win(plugin_name, tag);
} }
void void
plugins_on_start(void) plugins_on_start(void)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_start_func(plugin); plugin->on_start_func(plugin);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_shutdown(void) plugins_on_shutdown(void)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_shutdown_func(plugin); plugin->on_shutdown_func(plugin);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_connect(const char * const account_name, const char * const fulljid) plugins_on_connect(const char * const account_name, const char * const fulljid)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_connect_func(plugin, account_name, fulljid); plugin->on_connect_func(plugin, account_name, fulljid);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_disconnect(const char * const account_name, const char * const fulljid) plugins_on_disconnect(const char * const account_name, const char * const fulljid)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_disconnect_func(plugin, account_name, fulljid); plugin->on_disconnect_func(plugin, account_name, fulljid);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
char* char*
@ -287,7 +376,8 @@ plugins_pre_chat_message_display(const char * const jid, const char *message)
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_chat_message_display(plugin, jid, curr_message); new_message = plugin->pre_chat_message_display(plugin, jid, curr_message);
@ -296,8 +386,9 @@ plugins_pre_chat_message_display(const char * const jid, const char *message)
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_message; return curr_message;
} }
@ -305,12 +396,14 @@ plugins_pre_chat_message_display(const char * const jid, const char *message)
void void
plugins_post_chat_message_display(const char * const jid, const char *message) plugins_post_chat_message_display(const char * const jid, const char *message)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_chat_message_display(plugin, jid, message); plugin->post_chat_message_display(plugin, jid, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
char* char*
@ -319,7 +412,8 @@ plugins_pre_chat_message_send(const char * const jid, const char *message)
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_chat_message_send(plugin, jid, curr_message); new_message = plugin->pre_chat_message_send(plugin, jid, curr_message);
@ -328,8 +422,9 @@ plugins_pre_chat_message_send(const char * const jid, const char *message)
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_message; return curr_message;
} }
@ -337,12 +432,14 @@ plugins_pre_chat_message_send(const char * const jid, const char *message)
void void
plugins_post_chat_message_send(const char * const jid, const char *message) plugins_post_chat_message_send(const char * const jid, const char *message)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_chat_message_send(plugin, jid, message); plugin->post_chat_message_send(plugin, jid, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
char* char*
@ -351,7 +448,8 @@ plugins_pre_room_message_display(const char * const room, const char * const nic
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_room_message_display(plugin, room, nick, curr_message); new_message = plugin->pre_room_message_display(plugin, room, nick, curr_message);
@ -360,8 +458,9 @@ plugins_pre_room_message_display(const char * const room, const char * const nic
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_message; return curr_message;
} }
@ -369,12 +468,14 @@ plugins_pre_room_message_display(const char * const room, const char * const nic
void void
plugins_post_room_message_display(const char * const room, const char * const nick, const char *message) plugins_post_room_message_display(const char * const room, const char * const nick, const char *message)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_room_message_display(plugin, room, nick, message); plugin->post_room_message_display(plugin, room, nick, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
char* char*
@ -383,7 +484,8 @@ plugins_pre_room_message_send(const char * const room, const char *message)
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_room_message_send(plugin, room, curr_message); new_message = plugin->pre_room_message_send(plugin, room, curr_message);
@ -392,8 +494,9 @@ plugins_pre_room_message_send(const char * const room, const char *message)
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_message; return curr_message;
} }
@ -401,12 +504,14 @@ plugins_pre_room_message_send(const char * const room, const char *message)
void void
plugins_post_room_message_send(const char * const room, const char *message) plugins_post_room_message_send(const char * const room, const char *message)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_room_message_send(plugin, room, message); plugin->post_room_message_send(plugin, room, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
@ -420,12 +525,14 @@ plugins_on_room_history_message(const char *const room, const char *const nick,
timestamp_str = g_time_val_to_iso8601(&timestamp_tv); timestamp_str = g_time_val_to_iso8601(&timestamp_tv);
} }
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_room_history_message(plugin, room, nick, message, timestamp_str); plugin->on_room_history_message(plugin, room, nick, message, timestamp_str);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
free(timestamp_str); free(timestamp_str);
} }
@ -437,7 +544,8 @@ plugins_pre_priv_message_display(const char * const jid, const char *message)
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, curr_message); new_message = plugin->pre_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, curr_message);
@ -446,8 +554,9 @@ plugins_pre_priv_message_display(const char * const jid, const char *message)
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
jid_destroy(jidp); jid_destroy(jidp);
return curr_message; return curr_message;
@ -458,12 +567,14 @@ plugins_post_priv_message_display(const char * const jid, const char *message)
{ {
Jid *jidp = jid_create(jid); Jid *jidp = jid_create(jid);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, message); plugin->post_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
jid_destroy(jidp); jid_destroy(jidp);
} }
@ -475,7 +586,8 @@ plugins_pre_priv_message_send(const char * const jid, const char * const message
char *new_message = NULL; char *new_message = NULL;
char *curr_message = strdup(message); char *curr_message = strdup(message);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_message = plugin->pre_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, curr_message); new_message = plugin->pre_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, curr_message);
@ -484,8 +596,9 @@ plugins_pre_priv_message_send(const char * const jid, const char * const message
curr_message = strdup(new_message); curr_message = strdup(new_message);
free(new_message); free(new_message);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
jid_destroy(jidp); jid_destroy(jidp);
return curr_message; return curr_message;
@ -496,12 +609,14 @@ plugins_post_priv_message_send(const char * const jid, const char * const messag
{ {
Jid *jidp = jid_create(jid); Jid *jidp = jid_create(jid);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->post_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, message); plugin->post_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, message);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
jid_destroy(jidp); jid_destroy(jidp);
} }
@ -512,7 +627,8 @@ plugins_on_message_stanza_send(const char *const text)
char *new_stanza = NULL; char *new_stanza = NULL;
char *curr_stanza = strdup(text); char *curr_stanza = strdup(text);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_stanza = plugin->on_message_stanza_send(plugin, curr_stanza); new_stanza = plugin->on_message_stanza_send(plugin, curr_stanza);
@ -521,8 +637,9 @@ plugins_on_message_stanza_send(const char *const text)
curr_stanza = strdup(new_stanza); curr_stanza = strdup(new_stanza);
free(new_stanza); free(new_stanza);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_stanza; return curr_stanza;
} }
@ -532,15 +649,17 @@ plugins_on_message_stanza_receive(const char *const text)
{ {
gboolean cont = TRUE; gboolean cont = TRUE;
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
gboolean res = plugin->on_message_stanza_receive(plugin, text); gboolean res = plugin->on_message_stanza_receive(plugin, text);
if (res == FALSE) { if (res == FALSE) {
cont = FALSE; cont = FALSE;
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return cont; return cont;
} }
@ -551,7 +670,8 @@ plugins_on_presence_stanza_send(const char *const text)
char *new_stanza = NULL; char *new_stanza = NULL;
char *curr_stanza = strdup(text); char *curr_stanza = strdup(text);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_stanza = plugin->on_presence_stanza_send(plugin, curr_stanza); new_stanza = plugin->on_presence_stanza_send(plugin, curr_stanza);
@ -560,8 +680,9 @@ plugins_on_presence_stanza_send(const char *const text)
curr_stanza = strdup(new_stanza); curr_stanza = strdup(new_stanza);
free(new_stanza); free(new_stanza);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_stanza; return curr_stanza;
} }
@ -571,15 +692,17 @@ plugins_on_presence_stanza_receive(const char *const text)
{ {
gboolean cont = TRUE; gboolean cont = TRUE;
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
gboolean res = plugin->on_presence_stanza_receive(plugin, text); gboolean res = plugin->on_presence_stanza_receive(plugin, text);
if (res == FALSE) { if (res == FALSE) {
cont = FALSE; cont = FALSE;
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return cont; return cont;
} }
@ -590,7 +713,8 @@ plugins_on_iq_stanza_send(const char *const text)
char *new_stanza = NULL; char *new_stanza = NULL;
char *curr_stanza = strdup(text); char *curr_stanza = strdup(text);
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
new_stanza = plugin->on_iq_stanza_send(plugin, curr_stanza); new_stanza = plugin->on_iq_stanza_send(plugin, curr_stanza);
@ -599,8 +723,9 @@ plugins_on_iq_stanza_send(const char *const text)
curr_stanza = strdup(new_stanza); curr_stanza = strdup(new_stanza);
free(new_stanza); free(new_stanza);
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return curr_stanza; return curr_stanza;
} }
@ -610,15 +735,17 @@ plugins_on_iq_stanza_receive(const char *const text)
{ {
gboolean cont = TRUE; gboolean cont = TRUE;
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
gboolean res = plugin->on_iq_stanza_receive(plugin, text); gboolean res = plugin->on_iq_stanza_receive(plugin, text);
if (res == FALSE) { if (res == FALSE) {
cont = FALSE; cont = FALSE;
} }
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
return cont; return cont;
} }
@ -626,45 +753,53 @@ plugins_on_iq_stanza_receive(const char *const text)
void void
plugins_on_contact_offline(const char *const barejid, const char *const resource, const char *const status) plugins_on_contact_offline(const char *const barejid, const char *const resource, const char *const status)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_contact_offline(plugin, barejid, resource, status); plugin->on_contact_offline(plugin, barejid, resource, status);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_contact_presence(const char *const barejid, const char *const resource, const char *const presence, const char *const status, const int priority) plugins_on_contact_presence(const char *const barejid, const char *const resource, const char *const presence, const char *const status, const int priority)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_contact_presence(plugin, barejid, resource, presence, status, priority); plugin->on_contact_presence(plugin, barejid, resource, presence, status, priority);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_chat_win_focus(const char *const barejid) plugins_on_chat_win_focus(const char *const barejid)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_chat_win_focus(plugin, barejid); plugin->on_chat_win_focus(plugin, barejid);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
void void
plugins_on_room_win_focus(const char *const roomjid) plugins_on_room_win_focus(const char *const roomjid)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
ProfPlugin *plugin = curr->data; ProfPlugin *plugin = curr->data;
plugin->on_room_win_focus(plugin, roomjid); plugin->on_room_win_focus(plugin, roomjid);
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
} }
GList* GList*
@ -676,7 +811,8 @@ plugins_get_disco_features(void)
void void
plugins_shutdown(void) plugins_shutdown(void)
{ {
GSList *curr = plugins; GList *values = g_hash_table_get_values(plugins);
GList *curr = values;
while (curr) { while (curr) {
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
@ -690,8 +826,9 @@ plugins_shutdown(void)
} }
#endif #endif
curr = g_slist_next(curr); curr = g_list_next(curr);
} }
g_list_free(values);
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
python_shutdown(); python_shutdown();
#endif #endif

View File

@ -51,6 +51,7 @@ typedef struct prof_plugin_t {
void (*on_start_func)(struct prof_plugin_t* plugin); void (*on_start_func)(struct prof_plugin_t* plugin);
void (*on_shutdown_func)(struct prof_plugin_t* plugin); void (*on_shutdown_func)(struct prof_plugin_t* plugin);
void (*on_unload_func)(struct prof_plugin_t* plugin);
void (*on_connect_func)(struct prof_plugin_t* plugin, const char *const account_name, const char *const fulljid); void (*on_connect_func)(struct prof_plugin_t* plugin, const char *const account_name, const char *const fulljid);
void (*on_disconnect_func)(struct prof_plugin_t* plugin, const char *const account_name, void (*on_disconnect_func)(struct prof_plugin_t* plugin, const char *const account_name,
@ -98,13 +99,17 @@ typedef struct prof_plugin_t {
} ProfPlugin; } ProfPlugin;
void plugins_init(void); void plugins_init(void);
GSList* plugins_get_list(void);
GSList *plugins_unloaded_list(void); GSList *plugins_unloaded_list(void);
GList *plugins_loaded_list(void);
char* plugins_autocomplete(const char *const input); char* plugins_autocomplete(const char *const input);
void plugins_reset_autocomplete(void); void plugins_reset_autocomplete(void);
void plugins_shutdown(void); void plugins_shutdown(void);
gboolean plugins_install(const char *const plugin_name, const char *const filename);
gboolean plugins_load(const char *const name); gboolean plugins_load(const char *const name);
gboolean plugins_unload(const char *const name);
gboolean plugins_reload(const char *const name);
void plugins_reload_all(void);
void plugins_on_start(void); void plugins_on_start(void);
void plugins_on_shutdown(void); void plugins_on_shutdown(void);
@ -130,6 +135,7 @@ char* plugins_pre_priv_message_send(const char *const jid, const char *const mes
void plugins_post_priv_message_send(const char *const jid, const char *const message); void plugins_post_priv_message_send(const char *const jid, const char *const message);
void plugins_win_process_line(char *win, const char *const line); void plugins_win_process_line(char *win, const char *const line);
void plugins_close_win(const char *const plugin_name, const char *const tag);
char* plugins_on_message_stanza_send(const char *const text); char* plugins_on_message_stanza_send(const char *const text);
gboolean plugins_on_message_stanza_receive(const char *const text); gboolean plugins_on_message_stanza_receive(const char *const text);

View File

@ -42,15 +42,15 @@ int (*prof_cons_show)(const char * const message) = NULL;
int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL; int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL;
int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL; int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL;
void (*prof_register_command)(const char *command_name, int min_args, int max_args, void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void(*callback)(char **args)) = NULL; void(*callback)(char **args)) = NULL;
void (*prof_register_timed)(void(*callback)(void), int interval_seconds) = NULL; void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds) = NULL;
void (*prof_completer_add)(const char *key, char **items) = NULL; void (*_prof_completer_add)(const char *filename, const char *key, char **items) = NULL;
void (*prof_completer_remove)(const char *key, char **items) = NULL; void (*_prof_completer_remove)(const char *filename, const char *key, char **items) = NULL;
void (*prof_completer_clear)(const char *key) = NULL; void (*_prof_completer_clear)(const char *filename, const char *key) = NULL;
void (*prof_notify)(const char *message, int timeout_ms, const char *category) = NULL; void (*prof_notify)(const char *message, int timeout_ms, const char *category) = NULL;
@ -67,8 +67,8 @@ void (*prof_log_info)(const char *message) = NULL;
void (*prof_log_warning)(const char *message) = NULL; void (*prof_log_warning)(const char *message) = NULL;
void (*prof_log_error)(const char *message) = NULL; void (*prof_log_error)(const char *message) = NULL;
void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)) = NULL;
int (*prof_win_exists)(PROF_WIN_TAG win) = NULL; int (*prof_win_exists)(PROF_WIN_TAG win) = NULL;
void (*prof_win_create)(PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)) = NULL;
int (*prof_win_focus)(PROF_WIN_TAG win) = NULL; int (*prof_win_focus)(PROF_WIN_TAG win) = NULL;
int (*prof_win_show)(PROF_WIN_TAG win, char *line) = NULL; int (*prof_win_show)(PROF_WIN_TAG win, char *line) = NULL;
int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line) = NULL; int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line) = NULL;

View File

@ -35,6 +35,13 @@
#ifndef PROF_API_H #ifndef PROF_API_H
#define PROF_API_H #define PROF_API_H
#define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback)
#define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds)
#define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items)
#define prof_completer_remove(key, items) _prof_completer_remove(__FILE__, key, items)
#define prof_completer_clear(key) _prof_completer_clear(__FILE__, key)
#define prof_win_create(win, input_handler) _prof_win_create(__FILE__, win, input_handler)
typedef char* PROF_WIN_TAG; typedef char* PROF_WIN_TAG;
void (*prof_cons_alert)(void); void (*prof_cons_alert)(void);
@ -42,15 +49,15 @@ int (*prof_cons_show)(const char * const message);
int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message); int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message);
int (*prof_cons_bad_cmd_usage)(const char *const cmd); int (*prof_cons_bad_cmd_usage)(const char *const cmd);
void (*prof_register_command)(const char *command_name, int min_args, int max_args, void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args,
const char **synopsis, const char *description, const char *arguments[][2], const char **examples, const char **synopsis, const char *description, const char *arguments[][2], const char **examples,
void(*callback)(char **args)); void(*callback)(char **args));
void (*prof_register_timed)(void(*callback)(void), int interval_seconds); void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds);
void (*prof_completer_add)(const char *key, char **items); void (*_prof_completer_add)(const char *filename, const char *key, char **items);
void (*prof_completer_remove)(const char *key, char **items); void (*_prof_completer_remove)(const char *filename, const char *key, char **items);
void (*prof_completer_clear)(const char *key); void (*_prof_completer_clear)(const char *filename, const char *key);
void (*prof_notify)(const char *message, int timeout_ms, const char *category); void (*prof_notify)(const char *message, int timeout_ms, const char *category);
@ -67,8 +74,8 @@ void (*prof_log_info)(const char *message);
void (*prof_log_warning)(const char *message); void (*prof_log_warning)(const char *message);
void (*prof_log_error)(const char *message); void (*prof_log_error)(const char *message);
void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line));
int (*prof_win_exists)(PROF_WIN_TAG win); int (*prof_win_exists)(PROF_WIN_TAG win);
void (*prof_win_create)(PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line));
int (*prof_win_focus)(PROF_WIN_TAG win); int (*prof_win_focus)(PROF_WIN_TAG win);
int (*prof_win_show)(PROF_WIN_TAG win, char *line); int (*prof_win_show)(PROF_WIN_TAG win, char *line);
int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line); int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line);

View File

@ -33,6 +33,7 @@
*/ */
#include <Python.h> #include <Python.h>
#include <frameobject.h>
#include <glib.h> #include <glib.h>
@ -41,6 +42,9 @@
#include "plugins/python_plugins.h" #include "plugins/python_plugins.h"
#include "plugins/callbacks.h" #include "plugins/callbacks.h"
#include "plugins/autocompleters.h" #include "plugins/autocompleters.h"
#include "log.h"
static char* _python_plugin_name(void);
static PyObject* static PyObject*
python_api_cons_alert(PyObject *self, PyObject *args) python_api_cons_alert(PyObject *self, PyObject *args)
@ -115,6 +119,9 @@ python_api_register_command(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Register command %s for %s", command_name, plugin_name);
if (p_callback && PyCallable_Check(p_callback)) { if (p_callback && PyCallable_Check(p_callback)) {
Py_ssize_t len = PyList_Size(synopsis); Py_ssize_t len = PyList_Size(synopsis);
const char *c_synopsis[len == 0 ? 0 : len+1]; const char *c_synopsis[len == 0 ? 0 : len+1];
@ -158,11 +165,13 @@ python_api_register_command(PyObject *self, PyObject *args)
c_examples[len] = NULL; c_examples[len] = NULL;
allow_python_threads(); allow_python_threads();
api_register_command(command_name, min_args, max_args, c_synopsis, api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis,
description, c_arguments, c_examples, p_callback, python_command_callback); description, c_arguments, c_examples, p_callback, python_command_callback, NULL);
disable_python_threads(); disable_python_threads();
} }
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -176,12 +185,17 @@ python_api_register_timed(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Register timed for %s", plugin_name);
if (p_callback && PyCallable_Check(p_callback)) { if (p_callback && PyCallable_Check(p_callback)) {
allow_python_threads(); allow_python_threads();
api_register_timed(p_callback, interval_seconds, python_timed_callback); api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback, NULL);
disable_python_threads(); disable_python_threads();
} }
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -195,6 +209,9 @@ python_api_completer_add(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Autocomplete add %s for %s", key, plugin_name);
Py_ssize_t len = PyList_Size(items); Py_ssize_t len = PyList_Size(items);
char *c_items[len]; char *c_items[len];
@ -207,9 +224,11 @@ python_api_completer_add(PyObject *self, PyObject *args)
c_items[len] = NULL; c_items[len] = NULL;
allow_python_threads(); allow_python_threads();
autocompleters_add(key, c_items); api_completer_add(plugin_name, key, c_items);
disable_python_threads(); disable_python_threads();
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -223,6 +242,9 @@ python_api_completer_remove(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Autocomplete remove %s for %s", key, plugin_name);
Py_ssize_t len = PyList_Size(items); Py_ssize_t len = PyList_Size(items);
char *c_items[len]; char *c_items[len];
@ -235,9 +257,11 @@ python_api_completer_remove(PyObject *self, PyObject *args)
c_items[len] = NULL; c_items[len] = NULL;
allow_python_threads(); allow_python_threads();
autocompleters_remove(key, c_items); api_completer_remove(plugin_name, key, c_items);
disable_python_threads(); disable_python_threads();
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -250,10 +274,15 @@ python_api_completer_clear(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Autocomplete clear %s for %s", key, plugin_name);
allow_python_threads(); allow_python_threads();
autocompleters_clear(key); api_completer_clear(plugin_name, key);
disable_python_threads(); disable_python_threads();
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -447,12 +476,17 @@ python_api_win_create(PyObject *self, PyObject *args)
return Py_BuildValue(""); return Py_BuildValue("");
} }
char *plugin_name = _python_plugin_name();
log_debug("Win create %s for %s", tag, plugin_name);
if (p_callback && PyCallable_Check(p_callback)) { if (p_callback && PyCallable_Check(p_callback)) {
allow_python_threads(); allow_python_threads();
api_win_create(tag, p_callback, NULL, python_window_callback); api_win_create(plugin_name, tag, p_callback, python_window_callback, NULL);
disable_python_threads(); disable_python_threads();
} }
free(plugin_name);
return Py_BuildValue(""); return Py_BuildValue("");
} }
@ -790,3 +824,16 @@ python_api_init(void)
{ {
Py_InitModule("prof", apiMethods); Py_InitModule("prof", apiMethods);
} }
static char*
_python_plugin_name(void)
{
PyThreadState *ts = PyThreadState_Get();
PyFrameObject *frame = ts->frame;
char const* filename = PyString_AsString(frame->f_code->co_filename);
gchar **split = g_strsplit(filename, "/", 0);
char *plugin_name = strdup(split[g_strv_length(split)-1]);
g_strfreev(split);
return plugin_name;
}

View File

@ -43,6 +43,7 @@
#include "ui/ui.h" #include "ui/ui.h"
static PyThreadState *thread_state; static PyThreadState *thread_state;
static GHashTable *loaded_modules;
void void
allow_python_threads() allow_python_threads()
@ -56,9 +57,17 @@ disable_python_threads()
PyEval_RestoreThread(thread_state); PyEval_RestoreThread(thread_state);
} }
static void
_unref_module(PyObject *module)
{
Py_XDECREF(module);
}
void void
python_env_init(void) python_env_init(void)
{ {
loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_unref_module);
Py_Initialize(); Py_Initialize();
PyEval_InitThreads(); PyEval_InitThreads();
python_api_init(); python_api_init();
@ -80,8 +89,17 @@ ProfPlugin*
python_plugin_create(const char *const filename) python_plugin_create(const char *const filename)
{ {
disable_python_threads(); disable_python_threads();
gchar *module_name = g_strndup(filename, strlen(filename) - 3);
PyObject *p_module = PyImport_ImportModule(module_name); PyObject *p_module = g_hash_table_lookup(loaded_modules, filename);
if (p_module) {
p_module = PyImport_ReloadModule(p_module);
} else {
gchar *module_name = g_strndup(filename, strlen(filename) - 3);
p_module = PyImport_ImportModule(module_name);
g_hash_table_insert(loaded_modules, strdup(filename), p_module);
g_free(module_name);
}
python_check_error(); python_check_error();
if (p_module) { if (p_module) {
ProfPlugin *plugin = malloc(sizeof(ProfPlugin)); ProfPlugin *plugin = malloc(sizeof(ProfPlugin));
@ -91,6 +109,7 @@ python_plugin_create(const char *const filename)
plugin->init_func = python_init_hook; plugin->init_func = python_init_hook;
plugin->on_start_func = python_on_start_hook; plugin->on_start_func = python_on_start_hook;
plugin->on_shutdown_func = python_on_shutdown_hook; plugin->on_shutdown_func = python_on_shutdown_hook;
plugin->on_unload_func = python_on_unload_hook;
plugin->on_connect_func = python_on_connect_hook; plugin->on_connect_func = python_on_connect_hook;
plugin->on_disconnect_func = python_on_disconnect_hook; plugin->on_disconnect_func = python_on_disconnect_hook;
plugin->pre_chat_message_display = python_pre_chat_message_display_hook; plugin->pre_chat_message_display = python_pre_chat_message_display_hook;
@ -116,12 +135,10 @@ python_plugin_create(const char *const filename)
plugin->on_contact_presence = python_on_contact_presence_hook; plugin->on_contact_presence = python_on_contact_presence_hook;
plugin->on_chat_win_focus = python_on_chat_win_focus_hook; plugin->on_chat_win_focus = python_on_chat_win_focus_hook;
plugin->on_room_win_focus = python_on_room_win_focus_hook; plugin->on_room_win_focus = python_on_room_win_focus_hook;
g_free(module_name);
allow_python_threads(); allow_python_threads();
return plugin; return plugin;
} else { } else {
g_free(module_name);
allow_python_threads(); allow_python_threads();
return NULL; return NULL;
} }
@ -186,6 +203,25 @@ python_on_shutdown_hook(ProfPlugin *plugin)
allow_python_threads(); allow_python_threads();
} }
void
python_on_unload_hook(ProfPlugin *plugin)
{
disable_python_threads();
PyObject *p_function;
PyObject *p_module = plugin->module;
if (PyObject_HasAttrString(p_module, "prof_on_unload")) {
p_function = PyObject_GetAttrString(p_module, "prof_on_unload");
python_check_error();
if (p_function && PyCallable_Check(p_function)) {
PyObject_CallObject(p_function, NULL);
python_check_error();
Py_XDECREF(p_function);
}
}
allow_python_threads();
}
void void
python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid) python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid)
{ {
@ -889,8 +925,8 @@ void
python_plugin_destroy(ProfPlugin *plugin) python_plugin_destroy(ProfPlugin *plugin)
{ {
disable_python_threads(); disable_python_threads();
callbacks_remove(plugin->name);
free(plugin->name); free(plugin->name);
Py_XDECREF(plugin->module);
free(plugin); free(plugin);
allow_python_threads(); allow_python_threads();
} }
@ -899,5 +935,6 @@ void
python_shutdown(void) python_shutdown(void)
{ {
disable_python_threads(); disable_python_threads();
g_hash_table_destroy(loaded_modules);
Py_Finalize(); Py_Finalize();
} }

View File

@ -47,6 +47,7 @@ void python_init_hook(ProfPlugin *plugin, const char *const version, const char
const char *const account_name, const char *const fulljid); const char *const account_name, const char *const fulljid);
void python_on_start_hook(ProfPlugin *plugin); void python_on_start_hook(ProfPlugin *plugin);
void python_on_shutdown_hook(ProfPlugin *plugin); void python_on_shutdown_hook(ProfPlugin *plugin);
void python_on_unload_hook(ProfPlugin *plugin);
void python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);
void python_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void python_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);

View File

@ -61,7 +61,6 @@ plugin_themes_init(void)
g_chmod(fileloc->str, S_IRUSR | S_IWUSR); g_chmod(fileloc->str, S_IRUSR | S_IWUSR);
g_free(g_data); g_free(g_data);
g_string_free(fileloc, TRUE); g_string_free(fileloc, TRUE);
} }
void void

View File

@ -391,7 +391,6 @@ _shutdown(void)
plugins_on_shutdown(); plugins_on_shutdown();
muc_close(); muc_close();
caps_close(); caps_close();
ui_close();
#ifdef HAVE_LIBOTR #ifdef HAVE_LIBOTR
otr_shutdown(); otr_shutdown();
#endif #endif
@ -402,10 +401,11 @@ _shutdown(void)
theme_close(); theme_close();
accounts_close(); accounts_close();
tlscerts_close(); tlscerts_close();
cmd_uninit();
log_stderr_close(); log_stderr_close();
log_close(); log_close();
plugins_shutdown(); plugins_shutdown();
cmd_uninit();
ui_close();
prefs_close(); prefs_close();
if (saved_status) { if (saved_status) {
free(saved_status); free(saved_status);

View File

@ -117,6 +117,15 @@ autocomplete_add(Autocomplete ac, const char *item)
return; return;
} }
void
autocomplete_add_all(Autocomplete ac, char **items)
{
int i = 0;
for (i = 0; i < g_strv_length(items); i++) {
autocomplete_add(ac, items[i]);
}
}
void void
autocomplete_remove(Autocomplete ac, const char *const item) autocomplete_remove(Autocomplete ac, const char *const item)
{ {
@ -139,6 +148,15 @@ autocomplete_remove(Autocomplete ac, const char *const item)
return; return;
} }
void
autocomplete_remove_all(Autocomplete ac, char **items)
{
int i = 0;
for (i = 0; i < g_strv_length(items); i++) {
autocomplete_remove(ac, items[i]);
}
}
GSList* GSList*
autocomplete_create_list(Autocomplete ac) autocomplete_create_list(Autocomplete ac)
{ {

View File

@ -50,7 +50,9 @@ void autocomplete_clear(Autocomplete ac);
void autocomplete_free(Autocomplete ac); void autocomplete_free(Autocomplete ac);
void autocomplete_add(Autocomplete ac, const char *item); void autocomplete_add(Autocomplete ac, const char *item);
void autocomplete_add_all(Autocomplete ac, char **items);
void autocomplete_remove(Autocomplete ac, const char *const item); void autocomplete_remove(Autocomplete ac, const char *const item);
void autocomplete_remove_all(Autocomplete ac, char **items);
// find the next item prefixed with search string // find the next item prefixed with search string
gchar* autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote); gchar* autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote);

View File

@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char
} }
void void
ui_show_lines(ProfWin *window, const gchar** lines) ui_show_lines(ProfWin *window, gchar** lines)
{ {
if (lines) { if (lines) {
int i; int i;

View File

@ -110,7 +110,7 @@ void ui_goodbye_title(void);
void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message); void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message);
void ui_handle_room_config_submit_result(const char *const roomjid); void ui_handle_room_config_submit_result(const char *const roomjid);
void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message); void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message);
void ui_show_lines(ProfWin *window, const gchar** lines); void ui_show_lines(ProfWin *window, gchar** lines);
void ui_redraw_all_room_rosters(void); void ui_redraw_all_room_rosters(void);
void ui_show_all_room_rosters(void); void ui_show_all_room_rosters(void);
void ui_hide_all_room_rosters(void); void ui_hide_all_room_rosters(void);
@ -344,7 +344,7 @@ ProfWin* win_create_chat(const char *const barejid);
ProfWin* win_create_muc(const char *const roomjid); ProfWin* win_create_muc(const char *const roomjid);
ProfWin* win_create_muc_config(const char *const title, DataForm *form); ProfWin* win_create_muc_config(const char *const title, DataForm *form);
ProfWin* win_create_private(const char *const fulljid); ProfWin* win_create_private(const char *const fulljid);
ProfWin* win_create_plugin(const char *const tag); ProfWin* win_create_plugin(const char *const plugin_name, const char *const tag);
void win_update_virtual(ProfWin *window); void win_update_virtual(ProfWin *window);
void win_free(ProfWin *window); void win_free(ProfWin *window);
gboolean win_notify_remind(ProfWin *window); gboolean win_notify_remind(ProfWin *window);

View File

@ -190,6 +190,7 @@ typedef struct prof_xml_win_t {
typedef struct prof_plugin_win_t { typedef struct prof_plugin_win_t {
ProfWin super; ProfWin super;
char *tag; char *tag;
char *plugin_name;
unsigned long memcheck; unsigned long memcheck;
} ProfPluginWin; } ProfPluginWin;

View File

@ -238,13 +238,14 @@ win_create_xmlconsole(void)
} }
ProfWin* ProfWin*
win_create_plugin(const char *const tag) win_create_plugin(const char *const plugin_name, const char *const tag)
{ {
ProfPluginWin *new_win = malloc(sizeof(ProfPluginWin)); ProfPluginWin *new_win = malloc(sizeof(ProfPluginWin));
new_win->super.type = WIN_PLUGIN; new_win->super.type = WIN_PLUGIN;
new_win->super.layout = _win_create_simple_layout(); new_win->super.layout = _win_create_simple_layout();
new_win->tag = strdup(tag); new_win->tag = strdup(tag);
new_win->plugin_name = strdup(plugin_name);
new_win->memcheck = PROFPLUGINWIN_MEMCHECK; new_win->memcheck = PROFPLUGINWIN_MEMCHECK;

View File

@ -48,7 +48,7 @@
#include "window_list.h" #include "window_list.h"
#include "plugins/plugins.h" #include "plugins/plugins.h"
#include "xmpp/xmpp.h" #include "xmpp/xmpp.h"
#include "config/preferences.h"
static GHashTable *windows; static GHashTable *windows;
static int current; static int current;
@ -226,6 +226,22 @@ wins_get_plugin(const char *const tag)
return NULL; return NULL;
} }
void
wins_close_plugin(char *tag)
{
ProfWin *toclose = wins_get_by_string(tag);
if (toclose == NULL) {
return;
}
int index = wins_get_num(toclose);
ui_close_win(index);
if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) {
wins_tidy();
}
}
GList* GList*
wins_get_private_chats(const char *const roomjid) wins_get_private_chats(const char *const roomjid)
{ {
@ -564,6 +580,7 @@ wins_close_by_num(int i)
case WIN_PLUGIN: case WIN_PLUGIN:
{ {
ProfPluginWin *pluginwin = (ProfPluginWin*)window; ProfPluginWin *pluginwin = (ProfPluginWin*)window;
plugins_close_win(pluginwin->plugin_name, pluginwin->tag);
autocomplete_remove(wins_ac, pluginwin->tag); autocomplete_remove(wins_ac, pluginwin->tag);
autocomplete_remove(wins_close_ac, pluginwin->tag); autocomplete_remove(wins_close_ac, pluginwin->tag);
break; break;
@ -665,12 +682,12 @@ wins_new_private(const char *const fulljid)
} }
ProfWin * ProfWin *
wins_new_plugin(const char * const tag) wins_new_plugin(const char *const plugin_name, const char * const tag)
{ {
GList *keys = g_hash_table_get_keys(windows); GList *keys = g_hash_table_get_keys(windows);
int result = get_next_available_win_num(keys); int result = get_next_available_win_num(keys);
g_list_free(keys); g_list_free(keys);
ProfWin *newwin = win_create_plugin(tag); ProfWin *newwin = win_create_plugin(plugin_name, tag);
g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin);
autocomplete_add(wins_ac, tag); autocomplete_add(wins_ac, tag);
autocomplete_add(wins_close_ac, tag); autocomplete_add(wins_close_ac, tag);

View File

@ -44,7 +44,7 @@ ProfWin* wins_new_chat(const char *const barejid);
ProfWin* wins_new_muc(const char *const roomjid); ProfWin* wins_new_muc(const char *const roomjid);
ProfWin* wins_new_muc_config(const char *const roomjid, DataForm *form); ProfWin* wins_new_muc_config(const char *const roomjid, DataForm *form);
ProfWin* wins_new_private(const char *const fulljid); ProfWin* wins_new_private(const char *const fulljid);
ProfWin* wins_new_plugin(const char *const tag); ProfWin* wins_new_plugin(const char *const plugin_name, const char *const tag);
gboolean wins_chat_exists(const char *const barejid); gboolean wins_chat_exists(const char *const barejid);
GList* wins_get_private_chats(const char *const roomjid); GList* wins_get_private_chats(const char *const roomjid);
@ -61,6 +61,8 @@ ProfPrivateWin* wins_get_private(const char *const fulljid);
ProfPluginWin* wins_get_plugin(const char *const tag); ProfPluginWin* wins_get_plugin(const char *const tag);
ProfXMLWin* wins_get_xmlconsole(void); ProfXMLWin* wins_get_xmlconsole(void);
void wins_close_plugin(char *tag);
ProfWin* wins_get_current(void); ProfWin* wins_get_current(void);
void wins_set_current_by_num(int i); void wins_set_current_by_num(int i);

View File

@ -0,0 +1,57 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "plugins/callbacks.h"
#include "plugins/plugins.h"
void returns_no_commands(void **state)
{
callbacks_init();
GList *commands = plugins_get_command_names();
assert_true(commands == NULL);
}
void returns_commands(void **state)
{
callbacks_init();
PluginCommand *command1 = malloc(sizeof(PluginCommand));
command1->command_name = strdup("command1");
callbacks_add_command("plugin1", command1);
PluginCommand *command2 = malloc(sizeof(PluginCommand));
command2->command_name = strdup("command2");
callbacks_add_command("plugin1", command2);
PluginCommand *command3 = malloc(sizeof(PluginCommand));
command3->command_name = strdup("command3");
callbacks_add_command("plugin2", command3);
GList *names = plugins_get_command_names();
assert_true(g_list_length(names) == 3);
gboolean foundCommand1 = FALSE;
gboolean foundCommand2 = FALSE;
gboolean foundCommand3 = FALSE;
GList *curr = names;
while (curr) {
if (g_strcmp0(curr->data, "command1") == 0) {
foundCommand1 = TRUE;
}
if (g_strcmp0(curr->data, "command2") == 0) {
foundCommand2 = TRUE;
}
if (g_strcmp0(curr->data, "command3") == 0) {
foundCommand3 = TRUE;
}
curr = g_list_next(curr);
}
assert_true(foundCommand1 && foundCommand2 && foundCommand3);
}

View File

@ -0,0 +1,2 @@
void returns_no_commands(void **state);
void returns_commands(void **state);

View File

@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {}
void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {} void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {}
void mucconfwin_form_help(ProfMucConfWin *confwin) {} void mucconfwin_form_help(ProfMucConfWin *confwin) {}
void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {} void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {}
void ui_show_lines(ProfWin *window, const gchar** lines) {} void ui_show_lines(ProfWin *window, gchar** lines) {}
void ui_redraw_all_room_rosters(void) {} void ui_redraw_all_room_rosters(void) {}
void ui_show_all_room_rosters(void) {} void ui_show_all_room_rosters(void) {}
void ui_hide_all_room_rosters(void) {} void ui_hide_all_room_rosters(void) {}
@ -497,7 +497,7 @@ ProfWin* win_create_private(const char * const fulljid)
{ {
return NULL; return NULL;
} }
ProfWin* win_create_plugin(const char * const tag) ProfWin* win_create_plugin(const char *const plugin_name, const char * const tag)
{ {
return NULL; return NULL;
} }

View File

@ -33,6 +33,7 @@
#include "test_cmd_roster.h" #include "test_cmd_roster.h"
#include "test_cmd_disconnect.h" #include "test_cmd_disconnect.h"
#include "test_form.h" #include "test_form.h"
#include "test_callbacks.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
const UnitTest all_tests[] = { const UnitTest all_tests[] = {
@ -602,6 +603,9 @@ int main(int argc, char* argv[]) {
unit_test(prof_partial_occurrences_tests), unit_test(prof_partial_occurrences_tests),
unit_test(prof_whole_occurrences_tests), unit_test(prof_whole_occurrences_tests),
unit_test(returns_no_commands),
unit_test(returns_commands),
}; };
return run_tests(all_tests); return run_tests(all_tests);