libpurple/protocols/jabber/jabber.c

changeset 29853
c6ba9ac6a496
parent 29837
a35bc78641a6
parent 29849
d7b910200dc5
child 29864
76caf53857f5
child 30768
70a66a8a7a1f
--- a/libpurple/protocols/jabber/jabber.c	Wed Mar 10 05:10:43 2010 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Wed Mar 10 05:12:35 2010 +0000
@@ -74,7 +74,10 @@
 
 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);
@@ -867,7 +870,8 @@
 	js->old_length = 0;
 	js->keepalive_timeout = 0;
 	/* Set the default protocol version to 1.0. Overridden in parser.c. */
-	js->protocol_version = JABBER_PROTO_1_0;
+	js->protocol_version.major = 1;
+	js->protocol_version.minor = 0;
 	js->sessions = NULL;
 	js->stun_ip = NULL;
 	js->stun_port = 0;
@@ -3330,6 +3334,8 @@
 		} 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,
@@ -3337,44 +3343,43 @@
 		    PURPLE_MESSAGE_ERROR, time(NULL));
 		return PURPLE_CMD_RET_FAILED;
 	}
-
-	return PURPLE_CMD_STATUS_OK;
 }
 
-void jabber_register_commands(void)
+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,
@@ -3383,7 +3388,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 |
@@ -3391,7 +3396,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 |
@@ -3399,7 +3404,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 |
@@ -3407,7 +3412,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 |
@@ -3415,7 +3420,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 |
@@ -3423,7 +3428,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 |
@@ -3431,14 +3436,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 |
@@ -3446,31 +3451,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);
-	jabber_cmds = g_slist_prepend(jabber_cmds, GUINT_TO_POINTER(id));
+	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 */
 
 /**
@@ -3519,14 +3532,46 @@
 	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;
 	const gchar *type = "pc"; /* default client type, if unknown or
 								unspecified */
 	const gchar *ui_name = NULL;
+#ifdef HAVE_CYRUS_SASL
+	/* We really really only want to do this once per process */
+	static gboolean sasl_initialized = FALSE;
+#ifdef _WIN32
+	UINT old_error_mode;
+	gchar *sasldir;
+#endif
+	int ret;
+#endif
+
+	/* XXX - If any other plugin wants SASL this won't be good ... */
+#ifdef HAVE_CYRUS_SASL
+	if (!sasl_initialized) {
+		sasl_initialized = TRUE;
+#ifdef _WIN32
+		sasldir = g_build_filename(wpurple_install_dir(), "sasl2", NULL);
+		sasl_set_path(SASL_PATH_TYPE_PLUGIN, sasldir);
+		g_free(sasldir);
+		/* Suppress error popups for failing to load sasl plugins */
+		old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+#endif
+		if ((ret = sasl_client_init(NULL)) != SASL_OK) {
+			purple_debug_error("xmpp", "Error (%d) initializing SASL.\n", ret);
+		}
+#ifdef _WIN32
+		/* Restore the original error mode */
+		SetErrorMode(old_error_mode);
+#endif
+	}
+#endif
+
+	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) {
@@ -3590,7 +3635,53 @@
 			G_CALLBACK(jabber_caps_broadcast_change), NULL);
 #endif
 
+	/* reverse order of unload_plugin */
+	jabber_iq_init();
+	jabber_presence_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),
@@ -3605,7 +3696,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,
@@ -3619,14 +3709,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();
 }

mercurial