1 /* $Id: idwsf2_data_service.c 3101 2007-05-30 11:40:10Z dlaniel $
2  *
3  * Lasso - A free implementation of the Liberty Alliance specifications.
4  *
5  * Copyright (C) 2004-2007 Entr'ouvert
6  * http://lasso.entrouvert.org
7  *
8  * Authors: See AUTHORS file in top-level directory.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 /**
25  * SECTION:idwsf2_data_service
26  * @short_description: ID-WSF 2.0 Data Service profile
27  *
28  * DataService allows Attribute Consumers (WSC) to request an Attribute Provider (WSP) to get
29  * or modify data about users with their consent.
30  */
31 
32 #include "../xml/private.h"
33 #include <libxml/xpath.h>
34 #include <libxml/xpathInternals.h>
35 
36 #include "data_service.h"
37 #include "../xml/id-wsf-2.0/idwsf2_strings.h"
38 
39 #include "../xml/id-wsf-2.0/disco_service_type.h"
40 #include "../xml/id-wsf-2.0/dstref_query.h"
41 #include "../xml/id-wsf-2.0/dstref_query_response.h"
42 #include "../xml/id-wsf-2.0/dstref_data.h"
43 #include "../xml/id-wsf-2.0/util_status.h"
44 #include "../xml/id-wsf-2.0/util_response.h"
45 #include "../xml/id-wsf-2.0/sb2_redirect_request.h"
46 #include "../xml/id-wsf-2.0/dstref_modify.h"
47 #include "../xml/id-wsf-2.0/dstref_modify_item.h"
48 #include "../xml/id-wsf-2.0/dstref_modify_response.h"
49 #include "../xml/id-wsf-2.0/dstref_create.h"
50 #include "../xml/id-wsf-2.0/dstref_delete.h"
51 
52 #include "../xml/soap-1.1/soap_envelope.h"
53 #include "../xml/soap-1.1/soap_fault.h"
54 #include "../xml/private.h"
55 #include "../utils.h"
56 #include "private.h"
57 #include "idwsf2_helper.h"
58 #include "soap_binding.h"
59 
60 struct _LassoIdWsf2DataServicePrivate
61 {
62 	gboolean dispose_has_run;
63 	GList *query_items; /* of LassoIdWsf2DstRefQueryItem */
64 	GList *query_datas; /* of LassoIdWsf2DstRefData */
65 	GList *modify_items; /* of LassoIdWsf2DstRefModifyItem */
66 	gchar *service_type;
67 	gchar *service_type_prefix;
68 	GHashTable *namespaces;
69 };
70 
71 extern GHashTable *idwsf2_dst_services_by_prefix; /* cf xml/xml.c */
72 
73 #define lasso_idwsf2_data_service_set_dst_service_type(dst_node, service_type, prefix) \
74 	lasso_assign_string(dst_node->hrefServiceType, service_type); \
75 	lasso_assign_string(dst_node->prefixServiceType, prefix); \
76 
77 static void
lasso_idwsf2_data_service_clean_private_data(LassoIdWsf2DataService * service)78 lasso_idwsf2_data_service_clean_private_data(LassoIdWsf2DataService *service)
79 {
80 	LassoIdWsf2DataServicePrivate *pdata = service->private_data;
81 
82 	lasso_release_string(pdata->service_type);
83 	lasso_release_string(pdata->service_type_prefix);
84 	lasso_release_list_of_gobjects(pdata->query_items);
85 	lasso_release_list_of_gobjects(pdata->modify_items);
86 	lasso_release_ghashtable(pdata->namespaces);
87 }
88 
89 
90 /**
91  * lasso_idwsf2_data_service_set_service_type:
92  * @service: a #LassoIdWsf2DataService object
93  * @prefix: a prefix to use in producing XML documents
94  * @service_type: the service type URI
95  *
96  * Fix a service type for this @service.
97  */
98 gint
lasso_idwsf2_data_service_set_service_type(LassoIdWsf2DataService * service,const char * prefix,const char * service_type)99 lasso_idwsf2_data_service_set_service_type(LassoIdWsf2DataService *service, const char *prefix,
100 		const char *service_type)
101 {
102 	if (!LASSO_IS_IDWSF2_DATA_SERVICE(service) || lasso_strisempty(prefix)
103 			|| lasso_strisempty(service_type))
104 		return LASSO_PARAM_ERROR_INVALID_VALUE;
105 	lasso_assign_string(service->private_data->service_type_prefix, prefix);
106 	lasso_assign_string(service->private_data->service_type, service_type);
107 	return 0;
108 }
109 
110 /**
111  * lasso_idwsf2_data_service_get_service_type:
112  * @service: a #LassoIdWsf2DataService object
113  *
114  * Return the service type of the received request
115  *
116  * Return value:(allow-none)(transfer none): the URI of the service type or NULL.
117  */
118 const char*
lasso_idwsf2_data_service_get_service_type(LassoIdWsf2DataService * service)119 lasso_idwsf2_data_service_get_service_type(LassoIdWsf2DataService *service)
120 {
121 	if (! LASSO_IS_IDWSF2_DATA_SERVICE(service))
122 		return NULL;
123 	return service->private_data->service_type;
124 }
125 
126 /**
127  * lasso_idwsf2_data_service_get_service_type_prefix:
128  * @service: a #LassoIdWsf2DataService object
129  *
130  * Return the service type prefix of the received request
131  *
132  * Return value:(allow-none)(transfer none): the URI of the service type prefix or NULL.
133  */
134 const char*
lasso_idwsf2_data_service_get_service_type_prefix(LassoIdWsf2DataService * service)135 lasso_idwsf2_data_service_get_service_type_prefix(LassoIdWsf2DataService *service)
136 {
137 	if (! LASSO_IS_IDWSF2_DATA_SERVICE(service))
138 		return NULL;
139 	return service->private_data->service_type_prefix;
140 }
141 
142 static gint
lasso_idwsf2_data_service_init_request(LassoIdWsf2DataService * service,LassoNode * (* constructor)())143 lasso_idwsf2_data_service_init_request(LassoIdWsf2DataService *service,
144 		LassoNode *(*constructor)())
145 {
146 	int rc = 0;
147 	LassoNode *request;
148 	LassoSoapEnvelope *envelope;
149 
150 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
151 	lasso_release_list_of_gobjects(service->private_data->query_items);
152 	lasso_release_list_of_gobjects(service->private_data->modify_items);
153 	lasso_check_good_rc(lasso_idwsf2_profile_init_request(&service->parent));
154 	request = (LassoNode*)constructor();
155 	envelope = lasso_idwsf2_profile_get_soap_envelope_request(&service->parent);
156 	lasso_assign_new_gobject(service->parent.parent.request, request);
157 	lasso_soap_envelope_add_to_body(envelope, request);
158 
159 cleanup:
160 	return rc;
161 }
162 
163 /**
164  * lasso_idwsf2_data_service_init_query:
165  * @service: a #LassoIdWsf2DataService
166  *
167  * Initialise an ID-WSF 2.0 DataService query request.
168  *
169  * Return value: 0 on success; or a negative value otherwise.
170  **/
171 gint
lasso_idwsf2_data_service_init_query(LassoIdWsf2DataService * service)172 lasso_idwsf2_data_service_init_query(LassoIdWsf2DataService *service)
173 {
174 	return lasso_idwsf2_data_service_init_request(service,
175 			(LassoNode *(*)())lasso_idwsf2_dstref_query_new);
176 }
177 
178 /**
179  * lasso_idwsf2_data_service_init_modify:
180  * @service: a #LassoIdWsf2DataService
181  *
182  * Initialise an ID-WSF 2.0 DataService modify request.
183  *
184  * Return value: 0 on success; or a negative value otherwise.
185  **/
186 gint
lasso_idwsf2_data_service_init_modify(LassoIdWsf2DataService * service)187 lasso_idwsf2_data_service_init_modify(LassoIdWsf2DataService *service)
188 {
189 	return lasso_idwsf2_data_service_init_request(service,
190 			(LassoNode *(*)())lasso_idwsf2_dstref_modify_new);
191 }
192 
193 gint
lasso_idwsf2_data_service_init_create(LassoIdWsf2DataService * service)194 lasso_idwsf2_data_service_init_create(LassoIdWsf2DataService *service)
195 {
196 	return lasso_idwsf2_data_service_init_request(service,
197 			(LassoNode *(*)())lasso_idwsf2_dstref_create_new);
198 }
199 
200 gint
lasso_idwsf2_data_service_init_delete(LassoIdWsf2DataService * service)201 lasso_idwsf2_data_service_init_delete(LassoIdWsf2DataService *service)
202 {
203 	return lasso_idwsf2_data_service_init_request(service,
204 			(LassoNode *(*)())lasso_idwsf2_dstref_delete_new);
205 }
206 
207 /**
208  * lasso_idwsf2_data_service_get_request_type:
209  * @service: a #LassoIdWsf2DataService object
210  *
211  * Return the type of the currently handled request.
212  */
213 LassoIdWsf2DataServiceRequestType
lasso_idwsf2_data_service_get_request_type(LassoIdWsf2DataService * service)214 lasso_idwsf2_data_service_get_request_type(LassoIdWsf2DataService *service)
215 {
216 	GType request_type = 0;
217 
218 #define check_request_type(a, b) \
219 		if (request_type == a) { \
220 			return b ;\
221 		}
222 	if (! LASSO_IS_IDWSF2_DATA_SERVICE(service))
223 		return LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_UNKNOWN;
224 	request_type = G_TYPE_FROM_INSTANCE(service->parent.parent.request);
225 	check_request_type(LASSO_TYPE_IDWSF2_DSTREF_QUERY,
226 			LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY);
227 	check_request_type(LASSO_TYPE_IDWSF2_DSTREF_MODIFY,
228 			LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY);
229 #undef check_request_type
230 	return LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_UNKNOWN;
231 }
232 
233 /**
234  * lasso_idwsf2_data_service_add_query_item:
235  * @service: a #LassoIdWsf2DataService
236  * @item_query: a query string
237  * @item_id:(allow-none): identifier of the queried item, which will allow to retrieve it in the
238  * response
239  *
240  * Add an item in the query request.
241  *
242  * Return value: 0 on success; or a negative value otherwise.
243  **/
244 gint
lasso_idwsf2_data_service_add_query_item(LassoIdWsf2DataService * service,const gchar * item_query,const gchar * item_id)245 lasso_idwsf2_data_service_add_query_item(LassoIdWsf2DataService *service, const gchar *item_query,
246 	const gchar *item_id)
247 {
248 	LassoIdWsf2DstRefQueryItem *item;
249 	GList *i;
250 	int rc = 0;
251 
252 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
253 	lasso_check_non_empty_string(item_query);
254 
255 	if (item_id == NULL) {
256 		item_id = lasso_build_unique_id(32);
257 	}
258 	/* Check duplicates */
259 	lasso_foreach(i, service->private_data->query_items) {
260 		LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data;
261 		if (lasso_strisequal(old_item->parent.parent.itemID,item_id)) {
262 			return LASSO_IDWSF2_DST_ERROR_DUPLICATE_ITEM;
263 		}
264 	}
265 	item = lasso_idwsf2_dstref_query_item_new_full(item_query, item_id);
266 	lasso_list_add_gobject(service->private_data->query_items, item);
267 cleanup:
268 	return rc;
269 }
270 
271 /**
272  * lasso_idwsf2_data_service_add_modify_item:
273  * @service: a #LassoIdWsf2DataService
274  * @item_query: XPATH of the item to modify
275  * @new_data:(allow-none):new value for the selected item
276  * @overrideAllowed:(allow-none)(default FALSE): FALSE means only allowing to create a new item, but
277  * not modify existing one, TRUE means allowing to modify existing item
278  * @item_id:(allow-none): identifier of the item to modify
279  *
280  * Add an item in the modification request.
281  *
282  * Return value: 0 on success; or a negative value otherwise.
283  **/
284 gint
lasso_idwsf2_data_service_add_modify_item(LassoIdWsf2DataService * service,const gchar * item_query,xmlNode * new_data,gboolean overrideAllowed,const gchar * item_id)285 lasso_idwsf2_data_service_add_modify_item(LassoIdWsf2DataService *service, const gchar *item_query,
286 	xmlNode *new_data, gboolean overrideAllowed, const gchar *item_id)
287 {
288 	LassoIdWsf2DstRefModifyItem *item;
289 	int rc = 0;
290 	GList *i;
291 
292 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
293 	lasso_check_non_empty_string(item_query);
294 
295 	if (item_id == NULL) {
296 		item_id = lasso_build_unique_id(10);
297 	}
298 	lasso_foreach(i, service->private_data->modify_items) {
299 		LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data;
300 		if (lasso_strisequal(old_item->id,item_id)) {
301 			return LASSO_IDWSF2_DST_ERROR_DUPLICATE_ITEM;
302 		}
303 	}
304 	item = lasso_idwsf2_dstref_modify_item_new_full(
305 		item_query, item_id, new_data, overrideAllowed);
306 	lasso_list_add_gobject(service->private_data->modify_items, item);
307 
308 cleanup:
309 	return rc;
310 }
311 
312 /**
313  * lasso_idwsf2_data_service_get_item_ids:
314  * @service: a #LassoIdWsf2DataService object
315  *
316  * Return the list of items ids for the currently handled request.
317  *
318  * Return value:(element-type utf8)(transfer full): a list of string ids, or NULL if none is found.
319  * The caller must free the return value.
320  */
321 GList*
lasso_idwsf2_data_service_get_item_ids(LassoIdWsf2DataService * service)322 lasso_idwsf2_data_service_get_item_ids(LassoIdWsf2DataService *service)
323 {
324 	GList *i, *result = NULL;
325 
326 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
327 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
328 			lasso_foreach(i, service->private_data->query_items) {
329 				LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data;
330 				lasso_list_add_string(result, old_item->parent.parent.itemID);
331 			}
332 			break;
333 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
334 			lasso_foreach(i, service->private_data->modify_items) {
335 				LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data;
336 				lasso_list_add_string(result, old_item->id);
337 			}
338 			break;
339 		default:
340 			break;
341 	}
342 	return result;
343 }
344 
345 /**
346  * lasso_idwsf2_data_service_get_items:
347  * @service: a #LassoIdWsf2DataService object
348  *
349  * Return value:(element-type LassoNode)(transfer none): a list of Query or Modify items, or NULL if
350  * none is found.
351  */
352 GList*
lasso_idwsf2_data_service_get_items(LassoIdWsf2DataService * service)353 lasso_idwsf2_data_service_get_items(LassoIdWsf2DataService *service)
354 {
355 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
356 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
357 			return service->private_data->query_items;
358 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
359 			return service->private_data->modify_items;
360 		default:
361 			break;
362 	}
363 	return NULL;
364 }
365 
366 /**
367  * lasso_idwsf2_data_service_get_item:
368  * @service: a #LassoIdWsf2DataService object
369  * @item_id: the itemID of the item to return, if NULL try to get the only one item (if there is
370  * more than one, it returns NULL).
371  *
372  * Retrieve a specific item from a request.
373  *
374  * Return value:(transfer none)(allow-none): a #LassoIdWsf2DstRefQueryItem or a #LassoIdWsf2DstRefModifyItem object, or NULL if
375  * no item for the given item_id exists.
376  */
377 LassoNode*
lasso_idwsf2_data_service_get_item(LassoIdWsf2DataService * service,const char * item_id)378 lasso_idwsf2_data_service_get_item(LassoIdWsf2DataService *service,
379 		const char *item_id)
380 {
381 	GList *i;
382 
383 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
384 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
385 			if (item_id == NULL) {
386 				if (g_list_length(service->private_data->query_items) == 1)
387 					return (LassoNode*)service->private_data->query_items->data;
388 				else
389 					return NULL;
390 			}
391 			lasso_foreach(i, service->private_data->query_items) {
392 				LassoIdWsf2DstRefQueryItem *old_item = (LassoIdWsf2DstRefQueryItem *)i->data;
393 				if (lasso_strisequal(old_item->parent.parent.itemID,item_id)) {
394 					return (LassoNode*)old_item;
395 				}
396 			}
397 			break;
398 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
399 			if (item_id == NULL) {
400 				if (g_list_length(service->private_data->modify_items) == 1)
401 					return (LassoNode*)service->private_data->modify_items->data;
402 				else
403 					return NULL;
404 			}
405 			lasso_foreach(i, service->private_data->modify_items) {
406 				LassoIdWsf2DstRefModifyItem *old_item = (LassoIdWsf2DstRefModifyItem *)i->data;
407 				if (lasso_strisequal(old_item->id,item_id)) {
408 					return (LassoNode*)old_item;
409 				}
410 			}
411 			break;
412 		default:
413 			break;
414 	}
415 	return NULL;
416 }
417 
418 /**
419  * lasso_idwsf2_data_service_add_namespace:
420  * @service: a #LassoIdWsf2DataService object
421  *
422  * Add a new namespace to use for example in XPath elements or in Data or NewData objects.
423  *
424  * Return value: 0 if successful, an error code otherwise.
425  */
426 gint
lasso_idwsf2_data_service_add_namespace(LassoIdWsf2DataService * service,const char * prefix,const char * href)427 lasso_idwsf2_data_service_add_namespace(LassoIdWsf2DataService *service, const char *prefix,
428 		const char *href)
429 {
430 	if (xmlValidateNCName(BAD_CAST prefix, 0) && ! lasso_strisempty(href))
431 		return LASSO_PARAM_ERROR_INVALID_VALUE;
432 
433 	if (g_hash_table_lookup(service->private_data->namespaces, prefix) != NULL ||
434 			lasso_strisequal(service->private_data->service_type_prefix,prefix) ||
435 			lasso_strisequal(prefix,LASSO_IDWSF2_DSTREF_PREFIX)) {
436 		return LASSO_PARAM_ERROR_INVALID_VALUE;
437 	}
438 
439 	g_hash_table_insert(service->private_data->namespaces, g_strdup(prefix), g_strdup(href));
440 	return 0;
441 }
442 
443 static void
add_custom_namespace(const char * prefix,const char * href,LassoNode * node)444 add_custom_namespace(const char *prefix, const char *href, LassoNode *node)
445 {
446 	lasso_node_add_custom_namespace(node, prefix, href);
447 }
448 
449 /**
450  * lasso_idwsf2_data_service_build_request_msg:
451  * @service: a #LassoIdWsf2DataService object
452  * @security_mech_id:(allow-none): the security mechanism to employ, default is Bearer mechanism.
453  *
454  * Build the request message.
455  *
456  * Return value: 0 if successful, an error code otherwise.
457  */
458 gint
lasso_idwsf2_data_service_build_request_msg(LassoIdWsf2DataService * service,const char * security_mech_id)459 lasso_idwsf2_data_service_build_request_msg(LassoIdWsf2DataService *service,
460 		const char *security_mech_id)
461 {
462 	int rc = 0;
463 	LassoSoapEnvelope *envelope;
464 	LassoIdWsf2DstRefQuery *query = (LassoIdWsf2DstRefQuery*)service->parent.parent.request;
465 	LassoIdWsf2DstRefModify *modify = (LassoIdWsf2DstRefModify*)service->parent.parent.request;
466 	const char *service_type = NULL;
467 	const char *prefix = NULL;
468 
469 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
470 
471 	envelope = lasso_idwsf2_profile_get_soap_envelope_request(&service->parent);
472 	service_type = lasso_wsa_endpoint_reference_get_idwsf2_service_type(
473 			lasso_idwsf2_profile_get_epr(&service->parent));
474 	if (service_type) {
475 		const char *prefix = lasso_get_prefix_for_idwsf2_dst_service_href(service_type);
476 		if (! prefix)
477 			prefix = "dstref";
478 	} else {
479 		service_type = service->private_data->service_type;
480 		prefix = service->private_data->service_type_prefix;
481 	}
482 
483 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
484 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
485 			if (service_type) {
486 				lasso_idwsf2_data_service_set_dst_service_type(query, service_type, prefix);
487 			}
488 			lasso_assign_list_of_gobjects(query->QueryItem, service->private_data->query_items);
489 			g_hash_table_foreach(service->private_data->namespaces,
490 					(GHFunc)add_custom_namespace,
491 					query);
492 			break;
493 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
494 			if (service_type) {
495 				lasso_idwsf2_data_service_set_dst_service_type(modify, service_type, prefix);
496 			}
497 			lasso_assign_list_of_gobjects(modify->ModifyItem, service->private_data->modify_items);
498 			break;
499 		default:
500 			goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST);
501 			break;
502 	}
503 	rc = lasso_idwsf2_profile_build_request_msg(&service->parent, security_mech_id);
504 cleanup:
505 	return rc;
506 }
507 
508 static gint
lasso_idwsf2_data_service_process_query(LassoIdWsf2DataService * service)509 lasso_idwsf2_data_service_process_query(LassoIdWsf2DataService *service)
510 {
511 	LassoIdWsf2DstRefQuery *query;
512 	GList *i;
513 	int rc = 0;
514 
515 	query = (LassoIdWsf2DstRefQuery*)service->parent.parent.request;
516 	lasso_check_good_rc(lasso_idwsf2_data_service_set_service_type(
517 			service,
518 			query->prefixServiceType,
519 			query->hrefServiceType));
520 
521 	/* Parse QueryItems to get a list of Query strings */
522 	/* FIXME: extract TestItems */
523 	lasso_foreach(i, query->QueryItem)
524 	{
525 		LassoIdWsf2DstRefQueryItem *item = (LassoIdWsf2DstRefQueryItem *)i->data;
526 		/* FIXME: check more query items invariants. */
527 		if (! LASSO_IS_IDWSF2_DSTREF_QUERY_ITEM(item)) {
528 			lasso_release_list_of_gobjects(service->private_data->query_items);
529 			goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST);
530 		}
531 		lasso_list_add_gobject(service->private_data->query_items,
532 				item);
533 	}
534 cleanup:
535 	return rc;
536 }
537 
538 static gint
lasso_idwsf2_data_service_process_modify(LassoIdWsf2DataService * service)539 lasso_idwsf2_data_service_process_modify(LassoIdWsf2DataService *service)
540 {
541 	LassoIdWsf2DstRefModify *modify;
542 	GList *i;
543 	int rc = 0;
544 
545 	modify = (LassoIdWsf2DstRefModify*)service->parent.parent.request;
546 	lasso_foreach(i, modify->ModifyItem)
547 	{
548 		LassoIdWsf2DstRefModifyItem *item = (LassoIdWsf2DstRefModifyItem*)i->data;
549 		/* FIXME: check more Modify Item invariants */
550 		if (! LASSO_IS_IDWSF2_DSTREF_MODIFY_ITEM(item)) {
551 			lasso_release_list_of_gobjects(service->private_data->modify_items);
552 			goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_REQUEST);
553 		}
554 		lasso_list_add_gobject(service->private_data->modify_items, item);
555 	}
556 cleanup:
557 	return rc;
558 }
559 
560 /**
561  * lasso_idwsf2_data_service_process_request_msg:
562  * @service: a #LassoIdWsf2DataService object
563  * @msg: the message string
564  *
565  * Process a newly received requests.
566  */
567 gint
lasso_idwsf2_data_service_process_request_msg(LassoIdWsf2DataService * service,const char * msg)568 lasso_idwsf2_data_service_process_request_msg(LassoIdWsf2DataService *service, const char *msg)
569 {
570 	int rc = 0;
571 
572 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
573 
574 	lasso_check_good_rc(lasso_idwsf2_profile_process_request_msg(&service->parent, msg));
575 	lasso_idwsf2_data_service_clean_private_data(service);
576 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
577 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
578 			rc = lasso_idwsf2_data_service_process_query(service);
579 			break;
580 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
581 			rc = lasso_idwsf2_data_service_process_modify(service);
582 			break;
583 		default:
584 			rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
585 			break;
586 	}
587 	if (rc == LASSO_PROFILE_ERROR_INVALID_REQUEST) {
588 		lasso_idwsf2_data_service_set_status_code(service,
589 				LASSO_DST2_STATUS_CODE1_FAILED,
590 				"InvalidRequest");
591 	}
592 cleanup:
593 	return rc;
594 }
595 
596 /**
597  * lasso_idwsf2_data_service_validate_request:
598  * @service: a #LassoIdWsf2DataService object
599  *
600  * Initialize a new response object corresponding to the current request. If not request if found or
601  * the request is invalid, a failure response is created.
602  *
603  * Return value: 0 if successful, or LASSO_PROFILE_ERROR_INVALID_REQUEST.
604  */
605 gint
lasso_idwsf2_data_service_validate_request(LassoIdWsf2DataService * service)606 lasso_idwsf2_data_service_validate_request(LassoIdWsf2DataService *service)
607 {
608 	LassoIdWsf2DstRefQueryResponse *query_response;
609 	LassoIdWsf2DstRefModifyResponse *modify_response;
610 	LassoNode *response = NULL;
611 	int rc = 0;
612 	const char *service_type = NULL;
613 	const char *prefix = NULL;
614 
615 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
616 
617 	lasso_check_good_rc(lasso_idwsf2_profile_init_response(&service->parent));
618 	if (service_type) {
619 		const char *prefix = lasso_get_prefix_for_idwsf2_dst_service_href(service_type);
620 		if (! prefix)
621 			prefix = "dstref";
622 	} else {
623 		service_type = service->private_data->service_type;
624 		prefix = service->private_data->service_type_prefix;
625 	}
626 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
627 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
628 			query_response = lasso_idwsf2_dstref_query_response_new();
629 			if (service_type) {
630 				lasso_idwsf2_data_service_set_dst_service_type(query_response,
631 						service_type, prefix);
632 			}
633 			response = (LassoNode*)query_response;
634 			break;
635 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
636 			modify_response = lasso_idwsf2_dstref_modify_response_new();
637 			if (service_type) {
638 				lasso_idwsf2_data_service_set_dst_service_type(modify_response,
639 						service_type, prefix);
640 			}
641 			response = (LassoNode*)modify_response;
642 			break;
643 		default:
644 			lasso_idwsf2_data_service_set_status_code(service,
645 					LASSO_DST2_STATUS_CODE1_FAILED, "InvalidRequest");
646 			return LASSO_PROFILE_ERROR_INVALID_REQUEST;
647 	}
648 	if (response) {
649 		LassoSoapEnvelope *envelope =
650 			lasso_idwsf2_profile_get_soap_envelope_response(&service->parent);
651 		lasso_assign_new_gobject(service->parent.parent.response, response);
652 		lasso_soap_envelope_add_to_body(envelope, response);
653 		lasso_idwsf2_data_service_set_status_code(service, LASSO_DST2_STATUS_CODE1_OK, NULL);
654 	}
655 cleanup:
656 	return rc;
657 }
658 
659 /**
660  * lasso_idwsf2_data_service_set_status_code:
661  * @service: a #LassoIdWsf2DataService
662  * @status_code: a first level status code
663  * @status_code2: a second level status code
664  *
665  * Set the status code for the current response, if no response exists, it starts one using
666  * lasso_idwsf2_data_service_validate_request(), if it fails, report a SOAP Fault.
667  */
668 gint
lasso_idwsf2_data_service_set_status_code(LassoIdWsf2DataService * service,const char * status_code,const char * status_code2)669 lasso_idwsf2_data_service_set_status_code(LassoIdWsf2DataService *service,
670 		const char *status_code, const char *status_code2)
671 {
672 	LassoNode *response;
673 	LassoIdWsf2UtilStatus **status = NULL;
674 	LassoIdWsf2UtilStatus *new_status = NULL;
675 	int rc = 0;
676 
677 
678 	response = service->parent.parent.response;
679 	if (LASSO_IS_IDWSF2_UTIL_RESPONSE(response)) {
680 		switch (lasso_idwsf2_data_service_get_request_type(service)) {
681 			case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
682 				status = &LASSO_IDWSF2_UTIL_RESPONSE(response)->Status;
683 				break;
684 			case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
685 				status = &LASSO_IDWSF2_UTIL_RESPONSE(response)->Status;
686 				break;
687 			default:
688 				break;
689 		}
690 	}
691 
692 	new_status = lasso_idwsf2_util_status_new_with_code(status_code, status_code2);
693 
694 	if (! LASSO_IS_IDWSF2_UTIL_RESPONSE(response) || ! status) {
695 		GList details = { .data = new_status, .next = NULL, .prev = NULL };
696 
697 		lasso_check_good_rc(lasso_idwsf2_profile_init_soap_fault_response(&service->parent,
698 					LASSO_SOAP_FAULT_CODE_CLIENT, "Unknown Request Type",
699 					&details));
700 	} else {
701 		lasso_assign_gobject(*status, new_status);
702 	}
703 cleanup:
704 	lasso_release_gobject(new_status);
705 	return rc;
706 }
707 
708 /**
709  * lasso_idwsf2_data_service_set_query_item_result:
710  * @service: a #LassoIdWsf2DataService object
711  * @item_id:(allow-none): target a certain QueryItem if NULL, means there is only one query item
712  * @xml_data:(allow-none): the data to add
713  * @add:(allow-none)(default FALSE): add data to existing datas
714  *
715  * Set result data for a certain query-item.
716  */
717 gint
lasso_idwsf2_data_service_set_query_item_result(LassoIdWsf2DataService * service,const char * item_id,xmlNode * xml_data,gboolean add)718 lasso_idwsf2_data_service_set_query_item_result(LassoIdWsf2DataService *service,
719 		const char *item_id, xmlNode *xml_data, gboolean add)
720 {
721 	LassoIdWsf2DstRefQueryItem *item;
722 	LassoIdWsf2DstRefData *data;
723 	int rc = 0;
724 
725 	if (lasso_idwsf2_data_service_get_request_type(service)
726 			!= LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY) {
727 		goto_cleanup_with_rc(LASSO_IDWSF2_DST_ERROR_ITEM_NOT_FOUND);
728 	}
729 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
730 	item = (LassoIdWsf2DstRefQueryItem*)lasso_idwsf2_data_service_get_item(service, item_id);
731 	if (! LASSO_IS_IDWSF2_DSTREF_QUERY_ITEM(item)) {
732 		goto_cleanup_with_rc(LASSO_IDWSF2_DST_ERROR_ITEM_NOT_FOUND);
733 	}
734 	data = lasso_idwsf2_data_service_get_query_item_result(service, item_id);
735 	if (data == NULL) {
736 		data = lasso_idwsf2_dstref_data_new();
737 	}
738 	if (xml_data) {
739 		if (! add) {
740 			lasso_release_list_of_xml_node(data->parent.parent.any);
741 		}
742 		lasso_list_add_xml_node(data->parent.parent.any, xml_data);
743 	}
744 	if (item_id) {
745 		lasso_assign_string(data->parent.itemIDRef, item_id);
746 	}
747 	if (g_list_find(service->private_data->query_datas, data) == NULL) {
748 		lasso_list_add_gobject(service->private_data->query_datas, data);
749 	}
750 cleanup:
751 	return rc;
752 }
753 
754 /**
755  * lasso_idwsf2_data_service_build_response_msg:
756  * @service: a #LassoIdWsf2DataService object
757  *
758  * Build the response message corresponding to the current request.
759  *
760  * Return value: 0 if successfull, an error code otherwise.
761  */
762 gint
lasso_idwsf2_data_service_build_response_msg(LassoIdWsf2DataService * service)763 lasso_idwsf2_data_service_build_response_msg(LassoIdWsf2DataService *service)
764 {
765 	LassoIdWsf2DstRefQueryResponse *query_response;
766 	GList *datas;
767 	int rc = 0;
768 
769 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
770 	if (! LASSO_IS_SOAP_FAULT(service->parent.parent.response)) {
771 		switch (lasso_idwsf2_data_service_get_request_type(service)) {
772 			case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
773 				goto_cleanup_if_fail_with_rc(
774 						LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE(
775 							service->parent.parent.response),
776 						LASSO_PROFILE_ERROR_INVALID_RESPONSE);
777 				query_response = (LassoIdWsf2DstRefQueryResponse*)service->parent.parent.response;
778 				datas = lasso_idwsf2_data_service_get_query_item_results(service);
779 				lasso_assign_list_of_gobjects(query_response->Data, datas);
780 				break;
781 			case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
782 				goto_cleanup_with_rc(LASSO_ERROR_UNIMPLEMENTED);
783 				break;
784 			default:
785 				break;
786 		}
787 	}
788 	rc = lasso_idwsf2_profile_build_response_msg(&service->parent);
789 cleanup:
790 	return rc;
791 }
792 
793 static gint
_lasso_idwsf2_data_service_process_query_response(LassoIdWsf2DataService * service,LassoIdWsf2DstRefQueryResponse * response)794 _lasso_idwsf2_data_service_process_query_response(LassoIdWsf2DataService * service,
795 		LassoIdWsf2DstRefQueryResponse *response)
796 {
797 	int rc = 0;
798 
799 	goto_cleanup_if_fail_with_rc(LASSO_IS_IDWSF2_DSTREF_QUERY_RESPONSE(response),
800 			LASSO_PROFILE_ERROR_INVALID_RESPONSE);
801 
802 	if (service->private_data) {
803 		lasso_assign_list_of_gobjects(service->private_data->query_datas, response->Data);
804 	}
805 cleanup:
806 	return rc;
807 }
808 
809 /**
810  * lasso_idwsf2_data_service_process_response_msg:
811  * @service: a #LassoIdWsf2DataService object
812  * @msg: (allow-none): the message content
813  *
814  * Process a received SOAP message response.
815  *
816  * Return value: 0 if successful, an error code otherwise.
817  */
818 gint
lasso_idwsf2_data_service_process_response_msg(LassoIdWsf2DataService * service,const char * msg)819 lasso_idwsf2_data_service_process_response_msg(
820 	LassoIdWsf2DataService *service, const char *msg)
821 {
822 	LassoIdWsf2DstRefQueryResponse *query_response;
823 	LassoIdWsf2UtilStatus *status;
824 	int rc = 0;
825 
826 	lasso_bad_param(IDWSF2_DATA_SERVICE, service);
827 
828 	lasso_check_good_rc(lasso_idwsf2_profile_process_response_msg(&service->parent, msg));
829 
830 	status = lasso_idwsf2_data_service_get_response_status(service);
831 
832 	if (! status || ! status->code) {
833 		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
834 	}
835 	if (lasso_strisequal(status->code,LASSO_DST2_STATUS_CODE1_FAILED)) {
836 		goto_cleanup_with_rc(LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS);
837 	}
838 	if (lasso_strisequal(status->code,LASSO_DST2_STATUS_CODE1_PARTIAL)) {
839 		rc = LASSO_IDWSF2_DST_ERROR_PARTIAL_FAILURE;
840 	}
841 	if (lasso_strisnotequal(status->code,LASSO_DST2_STATUS_CODE1_OK)) {
842 		rc = LASSO_IDWSF2_DST_ERROR_UNKNOWN_STATUS_CODE;
843 	}
844 
845 	switch (lasso_idwsf2_data_service_get_request_type(service)) {
846 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_QUERY:
847 			query_response = (LassoIdWsf2DstRefQueryResponse*)service->parent.parent.response;
848 			lasso_check_good_rc(_lasso_idwsf2_data_service_process_query_response(service, query_response));
849 			break;
850 		case LASSO_IDWSF2_DATA_SERVICE_REQUEST_TYPE_MODIFY:
851 			rc = LASSO_ERROR_UNIMPLEMENTED;
852 			break;
853 		default:
854 			rc = LASSO_ERROR_UNDEFINED;
855 			break;
856 	}
857 
858 cleanup:
859 	return rc;
860 }
861 
862 /**
863  * lasso_idwsf2_data_service_get_response_status:
864  * @service: a #LassoIdWsf2UtilStatus object
865  *
866  * Return the status from the current response.
867  *
868  * Return value:(transfer none)(allow-none): a #LassoIdWsf2UtilStatus object, or NULL.
869  */
870 LassoIdWsf2UtilStatus*
lasso_idwsf2_data_service_get_response_status(LassoIdWsf2DataService * service)871 lasso_idwsf2_data_service_get_response_status(LassoIdWsf2DataService *service)
872 {
873 	LassoIdWsf2UtilResponse *response;
874 	LassoSoapFault *fault;
875 
876 	response = (void*)(fault = (void*)service->parent.parent.response);
877 	if (LASSO_IS_IDWSF2_UTIL_RESPONSE(response)) {
878 		return response->Status;
879 	}
880 	if (LASSO_IS_SOAP_FAULT(fault)) {
881 		if (LASSO_IS_SOAP_DETAIL(fault->Detail) && fault->Detail->any
882 				&& LASSO_IS_IDWSF2_UTIL_STATUS(fault->Detail->any->data)) {
883 			return (LassoIdWsf2UtilStatus*)fault->Detail->any->data;
884 		}
885 	}
886 	return NULL;
887 }
888 
889 /**
890  * lasso_idwsf2_data_service_get_query_item_result:
891  * @service: a #LassoIdWsf2DataService object
892  * @item_id:(allow-none): an item_id or NULL if only one data is present
893  *
894  * Return value:(allow-none)(transfer none): a #LassoIdWsf2DstRefData or NULL if none is found.
895  */
896 LassoIdWsf2DstRefData*
lasso_idwsf2_data_service_get_query_item_result(LassoIdWsf2DataService * service,const char * item_id)897 lasso_idwsf2_data_service_get_query_item_result(LassoIdWsf2DataService *service,
898 		const char *item_id)
899 {
900 	GList *i;
901 
902 	if (! LASSO_IS_IDWSF2_DATA_SERVICE(service))
903 		return NULL;
904 	if (! item_id) {
905 		if (g_list_length(service->private_data->query_datas) == 1) {
906 			return (LassoIdWsf2DstRefData*)service->private_data->query_datas->data;
907 		}
908 		return NULL;
909 	}
910 	lasso_foreach(i, service->private_data->query_datas) {
911 		LassoIdWsf2DstRefData *data = (LassoIdWsf2DstRefData*)i->data;
912 		if (lasso_strisequal(data->parent.itemIDRef,item_id)) {
913 			return data;
914 		}
915 	}
916 	return NULL;
917 }
918 
919 /**
920  * lasso_idwsf2_data_service_get_query_item_result_content:
921  * @service: a #LassoIdWsf2DataService object
922  * @item_id:(allow-none): the identifier of the result asked, if NULL and there is only one respone,
923  * returns it.
924  *
925  * Returns the text content of the query item result identified by @item_id or the only query item
926  * result if @item_id is NULL.
927  * <para>If @item_id is NULL and there is multiple results, returns NULL.</para>
928  *
929  * Return value:(transfer full): the text content of the query item result.
930  */
931 char*
lasso_idwsf2_data_service_get_query_item_result_content(LassoIdWsf2DataService * service,const char * item_id)932 lasso_idwsf2_data_service_get_query_item_result_content(LassoIdWsf2DataService *service,
933 		const char *item_id)
934 {
935 	LassoIdWsf2DstRefData *data = NULL;
936 	LassoIdWsf2DstRefAppData *app_data = NULL;
937 	GList *i = NULL;
938 	GString *gstr = NULL;
939 	char *result = NULL;
940 
941 	data = lasso_idwsf2_data_service_get_query_item_result(service, item_id);
942 	if (! data)
943 		return NULL;
944 	app_data = (LassoIdWsf2DstRefAppData*)data;
945 	gstr = g_string_sized_new(128);
946 	lasso_foreach(i, app_data->any) {
947 		xmlNode *node = (xmlNode*)i->data;
948 		xmlChar *content;
949 		content = xmlNodeGetContent(node);
950 		g_string_append(gstr, (char*)content);
951 		xmlFree(content);
952 	}
953 	result = gstr->str;
954 	lasso_release_gstring(gstr, FALSE);
955 	return result;
956 }
957 
958 /**
959  * lasso_idwsf2_data_service_get_query_item_results:
960  * @service: a #LassoIdWsf2DataService object
961  *
962  * Return value:(allow-none)(transfer none)(element-type LassoIdWsf2DstRefData): the list of
963  * #LassoIdWsf2DstRefData or NULL if none is found.
964  */
965 GList*
lasso_idwsf2_data_service_get_query_item_results(LassoIdWsf2DataService * service)966 lasso_idwsf2_data_service_get_query_item_results(LassoIdWsf2DataService *service)
967 {
968 
969 	if (LASSO_IS_IDWSF2_DATA_SERVICE(service) && service->private_data) {
970 		return service->private_data->query_datas;
971 	}
972 	return NULL;
973 }
974 
975 static LassoNodeClass *parent_class = NULL;
976 
977 static void
dispose(GObject * object)978 dispose(GObject *object)
979 {
980 	LassoIdWsf2DataService *service = LASSO_IDWSF2_DATA_SERVICE(object);
981 	LassoIdWsf2DataServicePrivate *pdata = service->private_data;
982 
983 	if (!pdata || pdata->dispose_has_run == TRUE)
984 		return;
985 	pdata->dispose_has_run = TRUE;
986 
987 	lasso_idwsf2_data_service_clean_private_data(service);
988 	G_OBJECT_CLASS(parent_class)->dispose(object);
989 }
990 
991 static void
finalize(GObject * object)992 finalize(GObject *object)
993 {
994 	LassoIdWsf2DataService *service = LASSO_IDWSF2_DATA_SERVICE(object);
995 	lasso_release(service->private_data);
996 	service->private_data = NULL;
997 	G_OBJECT_CLASS(parent_class)->finalize(object);
998 }
999 
1000 static void
instance_init(LassoIdWsf2DataService * service)1001 instance_init(LassoIdWsf2DataService *service)
1002 {
1003 	service->private_data = g_new0(LassoIdWsf2DataServicePrivate, 1);
1004 	service->private_data->namespaces = g_hash_table_new_full(g_str_hash, g_str_equal,
1005 			(GDestroyNotify)g_free, (GDestroyNotify)g_free);
1006 }
1007 
1008 static void
class_init(LassoIdWsf2DataServiceClass * klass,void * unused G_GNUC_UNUSED)1009 class_init(LassoIdWsf2DataServiceClass *klass, void *unused G_GNUC_UNUSED)
1010 {
1011 	parent_class = g_type_class_peek_parent(klass);
1012 
1013 	lasso_node_class_set_nodename(LASSO_NODE_CLASS(klass), "IdWsf2DataService");
1014 	lasso_node_class_set_ns(LASSO_NODE_CLASS(klass), LASSO_LASSO_HREF, LASSO_LASSO_PREFIX);
1015 	G_OBJECT_CLASS(klass)->dispose = dispose;
1016 	G_OBJECT_CLASS(klass)->finalize = finalize;
1017 }
1018 
1019 GType
lasso_idwsf2_data_service_get_type()1020 lasso_idwsf2_data_service_get_type()
1021 {
1022 	static GType this_type = 0;
1023 
1024 	if (!this_type) {
1025 		static const GTypeInfo this_info = {
1026 			sizeof(LassoIdWsf2DataServiceClass),
1027 			NULL,
1028 			NULL,
1029 			(GClassInitFunc) class_init,
1030 			NULL,
1031 			NULL,
1032 			sizeof(LassoIdWsf2DataService),
1033 			0,
1034 			(GInstanceInitFunc) instance_init,
1035 			NULL
1036 		};
1037 
1038 		this_type = g_type_register_static(LASSO_TYPE_IDWSF2_PROFILE,
1039 				"LassoIdWsf2DataService", &this_info, 0);
1040 	}
1041 	return this_type;
1042 }
1043 
1044 
1045 /**
1046  * lasso_idwsf2_data_service_new:
1047  * @server:(allow-none): a #LassoServer object, for resolving ProviderIDs
1048  *
1049  * Create a new #LassoIdWsf2DataService.
1050  *
1051  * Return value: a newly created #LassoIdWsf2DataService object
1052  **/
1053 LassoIdWsf2DataService*
lasso_idwsf2_data_service_new(LassoServer * server)1054 lasso_idwsf2_data_service_new(LassoServer *server)
1055 {
1056 	LassoIdWsf2DataService *service;
1057 
1058 	service = g_object_new(LASSO_TYPE_IDWSF2_DATA_SERVICE, NULL);
1059 	service->parent.parent.server = lasso_ref(server);
1060 
1061 	return service;
1062 }
1063