10 /* Get ISDS status info from ISDS @response XML document.
11 * Be ware that different request families return differently encoded status
12 * (e.g. dmStatus, dbStatus)
13 * @context is ISDS context
14 * @service is ISDS web service identifier
15 * @response is ISDS response document
16 * @code is automatically allocated status code of the response
17 * @message is automatically allocated status message. Returned NULL means no
18 * message was delivered by server. Use NULL if you don't care.
19 * @refnumber is automatically reallocated request serial number assigned by
20 * ISDS. Returned *NULL means no number was delivered by server.
21 * Use NULL if you don't care. */
22 _hidden isds_error
isds_response_status(struct isds_ctx
*context
,
23 const isds_service service
, xmlDocPtr response
,
24 xmlChar
**code
, xmlChar
**message
, xmlChar
**refnumber
) {
25 isds_error err
= IE_SUCCESS
;
26 xmlChar
*status_code_expr
= NULL
, *status_message_expr
= NULL
;
27 xmlXPathContextPtr xpath_ctx
= NULL
;
28 xmlXPathObjectPtr result
= NULL
;
30 if (!response
|| !code
) {
36 case SERVICE_DM_OPERATIONS
:
38 status_code_expr
= BAD_CAST
39 "/*/isds:dmStatus/isds:dmStatusCode/text()";
40 status_message_expr
= BAD_CAST
41 "/*/isds:dmStatus/isds:dmStatusMessage/text()";
43 case SERVICE_DB_SEARCH
:
44 case SERVICE_DB_ACCESS
:
45 case SERVICE_DB_MANIPULATION
:
46 status_code_expr
= BAD_CAST
47 "/*/isds:dbStatus/isds:dbStatusCode/text()";
48 status_message_expr
= BAD_CAST
49 "/*/isds:dbStatus/isds:dbStatusMessage/text()";
52 status_code_expr
= BAD_CAST
53 "/*/oisds:dbStatus/oisds:dbStatusCode/text()";
54 status_message_expr
= BAD_CAST
55 "/*/oisds:dbStatus/oisds:dbStatusMessage/text()";
62 xpath_ctx
= xmlXPathNewContext(response
);
67 if (_isds_register_namespaces(xpath_ctx
,
68 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
69 MESSAGE_NS_1
: MESSAGE_NS_UNSIGNED
)) {
75 result
= xmlXPathEvalExpression(status_code_expr
, xpath_ctx
);
80 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
81 isds_log_message(context
,
82 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
83 _("ISDS1 response is missing StatusCode element") :
84 _("ISDS response is missing StatusCode element"));
88 *code
= xmlXPathCastNodeSetToString(result
->nodesetval
);
95 /* Get status message */
96 xmlXPathFreeObject(result
);
97 result
= xmlXPathEvalExpression(status_message_expr
, xpath_ctx
);
102 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
103 /* E.g. CreateMessageResponse with dmStatusCode 9005 has empty
107 *message
= xmlXPathCastNodeSetToString(result
->nodesetval
);
108 if (NULL
== *message
) {
116 /* Get reference number of client request */
118 xmlXPathFreeObject(result
);
119 result
= xmlXPathEvalExpression(
120 (SERVICE_ASWS
== service
) ?
121 BAD_CAST
"/*/oisds:dbStatus/oisds:dbStatusRefNumber/text()":
122 BAD_CAST
"/*/isds:dbStatus/isds:dbStatusRefNumber/text()",
128 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
131 *refnumber
= xmlXPathCastNodeSetToString(result
->nodesetval
);
132 if (NULL
== *refnumber
) {
139 xmlXPathFreeObject(result
);
140 xmlXPathFreeContext(xpath_ctx
);
145 /* Send @request to ISDS and return ISDS @response as XML document.
146 * Be ware the @response can be invalid (in sense of XML Schema).
147 * (And it is because current ISDS server does not follow its own
148 * specification. Please apology my government, its herd of incompetent
150 * @context is ISDS session context,
151 * @service identifies ISDS web service
152 * @request is tree with ISDS message, can be NULL
153 * @response is automatically allocated response from server as XML Document
154 * @raw_response is automatically allocated bit stream with response body. Use
155 * NULL if you don't care
156 * @raw_response_length is size of @raw_response in bytes
157 * In case of error, @response and @raw_response will be deallocated.
159 _hidden isds_error
_isds(struct isds_ctx
*context
, const isds_service service
,
160 const xmlNodePtr request
, xmlDocPtr
*response
,
161 void **raw_response
, size_t *raw_response_length
) {
162 isds_error err
= IE_SUCCESS
;
163 xmlDocPtr response_document
= NULL
;
164 xmlNodePtr response_body
, isds_node
;
166 const char *name_space
= ISDS_NS
;
168 if (!context
) return IE_INVALID_CONTEXT
;
169 if (!response
) return IE_INVAL
;
170 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
172 /* Effective ISDS URL is build from base URL and suffix.
173 * Other connection types has specific stable URL. */
174 if (context
->type
== CTX_TYPE_ISDS
) {
176 case SERVICE_DM_OPERATIONS
: file
= "DS/dz"; break;
177 case SERVICE_DM_INFO
: file
= "DS/dx"; break;
178 case SERVICE_DB_SEARCH
: file
= "DS/df"; break;
179 case SERVICE_DB_ACCESS
: file
= "DS/DsManage"; break;
180 case SERVICE_DB_MANIPULATION
: file
= "DS/DsManage"; break;
181 case SERVICE_ASWS
: file
= ""; break;
182 default: return (IE_INVAL
);
186 /* Also name space differs in some cases */
187 if (CTX_TYPE_TESTING_REQUEST_COLLECTOR
== context
->type
)
188 name_space
= ISDS1_NS
;
189 else if (SERVICE_ASWS
== service
)
190 name_space
= OISDS_NS
;
192 err
= _isds_soap(context
, file
, request
, &response_document
, &response_body
,
193 raw_response
, raw_response_length
);
197 if (!response_body
) {
198 isds_log_message(context
, _("SOAP returned empty body"));
202 /* Find ISDS element */
203 for (isds_node
= response_body
; isds_node
; isds_node
= isds_node
->next
) {
204 if (isds_node
->type
== XML_ELEMENT_NODE
&&
206 !xmlStrcmp(isds_node
->ns
->href
, BAD_CAST name_space
))
210 char *name_space_local
= _isds_utf82locale(name_space
);
211 isds_printf_message(context
,
212 _("SOAP response does not contain element from name space %s"),
214 free(name_space_local
);
219 /* TODO: validate the response */
221 /* Build XML document */
222 *response
= xmlNewDoc(BAD_CAST
"1.0");
224 isds_log_message(context
, _("Could not build ISDS response document"));
228 xmlDocSetRootElement(*response
, isds_node
);
232 xmlFreeDoc(*response
);
233 if (raw_response
) zfree(*raw_response
);
235 xmlFreeDoc(response_document
);
239 #endif /* HAVE_LIBCURL */
242 /* Walk through list of isds_documents and check for their types and
244 * @context is session context
245 * @documents is list of isds_document to check
246 * @returns IE_SUCCESS if structure is valid, otherwise context' message will
247 * be filled with explanation of found problem. */
248 _hidden isds_error
_isds_check_documents_hierarchy(struct isds_ctx
*context
,
249 const struct isds_list
*documents
) {
251 const struct isds_list
*item
;
252 const struct isds_document
*document
;
253 _Bool main_exists
= 0;
255 if (!context
) return IE_INVALID_CONTEXT
;
256 if (!documents
) return IE_INVAL
;
258 for (item
= documents
; item
; item
= item
->next
) {
259 document
= (const struct isds_document
*) item
->data
;
260 if (!document
) continue;
262 /* Only one document can be main */
263 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
) {
265 isds_log_message(context
,
266 _("List contains more main documents"));
272 /* All document identifiers should be unique */
273 if (document
->dmFileGuid
) {
274 if (isds_find_document_by_id(documents
, document
->dmFileGuid
) !=
276 isds_printf_message(context
, _("List contains more documents "
277 "with the same ID `%s'"), document
->dmFileGuid
);
282 /* All document references should point to existing document ID */
283 /* ???: Should we forbid self-referencing? */
284 if (document
->dmUpFileGuid
) {
285 if (!isds_find_document_by_id(documents
,
286 document
->dmUpFileGuid
)) {
287 isds_printf_message(context
, _("List contains documents "
288 "referencing to not existing document ID `%s'"),
289 document
->dmUpFileGuid
);
296 isds_log_message(context
, _("List does not contain main document"));
304 /* Check for message ID length
305 * @context is session context
306 * @message_id checked message ID
307 * @return IE_SUCCESS or appropriate error code and fill context' message */
308 isds_error
validate_message_id_length(struct isds_ctx
*context
,
309 const xmlChar
*message_id
) {
310 if (!context
) return IE_INVALID_CONTEXT
;
311 if (!message_id
) return IE_INVAL
;
313 const int length
= xmlUTF8Strlen(message_id
);
316 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
317 isds_printf_message(context
,
318 _("Could not check message ID length: %s"),
320 free(message_id_locale
);
325 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
326 isds_printf_message(context
,
327 _("Message ID must not be longer than 20 characters: %s"),
329 free(message_id_locale
);
338 /* Send @request to Czech POINT conversion deposit and return response
340 * @context is Czech POINT session context,
341 * @request is tree with deposit message, can be NULL
342 * @response is automatically allocated response from server as XML Document
343 * In case of error, @response will be deallocated.
345 _hidden isds_error
_czp_czpdeposit(struct isds_ctx
*context
,
346 const xmlNodePtr request
, xmlDocPtr
*response
) {
347 isds_error err
= IE_SUCCESS
;
348 xmlDocPtr response_document
= NULL
;
349 xmlNodePtr response_body
= NULL
, deposit_node
;
351 if (!context
) return IE_INVALID_CONTEXT
;
352 if (!response
) return IE_INVAL
;
354 err
= _isds_soap(context
, NULL
, request
,
355 &response_document
, &response_body
, NULL
, NULL
);
359 if (!response_body
) {
360 isds_log_message(context
, _("SOAP returned empty body"));
364 /* Find deposit element */
365 for (deposit_node
= response_body
; deposit_node
;
366 deposit_node
= deposit_node
->next
) {
367 if (deposit_node
->type
== XML_ELEMENT_NODE
&&
369 !xmlStrcmp(deposit_node
->ns
->href
, BAD_CAST DEPOSIT_NS
))
373 isds_log_message(context
,
374 _("SOAP response does not contain "
375 "Czech POINT deposit element"));
380 /* Build XML document */
381 *response
= xmlNewDoc(BAD_CAST
"1.0");
383 isds_log_message(context
,
384 _("Could not build Czech POINT deposit response document"));
388 xmlDocSetRootElement(*response
, deposit_node
);
392 xmlFreeDoc(*response
);
394 xmlFreeDoc(response_document
);
398 #endif /* HAVE_LIBCURL */