1 /* $Id$
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:data_service
26  * @short_description: ID-WSF 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  * Following up on #LassoDiscovery first example, it created a @service object,
32  * this is a #LassoDataService instance.  This example continues from that step
33  * and retrieves the name of the principal:
34  *
35  * <informalexample>
36  * <programlisting>
37  * char *soap_answer;            // SOAP answer from data service
38  * xmlNode *principal_name;      // libxml2 xmlNode with the principal name
39  *
40  * service = lasso_discovery_get_service(discovery);
41  * lasso_data_service_init_query(service, "/pp:PP/pp:InformalName", NULL);
42  * lasso_data_service_build_request_msg(service);
43  *
44  * // service must perform SOAP call to LASSO_WSF_PROFILE(service)->msg_url
45  * // the SOAP message is LASSO_WSF_PROFILE(service)->msg_body.  The answer
46  * // is stored in char* soap_answer;
47  *
48  * lasso_data_service_process_query_response_msg(service, soap_answer);
49  * principal_name = lasso_data_service_get_answer(service, "/pp:PP/pp:InformalName");
50  *
51  * // app should probably then use xmlNodeGetContent libxml2 function to get
52  * // access to node content.
53  * </programlisting>
54  * </informalexample>
55  *
56  */
57 
58 #include "../xml/private.h"
59 #include "../utils.h"
60 #include <libxml/xpath.h>
61 #include <libxml/xpathInternals.h>
62 
63 #include "discovery.h"
64 #include "data_service.h"
65 #include "../xml/idwsf_strings.h"
66 #include "../xml/dst_query.h"
67 #include "../xml/dst_query_response.h"
68 #include "../xml/dst_modify.h"
69 #include "../xml/dst_modify_response.h"
70 #include "../xml/soap_binding_correlation.h"
71 #include "../xml/soap-1.1/soap_fault.h"
72 #include "../xml/is_redirect_request.h"
73 
74 #include <xmlsec/xmltree.h>
75 #include <xmlsec/xmldsig.h>
76 #include <xmlsec/templates.h>
77 #include <xmlsec/crypto.h>
78 #include "wsf_profile_private.h"
79 
80 extern GHashTable *dst_services_by_prefix; /* cf xml/xml.c */
81 
82 static void lasso_register_idwsf_xpath_namespaces(xmlXPathContext *xpathCtx);
83 static gint lasso_data_service_process_query_msg(LassoDataService *service,
84 		LassoDstQuery *query);
85 static gint lasso_data_service_process_modify_msg(LassoDataService *service,
86 		LassoDstModify *modify);
87 static gint lasso_data_service_validate_query_request(LassoDataService *service, xmlNode *data);
88 static gint lasso_data_service_apply_queries(LassoDataService *service,
89 		LassoDstQueryResponse *query_response, GList *queries, xmlNode *data);
90 static gint lasso_data_service_apply_query(LassoDataService *service,
91 		LassoDstQueryResponse *query_response, xmlXPathContext *xpathCtx,
92 		LassoDstQueryItem *item);
93 static gint lasso_data_service_validate_modify_request(LassoDataService *service, xmlNode **data);
94 static gint lasso_data_service_apply_modifications(LassoDstModify *modify,
95 		LassoDstModifyResponse *modify_response, GList *modifications,
96 		xmlNode **resource_data);
97 static gint lasso_data_service_apply_modification(LassoDstModify *modify,
98 		LassoDstModification *modification, LassoDstModifyResponse *modify_response,
99 		xmlNode **resource_data);
100 
101 struct _LassoDataServicePrivate {
102 	xmlNode *resource_data;
103 	LassoDiscoResourceID *ResourceID;
104 	LassoDiscoResourceID *EncryptedResourceID;
105 };
106 
107 /*****************************************************************************/
108 /* public methods                                                            */
109 /*****************************************************************************/
110 
111 /**
112  * lasso_data_service_init_query
113  * @service: a #LassoDataService
114  * @select: resource selection string (typically a XPath query)
115  * @item_id: (allow-none): query item identifier (optional)
116  * @security_mech_id: (allow-none): a security mechanism id
117  *
118  * Initializes a new dst:Query request, asking for element @select (with optional itemID set to
119  * @item_id).  @item_id may be NULL only if the query won't contain other query items. You must
120  * follow this constraint, it will not be checked.
121  *
122  * If both @select and @item_id are NULL, only a skeleton request is created and calls to
123  * lasso_data_service_add_query_item() will need to be done.
124  *
125  * Return value: 0 on success; or a negative value otherwise.
126  **/
127 gint
lasso_data_service_init_query(LassoDataService * service,const char * select,const char * item_id,const char * security_mech_id)128 lasso_data_service_init_query(LassoDataService *service, const char *select,
129 	const char *item_id, const char *security_mech_id)
130 {
131 	LassoWsfProfile *wsf_profile = NULL;
132 	LassoDstQuery *query = NULL;
133 	LassoDiscoResourceOffering *offering = NULL;
134 	gint rc = 0;
135 
136 	lasso_bad_param(DATA_SERVICE, service);
137 	wsf_profile = &service->parent;
138 
139 	/* 1. build the message content */
140 	if (select) {
141 		query = lasso_dst_query_new(lasso_dst_query_item_new(select, item_id));
142 	} else {
143 		query = lasso_dst_query_new(NULL);
144 	}
145 	offering = lasso_wsf_profile_get_resource_offering(wsf_profile);
146 	if (! LASSO_IS_DISCO_RESOURCE_OFFERING(offering))
147 		goto cleanup;
148 	lasso_assign_string(query->hrefServiceType, offering->ServiceInstance->ServiceType);
149 	lasso_assign_new_string(query->prefixServiceType, lasso_get_prefix_for_dst_service_href(
150 				query->hrefServiceType));
151 	goto_cleanup_if_fail_with_rc (query->prefixServiceType != NULL,
152 			LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST);
153 	lasso_wsf_profile_helper_assign_resource_id(query, offering);
154 
155 	/* 2. build the envelope */
156 	rc = lasso_wsf_profile_init_soap_request(wsf_profile, &query->parent);
157 	if (rc)
158 		goto cleanup;
159 
160 	/* 3. set the security mechanism */
161 	rc = lasso_wsf_profile_set_security_mech_id(wsf_profile, security_mech_id);
162 
163 cleanup:
164 	lasso_release_gobject(query);
165 	lasso_release_gobject(offering);
166 	return rc;
167 }
168 
169 /**
170  * lasso_data_service_add_query_item:
171  * @service: a #LassoDataService
172  * @select: resource selection string (typically a XPath query)
173  * @item_id: query item identifier
174  *
175  * Adds a dst:QueryItem to the current dst:Query request. If there are already query item in the
176  * request and @itemId is NULL, the call will fail.
177  *
178  * Return value: 0 if sucessfull, an error code otherwise.
179  **/
180 gint
lasso_data_service_add_query_item(LassoDataService * service,const char * select,const char * item_id)181 lasso_data_service_add_query_item(LassoDataService *service,
182 		const char *select, const char *item_id)
183 {
184 	LassoWsfProfile *wsf_profile;
185 	LassoDstQuery *query = NULL;
186 	int rc = 0;
187 
188 	lasso_bad_param(DATA_SERVICE, service);
189 	wsf_profile = &service->parent;
190 
191 	lasso_return_val_if_invalid_param(DST_QUERY, wsf_profile->request,
192 			LASSO_PROFILE_ERROR_MISSING_REQUEST);
193 	query = (LassoDstQuery*)wsf_profile->request;
194 
195 	/** Check that we can add a new item */
196 	if (query->QueryItem && (
197 		(query->QueryItem->data &&
198 		 (! LASSO_IS_DST_QUERY_ITEM(query->QueryItem->data) ||
199 		  LASSO_DST_QUERY_ITEM(query->QueryItem->data)->itemID == NULL)) ||
200 		(item_id == NULL))) {
201 		return LASSO_DATA_SERVICE_ERROR_CANNOT_ADD_ITEM;
202 	}
203 
204 	lasso_list_add_new_gobject(query->QueryItem, lasso_dst_query_item_new(select, item_id));
205 
206 	return rc;
207 }
208 
209 /**
210  * lasso_data_service_get_query_item:
211  * @service: a #LassoDataService
212  * @select: the select string of the query item to found
213  * @item_id: the item id of the query item to found
214  * @output:(transfer none): a #LassoDstQueryItem handle to store the result object, its reference count is not
215  * incremented.
216  *
217  * Look up the first query item in the current request matching the given criteria, @select or
218  * @item_id. At least one of the criteria must be present for the call to succeed.
219  *
220  * Return value: 0 if successful, an error code otherwise.
221  */
222 gint
lasso_data_service_get_query_item(LassoDataService * service,const char * select,const char * item_id,LassoDstQueryItem ** output)223 lasso_data_service_get_query_item(LassoDataService *service,
224 		const char *select, const char *item_id, LassoDstQueryItem **output)
225 {
226 	LassoDstQuery *query = NULL;
227 	GList *query_items = NULL;
228 	LassoWsfProfile *wsf_profile = NULL;
229 	gint rc = 0;
230 
231 	lasso_bad_param(DATA_SERVICE, service);
232 	g_return_val_if_fail(select || item_id, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
233 	wsf_profile = &service->parent;
234 	lasso_extract_node_or_fail(query, wsf_profile->request, DST_QUERY, LASSO_PROFILE_ERROR_MISSING_REQUEST);
235 	lasso_foreach(query_items, query->QueryItem)
236 	{
237 		LassoDstQueryItem *query_item = NULL;
238 		lasso_extract_node_or_fail(query_item, query_items->data, DST_QUERY_ITEM, LASSO_ERROR_CAST_FAILED);
239 		if ((select && lasso_strisequal(select,query_item->Select)) ||
240 			(item_id && lasso_strisequal(item_id,query_item->itemID)))
241 		{
242 			if (output) {
243 				lasso_assign_new_gobject(*output, query_item);
244 			}
245 		}
246 	}
247 
248 cleanup:
249 	return rc;
250 }
251 
252 /**
253  * lasso_data_service_process_query_msg:
254  * @service: a #LassoDataService
255  * @message: the dst query message
256  *
257  * Processes a dst:Query message.  Rebuilds a request object from the message
258  * and extracts ResourceID.
259  *
260  * Return value: 0 on success; or a negative value otherwise.
261  **/
262 static gint
lasso_data_service_process_query_msg(LassoDataService * service,LassoDstQuery * query)263 lasso_data_service_process_query_msg(LassoDataService *service, LassoDstQuery *query)
264 {
265 	LassoWsfProfile *wsf_profile = NULL;
266 	LassoDstQueryResponse *query_response = NULL;
267 	gchar *service_type = NULL;
268 	int rc = 0;
269 
270 	wsf_profile = &service->parent;
271 
272 	lasso_assign_string(service_type, query->hrefServiceType);
273 
274 	lasso_wsf_profile_helper_assign_resource_id(service->private_data, query);
275 	query_response = lasso_dst_query_response_new(lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
276 	query_response->prefixServiceType = g_strdup(query->prefixServiceType);
277 	query_response->hrefServiceType = g_strdup(query->hrefServiceType);
278 
279 	rc = lasso_wsf_profile_init_soap_response(wsf_profile, LASSO_NODE(query_response));
280 	lasso_release_gobject(query_response);
281 	return rc;
282 }
283 
284 
285 /**
286  * lasso_data_service_build_response_msg:
287  * @service: a #LassoDataService
288  *
289  * Builds a dst:QueryResponse message.
290  *
291  * Return value: 0 on success; or a negative value otherwise.
292  **/
293 gint
lasso_data_service_build_response_msg(LassoDataService * service)294 lasso_data_service_build_response_msg(LassoDataService *service)
295 {
296 	lasso_bad_param(DATA_SERVICE, service);
297 	return lasso_wsf_profile_build_soap_response_msg(&service->parent);
298 }
299 
300 /**
301  * lasso_data_service_get_answers:
302  * @service: a #LassoDataService object.
303  * @output:(transfer full)(allow-none)(element-type xmlNode): an xmlNode** pointer where to put the xmlNode* of the result
304  *
305  * Get all the xmlNode content of the first Data element of the QueryResponse message.
306  *
307  * Return value: 0 if sucessful, an error code otherwise.
308  */
309 gint
lasso_data_service_get_answers(LassoDataService * service,GList ** output)310 lasso_data_service_get_answers(LassoDataService *service, GList **output)
311 {
312 	LassoDstQueryResponse *query_response = NULL;
313 	LassoDstData *data = NULL;
314 	LassoWsfProfile *wsf_profile = NULL;
315 	GList *datas = NULL;
316 	int rc = 0;
317 
318 	lasso_bad_param(DATA_SERVICE, service);
319 	wsf_profile = &service->parent;
320 	lasso_extract_node_or_fail(query_response, wsf_profile->request, DST_QUERY_RESPONSE,
321 			LASSO_PROFILE_ERROR_MISSING_REQUEST);
322 
323 	datas = query_response->Data;
324 
325 	if (datas) {
326 		lasso_extract_node_or_fail(data, datas->data, DST_DATA,
327 				LASSO_ERROR_CAST_FAILED);
328 	}
329 
330 	if (data) {
331 		if (output) {
332 			GList *data_content = data->any;
333 			lasso_release_list_of_xml_node(*output);
334 			for (;data_content; data_content = g_list_next(data_content)) {
335 				lasso_list_add_xml_node(*output, data_content->data);
336 			}
337 		}
338 	} else {
339 		rc = LASSO_DST_ERROR_NO_DATA;
340 	}
341 
342 cleanup:
343 	return rc;
344 }
345 /**
346  * lasso_data_service_get_answer:
347  * @service: a #LassoDataService object.
348  * @output: (out): an xmlNode** pointer where to put the xmlNode* of the result
349  *
350  * Get the first xmlNode of the first Data element of the QueryResponse message.
351  *
352  * Return value: 0 if sucessful, an error code otherwise.
353  */
354 gint
lasso_data_service_get_answer(LassoDataService * service,xmlNode ** output)355 lasso_data_service_get_answer(LassoDataService *service, xmlNode **output)
356 {
357 	LassoDstQueryResponse *query_response = NULL;
358 	LassoDstData *data = NULL;
359 	LassoWsfProfile *wsf_profile = NULL;
360 	GList *datas = NULL;
361 	int rc = 0;
362 
363 	lasso_bad_param(DATA_SERVICE, service);
364 	wsf_profile = &service->parent;
365 	lasso_extract_node_or_fail(query_response, wsf_profile->response, DST_QUERY_RESPONSE,
366 			LASSO_PROFILE_ERROR_MISSING_RESPONSE);
367 
368 	datas = query_response->Data;
369 
370 	if (datas) {
371 		lasso_extract_node_or_fail(data, datas->data, DST_DATA,
372 				LASSO_ERROR_CAST_FAILED);
373 	}
374 
375 	if (data) {
376 		if (output) {
377 			xmlNode *first_element = NULL;
378 			if (data->any) {
379 				first_element = data->any->data;
380 			}
381 			lasso_assign_xml_node(*output, first_element);
382 		}
383 	} else {
384 		rc = LASSO_DST_ERROR_NO_DATA;
385 	}
386 
387 cleanup:
388 	return rc;
389 }
390 
391 /**
392  * lasso_data_service_get_answers_by_select:
393  * @service: a #LassoDataService
394  * @select: resource selection string (typically a XPath query)
395  * @output: (allow-none) (element-type xmlNode): a GList** to store a GList* containing the result, it must be freed.
396  *
397  * Returns the answers for the specified @select request.
398  *
399  * Return value: 0 if successful, an error code otheriwse
400  *
401  **/
402 gint
lasso_data_service_get_answers_by_select(LassoDataService * service,const char * select,GList ** output)403 lasso_data_service_get_answers_by_select(LassoDataService *service, const char *select, GList **output)
404 {
405 	LassoDstQuery *query = NULL;
406 	LassoDstQueryResponse *query_response = NULL;
407 	LassoDstData *data = NULL;
408 	LassoWsfProfile *wsf_profile = NULL;
409 	LassoDstQueryItem *query_item = NULL;
410 	GList *iter = NULL;
411 	GList *datas = NULL;
412 	int rc = 0;
413 
414 	lasso_bad_param(DATA_SERVICE, service);
415 	lasso_null_param(select);
416 	wsf_profile = &service->parent;
417 	lasso_extract_node_or_fail(query, wsf_profile->request, DST_QUERY,
418 			LASSO_PROFILE_ERROR_MISSING_REQUEST);
419 	lasso_extract_node_or_fail(query_response, wsf_profile->response, DST_QUERY_RESPONSE,
420 			LASSO_PROFILE_ERROR_MISSING_RESPONSE);
421 
422 	iter = query->QueryItem;
423 	datas = query_response->Data;
424 
425 	/* one query, no need for itemID, data is the first one, or absent */
426 	if (iter && iter->next == NULL) {
427 		lasso_extract_node_or_fail(query_item, iter->data, DST_QUERY_ITEM,
428 				LASSO_ERROR_CAST_FAILED);
429 
430 		if (datas) {
431 			lasso_extract_node_or_fail(data, datas->data, DST_DATA,
432 					LASSO_ERROR_CAST_FAILED);
433 			if (lasso_strisnotequal(select,query_item->Select)) {
434 				data = NULL;
435 				rc = LASSO_DST_ERROR_QUERY_NOT_FOUND;
436 			}
437 		} else {
438 			rc = LASSO_DST_ERROR_NO_DATA;
439 		}
440 	/* many queries */
441 	} else {
442 		/* lookup select in query to get itemId, then get data with itemIdRef */
443 		while (iter) {
444 			lasso_extract_node_or_fail(query_item, iter->data, DST_QUERY_ITEM,
445 					LASSO_ERROR_CAST_FAILED);
446 			if (lasso_strisequal(query_item->Select,select)) {
447 				break;
448 			}
449 			query_item = NULL;
450 			iter = g_list_next(iter);
451 		}
452 		if (query_item && ! query_item->itemID) {
453 			goto_cleanup_with_rc(LASSO_DST_ERROR_MALFORMED_QUERY);
454 		}
455 
456 		while (datas) {
457 			lasso_extract_node_or_fail(data, datas->data, DST_DATA,
458 					LASSO_ERROR_CAST_FAILED);
459 			if (lasso_strisequal(data->itemIDRef,query_item->itemID)) {
460 				break;
461 			}
462 			data = NULL;
463 			datas = g_list_next(datas);
464 		}
465 	}
466 
467 	if (data) {
468 		if (output) {
469 			GList *data_content = data->any;
470 			lasso_release_list_of_xml_node(*output);
471 			for (;data_content; data_content = g_list_next(data_content)) {
472 				lasso_list_add_xml_node(*output, data_content->data);
473 			}
474 		}
475 	} else {
476 		rc = LASSO_DST_ERROR_NO_DATA;
477 	}
478 
479 cleanup:
480 	return rc;
481 }
482 
483 /**
484  * lasso_data_service_get_answers_by_item_id:
485  * @service: a #LassoDataService
486  * @item_id: query item identifier
487  * @output: (allow-none) (element-type xmlNode): a GList** to store a GList* containing the result, it must be freed.
488  *
489  * Returns the answers for the specified @itemID request.
490  *
491  * Return value: 0 if successful, an error code otherwise
492  *
493  **/
494 gint
lasso_data_service_get_answers_by_item_id(LassoDataService * service,const char * item_id,GList ** output)495 lasso_data_service_get_answers_by_item_id(LassoDataService *service, const char *item_id, GList **output)
496 {
497 	LassoDstQueryResponse *query_response = NULL;
498 	LassoDstData *data = NULL;
499 	LassoWsfProfile *wsf_profile = NULL;
500 	GList *datas = NULL;
501 	int rc = 0;
502 
503 	lasso_bad_param(DATA_SERVICE, service);
504 	lasso_null_param(select);
505 	wsf_profile = &service->parent;
506 	lasso_extract_node_or_fail(query_response, wsf_profile->request, DST_QUERY_RESPONSE,
507 			LASSO_PROFILE_ERROR_MISSING_REQUEST);
508 
509 	datas = query_response->Data;
510 	while (datas) {
511 		lasso_extract_node_or_fail(data, datas->data, DST_DATA, LASSO_ERROR_CAST_FAILED);
512 		if (lasso_strisequal(data->itemIDRef,item_id)) {
513 			break;
514 		}
515 		data = NULL;
516 		datas = g_list_next(datas);
517 	}
518 
519 	if (data) {
520 		if (output) {
521 			GList *data_content = data->any;
522 			lasso_release_list_of_xml_node(*output);
523 			for (;data_content; data_content = g_list_next(data_content)) {
524 				lasso_list_add_xml_node(*output, data_content->data);
525 			}
526 		}
527 	} else {
528 		rc = LASSO_DST_ERROR_NO_DATA;
529 	}
530 
531 cleanup:
532 	return rc;
533 }
534 
535 /**
536  * lasso_data_service_process_query_response_msg:
537  * @service: a #LassoDataService
538  * @message: the dst query response message
539  *
540  * Processes a dst:Query message.  Rebuilds a request object from the message
541  * and extracts ResourcedID.
542  *
543  * Return value: 0 on success; or a negative value otherwise.
544  **/
545 gint
lasso_data_service_process_query_response_msg(LassoDataService * service,const char * message)546 lasso_data_service_process_query_response_msg(LassoDataService *service,
547 	const char *message)
548 {
549 	int rc = 0;
550 
551 	rc = lasso_wsf_profile_process_soap_response_msg(LASSO_WSF_PROFILE(service), message);
552 	if (! rc && ! LASSO_IS_DST_QUERY_RESPONSE(service->parent.response)) {
553 		rc = LASSO_PROFILE_ERROR_MISSING_RESPONSE;
554 	}
555 
556 	return rc;
557 }
558 
559 /**
560  * lasso_data_service_init_modify:
561  * @service: a #LassoDataService object
562  * @security_mech_id: (allow-none): a security mechanism id
563  *
564  * Initialize a Data Service Template Modify request using a command to select some data, and an XML
565  * fragment to replace the selected data.
566  *
567  * Return value: 0 if successful, an error code otherwise.
568  */
569 gint
lasso_data_service_init_modify(LassoDataService * service,const char * security_mech_id)570 lasso_data_service_init_modify(LassoDataService *service, const char *security_mech_id)
571 {
572 	LassoDiscoResourceOffering *offering = NULL;
573 	LassoWsfProfile *wsf_profile = NULL;
574 	LassoDstModify *modify = NULL;
575 	gint rc = 0;
576 
577 	lasso_bad_param(DATA_SERVICE, service);
578 	lasso_null_param(service);
579 	wsf_profile = &service->parent;
580 
581 	/* 1. build the message content */
582 	modify = lasso_dst_modify_new();
583 
584 	offering = lasso_wsf_profile_get_resource_offering(wsf_profile);
585 	goto_cleanup_if_fail_with_rc (LASSO_IS_DISCO_RESOURCE_OFFERING(offering), LASSO_PROFILE_ERROR_MISSING_RESOURCE_OFFERING);
586 	goto_cleanup_if_fail_with_rc (offering->ServiceInstance != NULL &&
587 			offering->ServiceInstance->ServiceType != NULL,
588 			LASSO_PROFILE_ERROR_MISSING_SERVICE_TYPE);
589 	lasso_assign_string(modify->hrefServiceType, offering->ServiceInstance->ServiceType);
590 	lasso_assign_new_string(modify->prefixServiceType, lasso_get_prefix_for_dst_service_href(
591 				modify->hrefServiceType));
592 	goto_cleanup_if_fail_with_rc (modify->prefixServiceType != NULL, LASSO_DATA_SERVICE_ERROR_UNREGISTERED_DST);
593 	lasso_wsf_profile_helper_assign_resource_id(modify, offering);
594 
595 	/* 2. build the envelope */
596 	rc = lasso_wsf_profile_init_soap_request(wsf_profile, &modify->parent);
597 	if (rc)
598 		goto cleanup;
599 
600 	/* 3. set the security mechanism */
601 	rc = lasso_wsf_profile_set_security_mech_id(wsf_profile, security_mech_id);
602 
603 cleanup:
604 	lasso_release_gobject(modify);
605 	lasso_release_gobject(offering);
606 	return rc;
607 }
608 
609 /**
610  * lasso_data_service_add_modification:
611  * @service: a #LassoDataService object
612  * @select: a selector string
613  * @xmlData: (allow-none): optional NewData content
614  * @overrideAllowed: (allow-none)(default FALSE):whether to permit delete or replace of existings
615  * @notChangedSince: (allow-none): if not NULL, give the time (as a local time_t value) of the last known
616  * modification to the datas, it is used to permit secure concurrent accesses.
617  * @output: (out): a #LassoDstModification** pointer where to put the #LassoDstModification of the result
618  *
619  * Add a new modification to the current modify request. If overrideAllowed is FALSE, xmlData must
620  * absolutely be present. Refer to the ID-WSF DST 1.0 specification for the semantic of the created
621  * message.
622  *
623  * Return value: 0 if successful and the new modification object in *output, an error code
624  * otherwise.
625  */
626 gint
lasso_data_service_add_modification(LassoDataService * service,const gchar * select,xmlNode * xmlData,gboolean overrideAllowed,time_t * notChangedSince,LassoDstModification ** output)627 lasso_data_service_add_modification(LassoDataService *service, const gchar *select,
628 		xmlNode *xmlData, gboolean overrideAllowed, time_t *notChangedSince,
629 		LassoDstModification **output)
630 {
631 	LassoWsfProfile *wsf_profile = NULL;
632 	LassoDstModification *modification = NULL;
633 	LassoDstNewData *newData = NULL;
634 	LassoDstModify *modify = NULL;
635 	gint rc = 0;
636 
637 	lasso_bad_param(DATA_SERVICE, service);
638 	lasso_null_param(select);
639 
640 	wsf_profile = &service->parent;
641 	lasso_extract_node_or_fail(modify, wsf_profile->request, DST_MODIFY,
642 			LASSO_ERROR_CAST_FAILED);
643 
644 	modification = lasso_dst_modification_new(select);
645 	newData = lasso_dst_new_data_new();
646 	lasso_release_list_of_xml_node(newData->any);
647 	lasso_list_add_xml_node(newData->any, xmlData);
648 	lasso_assign_new_gobject(modification->NewData, newData);
649 	lasso_list_add_new_gobject(modify->Modification,
650 			modification);
651 	modification->overrideAllowed = overrideAllowed;
652 	if (notChangedSince) {
653 		lasso_assign_new_string(modification->notChangedSince,
654 				lasso_time_to_iso_8601_gmt(*notChangedSince));
655 	}
656 
657 	if (*output) {
658 		lasso_assign_gobject(*output, modification);
659 	}
660 
661 cleanup:
662 	return rc;
663 }
664 
665 static gint
lasso_data_service_apply_modification(LassoDstModify * modify,LassoDstModification * modification,LassoDstModifyResponse * modify_response,xmlNode ** resource_data)666 lasso_data_service_apply_modification(LassoDstModify *modify, LassoDstModification *modification, LassoDstModifyResponse *modify_response,
667 		xmlNode **resource_data)
668 {
669 	gint rc = 0;
670 	xmlXPathObject *xpathObj = NULL;
671 	gint xpath_error_code = 0;
672 	char *failure_code = NULL;
673 	LassoDstNewData *NewData = NULL;
674 	xmlNode *cur_data = NULL;
675 	xmlDoc *doc = NULL;
676 	xmlXPathContext *xpathCtx = NULL;
677 	GList *node_to_free = NULL;
678 	gboolean overrideAllowed = modification->overrideAllowed;
679 
680 	if (LASSO_IS_DST_NEW_DATA(modification->NewData)) {
681 		NewData = modification->NewData;
682 	}
683 
684 	if (! modification->Select) {
685 		failure_code = LASSO_DST_STATUS_CODE_MISSING_SELECT;
686 		goto failure;
687 	}
688 
689 	if ((! NewData || ! NewData->any) && ! overrideAllowed) {
690 		failure_code = LASSO_DST_STATUS_CODE_MISSING_NEW_DATA_ELEMENT;
691 		goto failure;
692 	}
693 
694 	lasso_assign_xml_node(cur_data, *resource_data);
695 	doc = xmlNewDoc((xmlChar*)"1.0");
696 	xmlDocSetRootElement(doc, cur_data);
697 	xpathCtx = xmlXPathNewContext(doc);
698 	lasso_register_idwsf_xpath_namespaces(xpathCtx);
699 
700 	/* register namespace of the query */
701 	xmlXPathRegisterNs(xpathCtx, BAD_CAST(modify->prefixServiceType), BAD_CAST(modify->hrefServiceType));
702 	if (lasso_eval_xpath_expression(xpathCtx, modification->Select, &xpathObj, &xpath_error_code)) {
703 		if (xpathObj && xpathObj->type == XPATH_NODESET) {
704 			if (xmlXPathNodeSetIsEmpty(xpathObj->nodesetval) || (xpathObj->nodesetval->nodeNr > 1 && NewData))
705 			{
706 				failure_code = "too few or too much targets";
707 				goto failure;
708 			}
709 			if (NewData) {
710 				xmlNode *target = xpathObj->nodesetval->nodeTab[0];
711 				GList *new_nodes = NewData->any;
712 
713 				if (target == cur_data && overrideAllowed){
714 					if (new_nodes->next) {
715 						failure_code = "cannot replace root node by multiple nodes";
716 						goto failure;
717 					}
718 					xmlDocSetRootElement(doc,
719 							xmlCopyNode((xmlNode*)new_nodes->data,
720 								1));
721 					lasso_list_add_xml_node(node_to_free, target);
722 				} else {
723 					while (new_nodes) {
724 						xmlNode *new_data = NULL;
725 						lasso_assign_xml_node(new_data, (xmlNode*)new_nodes->data);
726 						if (overrideAllowed)
727 							xmlAddNextSibling(target, new_data);
728 						else
729 							xmlAddChild(target, new_data);
730 						new_nodes = g_list_next(new_nodes);
731 					}
732 					if (overrideAllowed) {
733 						xmlUnlinkNode(target);
734 						lasso_list_add_xml_node(node_to_free, target);
735 					}
736 				}
737 			} else {
738 				int i;
739 				for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
740 					xmlNode *target = xpathObj->nodesetval->nodeTab[i];
741 					g_assert(overrideAllowed);
742 					xmlUnlinkNode(target);
743 					lasso_list_add_xml_node(node_to_free, target);
744 				}
745 			}
746 		} else {
747 			failure_code = LASSO_DST_STATUS_CODE_INVALID_SELECT;
748 			goto failure;
749 		}
750 
751 	}
752 	lasso_assign_xml_node(*resource_data, xmlDocGetRootElement(doc));
753 	goto cleanup;
754 
755 failure:
756 		lasso_wsf_profile_helper_set_status(modify_response, LASSO_DST_STATUS_CODE_FAILED);
757 		lasso_wsf_profile_helper_set_status(modify_response->Status, failure_code);
758 		rc = LASSO_DST_ERROR_MODIFY_FAILED;
759 
760 cleanup:
761 	lasso_release_xpath_object(xpathObj);
762 	lasso_release_xpath_context(xpathCtx);
763 	g_list_foreach(node_to_free, (GFunc)xmlFreeNode, NULL);
764 	lasso_release_doc(doc);
765 	lasso_release_list(node_to_free);
766 	return rc;
767 }
768 
769 static gint
lasso_data_service_apply_modifications(LassoDstModify * modify,LassoDstModifyResponse * modify_response,GList * modifications,xmlNode ** resource_data)770 lasso_data_service_apply_modifications(LassoDstModify *modify,
771 		LassoDstModifyResponse *modify_response, GList *modifications,
772 		xmlNode **resource_data)
773 {
774 	gint rc = 0;
775 
776 	/* 1. check modifications */
777 	if (modifications && modifications->next) {
778 		lasso_foreach_full_begin(LassoDstModification*, modification, i, modifications)
779 		{
780 			if (! LASSO_IS_DST_MODIFICATION(modification) ||
781 					! modification->id)
782 			{
783 				lasso_wsf_profile_helper_set_status(modify_response,
784 						LASSO_DST_STATUS_CODE_FAILED);
785 				lasso_wsf_profile_helper_set_status(modify_response->Status,
786 						"id expected");
787 				goto_cleanup_with_rc(LASSO_DST_ERROR_QUERY_FAILED);
788 			}
789 		}
790 		lasso_foreach_full_end()
791 	}
792 	/* 2. setup workbench */
793 
794 	lasso_foreach_full_begin(LassoDstModification*, modification, i, modifications)
795 	{
796 		rc = lasso_data_service_apply_modification(modify, modification, modify_response,
797 				resource_data);
798 		// First error, stop
799 		if (rc) {
800 			goto cleanup;
801 		}
802 	}
803 	lasso_foreach_full_end()
804 cleanup:
805 	return rc;
806 }
807 
808 /* Internal implementation for processing query request messages */
809 static gint
lasso_data_service_validate_query_request(LassoDataService * service,xmlNode * data)810 lasso_data_service_validate_query_request(LassoDataService *service, xmlNode *data)
811 {
812 	LassoWsfProfile *wsf_profile = &service->parent;
813 	LassoDstQuery *query = NULL;
814 	LassoDstQueryResponse *query_response = NULL;
815 	gint rc = 0;
816 
817 	/* already checked by lasso_data_service_validate_request */
818 	query = (LassoDstQuery*)wsf_profile->request;
819 	lasso_extract_node_or_fail(query_response, wsf_profile->response, DST_QUERY_RESPONSE, LASSO_PROFILE_ERROR_MISSING_RESPONSE);
820 
821 	rc = lasso_data_service_apply_queries(service, query_response, query->QueryItem, data);
822 
823 cleanup:
824 	return rc;
825 }
826 
827 /* Internal implementation for processing modify request messages */
828 static gint
lasso_data_service_validate_modify_request(LassoDataService * service,xmlNode ** data)829 lasso_data_service_validate_modify_request(LassoDataService *service, xmlNode **data)
830 {
831 	LassoWsfProfile *wsf_profile = &service->parent;
832 	LassoDstModify *modify = NULL;
833 	LassoDstModifyResponse *modify_response = NULL;
834 	gint rc = 0;
835 
836 	/* already checked in lasso_data_service_validate_request */
837 	modify = (LassoDstModify*)wsf_profile->request;
838 	lasso_extract_node_or_fail(modify_response, service->parent.response, DST_MODIFY_RESPONSE,
839 			LASSO_PROFILE_ERROR_MISSING_RESPONSE);
840 
841 	rc = lasso_data_service_apply_modifications(modify, modify_response, modify->Modification, data);
842 
843 cleanup:
844 	return rc;
845 }
846 
847 gint
lasso_data_service_validate_request(LassoDataService * service)848 lasso_data_service_validate_request(LassoDataService *service)
849 {
850 	LassoWsfProfile *wsf_profile = NULL;
851 	xmlNode *resource_data = NULL;
852 	gint rc = 0;
853 
854 	lasso_bad_param(DATA_SERVICE, service);
855 	wsf_profile = &service->parent;
856 	g_return_val_if_fail(service->private_data, LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
857 	resource_data = service->private_data->resource_data;
858 	if (! resource_data) {
859 		rc = LASSO_DST_ERROR_MISSING_SERVICE_DATA;
860 		goto cleanup;
861 	}
862 
863 	if (! LASSO_IS_NODE(wsf_profile->request)) {
864 		rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
865 		goto cleanup;
866 	} else {
867 		if (LASSO_IS_DST_QUERY(wsf_profile->request)) {
868 			rc = lasso_data_service_validate_query_request(service, service->private_data->resource_data);
869 		} else if (LASSO_IS_DST_MODIFY(wsf_profile->request)) {
870 			rc = lasso_data_service_validate_modify_request(service, &service->private_data->resource_data);
871 		} else {
872 			rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
873 			goto cleanup;
874 		}
875 	}
876 
877 cleanup:
878 	return rc;
879 }
880 
881 gint
lasso_data_service_build_modify_response_msg(LassoDataService * service)882 lasso_data_service_build_modify_response_msg(LassoDataService *service)
883 {
884 	return lasso_data_service_build_response_msg(service);
885 }
886 
887 gint
lasso_data_service_build_query_response_msg(LassoDataService * service)888 lasso_data_service_build_query_response_msg(LassoDataService *service)
889 {
890 	return lasso_data_service_build_response_msg(service);
891 }
892 
893 /**
894  * lasso_data_service_process_modify_msg:
895  * @service: a #LassoDataService object
896  * @modify_soap_msg: the SOAP request string
897  * @security_mech_id: the security mechanism to apply
898  *
899  * Parse the given request message, and initialize needed structures.
900  *
901  * Return value: 0 if successful, an error code otherwise.
902  */
903 static gint
lasso_data_service_process_modify_msg(LassoDataService * service,LassoDstModify * modify)904 lasso_data_service_process_modify_msg(LassoDataService *service, LassoDstModify *modify)
905 {
906 	LassoDstModifyResponse *modify_response = NULL;
907 	LassoWsfProfile *wsf_profile = NULL;
908 	int rc = 0;
909 
910 	wsf_profile = &service->parent;
911 
912 	lasso_wsf_profile_helper_assign_resource_id(service->private_data, modify);
913 	modify_response = lasso_dst_modify_response_new(lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
914 	lasso_assign_string(modify_response->prefixServiceType, modify->prefixServiceType);
915 	lasso_assign_string(modify_response->hrefServiceType, modify->hrefServiceType);
916 	rc = lasso_wsf_profile_init_soap_response(wsf_profile, LASSO_NODE(modify_response));
917 	lasso_release_gobject(modify_response);
918 	return rc;
919 }
920 
921 /**
922  * lasso_data_service_process_modify_response_msg
923  * @service: a #LassoDataService
924  * @soap_msg: the SOAP message
925  *
926  * Process a modify response message.
927  *
928  * Return value: 0 on success; or a negative value otherwise.
929  **/
930 gint
lasso_data_service_process_modify_response_msg(LassoDataService * service,const gchar * soap_msg)931 lasso_data_service_process_modify_response_msg(LassoDataService *service, const gchar *soap_msg)
932 {
933 	int rc = 0;
934 
935 	lasso_bad_param(DATA_SERVICE, service);
936 	lasso_null_param(soap_msg);
937 
938 	rc = lasso_wsf_profile_process_soap_response_msg(&service->parent, soap_msg);
939 
940 	if ( rc == 0 && ! LASSO_IS_DST_MODIFY_RESPONSE(service->parent.response)) {
941 		rc = LASSO_PROFILE_ERROR_MISSING_RESPONSE;
942 	}
943 
944 	return rc;
945 }
946 
947 
948 /*****************************************************************************/
949 /* private methods                                                           */
950 /*****************************************************************************/
951 
952 static LassoNodeClass *parent_class = NULL;
953 
954 static void
register_xpath_namespace(gchar * prefix,gchar * href,xmlXPathContext * xpathCtx)955 register_xpath_namespace(gchar *prefix, gchar *href, xmlXPathContext *xpathCtx)
956 {
957 	xmlXPathRegisterNs(xpathCtx, (xmlChar*)prefix, (xmlChar*)href);
958 }
959 
960 static void
lasso_register_idwsf_xpath_namespaces(xmlXPathContext * xpathCtx)961 lasso_register_idwsf_xpath_namespaces(xmlXPathContext *xpathCtx)
962 {
963 	xmlXPathRegisterNs(xpathCtx, (xmlChar*)LASSO_PP10_PREFIX,
964 			(xmlChar*)LASSO_PP10_HREF);
965 	xmlXPathRegisterNs(xpathCtx, (xmlChar*)LASSO_EP_PREFIX,
966 			(xmlChar*)LASSO_EP_HREF);
967 	if (dst_services_by_prefix == NULL)
968 		return;
969 	g_hash_table_foreach(dst_services_by_prefix,
970 			(GHFunc)register_xpath_namespace, xpathCtx);
971 }
972 
973 static gint
lasso_data_service_apply_query(LassoDataService * service,LassoDstQueryResponse * query_response,xmlXPathContext * xpathCtx,LassoDstQueryItem * item)974 lasso_data_service_apply_query(LassoDataService *service, LassoDstQueryResponse *query_response, xmlXPathContext *xpathCtx, LassoDstQueryItem *item)
975 {
976 	gint rc = 0;
977 	xmlXPathObject *xpathObj = NULL;
978 	gint xpath_error_code = 0;
979 
980 	lasso_bad_param(DATA_SERVICE, service);
981 	lasso_bad_param(DST_QUERY_RESPONSE, query_response);
982 	lasso_bad_param(DST_QUERY_ITEM, item);
983 
984 	if (! item->Select) {
985 		lasso_wsf_profile_helper_set_status(query_response, LASSO_DST_STATUS_CODE_FAILED);
986 		lasso_wsf_profile_helper_set_status(query_response->Status, LASSO_DST_STATUS_CODE_MISSING_SELECT);
987 		goto_cleanup_with_rc(LASSO_DST_ERROR_QUERY_FAILED);
988 	}
989 
990 	if (lasso_eval_xpath_expression(xpathCtx, item->Select, &xpathObj, &xpath_error_code)) {
991 		LassoDstData *data = NULL;
992 
993 		/* Found zero or more node answers */
994 		if (xpathObj && xpathObj->type == XPATH_NODESET){
995 			int i = 0;
996 
997 			if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
998 				data = lasso_dst_data_new();
999 			}
1000 
1001 			for (i = 0; xpathObj->nodesetval && i < xpathObj->nodesetval->nodeNr;
1002 					i++) {
1003 				lasso_list_add_xml_node(data->any,
1004 						xpathObj->nodesetval->nodeTab[i]);
1005 			}
1006 		/* Found other kind of answers, convert to string */
1007 		} else  {
1008 			xmlChar *str;
1009 
1010 			data = lasso_dst_data_new();
1011 			str = xmlXPathCastToString(xpathObj);
1012 			lasso_list_add_xml_node(data->any, xmlNewText(str));
1013 			lasso_release_xml_string(str);
1014 		}
1015 		if (data) {
1016 			lasso_assign_string(data->itemIDRef, item->itemID);
1017 			lasso_list_add_gobject(query_response->Data, data);
1018 		}
1019 		lasso_release_gobject(data);
1020 	} else {
1021 		char *code = g_strdup_printf("LIBXML_XPATH_ERROR_%d", xpath_error_code);
1022 
1023 		lasso_wsf_profile_helper_set_status(query_response, LASSO_DST_STATUS_CODE_FAILED);
1024 		lasso_wsf_profile_helper_set_status(query_response->Status, LASSO_DST_STATUS_CODE_INVALID_SELECT);
1025 		lasso_wsf_profile_helper_set_status(query_response->Status->Status, code);
1026 		lasso_release_string(code);
1027 		goto_cleanup_with_rc(1);
1028 	}
1029 
1030 cleanup:
1031 	lasso_release_xpath_object(xpathObj);
1032 	return rc;
1033 }
1034 
1035 static gint
lasso_data_service_apply_queries(LassoDataService * service,LassoDstQueryResponse * query_response,GList * queries,xmlNode * data)1036 lasso_data_service_apply_queries(LassoDataService *service, LassoDstQueryResponse *query_response, GList *queries, xmlNode *data)
1037 {
1038 	gint rc = 0;
1039 	LassoWsfProfile *wsf_profile = NULL;
1040 	xmlDoc *doc = NULL;
1041 	xmlXPathContext *xpathCtx = NULL;
1042 	GList *query = NULL;
1043 
1044 	lasso_bad_param(DATA_SERVICE, service);
1045 	g_return_val_if_fail(service->private_data, LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
1046 	wsf_profile = &service->parent;
1047 
1048 	/* 1. Check query */
1049 	if (queries && queries->next) {
1050 		GList *q = queries;
1051 		while (q) {
1052 			if (! LASSO_IS_DST_QUERY_ITEM(q->data) || !
1053 					LASSO_DST_QUERY_ITEM(q->data)->itemID) {
1054 				lasso_wsf_profile_helper_set_status(query_response,
1055 						LASSO_DST_STATUS_CODE_FAILED);
1056 				lasso_wsf_profile_helper_set_status(query_response->Status,
1057 						"itemID expected");
1058 				goto_cleanup_with_rc(LASSO_DST_ERROR_QUERY_FAILED);
1059 			}
1060 			q = g_list_next(q);
1061 		}
1062 	}
1063 
1064 	/* 1. Setup workbench */
1065 	doc = xmlNewDoc((xmlChar*)"1.0");
1066 	xmlDocSetRootElement(doc, data);
1067 	xpathCtx = xmlXPathNewContext(doc);
1068 	lasso_register_idwsf_xpath_namespaces(xpathCtx);
1069 
1070 	lasso_foreach (query, queries) {
1071 		LassoDstQueryItem *item = query->data;
1072 
1073 		goto_cleanup_if_fail_with_rc(lasso_data_service_apply_query(service, query_response,
1074 					xpathCtx, item) == 0, query_response->Data ?
1075 				LASSO_DST_ERROR_QUERY_PARTIALLY_FAILED :
1076 				LASSO_DST_ERROR_QUERY_FAILED);
1077 	}
1078 
1079 cleanup:
1080 	xmlUnlinkNode(service->private_data->resource_data);
1081 	xmlSetTreeDoc(service->private_data->resource_data, NULL);
1082 	lasso_release_xpath_context(xpathCtx);
1083 	lasso_release_doc(doc);
1084 
1085 	return rc;
1086 }
1087 
1088 /**
1089  * lasso_data_service_process_request_msg:
1090  * @service: a #LassoDataService object
1091  * @message: a C string containing the SOAP request
1092  * @security_mech_id:(allow-none): a C string describing the required security mechanism or NULL
1093  *
1094  * Return value: 0 if successfull, an error code otherwise.
1095  */
1096 gint
lasso_data_service_process_request_msg(LassoDataService * service,const char * message,const char * security_mech_id)1097 lasso_data_service_process_request_msg(LassoDataService *service,
1098 		const char *message, const char *security_mech_id)
1099 {
1100 	LassoWsfProfile *wsf_profile = NULL;
1101 	LassoNode *request = NULL;
1102 	int rc = 0;
1103 
1104 	lasso_bad_param(DATA_SERVICE, service);
1105 	lasso_null_param(message);
1106 	wsf_profile = &service->parent;
1107 
1108 	rc = lasso_wsf_profile_process_soap_request_msg(wsf_profile, message, security_mech_id);
1109 	goto_cleanup_if_fail(! rc);
1110 	request = wsf_profile->request;
1111 	if (LASSO_IS_DST_QUERY(request)) {
1112 		rc = lasso_data_service_process_query_msg(service, (LassoDstQuery*)request);
1113 	} else if (LASSO_IS_DST_MODIFY(wsf_profile->request)) {
1114 		rc = lasso_data_service_process_modify_msg(service, (LassoDstModify*)request);
1115 	} else {
1116 		rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
1117 	}
1118 cleanup:
1119 	return rc;
1120 }
1121 
1122 /*****************************************************************************/
1123 /* overrided parent class methods */
1124 /*****************************************************************************/
1125 
1126 static void
dispose(GObject * object)1127 dispose(GObject *object)
1128 {
1129 	LassoDataService *service = LASSO_DATA_SERVICE(object);
1130 
1131 	lasso_release_xml_node(service->private_data->resource_data);
1132 	lasso_release_gobject(service->private_data->ResourceID);
1133 	lasso_release_gobject(service->private_data->EncryptedResourceID);
1134 
1135 	G_OBJECT_CLASS(parent_class)->dispose(object);
1136 }
1137 
1138 static void
finalize(GObject * object)1139 finalize(GObject *object)
1140 {
1141 	lasso_release(((LassoDataService*)object)->private_data);
1142 
1143 	G_OBJECT_CLASS(parent_class)->finalize(object);
1144 }
1145 
1146 
1147 /*****************************************************************************/
1148 /* instance and class init functions                                         */
1149 /*****************************************************************************/
1150 
1151 static void
instance_init(LassoDataService * service)1152 instance_init(LassoDataService *service)
1153 {
1154 	service->private_data = g_new0(LassoDataServicePrivate, 1);
1155 }
1156 
1157 static void
class_init(LassoDataServiceClass * klass,void * unused G_GNUC_UNUSED)1158 class_init(LassoDataServiceClass *klass, void *unused G_GNUC_UNUSED)
1159 {
1160 	parent_class = g_type_class_peek_parent(klass);
1161 
1162 	G_OBJECT_CLASS(klass)->dispose = dispose;
1163 	G_OBJECT_CLASS(klass)->finalize = finalize;
1164 }
1165 
1166 GType
lasso_data_service_get_type()1167 lasso_data_service_get_type()
1168 {
1169 	static GType this_type = 0;
1170 
1171 	if (!this_type) {
1172 		static const GTypeInfo this_info = {
1173 			sizeof(LassoDataServiceClass),
1174 			NULL,
1175 			NULL,
1176 			(GClassInitFunc) class_init,
1177 			NULL,
1178 			NULL,
1179 			sizeof(LassoDataService),
1180 			0,
1181 			(GInstanceInitFunc) instance_init,
1182 			NULL
1183 		};
1184 
1185 		this_type = g_type_register_static(LASSO_TYPE_WSF_PROFILE,
1186 				"LassoDataService", &this_info, 0);
1187 	}
1188 	return this_type;
1189 }
1190 
1191 
1192 /**
1193  * lasso_data_service_new:
1194  * @server: the #LassoServer
1195  *
1196  * Creates a new #LassoDataService.
1197  *
1198  * Return value: a newly created #LassoDataService object; or NULL if an
1199  *      error occured.
1200  **/
1201 LassoDataService*
lasso_data_service_new(LassoServer * server)1202 lasso_data_service_new(LassoServer *server)
1203 {
1204 	LassoDataService *service;
1205 
1206 	g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
1207 
1208 	service = g_object_new(LASSO_TYPE_DATA_SERVICE, NULL);
1209 	LASSO_WSF_PROFILE(service)->server = g_object_ref(server);
1210 
1211 	return service;
1212 }
1213 
1214 /**
1215  * lasso_data_service_new_full:
1216  * @server: the #LassoServer
1217  * @offering: the #LassoDiscoResourceOffering
1218  *
1219  * Creates a new #LassoDataService.
1220  *
1221  * Return value: a newly created #LassoDataService object; or NULL if an error occured.
1222  **/
1223 LassoDataService*
lasso_data_service_new_full(LassoServer * server,LassoDiscoResourceOffering * offering)1224 lasso_data_service_new_full(LassoServer *server, LassoDiscoResourceOffering *offering)
1225 {
1226 	LassoDataService *service = lasso_data_service_new(server);
1227 
1228 	g_return_val_if_fail(LASSO_IS_DISCO_RESOURCE_OFFERING(offering), NULL);
1229 
1230 	if (service == NULL) {
1231 		return NULL;
1232 	}
1233 
1234 	lasso_wsf_profile_set_resource_offering(&service->parent, offering);
1235 
1236 	return service;
1237 }
1238 
1239 /**
1240  * lasso_data_service_set_resource_data:
1241  * @service: a #LassoDataService object
1242  * @resource_data: (allow-none): an xmlnode representing the resource data of the service
1243  *
1244  * Set the resource data content.
1245  */
1246 void
lasso_data_service_set_resource_data(LassoDataService * service,const xmlNode * resource_data)1247 lasso_data_service_set_resource_data(LassoDataService *service, const xmlNode *resource_data)
1248 {
1249 	lasso_assign_xml_node(service->private_data->resource_data, (xmlNode*)resource_data);
1250 }
1251 
1252 
1253 /**
1254  * lasso_data_service_get_resource_data:
1255  * @service: a #LassoDataService object
1256  *
1257  * Return the XML resrouce data in this data service.
1258  *
1259  * Return value:(transfer full)(allow-none): a newly allocated #xmlNode or NULL.
1260  */
1261 xmlNode *
lasso_data_service_get_resource_data(LassoDataService * service)1262 lasso_data_service_get_resource_data(LassoDataService *service)
1263 {
1264 	xmlNode *rv = NULL;
1265 
1266 	lasso_assign_xml_node(rv, service->private_data->resource_data);
1267 
1268 	return rv;
1269 }
1270