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
);
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
);
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 xmlNodePtr response_body
= NULL
, isds_node
;
165 const char *name_space
= ISDS_NS
;
167 if (!context
) return IE_INVALID_CONTEXT
;
168 if (!response
) return IE_INVAL
;
169 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
171 /* Effective ISDS URL is build from base URL and suffix.
172 * Other connection types has specific stable URL. */
173 if (context
->type
== CTX_TYPE_ISDS
) {
175 case SERVICE_DM_OPERATIONS
: file
= "DS/dz"; break;
176 case SERVICE_DM_INFO
: file
= "DS/dx"; break;
177 case SERVICE_DB_SEARCH
: file
= "DS/df"; break;
178 case SERVICE_DB_ACCESS
: file
= "DS/DsManage"; break;
179 case SERVICE_DB_MANIPULATION
: file
= "DS/DsManage"; break;
180 case SERVICE_ASWS
: file
= ""; break;
181 default: return (IE_INVAL
);
185 /* Also name space differs in some cases */
186 if (CTX_TYPE_TESTING_REQUEST_COLLECTOR
== context
->type
)
187 name_space
= ISDS1_NS
;
188 else if (SERVICE_ASWS
== service
)
189 name_space
= OISDS_NS
;
191 err
= _isds_soap(context
, file
, request
, &response_body
,
192 raw_response
, raw_response_length
);
196 if (!response_body
) {
197 isds_log_message(context
, _("SOAP returned empty body"));
201 /* Find ISDS element */
202 for (isds_node
= response_body
; isds_node
; isds_node
= isds_node
->next
) {
203 if (isds_node
->type
== XML_ELEMENT_NODE
&&
205 !xmlStrcmp(isds_node
->ns
->href
, BAD_CAST name_space
))
209 char *name_space_local
= _isds_utf82locale(name_space
);
210 isds_printf_message(context
,
211 _("SOAP response does not contain element from name space %s"),
213 free(name_space_local
);
218 /* Destroy other nodes */
219 if (isds_node
== response_body
)
220 response_body
= response_body
->next
;
221 xmlUnlinkNode(isds_node
);
222 xmlFreeNodeList(response_body
);
223 response_body
= NULL
;
225 /* TODO: validate the response */
227 /* Build XML document */
228 *response
= xmlNewDoc(BAD_CAST
"1.0");
230 isds_log_message(context
, _("Could not build ISDS response document"));
234 xmlDocSetRootElement(*response
, isds_node
);
238 xmlFreeDoc(*response
);
239 if (raw_response
) zfree(*raw_response
);
241 xmlFreeNodeList(response_body
);
245 #endif /* HAVE_LIBCURL */
248 /* Walk through list of isds_documents and check for their types and
250 * @context is session context
251 * @documents is list of isds_document to check
252 * @returns IE_SUCCESS if structure is valid, otherwise context' message will
253 * be filled with explanation of found problem. */
254 _hidden isds_error
_isds_check_documents_hierarchy(struct isds_ctx
*context
,
255 const struct isds_list
*documents
) {
257 const struct isds_list
*item
;
258 const struct isds_document
*document
;
259 _Bool main_exists
= 0;
261 if (!context
) return IE_INVALID_CONTEXT
;
262 if (!documents
) return IE_INVAL
;
264 for (item
= documents
; item
; item
= item
->next
) {
265 document
= (const struct isds_document
*) item
->data
;
266 if (!document
) continue;
268 /* Only one document can be main */
269 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
) {
271 isds_log_message(context
,
272 _("List contains more main documents"));
278 /* All document identifiers should be unique */
279 if (document
->dmFileGuid
) {
280 if (isds_find_document_by_id(documents
, document
->dmFileGuid
) !=
282 isds_printf_message(context
, _("List contains more documents "
283 "with the same ID `%s'"), document
->dmFileGuid
);
288 /* All document references should point to existing document ID */
289 /* ???: Should we forbid self-referencing? */
290 if (document
->dmUpFileGuid
) {
291 if (!isds_find_document_by_id(documents
,
292 document
->dmUpFileGuid
)) {
293 isds_printf_message(context
, _("List contains documents "
294 "referencing to not existing document ID `%s'"),
295 document
->dmUpFileGuid
);
302 isds_log_message(context
, _("List does not contain main document"));
310 /* Check for message ID length
311 * @context is session context
312 * @message_id checked message ID
313 * @return IE_SUCCESS or appropriate error code and fill context' message */
314 isds_error
validate_message_id_length(struct isds_ctx
*context
,
315 const xmlChar
*message_id
) {
316 if (!context
) return IE_INVALID_CONTEXT
;
317 if (!message_id
) return IE_INVAL
;
319 const int length
= xmlUTF8Strlen(message_id
);
322 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
323 isds_printf_message(context
,
324 _("Could not check message ID length: %s"),
326 free(message_id_locale
);
331 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
332 isds_printf_message(context
,
333 _("Message ID must not be longer than 20 characters: %s"),
335 free(message_id_locale
);
344 /* Send @request to Czech POINT conversion deposit and return response
346 * @context is Czech POINT session context,
347 * @request is tree with deposit message, can be NULL
348 * @response is automatically allocated response from server as XML Document
349 * In case of error, @response will be deallocated.
351 _hidden isds_error
_czp_czpdeposit(struct isds_ctx
*context
,
352 const xmlNodePtr request
, xmlDocPtr
*response
) {
353 isds_error err
= IE_SUCCESS
;
354 xmlNodePtr response_body
= NULL
, deposit_node
;
356 if (!context
) return IE_INVALID_CONTEXT
;
357 if (!response
) return IE_INVAL
;
359 err
= _isds_soap(context
, NULL
, request
, &response_body
, NULL
, NULL
);
363 if (!response_body
) {
364 isds_log_message(context
, _("SOAP returned empty body"));
368 /* Find deposit element */
369 for (deposit_node
= response_body
; deposit_node
;
370 deposit_node
= deposit_node
->next
) {
371 if (deposit_node
->type
== XML_ELEMENT_NODE
&&
373 !xmlStrcmp(deposit_node
->ns
->href
, BAD_CAST DEPOSIT_NS
))
377 isds_log_message(context
,
378 _("SOAP response does not contain "
379 "Czech POINT deposit element"));
384 /* Destroy other nodes */
385 if (deposit_node
== response_body
)
386 response_body
= response_body
->next
;
387 xmlUnlinkNode(deposit_node
);
388 xmlFreeNodeList(response_body
);
389 response_body
= NULL
;
391 /* Build XML document */
392 *response
= xmlNewDoc(BAD_CAST
"1.0");
394 isds_log_message(context
,
395 _("Could not build Czech POINT deposit response document"));
399 xmlDocSetRootElement(*response
, deposit_node
);
403 xmlFreeDoc(*response
);
405 xmlFreeNodeList(response_body
);
409 #endif /* HAVE_LIBCURL */