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 allocated status reference number. Returned
17 * NULL means no referce was delivered by server. 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_SUPPLEMENTARY
:
42 status_code_expr
= BAD_CAST
43 "/*/isds:dbStatus/isds:dbStatusCode/text()";
44 status_message_expr
= BAD_CAST
45 "/*/isds:dbStatus/isds:dbStatusMessage/text()";
52 xpath_ctx
= xmlXPathNewContext(response
);
57 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
63 result
= xmlXPathEvalExpression(status_code_expr
, xpath_ctx
);
68 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
69 isds_log_message(context
, _("ISDS response is missing StatusCode"));
73 *code
= xmlXPathCastNodeSetToString(result
->nodesetval
);
80 /* Get status message */
81 xmlXPathFreeObject(result
);
82 result
= xmlXPathEvalExpression(status_message_expr
, xpath_ctx
);
87 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
88 /* E.g. CreateMessageResponse with dmStatusCode 9005 has empty
92 *message
= xmlXPathCastNodeSetToString(result
->nodesetval
);
101 /* Get status reference number */
102 xmlXPathFreeObject(result
);
103 result
= xmlXPathEvalExpression(
104 BAD_CAST
"/*/isds:dbStatus/isds:dbStatusRefNumber/text()",
110 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
113 *refnumber
= xmlXPathCastNodeSetToString(result
->nodesetval
);
121 xmlXPathFreeObject(result
);
122 xmlXPathFreeContext(xpath_ctx
);
127 /* Send @request to ISDS and return ISDS @response as XML document.
128 * Be ware the @response can be invalid (in sense of XML Schema).
129 * (And it is because current ISDS server does not follow its own
130 * specification. Please appology my government, its herd of imcompetent
132 * @context is ISDS session context,
133 * @service identifies ISDS web service
134 * @request is tree with ISDS message, can be NULL
135 * @response is automatically allocated response from server as XML Document
136 * @raw_response is automatically allocated bitstream with response body. Use
137 * NULL if you don't care
138 * @raw_response_length is size of @raw_response in bytes
139 * In case of error, @response and @raw_response will be dealocated.
141 _hidden isds_error
isds(struct isds_ctx
*context
, const isds_service service
,
142 const xmlNodePtr request
, xmlDocPtr
*response
,
143 void **raw_response
, size_t *raw_response_length
) {
144 isds_error err
= IE_SUCCESS
;
145 xmlNodePtr response_body
= NULL
, isds_node
;
148 if (!context
) return IE_INVALID_CONTEXT
;
149 if (!response
) return IE_INVAL
;
150 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
153 case SERVICE_DM_OPERATIONS
: file
= "dz"; break;
154 case SERVICE_DM_INFO
: file
= "dx"; break;
155 case SERVICE_DB_SEARCH
: file
= "df"; break;
156 case SERVICE_DB_SUPPLEMENTARY
: file
= "DsManage"; break;
157 default: return (IE_INVAL
);
160 err
= soap(context
, file
, request
, &response_body
,
161 raw_response
, raw_response_length
);
165 if (!response_body
) {
166 isds_log_message(context
, _("SOAP returned empty body"));
170 /* Find ISDS element */
171 for (isds_node
= response_body
; isds_node
; isds_node
= isds_node
->next
) {
172 if (isds_node
->type
== XML_ELEMENT_NODE
&&
174 !xmlStrcmp(isds_node
->ns
->href
, BAD_CAST ISDS_NS
))
178 isds_log_message(context
,
179 _("SOAP response does not contain ISDS elemement"));
184 /* Destroy other nodes */
185 if (isds_node
== response_body
)
186 response_body
= response_body
->next
;
187 xmlUnlinkNode(isds_node
);
188 xmlFreeNodeList(response_body
);
189 response_body
= NULL
;
191 /* TODO: validate the response */
193 /* Build XML document */
194 *response
= xmlNewDoc(BAD_CAST
"1.0");
196 isds_log_message(context
, _("Could not build ISDS response document"));
200 xmlDocSetRootElement(*response
, isds_node
);
204 xmlFreeDoc(*response
);
205 if (raw_response
) zfree(*raw_response
);
207 xmlFreeNodeList(response_body
);
212 /* Walk through list of isds_documents and check for their types and
214 * @context is session context
215 * @documents is list of isds_document to check
216 * @returns IE_SUCCESS if structure is valid, otherwise context' message will
217 * be filled with explanation of found problem. */
218 _hidden isds_error
check_documents_hierarchy(struct isds_ctx
*context
,
219 const struct isds_list
*documents
) {
221 const struct isds_list
*item
;
222 const struct isds_document
*document
;
223 _Bool main_exists
= 0;
225 if (!context
) return IE_INVALID_CONTEXT
;
226 if (!documents
) return IE_INVAL
;
228 for (item
= documents
; item
; item
= item
->next
) {
229 document
= (const struct isds_document
*) item
->data
;
230 if (!document
) continue;
232 /* Only one document can be main */
233 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
) {
235 isds_log_message(context
,
236 _("List contains more main documents"));
242 /* All document identifiers should be unique */
243 if (document
->dmFileGuid
) {
244 if (isds_find_document_by_id(documents
, document
->dmFileGuid
) !=
246 isds_printf_message(context
, _("List contains more documents "
247 "with the same ID `%s'"), document
->dmFileGuid
);
252 /* All document references should point to existing document ID */
253 /* ???: Should we forbid self-refencing? */
254 if (document
->dmUpFileGuid
) {
255 if (!isds_find_document_by_id(documents
,
256 document
->dmUpFileGuid
)) {
257 isds_printf_message(context
, _("List contains documents "
258 "referencing to unexisting document ID `%s'"),
259 document
->dmUpFileGuid
);
266 isds_log_message(context
, _("List does not contain main document"));
274 /* Check for message ID length
275 * @context is session context
276 * @message_id checked message ID
277 * @return IE_SUCCESS or appropriate error code and fill context' message */
278 isds_error
validate_message_id_length(struct isds_ctx
*context
,
279 const xmlChar
*message_id
) {
280 if (!context
) return IE_INVALID_CONTEXT
;
281 if (!message_id
) return IE_INVAL
;
283 const int length
= xmlUTF8Strlen(message_id
);
286 char *message_id_locale
= utf82locale((char*) message_id
);
287 isds_printf_message(context
,
288 _("Could not check message ID length: %s"),
290 free(message_id_locale
);
295 char *message_id_locale
= utf82locale((char*) message_id
);
296 isds_printf_message(context
,
297 _("Message ID must not be longer than 20 characters: %s"),
299 free(message_id_locale
);