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