aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitlbee.h1
-rwxr-xr-xconfigure2
-rw-r--r--doc/user-guide/commands.xml12
-rw-r--r--otr.c16
-rw-r--r--protocols/nogaim.c81
-rw-r--r--protocols/nogaim.h16
-rw-r--r--protocols/purple/purple.c9
-rw-r--r--protocols/skype/skype.c14
-rw-r--r--protocols/twitter/twitter.c3
-rw-r--r--root_commands.c86
10 files changed, 235 insertions, 5 deletions
diff --git a/bitlbee.h b/bitlbee.h
index 14ca68d2..cbc44af1 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -41,6 +41,7 @@ extern "C" {
#define VERSION BITLBEE_VERSION
#define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 2)
+#define BITLBEE_ABI_VERSION_CODE 1
#define MAX_STRING 511
diff --git a/configure b/configure
index 48ba506e..1bd7fef3 100755
--- a/configure
+++ b/configure
@@ -57,6 +57,8 @@ ldap=0
pie=1
+arch=$(uname -s)
+
GLIB_MIN_VERSION=2.16
# Cygwin and Darwin don't support PIC/PIE
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index 6f66a39d..56beba54 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -1834,6 +1834,18 @@
</description>
</bitlbee-command>
+ <bitlbee-command name="plugins">
+ <short-description>List all the external plugins and protocols</short-description>
+ <syntax>plugins</syntax>
+
+ <description>
+ <para>
+ This gives you a list of all the external plugins and protocols.
+ </para>
+ </description>
+
+ </bitlbee-command>
+
<bitlbee-command name="qlist">
<short-description>List all the unanswered questions root asked</short-description>
<syntax>qlist</syntax>
diff --git a/otr.c b/otr.c
index 4888691a..0328f478 100644
--- a/otr.c
+++ b/otr.c
@@ -267,6 +267,22 @@ void init_plugin(void)
register_irc_plugin(&otr_plugin);
}
+#ifndef OTR_BI
+struct plugin_info *init_plugin_info(void)
+{
+ static struct plugin_info info = {
+ BITLBEE_ABI_VERSION_CODE,
+ "otr",
+ BITLBEE_VERSION,
+ "Off-the-Record communication",
+ NULL,
+ NULL
+ };
+
+ return &info;
+}
+#endif
+
gboolean otr_irc_new(irc_t *irc)
{
set_t *s;
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index c9cbb033..ab11508b 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -39,24 +39,84 @@
GSList *connections;
#ifdef WITH_PLUGINS
+GList *plugins = NULL;
+
+static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data)
+{
+ const struct plugin_info *ia = a;
+ const struct plugin_info *ib = b;
+
+ return g_strcasecmp(ia->name, ib->name);
+}
+
gboolean load_plugin(char *path)
{
+ GList *l;
+ struct plugin_info *i;
+ struct plugin_info *info;
+ struct plugin_info * (*info_function) (void) = NULL;
void (*init_function) (void);
GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
+ gboolean loaded = FALSE;
if (!mod) {
log_message(LOGLVL_ERROR, "Error loading plugin `%s': %s\n", path, g_module_error());
return FALSE;
}
+ if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) {
+ info = info_function();
+
+ if (info->abiver != BITLBEE_ABI_VERSION_CODE) {
+ log_message(LOGLVL_ERROR,
+ "`%s' uses ABI %u but %u is required\n",
+ path, info->abiver,
+ BITLBEE_ABI_VERSION_CODE);
+ g_module_close(mod);
+ return FALSE;
+ }
+
+ if (!info->name || !info->version) {
+ log_message(LOGLVL_ERROR,
+ "Name or version missing from the "
+ "plugin info in `%s'\n", path);
+ g_module_close(mod);
+ return FALSE;
+ }
+
+ for (l = plugins; l; l = l->next) {
+ i = l->data;
+
+ if (g_strcasecmp(i->name, info->name) == 0) {
+ loaded = TRUE;
+ break;
+ }
+ }
+
+ if (loaded) {
+ log_message(LOGLVL_WARNING,
+ "%s plugin already loaded\n",
+ info->name);
+ g_module_close(mod);
+ return FALSE;
+ }
+ } else {
+ log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path);
+ }
+
if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) {
log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
+ g_module_close(mod);
return FALSE;
}
- init_function();
+ if (info_function) {
+ plugins = g_list_insert_sorted_with_data(plugins, info,
+ pluginscmp, NULL);
+ }
+ init_function();
return TRUE;
}
@@ -72,6 +132,10 @@ void load_plugins(void)
char *path;
while ((entry = g_dir_read_name(dir))) {
+ if (!g_str_has_suffix(entry, "." G_MODULE_SUFFIX)) {
+ continue;
+ }
+
path = g_build_filename(global.conf->plugindir, entry, NULL);
if (!path) {
log_message(LOGLVL_WARNING, "Can't build path for %s\n", entry);
@@ -86,6 +150,11 @@ void load_plugins(void)
g_dir_close(dir);
}
}
+
+GList *get_plugins()
+{
+ return plugins;
+}
#endif
GList *protocols = NULL;
@@ -164,6 +233,16 @@ void nogaim_init()
#endif
}
+GList *get_protocols()
+{
+ return protocols;
+}
+
+GList *get_protocols_disabled()
+{
+ return disabled_protocols;
+}
+
GSList *get_connections()
{
return connections;
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 40b1ed7b..e5569313 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -270,8 +270,24 @@ struct prpl {
void *resv5;
};
+struct plugin_info
+{
+ guint abiver;
+ const char *name;
+ const char *version;
+ const char *description;
+ const char *author;
+ const char *url;
+};
+
+#ifdef WITH_PLUGINS
+G_MODULE_EXPORT GList *get_plugins();
+#endif
+
/* im_api core stuff. */
void nogaim_init();
+G_MODULE_EXPORT GList *get_protocols();
+G_MODULE_EXPORT GList *get_protocols_disabled();
G_MODULE_EXPORT GSList *get_connections();
G_MODULE_EXPORT struct prpl *find_protocol(const char *name);
G_MODULE_EXPORT gboolean is_protocol_disabled(const char *name);
diff --git a/protocols/purple/purple.c b/protocols/purple/purple.c
index 2b3a09a3..589cc093 100644
--- a/protocols/purple/purple.c
+++ b/protocols/purple/purple.c
@@ -978,10 +978,11 @@ void prplcb_conv_del_users(PurpleConversation *conv, GList *cbuddies)
}
/* Generic handler for IM or chat messages, covers write_chat, write_im and write_conv */
-static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message, guint32 bee_flags, time_t mtime)
+static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message_, guint32 bee_flags, time_t mtime)
{
struct im_connection *ic = purple_ic_by_pa(conv->account);
struct groupchat *gc = conv->ui_data;
+ char *message = g_strdup(message_);
PurpleBuddy *buddy;
buddy = purple_find_buddy(conv->account, who);
@@ -990,10 +991,12 @@ static void handle_conv_msg(PurpleConversation *conv, const char *who, const cha
}
if (conv->type == PURPLE_CONV_TYPE_IM) {
- imcb_buddy_msg(ic, (char *) who, (char *) message, bee_flags, mtime);
+ imcb_buddy_msg(ic, who, message, bee_flags, mtime);
} else if (gc) {
- imcb_chat_msg(gc, who, (char *) message, bee_flags, mtime);
+ imcb_chat_msg(gc, who, message, bee_flags, mtime);
}
+
+ g_free(message);
}
/* Handles write_im and write_chat. Removes echoes of locally sent messages */
diff --git a/protocols/skype/skype.c b/protocols/skype/skype.c
index a21af8ef..bd8a1850 100644
--- a/protocols/skype/skype.c
+++ b/protocols/skype/skype.c
@@ -1762,3 +1762,17 @@ void init_plugin(void)
#endif
register_protocol(ret);
}
+
+struct plugin_info *init_plugin_info(void)
+{
+ static struct plugin_info info = {
+ BITLBEE_ABI_VERSION_CODE,
+ "skype",
+ BITLBEE_VERSION,
+ "Skype protocol plugin",
+ NULL,
+ NULL
+ };
+
+ return &info;
+}
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index 5694c1b6..5f6156a6 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -985,7 +985,8 @@ static void twitter_handle_command(struct im_connection *ic, char *message)
goto eof;
} else if ((g_strcasecmp(cmd[0], "favourite") == 0 ||
g_strcasecmp(cmd[0], "favorite") == 0 ||
- g_strcasecmp(cmd[0], "fav") == 0) && cmd[1]) {
+ g_strcasecmp(cmd[0], "fav") == 0 ||
+ g_strcasecmp(cmd[0], "like") == 0) && cmd[1]) {
if ((id = twitter_message_id_from_command_arg(ic, cmd[1], NULL))) {
twitter_favourite_tweet(ic, id);
} else {
diff --git a/root_commands.c b/root_commands.c
index 702a068d..add9bceb 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -1123,6 +1123,91 @@ static void cmd_blist(irc_t *irc, char **cmd)
}
}
+static gint prplcmp(gconstpointer a, gconstpointer b)
+{
+ const struct prpl *pa = a;
+ const struct prpl *pb = b;
+
+ return g_strcasecmp(pa->name, pb->name);
+}
+
+static void prplstr(GList *prpls, GString *gstr)
+{
+ const char *last = NULL;
+ GList *l;
+ struct prpl *p;
+
+ prpls = g_list_copy(prpls);
+ prpls = g_list_sort(prpls, prplcmp);
+
+ for (l = prpls; l; l = l->next) {
+ p = l->data;
+
+ if (last && g_strcasecmp(p->name, last) == 0) {
+ /* Ignore duplicates (mainly for libpurple) */
+ continue;
+ }
+
+ if (gstr->len != 0) {
+ g_string_append(gstr, ", ");
+ }
+
+ g_string_append(gstr, p->name);
+ last = p->name;
+ }
+
+ g_list_free(prpls);
+}
+
+static void cmd_plugins(irc_t *irc, char **cmd)
+{
+ GList *prpls;
+ GString *gstr;
+
+#ifdef WITH_PLUGINS
+ GList *l;
+ struct plugin_info *info;
+
+ for (l = get_plugins(); l; l = l->next) {
+ info = l->data;
+ irc_rootmsg(irc, "%s:", info->name);
+ irc_rootmsg(irc, " Version: %s", info->version);
+
+ if (info->description) {
+ irc_rootmsg(irc, " Description: %s", info->description);
+ }
+
+ if (info->author) {
+ irc_rootmsg(irc, " Author: %s", info->author);
+ }
+
+ if (info->url) {
+ irc_rootmsg(irc, " URL: %s", info->url);
+ }
+
+ irc_rootmsg(irc, "");
+ }
+#endif
+
+ gstr = g_string_new(NULL);
+ prpls = get_protocols();
+
+ if (prpls) {
+ prplstr(prpls, gstr);
+ irc_rootmsg(irc, "Enabled Protocols: %s", gstr->str);
+ g_string_truncate(gstr, 0);
+ }
+
+ prpls = get_protocols_disabled();
+
+ if (prpls) {
+ prplstr(prpls, gstr);
+ irc_rootmsg(irc, "Disabled Protocols: %s", gstr->str);
+ }
+
+ g_string_free(gstr, TRUE);
+}
+
static void cmd_qlist(irc_t *irc, char **cmd)
{
query_t *q = irc->queries;
@@ -1381,6 +1466,7 @@ command_t root_commands[] = {
{ "info", 1, cmd_info, 0 },
{ "nick", 1, cmd_nick, 0 },
{ "no", 0, cmd_yesno, 0 },
+ { "plugins", 0, cmd_plugins, 0 },
{ "qlist", 0, cmd_qlist, 0 },
{ "register", 0, cmd_register, 0 },
{ "remove", 1, cmd_remove, 0 },