Mercurial > pidgin.yaz
diff libpurple/protocols/jabber/jabber.c @ 30959:8648453adb22
propagate from branch 'im.pidgin.pidgin' (head 96b27a20c7250b87761a8bd4f5540bf1fa32b6f4)
to branch 'im.pidgin.cpw.malu.xmpp.google_relay' (head 303f4072d75faa7770a5339dbfea05da7cee30a4)
author | Marcus Lundblad <ml@update.uu.se> |
---|---|
date | Tue, 09 Mar 2010 21:41:41 +0000 |
parents | ee3226c6092f d93676b59db1 |
children | f01d73b4452e |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/jabber.c Thu Feb 18 22:42:19 2010 +0000 +++ b/libpurple/protocols/jabber/jabber.c Tue Mar 09 21:41:41 2010 +0000 @@ -62,6 +62,7 @@ #include "roster.h" #include "ping.h" #include "si.h" +#include "usermood.h" #include "xdata.h" #include "pep.h" #include "adhoccommands.h" @@ -69,9 +70,14 @@ #include "jingle/jingle.h" #include "jingle/rtp.h" +#define PING_TIMEOUT 60 + GList *jabber_features = NULL; GList *jabber_identities = NULL; -static GSList *jabber_cmds = NULL; + +static GHashTable *jabber_cmds = NULL; /* PurplePlugin * => GSList of ids */ + +static gint plugin_ref = 0; static void jabber_unregister_account_cb(JabberStream *js); static void try_srv_connect(JabberStream *js); @@ -520,9 +526,12 @@ void jabber_keepalive(PurpleConnection *gc) { - JabberStream *js = gc->proto_data; - - if (js->keepalive_timeout == 0) { + JabberStream *js = purple_connection_get_protocol_data(gc); + time_t now = time(NULL); + + if (js->keepalive_timeout == 0 && (now - js->last_ping) >= PING_TIMEOUT) { + js->last_ping = now; + jabber_keepalive_ping(js); js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_keepalive_timeout), gc); @@ -2080,18 +2089,31 @@ if (full) { PurpleStatus *status; - status = purple_presence_get_active_status(presence); - mood = purple_status_get_attr_string(status, "mood"); - if(mood != NULL) { + status = purple_presence_get_status(presence, "mood"); + mood = purple_status_get_attr_string(status, PURPLE_MOOD_NAME); + if(mood && *mood) { const char *moodtext; - moodtext = purple_status_get_attr_string(status, "moodtext"); - if(moodtext != NULL) { - char *moodplustext = g_strdup_printf("%s (%s)", mood, moodtext); + /* find the mood */ + PurpleMood *moods = jabber_get_moods(account); + const char *description = NULL; + + for (; moods->mood ; moods++) { + if (purple_strequal(moods->mood, mood)) { + description = moods->description; + break; + } + } + + moodtext = purple_status_get_attr_string(status, PURPLE_MOOD_COMMENT); + if(moodtext && *moodtext) { + char *moodplustext = + g_strdup_printf("%s (%s)", description ? _(description) : mood, moodtext); purple_notify_user_info_add_pair(user_info, _("Mood"), moodplustext); g_free(moodplustext); } else - purple_notify_user_info_add_pair(user_info, _("Mood"), mood); + purple_notify_user_info_add_pair(user_info, _("Mood"), + description ? _(description) : mood); } if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_TUNE)) { PurpleStatus *tune = purple_presence_get_status(presence, "tune"); @@ -2152,7 +2174,15 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); + + + type = purple_status_type_new_with_attrs(PURPLE_STATUS_MOOD, + "mood", NULL, TRUE, TRUE, TRUE, + PURPLE_MOOD_NAME, _("Mood Name"), purple_value_new(PURPLE_TYPE_STRING), + PURPLE_MOOD_COMMENT, _("Mood Comment"), purple_value_new(PURPLE_TYPE_STRING), + NULL); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 1); @@ -2168,7 +2198,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2184,7 +2214,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2200,7 +2230,7 @@ "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), "buzz", _("Allow Buzz"), buzz_enabled, NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); priority_value = purple_value_new(PURPLE_TYPE_INT); purple_value_set_int(priority_value, 0); @@ -2213,11 +2243,11 @@ "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); /* if(js->protocol_version == JABBER_PROTO_0_9) - m = g_list_append(m, _("Invisible")); + "Invisible" */ type = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE, @@ -2225,7 +2255,7 @@ NULL, TRUE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); + types = g_list_prepend(types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_TUNE, "tune", NULL, FALSE, TRUE, TRUE, @@ -2239,9 +2269,9 @@ PURPLE_TUNE_YEAR, _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), PURPLE_TUNE_URL, _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), NULL); - types = g_list_append(types, type); - - return types; + types = g_list_prepend(types, type); + + return g_list_reverse(types); } static void @@ -2948,7 +2978,16 @@ gchar *error = NULL; if (!_jabber_send_buzz(js, username, &error)) { + PurpleAccount *account = purple_connection_get_account(gc); + PurpleConversation *conv = + purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, username, account); purple_debug_error("jabber", "jabber_send_attention: jabber_cmd_buzz failed with error: %s\n", error ? error : "(NULL)"); + + if (conv) { + purple_conversation_write(conv, username, error, PURPLE_MESSAGE_ERROR, + time(NULL)); + } + g_free(error); return FALSE; } @@ -3301,40 +3340,67 @@ } } -void jabber_register_commands(void) +static PurpleCmdRet +jabber_cmd_mood(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) { + JabberStream *js = conv->account->gc->proto_data; + + if (js->pep) { + /* if no argument was given, unset mood */ + if (!args | !args[0]) { + jabber_mood_set(js, NULL, NULL); + } else if (!args[1]) { + jabber_mood_set(js, args[0], NULL); + } else { + jabber_mood_set(js, args[0], args[1]); + } + + return PURPLE_CMD_RET_OK; + } else { + /* account does not support PEP, can't set a mood */ + purple_conversation_write(conv, NULL, + _("Account does not support PEP, can't set mood"), + PURPLE_MESSAGE_ERROR, time(NULL)); + return PURPLE_CMD_RET_FAILED; + } +} + +static void jabber_register_commands(PurplePlugin *plugin) +{ + GSList *commands = NULL; PurpleCmdId id; id = purple_cmd_register("config", "", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, "prpl-jabber", jabber_cmd_chat_config, _("config: Configure a chat room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("configure", "", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, "prpl-jabber", jabber_cmd_chat_config, _("configure: Configure a chat room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("nick", "s", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, "prpl-jabber", jabber_cmd_chat_nick, _("nick <new nickname>: Change your nickname."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("part", "s", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", jabber_cmd_chat_part, _("part [message]: Leave the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("register", "", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, "prpl-jabber", jabber_cmd_chat_register, _("register: Register with a chat room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); /* XXX: there needs to be a core /topic cmd, methinks */ id = purple_cmd_register("topic", "s", PURPLE_CMD_P_PRPL, @@ -3343,7 +3409,7 @@ jabber_cmd_chat_topic, _("topic [new topic]: View or change the topic."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("ban", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3351,7 +3417,7 @@ jabber_cmd_chat_ban, _("ban <user> [reason]: Ban a user from the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("affiliate", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3359,7 +3425,7 @@ jabber_cmd_chat_affiliate, _("affiliate <owner|admin|member|outcast|none> [nick1] [nick2] ...: Get the users with an affiliation or set users' affiliation with the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("role", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3367,7 +3433,7 @@ jabber_cmd_chat_role, _("role <moderator|participant|visitor|none> [nick1] [nick2] ...: Get the users with a role or set users' role with the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("invite", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3375,7 +3441,7 @@ jabber_cmd_chat_invite, _("invite <user> [message]: Invite a user to the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("join", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3383,7 +3449,7 @@ jabber_cmd_chat_join, _("join: <room> [password]: Join a chat on this server."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("kick", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | @@ -3391,14 +3457,14 @@ jabber_cmd_chat_kick, _("kick <user> [reason]: Kick a user from the room."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("msg", "ws", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, "prpl-jabber", jabber_cmd_chat_msg, _("msg <user> <message>: Send a private message to another user."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("ping", "w", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | @@ -3406,24 +3472,39 @@ "prpl-jabber", jabber_cmd_ping, _("ping <jid>: Ping a user/component/server."), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); id = purple_cmd_register("buzz", "w", PURPLE_CMD_P_PRPL, PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", jabber_cmd_buzz, _("buzz: Buzz a user to get their attention"), NULL); - jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id)); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); + + id = purple_cmd_register("mood", "ws", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | + PURPLE_CMD_FLAG_PRPL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, + "prpl-jabber", jabber_cmd_mood, + _("mood: Set current user mood"), NULL); + commands = g_slist_prepend(commands, GUINT_TO_POINTER(id)); + + g_hash_table_insert(jabber_cmds, plugin, commands); } -void jabber_unregister_commands(void) +static void cmds_free_func(gpointer value) { - while (jabber_cmds != NULL) { - purple_cmd_unregister(GPOINTER_TO_UINT(jabber_cmds->data)); - jabber_cmds = g_slist_delete_link(jabber_cmds, jabber_cmds); + GSList *commands = value; + while (commands) { + purple_cmd_unregister(GPOINTER_TO_UINT(commands->data)); + commands = g_slist_delete_link(commands, commands); } } +static void jabber_unregister_commands(PurplePlugin *plugin) +{ + g_hash_table_remove(jabber_cmds, plugin); +} + /* IPC functions */ /** @@ -3472,8 +3553,8 @@ jabber_caps_broadcast_change(); } -void -jabber_init_plugin(PurplePlugin *plugin) +static void +jabber_do_init(void) { GHashTable *ui_info = purple_core_get_ui_info(); const gchar *ui_type; @@ -3481,6 +3562,8 @@ unspecified */ const gchar *ui_name = NULL; + jabber_cmds = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, cmds_free_func); + ui_type = ui_info ? g_hash_table_lookup(ui_info, "client_type") : NULL; if (ui_type) { if (strcmp(ui_type, "pc") == 0 || @@ -3543,7 +3626,52 @@ G_CALLBACK(jabber_caps_broadcast_change), NULL); #endif + /* reverse order of unload_plugin */ + jabber_iq_init(); + jabber_caps_init(); + /* PEP things should be init via jabber_pep_init, not here */ + jabber_pep_init(); + jabber_data_init(); + jabber_bosh_init(); + + /* TODO: Implement adding and retrieving own features via IPC API */ + + jabber_ibb_init(); + jabber_si_init(); + jabber_auth_init(); +} + +static void +jabber_do_uninit(void) +{ + /* reverse order of jabber_do_init */ + jabber_bosh_uninit(); + jabber_data_uninit(); + jabber_si_uninit(); + jabber_ibb_uninit(); + /* PEP things should be uninit via jabber_pep_uninit, not here */ + jabber_pep_uninit(); + jabber_caps_uninit(); + jabber_presence_uninit(); + jabber_iq_uninit(); + + jabber_auth_uninit(); + jabber_features_destroy(); + jabber_identities_destroy(); + + g_hash_table_destroy(jabber_cmds); + jabber_cmds = NULL; +} + +void jabber_plugin_init(PurplePlugin *plugin) +{ + ++plugin_ref; + + if (plugin_ref == 1) + jabber_do_init(); + + jabber_register_commands(plugin); /* IPC functions */ purple_plugin_ipc_register(plugin, "contact_has_feature", PURPLE_CALLBACK(jabber_ipc_contact_has_feature), @@ -3558,7 +3686,6 @@ NULL, 1, purple_value_new(PURPLE_TYPE_STRING)); - /* Modifying these? Look at libxmpp.c:load_plugin for the signal versions */ purple_plugin_ipc_register(plugin, "register_namespace_watcher", PURPLE_CALLBACK(jabber_iq_signal_register), purple_marshal_VOID__POINTER_POINTER, @@ -3572,14 +3699,95 @@ NULL, 2, purple_value_new(PURPLE_TYPE_STRING), /* node */ purple_value_new(PURPLE_TYPE_STRING)); /* namespace */ + + purple_signal_register(plugin, "jabber-register-namespace-watcher", + purple_marshal_VOID__POINTER_POINTER, + NULL, 2, + purple_value_new(PURPLE_TYPE_STRING), /* node */ + purple_value_new(PURPLE_TYPE_STRING)); /* namespace */ + + purple_signal_register(plugin, "jabber-unregister-namespace-watcher", + purple_marshal_VOID__POINTER_POINTER, + NULL, 2, + purple_value_new(PURPLE_TYPE_STRING), /* node */ + purple_value_new(PURPLE_TYPE_STRING)); /* namespace */ + + purple_signal_connect(plugin, "jabber-register-namespace-watcher", + plugin, PURPLE_CALLBACK(jabber_iq_signal_register), NULL); + purple_signal_connect(plugin, "jabber-unregister-namespace-watcher", + plugin, PURPLE_CALLBACK(jabber_iq_signal_unregister), NULL); + + + purple_signal_register(plugin, "jabber-receiving-xmlnode", + purple_marshal_VOID__POINTER_POINTER, NULL, 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new_outgoing(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); + + purple_signal_register(plugin, "jabber-sending-xmlnode", + purple_marshal_VOID__POINTER_POINTER, NULL, 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new_outgoing(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); + + /* + * Do not remove this or the plugin will fail. Completely. You have been + * warned! + */ + purple_signal_connect_priority(plugin, "jabber-sending-xmlnode", + plugin, PURPLE_CALLBACK(jabber_send_signal_cb), + NULL, PURPLE_SIGNAL_PRIORITY_HIGHEST); + + purple_signal_register(plugin, "jabber-sending-text", + purple_marshal_VOID__POINTER_POINTER, NULL, 2, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new_outgoing(PURPLE_TYPE_STRING)); + + purple_signal_register(plugin, "jabber-receiving-message", + purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER_POINTER, + purple_value_new(PURPLE_TYPE_BOOLEAN), 6, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new(PURPLE_TYPE_STRING), /* type */ + purple_value_new(PURPLE_TYPE_STRING), /* id */ + purple_value_new(PURPLE_TYPE_STRING), /* from */ + purple_value_new(PURPLE_TYPE_STRING), /* to */ + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); + + purple_signal_register(plugin, "jabber-receiving-iq", + purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER, + purple_value_new(PURPLE_TYPE_BOOLEAN), 5, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new(PURPLE_TYPE_STRING), /* type */ + purple_value_new(PURPLE_TYPE_STRING), /* id */ + purple_value_new(PURPLE_TYPE_STRING), /* from */ + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); + + purple_signal_register(plugin, "jabber-watched-iq", + purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER, + purple_value_new(PURPLE_TYPE_BOOLEAN), 5, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new(PURPLE_TYPE_STRING), /* type */ + purple_value_new(PURPLE_TYPE_STRING), /* id */ + purple_value_new(PURPLE_TYPE_STRING), /* from */ + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); /* child */ + + purple_signal_register(plugin, "jabber-receiving-presence", + purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER, + purple_value_new(PURPLE_TYPE_BOOLEAN), 4, + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION), + purple_value_new(PURPLE_TYPE_STRING), /* type */ + purple_value_new(PURPLE_TYPE_STRING), /* from */ + purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); } -void -jabber_uninit_plugin(PurplePlugin *plugin) +void jabber_plugin_uninit(PurplePlugin *plugin) { + g_return_if_fail(plugin_ref > 0); + + purple_signals_unregister_by_instance(plugin); purple_plugin_ipc_unregister_all(plugin); - jabber_auth_uninit(); - jabber_features_destroy(); - jabber_identities_destroy(); + jabber_unregister_commands(plugin); + + --plugin_ref; + if (plugin_ref == 0) + jabber_do_uninit(); }