Mercurial > pidgin
comparison src/protocols/jabber/parser.c @ 13806:25e63008d3bb
[gaim-migrate @ 16229]
Use libxml2 for XML parsing, if available. The biggest benefit from this is actual support for XML namespaces. This fixes a handful of Google Talk integration problems, including typing notifications and buddy icons.
committer: Tailor Script <tailor@pidgin.im>
| author | Sean Egan <seanegan@gmail.com> |
|---|---|
| date | Thu, 08 Jun 2006 01:03:51 +0000 |
| parents | dd6fe7d965aa |
| children |
comparison
equal
deleted
inserted
replaced
| 13805:853fefb07c79 | 13806:25e63008d3bb |
|---|---|
| 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 * | 19 * |
| 20 */ | 20 */ |
| 21 #include "internal.h" | 21 #include "internal.h" |
| 22 | 22 |
| 23 #ifdef HAVE_LIBXML | |
| 24 #include <libxml/parser.h> | |
| 25 #endif | |
| 26 | |
| 23 #include "connection.h" | 27 #include "connection.h" |
| 24 | 28 #include "debug.h" |
| 25 #include "jabber.h" | 29 #include "jabber.h" |
| 26 #include "parser.h" | 30 #include "parser.h" |
| 27 #include "xmlnode.h" | 31 #include "xmlnode.h" |
| 28 | 32 |
| 33 #ifndef HAVE_LIBXML | |
| 29 static void | 34 static void |
| 30 jabber_parser_element_start(GMarkupParseContext *context, | 35 jabber_parser_element_start(GMarkupParseContext *context, |
| 31 const char *element_name, const char **attrib_names, | 36 const char *element_name, const char **attrib_names, |
| 32 const char **attrib_values, gpointer user_data, GError **error) | 37 const char **attrib_values, gpointer user_data, GError **error) |
| 33 { | 38 { |
| 102 return; | 107 return; |
| 103 | 108 |
| 104 xmlnode_insert_data(js->current, text, text_len); | 109 xmlnode_insert_data(js->current, text, text_len); |
| 105 } | 110 } |
| 106 | 111 |
| 112 #else /* HAVE_LIBXML */ | |
| 113 | |
| 114 static void | |
| 115 jabber_parser_element_start_libxml(void *user_data, | |
| 116 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, | |
| 117 int nb_namespaces, const xmlChar **namespaces, | |
| 118 int nb_attributes, int nb_defaulted, const xmlChar **attributes) | |
| 119 { | |
| 120 JabberStream *js = user_data; | |
| 121 xmlnode *node; | |
| 122 int i; | |
| 123 | |
| 124 if(!element_name) { | |
| 125 return; | |
| 126 } else if(!strcmp(element_name, "stream")) { | |
| 127 js->protocol_version = JABBER_PROTO_0_9; | |
| 128 for(i=0; i < nb_attributes * 5; i += 5) { | |
| 129 int attrib_len = attributes[i+4] - attributes[i+3]; | |
| 130 char *attrib = g_malloc(attrib_len + 1); | |
| 131 memcpy(attrib, attributes[i+3], attrib_len); | |
| 132 attrib[attrib_len] = '\0'; | |
| 133 | |
| 134 if(!strcmp(attributes[i], "version") | |
| 135 && !strcmp(attrib, "1.0")) { | |
| 136 js->protocol_version = JABBER_PROTO_1_0; | |
| 137 } else if(!strcmp(attributes[i], "id")) { | |
| 138 if(js->stream_id) | |
| 139 g_free(js->stream_id); | |
| 140 js->stream_id = g_strdup(attrib); | |
| 141 } | |
| 142 g_free(attrib); | |
| 143 } | |
| 144 if(js->protocol_version == JABBER_PROTO_0_9) | |
| 145 js->auth_type = JABBER_AUTH_IQ_AUTH; | |
| 146 | |
| 147 if(js->state == JABBER_STREAM_INITIALIZING) | |
| 148 jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING); | |
| 149 } else { | |
| 150 | |
| 151 if(js->current) | |
| 152 node = xmlnode_new_child(js->current, element_name); | |
| 153 else | |
| 154 node = xmlnode_new(element_name); | |
| 155 xmlnode_set_namespace(node, namespace); | |
| 156 | |
| 157 for(i=0; i < nb_attributes * 5; i+=5) { | |
| 158 int attrib_len = attributes[i+4] - attributes[i+3]; | |
| 159 char *attrib = g_malloc(attrib_len + 1); | |
| 160 memcpy(attrib, attributes[i+3], attrib_len); | |
| 161 attrib[attrib_len] = '\0'; | |
| 162 xmlnode_set_attrib(node, attributes[i], attrib); | |
| 163 g_free(attrib); | |
| 164 } | |
| 165 | |
| 166 js->current = node; | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 static void | |
| 171 jabber_parser_element_end_libxml(void *user_data, const xmlChar *element_name, | |
| 172 const xmlChar *prefix, const xmlChar *namespace) | |
| 173 { | |
| 174 JabberStream *js = user_data; | |
| 175 | |
| 176 if(!js->current) | |
| 177 return; | |
| 178 | |
| 179 if(js->current->parent) { | |
| 180 if(!strcmp(js->current->name, element_name)) | |
| 181 js->current = js->current->parent; | |
| 182 } else { | |
| 183 xmlnode *packet = js->current; | |
| 184 js->current = NULL; | |
| 185 jabber_process_packet(js, packet); | |
| 186 xmlnode_free(packet); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 static void | |
| 191 jabber_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) | |
| 192 { | |
| 193 JabberStream *js = user_data; | |
| 194 | |
| 195 if(!js->current) | |
| 196 return; | |
| 197 | |
| 198 if(!text || !text_len) | |
| 199 return; | |
| 200 | |
| 201 xmlnode_insert_data(js->current, text, text_len); | |
| 202 } | |
| 203 #endif /* HAVE_LIBXML */ | |
| 204 | |
| 205 | |
| 206 #ifdef HAVE_LIBXML | |
| 207 static xmlSAXHandler jabber_parser_libxml = { | |
| 208 .internalSubset = NULL, | |
| 209 .isStandalone = NULL, | |
| 210 .hasInternalSubset = NULL, | |
| 211 .hasExternalSubset = NULL, | |
| 212 .resolveEntity = NULL, | |
| 213 .getEntity = NULL, | |
| 214 .entityDecl = NULL, | |
| 215 .notationDecl = NULL, | |
| 216 .attributeDecl = NULL, | |
| 217 .elementDecl = NULL, | |
| 218 .unparsedEntityDecl = NULL, | |
| 219 .setDocumentLocator = NULL, | |
| 220 .startDocument = NULL, | |
| 221 .endDocument = NULL, | |
| 222 .startElement = NULL, | |
| 223 .endElement = NULL, | |
| 224 .reference = NULL, | |
| 225 .characters = jabber_parser_element_text_libxml, | |
| 226 .ignorableWhitespace = NULL, | |
| 227 .processingInstruction = NULL, | |
| 228 .comment = NULL, | |
| 229 .warning = NULL, | |
| 230 .error = NULL, | |
| 231 .fatalError = NULL, | |
| 232 .getParameterEntity = NULL, | |
| 233 .cdataBlock = NULL, | |
| 234 .externalSubset = NULL, | |
| 235 .initialized = XML_SAX2_MAGIC, | |
| 236 ._private = NULL, | |
| 237 .startElementNs = jabber_parser_element_start_libxml, | |
| 238 .endElementNs = jabber_parser_element_end_libxml, | |
| 239 .serror = NULL | |
| 240 }; | |
| 241 #else | |
| 107 static GMarkupParser jabber_parser = { | 242 static GMarkupParser jabber_parser = { |
| 108 jabber_parser_element_start, | 243 jabber_parser_element_start, |
| 109 jabber_parser_element_end, | 244 jabber_parser_element_end, |
| 110 jabber_parser_element_text, | 245 jabber_parser_element_text, |
| 111 NULL, | 246 NULL, |
| 112 NULL | 247 NULL |
| 113 }; | 248 }; |
| 249 #endif | |
| 114 | 250 |
| 115 void | 251 void |
| 116 jabber_parser_setup(JabberStream *js) | 252 jabber_parser_setup(JabberStream *js) |
| 117 { | 253 { |
| 254 #ifdef HAVE_LIBXML | |
| 255 /* This seems backwards, but it makes sense. The libxml code creates the parser | |
| 256 * context when you try to use it (this way, it can figure out the encoding at | |
| 257 * creation time. So, setting up the parser is just a matter of destroying any | |
| 258 * current parser. */ | |
| 259 if (js->context) { | |
| 260 xmlParseChunk(js->context, NULL,0,1); | |
| 261 xmlFreeParserCtxt(js->context); | |
| 262 js->context = NULL; | |
| 263 } | |
| 264 #else | |
| 118 if(!js->context) | 265 if(!js->context) |
| 119 js->context = g_markup_parse_context_new(&jabber_parser, 0, js, NULL); | 266 js->context = g_markup_parse_context_new(&jabber_parser, 0, js, NULL); |
| 267 #endif | |
| 120 } | 268 } |
| 121 | 269 |
| 122 | 270 |
| 123 void jabber_parser_process(JabberStream *js, const char *buf, int len) | 271 void jabber_parser_process(JabberStream *js, const char *buf, int len) |
| 124 { | 272 { |
| 125 | 273 |
| 274 #ifndef HAVE_LIBXML | |
| 126 /* May need to check for other encodings and do the conversion here */ | 275 /* May need to check for other encodings and do the conversion here */ |
| 127 | |
| 128 if(!g_markup_parse_context_parse(js->context, buf, len, NULL)) { | 276 if(!g_markup_parse_context_parse(js->context, buf, len, NULL)) { |
| 129 g_markup_parse_context_free(js->context); | 277 g_markup_parse_context_free(js->context); |
| 130 js->context = NULL; | 278 js->context = NULL; |
| 131 gaim_connection_error(js->gc, _("XML Parse error")); | 279 gaim_connection_error(js->gc, _("XML Parse error")); |
| 132 } | 280 } |
| 133 } | 281 #else |
| 134 | 282 if (js->context == NULL) { |
| 283 /* libxml inconsistently starts parsing on creating the parser, so so a ParseChunk | |
| 284 * right afterwards to force it. */ | |
| 285 js->context = xmlCreatePushParserCtxt(&jabber_parser_libxml, js, buf, len, NULL); | |
| 286 xmlParseChunk(js->context, NULL, 0, 0); | |
| 287 } else if (xmlParseChunk(js->context, buf, len, 0) < 0) { | |
| 288 gaim_connection_error(js->gc, _("XML Parse error")); | |
| 289 } | |
| 290 #endif | |
| 291 } | |
| 292 |
