/* * wocky-porter.c - Source for WockyPorter * Copyright (C) 2009-2011 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "wocky-porter.h" #include "wocky-signals-marshal.h" #include "wocky-xmpp-connection.h" G_DEFINE_INTERFACE (WockyPorter, wocky_porter, G_TYPE_OBJECT) static void wocky_porter_default_init (WockyPorterInterface *iface) { GType iface_type = G_TYPE_FROM_INTERFACE (iface); static gsize initialization_value = 0; GParamSpec *spec; if (g_once_init_enter (&initialization_value)) { /** * WockyPorter:connection: * * The underlying #WockyXmppConnection wrapped by the #WockyPorter */ spec = g_param_spec_object ("connection", "XMPP connection", "the XMPP connection used by this porter", WOCKY_TYPE_XMPP_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, spec); /** * WockyPorter:full-jid: * * The user's full JID (node@domain/resource). */ spec = g_param_spec_string ("full-jid", "Full JID", "The user's own full JID (node@domain/resource)", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, spec); /** * WockyPorter:bare-jid: * * The user's bare JID (node@domain). */ spec = g_param_spec_string ("bare-jid", "Bare JID", "The user's own bare JID (node@domain)", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, spec); /** * WockyPorter:resource: * * The resource part of the user's full JID, or %NULL if their full JID does * not contain a resource at all. */ spec = g_param_spec_string ("resource", "Resource", "The user's resource", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (iface, spec); /** * WockyPorter::remote-closed: * @porter: the object on which the signal is emitted * * The ::remote-closed signal is emitted when the other side closed the XMPP * stream. */ g_signal_new ("remote-closed", iface_type, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * WockyPorter::remote-error: * @porter: the object on which the signal is emitted * @domain: error domain (a #GQuark) * @code: error code * @message: human-readable informative error message * * The ::remote-error signal is emitted when an error has been detected * on the XMPP stream. */ g_signal_new ("remote-error", iface_type, G_SIGNAL_RUN_LAST, 0, NULL, NULL, _wocky_signals_marshal_VOID__UINT_INT_STRING, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING); /** * WockyPorter::closing: * @porter: the object on which the signal is emitted * * The ::closing signal is emitted when the #WockyPorter starts to close its * XMPP connection. Once this signal has been emitted, the #WockyPorter * can't be used to send stanzas any more. */ g_signal_new ("closing", iface_type, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * WockyPorter::sending: * @porter: the object on which the signal is emitted * @stanza: the #WockyStanza being sent, or %NULL if @porter is just * sending whitespace * * The ::sending signal is emitted whenever #WockyPorter sends data * on the XMPP connection. */ g_signal_new ("sending", iface_type, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, WOCKY_TYPE_STANZA); g_once_init_leave (&initialization_value, 1); } } /** * wocky_porter_error_quark: * * Get the error quark used by the porter. * * Returns: the quark for porter errors. */ GQuark wocky_porter_error_quark (void) { static GQuark quark = 0; if (quark == 0) quark = g_quark_from_static_string ("wocky-porter-error"); return quark; } /** * wocky_porter_get_full_jid: (skip) * @self: a porter * * * * Returns: (transfer none): the value of #WockyPorter:full-jid */ const gchar * wocky_porter_get_full_jid (WockyPorter *self) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), NULL); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->get_full_jid != NULL); return iface->get_full_jid (self); } /** * wocky_porter_get_bare_jid: (skip) * @self: a porter * * * * Returns: (transfer none): the value of #WockyPorter:bare-jid */ const gchar * wocky_porter_get_bare_jid (WockyPorter *self) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), NULL); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->get_bare_jid != NULL); return iface->get_bare_jid (self); } /** * wocky_porter_get_resource: (skip) * @self: a porter * * * * Returns: (transfer none): the value of #WockyPorter:resource */ const gchar * wocky_porter_get_resource (WockyPorter *self) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), NULL); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->get_resource != NULL); return iface->get_resource (self); } /** * wocky_porter_start: * @porter: a #WockyPorter * * Start a #WockyPorter to make it read and dispatch incoming stanzas. */ void wocky_porter_start (WockyPorter *self) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->start != NULL); iface->start (self); } /** * wocky_porter_send_async: * @porter: a #WockyPorter * @stanza: the #WockyStanza to send * @cancellable: optional #GCancellable object, %NULL to ignore * @callback: callback to call when the request is satisfied * @user_data: the data to pass to callback function * * Request asynchronous sending of a #WockyStanza. * When the stanza has been sent callback will be called. * You can then call wocky_porter_send_finish() to get the result * of the operation. */ void wocky_porter_send_async (WockyPorter *self, WockyStanza *stanza, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->send_async != NULL); iface->send_async (self, stanza, cancellable, callback, user_data); } /** * wocky_porter_send_finish: * @porter: a #WockyPorter * @result: a #GAsyncResult * @error: a #GError location to store the error occuring, or %NULL to * ignore. * * Finishes sending a #WockyStanza. * * Returns: %TRUE on success or %FALSE on error. */ gboolean wocky_porter_send_finish (WockyPorter *self, GAsyncResult *result, GError **error) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), FALSE); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->send_finish != NULL); return iface->send_finish (self, result, error); } /** * wocky_porter_send: * @porter: a #WockyPorter * @stanza: the #WockyStanza to send * * Send a #WockyStanza. This is a convenient function to not have to * call wocky_porter_send_async() with lot of %NULL arguments if you * don't care to know when the stanza has been actually sent. */ void wocky_porter_send (WockyPorter *porter, WockyStanza *stanza) { wocky_porter_send_async (porter, stanza, NULL, NULL, NULL); } /** * wocky_porter_register_handler_from_va: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @from: the JID whose messages this handler is intended for (may not be * %NULL) * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @ap: a wocky_stanza_build() specification. The handler * will match a stanza only if the stanza received is a superset of the one * passed to this function, as per wocky_node_is_superset(). * * A va_list version of wocky_porter_register_handler_from(); see * that function for more details. * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from_va (WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, const gchar *from, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, va_list ap) { guint ret; WockyStanza *stanza; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); g_return_val_if_fail (from != NULL, 0); if (type == WOCKY_STANZA_TYPE_NONE) { stanza = NULL; g_return_val_if_fail ( (va_arg (ap, WockyNodeBuildTag) == 0) && "Pattern-matching is not supported when matching stanzas " "of any type", 0); } else { stanza = wocky_stanza_build_va (type, WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL, ap); g_assert (stanza != NULL); } ret = wocky_porter_register_handler_from_by_stanza (self, type, sub_type, from, priority, callback, user_data, stanza); if (stanza != NULL) g_object_unref (stanza); return ret; } /** * wocky_porter_register_handler_from_by_stanza: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @from: the JID whose messages this handler is intended for (may not be * %NULL) * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @stanza: a #WockyStanza. The handler will match a stanza only if * the stanza received is a superset of the one passed to this * function, as per wocky_node_is_superset(). * * A #WockyStanza version of wocky_porter_register_handler_from(); see * that function for more details. * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from_by_stanza (WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, const gchar *from, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, WockyStanza *stanza) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); g_return_val_if_fail (from != NULL, 0); if (type == WOCKY_STANZA_TYPE_NONE) g_return_val_if_fail (stanza == NULL, 0); else g_return_val_if_fail (WOCKY_IS_STANZA (stanza), 0); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->register_handler_from_by_stanza != NULL); return iface->register_handler_from_by_stanza (self, type, sub_type, from, priority, callback, user_data, stanza); } /** * wocky_porter_register_handler_from: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @from: the JID whose messages this handler is intended for (may not be * %NULL) * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @...: a wocky_stanza_build() specification. The handler * will match a stanza only if the stanza received is a superset of the one * passed to this function, as per wocky_node_is_superset(). * * Register a new stanza handler. * Stanza handlers are called when the Porter receives a new stanza matching * the rules of the handler. Matching handlers are sorted by priority and are * called until one claims to have handled the stanza (by returning %TRUE). * * If @from is a bare JID, then the resource of the JID in the from attribute * will be ignored: In other words, a handler registered against a bare JID * will match all stanzas from a JID with the same node * and domain: * "foo@bar.org" will match * "foo@bar.org", * "foo@bar.org/moose" and so forth. * * To register an IQ handler from Juliet for all the Jingle stanzas related * to one Jingle session: * * |[ * id = wocky_porter_register_handler_from (porter, * WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_NONE, * "juliet@example.com/Balcony", * WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, * jingle_cb, * '(', "jingle", * ':', "urn:xmpp:jingle:1", * '@', "sid", "my_sid", * ')', NULL); * ]| * * To match stanzas from any sender, see * wocky_porter_register_handler_from_anyone(). If the porter is a * #WockyC2SPorter, one can match stanzas sent by the server; see * wocky_c2s_porter_register_handler_from_server(). * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from (WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, const gchar *from, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, ...) { va_list ap; guint ret; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); g_return_val_if_fail (from != NULL, 0); va_start (ap, user_data); ret = wocky_porter_register_handler_from_va (self, type, sub_type, from, priority, callback, user_data, ap); va_end (ap); return ret; } /** * wocky_porter_register_handler_from_anyone_va: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @ap: a wocky_stanza_build() specification. The handler * will match a stanza only if the stanza received is a superset of the one * passed to this function, as per wocky_node_is_superset(). * * A va_list version of * wocky_porter_register_handler_from_anyone(); see that function for more * details. * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from_anyone_va ( WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, va_list ap) { guint ret; WockyStanza *stanza; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); if (type == WOCKY_STANZA_TYPE_NONE) { stanza = NULL; g_return_val_if_fail ( (va_arg (ap, WockyNodeBuildTag) == 0) && "Pattern-matching is not supported when matching stanzas " "of any type", 0); } else { stanza = wocky_stanza_build_va (type, WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL, ap); g_assert (stanza != NULL); } ret = wocky_porter_register_handler_from_anyone_by_stanza (self, type, sub_type, priority, callback, user_data, stanza); if (stanza != NULL) g_object_unref (stanza); return ret; } /** * wocky_porter_register_handler_from_anyone_by_stanza: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @stanza: a #WockyStanza. The handler will match a stanza only if * the stanza received is a superset of the one passed to this * function, as per wocky_node_is_superset(). * * A #WockyStanza version of * wocky_porter_register_handler_from_anyone(); see that function for * more details. * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from_anyone_by_stanza ( WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, WockyStanza *stanza) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); if (type == WOCKY_STANZA_TYPE_NONE) g_return_val_if_fail (stanza == NULL, 0); else g_return_val_if_fail (WOCKY_IS_STANZA (stanza), 0); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->register_handler_from_anyone_by_stanza != NULL); return iface->register_handler_from_anyone_by_stanza (self, type, sub_type, priority, callback, user_data, stanza); } /** * wocky_porter_register_handler_from_anyone: * @self: A #WockyPorter instance (passed to @callback). * @type: The type of stanza to be handled, or WOCKY_STANZA_TYPE_NONE to match * any type of stanza. * @sub_type: The subtype of stanza to be handled, or * WOCKY_STANZA_SUB_TYPE_NONE to match any type of stanza. * @priority: a priority between %WOCKY_PORTER_HANDLER_PRIORITY_MIN and * %WOCKY_PORTER_HANDLER_PRIORITY_MAX (often * %WOCKY_PORTER_HANDLER_PRIORITY_NORMAL). Handlers with a higher priority * (larger number) are called first. * @callback: A #WockyPorterHandlerFunc, which should return %FALSE to decline * the stanza (Wocky will continue to the next handler, if any), or %TRUE to * stop further processing. * @user_data: Passed to @callback. * @...: a wocky_stanza_build() specification. The handler * will match a stanza only if the stanza received is a superset of the one * passed to this function, as per wocky_node_is_superset(). * * Registers a handler for incoming stanzas from anyone, including those where * the from attribute is missing. * * For example, to register a handler matching all message stanzas received * from anyone, call: * * |[ * id = wocky_porter_register_handler (porter, * WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, NULL, * WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, message_received_cb, NULL, * NULL); * ]| * * As a more interesting example, the following matches incoming PEP * notifications for contacts' geolocation information: * * |[ * id = wocky_porter_register_handler_from_anyone (porter, * WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, * WOCKY_PORTER_HANDLER_PRIORITY_MAX, * msg_event_cb, self, * '(', "event", * ':', WOCKY_XMPP_NS_PUBSUB_EVENT, * '(', "items", * '@', "node", "http://jabber.org/protocol/geoloc", * ')', * ')', * NULL); * ]| * * Returns: a non-zero ID for use with wocky_porter_unregister_handler(). */ guint wocky_porter_register_handler_from_anyone ( WockyPorter *self, WockyStanzaType type, WockyStanzaSubType sub_type, guint priority, WockyPorterHandlerFunc callback, gpointer user_data, ...) { va_list ap; guint ret; g_return_val_if_fail (WOCKY_IS_PORTER (self), 0); va_start (ap, user_data); ret = wocky_porter_register_handler_from_anyone_va (self, type, sub_type, priority, callback, user_data, ap); va_end (ap); return ret; } /** * wocky_porter_unregister_handler: * @porter: a #WockyPorter * @id: the id of the handler to unregister * * Unregister a registered handler. This handler won't be called when * receiving stanzas anymore. */ void wocky_porter_unregister_handler (WockyPorter *self, guint id) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->unregister_handler != NULL); iface->unregister_handler (self, id); } /** * wocky_porter_close_async: * @porter: a #WockyPorter * @cancellable: optional #GCancellable object, %NULL to ignore * @callback: callback to call when the request is satisfied * @user_data: the data to pass to callback function * * Request asynchronous closing of a #WockyPorter. This fires the * WockyPorter::closing signal, flushes the sending queue, closes the XMPP * stream and waits that the other side closes the XMPP stream as well. * When this is done, @callback is called. * You can then call wocky_porter_close_finish() to get the result of * the operation. */ void wocky_porter_close_async (WockyPorter *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->close_async != NULL); iface->close_async (self, cancellable, callback, user_data); } /** * wocky_porter_close_finish: * @porter: a #WockyPorter * @result: a #GAsyncResult * @error: a #GError location to store the error occuring, or %NULL to ignore. * * Finishes a close operation. * * Returns: %TRUE on success or %FALSE on error. */ gboolean wocky_porter_close_finish (WockyPorter *self, GAsyncResult *result, GError **error) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), FALSE); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->close_finish != NULL); return iface->close_finish (self, result, error); } /** * wocky_porter_send_iq_async: * @porter: a #WockyPorter * @stanza: the #WockyStanza to send * @cancellable: optional #GCancellable object, %NULL to ignore * @callback: callback to call when the request is satisfied * @user_data: the data to pass to callback function * * Request asynchronous sending of a #WockyStanza of type * %WOCKY_STANZA_TYPE_IQ and sub-type %WOCKY_STANZA_SUB_TYPE_GET or * %WOCKY_STANZA_SUB_TYPE_SET. * When the reply to this IQ has been received callback will be called. * You can then call #wocky_porter_send_iq_finish to get the reply stanza. */ void wocky_porter_send_iq_async (WockyPorter *self, WockyStanza *stanza, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->send_iq_async != NULL); iface->send_iq_async (self, stanza, cancellable, callback, user_data); } /** * wocky_porter_send_iq_finish: * @porter: a #WockyPorter * @result: a #GAsyncResult * @error: a #GError location to store the error occuring, or %NULL to ignore. * * Get the reply of an IQ query. * * Returns: a reffed #WockyStanza on success, %NULL on error */ WockyStanza * wocky_porter_send_iq_finish (WockyPorter *self, GAsyncResult *result, GError **error) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), FALSE); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->send_iq_finish != NULL); return iface->send_iq_finish (self, result, error); } /** * wocky_porter_acknowledge_iq: * @porter: a #WockyPorter * @stanza: a stanza of type #WOCKY_STANZA_TYPE_IQ and sub-type either * #WOCKY_STANZA_SUB_TYPE_SET or #WOCKY_STANZA_SUB_TYPE_GET * @...: a wocky_stanza_build() specification; pass %NULL to include no * body in the reply. * * Sends an acknowledgement for @stanza back to the sender, as a shorthand for * calling wocky_stanza_build_iq_result() and wocky_porter_send(). */ void wocky_porter_acknowledge_iq ( WockyPorter *porter, WockyStanza *stanza, ...) { WockyStanzaType type; WockyStanzaSubType sub_type; WockyStanza *result; va_list ap; g_return_if_fail (WOCKY_IS_PORTER (porter)); g_return_if_fail (WOCKY_IS_STANZA (stanza)); wocky_stanza_get_type_info (stanza, &type, &sub_type); g_return_if_fail (type == WOCKY_STANZA_TYPE_IQ); g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_GET || sub_type == WOCKY_STANZA_SUB_TYPE_SET); va_start (ap, stanza); result = wocky_stanza_build_iq_result_va (stanza, ap); va_end (ap); if (result != NULL) { wocky_porter_send (porter, result); g_object_unref (result); } } /** * wocky_porter_send_iq_error: * @porter: the porter whence @stanza came * @stanza: a stanza of type %WOCKY_STANZA_TYPE_IQ and sub-type either * #WOCKY_STANZA_SUB_TYPE_SET or #WOCKY_STANZA_SUB_TYPE_GET * @error_code: an XMPP Core stanza error code * @message: (allow-none): an optional error message to include with the reply. * * Sends an error reply for @stanza back to its sender, with the given * @error_code and @message, and including the child element from the original * stanza. * * To send error replies with more detailed error elements, see * wocky_porter_send_iq_gerror(), or use wocky_stanza_build_iq_error() and * wocky_porter_send() directly, possibly using wocky_stanza_error_to_node() to * construct the error element. */ void wocky_porter_send_iq_error ( WockyPorter *porter, WockyStanza *stanza, WockyXmppError error_code, const gchar *message) { WockyStanzaType type; WockyStanzaSubType sub_type; GError *error = NULL; g_return_if_fail (WOCKY_IS_PORTER (porter)); g_return_if_fail (WOCKY_IS_STANZA (stanza)); wocky_stanza_get_type_info (stanza, &type, &sub_type); g_return_if_fail (type == WOCKY_STANZA_TYPE_IQ); g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_GET || sub_type == WOCKY_STANZA_SUB_TYPE_SET); g_return_if_fail (error_code < NUM_WOCKY_XMPP_ERRORS); error = g_error_new_literal (WOCKY_XMPP_ERROR, error_code, message != NULL ? message : ""); wocky_porter_send_iq_gerror (porter, stanza, error); g_clear_error (&error); } /** * wocky_porter_send_iq_gerror: * @porter: the porter whence @stanza came * @stanza: a stanza of type %WOCKY_STANZA_TYPE_IQ and sub-type either * #WOCKY_STANZA_SUB_TYPE_SET or #WOCKY_STANZA_SUB_TYPE_GET * @error: an error whose domain is either %WOCKY_XMPP_ERROR, some other stanza * error domain supplied with Wocky (such as %WOCKY_JINGLE_ERROR or * %WOCKY_SI_ERROR), or a custom domain registered with * wocky_xmpp_error_register_domain() * * Sends an error reply for @stanza back to its sender, building the * <error/> element from the given @error. To send error * replies with simple XMPP Core stanza errors in the %WOCKY_XMPP_ERROR domain, * wocky_porter_send_iq_error() may be more convenient to use. */ void wocky_porter_send_iq_gerror ( WockyPorter *porter, WockyStanza *stanza, const GError *error) { WockyStanzaType type; WockyStanzaSubType sub_type; WockyStanza *result; WockyNode *result_node; g_return_if_fail (WOCKY_IS_PORTER (porter)); g_return_if_fail (WOCKY_IS_STANZA (stanza)); g_return_if_fail (error != NULL); wocky_stanza_get_type_info (stanza, &type, &sub_type); g_return_if_fail (type == WOCKY_STANZA_TYPE_IQ); g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_GET || sub_type == WOCKY_STANZA_SUB_TYPE_SET); result = wocky_stanza_build_iq_error (stanza, '*', &result_node, NULL); if (result != NULL) { /* RFC3920 §9.2.3 dictates: * An IQ stanza of type "error" … MUST include an child. */ wocky_stanza_error_to_node (error, result_node); wocky_porter_send (porter, result); g_object_unref (result); } } /** * wocky_porter_force_close_async: * @porter: a #WockyPorter * @cancellable: optional #GCancellable object, %NULL to ignore * @callback: callback to call when the request is satisfied * @user_data: the data to pass to callback function * * Force the #WockyPorter to close the TCP connection of the underlying * #WockyXmppConnection. * If a close operation is pending, it will be completed with the * %WOCKY_PORTER_ERROR_FORCIBLY_CLOSED error. * When the connection has been closed, @callback will be called. * You can then call wocky_porter_force_close_finish() to get the result of * the operation. */ void wocky_porter_force_close_async (WockyPorter *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { WockyPorterInterface *iface; g_return_if_fail (WOCKY_IS_PORTER (self)); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->force_close_async != NULL); iface->force_close_async (self, cancellable, callback, user_data); } /** * wocky_porter_force_close_finish: * @porter: a #WockyPorter * @result: a #GAsyncResult * @error: a #GError location to store the error occuring, or %NULL to ignore. * * Finishes a force close operation. * * Returns: %TRUE on success or %FALSE on error. */ gboolean wocky_porter_force_close_finish ( WockyPorter *self, GAsyncResult *result, GError **error) { WockyPorterInterface *iface; g_return_val_if_fail (WOCKY_IS_PORTER (self), FALSE); iface = WOCKY_PORTER_GET_INTERFACE (self); g_assert (iface->force_close_finish != NULL); return iface->force_close_finish (self, result, error); }