Mercurial > pidgin.yaz
changeset 18761:316be7e715c6
Update the Bonjour prpl to use libxml explicitly instead of the xml_node stuff. This allows us to deal with partial reads. I also fixed issues related to starting conversations with iChat and a couple other things. Fixes #2022,#1652
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Tue, 31 Jul 2007 23:23:25 +0000 |
parents | bf47d0401a96 |
children | a582b09109bc |
files | libpurple/protocols/bonjour/Makefile.am libpurple/protocols/bonjour/Makefile.mingw libpurple/protocols/bonjour/jabber.c libpurple/protocols/bonjour/jabber.h libpurple/protocols/bonjour/mdns_win32.c libpurple/protocols/bonjour/parser.c libpurple/protocols/bonjour/parser.h |
diffstat | 7 files changed, 386 insertions(+), 169 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/Makefile.am Tue Jul 31 23:20:56 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.am Tue Jul 31 23:23:25 2007 +0000 @@ -17,7 +17,9 @@ mdns_common.h \ mdns_howl.c \ mdns_howl.h \ - mdns_types.h + mdns_types.h \ + parser.c \ + parser.h AM_CFLAGS = $(st) -DUSE_BONJOUR_HOWL @@ -36,7 +38,7 @@ st = pkg_LTLIBRARIES = libbonjour.la libbonjour_la_SOURCES = $(BONJOURSOURCES) -libbonjour_la_LIBADD = $(GLIB_LIBS) $(HOWL_LIBS) +libbonjour_la_LIBADD = $(GLIB_LIBS) $(HOWL_LIBS) $(LIBXML_LIBS) endif @@ -46,4 +48,5 @@ -I$(top_builddir)/libpurple \ $(GLIB_CFLAGS) \ $(DEBUG_CFLAGS) \ - $(HOWL_CFLAGS) + $(HOWL_CFLAGS) \ + $(LIBXML_CFLAGS)
--- a/libpurple/protocols/bonjour/Makefile.mingw Tue Jul 31 23:20:56 2007 +0000 +++ b/libpurple/protocols/bonjour/Makefile.mingw Tue Jul 31 23:23:25 2007 +0000 @@ -30,12 +30,14 @@ -I$(GTK_TOP)/include/glib-2.0 \ -I$(GTK_TOP)/lib/glib-2.0/include \ -I$(BONJOUR_TOP)/include \ + -I$(LIBXML2_TOP)/include \ -I$(PURPLE_TOP) \ -I$(PURPLE_TOP)/win32 \ -I$(PIDGIN_TREE_TOP) LIB_PATHS += -L$(GTK_TOP)/lib \ -L$(BONJOUR_TOP)/lib \ + -L$(LIBXML2_TOP)/lib \ -L$(PURPLE_TOP) ## @@ -45,6 +47,7 @@ buddy.c \ mdns_common.c \ mdns_win32.c \ + parser.c \ jabber.c OBJECTS = $(C_SRC:%.c=%.o) @@ -58,6 +61,7 @@ -lintl \ -ldnssd \ -lnetapi32 \ + -lxml2 \ -lpurple include $(PIDGIN_COMMON_RULES)
--- a/libpurple/protocols/bonjour/jabber.c Tue Jul 31 23:20:56 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.c Tue Jul 31 23:23:25 2007 +0000 @@ -42,6 +42,7 @@ #include "util.h" #include "jabber.h" +#include "parser.h" #include "bonjour.h" #include "buddy.h" @@ -109,9 +110,10 @@ } static void -_jabber_parse_and_write_message_to_ui(xmlnode *message_node, PurpleConnection *connection, PurpleBuddy *pb) +_jabber_parse_and_write_message_to_ui(xmlnode *message_node, PurpleBuddy *pb) { xmlnode *body_node, *html_node, *events_node; + PurpleConnection *gc = pb->account->gc; char *body, *html_body = NULL; const char *ichat_balloon_color = NULL; const char *ichat_text_color = NULL; @@ -186,7 +188,7 @@ /* TODO: Should we do something with "composing_event" here? */ /* Send the message to the UI */ - serv_got_im(connection, pb->name, body, 0, time(NULL)); + serv_got_im(gc, pb->name, body, 0, time(NULL)); g_free(body); g_free(html_body); @@ -218,37 +220,6 @@ } } -static gint -_read_data(gint socket, char **message) -{ - GString *data = g_string_new(""); - char partial_data[512]; - gint total_message_length = 0; - gint partial_message_length = 0; - - /* Read chunks of 512 bytes till the end of the data */ - while ((partial_message_length = recv(socket, partial_data, 512, 0)) > 0) - { - g_string_append_len(data, partial_data, partial_message_length); - total_message_length += partial_message_length; - } - - if (partial_message_length == -1) - { - if (errno != EAGAIN) - purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); - if (total_message_length == 0) { - return -1; - } - } - - *message = g_string_free(data, FALSE); - if (total_message_length != 0) - purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length); - - return total_message_length; -} - static void _send_data_write_cb(gpointer data, gint source, PurpleInputCondition cond) { @@ -303,7 +274,8 @@ /* If we're not ready to actually send, append it to the buffer */ if (bconv->tx_handler != -1 || bconv->connect_data != NULL - || !bconv->stream_started + || !bconv->sent_stream_start + || !bconv->recv_stream_start || purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { ret = -1; errno = EAGAIN; @@ -341,20 +313,32 @@ return ret; } +void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet) { + if (!strcmp(packet->name, "message")) + _jabber_parse_and_write_message_to_ui(packet, pb); + else + purple_debug_warning("bonjour", "Unknown packet: %s\n", + packet->name); +} + + static void _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition) { - char *message = NULL; - gint message_length; PurpleBuddy *pb = data; - PurpleAccount *account = pb->account; - BonjourBuddy *bb = pb->proto_data; - gboolean closed_conversation = FALSE; + gint len, message_length; + static char message[4096]; + + /*TODO: use a static buffer */ /* Read the data from the socket */ - if ((message_length = _read_data(socket, &message)) == -1) { + if ((len = recv(socket, message, sizeof(message) - 1, 0)) == -1) { /* There have been an error reading from the socket */ if (errno != EAGAIN) { + BonjourBuddy *bb = pb->proto_data; + + purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); + bonjour_jabber_close_conversation(bb->conversation); bb->conversation = NULL; @@ -362,65 +346,71 @@ * If they try to send another message it'll reconnect */ } return; - } else if (message_length == 0) { /* The other end has closed the socket */ - closed_conversation = TRUE; + } else if (len == 0) { /* The other end has closed the socket */ + purple_debug_warning("bonjour", "Connection closed (without stream end) by %s.\n", pb->name); + bonjour_jabber_stream_ended(pb); + return; } else { + message_length = len; message[message_length] = '\0'; - while (g_ascii_iscntrl(message[message_length - 1])) { + while (message_length > 0 && g_ascii_iscntrl(message[message_length - 1])) { message[message_length - 1] = '\0'; message_length--; } } - /* - * Check that this is not the end of the conversation. This is - * using a magic string, but xmlnode won't play nice when just - * parsing an end tag - */ - if (closed_conversation || purple_str_has_prefix(message, STREAM_END)) { - PurpleConversation *conv; + purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", message, len); + + bonjour_parser_process(pb, message, message_length); +} - /* Close the socket, clear the watcher and free memory */ - bonjour_jabber_close_conversation(bb->conversation); - bb->conversation = NULL; +void bonjour_jabber_stream_ended(PurpleBuddy *pb) { + BonjourBuddy *bb = pb->proto_data; + PurpleConversation *conv; + + purple_debug_info("bonjour", "Recieved conversation close notification from %s.\n", pb->name); + + /* Close the socket, clear the watcher and free memory */ + bonjour_jabber_close_conversation(bb->conversation); + bb->conversation = NULL; - /* Inform the user that the conversation has been closed */ - conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, account); - if (conv != NULL) { - char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); - purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); - g_free(tmp); - } - } else { - xmlnode *message_node; + /* Inform the user that the conversation has been closed */ + conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pb->name, pb->account); + if (conv != NULL) { + char *tmp = g_strdup_printf(_("%s has closed the conversation."), pb->name); + purple_conversation_write(conv, NULL, tmp, PURPLE_MESSAGE_SYSTEM, time(NULL)); + g_free(tmp); + } +} - /* Parse the message into an XMLnode for analysis */ - message_node = xmlnode_from_str(message, strlen(message)); +void bonjour_jabber_stream_started(PurpleBuddy *pb) { + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; - if (message_node != NULL) { - /* Parse the message to get the data and send to the ui */ - _jabber_parse_and_write_message_to_ui(message_node, account->gc, pb); - xmlnode_free(message_node); - } else { - /* TODO: Deal with receiving only a partial message */ - } + /* If the stream has been completely started, we can start doing stuff */ + if (bconv->sent_stream_start && bconv->recv_stream_start && purple_circ_buffer_get_max_read(bconv->tx_buf) > 0) { + /* Watch for when we can write the buffered messages */ + bconv->tx_handler = purple_input_add(bconv->socket, PURPLE_INPUT_WRITE, + _send_data_write_cb, pb); + /* We can probably write the data right now. */ + _send_data_write_cb(pb, bconv->socket, PURPLE_INPUT_WRITE); } - g_free(message); } struct _stream_start_data { char *msg; - PurpleInputFunction tx_handler_cb; }; + static void _start_stream(gpointer data, gint source, PurpleInputCondition condition) { PurpleBuddy *pb = data; BonjourBuddy *bb = pb->proto_data; - struct _stream_start_data *ss = bb->conversation->stream_data; + BonjourJabberConversation *bconv = bb->conversation; + struct _stream_start_data *ss = bconv->stream_data; int len, ret; len = strlen(ss->msg); @@ -443,7 +433,7 @@ _("Unable to send the message, the conversation couldn't be started."), PURPLE_MESSAGE_SYSTEM, time(NULL)); - bonjour_jabber_close_conversation(bb->conversation); + bonjour_jabber_close_conversation(bconv); bb->conversation = NULL; return; @@ -457,22 +447,67 @@ return; } - /* Stream started; process the send buffer if there is one*/ - purple_input_remove(bb->conversation->tx_handler); - bb->conversation->tx_handler= -1; - - bb->conversation->stream_started = TRUE; - g_free(ss->msg); g_free(ss); - bb->conversation->stream_data = NULL; + bconv->stream_data = NULL; + + /* Stream started; process the send buffer if there is one */ + purple_input_remove(bconv->tx_handler); + bconv->tx_handler= -1; + bconv->sent_stream_start = TRUE; + + bonjour_jabber_stream_started(pb); + +} + +static gboolean bonjour_jabber_stream_init(PurpleBuddy *pb, int client_socket) +{ + int ret, len; + char *stream_start; + BonjourBuddy *bb = pb->proto_data; + + stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), + purple_buddy_get_name(pb)); + len = strlen(stream_start); + + /* Start the stream */ + ret = send(client_socket, stream_start, len, 0); + + if (ret == -1 && errno == EAGAIN) + ret = 0; + else if (ret <= 0) { + const char *err = strerror(errno); - if (ss->tx_handler_cb) { - bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, - ss->tx_handler_cb, pb); - /* We can probably write the data now. */ - (ss->tx_handler_cb)(pb, source, PURPLE_INPUT_WRITE); + purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", + purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); + + close(client_socket); + g_free(stream_start); + + return FALSE; } + + /* This is unlikely to happen */ + if (ret < len) { + struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); + ss->msg = g_strdup(stream_start + ret); + bb->conversation->stream_data = ss; + /* Finish sending the stream start */ + bb->conversation->tx_handler = purple_input_add(client_socket, + PURPLE_INPUT_WRITE, _start_stream, pb); + } else + bb->conversation->sent_stream_start = TRUE; + + g_free(stream_start); + + /* setup the parser fresh for each stream */ + bonjour_parser_setup(bb->conversation); + + bb->conversation->socket = client_socket; + bb->conversation->rx_handler = purple_input_add(client_socket, + PURPLE_INPUT_READ, _client_socket_handler, pb); + + return TRUE; } static void @@ -498,6 +533,7 @@ /* Look for the buddy that has opened the conversation and fill information */ address_text = inet_ntoa(their_addr.sin_addr); + purple_debug_info("bonjour", "Received incoming connection from %s\n.", address_text); cbba = g_new0(struct _check_buddy_by_address_t, 1); cbba->address = address_text; cbba->pb = &pb; @@ -515,49 +551,15 @@ /* Check if the conversation has been previously started */ if (bb->conversation == NULL) { - int ret, len; - char *stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), - purple_buddy_get_name(pb)); - - len = strlen(stream_start); - - /* Start the stream */ - ret = send(client_socket, stream_start, len, 0); + bb->conversation = bonjour_jabber_conv_new(); - if (ret == -1 && errno == EAGAIN) - ret = 0; - else if (ret <= 0) { - const char *err = strerror(errno); - - purple_debug_error("bonjour", "Error starting stream with buddy %s at %s:%d error: %s\n", - purple_buddy_get_name(pb), bb->ip ? bb->ip : "(null)", bb->port_p2pj, err ? err : "(null)"); - + if (!bonjour_jabber_stream_init(pb, client_socket)) { close(client_socket); - g_free(stream_start); - return; } - bb->conversation = bonjour_jabber_conv_new(); - bb->conversation->socket = client_socket; - bb->conversation->rx_handler = purple_input_add(client_socket, - PURPLE_INPUT_READ, _client_socket_handler, pb); - - /* This is unlikely to happen */ - if (ret < len) { - struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); - ss->msg = g_strdup(stream_start + ret); - ss->tx_handler_cb = NULL; /* We have nothing to write yet */ - bb->conversation->stream_data = ss; - /* Finish sending the stream start */ - bb->conversation->tx_handler = purple_input_add(client_socket, - PURPLE_INPUT_WRITE, _start_stream, pb); - } else { - bb->conversation->stream_started = TRUE; - } - - g_free(stream_start); } else { + purple_debug_warning("bonjour", "Ignoring incoming connection because an existing connection exists.\n"); close(client_socket); } } @@ -639,8 +641,6 @@ { PurpleBuddy *pb = data; BonjourBuddy *bb = pb->proto_data; - int len, ret; - char *stream_start; bb->conversation->connect_data = NULL; @@ -661,15 +661,7 @@ return; } - stream_start = g_strdup_printf(DOCTYPE, purple_account_get_username(pb->account), purple_buddy_get_name(pb)); - len = strlen(stream_start); - - /* Start the stream and send queued messages */ - ret = send(source, stream_start, len, 0); - - if (ret == -1 && errno == EAGAIN) - ret = 0; - else if (ret <= 0) { + if (!bonjour_jabber_stream_init(pb, source)) { const char *err = strerror(errno); PurpleConversation *conv; @@ -685,37 +677,8 @@ close(source); bonjour_jabber_close_conversation(bb->conversation); bb->conversation = NULL; - - g_free(stream_start); - return; } - - bb->conversation->socket = source; - bb->conversation->rx_handler = purple_input_add(source, - PURPLE_INPUT_READ, _client_socket_handler, pb); - - /* This is unlikely to happen */ - if (ret < len) { - struct _stream_start_data *ss = g_new(struct _stream_start_data, 1); - ss->msg = g_strdup(stream_start + ret); - ss->tx_handler_cb = _send_data_write_cb; - bb->conversation->stream_data = ss; - /* Finish sending the stream start */ - bb->conversation->tx_handler = purple_input_add(source, - PURPLE_INPUT_WRITE, _start_stream, pb); - } - /* Process the send buffer */ - else { - bb->conversation->stream_started = TRUE; - /* Watch for when we can write the buffered messages */ - bb->conversation->tx_handler = purple_input_add(source, PURPLE_INPUT_WRITE, - _send_data_write_cb, pb); - /* We can probably write the data now. */ - _send_data_write_cb(pb, source, PURPLE_INPUT_WRITE); - } - - g_free(stream_start); } int @@ -809,7 +772,7 @@ /* Close the socket and remove the watcher */ if (bconv->socket >= 0) { /* Send the end of the stream to the other end of the conversation */ - if (bconv->stream_started) + if (bconv->sent_stream_start) send(bconv->socket, STREAM_END, strlen(STREAM_END), 0); /* TODO: We're really supposed to wait for "</stream:stream>" before closing the socket */ close(bconv->socket); @@ -828,6 +791,10 @@ g_free(ss->msg); g_free(ss); } + + if (bconv->context != NULL) + bonjour_parser_setup(bconv); + g_free(bconv); } }
--- a/libpurple/protocols/bonjour/jabber.h Tue Jul 31 23:20:56 2007 +0000 +++ b/libpurple/protocols/bonjour/jabber.h Tue Jul 31 23:23:25 2007 +0000 @@ -26,6 +26,10 @@ #ifndef _BONJOUR_JABBER_H_ #define _BONJOUR_JABBER_H_ +#include <libxml/parser.h> + +#include "xmlnode.h" + #include "account.h" #include "circbuffer.h" @@ -43,9 +47,12 @@ guint rx_handler; guint tx_handler; PurpleCircBuffer *tx_buf; - gboolean stream_started; + gboolean sent_stream_start; + gboolean recv_stream_start; PurpleProxyConnectData *connect_data; gpointer stream_data; + xmlParserCtxt *context; + xmlnode *current; } BonjourJabberConversation; /** @@ -60,6 +67,12 @@ void bonjour_jabber_close_conversation(BonjourJabberConversation *bconv); +void bonjour_jabber_stream_started(PurpleBuddy *pb); + +void bonjour_jabber_stream_ended(PurpleBuddy *pb); + +void bonjour_jabber_process_packet(PurpleBuddy *pb, xmlnode *packet); + void bonjour_jabber_stop(BonjourJabber *data); #endif /* _BONJOUR_JABBER_H_ */
--- a/libpurple/protocols/bonjour/mdns_win32.c Tue Jul 31 23:20:56 2007 +0000 +++ b/libpurple/protocols/bonjour/mdns_win32.c Tue Jul 31 23:23:25 2007 +0000 @@ -84,6 +84,8 @@ buddy->txt_query_fd = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, buddy->txt_query); bonjour_buddy_add_to_purple(buddy); + + purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", buddy->name, buddy->ip, buddy->port_p2pj); } else bonjour_buddy_delete(buddy); @@ -262,6 +264,7 @@ switch (type) { case PUBLISH_START: + purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj); err = DNSServiceRegister(&data->advertisement, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), _mdns_service_register_callback, NULL);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/parser.c Tue Jul 31 23:23:25 2007 +0000 @@ -0,0 +1,194 @@ +/* + * purple - Bonjour Jabber XML parser stuff + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "internal.h" + +#include <libxml/parser.h> + +#include "connection.h" +#include "debug.h" +#include "jabber.h" +#include "parser.h" +#include "util.h" +#include "xmlnode.h" + +static void +bonjour_parser_element_start_libxml(void *user_data, + const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, + int nb_namespaces, const xmlChar **namespaces, + int nb_attributes, int nb_defaulted, const xmlChar **attributes) +{ + PurpleBuddy *pb = user_data; + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + xmlnode *node; + int i; + + if(!element_name) { + return; + } else if(!xmlStrcmp(element_name, (xmlChar*) "stream")) { + bconv->recv_stream_start = TRUE; + bonjour_jabber_stream_started(pb); + } else { + + if(bconv->current) + node = xmlnode_new_child(bconv->current, (const char*) element_name); + else + node = xmlnode_new((const char*) element_name); + xmlnode_set_namespace(node, (const char*) namespace); + + for(i=0; i < nb_attributes * 5; i+=5) { + char *txt; + int attrib_len = attributes[i+4] - attributes[i+3]; + char *attrib = g_malloc(attrib_len + 1); + char *attrib_ns = NULL; + + if (attributes[i+2]) { + attrib_ns = g_strdup((char*)attributes[i+2]);; + } + + memcpy(attrib, attributes[i+3], attrib_len); + attrib[attrib_len] = '\0'; + + txt = attrib; + attrib = purple_unescape_html(txt); + g_free(txt); + xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib); + g_free(attrib); + g_free(attrib_ns); + } + + bconv->current = node; + } +} + +static void +bonjour_parser_element_end_libxml(void *user_data, const xmlChar *element_name, + const xmlChar *prefix, const xmlChar *namespace) +{ + PurpleBuddy *pb = user_data; + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + if(!bconv->current) { + /* We don't keep a reference to the start stream xmlnode, + * so we have to check for it here to close the conversation */ + if(!xmlStrcmp(element_name, (xmlChar*) "stream")) { + bonjour_jabber_stream_ended(pb); + } + return; + } + + if(bconv->current->parent) { + if(!xmlStrcmp((xmlChar*) bconv->current->name, element_name)) + bconv->current = bconv->current->parent; + } else { + xmlnode *packet = bconv->current; + bconv->current = NULL; + bonjour_jabber_process_packet(pb, packet); + xmlnode_free(packet); + } +} + +static void +bonjour_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) +{ + PurpleBuddy *pb = user_data; + BonjourBuddy *bb = pb->proto_data; + BonjourJabberConversation *bconv = bb->conversation; + + if(!bconv->current) + return; + + if(!text || !text_len) + return; + + xmlnode_insert_data(bconv->current, (const char*) text, text_len); +} + +static xmlSAXHandler bonjour_parser_libxml = { + .internalSubset = NULL, + .isStandalone = NULL, + .hasInternalSubset = NULL, + .hasExternalSubset = NULL, + .resolveEntity = NULL, + .getEntity = NULL, + .entityDecl = NULL, + .notationDecl = NULL, + .attributeDecl = NULL, + .elementDecl = NULL, + .unparsedEntityDecl = NULL, + .setDocumentLocator = NULL, + .startDocument = NULL, + .endDocument = NULL, + .startElement = NULL, + .endElement = NULL, + .reference = NULL, + .characters = bonjour_parser_element_text_libxml, + .ignorableWhitespace = NULL, + .processingInstruction = NULL, + .comment = NULL, + .warning = NULL, + .error = NULL, + .fatalError = NULL, + .getParameterEntity = NULL, + .cdataBlock = NULL, + .externalSubset = NULL, + .initialized = XML_SAX2_MAGIC, + ._private = NULL, + .startElementNs = bonjour_parser_element_start_libxml, + .endElementNs = bonjour_parser_element_end_libxml, + .serror = NULL +}; + +void +bonjour_parser_setup(BonjourJabberConversation *bconv) +{ + + /* This seems backwards, but it makes sense. The libxml code creates + * the parser context when you try to use it (this way, it can figure + * out the encoding at creation time. So, setting up the parser is + * just a matter of destroying any current parser. */ + if (bconv->context) { + xmlParseChunk(bconv->context, NULL,0,1); + xmlFreeParserCtxt(bconv->context); + bconv->context = NULL; + } +} + + +void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len) +{ + BonjourBuddy *bb = pb->proto_data; + + if (bb->conversation->context == NULL) { + /* libxml inconsistently starts parsing on creating the + * parser, so do a ParseChunk right afterwards to force it. */ + bb->conversation->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, pb, buf, len, NULL); + xmlParseChunk(bb->conversation->context, "", 0, 0); + } else if (xmlParseChunk(bb->conversation->context, buf, len, 0) < 0) { + /* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */ + purple_debug_error("bonjour", "Error parsing xml.\n"); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/bonjour/parser.h Tue Jul 31 23:23:25 2007 +0000 @@ -0,0 +1,33 @@ +/** + * @file parser.h Bonjour Jabber XML parser functions + * + * purple + * + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * source distribution. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _PURPLE_BONJOUR_PARSER_H_ +#define _PURPLE_BONJOUR_PARSER_H_ + +#include "buddy.h" +#include "jabber.h" + +void bonjour_parser_setup(BonjourJabberConversation *bconv); +void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len); + +#endif /* _PURPLE_BONJOUR_PARSER_H_ */