diff options
author | Will Thompson <will.thompson@collabora.co.uk> | 2011-03-17 16:29:27 +0000 |
---|---|---|
committer | Will Thompson <will.thompson@collabora.co.uk> | 2011-03-17 16:36:50 +0000 |
commit | 27252c32885bcc057654dcbc3191812b745238a2 (patch) | |
tree | 98bc4793b672de14d6b43affcd2b50a5a725f857 | |
parent | d3354fd9c095a2c7c1f381e62a4d7b8481fd9edc (diff) | |
parent | c0638dd2dfc88c5d8404618fe359f5a1185d13d0 (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-- | .gitignore | 3 | ||||
-rw-r--r-- | examples/Makefile.am | 13 | ||||
-rw-r--r-- | examples/connect.c | 432 | ||||
-rw-r--r-- | examples/receive-messages.c | 197 | ||||
-rw-r--r-- | examples/send-message.c | 138 | ||||
-rw-r--r-- | tests/wocky-porter-test.c | 167 | ||||
-rw-r--r-- | wocky/wocky-c2s-porter.c | 5 | ||||
-rw-r--r-- | wocky/wocky-connector.c | 4 | ||||
-rw-r--r-- | wocky/wocky-sasl-auth.c | 19 | ||||
-rw-r--r-- | wocky/wocky-stanza.c | 15 |
10 files changed, 536 insertions, 457 deletions
@@ -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; } |