7 /* Get ISDS status info from ISDS @response XML document.
8 * Be ware that different request families return differently encoded status
9 * (e.g. dmStatus, dbStatus)
10 * @context is ISDS context
11 * @service is ISDS web service identifier
12 * @response is ISDS response document
13 * @code is automatically allocated status code of the response
14 * @message is automatically allocated status message. Returned NULL means no
15 * message was delivered by server. Use NULL if you don't care.
16 * @refnumber is automatically reallocated request serial number assigned by
17 * ISDS. Returned *NULL means no number was delivered by server.
18 * Use NULL if you don't care. */
19 _hidden isds_error
isds_response_status(struct isds_ctx
*context
,
20 const isds_service service
, xmlDocPtr response
,
21 xmlChar
**code
, xmlChar
**message
, xmlChar
**refnumber
) {
22 isds_error err
= IE_SUCCESS
;
23 xmlChar
*status_code_expr
= NULL
, *status_message_expr
= NULL
;
24 xmlXPathContextPtr xpath_ctx
= NULL
;
25 xmlXPathObjectPtr result
= NULL
;
27 if (!response
|| !code
) {
33 case SERVICE_DM_OPERATIONS
:
35 status_code_expr
= BAD_CAST
36 "/*/isds:dmStatus/isds:dmStatusCode/text()";
37 status_message_expr
= BAD_CAST
38 "/*/isds:dmStatus/isds:dmStatusMessage/text()";
40 case SERVICE_DB_SEARCH
:
41 case SERVICE_DB_ACCESS
:
42 case SERVICE_DB_MANIPULATION
:
43 status_code_expr
= BAD_CAST
44 "/*/isds:dbStatus/isds:dbStatusCode/text()";
45 status_message_expr
= BAD_CAST
46 "/*/isds:dbStatus/isds:dbStatusMessage/text()";
53 xpath_ctx
= xmlXPathNewContext(response
);
58 if (register_namespaces(xpath_ctx
,
59 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
60 MESSAGE_NS_1
: MESSAGE_NS_UNSIGNED
)) {
66 result
= xmlXPathEvalExpression(status_code_expr
, xpath_ctx
);
71 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
72 isds_log_message(context
,
73 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
74 _("ISDS1 response is missing StatusCode element") :
75 _("ISDS response is missing StatusCode element"));
79 *code
= xmlXPathCastNodeSetToString(result
->nodesetval
);
86 /* Get status message */
87 xmlXPathFreeObject(result
);
88 result
= xmlXPathEvalExpression(status_message_expr
, xpath_ctx
);
93 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
94 /* E.g. CreateMessageResponse with dmStatusCode 9005 has empty
98 *message
= xmlXPathCastNodeSetToString(result
->nodesetval
);
107 /* Get reference number of client request */
109 xmlXPathFreeObject(result
);
110 result
= xmlXPathEvalExpression(
111 BAD_CAST
"/*/isds:dbStatus/isds:dbStatusRefNumber/text()",
117 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
120 *refnumber
= xmlXPathCastNodeSetToString(result
->nodesetval
);
128 xmlXPathFreeObject(result
);
129 xmlXPathFreeContext(xpath_ctx
);
134 /* Send @request to ISDS and return ISDS @response as XML document.
135 * Be ware the @response can be invalid (in sense of XML Schema).
136 * (And it is because current ISDS server does not follow its own
137 * specification. Please appology my government, its herd of imcompetent
139 * @context is ISDS session context,
140 * @service identifies ISDS web service
141 * @request is tree with ISDS message, can be NULL
142 * @response is automatically allocated response from server as XML Document
143 * @raw_response is automatically allocated bitstream with response body. Use
144 * NULL if you don't care
145 * @raw_response_length is size of @raw_response in bytes
146 * In case of error, @response and @raw_response will be dealocated.
148 _hidden isds_error
isds(struct isds_ctx
*context
, const isds_service service
,
149 const xmlNodePtr request
, xmlDocPtr
*response
,
150 void **raw_response
, size_t *raw_response_length
) {
151 isds_error err
= IE_SUCCESS
;
152 xmlNodePtr response_body
= NULL
, isds_node
;
155 if (!context
) return IE_INVALID_CONTEXT
;
156 if (!response
) return IE_INVAL
;
157 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
159 /* Effective ISDS URL is build from base URL and suffix.
160 * Other conenction types has specific stable URL. */
161 if (context
->type
== CTX_TYPE_ISDS
) {
163 case SERVICE_DM_OPERATIONS
: file
= "DS/dz"; break;
164 case SERVICE_DM_INFO
: file
= "DS/dx"; break;
165 case SERVICE_DB_SEARCH
: file
= "DS/df"; break;
166 case SERVICE_DB_ACCESS
: file
= "DS/DsManage"; break;
167 case SERVICE_DB_MANIPULATION
: file
= "DS/DsManage"; break;
168 default: return (IE_INVAL
);
172 err
= soap(context
, file
, request
, &response_body
,
173 raw_response
, raw_response_length
);
177 if (!response_body
) {
178 isds_log_message(context
, _("SOAP returned empty body"));
182 /* Find ISDS element */
183 for (isds_node
= response_body
; isds_node
; isds_node
= isds_node
->next
) {
184 if (isds_node
->type
== XML_ELEMENT_NODE
&&
186 !xmlStrcmp(isds_node
->ns
->href
,
187 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
188 BAD_CAST ISDS1_NS
: BAD_CAST ISDS_NS
))
192 isds_log_message(context
,
193 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
194 _("SOAP response does not contain ISDS1 element") :
195 _("SOAP response does not contain ISDS element"));
200 /* Destroy other nodes */
201 if (isds_node
== response_body
)
202 response_body
= response_body
->next
;
203 xmlUnlinkNode(isds_node
);
204 xmlFreeNodeList(response_body
);
205 response_body
= NULL
;
207 /* TODO: validate the response */
209 /* Build XML document */
210 *response
= xmlNewDoc(BAD_CAST
"1.0");
212 isds_log_message(context
,
213 (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) ?
214 _("Could not build ISDS1 response document") :
215 _("Could not build ISDS response document"));
219 xmlDocSetRootElement(*response
, isds_node
);
223 xmlFreeDoc(*response
);
224 if (raw_response
) zfree(*raw_response
);
226 xmlFreeNodeList(response_body
);
232 /* Walk through list of isds_documents and check for their types and
234 * @context is session context
235 * @documents is list of isds_document to check
236 * @returns IE_SUCCESS if structure is valid, otherwise context' message will
237 * be filled with explanation of found problem. */
238 _hidden isds_error
check_documents_hierarchy(struct isds_ctx
*context
,
239 const struct isds_list
*documents
) {
241 const struct isds_list
*item
;
242 const struct isds_document
*document
;
243 _Bool main_exists
= 0;
245 if (!context
) return IE_INVALID_CONTEXT
;
246 if (!documents
) return IE_INVAL
;
248 for (item
= documents
; item
; item
= item
->next
) {
249 document
= (const struct isds_document
*) item
->data
;
250 if (!document
) continue;
252 /* Only one document can be main */
253 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
) {
255 isds_log_message(context
,
256 _("List contains more main documents"));
262 /* All document identifiers should be unique */
263 if (document
->dmFileGuid
) {
264 if (isds_find_document_by_id(documents
, document
->dmFileGuid
) !=
266 isds_printf_message(context
, _("List contains more documents "
267 "with the same ID `%s'"), document
->dmFileGuid
);
272 /* All document references should point to existing document ID */
273 /* ???: Should we forbid self-refencing? */
274 if (document
->dmUpFileGuid
) {
275 if (!isds_find_document_by_id(documents
,
276 document
->dmUpFileGuid
)) {
277 isds_printf_message(context
, _("List contains documents "
278 "referencing to unexisting document ID `%s'"),
279 document
->dmUpFileGuid
);
286 isds_log_message(context
, _("List does not contain main document"));
294 /* Check for message ID length
295 * @context is session context
296 * @message_id checked message ID
297 * @return IE_SUCCESS or appropriate error code and fill context' message */
298 isds_error
validate_message_id_length(struct isds_ctx
*context
,
299 const xmlChar
*message_id
) {
300 if (!context
) return IE_INVALID_CONTEXT
;
301 if (!message_id
) return IE_INVAL
;
303 const int length
= xmlUTF8Strlen(message_id
);
306 char *message_id_locale
= utf82locale((char*) message_id
);
307 isds_printf_message(context
,
308 _("Could not check message ID length: %s"),
310 free(message_id_locale
);
315 char *message_id_locale
= utf82locale((char*) message_id
);
316 isds_printf_message(context
,
317 _("Message ID must not be longer than 20 characters: %s"),
319 free(message_id_locale
);
327 /* Send @request to Czech POINT conversion deposit and return response
329 * @context is Czech POINT session context,
330 * @request is tree with deposit message, can be NULL
331 * @response is automatically allocated response from server as XML Document
332 * In case of error, @response will be dealocated.
334 _hidden isds_error
czpdeposit(struct isds_ctx
*context
,
335 const xmlNodePtr request
, xmlDocPtr
*response
) {
336 isds_error err
= IE_SUCCESS
;
337 xmlNodePtr response_body
= NULL
, deposit_node
;
339 if (!context
) return IE_INVALID_CONTEXT
;
340 if (!response
) return IE_INVAL
;
342 err
= soap(context
, NULL
, request
, &response_body
, NULL
, NULL
);
346 if (!response_body
) {
347 isds_log_message(context
, _("SOAP returned empty body"));
351 /* Find deposit element */
352 for (deposit_node
= response_body
; deposit_node
;
353 deposit_node
= deposit_node
->next
) {
354 if (deposit_node
->type
== XML_ELEMENT_NODE
&&
356 !xmlStrcmp(deposit_node
->ns
->href
, BAD_CAST DEPOSIT_NS
))
360 isds_log_message(context
,
361 _("SOAP response does not contain "
362 "Czech POINT deposit element"));
367 /* Destroy other nodes */
368 if (deposit_node
== response_body
)
369 response_body
= response_body
->next
;
370 xmlUnlinkNode(deposit_node
);
371 xmlFreeNodeList(response_body
);
372 response_body
= NULL
;
374 /* Build XML document */
375 *response
= xmlNewDoc(BAD_CAST
"1.0");
377 isds_log_message(context
,
378 _("Could not build Czech POINT deposit response document"));
382 xmlDocSetRootElement(*response
, deposit_node
);
386 xmlFreeDoc(*response
);
388 xmlFreeNodeList(response_body
);