1 #define _XOPEN_SOURCE 500 /* strdup from string.h, strptime from time.h */
10 #include "validator.h"
12 #include <gpg-error.h> /* Because of ksba or gpgme */
15 /* Free isds_list with all member data.
16 * @list list to free, on return will be NULL */
17 void isds_list_free(struct isds_list
**list
) {
18 struct isds_list
*item
, *next_item
;
20 if (!list
|| !*list
) return;
22 for(item
= *list
; item
; item
= next_item
) {
23 (item
->destructor
)(&(item
->data
));
24 next_item
= item
->next
;
32 /* Deallocate structure isds_hash and NULL it.
33 * @hash hash to to free */
34 void isds_hash_free(struct isds_hash
**hash
) {
35 if(!hash
|| !*hash
) return;
41 /* Deallocate structure isds_PersonName recursively and NULL it */
42 static void isds_PersonName_free(struct isds_PersonName
**person_name
) {
43 if (!person_name
|| !*person_name
) return;
45 free((*person_name
)->pnFirstName
);
46 free((*person_name
)->pnMiddleName
);
47 free((*person_name
)->pnLastName
);
48 free((*person_name
)->pnLastNameAtBirth
);
55 /* Deallocate structure isds_BirthInfo recursively and NULL it */
56 static void isds_BirthInfo_free(struct isds_BirthInfo
**birth_info
) {
57 if (!birth_info
|| !*birth_info
) return;
59 free((*birth_info
)->biDate
);
60 free((*birth_info
)->biCity
);
61 free((*birth_info
)->biCounty
);
62 free((*birth_info
)->biState
);
69 /* Deallocate structure isds_Address recursively and NULL it */
70 static void isds_Address_free(struct isds_Address
**address
) {
71 if (!address
|| !*address
) return;
73 free((*address
)->adCity
);
74 free((*address
)->adStreet
);
75 free((*address
)->adNumberInStreet
);
76 free((*address
)->adNumberInMunicipality
);
77 free((*address
)->adZipCode
);
78 free((*address
)->adState
);
85 /* Deallocate structure isds_DbOwnerInfo recursively and NULL it */
86 void isds_DbOwnerInfo_free(struct isds_DbOwnerInfo
**db_owner_info
) {
87 if (!db_owner_info
|| !*db_owner_info
) return;
89 free((*db_owner_info
)->dbID
);
90 free((*db_owner_info
)->dbType
);
91 free((*db_owner_info
)->ic
);
92 isds_PersonName_free(&((*db_owner_info
)->personName
));
93 free((*db_owner_info
)->firmName
);
94 isds_BirthInfo_free(&((*db_owner_info
)->birthInfo
));
95 isds_Address_free(&((*db_owner_info
)->address
));
96 free((*db_owner_info
)->nationality
);
97 free((*db_owner_info
)->email
);
98 free((*db_owner_info
)->telNumber
);
99 free((*db_owner_info
)->identifier
);
100 free((*db_owner_info
)->registryCode
);
101 free((*db_owner_info
)->dbState
);
102 free((*db_owner_info
)->dbEffectiveOVM
);
104 free(*db_owner_info
);
105 *db_owner_info
= NULL
;
109 /* Deallocate struct isds_envelope recurisvely and NULL it */
110 void isds_envelope_free(struct isds_envelope
**envelope
) {
111 if (!envelope
|| !*envelope
) return;
113 free((*envelope
)->dmID
);
114 free((*envelope
)->dbIDSender
);
115 free((*envelope
)->dmSender
);
116 free((*envelope
)->dmSenderAddress
);
117 free((*envelope
)->dmSenderType
);
118 free((*envelope
)->dmRecipient
);
119 free((*envelope
)->dmRecipientAddress
);
120 free((*envelope
)->dmAmbiguousRecipient
);
122 free((*envelope
)->dmOrdinal
);
123 free((*envelope
)->dmMessageStatus
);
124 free((*envelope
)->dmDeliveryTime
);
125 free((*envelope
)->dmAcceptanceTime
);
126 isds_hash_free(&(*envelope
)->hash
);
127 free((*envelope
)->timestamp
);
129 free((*envelope
)->dmSenderOrgUnit
);
130 free((*envelope
)->dmSenderOrgUnitNum
);
131 free((*envelope
)->dbIDRecipient
);
132 free((*envelope
)->dmRecipientOrgUnit
);
133 free((*envelope
)->dmRecipientOrgUnitNum
);
134 free((*envelope
)->dmToHands
);
135 free((*envelope
)->dmAnnotation
);
136 free((*envelope
)->dmRecipientRefNumber
);
137 free((*envelope
)->dmSenderRefNumber
);
138 free((*envelope
)->dmRecipientIdent
);
139 free((*envelope
)->dmSenderIdent
);
141 free((*envelope
)->dmLegalTitleLaw
);
142 free((*envelope
)->dmLegalTitleYear
);
143 free((*envelope
)->dmLegalTitleSect
);
144 free((*envelope
)->dmLegalTitlePar
);
145 free((*envelope
)->dmLegalTitlePoint
);
147 free((*envelope
)->dmPersonalDelivery
);
148 free((*envelope
)->dmAllowSubstDelivery
);
149 free((*envelope
)->dmOVM
);
156 /* Deallocate struct isds_message recurisvely and NULL it */
157 void isds_message_free(struct isds_message
**message
) {
158 if (!message
|| !*message
) return;
160 free((*message
)->raw
);
161 isds_envelope_free(&((*message
)->envelope
));
162 isds_list_free(&((*message
)->documents
));
169 /* Deallocate struct isds_document recurisvely and NULL it */
170 void isds_document_free(struct isds_document
**document
) {
171 if (!document
|| !*document
) return;
173 free((*document
)->data
);
174 free((*document
)->dmMimeType
);
175 free((*document
)->dmFileGuid
);
176 free((*document
)->dmUpFileGuid
);
177 free((*document
)->dmFileDescr
);
178 free((*document
)->dmFormat
);
185 /* Initialize ISDS library.
186 * Global function, must be called before other functions.
187 * If it failes you can not use ISDS library and must call isds_cleanup() to
188 * free partially inititialized global variables. */
189 isds_error
isds_init(void) {
190 /* NULL global variables */
191 log_facilities
= ILF_ALL
;
192 log_level
= ILL_WARNING
;
194 /* Initialize CURL */
195 if (curl_global_init(CURL_GLOBAL_ALL
)) {
196 isds_log(ILF_ISDS
, ILL_CRIT
, _("CURL library initialization failed\n"));
200 /* Inicialize gpg-error because of gpgme and ksba */
201 if (gpg_err_init()) {
202 isds_log(ILF_ISDS
, ILL_CRIT
,
203 _("gpg-error library initialization failed\n"));
207 /* Initialize GPGME */
209 isds_log(ILF_ISDS
, ILL_CRIT
,
210 _("GPGME library initialization failed\n"));
214 /* Initialize gcrypt */
216 isds_log(ILF_ISDS
, ILL_CRIT
,
217 _("gcrypt library initialization failed\n"));
222 /* This can _exit() current program. Find not so assertive check. */
225 /* Allocate global variables */
232 /* Deinicialize ISDS library.
233 * Global function, must be called as last library function. */
234 isds_error
isds_cleanup(void) {
239 curl_global_cleanup();
245 /* Return text description of ISDS error */
246 char *isds_strerror(const isds_error error
) {
249 return(_("Success")); break;
251 return(_("Unspecified error")); break;
253 return(_("Not supported")); break;
255 return(_("Invalid value")); break;
256 case IE_INVALID_CONTEXT
:
257 return(_("Invalid context")); break;
258 case IE_NOT_LOGGED_IN
:
259 return(_("Not logged in")); break;
260 case IE_CONNECTION_CLOSED
:
261 return(_("Connection closed")); break;
263 return(_("Timed out")); break;
265 return(_("Not exist")); break;
267 return(_("Out of memory")); break;
269 return(_("Network problem")); break;
271 return(_("HTTP problem")); break;
273 return(_("SOAP problem")); break;
275 return(_("XML problem")); break;
277 return(_("ISDS server problem")); break;
279 return(_("Invalid enum value")); break;
281 return(_("Invalid date value")); break;
283 return(_("Too big")); break;
285 return(_("Value not unique")); break;
287 return(_("Unknown error"));
292 /* Create ISDS context.
293 * Each context can be used for different sessions to (possibly) differnet
294 * ISDS server with different credentials. */
295 struct isds_ctx
*isds_ctx_create(void) {
296 struct isds_ctx
*context
;
297 context
= malloc(sizeof(*context
));
298 if (context
) memset(context
, 0, sizeof(*context
));
303 /* Destroy ISDS context and free memmory.
304 * @context will be NULLed on success. */
305 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
306 if (!context
|| !*context
) {
307 return IE_INVALID_CONTEXT
;
310 /* Discard credentials */
311 isds_logout(*context
);
313 /* Free other structures */
314 free((*context
)->tls_verify_server
);
315 free((*context
)->tls_ca_file
);
316 free((*context
)->tls_ca_dir
);
317 free((*context
)->long_message
);
325 /* Return long message text produced by library fucntion, e.g. detailed error
326 * mesage. Returned pointer is only valid until new library function is
327 * called for the same context. Could be NULL, especially if NULL context is
328 * supplied. Return string is locale encoded. */
329 char *isds_long_message(const struct isds_ctx
*context
) {
330 if (!context
) return NULL
;
331 return context
->long_message
;
335 /* Stores message into context' long_message buffer.
336 * Application can pick the message up using isds_long_message().
337 * NULL @message truncates the buffer but does not deallocate it.
338 * @message is coded in locale encoding */
339 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
340 const char *message
) {
344 if (!context
) return IE_INVALID_CONTEXT
;
346 /* FIXME: Check for integer overflow */
347 length
= 1 + ((message
) ? strlen(message
) : 0);
348 buffer
= realloc(context
->long_message
, length
);
349 if (!buffer
) return IE_NOMEM
;
352 strcpy(buffer
, message
);
356 context
->long_message
= buffer
;
361 /* Appends message into context' long_message buffer.
362 * Application can pick the message up using isds_long_message().
363 * NULL message has void effect. */
364 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
365 const char *message
) {
367 size_t old_length
, length
;
369 if (!context
) return IE_INVALID_CONTEXT
;
370 if (!message
) return IE_SUCCESS
;
371 if (!context
->long_message
)
372 return isds_log_message(context
, message
);
374 old_length
= strlen(context
->long_message
);
375 /* FIXME: Check for integer overflow */
376 length
= 1 + old_length
+ strlen(message
);
377 buffer
= realloc(context
->long_message
, length
);
378 if (!buffer
) return IE_NOMEM
;
380 strcpy(buffer
+ old_length
, message
);
382 context
->long_message
= buffer
;
387 /* Stores formated message into context' long_message buffer.
388 * Application can pick the message up using isds_long_message(). */
389 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
390 const char *format
, ...) {
394 if (!context
) return IE_INVALID_CONTEXT
;
395 va_start(ap
, format
);
396 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
399 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
404 * @facilities is bitmask of isds_log_facility values,
405 * @level is verbosity level. */
406 void isds_set_logging(const unsigned int facilities
,
407 const isds_log_level level
) {
408 log_facilities
= facilities
;
413 /* Log @message in class @facility with log @level into global log. @message
414 * is printf(3) formating string, variadic arguments may be neccessary.
415 * For debugging purposes. */
416 _hidden isds_error
isds_log(const isds_log_facility facility
,
417 const isds_log_level level
, const char *message
, ...) {
420 if (level
> log_level
) return IE_SUCCESS
;
421 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
422 if (!message
) return IE_INVAL
;
424 /* TODO: Allow to register output function privided by application
425 * (e.g. fprintf to stderr or copy to text area GUI widget). */
427 va_start(ap
, message
);
428 vfprintf(stderr
, message
, ap
);
430 /* Line buffered printf is default.
437 /* Connect to given url.
438 * It just makes TCP connection to ISDS server found in @url hostname part. */
439 /*int isds_connect(struct isds_ctx *context, const char *url);*/
441 /* Set timeout in miliseconds for each network job like connecting to server
442 * or sending message. Use 0 to disable timeout limits. */
443 isds_error
isds_set_timeout(struct isds_ctx
*context
,
444 const unsigned int timeout
) {
445 if (!context
) return IE_INVALID_CONTEXT
;
447 context
->timeout
= timeout
;
452 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
454 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
456 if (curl_err
) return IE_ERROR
;
463 /* Change SSL/TLS settings.
464 * @context is context which setting will be applied to
465 * @option is name of option. It determines the type of last argument. See
466 * isds_tls_option definition for more info.
467 * @... is value of new setting. Type is determined by @option
469 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
471 isds_error err
= IE_SUCCESS
;
473 char *pointer
, *string
;
475 if (!context
) return IE_INVALID_CONTEXT
;
477 va_start(ap
, option
);
479 #define REPLACE_VA_STRING(destination) \
480 string = va_arg(ap, char *); \
482 pointer = realloc((destination), 1 + strlen(string)); \
483 if (!pointer) { err = IE_NOMEM; goto leave; } \
484 strcpy(pointer, string); \
485 (destination) = pointer; \
488 (destination) = NULL; \
492 case ITLS_VERIFY_SERVER
:
493 if (!context
->tls_verify_server
) {
494 context
->tls_verify_server
=
495 malloc(sizeof(*context
->tls_verify_server
));
496 if (!context
->tls_verify_server
) {
497 err
= IE_NOMEM
; goto leave
;
500 *context
->tls_verify_server
= (_Bool
) (0 != va_arg(ap
, int));
504 REPLACE_VA_STRING(context
->tls_ca_file
);
506 case ITLS_CA_DIRECTORY
:
507 REPLACE_VA_STRING(context
->tls_ca_dir
);
511 err
= IE_ENUM
; goto leave
;
514 #undef REPLACE_VA_STRING
522 /* Discard credentials.
523 * Only that. It does not cause log out, connection close or similar. */
524 static isds_error
discard_credentials(struct isds_ctx
*context
) {
525 if(!context
) return IE_INVALID_CONTEXT
;
527 if (context
->username
) {
528 memset(context
->username
, 0, strlen(context
->username
));
529 free(context
->username
);
530 context
->username
= NULL
;
532 if (context
->password
) {
533 memset(context
->password
, 0, strlen(context
->password
));
534 free(context
->password
);
535 context
->password
= NULL
;
542 /* Connect and log in into ISDS server.
543 * @url is address of ISDS web service
544 * @username is user name of ISDS user
545 * @password is user's secret password
546 * @certificate is NULL terminated string with PEM formated client's
547 * certificate. Use NULL if only password autentication should be performed.
548 * @key is private key for client's certificate as (base64 encoded?) NULL
549 * terminated string. Use NULL if only password autentication is desired.
551 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
552 const char *username
, const char *password
,
553 const char *certificate
, const char* key
) {
554 isds_error err
= IE_NOT_LOGGED_IN
;
556 xmlNsPtr isds_ns
= NULL
;
557 xmlNodePtr request
= NULL
;
558 xmlNodePtr response
= NULL
;
560 if (!context
) return IE_INVALID_CONTEXT
;
561 if (!url
|| !username
|| !password
) return IE_INVAL
;
562 if (certificate
|| key
) return IE_NOTSUP
;
564 /* Store configuration */
566 context
->url
= strdup(url
);
570 /* Close connection if already logged in */
572 close_connection(context
);
575 /* Prepare CURL handle */
576 context
->curl
= curl_easy_init();
577 if (!(context
->curl
))
580 /* Build login request */
581 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
583 isds_log_message(context
, _("Could build ISDS login request"));
586 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
588 isds_log_message(context
, _("Could not create ISDS name space"));
589 xmlFreeNode(request
);
592 xmlSetNs(request
, isds_ns
);
594 /* Store credentials */
595 /* FIXME: mlock password
596 * (I have a library) */
597 discard_credentials(context
);
598 context
->username
= strdup(username
);
599 context
->password
= strdup(password
);
600 if (!(context
->username
&& context
->password
)) {
601 discard_credentials(context
);
602 xmlFreeNode(request
);
606 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
609 /* Send login request */
610 soap_err
= soap(context
, "dz", request
, &response
);
612 /* Remove credentials */
613 discard_credentials(context
);
615 /* Destroy login request */
616 xmlFreeNode(request
);
619 xmlFreeNodeList(response
);
620 close_connection(context
);
624 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
625 * authentication succeeded if soap_err == IE_SUCCESS */
628 xmlFreeNodeList(response
);
631 isds_log(ILF_ISDS
, ILL_DEBUG
,
632 _("User %s has been logged into server %s successfully\n"),
638 /* Log out from ISDS server discards credentials and connection configuration. */
639 isds_error
isds_logout(struct isds_ctx
*context
) {
640 if (!context
) return IE_INVALID_CONTEXT
;
642 /* Close connection */
644 close_connection(context
);
646 /* Discard credentials for sure. They should not survive isds_login(),
647 * even successful .*/
648 discard_credentials(context
);
652 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
654 discard_credentials(context
);
660 /* Verify connection to ISDS is alive and server is responding.
661 * Sent dumy request to ISDS and expect dummy response. */
662 isds_error
isds_ping(struct isds_ctx
*context
) {
664 xmlNsPtr isds_ns
= NULL
;
665 xmlNodePtr request
= NULL
;
666 xmlNodePtr response
= NULL
;
668 if (!context
) return IE_INVALID_CONTEXT
;
670 /* Check if connection is established */
671 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
674 /* Build dummy request */
675 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
677 isds_log_message(context
, _("Could build ISDS dummy request"));
680 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
682 isds_log_message(context
, _("Could not create ISDS name space"));
683 xmlFreeNode(request
);
686 xmlSetNs(request
, isds_ns
);
688 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
690 /* Sent dummy request */
691 soap_err
= soap(context
, "dz", request
, &response
);
693 /* Destroy login request */
694 xmlFreeNode(request
);
697 isds_log(ILF_ISDS
, ILL_DEBUG
,
698 _("ISDS server could not be contacted\n"));
699 xmlFreeNodeList(response
);
700 close_connection(context
);
704 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
705 * authentication succeeded if soap_err == IE_SUCCESS */
706 /* TODO: ISDS documentation does not specify response body.
707 * However real server sends back DummyOperationResponse */
710 xmlFreeNodeList(response
);
712 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
718 /* Send bogus request to ISDS.
719 * Just for test purposes */
720 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
722 xmlNsPtr isds_ns
= NULL
;
723 xmlNodePtr request
= NULL
;
724 xmlDocPtr response
= NULL
;
725 xmlChar
*code
= NULL
, *message
= NULL
;
727 if (!context
) return IE_INVALID_CONTEXT
;
729 /* Check if connection is established */
730 if (!context
->curl
) {
731 /* Testing printf message */
732 isds_printf_message(context
, "%s", _("I said connection closed"));
733 return IE_CONNECTION_CLOSED
;
737 /* Build dummy request */
738 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
740 isds_log_message(context
, _("Could build ISDS bogus request"));
743 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
745 isds_log_message(context
, _("Could not create ISDS name space"));
746 xmlFreeNode(request
);
749 xmlSetNs(request
, isds_ns
);
751 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
753 /* Sent bogus request */
754 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
756 /* Destroy request */
757 xmlFreeNode(request
);
760 isds_log(ILF_ISDS
, ILL_DEBUG
,
761 _("Processing ISDS response on bogus request failed\n"));
762 xmlFreeDoc(response
);
766 /* Check for response status */
767 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
768 &code
, &message
, NULL
);
770 isds_log(ILF_ISDS
, ILL_DEBUG
,
771 _("ISDS response on bogus request is missing status\n"));
774 xmlFreeDoc(response
);
777 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
778 char *code_locale
= utf82locale((char*)code
);
779 char *message_locale
= utf82locale((char*)message
);
780 isds_log(ILF_ISDS
, ILL_DEBUG
,
781 _("Server refused bogus request (code=%s, message=%s)\n"),
782 code_locale
, message_locale
);
783 /* XXX: Literal error messages from ISDS are Czech mesages
784 * (English sometimes) in UTF-8. It's hard to catch them for
785 * translation. Successfully gettextized would return in locale
786 * encoding, unsuccessfully translated would pass in UTF-8. */
787 isds_log_message(context
, message_locale
);
789 free(message_locale
);
792 xmlFreeDoc(response
);
799 xmlFreeDoc(response
);
801 isds_log(ILF_ISDS
, ILL_DEBUG
,
802 _("Bogus message accepted by server. This should not happen.\n"));
808 /* Serialize XML subtree to buffer preserving XML indentatition.
809 * @context is session context
810 * @subtree is XML element to be serialized (with childern)
811 * @buffer is automarically reallocated buffer where serialize to
812 * @length is size of serialized stream in bytes
813 * @return standard error code, free @buffer in case of error */
814 static isds_error
serialize_subtree(struct isds_ctx
*context
,
815 xmlNodePtr subtree
, void **buffer
, size_t *length
) {
816 isds_error err
= IE_SUCCESS
;
817 xmlBufferPtr xml_buffer
= NULL
;
818 xmlSaveCtxtPtr save_ctx
= NULL
;
819 xmlDocPtr subtree_doc
= NULL
;
820 xmlNodePtr subtree_copy
;
824 if (!context
) return IE_INVALID_CONTEXT
;
825 if (!buffer
) return IE_INVAL
;
827 if (!subtree
|| !length
) return IE_INVAL
;
829 /* Make temporary XML document with @subtree root element */
830 /* XXX: We can not use xmlNodeDump() because it dumps the subtree as is.
831 * It can result in not well-formed on invalid XML tree (e.g. name space
832 * prefix definition can miss. */
835 subtree_doc
= xmlNewDoc(BAD_CAST
"1.0");
837 isds_log_message(context
, _("Could not build temporary document"));
842 /* XXX: Copy subtree and attach the copy to document.
843 * One node can not bee attached into more document at the same time.
844 * XXX: Check xmlDOMWrapRemoveNode(). It could solve NS references
846 * XXX: Check xmlSaveTree() too. */
847 subtree_copy
= xmlCopyNodeList(subtree
);
849 isds_log_message(context
, _("Could not copy subtree"));
853 xmlDocSetRootElement(subtree_doc
, subtree_copy
);
855 /* Only this way we get namespace definition as @xmlns:isds,
856 * otherwise we get namespace prefix without definition */
857 /* FIXME: Don't overwrite original default namespace */
858 isds_ns
= xmlNewNs(subtree_copy
, BAD_CAST ISDS_NS
, NULL
);
860 isds_log_message(context
, _("Could not create ISDS name space"));
864 xmlSetNs(subtree_copy
, isds_ns
);
867 /* Serialize the document into buffer */
868 xml_buffer
= xmlBufferCreate();
870 isds_log_message(context
, _("Could not create xmlBuffer"));
874 /* Last argument 0 means to not format the XML tree */
875 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8", 0);
877 isds_log_message(context
, _("Could not create XML serializer"));
881 /* XXX: According LibXML documentation, this function does not return
882 * meaningfull value yet */
883 xmlSaveDoc(save_ctx
, subtree_doc
);
884 if (-1 == xmlSaveFlush(save_ctx
)) {
885 isds_log_message(context
,
886 _("Could not serialize XML subtree"));
890 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
891 * even after xmlSaveFlush(). Thus close it here */
892 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
895 /* Store and detach buffer from xml_buffer */
896 *buffer
= xml_buffer
->content
;
897 *length
= xml_buffer
->use
;
898 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
901 new_buffer
= realloc(*buffer
, *length
);
902 if (new_buffer
) *buffer
= new_buffer
;
910 xmlSaveClose(save_ctx
);
911 xmlBufferFree(xml_buffer
);
912 xmlFreeDoc(subtree_doc
); /* Frees subtree_copy, isds_ns etc. */
917 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
918 * @context is session context
919 * @document is original document where @nodeset points to
920 * @nodeset is XPath node set to dump (recursively)
921 * @buffer is automarically reallocated buffer where serialize to
922 * @length is size of serialized stream in bytes
923 * @return standard error code, free @buffer in case of error */
924 static isds_error
dump_nodeset(struct isds_ctx
*context
,
925 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
926 void **buffer
, size_t *length
) {
927 isds_error err
= IE_SUCCESS
;
928 xmlBufferPtr xml_buffer
= NULL
;
931 if (!context
) return IE_INVALID_CONTEXT
;
932 if (!buffer
) return IE_INVAL
;
934 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
937 /* Empty node set results into NULL buffer */
938 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
942 /* Resuling the document into buffer */
943 xml_buffer
= xmlBufferCreate();
945 isds_log_message(context
, _("Could not create xmlBuffer"));
950 /* Itearate over all nodes */
951 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
953 * XXX: xmlNodeDump() appends to xml_buffer. */
955 xmlNodeDump(xml_buffer
, document
, nodeset
->nodeTab
[i
], 0, 0)) {
956 isds_log_message(context
, _("Could not dump XML node"));
962 /* Store and detach buffer from xml_buffer */
963 *buffer
= xml_buffer
->content
;
964 *length
= xml_buffer
->use
;
965 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
968 new_buffer
= realloc(*buffer
, *length
);
969 if (new_buffer
) *buffer
= new_buffer
;
978 xmlBufferFree(xml_buffer
);
983 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
984 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
985 if (!string
|| !type
) return IE_INVAL
;
987 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
989 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
991 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
992 *type
= DBTYPE_PFO_ADVOK
;
993 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
994 *type
= DBTYPE_PFO_DANPOR
;
995 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
996 *type
= DBTYPE_PFO_INSSPR
;
997 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
999 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
1000 *type
= DBTYPE_PO_ZAK
;
1001 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
1002 *type
= DBTYPE_PO_REQ
;
1003 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
1005 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
1006 *type
= DBTYPE_OVM_NOTAR
;
1007 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
1008 *type
= DBTYPE_OVM_EXEKUT
;
1009 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
1010 *type
= DBTYPE_OVM_REQ
;
1017 /* Convert ISDS dbType enum @type to UTF-8 string.
1018 * @Return pointer to static string, or NULL if unkwnow enum value */
1019 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
1021 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
1022 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
1023 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
1024 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DAPOR"); break;
1025 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
1026 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
1027 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
1028 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
1029 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
1030 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
1031 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
1032 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
1033 default: return NULL
; break;
1038 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
1039 * @Return pointer to static string, or NULL if unkwnow enum value */
1040 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
1042 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
1043 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
1044 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
1045 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
1046 default: return NULL
; break;
1051 /* Convert UTF-8 @string to ISDS dmFileMetaType enum @type.
1052 * @Return IE_ENUM if @string is not valid enum member */
1053 static isds_error
string2isds_FileMetaType(const xmlChar
*string
,
1054 isds_FileMetaType
*type
) {
1055 if (!string
|| !type
) return IE_INVAL
;
1057 if (!xmlStrcmp(string
, BAD_CAST
"main"))
1058 *type
= FILEMETATYPE_MAIN
;
1059 else if (!xmlStrcmp(string
, BAD_CAST
"enclosure"))
1060 *type
= FILEMETATYPE_ENCLOSURE
;
1061 else if (!xmlStrcmp(string
, BAD_CAST
"signature"))
1062 *type
= FILEMETATYPE_SIGNATURE
;
1063 else if (!xmlStrcmp(string
, BAD_CAST
"meta"))
1064 *type
= FILEMETATYPE_META
;
1071 /* Convert UTF-8 @string to ISDS hash @algorithm.
1072 * @Return IE_ENUM if @string is not valid enum member */
1073 static isds_error
string2isds_hash_algorithm(const xmlChar
*string
,
1074 isds_hash_algorithm
*algorithm
) {
1075 if (!string
|| !algorithm
) return IE_INVAL
;
1077 if (!xmlStrcmp(string
, BAD_CAST
"MD5"))
1078 *algorithm
= HASH_ALGORITHM_MD5
;
1079 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-1"))
1080 *algorithm
= HASH_ALGORITHM_SHA_1
;
1081 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-256"))
1082 *algorithm
= HASH_ALGORITHM_SHA_256
;
1083 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-512"))
1084 *algorithm
= HASH_ALGORITHM_SHA_512
;
1091 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
1092 * XXX: Not all ISO formats are supported */
1093 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
1095 if (!string
|| !time
) return IE_INVAL
;
1097 /* xsd:date is ISO 8601 string, thus ASCII */
1098 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
1099 if (offset
&& *offset
== '\0')
1102 offset
= strptime((char*)string
, "%Y%m%d", time
);
1103 if (offset
&& *offset
== '\0')
1106 offset
= strptime((char*)string
, "%Y-%j", time
);
1107 if (offset
&& *offset
== '\0')
1114 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
1115 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
1116 if (!time
|| !string
) return IE_INVAL
;
1118 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
1119 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
1126 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
1127 * respects the @time microseconds too. */
1128 static isds_error
timeval2timestring(const struct timeval
*time
,
1132 if (!time
|| !string
) return IE_INVAL
;
1134 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
1135 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
1137 /* TODO: small negative year should be formated as "-0012". This is not
1138 * true for glibc "%04d". We should implement it.
1139 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
1140 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
1141 if (-1 == isds_asprintf((char **) string
,
1142 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
1143 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
1144 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
1152 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
1153 * It respects microseconds too.
1154 * In case of error, @time will be freed. */
1155 static isds_error
timestring2timeval(const xmlChar
*string
,
1156 struct timeval
**time
) {
1158 char *offset
, *delim
, *endptr
;
1160 int offset_hours
, offset_minutes
;
1163 if (!time
) return IE_INVAL
;
1165 memset(&broken
, 0, sizeof(broken
));
1168 *time
= calloc(1, sizeof(**time
));
1169 if (!*time
) return IE_NOMEM
;
1171 memset(*time
, 0, sizeof(**time
));
1175 /* xsd:date is ISO 8601 string, thus ASCII */
1176 /*TODO: negative year */
1178 /* Parse date and time without subseconds and offset */
1179 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
1181 free(*time
); *time
= NULL
;
1185 /* Get subseconds */
1186 if (*offset
== '.' ) {
1189 /* Copy first 6 digits, padd it with zeros.
1190 * XXX: It truncates longer number, no round.
1191 * Current server implementation uses only milisecond resolution. */
1192 /* TODO: isdigit() is locale sensitive */
1194 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
1196 subseconds
[i
] = *offset
;
1198 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
1199 subseconds
[i
] = '0';
1201 subseconds
[6] = '\0';
1203 /* Convert it into integer */
1204 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
1205 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
1206 (*time
)->tv_usec
== LONG_MAX
) {
1207 free(*time
); *time
= NULL
;
1211 /* move to the zone offset delimiter */
1212 delim
= strchr(offset
, '-');
1214 delim
= strchr(offset
, '+');
1218 /* Get zone offset */
1219 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
1220 * "" equals to "Z" and it means UTC zone. */
1221 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
1222 * colon separator */
1223 if (*offset
== '-' || *offset
== '+') {
1225 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
1226 free(*time
); *time
= NULL
;
1229 broken
.tm_hour
-= offset_hours
;
1230 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
1233 /* Convert to time_t */
1235 (*time
)->tv_sec
= mktime(&broken
);
1236 switch_tz_to_native();
1237 if ((*time
)->tv_sec
== (time_t) -1) {
1238 free(*time
); *time
= NULL
;
1246 /* Convert unsigned int into isds_message_status.
1247 * @context is session context
1248 * @number is pointer to number value. NULL will be treated as invalid value.
1249 * @status is automatically reallocated status
1250 * @return IE_SUCCESS, or error code and free status */
1251 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1252 const unsigned long int *number
, isds_message_status
**status
) {
1253 if (!context
) return IE_INVALID_CONTEXT
;
1254 if (!status
) return IE_INVAL
;
1256 free(*status
); *status
= NULL
;
1257 if (!number
) return IE_INVAL
;
1259 if (*number
< 1 || *number
> 9) {
1260 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1265 *status
= malloc(sizeof(**status
));
1266 if (!*status
) return IE_NOMEM
;
1268 **status
= 1 << *number
;
1273 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1274 * and leave lable */
1275 #define EXTRACT_STRING(element, string) \
1276 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
1281 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
1282 if (result->nodesetval->nodeNr > 1) { \
1283 isds_log_message(context, _("Multiple " element " element")); \
1287 (string) = (char *) \
1288 xmlXPathCastNodeSetToString(result->nodesetval); \
1295 #define EXTRACT_BOOLEAN(element, booleanPtr) \
1297 char *string = NULL; \
1298 EXTRACT_STRING(element, string); \
1301 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
1302 if (!(booleanPtr)) { \
1308 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
1309 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
1310 *(booleanPtr) = 1; \
1311 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
1312 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
1313 *(booleanPtr) = 0; \
1315 char *string_locale = utf82locale((char*)string); \
1316 isds_printf_message(context, \
1317 _(element " value is not valid boolean: "), \
1319 free(string_locale); \
1329 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
1331 char *string = NULL; \
1332 EXTRACT_STRING(element, string); \
1337 number = strtol((char*)string, &endptr, 10); \
1339 if (*endptr != '\0') { \
1340 char *string_locale = utf82locale((char *)string); \
1341 isds_printf_message(context, \
1342 _(element" is not valid integer: %s"), \
1344 free(string_locale); \
1350 if (number == LONG_MIN || number == LONG_MAX) { \
1351 char *string_locale = utf82locale((char *)string); \
1352 isds_printf_message(context, \
1353 _(element " value out of range of long int: %s"), \
1355 free(string_locale); \
1361 free(string); string = NULL; \
1363 if (!(preallocated)) { \
1364 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
1365 if (!(longintPtr)) { \
1370 *(longintPtr) = number; \
1374 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
1376 char *string = NULL; \
1377 EXTRACT_STRING(element, string); \
1382 number = strtol((char*)string, &endptr, 10); \
1384 if (*endptr != '\0') { \
1385 char *string_locale = utf82locale((char *)string); \
1386 isds_printf_message(context, \
1387 _(element" is not valid integer: %s"), \
1389 free(string_locale); \
1395 if (number == LONG_MIN || number == LONG_MAX) { \
1396 char *string_locale = utf82locale((char *)string); \
1397 isds_printf_message(context, \
1398 _(element " value out of range of long int: %s"), \
1400 free(string_locale); \
1406 free(string); string = NULL; \
1408 isds_printf_message(context, \
1409 _(element " value is negative: %ld"), number); \
1414 if (!(preallocated)) { \
1415 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
1416 if (!(ulongintPtr)) { \
1421 *(ulongintPtr) = number; \
1425 #define EXTRACT_STRING_ATTRIBUTE(attribute, string, required) \
1426 (string) = (char *) xmlGetNsProp(xpath_ctx->node, ( BAD_CAST attribute), \
1428 if ((required) && (!string)) { \
1429 char *attribute_locale = utf82locale(attribute); \
1430 char *element_locale = utf82locale((char *)xpath_ctx->node->name); \
1431 isds_printf_message(context, \
1432 _("Could not extract required %s attribute value from " \
1433 "%s element"), attribute_locale, element_locale); \
1434 free(element_locale); \
1435 free(attribute_locale); \
1441 #define INSERT_STRING(parent, element, string) \
1442 node = xmlNewTextChild(parent, NULL, BAD_CAST (element), \
1443 (xmlChar *) (string)); \
1445 isds_printf_message(context, _("Could not add " element " child to " \
1446 "%s element"), (parent)->name); \
1451 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
1452 if ((booleanPtr)) { \
1453 if (*(booleanPtr)) { INSERT_STRING(parent, element, "true"); } \
1454 else { INSERT_STRING(parent, element, "false") } \
1455 } else { INSERT_STRING(parent, element, NULL) }
1457 #define INSERT_LONGINT(parent, element, longintPtr, buffer) \
1458 if ((longintPtr)) { \
1459 /* FIXME: locale sensitive */ \
1460 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
1464 INSERT_STRING(parent, element, buffer) \
1465 free(buffer); (buffer) = NULL; \
1466 } else { INSERT_STRING(parent, element, NULL) }
1468 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) \
1469 if ((ulongintPtr)) { \
1470 /* FIXME: locale sensitive */ \
1471 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
1475 INSERT_STRING(parent, element, buffer) \
1476 free(buffer); (buffer) = NULL; \
1477 } else { INSERT_STRING(parent, element, NULL) }
1479 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
1480 /* FIXME: locale sensitive */ \
1481 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
1485 INSERT_STRING(parent, element, buffer) \
1486 free(buffer); (buffer) = NULL; \
1488 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
1489 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
1490 (xmlChar *) (string)); \
1491 if (!attribute_node) { \
1492 isds_printf_message(context, _("Could not add " attribute \
1493 " attribute to %s element"), (parent)->name); \
1499 /* Find child element by name in given XPath context and switch context onto
1500 * it. The child must be uniq and must exist. Otherwise failes.
1501 * @context is ISDS context
1502 * @child is child element name
1503 * @xpath_ctx is XPath context. In success, the @xpath_ctx will be changed
1504 * into it child. In error case, the @xpath_ctx keeps original value. */
1505 static isds_error
move_xpathctx_to_child(struct isds_ctx
*context
,
1506 const xmlChar
*child
, xmlXPathContextPtr xpath_ctx
) {
1507 isds_error err
= IE_SUCCESS
;
1508 xmlXPathObjectPtr result
= NULL
;
1510 if (!context
) return IE_INVALID_CONTEXT
;
1511 if (!child
|| !xpath_ctx
) return IE_INVAL
;
1514 result
= xmlXPathEvalExpression(child
, xpath_ctx
);
1521 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
1522 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1523 char *child_locale
= utf82locale((char*) child
);
1524 isds_printf_message(context
,
1525 _("%s element does not contain %s child"),
1526 parent_locale
, child_locale
);
1528 free(parent_locale
);
1534 if (result
->nodesetval
->nodeNr
> 1) {
1535 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1536 char *child_locale
= utf82locale((char*) child
);
1537 isds_printf_message(context
,
1538 _("%s element contains multiple %s childs"),
1539 parent_locale
, child_locale
);
1541 free(parent_locale
);
1546 /* Switch context */
1547 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
1550 xmlXPathFreeObject(result
);
1556 /* Convert isds:dBOwnerInfo XML tree into structure
1557 * @context is ISDS context
1558 * @db_owner_info is automically reallocated box owner info structure
1559 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
1560 * In case of error @db_owner_info will be freed. */
1561 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
1562 struct isds_DbOwnerInfo
**db_owner_info
,
1563 xmlXPathContextPtr xpath_ctx
) {
1564 isds_error err
= IE_SUCCESS
;
1565 xmlXPathObjectPtr result
= NULL
;
1566 char *string
= NULL
;
1568 if (!context
) return IE_INVALID_CONTEXT
;
1569 if (!db_owner_info
) return IE_INVAL
;
1570 isds_DbOwnerInfo_free(db_owner_info
);
1571 if (!xpath_ctx
) return IE_INVAL
;
1574 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
1575 if (!*db_owner_info
) {
1580 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
1582 EXTRACT_STRING("isds:dbType", string
);
1584 (*db_owner_info
)->dbType
=
1585 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
1586 if (!(*db_owner_info
)->dbType
) {
1590 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
1592 free((*db_owner_info
)->dbType
);
1593 (*db_owner_info
)->dbType
= NULL
;
1594 if (err
== IE_ENUM
) {
1596 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
1601 free(string
); string
= NULL
;
1604 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
1606 (*db_owner_info
)->personName
=
1607 calloc(1, sizeof(*((*db_owner_info
)->personName
)));
1608 if (!(*db_owner_info
)->personName
) {
1612 EXTRACT_STRING("isds:pnFirstName",
1613 (*db_owner_info
)->personName
->pnFirstName
);
1614 EXTRACT_STRING("isds:pnMiddleName",
1615 (*db_owner_info
)->personName
->pnMiddleName
);
1616 EXTRACT_STRING("isds:pnLastName",
1617 (*db_owner_info
)->personName
->pnLastName
);
1618 EXTRACT_STRING("isds:pnLastNameAtBirth",
1619 (*db_owner_info
)->personName
->pnLastNameAtBirth
);
1620 if (!(*db_owner_info
)->personName
->pnFirstName
&&
1621 !(*db_owner_info
)->personName
->pnMiddleName
&&
1622 !(*db_owner_info
)->personName
->pnLastName
&&
1623 !(*db_owner_info
)->personName
->pnLastNameAtBirth
)
1624 isds_PersonName_free(&(*db_owner_info
)->personName
);
1626 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
1628 (*db_owner_info
)->birthInfo
=
1629 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
1630 if (!(*db_owner_info
)->birthInfo
) {
1634 EXTRACT_STRING("isds:biDate", string
);
1636 (*db_owner_info
)->birthInfo
->biDate
=
1637 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
->biDate
)));
1638 if (!(*db_owner_info
)->birthInfo
->biDate
) {
1642 err
= datestring2tm((xmlChar
*)string
,
1643 (*db_owner_info
)->birthInfo
->biDate
);
1645 free((*db_owner_info
)->birthInfo
->biDate
);
1646 (*db_owner_info
)->birthInfo
->biDate
= NULL
;
1647 if (err
== IE_NOTSUP
) {
1649 isds_printf_message(context
,
1650 _("Invalid isds:biDate value: %s"), (char *)string
);
1654 free(string
); string
= NULL
;
1656 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
1657 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
1658 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
1659 if (!(*db_owner_info
)->birthInfo
->biDate
&&
1660 !(*db_owner_info
)->birthInfo
->biCity
&&
1661 !(*db_owner_info
)->birthInfo
->biCounty
&&
1662 !(*db_owner_info
)->birthInfo
->biState
)
1663 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
1665 (*db_owner_info
)->address
=
1666 calloc(1, sizeof(*((*db_owner_info
)->address
)));
1667 if (!(*db_owner_info
)->address
) {
1671 EXTRACT_STRING("isds:adCity",
1672 (*db_owner_info
)->address
->adCity
);
1673 EXTRACT_STRING("isds:adStreet",
1674 (*db_owner_info
)->address
->adStreet
);
1675 EXTRACT_STRING("isds:adNumberInStreet",
1676 (*db_owner_info
)->address
->adNumberInStreet
);
1677 EXTRACT_STRING("isds:adNumberInMunicipality",
1678 (*db_owner_info
)->address
->adNumberInMunicipality
);
1679 EXTRACT_STRING("isds:adZipCode",
1680 (*db_owner_info
)->address
->adZipCode
);
1681 EXTRACT_STRING("isds:adState",
1682 (*db_owner_info
)->address
->adState
);
1683 if (!(*db_owner_info
)->address
->adCity
&&
1684 !(*db_owner_info
)->address
->adStreet
&&
1685 !(*db_owner_info
)->address
->adNumberInStreet
&&
1686 !(*db_owner_info
)->address
->adNumberInMunicipality
&&
1687 !(*db_owner_info
)->address
->adZipCode
&&
1688 !(*db_owner_info
)->address
->adState
)
1689 isds_Address_free(&(*db_owner_info
)->address
);
1691 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
1692 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
1693 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
1694 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
1695 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
1697 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
1699 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
1700 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
1701 (*db_owner_info
)->dbOpenAddressing
);
1704 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
1706 xmlXPathFreeObject(result
);
1711 /* Convert XSD gMessageEnvelopeSub group of elements from XML tree into
1712 * isds_envelope structure. The envelope is automatically allocated but not
1713 * reallocated. The date are just appended into envelope structure.
1714 * @context is ISDS context
1715 * @envelope is automically allocated message envelope structure
1716 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
1717 * In case of error @envelope will be freed. */
1718 static isds_error
append_GMessageEnvelopeSub(struct isds_ctx
*context
,
1719 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1720 isds_error err
= IE_SUCCESS
;
1721 xmlXPathObjectPtr result
= NULL
;
1723 if (!context
) return IE_INVALID_CONTEXT
;
1724 if (!envelope
) return IE_INVAL
;
1725 if (!xpath_ctx
) return IE_INVAL
;
1729 /* Allocate envelope */
1730 *envelope
= calloc(1, sizeof(**envelope
));
1736 /* Else free former data */
1737 zfree((*envelope
)->dmSenderOrgUnit
);
1738 zfree((*envelope
)->dmSenderOrgUnitNum
);
1739 zfree((*envelope
)->dbIDRecipient
);
1740 zfree((*envelope
)->dmRecipientOrgUnit
);
1741 zfree((*envelope
)->dmSenderOrgUnitNum
);
1742 zfree((*envelope
)->dmToHands
);
1743 zfree((*envelope
)->dmAnnotation
);
1744 zfree((*envelope
)->dmRecipientRefNumber
);
1745 zfree((*envelope
)->dmSenderRefNumber
);
1746 zfree((*envelope
)->dmRecipientIdent
);
1747 zfree((*envelope
)->dmSenderIdent
);
1748 zfree((*envelope
)->dmLegalTitleLaw
);
1749 zfree((*envelope
)->dmLegalTitleYear
);
1750 zfree((*envelope
)->dmLegalTitleSect
);
1751 zfree((*envelope
)->dmLegalTitlePar
);
1752 zfree((*envelope
)->dmLegalTitlePoint
);
1753 zfree((*envelope
)->dmPersonalDelivery
);
1754 zfree((*envelope
)->dmAllowSubstDelivery
);
1757 /* Extract envelope elements added by sender or ISDS
1758 * (XSD: gMessageEnvelopeSub type) */
1759 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
1760 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
1761 (*envelope
)->dmSenderOrgUnitNum
, 0);
1762 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
1763 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
1764 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
1765 (*envelope
)->dmSenderOrgUnitNum
, 0);
1766 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
1767 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
1768 EXTRACT_STRING("isds:dmRecipientRefNumber",
1769 (*envelope
)->dmRecipientRefNumber
);
1770 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
1771 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
1772 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
1774 /* Extract envelope elements regarding law refference */
1775 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
1776 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
1777 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
1778 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
1779 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
1781 /* Extract envelope other elements */
1782 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
1783 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
1784 (*envelope
)->dmAllowSubstDelivery
);
1787 if (err
) isds_envelope_free(envelope
);
1788 xmlXPathFreeObject(result
);
1794 /* Convert XSD gMessageEnvelope group of elements from XML tree into
1795 * isds_envelope structure. The envelope is automatically allocated but not
1796 * reallocated. The date are just appended into envelope structure.
1797 * @context is ISDS context
1798 * @envelope is automically allocated message envelope structure
1799 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
1800 * In case of error @envelope will be freed. */
1801 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
1802 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1803 isds_error err
= IE_SUCCESS
;
1804 xmlXPathObjectPtr result
= NULL
;
1806 if (!context
) return IE_INVALID_CONTEXT
;
1807 if (!envelope
) return IE_INVAL
;
1808 if (!xpath_ctx
) return IE_INVAL
;
1812 /* Allocate envelope */
1813 *envelope
= calloc(1, sizeof(**envelope
));
1819 /* Else free former data */
1820 zfree((*envelope
)->dmID
);
1821 zfree((*envelope
)->dbIDSender
);
1822 zfree((*envelope
)->dmSender
);
1823 zfree((*envelope
)->dmSenderAddress
);
1824 zfree((*envelope
)->dmSenderType
);
1825 zfree((*envelope
)->dmRecipient
);
1826 zfree((*envelope
)->dmRecipientAddress
);
1827 zfree((*envelope
)->dmAmbiguousRecipient
);
1830 /* Extract envelope elements added by ISDS
1831 * (XSD: gMessageEnvelope type) */
1832 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
1833 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
1834 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
1835 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
1836 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
1837 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
1838 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
1839 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
1840 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
1841 (*envelope
)->dmAmbiguousRecipient
);
1843 /* Extract envelope elements added by sender and ISDS
1844 * (XSD: gMessageEnvelope type) */
1845 err
= append_GMessageEnvelopeSub(context
, envelope
, xpath_ctx
);
1846 if (err
) goto leave
;
1849 if (err
) isds_envelope_free(envelope
);
1850 xmlXPathFreeObject(result
);
1855 /* Convert other envelope elements from XML tree into isds_envelope structure:
1856 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
1857 * The envelope is automatically allocated but not reallocated.
1858 * The data are just appended into envelope structure.
1859 * @context is ISDS context
1860 * @envelope is automically allocated message envelope structure
1861 * @xpath_ctx is XPath context with current node as parent desired elements
1862 * In case of error @envelope will be freed. */
1863 static isds_error
append_status_size_times(struct isds_ctx
*context
,
1864 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1865 isds_error err
= IE_SUCCESS
;
1866 xmlXPathObjectPtr result
= NULL
;
1867 char *string
= NULL
;
1868 unsigned long int *unumber
= NULL
;
1870 if (!context
) return IE_INVALID_CONTEXT
;
1871 if (!envelope
) return IE_INVAL
;
1872 if (!xpath_ctx
) return IE_INVAL
;
1877 *envelope
= calloc(1, sizeof(**envelope
));
1884 zfree((*envelope
)->dmMessageStatus
);
1885 zfree((*envelope
)->dmAttachmentSize
);
1886 zfree((*envelope
)->dmDeliveryTime
);
1887 zfree((*envelope
)->dmAcceptanceTime
);
1891 /* dmMessageStatus element is mandatory */
1892 EXTRACT_ULONGINT("sisds:dmMessageStatus", unumber
, 0);
1894 isds_log_message(context
,
1895 _("Missing mandatory sisds:dmMessageStatus integer"));
1899 err
= uint2isds_message_status(context
, unumber
,
1900 &((*envelope
)->dmMessageStatus
));
1902 if (err
== IE_ENUM
) err
= IE_ISDS
;
1905 free(unumber
); unumber
= NULL
;
1907 EXTRACT_ULONGINT("sisds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
,
1910 EXTRACT_STRING("sisds:dmDeliveryTime", string
);
1912 err
= timestring2timeval((xmlChar
*) string
,
1913 &((*envelope
)->dmDeliveryTime
));
1915 char *string_locale
= utf82locale(string
);
1916 if (err
== IE_DATE
) err
= IE_ISDS
;
1917 isds_printf_message(context
,
1918 _("Could not convert dmDeliveryTime as ISO time: %s"),
1920 free(string_locale
);
1925 EXTRACT_STRING("sisds:dmAcceptanceTime", string
);
1927 err
= timestring2timeval((xmlChar
*) string
,
1928 &((*envelope
)->dmAcceptanceTime
));
1930 char *string_locale
= utf82locale(string
);
1931 if (err
== IE_DATE
) err
= IE_ISDS
;
1932 isds_printf_message(context
,
1933 _("Could not convert dmAcceptanceTime as ISO time: %s"),
1935 free(string_locale
);
1941 if (err
) isds_envelope_free(envelope
);
1944 xmlXPathFreeObject(result
);
1949 /* Extract message document into reallocated document structure
1950 * @context is ISDS context
1951 * @document is automically reallocated message documents structure
1952 * @xpath_ctx is XPath context with current node as isds:dmFile
1953 * In case of error @document will be freed. */
1954 static isds_error
extract_document(struct isds_ctx
*context
,
1955 struct isds_document
**document
, xmlXPathContextPtr xpath_ctx
) {
1956 isds_error err
= IE_SUCCESS
;
1957 xmlXPathObjectPtr result
= NULL
;
1958 xmlNodePtr file_node
= xpath_ctx
->node
;
1959 char *string
= NULL
;
1961 if (!context
) return IE_INVALID_CONTEXT
;
1962 if (!document
) return IE_INVAL
;
1963 isds_document_free(document
);
1964 if (!xpath_ctx
) return IE_INVAL
;
1966 *document
= calloc(1, sizeof(**document
));
1972 /* Extract document metadata */
1973 EXTRACT_STRING_ATTRIBUTE("dmMimeType", (*document
)->dmMimeType
, 1)
1975 EXTRACT_STRING_ATTRIBUTE("dmFileMetaType", string
, 1)
1976 err
= string2isds_FileMetaType((xmlChar
*)string
,
1977 &((*document
)->dmFileMetaType
));
1979 char *meta_type_locale
= utf82locale(string
);
1980 isds_printf_message(context
,
1981 _("Document has invalid dmFileMetaType attribute value: %s"),
1983 free(meta_type_locale
);
1989 EXTRACT_STRING_ATTRIBUTE("dmFileGuid", (*document
)->dmFileGuid
, 0)
1990 EXTRACT_STRING_ATTRIBUTE("dmUpFileGuid", (*document
)->dmUpFileGuid
, 0)
1991 EXTRACT_STRING_ATTRIBUTE("dmFileDescr", (*document
)->dmFileDescr
, 0)
1992 EXTRACT_STRING_ATTRIBUTE("dmFormat", (*document
)->dmFormat
, 0)
1995 /* Extract document data.
1996 * Base64 encoded blob or XML subtree must be presented. */
1998 /* Check from dmEncodedContent */
1999 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmEncodedContent",
2006 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2007 /* Here we have Base64 blob */
2009 if (result
->nodesetval
->nodeNr
> 1) {
2010 isds_printf_message(context
,
2011 _("Document has more dmEncodedContent elements"));
2016 xmlXPathFreeObject(result
); result
= NULL
;
2017 EXTRACT_STRING("isds:dmEncodedContent", string
);
2019 /* Decode non-emptys document */
2020 if (string
&& string
[0] != '\0') {
2021 (*document
)->data_length
= b64decode(string
, &((*document
)->data
));
2022 if ((*document
)->data_length
== (size_t) -1) {
2023 isds_printf_message(context
,
2024 _("Error while Base64-decoding document content"));
2030 /* No Base64 blob, try XML document */
2031 xmlXPathFreeObject(result
); result
= NULL
;
2032 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmXMLContent",
2039 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2040 /* Here we have XML document */
2042 if (result
->nodesetval
->nodeNr
> 1) {
2043 isds_printf_message(context
,
2044 _("Document has more dmXMLContent elements"));
2049 /* FIXME: Serialize the tree rooted at result's node */
2050 isds_printf_message(context
,
2051 _("XML documents not yet supported"));
2055 /* No bas64 blob, nor XML document */
2056 isds_printf_message(context
,
2057 _("Document has no dmEncodedContent, nor dmXMLContent "
2066 if (err
) isds_document_free(document
);
2068 xmlXPathFreeObject(result
);
2069 xpath_ctx
->node
= file_node
;
2075 /* Extract message documents into reallocated list of documents
2076 * @context is ISDS context
2077 * @documents is automically reallocated message documents list structure
2078 * @xpath_ctx is XPath context with current node as XSD tFilesArray
2079 * In case of error @documents will be freed. */
2080 static isds_error
extract_documents(struct isds_ctx
*context
,
2081 struct isds_list
**documents
, xmlXPathContextPtr xpath_ctx
) {
2082 isds_error err
= IE_SUCCESS
;
2083 xmlXPathObjectPtr result
= NULL
;
2085 xmlNodePtr files_node
= xpath_ctx
->node
;
2086 struct isds_list
*document
, *prev_document
;
2088 if (!context
) return IE_INVALID_CONTEXT
;
2089 if (!documents
) return IE_INVAL
;
2090 isds_list_free(documents
);
2091 if (!xpath_ctx
) return IE_INVAL
;
2093 /* Find documents */
2094 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmFile", xpath_ctx
);
2101 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2102 isds_printf_message(context
,
2103 _("Message does not contain any document"));
2109 /* Iterate over documents */
2110 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2111 file
= result
->nodesetval
->nodeTab
[i
];
2113 /* Allocate and append list item */
2114 document
= calloc(1, sizeof(*document
));
2119 document
->destructor
= (void (*)(void **))isds_document_free
;
2120 if (i
== 0) *documents
= document
;
2121 else prev_document
->next
= document
;
2122 prev_document
= document
;
2124 /* Extract document */
2125 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2126 err
= extract_document(context
,
2127 (struct isds_document
**) &(document
->data
), xpath_ctx
);
2128 if (err
) goto leave
;
2133 if (err
) isds_list_free(documents
);
2134 xmlXPathFreeObject(result
);
2135 xpath_ctx
->node
= files_node
;
2140 /* Convert isds:dmRecord XML tree into structure
2141 * @context is ISDS context
2142 * @envelope is automically reallocated message envelope structure
2143 * @xpath_ctx is XPath context with current node as isds:dmRecord element
2144 * In case of error @envelope will be freed. */
2145 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
2146 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2147 isds_error err
= IE_SUCCESS
;
2148 xmlXPathObjectPtr result
= NULL
;
2150 if (!context
) return IE_INVALID_CONTEXT
;
2151 if (!envelope
) return IE_INVAL
;
2152 isds_envelope_free(envelope
);
2153 if (!xpath_ctx
) return IE_INVAL
;
2156 *envelope
= calloc(1, sizeof(**envelope
));
2163 /* Extract tRecord data */
2164 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
2166 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
2167 * dmAcceptanceTime. */
2168 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
2169 if (err
) goto leave
;
2171 /* Extract envelope elements added by sender and ISDS
2172 * (XSD: gMessageEnvelope type) */
2173 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
2174 if (err
) goto leave
;
2175 /* dmOVM can not be obtained from ISDS */
2178 if (err
) isds_envelope_free(envelope
);
2179 xmlXPathFreeObject(result
);
2184 /* Find and convert isds:dmHash XML tree into structure
2185 * @context is ISDS context
2186 * @envelope is automically reallocated message hash structure
2187 * @xpath_ctx is XPath context with current node containing isds:dmHash child
2188 * In case of error @hash will be freed. */
2189 static isds_error
find_and_extract_DmHash(struct isds_ctx
*context
,
2190 struct isds_hash
**hash
, xmlXPathContextPtr xpath_ctx
) {
2191 isds_error err
= IE_SUCCESS
;
2192 xmlNodePtr old_ctx_node
;
2193 xmlXPathObjectPtr result
= NULL
;
2194 char *string
= NULL
;
2196 if (!context
) return IE_INVALID_CONTEXT
;
2197 if (!hash
) return IE_INVAL
;
2198 isds_hash_free(hash
);
2199 if (!xpath_ctx
) return IE_INVAL
;
2202 *hash
= calloc(1, sizeof(**hash
));
2208 old_ctx_node
= xpath_ctx
->node
;
2211 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmHash", xpath_ctx
);
2212 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
2221 /* Get hash algorithm */
2222 EXTRACT_STRING_ATTRIBUTE("algorithm", string
, 1);
2223 err
= string2isds_hash_algorithm((xmlChar
*) string
, &(*hash
)->algorithm
);
2225 if (err
== IE_ENUM
) {
2226 char *string_locale
= utf82locale(string
);
2227 isds_printf_message(context
, _("Unsported hash algorithm: %s"),
2229 free(string_locale
);
2235 /* Get hash value */
2236 EXTRACT_STRING(".", string
);
2238 isds_printf_message(context
, _("tHash element is missing hash value"));
2242 (*hash
)->length
= b64decode(string
, &((*hash
)->value
));
2243 if ((*hash
)->length
== (size_t) -1) {
2244 isds_printf_message(context
,
2245 _("Error while Base64-decoding hash value"));
2251 if (err
) isds_hash_free(hash
);
2253 xmlXPathFreeObject(result
);
2254 xpath_ctx
->node
= old_ctx_node
;
2259 /* Find and append isds:dmQTimestamp XML tree into envelope
2260 * @context is ISDS context
2261 * @envelope is automically allocated evnelope structure
2262 * @xpath_ctx is XPath context with current node containing isds:dmQTimestamp
2264 * In case of error @envelope will be freed. */
2265 static isds_error
find_and_append_DmQTimestamp(struct isds_ctx
*context
,
2266 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2267 isds_error err
= IE_SUCCESS
;
2268 xmlXPathObjectPtr result
= NULL
;
2269 char *string
= NULL
;
2271 if (!context
) return IE_INVALID_CONTEXT
;
2272 if (!envelope
) return IE_INVAL
;
2274 isds_envelope_free(envelope
);
2279 *envelope
= calloc(1, sizeof(**envelope
));
2285 zfree((*envelope
)->timestamp
);
2286 (*envelope
)->timestamp_length
= 0;
2289 /* Get dmQTimestamp */
2290 EXTRACT_STRING("sisds:dmQTimestamp", string
);
2292 isds_printf_message(context
, _("Missing dmQTimestamp element content"));
2296 (*envelope
)->timestamp_length
=
2297 b64decode(string
, &((*envelope
)->timestamp
));
2298 if ((*envelope
)->timestamp_length
== (size_t) -1) {
2299 isds_printf_message(context
,
2300 _("Error while Base64-decoding timestamp value"));
2306 if (err
) isds_envelope_free(envelope
);
2308 xmlXPathFreeObject(result
);
2313 /* Convert XSD tReturnedMessage XML tree into message structure.
2314 * It doea not store XML tree into message->raw.
2315 * @context is ISDS context
2316 * @message is automically reallocated message structure
2317 * @xpath_ctx is XPath context with current node as tReturnedMessage element
2319 * In case of error @message will be freed. */
2320 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
2321 struct isds_message
**message
, xmlXPathContextPtr xpath_ctx
) {
2322 isds_error err
= IE_SUCCESS
;
2323 xmlNodePtr message_node
;
2325 if (!context
) return IE_INVALID_CONTEXT
;
2326 if (!message
) return IE_INVAL
;
2327 isds_message_free(message
);
2328 if (!xpath_ctx
) return IE_INVAL
;
2331 *message
= calloc(1, sizeof(**message
));
2337 /* Save message XPATH context node */
2338 message_node
= xpath_ctx
->node
;
2342 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
2343 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
2344 if (err
) { err
= IE_ERROR
; goto leave
; }
2345 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
2346 if (err
) goto leave
;
2348 /* Extract dmFiles */
2349 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles", xpath_ctx
);
2350 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
2351 if (err
) { err
= IE_ERROR
; goto leave
; }
2352 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
2353 if (err
) goto leave
;
2356 /* Restore context to message */
2357 xpath_ctx
->node
= message_node
;
2359 /* Extract dmHash */
2360 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
2362 if (err
) goto leave
;
2364 /* Extract dmQTimestamp, */
2365 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
2367 if (err
) goto leave
;
2369 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
2370 * dmAcceptanceTime. */
2371 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
2372 if (err
) goto leave
;
2375 if (err
) isds_message_free(message
);
2380 /* Convert isds_document structure into XML tree and append to dmFiles node.
2381 * @context is session context
2382 * @document is ISDS document
2383 * @dm_files is XML element the resulting tree will be appended to as a child.
2384 * @return error code, in case of error context' message is filled. */
2385 static isds_error
insert_document(struct isds_ctx
*context
,
2386 struct isds_document
*document
, xmlNodePtr dm_files
) {
2387 isds_error err
= IE_SUCCESS
;
2388 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
2389 xmlAttrPtr attribute_node
;
2390 xmlChar
*base64data
= NULL
;
2392 if (!context
) return IE_INVALID_CONTEXT
;
2393 if (!document
|| !dm_files
) return IE_INVAL
;
2395 /* Allocate new dmFile */
2396 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
2398 isds_printf_message(context
, _("Could not allocate main dmFile"));
2402 /* Append the new dmFile.
2403 * XXX: Main document must go first */
2404 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
2405 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
2407 file
= xmlAddChild(dm_files
, new_file
);
2410 xmlFreeNode(new_file
); new_file
= NULL
;
2411 isds_printf_message(context
, _("Could not add dmFile child to "
2412 "%s element"), dm_files
->name
);
2417 /* @dmMimeType is required */
2418 if (!document
->dmMimeType
) {
2419 isds_log_message(context
,
2420 _("Document is missing mandatory MIME type definition"));
2424 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
2426 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
2428 isds_printf_message(context
,
2429 _("Document has unkown dmFileMetaType: %ld"),
2430 document
->dmFileMetaType
);
2434 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
2436 if (document
->dmFileGuid
) {
2437 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
2439 if (document
->dmUpFileGuid
) {
2440 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
2443 /* @dmFileDescr is required */
2444 if (!document
->dmFileDescr
) {
2445 isds_log_message(context
,
2446 _("Document is missing mandatory description (title)"));
2450 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
2452 if (document
->dmFormat
) {
2453 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
2457 /* Insert content (data) of the document. */
2458 /* XXX; Only base64 is implemented currently. */
2459 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
2461 isds_printf_message(context
,
2462 _("Not enought memory to encode %zd bytes into Base64"),
2463 document
->data_length
);
2467 INSERT_STRING(file
, "dmEncodedContent", base64data
);
2475 /* Get data about logged in user and his box. */
2476 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
2477 struct isds_DbOwnerInfo
**db_owner_info
) {
2478 isds_error err
= IE_SUCCESS
;
2479 xmlNsPtr isds_ns
= NULL
;
2480 xmlNodePtr request
= NULL
;
2481 xmlDocPtr response
= NULL
;
2482 xmlChar
*code
= NULL
, *message
= NULL
;
2484 xmlXPathContextPtr xpath_ctx
= NULL
;
2485 xmlXPathObjectPtr result
= NULL
;
2486 char *string
= NULL
;
2488 if (!context
) return IE_INVALID_CONTEXT
;
2489 if (!db_owner_info
) return IE_INVAL
;
2491 /* Check if connection is established */
2492 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2495 /* Build GetOwnerInfoFromLogin request */
2496 request
= xmlNewNode(NULL
, BAD_CAST
"GetOwnerInfoFromLogin");
2498 isds_log_message(context
,
2499 _("Could build GetOwnerInfoFromLogin request"));
2502 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2504 isds_log_message(context
, _("Could not create ISDS name space"));
2505 xmlFreeNode(request
);
2508 xmlSetNs(request
, isds_ns
);
2509 node
= xmlNewChild(request
, NULL
, BAD_CAST
"dbDummy", NULL
);
2511 isds_log_message(context
, _("Could nod add dbDummy Child to "
2512 "GetOwnerInfoFromLogin element"));
2513 xmlFreeNode(request
);
2518 isds_log(ILF_ISDS
, ILL_DEBUG
,
2519 _("Sending GetOwnerInfoFromLogin request to ISDS\n"));
2522 err
= isds(context
, SERVICE_DB_SUPPLEMENTARY
, request
, &response
);
2524 /* Destroy request */
2525 xmlFreeNode(request
);
2528 isds_log(ILF_ISDS
, ILL_DEBUG
,
2529 _("Processing ISDS response on GetOwnerInfoFromLogin "
2530 "request failed\n"));
2531 xmlFreeDoc(response
);
2535 /* Check for response status */
2536 err
= isds_response_status(context
, SERVICE_DB_SUPPLEMENTARY
, response
,
2537 &code
, &message
, NULL
);
2539 isds_log(ILF_ISDS
, ILL_DEBUG
,
2540 _("ISDS response on GetOwnerInfoFromLogin request is "
2541 "missing status\n"));
2544 xmlFreeDoc(response
);
2547 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2548 char *code_locale
= utf82locale((char*)code
);
2549 char *message_locale
= utf82locale((char*)message
);
2550 isds_log(ILF_ISDS
, ILL_DEBUG
,
2551 _("Server refused GetOwnerInfoFromLogin request "
2552 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2553 isds_log_message(context
, message_locale
);
2555 free(message_locale
);
2558 xmlFreeDoc(response
);
2563 /* Prepare stucture */
2564 isds_DbOwnerInfo_free(db_owner_info
);
2565 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
2566 if (!*db_owner_info
) {
2570 xpath_ctx
= xmlXPathNewContext(response
);
2575 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
2580 /* Set context node */
2581 result
= xmlXPathEvalExpression(BAD_CAST
2582 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
2587 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2588 isds_log_message(context
, _("Missing dbOwnerInfo element"));
2592 if (result
->nodesetval
->nodeNr
> 1) {
2593 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
2597 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2598 xmlXPathFreeObject(result
); result
= NULL
;
2601 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
2605 isds_DbOwnerInfo_free(db_owner_info
);
2609 xmlXPathFreeObject(result
);
2610 xmlXPathFreeContext(xpath_ctx
);
2614 xmlFreeDoc(response
);
2617 isds_log(ILF_ISDS
, ILL_DEBUG
,
2618 _("GetOwnerInfoFromLogin request processed by server "
2619 "successfully.\n"));
2625 /* Find boxes suiting given criteria.
2626 * @criteria is filter. You should fill in at least some memebers.
2627 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
2628 * possibly empty. Input NULL or valid old structure.
2630 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
2631 * IE_NOEXIST if no such box exists, @boxes will be NULL
2632 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
2633 * contains still valid data
2634 * other code if something bad happens. @boxes will be NULL. */
2635 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
2636 const struct isds_DbOwnerInfo
*criteria
,
2637 struct isds_list
**boxes
) {
2638 isds_error err
= IE_SUCCESS
;
2639 _Bool truncated
= 0;
2640 xmlNsPtr isds_ns
= NULL
;
2641 xmlNodePtr request
= NULL
;
2642 xmlDocPtr response
= NULL
;
2643 xmlChar
*code
= NULL
, *message
= NULL
;
2644 xmlNodePtr db_owner_info
, node
;
2645 xmlXPathContextPtr xpath_ctx
= NULL
;
2646 xmlXPathObjectPtr result
= NULL
;
2647 xmlChar
*string
= NULL
;
2650 if (!context
) return IE_INVALID_CONTEXT
;
2651 if (!boxes
) return IE_INVAL
;
2652 isds_list_free(boxes
);
2658 /* Check if connection is established
2659 * TODO: This check should be done donwstairs. */
2660 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2663 /* Build FindDataBox request */
2664 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
2666 isds_log_message(context
,
2667 _("Could build FindDataBox request"));
2670 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2672 isds_log_message(context
, _("Could not create ISDS name space"));
2673 xmlFreeNode(request
);
2676 xmlSetNs(request
, isds_ns
);
2677 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
2678 if (!db_owner_info
) {
2679 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
2680 "FindDataBox element"));
2681 xmlFreeNode(request
);
2686 INSERT_STRING(db_owner_info
, "dbID", criteria
->dbID
);
2689 if (criteria
->dbType
) {
2690 const xmlChar
*type_string
= isds_DbType2string(*(criteria
->dbType
));
2692 isds_printf_message(context
, _("Invalid dbType value: %d"),
2693 *(criteria
->dbType
));
2697 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2700 INSERT_STRING(db_owner_info
, "firmName", criteria
->firmName
);
2701 INSERT_STRING(db_owner_info
, "ic", criteria
->ic
);
2702 if (criteria
->personName
) {
2703 INSERT_STRING(db_owner_info
, "pnFirstName",
2704 criteria
->personName
->pnFirstName
);
2705 INSERT_STRING(db_owner_info
, "pnMiddleName",
2706 criteria
->personName
->pnMiddleName
);
2707 INSERT_STRING(db_owner_info
, "pnLastName",
2708 criteria
->personName
->pnLastName
);
2709 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2710 criteria
->personName
->pnLastNameAtBirth
);
2712 if (criteria
->birthInfo
) {
2713 if (criteria
->birthInfo
->biDate
) {
2714 if (!tm2datestring(criteria
->birthInfo
->biDate
, &string
))
2715 INSERT_STRING(db_owner_info
, "biDate", string
);
2716 free(string
); string
= NULL
;
2718 INSERT_STRING(db_owner_info
, "biCity", criteria
->birthInfo
->biCity
);
2719 INSERT_STRING(db_owner_info
, "biCounty", criteria
->birthInfo
->biCounty
);
2720 INSERT_STRING(db_owner_info
, "biState", criteria
->birthInfo
->biState
);
2722 if (criteria
->address
) {
2723 INSERT_STRING(db_owner_info
, "adCity", criteria
->address
->adCity
);
2724 INSERT_STRING(db_owner_info
, "adStreet", criteria
->address
->adStreet
);
2725 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2726 criteria
->address
->adNumberInStreet
);
2727 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2728 criteria
->address
->adNumberInMunicipality
);
2729 INSERT_STRING(db_owner_info
, "adZipCode", criteria
->address
->adZipCode
);
2730 INSERT_STRING(db_owner_info
, "adState", criteria
->address
->adState
);
2732 INSERT_STRING(db_owner_info
, "nationality", criteria
->nationality
);
2733 INSERT_STRING(db_owner_info
, "email", criteria
->email
);
2734 INSERT_STRING(db_owner_info
, "telNumber", criteria
->telNumber
);
2735 INSERT_STRING(db_owner_info
, "identifier", criteria
->identifier
);
2736 INSERT_STRING(db_owner_info
, "registryCode", criteria
->registryCode
);
2738 INSERT_LONGINT(db_owner_info
, "dbState", criteria
->dbState
, string
);
2740 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", criteria
->dbEffectiveOVM
);
2741 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2742 criteria
->dbOpenAddressing
);
2745 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
2748 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2750 /* Destroy request */
2751 xmlFreeNode(request
); request
= NULL
;
2754 isds_log(ILF_ISDS
, ILL_DEBUG
,
2755 _("Processing ISDS response on FindDataBox "
2756 "request failed\n"));
2760 /* Check for response status */
2761 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2762 &code
, &message
, NULL
);
2764 isds_log(ILF_ISDS
, ILL_DEBUG
,
2765 _("ISDS response on FindDataBox request is missing status\n"));
2769 /* Request processed, but nothing found */
2770 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
2771 !xmlStrcmp(code
, BAD_CAST
"5001")) {
2772 char *code_locale
= utf82locale((char*)code
);
2773 char *message_locale
= utf82locale((char*)message
);
2774 isds_log(ILF_ISDS
, ILL_DEBUG
,
2775 _("Server did not found any box on FindDataBox request "
2776 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2777 isds_log_message(context
, message_locale
);
2779 free(message_locale
);
2784 /* Warning, not a error */
2785 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
2786 char *code_locale
= utf82locale((char*)code
);
2787 char *message_locale
= utf82locale((char*)message
);
2788 isds_log(ILF_ISDS
, ILL_DEBUG
,
2789 _("Server truncated response on FindDataBox request "
2790 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2791 isds_log_message(context
, message_locale
);
2793 free(message_locale
);
2798 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2799 char *code_locale
= utf82locale((char*)code
);
2800 char *message_locale
= utf82locale((char*)message
);
2801 isds_log(ILF_ISDS
, ILL_DEBUG
,
2802 _("Server refused FindDataBox request "
2803 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2804 isds_log_message(context
, message_locale
);
2806 free(message_locale
);
2811 xpath_ctx
= xmlXPathNewContext(response
);
2816 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
2821 /* Extract boxes if they present */
2822 result
= xmlXPathEvalExpression(BAD_CAST
2823 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
2829 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2830 struct isds_list
*item
, *prev_item
= NULL
;
2831 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2832 item
= calloc(1, sizeof(*item
));
2838 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
2839 if (i
== 0) *boxes
= item
;
2840 else prev_item
->next
= item
;
2843 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2844 err
= extract_DbOwnerInfo(context
,
2845 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
2846 if (err
) goto leave
;
2852 isds_list_free(boxes
);
2854 if (truncated
) err
= IE_2BIG
;
2858 xmlFreeNode(request
);
2859 xmlXPathFreeObject(result
);
2860 xmlXPathFreeContext(xpath_ctx
);
2864 xmlFreeDoc(response
);
2867 isds_log(ILF_ISDS
, ILL_DEBUG
,
2868 _("FindDataBox request processed by server successfully.\n"));
2874 /* Get status of a box.
2875 * @context is ISDS session context.
2876 * @box_id is UTF-8 encoded box identifier as zero terminated string
2877 * @box_status is return value of box status.
2879 * IE_SUCCESS if box has been found and its status retrieved
2880 * IE_NOEXIST if box is not known to ISDS server
2881 * or other appropriate error.
2882 * You can use isds_DbState to enumerate box status. However out of enum
2883 * range value can be returned too. This is feature because ISDS
2884 * specification leaves the set of values open.
2885 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
2886 * the box has been deleted, but ISDS still lists its former existence. */
2887 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
2888 long int *box_status
) {
2889 isds_error err
= IE_SUCCESS
;
2890 xmlNsPtr isds_ns
= NULL
;
2891 xmlNodePtr request
= NULL
, db_id
;
2892 xmlDocPtr response
= NULL
;
2893 xmlChar
*code
= NULL
, *message
= NULL
;
2894 xmlXPathContextPtr xpath_ctx
= NULL
;
2895 xmlXPathObjectPtr result
= NULL
;
2896 xmlChar
*string
= NULL
;
2898 if (!context
) return IE_INVALID_CONTEXT
;
2899 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
2901 /* Check if connection is established
2902 * TODO: This check should be done donwstairs. */
2903 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2906 /* Build CheckDataBox request */
2907 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
2909 isds_log_message(context
,
2910 _("Could build CheckDataBox request"));
2913 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2915 isds_log_message(context
, _("Could not create ISDS name space"));
2916 xmlFreeNode(request
);
2919 xmlSetNs(request
, isds_ns
);
2920 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
2922 isds_log_message(context
, _("Could not add dbId Child to "
2923 "CheckDataBox element"));
2924 xmlFreeNode(request
);
2929 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
2932 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2934 /* Destroy request */
2935 xmlFreeNode(request
);
2938 isds_log(ILF_ISDS
, ILL_DEBUG
,
2939 _("Processing ISDS response on CheckDataBox "
2940 "request failed\n"));
2944 /* Check for response status */
2945 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2946 &code
, &message
, NULL
);
2948 isds_log(ILF_ISDS
, ILL_DEBUG
,
2949 _("ISDS response on CheckDataBox request is missing status\n"));
2953 /* Request processed, but nothing found */
2954 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
2955 char *box_id_locale
= utf82locale((char*)box_id
);
2956 char *code_locale
= utf82locale((char*)code
);
2957 char *message_locale
= utf82locale((char*)message
);
2958 isds_log(ILF_ISDS
, ILL_DEBUG
,
2959 _("Server did not found box %s on CheckDataBox request "
2960 "(code=%s, message=%s)\n"),
2961 box_id_locale
, code_locale
, message_locale
);
2962 isds_log_message(context
, message_locale
);
2963 free(box_id_locale
);
2965 free(message_locale
);
2971 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2972 char *code_locale
= utf82locale((char*)code
);
2973 char *message_locale
= utf82locale((char*)message
);
2974 isds_log(ILF_ISDS
, ILL_DEBUG
,
2975 _("Server refused CheckDataBox request "
2976 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2977 isds_log_message(context
, message_locale
);
2979 free(message_locale
);
2985 xpath_ctx
= xmlXPathNewContext(response
);
2990 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
2994 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
3000 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3001 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
3005 if (result
->nodesetval
->nodeNr
> 1) {
3006 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
3010 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3011 xmlXPathFreeObject(result
); result
= NULL
;
3013 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
3018 xmlXPathFreeObject(result
);
3019 xmlXPathFreeContext(xpath_ctx
);
3023 xmlFreeDoc(response
);
3026 isds_log(ILF_ISDS
, ILL_DEBUG
,
3027 _("CheckDataBox request processed by server successfully.\n"));
3033 /* Send a message via ISDS to a recipent
3034 * @context is session context
3035 * @outgoing_message is message to send; Some memebers are mandatory (like
3036 * dbIDRecipient), some are optional and some are irrelevant (especialy data
3037 * about sender). Included pointer to isds_list documents must contain at
3038 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
3039 * members will be filled with valid data from ISDS. Exact list of write
3040 * members is subject to change. Currently dmId is changed.
3041 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
3042 isds_error
isds_send_message(struct isds_ctx
*context
,
3043 struct isds_message
*outgoing_message
) {
3045 isds_error err
= IE_SUCCESS
;
3046 xmlNsPtr isds_ns
= NULL
;
3047 xmlNodePtr request
= NULL
, envelope
, dm_files
, node
;
3048 xmlDocPtr response
= NULL
;
3049 xmlChar
*code
= NULL
, *message
= NULL
;
3050 xmlXPathContextPtr xpath_ctx
= NULL
;
3051 xmlXPathObjectPtr result
= NULL
;
3052 xmlChar
*string
= NULL
;
3053 _Bool message_is_complete
= 0;
3055 if (!context
) return IE_INVALID_CONTEXT
;
3056 if (!outgoing_message
) return IE_INVAL
;
3058 /* Check if connection is established
3059 * TODO: This check should be done donwstairs. */
3060 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3063 /* Build CreateMessage request */
3064 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
3066 isds_log_message(context
,
3067 _("Could build CreateMessage request"));
3070 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3072 isds_log_message(context
, _("Could not create ISDS name space"));
3073 xmlFreeNode(request
);
3076 xmlSetNs(request
, isds_ns
);
3079 /* Build envelope */
3080 envelope
= xmlNewChild(request
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
3082 isds_log_message(context
, _("Could not add dmEnvelope child to "
3083 "CreateMessage element"));
3084 xmlFreeNode(request
);
3088 if (!outgoing_message
->envelope
) {
3089 isds_log_message(context
, _("outgoing message is missing envelope"));
3094 INSERT_STRING(envelope
, "dmSenderOrgUnit",
3095 outgoing_message
->envelope
->dmSenderOrgUnit
);
3096 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
3097 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
3099 if (!outgoing_message
->envelope
->dbIDRecipient
) {
3100 isds_log_message(context
,
3101 _("outgoing message is missing recipient box identifier"));
3105 INSERT_STRING(envelope
, "dbIDRecipient",
3106 outgoing_message
->envelope
->dbIDRecipient
);
3108 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
3109 outgoing_message
->envelope
->dmRecipientOrgUnit
);
3110 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
3111 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
3112 INSERT_STRING(envelope
, "dmToHands", outgoing_message
->envelope
->dmToHands
);
3114 #define CHECK_FOR_STRING_LENGTH(string, limit, name) \
3115 if ((string) && xmlUTF8Strlen((xmlChar *) (string)) > (limit)) { \
3116 isds_printf_message(context, \
3117 _("%s has more than %d characters"), (name), (limit)); \
3122 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 255,
3124 INSERT_STRING(envelope
, "dmAnnotation",
3125 outgoing_message
->envelope
->dmAnnotation
);
3127 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
3128 50, "dmRecipientRefNumber");
3129 INSERT_STRING(envelope
, "dmRecipientRefNumber",
3130 outgoing_message
->envelope
->dmRecipientRefNumber
);
3132 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
3133 50, "dmSenderRefNumber");
3134 INSERT_STRING(envelope
, "dmSenderRefNumber",
3135 outgoing_message
->envelope
->dmSenderRefNumber
);
3137 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
3138 50, "dmRecipientIdent");
3139 INSERT_STRING(envelope
, "dmRecipientIdent",
3140 outgoing_message
->envelope
->dmRecipientIdent
);
3142 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
3143 50, "dmSenderIdent");
3144 INSERT_STRING(envelope
, "dmSenderIdent",
3145 outgoing_message
->envelope
->dmSenderIdent
);
3147 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
3148 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
3149 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
3150 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
3151 INSERT_STRING(envelope
, "dmLegalTitleSect",
3152 outgoing_message
->envelope
->dmLegalTitleSect
);
3153 INSERT_STRING(envelope
, "dmLegalTitlePar",
3154 outgoing_message
->envelope
->dmLegalTitlePar
);
3155 INSERT_STRING(envelope
, "dmLegalTitlePoint",
3156 outgoing_message
->envelope
->dmLegalTitlePoint
);
3158 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
3159 outgoing_message
->envelope
->dmPersonalDelivery
);
3160 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
3161 outgoing_message
->envelope
->dmAllowSubstDelivery
);
3163 #undef CHECK_FOR_STRING_LENGTH
3165 /* ???: Should we require value for dbEffectiveOVM sender?
3166 * ISDS has default as true */
3167 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
3170 /* Append dmFiles */
3171 if (!outgoing_message
->documents
) {
3172 isds_log_message(context
,
3173 _("outgoing message is missing list of documents"));
3177 dm_files
= xmlNewChild(request
, NULL
, BAD_CAST
"dmFiles", NULL
);
3179 isds_log_message(context
, _("Could not add dmFiles child to "
3180 "CreateMessage element"));
3185 /* Check for document hieararchy */
3186 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
3187 if (err
) goto leave
;
3189 /* Process each document */
3190 for (struct isds_list
*item
=
3191 (struct isds_list
*) outgoing_message
->documents
;
3192 item
; item
= item
->next
) {
3194 isds_log_message(context
,
3195 _("list of documents contains empty item"));
3199 /* FIXME: Check for dmFileMetaType and for document references.
3200 * Only first document can be of MAIN type */
3201 err
= insert_document(context
, (struct isds_document
*) item
->data
,
3204 if (err
) goto leave
;
3207 /* Signal we can serilize message since now */
3208 message_is_complete
= 1;
3212 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
3215 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
3217 /* Dont' destroy request, we want to privode it to application later */
3220 isds_log(ILF_ISDS
, ILL_DEBUG
,
3221 _("Processing ISDS response on CreateMessage "
3222 "request failed\n"));
3226 /* Check for response status */
3227 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
3228 &code
, &message
, NULL
);
3230 isds_log(ILF_ISDS
, ILL_DEBUG
,
3231 _("ISDS response on CreateMessage request "
3232 "is missing status\n"));
3236 /* Request processed, but nothing found */
3237 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3238 char *box_id_locale
=
3239 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
3240 char *code_locale
= utf82locale((char*)code
);
3241 char *message_locale
= utf82locale((char*)message
);
3242 isds_log(ILF_ISDS
, ILL_DEBUG
,
3243 _("Server did not accept message for %s on CreateMessage "
3244 "request (code=%s, message=%s)\n"),
3245 box_id_locale
, code_locale
, message_locale
);
3246 isds_log_message(context
, message_locale
);
3247 free(box_id_locale
);
3249 free(message_locale
);
3256 xpath_ctx
= xmlXPathNewContext(response
);
3261 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3265 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
3271 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3272 isds_log_message(context
, _("Missing CreateMessageResponse element"));
3276 if (result
->nodesetval
->nodeNr
> 1) {
3277 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
3281 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3282 xmlXPathFreeObject(result
); result
= NULL
;
3284 if (outgoing_message
->envelope
->dmID
) {
3285 free(outgoing_message
->envelope
->dmID
);
3286 outgoing_message
->envelope
->dmID
= NULL
;
3288 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
3289 if (!outgoing_message
->envelope
->dmID
) {
3290 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3291 "but did not returen assigned message ID\n"));
3295 /* TODO: Serialize message into structure member raw */
3296 /* XXX: Each web service transport message in different format.
3297 * Therefore it's not possible to save them directly.
3298 * To save them, one must figure out common format.
3299 * We can leave it on application, or we can implement the ESS format. */
3300 /*if (message_is_complete) {
3301 if (outgoing_message->envelope->dmID) {
3303 /* Add assigned message ID as first child*/
3304 /*xmlNodePtr dmid_text = xmlNewText(
3305 (xmlChar *) outgoing_message->envelope->dmID);
3306 if (!dmid_text) goto serialization_failed;
3308 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
3310 if (!dmid_element) {
3311 xmlFreeNode(dmid_text);
3312 goto serialization_failed;
3315 xmlNodePtr dmid_element_with_text =
3316 xmlAddChild(dmid_element, dmid_text);
3317 if (!dmid_element_with_text) {
3318 xmlFreeNode(dmid_element);
3319 xmlFreeNode(dmid_text);
3320 goto serialization_failed;
3323 node = xmlAddPrevSibling(envelope->childern,
3324 dmid_element_with_text);
3326 xmlFreeNodeList(dmid_element_with_text);
3327 goto serialization_failed;
3331 /* Serialize message with ID into raw */
3332 /*buffer = serialize_element(envelope)*/
3335 serialization_failed:
3342 xmlXPathFreeObject(result
);
3343 xmlXPathFreeContext(xpath_ctx
);
3347 xmlFreeDoc(response
);
3348 xmlFreeNode(request
);
3351 isds_log(ILF_ISDS
, ILL_DEBUG
,
3352 _("CreateMessage request processed by server "
3353 "successfully.\n"));
3359 /* Get list of messages. This is common core for getting sent or received
3361 * Any criterion argument can be NULL, if you don't care about it.
3362 * @context is session context. Must not be NULL.
3363 * @outgoing_direction is true if you want list of outgoing messages,
3364 * it's false if you want incoming messages.
3365 * @from_time is minimal time and date of message sending inclusive.
3366 * @to_time is maximal time and date of message sending inclusive
3367 * @organization_unit_number is number of sender/recipient respectively.
3368 * @status_filter is bit field of isds_message_status values. Use special
3369 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3370 * all values, you can use bitwise arithmetic if you want.)
3371 * @offset is index of first message we are interested in. First message is 1.
3372 * Set to 0 (or 1) if you don't care.
3373 * @number is maximal length of list you want to get as input value, outputs
3374 * number of messages matching these criteria. Can be NULL if you don't care
3375 * (applies to output value either).
3376 * @messages is automatically reallocated list of isds_message's. Be ware that
3377 * it returns only brief overview (envelope and some other fields) about each
3378 * message, not the complete message. FIXME: Specify exact fields.
3379 * The list is sorted by delivery time in ascending order.
3381 * you don't care about don't need the data (useful if you want to know only
3382 * the @number). If you provide &NULL, list will be allocated on heap, if you
3383 * provide pointer to non-NULL, list will be freed automacally at first. Also
3384 * in case of error the list will be NULLed.
3385 * @return IE_SUCCESS or appropriate error code. */
3386 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
3387 _Bool outgoing_direction
,
3388 const struct timeval
*from_time
, const struct timeval
*to_time
,
3389 const long int *organization_unit_number
,
3390 const unsigned int status_filter
,
3391 const unsigned long int offset
, unsigned long int *number
,
3392 struct isds_list
**messages
) {
3394 isds_error err
= IE_SUCCESS
;
3395 xmlNsPtr isds_ns
= NULL
;
3396 xmlNodePtr request
= NULL
, node
;
3397 xmlDocPtr response
= NULL
;
3398 xmlChar
*code
= NULL
, *message
= NULL
;
3399 xmlXPathContextPtr xpath_ctx
= NULL
;
3400 xmlXPathObjectPtr result
= NULL
;
3401 xmlChar
*string
= NULL
;
3402 long unsigned int count
= 0;
3404 if (!context
) return IE_INVALID_CONTEXT
;
3406 /* Free former message list if any */
3407 if (messages
) isds_list_free(messages
);
3409 /* Check if connection is established
3410 * TODO: This check should be done donwstairs. */
3411 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3413 /* Build GetListOf*Messages request */
3414 request
= xmlNewNode(NULL
,
3415 (outgoing_direction
) ?
3416 BAD_CAST
"GetListOfSentMessages" :
3417 BAD_CAST
"GetListOfReceivedMessages"
3420 isds_log_message(context
,
3421 (outgoing_direction
) ?
3422 _("Could not build GetListOfSentMessages request") :
3423 _("Could not build GetListOfReceivedMessages request")
3427 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3429 isds_log_message(context
, _("Could not create ISDS name space"));
3430 xmlFreeNode(request
);
3433 xmlSetNs(request
, isds_ns
);
3437 err
= timeval2timestring(from_time
, &string
);
3438 if (err
) goto leave
;
3440 INSERT_STRING(request
, "dmFromTime", string
);
3441 free(string
); string
= NULL
;
3444 err
= timeval2timestring(to_time
, &string
);
3445 if (err
) goto leave
;
3447 INSERT_STRING(request
, "dmToTime", string
);
3448 free(string
); string
= NULL
;
3450 if (outgoing_direction
) {
3451 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
3452 organization_unit_number
, string
);
3454 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
3455 organization_unit_number
, string
);
3458 if (status_filter
> MESSAGESTATE_ANY
) {
3459 isds_printf_message(context
,
3460 _("Invalid message state filter value: %ld"), status_filter
);
3464 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
3467 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
3469 INSERT_STRING(request
, "dmOffset", "1");
3472 /* number 0 means no limit */
3473 if (number
&& *number
== 0) {
3474 INSERT_STRING(request
, "dmLimit", NULL
);
3476 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
3480 isds_log(ILF_ISDS
, ILL_DEBUG
,
3481 (outgoing_direction
) ?
3482 _("Sending GetListOfSentMessages request to ISDS\n") :
3483 _("Sending GetListOfReceivedMessages request to ISDS\n")
3487 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
);
3488 xmlFreeNode(request
); request
= NULL
;
3491 isds_log(ILF_ISDS
, ILL_DEBUG
,
3492 (outgoing_direction
) ?
3493 _("Processing ISDS response on GetListOfSentMessages "
3494 "request failed\n") :
3495 _("Processing ISDS response on GetListOfReceivedMessages "
3501 /* Check for response status */
3502 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
3503 &code
, &message
, NULL
);
3505 isds_log(ILF_ISDS
, ILL_DEBUG
,
3506 (outgoing_direction
) ?
3507 _("ISDS response on GetListOfSentMessages request "
3508 "is missing status\n") :
3509 _("ISDS response on GetListOfReceivedMessages request "
3510 "is missing status\n")
3515 /* Request processed, but nothing found */
3516 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3517 char *code_locale
= utf82locale((char*)code
);
3518 char *message_locale
= utf82locale((char*)message
);
3519 isds_log(ILF_ISDS
, ILL_DEBUG
,
3520 (outgoing_direction
) ?
3521 _("Server refused GetListOfSentMessages request "
3522 "(code=%s, message=%s)\n") :
3523 _("Server refused GetListOfReceivedMessages request "
3524 "(code=%s, message=%s)\n"),
3525 code_locale
, message_locale
);
3526 isds_log_message(context
, message_locale
);
3528 free(message_locale
);
3535 xpath_ctx
= xmlXPathNewContext(response
);
3540 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3544 result
= xmlXPathEvalExpression(
3545 (outgoing_direction
) ?
3546 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
3547 "isds:dmRecords/isds:dmRecord" :
3548 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
3549 "isds:dmRecords/isds:dmRecord",
3556 /* Fill output arguments in */
3557 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3558 struct isds_envelope
*envelope
;
3559 struct isds_list
*item
= NULL
, *last_item
= NULL
;
3561 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
3562 /* Create new message */
3563 item
= calloc(1, sizeof(*item
));
3568 item
->destructor
= (void(*)(void**)) &isds_message_free
;
3569 item
->data
= calloc(1, sizeof(struct isds_message
));
3571 isds_list_free(&item
);
3576 /* Extract envelope data */
3577 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
3579 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
3581 isds_list_free(&item
);
3585 /* Attach extracted envelope */
3586 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
3588 /* Append new message into the list */
3590 *messages
= last_item
= item
;
3592 last_item
->next
= item
;
3597 if (number
) *number
= count
;
3601 isds_list_free(messages
);
3605 xmlXPathFreeObject(result
);
3606 xmlXPathFreeContext(xpath_ctx
);
3610 xmlFreeDoc(response
);
3611 xmlFreeNode(request
);
3614 isds_log(ILF_ISDS
, ILL_DEBUG
,
3615 (outgoing_direction
) ?
3616 _("GetListOfSentMessages request processed by server "
3617 "successfully.\n") :
3618 _("GetListOfReceivedMessages request processed by server "
3625 /* Get list of outgoing (already sent) messages.
3626 * Any criterion argument can be NULL, if you don't care about it.
3627 * @context is session context. Must not be NULL.
3628 * @from_time is minimal time and date of message sending inclusive.
3629 * @to_time is maximal time and date of message sending inclusive
3630 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
3631 * @status_filter is bit field of isds_message_status values. Use special
3632 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3633 * all values, you can use bitwise arithmetic if you want.)
3634 * @offset is index of first message we are interested in. First message is 1.
3635 * Set to 0 (or 1) if you don't care.
3636 * @number is maximal length of list you want to get as input value, outputs
3637 * number of messages matching these criteria. Can be NULL if you don't care
3638 * (applies to output value either).
3639 * @messages is automatically reallocated list of isds_message's. Be ware that
3640 * it returns only brief overview (envelope and some other fields) about each
3641 * message, not the complete message. FIXME: Specify exact fields.
3642 * The list is sorted by delivery time in ascending order.
3643 * Use NULL if you don't care about the metadata (useful if you want to know
3644 * only the @number). If you provide &NULL, list will be allocated on heap,
3645 * if you provide pointer to non-NULL, list will be freed automacally at first.
3646 * Also in case of error the list will be NULLed.
3647 * @return IE_SUCCESS or appropriate error code. */
3648 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
3649 const struct timeval
*from_time
, const struct timeval
*to_time
,
3650 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
3651 const unsigned long int offset
, unsigned long int *number
,
3652 struct isds_list
**messages
) {
3654 return isds_get_list_of_messages(
3656 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
3662 /* Get list of incoming (addressed to you) messages.
3663 * Any criterion argument can be NULL, if you don't care about it.
3664 * @context is session context. Must not be NULL.
3665 * @from_time is minimal time and date of message sending inclusive.
3666 * @to_time is maximal time and date of message sending inclusive
3667 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
3668 * @status_filter is bit field of isds_message_status values. Use special
3669 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3670 * all values, you can use bitwise arithmetic if you want.)
3671 * @offset is index of first message we are interested in. First message is 1.
3672 * Set to 0 (or 1) if you don't care.
3673 * @number is maximal length of list you want to get as input value, outputs
3674 * number of messages matching these criteria. Can be NULL if you don't care
3675 * (applies to output value either).
3676 * @messages is automatically reallocated list of isds_message's. Be ware that
3677 * it returns only brief overview (envelope and some other fields) about each
3678 * message, not the complete message. FIXME: Specify exact fields.
3679 * Use NULL if you don't care about the metadata (useful if you want to know
3680 * only the @number). If you provide &NULL, list will be allocated on heap,
3681 * if you provide pointer to non-NULL, list will be freed automacally at first.
3682 * Also in case of error the list will be NULLed.
3683 * @return IE_SUCCESS or appropriate error code. */
3684 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
3685 const struct timeval
*from_time
, const struct timeval
*to_time
,
3686 const long int *dmRecipientOrgUnitNum
,
3687 const unsigned int status_filter
,
3688 const unsigned long int offset
, unsigned long int *number
,
3689 struct isds_list
**messages
) {
3691 return isds_get_list_of_messages(
3693 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
3699 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
3701 * @context is session context
3702 * @service is ISDS WS service handler
3703 * @service_name is name of SERVICE_DM_OPERATIONS
3704 * @message_id is message ID to send as service argument to ISDS
3705 * @response is server SOAP body response as XML document
3706 * @code is ISDS status code
3707 * @status_message is ISDS status message
3708 * @return error coded from lower layer, context message will be set up
3710 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
3711 const isds_service service
, const xmlChar
*service_name
,
3712 const char *message_id
,
3713 xmlDocPtr
*response
, xmlChar
**code
, xmlChar
**status_message
) {
3714 /* ???: XSD allows list of @message_id's and list of @message's, but
3715 * documentation talks only about `a message' */
3717 isds_error err
= IE_SUCCESS
;
3718 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
3719 xmlNodePtr request
= NULL
, node
;
3720 xmlNsPtr isds_ns
= NULL
;
3722 if (!context
) return IE_INVALID_CONTEXT
;
3723 if (!service_name
|| !message_id
) return IE_INVAL
;
3724 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3726 /* Free output argument */
3727 xmlFreeDoc(*response
);
3729 free(*status_message
);
3732 /* Check if connection is established
3733 * TODO: This check should be done donwstairs. */
3734 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3736 service_name_locale
= utf82locale((char*)service_name
);
3737 message_id_locale
= utf82locale(message_id
);
3738 if (!service_name_locale
|| !message_id_locale
) {
3744 request
= xmlNewNode(NULL
, service_name
);
3746 isds_printf_message(context
,
3747 _("Could not build %s request"), service_name_locale
);
3751 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3753 isds_log_message(context
, _("Could not create ISDS name space"));
3757 xmlSetNs(request
, isds_ns
);
3760 /* Add requested ID */
3761 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
3762 if (err
) goto leave
;
3763 INSERT_STRING(request
, "dmID", message_id
);
3766 isds_log(ILF_ISDS
, ILL_DEBUG
,
3767 _("Sending %s request for %s message ID to ISDS\n"),
3768 service_name_locale
, message_id_locale
);
3771 err
= isds(context
, service
, request
, response
);
3772 xmlFreeNode(request
); request
= NULL
;
3775 isds_log(ILF_ISDS
, ILL_DEBUG
,
3776 _("Processing ISDS response on %s request failed\n"),
3777 service_name_locale
);
3781 /* Check for response status */
3782 err
= isds_response_status(context
, service
, *response
,
3783 code
, status_message
, NULL
);
3785 isds_log(ILF_ISDS
, ILL_DEBUG
,
3786 _("ISDS response on %s request is missing status\n"),
3787 service_name_locale
);
3791 /* Request processed, but nothing found */
3792 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3793 char *code_locale
= utf82locale((char*) *code
);
3794 char *status_message_locale
= utf82locale((char*) *status_message
);
3795 isds_log(ILF_ISDS
, ILL_DEBUG
,
3796 _("Server refused %s request for %s message ID "
3797 "(code=%s, message=%s)\n"),
3798 service_name_locale
, message_id_locale
,
3799 code_locale
, status_message_locale
);
3800 isds_log_message(context
, status_message_locale
);
3802 free(status_message_locale
);
3808 free(message_id_locale
);
3809 free(service_name_locale
);
3810 xmlFreeNode(request
);
3816 /* Dwwnload incomping message identified by ID.
3817 * @context is session context
3818 * @message_id is message identifier (you can get them from
3819 * isds_get_list_of_received_messages())
3820 * @message is automatically reallocated message retrieved from ISDS */
3821 isds_error
isds_get_received_message(struct isds_ctx
*context
,
3822 const char *message_id
, struct isds_message
**message
) {
3823 /* ???: XSD allows list of @message_id's and list of @message's, but
3824 * documentation talks only about `a message' */
3826 isds_error err
= IE_SUCCESS
;
3827 xmlDocPtr response
= NULL
;
3828 xmlChar
*code
= NULL
, *status_message
= NULL
;
3829 xmlXPathContextPtr xpath_ctx
= NULL
;
3830 xmlXPathObjectPtr result
= NULL
;
3832 if (!context
) return IE_INVALID_CONTEXT
;
3834 /* Free former message if any */
3835 if (message
) isds_message_free(message
);
3837 /* Do request and check for success */
3838 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
3839 BAD_CAST
"MessageDownload", message_id
,
3840 &response
, &code
, &status_message
);
3841 if (err
) goto leave
;
3844 xpath_ctx
= xmlXPathNewContext(response
);
3849 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3853 result
= xmlXPathEvalExpression(
3854 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
3860 /* Empty response */
3861 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3862 char *message_id_locale
= utf82locale((char*) message_id
);
3863 isds_printf_message(context
,
3864 _("Server did not return any message for ID `%s' "
3865 "on MessageDownload request"), message_id_locale
);
3866 free(message_id_locale
);
3871 if (result
->nodesetval
->nodeNr
> 1) {
3872 char *message_id_locale
= utf82locale((char*) message_id
);
3873 isds_printf_message(context
,
3874 _("Server did return more messages for ID `%s' "
3875 "on MessageDownload request"), message_id_locale
);
3876 free(message_id_locale
);
3881 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3883 /* Extract the message */
3884 err
= extract_TReturnedMessage(context
, message
, xpath_ctx
);
3885 if (err
) goto leave
;
3888 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
3889 &(*message
)->raw_length
);
3893 isds_message_free(message
);
3896 xmlXPathFreeObject(result
);
3897 xmlXPathFreeContext(xpath_ctx
);
3900 free(status_message
);
3901 xmlFreeDoc(response
);
3904 isds_log(ILF_ISDS
, ILL_DEBUG
,
3905 _("MessageDownload request processed by server "
3912 /* Download signed incoming/outgoing message identified by ID.
3913 * @context is session context
3914 * @output is true for outging message, false for incoming message
3915 * @message_id is message identifier (you can get them from
3916 * isds_get_list_of_{sent,received}_messages())
3917 * @message is automatically reallocated message retrieved from ISDS. The raw
3918 * memeber will be filled with PKCS#7 structure in DER format. */
3919 _hidden isds_error
isds_get_signed_message(struct isds_ctx
*context
,
3920 const _Bool outgoing
, const char *message_id
,
3921 struct isds_message
**message
) {
3923 isds_error err
= IE_SUCCESS
;
3924 xmlDocPtr response
= NULL
, message_doc
= NULL
;
3925 xmlChar
*code
= NULL
, *status_message
= NULL
;
3926 xmlXPathContextPtr xpath_ctx
= NULL
;
3927 xmlXPathObjectPtr result
= NULL
;
3928 char *encoded_structure
= NULL
;
3929 void *raw
= NULL
, *xml_stream
= NULL
;
3930 size_t raw_length
= 0, xml_stream_length
= 0;
3932 if (!context
) return IE_INVALID_CONTEXT
;
3934 /* Free former message if any */
3935 if (message
) isds_message_free(message
);
3937 /* Do request and check for success */
3938 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
3939 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
3940 BAD_CAST
"SignedMessageDownload",
3941 message_id
, &response
, &code
, &status_message
);
3942 if (err
) goto leave
;
3945 xpath_ctx
= xmlXPathNewContext(response
);
3950 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3954 result
= xmlXPathEvalExpression(
3955 (outgoing
) ? BAD_CAST
3956 "/isds:SignedSentMessageDownloadResponse/isds:dmSignature" :
3957 BAD_CAST
"/isds:SignedMessageDownloadResponse/isds:dmSignature",
3963 /* Empty response */
3964 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3965 char *message_id_locale
= utf82locale((char*) message_id
);
3966 isds_printf_message(context
,
3968 _("Server did not return any message for ID `%s' "
3969 "on SignedSentMessageDownload request") :
3970 _("Server did not return any message for ID `%s' "
3971 "on SignedMessageDownload request"),
3973 free(message_id_locale
);
3978 if (result
->nodesetval
->nodeNr
> 1) {
3979 char *message_id_locale
= utf82locale((char*) message_id
);
3980 isds_printf_message(context
,
3982 _("Server did return more messages for ID `%s' "
3983 "on SignedSentMessageDownload request") :
3984 _("Server did return more messages for ID `%s' "
3985 "on SignedMessageDownload request"),
3987 free(message_id_locale
);
3992 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3994 /* Extract PKCS#7 structure */
3995 EXTRACT_STRING(".", encoded_structure
);
3996 if (!encoded_structure
) {
3997 isds_log_message(context
, _("dmSignature element is empty"));
4000 /* Here we have message as standalone CMS in encoded_structure.
4001 * We don't need any other data, free them: */
4002 xmlXPathFreeObject(result
); result
= NULL
;
4003 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
4005 zfree(status_message
);
4006 xmlFreeDoc(response
); response
= NULL
;
4010 /* Decode PKCS#7 to DER format */
4011 raw_length
= b64decode(encoded_structure
, &raw
);
4012 if (raw_length
== (size_t) -1) {
4013 isds_log_message(context
,
4014 _("Error while Base64-decoding PKCS#7 structure"));
4018 zfree(encoded_structure
);
4020 /* Extract message from PKCS#7 structure */
4021 err
= extract_cms_data(context
, raw
, raw_length
,
4022 &xml_stream
, &xml_stream_length
);
4023 if (err
) goto leave
;
4025 isds_log(ILF_ISDS
, ILL_DEBUG
, (outgoing
) ?
4026 _("Signed outgoing message content:\n%.*s\nEnd of message\n") :
4027 _("Signed incoming message content:\n%.*s\nEnd of message\n"),
4028 xml_stream_length
, xml_stream
);
4030 /* Convert extracted messages XML stream into XPath context */
4031 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
4036 xpath_ctx
= xmlXPathNewContext(message_doc
);
4041 /* XXX: Name spaces mangled for outgoing direction:
4042 * http://isds.czechpoint.cz/v20/SentMessage:
4044 * <q:MessageDownloadResponse
4045 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
4046 * <q:dmReturnedMessage>
4047 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
4048 * <p:dmID>151916</p:dmID>
4051 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
4053 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
4054 * </q:dmReturnedMessage>
4055 * </q:MessageDownloadResponse>
4057 * XXX: Name spaces mangled for incoming direction:
4058 * http://isds.czechpoint.cz/v20/message:
4060 * <q:MessageDownloadResponse
4061 * xmlns:q="http://isds.czechpoint.cz/v20/message">
4062 * <q:dmReturnedMessage>
4063 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
4064 * <p:dmID>151916</p:dmID>
4067 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
4069 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
4070 * </q:dmReturnedMessage>
4071 * </q:MessageDownloadResponse>
4073 * Stupidity of ISDS developers is unlimited */
4074 if (register_namespaces(xpath_ctx
, (outgoing
) ?
4075 MESSAGE_NS_SIGNED_OUTGOING
: MESSAGE_NS_SIGNED_INCOMING
)) {
4079 /* XXX: Embeded message XML document is always rooted as
4080 * /sisds:MessageDownloadResponse (even outgoind message). */
4081 result
= xmlXPathEvalExpression(
4082 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
4088 /* Empty embedded message */
4089 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4090 isds_printf_message(context
,
4091 _("XML document embedded into PKCS#7 structure is not "
4092 "sisds:dmReturnedMessage document"));
4096 /* More embedded messages */
4097 if (result
->nodesetval
->nodeNr
> 1) {
4098 isds_printf_message(context
,
4099 _("Embeded XML document into PKCS#7 structure has more "
4100 "root isds:dmReturnedMessage elements"));
4104 /* One embedded message */
4105 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4107 /* Extract the message */
4108 err
= extract_TReturnedMessage(context
, message
, xpath_ctx
);
4109 if (err
) goto leave
;
4111 /* Append raw CMS structure into message */
4112 (*message
)->raw
= raw
;
4113 (*message
)->raw_length
= raw_length
;
4119 isds_message_free(message
);
4122 xmlFreeDoc(message_doc
);
4123 cms_data_free(xml_stream
);
4124 free(encoded_structure
);
4125 xmlXPathFreeObject(result
);
4126 xmlXPathFreeContext(xpath_ctx
);
4130 free(status_message
);
4131 xmlFreeDoc(response
);
4134 isds_log(ILF_ISDS
, ILL_DEBUG
,
4136 _("signedmessagedownload request processed by server "
4137 "successfully.\n") :
4138 _("signedmessagedownload request processed by server "
4146 /* Download signed incoming message identified by ID.
4147 * @context is session context
4148 * @message_id is message identifier (you can get them from
4149 * isds_get_list_of_received_messages())
4150 * @message is automatically reallocated message retrieved from ISDS. The raw
4151 * memeber will be filled with PKCS#7 structure in DER format. */
4152 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
4153 const char *message_id
, struct isds_message
**message
) {
4154 return isds_get_signed_message(context
, 0, message_id
, message
);
4158 /* Download signed outgoing message identified by ID.
4159 * @context is session context
4160 * @message_id is message identifier (you can get them from
4161 * isds_get_list_of_sent_messages())
4162 * @message is automatically reallocated message retrieved from ISDS. The raw
4163 * memeber will be filled with PKCS#7 structure in DER format. */
4164 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
4165 const char *message_id
, struct isds_message
**message
) {
4166 return isds_get_signed_message(context
, 1, message_id
, message
);
4170 /* Retrieve hash of message identified by ID stored in ISDS.
4171 * @context is session context
4172 * @message_id is message identifier
4173 * @hash is automatically reallocated message hash downloaded from ISDS.
4174 * Message must exist in system and must not be deleted. */
4175 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
4176 const char *message_id
, struct isds_hash
**hash
) {
4177 /* ???: XSD allows list of @message_id's and list of @message's, but
4178 * documentation talks only about `a message' */
4180 isds_error err
= IE_SUCCESS
;
4181 xmlDocPtr response
= NULL
;
4182 xmlChar
*code
= NULL
, *status_message
= NULL
;
4183 xmlXPathContextPtr xpath_ctx
= NULL
;
4184 xmlXPathObjectPtr result
= NULL
;
4186 if (!context
) return IE_INVALID_CONTEXT
;
4188 isds_hash_free(hash
);
4190 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
4191 BAD_CAST
"VerifyMessage", message_id
,
4192 &response
, &code
, &status_message
);
4193 if (err
) goto leave
;
4197 xpath_ctx
= xmlXPathNewContext(response
);
4202 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4206 result
= xmlXPathEvalExpression(
4207 BAD_CAST
"/isds:VerifyMessageResponse",
4213 /* Empty response */
4214 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4215 char *message_id_locale
= utf82locale((char*) message_id
);
4216 isds_printf_message(context
,
4217 _("Server did not return any response for ID `%s' "
4218 "on VerifyMessage request"), message_id_locale
);
4219 free(message_id_locale
);
4223 /* More responses */
4224 if (result
->nodesetval
->nodeNr
> 1) {
4225 char *message_id_locale
= utf82locale((char*) message_id
);
4226 isds_printf_message(context
,
4227 _("Server did return more responses for ID `%s' "
4228 "on VerifyMessage request"), message_id_locale
);
4229 free(message_id_locale
);
4234 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4236 /* Extract the hash */
4237 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
4241 isds_hash_free(hash
);
4244 xmlXPathFreeObject(result
);
4245 xmlXPathFreeContext(xpath_ctx
);
4248 free(status_message
);
4249 xmlFreeDoc(response
);
4252 isds_log(ILF_ISDS
, ILL_DEBUG
,
4253 _("VerifyMessage request processed by server "
4260 #undef INSERT_STRING_ATTRIBUTE
4261 #undef INSERT_ULONGINTNOPTR
4262 #undef INSERT_ULONGINT
4263 #undef INSERT_LONGINT
4264 #undef INSERT_BOOLEAN
4265 #undef INSERT_STRING
4266 #undef EXTRACT_STRING_ATTRIBUTE
4267 #undef EXTRACT_ULONGINT
4268 #undef EXTRACT_LONGINT
4269 #undef EXTRACT_BOOLEAN
4270 #undef EXTRACT_STRING
4273 /* Compute hash of message from raw representation and store it into envelope.
4274 * Original hash structure will be destroyed in envelope.
4275 * @context is session context
4276 * @message is message carrying raw XML message blob
4277 * @algorithm is desired hash algorithm to use */
4278 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
4279 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
4280 isds_error err
= IE_SUCCESS
;
4281 xmlDocPtr message_doc
= NULL
;
4282 xmlXPathContextPtr xpath_ctx
= NULL
;
4283 xmlXPathObjectPtr result
= NULL
;
4286 struct isds_hash
*new_hash
= NULL
;
4289 if (!context
) return IE_INVALID_CONTEXT
;
4290 if (!message
) return IE_INVAL
;
4292 if (!message
->raw
) {
4293 isds_log_message(context
,
4294 _("Message does not carry raw XML representation"));
4298 /* Parse raw message */
4299 message_doc
= xmlParseMemory(message
->raw
, message
->raw_length
);
4301 isds_log_message(context
,
4302 _("Message does not carry well-formed XML representation"));
4307 /* Find dmDM element */
4308 xpath_ctx
= xmlXPathNewContext(message_doc
);
4313 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4317 result
= xmlXPathEvalExpression(
4318 BAD_CAST
"/isds:dmReturnedMessage/isds:dmDm", xpath_ctx
);
4323 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4324 isds_log_message(context
,
4325 _("Raw message does not contain isds:dmDm element"));
4329 if (result
->nodesetval
->nodeNr
> 1) {
4330 isds_log_message(context
,
4331 _("Raw message contains more isds:dmDm elements"));
4335 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4337 /* XXX: We need all childern of isds:dmDm: elements, text nodes, PIs,
4338 * CDATA, comments. Is asterisk sufficient? */
4339 result
= xmlXPathEvalExpression(BAD_CAST
"*", xpath_ctx
);
4345 /* Extract dmDM content as bit stream */
4346 err
= dump_nodeset(context
, message_doc
, result
->nodesetval
,
4347 (void**) &buffer
, &length
);
4348 if (err
) goto leave
;
4351 xmlXPathFreeObject(result
); result
= NULL
;
4352 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
4353 xmlFreeDoc(message_doc
); message_doc
= NULL
;
4355 /* TODO: Compute hash */
4356 new_hash
= calloc(1, sizeof(*new_hash
));
4361 new_hash
->algorithm
= algorithm
;
4362 err
= compute_hash(buffer
, length
, new_hash
);
4364 isds_log_message(context
, _("Could not compute message hash"));
4368 /* Save cumputed hash */
4369 if (!message
->envelope
) {
4370 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
4371 if (!message
->envelope
) {
4376 isds_hash_free(&message
->envelope
->hash
);
4377 message
->envelope
->hash
= new_hash
;
4381 isds_hash_free(&new_hash
);
4385 xmlXPathFreeObject(result
);
4386 xmlXPathFreeContext(xpath_ctx
);
4387 xmlFreeDoc(message_doc
);
4392 /* Search for document by document ID in list of documents. IDs are compared
4394 * @documents is list of isds_documents
4395 * @id is document identifier
4396 * @return first matching document or NULL. */
4397 const struct isds_document
*isds_find_document_by_id(
4398 const struct isds_list
*documents
, const char *id
) {
4399 const struct isds_list
*item
;
4400 const struct isds_document
*document
;
4402 for (item
= documents
; item
; item
= item
->next
) {
4403 document
= (struct isds_document
*) item
->data
;
4404 if (!document
) continue;
4406 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
4414 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
4415 struct isds_message **message);
4416 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
4417 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
4418 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
4419 struct isds_address **address);
4421 int isds_message_free(struct isds_message **message);
4422 int isds_address_free(struct isds_address **address);
4426 /* Makes known all relevant namespaces to given XPath context
4427 * @xpat_ctx is XPath context
4428 * @message_ns selects propper message name space. Unsisnged and signed
4430 * prefix and to URI ISDS_NS */
4431 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
,
4432 const message_ns_type message_ns
) {
4433 const xmlChar
*message_namespace
= NULL
;
4435 if (!xpath_ctx
) return IE_ERROR
;
4437 switch(message_ns
) {
4438 case MESSAGE_NS_UNSIGNED
:
4439 message_namespace
= BAD_CAST ISDS_NS
; break;
4440 case MESSAGE_NS_SIGNED_INCOMING
:
4441 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
4442 case MESSAGE_NS_SIGNED_OUTGOING
:
4443 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
4448 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
4450 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
4452 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
4454 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))