1 #define _XOPEN_SOURCE 500 /* strdup from string.h, strptime from time.h */
11 #include "validator.h"
13 #include <gpg-error.h> /* Because of ksba or gpgme */
17 /* Free isds_list with all member data.
18 * @list list to free, on return will be NULL */
19 void isds_list_free(struct isds_list
**list
) {
20 struct isds_list
*item
, *next_item
;
22 if (!list
|| !*list
) return;
24 for(item
= *list
; item
; item
= next_item
) {
25 (item
->destructor
)(&(item
->data
));
26 next_item
= item
->next
;
34 /* Deallocate structure isds_hash and NULL it.
35 * @hash hash to to free */
36 void isds_hash_free(struct isds_hash
**hash
) {
37 if(!hash
|| !*hash
) return;
43 /* Deallocate structure isds_PersonName recursively and NULL it */
44 static void isds_PersonName_free(struct isds_PersonName
**person_name
) {
45 if (!person_name
|| !*person_name
) return;
47 free((*person_name
)->pnFirstName
);
48 free((*person_name
)->pnMiddleName
);
49 free((*person_name
)->pnLastName
);
50 free((*person_name
)->pnLastNameAtBirth
);
57 /* Deallocate structure isds_BirthInfo recursively and NULL it */
58 static void isds_BirthInfo_free(struct isds_BirthInfo
**birth_info
) {
59 if (!birth_info
|| !*birth_info
) return;
61 free((*birth_info
)->biDate
);
62 free((*birth_info
)->biCity
);
63 free((*birth_info
)->biCounty
);
64 free((*birth_info
)->biState
);
71 /* Deallocate structure isds_Address recursively and NULL it */
72 static void isds_Address_free(struct isds_Address
**address
) {
73 if (!address
|| !*address
) return;
75 free((*address
)->adCity
);
76 free((*address
)->adStreet
);
77 free((*address
)->adNumberInStreet
);
78 free((*address
)->adNumberInMunicipality
);
79 free((*address
)->adZipCode
);
80 free((*address
)->adState
);
87 /* Deallocate structure isds_DbOwnerInfo recursively and NULL it */
88 void isds_DbOwnerInfo_free(struct isds_DbOwnerInfo
**db_owner_info
) {
89 if (!db_owner_info
|| !*db_owner_info
) return;
91 free((*db_owner_info
)->dbID
);
92 free((*db_owner_info
)->dbType
);
93 free((*db_owner_info
)->ic
);
94 isds_PersonName_free(&((*db_owner_info
)->personName
));
95 free((*db_owner_info
)->firmName
);
96 isds_BirthInfo_free(&((*db_owner_info
)->birthInfo
));
97 isds_Address_free(&((*db_owner_info
)->address
));
98 free((*db_owner_info
)->nationality
);
99 free((*db_owner_info
)->email
);
100 free((*db_owner_info
)->telNumber
);
101 free((*db_owner_info
)->identifier
);
102 free((*db_owner_info
)->registryCode
);
103 free((*db_owner_info
)->dbState
);
104 free((*db_owner_info
)->dbEffectiveOVM
);
106 free(*db_owner_info
);
107 *db_owner_info
= NULL
;
110 /* Deallocate structure isds_DbUserInfo recursively and NULL it */
111 void isds_DbUserInfo_free(struct isds_DbUserInfo
**db_user_info
) {
112 if (!db_user_info
|| !*db_user_info
) return;
114 free((*db_user_info
)->userID
);
115 free((*db_user_info
)->userType
);
116 free((*db_user_info
)->userPrivils
);
117 isds_PersonName_free(&((*db_user_info
)->personName
));
118 isds_Address_free(&((*db_user_info
)->address
));
119 free((*db_user_info
)->biDate
);
120 free((*db_user_info
)->ic
);
121 free((*db_user_info
)->firmName
);
122 free((*db_user_info
)->caStreet
);
123 free((*db_user_info
)->caCity
);
124 free((*db_user_info
)->caZipCode
);
126 zfree(*db_user_info
);
130 /* Deallocate struct isds_event recursively and NULL it */
131 void isds_event_free(struct isds_event
**event
) {
132 if (!event
|| !*event
) return;
134 free((*event
)->time
);
135 free((*event
)->type
);
136 free((*event
)->description
);
141 /* Deallocate struct isds_envelope recursively and NULL it */
142 void isds_envelope_free(struct isds_envelope
**envelope
) {
143 if (!envelope
|| !*envelope
) return;
145 free((*envelope
)->dmID
);
146 free((*envelope
)->dbIDSender
);
147 free((*envelope
)->dmSender
);
148 free((*envelope
)->dmSenderAddress
);
149 free((*envelope
)->dmSenderType
);
150 free((*envelope
)->dmRecipient
);
151 free((*envelope
)->dmRecipientAddress
);
152 free((*envelope
)->dmAmbiguousRecipient
);
153 free((*envelope
)->dmType
);
155 free((*envelope
)->dmOrdinal
);
156 free((*envelope
)->dmMessageStatus
);
157 free((*envelope
)->dmDeliveryTime
);
158 free((*envelope
)->dmAcceptanceTime
);
159 isds_hash_free(&(*envelope
)->hash
);
160 free((*envelope
)->timestamp
);
161 isds_list_free(&(*envelope
)->events
);
163 free((*envelope
)->dmSenderOrgUnit
);
164 free((*envelope
)->dmSenderOrgUnitNum
);
165 free((*envelope
)->dbIDRecipient
);
166 free((*envelope
)->dmRecipientOrgUnit
);
167 free((*envelope
)->dmRecipientOrgUnitNum
);
168 free((*envelope
)->dmToHands
);
169 free((*envelope
)->dmAnnotation
);
170 free((*envelope
)->dmRecipientRefNumber
);
171 free((*envelope
)->dmSenderRefNumber
);
172 free((*envelope
)->dmRecipientIdent
);
173 free((*envelope
)->dmSenderIdent
);
175 free((*envelope
)->dmLegalTitleLaw
);
176 free((*envelope
)->dmLegalTitleYear
);
177 free((*envelope
)->dmLegalTitleSect
);
178 free((*envelope
)->dmLegalTitlePar
);
179 free((*envelope
)->dmLegalTitlePoint
);
181 free((*envelope
)->dmPersonalDelivery
);
182 free((*envelope
)->dmAllowSubstDelivery
);
183 free((*envelope
)->dmOVM
);
190 /* Deallocate struct isds_message recursively and NULL it */
191 void isds_message_free(struct isds_message
**message
) {
192 if (!message
|| !*message
) return;
194 free((*message
)->raw
);
195 isds_envelope_free(&((*message
)->envelope
));
196 isds_list_free(&((*message
)->documents
));
203 /* Deallocate struct isds_document recursively and NULL it */
204 void isds_document_free(struct isds_document
**document
) {
205 if (!document
|| !*document
) return;
207 free((*document
)->data
);
208 free((*document
)->dmMimeType
);
209 free((*document
)->dmFileGuid
);
210 free((*document
)->dmUpFileGuid
);
211 free((*document
)->dmFileDescr
);
212 free((*document
)->dmFormat
);
219 /* Deallocate struct isds_message_copy recursively and NULL it */
220 void isds_message_copy_free(struct isds_message_copy
**copy
) {
221 if (!copy
|| !*copy
) return;
223 free((*copy
)->dbIDRecipient
);
224 free((*copy
)->dmRecipientOrgUnit
);
225 free((*copy
)->dmRecipientOrgUnitNum
);
226 free((*copy
)->dmToHands
);
228 free((*copy
)->dmStatus
);
235 /* Initialize ISDS library.
236 * Global function, must be called before other functions.
237 * If it failes you can not use ISDS library and must call isds_cleanup() to
238 * free partially inititialized global variables. */
239 isds_error
isds_init(void) {
240 /* NULL global variables */
241 log_facilities
= ILF_ALL
;
242 log_level
= ILL_WARNING
;
245 /* Initialize gettext */
246 bindtextdomain(PACKAGE
, LOCALEDIR
);
249 /* Initialize CURL */
250 if (curl_global_init(CURL_GLOBAL_ALL
)) {
251 isds_log(ILF_ISDS
, ILL_CRIT
, _("CURL library initialization failed\n"));
255 /* Inicialize gpg-error because of gpgme and ksba */
256 if (gpg_err_init()) {
257 isds_log(ILF_ISDS
, ILL_CRIT
,
258 _("gpg-error library initialization failed\n"));
262 /* Initialize GPGME */
264 isds_log(ILF_ISDS
, ILL_CRIT
,
265 _("GPGME library initialization failed\n"));
269 /* Initialize gcrypt */
271 isds_log(ILF_ISDS
, ILL_CRIT
,
272 _("gcrypt library initialization failed\n"));
276 /* This can _exit() current program. Find not so assertive check. */
281 isds_log(ILF_ISDS
, ILL_CRIT
,
282 _("expat library initialization failed\n"));
286 /* Allocate global variables */
293 /* Deinicialize ISDS library.
294 * Global function, must be called as last library function. */
295 isds_error
isds_cleanup(void) {
300 curl_global_cleanup();
306 /* Return text description of ISDS error */
307 const char *isds_strerror(const isds_error error
) {
310 return(_("Success")); break;
312 return(_("Unspecified error")); break;
314 return(_("Not supported")); break;
316 return(_("Invalid value")); break;
317 case IE_INVALID_CONTEXT
:
318 return(_("Invalid context")); break;
319 case IE_NOT_LOGGED_IN
:
320 return(_("Not logged in")); break;
321 case IE_CONNECTION_CLOSED
:
322 return(_("Connection closed")); break;
324 return(_("Timed out")); break;
326 return(_("Not exist")); break;
328 return(_("Out of memory")); break;
330 return(_("Network problem")); break;
332 return(_("HTTP problem")); break;
334 return(_("SOAP problem")); break;
336 return(_("XML problem")); break;
338 return(_("ISDS server problem")); break;
340 return(_("Invalid enum value")); break;
342 return(_("Invalid date value")); break;
344 return(_("Too big")); break;
346 return(_("Value not unique")); break;
348 return(_("Values not uqual")); break;
349 case IE_PARTIAL_SUCCESS
:
350 return(_("Some suboperations failed")); break;
352 return(_("Unknown error"));
357 /* Create ISDS context.
358 * Each context can be used for different sessions to (possibly) differnet
359 * ISDS server with different credentials. */
360 struct isds_ctx
*isds_ctx_create(void) {
361 struct isds_ctx
*context
;
362 context
= malloc(sizeof(*context
));
363 if (context
) memset(context
, 0, sizeof(*context
));
368 /* Destroy ISDS context and free memmory.
369 * @context will be NULLed on success. */
370 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
371 if (!context
|| !*context
) {
372 return IE_INVALID_CONTEXT
;
375 /* Discard credentials */
376 isds_logout(*context
);
378 /* Free other structures */
379 free((*context
)->tls_verify_server
);
380 free((*context
)->tls_ca_file
);
381 free((*context
)->tls_ca_dir
);
382 free((*context
)->long_message
);
390 /* Return long message text produced by library fucntion, e.g. detailed error
391 * mesage. Returned pointer is only valid until new library function is
392 * called for the same context. Could be NULL, especially if NULL context is
393 * supplied. Return string is locale encoded. */
394 char *isds_long_message(const struct isds_ctx
*context
) {
395 if (!context
) return NULL
;
396 return context
->long_message
;
400 /* Stores message into context' long_message buffer.
401 * Application can pick the message up using isds_long_message().
402 * NULL @message truncates the buffer but does not deallocate it.
403 * @message is coded in locale encoding */
404 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
405 const char *message
) {
409 if (!context
) return IE_INVALID_CONTEXT
;
411 /* FIXME: Check for integer overflow */
412 length
= 1 + ((message
) ? strlen(message
) : 0);
413 buffer
= realloc(context
->long_message
, length
);
414 if (!buffer
) return IE_NOMEM
;
417 strcpy(buffer
, message
);
421 context
->long_message
= buffer
;
426 /* Appends message into context' long_message buffer.
427 * Application can pick the message up using isds_long_message().
428 * NULL message has void effect. */
429 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
430 const char *message
) {
432 size_t old_length
, length
;
434 if (!context
) return IE_INVALID_CONTEXT
;
435 if (!message
) return IE_SUCCESS
;
436 if (!context
->long_message
)
437 return isds_log_message(context
, message
);
439 old_length
= strlen(context
->long_message
);
440 /* FIXME: Check for integer overflow */
441 length
= 1 + old_length
+ strlen(message
);
442 buffer
= realloc(context
->long_message
, length
);
443 if (!buffer
) return IE_NOMEM
;
445 strcpy(buffer
+ old_length
, message
);
447 context
->long_message
= buffer
;
452 /* Stores formated message into context' long_message buffer.
453 * Application can pick the message up using isds_long_message(). */
454 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
455 const char *format
, ...) {
459 if (!context
) return IE_INVALID_CONTEXT
;
460 va_start(ap
, format
);
461 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
464 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
469 * @facilities is bitmask of isds_log_facility values,
470 * @level is verbosity level. */
471 void isds_set_logging(const unsigned int facilities
,
472 const isds_log_level level
) {
473 log_facilities
= facilities
;
478 /* Log @message in class @facility with log @level into global log. @message
479 * is printf(3) formating string, variadic arguments may be neccessary.
480 * For debugging purposes. */
481 _hidden isds_error
isds_log(const isds_log_facility facility
,
482 const isds_log_level level
, const char *message
, ...) {
485 if (level
> log_level
) return IE_SUCCESS
;
486 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
487 if (!message
) return IE_INVAL
;
489 /* TODO: Allow to register output function provided by application
490 * (e.g. fprintf to stderr or copy to text area GUI widget). */
492 va_start(ap
, message
);
493 vfprintf(stderr
, message
, ap
);
495 /* Line buffered printf is default.
502 /* Set timeout in miliseconds for each network job like connecting to server
503 * or sending message. Use 0 to disable timeout limits. */
504 isds_error
isds_set_timeout(struct isds_ctx
*context
,
505 const unsigned int timeout
) {
506 if (!context
) return IE_INVALID_CONTEXT
;
508 context
->timeout
= timeout
;
513 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
515 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
517 if (curl_err
) return IE_ERROR
;
524 /* Register callback function libisds calls periodocally during HTTP data
526 * @context is session context
527 * @callback is function provided by application libsds will call. See type
528 * defition for @callback argument explanation.
529 * @data is application specific data @callback gets as last argument */
530 isds_error
isds_set_progress_callback(struct isds_ctx
*context
,
531 isds_progress_callback callback
, void *data
) {
532 if (!context
) return IE_INVALID_CONTEXT
;
534 context
->progress_callback
= callback
;
535 context
->progress_callback_data
= data
;
541 /* Change SSL/TLS settings.
542 * @context is context which setting will be applied to
543 * @option is name of option. It determines the type of last argument. See
544 * isds_tls_option definition for more info.
545 * @... is value of new setting. Type is determined by @option
547 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
549 isds_error err
= IE_SUCCESS
;
551 char *pointer
, *string
;
553 if (!context
) return IE_INVALID_CONTEXT
;
555 va_start(ap
, option
);
557 #define REPLACE_VA_STRING(destination) \
558 string = va_arg(ap, char *); \
560 pointer = realloc((destination), 1 + strlen(string)); \
561 if (!pointer) { err = IE_NOMEM; goto leave; } \
562 strcpy(pointer, string); \
563 (destination) = pointer; \
566 (destination) = NULL; \
570 case ITLS_VERIFY_SERVER
:
571 if (!context
->tls_verify_server
) {
572 context
->tls_verify_server
=
573 malloc(sizeof(*context
->tls_verify_server
));
574 if (!context
->tls_verify_server
) {
575 err
= IE_NOMEM
; goto leave
;
578 *context
->tls_verify_server
= (_Bool
) (0 != va_arg(ap
, int));
582 REPLACE_VA_STRING(context
->tls_ca_file
);
584 case ITLS_CA_DIRECTORY
:
585 REPLACE_VA_STRING(context
->tls_ca_dir
);
589 err
= IE_ENUM
; goto leave
;
592 #undef REPLACE_VA_STRING
600 /* Discard credentials.
601 * Only that. It does not cause log out, connection close or similar. */
602 static isds_error
discard_credentials(struct isds_ctx
*context
) {
603 if(!context
) return IE_INVALID_CONTEXT
;
605 if (context
->username
) {
606 memset(context
->username
, 0, strlen(context
->username
));
607 free(context
->username
);
608 context
->username
= NULL
;
610 if (context
->password
) {
611 memset(context
->password
, 0, strlen(context
->password
));
612 free(context
->password
);
613 context
->password
= NULL
;
620 /* Connect and log in into ISDS server.
621 * @url is address of ISDS web service
622 * @username is user name of ISDS user
623 * @password is user's secret password
624 * @certificate is NULL terminated string with PEM formated client's
625 * certificate. Use NULL if only password autentication should be performed.
626 * @key is private key for client's certificate as (base64 encoded?) NULL
627 * terminated string. Use NULL if only password autentication is desired.
629 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
630 const char *username
, const char *password
,
631 const char *certificate
, const char* key
) {
632 isds_error err
= IE_NOT_LOGGED_IN
;
634 xmlNsPtr isds_ns
= NULL
;
635 xmlNodePtr request
= NULL
;
636 xmlNodePtr response
= NULL
;
638 if (!context
) return IE_INVALID_CONTEXT
;
639 if (!url
|| !username
|| !password
) return IE_INVAL
;
640 if (certificate
|| key
) return IE_NOTSUP
;
642 /* Store configuration */
644 context
->url
= strdup(url
);
648 /* Close connection if already logged in */
650 close_connection(context
);
653 /* Prepare CURL handle */
654 context
->curl
= curl_easy_init();
655 if (!(context
->curl
))
658 /* Build login request */
659 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
661 isds_log_message(context
, _("Could build ISDS login request"));
664 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
666 isds_log_message(context
, _("Could not create ISDS name space"));
667 xmlFreeNode(request
);
670 xmlSetNs(request
, isds_ns
);
672 /* Store credentials */
673 /* FIXME: mlock password
674 * (I have a library) */
675 discard_credentials(context
);
676 context
->username
= strdup(username
);
677 context
->password
= strdup(password
);
678 if (!(context
->username
&& context
->password
)) {
679 discard_credentials(context
);
680 xmlFreeNode(request
);
684 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
687 /* Send login request */
688 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
690 /* Remove credentials */
691 discard_credentials(context
);
693 /* Destroy login request */
694 xmlFreeNode(request
);
697 xmlFreeNodeList(response
);
698 close_connection(context
);
702 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
703 * authentication succeeded if soap_err == IE_SUCCESS */
706 xmlFreeNodeList(response
);
709 isds_log(ILF_ISDS
, ILL_DEBUG
,
710 _("User %s has been logged into server %s successfully\n"),
716 /* Log out from ISDS server discards credentials and connection configuration. */
717 isds_error
isds_logout(struct isds_ctx
*context
) {
718 if (!context
) return IE_INVALID_CONTEXT
;
720 /* Close connection */
722 close_connection(context
);
724 /* Discard credentials for sure. They should not survive isds_login(),
725 * even successful .*/
726 discard_credentials(context
);
730 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
732 discard_credentials(context
);
738 /* Verify connection to ISDS is alive and server is responding.
739 * Sent dumy request to ISDS and expect dummy response. */
740 isds_error
isds_ping(struct isds_ctx
*context
) {
742 xmlNsPtr isds_ns
= NULL
;
743 xmlNodePtr request
= NULL
;
744 xmlNodePtr response
= NULL
;
746 if (!context
) return IE_INVALID_CONTEXT
;
748 /* Check if connection is established */
749 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
752 /* Build dummy request */
753 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
755 isds_log_message(context
, _("Could build ISDS dummy request"));
758 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
760 isds_log_message(context
, _("Could not create ISDS name space"));
761 xmlFreeNode(request
);
764 xmlSetNs(request
, isds_ns
);
766 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
768 /* Sent dummy request */
769 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
771 /* Destroy login request */
772 xmlFreeNode(request
);
775 isds_log(ILF_ISDS
, ILL_DEBUG
,
776 _("ISDS server could not be contacted\n"));
777 xmlFreeNodeList(response
);
778 close_connection(context
);
782 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
783 * authentication succeeded if soap_err == IE_SUCCESS */
784 /* TODO: ISDS documentation does not specify response body.
785 * However real server sends back DummyOperationResponse */
788 xmlFreeNodeList(response
);
790 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
796 /* Send bogus request to ISDS.
797 * Just for test purposes */
798 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
800 xmlNsPtr isds_ns
= NULL
;
801 xmlNodePtr request
= NULL
;
802 xmlDocPtr response
= NULL
;
803 xmlChar
*code
= NULL
, *message
= NULL
;
805 if (!context
) return IE_INVALID_CONTEXT
;
807 /* Check if connection is established */
808 if (!context
->curl
) {
809 /* Testing printf message */
810 isds_printf_message(context
, "%s", _("I said connection closed"));
811 return IE_CONNECTION_CLOSED
;
815 /* Build dummy request */
816 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
818 isds_log_message(context
, _("Could build ISDS bogus request"));
821 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
823 isds_log_message(context
, _("Could not create ISDS name space"));
824 xmlFreeNode(request
);
827 xmlSetNs(request
, isds_ns
);
829 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
831 /* Sent bogus request */
832 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
834 /* Destroy request */
835 xmlFreeNode(request
);
838 isds_log(ILF_ISDS
, ILL_DEBUG
,
839 _("Processing ISDS response on bogus request failed\n"));
840 xmlFreeDoc(response
);
844 /* Check for response status */
845 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
846 &code
, &message
, NULL
);
848 isds_log(ILF_ISDS
, ILL_DEBUG
,
849 _("ISDS response on bogus request is missing status\n"));
852 xmlFreeDoc(response
);
855 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
856 char *code_locale
= utf82locale((char*)code
);
857 char *message_locale
= utf82locale((char*)message
);
858 isds_log(ILF_ISDS
, ILL_DEBUG
,
859 _("Server refused bogus request (code=%s, message=%s)\n"),
860 code_locale
, message_locale
);
861 /* XXX: Literal error messages from ISDS are Czech mesages
862 * (English sometimes) in UTF-8. It's hard to catch them for
863 * translation. Successfully gettextized would return in locale
864 * encoding, unsuccessfully translated would pass in UTF-8. */
865 isds_log_message(context
, message_locale
);
867 free(message_locale
);
870 xmlFreeDoc(response
);
877 xmlFreeDoc(response
);
879 isds_log(ILF_ISDS
, ILL_DEBUG
,
880 _("Bogus message accepted by server. This should not happen.\n"));
886 /* Serialize XML subtree to buffer preserving XML indentatition.
887 * @context is session context
888 * @subtree is XML element to be serialized (with childern)
889 * @buffer is automatically reallocated buffer where serialize to
890 * @length is size of serialized stream in bytes
891 * @return standard error code, free @buffer in case of error */
892 static isds_error
serialize_subtree(struct isds_ctx
*context
,
893 xmlNodePtr subtree
, void **buffer
, size_t *length
) {
894 isds_error err
= IE_SUCCESS
;
895 xmlBufferPtr xml_buffer
= NULL
;
896 xmlSaveCtxtPtr save_ctx
= NULL
;
897 xmlDocPtr subtree_doc
= NULL
;
898 xmlNodePtr subtree_copy
;
902 if (!context
) return IE_INVALID_CONTEXT
;
903 if (!buffer
) return IE_INVAL
;
905 if (!subtree
|| !length
) return IE_INVAL
;
907 /* Make temporary XML document with @subtree root element */
908 /* XXX: We can not use xmlNodeDump() because it dumps the subtree as is.
909 * It can result in not well-formed on invalid XML tree (e.g. name space
910 * prefix definition can miss. */
913 subtree_doc
= xmlNewDoc(BAD_CAST
"1.0");
915 isds_log_message(context
, _("Could not build temporary document"));
920 /* XXX: Copy subtree and attach the copy to document.
921 * One node can not bee attached into more document at the same time.
922 * XXX: Check xmlDOMWrapRemoveNode(). It could solve NS references
924 * XXX: Check xmlSaveTree() too. */
925 subtree_copy
= xmlCopyNodeList(subtree
);
927 isds_log_message(context
, _("Could not copy subtree"));
931 xmlDocSetRootElement(subtree_doc
, subtree_copy
);
933 /* Only this way we get namespace definition as @xmlns:isds,
934 * otherwise we get namespace prefix without definition */
935 /* FIXME: Don't overwrite original default namespace */
936 isds_ns
= xmlNewNs(subtree_copy
, BAD_CAST ISDS_NS
, NULL
);
938 isds_log_message(context
, _("Could not create ISDS name space"));
942 xmlSetNs(subtree_copy
, isds_ns
);
945 /* Serialize the document into buffer */
946 xml_buffer
= xmlBufferCreate();
948 isds_log_message(context
, _("Could not create xmlBuffer"));
952 /* Last argument 0 means to not format the XML tree */
953 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8", 0);
955 isds_log_message(context
, _("Could not create XML serializer"));
959 /* XXX: According LibXML documentation, this function does not return
960 * meaningfull value yet */
961 xmlSaveDoc(save_ctx
, subtree_doc
);
962 if (-1 == xmlSaveFlush(save_ctx
)) {
963 isds_log_message(context
,
964 _("Could not serialize XML subtree"));
968 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
969 * even after xmlSaveFlush(). Thus close it here */
970 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
973 /* Store and detach buffer from xml_buffer */
974 *buffer
= xml_buffer
->content
;
975 *length
= xml_buffer
->use
;
976 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
979 new_buffer
= realloc(*buffer
, *length
);
980 if (new_buffer
) *buffer
= new_buffer
;
988 xmlSaveClose(save_ctx
);
989 xmlBufferFree(xml_buffer
);
990 xmlFreeDoc(subtree_doc
); /* Frees subtree_copy, isds_ns etc. */
995 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
996 * @context is session context
997 * @document is original document where @nodeset points to
998 * @nodeset is XPath node set to dump (recursively)
999 * @buffer is automarically reallocated buffer where serialize to
1000 * @length is size of serialized stream in bytes
1001 * @return standard error code, free @buffer in case of error */
1002 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1003 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1004 void **buffer
, size_t *length
) {
1005 isds_error err
= IE_SUCCESS
;
1006 xmlBufferPtr xml_buffer
= NULL
;
1009 if (!context
) return IE_INVALID_CONTEXT
;
1010 if (!buffer
) return IE_INVAL
;
1012 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1015 /* Empty node set results into NULL buffer */
1016 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1020 /* Resuling the document into buffer */
1021 xml_buffer
= xmlBufferCreate();
1023 isds_log_message(context
, _("Could not create xmlBuffer"));
1028 /* Itearate over all nodes */
1029 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1031 * XXX: xmlNodeDump() appends to xml_buffer. */
1033 xmlNodeDump(xml_buffer
, document
, nodeset
->nodeTab
[i
], 0, 0)) {
1034 isds_log_message(context
, _("Could not dump XML node"));
1040 /* Store and detach buffer from xml_buffer */
1041 *buffer
= xml_buffer
->content
;
1042 *length
= xml_buffer
->use
;
1043 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1046 new_buffer
= realloc(*buffer
, *length
);
1047 if (new_buffer
) *buffer
= new_buffer
;
1056 xmlBufferFree(xml_buffer
);
1062 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1063 * @context is session context
1064 * @document is original document where @nodeset points to
1065 * @nodeset is XPath node set to dump (recursively)
1066 * @buffer is automarically reallocated buffer where serialize to
1067 * @length is size of serialized stream in bytes
1068 * @return standard error code, free @buffer in case of error */
1069 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1070 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1071 void **buffer
, size_t *length
) {
1072 isds_error err
= IE_SUCCESS
;
1073 xmlBufferPtr xml_buffer
= NULL
;
1074 xmlSaveCtxtPtr save_ctx
= NULL
;
1077 if (!context
) return IE_INVALID_CONTEXT
;
1078 if (!buffer
) return IE_INVAL
;
1080 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1083 /* Empty node set results into NULL buffer */
1084 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1088 /* Resuling the document into buffer */
1089 xml_buffer
= xmlBufferCreate();
1091 isds_log_message(context
, _("Could not create xmlBuffer"));
1095 if (xmlSubstituteEntitiesDefault(1)) {
1096 isds_log_message(context
, _("Could not disable attribute escaping"));
1100 /* Last argument means:
1101 * 0 to not format the XML tree
1102 * XML_SAVE_NO_EMPTY ISDS does not produce shorten tags */
1103 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8",
1104 XML_SAVE_NO_DECL
|XML_SAVE_NO_EMPTY
|XML_SAVE_NO_XHTML
);
1106 isds_log_message(context
, _("Could not create XML serializer"));
1110 /*if (xmlSaveSetAttrEscape(save_ctx, NULL)) {
1111 isds_log_message(context, _("Could not disable attribute escaping"));
1117 /* Itearate over all nodes */
1118 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1120 * XXX: xmlNodeDump() appends to xml_buffer. */
1122 xmlNodeDump(xml_buffer, document, nodeset->nodeTab[i], 0, 0)) {
1124 /* XXX: According LibXML documentation, this function does not return
1125 * meaningfull value yet */
1126 xmlSaveTree(save_ctx
, nodeset
->nodeTab
[i
]);
1127 if (-1 == xmlSaveFlush(save_ctx
)) {
1128 isds_log_message(context
,
1129 _("Could not serialize XML subtree"));
1135 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1136 * even after xmlSaveFlush(). Thus close it here */
1137 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1139 /* Store and detach buffer from xml_buffer */
1140 *buffer
= xml_buffer
->content
;
1141 *length
= xml_buffer
->use
;
1142 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1145 new_buffer
= realloc(*buffer
, *length
);
1146 if (new_buffer
) *buffer
= new_buffer
;
1154 xmlSaveClose(save_ctx
);
1155 xmlBufferFree(xml_buffer
);
1161 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
1162 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
1163 if (!string
|| !type
) return IE_INVAL
;
1165 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
1167 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
1169 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
1170 *type
= DBTYPE_PFO_ADVOK
;
1171 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
1172 *type
= DBTYPE_PFO_DANPOR
;
1173 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
1174 *type
= DBTYPE_PFO_INSSPR
;
1175 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
1177 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
1178 *type
= DBTYPE_PO_ZAK
;
1179 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
1180 *type
= DBTYPE_PO_REQ
;
1181 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
1183 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
1184 *type
= DBTYPE_OVM_NOTAR
;
1185 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
1186 *type
= DBTYPE_OVM_EXEKUT
;
1187 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
1188 *type
= DBTYPE_OVM_REQ
;
1195 /* Convert ISDS dbType enum @type to UTF-8 string.
1196 * @Return pointer to static string, or NULL if unkwnow enum value */
1197 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
1199 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
1200 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
1201 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
1202 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DANPOR"); break;
1203 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
1204 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
1205 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
1206 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
1207 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
1208 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
1209 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
1210 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
1211 default: return NULL
; break;
1216 /* Convert UTF-8 @string represantion of ISDS userType to enum @type */
1217 static isds_error
string2isds_UserType(xmlChar
*string
, isds_UserType
*type
) {
1218 if (!string
|| !type
) return IE_INVAL
;
1220 if (!xmlStrcmp(string
, BAD_CAST
"PRIMARY_USER"))
1221 *type
= USERTYPE_PRIMARY
;
1222 else if (!xmlStrcmp(string
, BAD_CAST
"ENTRUSTED_USER"))
1223 *type
= USERTYPE_ENTRUSTED
;
1224 else if (!xmlStrcmp(string
, BAD_CAST
"ADMINISTRATOR"))
1225 *type
= USERTYPE_ADMINISTRATOR
;
1226 else if (!xmlStrcmp(string
, BAD_CAST
"OFFICIAL"))
1227 *type
= USERTYPE_OFFICIAL
;
1233 #if 0 /* Not yet used */
1234 /* Convert ISDS userType enum @type to UTF-8 string.
1235 * @Return pointer to static string, or NULL if unkwnow enum value */
1236 static const xmlChar
*isds_UserType2string(const isds_UserType type
) {
1238 case USERTYPE_PRIMARY
: return(BAD_CAST
"PRIMARY_USER"); break;
1239 case USERTYPE_ENTRUSTED
: return(BAD_CAST
"ENTRUSTED_USER"); break;
1240 case USERTYPE_ADMINISTRATOR
: return(BAD_CAST
"ADMINISTRATOR"); break;
1241 case USERTYPE_OFFICIAL
: return(BAD_CAST
"OFFICIAL"); break;
1242 default: return NULL
; break;
1248 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
1249 * @Return pointer to static string, or NULL if unkwnow enum value */
1250 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
1252 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
1253 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
1254 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
1255 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
1256 default: return NULL
; break;
1261 /* Convert UTF-8 @string to ISDS dmFileMetaType enum @type.
1262 * @Return IE_ENUM if @string is not valid enum member */
1263 static isds_error
string2isds_FileMetaType(const xmlChar
*string
,
1264 isds_FileMetaType
*type
) {
1265 if (!string
|| !type
) return IE_INVAL
;
1267 if (!xmlStrcmp(string
, BAD_CAST
"main"))
1268 *type
= FILEMETATYPE_MAIN
;
1269 else if (!xmlStrcmp(string
, BAD_CAST
"enclosure"))
1270 *type
= FILEMETATYPE_ENCLOSURE
;
1271 else if (!xmlStrcmp(string
, BAD_CAST
"signature"))
1272 *type
= FILEMETATYPE_SIGNATURE
;
1273 else if (!xmlStrcmp(string
, BAD_CAST
"meta"))
1274 *type
= FILEMETATYPE_META
;
1281 /* Convert UTF-8 @string to ISDS hash @algorithm.
1282 * @Return IE_ENUM if @string is not valid enum member */
1283 static isds_error
string2isds_hash_algorithm(const xmlChar
*string
,
1284 isds_hash_algorithm
*algorithm
) {
1285 if (!string
|| !algorithm
) return IE_INVAL
;
1287 if (!xmlStrcmp(string
, BAD_CAST
"MD5"))
1288 *algorithm
= HASH_ALGORITHM_MD5
;
1289 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-1"))
1290 *algorithm
= HASH_ALGORITHM_SHA_1
;
1291 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-256"))
1292 *algorithm
= HASH_ALGORITHM_SHA_256
;
1293 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-512"))
1294 *algorithm
= HASH_ALGORITHM_SHA_512
;
1301 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
1302 * XXX: Not all ISO formats are supported */
1303 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
1305 if (!string
|| !time
) return IE_INVAL
;
1307 /* xsd:date is ISO 8601 string, thus ASCII */
1308 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
1309 if (offset
&& *offset
== '\0')
1312 offset
= strptime((char*)string
, "%Y%m%d", time
);
1313 if (offset
&& *offset
== '\0')
1316 offset
= strptime((char*)string
, "%Y-%j", time
);
1317 if (offset
&& *offset
== '\0')
1324 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
1325 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
1326 if (!time
|| !string
) return IE_INVAL
;
1328 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
1329 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
1336 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
1337 * respects the @time microseconds too. */
1338 static isds_error
timeval2timestring(const struct timeval
*time
,
1342 if (!time
|| !string
) return IE_INVAL
;
1344 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
1345 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
1347 /* TODO: small negative year should be formated as "-0012". This is not
1348 * true for glibc "%04d". We should implement it.
1349 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
1350 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
1351 if (-1 == isds_asprintf((char **) string
,
1352 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
1353 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
1354 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
1362 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
1363 * It respects microseconds too.
1364 * In case of error, @time will be freed. */
1365 static isds_error
timestring2timeval(const xmlChar
*string
,
1366 struct timeval
**time
) {
1368 char *offset
, *delim
, *endptr
;
1370 int offset_hours
, offset_minutes
;
1373 if (!time
) return IE_INVAL
;
1375 memset(&broken
, 0, sizeof(broken
));
1378 *time
= calloc(1, sizeof(**time
));
1379 if (!*time
) return IE_NOMEM
;
1381 memset(*time
, 0, sizeof(**time
));
1385 /* xsd:date is ISO 8601 string, thus ASCII */
1386 /*TODO: negative year */
1388 /* Parse date and time without subseconds and offset */
1389 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
1391 free(*time
); *time
= NULL
;
1395 /* Get subseconds */
1396 if (*offset
== '.' ) {
1399 /* Copy first 6 digits, padd it with zeros.
1400 * XXX: It truncates longer number, no round.
1401 * Current server implementation uses only milisecond resolution. */
1402 /* TODO: isdigit() is locale sensitive */
1404 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
1406 subseconds
[i
] = *offset
;
1408 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
1409 subseconds
[i
] = '0';
1411 subseconds
[6] = '\0';
1413 /* Convert it into integer */
1414 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
1415 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
1416 (*time
)->tv_usec
== LONG_MAX
) {
1417 free(*time
); *time
= NULL
;
1421 /* move to the zone offset delimiter */
1422 delim
= strchr(offset
, '-');
1424 delim
= strchr(offset
, '+');
1428 /* Get zone offset */
1429 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
1430 * "" equals to "Z" and it means UTC zone. */
1431 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
1432 * colon separator */
1433 if (*offset
== '-' || *offset
== '+') {
1435 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
1436 free(*time
); *time
= NULL
;
1439 broken
.tm_hour
-= offset_hours
;
1440 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
1443 /* Convert to time_t */
1445 (*time
)->tv_sec
= mktime(&broken
);
1446 switch_tz_to_native();
1447 if ((*time
)->tv_sec
== (time_t) -1) {
1448 free(*time
); *time
= NULL
;
1456 /* Convert unsigned int into isds_message_status.
1457 * @context is session context
1458 * @number is pointer to number value. NULL will be treated as invalid value.
1459 * @status is automatically reallocated status
1460 * @return IE_SUCCESS, or error code and free status */
1461 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1462 const unsigned long int *number
, isds_message_status
**status
) {
1463 if (!context
) return IE_INVALID_CONTEXT
;
1464 if (!status
) return IE_INVAL
;
1466 free(*status
); *status
= NULL
;
1467 if (!number
) return IE_INVAL
;
1469 if (*number
< 1 || *number
> 10) {
1470 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1475 *status
= malloc(sizeof(**status
));
1476 if (!*status
) return IE_NOMEM
;
1478 **status
= 1 << *number
;
1483 /* Convert event description string into isds_event memebers type and
1485 * @string is raw event decsription starting with event prefix
1486 * @event is structure where to store type and stripped description to
1487 * @return standard error code, unkown prefix is not classified as an error. */
1488 static isds_error
eventstring2event(const xmlChar
*string
,
1489 struct isds_event
* event
) {
1490 const xmlChar
*known_prefixes
[] = {
1496 const isds_event_type types
[] = {
1497 EVENT_ACCEPTED_BY_RECIPIENT
,
1498 EVENT_ACCEPTED_BY_FICTION
,
1499 EVENT_UNDELIVERABLE
,
1500 EVENT_COMMERCIAL_ACCEPTED
1505 if (!string
|| !event
) return IE_INVAL
;
1508 event
->type
= malloc(sizeof(*event
->type
));
1509 if (!(event
->type
)) return IE_NOMEM
;
1511 zfree(event
->description
);
1513 for (index
= 0; index
< sizeof(known_prefixes
)/sizeof(known_prefixes
[0]);
1515 length
= xmlUTF8Strlen(known_prefixes
[index
]);
1517 if (!xmlStrncmp(string
, known_prefixes
[index
], length
)) {
1518 /* Prefix is known */
1519 *event
->type
= types
[index
];
1521 /* Strip prefix from description and spaces */
1522 /* TODO: Recognize all wite spaces from UCS blank class and
1523 * operate on UTF-8 chars. */
1524 for (; string
[length
] != '\0' && string
[length
] == ' '; length
++);
1525 event
->description
= strdup((char *) (string
+ length
));
1526 if (!(event
->description
)) return IE_NOMEM
;
1532 /* Unknown event prefix.
1533 * XSD allows any string */
1534 char *string_locale
= utf82locale((char *) string
);
1535 isds_log(ILF_ISDS
, ILL_WARNING
,
1536 _("Uknown delivery info event prefix: %s\n"), string_locale
);
1537 free(string_locale
);
1539 *event
->type
= EVENT_UKNOWN
;
1540 event
->description
= strdup((char *) string
);
1541 if (!(event
->description
)) return IE_NOMEM
;
1547 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1548 * and leave lable */
1549 #define EXTRACT_STRING(element, string) \
1550 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
1555 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
1556 if (result->nodesetval->nodeNr > 1) { \
1557 isds_printf_message(context, _("Multiple %s element"), element); \
1561 (string) = (char *) \
1562 xmlXPathCastNodeSetToString(result->nodesetval); \
1569 #define EXTRACT_BOOLEAN(element, booleanPtr) \
1571 char *string = NULL; \
1572 EXTRACT_STRING(element, string); \
1575 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
1576 if (!(booleanPtr)) { \
1582 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
1583 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
1584 *(booleanPtr) = 1; \
1585 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
1586 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
1587 *(booleanPtr) = 0; \
1589 char *string_locale = utf82locale((char*)string); \
1590 isds_printf_message(context, \
1591 _("%s value is not valid boolean: "), \
1592 element, string_locale); \
1593 free(string_locale); \
1603 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
1605 char *string = NULL; \
1606 EXTRACT_STRING(element, string); \
1611 number = strtol((char*)string, &endptr, 10); \
1613 if (*endptr != '\0') { \
1614 char *string_locale = utf82locale((char *)string); \
1615 isds_printf_message(context, \
1616 _("%s is not valid integer: %s"), \
1617 element, string_locale); \
1618 free(string_locale); \
1624 if (number == LONG_MIN || number == LONG_MAX) { \
1625 char *string_locale = utf82locale((char *)string); \
1626 isds_printf_message(context, \
1627 _("%s value out of range of long int: %s"), \
1628 element, string_locale); \
1629 free(string_locale); \
1635 free(string); string = NULL; \
1637 if (!(preallocated)) { \
1638 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
1639 if (!(longintPtr)) { \
1644 *(longintPtr) = number; \
1648 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
1650 char *string = NULL; \
1651 EXTRACT_STRING(element, string); \
1656 number = strtol((char*)string, &endptr, 10); \
1658 if (*endptr != '\0') { \
1659 char *string_locale = utf82locale((char *)string); \
1660 isds_printf_message(context, \
1661 _("%s is not valid integer: %s"), \
1662 element, string_locale); \
1663 free(string_locale); \
1669 if (number == LONG_MIN || number == LONG_MAX) { \
1670 char *string_locale = utf82locale((char *)string); \
1671 isds_printf_message(context, \
1672 _("%s value out of range of long int: %s"), \
1673 element, string_locale); \
1674 free(string_locale); \
1680 free(string); string = NULL; \
1682 isds_printf_message(context, \
1683 _("%s value is negative: %ld"), element, number); \
1688 if (!(preallocated)) { \
1689 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
1690 if (!(ulongintPtr)) { \
1695 *(ulongintPtr) = number; \
1699 #define EXTRACT_STRING_ATTRIBUTE(attribute, string, required) \
1700 (string) = (char *) xmlGetNsProp(xpath_ctx->node, ( BAD_CAST attribute), \
1702 if ((required) && (!string)) { \
1703 char *attribute_locale = utf82locale(attribute); \
1704 char *element_locale = utf82locale((char *)xpath_ctx->node->name); \
1705 isds_printf_message(context, \
1706 _("Could not extract required %s attribute value from " \
1707 "%s element"), attribute_locale, element_locale); \
1708 free(element_locale); \
1709 free(attribute_locale); \
1715 #define INSERT_STRING(parent, element, string) \
1716 node = xmlNewTextChild(parent, NULL, BAD_CAST (element), \
1717 (xmlChar *) (string)); \
1719 isds_printf_message(context, \
1720 _("Could not add %s child to %s element"), \
1721 element, (parent)->name); \
1726 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
1727 if ((booleanPtr)) { \
1728 if (*(booleanPtr)) { INSERT_STRING(parent, element, "true"); } \
1729 else { INSERT_STRING(parent, element, "false") } \
1730 } else { INSERT_STRING(parent, element, NULL) }
1732 #define INSERT_LONGINT(parent, element, longintPtr, buffer) \
1733 if ((longintPtr)) { \
1734 /* FIXME: locale sensitive */ \
1735 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
1739 INSERT_STRING(parent, element, buffer) \
1740 free(buffer); (buffer) = NULL; \
1741 } else { INSERT_STRING(parent, element, NULL) }
1743 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) \
1744 if ((ulongintPtr)) { \
1745 /* FIXME: locale sensitive */ \
1746 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
1750 INSERT_STRING(parent, element, buffer) \
1751 free(buffer); (buffer) = NULL; \
1752 } else { INSERT_STRING(parent, element, NULL) }
1754 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
1755 /* FIXME: locale sensitive */ \
1756 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
1760 INSERT_STRING(parent, element, buffer) \
1761 free(buffer); (buffer) = NULL; \
1763 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
1764 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
1765 (xmlChar *) (string)); \
1766 if (!attribute_node) { \
1767 isds_printf_message(context, _("Could not add %s " \
1768 "attribute to %s element"), (attribute), (parent)->name); \
1774 /* Find child element by name in given XPath context and switch context onto
1775 * it. The child must be uniq and must exist. Otherwise failes.
1776 * @context is ISDS context
1777 * @child is child element name
1778 * @xpath_ctx is XPath context. In success, the @xpath_ctx will be changed
1779 * into it child. In error case, the @xpath_ctx keeps original value. */
1780 static isds_error
move_xpathctx_to_child(struct isds_ctx
*context
,
1781 const xmlChar
*child
, xmlXPathContextPtr xpath_ctx
) {
1782 isds_error err
= IE_SUCCESS
;
1783 xmlXPathObjectPtr result
= NULL
;
1785 if (!context
) return IE_INVALID_CONTEXT
;
1786 if (!child
|| !xpath_ctx
) return IE_INVAL
;
1789 result
= xmlXPathEvalExpression(child
, xpath_ctx
);
1796 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
1797 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1798 char *child_locale
= utf82locale((char*) child
);
1799 isds_printf_message(context
,
1800 _("%s element does not contain %s child"),
1801 parent_locale
, child_locale
);
1803 free(parent_locale
);
1809 if (result
->nodesetval
->nodeNr
> 1) {
1810 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1811 char *child_locale
= utf82locale((char*) child
);
1812 isds_printf_message(context
,
1813 _("%s element contains multiple %s childs"),
1814 parent_locale
, child_locale
);
1816 free(parent_locale
);
1821 /* Switch context */
1822 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
1825 xmlXPathFreeObject(result
);
1831 /* Find and convert XSD:gPersonName group in current node into structure
1832 * @context is ISDS context
1833 * @personName is automically reallocated person name structure. If no member
1834 * value is found, will be freed.
1835 * @xpath_ctx is XPath context with current node as parent for XSD:gPersonName
1837 * In case of error @personName will be freed. */
1838 static isds_error
extract_gPersonName(struct isds_ctx
*context
,
1839 struct isds_PersonName
**personName
, xmlXPathContextPtr xpath_ctx
) {
1840 isds_error err
= IE_SUCCESS
;
1841 xmlXPathObjectPtr result
= NULL
;
1843 if (!context
) return IE_INVALID_CONTEXT
;
1844 if (!personName
) return IE_INVAL
;
1845 isds_PersonName_free(personName
);
1846 if (!xpath_ctx
) return IE_INVAL
;
1849 *personName
= calloc(1, sizeof(**personName
));
1855 EXTRACT_STRING("isds:pnFirstName", (*personName
)->pnFirstName
);
1856 EXTRACT_STRING("isds:pnMiddleName", (*personName
)->pnMiddleName
);
1857 EXTRACT_STRING("isds:pnLastName", (*personName
)->pnLastName
);
1858 EXTRACT_STRING("isds:pnLastNameAtBirth", (*personName
)->pnLastNameAtBirth
);
1860 if (!(*personName
)->pnFirstName
&& !(*personName
)->pnMiddleName
&&
1861 !(*personName
)->pnLastName
&& !(*personName
)->pnLastNameAtBirth
)
1862 isds_PersonName_free(personName
);
1865 if (err
) isds_PersonName_free(personName
);
1866 xmlXPathFreeObject(result
);
1871 /* Find and convert XSD:gAddress group in current node into structure
1872 * @context is ISDS context
1873 * @address is automically reallocated address structure. If no member
1874 * value is found, will be freed.
1875 * @xpath_ctx is XPath context with current node as parent for XSD:gAddress
1877 * In case of error @address will be freed. */
1878 static isds_error
extract_gAddress(struct isds_ctx
*context
,
1879 struct isds_Address
**address
, xmlXPathContextPtr xpath_ctx
) {
1880 isds_error err
= IE_SUCCESS
;
1881 xmlXPathObjectPtr result
= NULL
;
1883 if (!context
) return IE_INVALID_CONTEXT
;
1884 if (!address
) return IE_INVAL
;
1885 isds_Address_free(address
);
1886 if (!xpath_ctx
) return IE_INVAL
;
1889 *address
= calloc(1, sizeof(**address
));
1895 EXTRACT_STRING("isds:adCity", (*address
)->adCity
);
1896 EXTRACT_STRING("isds:adStreet", (*address
)->adStreet
);
1897 EXTRACT_STRING("isds:adNumberInStreet", (*address
)->adNumberInStreet
);
1898 EXTRACT_STRING("isds:adNumberInMunicipality",
1899 (*address
)->adNumberInMunicipality
);
1900 EXTRACT_STRING("isds:adZipCode", (*address
)->adZipCode
);
1901 EXTRACT_STRING("isds:adState", (*address
)->adState
);
1903 if (!(*address
)->adCity
&& !(*address
)->adStreet
&&
1904 !(*address
)->adNumberInStreet
&&
1905 !(*address
)->adNumberInMunicipality
&&
1906 !(*address
)->adZipCode
&& !(*address
)->adState
)
1907 isds_Address_free(address
);
1910 if (err
) isds_Address_free(address
);
1911 xmlXPathFreeObject(result
);
1916 /* Find and convert isds:biDate element in current node into structure
1917 * @context is ISDS context
1918 * @biDate is automically reallocated birth date structure. If no member
1919 * value is found, will be freed.
1920 * @xpath_ctx is XPath context with current node as parent for isds:biDate
1922 * In case of error @biDate will be freed. */
1923 static isds_error
extract_BiDate(struct isds_ctx
*context
,
1924 struct tm
**biDate
, xmlXPathContextPtr xpath_ctx
) {
1925 isds_error err
= IE_SUCCESS
;
1926 xmlXPathObjectPtr result
= NULL
;
1927 char *string
= NULL
;
1929 if (!context
) return IE_INVALID_CONTEXT
;
1930 if (!biDate
) return IE_INVAL
;
1932 if (!xpath_ctx
) return IE_INVAL
;
1934 EXTRACT_STRING("isds:biDate", string
);
1936 *biDate
= calloc(1, sizeof(**biDate
));
1941 err
= datestring2tm((xmlChar
*)string
, *biDate
);
1943 if (err
== IE_NOTSUP
) {
1945 char *string_locale
= utf82locale(string
);
1946 isds_printf_message(context
,
1947 _("Invalid isds:biDate value: %s"), string_locale
);
1948 free(string_locale
);
1955 if (err
) zfree(*biDate
);
1957 xmlXPathFreeObject(result
);
1962 /* Convert isds:dBOwnerInfo XML tree into structure
1963 * @context is ISDS context
1964 * @db_owner_info is automically reallocated box owner info structure
1965 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
1966 * In case of error @db_owner_info will be freed. */
1967 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
1968 struct isds_DbOwnerInfo
**db_owner_info
,
1969 xmlXPathContextPtr xpath_ctx
) {
1970 isds_error err
= IE_SUCCESS
;
1971 xmlXPathObjectPtr result
= NULL
;
1972 char *string
= NULL
;
1974 if (!context
) return IE_INVALID_CONTEXT
;
1975 if (!db_owner_info
) return IE_INVAL
;
1976 isds_DbOwnerInfo_free(db_owner_info
);
1977 if (!xpath_ctx
) return IE_INVAL
;
1980 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
1981 if (!*db_owner_info
) {
1986 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
1988 EXTRACT_STRING("isds:dbType", string
);
1990 (*db_owner_info
)->dbType
=
1991 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
1992 if (!(*db_owner_info
)->dbType
) {
1996 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
1998 zfree((*db_owner_info
)->dbType
);
1999 if (err
== IE_ENUM
) {
2001 char *string_locale
= utf82locale(string
);
2002 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
2004 free(string_locale
);
2011 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
2013 err
= extract_gPersonName(context
, &(*db_owner_info
)->personName
,
2015 if (err
) goto leave
;
2017 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
2019 (*db_owner_info
)->birthInfo
=
2020 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
2021 if (!(*db_owner_info
)->birthInfo
) {
2025 err
= extract_BiDate(context
, &(*db_owner_info
)->birthInfo
->biDate
,
2027 if (err
) goto leave
;
2028 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
2029 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
2030 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
2031 if (!(*db_owner_info
)->birthInfo
->biDate
&&
2032 !(*db_owner_info
)->birthInfo
->biCity
&&
2033 !(*db_owner_info
)->birthInfo
->biCounty
&&
2034 !(*db_owner_info
)->birthInfo
->biState
)
2035 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
2037 err
= extract_gAddress(context
, &(*db_owner_info
)->address
, xpath_ctx
);
2038 if (err
) goto leave
;
2040 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
2041 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
2042 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
2043 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
2044 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
2046 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
2048 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
2049 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
2050 (*db_owner_info
)->dbOpenAddressing
);
2053 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
2055 xmlXPathFreeObject(result
);
2060 /* Convert XSD:tDbUserInfo XML tree into structure
2061 * @context is ISDS context
2062 * @db_user_info is automically reallocated user info structure
2063 * @xpath_ctx is XPath context with current node as XSD:tDbUserInfo element
2064 * In case of error @db_user_info will be freed. */
2065 static isds_error
extract_DbUserInfo(struct isds_ctx
*context
,
2066 struct isds_DbUserInfo
**db_user_info
, xmlXPathContextPtr xpath_ctx
) {
2067 isds_error err
= IE_SUCCESS
;
2068 xmlXPathObjectPtr result
= NULL
;
2069 char *string
= NULL
;
2071 if (!context
) return IE_INVALID_CONTEXT
;
2072 if (!db_user_info
) return IE_INVAL
;
2073 isds_DbUserInfo_free(db_user_info
);
2074 if (!xpath_ctx
) return IE_INVAL
;
2077 *db_user_info
= calloc(1, sizeof(**db_user_info
));
2078 if (!*db_user_info
) {
2083 EXTRACT_STRING("isds:userID", (*db_user_info
)->userID
);
2085 EXTRACT_STRING("isds:userType", string
);
2087 (*db_user_info
)->userType
=
2088 calloc(1, sizeof(*((*db_user_info
)->userType
)));
2089 if (!(*db_user_info
)->userType
) {
2093 err
= string2isds_UserType((xmlChar
*)string
,
2094 (*db_user_info
)->userType
);
2096 zfree((*db_user_info
)->userType
);
2097 if (err
== IE_ENUM
) {
2099 char *string_locale
= utf82locale(string
);
2100 isds_printf_message(context
, _("Unknown isds:userType: %s"),
2102 free(string_locale
);
2109 EXTRACT_LONGINT("isds:userPrivils", (*db_user_info
)->userPrivils
, 0);
2111 (*db_user_info
)->personName
=
2112 calloc(1, sizeof(*((*db_user_info
)->personName
)));
2113 if (!(*db_user_info
)->personName
) {
2118 err
= extract_gPersonName(context
, &(*db_user_info
)->personName
,
2120 if (err
) goto leave
;
2122 err
= extract_gAddress(context
, &(*db_user_info
)->address
, xpath_ctx
);
2123 if (err
) goto leave
;
2125 err
= extract_BiDate(context
, &(*db_user_info
)->biDate
, xpath_ctx
);
2126 if (err
) goto leave
;
2128 EXTRACT_STRING("isds:ic", (*db_user_info
)->ic
);
2129 EXTRACT_STRING("isds:firmName", (*db_user_info
)->firmName
);
2131 EXTRACT_STRING("isds:caStreet", (*db_user_info
)->caStreet
);
2132 EXTRACT_STRING("isds:caCity", (*db_user_info
)->caCity
);
2133 EXTRACT_STRING("isds:caZipCode", (*db_user_info
)->caZipCode
);
2136 if (err
) isds_DbUserInfo_free(db_user_info
);
2138 xmlXPathFreeObject(result
);
2143 /* Convert XSD gMessageEnvelopeSub group of elements from XML tree into
2144 * isds_envelope structure. The envelope is automatically allocated but not
2145 * reallocated. The date are just appended into envelope structure.
2146 * @context is ISDS context
2147 * @envelope is automically allocated message envelope structure
2148 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2149 * In case of error @envelope will be freed. */
2150 static isds_error
append_GMessageEnvelopeSub(struct isds_ctx
*context
,
2151 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2152 isds_error err
= IE_SUCCESS
;
2153 xmlXPathObjectPtr result
= NULL
;
2155 if (!context
) return IE_INVALID_CONTEXT
;
2156 if (!envelope
) return IE_INVAL
;
2157 if (!xpath_ctx
) return IE_INVAL
;
2161 /* Allocate envelope */
2162 *envelope
= calloc(1, sizeof(**envelope
));
2168 /* Else free former data */
2169 zfree((*envelope
)->dmSenderOrgUnit
);
2170 zfree((*envelope
)->dmSenderOrgUnitNum
);
2171 zfree((*envelope
)->dbIDRecipient
);
2172 zfree((*envelope
)->dmRecipientOrgUnit
);
2173 zfree((*envelope
)->dmSenderOrgUnitNum
);
2174 zfree((*envelope
)->dmToHands
);
2175 zfree((*envelope
)->dmAnnotation
);
2176 zfree((*envelope
)->dmRecipientRefNumber
);
2177 zfree((*envelope
)->dmSenderRefNumber
);
2178 zfree((*envelope
)->dmRecipientIdent
);
2179 zfree((*envelope
)->dmSenderIdent
);
2180 zfree((*envelope
)->dmLegalTitleLaw
);
2181 zfree((*envelope
)->dmLegalTitleYear
);
2182 zfree((*envelope
)->dmLegalTitleSect
);
2183 zfree((*envelope
)->dmLegalTitlePar
);
2184 zfree((*envelope
)->dmLegalTitlePoint
);
2185 zfree((*envelope
)->dmPersonalDelivery
);
2186 zfree((*envelope
)->dmAllowSubstDelivery
);
2189 /* Extract envelope elements added by sender or ISDS
2190 * (XSD: gMessageEnvelopeSub type) */
2191 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
2192 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
2193 (*envelope
)->dmSenderOrgUnitNum
, 0);
2194 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
2195 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
2196 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
2197 (*envelope
)->dmSenderOrgUnitNum
, 0);
2198 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
2199 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
2200 EXTRACT_STRING("isds:dmRecipientRefNumber",
2201 (*envelope
)->dmRecipientRefNumber
);
2202 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
2203 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
2204 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
2206 /* Extract envelope elements regarding law refference */
2207 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
2208 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
2209 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
2210 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
2211 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
2213 /* Extract envelope other elements */
2214 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
2215 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
2216 (*envelope
)->dmAllowSubstDelivery
);
2219 if (err
) isds_envelope_free(envelope
);
2220 xmlXPathFreeObject(result
);
2226 /* Convert XSD gMessageEnvelope group of elements from XML tree into
2227 * isds_envelope structure. The envelope is automatically allocated but not
2228 * reallocated. The date are just appended into envelope structure.
2229 * @context is ISDS context
2230 * @envelope is automically allocated message envelope structure
2231 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2232 * In case of error @envelope will be freed. */
2233 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
2234 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2235 isds_error err
= IE_SUCCESS
;
2236 xmlXPathObjectPtr result
= NULL
;
2238 if (!context
) return IE_INVALID_CONTEXT
;
2239 if (!envelope
) return IE_INVAL
;
2240 if (!xpath_ctx
) return IE_INVAL
;
2244 /* Allocate envelope */
2245 *envelope
= calloc(1, sizeof(**envelope
));
2251 /* Else free former data */
2252 zfree((*envelope
)->dmID
);
2253 zfree((*envelope
)->dbIDSender
);
2254 zfree((*envelope
)->dmSender
);
2255 zfree((*envelope
)->dmSenderAddress
);
2256 zfree((*envelope
)->dmSenderType
);
2257 zfree((*envelope
)->dmRecipient
);
2258 zfree((*envelope
)->dmRecipientAddress
);
2259 zfree((*envelope
)->dmAmbiguousRecipient
);
2262 /* Extract envelope elements added by ISDS
2263 * (XSD: gMessageEnvelope type) */
2264 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
2265 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
2266 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
2267 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
2268 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
2269 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
2270 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
2271 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
2272 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
2273 (*envelope
)->dmAmbiguousRecipient
);
2275 /* Extract envelope elements added by sender and ISDS
2276 * (XSD: gMessageEnvelope type) */
2277 err
= append_GMessageEnvelopeSub(context
, envelope
, xpath_ctx
);
2278 if (err
) goto leave
;
2281 if (err
) isds_envelope_free(envelope
);
2282 xmlXPathFreeObject(result
);
2287 /* Convert other envelope elements from XML tree into isds_envelope structure:
2288 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
2289 * The envelope is automatically allocated but not reallocated.
2290 * The data are just appended into envelope structure.
2291 * @context is ISDS context
2292 * @envelope is automically allocated message envelope structure
2293 * @xpath_ctx is XPath context with current node as parent desired elements
2294 * In case of error @envelope will be freed. */
2295 static isds_error
append_status_size_times(struct isds_ctx
*context
,
2296 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2297 isds_error err
= IE_SUCCESS
;
2298 xmlXPathObjectPtr result
= NULL
;
2299 char *string
= NULL
;
2300 unsigned long int *unumber
= NULL
;
2302 if (!context
) return IE_INVALID_CONTEXT
;
2303 if (!envelope
) return IE_INVAL
;
2304 if (!xpath_ctx
) return IE_INVAL
;
2309 *envelope
= calloc(1, sizeof(**envelope
));
2316 zfree((*envelope
)->dmMessageStatus
);
2317 zfree((*envelope
)->dmAttachmentSize
);
2318 zfree((*envelope
)->dmDeliveryTime
);
2319 zfree((*envelope
)->dmAcceptanceTime
);
2323 /* dmMessageStatus element is mandatory */
2324 EXTRACT_ULONGINT("sisds:dmMessageStatus", unumber
, 0);
2326 isds_log_message(context
,
2327 _("Missing mandatory sisds:dmMessageStatus integer"));
2331 err
= uint2isds_message_status(context
, unumber
,
2332 &((*envelope
)->dmMessageStatus
));
2334 if (err
== IE_ENUM
) err
= IE_ISDS
;
2337 free(unumber
); unumber
= NULL
;
2339 EXTRACT_ULONGINT("sisds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
,
2342 EXTRACT_STRING("sisds:dmDeliveryTime", string
);
2344 err
= timestring2timeval((xmlChar
*) string
,
2345 &((*envelope
)->dmDeliveryTime
));
2347 char *string_locale
= utf82locale(string
);
2348 if (err
== IE_DATE
) err
= IE_ISDS
;
2349 isds_printf_message(context
,
2350 _("Could not convert dmDeliveryTime as ISO time: %s"),
2352 free(string_locale
);
2358 EXTRACT_STRING("sisds:dmAcceptanceTime", string
);
2360 err
= timestring2timeval((xmlChar
*) string
,
2361 &((*envelope
)->dmAcceptanceTime
));
2363 char *string_locale
= utf82locale(string
);
2364 if (err
== IE_DATE
) err
= IE_ISDS
;
2365 isds_printf_message(context
,
2366 _("Could not convert dmAcceptanceTime as ISO time: %s"),
2368 free(string_locale
);
2375 if (err
) isds_envelope_free(envelope
);
2378 xmlXPathFreeObject(result
);
2383 /* Convert message type attribute of current element into isds_envelope
2385 * TODO: This function can be incorporated into append_status_size_times() as
2386 * they are called always together.
2387 * The envelope is automatically allocated but not reallocated.
2388 * The data are just appended into envelope structure.
2389 * @context is ISDS context
2390 * @envelope is automically allocated message envelope structure
2391 * @xpath_ctx is XPath context with current node as parent of attribute
2392 * carrying message type
2393 * In case of error @envelope will be freed. */
2394 static isds_error
append_message_type(struct isds_ctx
*context
,
2395 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2396 isds_error err
= IE_SUCCESS
;
2398 if (!context
) return IE_INVALID_CONTEXT
;
2399 if (!envelope
) return IE_INVAL
;
2400 if (!xpath_ctx
) return IE_INVAL
;
2405 *envelope
= calloc(1, sizeof(**envelope
));
2412 zfree((*envelope
)->dmType
);
2416 EXTRACT_STRING_ATTRIBUTE("dmType", (*envelope
)->dmType
, 0);
2418 if (!(*envelope
)->dmType
) {
2419 /* Use default value */
2420 (*envelope
)->dmType
= strdup("V");
2421 if (!(*envelope
)->dmType
) {
2425 } else if (1 != xmlUTF8Strlen((xmlChar
*) (*envelope
)->dmType
)) {
2426 char *type_locale
= utf82locale((*envelope
)->dmType
);
2427 isds_printf_message(context
,
2428 _("Message type in dmType attribute is not 1 character long: "
2437 if (err
) isds_envelope_free(envelope
);
2443 /* Extract message document into reallocated document structure
2444 * @context is ISDS context
2445 * @document is automically reallocated message documents structure
2446 * @xpath_ctx is XPath context with current node as isds:dmFile
2447 * In case of error @document will be freed. */
2448 static isds_error
extract_document(struct isds_ctx
*context
,
2449 struct isds_document
**document
, xmlXPathContextPtr xpath_ctx
) {
2450 isds_error err
= IE_SUCCESS
;
2451 xmlXPathObjectPtr result
= NULL
;
2452 xmlNodePtr file_node
= xpath_ctx
->node
;
2453 char *string
= NULL
;
2455 if (!context
) return IE_INVALID_CONTEXT
;
2456 if (!document
) return IE_INVAL
;
2457 isds_document_free(document
);
2458 if (!xpath_ctx
) return IE_INVAL
;
2460 *document
= calloc(1, sizeof(**document
));
2466 /* Extract document metadata */
2467 EXTRACT_STRING_ATTRIBUTE("dmMimeType", (*document
)->dmMimeType
, 1)
2469 EXTRACT_STRING_ATTRIBUTE("dmFileMetaType", string
, 1)
2470 err
= string2isds_FileMetaType((xmlChar
*)string
,
2471 &((*document
)->dmFileMetaType
));
2473 char *meta_type_locale
= utf82locale(string
);
2474 isds_printf_message(context
,
2475 _("Document has invalid dmFileMetaType attribute value: %s"),
2477 free(meta_type_locale
);
2483 EXTRACT_STRING_ATTRIBUTE("dmFileGuid", (*document
)->dmFileGuid
, 0)
2484 EXTRACT_STRING_ATTRIBUTE("dmUpFileGuid", (*document
)->dmUpFileGuid
, 0)
2485 EXTRACT_STRING_ATTRIBUTE("dmFileDescr", (*document
)->dmFileDescr
, 0)
2486 EXTRACT_STRING_ATTRIBUTE("dmFormat", (*document
)->dmFormat
, 0)
2489 /* Extract document data.
2490 * Base64 encoded blob or XML subtree must be presented. */
2492 /* Check from dmEncodedContent */
2493 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmEncodedContent",
2500 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2501 /* Here we have Base64 blob */
2503 if (result
->nodesetval
->nodeNr
> 1) {
2504 isds_printf_message(context
,
2505 _("Document has more dmEncodedContent elements"));
2510 xmlXPathFreeObject(result
); result
= NULL
;
2511 EXTRACT_STRING("isds:dmEncodedContent", string
);
2513 /* Decode non-emptys document */
2514 if (string
&& string
[0] != '\0') {
2515 (*document
)->data_length
= b64decode(string
, &((*document
)->data
));
2516 if ((*document
)->data_length
== (size_t) -1) {
2517 isds_printf_message(context
,
2518 _("Error while Base64-decoding document content"));
2524 /* No Base64 blob, try XML document */
2525 xmlXPathFreeObject(result
); result
= NULL
;
2526 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmXMLContent",
2533 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2534 /* Here we have XML document */
2536 if (result
->nodesetval
->nodeNr
> 1) {
2537 isds_printf_message(context
,
2538 _("Document has more dmXMLContent elements"));
2543 /* FIXME: Serialize the tree rooted at result's node */
2544 isds_printf_message(context
,
2545 _("XML documents not yet supported"));
2549 /* No bas64 blob, nor XML document */
2550 isds_printf_message(context
,
2551 _("Document has no dmEncodedContent, nor dmXMLContent "
2560 if (err
) isds_document_free(document
);
2562 xmlXPathFreeObject(result
);
2563 xpath_ctx
->node
= file_node
;
2569 /* Extract message documents into reallocated list of documents
2570 * @context is ISDS context
2571 * @documents is automically reallocated message documents list structure
2572 * @xpath_ctx is XPath context with current node as XSD tFilesArray
2573 * In case of error @documents will be freed. */
2574 static isds_error
extract_documents(struct isds_ctx
*context
,
2575 struct isds_list
**documents
, xmlXPathContextPtr xpath_ctx
) {
2576 isds_error err
= IE_SUCCESS
;
2577 xmlXPathObjectPtr result
= NULL
;
2578 xmlNodePtr files_node
= xpath_ctx
->node
;
2579 struct isds_list
*document
, *prev_document
;
2581 if (!context
) return IE_INVALID_CONTEXT
;
2582 if (!documents
) return IE_INVAL
;
2583 isds_list_free(documents
);
2584 if (!xpath_ctx
) return IE_INVAL
;
2586 /* Find documents */
2587 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmFile", xpath_ctx
);
2594 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2595 isds_printf_message(context
,
2596 _("Message does not contain any document"));
2602 /* Iterate over documents */
2603 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2605 /* Allocate and append list item */
2606 document
= calloc(1, sizeof(*document
));
2611 document
->destructor
= (void (*)(void **))isds_document_free
;
2612 if (i
== 0) *documents
= document
;
2613 else prev_document
->next
= document
;
2614 prev_document
= document
;
2616 /* Extract document */
2617 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2618 err
= extract_document(context
,
2619 (struct isds_document
**) &(document
->data
), xpath_ctx
);
2620 if (err
) goto leave
;
2625 if (err
) isds_list_free(documents
);
2626 xmlXPathFreeObject(result
);
2627 xpath_ctx
->node
= files_node
;
2632 /* Convert isds:dmRecord XML tree into structure
2633 * @context is ISDS context
2634 * @envelope is automically reallocated message envelope structure
2635 * @xpath_ctx is XPath context with current node as isds:dmRecord element
2636 * In case of error @envelope will be freed. */
2637 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
2638 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2639 isds_error err
= IE_SUCCESS
;
2640 xmlXPathObjectPtr result
= NULL
;
2642 if (!context
) return IE_INVALID_CONTEXT
;
2643 if (!envelope
) return IE_INVAL
;
2644 isds_envelope_free(envelope
);
2645 if (!xpath_ctx
) return IE_INVAL
;
2648 *envelope
= calloc(1, sizeof(**envelope
));
2655 /* Extract tRecord data */
2656 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
2658 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
2659 * dmAcceptanceTime. */
2660 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
2661 if (err
) goto leave
;
2663 /* Extract envelope elements added by sender and ISDS
2664 * (XSD: gMessageEnvelope type) */
2665 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
2666 if (err
) goto leave
;
2667 /* dmOVM can not be obtained from ISDS */
2669 /* Get message type */
2670 err
= append_message_type(context
, envelope
, xpath_ctx
);
2671 if (err
) goto leave
;
2675 if (err
) isds_envelope_free(envelope
);
2676 xmlXPathFreeObject(result
);
2681 /* Find and convert isds:dmHash XML tree into structure
2682 * @context is ISDS context
2683 * @envelope is automically reallocated message hash structure
2684 * @xpath_ctx is XPath context with current node containing isds:dmHash child
2685 * In case of error @hash will be freed. */
2686 static isds_error
find_and_extract_DmHash(struct isds_ctx
*context
,
2687 struct isds_hash
**hash
, xmlXPathContextPtr xpath_ctx
) {
2688 isds_error err
= IE_SUCCESS
;
2689 xmlNodePtr old_ctx_node
;
2690 xmlXPathObjectPtr result
= NULL
;
2691 char *string
= NULL
;
2693 if (!context
) return IE_INVALID_CONTEXT
;
2694 if (!hash
) return IE_INVAL
;
2695 isds_hash_free(hash
);
2696 if (!xpath_ctx
) return IE_INVAL
;
2698 old_ctx_node
= xpath_ctx
->node
;
2700 *hash
= calloc(1, sizeof(**hash
));
2707 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmHash", xpath_ctx
);
2708 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
2717 /* Get hash algorithm */
2718 EXTRACT_STRING_ATTRIBUTE("algorithm", string
, 1);
2719 err
= string2isds_hash_algorithm((xmlChar
*) string
, &(*hash
)->algorithm
);
2721 if (err
== IE_ENUM
) {
2722 char *string_locale
= utf82locale(string
);
2723 isds_printf_message(context
, _("Unsported hash algorithm: %s"),
2725 free(string_locale
);
2731 /* Get hash value */
2732 EXTRACT_STRING(".", string
);
2734 isds_printf_message(context
, _("tHash element is missing hash value"));
2738 (*hash
)->length
= b64decode(string
, &((*hash
)->value
));
2739 if ((*hash
)->length
== (size_t) -1) {
2740 isds_printf_message(context
,
2741 _("Error while Base64-decoding hash value"));
2747 if (err
) isds_hash_free(hash
);
2749 xmlXPathFreeObject(result
);
2750 xpath_ctx
->node
= old_ctx_node
;
2755 /* Find and append isds:dmQTimestamp XML tree into envelope
2756 * @context is ISDS context
2757 * @envelope is automically allocated evnelope structure
2758 * @xpath_ctx is XPath context with current node containing isds:dmQTimestamp
2760 * In case of error @envelope will be freed. */
2761 static isds_error
find_and_append_DmQTimestamp(struct isds_ctx
*context
,
2762 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2763 isds_error err
= IE_SUCCESS
;
2764 xmlXPathObjectPtr result
= NULL
;
2765 char *string
= NULL
;
2767 if (!context
) return IE_INVALID_CONTEXT
;
2768 if (!envelope
) return IE_INVAL
;
2770 isds_envelope_free(envelope
);
2775 *envelope
= calloc(1, sizeof(**envelope
));
2781 zfree((*envelope
)->timestamp
);
2782 (*envelope
)->timestamp_length
= 0;
2785 /* Get dmQTimestamp */
2786 EXTRACT_STRING("sisds:dmQTimestamp", string
);
2788 isds_printf_message(context
, _("Missing dmQTimestamp element content"));
2792 (*envelope
)->timestamp_length
=
2793 b64decode(string
, &((*envelope
)->timestamp
));
2794 if ((*envelope
)->timestamp_length
== (size_t) -1) {
2795 isds_printf_message(context
,
2796 _("Error while Base64-decoding timestamp value"));
2802 if (err
) isds_envelope_free(envelope
);
2804 xmlXPathFreeObject(result
);
2809 /* Convert XSD tReturnedMessage XML tree into message structure.
2810 * It doea not store XML tree into message->raw.
2811 * @context is ISDS context
2812 * @include_documents Use true if documents must be extracted
2813 * (tReturnedMessage XSD type), use false if documents shall be ommited
2814 * (tReturnedMessageEnvelope).
2815 * @message is automically reallocated message structure
2816 * @xpath_ctx is XPath context with current node as tReturnedMessage element
2818 * In case of error @message will be freed. */
2819 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
2820 const _Bool include_documents
, struct isds_message
**message
,
2821 xmlXPathContextPtr xpath_ctx
) {
2822 isds_error err
= IE_SUCCESS
;
2823 xmlNodePtr message_node
;
2825 if (!context
) return IE_INVALID_CONTEXT
;
2826 if (!message
) return IE_INVAL
;
2827 isds_message_free(message
);
2828 if (!xpath_ctx
) return IE_INVAL
;
2831 *message
= calloc(1, sizeof(**message
));
2837 /* Save message XPATH context node */
2838 message_node
= xpath_ctx
->node
;
2842 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
2843 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
2844 if (err
) { err
= IE_ERROR
; goto leave
; }
2845 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
2846 if (err
) goto leave
;
2848 if (include_documents
) {
2849 /* Extract dmFiles */
2850 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles",
2852 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
2853 err
= IE_ISDS
; goto leave
;
2855 if (err
) { err
= IE_ERROR
; goto leave
; }
2856 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
2857 if (err
) goto leave
;
2861 /* Restore context to message */
2862 xpath_ctx
->node
= message_node
;
2864 /* Extract dmHash */
2865 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
2867 if (err
) goto leave
;
2869 /* Extract dmQTimestamp, */
2870 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
2872 if (err
) goto leave
;
2874 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
2875 * dmAcceptanceTime. */
2876 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
2877 if (err
) goto leave
;
2879 /* Get message type */
2880 err
= append_message_type(context
, &((*message
)->envelope
), xpath_ctx
);
2881 if (err
) goto leave
;
2884 if (err
) isds_message_free(message
);
2889 /* Extract message event into reallocated isds_event structure
2890 * @context is ISDS context
2891 * @event is automically reallocated message event structure
2892 * @xpath_ctx is XPath context with current node as isds:dmEvent
2893 * In case of error @event will be freed. */
2894 static isds_error
extract_event(struct isds_ctx
*context
,
2895 struct isds_event
**event
, xmlXPathContextPtr xpath_ctx
) {
2896 isds_error err
= IE_SUCCESS
;
2897 xmlXPathObjectPtr result
= NULL
;
2898 xmlNodePtr event_node
= xpath_ctx
->node
;
2899 char *string
= NULL
;
2901 if (!context
) return IE_INVALID_CONTEXT
;
2902 if (!event
) return IE_INVAL
;
2903 isds_event_free(event
);
2904 if (!xpath_ctx
) return IE_INVAL
;
2906 *event
= calloc(1, sizeof(**event
));
2912 /* Extract event data.
2913 * All elements are optional according XSD. That's funny. */
2914 EXTRACT_STRING("sisds:dmEventTime", string
);
2916 err
= timestring2timeval((xmlChar
*) string
, &((*event
)->time
));
2918 char *string_locale
= utf82locale(string
);
2919 if (err
== IE_DATE
) err
= IE_ISDS
;
2920 isds_printf_message(context
,
2921 _("Could not convert dmEventTime as ISO time: %s"),
2923 free(string_locale
);
2929 /* dmEventDescr element has prefix and the rest */
2930 EXTRACT_STRING("sisds:dmEventDescr", string
);
2932 err
= eventstring2event((xmlChar
*) string
, *event
);
2933 if (err
) goto leave
;
2938 if (err
) isds_event_free(event
);
2940 xmlXPathFreeObject(result
);
2941 xpath_ctx
->node
= event_node
;
2946 /* Convert element of XSD tEventsArray type from XML tree into
2947 * isds_list of isds_event's structure. The list is automatically reallocated.
2948 * @context is ISDS context
2949 * @events is automically reallocated list of event structures
2950 * @xpath_ctx is XPath context with current node as tEventsArray
2951 * In case of error @evnets will be freed. */
2952 static isds_error
extract_events(struct isds_ctx
*context
,
2953 struct isds_list
**events
, xmlXPathContextPtr xpath_ctx
) {
2954 isds_error err
= IE_SUCCESS
;
2955 xmlXPathObjectPtr result
= NULL
;
2956 xmlNodePtr events_node
= xpath_ctx
->node
;
2957 struct isds_list
*event
, *prev_event
= NULL
;
2959 if (!context
) return IE_INVALID_CONTEXT
;
2960 if (!events
) return IE_INVAL
;
2961 if (!xpath_ctx
) return IE_INVAL
;
2964 isds_list_free(events
);
2967 result
= xmlXPathEvalExpression(BAD_CAST
"sisds:dmEvent", xpath_ctx
);
2974 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2975 isds_printf_message(context
,
2976 _("Delivery info does not contain any event"));
2982 /* Iterate over events */
2983 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2985 /* Allocate and append list item */
2986 event
= calloc(1, sizeof(*event
));
2991 event
->destructor
= (void (*)(void **))isds_event_free
;
2992 if (i
== 0) *events
= event
;
2993 else prev_event
->next
= event
;
2997 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2998 err
= extract_event(context
,
2999 (struct isds_event
**) &(event
->data
), xpath_ctx
);
3000 if (err
) goto leave
;
3005 if (err
) isds_list_free(events
);
3006 xmlXPathFreeObject(result
);
3007 xpath_ctx
->node
= events_node
;
3012 /* Convert isds_document structure into XML tree and append to dmFiles node.
3013 * @context is session context
3014 * @document is ISDS document
3015 * @dm_files is XML element the resulting tree will be appended to as a child.
3016 * @return error code, in case of error context' message is filled. */
3017 static isds_error
insert_document(struct isds_ctx
*context
,
3018 struct isds_document
*document
, xmlNodePtr dm_files
) {
3019 isds_error err
= IE_SUCCESS
;
3020 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
3021 xmlAttrPtr attribute_node
;
3022 xmlChar
*base64data
= NULL
;
3024 if (!context
) return IE_INVALID_CONTEXT
;
3025 if (!document
|| !dm_files
) return IE_INVAL
;
3027 /* Allocate new dmFile */
3028 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
3030 isds_printf_message(context
, _("Could not allocate main dmFile"));
3034 /* Append the new dmFile.
3035 * XXX: Main document must go first */
3036 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
3037 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
3039 file
= xmlAddChild(dm_files
, new_file
);
3042 xmlFreeNode(new_file
); new_file
= NULL
;
3043 isds_printf_message(context
, _("Could not add dmFile child to "
3044 "%s element"), dm_files
->name
);
3049 /* @dmMimeType is required */
3050 if (!document
->dmMimeType
) {
3051 isds_log_message(context
,
3052 _("Document is missing mandatory MIME type definition"));
3056 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
3058 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
3060 isds_printf_message(context
,
3061 _("Document has unkown dmFileMetaType: %ld"),
3062 document
->dmFileMetaType
);
3066 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
3068 if (document
->dmFileGuid
) {
3069 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
3071 if (document
->dmUpFileGuid
) {
3072 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
3075 /* @dmFileDescr is required */
3076 if (!document
->dmFileDescr
) {
3077 isds_log_message(context
,
3078 _("Document is missing mandatory description (title)"));
3082 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
3084 if (document
->dmFormat
) {
3085 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
3089 /* Insert content (data) of the document. */
3090 /* XXX; Only base64 is implemented currently. */
3091 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
3093 isds_printf_message(context
,
3094 _("Not enought memory to encode %zd bytes into Base64"),
3095 document
->data_length
);
3099 INSERT_STRING(file
, "dmEncodedContent", base64data
);
3107 /* Append XSD tMStatus XML tree into isds_message_copy structure.
3108 * The copy must pre prealocated, the date are just appended into structure.
3109 * @context is ISDS context
3110 * @copy is message copy struture
3111 * @xpath_ctx is XPath context with current node as tMStatus */
3112 static isds_error
append_TMStatus(struct isds_ctx
*context
,
3113 struct isds_message_copy
*copy
, xmlXPathContextPtr xpath_ctx
) {
3114 isds_error err
= IE_SUCCESS
;
3115 xmlXPathObjectPtr result
= NULL
;
3116 char *code
= NULL
, *message
= NULL
;
3118 if (!context
) return IE_INVALID_CONTEXT
;
3119 if (!copy
|| !xpath_ctx
) return IE_INVAL
;
3121 /* Free old values */
3122 zfree(copy
->dmStatus
);
3125 /* Get error specific to this copy */
3126 EXTRACT_STRING("isds:dmStatus/isds:dmStatusCode", code
);
3128 isds_log_message(context
,
3129 _("Missing isds:dmStatusCode under "
3130 "XSD:tMStatus type element"));
3135 if (xmlStrcmp((const xmlChar
*)code
, BAD_CAST
"0000")) {
3136 /* This copy failed */
3137 copy
->error
= IE_ISDS
;
3138 EXTRACT_STRING("isds:dmStatus/isds:dmStatusMessage", message
);
3140 copy
->dmStatus
= astrcat3(code
, ": ", message
);
3141 if (!copy
->dmStatus
) {
3142 copy
->dmStatus
= code
;
3146 copy
->dmStatus
= code
;
3150 /* This copy succeeded. In this case only, message ID is valid */
3151 copy
->error
= IE_SUCCESS
;
3153 EXTRACT_STRING("isds:dmID", copy
->dmID
);
3155 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3156 "but did not returned assigned message ID\n"));
3164 xmlXPathFreeObject(result
);
3169 /* Build ISDS request of XSD tDummyInput type, sent it and check for error
3171 * @context is session context
3172 * @service_name is name of SERVICE_DB_ACCESS
3173 * @response is server SOAP body response as XML document
3174 * @raw_response is automatically reallocated bitstream with response body. Use
3175 * NULL if you don't care
3176 * @raw_response_length is size of @raw_response in bytes
3177 * @code is ISDS status code
3178 * @status_message is ISDS status message
3179 * @return error coded from lower layer, context message will be set up
3181 static isds_error
build_send_check_dbdummy_request(struct isds_ctx
*context
,
3182 const xmlChar
*service_name
,
3183 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
3184 xmlChar
**code
, xmlChar
**status_message
) {
3186 isds_error err
= IE_SUCCESS
;
3187 char *service_name_locale
= NULL
;
3188 xmlNodePtr request
= NULL
, node
;
3189 xmlNsPtr isds_ns
= NULL
;
3191 if (!context
) return IE_INVALID_CONTEXT
;
3192 if (!service_name
) return IE_INVAL
;
3193 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3194 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
3196 /* Free output argument */
3197 xmlFreeDoc(*response
); *response
= NULL
;
3198 if (raw_response
) zfree(*raw_response
);
3200 free(*status_message
);
3203 /* Check if connection is established
3204 * TODO: This check should be done donwstairs. */
3205 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3207 service_name_locale
= utf82locale((char*)service_name
);
3208 if (!service_name_locale
) {
3214 request
= xmlNewNode(NULL
, service_name
);
3216 isds_printf_message(context
,
3217 _("Could not build %s request"), service_name_locale
);
3221 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3223 isds_log_message(context
, _("Could not create ISDS name space"));
3227 xmlSetNs(request
, isds_ns
);
3230 /* Add XSD:tDummyInput child */
3231 INSERT_STRING(request
, "dbDummy", NULL
);
3234 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
3235 service_name_locale
);
3238 err
= isds(context
, SERVICE_DB_ACCESS
, request
, response
,
3239 raw_response
, raw_response_length
);
3240 xmlFreeNode(request
); request
= NULL
;
3243 isds_log(ILF_ISDS
, ILL_DEBUG
,
3244 _("Processing ISDS response on %s request failed\n"),
3245 service_name_locale
);
3249 /* Check for response status */
3250 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, *response
,
3251 code
, status_message
, NULL
);
3253 isds_log(ILF_ISDS
, ILL_DEBUG
,
3254 _("ISDS response on %s request is missing status\n"),
3255 service_name_locale
);
3259 /* Request processed, but nothing found */
3260 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3261 char *code_locale
= utf82locale((char*) *code
);
3262 char *status_message_locale
= utf82locale((char*) *status_message
);
3263 isds_log(ILF_ISDS
, ILL_DEBUG
,
3264 _("Server refused %s request (code=%s, message=%s)\n"),
3265 service_name_locale
, code_locale
, status_message_locale
);
3266 isds_log_message(context
, status_message_locale
);
3268 free(status_message_locale
);
3274 free(service_name_locale
);
3275 xmlFreeNode(request
);
3280 /* Get data about logged in user and his box. */
3281 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
3282 struct isds_DbOwnerInfo
**db_owner_info
) {
3283 isds_error err
= IE_SUCCESS
;
3284 xmlDocPtr response
= NULL
;
3285 xmlChar
*code
= NULL
, *message
= NULL
;
3286 xmlXPathContextPtr xpath_ctx
= NULL
;
3287 xmlXPathObjectPtr result
= NULL
;
3288 char *string
= NULL
;
3290 if (!context
) return IE_INVALID_CONTEXT
;
3291 if (!db_owner_info
) return IE_INVAL
;
3293 /* Check if connection is established */
3294 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3297 /* Do request and check for success */
3298 err
= build_send_check_dbdummy_request(context
,
3299 BAD_CAST
"GetOwnerInfoFromLogin",
3300 &response
, NULL
, NULL
, &code
, &message
);
3301 if (err
) goto leave
;
3305 /* Prepare stucture */
3306 isds_DbOwnerInfo_free(db_owner_info
);
3307 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
3308 if (!*db_owner_info
) {
3312 xpath_ctx
= xmlXPathNewContext(response
);
3317 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3322 /* Set context node */
3323 result
= xmlXPathEvalExpression(BAD_CAST
3324 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
3329 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3330 isds_log_message(context
, _("Missing dbOwnerInfo element"));
3334 if (result
->nodesetval
->nodeNr
> 1) {
3335 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
3339 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3340 xmlXPathFreeObject(result
); result
= NULL
;
3343 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
3347 isds_DbOwnerInfo_free(db_owner_info
);
3351 xmlXPathFreeObject(result
);
3352 xmlXPathFreeContext(xpath_ctx
);
3356 xmlFreeDoc(response
);
3359 isds_log(ILF_ISDS
, ILL_DEBUG
,
3360 _("GetOwnerInfoFromLogin request processed by server "
3361 "successfully.\n"));
3367 /* Get data about logged in user. */
3368 isds_error
isds_GetUserInfoFromLogin(struct isds_ctx
*context
,
3369 struct isds_DbUserInfo
**db_user_info
) {
3370 isds_error err
= IE_SUCCESS
;
3371 xmlDocPtr response
= NULL
;
3372 xmlChar
*code
= NULL
, *message
= NULL
;
3373 xmlXPathContextPtr xpath_ctx
= NULL
;
3374 xmlXPathObjectPtr result
= NULL
;
3376 if (!context
) return IE_INVALID_CONTEXT
;
3377 if (!db_user_info
) return IE_INVAL
;
3379 /* Check if connection is established */
3380 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3383 /* Do request and check for success */
3384 err
= build_send_check_dbdummy_request(context
,
3385 BAD_CAST
"GetUserInfoFromLogin",
3386 &response
, NULL
, NULL
, &code
, &message
);
3387 if (err
) goto leave
;
3391 /* Prepare stucture */
3392 isds_DbUserInfo_free(db_user_info
);
3393 *db_user_info
= calloc(1, sizeof(**db_user_info
));
3394 if (!*db_user_info
) {
3398 xpath_ctx
= xmlXPathNewContext(response
);
3403 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3408 /* Set context node */
3409 result
= xmlXPathEvalExpression(BAD_CAST
3410 "/isds:GetUserInfoFromLoginResponse/isds:dbUserInfo", xpath_ctx
);
3415 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3416 isds_log_message(context
, _("Missing dbUserInfo element"));
3420 if (result
->nodesetval
->nodeNr
> 1) {
3421 isds_log_message(context
, _("Multiple dbUserInfo element"));
3425 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3426 xmlXPathFreeObject(result
); result
= NULL
;
3429 err
= extract_DbUserInfo(context
, db_user_info
, xpath_ctx
);
3433 isds_DbUserInfo_free(db_user_info
);
3436 xmlXPathFreeObject(result
);
3437 xmlXPathFreeContext(xpath_ctx
);
3441 xmlFreeDoc(response
);
3444 isds_log(ILF_ISDS
, ILL_DEBUG
,
3445 _("GetUserInfoFromLogin request processed by server "
3446 "successfully.\n"));
3452 /* Get data about all users with access to your box.
3453 * @context is session context
3454 * @users is automatically reallocated list of struct isds_DbUserInfo */
3455 isds_error
isds_GetDataBoxUsers(struct isds_ctx
*context
,
3456 struct isds_list
**users
) {
3457 isds_error err
= IE_SUCCESS
;
3458 xmlDocPtr response
= NULL
;
3459 xmlChar
*code
= NULL
, *message
= NULL
;
3460 xmlXPathContextPtr xpath_ctx
= NULL
;
3461 xmlXPathObjectPtr result
= NULL
;
3463 struct isds_list
*item
, *prev_item
= NULL
;
3465 if (!context
) return IE_INVALID_CONTEXT
;
3466 if (!users
) return IE_INVAL
;
3468 /* Check if connection is established */
3469 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3472 /* Do request and check for success */
3473 err
= build_send_check_dbdummy_request(context
,
3474 BAD_CAST
"GetDataBoxUsers",
3475 &response
, NULL
, NULL
, &code
, &message
);
3476 if (err
) goto leave
;
3480 /* Prepare stucture */
3481 isds_list_free(users
);
3482 xpath_ctx
= xmlXPathNewContext(response
);
3487 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3492 /* Set context node */
3493 result
= xmlXPathEvalExpression(BAD_CAST
3494 "/isds:EnableOwnDataBoxResponse/isds:dbUsers/isds:dbUserInfo",
3500 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3501 isds_log_message(context
, _("Missing dbUserInfo element"));
3506 /* Iterate over all users */
3507 for (i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3509 /* Prepare structure */
3510 item
= calloc(1, sizeof(*item
));
3515 item
->destructor
= (void(*)(void**))isds_DbUserInfo_free
;
3516 if (i
== 0) *users
= item
;
3517 else prev_item
->next
= item
;
3521 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3522 err
= extract_DbUserInfo(context
,
3523 (struct isds_DbUserInfo
**) (&item
->data
), xpath_ctx
);
3524 if (err
) goto leave
;
3529 isds_list_free(users
);
3532 xmlXPathFreeObject(result
);
3533 xmlXPathFreeContext(xpath_ctx
);
3537 xmlFreeDoc(response
);
3540 isds_log(ILF_ISDS
, ILL_DEBUG
,
3541 _("GetUserInfoFromLogin request processed by server "
3542 "successfully.\n"));
3548 /* Get expiration time of current password
3549 * @context is session context
3550 * @expiration is automatically reallocated time when password expires, In
3551 * case of error will be nulled. */
3552 isds_error
isds_get_password_expiration(struct isds_ctx
*context
,
3553 struct timeval
**expiration
) {
3554 isds_error err
= IE_SUCCESS
;
3555 xmlDocPtr response
= NULL
;
3556 xmlChar
*code
= NULL
, *message
= NULL
;
3557 xmlXPathContextPtr xpath_ctx
= NULL
;
3558 xmlXPathObjectPtr result
= NULL
;
3559 char *string
= NULL
;
3561 if (!context
) return IE_INVALID_CONTEXT
;
3562 if (!expiration
) return IE_INVAL
;
3564 /* Check if connection is established */
3565 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3568 /* Do request and check for success */
3569 err
= build_send_check_dbdummy_request(context
,
3570 BAD_CAST
"GetPasswordInfo",
3571 &response
, NULL
, NULL
, &code
, &message
);
3572 if (err
) goto leave
;
3576 xpath_ctx
= xmlXPathNewContext(response
);
3581 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3586 /* Set context node */
3587 result
= xmlXPathEvalExpression(BAD_CAST
3588 "/isds:GetPasswordInfoResponse", xpath_ctx
);
3593 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3594 isds_log_message(context
,
3595 _("Missing GetPasswordInfoResponse element"));
3599 if (result
->nodesetval
->nodeNr
> 1) {
3600 isds_log_message(context
,
3601 _("Multiple GetPasswordInfoResponse element"));
3605 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3606 xmlXPathFreeObject(result
); result
= NULL
;
3608 /* Extract expiration date */
3609 EXTRACT_STRING("isds:pswExpDate", string
);
3611 isds_log_message(context
, _("Missing pswExpDate element"));
3616 err
= timestring2timeval((xmlChar
*) string
, expiration
);
3618 char *string_locale
= utf82locale(string
);
3619 if (err
== IE_DATE
) err
= IE_ISDS
;
3620 isds_printf_message(context
,
3621 _("Could not convert pswExpDate as ISO time: %s"),
3623 free(string_locale
);
3635 xmlXPathFreeObject(result
);
3636 xmlXPathFreeContext(xpath_ctx
);
3640 xmlFreeDoc(response
);
3643 isds_log(ILF_ISDS
, ILL_DEBUG
,
3644 _("GetPasswordInfo request processed by server "
3645 "successfully.\n"));
3651 /* Change user password in ISDS.
3652 * User must supply old password, new password will takes effect after some
3653 * time, current session can continue. Password must fulfill some constraints.
3654 * @context is session context
3655 * @old_password is current password.
3656 * @new_password is requested new password */
3657 isds_error
isds_change_password(struct isds_ctx
*context
,
3658 const char *old_password
, const char *new_password
) {
3659 isds_error err
= IE_SUCCESS
;
3660 xmlNsPtr isds_ns
= NULL
;
3661 xmlNodePtr request
= NULL
, node
;
3662 xmlDocPtr response
= NULL
;
3663 xmlChar
*code
= NULL
, *message
= NULL
;
3665 if (!context
) return IE_INVALID_CONTEXT
;
3666 if (!old_password
|| !new_password
) return IE_INVAL
;
3668 /* Check if connection is established
3669 * TODO: This check should be done donwstairs. */
3670 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3673 /* Build ChangeISDSPassword request */
3674 request
= xmlNewNode(NULL
, BAD_CAST
"ChangeISDSPassword");
3676 isds_log_message(context
,
3677 _("Could build ChangeISDSPassword request"));
3680 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3682 isds_log_message(context
, _("Could not create ISDS name space"));
3683 xmlFreeNode(request
);
3686 xmlSetNs(request
, isds_ns
);
3688 INSERT_STRING(request
, "dbOldPassword", old_password
);
3689 INSERT_STRING(request
, "dbNewPassword", new_password
);
3692 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
3695 err
= isds(context
, SERVICE_DB_ACCESS
, request
, &response
, NULL
, NULL
);
3697 /* Destroy request */
3698 xmlFreeNode(request
); request
= NULL
;
3701 isds_log(ILF_ISDS
, ILL_DEBUG
,
3702 _("Processing ISDS response on ChangeISDSPassword "
3703 "request failed\n"));
3707 /* Check for response status */
3708 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, response
,
3709 &code
, &message
, NULL
);
3711 isds_log(ILF_ISDS
, ILL_DEBUG
,
3712 _("ISDS response on ChangeISDSPassword request is missing "
3717 /* Request processed, but empty password refused */
3718 if (!xmlStrcmp(code
, BAD_CAST
"1066")) {
3719 char *code_locale
= utf82locale((char*)code
);
3720 char *message_locale
= utf82locale((char*)message
);
3721 isds_log(ILF_ISDS
, ILL_DEBUG
,
3722 _("Server refused empty password on ChangeISDSPassword "
3723 "request (code=%s, message=%s)\n"),
3724 code_locale
, message_locale
);
3725 isds_log_message(context
, _("Password must not be empty"));
3727 free(message_locale
);
3732 /* Request processed, but new password was reused */
3733 else if (!xmlStrcmp(code
, BAD_CAST
"1067")) {
3734 char *code_locale
= utf82locale((char*)code
);
3735 char *message_locale
= utf82locale((char*)message
);
3736 isds_log(ILF_ISDS
, ILL_DEBUG
,
3737 _("Server refused the same new password on ChangeISDSPassword "
3738 "request (code=%s, message=%s)\n"),
3739 code_locale
, message_locale
);
3740 isds_log_message(context
,
3741 _("New password must differ from the current one"));
3743 free(message_locale
);
3749 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3750 char *code_locale
= utf82locale((char*)code
);
3751 char *message_locale
= utf82locale((char*)message
);
3752 isds_log(ILF_ISDS
, ILL_DEBUG
,
3753 _("Server refused to change password on ChangeISDSPassword "
3754 "request (code=%s, message=%s)\n"),
3755 code_locale
, message_locale
);
3756 isds_log_message(context
, message_locale
);
3758 free(message_locale
);
3763 /* Otherwise password changed successfully */
3768 xmlFreeDoc(response
);
3769 xmlFreeNode(request
);
3772 isds_log(ILF_ISDS
, ILL_DEBUG
,
3773 _("Password changed successfully on ChangeISDSPassword "
3780 /* Find boxes suiting given criteria.
3781 * @criteria is filter. You should fill in at least some memebers.
3782 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
3783 * possibly empty. Input NULL or valid old structure.
3785 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
3786 * IE_NOEXIST if no such box exists, @boxes will be NULL
3787 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
3788 * contains still valid data
3789 * other code if something bad happens. @boxes will be NULL. */
3790 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
3791 const struct isds_DbOwnerInfo
*criteria
,
3792 struct isds_list
**boxes
) {
3793 isds_error err
= IE_SUCCESS
;
3794 _Bool truncated
= 0;
3795 xmlNsPtr isds_ns
= NULL
;
3796 xmlNodePtr request
= NULL
;
3797 xmlDocPtr response
= NULL
;
3798 xmlChar
*code
= NULL
, *message
= NULL
;
3799 xmlNodePtr db_owner_info
, node
;
3800 xmlXPathContextPtr xpath_ctx
= NULL
;
3801 xmlXPathObjectPtr result
= NULL
;
3802 xmlChar
*string
= NULL
;
3805 if (!context
) return IE_INVALID_CONTEXT
;
3806 if (!boxes
) return IE_INVAL
;
3807 isds_list_free(boxes
);
3813 /* Check if connection is established
3814 * TODO: This check should be done donwstairs. */
3815 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3818 /* Build FindDataBox request */
3819 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
3821 isds_log_message(context
,
3822 _("Could build FindDataBox request"));
3825 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3827 isds_log_message(context
, _("Could not create ISDS name space"));
3828 xmlFreeNode(request
);
3831 xmlSetNs(request
, isds_ns
);
3832 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
3833 if (!db_owner_info
) {
3834 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
3835 "FindDataBox element"));
3836 xmlFreeNode(request
);
3841 INSERT_STRING(db_owner_info
, "dbID", criteria
->dbID
);
3844 if (criteria
->dbType
) {
3845 const xmlChar
*type_string
= isds_DbType2string(*(criteria
->dbType
));
3847 isds_printf_message(context
, _("Invalid dbType value: %d"),
3848 *(criteria
->dbType
));
3852 INSERT_STRING(db_owner_info
, "dbType", type_string
);
3855 INSERT_STRING(db_owner_info
, "firmName", criteria
->firmName
);
3856 INSERT_STRING(db_owner_info
, "ic", criteria
->ic
);
3857 if (criteria
->personName
) {
3858 INSERT_STRING(db_owner_info
, "pnFirstName",
3859 criteria
->personName
->pnFirstName
);
3860 INSERT_STRING(db_owner_info
, "pnMiddleName",
3861 criteria
->personName
->pnMiddleName
);
3862 INSERT_STRING(db_owner_info
, "pnLastName",
3863 criteria
->personName
->pnLastName
);
3864 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
3865 criteria
->personName
->pnLastNameAtBirth
);
3867 if (criteria
->birthInfo
) {
3868 if (criteria
->birthInfo
->biDate
) {
3869 if (!tm2datestring(criteria
->birthInfo
->biDate
, &string
))
3870 INSERT_STRING(db_owner_info
, "biDate", string
);
3871 free(string
); string
= NULL
;
3873 INSERT_STRING(db_owner_info
, "biCity", criteria
->birthInfo
->biCity
);
3874 INSERT_STRING(db_owner_info
, "biCounty", criteria
->birthInfo
->biCounty
);
3875 INSERT_STRING(db_owner_info
, "biState", criteria
->birthInfo
->biState
);
3877 if (criteria
->address
) {
3878 INSERT_STRING(db_owner_info
, "adCity", criteria
->address
->adCity
);
3879 INSERT_STRING(db_owner_info
, "adStreet", criteria
->address
->adStreet
);
3880 INSERT_STRING(db_owner_info
, "adNumberInStreet",
3881 criteria
->address
->adNumberInStreet
);
3882 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
3883 criteria
->address
->adNumberInMunicipality
);
3884 INSERT_STRING(db_owner_info
, "adZipCode", criteria
->address
->adZipCode
);
3885 INSERT_STRING(db_owner_info
, "adState", criteria
->address
->adState
);
3887 INSERT_STRING(db_owner_info
, "nationality", criteria
->nationality
);
3888 INSERT_STRING(db_owner_info
, "email", criteria
->email
);
3889 INSERT_STRING(db_owner_info
, "telNumber", criteria
->telNumber
);
3890 INSERT_STRING(db_owner_info
, "identifier", criteria
->identifier
);
3891 INSERT_STRING(db_owner_info
, "registryCode", criteria
->registryCode
);
3893 INSERT_LONGINT(db_owner_info
, "dbState", criteria
->dbState
, string
);
3895 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", criteria
->dbEffectiveOVM
);
3896 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
3897 criteria
->dbOpenAddressing
);
3900 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
3903 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
3905 /* Destroy request */
3906 xmlFreeNode(request
); request
= NULL
;
3909 isds_log(ILF_ISDS
, ILL_DEBUG
,
3910 _("Processing ISDS response on FindDataBox "
3911 "request failed\n"));
3915 /* Check for response status */
3916 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
3917 &code
, &message
, NULL
);
3919 isds_log(ILF_ISDS
, ILL_DEBUG
,
3920 _("ISDS response on FindDataBox request is missing status\n"));
3924 /* Request processed, but nothing found */
3925 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
3926 !xmlStrcmp(code
, BAD_CAST
"5001")) {
3927 char *code_locale
= utf82locale((char*)code
);
3928 char *message_locale
= utf82locale((char*)message
);
3929 isds_log(ILF_ISDS
, ILL_DEBUG
,
3930 _("Server did not found any box on FindDataBox request "
3931 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
3932 isds_log_message(context
, message_locale
);
3934 free(message_locale
);
3939 /* Warning, not a error */
3940 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
3941 char *code_locale
= utf82locale((char*)code
);
3942 char *message_locale
= utf82locale((char*)message
);
3943 isds_log(ILF_ISDS
, ILL_DEBUG
,
3944 _("Server truncated response on FindDataBox request "
3945 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
3946 isds_log_message(context
, message_locale
);
3948 free(message_locale
);
3953 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3954 char *code_locale
= utf82locale((char*)code
);
3955 char *message_locale
= utf82locale((char*)message
);
3956 isds_log(ILF_ISDS
, ILL_DEBUG
,
3957 _("Server refused FindDataBox request "
3958 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
3959 isds_log_message(context
, message_locale
);
3961 free(message_locale
);
3966 xpath_ctx
= xmlXPathNewContext(response
);
3971 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3976 /* Extract boxes if they present */
3977 result
= xmlXPathEvalExpression(BAD_CAST
3978 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
3984 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3985 struct isds_list
*item
, *prev_item
= NULL
;
3986 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3987 item
= calloc(1, sizeof(*item
));
3993 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
3994 if (i
== 0) *boxes
= item
;
3995 else prev_item
->next
= item
;
3998 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3999 err
= extract_DbOwnerInfo(context
,
4000 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
4001 if (err
) goto leave
;
4007 isds_list_free(boxes
);
4009 if (truncated
) err
= IE_2BIG
;
4013 xmlFreeNode(request
);
4014 xmlXPathFreeObject(result
);
4015 xmlXPathFreeContext(xpath_ctx
);
4019 xmlFreeDoc(response
);
4022 isds_log(ILF_ISDS
, ILL_DEBUG
,
4023 _("FindDataBox request processed by server successfully.\n"));
4029 /* Get status of a box.
4030 * @context is ISDS session context.
4031 * @box_id is UTF-8 encoded box identifier as zero terminated string
4032 * @box_status is return value of box status.
4034 * IE_SUCCESS if box has been found and its status retrieved
4035 * IE_NOEXIST if box is not known to ISDS server
4036 * or other appropriate error.
4037 * You can use isds_DbState to enumerate box status. However out of enum
4038 * range value can be returned too. This is feature because ISDS
4039 * specification leaves the set of values open.
4040 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
4041 * the box has been deleted, but ISDS still lists its former existence. */
4042 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
4043 long int *box_status
) {
4044 isds_error err
= IE_SUCCESS
;
4045 xmlNsPtr isds_ns
= NULL
;
4046 xmlNodePtr request
= NULL
, db_id
;
4047 xmlDocPtr response
= NULL
;
4048 xmlChar
*code
= NULL
, *message
= NULL
;
4049 xmlXPathContextPtr xpath_ctx
= NULL
;
4050 xmlXPathObjectPtr result
= NULL
;
4051 xmlChar
*string
= NULL
;
4053 if (!context
) return IE_INVALID_CONTEXT
;
4054 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
4056 /* Check if connection is established
4057 * TODO: This check should be done donwstairs. */
4058 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4061 /* Build CheckDataBox request */
4062 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
4064 isds_log_message(context
,
4065 _("Could build CheckDataBox request"));
4068 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4070 isds_log_message(context
, _("Could not create ISDS name space"));
4071 xmlFreeNode(request
);
4074 xmlSetNs(request
, isds_ns
);
4075 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
4077 isds_log_message(context
, _("Could not add dbId Child to "
4078 "CheckDataBox element"));
4079 xmlFreeNode(request
);
4084 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
4087 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
4089 /* Destroy request */
4090 xmlFreeNode(request
);
4093 isds_log(ILF_ISDS
, ILL_DEBUG
,
4094 _("Processing ISDS response on CheckDataBox "
4095 "request failed\n"));
4099 /* Check for response status */
4100 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
4101 &code
, &message
, NULL
);
4103 isds_log(ILF_ISDS
, ILL_DEBUG
,
4104 _("ISDS response on CheckDataBox request is missing status\n"));
4108 /* Request processed, but nothing found */
4109 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
4110 char *box_id_locale
= utf82locale((char*)box_id
);
4111 char *code_locale
= utf82locale((char*)code
);
4112 char *message_locale
= utf82locale((char*)message
);
4113 isds_log(ILF_ISDS
, ILL_DEBUG
,
4114 _("Server did not found box %s on CheckDataBox request "
4115 "(code=%s, message=%s)\n"),
4116 box_id_locale
, code_locale
, message_locale
);
4117 isds_log_message(context
, message_locale
);
4118 free(box_id_locale
);
4120 free(message_locale
);
4126 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4127 char *code_locale
= utf82locale((char*)code
);
4128 char *message_locale
= utf82locale((char*)message
);
4129 isds_log(ILF_ISDS
, ILL_DEBUG
,
4130 _("Server refused CheckDataBox request "
4131 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
4132 isds_log_message(context
, message_locale
);
4134 free(message_locale
);
4140 xpath_ctx
= xmlXPathNewContext(response
);
4145 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4149 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
4155 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4156 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
4160 if (result
->nodesetval
->nodeNr
> 1) {
4161 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
4165 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4166 xmlXPathFreeObject(result
); result
= NULL
;
4168 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
4173 xmlXPathFreeObject(result
);
4174 xmlXPathFreeContext(xpath_ctx
);
4178 xmlFreeDoc(response
);
4181 isds_log(ILF_ISDS
, ILL_DEBUG
,
4182 _("CheckDataBox request processed by server successfully.\n"));
4188 /* Insert struct isds_message data (envelope (recipient data optional) and
4189 * documents) into XML tree
4190 * @context is sesstion context
4191 * @outgoing_message is libsids structure with message data
4192 * @create_message is XML CreateMessage or CreateMultipleMessage element
4193 * @process_recipient true for recipient data serialization, false for no
4195 static isds_error
insert_envelope_files(struct isds_ctx
*context
,
4196 const struct isds_message
*outgoing_message
, xmlNodePtr create_message
,
4197 const _Bool process_recipient
) {
4199 isds_error err
= IE_SUCCESS
;
4200 xmlNodePtr envelope
, dm_files
, node
;
4201 xmlChar
*string
= NULL
;
4203 if (!context
) return IE_INVALID_CONTEXT
;
4204 if (!outgoing_message
|| !create_message
) return IE_INVAL
;
4207 /* Build envelope */
4208 envelope
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
4210 isds_printf_message(context
, _("Could not add dmEnvelope child to "
4211 "%s element"), create_message
->name
);
4215 if (!outgoing_message
->envelope
) {
4216 isds_log_message(context
, _("Outgoing message is missing envelope"));
4221 INSERT_STRING(envelope
, "dmSenderOrgUnit",
4222 outgoing_message
->envelope
->dmSenderOrgUnit
);
4223 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
4224 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
4226 if (process_recipient
) {
4227 if (!outgoing_message
->envelope
->dbIDRecipient
) {
4228 isds_log_message(context
,
4229 _("Outgoing message is missing recipient box identifier"));
4233 INSERT_STRING(envelope
, "dbIDRecipient",
4234 outgoing_message
->envelope
->dbIDRecipient
);
4236 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
4237 outgoing_message
->envelope
->dmRecipientOrgUnit
);
4238 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
4239 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
4240 INSERT_STRING(envelope
, "dmToHands",
4241 outgoing_message
->envelope
->dmToHands
);
4244 #define CHECK_FOR_STRING_LENGTH(string, limit, name) \
4245 if ((string) && xmlUTF8Strlen((xmlChar *) (string)) > (limit)) { \
4246 isds_printf_message(context, \
4247 _("%s has more than %d characters"), (name), (limit)); \
4252 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 255,
4254 INSERT_STRING(envelope
, "dmAnnotation",
4255 outgoing_message
->envelope
->dmAnnotation
);
4257 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
4258 50, "dmRecipientRefNumber");
4259 INSERT_STRING(envelope
, "dmRecipientRefNumber",
4260 outgoing_message
->envelope
->dmRecipientRefNumber
);
4262 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
4263 50, "dmSenderRefNumber");
4264 INSERT_STRING(envelope
, "dmSenderRefNumber",
4265 outgoing_message
->envelope
->dmSenderRefNumber
);
4267 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
4268 50, "dmRecipientIdent");
4269 INSERT_STRING(envelope
, "dmRecipientIdent",
4270 outgoing_message
->envelope
->dmRecipientIdent
);
4272 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
4273 50, "dmSenderIdent");
4274 INSERT_STRING(envelope
, "dmSenderIdent",
4275 outgoing_message
->envelope
->dmSenderIdent
);
4277 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
4278 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
4279 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
4280 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
4281 INSERT_STRING(envelope
, "dmLegalTitleSect",
4282 outgoing_message
->envelope
->dmLegalTitleSect
);
4283 INSERT_STRING(envelope
, "dmLegalTitlePar",
4284 outgoing_message
->envelope
->dmLegalTitlePar
);
4285 INSERT_STRING(envelope
, "dmLegalTitlePoint",
4286 outgoing_message
->envelope
->dmLegalTitlePoint
);
4288 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
4289 outgoing_message
->envelope
->dmPersonalDelivery
);
4290 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
4291 outgoing_message
->envelope
->dmAllowSubstDelivery
);
4293 #undef CHECK_FOR_STRING_LENGTH
4295 /* ???: Should we require value for dbEffectiveOVM sender?
4296 * ISDS has default as true */
4297 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
4300 /* Append dmFiles */
4301 if (!outgoing_message
->documents
) {
4302 isds_log_message(context
,
4303 _("Outgoing message is missing list of documents"));
4307 dm_files
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmFiles", NULL
);
4309 isds_printf_message(context
, _("Could not add dmFiles child to "
4310 "%s element"), create_message
->name
);
4315 /* Check for document hieararchy */
4316 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
4317 if (err
) goto leave
;
4319 /* Process each document */
4320 for (struct isds_list
*item
=
4321 (struct isds_list
*) outgoing_message
->documents
;
4322 item
; item
= item
->next
) {
4324 isds_log_message(context
,
4325 _("List of documents contains empty item"));
4329 /* FIXME: Check for dmFileMetaType and for document references.
4330 * Only first document can be of MAIN type */
4331 err
= insert_document(context
, (struct isds_document
*) item
->data
,
4334 if (err
) goto leave
;
4343 /* Send a message via ISDS to a recipent
4344 * @context is session context
4345 * @outgoing_message is message to send; Some memebers are mandatory (like
4346 * dbIDRecipient), some are optional and some are irrelevant (especialy data
4347 * about sender). Included pointer to isds_list documents must contain at
4348 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
4349 * members will be filled with valid data from ISDS. Exact list of write
4350 * members is subject to change. Currently dmId is changed.
4351 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
4352 isds_error
isds_send_message(struct isds_ctx
*context
,
4353 struct isds_message
*outgoing_message
) {
4355 isds_error err
= IE_SUCCESS
;
4356 xmlNsPtr isds_ns
= NULL
;
4357 xmlNodePtr request
= NULL
;
4358 xmlDocPtr response
= NULL
;
4359 xmlChar
*code
= NULL
, *message
= NULL
;
4360 xmlXPathContextPtr xpath_ctx
= NULL
;
4361 xmlXPathObjectPtr result
= NULL
;
4362 _Bool message_is_complete
= 0;
4364 if (!context
) return IE_INVALID_CONTEXT
;
4365 if (!outgoing_message
) return IE_INVAL
;
4367 /* Check if connection is established
4368 * TODO: This check should be done donwstairs. */
4369 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4372 /* Build CreateMessage request */
4373 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
4375 isds_log_message(context
,
4376 _("Could build CreateMessage request"));
4379 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4381 isds_log_message(context
, _("Could not create ISDS name space"));
4382 xmlFreeNode(request
);
4385 xmlSetNs(request
, isds_ns
);
4387 /* Append envelope and files */
4388 err
= insert_envelope_files(context
, outgoing_message
, request
, 1);
4389 if (err
) goto leave
;
4392 /* Signal we can serilize message since now */
4393 message_is_complete
= 1;
4396 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
4399 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
4401 /* Dont' destroy request, we want to provide it to application later */
4404 isds_log(ILF_ISDS
, ILL_DEBUG
,
4405 _("Processing ISDS response on CreateMessage "
4406 "request failed\n"));
4410 /* Check for response status */
4411 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
4412 &code
, &message
, NULL
);
4414 isds_log(ILF_ISDS
, ILL_DEBUG
,
4415 _("ISDS response on CreateMessage request "
4416 "is missing status\n"));
4420 /* Request processed, but refused by server or server failed */
4421 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4422 char *box_id_locale
=
4423 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
4424 char *code_locale
= utf82locale((char*)code
);
4425 char *message_locale
= utf82locale((char*)message
);
4426 isds_log(ILF_ISDS
, ILL_DEBUG
,
4427 _("Server did not accept message for %s on CreateMessage "
4428 "request (code=%s, message=%s)\n"),
4429 box_id_locale
, code_locale
, message_locale
);
4430 isds_log_message(context
, message_locale
);
4431 free(box_id_locale
);
4433 free(message_locale
);
4440 xpath_ctx
= xmlXPathNewContext(response
);
4445 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4449 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
4455 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4456 isds_log_message(context
, _("Missing CreateMessageResponse element"));
4460 if (result
->nodesetval
->nodeNr
> 1) {
4461 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
4465 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4466 xmlXPathFreeObject(result
); result
= NULL
;
4468 if (outgoing_message
->envelope
->dmID
) {
4469 free(outgoing_message
->envelope
->dmID
);
4470 outgoing_message
->envelope
->dmID
= NULL
;
4472 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
4473 if (!outgoing_message
->envelope
->dmID
) {
4474 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
4475 "but did not returen assigned message ID\n"));
4479 /* TODO: Serialize message into structure member raw */
4480 /* XXX: Each web service transport message in different format.
4481 * Therefore it's not possible to save them directly.
4482 * To save them, one must figure out common format.
4483 * We can leave it on application, or we can implement the ESS format. */
4484 /*if (message_is_complete) {
4485 if (outgoing_message->envelope->dmID) {
4487 /* Add assigned message ID as first child*/
4488 /*xmlNodePtr dmid_text = xmlNewText(
4489 (xmlChar *) outgoing_message->envelope->dmID);
4490 if (!dmid_text) goto serialization_failed;
4492 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
4494 if (!dmid_element) {
4495 xmlFreeNode(dmid_text);
4496 goto serialization_failed;
4499 xmlNodePtr dmid_element_with_text =
4500 xmlAddChild(dmid_element, dmid_text);
4501 if (!dmid_element_with_text) {
4502 xmlFreeNode(dmid_element);
4503 xmlFreeNode(dmid_text);
4504 goto serialization_failed;
4507 node = xmlAddPrevSibling(envelope->childern,
4508 dmid_element_with_text);
4510 xmlFreeNodeList(dmid_element_with_text);
4511 goto serialization_failed;
4515 /* Serialize message with ID into raw */
4516 /*buffer = serialize_element(envelope)*/
4519 serialization_failed:
4524 xmlXPathFreeObject(result
);
4525 xmlXPathFreeContext(xpath_ctx
);
4529 xmlFreeDoc(response
);
4530 xmlFreeNode(request
);
4533 isds_log(ILF_ISDS
, ILL_DEBUG
,
4534 _("CreateMessage request processed by server "
4535 "successfully.\n"));
4541 /* Send a message via ISDS to a multiple recipents
4542 * @context is session context
4543 * @outgoing_message is message to send; Some memebers are mandatory,
4544 * some are optional and some are irrelevant (especialy data
4545 * about sender). Data about recipient will be substituted by ISDS from
4546 * @copies. Included pointer to isds_list documents must
4547 * contain at least one document of FILEMETATYPE_MAIN.
4548 * @copies is list of isds_message_copy structures addressing all desired
4549 * recipients. This is read-write structure, some members will be filled with
4550 * valid data from ISDS (message IDs, error codes, error descriptions).
4552 * ISDS_SUCCESS if all messages have been sent
4553 * ISDS_PARTIAL_SUCCESS if sending of some messages has failed (failed and
4554 * succesed messages can be identified by copies->data->error),
4555 * or other error code if something other goes wrong. */
4556 isds_error
isds_send_message_to_multiple_recipients(struct isds_ctx
*context
,
4557 const struct isds_message
*outgoing_message
,
4558 struct isds_list
*copies
) {
4560 isds_error err
= IE_SUCCESS
, append_err
;
4561 xmlNsPtr isds_ns
= NULL
;
4562 xmlNodePtr request
= NULL
, recipients
, recipient
, node
;
4563 struct isds_list
*item
;
4564 struct isds_message_copy
*copy
;
4565 xmlDocPtr response
= NULL
;
4566 xmlChar
*code
= NULL
, *message
= NULL
;
4567 xmlXPathContextPtr xpath_ctx
= NULL
;
4568 xmlXPathObjectPtr result
= NULL
;
4569 xmlChar
*string
= NULL
;
4572 if (!context
) return IE_INVALID_CONTEXT
;
4573 if (!outgoing_message
|| !copies
) return IE_INVAL
;
4575 /* Check if connection is established
4576 * TODO: This check should be done donwstairs. */
4577 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4580 /* Build CreateMultipleMessage request */
4581 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMultipleMessage");
4583 isds_log_message(context
,
4584 _("Could build CreateMultipleMessage request"));
4587 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4589 isds_log_message(context
, _("Could not create ISDS name space"));
4590 xmlFreeNode(request
);
4593 xmlSetNs(request
, isds_ns
);
4596 /* Build recipients */
4597 recipients
= xmlNewChild(request
, NULL
, BAD_CAST
"dmRecipients", NULL
);
4599 isds_log_message(context
, _("Could not add dmRecipients child to "
4600 "CreateMultipleMessage element"));
4601 xmlFreeNode(request
);
4605 /* Insert each recipient */
4606 for (item
= copies
; item
; item
= item
->next
) {
4607 copy
= (struct isds_message_copy
*) item
->data
;
4609 isds_log_message(context
,
4610 _("copies list item contains empty data"));
4615 recipient
= xmlNewChild(recipients
, NULL
, BAD_CAST
"dmRecipient", NULL
);
4617 isds_log_message(context
, _("Could not add dmRecipient child to "
4618 "dmRecipient element"));
4623 if (!copy
->dbIDRecipient
) {
4624 isds_log_message(context
,
4625 _("Message copy is missing recipient box identifier"));
4629 INSERT_STRING(recipient
, "dbIDRecipient", copy
->dbIDRecipient
);
4630 INSERT_STRING(recipient
, "dmRecipientOrgUnit",
4631 copy
->dmRecipientOrgUnit
);
4632 INSERT_LONGINT(recipient
, "dmRecipientOrgUnitNum",
4633 copy
->dmRecipientOrgUnitNum
, string
);
4634 INSERT_STRING(recipient
, "dmToHands", copy
->dmToHands
);
4637 /* Append envelope and files */
4638 err
= insert_envelope_files(context
, outgoing_message
, request
, 0);
4639 if (err
) goto leave
;
4642 isds_log(ILF_ISDS
, ILL_DEBUG
,
4643 _("Sending CreateMultipleMessage request to ISDS\n"));
4646 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
4648 isds_log(ILF_ISDS
, ILL_DEBUG
,
4649 _("Processing ISDS response on CreateMultipleMessage "
4650 "request failed\n"));
4654 /* Check for response status */
4655 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
4656 &code
, &message
, NULL
);
4658 isds_log(ILF_ISDS
, ILL_DEBUG
,
4659 _("ISDS response on CreateMultipleMessage request "
4660 "is missing status\n"));
4664 /* Request processed, but some copies failed */
4665 if (!xmlStrcmp(code
, BAD_CAST
"0004")) {
4666 char *box_id_locale
=
4667 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
4668 char *code_locale
= utf82locale((char*)code
);
4669 char *message_locale
= utf82locale((char*)message
);
4670 isds_log(ILF_ISDS
, ILL_DEBUG
,
4671 _("Server did accept message for multiple recipients "
4672 "on CreateMultipleMessage request but delivery to "
4673 "some of them failed (code=%s, message=%s)\n"),
4674 box_id_locale
, code_locale
, message_locale
);
4675 isds_log_message(context
, message_locale
);
4676 free(box_id_locale
);
4678 free(message_locale
);
4679 err
= IE_PARTIAL_SUCCESS
;
4682 /* Request refused by server as whole */
4683 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4684 char *box_id_locale
=
4685 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
4686 char *code_locale
= utf82locale((char*)code
);
4687 char *message_locale
= utf82locale((char*)message
);
4688 isds_log(ILF_ISDS
, ILL_DEBUG
,
4689 _("Server did not accept message for multiple recipients "
4690 "on CreateMultipleMessage request (code=%s, message=%s)\n"),
4691 box_id_locale
, code_locale
, message_locale
);
4692 isds_log_message(context
, message_locale
);
4693 free(box_id_locale
);
4695 free(message_locale
);
4702 xpath_ctx
= xmlXPathNewContext(response
);
4707 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4711 result
= xmlXPathEvalExpression(
4712 BAD_CAST
"/isds:CreateMultipleMessageResponse"
4713 "/isds:dmMultipleStatus/isds:dmSingleStatus",
4719 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4720 isds_log_message(context
, _("Missing isds:dmSingleStatus element"));
4725 /* Extract message ID and delivery status for each copy */
4726 for (item
= copies
, i
= 0; item
&& i
< result
->nodesetval
->nodeNr
;
4727 item
= item
->next
, i
++) {
4728 copy
= (struct isds_message_copy
*) item
->data
;
4729 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
4731 append_err
= append_TMStatus(context
, copy
, xpath_ctx
);
4737 if (item
|| i
< result
->nodesetval
->nodeNr
) {
4738 isds_printf_message(context
, _("ISDS returned unexpected number of "
4739 "message copy delivery states: %d"),
4740 result
->nodesetval
->nodeNr
);
4749 xmlXPathFreeObject(result
);
4750 xmlXPathFreeContext(xpath_ctx
);
4754 xmlFreeDoc(response
);
4755 xmlFreeNode(request
);
4758 isds_log(ILF_ISDS
, ILL_DEBUG
,
4759 _("CreateMultipleMessageResponse request processed by server "
4760 "successfully.\n"));
4766 /* Get list of messages. This is common core for getting sent or received
4768 * Any criterion argument can be NULL, if you don't care about it.
4769 * @context is session context. Must not be NULL.
4770 * @outgoing_direction is true if you want list of outgoing messages,
4771 * it's false if you want incoming messages.
4772 * @from_time is minimal time and date of message sending inclusive.
4773 * @to_time is maximal time and date of message sending inclusive
4774 * @organization_unit_number is number of sender/recipient respectively.
4775 * @status_filter is bit field of isds_message_status values. Use special
4776 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
4777 * all values, you can use bitwise arithmetic if you want.)
4778 * @offset is index of first message we are interested in. First message is 1.
4779 * Set to 0 (or 1) if you don't care.
4780 * @number is maximal length of list you want to get as input value, outputs
4781 * number of messages matching these criteria. Can be NULL if you don't care
4782 * (applies to output value either).
4783 * @messages is automatically reallocated list of isds_message's. Be ware that
4784 * it returns only brief overview (envelope and some other fields) about each
4785 * message, not the complete message. FIXME: Specify exact fields.
4786 * The list is sorted by delivery time in ascending order.
4788 * you don't care about don't need the data (useful if you want to know only
4789 * the @number). If you provide &NULL, list will be allocated on heap, if you
4790 * provide pointer to non-NULL, list will be freed automacally at first. Also
4791 * in case of error the list will be NULLed.
4792 * @return IE_SUCCESS or appropriate error code. */
4793 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
4794 _Bool outgoing_direction
,
4795 const struct timeval
*from_time
, const struct timeval
*to_time
,
4796 const long int *organization_unit_number
,
4797 const unsigned int status_filter
,
4798 const unsigned long int offset
, unsigned long int *number
,
4799 struct isds_list
**messages
) {
4801 isds_error err
= IE_SUCCESS
;
4802 xmlNsPtr isds_ns
= NULL
;
4803 xmlNodePtr request
= NULL
, node
;
4804 xmlDocPtr response
= NULL
;
4805 xmlChar
*code
= NULL
, *message
= NULL
;
4806 xmlXPathContextPtr xpath_ctx
= NULL
;
4807 xmlXPathObjectPtr result
= NULL
;
4808 xmlChar
*string
= NULL
;
4809 long unsigned int count
= 0;
4811 if (!context
) return IE_INVALID_CONTEXT
;
4813 /* Free former message list if any */
4814 if (messages
) isds_list_free(messages
);
4816 /* Check if connection is established
4817 * TODO: This check should be done donwstairs. */
4818 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4820 /* Build GetListOf*Messages request */
4821 request
= xmlNewNode(NULL
,
4822 (outgoing_direction
) ?
4823 BAD_CAST
"GetListOfSentMessages" :
4824 BAD_CAST
"GetListOfReceivedMessages"
4827 isds_log_message(context
,
4828 (outgoing_direction
) ?
4829 _("Could not build GetListOfSentMessages request") :
4830 _("Could not build GetListOfReceivedMessages request")
4834 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4836 isds_log_message(context
, _("Could not create ISDS name space"));
4837 xmlFreeNode(request
);
4840 xmlSetNs(request
, isds_ns
);
4844 err
= timeval2timestring(from_time
, &string
);
4845 if (err
) goto leave
;
4847 INSERT_STRING(request
, "dmFromTime", string
);
4848 free(string
); string
= NULL
;
4851 err
= timeval2timestring(to_time
, &string
);
4852 if (err
) goto leave
;
4854 INSERT_STRING(request
, "dmToTime", string
);
4855 free(string
); string
= NULL
;
4857 if (outgoing_direction
) {
4858 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
4859 organization_unit_number
, string
);
4861 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
4862 organization_unit_number
, string
);
4865 if (status_filter
> MESSAGESTATE_ANY
) {
4866 isds_printf_message(context
,
4867 _("Invalid message state filter value: %ld"), status_filter
);
4871 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
4874 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
4876 INSERT_STRING(request
, "dmOffset", "1");
4879 /* number 0 means no limit */
4880 if (number
&& *number
== 0) {
4881 INSERT_STRING(request
, "dmLimit", NULL
);
4883 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
4887 isds_log(ILF_ISDS
, ILL_DEBUG
,
4888 (outgoing_direction
) ?
4889 _("Sending GetListOfSentMessages request to ISDS\n") :
4890 _("Sending GetListOfReceivedMessages request to ISDS\n")
4894 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
, NULL
, NULL
);
4895 xmlFreeNode(request
); request
= NULL
;
4898 isds_log(ILF_ISDS
, ILL_DEBUG
,
4899 (outgoing_direction
) ?
4900 _("Processing ISDS response on GetListOfSentMessages "
4901 "request failed\n") :
4902 _("Processing ISDS response on GetListOfReceivedMessages "
4908 /* Check for response status */
4909 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
4910 &code
, &message
, NULL
);
4912 isds_log(ILF_ISDS
, ILL_DEBUG
,
4913 (outgoing_direction
) ?
4914 _("ISDS response on GetListOfSentMessages request "
4915 "is missing status\n") :
4916 _("ISDS response on GetListOfReceivedMessages request "
4917 "is missing status\n")
4922 /* Request processed, but nothing found */
4923 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4924 char *code_locale
= utf82locale((char*)code
);
4925 char *message_locale
= utf82locale((char*)message
);
4926 isds_log(ILF_ISDS
, ILL_DEBUG
,
4927 (outgoing_direction
) ?
4928 _("Server refused GetListOfSentMessages request "
4929 "(code=%s, message=%s)\n") :
4930 _("Server refused GetListOfReceivedMessages request "
4931 "(code=%s, message=%s)\n"),
4932 code_locale
, message_locale
);
4933 isds_log_message(context
, message_locale
);
4935 free(message_locale
);
4942 xpath_ctx
= xmlXPathNewContext(response
);
4947 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4951 result
= xmlXPathEvalExpression(
4952 (outgoing_direction
) ?
4953 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
4954 "isds:dmRecords/isds:dmRecord" :
4955 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
4956 "isds:dmRecords/isds:dmRecord",
4963 /* Fill output arguments in */
4964 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4965 struct isds_envelope
*envelope
;
4966 struct isds_list
*item
= NULL
, *last_item
= NULL
;
4968 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
4969 /* Create new message */
4970 item
= calloc(1, sizeof(*item
));
4975 item
->destructor
= (void(*)(void**)) &isds_message_free
;
4976 item
->data
= calloc(1, sizeof(struct isds_message
));
4978 isds_list_free(&item
);
4983 /* Extract envelope data */
4984 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
4986 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
4988 isds_list_free(&item
);
4992 /* Attach extracted envelope */
4993 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
4995 /* Append new message into the list */
4997 *messages
= last_item
= item
;
4999 last_item
->next
= item
;
5004 if (number
) *number
= count
;
5008 isds_list_free(messages
);
5012 xmlXPathFreeObject(result
);
5013 xmlXPathFreeContext(xpath_ctx
);
5017 xmlFreeDoc(response
);
5018 xmlFreeNode(request
);
5021 isds_log(ILF_ISDS
, ILL_DEBUG
,
5022 (outgoing_direction
) ?
5023 _("GetListOfSentMessages request processed by server "
5024 "successfully.\n") :
5025 _("GetListOfReceivedMessages request processed by server "
5032 /* Get list of outgoing (already sent) messages.
5033 * Any criterion argument can be NULL, if you don't care about it.
5034 * @context is session context. Must not be NULL.
5035 * @from_time is minimal time and date of message sending inclusive.
5036 * @to_time is maximal time and date of message sending inclusive
5037 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
5038 * @status_filter is bit field of isds_message_status values. Use special
5039 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
5040 * all values, you can use bitwise arithmetic if you want.)
5041 * @offset is index of first message we are interested in. First message is 1.
5042 * Set to 0 (or 1) if you don't care.
5043 * @number is maximal length of list you want to get as input value, outputs
5044 * number of messages matching these criteria. Can be NULL if you don't care
5045 * (applies to output value either).
5046 * @messages is automatically reallocated list of isds_message's. Be ware that
5047 * it returns only brief overview (envelope and some other fields) about each
5048 * message, not the complete message. FIXME: Specify exact fields.
5049 * The list is sorted by delivery time in ascending order.
5050 * Use NULL if you don't care about the metadata (useful if you want to know
5051 * only the @number). If you provide &NULL, list will be allocated on heap,
5052 * if you provide pointer to non-NULL, list will be freed automacally at first.
5053 * Also in case of error the list will be NULLed.
5054 * @return IE_SUCCESS or appropriate error code. */
5055 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
5056 const struct timeval
*from_time
, const struct timeval
*to_time
,
5057 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
5058 const unsigned long int offset
, unsigned long int *number
,
5059 struct isds_list
**messages
) {
5061 return isds_get_list_of_messages(
5063 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
5069 /* Get list of incoming (addressed to you) messages.
5070 * Any criterion argument can be NULL, if you don't care about it.
5071 * @context is session context. Must not be NULL.
5072 * @from_time is minimal time and date of message sending inclusive.
5073 * @to_time is maximal time and date of message sending inclusive
5074 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
5075 * @status_filter is bit field of isds_message_status values. Use special
5076 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
5077 * all values, you can use bitwise arithmetic if you want.)
5078 * @offset is index of first message we are interested in. First message is 1.
5079 * Set to 0 (or 1) if you don't care.
5080 * @number is maximal length of list you want to get as input value, outputs
5081 * number of messages matching these criteria. Can be NULL if you don't care
5082 * (applies to output value either).
5083 * @messages is automatically reallocated list of isds_message's. Be ware that
5084 * it returns only brief overview (envelope and some other fields) about each
5085 * message, not the complete message. FIXME: Specify exact fields.
5086 * Use NULL if you don't care about the metadata (useful if you want to know
5087 * only the @number). If you provide &NULL, list will be allocated on heap,
5088 * if you provide pointer to non-NULL, list will be freed automacally at first.
5089 * Also in case of error the list will be NULLed.
5090 * @return IE_SUCCESS or appropriate error code. */
5091 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
5092 const struct timeval
*from_time
, const struct timeval
*to_time
,
5093 const long int *dmRecipientOrgUnitNum
,
5094 const unsigned int status_filter
,
5095 const unsigned long int offset
, unsigned long int *number
,
5096 struct isds_list
**messages
) {
5098 return isds_get_list_of_messages(
5100 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
5106 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
5108 * @context is session context
5109 * @service is ISDS WS service handler
5110 * @service_name is name of SERVICE_DM_OPERATIONS
5111 * @message_id is message ID to send as service argument to ISDS
5112 * @response is server SOAP body response as XML document
5113 * @raw_response is automatically reallocated bitstream with response body. Use
5114 * NULL if you don't care
5115 * @raw_response_length is size of @raw_response in bytes
5116 * @code is ISDS status code
5117 * @status_message is ISDS status message
5118 * @return error coded from lower layer, context message will be set up
5120 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
5121 const isds_service service
, const xmlChar
*service_name
,
5122 const char *message_id
,
5123 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
5124 xmlChar
**code
, xmlChar
**status_message
) {
5126 isds_error err
= IE_SUCCESS
;
5127 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
5128 xmlNodePtr request
= NULL
, node
;
5129 xmlNsPtr isds_ns
= NULL
;
5131 if (!context
) return IE_INVALID_CONTEXT
;
5132 if (!service_name
|| !message_id
) return IE_INVAL
;
5133 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
5134 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
5136 /* Free output argument */
5137 xmlFreeDoc(*response
); *response
= NULL
;
5138 if (raw_response
) zfree(*raw_response
);
5140 free(*status_message
);
5143 /* Check if connection is established
5144 * TODO: This check should be done donwstairs. */
5145 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5147 service_name_locale
= utf82locale((char*)service_name
);
5148 message_id_locale
= utf82locale(message_id
);
5149 if (!service_name_locale
|| !message_id_locale
) {
5155 request
= xmlNewNode(NULL
, service_name
);
5157 isds_printf_message(context
,
5158 _("Could not build %s request"), service_name_locale
);
5162 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5164 isds_log_message(context
, _("Could not create ISDS name space"));
5168 xmlSetNs(request
, isds_ns
);
5171 /* Add requested ID */
5172 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
5173 if (err
) goto leave
;
5174 INSERT_STRING(request
, "dmID", message_id
);
5177 isds_log(ILF_ISDS
, ILL_DEBUG
,
5178 _("Sending %s request for %s message ID to ISDS\n"),
5179 service_name_locale
, message_id_locale
);
5182 err
= isds(context
, service
, request
, response
,
5183 raw_response
, raw_response_length
);
5184 xmlFreeNode(request
); request
= NULL
;
5187 isds_log(ILF_ISDS
, ILL_DEBUG
,
5188 _("Processing ISDS response on %s request failed\n"),
5189 service_name_locale
);
5193 /* Check for response status */
5194 err
= isds_response_status(context
, service
, *response
,
5195 code
, status_message
, NULL
);
5197 isds_log(ILF_ISDS
, ILL_DEBUG
,
5198 _("ISDS response on %s request is missing status\n"),
5199 service_name_locale
);
5203 /* Request processed, but nothing found */
5204 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
5205 char *code_locale
= utf82locale((char*) *code
);
5206 char *status_message_locale
= utf82locale((char*) *status_message
);
5207 isds_log(ILF_ISDS
, ILL_DEBUG
,
5208 _("Server refused %s request for %s message ID "
5209 "(code=%s, message=%s)\n"),
5210 service_name_locale
, message_id_locale
,
5211 code_locale
, status_message_locale
);
5212 isds_log_message(context
, status_message_locale
);
5214 free(status_message_locale
);
5220 free(message_id_locale
);
5221 free(service_name_locale
);
5222 xmlFreeNode(request
);
5227 /* Find dmSignature in ISDS response, extract decoded CMS structure, extract
5228 * signed data and free ISDS response.
5229 * @context is session context
5230 * @message_id is UTF-8 encoded message ID for loging purpose
5231 * @response is parsed XML document. It will be freed and NULLed in the middle
5232 * of function run to save memmory. This is not guaranted in case of error.
5233 * @request_name is name of ISDS request used to construct response root
5234 * element name and for logging purpose.
5235 * @raw is reallocated output buffer with DER encoded CMS data
5236 * @raw_length is size of @raw buffer in bytes
5237 * @returns standard error codes, in case of error, @raw will be freed and
5238 * NULLed, @response sometimes. */
5239 static isds_error
find_extract_signed_data_free_response(
5240 struct isds_ctx
*context
, const xmlChar
*message_id
,
5241 xmlDocPtr
*response
, const xmlChar
*request_name
,
5242 void **raw
, size_t *raw_length
) {
5244 isds_error err
= IE_SUCCESS
;
5245 char *xpath_expression
= NULL
;
5246 xmlXPathContextPtr xpath_ctx
= NULL
;
5247 xmlXPathObjectPtr result
= NULL
;
5248 char *encoded_structure
= NULL
;
5250 if (!context
) return IE_INVALID_CONTEXT
;
5251 if (!raw
) return IE_INVAL
;
5253 if (!message_id
|| !response
|| !*response
|| !request_name
|| !raw_length
)
5256 /* Build XPath expression */
5257 xpath_expression
= astrcat3("/isds:", (char *) request_name
,
5258 "Response/isds:dmSignature");
5259 if (!xpath_expression
) return IE_NOMEM
;
5262 xpath_ctx
= xmlXPathNewContext(*response
);
5267 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5271 result
= xmlXPathEvalExpression(BAD_CAST xpath_expression
, xpath_ctx
);
5276 /* Empty response */
5277 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5278 char *message_id_locale
= utf82locale((char*) message_id
);
5279 isds_printf_message(context
,
5280 _("Server did not return any signed data for mesage ID `%s' "
5282 message_id_locale
, request_name
);
5283 free(message_id_locale
);
5288 if (result
->nodesetval
->nodeNr
> 1) {
5289 char *message_id_locale
= utf82locale((char*) message_id
);
5290 isds_printf_message(context
,
5291 _("Server did return more signed data for message ID `%s' "
5293 message_id_locale
, request_name
);
5294 free(message_id_locale
);
5299 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5301 /* Extract PKCS#7 structure */
5302 EXTRACT_STRING(".", encoded_structure
);
5303 if (!encoded_structure
) {
5304 isds_log_message(context
, _("dmSignature element is empty"));
5307 /* Here we have delivery info as standalone CMS in encoded_structure.
5308 * We don't need any other data, free them: */
5309 xmlXPathFreeObject(result
); result
= NULL
;
5310 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
5311 xmlFreeDoc(*response
); *response
= NULL
;
5314 /* Decode PKCS#7 to DER format */
5315 *raw_length
= b64decode(encoded_structure
, raw
);
5316 if (*raw_length
== (size_t) -1) {
5317 isds_log_message(context
,
5318 _("Error while Base64-decoding PKCS#7 structure"));
5329 free(encoded_structure
);
5330 xmlXPathFreeObject(result
);
5331 xmlXPathFreeContext(xpath_ctx
);
5332 free(xpath_expression
);
5338 /* Download incoming message envelope identified by ID.
5339 * @context is session context
5340 * @message_id is message identifier (you can get them from
5341 * isds_get_list_of_received_messages())
5342 * @message is automatically reallocated message retrieved from ISDS.
5343 * It will miss documents per se. Use isds_get_received_message(), if you are
5344 * interrested in documents (content) too.
5345 * Returned hash and timestamp require documents to be verifiable. */
5346 isds_error
isds_get_received_envelope(struct isds_ctx
*context
,
5347 const char *message_id
, struct isds_message
**message
) {
5349 isds_error err
= IE_SUCCESS
;
5350 xmlDocPtr response
= NULL
;
5351 xmlChar
*code
= NULL
, *status_message
= NULL
;
5352 xmlXPathContextPtr xpath_ctx
= NULL
;
5353 xmlXPathObjectPtr result
= NULL
;
5355 if (!context
) return IE_INVALID_CONTEXT
;
5357 /* Free former message if any */
5358 if (!message
) return IE_INVAL
;
5359 isds_message_free(message
);
5361 /* Do request and check for success */
5362 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
5363 BAD_CAST
"MessageEnvelopeDownload", message_id
,
5364 &response
, NULL
, NULL
, &code
, &status_message
);
5365 if (err
) goto leave
;
5368 xpath_ctx
= xmlXPathNewContext(response
);
5373 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5377 result
= xmlXPathEvalExpression(
5378 BAD_CAST
"/isds:MessageEnvelopeDownloadResponse/"
5379 "isds:dmReturnedMessageEnvelope",
5385 /* Empty response */
5386 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5387 char *message_id_locale
= utf82locale((char*) message_id
);
5388 isds_printf_message(context
,
5389 _("Server did not return any envelope for ID `%s' "
5390 "on MessageEnvelopeDownload request"), message_id_locale
);
5391 free(message_id_locale
);
5396 if (result
->nodesetval
->nodeNr
> 1) {
5397 char *message_id_locale
= utf82locale((char*) message_id
);
5398 isds_printf_message(context
,
5399 _("Server did return more envelopes for ID `%s' "
5400 "on MessageEnvelopeDownload request"), message_id_locale
);
5401 free(message_id_locale
);
5406 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5408 /* Extract the envelope (= message without documents, hence 0) */
5409 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
5410 if (err
) goto leave
;
5413 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
5414 &(*message
)->raw_length
);
5418 isds_message_free(message
);
5421 xmlXPathFreeObject(result
);
5422 xmlXPathFreeContext(xpath_ctx
);
5425 free(status_message
);
5426 xmlFreeDoc(response
);
5429 isds_log(ILF_ISDS
, ILL_DEBUG
,
5430 _("MessageEnvelopeDownload request processed by server "
5437 /* Load delivery info of any format from buffer.
5438 * @context is session context
5439 * @raw_type advertises format of @buffer content. Only delivery info types
5441 * @buffer is DER encoded PKCS#7 structure with signed delivery info. You can
5442 * retrieve such data from message->raw after calling
5443 * isds_get_signed_delivery_info().
5444 * @length is length of buffer in bytes.
5445 * @message is automatically reallocated message parsed from @buffer.
5446 * @strategy selects how buffer will be attached into raw isds_message member.
5448 isds_error
isds_load_delivery_info(struct isds_ctx
*context
,
5449 const isds_raw_type raw_type
,
5450 const void *buffer
, const size_t length
,
5451 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
5453 isds_error err
= IE_SUCCESS
;
5454 message_ns_type message_ns
;
5455 xmlDocPtr message_doc
= NULL
;
5456 xmlXPathContextPtr xpath_ctx
= NULL
;
5457 xmlXPathObjectPtr result
= NULL
;
5458 void *xml_stream
= NULL
;
5459 size_t xml_stream_length
= 0;
5461 if (!context
) return IE_INVALID_CONTEXT
;
5462 if (!message
) return IE_INVAL
;
5463 isds_message_free(message
);
5464 if (!buffer
) return IE_INVAL
;
5467 /* Select buffer format and extract XML from CMS*/
5469 case RAWTYPE_DELIVERYINFO
:
5470 message_ns
= MESSAGE_NS_UNSIGNED
;
5471 xml_stream
= (void *) buffer
;
5472 xml_stream_length
= length
;
5475 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
5476 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
5477 xml_stream
= (void *) buffer
;
5478 xml_stream_length
= length
;
5481 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
5482 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
5483 err
= extract_cms_data(context
, buffer
, length
,
5484 &xml_stream
, &xml_stream_length
);
5485 if (err
) goto leave
;
5489 isds_log_message(context
, _("Bad raw delivery representation type"));
5494 isds_log(ILF_ISDS
, ILL_DEBUG
,
5495 _("Delivery info content:\n%.*s\nEnd of delivery info\n"),
5496 xml_stream_length
, xml_stream
);
5498 /* Convert delivery info XML stream into XPath context */
5499 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
5504 xpath_ctx
= xmlXPathNewContext(message_doc
);
5509 /* XXX: Name spaces mangled for signed delivery info:
5510 * http://isds.czechpoint.cz/v20/delivery:
5512 * <q:GetDeliveryInfoResponse xmlns:q="http://isds.czechpoint.cz/v20/delivery">
5514 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
5515 * <p:dmID>170272</p:dmID>
5518 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
5520 * </q:dmEvents>...</q:dmEvents>
5522 * </q:GetDeliveryInfoResponse>
5524 if (register_namespaces(xpath_ctx
, message_ns
)) {
5528 result
= xmlXPathEvalExpression(
5529 BAD_CAST
"/sisds:GetDeliveryInfoResponse/sisds:dmDelivery",
5535 /* Empty delivery info */
5536 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5537 isds_printf_message(context
,
5538 _("XML document ss not sisds:dmDelivery document"));
5542 /* More delivery infos */
5543 if (result
->nodesetval
->nodeNr
> 1) {
5544 isds_printf_message(context
,
5545 _("XML document has more sisds:dmDelivery elements"));
5549 /* One delivery info */
5550 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5552 /* Extract the envelope (= message without documents, hence 0).
5553 * XXX: extract_TReturnedMessage() can obtain attachments size,
5554 * but delivery info carries none. It's coded as option elements,
5555 * so it should work. */
5556 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
5557 if (err
) goto leave
;
5559 /* Extract events */
5560 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmEvents", xpath_ctx
);
5561 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
5562 if (err
) { err
= IE_ERROR
; goto leave
; }
5563 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
5564 if (err
) goto leave
;
5566 /* Append raw CMS structure into message */
5567 (*message
)->raw_type
= raw_type
;
5569 case BUFFER_DONT_STORE
:
5572 (*message
)->raw
= malloc(length
);
5573 if (!(*message
)->raw
) {
5577 memcpy((*message
)->raw
, buffer
, length
);
5578 (*message
)->raw_length
= length
;
5581 (*message
)->raw
= (void *) buffer
;
5582 (*message
)->raw_length
= length
;
5591 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
5592 isds_message_free(message
);
5595 xmlXPathFreeObject(result
);
5596 xmlXPathFreeContext(xpath_ctx
);
5597 xmlFreeDoc(message_doc
);
5598 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
5601 isds_log(ILF_ISDS
, ILL_DEBUG
,
5602 _("Delivery info loaded successfully.\n"));
5607 /* Download signed delivery infosheet of given message identified by ID.
5608 * @context is session context
5609 * @message_id is message identifier (you can get them from
5610 * isds_get_list_of_{sent,received}_messages())
5611 * @message is automatically reallocated message retrieved from ISDS.
5612 * It will miss documents per se. Use isds_get_signed_received_message(),
5613 * if you are interrested in documents (content). OTOH, only this function
5614 * can get list events message has gone through. */
5615 isds_error
isds_get_signed_delivery_info(struct isds_ctx
*context
,
5616 const char *message_id
, struct isds_message
**message
) {
5618 isds_error err
= IE_SUCCESS
;
5619 xmlDocPtr response
= NULL
;
5620 xmlChar
*code
= NULL
, *status_message
= NULL
;
5622 size_t raw_length
= 0;
5624 if (!context
) return IE_INVALID_CONTEXT
;
5626 /* Free former message if any */
5627 if (!message
) return IE_INVAL
;
5628 isds_message_free(message
);
5630 /* Do request and check for success */
5631 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
5632 BAD_CAST
"GetSignedDeliveryInfo", message_id
,
5633 &response
, NULL
, NULL
, &code
, &status_message
);
5634 if (err
) goto leave
;
5636 /* Find signed delivery info, extract it into raw and maybe free
5638 err
= find_extract_signed_data_free_response(context
,
5639 (xmlChar
*)message_id
, &response
,
5640 BAD_CAST
"GetSignedDeliveryInfo", &raw
, &raw_length
);
5641 if (err
) goto leave
;
5643 /* Parse delivery info */
5644 err
= isds_load_delivery_info(context
,
5645 RAWTYPE_CMS_SIGNED_DELIVERYINFO
, raw
, raw_length
,
5646 message
, BUFFER_MOVE
);
5647 if (err
) goto leave
;
5653 isds_message_free(message
);
5658 free(status_message
);
5659 xmlFreeDoc(response
);
5662 isds_log(ILF_ISDS
, ILL_DEBUG
,
5663 _("GetSignedDeliveryInfo request processed by server "
5670 /* Download delivery infosheet of given message identified by ID.
5671 * @context is session context
5672 * @message_id is message identifier (you can get them from
5673 * isds_get_list_of_{sent,received}_messages())
5674 * @message is automatically reallocated message retrieved from ISDS.
5675 * It will miss documents per se. Use isds_get_received_message(), if you are
5676 * interrested in documents (content). OTOH, only this function can get list
5677 * events message has gone through. */
5678 isds_error
isds_get_delivery_info(struct isds_ctx
*context
,
5679 const char *message_id
, struct isds_message
**message
) {
5681 isds_error err
= IE_SUCCESS
;
5682 xmlDocPtr response
= NULL
;
5683 xmlChar
*code
= NULL
, *status_message
= NULL
;
5684 xmlXPathContextPtr xpath_ctx
= NULL
;
5685 xmlXPathObjectPtr result
= NULL
;
5686 xmlNodePtr delivery_node
= NULL
;
5688 if (!context
) return IE_INVALID_CONTEXT
;
5690 /* Free former message if any */
5691 if (!message
) return IE_INVAL
;
5692 isds_message_free(message
);
5694 /* Do request and check for success */
5695 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
5696 BAD_CAST
"GetDeliveryInfo", message_id
,
5697 &response
, NULL
, NULL
, &code
, &status_message
);
5698 if (err
) goto leave
;
5701 xpath_ctx
= xmlXPathNewContext(response
);
5706 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5710 result
= xmlXPathEvalExpression(
5711 BAD_CAST
"/isds:GetDeliveryInfoResponse/isds:dmDelivery",
5717 /* Empty response */
5718 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5719 char *message_id_locale
= utf82locale((char*) message_id
);
5720 isds_printf_message(context
,
5721 _("Server did not return any delivery info for ID `%s' "
5722 "on GetDeliveryInfo request"), message_id_locale
);
5723 free(message_id_locale
);
5727 /* More delivery infos */
5728 if (result
->nodesetval
->nodeNr
> 1) {
5729 char *message_id_locale
= utf82locale((char*) message_id
);
5730 isds_printf_message(context
,
5731 _("Server did return more delivery infos for ID `%s' "
5732 "on GetDeliveryInfo request"), message_id_locale
);
5733 free(message_id_locale
);
5737 /* One delivery info */
5738 xpath_ctx
->node
= delivery_node
= result
->nodesetval
->nodeTab
[0];
5740 /* Extract the envelope (= message without documents, hence 0).
5741 * XXX: extract_TReturnedMessage() can obtain attachments size,
5742 * but delivery info carries none. It's coded as option elements,
5743 * so it should work. */
5744 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
5745 if (err
) goto leave
;
5747 /* Extract events */
5748 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmEvents", xpath_ctx
);
5749 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
5750 if (err
) { err
= IE_ERROR
; goto leave
; }
5751 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
5752 if (err
) goto leave
;
5755 err
= serialize_subtree(context
, delivery_node
, &(*message
)->raw
,
5756 &(*message
)->raw_length
);
5760 isds_message_free(message
);
5763 xmlXPathFreeObject(result
);
5764 xmlXPathFreeContext(xpath_ctx
);
5767 free(status_message
);
5768 xmlFreeDoc(response
);
5771 isds_log(ILF_ISDS
, ILL_DEBUG
,
5772 _("GetDeliveryInfo request processed by server "
5779 /* Load incoming message from buffer.
5780 * @context is session context
5781 * @buffer XML stream with unsigned message. You can retrieve such data from
5782 * message->raw after calling isds_get_received_message().
5783 * @length is length of buffer in bytes.
5784 * @message is automatically reallocated message parsed from @buffer.
5785 * @strategy selects how buffer will be attached into raw isds_message member.
5787 isds_error
isds_load_received_message(struct isds_ctx
*context
,
5788 const void *buffer
, const size_t length
,
5789 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
5791 isds_error err
= IE_SUCCESS
;
5792 xmlDocPtr message_doc
= NULL
;
5793 xmlXPathContextPtr xpath_ctx
= NULL
;
5794 xmlXPathObjectPtr result
= NULL
;
5796 if (!context
) return IE_INVALID_CONTEXT
;
5797 if (!message
) return IE_INVAL
;
5798 isds_message_free(message
);
5799 if (!buffer
) return IE_INVAL
;
5802 isds_log(ILF_ISDS
, ILL_DEBUG
,
5803 _("Incoming message content:\n%.*s\nEnd of message\n"),
5806 /* Convert extracted messages XML stream into XPath context */
5807 message_doc
= xmlParseMemory(buffer
, length
);
5812 xpath_ctx
= xmlXPathNewContext(message_doc
);
5817 /* XXX: Standard name space */
5818 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5822 result
= xmlXPathEvalExpression(
5823 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
5829 /* Missing dmReturnedMessage */
5830 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5831 isds_printf_message(context
,
5832 _("XML document does not contain isds:dmReturnedMessage "
5837 /* More elements. This should never happen. */
5838 if (result
->nodesetval
->nodeNr
> 1) {
5839 isds_printf_message(context
,
5840 _("XML document has more isds:dmReturnedMessage elements"));
5845 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5847 /* Extract the message */
5848 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
5849 if (err
) goto leave
;
5851 /* Append XML stream into message */
5852 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
5854 case BUFFER_DONT_STORE
:
5857 (*message
)->raw
= malloc(length
);
5858 if (!(*message
)->raw
) {
5862 memcpy((*message
)->raw
, buffer
, length
);
5863 (*message
)->raw_length
= length
;
5866 (*message
)->raw
= (void *) buffer
;
5867 (*message
)->raw_length
= length
;
5876 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
5877 isds_message_free(message
);
5880 xmlFreeDoc(message_doc
);
5881 xmlXPathFreeObject(result
);
5882 xmlXPathFreeContext(xpath_ctx
);
5885 isds_log(ILF_ISDS
, ILL_DEBUG
,
5886 _("Incoming message loaded successfully.\n"));
5891 /* Download incoming message identified by ID.
5892 * @context is session context
5893 * @message_id is message identifier (you can get them from
5894 * isds_get_list_of_received_messages())
5895 * @message is automatically reallocated message retrieved from ISDS */
5896 isds_error
isds_get_received_message(struct isds_ctx
*context
,
5897 const char *message_id
, struct isds_message
**message
) {
5899 isds_error err
= IE_SUCCESS
;
5900 xmlDocPtr response
= NULL
;
5901 void *xml_stream
= NULL
;
5902 size_t xml_stream_length
;
5903 xmlChar
*code
= NULL
, *status_message
= NULL
;
5904 xmlXPathContextPtr xpath_ctx
= NULL
;
5905 xmlXPathObjectPtr result
= NULL
;
5906 char *phys_path
= NULL
;
5907 size_t phys_start
, phys_end
;
5909 if (!context
) return IE_INVALID_CONTEXT
;
5911 /* Free former message if any */
5912 if (message
) isds_message_free(message
);
5914 /* Do request and check for success */
5915 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
5916 BAD_CAST
"MessageDownload", message_id
,
5917 &response
, &xml_stream
, &xml_stream_length
,
5918 &code
, &status_message
);
5919 if (err
) goto leave
;
5922 xpath_ctx
= xmlXPathNewContext(response
);
5927 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5931 result
= xmlXPathEvalExpression(
5932 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
5938 /* Empty response */
5939 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5940 char *message_id_locale
= utf82locale((char*) message_id
);
5941 isds_printf_message(context
,
5942 _("Server did not return any message for ID `%s' "
5943 "on MessageDownload request"), message_id_locale
);
5944 free(message_id_locale
);
5949 if (result
->nodesetval
->nodeNr
> 1) {
5950 char *message_id_locale
= utf82locale((char*) message_id
);
5951 isds_printf_message(context
,
5952 _("Server did return more messages for ID `%s' "
5953 "on MessageDownload request"), message_id_locale
);
5954 free(message_id_locale
);
5959 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5961 /* Extract the message */
5962 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
5963 if (err
) goto leave
;
5965 /* Locate raw XML blob */
5967 SOAP_NS PHYSXML_NS_SEPARATOR
"Envelope"
5968 PHYSXML_ELEMENT_SEPARATOR
5969 SOAP_NS PHYSXML_NS_SEPARATOR
"Body"
5970 PHYSXML_ELEMENT_SEPARATOR
5971 ISDS_NS PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
5977 err
= find_element_boundary(xml_stream
, xml_stream_length
,
5978 phys_path
, &phys_start
, &phys_end
);
5981 isds_log_message(context
,
5982 _("Substring with isds:MessageDownloadResponse element "
5983 "could not be located in raw SOAP message"));
5987 /*err = serialize_subtree(context, xpath_ctx->node, &(*message)->raw,
5988 &(*message)->raw_length);*/
5989 /* TODO: Store name space declarations from ancestors */
5990 /* TODO: Handle non-UTF-8 encoding (XML prologue) */
5991 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
5992 (*message
)->raw_length
= phys_end
- phys_start
+ 1;
5993 (*message
)->raw
= malloc((*message
)->raw_length
);
5994 if (!(*message
)->raw
) {
5998 memcpy((*message
)->raw
, xml_stream
+ phys_start
, (*message
)->raw_length
);
6003 isds_message_free(message
);
6008 xmlXPathFreeObject(result
);
6009 xmlXPathFreeContext(xpath_ctx
);
6012 free(status_message
);
6014 xmlFreeDoc(response
);
6017 isds_log(ILF_ISDS
, ILL_DEBUG
,
6018 _("MessageDownload request processed by server "
6025 /* Load signed message from buffer.
6026 * @context is session context
6027 * @outgoing is true if message is outgoing, false if message is incoming
6028 * @buffer is DER encoded PKCS#7 structure with signed message. You can
6029 * retrieve such data from message->raw after calling
6030 * isds_get_signed_{received,sent}_message().
6031 * @length is length of buffer in bytes.
6032 * @message is automatically reallocated message parsed from @buffer.
6033 * @strategy selects how buffer will be attached into raw isds_message member.
6035 isds_error
isds_load_signed_message(struct isds_ctx
*context
,
6036 const _Bool outgoing
, const void *buffer
, const size_t length
,
6037 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
6039 isds_error err
= IE_SUCCESS
;
6040 xmlDocPtr message_doc
= NULL
;
6041 xmlXPathContextPtr xpath_ctx
= NULL
;
6042 xmlXPathObjectPtr result
= NULL
;
6043 void *xml_stream
= NULL
;
6044 size_t xml_stream_length
= 0;
6046 if (!context
) return IE_INVALID_CONTEXT
;
6047 if (!message
) return IE_INVAL
;
6048 isds_message_free(message
);
6049 if (!buffer
) return IE_INVAL
;
6052 /* Extract message from PKCS#7 structure */
6053 err
= extract_cms_data(context
, buffer
, length
,
6054 &xml_stream
, &xml_stream_length
);
6055 if (err
) goto leave
;
6057 isds_log(ILF_ISDS
, ILL_DEBUG
, (outgoing
) ?
6058 _("Signed outgoing message content:\n%.*s\nEnd of message\n") :
6059 _("Signed incoming message content:\n%.*s\nEnd of message\n"),
6060 xml_stream_length
, xml_stream
);
6062 /* Convert extracted messages XML stream into XPath context */
6063 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
6068 xpath_ctx
= xmlXPathNewContext(message_doc
);
6073 /* XXX: Name spaces mangled for outgoing direction:
6074 * http://isds.czechpoint.cz/v20/SentMessage:
6076 * <q:MessageDownloadResponse
6077 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
6078 * <q:dmReturnedMessage>
6079 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6080 * <p:dmID>151916</p:dmID>
6083 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6085 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
6086 * </q:dmReturnedMessage>
6087 * </q:MessageDownloadResponse>
6089 * XXX: Name spaces mangled for incoming direction:
6090 * http://isds.czechpoint.cz/v20/message:
6092 * <q:MessageDownloadResponse
6093 * xmlns:q="http://isds.czechpoint.cz/v20/message">
6094 * <q:dmReturnedMessage>
6095 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6096 * <p:dmID>151916</p:dmID>
6099 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6101 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
6102 * </q:dmReturnedMessage>
6103 * </q:MessageDownloadResponse>
6105 * Stupidity of ISDS developers is unlimited */
6106 if (register_namespaces(xpath_ctx
, (outgoing
) ?
6107 MESSAGE_NS_SIGNED_OUTGOING
: MESSAGE_NS_SIGNED_INCOMING
)) {
6111 /* XXX: Embeded message XML document is always rooted as
6112 * /sisds:MessageDownloadResponse (even outgoing message). */
6113 result
= xmlXPathEvalExpression(
6114 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
6120 /* Empty embedded message */
6121 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6122 isds_printf_message(context
,
6123 _("XML document embedded into PKCS#7 structure is not "
6124 "sisds:dmReturnedMessage document"));
6128 /* More embedded messages */
6129 if (result
->nodesetval
->nodeNr
> 1) {
6130 isds_printf_message(context
,
6131 _("Embeded XML document into PKCS#7 structure has more "
6132 "root sisds:dmReturnedMessage elements"));
6136 /* One embedded message */
6137 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6139 /* Extract the message */
6140 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
6141 if (err
) goto leave
;
6143 /* Append raw CMS structure into message */
6144 (*message
)->raw_type
= (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
6145 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
;
6147 case BUFFER_DONT_STORE
:
6150 (*message
)->raw
= malloc(length
);
6151 if (!(*message
)->raw
) {
6155 memcpy((*message
)->raw
, buffer
, length
);
6156 (*message
)->raw_length
= length
;
6159 (*message
)->raw
= (void *) buffer
;
6160 (*message
)->raw_length
= length
;
6170 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
6171 isds_message_free(message
);
6174 xmlFreeDoc(message_doc
);
6175 cms_data_free(xml_stream
);
6176 xmlXPathFreeObject(result
);
6177 xmlXPathFreeContext(xpath_ctx
);
6180 isds_log(ILF_ISDS
, ILL_DEBUG
,
6181 _("Signed message loaded successfully.\n"));
6186 /* Load message of any type from buffer.
6187 * @context is session context
6188 * @raw_type defines content type of @buffer. Only message types are allowed.
6189 * @buffer is message raw representation. Format (CMS, plain signed,
6190 * message direction) is defined in @raw_type. You can retrieve such data
6191 * from message->raw after calling isds_get_[signed]{received,sent}_message().
6192 * @length is length of buffer in bytes.
6193 * @message is automatically reallocated message parsed from @buffer.
6194 * @strategy selects how buffer will be attached into raw isds_message member.
6196 isds_error
isds_load_message(struct isds_ctx
*context
,
6197 const isds_raw_type raw_type
, const void *buffer
, const size_t length
,
6198 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
6200 isds_error err
= IE_SUCCESS
;
6201 void *xml_stream
= NULL
;
6202 size_t xml_stream_length
= 0;
6203 message_ns_type message_ns
;
6204 xmlDocPtr message_doc
= NULL
;
6205 xmlXPathContextPtr xpath_ctx
= NULL
;
6206 xmlXPathObjectPtr result
= NULL
;
6208 if (!context
) return IE_INVALID_CONTEXT
;
6209 if (!message
) return IE_INVAL
;
6210 isds_message_free(message
);
6211 if (!buffer
) return IE_INVAL
;
6214 /* Select buffer format and extract XML from CMS*/
6216 case RAWTYPE_INCOMING_MESSAGE
:
6217 message_ns
= MESSAGE_NS_UNSIGNED
;
6218 xml_stream
= (void *) buffer
;
6219 xml_stream_length
= length
;
6222 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
6223 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
6224 xml_stream
= (void *) buffer
;
6225 xml_stream_length
= length
;
6228 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
6229 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
6230 err
= extract_cms_data(context
, buffer
, length
,
6231 &xml_stream
, &xml_stream_length
);
6232 if (err
) goto leave
;
6235 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
6236 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
6237 xml_stream
= (void *) buffer
;
6238 xml_stream_length
= length
;
6241 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
6242 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
6243 err
= extract_cms_data(context
, buffer
, length
,
6244 &xml_stream
, &xml_stream_length
);
6245 if (err
) goto leave
;
6249 isds_log_message(context
, _("Bad raw message representation type"));
6254 isds_log(ILF_ISDS
, ILL_DEBUG
,
6255 _("Loading message:\n%.*s\nEnd of message\n"),
6256 xml_stream_length
, xml_stream
);
6258 /* Convert messages XML stream into XPath context */
6259 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
6264 xpath_ctx
= xmlXPathNewContext(message_doc
);
6269 /* XXX: Standard name space for unsigned icoming direction:
6270 * http://isds.czechpoint.cz/v20/SentMessage
6272 * XXX: Name spaces mangled for signed outgoing direction:
6273 * http://isds.czechpoint.cz/v20/SentMessage:
6275 * <q:MessageDownloadResponse
6276 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
6277 * <q:dmReturnedMessage>
6278 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6279 * <p:dmID>151916</p:dmID>
6282 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6284 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
6285 * </q:dmReturnedMessage>
6286 * </q:MessageDownloadResponse>
6288 * XXX: Name spaces mangled for signed incoming direction:
6289 * http://isds.czechpoint.cz/v20/message:
6291 * <q:MessageDownloadResponse
6292 * xmlns:q="http://isds.czechpoint.cz/v20/message">
6293 * <q:dmReturnedMessage>
6294 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6295 * <p:dmID>151916</p:dmID>
6298 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6300 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
6301 * </q:dmReturnedMessage>
6302 * </q:MessageDownloadResponse>
6304 * Stupidity of ISDS developers is unlimited */
6305 if (register_namespaces(xpath_ctx
, message_ns
)) {
6309 result
= xmlXPathEvalExpression(
6310 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
6317 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6318 isds_printf_message(context
,
6319 _("XML document does not contain "
6320 "sisds:dmReturnedMessage element"));
6325 if (result
->nodesetval
->nodeNr
> 1) {
6326 isds_printf_message(context
,
6327 _("XML document has more sisds:dmReturnedMessage elements"));
6332 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6334 /* Extract the message */
6335 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
6336 if (err
) goto leave
;
6338 /* Append raw buffer into message */
6339 (*message
)->raw_type
= raw_type
;
6341 case BUFFER_DONT_STORE
:
6344 (*message
)->raw
= malloc(length
);
6345 if (!(*message
)->raw
) {
6349 memcpy((*message
)->raw
, buffer
, length
);
6350 (*message
)->raw_length
= length
;
6353 (*message
)->raw
= (void *) buffer
;
6354 (*message
)->raw_length
= length
;
6364 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
6365 isds_message_free(message
);
6368 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
6369 xmlXPathFreeObject(result
);
6370 xmlXPathFreeContext(xpath_ctx
);
6371 xmlFreeDoc(message_doc
);
6374 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Message loaded successfully.\n"));
6379 /* Download signed incoming/outgoing message identified by ID.
6380 * @context is session context
6381 * @output is true for outging message, false for incoming message
6382 * @message_id is message identifier (you can get them from
6383 * isds_get_list_of_{sent,received}_messages())
6384 * @message is automatically reallocated message retrieved from ISDS. The raw
6385 * memeber will be filled with PKCS#7 structure in DER format. */
6386 _hidden isds_error
isds_get_signed_message(struct isds_ctx
*context
,
6387 const _Bool outgoing
, const char *message_id
,
6388 struct isds_message
**message
) {
6390 isds_error err
= IE_SUCCESS
;
6391 xmlDocPtr response
= NULL
;
6392 xmlChar
*code
= NULL
, *status_message
= NULL
;
6393 xmlXPathContextPtr xpath_ctx
= NULL
;
6394 xmlXPathObjectPtr result
= NULL
;
6395 char *encoded_structure
= NULL
;
6397 size_t raw_length
= 0;
6399 if (!context
) return IE_INVALID_CONTEXT
;
6400 if (!message
) return IE_INVAL
;
6401 isds_message_free(message
);
6403 /* Do request and check for success */
6404 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
6405 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
6406 BAD_CAST
"SignedMessageDownload",
6407 message_id
, &response
, NULL
, NULL
, &code
, &status_message
);
6408 if (err
) goto leave
;
6410 /* Find signed message, extract it into raw and maybe free
6412 err
= find_extract_signed_data_free_response(context
,
6413 (xmlChar
*)message_id
, &response
,
6414 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
6415 BAD_CAST
"SignedMessageDownload",
6417 if (err
) goto leave
;
6420 err
= isds_load_message(context
,
6421 (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
6422 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
,
6423 raw
, raw_length
, message
, BUFFER_MOVE
);
6424 if (err
) goto leave
;
6430 isds_message_free(message
);
6433 free(encoded_structure
);
6434 xmlXPathFreeObject(result
);
6435 xmlXPathFreeContext(xpath_ctx
);
6439 free(status_message
);
6440 xmlFreeDoc(response
);
6443 isds_log(ILF_ISDS
, ILL_DEBUG
,
6445 _("SignedSentMessageDownload request processed by server "
6446 "successfully.\n") :
6447 _("SignedMessageDownload request processed by server "
6454 /* Download signed incoming message identified by ID.
6455 * @context is session context
6456 * @message_id is message identifier (you can get them from
6457 * isds_get_list_of_received_messages())
6458 * @message is automatically reallocated message retrieved from ISDS. The raw
6459 * memeber will be filled with PKCS#7 structure in DER format. */
6460 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
6461 const char *message_id
, struct isds_message
**message
) {
6462 return isds_get_signed_message(context
, 0, message_id
, message
);
6466 /* Download signed outgoing message identified by ID.
6467 * @context is session context
6468 * @message_id is message identifier (you can get them from
6469 * isds_get_list_of_sent_messages())
6470 * @message is automatically reallocated message retrieved from ISDS. The raw
6471 * memeber will be filled with PKCS#7 structure in DER format. */
6472 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
6473 const char *message_id
, struct isds_message
**message
) {
6474 return isds_get_signed_message(context
, 1, message_id
, message
);
6478 /* Retrieve hash of message identified by ID stored in ISDS.
6479 * @context is session context
6480 * @message_id is message identifier
6481 * @hash is automatically reallocated message hash downloaded from ISDS.
6482 * Message must exist in system and must not be deleted. */
6483 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
6484 const char *message_id
, struct isds_hash
**hash
) {
6486 isds_error err
= IE_SUCCESS
;
6487 xmlDocPtr response
= NULL
;
6488 xmlChar
*code
= NULL
, *status_message
= NULL
;
6489 xmlXPathContextPtr xpath_ctx
= NULL
;
6490 xmlXPathObjectPtr result
= NULL
;
6492 if (!context
) return IE_INVALID_CONTEXT
;
6494 isds_hash_free(hash
);
6496 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6497 BAD_CAST
"VerifyMessage", message_id
,
6498 &response
, NULL
, NULL
, &code
, &status_message
);
6499 if (err
) goto leave
;
6503 xpath_ctx
= xmlXPathNewContext(response
);
6508 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6512 result
= xmlXPathEvalExpression(
6513 BAD_CAST
"/isds:VerifyMessageResponse",
6519 /* Empty response */
6520 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6521 char *message_id_locale
= utf82locale((char*) message_id
);
6522 isds_printf_message(context
,
6523 _("Server did not return any response for ID `%s' "
6524 "on VerifyMessage request"), message_id_locale
);
6525 free(message_id_locale
);
6529 /* More responses */
6530 if (result
->nodesetval
->nodeNr
> 1) {
6531 char *message_id_locale
= utf82locale((char*) message_id
);
6532 isds_printf_message(context
,
6533 _("Server did return more responses for ID `%s' "
6534 "on VerifyMessage request"), message_id_locale
);
6535 free(message_id_locale
);
6540 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6542 /* Extract the hash */
6543 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
6547 isds_hash_free(hash
);
6550 xmlXPathFreeObject(result
);
6551 xmlXPathFreeContext(xpath_ctx
);
6554 free(status_message
);
6555 xmlFreeDoc(response
);
6558 isds_log(ILF_ISDS
, ILL_DEBUG
,
6559 _("VerifyMessage request processed by server "
6566 /* Mark message as read. This is a transactional commit function to acknoledge
6567 * to ISDS the message has been downloaded and processed by client properly.
6568 * @context is session context
6569 * @message_id is message identifier. */
6570 isds_error
isds_mark_message_read(struct isds_ctx
*context
,
6571 const char *message_id
) {
6573 isds_error err
= IE_SUCCESS
;
6574 xmlDocPtr response
= NULL
;
6575 xmlChar
*code
= NULL
, *status_message
= NULL
;
6577 if (!context
) return IE_INVALID_CONTEXT
;
6579 /* Do request and check for success */
6580 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6581 BAD_CAST
"MarkMessageAsDownloaded", message_id
,
6582 &response
, NULL
, NULL
, &code
, &status_message
);
6585 free(status_message
);
6586 xmlFreeDoc(response
);
6589 isds_log(ILF_ISDS
, ILL_DEBUG
,
6590 _("MarkMessageAsDownloaded request processed by server "
6596 /* Mark message as received by recipient. This is applicable only to
6597 * commercial message. There is no specified way how to distinguishe
6598 * commercial message from government message yet. Government message is
6599 * received automatically (by law), commenrcial message on recipient request.
6600 * @context is session context
6601 * @message_id is message identifier. */
6602 isds_error
isds_mark_message_received(struct isds_ctx
*context
,
6603 const char *message_id
) {
6605 isds_error err
= IE_SUCCESS
;
6606 xmlDocPtr response
= NULL
;
6607 xmlChar
*code
= NULL
, *status_message
= NULL
;
6609 if (!context
) return IE_INVALID_CONTEXT
;
6611 /* Do request and check for success */
6612 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6613 BAD_CAST
"ConfirmDelivery", message_id
,
6614 &response
, NULL
, NULL
, &code
, &status_message
);
6617 free(status_message
);
6618 xmlFreeDoc(response
);
6621 isds_log(ILF_ISDS
, ILL_DEBUG
,
6622 _("ConfirmDelivery request processed by server "
6629 #undef INSERT_STRING_ATTRIBUTE
6630 #undef INSERT_ULONGINTNOPTR
6631 #undef INSERT_ULONGINT
6632 #undef INSERT_LONGINT
6633 #undef INSERT_BOOLEAN
6634 #undef INSERT_STRING
6635 #undef EXTRACT_STRING_ATTRIBUTE
6636 #undef EXTRACT_ULONGINT
6637 #undef EXTRACT_LONGINT
6638 #undef EXTRACT_BOOLEAN
6639 #undef EXTRACT_STRING
6642 /* Compute hash of message from raw representation and store it into envelope.
6643 * Original hash structure will be destroyed in envelope.
6644 * @context is session context
6645 * @message is message carrying raw XML message blob
6646 * @algorithm is desired hash algorithm to use */
6647 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
6648 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
6649 isds_error err
= IE_SUCCESS
;
6651 void *xml_stream
= NULL
;
6652 size_t xml_stream_length
;
6653 size_t phys_start
, phys_end
;
6654 char *phys_path
= NULL
;
6655 struct isds_hash
*new_hash
= NULL
;
6658 if (!context
) return IE_INVALID_CONTEXT
;
6659 if (!message
) return IE_INVAL
;
6661 if (!message
->raw
) {
6662 isds_log_message(context
,
6663 _("Message does not carry raw representation"));
6667 switch (message
->raw_type
) {
6668 case RAWTYPE_INCOMING_MESSAGE
:
6670 xml_stream
= message
->raw
;
6671 xml_stream_length
= message
->raw_length
;
6674 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
6675 nsuri
= SISDS_INCOMING_NS
;
6676 xml_stream
= message
->raw
;
6677 xml_stream_length
= message
->raw_length
;
6680 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
6681 nsuri
= SISDS_INCOMING_NS
;
6682 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
6683 &xml_stream
, &xml_stream_length
);
6684 if (err
) goto leave
;
6687 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
6688 nsuri
= SISDS_OUTGOING_NS
;
6689 xml_stream
= message
->raw
;
6690 xml_stream_length
= message
->raw_length
;
6693 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
6694 nsuri
= SISDS_OUTGOING_NS
;
6695 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
6696 &xml_stream
, &xml_stream_length
);
6697 if (err
) goto leave
;
6701 isds_log_message(context
, _("Bad raw representation type"));
6707 /* XXX: Hash is computed from original string represinting isds:dmDm
6708 * subtree. That means no encoding, white space, xmlns attributes changes.
6709 * In other words, input for hash can be invalid XML stream. */
6710 if (-1 == isds_asprintf(&phys_path
, "%s%s%s%s",
6711 nsuri
, PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
6712 PHYSXML_ELEMENT_SEPARATOR
,
6713 nsuri
, PHYSXML_NS_SEPARATOR
"dmReturnedMessage"
6714 PHYSXML_ELEMENT_SEPARATOR
6715 ISDS_NS PHYSXML_NS_SEPARATOR
"dmDm")) {
6719 err
= find_element_boundary(xml_stream
, xml_stream_length
,
6720 phys_path
, &phys_start
, &phys_end
);
6723 isds_log_message(context
,
6724 _("Substring with isds:dmDM element could not be located "
6731 new_hash
= calloc(1, sizeof(*new_hash
));
6736 new_hash
->algorithm
= algorithm
;
6737 err
= compute_hash(xml_stream
+ phys_start
, phys_end
- phys_start
+ 1,
6740 isds_log_message(context
, _("Could not compute message hash"));
6744 /* Save computed hash */
6745 if (!message
->envelope
) {
6746 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
6747 if (!message
->envelope
) {
6752 isds_hash_free(&message
->envelope
->hash
);
6753 message
->envelope
->hash
= new_hash
;
6757 isds_hash_free(&new_hash
);
6761 if (xml_stream
!= message
->raw
) free(xml_stream
);
6766 /* Compare two hashes.
6768 * @h2 is another hash
6770 * IE_SUCCESS if hashes equal
6771 * IE_NOTUNIQ if hashes are comparable, but they don't equal
6772 * IE_ENUM if not comparable, but both structures defined
6773 * IE_INVAL if some of the structures are undefined (NULL)
6774 * IE_ERROR if internal error occurs */
6775 isds_error
isds_hash_cmp(const struct isds_hash
*h1
, const struct isds_hash
*h2
) {
6776 if (h1
== NULL
|| h2
== NULL
) return IE_INVAL
;
6777 if (h1
->algorithm
!= h2
->algorithm
) return IE_ENUM
;
6778 if (h1
->length
!= h2
->length
) return IE_ERROR
;
6779 if (h1
->length
> 0 && !h1
->value
) return IE_ERROR
;
6780 if (h2
->length
> 0 && !h2
->value
) return IE_ERROR
;
6782 for (int i
= 0; i
< h1
->length
; i
++) {
6783 if (((uint8_t *) (h1
->value
))[i
] != ((uint8_t *) (h2
->value
))[i
])
6790 /* Check message has gone through ISDS by comparing message hash stored in
6791 * ISDS and locally computed hash. You must provide message with valid raw
6792 * member (do not use isds_load_message(..., BUFFER_DONT_STORE)).
6793 * This is convenient wrapper for isds_download_message_hash(),
6794 * isds_compute_message_hash(), and isds_hash_cmp() sequence.
6795 * @context is session context
6796 * @message is message with valid raw and envelope member; envelope->hash
6797 * member will be changed during funcion run. Use envelope on heap only.
6799 * IE_SUCCESS if message originates in ISDS
6800 * IE_NOTEQUAL if message is unknown to ISDS
6801 * other code for other errors */
6802 isds_error
isds_verify_message_hash(struct isds_ctx
*context
,
6803 struct isds_message
*message
) {
6804 isds_error err
= IE_SUCCESS
;
6805 struct isds_hash
*downloaded_hash
= NULL
;
6807 if (!context
) return IE_INVALID_CONTEXT
;
6808 if (!message
) return IE_INVAL
;
6810 if (!message
->envelope
) {
6811 isds_log_message(context
,
6812 _("Given message structure is missing envelope"));
6815 if (!message
->raw
) {
6816 isds_log_message(context
,
6817 _("Given message structure is missing raw representation"));
6821 err
= isds_download_message_hash(context
, message
->envelope
->dmID
,
6823 if (err
) goto leave
;
6825 err
= isds_compute_message_hash(context
, message
,
6826 downloaded_hash
->algorithm
);
6827 if (err
) goto leave
;
6829 err
= isds_hash_cmp(downloaded_hash
, message
->envelope
->hash
);
6832 isds_hash_free(&downloaded_hash
);
6837 /* Search for document by document ID in list of documents. IDs are compared
6839 * @documents is list of isds_documents
6840 * @id is document identifier
6841 * @return first matching document or NULL. */
6842 const struct isds_document
*isds_find_document_by_id(
6843 const struct isds_list
*documents
, const char *id
) {
6844 const struct isds_list
*item
;
6845 const struct isds_document
*document
;
6847 for (item
= documents
; item
; item
= item
->next
) {
6848 document
= (struct isds_document
*) item
->data
;
6849 if (!document
) continue;
6851 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
6859 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
6860 struct isds_message **message);
6861 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
6862 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
6863 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
6864 struct isds_address **address);
6866 int isds_message_free(struct isds_message **message);
6867 int isds_address_free(struct isds_address **address);
6871 /* Makes known all relevant namespaces to given XPath context
6872 * @xpat_ctx is XPath context
6873 * @message_ns selects propper message name space. Unsisnged and signed
6875 * prefix and to URI ISDS_NS */
6876 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
,
6877 const message_ns_type message_ns
) {
6878 const xmlChar
*message_namespace
= NULL
;
6880 if (!xpath_ctx
) return IE_ERROR
;
6882 switch(message_ns
) {
6883 case MESSAGE_NS_UNSIGNED
:
6884 message_namespace
= BAD_CAST ISDS_NS
; break;
6885 case MESSAGE_NS_SIGNED_INCOMING
:
6886 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
6887 case MESSAGE_NS_SIGNED_OUTGOING
:
6888 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
6889 case MESSAGE_NS_SIGNED_DELIVERY
:
6890 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
6895 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
6897 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
6899 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
6901 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))