libpurple/protocols/jabber/parser.c

branch
cpw.khc.msnp14
changeset 20478
46933dc62880
parent 20472
6a6d2ef151e6
parent 15884
4de1981757fc
child 20481
65485e2ed8a3
equal deleted inserted replaced
20476:198222e01a7d 20478:46933dc62880
1 /*
2 * purple - Jabber XML parser stuff
3 *
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 #include "internal.h"
22
23 #include <libxml/parser.h>
24
25 #include "connection.h"
26 #include "debug.h"
27 #include "jabber.h"
28 #include "parser.h"
29 #include "util.h"
30 #include "xmlnode.h"
31
32 static void
33 jabber_parser_element_start_libxml(void *user_data,
34 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace,
35 int nb_namespaces, const xmlChar **namespaces,
36 int nb_attributes, int nb_defaulted, const xmlChar **attributes)
37 {
38 JabberStream *js = user_data;
39 xmlnode *node;
40 int i;
41
42 if(!element_name) {
43 return;
44 } else if(!xmlStrcmp(element_name, (xmlChar*) "stream")) {
45 js->protocol_version = JABBER_PROTO_0_9;
46 for(i=0; i < nb_attributes * 5; i += 5) {
47 int attrib_len = attributes[i+4] - attributes[i+3];
48 char *attrib = g_malloc(attrib_len + 1);
49 memcpy(attrib, attributes[i+3], attrib_len);
50 attrib[attrib_len] = '\0';
51
52 if(!xmlStrcmp(attributes[i], (xmlChar*) "version")
53 && !strcmp(attrib, "1.0")) {
54 js->protocol_version = JABBER_PROTO_1_0;
55 g_free(attrib);
56 } else if(!xmlStrcmp(attributes[i], (xmlChar*) "id")) {
57 g_free(js->stream_id);
58 js->stream_id = attrib;
59 } else {
60 g_free(attrib);
61 }
62 }
63 if(js->protocol_version == JABBER_PROTO_0_9)
64 js->auth_type = JABBER_AUTH_IQ_AUTH;
65
66 if(js->state == JABBER_STREAM_INITIALIZING)
67 jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);
68 } else {
69
70 if(js->current)
71 node = xmlnode_new_child(js->current, (const char*) element_name);
72 else
73 node = xmlnode_new((const char*) element_name);
74 xmlnode_set_namespace(node, (const char*) namespace);
75
76 for(i=0; i < nb_attributes * 5; i+=5) {
77 char *txt;
78 int attrib_len = attributes[i+4] - attributes[i+3];
79 char *attrib = g_malloc(attrib_len + 1);
80 char *attrib_ns = NULL;
81
82 if (attributes[i+2]) {
83 attrib_ns = g_strdup((char*)attributes[i+2]);;
84 }
85
86 memcpy(attrib, attributes[i+3], attrib_len);
87 attrib[attrib_len] = '\0';
88
89 txt = attrib;
90 attrib = purple_unescape_html(txt);
91 g_free(txt);
92 xmlnode_set_attrib_with_namespace(node, (const char*) attributes[i], attrib_ns, attrib);
93 g_free(attrib);
94 g_free(attrib_ns);
95 }
96
97 js->current = node;
98 }
99 }
100
101 static void
102 jabber_parser_element_end_libxml(void *user_data, const xmlChar *element_name,
103 const xmlChar *prefix, const xmlChar *namespace)
104 {
105 JabberStream *js = user_data;
106
107 if(!js->current)
108 return;
109
110 if(js->current->parent) {
111 if(!xmlStrcmp((xmlChar*) js->current->name, element_name))
112 js->current = js->current->parent;
113 } else {
114 xmlnode *packet = js->current;
115 js->current = NULL;
116 jabber_process_packet(js, packet);
117 xmlnode_free(packet);
118 }
119 }
120
121 static void
122 jabber_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
123 {
124 JabberStream *js = user_data;
125
126 if(!js->current)
127 return;
128
129 if(!text || !text_len)
130 return;
131
132 xmlnode_insert_data(js->current, (const char*) text, text_len);
133 }
134
135 static xmlSAXHandler jabber_parser_libxml = {
136 .internalSubset = NULL,
137 .isStandalone = NULL,
138 .hasInternalSubset = NULL,
139 .hasExternalSubset = NULL,
140 .resolveEntity = NULL,
141 .getEntity = NULL,
142 .entityDecl = NULL,
143 .notationDecl = NULL,
144 .attributeDecl = NULL,
145 .elementDecl = NULL,
146 .unparsedEntityDecl = NULL,
147 .setDocumentLocator = NULL,
148 .startDocument = NULL,
149 .endDocument = NULL,
150 .startElement = NULL,
151 .endElement = NULL,
152 .reference = NULL,
153 .characters = jabber_parser_element_text_libxml,
154 .ignorableWhitespace = NULL,
155 .processingInstruction = NULL,
156 .comment = NULL,
157 .warning = NULL,
158 .error = NULL,
159 .fatalError = NULL,
160 .getParameterEntity = NULL,
161 .cdataBlock = NULL,
162 .externalSubset = NULL,
163 .initialized = XML_SAX2_MAGIC,
164 ._private = NULL,
165 .startElementNs = jabber_parser_element_start_libxml,
166 .endElementNs = jabber_parser_element_end_libxml,
167 .serror = NULL
168 };
169
170 void
171 jabber_parser_setup(JabberStream *js)
172 {
173 /* This seems backwards, but it makes sense. The libxml code creates
174 * the parser context when you try to use it (this way, it can figure
175 * out the encoding at creation time. So, setting up the parser is
176 * just a matter of destroying any current parser. */
177 if (js->context) {
178 xmlParseChunk(js->context, NULL,0,1);
179 xmlFreeParserCtxt(js->context);
180 js->context = NULL;
181 }
182 }
183
184
185 void jabber_parser_process(JabberStream *js, const char *buf, int len)
186 {
187 if (js->context == NULL) {
188 /* libxml inconsistently starts parsing on creating the
189 * parser, so do a ParseChunk right afterwards to force it. */
190 js->context = xmlCreatePushParserCtxt(&jabber_parser_libxml, js, buf, len, NULL);
191 xmlParseChunk(js->context, "", 0, 0);
192 } else if (xmlParseChunk(js->context, buf, len, 0) < 0) {
193 purple_connection_error(js->gc, _("XML Parse error"));
194 }
195 }
196

mercurial