diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2010-10-08 15:24:34 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2010-10-08 15:24:34 +0100 |
commit | e214e31e95f68c7088950daaa6acc39f2eaa1173 (patch) | |
tree | 4754e1df33802085c6d0cdebbc2141f6457f6473 /lib/gibber/gibber-xmpp-reader.c | |
parent | 2dfe5319d5a3603a450717a271a59f8b575e0588 (diff) | |
download | telepathy-salut-e214e31e95f68c7088950daaa6acc39f2eaa1173.tar.gz |
Implement GibberXmppReader in terms of WockyXmppReader
It has a different programming model (it emits signals rather than just
having a stanza queue) so instead of being the same, it's a subclass.
Diffstat (limited to 'lib/gibber/gibber-xmpp-reader.c')
-rw-r--r-- | lib/gibber/gibber-xmpp-reader.c | 376 |
1 files changed, 56 insertions, 320 deletions
diff --git a/lib/gibber/gibber-xmpp-reader.c b/lib/gibber/gibber-xmpp-reader.c index 096958bd..a21dd017 100644 --- a/lib/gibber/gibber-xmpp-reader.c +++ b/lib/gibber/gibber-xmpp-reader.c @@ -18,14 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <libxml/parser.h> - #include "gibber-xmpp-reader.h" + #include "gibber-signals-marshal.h" #include "gibber-xmpp-stanza.h" @@ -35,7 +29,7 @@ #define DEBUG_FLAG DEBUG_XMPP_READER #include "gibber-debug.h" -G_DEFINE_TYPE (GibberXmppReader, gibber_xmpp_reader, G_TYPE_OBJECT) +G_DEFINE_TYPE (GibberXmppReader, gibber_xmpp_reader, WOCKY_TYPE_XMPP_READER) /* signal enum */ enum { @@ -47,104 +41,34 @@ enum { static guint signals[LAST_SIGNAL] = {0}; -/* Parser prototypes */ -static void _start_element_ns (void *user_data, - const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri, - int nb_namespaces, const xmlChar **namespaces, int nb_attributes, - int nb_defaulted, const xmlChar **attributes); - -static void _end_element_ns (void *user_data, const xmlChar *localname, - const xmlChar *prefix, const xmlChar *URI); - -static void _characters (void *user_data, const xmlChar *ch, int len); - -static void _error (void *user_data, xmlErrorPtr error); - -static xmlSAXHandler parser_handler = { - .initialized = XML_SAX2_MAGIC, - .startElementNs = _start_element_ns, - .endElementNs = _end_element_ns, - .characters = _characters, - .serror = _error, -}; - -typedef enum { - STATE_STREAM_CLOSE, - STATE_STREAM_OPENED, - STATE_STREAM_OPEN, - STATE_STREAM_CLOSED, -} StreamState; - /* private structure */ typedef struct _GibberXmppReaderPrivate GibberXmppReaderPrivate; struct _GibberXmppReaderPrivate { - xmlParserCtxtPtr parser; - guint depth; - GibberXmppStanza *stanza; - GibberXmppNode *node; - GQueue *nodes; - gchar *to; - gchar *from; - gchar *version; - gboolean dispose_has_run; - gboolean error; - gboolean stream_mode; - GQueue *stanzas; - StreamState state; + gboolean emitted_opened; + gboolean emitted_closed; }; #define GIBBER_XMPP_READER_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_XMPP_READER, \ GibberXmppReaderPrivate)) - -static void -gibber_init_xml_parser (GibberXmppReader *obj) -{ - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (obj); - - if (priv->parser != NULL) - xmlFreeParserCtxt (priv->parser); - - priv->parser = xmlCreatePushParserCtxt (&parser_handler, obj, NULL, 0, NULL); - xmlCtxtUseOptions (priv->parser, XML_PARSE_NOENT); - priv->depth = 0; - priv->state = STATE_STREAM_CLOSE; -} - static void gibber_xmpp_reader_init (GibberXmppReader *obj) { GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (obj); - /* allocate any data required by the object here */ - gibber_init_xml_parser (obj); - - priv->stanza = NULL; - priv->nodes = g_queue_new (); - priv->node = NULL; - priv->error = FALSE; - priv->stream_mode = TRUE; - priv->stanzas = g_queue_new (); - priv->state = STATE_STREAM_CLOSE; + priv->emitted_opened = FALSE; + priv->emitted_closed = FALSE; } -static void gibber_xmpp_reader_dispose (GObject *object); -static void gibber_xmpp_reader_finalize (GObject *object); - static void gibber_xmpp_reader_class_init (GibberXmppReaderClass *gibber_xmpp_reader_class) { - GObjectClass *object_class = G_OBJECT_CLASS (gibber_xmpp_reader_class); - g_type_class_add_private (gibber_xmpp_reader_class, sizeof (GibberXmppReaderPrivate)); - object_class->dispose = gibber_xmpp_reader_dispose; - object_class->finalize = gibber_xmpp_reader_finalize; - signals[RECEIVED_STANZA] = g_signal_new ("received-stanza", G_OBJECT_CLASS_TYPE(gibber_xmpp_reader_class), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, @@ -170,282 +94,94 @@ gibber_xmpp_reader_class_init (GibberXmppReaderClass *gibber_xmpp_reader_class) G_TYPE_NONE, 0); } -void -gibber_xmpp_reader_dispose (GObject *object) -{ - GibberXmppReader *self = GIBBER_XMPP_READER (object); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - /* release any references held by the object here */ - while (!g_queue_is_empty (priv->stanzas)) { - gpointer stanza; - stanza = g_queue_pop_head (priv->stanzas); - g_object_unref (stanza); - } - - if (G_OBJECT_CLASS (gibber_xmpp_reader_parent_class)->dispose) - G_OBJECT_CLASS (gibber_xmpp_reader_parent_class)->dispose (object); -} - -void -gibber_xmpp_reader_finalize (GObject *object) -{ - GibberXmppReader *self = GIBBER_XMPP_READER (object); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); - - /* free any data held directly by the object here */ - if (priv->parser != NULL) { - xmlFreeParserCtxt (priv->parser); - priv->parser = NULL; - } - g_queue_free (priv->stanzas); - g_queue_free (priv->nodes); - g_free (priv->to); - g_free (priv->from); - g_free (priv->version); - - G_OBJECT_CLASS (gibber_xmpp_reader_parent_class)->finalize (object); -} - - GibberXmppReader * gibber_xmpp_reader_new (void) { - return g_object_new (GIBBER_TYPE_XMPP_READER, NULL); + return g_object_new (GIBBER_TYPE_XMPP_READER, + NULL); } GibberXmppReader * gibber_xmpp_reader_new_no_stream (void) { - GibberXmppReader *result = g_object_new (GIBBER_TYPE_XMPP_READER, NULL); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (result); - - priv->stream_mode = FALSE; - - return result; + return g_object_new (GIBBER_TYPE_XMPP_READER, + "streaming-mode", FALSE, + NULL); } -static void -_start_element_ns (void *user_data, const xmlChar *localname, - const xmlChar *prefix, const xmlChar *uri, int nb_namespaces, - const xmlChar **namespaces, int nb_attributes, int nb_defaulted, - const xmlChar **attributes) +gboolean +gibber_xmpp_reader_push (GibberXmppReader *reader, const guint8 *data, + gsize length, GError **error) { - GibberXmppReader *self = GIBBER_XMPP_READER (user_data); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); - int i; + WockyXmppReader *wocky = WOCKY_XMPP_READER (reader); + GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (reader); + WockyStanza *stanza; + GError *e = NULL; + gboolean streaming_mode; - if (prefix) - { - DEBUG ("Element %s:%s started, depth %d", prefix, localname, - priv->depth); - } - else - { - DEBUG ("Element %s started, depth %d", localname, priv->depth); - } + g_return_val_if_fail (wocky_xmpp_reader_get_state (wocky) != + WOCKY_XMPP_READER_STATE_ERROR, FALSE); - if (priv->stream_mode && G_UNLIKELY (priv->depth == 0)) - { - if (strcmp ("stream", (gchar *) localname) - || strcmp (XMPP_STREAM_NAMESPACE, (gchar *) uri)) - { - priv->error = TRUE; - return; - } - priv->state = STATE_STREAM_OPENED; - - for (i = 0; i < nb_attributes * 5; i+=5) - { - if (!strcmp ((gchar *) attributes[i], "to")) - { - g_free (priv->to); - priv->to = g_strndup ((gchar *) attributes[i+3], - (gsize) (attributes[i+4] - attributes[i+3])); - } - - if (!strcmp ((gchar *) attributes[i], "from")) - { - g_free (priv->from); - priv->from = g_strndup ((gchar *) attributes[i+3], - (gsize) (attributes[i+4] - attributes[i+3])); - } - - if (!strcmp ((gchar *) attributes[i], "version")) - { - g_free (priv->version); - priv->version = g_strndup ((gchar *) attributes[i+3], - (gsize) (attributes[i+4] - attributes[i+3])); - } - } - priv->depth++; - return; - } + g_object_get (wocky, + "streaming-mode", &streaming_mode, + NULL); - if (priv->stanza == NULL) - { - if (uri != NULL) - { - priv->stanza = wocky_stanza_new ((gchar *) localname, (gchar *) uri); - } - else - { - /* This can only happy in non-streaming mode when the top node - * of the document doesn't have a namespace. */ - DEBUG ("Stanza without a namespace, using dummy namespace.."); - priv->stanza = wocky_stanza_new ((gchar *) localname, (gchar *) ""); - } - - priv->node = wocky_stanza_get_top_node (priv->stanza); - } - else - { - g_queue_push_tail (priv->nodes, priv->node); - priv->node = gibber_xmpp_node_add_child_ns (priv->node, - (gchar *) localname, (gchar *) uri); - } + wocky_xmpp_reader_push (wocky, data, length); - for (i = 0; i < nb_attributes * 5; i+=5) + if (wocky_xmpp_reader_get_state (wocky) == WOCKY_XMPP_READER_STATE_OPENED + && !priv->emitted_opened) { - /* Node is localname, prefix, uri, valuestart, valueend */ - if (attributes[i+1] != NULL && !strcmp ((gchar *) attributes[i+1], "xml") - && !strcmp ((gchar *) attributes[i], "lang")) - { - gibber_xmpp_node_set_language_n (priv->node, - (gchar *) attributes[i+3], - (gsize) (attributes[i+4] - attributes[i+3])); - } - else - { - gibber_xmpp_node_set_attribute_n_ns (priv->node, - (gchar *) attributes[i], (gchar *) attributes[i+3], - (gsize)(attributes[i+4] - attributes[i+3]), - (gchar *) attributes[i+2]); - } - } - priv->depth++; -} + gchar *from = NULL, *to = NULL, *version = NULL; -static void -_characters (void *user_data, const xmlChar *ch, int len) -{ - GibberXmppReader *self = GIBBER_XMPP_READER (user_data); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); + g_object_get (wocky, + "from", &from, + "to", &to, + "version", &version, + NULL); - if (priv->node != NULL) - { - gibber_xmpp_node_append_content_n (priv->node, (const gchar *)ch, - (gsize)len); + priv->emitted_opened = TRUE; + g_signal_emit (reader, signals[STREAM_OPENED], 0, to, from, version); + g_free (to); + g_free (from); + g_free (version); } -} -static void -_end_element_ns (void *user_data, const xmlChar *localname, - const xmlChar *prefix, const xmlChar *uri) -{ - GibberXmppReader *self = GIBBER_XMPP_READER (user_data); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); - - priv->depth--; - - if (prefix) - { - DEBUG ("Element %s:%s ended, depth %d", prefix, localname, priv->depth); - } - else + for (stanza = wocky_xmpp_reader_pop_stanza (wocky); + stanza != NULL; + stanza = wocky_xmpp_reader_pop_stanza (wocky)) { - DEBUG ("Element %s ended, depth %d", localname, priv->depth); + g_signal_emit (reader, signals[RECEIVED_STANZA], 0, stanza); + g_object_unref (stanza); } - if (priv->node && priv->node->content) + if (wocky_xmpp_reader_get_state (wocky) == WOCKY_XMPP_READER_STATE_CLOSED + && !priv->emitted_closed) { - /* Remove content if it's purely whitespace */ - const char *c; - for (c = priv->node->content; *c != '\0' && g_ascii_isspace (*c); c++) - ; - if (*c == '\0') - gibber_xmpp_node_set_content (priv->node, NULL); + priv->emitted_closed = TRUE; + g_signal_emit (reader, signals[STREAM_CLOSED], 0); } - if (priv->stream_mode && priv->depth == 0) - { - priv->state = STATE_STREAM_CLOSED; - } - else if (priv->depth == (priv->stream_mode ? 1 : 0)) + if (!streaming_mode) { - g_assert (g_queue_get_length (priv->nodes) == 0); - DEBUG ("Received stanza"); - g_queue_push_tail (priv->stanzas, priv->stanza); - priv->stanza = NULL; - priv->node = NULL; + wocky_xmpp_reader_reset (wocky); } - else - { - priv->node = (GibberXmppNode *) g_queue_pop_tail (priv->nodes); - } -} - -static void -_error (void *user_data, xmlErrorPtr error) -{ - GibberXmppReader *self = GIBBER_XMPP_READER (user_data); - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (self); - priv->error = TRUE; - - DEBUG ("Parsing failed %s", error->message); -} - -gboolean -gibber_xmpp_reader_push (GibberXmppReader *reader, const guint8 *data, - gsize length, GError **error) -{ - GibberXmppReaderPrivate *priv = GIBBER_XMPP_READER_GET_PRIVATE (reader); - xmlParserCtxtPtr parser; - - g_assert (!priv->error); - DEBUG ("Parsing chunk: %.*s", (int)length, data); - - parser = priv->parser; - xmlParseChunk (parser, (const char*)data, length, FALSE); - if (priv->state == STATE_STREAM_OPENED) - { - priv->state = STATE_STREAM_OPEN; - g_signal_emit (reader, signals[STREAM_OPENED], 0, - priv->to, priv->from, priv->version); - } + e = wocky_xmpp_reader_get_error (wocky); - while (!g_queue_is_empty (priv->stanzas)) + if (e == NULL) { - gpointer stanza; - stanza = g_queue_pop_head (priv->stanzas); - g_signal_emit (reader, signals[RECEIVED_STANZA], 0, stanza); - g_object_unref (stanza); + return TRUE; } - - if (priv->state == STATE_STREAM_CLOSED) + else { - priv->state = STATE_STREAM_CLOSE; - g_signal_emit (reader, signals[STREAM_CLOSED], 0); + g_propagate_error (error, e); + return FALSE; } - - if (!priv->stream_mode) - { - gibber_init_xml_parser (reader); - } - - return !priv->error; } void gibber_xmpp_reader_reset (GibberXmppReader *reader) { - DEBUG ("Resetting xmpp reader"); - gibber_init_xml_parser (reader); + wocky_xmpp_reader_reset (WOCKY_XMPP_READER (reader)); } |