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:
commit
069fe295e2
@ -123,6 +123,7 @@ unittest_sources = \
|
||||
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_disconnect.c tests/unittests/test_cmd_disconnect.h \
|
||||
tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \
|
||||
tests/unittests/unittests.c
|
||||
|
||||
functionaltest_sources = \
|
||||
|
@ -57,6 +57,8 @@
|
||||
#include "pgp/gpg.h"
|
||||
#endif
|
||||
|
||||
static char* _complete_filepath(const char *const input, char *const startstr);
|
||||
|
||||
static char* _sub_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);
|
||||
@ -185,7 +187,9 @@ static Autocomplete console_msg_ac;
|
||||
static Autocomplete autoping_ac;
|
||||
static Autocomplete plugins_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 tray_ac;
|
||||
static Autocomplete presence_ac;
|
||||
@ -484,6 +488,8 @@ cmd_ac_init(void)
|
||||
|
||||
theme_load_ac = NULL;
|
||||
plugins_load_ac = NULL;
|
||||
plugins_unload_ac = NULL;
|
||||
plugins_reload_ac = NULL;
|
||||
|
||||
who_roster_ac = autocomplete_new();
|
||||
autocomplete_add(who_roster_ac, "chat");
|
||||
@ -701,9 +707,12 @@ cmd_ac_init(void)
|
||||
autocomplete_add(autoping_ac, "timeout");
|
||||
|
||||
plugins_ac = autocomplete_new();
|
||||
autocomplete_add(plugins_ac, "install");
|
||||
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();
|
||||
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
|
||||
cmd_ac_exists(char *cmd)
|
||||
{
|
||||
@ -889,7 +906,7 @@ cmd_ac_reset(ProfWin *window)
|
||||
autocomplete_reset(notify_mention_ac);
|
||||
autocomplete_reset(notify_trigger_ac);
|
||||
autocomplete_reset(sub_ac);
|
||||
autocomplete_reset(sendfile_ac);
|
||||
autocomplete_reset(filepath_ac);
|
||||
|
||||
autocomplete_reset(who_room_ac);
|
||||
autocomplete_reset(who_roster_ac);
|
||||
@ -909,6 +926,14 @@ cmd_ac_reset(ProfWin *window)
|
||||
autocomplete_free(plugins_load_ac);
|
||||
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_set_ac);
|
||||
autocomplete_reset(account_clear_ac);
|
||||
@ -1087,7 +1112,9 @@ cmd_ac_uninit(void)
|
||||
autocomplete_free(autoping_ac);
|
||||
autocomplete_free(plugins_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(tray_ac);
|
||||
autocomplete_free(presence_ac);
|
||||
@ -1865,6 +1892,11 @@ static char*
|
||||
_plugins_autocomplete(ProfWin *window, const char *const input)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
if (strncmp(input, "/plugins install ", 17) == 0) {
|
||||
return _complete_filepath(input, "/plugins install");
|
||||
}
|
||||
|
||||
if (strncmp(input, "/plugins load ", 14) == 0) {
|
||||
if (plugins_load_ac == NULL) {
|
||||
plugins_load_ac = autocomplete_new();
|
||||
@ -1881,6 +1913,41 @@ _plugins_autocomplete(ProfWin *window, const char *const input)
|
||||
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);
|
||||
if (result) {
|
||||
return result;
|
||||
@ -2659,107 +2726,9 @@ _close_autocomplete(ProfWin *window, const char *const input)
|
||||
static char*
|
||||
_sendfile_autocomplete(ProfWin *window, const char *const input)
|
||||
{
|
||||
static char* last_directory = NULL;
|
||||
|
||||
unsigned int output_off = 0;
|
||||
|
||||
char *result = NULL;
|
||||
char *tmp;
|
||||
|
||||
// strip command
|
||||
char *inpcp = (char*)input + 9;
|
||||
while (*inpcp == ' ') {
|
||||
inpcp++;
|
||||
return _complete_filepath(input, "/sendfile");
|
||||
}
|
||||
|
||||
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*
|
||||
_subject_autocomplete(ProfWin *window, const char *const input)
|
||||
{
|
||||
@ -2959,3 +2928,106 @@ _presence_autocomplete(ProfWin *window, const char *const input)
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ void cmd_ac_add_alias(ProfAlias *alias);
|
||||
void cmd_ac_add_alias_value(char *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);
|
||||
|
||||
gboolean cmd_ac_exists(char *cmd);
|
||||
|
@ -1979,13 +1979,22 @@ static struct cmd_t command_defs[] =
|
||||
CMD_NOTAGS
|
||||
CMD_SYN(
|
||||
"/plugins",
|
||||
"/plugins load <plugin>")
|
||||
"/plugins install <path>",
|
||||
"/plugins unload <plugin>",
|
||||
"/plugins load <plugin>",
|
||||
"/plugins reload [<plugin>]")
|
||||
CMD_DESC(
|
||||
"Manage plugins. Passing no arguments lists currently loaded plugins.")
|
||||
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(
|
||||
"/plugin load browser.py")
|
||||
"/plugin install /home/steveharris/Downloads/metal.py",
|
||||
"/plugin load browser.py",
|
||||
"/plugin unload say.py",
|
||||
"/plugin reload wikipedia.py")
|
||||
},
|
||||
|
||||
{ "/prefs",
|
||||
|
@ -3809,7 +3809,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args)
|
||||
} else {
|
||||
mucconfwin_form_help(confwin);
|
||||
|
||||
const gchar **help_text = NULL;
|
||||
gchar **help_text = NULL;
|
||||
Command *command = cmd_get("/form");
|
||||
|
||||
if (command) {
|
||||
@ -6025,34 +6025,103 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args)
|
||||
gboolean
|
||||
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) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
gboolean res = plugins_load(args[1]);
|
||||
if (res) {
|
||||
prefs_add_plugin(args[1]);
|
||||
cons_show("Loaded plugin: %s", args[1]);
|
||||
} else {
|
||||
cons_show("Failed to load plugin: %s", args[1]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else if (g_strcmp0(args[0], "unload") == 0) {
|
||||
if (args[1] == NULL) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
gboolean res = plugins_unload(args[1]);
|
||||
if (res) {
|
||||
cons_show("Unloaded plugin: %s", args[1]);
|
||||
} else {
|
||||
GSList *plugins = plugins_get_list();
|
||||
GSList *curr = plugins;
|
||||
if (curr == NULL) {
|
||||
cons_show("Failed to unload plugin: %s", args[1]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} 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]);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
GList *plugins = plugins_loaded_list();
|
||||
if (plugins == NULL) {
|
||||
cons_show("No plugins installed.");
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GList *curr = plugins;
|
||||
cons_show("Installed plugins:");
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
cons_show(" %s", plugin->name);
|
||||
curr = g_slist_next(curr);
|
||||
cons_show(" %s", curr->data);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
}
|
||||
g_slist_free(curr);
|
||||
g_list_free(plugins);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -39,11 +39,11 @@
|
||||
|
||||
// Command help strings
|
||||
typedef struct cmd_help_t {
|
||||
const gchar *tags[20];
|
||||
const gchar *synopsis[50];
|
||||
const gchar *desc;
|
||||
const gchar *args[128][2];
|
||||
const gchar *examples[20];
|
||||
gchar *tags[20];
|
||||
gchar *synopsis[50];
|
||||
gchar *desc;
|
||||
gchar *args[128][2];
|
||||
gchar *examples[20];
|
||||
} CommandHelp;
|
||||
|
||||
/*
|
||||
|
26
src/common.c
26
src/common.c
@ -38,6 +38,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@ -155,6 +156,31 @@ mkdir_recursive(const char *dir)
|
||||
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*
|
||||
str_replace(const char *string, const char *substr,
|
||||
const char *replacement)
|
||||
|
@ -102,6 +102,7 @@ gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key);
|
||||
|
||||
gboolean create_dir(char *name);
|
||||
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);
|
||||
int str_contains(const char str[], int size, char ch);
|
||||
gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg);
|
||||
|
@ -64,7 +64,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con
|
||||
GList *curr = glist;
|
||||
i = 0;
|
||||
while (curr) {
|
||||
new_list[i++] = strdup(curr->data);
|
||||
new_list[i++] = curr->data;
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
new_list[i] = NULL;
|
||||
@ -73,7 +73,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con
|
||||
// list not found
|
||||
} else {
|
||||
const gchar* new_list[2];
|
||||
new_list[0] = strdup(item);
|
||||
new_list[0] = item;
|
||||
new_list[1] = NULL;
|
||||
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;
|
||||
i = 0;
|
||||
while (curr) {
|
||||
new_list[i++] = strdup(curr->data);
|
||||
new_list[i++] = curr->data;
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
new_list[i] = NULL;
|
||||
|
@ -631,6 +631,13 @@ prefs_add_plugin(const char *const name)
|
||||
_save_prefs();
|
||||
}
|
||||
|
||||
void
|
||||
prefs_remove_plugin(const char *const name)
|
||||
{
|
||||
conf_string_list_remove(prefs, "plugins", "load", name);
|
||||
_save_prefs();
|
||||
}
|
||||
|
||||
void
|
||||
prefs_free_plugins(gchar **plugins)
|
||||
{
|
||||
|
@ -191,6 +191,7 @@ void prefs_set_autoxa_time(gint value);
|
||||
gchar** prefs_get_plugins(void);
|
||||
void prefs_free_plugins(gchar **plugins);
|
||||
void prefs_add_plugin(const char *const name);
|
||||
void prefs_remove_plugin(const char *const name);
|
||||
|
||||
char prefs_get_otr_char(void);
|
||||
void prefs_set_otr_char(char ch);
|
||||
|
@ -106,19 +106,22 @@ api_cons_bad_cmd_usage(const char *const cmd)
|
||||
}
|
||||
|
||||
void
|
||||
api_register_command(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,
|
||||
void(*callback_func)(PluginCommand *command, gchar **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, void(*callback_exec)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback))
|
||||
{
|
||||
PluginCommand *command = malloc(sizeof(PluginCommand));
|
||||
command->command_name = command_name;
|
||||
command->command_name = strdup(command_name);
|
||||
command->min_args = min_args;
|
||||
command->max_args = max_args;
|
||||
command->callback = callback;
|
||||
command->callback_func = callback_func;
|
||||
command->callback_exec = callback_exec;
|
||||
command->callback_destroy = callback_destroy;
|
||||
|
||||
CommandHelp *help = malloc(sizeof(CommandHelp));
|
||||
|
||||
help->tags[0] = NULL;
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; synopsis[i] != NULL; 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;
|
||||
|
||||
callbacks_add_command(command);
|
||||
callbacks_add_command(plugin_name, command);
|
||||
}
|
||||
|
||||
void
|
||||
api_register_timed(void *callback, int interval_seconds,
|
||||
void (*callback_func)(PluginTimedFunction *timed_function))
|
||||
api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
|
||||
void (*callback_exec)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback))
|
||||
{
|
||||
PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction));
|
||||
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->timer = g_timer_new();
|
||||
|
||||
callbacks_add_timed(timed_function);
|
||||
callbacks_add_timed(plugin_name, timed_function);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -292,17 +296,24 @@ api_win_exists(const char *tag)
|
||||
|
||||
void
|
||||
api_win_create(
|
||||
const char *const plugin_name,
|
||||
const char *tag,
|
||||
void *callback,
|
||||
void(*destroy)(void *callback),
|
||||
void(*callback_func)(PluginWindowCallback *window_callback, const char *tag, const char * const line))
|
||||
void(*callback_exec)(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));
|
||||
window->callback = callback;
|
||||
window->callback_func = callback_func;
|
||||
window->destroy = destroy;
|
||||
callbacks_add_window_handler(tag, window);
|
||||
wins_new_plugin(tag);
|
||||
window->callback_exec = callback_exec;
|
||||
window->callback_destroy = callback_destroy;
|
||||
|
||||
callbacks_add_window_handler(plugin_name, tag, window);
|
||||
|
||||
wins_new_plugin(plugin_name, tag);
|
||||
|
||||
// set status bar active
|
||||
ProfPluginWin *pluginwin = wins_get_plugin(tag);
|
||||
|
@ -50,15 +50,15 @@ gboolean api_current_win_is_console(void);
|
||||
char* api_get_current_nick(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,
|
||||
void *callback, void(*callback_func)(PluginCommand *command, gchar **args));
|
||||
void api_register_timed(void *callback, int interval_seconds,
|
||||
void (*callback_func)(PluginTimedFunction *timed_function));
|
||||
void *callback, void(*callback_func)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback));
|
||||
void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds,
|
||||
void (*callback_func)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback));
|
||||
|
||||
void api_completer_add(const char *key, char **items);
|
||||
void api_completer_remove(const char *key, char **items);
|
||||
void api_completer_clear(const char *key);
|
||||
void api_completer_add(const char *const plugin_name, 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 *const plugin_name, const char *key);
|
||||
|
||||
void api_log_debug(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);
|
||||
void api_win_create(
|
||||
const char *const plugin_name,
|
||||
const char *tag,
|
||||
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_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);
|
||||
|
@ -38,56 +38,71 @@
|
||||
|
||||
#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
|
||||
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
|
||||
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)) {
|
||||
Autocomplete existing_ac = g_hash_table_lookup(autocompleters, key);
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < g_strv_length(items); i++) {
|
||||
autocomplete_add(existing_ac, items[i]);
|
||||
}
|
||||
GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name);
|
||||
if (key_to_ac) {
|
||||
if (g_hash_table_contains(key_to_ac, key)) {
|
||||
Autocomplete existing_ac = g_hash_table_lookup(key_to_ac, key);
|
||||
autocomplete_add_all(existing_ac, items);
|
||||
} else {
|
||||
Autocomplete new_ac = autocomplete_new();
|
||||
int i = 0;
|
||||
for (i = 0; i < g_strv_length(items); i++) {
|
||||
autocomplete_add(new_ac, items[i]);
|
||||
autocomplete_add_all(new_ac, items);
|
||||
g_hash_table_insert(key_to_ac, strdup(key), new_ac);
|
||||
}
|
||||
g_hash_table_insert(autocompleters, strdup(key), new_ac);
|
||||
} 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_add_all(new_ac, items);
|
||||
g_hash_table_insert(key_to_ac, strdup(key), new_ac);
|
||||
g_hash_table_insert(plugin_to_acs, strdup(plugin_name), key_to_ac);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Autocomplete ac = g_hash_table_lookup(autocompleters, key);
|
||||
int i = 0;
|
||||
for (i = 0; i < g_strv_length(items); i++) {
|
||||
autocomplete_remove(ac, items[i]);
|
||||
if (!g_hash_table_contains(key_to_ac, key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Autocomplete ac = g_hash_table_lookup(key_to_ac, key);
|
||||
autocomplete_remove_all(ac, items);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -96,10 +111,15 @@ autocompleters_complete(const char * const input)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
GList *keys = g_hash_table_get_keys(autocompleters);
|
||||
GList *ac_hashes = g_hash_table_get_values(plugin_to_acs);
|
||||
GList *curr_hash = ac_hashes;
|
||||
while (curr_hash) {
|
||||
GHashTable *key_to_ac = curr_hash->data;
|
||||
|
||||
GList *keys = g_hash_table_get_keys(key_to_ac);
|
||||
GList *curr = keys;
|
||||
while (curr) {
|
||||
result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(autocompleters, curr->data), TRUE);
|
||||
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;
|
||||
@ -108,13 +128,20 @@ autocompleters_complete(const char * const input)
|
||||
}
|
||||
g_list_free(keys);
|
||||
|
||||
curr_hash = g_list_next(curr_hash);
|
||||
}
|
||||
g_list_free(ac_hashes);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_hash = ac_hashes;
|
||||
while (curr_hash) {
|
||||
GList *acs = g_hash_table_get_values(curr_hash->data);
|
||||
GList *curr = acs;
|
||||
while (curr) {
|
||||
autocomplete_reset(curr->data);
|
||||
@ -122,9 +149,13 @@ autocompleters_reset(void)
|
||||
}
|
||||
|
||||
g_list_free(acs);
|
||||
curr_hash = g_list_next(curr_hash);
|
||||
}
|
||||
|
||||
g_list_free(ac_hashes);
|
||||
}
|
||||
|
||||
void autocompleters_destroy(void)
|
||||
{
|
||||
g_hash_table_destroy(autocompleters);
|
||||
g_hash_table_destroy(plugin_to_acs);
|
||||
}
|
||||
|
@ -38,9 +38,9 @@
|
||||
#include <glib.h>
|
||||
|
||||
void autocompleters_init(void);
|
||||
void autocompleters_add(const char *key, char **items);
|
||||
void autocompleters_remove(const char *key, char **items);
|
||||
void autocompleters_clear(const char *key);
|
||||
void autocompleters_add(const char *const plugin_name, const char *key, char **items);
|
||||
void autocompleters_remove(const char *const plugin_name, const char *key, char **items);
|
||||
void autocompleters_clear(const char *const plugin_name, const char *key);
|
||||
char* autocompleters_complete(const char * const input);
|
||||
void autocompleters_reset(void);
|
||||
void autocompleters_destroy(void);
|
||||
|
@ -53,6 +53,8 @@ typedef struct window_wrapper_t {
|
||||
void(*func)(char *tag, char *line);
|
||||
} WindowWrapper;
|
||||
|
||||
static char* _c_plugin_name(const char *filename);
|
||||
|
||||
static void
|
||||
c_api_cons_alert(void)
|
||||
{
|
||||
@ -78,40 +80,65 @@ c_api_cons_bad_cmd_usage(const char *const cmd)
|
||||
}
|
||||
|
||||
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,
|
||||
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));
|
||||
wrapper->func = callback;
|
||||
api_register_command(command_name, min_args, max_args, synopsis,
|
||||
description, arguments, examples, wrapper, c_command_callback);
|
||||
api_register_command(plugin_name, command_name, min_args, max_args, synopsis,
|
||||
description, arguments, examples, wrapper, c_command_callback, free);
|
||||
|
||||
free(plugin_name);
|
||||
}
|
||||
|
||||
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));
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -187,11 +214,16 @@ c_api_win_exists(char *tag)
|
||||
}
|
||||
|
||||
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));
|
||||
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
|
||||
@ -297,11 +329,12 @@ c_api_init(void)
|
||||
prof_cons_show = c_api_cons_show;
|
||||
prof_cons_show_themed = c_api_cons_show_themed;
|
||||
prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage;
|
||||
prof_register_command = c_api_register_command;
|
||||
prof_register_timed = c_api_register_timed;
|
||||
prof_completer_add = c_api_completer_add;
|
||||
prof_completer_remove = c_api_completer_remove;
|
||||
prof_completer_clear = c_api_completer_clear;
|
||||
_prof_register_command = c_api_register_command;
|
||||
_prof_register_timed = c_api_register_timed;
|
||||
_prof_completer_add = c_api_completer_add;
|
||||
_prof_completer_remove = c_api_completer_remove;
|
||||
_prof_completer_clear = c_api_completer_clear;
|
||||
_prof_win_create = c_api_win_create;
|
||||
prof_notify = c_api_notify;
|
||||
prof_send_line = c_api_send_line;
|
||||
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_error = c_api_log_error;
|
||||
prof_win_exists = c_api_win_exists;
|
||||
prof_win_create = c_api_win_create;
|
||||
prof_win_focus = c_api_win_focus;
|
||||
prof_win_show = c_api_win_show;
|
||||
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_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;
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ c_plugin_create(const char *const filename)
|
||||
plugin->init_func = c_init_hook;
|
||||
plugin->on_start_func = c_on_start_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_disconnect_func = c_on_disconnect_hook;
|
||||
plugin->pre_chat_message_display = c_pre_chat_message_display_hook;
|
||||
@ -161,6 +162,20 @@ c_on_shutdown_hook(ProfPlugin *plugin)
|
||||
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
|
||||
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);
|
||||
|
||||
callbacks_remove(plugin->name);
|
||||
|
||||
if (dlclose (plugin->module)) {
|
||||
log_warning ("dlclose failed to close `%s' with `%s'", plugin->name, dlerror ());
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ void c_init_hook(ProfPlugin *plugin, const char *const version, const char *cons
|
||||
const char *const fulljid);
|
||||
void c_on_start_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_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);
|
||||
|
||||
|
@ -41,59 +41,227 @@
|
||||
#include "plugins/plugins.h"
|
||||
#include "tools/autocomplete.h"
|
||||
#include "tools/parser.h"
|
||||
#include "window_list.h"
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
static GSList *p_commands = NULL;
|
||||
static GSList *p_timed_functions = NULL;
|
||||
static GHashTable *p_commands = NULL;
|
||||
static GHashTable *p_timed_functions = NULL;
|
||||
static GHashTable *p_window_callbacks = NULL;
|
||||
|
||||
static void
|
||||
_free_window_callback(PluginWindowCallback *window_callback)
|
||||
{
|
||||
if (window_callback->destroy) {
|
||||
window_callback->destroy(window_callback->callback);
|
||||
if (window_callback->callback_destroy) {
|
||||
window_callback->callback_destroy(window_callback->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
|
||||
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
|
||||
callbacks_close(void)
|
||||
{
|
||||
g_hash_table_destroy(p_commands);
|
||||
g_hash_table_destroy(p_timed_functions);
|
||||
g_hash_table_destroy(p_window_callbacks);
|
||||
}
|
||||
|
||||
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_help(&command->command_name[1]);
|
||||
}
|
||||
|
||||
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
|
||||
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 *
|
||||
callbacks_get_window_handler(const char *tag)
|
||||
{
|
||||
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 {
|
||||
return NULL;
|
||||
}
|
||||
@ -104,25 +272,32 @@ plugins_run_command(const char * const input)
|
||||
{
|
||||
gchar **split = g_strsplit(input, " ", -1);
|
||||
|
||||
GSList *p_command = p_commands;
|
||||
while (p_command) {
|
||||
PluginCommand *command = p_command->data;
|
||||
if (g_strcmp0(split[0], command->command_name) == 0) {
|
||||
GList *command_hashes = g_hash_table_get_values(p_commands);
|
||||
GList *curr_hash = command_hashes;
|
||||
while (curr_hash) {
|
||||
GHashTable *command_hash = curr_hash->data;
|
||||
|
||||
PluginCommand *command = g_hash_table_lookup(command_hash, split[0]);
|
||||
if (command) {
|
||||
gboolean result;
|
||||
gchar **args = parse_args_with_freetext(input, command->min_args, command->max_args, &result);
|
||||
if (result == FALSE) {
|
||||
ui_invalid_command_usage(command->command_name, NULL);
|
||||
g_strfreev(split);
|
||||
g_list_free(command_hashes);
|
||||
return TRUE;
|
||||
} else {
|
||||
command->callback_func(command, args);
|
||||
command->callback_exec(command, args);
|
||||
g_strfreev(split);
|
||||
g_strfreev(args);
|
||||
g_list_free(command_hashes);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
p_command = g_slist_next(p_command);
|
||||
|
||||
curr_hash = g_list_next(curr_hash);
|
||||
}
|
||||
|
||||
g_strfreev(split);
|
||||
return FALSE;
|
||||
}
|
||||
@ -130,36 +305,50 @@ plugins_run_command(const char * const input)
|
||||
CommandHelp*
|
||||
plugins_get_help(const char *const cmd)
|
||||
{
|
||||
GSList *curr = p_commands;
|
||||
while (curr) {
|
||||
PluginCommand *command = curr->data;
|
||||
if (g_strcmp0(cmd, command->command_name) == 0) {
|
||||
GList *command_hashes = g_hash_table_get_values(p_commands);
|
||||
GList *curr_hash = command_hashes;
|
||||
while (curr_hash) {
|
||||
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;
|
||||
}
|
||||
|
||||
curr = g_slist_next(curr);
|
||||
curr_hash = g_list_next(curr_hash);
|
||||
}
|
||||
|
||||
g_list_free(command_hashes);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
plugins_run_timed(void)
|
||||
{
|
||||
GSList *p_timed_function = p_timed_functions;
|
||||
GList *timed_functions_lists = g_hash_table_get_values(p_timed_functions);
|
||||
|
||||
GList *curr_list = timed_functions_lists;
|
||||
while (curr_list) {
|
||||
GList *timed_function_list = curr_list->data;
|
||||
GList *curr = timed_function_list;
|
||||
while (curr) {
|
||||
PluginTimedFunction *timed_function = curr->data;
|
||||
|
||||
while (p_timed_function) {
|
||||
PluginTimedFunction *timed_function = p_timed_function->data;
|
||||
gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL);
|
||||
|
||||
if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) {
|
||||
timed_function->callback_func(timed_function);
|
||||
timed_function->callback_exec(timed_function);
|
||||
g_timer_start(timed_function->timer);
|
||||
}
|
||||
|
||||
p_timed_function = g_slist_next(p_timed_function);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
return;
|
||||
curr_list = g_list_next(curr_list);
|
||||
}
|
||||
|
||||
g_list_free(timed_functions_lists);
|
||||
}
|
||||
|
||||
GList*
|
||||
@ -167,12 +356,22 @@ plugins_get_command_names(void)
|
||||
{
|
||||
GList *result = NULL;
|
||||
|
||||
GSList *curr = p_commands;
|
||||
GList *command_hashes = g_hash_table_get_values(p_commands);
|
||||
GList *curr_hash = command_hashes;
|
||||
while (curr_hash) {
|
||||
GHashTable *command_hash = curr_hash->data;
|
||||
GList *commands = g_hash_table_get_keys(command_hash);
|
||||
GList *curr = commands;
|
||||
while (curr) {
|
||||
PluginCommand *command = curr->data;
|
||||
result = g_list_append(result, (char*)command->command_name);
|
||||
curr = g_slist_next(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;
|
||||
}
|
||||
|
@ -40,33 +40,38 @@
|
||||
#include "command/cmd_defs.h"
|
||||
|
||||
typedef struct p_command {
|
||||
const char *command_name;
|
||||
char *command_name;
|
||||
int min_args;
|
||||
int max_args;
|
||||
CommandHelp *help;
|
||||
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;
|
||||
|
||||
typedef struct p_timed_function {
|
||||
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;
|
||||
GTimer *timer;
|
||||
} PluginTimedFunction;
|
||||
|
||||
typedef struct p_window_input_callback {
|
||||
void *callback;
|
||||
void (*destroy)(void *callback);
|
||||
void (*callback_func)(struct p_window_input_callback *window_callback, const char *tag, const char * const line);
|
||||
void (*callback_exec)(struct p_window_input_callback *window_callback, const char *tag, const char * const line);
|
||||
void (*callback_destroy)(void *callback);
|
||||
} PluginWindowCallback;
|
||||
|
||||
void callbacks_init(void);
|
||||
void callbacks_remove(const char *const plugin_name);
|
||||
void callbacks_close(void);
|
||||
|
||||
void callbacks_add_command(PluginCommand *command);
|
||||
void callbacks_add_timed(PluginTimedFunction *timed_function);
|
||||
void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback);
|
||||
void callbacks_add_command(const char *const plugin_name, PluginCommand *command);
|
||||
void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function);
|
||||
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_remove_win(const char *const plugin_name, const char *const tag);
|
||||
|
||||
#endif
|
||||
|
@ -60,14 +60,18 @@
|
||||
|
||||
#include "ui/ui.h"
|
||||
|
||||
static GSList* plugins;
|
||||
static GHashTable *plugins;
|
||||
|
||||
static gchar* _get_plugins_dir(void);
|
||||
|
||||
void
|
||||
plugins_init(void)
|
||||
{
|
||||
plugins = NULL;
|
||||
plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
|
||||
callbacks_init();
|
||||
autocompleters_init();
|
||||
plugin_themes_init();
|
||||
plugin_settings_init();
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
python_env_init();
|
||||
@ -76,9 +80,6 @@ plugins_init(void)
|
||||
c_env_init();
|
||||
#endif
|
||||
|
||||
plugin_themes_init();
|
||||
plugin_settings_init();
|
||||
|
||||
// load plugins
|
||||
gchar **plugins_pref = prefs_get_plugins();
|
||||
if (plugins_pref) {
|
||||
@ -91,7 +92,7 @@ plugins_init(void)
|
||||
if (g_str_has_suffix(filename, ".py")) {
|
||||
ProfPlugin *plugin = python_plugin_create(filename);
|
||||
if (plugin) {
|
||||
plugins = g_slist_append(plugins, plugin);
|
||||
g_hash_table_insert(plugins, strdup(filename), plugin);
|
||||
loaded = TRUE;
|
||||
}
|
||||
}
|
||||
@ -100,7 +101,7 @@ plugins_init(void)
|
||||
if (g_str_has_suffix(filename, ".so")) {
|
||||
ProfPlugin *plugin = c_plugin_create(filename);
|
||||
if (plugin) {
|
||||
plugins = g_slist_append(plugins, plugin);
|
||||
g_hash_table_insert(plugins, strdup(filename), plugin);
|
||||
loaded = TRUE;
|
||||
}
|
||||
}
|
||||
@ -113,12 +114,15 @@ plugins_init(void)
|
||||
}
|
||||
|
||||
// initialise plugins
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
@ -127,24 +131,38 @@ plugins_init(void)
|
||||
}
|
||||
|
||||
gboolean
|
||||
_find_by_name(gconstpointer pluginp, gconstpointer namep)
|
||||
plugins_install(const char *const plugin_name, const char *const filename)
|
||||
{
|
||||
char *name = (char*)namep;
|
||||
ProfPlugin *plugin = (ProfPlugin*)pluginp;
|
||||
char *plugins_dir = _get_plugins_dir();
|
||||
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
|
||||
plugins_load(const char *const name)
|
||||
{
|
||||
GSList *found = g_slist_find_custom(plugins, name, (GCompareFunc)_find_by_name);
|
||||
if (found) {
|
||||
ProfPlugin *plugin = g_hash_table_lookup(plugins, name);
|
||||
if (plugin) {
|
||||
log_info("Failed to load plugin: %s, plugin already loaded", name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ProfPlugin *plugin = NULL;
|
||||
#ifdef HAVE_PYTHON
|
||||
if (g_str_has_suffix(name, ".py")) {
|
||||
plugin = python_plugin_create(name);
|
||||
@ -156,7 +174,7 @@ plugins_load(const char *const name)
|
||||
}
|
||||
#endif
|
||||
if (plugin) {
|
||||
plugins = g_slist_append(plugins, plugin);
|
||||
g_hash_table_insert(plugins, strdup(name), plugin);
|
||||
if (connection_get_status() == JABBER_CONNECTED) {
|
||||
const char *account_name = session_get_account_name();
|
||||
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);
|
||||
}
|
||||
log_info("Loaded plugin: %s", name);
|
||||
prefs_add_plugin(name);
|
||||
return TRUE;
|
||||
} else {
|
||||
log_info("Failed to load plugin: %s", name);
|
||||
@ -172,10 +191,58 @@ plugins_load(const char *const name)
|
||||
}
|
||||
}
|
||||
|
||||
GSList *
|
||||
plugins_get_list(void)
|
||||
gboolean
|
||||
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*
|
||||
@ -198,7 +265,7 @@ _plugins_unloaded_list_dir(const gchar *const dir, GSList **result)
|
||||
|
||||
const gchar *plugin = g_dir_read_name(plugins_dir);
|
||||
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) {
|
||||
*result = g_slist_append(*result, strdup(plugin));
|
||||
}
|
||||
@ -218,6 +285,12 @@ plugins_unloaded_list(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
GList*
|
||||
plugins_loaded_list(void)
|
||||
{
|
||||
return g_hash_table_get_keys(plugins);
|
||||
}
|
||||
|
||||
char *
|
||||
plugins_autocomplete(const char * const input)
|
||||
{
|
||||
@ -234,51 +307,67 @@ void
|
||||
plugins_win_process_line(char *win, const char * const line)
|
||||
{
|
||||
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
|
||||
plugins_on_start(void)
|
||||
{
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_start_func(plugin);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
void
|
||||
plugins_on_shutdown(void)
|
||||
{
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_shutdown_func(plugin);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_connect_func(plugin, account_name, fulljid);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_disconnect_func(plugin, account_name, fulljid);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
char*
|
||||
@ -287,7 +376,8 @@ plugins_pre_chat_message_display(const char * const jid, const char *message)
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_message;
|
||||
}
|
||||
@ -305,12 +396,14 @@ plugins_pre_chat_message_display(const char * const jid, const char *message)
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->post_chat_message_display(plugin, jid, message);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
char*
|
||||
@ -319,7 +412,8 @@ plugins_pre_chat_message_send(const char * const jid, const char *message)
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_message;
|
||||
}
|
||||
@ -337,12 +432,14 @@ plugins_pre_chat_message_send(const char * const jid, const char *message)
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->post_chat_message_send(plugin, jid, message);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
char*
|
||||
@ -351,7 +448,8 @@ plugins_pre_room_message_display(const char * const room, const char * const nic
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_message;
|
||||
}
|
||||
@ -369,12 +468,14 @@ plugins_pre_room_message_display(const char * const room, const char * const nic
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->post_room_message_display(plugin, room, nick, message);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
char*
|
||||
@ -383,7 +484,8 @@ plugins_pre_room_message_send(const char * const room, const char *message)
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_message;
|
||||
}
|
||||
@ -401,12 +504,14 @@ plugins_pre_room_message_send(const char * const room, const char *message)
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->post_room_message_send(plugin, room, message);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
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(×tamp_tv);
|
||||
}
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
}
|
||||
@ -437,7 +544,8 @@ plugins_pre_priv_message_display(const char * const jid, const char *message)
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
jid_destroy(jidp);
|
||||
return curr_message;
|
||||
@ -458,12 +567,14 @@ plugins_post_priv_message_display(const char * const jid, const char *message)
|
||||
{
|
||||
Jid *jidp = jid_create(jid);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
}
|
||||
@ -475,7 +586,8 @@ plugins_pre_priv_message_send(const char * const jid, const char * const message
|
||||
char *new_message = NULL;
|
||||
char *curr_message = strdup(message);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_message);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
jid_destroy(jidp);
|
||||
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);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
}
|
||||
@ -512,7 +627,8 @@ plugins_on_message_stanza_send(const char *const text)
|
||||
char *new_stanza = NULL;
|
||||
char *curr_stanza = strdup(text);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_stanza);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_stanza;
|
||||
}
|
||||
@ -532,15 +649,17 @@ plugins_on_message_stanza_receive(const char *const text)
|
||||
{
|
||||
gboolean cont = TRUE;
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
gboolean res = plugin->on_message_stanza_receive(plugin, text);
|
||||
if (res == FALSE) {
|
||||
cont = FALSE;
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return cont;
|
||||
}
|
||||
@ -551,7 +670,8 @@ plugins_on_presence_stanza_send(const char *const text)
|
||||
char *new_stanza = NULL;
|
||||
char *curr_stanza = strdup(text);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_stanza);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_stanza;
|
||||
}
|
||||
@ -571,15 +692,17 @@ plugins_on_presence_stanza_receive(const char *const text)
|
||||
{
|
||||
gboolean cont = TRUE;
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
gboolean res = plugin->on_presence_stanza_receive(plugin, text);
|
||||
if (res == FALSE) {
|
||||
cont = FALSE;
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return cont;
|
||||
}
|
||||
@ -590,7 +713,8 @@ plugins_on_iq_stanza_send(const char *const text)
|
||||
char *new_stanza = NULL;
|
||||
char *curr_stanza = strdup(text);
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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);
|
||||
free(new_stanza);
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return curr_stanza;
|
||||
}
|
||||
@ -610,15 +735,17 @@ plugins_on_iq_stanza_receive(const char *const text)
|
||||
{
|
||||
gboolean cont = TRUE;
|
||||
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
while (curr) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
gboolean res = plugin->on_iq_stanza_receive(plugin, text);
|
||||
if (res == FALSE) {
|
||||
cont = FALSE;
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
|
||||
return cont;
|
||||
}
|
||||
@ -626,45 +753,53 @@ plugins_on_iq_stanza_receive(const char *const text)
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_contact_offline(plugin, barejid, resource, status);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
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
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_chat_win_focus(plugin, barejid);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
void
|
||||
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) {
|
||||
ProfPlugin *plugin = curr->data;
|
||||
plugin->on_room_win_focus(plugin, roomjid);
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
}
|
||||
|
||||
GList*
|
||||
@ -676,7 +811,8 @@ plugins_get_disco_features(void)
|
||||
void
|
||||
plugins_shutdown(void)
|
||||
{
|
||||
GSList *curr = plugins;
|
||||
GList *values = g_hash_table_get_values(plugins);
|
||||
GList *curr = values;
|
||||
|
||||
while (curr) {
|
||||
#ifdef HAVE_PYTHON
|
||||
@ -690,8 +826,9 @@ plugins_shutdown(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
curr = g_slist_next(curr);
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
g_list_free(values);
|
||||
#ifdef HAVE_PYTHON
|
||||
python_shutdown();
|
||||
#endif
|
||||
|
@ -51,6 +51,7 @@ typedef struct prof_plugin_t {
|
||||
|
||||
void (*on_start_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_disconnect_func)(struct prof_plugin_t* plugin, const char *const account_name,
|
||||
@ -98,13 +99,17 @@ typedef struct prof_plugin_t {
|
||||
} ProfPlugin;
|
||||
|
||||
void plugins_init(void);
|
||||
GSList* plugins_get_list(void);
|
||||
GSList *plugins_unloaded_list(void);
|
||||
GList *plugins_loaded_list(void);
|
||||
char* plugins_autocomplete(const char *const input);
|
||||
void plugins_reset_autocomplete(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_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_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_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);
|
||||
gboolean plugins_on_message_stanza_receive(const char *const text);
|
||||
|
@ -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_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,
|
||||
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_remove)(const char *key, char **items) = NULL;
|
||||
void (*prof_completer_clear)(const char *key) = NULL;
|
||||
void (*_prof_completer_add)(const char *filename, 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 *filename, const char *key) = 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_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;
|
||||
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_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;
|
||||
|
@ -35,6 +35,13 @@
|
||||
#ifndef 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;
|
||||
|
||||
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_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,
|
||||
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_remove)(const char *key, char **items);
|
||||
void (*prof_completer_clear)(const char *key);
|
||||
void (*_prof_completer_add)(const char *filename, const char *key, char **items);
|
||||
void (*_prof_completer_remove)(const char *filename, const char *key, char **items);
|
||||
void (*_prof_completer_clear)(const char *filename, const char *key);
|
||||
|
||||
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_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);
|
||||
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_show)(PROF_WIN_TAG win, char *line);
|
||||
int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line);
|
||||
|
@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include <frameobject.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@ -41,6 +42,9 @@
|
||||
#include "plugins/python_plugins.h"
|
||||
#include "plugins/callbacks.h"
|
||||
#include "plugins/autocompleters.h"
|
||||
#include "log.h"
|
||||
|
||||
static char* _python_plugin_name(void);
|
||||
|
||||
static PyObject*
|
||||
python_api_cons_alert(PyObject *self, PyObject *args)
|
||||
@ -115,6 +119,9 @@ python_api_register_command(PyObject *self, PyObject *args)
|
||||
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)) {
|
||||
Py_ssize_t len = PyList_Size(synopsis);
|
||||
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;
|
||||
|
||||
allow_python_threads();
|
||||
api_register_command(command_name, min_args, max_args, c_synopsis,
|
||||
description, c_arguments, c_examples, p_callback, python_command_callback);
|
||||
api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis,
|
||||
description, c_arguments, c_examples, p_callback, python_command_callback, NULL);
|
||||
disable_python_threads();
|
||||
}
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -176,12 +185,17 @@ python_api_register_timed(PyObject *self, PyObject *args)
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
char *plugin_name = _python_plugin_name();
|
||||
log_debug("Register timed for %s", plugin_name);
|
||||
|
||||
if (p_callback && PyCallable_Check(p_callback)) {
|
||||
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();
|
||||
}
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -195,6 +209,9 @@ python_api_completer_add(PyObject *self, PyObject *args)
|
||||
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);
|
||||
char *c_items[len];
|
||||
|
||||
@ -207,9 +224,11 @@ python_api_completer_add(PyObject *self, PyObject *args)
|
||||
c_items[len] = NULL;
|
||||
|
||||
allow_python_threads();
|
||||
autocompleters_add(key, c_items);
|
||||
api_completer_add(plugin_name, key, c_items);
|
||||
disable_python_threads();
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -223,6 +242,9 @@ python_api_completer_remove(PyObject *self, PyObject *args)
|
||||
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);
|
||||
char *c_items[len];
|
||||
|
||||
@ -235,9 +257,11 @@ python_api_completer_remove(PyObject *self, PyObject *args)
|
||||
c_items[len] = NULL;
|
||||
|
||||
allow_python_threads();
|
||||
autocompleters_remove(key, c_items);
|
||||
api_completer_remove(plugin_name, key, c_items);
|
||||
disable_python_threads();
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -250,10 +274,15 @@ python_api_completer_clear(PyObject *self, PyObject *args)
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
char *plugin_name = _python_plugin_name();
|
||||
log_debug("Autocomplete clear %s for %s", key, plugin_name);
|
||||
|
||||
allow_python_threads();
|
||||
autocompleters_clear(key);
|
||||
api_completer_clear(plugin_name, key);
|
||||
disable_python_threads();
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -447,12 +476,17 @@ python_api_win_create(PyObject *self, PyObject *args)
|
||||
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)) {
|
||||
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();
|
||||
}
|
||||
|
||||
free(plugin_name);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -790,3 +824,16 @@ python_api_init(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "ui/ui.h"
|
||||
|
||||
static PyThreadState *thread_state;
|
||||
static GHashTable *loaded_modules;
|
||||
|
||||
void
|
||||
allow_python_threads()
|
||||
@ -56,9 +57,17 @@ disable_python_threads()
|
||||
PyEval_RestoreThread(thread_state);
|
||||
}
|
||||
|
||||
static void
|
||||
_unref_module(PyObject *module)
|
||||
{
|
||||
Py_XDECREF(module);
|
||||
}
|
||||
|
||||
void
|
||||
python_env_init(void)
|
||||
{
|
||||
loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_unref_module);
|
||||
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
python_api_init();
|
||||
@ -80,8 +89,17 @@ ProfPlugin*
|
||||
python_plugin_create(const char *const filename)
|
||||
{
|
||||
disable_python_threads();
|
||||
|
||||
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);
|
||||
PyObject *p_module = PyImport_ImportModule(module_name);
|
||||
p_module = PyImport_ImportModule(module_name);
|
||||
g_hash_table_insert(loaded_modules, strdup(filename), p_module);
|
||||
g_free(module_name);
|
||||
}
|
||||
|
||||
python_check_error();
|
||||
if (p_module) {
|
||||
ProfPlugin *plugin = malloc(sizeof(ProfPlugin));
|
||||
@ -91,6 +109,7 @@ python_plugin_create(const char *const filename)
|
||||
plugin->init_func = python_init_hook;
|
||||
plugin->on_start_func = python_on_start_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_disconnect_func = python_on_disconnect_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_chat_win_focus = python_on_chat_win_focus_hook;
|
||||
plugin->on_room_win_focus = python_on_room_win_focus_hook;
|
||||
g_free(module_name);
|
||||
|
||||
allow_python_threads();
|
||||
return plugin;
|
||||
} else {
|
||||
g_free(module_name);
|
||||
allow_python_threads();
|
||||
return NULL;
|
||||
}
|
||||
@ -186,6 +203,25 @@ python_on_shutdown_hook(ProfPlugin *plugin)
|
||||
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
|
||||
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)
|
||||
{
|
||||
disable_python_threads();
|
||||
callbacks_remove(plugin->name);
|
||||
free(plugin->name);
|
||||
Py_XDECREF(plugin->module);
|
||||
free(plugin);
|
||||
allow_python_threads();
|
||||
}
|
||||
@ -899,5 +935,6 @@ void
|
||||
python_shutdown(void)
|
||||
{
|
||||
disable_python_threads();
|
||||
g_hash_table_destroy(loaded_modules);
|
||||
Py_Finalize();
|
||||
}
|
||||
|
@ -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);
|
||||
void python_on_start_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_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid);
|
||||
|
||||
|
@ -61,7 +61,6 @@ plugin_themes_init(void)
|
||||
g_chmod(fileloc->str, S_IRUSR | S_IWUSR);
|
||||
g_free(g_data);
|
||||
g_string_free(fileloc, TRUE);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -391,7 +391,6 @@ _shutdown(void)
|
||||
plugins_on_shutdown();
|
||||
muc_close();
|
||||
caps_close();
|
||||
ui_close();
|
||||
#ifdef HAVE_LIBOTR
|
||||
otr_shutdown();
|
||||
#endif
|
||||
@ -402,10 +401,11 @@ _shutdown(void)
|
||||
theme_close();
|
||||
accounts_close();
|
||||
tlscerts_close();
|
||||
cmd_uninit();
|
||||
log_stderr_close();
|
||||
log_close();
|
||||
plugins_shutdown();
|
||||
cmd_uninit();
|
||||
ui_close();
|
||||
prefs_close();
|
||||
if (saved_status) {
|
||||
free(saved_status);
|
||||
|
@ -117,6 +117,15 @@ autocomplete_add(Autocomplete ac, const char *item)
|
||||
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
|
||||
autocomplete_remove(Autocomplete ac, const char *const item)
|
||||
{
|
||||
@ -139,6 +148,15 @@ autocomplete_remove(Autocomplete ac, const char *const item)
|
||||
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*
|
||||
autocomplete_create_list(Autocomplete ac)
|
||||
{
|
||||
|
@ -50,7 +50,9 @@ void autocomplete_clear(Autocomplete ac);
|
||||
void autocomplete_free(Autocomplete ac);
|
||||
|
||||
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_all(Autocomplete ac, char **items);
|
||||
|
||||
// find the next item prefixed with search string
|
||||
gchar* autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote);
|
||||
|
@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char
|
||||
}
|
||||
|
||||
void
|
||||
ui_show_lines(ProfWin *window, const gchar** lines)
|
||||
ui_show_lines(ProfWin *window, gchar** lines)
|
||||
{
|
||||
if (lines) {
|
||||
int i;
|
||||
|
@ -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_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_show_lines(ProfWin *window, const gchar** lines);
|
||||
void ui_show_lines(ProfWin *window, gchar** lines);
|
||||
void ui_redraw_all_room_rosters(void);
|
||||
void ui_show_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_config(const char *const title, DataForm *form);
|
||||
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_free(ProfWin *window);
|
||||
gboolean win_notify_remind(ProfWin *window);
|
||||
|
@ -190,6 +190,7 @@ typedef struct prof_xml_win_t {
|
||||
typedef struct prof_plugin_win_t {
|
||||
ProfWin super;
|
||||
char *tag;
|
||||
char *plugin_name;
|
||||
unsigned long memcheck;
|
||||
} ProfPluginWin;
|
||||
|
||||
|
@ -238,13 +238,14 @@ win_create_xmlconsole(void)
|
||||
}
|
||||
|
||||
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));
|
||||
new_win->super.type = WIN_PLUGIN;
|
||||
new_win->super.layout = _win_create_simple_layout();
|
||||
|
||||
new_win->tag = strdup(tag);
|
||||
new_win->plugin_name = strdup(plugin_name);
|
||||
|
||||
new_win->memcheck = PROFPLUGINWIN_MEMCHECK;
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
#include "window_list.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
|
||||
#include "config/preferences.h"
|
||||
|
||||
static GHashTable *windows;
|
||||
static int current;
|
||||
@ -226,6 +226,22 @@ wins_get_plugin(const char *const tag)
|
||||
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*
|
||||
wins_get_private_chats(const char *const roomjid)
|
||||
{
|
||||
@ -564,6 +580,7 @@ wins_close_by_num(int i)
|
||||
case WIN_PLUGIN:
|
||||
{
|
||||
ProfPluginWin *pluginwin = (ProfPluginWin*)window;
|
||||
plugins_close_win(pluginwin->plugin_name, pluginwin->tag);
|
||||
autocomplete_remove(wins_ac, pluginwin->tag);
|
||||
autocomplete_remove(wins_close_ac, pluginwin->tag);
|
||||
break;
|
||||
@ -665,12 +682,12 @@ wins_new_private(const char *const fulljid)
|
||||
}
|
||||
|
||||
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);
|
||||
int result = get_next_available_win_num(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);
|
||||
autocomplete_add(wins_ac, tag);
|
||||
autocomplete_add(wins_close_ac, tag);
|
||||
|
@ -44,7 +44,7 @@ ProfWin* wins_new_chat(const char *const barejid);
|
||||
ProfWin* wins_new_muc(const char *const roomjid);
|
||||
ProfWin* wins_new_muc_config(const char *const roomjid, DataForm *form);
|
||||
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);
|
||||
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);
|
||||
ProfXMLWin* wins_get_xmlconsole(void);
|
||||
|
||||
void wins_close_plugin(char *tag);
|
||||
|
||||
ProfWin* wins_get_current(void);
|
||||
|
||||
void wins_set_current_by_num(int i);
|
||||
|
57
tests/unittests/test_callbacks.c
Normal file
57
tests/unittests/test_callbacks.c
Normal 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);
|
||||
}
|
2
tests/unittests/test_callbacks.h
Normal file
2
tests/unittests/test_callbacks.h
Normal file
@ -0,0 +1,2 @@
|
||||
void returns_no_commands(void **state);
|
||||
void returns_commands(void **state);
|
@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {}
|
||||
void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {}
|
||||
void mucconfwin_form_help(ProfMucConfWin *confwin) {}
|
||||
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_show_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;
|
||||
}
|
||||
ProfWin* win_create_plugin(const char * const tag)
|
||||
ProfWin* win_create_plugin(const char *const plugin_name, const char * const tag)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "test_cmd_roster.h"
|
||||
#include "test_cmd_disconnect.h"
|
||||
#include "test_form.h"
|
||||
#include "test_callbacks.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const UnitTest all_tests[] = {
|
||||
@ -602,6 +603,9 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
unit_test(prof_partial_occurrences_tests),
|
||||
unit_test(prof_whole_occurrences_tests),
|
||||
|
||||
unit_test(returns_no_commands),
|
||||
unit_test(returns_commands),
|
||||
};
|
||||
|
||||
return run_tests(all_tests);
|
||||
|
Loading…
Reference in New Issue
Block a user