comparison libpurple/protocols/bonjour/parser.c @ 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
children 6e3cd5e80420
comparison
equal deleted inserted replaced
18760:bf47d0401a96 18761:316be7e715c6
1 /*
2 * purple - Bonjour Jabber XML parser stuff
3 *
4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23 #include "internal.h"
24
25 #include <libxml/parser.h>
26
27 #include "connection.h"
28 #include "debug.h"
29 #include "jabber.h"
30 #include "parser.h"
31 #include "util.h"
32 #include "xmlnode.h"
33
34 static void
35 bonjour_parser_element_start_libxml(void *user_data,
36 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace,
37 int nb_namespaces, const xmlChar **namespaces,
38 int nb_attributes, int nb_defaulted, const xmlChar **attributes)
39 {
40 PurpleBuddy *pb = user_data;
41 BonjourBuddy *bb = pb->proto_data;
42 BonjourJabberConversation *bconv = bb->conversation;
43
44 xmlnode *node;
45 int i;
46
47 if(!element_name) {
48 return;
49 } else if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
50 bconv->recv_stream_start = TRUE;
51 bonjour_jabber_stream_started(pb);
52 } else {
53
54 if(bconv->current)
55 node = xmlnode_new_child(bconv->current, (const char*) element_name);
56 else
57 node = xmlnode_new((const char*) element_name);
58 xmlnode_set_namespace(node, (const char*) namespace);
59
60 for(i=0; i < nb_attributes * 5; i+=5) {
61 char *txt;
62 int attrib_len = attributes[i+4] - attributes[i+3];
63 char *attrib = g_malloc(attrib_len + 1);
64 char *attrib_ns = NULL;
65
66 if (attributes[i+2]) {
67 attrib_ns = g_strdup((char*)attributes[i+2]);;
68 }
69
70 memcpy(attrib, attributes[i+3], attrib_len);
71 attrib[attrib_len] = '\0';
72
73 txt = attrib;
74 attrib = purple_unescape_html(txt);
75 g_free(txt);
76 xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
77 g_free(attrib);
78 g_free(attrib_ns);
79 }
80
81 bconv->current = node;
82 }
83 }
84
85 static void
86 bonjour_parser_element_end_libxml(void *user_data, const xmlChar *element_name,
87 const xmlChar *prefix, const xmlChar *namespace)
88 {
89 PurpleBuddy *pb = user_data;
90 BonjourBuddy *bb = pb->proto_data;
91 BonjourJabberConversation *bconv = bb->conversation;
92
93 if(!bconv->current) {
94 /* We don't keep a reference to the start stream xmlnode,
95 * so we have to check for it here to close the conversation */
96 if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
97 bonjour_jabber_stream_ended(pb);
98 }
99 return;
100 }
101
102 if(bconv->current->parent) {
103 if(!xmlStrcmp((xmlChar*) bconv->current->name, element_name))
104 bconv->current = bconv->current->parent;
105 } else {
106 xmlnode *packet = bconv->current;
107 bconv->current = NULL;
108 bonjour_jabber_process_packet(pb, packet);
109 xmlnode_free(packet);
110 }
111 }
112
113 static void
114 bonjour_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
115 {
116 PurpleBuddy *pb = user_data;
117 BonjourBuddy *bb = pb->proto_data;
118 BonjourJabberConversation *bconv = bb->conversation;
119
120 if(!bconv->current)
121 return;
122
123 if(!text || !text_len)
124 return;
125
126 xmlnode_insert_data(bconv->current, (const char*) text, text_len);
127 }
128
129 static xmlSAXHandler bonjour_parser_libxml = {
130 .internalSubset = NULL,
131 .isStandalone = NULL,
132 .hasInternalSubset = NULL,
133 .hasExternalSubset = NULL,
134 .resolveEntity = NULL,
135 .getEntity = NULL,
136 .entityDecl = NULL,
137 .notationDecl = NULL,
138 .attributeDecl = NULL,
139 .elementDecl = NULL,
140 .unparsedEntityDecl = NULL,
141 .setDocumentLocator = NULL,
142 .startDocument = NULL,
143 .endDocument = NULL,
144 .startElement = NULL,
145 .endElement = NULL,
146 .reference = NULL,
147 .characters = bonjour_parser_element_text_libxml,
148 .ignorableWhitespace = NULL,
149 .processingInstruction = NULL,
150 .comment = NULL,
151 .warning = NULL,
152 .error = NULL,
153 .fatalError = NULL,
154 .getParameterEntity = NULL,
155 .cdataBlock = NULL,
156 .externalSubset = NULL,
157 .initialized = XML_SAX2_MAGIC,
158 ._private = NULL,
159 .startElementNs = bonjour_parser_element_start_libxml,
160 .endElementNs = bonjour_parser_element_end_libxml,
161 .serror = NULL
162 };
163
164 void
165 bonjour_parser_setup(BonjourJabberConversation *bconv)
166 {
167
168 /* This seems backwards, but it makes sense. The libxml code creates
169 * the parser context when you try to use it (this way, it can figure
170 * out the encoding at creation time. So, setting up the parser is
171 * just a matter of destroying any current parser. */
172 if (bconv->context) {
173 xmlParseChunk(bconv->context, NULL,0,1);
174 xmlFreeParserCtxt(bconv->context);
175 bconv->context = NULL;
176 }
177 }
178
179
180 void bonjour_parser_process(PurpleBuddy *pb, const char *buf, int len)
181 {
182 BonjourBuddy *bb = pb->proto_data;
183
184 if (bb->conversation->context == NULL) {
185 /* libxml inconsistently starts parsing on creating the
186 * parser, so do a ParseChunk right afterwards to force it. */
187 bb->conversation->context = xmlCreatePushParserCtxt(&bonjour_parser_libxml, pb, buf, len, NULL);
188 xmlParseChunk(bb->conversation->context, "", 0, 0);
189 } else if (xmlParseChunk(bb->conversation->context, buf, len, 0) < 0) {
190 /* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */
191 purple_debug_error("bonjour", "Error parsing xml.\n");
192 }
193 }
194