Mercurial > pidgin
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 |