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