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
, MESSAGE_NS_UNSIGNED
)) {
64 result
= xmlXPathEvalExpression(status_code_expr
, xpath_ctx
);
69 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
70 isds_log_message(context
,
71 _("ISDS response is missing StatusCode element"));
75 *code
= xmlXPathCastNodeSetToString(result
->nodesetval
);
82 /* Get status message */
83 xmlXPathFreeObject(result
);
84 result
= xmlXPathEvalExpression(status_message_expr
, xpath_ctx
);
89 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
90 /* E.g. CreateMessageResponse with dmStatusCode 9005 has empty
94 *message
= xmlXPathCastNodeSetToString(result
->nodesetval
);
103 /* Get reference number of client request */
105 xmlXPathFreeObject(result
);
106 result
= xmlXPathEvalExpression(
107 BAD_CAST
"/*/isds:dbStatus/isds:dbStatusRefNumber/text()",
113 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
116 *refnumber
= xmlXPathCastNodeSetToString(result
->nodesetval
);
124 xmlXPathFreeObject(result
);
125 xmlXPathFreeContext(xpath_ctx
);
130 /* Send @request to ISDS and return ISDS @response as XML document.
131 * Be ware the @response can be invalid (in sense of XML Schema).
132 * (And it is because current ISDS server does not follow its own
133 * specification. Please appology my government, its herd of imcompetent
135 * @context is ISDS session context,
136 * @service identifies ISDS web service
137 * @request is tree with ISDS message, can be NULL
138 * @response is automatically allocated response from server as XML Document
139 * @raw_response is automatically allocated bitstream with response body. Use
140 * NULL if you don't care
141 * @raw_response_length is size of @raw_response in bytes
142 * In case of error, @response and @raw_response will be dealocated.
144 _hidden isds_error
isds(struct isds_ctx
*context
, const isds_service service
,
145 const xmlNodePtr request
, xmlDocPtr
*response
,
146 void **raw_response
, size_t *raw_response_length
) {
147 isds_error err
= IE_SUCCESS
;
148 xmlNodePtr response_body
= NULL
, isds_node
;
151 if (!context
) return IE_INVALID_CONTEXT
;
152 if (!response
) return IE_INVAL
;
153 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
156 case SERVICE_DM_OPERATIONS
: file
= "dz"; break;
157 case SERVICE_DM_INFO
: file
= "dx"; break;
158 case SERVICE_DB_SEARCH
: file
= "df"; break;
159 case SERVICE_DB_ACCESS
: file
= "DsManage"; break;
160 case SERVICE_DB_MANIPULATION
: file
= "DsManage"; break;
161 default: return (IE_INVAL
);
164 err
= soap(context
, file
, request
, &response_body
,
165 raw_response
, raw_response_length
);
169 if (!response_body
) {
170 isds_log_message(context
, _("SOAP returned empty body"));
174 /* Find ISDS element */
175 for (isds_node
= response_body
; isds_node
; isds_node
= isds_node
->next
) {
176 if (isds_node
->type
== XML_ELEMENT_NODE
&&
178 !xmlStrcmp(isds_node
->ns
->href
, BAD_CAST ISDS_NS
))
182 isds_log_message(context
,
183 _("SOAP response does not contain ISDS element"));
188 /* Destroy other nodes */
189 if (isds_node
== response_body
)
190 response_body
= response_body
->next
;
191 xmlUnlinkNode(isds_node
);
192 xmlFreeNodeList(response_body
);
193 response_body
= NULL
;
195 /* TODO: validate the response */
197 /* Build XML document */
198 *response
= xmlNewDoc(BAD_CAST
"1.0");
200 isds_log_message(context
, _("Could not build ISDS response document"));
204 xmlDocSetRootElement(*response
, isds_node
);
208 xmlFreeDoc(*response
);
209 if (raw_response
) zfree(*raw_response
);
211 xmlFreeNodeList(response_body
);
216 /* Walk through list of isds_documents and check for their types and
218 * @context is session context
219 * @documents is list of isds_document to check
220 * @returns IE_SUCCESS if structure is valid, otherwise context' message will
221 * be filled with explanation of found problem. */
222 _hidden isds_error
check_documents_hierarchy(struct isds_ctx
*context
,
223 const struct isds_list
*documents
) {
225 const struct isds_list
*item
;
226 const struct isds_document
*document
;
227 _Bool main_exists
= 0;
229 if (!context
) return IE_INVALID_CONTEXT
;
230 if (!documents
) return IE_INVAL
;
232 for (item
= documents
; item
; item
= item
->next
) {
233 document
= (const struct isds_document
*) item
->data
;
234 if (!document
) continue;
236 /* Only one document can be main */
237 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
) {
239 isds_log_message(context
,
240 _("List contains more main documents"));
246 /* All document identifiers should be unique */
247 if (document
->dmFileGuid
) {
248 if (isds_find_document_by_id(documents
, document
->dmFileGuid
) !=
250 isds_printf_message(context
, _("List contains more documents "
251 "with the same ID `%s'"), document
->dmFileGuid
);
256 /* All document references should point to existing document ID */
257 /* ???: Should we forbid self-refencing? */
258 if (document
->dmUpFileGuid
) {
259 if (!isds_find_document_by_id(documents
,
260 document
->dmUpFileGuid
)) {
261 isds_printf_message(context
, _("List contains documents "
262 "referencing to unexisting document ID `%s'"),
263 document
->dmUpFileGuid
);
270 isds_log_message(context
, _("List does not contain main document"));
278 /* Check for message ID length
279 * @context is session context
280 * @message_id checked message ID
281 * @return IE_SUCCESS or appropriate error code and fill context' message */
282 isds_error
validate_message_id_length(struct isds_ctx
*context
,
283 const xmlChar
*message_id
) {
284 if (!context
) return IE_INVALID_CONTEXT
;
285 if (!message_id
) return IE_INVAL
;
287 const int length
= xmlUTF8Strlen(message_id
);
290 char *message_id_locale
= utf82locale((char*) message_id
);
291 isds_printf_message(context
,
292 _("Could not check message ID length: %s"),
294 free(message_id_locale
);
299 char *message_id_locale
= utf82locale((char*) message_id
);
300 isds_printf_message(context
,
301 _("Message ID must not be longer than 20 characters: %s"),
303 free(message_id_locale
);