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