Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / bonjour / parser.c
blob1b571820b342f4c4c4fd5a78c92ac90db1caadad
1 /*
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
6 * source distribution.
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
23 #include "internal.h"
24 #include <purple.h>
26 #include <libxml/parser.h>
28 #include "jabber.h"
29 #include "parser.h"
31 static gboolean
32 parse_from_attrib_and_find_buddy(BonjourJabberConversation *bconv, int nb_attributes, const xmlChar **attributes) {
33 int i;
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);
46 return FALSE;
49 static void
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;
57 PurpleXmlNode *node;
58 int i;
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);
71 } else {
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. */
75 if(bconv->pb == NULL
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
81 by using the IP */
82 bonjour_jabber_conv_match_by_ip(bconv);
84 if(bconv->current)
85 node = purple_xmlnode_new_child(bconv->current, (const char*) element_name);
86 else
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];
94 char *txt;
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';
101 txt = attrib;
102 attrib = purple_unescape_text(txt);
103 g_free(txt);
104 purple_xmlnode_set_attrib_full(node, name, attrib_ns, prefix, attrib);
105 g_free(attrib);
108 bconv->current = node;
112 static void
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);
125 return;
128 if(bconv->current->parent) {
129 if(!xmlStrcmp((xmlChar*) bconv->current->name, element_name))
130 bconv->current = bconv->current->parent;
131 } else {
132 PurpleXmlNode *packet = bconv->current;
133 bconv->current = NULL;
134 bonjour_jabber_process_packet(bconv->pb, packet);
135 purple_xmlnode_free(packet);
139 static void
140 bonjour_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len)
142 BonjourJabberConversation *bconv = user_data;
144 if(!bconv->current)
145 return;
147 if(!text || !text_len)
148 return;
150 purple_xmlnode_insert_data(bconv->current, (const char*) text, text_len);
153 static void
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",
160 bconv,
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*/
171 NULL, /*getEntity*/
172 NULL, /*entityDecl*/
173 NULL, /*notationDecl*/
174 NULL, /*attributeDecl*/
175 NULL, /*elementDecl*/
176 NULL, /*unparsedEntityDecl*/
177 NULL, /*setDocumentLocator*/
178 NULL, /*startDocument*/
179 NULL, /*endDocument*/
180 NULL, /*startElement*/
181 NULL, /*endElement*/
182 NULL, /*reference*/
183 bonjour_parser_element_text_libxml, /*characters*/
184 NULL, /*ignorableWhitespace*/
185 NULL, /*processingInstruction*/
186 NULL, /*comment*/
187 NULL, /*warning*/
188 NULL, /*error*/
189 NULL, /*fatalError*/
190 NULL, /*getParameterEntity*/
191 NULL, /*cdataBlock*/
192 NULL, /*externalSubset*/
193 XML_SAX2_MAGIC, /*initialized*/
194 NULL, /*_private*/
195 bonjour_parser_element_start_libxml, /*startElementNs*/
196 bonjour_parser_element_end_libxml, /*endElementNs*/
197 bonjour_parser_structured_error_handler /*serror*/
200 void
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");