summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will.thompson@collabora.co.uk>2011-03-17 16:29:27 +0000
committerWill Thompson <will.thompson@collabora.co.uk>2011-03-17 16:36:50 +0000
commit27252c32885bcc057654dcbc3191812b745238a2 (patch)
tree98bc4793b672de14d6b43affcd2b50a5a725f857
parentd3354fd9c095a2c7c1f381e62a4d7b8481fd9edc (diff)
parentc0638dd2dfc88c5d8404618fe359f5a1185d13d0 (diff)
Merge branch 'examples'
Reviewed-by: Jonny Lamb <jonny.lamb@collabora.co.uk> Fixes: <https://bugs.freedesktop.org/show_bug.cgi?id=34308>
-rw-r--r--.gitignore3
-rw-r--r--examples/Makefile.am13
-rw-r--r--examples/connect.c432
-rw-r--r--examples/receive-messages.c197
-rw-r--r--examples/send-message.c138
-rw-r--r--tests/wocky-porter-test.c167
-rw-r--r--wocky/wocky-c2s-porter.c5
-rw-r--r--wocky/wocky-connector.c4
-rw-r--r--wocky/wocky-sasl-auth.c19
-rw-r--r--wocky/wocky-stanza.c15
10 files changed, 536 insertions, 457 deletions
diff --git a/.gitignore b/.gitignore
index e5fe18f..b2d059f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,8 +106,9 @@ tests/tardis
# tests/certs/cas/*
# tests/certs/crl/*
-examples/wocky-connect
examples/wocky-register
+examples/wocky-receive-messages
+examples/wocky-send-message
examples/wocky-unregister
coverage/
diff --git a/examples/Makefile.am b/examples/Makefile.am
index a771a61..5546f40 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,13 +1,17 @@
EXAMPLES =
-EXAMPLES += wocky-connect
+EXAMPLES += wocky-send-message
+EXAMPLES += wocky-receive-messages
EXAMPLES += wocky-register
EXAMPLES += wocky-unregister
INCLUDES := -I$(top_builddir)/wocky
-wocky_connect_SOURCES = connect.c
-wocky_connect_DEPENDENCIES = $(top_builddir)/wocky/libwocky.la
+wocky_send_message_SOURCES = send-message.c
+wocky_send_message_DEPENDENCIES = $(top_builddir)/wocky/libwocky.la
+
+wocky_receive_messages_SOURCES = receive-messages.c
+wocky_receive_messages_DEPENDENCIES = $(top_builddir)/wocky/libwocky.la
wocky_register_SOURCES = register.c
wocky_register_DEPENDENCIES = $(top_builddir)/wocky/libwocky.la
@@ -25,7 +29,8 @@ AM_CFLAGS = \
$(ERROR_CFLAGS) \
@GLIB_CFLAGS@
-check_c_sources = $(wocky_connect_SOURCES) \
+check_c_sources = $(wocky_send_message_SOURCES) \
+ $(wocky_receive_messages_SOURCES) \
$(wocky_register_SOURCES) \
$(wocky_unregister_SOURCES)
diff --git a/examples/connect.c b/examples/connect.c
deleted file mode 100644
index b74ed20..0000000
--- a/examples/connect.c
+++ /dev/null
@@ -1,432 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <string.h>
-
-#include <glib.h>
-
-#include <gio/gio.h>
-#include <wocky/wocky-connector.h>
-#include <wocky/wocky-xmpp-connection.h>
-#include <wocky/wocky-namespaces.h>
-#include <wocky/wocky-sasl-auth.h>
-#include <wocky/wocky.h>
-
-GMainLoop *mainloop;
-WockyXmppConnection *conn;
-const gchar *server;
-const gchar *username;
-const gchar *password;
-WockySaslAuth *sasl = NULL;
-GSocketConnection *tcp;
-
-GSocketClient *client;
-WockyTLSConnection *ssl;
-WockyTLSSession *ssl_session;
-
-static void
-post_auth_open_sent_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- if (!wocky_xmpp_connection_send_open_finish (conn, result, NULL))
- {
- printf ("Sending open failed\n");
- g_main_loop_quit (mainloop);
- }
-}
-
-static void
-auth_done_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- GError *error = NULL;
-
- if (!wocky_sasl_auth_authenticate_finish (WOCKY_SASL_AUTH (source),
- result, &error))
- {
- printf ("Authentication failed: %s\n", error->message);
- g_error_free (error);
- g_main_loop_quit (mainloop);
- return;
- }
-
- printf ("Authentication successfull!!\n");
-
- /* Reopen the connection */
- wocky_xmpp_connection_reset (conn);
- wocky_xmpp_connection_send_open_async (conn,
- server, NULL, "1.0", NULL, NULL,
- NULL, post_auth_open_sent_cb, NULL);
-}
-
-static void
-ssl_features_received_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- WockyStanza *stanza;
- WockyNode *node;
-
- stanza = wocky_xmpp_connection_recv_stanza_finish (conn, result, NULL);
-
- g_assert (stanza != NULL);
-
- node = wocky_stanza_get_top_node (stanza);
-
- if (strcmp (node->name, "features")
- || strcmp (wocky_node_get_ns (node), WOCKY_XMPP_NS_STREAM))
- {
- printf ("Didn't receive features stanza\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- sasl = wocky_sasl_auth_new (server, username, password, conn, NULL);
-
- wocky_sasl_auth_authenticate_async (sasl, stanza, TRUE, FALSE, NULL,
- auth_done_cb, NULL);
-}
-
-
-static void
-ssl_received_open_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- gchar *version;
- gchar *from;
- gchar *sid;
-
- if (!wocky_xmpp_connection_recv_open_finish (conn, result,
- NULL, &from, &version, NULL, &sid, NULL))
- {
- printf ("Didn't receive open\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- printf ("Stream opened -- from: %s version: %s\n", from, version);
- printf (" Session ID: %s\n", sid);
-
- if (version == NULL || strcmp (version, "1.0"))
- {
- printf ("Server is not xmpp compliant\n");
- g_main_loop_quit (mainloop);
- }
-
- /* waiting for features */
- wocky_xmpp_connection_recv_stanza_async (conn,
- NULL, ssl_features_received_cb, NULL);
-
- g_free (version);
- g_free (from);
- g_free (sid);
-}
-
-static void
-ssl_open_sent_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- if (!wocky_xmpp_connection_send_open_finish (conn, result, NULL))
- {
- printf ("Sending open failed\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- wocky_xmpp_connection_recv_open_async (conn, NULL,
- ssl_received_open_cb, NULL);
-}
-
-static void
-tcp_start_tls_recv_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- WockyStanza *stanza;
- WockyNode *node;
- GError *error = NULL;
-
- stanza = wocky_xmpp_connection_recv_stanza_finish (conn, result, NULL);
-
- g_assert (stanza != NULL);
-
- node = wocky_stanza_get_top_node (stanza);
-
- if (strcmp (node->name, "proceed")
- || strcmp (wocky_node_get_ns (node), WOCKY_XMPP_NS_TLS))
- {
- printf ("Server doesn't want to start tls");
- g_main_loop_quit (mainloop);
- return;
- }
-
- g_object_unref (conn);
-
- ssl_session = wocky_tls_session_new (G_IO_STREAM (tcp));
- ssl = wocky_tls_session_handshake (ssl_session, NULL, &error);
-
- if (ssl == NULL)
- g_error ("connect: %s: %d, %s", g_quark_to_string (error->domain),
- error->code, error->message);
-
- conn = wocky_xmpp_connection_new (G_IO_STREAM (ssl));
- wocky_xmpp_connection_send_open_async (conn,
- server, NULL, "1.0", NULL, NULL,
- NULL, ssl_open_sent_cb, NULL);
-}
-
-static void
-tcp_start_tls_send_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- g_assert (wocky_xmpp_connection_send_stanza_finish (conn, result, NULL));
-
- wocky_xmpp_connection_recv_stanza_async (conn,
- NULL, tcp_start_tls_recv_cb, NULL);
-}
-
-static void
-tcp_features_received_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- WockyStanza *stanza;
- WockyNode *tls, *node;
- WockyStanza *starttls;
-
- stanza = wocky_xmpp_connection_recv_stanza_finish (conn, result, NULL);
-
- g_assert (stanza != NULL);
-
- node = wocky_stanza_get_top_node (stanza);
-
- if (strcmp (node->name, "features")
- || strcmp (wocky_node_get_ns (node), WOCKY_XMPP_NS_STREAM))
- {
- printf ("Didn't receive features stanza\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- tls = wocky_node_get_child_ns (node, "starttls",
- WOCKY_XMPP_NS_TLS);
-
- if (tls == NULL)
- {
- printf ("Server doesn't support tls\n");
- g_main_loop_quit (mainloop);
- }
-
- starttls = wocky_stanza_new ("starttls", WOCKY_XMPP_NS_TLS);
-
- wocky_xmpp_connection_send_stanza_async (conn, starttls,
- NULL, tcp_start_tls_send_cb, NULL);
-
- g_object_unref (stanza);
- g_object_unref (starttls);
-}
-
-static void
-tcp_received_open_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- gchar *version;
- gchar *from;
- gchar *sid;
-
- if (!wocky_xmpp_connection_recv_open_finish (conn, result,
- NULL, &from, &version, NULL, &sid, NULL))
- {
- printf ("Didn't receive open\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- printf ("Stream opened -- from: %s version: %s\n", from, version);
- printf (" Session ID: %s\n", sid);
-
- if (version == NULL || strcmp (version, "1.0"))
- {
- printf ("Server is not xmpp compliant\n");
- g_main_loop_quit (mainloop);
- }
-
- /* waiting for features */
- wocky_xmpp_connection_recv_stanza_async (conn,
- NULL, tcp_features_received_cb, NULL);
-
- g_free (version);
- g_free (from);
- g_free (sid);
-}
-
-static void
-tcp_sent_open_cb (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- if (!wocky_xmpp_connection_send_open_finish (conn, result, NULL))
- {
- printf ("Sending open failed\n");
- g_main_loop_quit (mainloop);
- return;
- }
-
- wocky_xmpp_connection_recv_open_async (conn, NULL,
- tcp_received_open_cb, NULL);
-}
-
-static void
-tcp_do_connect (void)
-{
- g_assert (tcp != NULL);
-
- printf ("TCP connection established\n");
-
- conn = wocky_xmpp_connection_new (G_IO_STREAM (tcp));
-
- wocky_xmpp_connection_send_open_async (conn,
- server, NULL, "1.0", NULL, NULL,
- NULL, tcp_sent_open_cb, NULL);
-}
-
-static void
-tcp_host_connected (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- GError *error = NULL;
-
- tcp = g_socket_client_connect_to_host_finish (G_SOCKET_CLIENT (source),
- result, &error);
-
- if (tcp == NULL)
- {
- g_message ("HOST connect failed: %s: %d, %s\n",
- g_quark_to_string (error->domain),
- error->code, error->message);
-
- g_error_free (error);
- g_main_loop_quit (mainloop);
- }
- else
- {
- tcp_do_connect ();
- }
-}
-
-static void
-tcp_srv_connected (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- GError *error = NULL;
-
- tcp = g_socket_client_connect_to_service_finish (G_SOCKET_CLIENT (source),
- result, &error);
-
- if (tcp == NULL)
- {
- g_message ("SRV connect failed: %s: %d, %s",
- g_quark_to_string (error->domain),
- error->code, error->message);
-
- g_message ("Falling back to direct connection");
- g_error_free (error);
- g_socket_client_connect_to_host_async (client, server, 5222, NULL,
- tcp_host_connected, NULL);
- }
- else
- {
- tcp_do_connect ();
- }
-}
-
-static void
-connector_callback (GObject *source, GAsyncResult *res, gpointer user_data)
-{
- GError *error = NULL;
- gchar *jid = NULL;
- gchar *sid = NULL;
- WockyConnector *wcon = WOCKY_CONNECTOR (source);
- WockyXmppConnection *connection =
- wocky_connector_connect_finish (wcon, res, &jid, &sid, &error);
-
- if (connection != NULL)
- {
- printf ("connected (%s) [%s]!\n", jid, sid);
- g_free (sid);
- g_free (jid);
- }
- else
- {
- if (error)
- g_warning ("%s: %d: %s\n",
- g_quark_to_string (error->domain), error->code, error->message);
- g_main_loop_quit (mainloop);
- }
-}
-
-int
-main (int argc,
- char **argv)
-{
- gchar *jid;
- char *c;
- const char *type = "raw";
-
- g_type_init ();
- wocky_init ();
-
- if ((argc < 3) || (argc > 4))
- {
- printf ("Usage: %s <jid> <password> [connection-type]\n", argv[0]);
- printf (" connection-type is 'raw' or 'connector' (default raw)\n");
- return -1;
- }
-
- if (argc == 4)
- type = argv[3];
-
- mainloop = g_main_loop_new (NULL, FALSE);
-
- if (!strcmp ("connector",type))
- {
- WockyConnector *wcon = NULL;
- wcon = wocky_connector_new (argv[1], argv[2], NULL, NULL, NULL);
-
- wocky_connector_connect_async (wcon, NULL, connector_callback, NULL);
- g_main_loop_run (mainloop);
-
- return 0;
- }
-
- jid = g_strdup (argv[1]);
- password = argv[2];
- c = rindex (jid, '@');
- if (c == NULL)
- {
- printf ("JID should contain an @ sign\n");
- return -1;
- }
- *c = '\0';
- server = c + 1;
- username = jid;
-
- client = g_socket_client_new ();
-
- printf ("Connecting to %s\n", server);
-
- g_socket_client_connect_to_service_async (client, server,
- "xmpp-client", NULL, tcp_srv_connected, NULL);
-
- g_main_loop_run (mainloop);
- g_free (jid);
- return 0;
-}
diff --git a/examples/receive-messages.c b/examples/receive-messages.c
new file mode 100644
index 0000000..1f8a072
--- /dev/null
+++ b/examples/receive-messages.c
@@ -0,0 +1,197 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include <glib.h>
+
+#include <gio/gio.h>
+#include <wocky/wocky-connector.h>
+#include <wocky/wocky-xmpp-connection.h>
+#include <wocky/wocky.h>
+#include <wocky/wocky-porter.h>
+#include <wocky/wocky-session.h>
+
+GMainLoop *mainloop;
+
+static void
+porter_closed_cb (
+ GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WockyPorter *porter = WOCKY_PORTER (source);
+ WockySession *session = WOCKY_SESSION (user_data);
+ GError *error = NULL;
+
+ if (wocky_porter_close_finish (porter, res, &error))
+ {
+ g_print ("Signed out\n");
+ }
+ else
+ {
+ g_warning ("Couldn't sign out cleanly: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Either way, we're done. */
+ g_object_unref (session);
+ g_main_loop_quit (mainloop);
+}
+
+static gboolean
+message_received_cb (WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ WockyNode *body_node = wocky_node_get_child (
+ wocky_stanza_get_top_node (stanza),
+ "body");
+ const gchar *from = wocky_stanza_get_from (stanza);
+ const gchar *message;
+
+ /* We told the porter only to give us messages which contained a <body/>
+ * element.
+ */
+ g_assert (body_node != NULL);
+ message = body_node->content;
+
+ if (message == NULL)
+ message = "";
+
+ g_print ("Message received from %s: “%s”\n", from, message);
+
+ if (g_ascii_strcasecmp (message, "sign out") == 0)
+ {
+ WockyStanza *reply = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NORMAL, NULL, from,
+ '(', "body",
+ '$', "Say please! Didn’t your parents teach you any manners‽",
+ ')', NULL);
+
+ wocky_porter_send (porter, reply);
+ g_object_unref (reply);
+ }
+
+ /* Tell the porter that we've handled this stanza; if there were any
+ * lower-priority handlers, they would not be called for this stanza.
+ */
+ return TRUE;
+}
+
+static gboolean
+sign_out_message_received_cb (WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ WockySession *session = WOCKY_SESSION (user_data);
+ const gchar *from = wocky_stanza_get_from (stanza);
+
+ g_print ("%s asked us nicely to sign out\n", from);
+ wocky_porter_close_async (porter, NULL, porter_closed_cb, session);
+
+ /* Returning FALSE tells the porter that other, lower-priority handlers that
+ * match the stanza should be invoked — in this example, that means
+ * message_received_cb().
+ */
+ return FALSE;
+}
+
+static void
+connected_cb (
+ GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WockyConnector *connector = WOCKY_CONNECTOR (source);
+ WockyXmppConnection *connection;
+ gchar *jid = NULL;
+ GError *error = NULL;
+
+ connection = wocky_connector_connect_finish (connector, res, &jid, NULL,
+ &error);
+
+ if (connection == NULL)
+ {
+ g_warning ("Couldn't connect: %s", error->message);
+ g_clear_error (&error);
+ g_main_loop_quit (mainloop);
+ }
+ else
+ {
+ WockySession *session = wocky_session_new (connection, jid);
+ WockyPorter *porter = wocky_session_get_porter (session);
+ WockyStanza *stanza;
+
+ g_print ("Connected as %s\n", jid);
+
+ /* Register a callback for incoming <message type='chat'/> stanzas from
+ * anyone, but only if it contains a <body/> element (the element that
+ * actually contains the text of IMs). */
+ wocky_porter_register_handler_from_anyone (porter,
+ WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_CHAT,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
+ message_received_cb, session,
+ '(', "body", ')', NULL);
+
+ /* Register a higher-priority handler for incoming <message type='chat'/>
+ * stanzas which contain a <body/> element containing the text
+ * "please sign out".
+ */
+ wocky_porter_register_handler_from_anyone (porter,
+ WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_CHAT,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
+ sign_out_message_received_cb, session,
+ '(', "body",
+ '$', "please sign out",
+ ')', NULL);
+
+ wocky_porter_start (porter);
+
+ /* Broadcast presence for ourself, so our contacts can see us online,
+ * with a status message. */
+ stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_PRESENCE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL,
+ '(', "show",
+ '$', "chat",
+ ')',
+ '(', "status",
+ '$', "talk to me! (or tell me to “sign out”)",
+ ')', NULL);
+
+ wocky_porter_send (porter, stanza);
+
+ g_object_unref (stanza);
+ g_free (jid);
+ }
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ char *jid, *password;
+ WockyConnector *connector;
+
+ g_type_init ();
+ wocky_init ();
+
+ if (argc != 3)
+ {
+ printf ("Usage: %s <jid> <password>\n", argv[0]);
+ return -1;
+ }
+
+ jid = argv[1];
+ password = argv[2];
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+ connector = wocky_connector_new (jid, password, NULL, NULL, NULL);
+ wocky_connector_connect_async (connector, NULL, connected_cb, NULL);
+
+ g_main_loop_run (mainloop);
+
+ g_object_unref (connector);
+ g_main_loop_unref (mainloop);
+ return 0;
+}
diff --git a/examples/send-message.c b/examples/send-message.c
new file mode 100644
index 0000000..de1c234
--- /dev/null
+++ b/examples/send-message.c
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include <glib.h>
+
+#include <gio/gio.h>
+#include <wocky/wocky-connector.h>
+#include <wocky/wocky-xmpp-connection.h>
+#include <wocky/wocky.h>
+#include <wocky/wocky-porter.h>
+#include <wocky/wocky-session.h>
+
+GMainLoop *mainloop;
+char *recipient;
+char *message;
+
+static void
+closed_cb (
+ GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WockyPorter *porter = WOCKY_PORTER (source);
+ WockySession *session = WOCKY_SESSION (user_data);
+ GError *error = NULL;
+
+ if (wocky_porter_close_finish (porter, res, &error))
+ {
+ g_print ("Signed out\n");
+ }
+ else
+ {
+ g_warning ("Couldn't sign out cleanly: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Either way, we're done. */
+ g_object_unref (session);
+ g_main_loop_quit (mainloop);
+}
+
+static void
+message_sent_cb (
+ GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WockyPorter *porter = WOCKY_PORTER (source);
+ WockySession *session = WOCKY_SESSION (user_data);
+ GError *error = NULL;
+
+ if (wocky_porter_send_finish (porter, res, &error))
+ {
+ g_print ("Sent '%s' to %s\n", message, recipient);
+ }
+ else
+ {
+ g_warning ("Couldn't send message: %s\n", error->message);
+ g_clear_error (&error);
+ }
+
+ /* Sign out. */
+ wocky_porter_close_async (porter, NULL, closed_cb, session);
+}
+
+static void
+connected_cb (
+ GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WockyConnector *connector = WOCKY_CONNECTOR (source);
+ WockyXmppConnection *connection;
+ gchar *jid = NULL;
+ GError *error = NULL;
+
+ connection = wocky_connector_connect_finish (connector, res, &jid, NULL,
+ &error);
+
+ if (connection == NULL)
+ {
+ g_warning ("Couldn't connect: %s", error->message);
+ g_clear_error (&error);
+ g_main_loop_quit (mainloop);
+ }
+ else
+ {
+ WockySession *session = wocky_session_new (connection, jid);
+ WockyPorter *porter = wocky_session_get_porter (session);
+ WockyStanza *stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, recipient,
+ '(', "body",
+ '$', message,
+ ')', NULL);
+
+ g_print ("Connected as %s\n", jid);
+
+ wocky_porter_start (porter);
+ wocky_porter_send_async (porter, stanza, NULL, message_sent_cb, session);
+
+ g_object_unref (stanza);
+ g_free (jid);
+ }
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ char *jid, *password;
+ WockyConnector *connector;
+
+ g_type_init ();
+ wocky_init ();
+
+ if (argc != 5)
+ {
+ printf ("Usage: %s <jid> <password> <recipient> <message>\n", argv[0]);
+ return -1;
+ }
+
+ jid = argv[1];
+ password = argv[2];
+ recipient = argv[3];
+ message = argv[4];
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+ connector = wocky_connector_new (jid, password, NULL, NULL, NULL);
+ wocky_connector_connect_async (connector, NULL, connected_cb, NULL);
+
+ g_main_loop_run (mainloop);
+
+ g_object_unref (connector);
+ g_main_loop_unref (mainloop);
+ return 0;
+}
diff --git a/tests/wocky-porter-test.c b/tests/wocky-porter-test.c
index 47fc41c..9c6111a 100644
--- a/tests/wocky-porter-test.c
+++ b/tests/wocky-porter-test.c
@@ -3119,6 +3119,169 @@ handler_from_anyone (void)
teardown_test (test);
}
+static void
+closed_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WockyPorter *porter = WOCKY_PORTER (source);
+ test_data_t *test = user_data;
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = wocky_porter_close_finish (porter, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ test->outstanding--;
+ g_main_loop_quit (test->loop);
+}
+
+static void
+sent_stanza_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WockyPorter *porter = WOCKY_PORTER (source);
+ test_data_t *test = user_data;
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = wocky_porter_send_finish (porter, result, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* Close up both porters. There's no reason why either of these operations
+ * should fail.
+ */
+ wocky_porter_close_async (test->sched_out, NULL, closed_cb, test);
+ wocky_porter_close_async (test->sched_in, NULL, closed_cb, test);
+}
+
+static void
+close_from_send_callback (void)
+{
+ test_data_t *test = setup_test ();
+ WockyStanza *stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL,
+ '(', "body", '$', "I am made of chalk.", ')', NULL);
+
+ /* Fire up porters in both directions. */
+ test_open_both_connections (test);
+ wocky_porter_start (test->sched_in);
+ wocky_porter_start (test->sched_out);
+
+ /* Send a stanza. Once it's been safely sent, we should be able to close up
+ * the connection in both directions without any trouble.
+ */
+ wocky_porter_send_async (test->sched_in, stanza, NULL, sent_stanza_cb, test);
+ g_object_unref (stanza);
+
+ /* The two outstanding events are both porters ultimately closing
+ * successfully. */
+ test->outstanding += 2;
+ test_wait_pending (test);
+
+ teardown_test (test);
+}
+
+/* Callbacks used in send_from_send_callback() */
+static gboolean
+message_received_cb (
+ WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ test_data_t *test = user_data;
+
+ test_expected_stanza_received (test, stanza);
+ return TRUE;
+}
+
+static void
+sent_second_or_third_stanza_cb (
+ GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ test_data_t *test = user_data;
+ GError *error = NULL;
+
+ wocky_porter_send_finish (WOCKY_PORTER (source), result, &error);
+ g_assert_no_error (error);
+
+ test->outstanding--;
+ g_main_loop_quit (test->loop);
+}
+
+static void
+sent_first_stanza_cb (
+ GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ test_data_t *test = user_data;
+ WockyStanza *third_stanza;
+ GError *error = NULL;
+
+ wocky_porter_send_finish (WOCKY_PORTER (source), result, &error);
+ g_assert_no_error (error);
+
+ third_stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL,
+ '(', "body", '$', "I am made of dur butter.", ')', NULL);
+ wocky_porter_send_async (test->sched_in, third_stanza, NULL,
+ sent_second_or_third_stanza_cb, test);
+ g_queue_push_tail (test->expected_stanzas, third_stanza);
+ /* One for the callback; one for the receiving end. */
+ test->outstanding += 2;
+
+ test->outstanding--;
+ g_main_loop_quit (test->loop);
+}
+
+static void
+send_from_send_callback (void)
+{
+ test_data_t *test = setup_test ();
+ WockyStanza *stanza;
+
+ test_open_both_connections (test);
+ wocky_porter_start (test->sched_in);
+ wocky_porter_start (test->sched_out);
+
+ wocky_porter_register_handler_from_anyone (test->sched_out,
+ WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, message_received_cb, test,
+ '(', "body", ')', NULL);
+
+ /* Send a stanza; in the callback for this stanza, we'll send another stanza.
+ */
+ stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL,
+ '(', "body", '$', "I am made of chalk.", ')', NULL);
+ wocky_porter_send_async (test->sched_in, stanza, NULL,
+ sent_first_stanza_cb, test);
+ g_queue_push_tail (test->expected_stanzas, stanza);
+ /* One for the callback; one for the receiving end. */
+ test->outstanding += 2;
+
+ /* But before we've had a chance to send that one, send a second. */
+ stanza = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL,
+ '(', "body", '$', "I am made of jelly.", ')', NULL);
+ wocky_porter_send_async (test->sched_in, stanza, NULL,
+ sent_second_or_third_stanza_cb, test);
+ g_queue_push_tail (test->expected_stanzas, stanza);
+ /* One for the callback; one for the receiving end. */
+ test->outstanding += 2;
+
+ test_wait_pending (test);
+
+ test_close_both_porters (test);
+ teardown_test (test);
+}
+
int
main (int argc, char **argv)
{
@@ -3177,6 +3340,10 @@ main (int argc, char **argv)
g_test_add_func ("/xmpp-porter/send-and-disconnect", send_and_disconnect);
g_test_add_func ("/xmpp-porter/handler-for-domain", handler_for_domain);
g_test_add_func ("/xmpp-porter/handler-from-anyone", handler_from_anyone);
+ g_test_add_func ("/xmpp-porter/close-from-send-callback",
+ close_from_send_callback);
+ g_test_add_func ("/xmpp-porter/send-from-send-callback",
+ send_from_send_callback);
result = g_test_run ();
test_deinit ();
diff --git a/wocky/wocky-c2s-porter.c b/wocky/wocky-c2s-porter.c
index a537565..8c94427 100644
--- a/wocky/wocky-c2s-porter.c
+++ b/wocky/wocky-c2s-porter.c
@@ -82,6 +82,7 @@ struct _WockyC2SPorterPrivate
GCancellable *receive_cancellable;
GSimpleAsyncResult *close_result;
+ gboolean waiting_to_close;
gboolean remote_closed;
gboolean local_closed;
GCancellable *close_cancellable;
@@ -669,7 +670,7 @@ send_stanza_cb (GObject *source,
}
}
- if (priv->close_result != NULL &&
+ if (priv->waiting_to_close &&
g_queue_get_length (priv->sending_queue) == 0)
{
/* Queue is empty and we are waiting to close the connection. */
@@ -1362,6 +1363,7 @@ send_close (WockyC2SPorter *self)
wocky_xmpp_connection_send_close_async (priv->connection,
NULL, close_sent_cb, self);
+ priv->waiting_to_close = FALSE;
}
static void
@@ -1422,6 +1424,7 @@ wocky_c2s_porter_close_async (WockyPorter *porter,
{
DEBUG ("Sending queue is not empty. Flushing it before "
"closing the connection.");
+ priv->waiting_to_close = TRUE;
return;
}
diff --git a/wocky/wocky-connector.c b/wocky/wocky-connector.c
index 5d20330..d5f9417 100644
--- a/wocky/wocky-connector.c
+++ b/wocky/wocky-connector.c
@@ -301,7 +301,6 @@ struct _WockyConnectorPrivate
static char *
state_message (WockyConnectorPrivate *priv, const char *str)
{
- GString *msg = g_string_new ("");
const char *state = NULL;
if (priv->authed)
@@ -318,8 +317,7 @@ state_message (WockyConnectorPrivate *priv, const char *str)
else
state = "Connecting... ";
- g_string_printf (msg, "%s: %s", state, str);
- return g_string_free (msg, FALSE);
+ return g_strdup_printf ("%s: %s", state, str);
}
static void
diff --git a/wocky/wocky-sasl-auth.c b/wocky/wocky-sasl-auth.c
index 1c70b91..d6afcc5 100644
--- a/wocky/wocky-sasl-auth.c
+++ b/wocky/wocky-sasl-auth.c
@@ -332,27 +332,20 @@ wocky_sasl_auth_new (const gchar *server,
NULL);
}
-static gboolean
-each_mechanism (WockyNode *node, gpointer user_data)
-{
- GSList **list = (GSList **)user_data;
- if (wocky_strdiff (node->name, "mechanism"))
- {
- return TRUE;
- }
- *list = g_slist_append (*list, g_strdup (node->content));
- return TRUE;
-}
-
static GSList *
wocky_sasl_auth_mechanisms_to_list (WockyNode *mechanisms)
{
GSList *result = NULL;
+ WockyNode *mechanism;
+ WockyNodeIter iter;
if (mechanisms == NULL)
return NULL;
- wocky_node_each_child (mechanisms, each_mechanism, &result);
+ wocky_node_iter_init (&iter, mechanisms, "mechanism", NULL);
+ while (wocky_node_iter_next (&iter, &mechanism))
+ result = g_slist_append (result, g_strdup (mechanism->content));
+
return result;
}
diff --git a/wocky/wocky-stanza.c b/wocky/wocky-stanza.c
index d8d53dd..2e88594 100644
--- a/wocky/wocky-stanza.c
+++ b/wocky/wocky-stanza.c
@@ -210,14 +210,23 @@ static gboolean
check_sub_type (WockyStanzaType type,
WockyStanzaSubType sub_type)
{
+ WockyStanzaType expected_type;
+
g_return_val_if_fail (type > WOCKY_STANZA_TYPE_NONE &&
type < NUM_WOCKY_STANZA_TYPE, FALSE);
g_return_val_if_fail (sub_type < NUM_WOCKY_STANZA_SUB_TYPE, FALSE);
g_assert (sub_type_names[sub_type].sub_type == sub_type);
- g_return_val_if_fail (
- sub_type_names[sub_type].type == WOCKY_STANZA_TYPE_NONE ||
- sub_type_names[sub_type].type == type, FALSE);
+
+ expected_type = sub_type_names[sub_type].type;
+
+ if (expected_type != WOCKY_STANZA_TYPE_NONE && expected_type != type)
+ {
+ g_critical ("Stanza sub-type '%s' may only be used with stanzas of "
+ "type '%s', not of type '%s'", sub_type_names[sub_type].name,
+ type_names[expected_type].name, type_names[type].name);
+ g_return_val_if_reached (FALSE);
+ }
return TRUE;
}