b0746d138ea35360ed4f738d6f99d354b76281d8
[platform/upstream/libsoup.git] / libsoup / soup-soap-response.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003, Novell, Inc.
4  */
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <libxml/tree.h>
9 #include "soup-misc.h"
10 #include "soup-soap-response.h"
11 #include "soup-types.h"
12
13 #define PARENT_TYPE G_TYPE_OBJECT
14
15 struct _SoupSoapResponsePrivate {
16         /* the XML document */
17         xmlDocPtr xmldoc;
18         xmlNodePtr xml_root;
19         xmlNodePtr xml_body;
20         xmlNodePtr xml_method;
21         xmlNodePtr soap_fault;
22         GList *parameters;
23 };
24
25 static GObjectClass *parent_class = NULL;
26
27 static void
28 finalize (GObject *object)
29 {
30         SoupSoapResponse *response = SOUP_SOAP_RESPONSE (object);
31
32         /* free memory */
33         if (response->priv->xmldoc) {
34                 xmlFreeDoc (response->priv->xmldoc);
35                 response->priv->xmldoc = NULL;
36         }
37
38         response->priv->xml_root = NULL;
39         response->priv->xml_body = NULL;
40         response->priv->xml_method = NULL;
41
42         if (response->priv->parameters != NULL) {
43                 g_list_free (response->priv->parameters);
44                 response->priv->parameters = NULL;
45         }
46
47         g_free (response->priv);
48         response->priv = NULL;
49
50         parent_class->finalize (object);
51 }
52
53 static void
54 class_init (SoupSoapResponseClass *klass)
55 {
56         GObjectClass *object_class;
57
58         parent_class = g_type_class_peek_parent (klass);
59
60         object_class = G_OBJECT_CLASS (klass);
61         object_class->finalize = finalize;
62 }
63
64 static void
65 init (SoupSoapResponse *response, SoupSoapResponseClass *klass)
66 {
67         response->priv = g_new0 (SoupSoapResponsePrivate, 1);
68
69         response->priv->xmldoc = xmlNewDoc ("1.0");
70 }
71
72 SOUP_MAKE_TYPE (soup_soap_response, SoupSoapResponse, class_init, init, PARENT_TYPE)
73
74 /**
75  * soup_soap_response_new:
76  *
77  * Create a new empty %SoupSoapResponse object, which can be modified with the
78  * accessor functions provided with this class.
79  *
80  * Return value: the new %SoupSoapResponse (or %NULL if there was an error).
81  */
82 SoupSoapResponse *
83 soup_soap_response_new (void)
84 {
85         SoupSoapResponse *response;
86
87         response = g_object_new (SOUP_TYPE_SOAP_RESPONSE, NULL);
88         return response;
89 }
90
91 /**
92  * soup_soap_response_new_from_string:
93  * @xmlstr: the XML string to parse.
94  *
95  * Create a new %SoupSoapResponse object from the XML string contained in
96  * @xmlstr.
97  *
98  * Return value: the new %SoupSoapResponse (or %NULL if there was an error).
99  */
100 SoupSoapResponse *
101 soup_soap_response_new_from_string (const char *xmlstr)
102 {
103         SoupSoapResponse *response;
104
105         g_return_val_if_fail (xmlstr != NULL, NULL);
106
107         response = g_object_new (SOUP_TYPE_SOAP_RESPONSE, NULL);
108         if (!soup_soap_response_from_string (response, xmlstr)) {
109                 g_object_unref (response);
110                 return NULL;
111         }
112
113         return response;
114 }
115
116 static void
117 parse_parameters (SoupSoapResponse *response, xmlNodePtr xml_method)
118 {
119         xmlNodePtr tmp;
120
121         for (tmp = xml_method->xmlChildrenNode; tmp != NULL; tmp = tmp->next) {
122                 if (!strcmp (tmp->name, "Fault")) {
123                         response->priv->soap_fault = tmp;
124                         continue;
125                 } else {
126                         /* regular parameters */
127                         response->priv->parameters = g_list_append (response->priv->parameters, tmp);
128                 }
129         }
130 }
131
132 /**
133  * soup_soap_response_from_string:
134  * @response: the %SoupSoapResponse object.
135  * @xmlstr: XML string to parse.
136  *
137  * Parses the string contained in @xmlstr and sets all properties from it in the
138  * @response object.
139  *
140  * Return value: %TRUE if successful, %FALSE otherwise.
141  */
142 gboolean
143 soup_soap_response_from_string (SoupSoapResponse *response, const char *xmlstr)
144 {
145         xmlDocPtr old_doc = NULL;
146         xmlNodePtr xml_root, xml_body = NULL, xml_method = NULL;
147
148         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), FALSE);
149         g_return_val_if_fail (xmlstr != NULL, FALSE);
150
151         /* clear the previous contents */
152         if (response->priv->xmldoc)
153                 old_doc = response->priv->xmldoc;
154
155         /* parse the string */
156         response->priv->xmldoc = xmlParseMemory (xmlstr, strlen (xmlstr));
157         if (!response->priv->xmldoc) {
158                 response->priv->xmldoc = old_doc;
159                 return FALSE;
160         }
161
162         xml_root = xmlDocGetRootElement (response->priv->xmldoc);
163         if (!xml_root) {
164                 xmlFreeDoc (response->priv->xmldoc);
165                 response->priv->xmldoc = old_doc;
166                 return FALSE;
167         }
168
169         if (strcmp (xml_root->name, "Envelope") != 0) {
170                 xmlFreeDoc (response->priv->xmldoc);
171                 response->priv->xmldoc = old_doc;
172                 return FALSE;
173         }
174
175         if (xml_root->xmlChildrenNode != NULL) {
176                 xml_body = xml_root->xmlChildrenNode;
177                 if (strcmp (xml_body->name, "Header") == 0)
178                         xml_body = xml_root->xmlChildrenNode->next;
179                 if (strcmp (xml_body->name, "Body") != 0) {
180                         xmlFreeDoc (response->priv->xmldoc);
181                         response->priv->xmldoc = old_doc;
182                         return FALSE;
183                 }
184
185                 xml_method = xml_body->xmlChildrenNode;
186
187                 /* read all parameters */
188                 if (xml_method)
189                         parse_parameters (response, xml_method);
190         }
191
192         xmlFreeDoc (old_doc);
193
194         response->priv->xml_root = xml_root;
195         response->priv->xml_body = xml_body;
196         response->priv->xml_method = xml_method;
197
198         return TRUE;
199 }
200
201 /**
202  * soup_soap_response_get_method_name:
203  * @response: the %SoupSoapResponse object.
204  *
205  * Gets the method name from the SOAP response.
206  *
207  * Return value: the method name.
208  */
209 const char *
210 soup_soap_response_get_method_name (SoupSoapResponse *response)
211 {
212         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
213         g_return_val_if_fail (response->priv->xml_method != NULL, NULL);
214
215         return (const char *) response->priv->xml_method->name;
216 }
217
218 /**
219  * soup_soap_response_set_method_name:
220  * @response: the %SoupSoapResponse object.
221  * @method_name: the method name to set.
222  *
223  * Sets the method name on the given %SoupSoapResponse.
224  */
225 void
226 soup_soap_response_set_method_name (SoupSoapResponse *response, const char *method_name)
227 {
228         g_return_if_fail (SOUP_IS_SOAP_RESPONSE (response));
229         g_return_if_fail (response->priv->xml_method != NULL);
230         g_return_if_fail (method_name != NULL);
231
232         xmlNodeSetName (response->priv->xml_method, method_name);
233 }
234
235 /**
236  * soup_soap_parameter_get_name:
237  */
238 const char *
239 soup_soap_parameter_get_name (SoupSoapParameter *param)
240 {
241         g_return_val_if_fail (param != NULL, NULL);
242
243         return (const char *) param->name;
244 }
245
246 /**
247  * soup_soap_parameter_get_int_value:
248  */
249 int
250 soup_soap_parameter_get_int_value (SoupSoapParameter *param)
251 {
252         int i;
253         char *s;
254         g_return_val_if_fail (param != NULL, -1);
255
256         s = xmlNodeGetContent (param);
257         if (s) {
258                 i = atoi (s);
259                 xmlFree (s);
260
261                 return i;
262         }
263
264         return -1;
265 }
266
267 /**
268  * soup_soap_parameter_get_string_value:
269  */
270 char *
271 soup_soap_parameter_get_string_value (SoupSoapParameter *param)
272 {
273         char *xml_s, *s;
274         g_return_val_if_fail (param != NULL, NULL);
275
276         xml_s = xmlNodeGetContent (param);
277         s = g_strdup (xml_s);
278         xmlFree (xml_s);
279
280         return s;
281 }
282
283 /**
284  * soup_soap_parameter_get_first_child:
285  * @param: A %SoupSoapParameter.
286  *
287  * Gets the first child of the given %SoupSoapParameter. This is used
288  * for compound data types, which can contain several parameters
289  * themselves.
290  *
291  * Return value: the first child or NULL if there are no children.
292  */
293 SoupSoapParameter *
294 soup_soap_parameter_get_first_child (SoupSoapParameter *param)
295 {
296         g_return_val_if_fail (param != NULL, NULL);
297
298         return param->xmlChildrenNode ? param->xmlChildrenNode : NULL;
299 }
300
301 /**
302  * soup_soap_parameter_get_first_child_by_name:
303  * @param: A %SoupSoapParameter.
304  * @name: The name of the child parameter to look for.
305  *
306  * Gets the first child of the given %SoupSoapParameter whose name
307  * is @name.
308  *
309  * Return value: the first child with the given name or NULL if there
310  * are no children.
311  */
312 SoupSoapParameter *
313 soup_soap_parameter_get_first_child_by_name (SoupSoapParameter *param, const char *name)
314 {
315         SoupSoapParameter *tmp;
316
317         g_return_val_if_fail (param != NULL, NULL);
318         g_return_val_if_fail (name != NULL, NULL);
319
320         for (tmp = soup_soap_parameter_get_first_child (param);
321              tmp != NULL;
322              tmp = soup_soap_parameter_get_next_child (tmp)) {
323                 if (!strcmp (name, tmp->name))
324                         return tmp;
325         }
326
327         return NULL;
328 }
329
330 /**
331  * soup_soap_parameter_get_next_child:
332  * @param: A %SoupSoapParameter.
333  */
334 SoupSoapParameter *
335 soup_soap_parameter_get_next_child (SoupSoapParameter *param)
336 {
337         g_return_val_if_fail (param != NULL, NULL);
338
339         return param->next;
340 }
341
342 /**
343  * soup_soap_parameter_get_next_child_by_name:
344  */
345 SoupSoapParameter *
346 soup_soap_parameter_get_next_child_by_name (SoupSoapParameter *param,
347                                             const char *name)
348 {
349         SoupSoapParameter *tmp;
350
351         g_return_val_if_fail (param != NULL, NULL);
352         g_return_val_if_fail (name != NULL, NULL);
353
354         for (tmp = soup_soap_parameter_get_next_child (param);
355              tmp != NULL;
356              tmp = soup_soap_parameter_get_next_child (tmp)) {
357                 if (!strcmp (name, tmp->name))
358                         return tmp;
359         }
360
361         return NULL;
362 }
363
364 /**
365  * soup_soap_parameter_get_property:
366  * @param:
367  * @prop_name: Name of the property to retrieve.
368  */
369 char *
370 soup_soap_parameter_get_property (SoupSoapParameter *param, const char *prop_name)
371 {
372         char *xml_s, *s;
373
374         g_return_val_if_fail (param != NULL, NULL);
375         g_return_val_if_fail (prop_name != NULL, NULL);
376
377         xml_s = xmlGetProp (param, prop_name);
378         s = g_strdup (xml_s);
379         xmlFree (xml_s);
380
381         return s;
382 }
383
384 /**
385  * soup_soap_response_get_parameters:
386  * @response: the %SoupSoapResponse object.
387  *
388  * Returns the list of parameters received in the SOAP response.
389  *
390  * Return value: the list of parameters, represented in
391  * SoupSoapParameter's, which is an opaque type used to
392  * represent a parameter in the SOAP response.
393  */
394 const GList *
395 soup_soap_response_get_parameters (SoupSoapResponse *response)
396 {
397         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
398
399         return (const GList *) response->priv->parameters;
400 }
401
402 /**
403  * soup_soap_response_get_first_parameter:
404  * @response: the %SoupSoapResponse object.
405  *
406  * Retrieves the first parameter contained in the SOAP response.
407  *
408  * Return value: a %SoupSoapParameter representing the
409  * first parameter. This is an opaque type used to
410  * represent a parameter in the SOAP response.
411  */
412 SoupSoapParameter *
413 soup_soap_response_get_first_parameter (SoupSoapResponse *response)
414 {
415         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
416
417         return response->priv->parameters ? response->priv->parameters->data : NULL;
418 }
419
420 /**
421  * soup_soap_response_get_first_parameter_by_name:
422  * @response: the %SoupSoapResponse object.
423  * @name: the name of the parameter to look for.
424  *
425  * Retrieves the first parameter contained in the SOAP response whose
426  * name is @name.
427  *
428  * Return value: a %SoupSoapParameter representing the
429  * first parameter. This is an opaque type used to
430  * represent a parameter in the SOAP response.
431  */
432 SoupSoapParameter *
433 soup_soap_response_get_first_parameter_by_name (SoupSoapResponse *response,
434                                                 const char *name)
435 {
436         GList *l;
437
438         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
439         g_return_val_if_fail (name != NULL, NULL);
440
441         for (l = response->priv->parameters; l != NULL; l = l->next) {
442                 SoupSoapParameter *param = (SoupSoapParameter *) l->data;
443
444                 if (!strcmp (name, param->name))
445                         return param;
446         }
447
448         return NULL;
449 }
450
451 /**
452  * soup_soap_response_get_next_parameter:
453  * @response: the %SoupSoapResponse object.
454  * @from: the parameter to start from.
455  *
456  * Retrieves the parameter following @from in the %SoupSoapResponse object.
457  *
458  * Return value: a %SoupSoapParameter representing the parameter.
459  */
460 SoupSoapParameter *
461 soup_soap_response_get_next_parameter (SoupSoapResponse *response,
462                                        SoupSoapParameter *from)
463 {
464         GList *l;
465
466         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
467         g_return_val_if_fail (from != NULL, NULL);
468
469         l = g_list_find (response->priv->parameters, (gconstpointer) from);
470         if (!l)
471                 return NULL;
472
473         return l->next ? (SoupSoapParameter *) l->next->data : NULL;
474 }
475
476 /**
477  * soup_soap_response_get_next_parameter_by_name:
478  * @response: the %SoupSoapResponse object.
479  * @from: the parameter to start from.
480  * @name: the name of the parameter to look for.
481  *
482  * Retrieves the parameter following @from in the %SoupSoapResponse object
483  * whose name matches @name.
484  *
485  * Return value: a %SoupSoapParameter representing the parameter.
486  */
487 SoupSoapParameter *
488 soup_soap_response_get_next_parameter_by_name (SoupSoapResponse *response,
489                                                SoupSoapParameter *from,
490                                                const char *name)
491 {
492         SoupSoapParameter *param;
493
494         g_return_val_if_fail (SOUP_IS_SOAP_RESPONSE (response), NULL);
495         g_return_val_if_fail (from != NULL, NULL);
496         g_return_val_if_fail (name != NULL, NULL);
497
498         param = soup_soap_response_get_next_parameter (response, from);
499         while (param) {
500                 const char *param_name = soup_soap_parameter_get_name (param);
501
502                 if (param_name) {
503                         if (!strcmp (name, param_name))
504                                 return param;
505                 }
506
507                 param = soup_soap_response_get_next_parameter (response, param);
508         }
509
510         return NULL;
511 }