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
26 #include <libxml/parser.h>
32 parse_from_attrib_and_find_buddy(BonjourJabberConversation
*bconv
, int nb_attributes
, const xmlChar
**attributes
) {
35 /* If the "from" attribute is specified, attach it to the conversation. */
36 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
37 if(!xmlStrcmp(attributes
[i
], (xmlChar
*) "from")) {
38 int len
= attributes
[i
+4] - attributes
[i
+3];
39 bconv
->buddy_name
= g_strndup((char *)attributes
[i
+3], len
);
40 bonjour_jabber_conv_match_by_name(bconv
);
42 return (bconv
->pb
!= NULL
);
50 bonjour_parser_element_start_libxml(void *user_data
,
51 const xmlChar
*element_name
, const xmlChar
*prefix
, const xmlChar
*namespace,
52 int nb_namespaces
, const xmlChar
**namespaces
,
53 int nb_attributes
, int nb_defaulted
, const xmlChar
**attributes
)
55 BonjourJabberConversation
*bconv
= user_data
;
60 g_return_if_fail(element_name
!= NULL
);
62 if(!xmlStrcmp(element_name
, (xmlChar
*) "stream")) {
63 if(!bconv
->recv_stream_start
) {
64 bconv
->recv_stream_start
= TRUE
;
66 if (bconv
->pb
== NULL
)
67 parse_from_attrib_and_find_buddy(bconv
, nb_attributes
, attributes
);
69 bonjour_jabber_stream_started(bconv
);
73 /* If we haven't yet attached a buddy and this isn't "<stream:features />",
74 * try to get a "from" attribute as a last resort to match our buddy. */
76 && !(prefix
&& !xmlStrcmp(prefix
, (xmlChar
*) "stream")
77 && !xmlStrcmp(element_name
, (xmlChar
*) "features"))
78 && !parse_from_attrib_and_find_buddy(bconv
, nb_attributes
, attributes
))
79 /* We've run out of options for finding who the conversation is from
80 using explicitly specified stuff; see if we can make a good match
82 bonjour_jabber_conv_match_by_ip(bconv
);
85 node
= purple_xmlnode_new_child(bconv
->current
, (const char*) element_name
);
87 node
= purple_xmlnode_new((const char*) element_name
);
88 purple_xmlnode_set_namespace(node
, (const char*) namespace);
90 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
91 const char *name
= (const char *)attributes
[i
];
92 const char *prefix
= (const char *)attributes
[i
+1];
93 const char *attrib_ns
= (const char *)attributes
[i
+2];
95 int attrib_len
= attributes
[i
+4] - attributes
[i
+3];
96 char *attrib
= g_malloc(attrib_len
+ 1);
98 memcpy(attrib
, attributes
[i
+3], attrib_len
);
99 attrib
[attrib_len
] = '\0';
102 attrib
= purple_unescape_text(txt
);
104 purple_xmlnode_set_attrib_full(node
, name
, attrib_ns
, prefix
, attrib
);
108 bconv
->current
= node
;
113 bonjour_parser_element_end_libxml(void *user_data
, const xmlChar
*element_name
,
114 const xmlChar
*prefix
, const xmlChar
*namespace)
116 BonjourJabberConversation
*bconv
= user_data
;
118 if(!bconv
->current
) {
119 /* We don't keep a reference to the start stream PurpleXmlNode,
120 * so we have to check for it here to close the conversation */
121 if(!xmlStrcmp(element_name
, (xmlChar
*) "stream"))
122 /* Asynchronously close the conversation to prevent bonjour_parser_setup()
123 * being called from within this context */
124 async_bonjour_jabber_close_conversation(bconv
);
128 if(bconv
->current
->parent
) {
129 if(!xmlStrcmp((xmlChar
*) bconv
->current
->name
, element_name
))
130 bconv
->current
= bconv
->current
->parent
;
132 PurpleXmlNode
*packet
= bconv
->current
;
133 bconv
->current
= NULL
;
134 bonjour_jabber_process_packet(bconv
->pb
, packet
);
135 purple_xmlnode_free(packet
);
140 bonjour_parser_element_text_libxml(void *user_data
, const xmlChar
*text
, int text_len
)
142 BonjourJabberConversation
*bconv
= user_data
;
147 if(!text
|| !text_len
)
150 purple_xmlnode_insert_data(bconv
->current
, (const char*) text
, text_len
);
154 bonjour_parser_structured_error_handler(void *user_data
, xmlErrorPtr error
)
156 BonjourJabberConversation
*bconv
= user_data
;
158 purple_debug_error("jabber", "XML parser error for BonjourJabberConversation %p: "
159 "Domain %i, code %i, level %i: %s",
161 error
->domain
, error
->code
, error
->level
,
162 (error
->message
? error
->message
: "(null)\n"));
165 static xmlSAXHandler bonjour_parser_libxml
= {
166 NULL
, /*internalSubset*/
167 NULL
, /*isStandalone*/
168 NULL
, /*hasInternalSubset*/
169 NULL
, /*hasExternalSubset*/
170 NULL
, /*resolveEntity*/
173 NULL
, /*notationDecl*/
174 NULL
, /*attributeDecl*/
175 NULL
, /*elementDecl*/
176 NULL
, /*unparsedEntityDecl*/
177 NULL
, /*setDocumentLocator*/
178 NULL
, /*startDocument*/
179 NULL
, /*endDocument*/
180 NULL
, /*startElement*/
183 bonjour_parser_element_text_libxml
, /*characters*/
184 NULL
, /*ignorableWhitespace*/
185 NULL
, /*processingInstruction*/
190 NULL
, /*getParameterEntity*/
192 NULL
, /*externalSubset*/
193 XML_SAX2_MAGIC
, /*initialized*/
195 bonjour_parser_element_start_libxml
, /*startElementNs*/
196 bonjour_parser_element_end_libxml
, /*endElementNs*/
197 bonjour_parser_structured_error_handler
/*serror*/
201 bonjour_parser_setup(BonjourJabberConversation
*bconv
)
204 /* This seems backwards, but it makes sense. The libxml code creates
205 * the parser context when you try to use it (this way, it can figure
206 * out the encoding at creation time. So, setting up the parser is
207 * just a matter of destroying any current parser. */
208 if (bconv
->context
) {
209 xmlParseChunk(bconv
->context
, NULL
,0,1);
210 xmlFreeParserCtxt(bconv
->context
);
211 bconv
->context
= NULL
;
216 void bonjour_parser_process(BonjourJabberConversation
*bconv
, const char *buf
, int len
)
219 if (bconv
->context
== NULL
) {
220 /* libxml inconsistently starts parsing on creating the
221 * parser, so do a ParseChunk right afterwards to force it. */
222 bconv
->context
= xmlCreatePushParserCtxt(&bonjour_parser_libxml
, bconv
, buf
, len
, NULL
);
223 xmlParseChunk(bconv
->context
, "", 0, 0);
224 } else if (xmlParseChunk(bconv
->context
, buf
, len
, 0) < 0)
225 /* TODO: What should we do here - I assume we should display an error or something (maybe just print something to the conv?) */
226 purple_debug_error("bonjour", "Error parsing xml.\n");