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 * @include_documents Use true if documents must be extracted
2317 * (tReturnedMessage XSD type), use false if documents shall be ommited
2318 * (tReturnedMessageEnvelope).
2319 * @message is automically reallocated message structure
2320 * @xpath_ctx is XPath context with current node as tReturnedMessage element
2322 * In case of error @message will be freed. */
2323 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
2324 const _Bool include_documents
, struct isds_message
**message
,
2325 xmlXPathContextPtr xpath_ctx
) {
2326 isds_error err
= IE_SUCCESS
;
2327 xmlNodePtr message_node
;
2329 if (!context
) return IE_INVALID_CONTEXT
;
2330 if (!message
) return IE_INVAL
;
2331 isds_message_free(message
);
2332 if (!xpath_ctx
) return IE_INVAL
;
2335 *message
= calloc(1, sizeof(**message
));
2341 /* Save message XPATH context node */
2342 message_node
= xpath_ctx
->node
;
2346 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
2347 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
2348 if (err
) { err
= IE_ERROR
; goto leave
; }
2349 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
2350 if (err
) goto leave
;
2352 if (include_documents
) {
2353 /* Extract dmFiles */
2354 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles",
2356 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
2357 err
= IE_ISDS
; goto leave
;
2359 if (err
) { err
= IE_ERROR
; goto leave
; }
2360 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
2361 if (err
) goto leave
;
2365 /* Restore context to message */
2366 xpath_ctx
->node
= message_node
;
2368 /* Extract dmHash */
2369 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
2371 if (err
) goto leave
;
2373 /* Extract dmQTimestamp, */
2374 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
2376 if (err
) goto leave
;
2378 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
2379 * dmAcceptanceTime. */
2380 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
2381 if (err
) goto leave
;
2384 if (err
) isds_message_free(message
);
2389 /* Convert isds_document structure into XML tree and append to dmFiles node.
2390 * @context is session context
2391 * @document is ISDS document
2392 * @dm_files is XML element the resulting tree will be appended to as a child.
2393 * @return error code, in case of error context' message is filled. */
2394 static isds_error
insert_document(struct isds_ctx
*context
,
2395 struct isds_document
*document
, xmlNodePtr dm_files
) {
2396 isds_error err
= IE_SUCCESS
;
2397 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
2398 xmlAttrPtr attribute_node
;
2399 xmlChar
*base64data
= NULL
;
2401 if (!context
) return IE_INVALID_CONTEXT
;
2402 if (!document
|| !dm_files
) return IE_INVAL
;
2404 /* Allocate new dmFile */
2405 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
2407 isds_printf_message(context
, _("Could not allocate main dmFile"));
2411 /* Append the new dmFile.
2412 * XXX: Main document must go first */
2413 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
2414 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
2416 file
= xmlAddChild(dm_files
, new_file
);
2419 xmlFreeNode(new_file
); new_file
= NULL
;
2420 isds_printf_message(context
, _("Could not add dmFile child to "
2421 "%s element"), dm_files
->name
);
2426 /* @dmMimeType is required */
2427 if (!document
->dmMimeType
) {
2428 isds_log_message(context
,
2429 _("Document is missing mandatory MIME type definition"));
2433 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
2435 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
2437 isds_printf_message(context
,
2438 _("Document has unkown dmFileMetaType: %ld"),
2439 document
->dmFileMetaType
);
2443 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
2445 if (document
->dmFileGuid
) {
2446 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
2448 if (document
->dmUpFileGuid
) {
2449 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
2452 /* @dmFileDescr is required */
2453 if (!document
->dmFileDescr
) {
2454 isds_log_message(context
,
2455 _("Document is missing mandatory description (title)"));
2459 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
2461 if (document
->dmFormat
) {
2462 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
2466 /* Insert content (data) of the document. */
2467 /* XXX; Only base64 is implemented currently. */
2468 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
2470 isds_printf_message(context
,
2471 _("Not enought memory to encode %zd bytes into Base64"),
2472 document
->data_length
);
2476 INSERT_STRING(file
, "dmEncodedContent", base64data
);
2484 /* Get data about logged in user and his box. */
2485 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
2486 struct isds_DbOwnerInfo
**db_owner_info
) {
2487 isds_error err
= IE_SUCCESS
;
2488 xmlNsPtr isds_ns
= NULL
;
2489 xmlNodePtr request
= NULL
;
2490 xmlDocPtr response
= NULL
;
2491 xmlChar
*code
= NULL
, *message
= NULL
;
2493 xmlXPathContextPtr xpath_ctx
= NULL
;
2494 xmlXPathObjectPtr result
= NULL
;
2495 char *string
= NULL
;
2497 if (!context
) return IE_INVALID_CONTEXT
;
2498 if (!db_owner_info
) return IE_INVAL
;
2500 /* Check if connection is established */
2501 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2504 /* Build GetOwnerInfoFromLogin request */
2505 request
= xmlNewNode(NULL
, BAD_CAST
"GetOwnerInfoFromLogin");
2507 isds_log_message(context
,
2508 _("Could build GetOwnerInfoFromLogin request"));
2511 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2513 isds_log_message(context
, _("Could not create ISDS name space"));
2514 xmlFreeNode(request
);
2517 xmlSetNs(request
, isds_ns
);
2518 node
= xmlNewChild(request
, NULL
, BAD_CAST
"dbDummy", NULL
);
2520 isds_log_message(context
, _("Could nod add dbDummy Child to "
2521 "GetOwnerInfoFromLogin element"));
2522 xmlFreeNode(request
);
2527 isds_log(ILF_ISDS
, ILL_DEBUG
,
2528 _("Sending GetOwnerInfoFromLogin request to ISDS\n"));
2531 err
= isds(context
, SERVICE_DB_SUPPLEMENTARY
, request
, &response
);
2533 /* Destroy request */
2534 xmlFreeNode(request
);
2537 isds_log(ILF_ISDS
, ILL_DEBUG
,
2538 _("Processing ISDS response on GetOwnerInfoFromLogin "
2539 "request failed\n"));
2540 xmlFreeDoc(response
);
2544 /* Check for response status */
2545 err
= isds_response_status(context
, SERVICE_DB_SUPPLEMENTARY
, response
,
2546 &code
, &message
, NULL
);
2548 isds_log(ILF_ISDS
, ILL_DEBUG
,
2549 _("ISDS response on GetOwnerInfoFromLogin request is "
2550 "missing status\n"));
2553 xmlFreeDoc(response
);
2556 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2557 char *code_locale
= utf82locale((char*)code
);
2558 char *message_locale
= utf82locale((char*)message
);
2559 isds_log(ILF_ISDS
, ILL_DEBUG
,
2560 _("Server refused GetOwnerInfoFromLogin request "
2561 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2562 isds_log_message(context
, message_locale
);
2564 free(message_locale
);
2567 xmlFreeDoc(response
);
2572 /* Prepare stucture */
2573 isds_DbOwnerInfo_free(db_owner_info
);
2574 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
2575 if (!*db_owner_info
) {
2579 xpath_ctx
= xmlXPathNewContext(response
);
2584 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
2589 /* Set context node */
2590 result
= xmlXPathEvalExpression(BAD_CAST
2591 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
2596 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2597 isds_log_message(context
, _("Missing dbOwnerInfo element"));
2601 if (result
->nodesetval
->nodeNr
> 1) {
2602 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
2606 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2607 xmlXPathFreeObject(result
); result
= NULL
;
2610 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
2614 isds_DbOwnerInfo_free(db_owner_info
);
2618 xmlXPathFreeObject(result
);
2619 xmlXPathFreeContext(xpath_ctx
);
2623 xmlFreeDoc(response
);
2626 isds_log(ILF_ISDS
, ILL_DEBUG
,
2627 _("GetOwnerInfoFromLogin request processed by server "
2628 "successfully.\n"));
2634 /* Find boxes suiting given criteria.
2635 * @criteria is filter. You should fill in at least some memebers.
2636 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
2637 * possibly empty. Input NULL or valid old structure.
2639 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
2640 * IE_NOEXIST if no such box exists, @boxes will be NULL
2641 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
2642 * contains still valid data
2643 * other code if something bad happens. @boxes will be NULL. */
2644 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
2645 const struct isds_DbOwnerInfo
*criteria
,
2646 struct isds_list
**boxes
) {
2647 isds_error err
= IE_SUCCESS
;
2648 _Bool truncated
= 0;
2649 xmlNsPtr isds_ns
= NULL
;
2650 xmlNodePtr request
= NULL
;
2651 xmlDocPtr response
= NULL
;
2652 xmlChar
*code
= NULL
, *message
= NULL
;
2653 xmlNodePtr db_owner_info
, node
;
2654 xmlXPathContextPtr xpath_ctx
= NULL
;
2655 xmlXPathObjectPtr result
= NULL
;
2656 xmlChar
*string
= NULL
;
2659 if (!context
) return IE_INVALID_CONTEXT
;
2660 if (!boxes
) return IE_INVAL
;
2661 isds_list_free(boxes
);
2667 /* Check if connection is established
2668 * TODO: This check should be done donwstairs. */
2669 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2672 /* Build FindDataBox request */
2673 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
2675 isds_log_message(context
,
2676 _("Could build FindDataBox request"));
2679 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2681 isds_log_message(context
, _("Could not create ISDS name space"));
2682 xmlFreeNode(request
);
2685 xmlSetNs(request
, isds_ns
);
2686 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
2687 if (!db_owner_info
) {
2688 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
2689 "FindDataBox element"));
2690 xmlFreeNode(request
);
2695 INSERT_STRING(db_owner_info
, "dbID", criteria
->dbID
);
2698 if (criteria
->dbType
) {
2699 const xmlChar
*type_string
= isds_DbType2string(*(criteria
->dbType
));
2701 isds_printf_message(context
, _("Invalid dbType value: %d"),
2702 *(criteria
->dbType
));
2706 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2709 INSERT_STRING(db_owner_info
, "firmName", criteria
->firmName
);
2710 INSERT_STRING(db_owner_info
, "ic", criteria
->ic
);
2711 if (criteria
->personName
) {
2712 INSERT_STRING(db_owner_info
, "pnFirstName",
2713 criteria
->personName
->pnFirstName
);
2714 INSERT_STRING(db_owner_info
, "pnMiddleName",
2715 criteria
->personName
->pnMiddleName
);
2716 INSERT_STRING(db_owner_info
, "pnLastName",
2717 criteria
->personName
->pnLastName
);
2718 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2719 criteria
->personName
->pnLastNameAtBirth
);
2721 if (criteria
->birthInfo
) {
2722 if (criteria
->birthInfo
->biDate
) {
2723 if (!tm2datestring(criteria
->birthInfo
->biDate
, &string
))
2724 INSERT_STRING(db_owner_info
, "biDate", string
);
2725 free(string
); string
= NULL
;
2727 INSERT_STRING(db_owner_info
, "biCity", criteria
->birthInfo
->biCity
);
2728 INSERT_STRING(db_owner_info
, "biCounty", criteria
->birthInfo
->biCounty
);
2729 INSERT_STRING(db_owner_info
, "biState", criteria
->birthInfo
->biState
);
2731 if (criteria
->address
) {
2732 INSERT_STRING(db_owner_info
, "adCity", criteria
->address
->adCity
);
2733 INSERT_STRING(db_owner_info
, "adStreet", criteria
->address
->adStreet
);
2734 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2735 criteria
->address
->adNumberInStreet
);
2736 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2737 criteria
->address
->adNumberInMunicipality
);
2738 INSERT_STRING(db_owner_info
, "adZipCode", criteria
->address
->adZipCode
);
2739 INSERT_STRING(db_owner_info
, "adState", criteria
->address
->adState
);
2741 INSERT_STRING(db_owner_info
, "nationality", criteria
->nationality
);
2742 INSERT_STRING(db_owner_info
, "email", criteria
->email
);
2743 INSERT_STRING(db_owner_info
, "telNumber", criteria
->telNumber
);
2744 INSERT_STRING(db_owner_info
, "identifier", criteria
->identifier
);
2745 INSERT_STRING(db_owner_info
, "registryCode", criteria
->registryCode
);
2747 INSERT_LONGINT(db_owner_info
, "dbState", criteria
->dbState
, string
);
2749 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", criteria
->dbEffectiveOVM
);
2750 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2751 criteria
->dbOpenAddressing
);
2754 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
2757 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2759 /* Destroy request */
2760 xmlFreeNode(request
); request
= NULL
;
2763 isds_log(ILF_ISDS
, ILL_DEBUG
,
2764 _("Processing ISDS response on FindDataBox "
2765 "request failed\n"));
2769 /* Check for response status */
2770 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2771 &code
, &message
, NULL
);
2773 isds_log(ILF_ISDS
, ILL_DEBUG
,
2774 _("ISDS response on FindDataBox request is missing status\n"));
2778 /* Request processed, but nothing found */
2779 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
2780 !xmlStrcmp(code
, BAD_CAST
"5001")) {
2781 char *code_locale
= utf82locale((char*)code
);
2782 char *message_locale
= utf82locale((char*)message
);
2783 isds_log(ILF_ISDS
, ILL_DEBUG
,
2784 _("Server did not found any box on FindDataBox request "
2785 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2786 isds_log_message(context
, message_locale
);
2788 free(message_locale
);
2793 /* Warning, not a error */
2794 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
2795 char *code_locale
= utf82locale((char*)code
);
2796 char *message_locale
= utf82locale((char*)message
);
2797 isds_log(ILF_ISDS
, ILL_DEBUG
,
2798 _("Server truncated response on FindDataBox request "
2799 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2800 isds_log_message(context
, message_locale
);
2802 free(message_locale
);
2807 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2808 char *code_locale
= utf82locale((char*)code
);
2809 char *message_locale
= utf82locale((char*)message
);
2810 isds_log(ILF_ISDS
, ILL_DEBUG
,
2811 _("Server refused FindDataBox request "
2812 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2813 isds_log_message(context
, message_locale
);
2815 free(message_locale
);
2820 xpath_ctx
= xmlXPathNewContext(response
);
2825 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
2830 /* Extract boxes if they present */
2831 result
= xmlXPathEvalExpression(BAD_CAST
2832 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
2838 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2839 struct isds_list
*item
, *prev_item
= NULL
;
2840 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2841 item
= calloc(1, sizeof(*item
));
2847 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
2848 if (i
== 0) *boxes
= item
;
2849 else prev_item
->next
= item
;
2852 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2853 err
= extract_DbOwnerInfo(context
,
2854 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
2855 if (err
) goto leave
;
2861 isds_list_free(boxes
);
2863 if (truncated
) err
= IE_2BIG
;
2867 xmlFreeNode(request
);
2868 xmlXPathFreeObject(result
);
2869 xmlXPathFreeContext(xpath_ctx
);
2873 xmlFreeDoc(response
);
2876 isds_log(ILF_ISDS
, ILL_DEBUG
,
2877 _("FindDataBox request processed by server successfully.\n"));
2883 /* Get status of a box.
2884 * @context is ISDS session context.
2885 * @box_id is UTF-8 encoded box identifier as zero terminated string
2886 * @box_status is return value of box status.
2888 * IE_SUCCESS if box has been found and its status retrieved
2889 * IE_NOEXIST if box is not known to ISDS server
2890 * or other appropriate error.
2891 * You can use isds_DbState to enumerate box status. However out of enum
2892 * range value can be returned too. This is feature because ISDS
2893 * specification leaves the set of values open.
2894 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
2895 * the box has been deleted, but ISDS still lists its former existence. */
2896 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
2897 long int *box_status
) {
2898 isds_error err
= IE_SUCCESS
;
2899 xmlNsPtr isds_ns
= NULL
;
2900 xmlNodePtr request
= NULL
, db_id
;
2901 xmlDocPtr response
= NULL
;
2902 xmlChar
*code
= NULL
, *message
= NULL
;
2903 xmlXPathContextPtr xpath_ctx
= NULL
;
2904 xmlXPathObjectPtr result
= NULL
;
2905 xmlChar
*string
= NULL
;
2907 if (!context
) return IE_INVALID_CONTEXT
;
2908 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
2910 /* Check if connection is established
2911 * TODO: This check should be done donwstairs. */
2912 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2915 /* Build CheckDataBox request */
2916 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
2918 isds_log_message(context
,
2919 _("Could build CheckDataBox request"));
2922 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2924 isds_log_message(context
, _("Could not create ISDS name space"));
2925 xmlFreeNode(request
);
2928 xmlSetNs(request
, isds_ns
);
2929 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
2931 isds_log_message(context
, _("Could not add dbId Child to "
2932 "CheckDataBox element"));
2933 xmlFreeNode(request
);
2938 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
2941 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2943 /* Destroy request */
2944 xmlFreeNode(request
);
2947 isds_log(ILF_ISDS
, ILL_DEBUG
,
2948 _("Processing ISDS response on CheckDataBox "
2949 "request failed\n"));
2953 /* Check for response status */
2954 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2955 &code
, &message
, NULL
);
2957 isds_log(ILF_ISDS
, ILL_DEBUG
,
2958 _("ISDS response on CheckDataBox request is missing status\n"));
2962 /* Request processed, but nothing found */
2963 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
2964 char *box_id_locale
= utf82locale((char*)box_id
);
2965 char *code_locale
= utf82locale((char*)code
);
2966 char *message_locale
= utf82locale((char*)message
);
2967 isds_log(ILF_ISDS
, ILL_DEBUG
,
2968 _("Server did not found box %s on CheckDataBox request "
2969 "(code=%s, message=%s)\n"),
2970 box_id_locale
, code_locale
, message_locale
);
2971 isds_log_message(context
, message_locale
);
2972 free(box_id_locale
);
2974 free(message_locale
);
2980 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2981 char *code_locale
= utf82locale((char*)code
);
2982 char *message_locale
= utf82locale((char*)message
);
2983 isds_log(ILF_ISDS
, ILL_DEBUG
,
2984 _("Server refused CheckDataBox request "
2985 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2986 isds_log_message(context
, message_locale
);
2988 free(message_locale
);
2994 xpath_ctx
= xmlXPathNewContext(response
);
2999 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3003 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
3009 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3010 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
3014 if (result
->nodesetval
->nodeNr
> 1) {
3015 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
3019 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3020 xmlXPathFreeObject(result
); result
= NULL
;
3022 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
3027 xmlXPathFreeObject(result
);
3028 xmlXPathFreeContext(xpath_ctx
);
3032 xmlFreeDoc(response
);
3035 isds_log(ILF_ISDS
, ILL_DEBUG
,
3036 _("CheckDataBox request processed by server successfully.\n"));
3042 /* Send a message via ISDS to a recipent
3043 * @context is session context
3044 * @outgoing_message is message to send; Some memebers are mandatory (like
3045 * dbIDRecipient), some are optional and some are irrelevant (especialy data
3046 * about sender). Included pointer to isds_list documents must contain at
3047 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
3048 * members will be filled with valid data from ISDS. Exact list of write
3049 * members is subject to change. Currently dmId is changed.
3050 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
3051 isds_error
isds_send_message(struct isds_ctx
*context
,
3052 struct isds_message
*outgoing_message
) {
3054 isds_error err
= IE_SUCCESS
;
3055 xmlNsPtr isds_ns
= NULL
;
3056 xmlNodePtr request
= NULL
, envelope
, dm_files
, node
;
3057 xmlDocPtr response
= NULL
;
3058 xmlChar
*code
= NULL
, *message
= NULL
;
3059 xmlXPathContextPtr xpath_ctx
= NULL
;
3060 xmlXPathObjectPtr result
= NULL
;
3061 xmlChar
*string
= NULL
;
3062 _Bool message_is_complete
= 0;
3064 if (!context
) return IE_INVALID_CONTEXT
;
3065 if (!outgoing_message
) return IE_INVAL
;
3067 /* Check if connection is established
3068 * TODO: This check should be done donwstairs. */
3069 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3072 /* Build CreateMessage request */
3073 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
3075 isds_log_message(context
,
3076 _("Could build CreateMessage request"));
3079 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3081 isds_log_message(context
, _("Could not create ISDS name space"));
3082 xmlFreeNode(request
);
3085 xmlSetNs(request
, isds_ns
);
3088 /* Build envelope */
3089 envelope
= xmlNewChild(request
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
3091 isds_log_message(context
, _("Could not add dmEnvelope child to "
3092 "CreateMessage element"));
3093 xmlFreeNode(request
);
3097 if (!outgoing_message
->envelope
) {
3098 isds_log_message(context
, _("outgoing message is missing envelope"));
3103 INSERT_STRING(envelope
, "dmSenderOrgUnit",
3104 outgoing_message
->envelope
->dmSenderOrgUnit
);
3105 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
3106 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
3108 if (!outgoing_message
->envelope
->dbIDRecipient
) {
3109 isds_log_message(context
,
3110 _("outgoing message is missing recipient box identifier"));
3114 INSERT_STRING(envelope
, "dbIDRecipient",
3115 outgoing_message
->envelope
->dbIDRecipient
);
3117 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
3118 outgoing_message
->envelope
->dmRecipientOrgUnit
);
3119 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
3120 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
3121 INSERT_STRING(envelope
, "dmToHands", outgoing_message
->envelope
->dmToHands
);
3123 #define CHECK_FOR_STRING_LENGTH(string, limit, name) \
3124 if ((string) && xmlUTF8Strlen((xmlChar *) (string)) > (limit)) { \
3125 isds_printf_message(context, \
3126 _("%s has more than %d characters"), (name), (limit)); \
3131 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 255,
3133 INSERT_STRING(envelope
, "dmAnnotation",
3134 outgoing_message
->envelope
->dmAnnotation
);
3136 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
3137 50, "dmRecipientRefNumber");
3138 INSERT_STRING(envelope
, "dmRecipientRefNumber",
3139 outgoing_message
->envelope
->dmRecipientRefNumber
);
3141 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
3142 50, "dmSenderRefNumber");
3143 INSERT_STRING(envelope
, "dmSenderRefNumber",
3144 outgoing_message
->envelope
->dmSenderRefNumber
);
3146 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
3147 50, "dmRecipientIdent");
3148 INSERT_STRING(envelope
, "dmRecipientIdent",
3149 outgoing_message
->envelope
->dmRecipientIdent
);
3151 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
3152 50, "dmSenderIdent");
3153 INSERT_STRING(envelope
, "dmSenderIdent",
3154 outgoing_message
->envelope
->dmSenderIdent
);
3156 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
3157 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
3158 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
3159 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
3160 INSERT_STRING(envelope
, "dmLegalTitleSect",
3161 outgoing_message
->envelope
->dmLegalTitleSect
);
3162 INSERT_STRING(envelope
, "dmLegalTitlePar",
3163 outgoing_message
->envelope
->dmLegalTitlePar
);
3164 INSERT_STRING(envelope
, "dmLegalTitlePoint",
3165 outgoing_message
->envelope
->dmLegalTitlePoint
);
3167 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
3168 outgoing_message
->envelope
->dmPersonalDelivery
);
3169 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
3170 outgoing_message
->envelope
->dmAllowSubstDelivery
);
3172 #undef CHECK_FOR_STRING_LENGTH
3174 /* ???: Should we require value for dbEffectiveOVM sender?
3175 * ISDS has default as true */
3176 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
3179 /* Append dmFiles */
3180 if (!outgoing_message
->documents
) {
3181 isds_log_message(context
,
3182 _("outgoing message is missing list of documents"));
3186 dm_files
= xmlNewChild(request
, NULL
, BAD_CAST
"dmFiles", NULL
);
3188 isds_log_message(context
, _("Could not add dmFiles child to "
3189 "CreateMessage element"));
3194 /* Check for document hieararchy */
3195 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
3196 if (err
) goto leave
;
3198 /* Process each document */
3199 for (struct isds_list
*item
=
3200 (struct isds_list
*) outgoing_message
->documents
;
3201 item
; item
= item
->next
) {
3203 isds_log_message(context
,
3204 _("list of documents contains empty item"));
3208 /* FIXME: Check for dmFileMetaType and for document references.
3209 * Only first document can be of MAIN type */
3210 err
= insert_document(context
, (struct isds_document
*) item
->data
,
3213 if (err
) goto leave
;
3216 /* Signal we can serilize message since now */
3217 message_is_complete
= 1;
3221 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
3224 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
3226 /* Dont' destroy request, we want to privode it to application later */
3229 isds_log(ILF_ISDS
, ILL_DEBUG
,
3230 _("Processing ISDS response on CreateMessage "
3231 "request failed\n"));
3235 /* Check for response status */
3236 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
3237 &code
, &message
, NULL
);
3239 isds_log(ILF_ISDS
, ILL_DEBUG
,
3240 _("ISDS response on CreateMessage request "
3241 "is missing status\n"));
3245 /* Request processed, but nothing found */
3246 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3247 char *box_id_locale
=
3248 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
3249 char *code_locale
= utf82locale((char*)code
);
3250 char *message_locale
= utf82locale((char*)message
);
3251 isds_log(ILF_ISDS
, ILL_DEBUG
,
3252 _("Server did not accept message for %s on CreateMessage "
3253 "request (code=%s, message=%s)\n"),
3254 box_id_locale
, code_locale
, message_locale
);
3255 isds_log_message(context
, message_locale
);
3256 free(box_id_locale
);
3258 free(message_locale
);
3265 xpath_ctx
= xmlXPathNewContext(response
);
3270 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3274 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
3280 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3281 isds_log_message(context
, _("Missing CreateMessageResponse element"));
3285 if (result
->nodesetval
->nodeNr
> 1) {
3286 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
3290 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3291 xmlXPathFreeObject(result
); result
= NULL
;
3293 if (outgoing_message
->envelope
->dmID
) {
3294 free(outgoing_message
->envelope
->dmID
);
3295 outgoing_message
->envelope
->dmID
= NULL
;
3297 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
3298 if (!outgoing_message
->envelope
->dmID
) {
3299 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3300 "but did not returen assigned message ID\n"));
3304 /* TODO: Serialize message into structure member raw */
3305 /* XXX: Each web service transport message in different format.
3306 * Therefore it's not possible to save them directly.
3307 * To save them, one must figure out common format.
3308 * We can leave it on application, or we can implement the ESS format. */
3309 /*if (message_is_complete) {
3310 if (outgoing_message->envelope->dmID) {
3312 /* Add assigned message ID as first child*/
3313 /*xmlNodePtr dmid_text = xmlNewText(
3314 (xmlChar *) outgoing_message->envelope->dmID);
3315 if (!dmid_text) goto serialization_failed;
3317 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
3319 if (!dmid_element) {
3320 xmlFreeNode(dmid_text);
3321 goto serialization_failed;
3324 xmlNodePtr dmid_element_with_text =
3325 xmlAddChild(dmid_element, dmid_text);
3326 if (!dmid_element_with_text) {
3327 xmlFreeNode(dmid_element);
3328 xmlFreeNode(dmid_text);
3329 goto serialization_failed;
3332 node = xmlAddPrevSibling(envelope->childern,
3333 dmid_element_with_text);
3335 xmlFreeNodeList(dmid_element_with_text);
3336 goto serialization_failed;
3340 /* Serialize message with ID into raw */
3341 /*buffer = serialize_element(envelope)*/
3344 serialization_failed:
3351 xmlXPathFreeObject(result
);
3352 xmlXPathFreeContext(xpath_ctx
);
3356 xmlFreeDoc(response
);
3357 xmlFreeNode(request
);
3360 isds_log(ILF_ISDS
, ILL_DEBUG
,
3361 _("CreateMessage request processed by server "
3362 "successfully.\n"));
3368 /* Get list of messages. This is common core for getting sent or received
3370 * Any criterion argument can be NULL, if you don't care about it.
3371 * @context is session context. Must not be NULL.
3372 * @outgoing_direction is true if you want list of outgoing messages,
3373 * it's false if you want incoming messages.
3374 * @from_time is minimal time and date of message sending inclusive.
3375 * @to_time is maximal time and date of message sending inclusive
3376 * @organization_unit_number is number of sender/recipient respectively.
3377 * @status_filter is bit field of isds_message_status values. Use special
3378 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3379 * all values, you can use bitwise arithmetic if you want.)
3380 * @offset is index of first message we are interested in. First message is 1.
3381 * Set to 0 (or 1) if you don't care.
3382 * @number is maximal length of list you want to get as input value, outputs
3383 * number of messages matching these criteria. Can be NULL if you don't care
3384 * (applies to output value either).
3385 * @messages is automatically reallocated list of isds_message's. Be ware that
3386 * it returns only brief overview (envelope and some other fields) about each
3387 * message, not the complete message. FIXME: Specify exact fields.
3388 * The list is sorted by delivery time in ascending order.
3390 * you don't care about don't need the data (useful if you want to know only
3391 * the @number). If you provide &NULL, list will be allocated on heap, if you
3392 * provide pointer to non-NULL, list will be freed automacally at first. Also
3393 * in case of error the list will be NULLed.
3394 * @return IE_SUCCESS or appropriate error code. */
3395 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
3396 _Bool outgoing_direction
,
3397 const struct timeval
*from_time
, const struct timeval
*to_time
,
3398 const long int *organization_unit_number
,
3399 const unsigned int status_filter
,
3400 const unsigned long int offset
, unsigned long int *number
,
3401 struct isds_list
**messages
) {
3403 isds_error err
= IE_SUCCESS
;
3404 xmlNsPtr isds_ns
= NULL
;
3405 xmlNodePtr request
= NULL
, node
;
3406 xmlDocPtr response
= NULL
;
3407 xmlChar
*code
= NULL
, *message
= NULL
;
3408 xmlXPathContextPtr xpath_ctx
= NULL
;
3409 xmlXPathObjectPtr result
= NULL
;
3410 xmlChar
*string
= NULL
;
3411 long unsigned int count
= 0;
3413 if (!context
) return IE_INVALID_CONTEXT
;
3415 /* Free former message list if any */
3416 if (messages
) isds_list_free(messages
);
3418 /* Check if connection is established
3419 * TODO: This check should be done donwstairs. */
3420 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3422 /* Build GetListOf*Messages request */
3423 request
= xmlNewNode(NULL
,
3424 (outgoing_direction
) ?
3425 BAD_CAST
"GetListOfSentMessages" :
3426 BAD_CAST
"GetListOfReceivedMessages"
3429 isds_log_message(context
,
3430 (outgoing_direction
) ?
3431 _("Could not build GetListOfSentMessages request") :
3432 _("Could not build GetListOfReceivedMessages request")
3436 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3438 isds_log_message(context
, _("Could not create ISDS name space"));
3439 xmlFreeNode(request
);
3442 xmlSetNs(request
, isds_ns
);
3446 err
= timeval2timestring(from_time
, &string
);
3447 if (err
) goto leave
;
3449 INSERT_STRING(request
, "dmFromTime", string
);
3450 free(string
); string
= NULL
;
3453 err
= timeval2timestring(to_time
, &string
);
3454 if (err
) goto leave
;
3456 INSERT_STRING(request
, "dmToTime", string
);
3457 free(string
); string
= NULL
;
3459 if (outgoing_direction
) {
3460 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
3461 organization_unit_number
, string
);
3463 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
3464 organization_unit_number
, string
);
3467 if (status_filter
> MESSAGESTATE_ANY
) {
3468 isds_printf_message(context
,
3469 _("Invalid message state filter value: %ld"), status_filter
);
3473 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
3476 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
3478 INSERT_STRING(request
, "dmOffset", "1");
3481 /* number 0 means no limit */
3482 if (number
&& *number
== 0) {
3483 INSERT_STRING(request
, "dmLimit", NULL
);
3485 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
3489 isds_log(ILF_ISDS
, ILL_DEBUG
,
3490 (outgoing_direction
) ?
3491 _("Sending GetListOfSentMessages request to ISDS\n") :
3492 _("Sending GetListOfReceivedMessages request to ISDS\n")
3496 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
);
3497 xmlFreeNode(request
); request
= NULL
;
3500 isds_log(ILF_ISDS
, ILL_DEBUG
,
3501 (outgoing_direction
) ?
3502 _("Processing ISDS response on GetListOfSentMessages "
3503 "request failed\n") :
3504 _("Processing ISDS response on GetListOfReceivedMessages "
3510 /* Check for response status */
3511 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
3512 &code
, &message
, NULL
);
3514 isds_log(ILF_ISDS
, ILL_DEBUG
,
3515 (outgoing_direction
) ?
3516 _("ISDS response on GetListOfSentMessages request "
3517 "is missing status\n") :
3518 _("ISDS response on GetListOfReceivedMessages request "
3519 "is missing status\n")
3524 /* Request processed, but nothing found */
3525 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3526 char *code_locale
= utf82locale((char*)code
);
3527 char *message_locale
= utf82locale((char*)message
);
3528 isds_log(ILF_ISDS
, ILL_DEBUG
,
3529 (outgoing_direction
) ?
3530 _("Server refused GetListOfSentMessages request "
3531 "(code=%s, message=%s)\n") :
3532 _("Server refused GetListOfReceivedMessages request "
3533 "(code=%s, message=%s)\n"),
3534 code_locale
, message_locale
);
3535 isds_log_message(context
, message_locale
);
3537 free(message_locale
);
3544 xpath_ctx
= xmlXPathNewContext(response
);
3549 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3553 result
= xmlXPathEvalExpression(
3554 (outgoing_direction
) ?
3555 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
3556 "isds:dmRecords/isds:dmRecord" :
3557 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
3558 "isds:dmRecords/isds:dmRecord",
3565 /* Fill output arguments in */
3566 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3567 struct isds_envelope
*envelope
;
3568 struct isds_list
*item
= NULL
, *last_item
= NULL
;
3570 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
3571 /* Create new message */
3572 item
= calloc(1, sizeof(*item
));
3577 item
->destructor
= (void(*)(void**)) &isds_message_free
;
3578 item
->data
= calloc(1, sizeof(struct isds_message
));
3580 isds_list_free(&item
);
3585 /* Extract envelope data */
3586 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
3588 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
3590 isds_list_free(&item
);
3594 /* Attach extracted envelope */
3595 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
3597 /* Append new message into the list */
3599 *messages
= last_item
= item
;
3601 last_item
->next
= item
;
3606 if (number
) *number
= count
;
3610 isds_list_free(messages
);
3614 xmlXPathFreeObject(result
);
3615 xmlXPathFreeContext(xpath_ctx
);
3619 xmlFreeDoc(response
);
3620 xmlFreeNode(request
);
3623 isds_log(ILF_ISDS
, ILL_DEBUG
,
3624 (outgoing_direction
) ?
3625 _("GetListOfSentMessages request processed by server "
3626 "successfully.\n") :
3627 _("GetListOfReceivedMessages request processed by server "
3634 /* Get list of outgoing (already sent) messages.
3635 * Any criterion argument can be NULL, if you don't care about it.
3636 * @context is session context. Must not be NULL.
3637 * @from_time is minimal time and date of message sending inclusive.
3638 * @to_time is maximal time and date of message sending inclusive
3639 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
3640 * @status_filter is bit field of isds_message_status values. Use special
3641 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3642 * all values, you can use bitwise arithmetic if you want.)
3643 * @offset is index of first message we are interested in. First message is 1.
3644 * Set to 0 (or 1) if you don't care.
3645 * @number is maximal length of list you want to get as input value, outputs
3646 * number of messages matching these criteria. Can be NULL if you don't care
3647 * (applies to output value either).
3648 * @messages is automatically reallocated list of isds_message's. Be ware that
3649 * it returns only brief overview (envelope and some other fields) about each
3650 * message, not the complete message. FIXME: Specify exact fields.
3651 * The list is sorted by delivery time in ascending order.
3652 * Use NULL if you don't care about the metadata (useful if you want to know
3653 * only the @number). If you provide &NULL, list will be allocated on heap,
3654 * if you provide pointer to non-NULL, list will be freed automacally at first.
3655 * Also in case of error the list will be NULLed.
3656 * @return IE_SUCCESS or appropriate error code. */
3657 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
3658 const struct timeval
*from_time
, const struct timeval
*to_time
,
3659 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
3660 const unsigned long int offset
, unsigned long int *number
,
3661 struct isds_list
**messages
) {
3663 return isds_get_list_of_messages(
3665 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
3671 /* Get list of incoming (addressed to you) messages.
3672 * Any criterion argument can be NULL, if you don't care about it.
3673 * @context is session context. Must not be NULL.
3674 * @from_time is minimal time and date of message sending inclusive.
3675 * @to_time is maximal time and date of message sending inclusive
3676 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
3677 * @status_filter is bit field of isds_message_status values. Use special
3678 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
3679 * all values, you can use bitwise arithmetic if you want.)
3680 * @offset is index of first message we are interested in. First message is 1.
3681 * Set to 0 (or 1) if you don't care.
3682 * @number is maximal length of list you want to get as input value, outputs
3683 * number of messages matching these criteria. Can be NULL if you don't care
3684 * (applies to output value either).
3685 * @messages is automatically reallocated list of isds_message's. Be ware that
3686 * it returns only brief overview (envelope and some other fields) about each
3687 * message, not the complete message. FIXME: Specify exact fields.
3688 * Use NULL if you don't care about the metadata (useful if you want to know
3689 * only the @number). If you provide &NULL, list will be allocated on heap,
3690 * if you provide pointer to non-NULL, list will be freed automacally at first.
3691 * Also in case of error the list will be NULLed.
3692 * @return IE_SUCCESS or appropriate error code. */
3693 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
3694 const struct timeval
*from_time
, const struct timeval
*to_time
,
3695 const long int *dmRecipientOrgUnitNum
,
3696 const unsigned int status_filter
,
3697 const unsigned long int offset
, unsigned long int *number
,
3698 struct isds_list
**messages
) {
3700 return isds_get_list_of_messages(
3702 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
3708 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
3710 * @context is session context
3711 * @service is ISDS WS service handler
3712 * @service_name is name of SERVICE_DM_OPERATIONS
3713 * @message_id is message ID to send as service argument to ISDS
3714 * @response is server SOAP body response as XML document
3715 * @code is ISDS status code
3716 * @status_message is ISDS status message
3717 * @return error coded from lower layer, context message will be set up
3719 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
3720 const isds_service service
, const xmlChar
*service_name
,
3721 const char *message_id
,
3722 xmlDocPtr
*response
, xmlChar
**code
, xmlChar
**status_message
) {
3723 /* ???: XSD allows list of @message_id's and list of @message's, but
3724 * documentation talks only about `a message' */
3726 isds_error err
= IE_SUCCESS
;
3727 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
3728 xmlNodePtr request
= NULL
, node
;
3729 xmlNsPtr isds_ns
= NULL
;
3731 if (!context
) return IE_INVALID_CONTEXT
;
3732 if (!service_name
|| !message_id
) return IE_INVAL
;
3733 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3735 /* Free output argument */
3736 xmlFreeDoc(*response
);
3738 free(*status_message
);
3741 /* Check if connection is established
3742 * TODO: This check should be done donwstairs. */
3743 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3745 service_name_locale
= utf82locale((char*)service_name
);
3746 message_id_locale
= utf82locale(message_id
);
3747 if (!service_name_locale
|| !message_id_locale
) {
3753 request
= xmlNewNode(NULL
, service_name
);
3755 isds_printf_message(context
,
3756 _("Could not build %s request"), service_name_locale
);
3760 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3762 isds_log_message(context
, _("Could not create ISDS name space"));
3766 xmlSetNs(request
, isds_ns
);
3769 /* Add requested ID */
3770 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
3771 if (err
) goto leave
;
3772 INSERT_STRING(request
, "dmID", message_id
);
3775 isds_log(ILF_ISDS
, ILL_DEBUG
,
3776 _("Sending %s request for %s message ID to ISDS\n"),
3777 service_name_locale
, message_id_locale
);
3780 err
= isds(context
, service
, request
, response
);
3781 xmlFreeNode(request
); request
= NULL
;
3784 isds_log(ILF_ISDS
, ILL_DEBUG
,
3785 _("Processing ISDS response on %s request failed\n"),
3786 service_name_locale
);
3790 /* Check for response status */
3791 err
= isds_response_status(context
, service
, *response
,
3792 code
, status_message
, NULL
);
3794 isds_log(ILF_ISDS
, ILL_DEBUG
,
3795 _("ISDS response on %s request is missing status\n"),
3796 service_name_locale
);
3800 /* Request processed, but nothing found */
3801 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3802 char *code_locale
= utf82locale((char*) *code
);
3803 char *status_message_locale
= utf82locale((char*) *status_message
);
3804 isds_log(ILF_ISDS
, ILL_DEBUG
,
3805 _("Server refused %s request for %s message ID "
3806 "(code=%s, message=%s)\n"),
3807 service_name_locale
, message_id_locale
,
3808 code_locale
, status_message_locale
);
3809 isds_log_message(context
, status_message_locale
);
3811 free(status_message_locale
);
3817 free(message_id_locale
);
3818 free(service_name_locale
);
3819 xmlFreeNode(request
);
3824 /* Download incoming message envelope identified by ID.
3825 * @context is session context
3826 * @message_id is message identifier (you can get them from
3827 * isds_get_list_of_received_messages())
3828 * @message is automatically reallocated message retrieved from ISDS.
3829 * It will miss documents per se. Use isds_get_received_message(), if you are
3830 * interrested in documents (content) too.
3831 * Returned hash and timestamp require documents to be verifiable. */
3832 isds_error
isds_get_received_envelope(struct isds_ctx
*context
,
3833 const char *message_id
, struct isds_message
**message
) {
3835 isds_error err
= IE_SUCCESS
;
3836 xmlDocPtr response
= NULL
;
3837 xmlChar
*code
= NULL
, *status_message
= NULL
;
3838 xmlXPathContextPtr xpath_ctx
= NULL
;
3839 xmlXPathObjectPtr result
= NULL
;
3841 if (!context
) return IE_INVALID_CONTEXT
;
3843 /* Free former message if any */
3844 if (message
) isds_message_free(message
);
3846 /* Do request and check for success */
3847 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
3848 BAD_CAST
"MessageEnvelopeDownload", message_id
,
3849 &response
, &code
, &status_message
);
3850 if (err
) goto leave
;
3853 xpath_ctx
= xmlXPathNewContext(response
);
3858 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3862 result
= xmlXPathEvalExpression(
3863 BAD_CAST
"/isds:MessageEnvelopeDownloadResponse/"
3864 "isds:dmReturnedMessageEnvelope",
3870 /* Empty response */
3871 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3872 char *message_id_locale
= utf82locale((char*) message_id
);
3873 isds_printf_message(context
,
3874 _("Server did not return any envelope for ID `%s' "
3875 "on MessageEnvelopeDownload request"), message_id_locale
);
3876 free(message_id_locale
);
3881 if (result
->nodesetval
->nodeNr
> 1) {
3882 char *message_id_locale
= utf82locale((char*) message_id
);
3883 isds_printf_message(context
,
3884 _("Server did return more envelopes for ID `%s' "
3885 "on MessageEnvelopeDownload request"), message_id_locale
);
3886 free(message_id_locale
);
3891 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3893 /* Extract the envelope (= message without documents, hence 0) */
3894 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
3895 if (err
) goto leave
;
3898 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
3899 &(*message
)->raw_length
);
3903 isds_message_free(message
);
3906 xmlXPathFreeObject(result
);
3907 xmlXPathFreeContext(xpath_ctx
);
3910 free(status_message
);
3911 xmlFreeDoc(response
);
3914 isds_log(ILF_ISDS
, ILL_DEBUG
,
3915 _("MessageEnvelopeDownload request processed by server "
3922 /* Dwwnload incoming message identified by ID.
3923 * @context is session context
3924 * @message_id is message identifier (you can get them from
3925 * isds_get_list_of_received_messages())
3926 * @message is automatically reallocated message retrieved from ISDS */
3927 isds_error
isds_get_received_message(struct isds_ctx
*context
,
3928 const char *message_id
, struct isds_message
**message
) {
3929 /* ???: XSD allows list of @message_id's and list of @message's, but
3930 * documentation talks only about `a message' */
3932 isds_error err
= IE_SUCCESS
;
3933 xmlDocPtr response
= NULL
;
3934 xmlChar
*code
= NULL
, *status_message
= NULL
;
3935 xmlXPathContextPtr xpath_ctx
= NULL
;
3936 xmlXPathObjectPtr result
= NULL
;
3938 if (!context
) return IE_INVALID_CONTEXT
;
3940 /* Free former message if any */
3941 if (message
) isds_message_free(message
);
3943 /* Do request and check for success */
3944 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
3945 BAD_CAST
"MessageDownload", message_id
,
3946 &response
, &code
, &status_message
);
3947 if (err
) goto leave
;
3950 xpath_ctx
= xmlXPathNewContext(response
);
3955 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3959 result
= xmlXPathEvalExpression(
3960 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
3966 /* Empty response */
3967 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3968 char *message_id_locale
= utf82locale((char*) message_id
);
3969 isds_printf_message(context
,
3970 _("Server did not return any message for ID `%s' "
3971 "on MessageDownload request"), message_id_locale
);
3972 free(message_id_locale
);
3977 if (result
->nodesetval
->nodeNr
> 1) {
3978 char *message_id_locale
= utf82locale((char*) message_id
);
3979 isds_printf_message(context
,
3980 _("Server did return more messages for ID `%s' "
3981 "on MessageDownload request"), message_id_locale
);
3982 free(message_id_locale
);
3987 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3989 /* Extract the message */
3990 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
3991 if (err
) goto leave
;
3994 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
3995 &(*message
)->raw_length
);
3999 isds_message_free(message
);
4002 xmlXPathFreeObject(result
);
4003 xmlXPathFreeContext(xpath_ctx
);
4006 free(status_message
);
4007 xmlFreeDoc(response
);
4010 isds_log(ILF_ISDS
, ILL_DEBUG
,
4011 _("MessageDownload request processed by server "
4018 /* Download signed incoming/outgoing message identified by ID.
4019 * @context is session context
4020 * @output is true for outging message, false for incoming message
4021 * @message_id is message identifier (you can get them from
4022 * isds_get_list_of_{sent,received}_messages())
4023 * @message is automatically reallocated message retrieved from ISDS. The raw
4024 * memeber will be filled with PKCS#7 structure in DER format. */
4025 _hidden isds_error
isds_get_signed_message(struct isds_ctx
*context
,
4026 const _Bool outgoing
, const char *message_id
,
4027 struct isds_message
**message
) {
4029 isds_error err
= IE_SUCCESS
;
4030 xmlDocPtr response
= NULL
, message_doc
= NULL
;
4031 xmlChar
*code
= NULL
, *status_message
= NULL
;
4032 xmlXPathContextPtr xpath_ctx
= NULL
;
4033 xmlXPathObjectPtr result
= NULL
;
4034 char *encoded_structure
= NULL
;
4035 void *raw
= NULL
, *xml_stream
= NULL
;
4036 size_t raw_length
= 0, xml_stream_length
= 0;
4038 if (!context
) return IE_INVALID_CONTEXT
;
4040 /* Free former message if any */
4041 if (message
) isds_message_free(message
);
4043 /* Do request and check for success */
4044 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
4045 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
4046 BAD_CAST
"SignedMessageDownload",
4047 message_id
, &response
, &code
, &status_message
);
4048 if (err
) goto leave
;
4051 xpath_ctx
= xmlXPathNewContext(response
);
4056 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4060 result
= xmlXPathEvalExpression(
4061 (outgoing
) ? BAD_CAST
4062 "/isds:SignedSentMessageDownloadResponse/isds:dmSignature" :
4063 BAD_CAST
"/isds:SignedMessageDownloadResponse/isds:dmSignature",
4069 /* Empty response */
4070 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4071 char *message_id_locale
= utf82locale((char*) message_id
);
4072 isds_printf_message(context
,
4074 _("Server did not return any message for ID `%s' "
4075 "on SignedSentMessageDownload request") :
4076 _("Server did not return any message for ID `%s' "
4077 "on SignedMessageDownload request"),
4079 free(message_id_locale
);
4084 if (result
->nodesetval
->nodeNr
> 1) {
4085 char *message_id_locale
= utf82locale((char*) message_id
);
4086 isds_printf_message(context
,
4088 _("Server did return more messages for ID `%s' "
4089 "on SignedSentMessageDownload request") :
4090 _("Server did return more messages for ID `%s' "
4091 "on SignedMessageDownload request"),
4093 free(message_id_locale
);
4098 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4100 /* Extract PKCS#7 structure */
4101 EXTRACT_STRING(".", encoded_structure
);
4102 if (!encoded_structure
) {
4103 isds_log_message(context
, _("dmSignature element is empty"));
4106 /* Here we have message as standalone CMS in encoded_structure.
4107 * We don't need any other data, free them: */
4108 xmlXPathFreeObject(result
); result
= NULL
;
4109 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
4111 zfree(status_message
);
4112 xmlFreeDoc(response
); response
= NULL
;
4116 /* Decode PKCS#7 to DER format */
4117 raw_length
= b64decode(encoded_structure
, &raw
);
4118 if (raw_length
== (size_t) -1) {
4119 isds_log_message(context
,
4120 _("Error while Base64-decoding PKCS#7 structure"));
4124 zfree(encoded_structure
);
4126 /* Extract message from PKCS#7 structure */
4127 err
= extract_cms_data(context
, raw
, raw_length
,
4128 &xml_stream
, &xml_stream_length
);
4129 if (err
) goto leave
;
4131 isds_log(ILF_ISDS
, ILL_DEBUG
, (outgoing
) ?
4132 _("Signed outgoing message content:\n%.*s\nEnd of message\n") :
4133 _("Signed incoming message content:\n%.*s\nEnd of message\n"),
4134 xml_stream_length
, xml_stream
);
4136 /* Convert extracted messages XML stream into XPath context */
4137 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
4142 xpath_ctx
= xmlXPathNewContext(message_doc
);
4147 /* XXX: Name spaces mangled for outgoing direction:
4148 * http://isds.czechpoint.cz/v20/SentMessage:
4150 * <q:MessageDownloadResponse
4151 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
4152 * <q:dmReturnedMessage>
4153 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
4154 * <p:dmID>151916</p:dmID>
4157 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
4159 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
4160 * </q:dmReturnedMessage>
4161 * </q:MessageDownloadResponse>
4163 * XXX: Name spaces mangled for incoming direction:
4164 * http://isds.czechpoint.cz/v20/message:
4166 * <q:MessageDownloadResponse
4167 * xmlns:q="http://isds.czechpoint.cz/v20/message">
4168 * <q:dmReturnedMessage>
4169 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
4170 * <p:dmID>151916</p:dmID>
4173 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
4175 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
4176 * </q:dmReturnedMessage>
4177 * </q:MessageDownloadResponse>
4179 * Stupidity of ISDS developers is unlimited */
4180 if (register_namespaces(xpath_ctx
, (outgoing
) ?
4181 MESSAGE_NS_SIGNED_OUTGOING
: MESSAGE_NS_SIGNED_INCOMING
)) {
4185 /* XXX: Embeded message XML document is always rooted as
4186 * /sisds:MessageDownloadResponse (even outgoind message). */
4187 result
= xmlXPathEvalExpression(
4188 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
4194 /* Empty embedded message */
4195 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4196 isds_printf_message(context
,
4197 _("XML document embedded into PKCS#7 structure is not "
4198 "sisds:dmReturnedMessage document"));
4202 /* More embedded messages */
4203 if (result
->nodesetval
->nodeNr
> 1) {
4204 isds_printf_message(context
,
4205 _("Embeded XML document into PKCS#7 structure has more "
4206 "root isds:dmReturnedMessage elements"));
4210 /* One embedded message */
4211 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4213 /* Extract the message */
4214 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
4215 if (err
) goto leave
;
4217 /* Append raw CMS structure into message */
4218 (*message
)->raw
= raw
;
4219 (*message
)->raw_length
= raw_length
;
4225 isds_message_free(message
);
4228 xmlFreeDoc(message_doc
);
4229 cms_data_free(xml_stream
);
4230 free(encoded_structure
);
4231 xmlXPathFreeObject(result
);
4232 xmlXPathFreeContext(xpath_ctx
);
4236 free(status_message
);
4237 xmlFreeDoc(response
);
4240 isds_log(ILF_ISDS
, ILL_DEBUG
,
4242 _("signedmessagedownload request processed by server "
4243 "successfully.\n") :
4244 _("signedmessagedownload request processed by server "
4252 /* Download signed incoming message identified by ID.
4253 * @context is session context
4254 * @message_id is message identifier (you can get them from
4255 * isds_get_list_of_received_messages())
4256 * @message is automatically reallocated message retrieved from ISDS. The raw
4257 * memeber will be filled with PKCS#7 structure in DER format. */
4258 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
4259 const char *message_id
, struct isds_message
**message
) {
4260 return isds_get_signed_message(context
, 0, message_id
, message
);
4264 /* Download signed outgoing message identified by ID.
4265 * @context is session context
4266 * @message_id is message identifier (you can get them from
4267 * isds_get_list_of_sent_messages())
4268 * @message is automatically reallocated message retrieved from ISDS. The raw
4269 * memeber will be filled with PKCS#7 structure in DER format. */
4270 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
4271 const char *message_id
, struct isds_message
**message
) {
4272 return isds_get_signed_message(context
, 1, message_id
, message
);
4276 /* Retrieve hash of message identified by ID stored in ISDS.
4277 * @context is session context
4278 * @message_id is message identifier
4279 * @hash is automatically reallocated message hash downloaded from ISDS.
4280 * Message must exist in system and must not be deleted. */
4281 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
4282 const char *message_id
, struct isds_hash
**hash
) {
4283 /* ???: XSD allows list of @message_id's and list of @message's, but
4284 * documentation talks only about `a message' */
4286 isds_error err
= IE_SUCCESS
;
4287 xmlDocPtr response
= NULL
;
4288 xmlChar
*code
= NULL
, *status_message
= NULL
;
4289 xmlXPathContextPtr xpath_ctx
= NULL
;
4290 xmlXPathObjectPtr result
= NULL
;
4292 if (!context
) return IE_INVALID_CONTEXT
;
4294 isds_hash_free(hash
);
4296 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
4297 BAD_CAST
"VerifyMessage", message_id
,
4298 &response
, &code
, &status_message
);
4299 if (err
) goto leave
;
4303 xpath_ctx
= xmlXPathNewContext(response
);
4308 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4312 result
= xmlXPathEvalExpression(
4313 BAD_CAST
"/isds:VerifyMessageResponse",
4319 /* Empty response */
4320 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4321 char *message_id_locale
= utf82locale((char*) message_id
);
4322 isds_printf_message(context
,
4323 _("Server did not return any response for ID `%s' "
4324 "on VerifyMessage request"), message_id_locale
);
4325 free(message_id_locale
);
4329 /* More responses */
4330 if (result
->nodesetval
->nodeNr
> 1) {
4331 char *message_id_locale
= utf82locale((char*) message_id
);
4332 isds_printf_message(context
,
4333 _("Server did return more responses for ID `%s' "
4334 "on VerifyMessage request"), message_id_locale
);
4335 free(message_id_locale
);
4340 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4342 /* Extract the hash */
4343 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
4347 isds_hash_free(hash
);
4350 xmlXPathFreeObject(result
);
4351 xmlXPathFreeContext(xpath_ctx
);
4354 free(status_message
);
4355 xmlFreeDoc(response
);
4358 isds_log(ILF_ISDS
, ILL_DEBUG
,
4359 _("VerifyMessage request processed by server "
4366 /* Mark message as read. This is a transactional commit function to acknoledge
4367 * to ISDS the message has been downloaded and processed by client properly.
4368 * @context is session context
4369 * @message_id is message identifier. */
4370 isds_error
isds_mark_message_read(struct isds_ctx
*context
,
4371 const char *message_id
) {
4372 /* ???: XSD allows list of @message_id's, but
4373 * documentation talks only about `a message' */
4375 isds_error err
= IE_SUCCESS
;
4376 xmlDocPtr response
= NULL
;
4377 xmlChar
*code
= NULL
, *status_message
= NULL
;
4379 if (!context
) return IE_INVALID_CONTEXT
;
4381 /* Do request and check for success */
4382 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
4383 BAD_CAST
"MarkMessageAsDownloaded", message_id
,
4384 &response
, &code
, &status_message
);
4387 free(status_message
);
4388 xmlFreeDoc(response
);
4391 isds_log(ILF_ISDS
, ILL_DEBUG
,
4392 _("MarkMessageAsDownloaded request processed by server "
4399 #undef INSERT_STRING_ATTRIBUTE
4400 #undef INSERT_ULONGINTNOPTR
4401 #undef INSERT_ULONGINT
4402 #undef INSERT_LONGINT
4403 #undef INSERT_BOOLEAN
4404 #undef INSERT_STRING
4405 #undef EXTRACT_STRING_ATTRIBUTE
4406 #undef EXTRACT_ULONGINT
4407 #undef EXTRACT_LONGINT
4408 #undef EXTRACT_BOOLEAN
4409 #undef EXTRACT_STRING
4412 /* Compute hash of message from raw representation and store it into envelope.
4413 * Original hash structure will be destroyed in envelope.
4414 * @context is session context
4415 * @message is message carrying raw XML message blob
4416 * @algorithm is desired hash algorithm to use */
4417 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
4418 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
4419 isds_error err
= IE_SUCCESS
;
4420 xmlDocPtr message_doc
= NULL
;
4421 xmlXPathContextPtr xpath_ctx
= NULL
;
4422 xmlXPathObjectPtr result
= NULL
;
4425 struct isds_hash
*new_hash
= NULL
;
4428 if (!context
) return IE_INVALID_CONTEXT
;
4429 if (!message
) return IE_INVAL
;
4431 if (!message
->raw
) {
4432 isds_log_message(context
,
4433 _("Message does not carry raw XML representation"));
4437 /* Parse raw message */
4438 message_doc
= xmlParseMemory(message
->raw
, message
->raw_length
);
4440 isds_log_message(context
,
4441 _("Message does not carry well-formed XML representation"));
4446 /* Find dmDM element */
4447 xpath_ctx
= xmlXPathNewContext(message_doc
);
4452 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4456 result
= xmlXPathEvalExpression(
4457 BAD_CAST
"/isds:dmReturnedMessage/isds:dmDm", xpath_ctx
);
4462 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4463 isds_log_message(context
,
4464 _("Raw message does not contain isds:dmDm element"));
4468 if (result
->nodesetval
->nodeNr
> 1) {
4469 isds_log_message(context
,
4470 _("Raw message contains more isds:dmDm elements"));
4474 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4476 /* XXX: We need all childern of isds:dmDm: elements, text nodes, PIs,
4477 * CDATA, comments. Is asterisk sufficient? */
4478 result
= xmlXPathEvalExpression(BAD_CAST
"*", xpath_ctx
);
4484 /* Extract dmDM content as bit stream */
4485 err
= dump_nodeset(context
, message_doc
, result
->nodesetval
,
4486 (void**) &buffer
, &length
);
4487 if (err
) goto leave
;
4490 xmlXPathFreeObject(result
); result
= NULL
;
4491 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
4492 xmlFreeDoc(message_doc
); message_doc
= NULL
;
4494 /* TODO: Compute hash */
4495 new_hash
= calloc(1, sizeof(*new_hash
));
4500 new_hash
->algorithm
= algorithm
;
4501 err
= compute_hash(buffer
, length
, new_hash
);
4503 isds_log_message(context
, _("Could not compute message hash"));
4507 /* Save cumputed hash */
4508 if (!message
->envelope
) {
4509 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
4510 if (!message
->envelope
) {
4515 isds_hash_free(&message
->envelope
->hash
);
4516 message
->envelope
->hash
= new_hash
;
4520 isds_hash_free(&new_hash
);
4524 xmlXPathFreeObject(result
);
4525 xmlXPathFreeContext(xpath_ctx
);
4526 xmlFreeDoc(message_doc
);
4531 /* Search for document by document ID in list of documents. IDs are compared
4533 * @documents is list of isds_documents
4534 * @id is document identifier
4535 * @return first matching document or NULL. */
4536 const struct isds_document
*isds_find_document_by_id(
4537 const struct isds_list
*documents
, const char *id
) {
4538 const struct isds_list
*item
;
4539 const struct isds_document
*document
;
4541 for (item
= documents
; item
; item
= item
->next
) {
4542 document
= (struct isds_document
*) item
->data
;
4543 if (!document
) continue;
4545 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
4553 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
4554 struct isds_message **message);
4555 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
4556 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
4557 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
4558 struct isds_address **address);
4560 int isds_message_free(struct isds_message **message);
4561 int isds_address_free(struct isds_address **address);
4565 /* Makes known all relevant namespaces to given XPath context
4566 * @xpat_ctx is XPath context
4567 * @message_ns selects propper message name space. Unsisnged and signed
4569 * prefix and to URI ISDS_NS */
4570 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
,
4571 const message_ns_type message_ns
) {
4572 const xmlChar
*message_namespace
= NULL
;
4574 if (!xpath_ctx
) return IE_ERROR
;
4576 switch(message_ns
) {
4577 case MESSAGE_NS_UNSIGNED
:
4578 message_namespace
= BAD_CAST ISDS_NS
; break;
4579 case MESSAGE_NS_SIGNED_INCOMING
:
4580 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
4581 case MESSAGE_NS_SIGNED_OUTGOING
:
4582 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
4587 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
4589 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
4591 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
4593 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))