2 * purple - Bonjour Jabber XML parser stuff
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
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include <libxml/parser.h>
27 #include "connection.h"
35 parse_from_attrib_and_find_buddy(BonjourJabberConversation
*bconv
, int nb_attributes
, const xmlChar
**attributes
) {
38 /* If the "from" attribute is specified, attach it to the conversation. */
39 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
40 if(!xmlStrcmp(attributes
[i
], (xmlChar
*) "from")) {
41 int len
= attributes
[i
+4] - attributes
[i
+3];
42 bconv
->buddy_name
= g_strndup((char *)attributes
[i
+3], len
);
43 bonjour_jabber_conv_match_by_name(bconv
);
45 return (bconv
->pb
!= NULL
);
53 bonjour_parser_element_start_libxml(void *user_data
,
54 const xmlChar
*element_name
, const xmlChar
*prefix
, const xmlChar
*namespace,
55 int nb_namespaces
, const xmlChar
**namespaces
,
56 int nb_attributes
, int nb_defaulted
, const xmlChar
**attributes
)
58 BonjourJabberConversation
*bconv
= user_data
;
63 g_return_if_fail(element_name
!= NULL
);
65 if(!xmlStrcmp(element_name
, (xmlChar
*) "stream")) {
66 if(!bconv
->recv_stream_start
) {
67 bconv
->recv_stream_start
= TRUE
;
69 if (bconv
->pb
== NULL
)
70 parse_from_attrib_and_find_buddy(bconv
, nb_attributes
, attributes
);
72 bonjour_jabber_stream_started(bconv
);
76 /* If we haven't yet attached a buddy and this isn't "<stream:features />",
77 * try to get a "from" attribute as a last resort to match our buddy. */
79 && !(prefix
&& !xmlStrcmp(prefix
, (xmlChar
*) "stream")
80 && !xmlStrcmp(element_name
, (xmlChar
*) "features"))
81 && !parse_from_attrib_and_find_buddy(bconv
, nb_attributes
, attributes
))
82 /* We've run out of options for finding who the conversation is from
83 using explicitly specified stuff; see if we can make a good match
85 bonjour_jabber_conv_match_by_ip(bconv
);
88 node
= purple_xmlnode_new_child(bconv
->current
, (const char*) element_name
);
90 node
= purple_xmlnode_new((const char*) element_name
);
91 purple_xmlnode_set_namespace(node
, (const char*) namespace);
93 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
94 const char *name
= (const char *)attributes
[i
];
95 const char *prefix
= (const char *)attributes
[i
+1];
96 const char *attrib_ns
= (const char *)attributes
[i
+2];
98 int attrib_len
= attributes
[i
+4] - attributes
[i
+3];
99 char *attrib
= g_malloc(attrib_len
+ 1);
101 memcpy(attrib
, attributes
[i
+3], attrib_len
);
102 attrib
[attrib_len
] = '\0';
105 attrib
= purple_unescape_text(txt
);
107 purple_xmlnode_set_attrib_full(node
, name
, attrib_ns
, prefix
, attrib
);
111 bconv
->current
= node
;
116 bonjour_parser_element_end_libxml(void *user_data
, const xmlChar
*element_name
,
117 const xmlChar
*prefix
, const xmlChar
*namespace)
119 BonjourJabberConversation
*bconv
= user_data
;
121 if(!bconv
->current
) {
122 /* We don't keep a reference to the start stream PurpleXmlNode,
123 * so we have to check for it here to close the conversation */
124 if(!xmlStrcmp(element_name
, (xmlChar
*) "stream"))
125 /* Asynchronously close the conversation to prevent bonjour_parser_setup()
126 * being called from within this context */
127 async_bonjour_jabber_close_conversation(bconv
);
131 if(bconv
->current
->parent
) {
132 if(!xmlStrcmp((xmlChar
*) bconv
->current
->name
, element_name
))
133 bconv
->current
= bconv
->current
->parent
;
135 PurpleXmlNode
*packet
= bconv
->current
;
136 bconv
->current
= NULL
;
137 bonjour_jabber_process_packet(bconv
->pb
, packet
);
138 purple_xmlnode_free(packet
);
143 bonjour_parser_element_text_libxml(void *user_data
, const xmlChar
*text
, int text_len
)
145 BonjourJabberConversation
*bconv
= user_data
;
150 if(!text
|| !text_len
)
153 purple_xmlnode_insert_data(bconv
->current
, (const char*) text
, text_len
);
157 bonjour_parser_structured_error_handler(void *user_data
, xmlErrorPtr error
)
159 BonjourJabberConversation
*bconv
= user_data
;
161 purple_debug_error("jabber", "XML parser error for BonjourJabberConversation %p: "
162 "Domain %i, code %i, level %i: %s",
164 error
->domain
, error
->code
, error
->level
,
165 (error
->message
? error
->message
: "(null)\n"));
168 static xmlSAXHandler bonjour_parser_libxml
= {
169 NULL
, /*internalSubset*/
170 NULL
, /*isStandalone*/
171 NULL
, /*hasInternalSubset*/
172 NULL
, /*hasExternalSubset*/
173 NULL
, /*resolveEntity*/
176 NULL
, /*notationDecl*/
177 NULL
, /*attributeDecl*/
178 NULL
, /*elementDecl*/
179 NULL
, /*unparsedEntityDecl*/
180 NULL
, /*setDocumentLocator*/
181 NULL
, /*startDocument*/
182 NULL
, /*endDocument*/
183 NULL
, /*startElement*/
186 bonjour_parser_element_text_libxml
, /*characters*/
187 NULL
, /*ignorableWhitespace*/
188 NULL
, /*processingInstruction*/
193 NULL
, /*getParameterEntity*/
195 NULL
, /*externalSubset*/
196 XML_SAX2_MAGIC
, /*initialized*/
198 bonjour_parser_element_start_libxml
, /*startElementNs*/
199 bonjour_parser_element_end_libxml
, /*endElementNs*/
200 bonjour_parser_structured_error_handler
/*serror*/
204 bonjour_parser_setup(BonjourJabberConversation
*bconv
)
207 /* This seems backwards, but it makes sense. The libxml code creates
208 * the parser context when you try to use it (this way, it can figure
209 * out the encoding at creation time. So, setting up the parser is
210 * just a matter of destroying any current parser. */
211 if (bconv
->context
) {
212 xmlParseChunk(bconv
->context
, NULL
,0,1);
213 xmlFreeParserCtxt(bconv
->context
);
214 bconv
->context
= NULL
;
219 void bonjour_parser_process(BonjourJabberConversation
*bconv
, const char *buf
, int len
)
222 if (bconv
->context
== NULL
) {
223 /* libxml inconsistently starts parsing on creating the
224 * parser, so do a ParseChunk right afterwards to force it. */
225 bconv
->context
= xmlCreatePushParserCtxt(&bonjour_parser_libxml
, bconv
, buf
, len
, NULL
);
226 xmlParseChunk(bconv
->context
, "", 0, 0);
227 } else if (xmlParseChunk(bconv
->context
, buf
, len
, 0) < 0)
228 /* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */
229 purple_debug_error("bonjour", "Error parsing xml.\n");