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 /* *DUP_OR_ERROR macros needs error label */
236 #define STRDUP_OR_ERROR(new, template) { \
240 (new) = strdup(template); \
241 if (!new) goto error; \
245 #define FLATDUP_OR_ERROR(new, template) { \
249 (new) = malloc(sizeof(*(new))); \
250 if (!new) goto error; \
251 memcpy((new), (template), sizeof(*(template))); \
256 /* Copy structure isds_PersonName recursively */
257 struct isds_PersonName
*isds_PersonName_duplicate(
258 const struct isds_PersonName
*template) {
259 struct isds_PersonName
*new = NULL
;
261 if (!template) return NULL
;
263 new = calloc(1, sizeof(*new));
264 if (!new) return NULL
;
266 STRDUP_OR_ERROR(new->pnFirstName
, template->pnFirstName
);
267 STRDUP_OR_ERROR(new->pnMiddleName
, template->pnMiddleName
);
268 STRDUP_OR_ERROR(new->pnLastName
, template->pnLastName
);
269 STRDUP_OR_ERROR(new->pnLastNameAtBirth
, template->pnLastNameAtBirth
);
274 isds_PersonName_free(&new);
279 /* Copy structure isds_BirthInfo recursively */
280 static struct isds_BirthInfo
*isds_BirthInfo_duplicate(
281 const struct isds_BirthInfo
*template) {
282 struct isds_BirthInfo
*new = NULL
;
284 if (!template) return NULL
;
286 new = calloc(1, sizeof(*new));
287 if (!new) return NULL
;
289 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
290 STRDUP_OR_ERROR(new->biCity
, template->biCity
);
291 STRDUP_OR_ERROR(new->biCounty
, template->biCounty
);
292 STRDUP_OR_ERROR(new->biState
, template->biState
);
297 isds_BirthInfo_free(&new);
302 /* Copy structure isds_Address recursively */
303 struct isds_Address
*isds_Address_duplicate(
304 const struct isds_Address
*template) {
305 struct isds_Address
*new = NULL
;
307 if (!template) return NULL
;
309 new = calloc(1, sizeof(*new));
310 if (!new) return NULL
;
312 STRDUP_OR_ERROR(new->adCity
, template->adCity
);
313 STRDUP_OR_ERROR(new->adStreet
, template->adStreet
);
314 STRDUP_OR_ERROR(new->adNumberInStreet
, template->adNumberInStreet
);
315 STRDUP_OR_ERROR(new->adNumberInMunicipality
,
316 template->adNumberInMunicipality
);
317 STRDUP_OR_ERROR(new->adZipCode
, template->adZipCode
);
318 STRDUP_OR_ERROR(new->adState
, template->adState
);
323 isds_Address_free(&new);
328 /* Copy structure isds_DbOwnerInfo recursively */
329 struct isds_DbOwnerInfo
*isds_DbOwnerInfo_duplicate(
330 const struct isds_DbOwnerInfo
*template) {
331 struct isds_DbOwnerInfo
*new = NULL
;
332 if (!template) return NULL
;
334 new = calloc(1, sizeof(*new));
335 if (!new) return NULL
;
337 STRDUP_OR_ERROR(new->dbID
, template->dbID
);
338 FLATDUP_OR_ERROR(new->dbType
, template->dbType
);
339 STRDUP_OR_ERROR(new->ic
, template->ic
);
341 if (template->personName
) {
342 if (!(new->personName
=
343 isds_PersonName_duplicate(template->personName
)))
347 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
349 if (template->birthInfo
) {
350 if (!(new->birthInfo
=
351 isds_BirthInfo_duplicate(template->birthInfo
)))
355 if (template->address
) {
356 if (!(new->address
= isds_Address_duplicate(template->address
)))
360 STRDUP_OR_ERROR(new->nationality
, template->nationality
);
361 STRDUP_OR_ERROR(new->email
, template->email
);
362 STRDUP_OR_ERROR(new->telNumber
, template->telNumber
);
363 STRDUP_OR_ERROR(new->identifier
, template->identifier
);
364 STRDUP_OR_ERROR(new->registryCode
, template->registryCode
);
365 FLATDUP_OR_ERROR(new->dbState
, template->dbState
);
366 FLATDUP_OR_ERROR(new->dbEffectiveOVM
, template->dbEffectiveOVM
);
367 FLATDUP_OR_ERROR(new->dbOpenAddressing
, template->dbOpenAddressing
);
372 isds_DbOwnerInfo_free(&new);
377 /* Copy structure isds_DbUserInfo recursively */
378 struct isds_DbUserInfo
*isds_DbUserInfo_duplicate(
379 const struct isds_DbUserInfo
*template) {
380 struct isds_DbUserInfo
*new = NULL
;
381 if (!template) return NULL
;
383 new = calloc(1, sizeof(*new));
384 if (!new) return NULL
;
386 STRDUP_OR_ERROR(new->userID
, template->userID
);
387 FLATDUP_OR_ERROR(new->userType
, template->userType
);
388 FLATDUP_OR_ERROR(new->userPrivils
, template->userPrivils
);
390 if (template->personName
) {
391 if (!(new->personName
=
392 isds_PersonName_duplicate(template->personName
)))
396 if (template->address
) {
397 if (!(new->address
= isds_Address_duplicate(template->address
)))
401 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
402 STRDUP_OR_ERROR(new->ic
, template->ic
);
403 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
404 STRDUP_OR_ERROR(new->caStreet
, template->caStreet
);
405 STRDUP_OR_ERROR(new->caCity
, template->caCity
);
406 STRDUP_OR_ERROR(new->caZipCode
, template->caZipCode
);
411 isds_DbUserInfo_free(&new);
415 #undef FLATDUP_OR_ERROR
416 #undef STRDUP_OR_ERROR
419 /* Initialize ISDS library.
420 * Global function, must be called before other functions.
421 * If it failes you can not use ISDS library and must call isds_cleanup() to
422 * free partially inititialized global variables. */
423 isds_error
isds_init(void) {
424 /* NULL global variables */
425 log_facilities
= ILF_ALL
;
426 log_level
= ILL_WARNING
;
429 /* Initialize gettext */
430 bindtextdomain(PACKAGE
, LOCALEDIR
);
433 /* Initialize CURL */
434 if (curl_global_init(CURL_GLOBAL_ALL
)) {
435 isds_log(ILF_ISDS
, ILL_CRIT
, _("CURL library initialization failed\n"));
439 /* Inicialize gpg-error because of gpgme and ksba */
440 if (gpg_err_init()) {
441 isds_log(ILF_ISDS
, ILL_CRIT
,
442 _("gpg-error library initialization failed\n"));
446 /* Initialize GPGME */
448 isds_log(ILF_ISDS
, ILL_CRIT
,
449 _("GPGME library initialization failed\n"));
453 /* Initialize gcrypt */
455 isds_log(ILF_ISDS
, ILL_CRIT
,
456 _("gcrypt library initialization failed\n"));
460 /* This can _exit() current program. Find not so assertive check. */
465 isds_log(ILF_ISDS
, ILL_CRIT
,
466 _("expat library initialization failed\n"));
470 /* Allocate global variables */
477 /* Deinicialize ISDS library.
478 * Global function, must be called as last library function. */
479 isds_error
isds_cleanup(void) {
484 curl_global_cleanup();
490 /* Return text description of ISDS error */
491 const char *isds_strerror(const isds_error error
) {
494 return(_("Success")); break;
496 return(_("Unspecified error")); break;
498 return(_("Not supported")); break;
500 return(_("Invalid value")); break;
501 case IE_INVALID_CONTEXT
:
502 return(_("Invalid context")); break;
503 case IE_NOT_LOGGED_IN
:
504 return(_("Not logged in")); break;
505 case IE_CONNECTION_CLOSED
:
506 return(_("Connection closed")); break;
508 return(_("Timed out")); break;
510 return(_("Not exist")); break;
512 return(_("Out of memory")); break;
514 return(_("Network problem")); break;
516 return(_("HTTP problem")); break;
518 return(_("SOAP problem")); break;
520 return(_("XML problem")); break;
522 return(_("ISDS server problem")); break;
524 return(_("Invalid enum value")); break;
526 return(_("Invalid date value")); break;
528 return(_("Too big")); break;
530 return(_("Too small")); break;
532 return(_("Value not unique")); break;
534 return(_("Values not uqual")); break;
535 case IE_PARTIAL_SUCCESS
:
536 return(_("Some suboperations failed")); break;
538 return(_("Unknown error"));
543 /* Create ISDS context.
544 * Each context can be used for different sessions to (possibly) differnet
545 * ISDS server with different credentials. */
546 struct isds_ctx
*isds_ctx_create(void) {
547 struct isds_ctx
*context
;
548 context
= malloc(sizeof(*context
));
549 if (context
) memset(context
, 0, sizeof(*context
));
554 /* Destroy ISDS context and free memmory.
555 * @context will be NULLed on success. */
556 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
557 if (!context
|| !*context
) {
558 return IE_INVALID_CONTEXT
;
561 /* Discard credentials */
562 isds_logout(*context
);
564 /* Free other structures */
565 free((*context
)->tls_verify_server
);
566 free((*context
)->tls_ca_file
);
567 free((*context
)->tls_ca_dir
);
568 free((*context
)->long_message
);
576 /* Return long message text produced by library fucntion, e.g. detailed error
577 * mesage. Returned pointer is only valid until new library function is
578 * called for the same context. Could be NULL, especially if NULL context is
579 * supplied. Return string is locale encoded. */
580 char *isds_long_message(const struct isds_ctx
*context
) {
581 if (!context
) return NULL
;
582 return context
->long_message
;
586 /* Stores message into context' long_message buffer.
587 * Application can pick the message up using isds_long_message().
588 * NULL @message truncates the buffer but does not deallocate it.
589 * @message is coded in locale encoding */
590 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
591 const char *message
) {
595 if (!context
) return IE_INVALID_CONTEXT
;
597 /* FIXME: Check for integer overflow */
598 length
= 1 + ((message
) ? strlen(message
) : 0);
599 buffer
= realloc(context
->long_message
, length
);
600 if (!buffer
) return IE_NOMEM
;
603 strcpy(buffer
, message
);
607 context
->long_message
= buffer
;
612 /* Appends message into context' long_message buffer.
613 * Application can pick the message up using isds_long_message().
614 * NULL message has void effect. */
615 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
616 const char *message
) {
618 size_t old_length
, length
;
620 if (!context
) return IE_INVALID_CONTEXT
;
621 if (!message
) return IE_SUCCESS
;
622 if (!context
->long_message
)
623 return isds_log_message(context
, message
);
625 old_length
= strlen(context
->long_message
);
626 /* FIXME: Check for integer overflow */
627 length
= 1 + old_length
+ strlen(message
);
628 buffer
= realloc(context
->long_message
, length
);
629 if (!buffer
) return IE_NOMEM
;
631 strcpy(buffer
+ old_length
, message
);
633 context
->long_message
= buffer
;
638 /* Stores formated message into context' long_message buffer.
639 * Application can pick the message up using isds_long_message(). */
640 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
641 const char *format
, ...) {
645 if (!context
) return IE_INVALID_CONTEXT
;
646 va_start(ap
, format
);
647 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
650 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
655 * @facilities is bitmask of isds_log_facility values,
656 * @level is verbosity level. */
657 void isds_set_logging(const unsigned int facilities
,
658 const isds_log_level level
) {
659 log_facilities
= facilities
;
664 /* Log @message in class @facility with log @level into global log. @message
665 * is printf(3) formating string, variadic arguments may be neccessary.
666 * For debugging purposes. */
667 _hidden isds_error
isds_log(const isds_log_facility facility
,
668 const isds_log_level level
, const char *message
, ...) {
671 if (level
> log_level
) return IE_SUCCESS
;
672 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
673 if (!message
) return IE_INVAL
;
675 /* TODO: Allow to register output function provided by application
676 * (e.g. fprintf to stderr or copy to text area GUI widget). */
678 va_start(ap
, message
);
679 vfprintf(stderr
, message
, ap
);
681 /* Line buffered printf is default.
688 /* Set timeout in miliseconds for each network job like connecting to server
689 * or sending message. Use 0 to disable timeout limits. */
690 isds_error
isds_set_timeout(struct isds_ctx
*context
,
691 const unsigned int timeout
) {
692 if (!context
) return IE_INVALID_CONTEXT
;
694 context
->timeout
= timeout
;
699 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
701 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
703 if (curl_err
) return IE_ERROR
;
710 /* Register callback function libisds calls periodocally during HTTP data
712 * @context is session context
713 * @callback is function provided by application libsds will call. See type
714 * defition for @callback argument explanation.
715 * @data is application specific data @callback gets as last argument */
716 isds_error
isds_set_progress_callback(struct isds_ctx
*context
,
717 isds_progress_callback callback
, void *data
) {
718 if (!context
) return IE_INVALID_CONTEXT
;
720 context
->progress_callback
= callback
;
721 context
->progress_callback_data
= data
;
727 /* Change SSL/TLS settings.
728 * @context is context which setting will be applied to
729 * @option is name of option. It determines the type of last argument. See
730 * isds_tls_option definition for more info.
731 * @... is value of new setting. Type is determined by @option
733 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
735 isds_error err
= IE_SUCCESS
;
737 char *pointer
, *string
;
739 if (!context
) return IE_INVALID_CONTEXT
;
741 va_start(ap
, option
);
743 #define REPLACE_VA_STRING(destination) \
744 string = va_arg(ap, char *); \
746 pointer = realloc((destination), 1 + strlen(string)); \
747 if (!pointer) { err = IE_NOMEM; goto leave; } \
748 strcpy(pointer, string); \
749 (destination) = pointer; \
752 (destination) = NULL; \
756 case ITLS_VERIFY_SERVER
:
757 if (!context
->tls_verify_server
) {
758 context
->tls_verify_server
=
759 malloc(sizeof(*context
->tls_verify_server
));
760 if (!context
->tls_verify_server
) {
761 err
= IE_NOMEM
; goto leave
;
764 *context
->tls_verify_server
= (_Bool
) (0 != va_arg(ap
, int));
768 REPLACE_VA_STRING(context
->tls_ca_file
);
770 case ITLS_CA_DIRECTORY
:
771 REPLACE_VA_STRING(context
->tls_ca_dir
);
775 err
= IE_ENUM
; goto leave
;
778 #undef REPLACE_VA_STRING
786 /* Discard credentials.
787 * Only that. It does not cause log out, connection close or similar. */
788 static isds_error
discard_credentials(struct isds_ctx
*context
) {
789 if(!context
) return IE_INVALID_CONTEXT
;
791 if (context
->username
) {
792 memset(context
->username
, 0, strlen(context
->username
));
793 free(context
->username
);
794 context
->username
= NULL
;
796 if (context
->password
) {
797 memset(context
->password
, 0, strlen(context
->password
));
798 free(context
->password
);
799 context
->password
= NULL
;
806 /* Connect and log in into ISDS server.
807 * @url is address of ISDS web service
808 * @username is user name of ISDS user
809 * @password is user's secret password
810 * @certificate is NULL terminated string with PEM formated client's
811 * certificate. Use NULL if only password autentication should be performed.
812 * @key is private key for client's certificate as (base64 encoded?) NULL
813 * terminated string. Use NULL if only password autentication is desired.
815 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
816 const char *username
, const char *password
,
817 const char *certificate
, const char* key
) {
818 isds_error err
= IE_NOT_LOGGED_IN
;
820 xmlNsPtr isds_ns
= NULL
;
821 xmlNodePtr request
= NULL
;
822 xmlNodePtr response
= NULL
;
824 if (!context
) return IE_INVALID_CONTEXT
;
825 if (!url
|| !username
|| !password
) return IE_INVAL
;
826 if (certificate
|| key
) return IE_NOTSUP
;
828 /* Store configuration */
830 context
->url
= strdup(url
);
834 /* Close connection if already logged in */
836 close_connection(context
);
839 /* Prepare CURL handle */
840 context
->curl
= curl_easy_init();
841 if (!(context
->curl
))
844 /* Build login request */
845 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
847 isds_log_message(context
, _("Could build ISDS login request"));
850 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
852 isds_log_message(context
, _("Could not create ISDS name space"));
853 xmlFreeNode(request
);
856 xmlSetNs(request
, isds_ns
);
858 /* Store credentials */
859 /* FIXME: mlock password
860 * (I have a library) */
861 discard_credentials(context
);
862 context
->username
= strdup(username
);
863 context
->password
= strdup(password
);
864 if (!(context
->username
&& context
->password
)) {
865 discard_credentials(context
);
866 xmlFreeNode(request
);
870 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
873 /* Send login request */
874 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
876 /* Remove credentials */
877 discard_credentials(context
);
879 /* Destroy login request */
880 xmlFreeNode(request
);
883 xmlFreeNodeList(response
);
884 close_connection(context
);
888 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
889 * authentication succeeded if soap_err == IE_SUCCESS */
892 xmlFreeNodeList(response
);
895 isds_log(ILF_ISDS
, ILL_DEBUG
,
896 _("User %s has been logged into server %s successfully\n"),
902 /* Log out from ISDS server discards credentials and connection configuration. */
903 isds_error
isds_logout(struct isds_ctx
*context
) {
904 if (!context
) return IE_INVALID_CONTEXT
;
906 /* Close connection */
908 close_connection(context
);
910 /* Discard credentials for sure. They should not survive isds_login(),
911 * even successful .*/
912 discard_credentials(context
);
916 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
918 discard_credentials(context
);
924 /* Verify connection to ISDS is alive and server is responding.
925 * Sent dumy request to ISDS and expect dummy response. */
926 isds_error
isds_ping(struct isds_ctx
*context
) {
928 xmlNsPtr isds_ns
= NULL
;
929 xmlNodePtr request
= NULL
;
930 xmlNodePtr response
= NULL
;
932 if (!context
) return IE_INVALID_CONTEXT
;
934 /* Check if connection is established */
935 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
938 /* Build dummy request */
939 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
941 isds_log_message(context
, _("Could build ISDS dummy request"));
944 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
946 isds_log_message(context
, _("Could not create ISDS name space"));
947 xmlFreeNode(request
);
950 xmlSetNs(request
, isds_ns
);
952 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
954 /* Sent dummy request */
955 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
957 /* Destroy login request */
958 xmlFreeNode(request
);
961 isds_log(ILF_ISDS
, ILL_DEBUG
,
962 _("ISDS server could not be contacted\n"));
963 xmlFreeNodeList(response
);
964 close_connection(context
);
968 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
969 * authentication succeeded if soap_err == IE_SUCCESS */
970 /* TODO: ISDS documentation does not specify response body.
971 * However real server sends back DummyOperationResponse */
974 xmlFreeNodeList(response
);
976 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
982 /* Send bogus request to ISDS.
983 * Just for test purposes */
984 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
986 xmlNsPtr isds_ns
= NULL
;
987 xmlNodePtr request
= NULL
;
988 xmlDocPtr response
= NULL
;
989 xmlChar
*code
= NULL
, *message
= NULL
;
991 if (!context
) return IE_INVALID_CONTEXT
;
993 /* Check if connection is established */
994 if (!context
->curl
) {
995 /* Testing printf message */
996 isds_printf_message(context
, "%s", _("I said connection closed"));
997 return IE_CONNECTION_CLOSED
;
1001 /* Build dummy request */
1002 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
1004 isds_log_message(context
, _("Could build ISDS bogus request"));
1007 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1009 isds_log_message(context
, _("Could not create ISDS name space"));
1010 xmlFreeNode(request
);
1013 xmlSetNs(request
, isds_ns
);
1015 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
1017 /* Sent bogus request */
1018 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
1020 /* Destroy request */
1021 xmlFreeNode(request
);
1024 isds_log(ILF_ISDS
, ILL_DEBUG
,
1025 _("Processing ISDS response on bogus request failed\n"));
1026 xmlFreeDoc(response
);
1030 /* Check for response status */
1031 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
1032 &code
, &message
, NULL
);
1034 isds_log(ILF_ISDS
, ILL_DEBUG
,
1035 _("ISDS response on bogus request is missing status\n"));
1038 xmlFreeDoc(response
);
1041 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
1042 char *code_locale
= utf82locale((char*)code
);
1043 char *message_locale
= utf82locale((char*)message
);
1044 isds_log(ILF_ISDS
, ILL_DEBUG
,
1045 _("Server refused bogus request (code=%s, message=%s)\n"),
1046 code_locale
, message_locale
);
1047 /* XXX: Literal error messages from ISDS are Czech mesages
1048 * (English sometimes) in UTF-8. It's hard to catch them for
1049 * translation. Successfully gettextized would return in locale
1050 * encoding, unsuccessfully translated would pass in UTF-8. */
1051 isds_log_message(context
, message_locale
);
1053 free(message_locale
);
1056 xmlFreeDoc(response
);
1063 xmlFreeDoc(response
);
1065 isds_log(ILF_ISDS
, ILL_DEBUG
,
1066 _("Bogus message accepted by server. This should not happen.\n"));
1072 /* Serialize XML subtree to buffer preserving XML indentatition.
1073 * @context is session context
1074 * @subtree is XML element to be serialized (with childern)
1075 * @buffer is automatically reallocated buffer where serialize to
1076 * @length is size of serialized stream in bytes
1077 * @return standard error code, free @buffer in case of error */
1078 static isds_error
serialize_subtree(struct isds_ctx
*context
,
1079 xmlNodePtr subtree
, void **buffer
, size_t *length
) {
1080 isds_error err
= IE_SUCCESS
;
1081 xmlBufferPtr xml_buffer
= NULL
;
1082 xmlSaveCtxtPtr save_ctx
= NULL
;
1083 xmlDocPtr subtree_doc
= NULL
;
1084 xmlNodePtr subtree_copy
;
1088 if (!context
) return IE_INVALID_CONTEXT
;
1089 if (!buffer
) return IE_INVAL
;
1091 if (!subtree
|| !length
) return IE_INVAL
;
1093 /* Make temporary XML document with @subtree root element */
1094 /* XXX: We can not use xmlNodeDump() because it dumps the subtree as is.
1095 * It can result in not well-formed on invalid XML tree (e.g. name space
1096 * prefix definition can miss. */
1099 subtree_doc
= xmlNewDoc(BAD_CAST
"1.0");
1101 isds_log_message(context
, _("Could not build temporary document"));
1106 /* XXX: Copy subtree and attach the copy to document.
1107 * One node can not bee attached into more document at the same time.
1108 * XXX: Check xmlDOMWrapRemoveNode(). It could solve NS references
1110 * XXX: Check xmlSaveTree() too. */
1111 subtree_copy
= xmlCopyNodeList(subtree
);
1112 if (!subtree_copy
) {
1113 isds_log_message(context
, _("Could not copy subtree"));
1117 xmlDocSetRootElement(subtree_doc
, subtree_copy
);
1119 /* Only this way we get namespace definition as @xmlns:isds,
1120 * otherwise we get namespace prefix without definition */
1121 /* FIXME: Don't overwrite original default namespace */
1122 isds_ns
= xmlNewNs(subtree_copy
, BAD_CAST ISDS_NS
, NULL
);
1124 isds_log_message(context
, _("Could not create ISDS name space"));
1128 xmlSetNs(subtree_copy
, isds_ns
);
1131 /* Serialize the document into buffer */
1132 xml_buffer
= xmlBufferCreate();
1134 isds_log_message(context
, _("Could not create xmlBuffer"));
1138 /* Last argument 0 means to not format the XML tree */
1139 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8", 0);
1141 isds_log_message(context
, _("Could not create XML serializer"));
1145 /* XXX: According LibXML documentation, this function does not return
1146 * meaningfull value yet */
1147 xmlSaveDoc(save_ctx
, subtree_doc
);
1148 if (-1 == xmlSaveFlush(save_ctx
)) {
1149 isds_log_message(context
,
1150 _("Could not serialize XML subtree"));
1154 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1155 * even after xmlSaveFlush(). Thus close it here */
1156 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1159 /* Store and detach buffer from xml_buffer */
1160 *buffer
= xml_buffer
->content
;
1161 *length
= xml_buffer
->use
;
1162 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1165 new_buffer
= realloc(*buffer
, *length
);
1166 if (new_buffer
) *buffer
= new_buffer
;
1174 xmlSaveClose(save_ctx
);
1175 xmlBufferFree(xml_buffer
);
1176 xmlFreeDoc(subtree_doc
); /* Frees subtree_copy, isds_ns etc. */
1181 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1182 * @context is session context
1183 * @document is original document where @nodeset points to
1184 * @nodeset is XPath node set to dump (recursively)
1185 * @buffer is automarically reallocated buffer where serialize to
1186 * @length is size of serialized stream in bytes
1187 * @return standard error code, free @buffer in case of error */
1188 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1189 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1190 void **buffer
, size_t *length
) {
1191 isds_error err
= IE_SUCCESS
;
1192 xmlBufferPtr xml_buffer
= NULL
;
1195 if (!context
) return IE_INVALID_CONTEXT
;
1196 if (!buffer
) return IE_INVAL
;
1198 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1201 /* Empty node set results into NULL buffer */
1202 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1206 /* Resuling the document into buffer */
1207 xml_buffer
= xmlBufferCreate();
1209 isds_log_message(context
, _("Could not create xmlBuffer"));
1214 /* Itearate over all nodes */
1215 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1217 * XXX: xmlNodeDump() appends to xml_buffer. */
1219 xmlNodeDump(xml_buffer
, document
, nodeset
->nodeTab
[i
], 0, 0)) {
1220 isds_log_message(context
, _("Could not dump XML node"));
1226 /* Store and detach buffer from xml_buffer */
1227 *buffer
= xml_buffer
->content
;
1228 *length
= xml_buffer
->use
;
1229 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1232 new_buffer
= realloc(*buffer
, *length
);
1233 if (new_buffer
) *buffer
= new_buffer
;
1242 xmlBufferFree(xml_buffer
);
1248 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1249 * @context is session context
1250 * @document is original document where @nodeset points to
1251 * @nodeset is XPath node set to dump (recursively)
1252 * @buffer is automarically reallocated buffer where serialize to
1253 * @length is size of serialized stream in bytes
1254 * @return standard error code, free @buffer in case of error */
1255 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1256 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1257 void **buffer
, size_t *length
) {
1258 isds_error err
= IE_SUCCESS
;
1259 xmlBufferPtr xml_buffer
= NULL
;
1260 xmlSaveCtxtPtr save_ctx
= NULL
;
1263 if (!context
) return IE_INVALID_CONTEXT
;
1264 if (!buffer
) return IE_INVAL
;
1266 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1269 /* Empty node set results into NULL buffer */
1270 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1274 /* Resuling the document into buffer */
1275 xml_buffer
= xmlBufferCreate();
1277 isds_log_message(context
, _("Could not create xmlBuffer"));
1281 if (xmlSubstituteEntitiesDefault(1)) {
1282 isds_log_message(context
, _("Could not disable attribute escaping"));
1286 /* Last argument means:
1287 * 0 to not format the XML tree
1288 * XML_SAVE_NO_EMPTY ISDS does not produce shorten tags */
1289 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8",
1290 XML_SAVE_NO_DECL
|XML_SAVE_NO_EMPTY
|XML_SAVE_NO_XHTML
);
1292 isds_log_message(context
, _("Could not create XML serializer"));
1296 /*if (xmlSaveSetAttrEscape(save_ctx, NULL)) {
1297 isds_log_message(context, _("Could not disable attribute escaping"));
1303 /* Itearate over all nodes */
1304 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1306 * XXX: xmlNodeDump() appends to xml_buffer. */
1308 xmlNodeDump(xml_buffer, document, nodeset->nodeTab[i], 0, 0)) {
1310 /* XXX: According LibXML documentation, this function does not return
1311 * meaningfull value yet */
1312 xmlSaveTree(save_ctx
, nodeset
->nodeTab
[i
]);
1313 if (-1 == xmlSaveFlush(save_ctx
)) {
1314 isds_log_message(context
,
1315 _("Could not serialize XML subtree"));
1321 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1322 * even after xmlSaveFlush(). Thus close it here */
1323 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1325 /* Store and detach buffer from xml_buffer */
1326 *buffer
= xml_buffer
->content
;
1327 *length
= xml_buffer
->use
;
1328 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1331 new_buffer
= realloc(*buffer
, *length
);
1332 if (new_buffer
) *buffer
= new_buffer
;
1340 xmlSaveClose(save_ctx
);
1341 xmlBufferFree(xml_buffer
);
1347 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
1348 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
1349 if (!string
|| !type
) return IE_INVAL
;
1351 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
1353 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
1355 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
1356 *type
= DBTYPE_PFO_ADVOK
;
1357 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
1358 *type
= DBTYPE_PFO_DANPOR
;
1359 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
1360 *type
= DBTYPE_PFO_INSSPR
;
1361 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
1363 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
1364 *type
= DBTYPE_PO_ZAK
;
1365 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
1366 *type
= DBTYPE_PO_REQ
;
1367 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
1369 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
1370 *type
= DBTYPE_OVM_NOTAR
;
1371 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
1372 *type
= DBTYPE_OVM_EXEKUT
;
1373 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
1374 *type
= DBTYPE_OVM_REQ
;
1381 /* Convert ISDS dbType enum @type to UTF-8 string.
1382 * @Return pointer to static string, or NULL if unkwnow enum value */
1383 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
1385 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
1386 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
1387 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
1388 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DANPOR"); break;
1389 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
1390 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
1391 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
1392 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
1393 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
1394 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
1395 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
1396 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
1397 default: return NULL
; break;
1402 /* Convert UTF-8 @string represantion of ISDS userType to enum @type */
1403 static isds_error
string2isds_UserType(xmlChar
*string
, isds_UserType
*type
) {
1404 if (!string
|| !type
) return IE_INVAL
;
1406 if (!xmlStrcmp(string
, BAD_CAST
"PRIMARY_USER"))
1407 *type
= USERTYPE_PRIMARY
;
1408 else if (!xmlStrcmp(string
, BAD_CAST
"ENTRUSTED_USER"))
1409 *type
= USERTYPE_ENTRUSTED
;
1410 else if (!xmlStrcmp(string
, BAD_CAST
"ADMINISTRATOR"))
1411 *type
= USERTYPE_ADMINISTRATOR
;
1412 else if (!xmlStrcmp(string
, BAD_CAST
"OFFICIAL"))
1413 *type
= USERTYPE_OFFICIAL
;
1420 /* Convert ISDS userType enum @type to UTF-8 string.
1421 * @Return pointer to static string, or NULL if unkwnow enum value */
1422 static const xmlChar
*isds_UserType2string(const isds_UserType type
) {
1424 case USERTYPE_PRIMARY
: return(BAD_CAST
"PRIMARY_USER"); break;
1425 case USERTYPE_ENTRUSTED
: return(BAD_CAST
"ENTRUSTED_USER"); break;
1426 case USERTYPE_ADMINISTRATOR
: return(BAD_CAST
"ADMINISTRATOR"); break;
1427 case USERTYPE_OFFICIAL
: return(BAD_CAST
"OFFICIAL"); break;
1428 default: return NULL
; break;
1433 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
1434 * @Return pointer to static string, or NULL if unkwnow enum value */
1435 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
1437 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
1438 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
1439 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
1440 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
1441 default: return NULL
; break;
1446 /* Convert UTF-8 @string to ISDS dmFileMetaType enum @type.
1447 * @Return IE_ENUM if @string is not valid enum member */
1448 static isds_error
string2isds_FileMetaType(const xmlChar
*string
,
1449 isds_FileMetaType
*type
) {
1450 if (!string
|| !type
) return IE_INVAL
;
1452 if (!xmlStrcmp(string
, BAD_CAST
"main"))
1453 *type
= FILEMETATYPE_MAIN
;
1454 else if (!xmlStrcmp(string
, BAD_CAST
"enclosure"))
1455 *type
= FILEMETATYPE_ENCLOSURE
;
1456 else if (!xmlStrcmp(string
, BAD_CAST
"signature"))
1457 *type
= FILEMETATYPE_SIGNATURE
;
1458 else if (!xmlStrcmp(string
, BAD_CAST
"meta"))
1459 *type
= FILEMETATYPE_META
;
1466 /* Convert UTF-8 @string to ISDS hash @algorithm.
1467 * @Return IE_ENUM if @string is not valid enum member */
1468 static isds_error
string2isds_hash_algorithm(const xmlChar
*string
,
1469 isds_hash_algorithm
*algorithm
) {
1470 if (!string
|| !algorithm
) return IE_INVAL
;
1472 if (!xmlStrcmp(string
, BAD_CAST
"MD5"))
1473 *algorithm
= HASH_ALGORITHM_MD5
;
1474 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-1"))
1475 *algorithm
= HASH_ALGORITHM_SHA_1
;
1476 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-256"))
1477 *algorithm
= HASH_ALGORITHM_SHA_256
;
1478 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-512"))
1479 *algorithm
= HASH_ALGORITHM_SHA_512
;
1486 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
1487 * XXX: Not all ISO formats are supported */
1488 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
1490 if (!string
|| !time
) return IE_INVAL
;
1492 /* xsd:date is ISO 8601 string, thus ASCII */
1493 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
1494 if (offset
&& *offset
== '\0')
1497 offset
= strptime((char*)string
, "%Y%m%d", time
);
1498 if (offset
&& *offset
== '\0')
1501 offset
= strptime((char*)string
, "%Y-%j", time
);
1502 if (offset
&& *offset
== '\0')
1509 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
1510 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
1511 if (!time
|| !string
) return IE_INVAL
;
1513 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
1514 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
1521 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
1522 * respects the @time microseconds too. */
1523 static isds_error
timeval2timestring(const struct timeval
*time
,
1527 if (!time
|| !string
) return IE_INVAL
;
1529 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
1530 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
1532 /* TODO: small negative year should be formated as "-0012". This is not
1533 * true for glibc "%04d". We should implement it.
1534 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
1535 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
1536 if (-1 == isds_asprintf((char **) string
,
1537 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
1538 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
1539 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
1547 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
1548 * It respects microseconds too.
1549 * In case of error, @time will be freed. */
1550 static isds_error
timestring2timeval(const xmlChar
*string
,
1551 struct timeval
**time
) {
1553 char *offset
, *delim
, *endptr
;
1555 int offset_hours
, offset_minutes
;
1558 if (!time
) return IE_INVAL
;
1560 memset(&broken
, 0, sizeof(broken
));
1563 *time
= calloc(1, sizeof(**time
));
1564 if (!*time
) return IE_NOMEM
;
1566 memset(*time
, 0, sizeof(**time
));
1570 /* xsd:date is ISO 8601 string, thus ASCII */
1571 /*TODO: negative year */
1573 /* Parse date and time without subseconds and offset */
1574 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
1576 free(*time
); *time
= NULL
;
1580 /* Get subseconds */
1581 if (*offset
== '.' ) {
1584 /* Copy first 6 digits, padd it with zeros.
1585 * XXX: It truncates longer number, no round.
1586 * Current server implementation uses only milisecond resolution. */
1587 /* TODO: isdigit() is locale sensitive */
1589 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
1591 subseconds
[i
] = *offset
;
1593 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
1594 subseconds
[i
] = '0';
1596 subseconds
[6] = '\0';
1598 /* Convert it into integer */
1599 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
1600 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
1601 (*time
)->tv_usec
== LONG_MAX
) {
1602 free(*time
); *time
= NULL
;
1606 /* move to the zone offset delimiter */
1607 delim
= strchr(offset
, '-');
1609 delim
= strchr(offset
, '+');
1613 /* Get zone offset */
1614 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
1615 * "" equals to "Z" and it means UTC zone. */
1616 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
1617 * colon separator */
1618 if (*offset
== '-' || *offset
== '+') {
1620 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
1621 free(*time
); *time
= NULL
;
1624 broken
.tm_hour
-= offset_hours
;
1625 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
1628 /* Convert to time_t */
1630 (*time
)->tv_sec
= mktime(&broken
);
1631 switch_tz_to_native();
1632 if ((*time
)->tv_sec
== (time_t) -1) {
1633 free(*time
); *time
= NULL
;
1641 /* Convert unsigned int into isds_message_status.
1642 * @context is session context
1643 * @number is pointer to number value. NULL will be treated as invalid value.
1644 * @status is automatically reallocated status
1645 * @return IE_SUCCESS, or error code and free status */
1646 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1647 const unsigned long int *number
, isds_message_status
**status
) {
1648 if (!context
) return IE_INVALID_CONTEXT
;
1649 if (!status
) return IE_INVAL
;
1651 free(*status
); *status
= NULL
;
1652 if (!number
) return IE_INVAL
;
1654 if (*number
< 1 || *number
> 10) {
1655 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1660 *status
= malloc(sizeof(**status
));
1661 if (!*status
) return IE_NOMEM
;
1663 **status
= 1 << *number
;
1668 /* Convert event description string into isds_event memebers type and
1670 * @string is raw event decsription starting with event prefix
1671 * @event is structure where to store type and stripped description to
1672 * @return standard error code, unkown prefix is not classified as an error. */
1673 static isds_error
eventstring2event(const xmlChar
*string
,
1674 struct isds_event
* event
) {
1675 const xmlChar
*known_prefixes
[] = {
1681 const isds_event_type types
[] = {
1682 EVENT_ACCEPTED_BY_RECIPIENT
,
1683 EVENT_ACCEPTED_BY_FICTION
,
1684 EVENT_UNDELIVERABLE
,
1685 EVENT_COMMERCIAL_ACCEPTED
1690 if (!string
|| !event
) return IE_INVAL
;
1693 event
->type
= malloc(sizeof(*event
->type
));
1694 if (!(event
->type
)) return IE_NOMEM
;
1696 zfree(event
->description
);
1698 for (index
= 0; index
< sizeof(known_prefixes
)/sizeof(known_prefixes
[0]);
1700 length
= xmlUTF8Strlen(known_prefixes
[index
]);
1702 if (!xmlStrncmp(string
, known_prefixes
[index
], length
)) {
1703 /* Prefix is known */
1704 *event
->type
= types
[index
];
1706 /* Strip prefix from description and spaces */
1707 /* TODO: Recognize all wite spaces from UCS blank class and
1708 * operate on UTF-8 chars. */
1709 for (; string
[length
] != '\0' && string
[length
] == ' '; length
++);
1710 event
->description
= strdup((char *) (string
+ length
));
1711 if (!(event
->description
)) return IE_NOMEM
;
1717 /* Unknown event prefix.
1718 * XSD allows any string */
1719 char *string_locale
= utf82locale((char *) string
);
1720 isds_log(ILF_ISDS
, ILL_WARNING
,
1721 _("Uknown delivery info event prefix: %s\n"), string_locale
);
1722 free(string_locale
);
1724 *event
->type
= EVENT_UKNOWN
;
1725 event
->description
= strdup((char *) string
);
1726 if (!(event
->description
)) return IE_NOMEM
;
1732 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1733 * and leave lable */
1734 #define EXTRACT_STRING(element, string) { \
1735 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
1740 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
1741 if (result->nodesetval->nodeNr > 1) { \
1742 isds_printf_message(context, _("Multiple %s element"), element); \
1746 (string) = (char *) \
1747 xmlXPathCastNodeSetToString(result->nodesetval); \
1755 #define EXTRACT_BOOLEAN(element, booleanPtr) \
1757 char *string = NULL; \
1758 EXTRACT_STRING(element, string); \
1761 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
1762 if (!(booleanPtr)) { \
1768 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
1769 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
1770 *(booleanPtr) = 1; \
1771 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
1772 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
1773 *(booleanPtr) = 0; \
1775 char *string_locale = utf82locale((char*)string); \
1776 isds_printf_message(context, \
1777 _("%s value is not valid boolean: "), \
1778 element, string_locale); \
1779 free(string_locale); \
1789 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
1791 char *string = NULL; \
1792 EXTRACT_STRING(element, string); \
1797 number = strtol((char*)string, &endptr, 10); \
1799 if (*endptr != '\0') { \
1800 char *string_locale = utf82locale((char *)string); \
1801 isds_printf_message(context, \
1802 _("%s is not valid integer: %s"), \
1803 element, string_locale); \
1804 free(string_locale); \
1810 if (number == LONG_MIN || number == LONG_MAX) { \
1811 char *string_locale = utf82locale((char *)string); \
1812 isds_printf_message(context, \
1813 _("%s value out of range of long int: %s"), \
1814 element, string_locale); \
1815 free(string_locale); \
1821 free(string); string = NULL; \
1823 if (!(preallocated)) { \
1824 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
1825 if (!(longintPtr)) { \
1830 *(longintPtr) = number; \
1834 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
1836 char *string = NULL; \
1837 EXTRACT_STRING(element, string); \
1842 number = strtol((char*)string, &endptr, 10); \
1844 if (*endptr != '\0') { \
1845 char *string_locale = utf82locale((char *)string); \
1846 isds_printf_message(context, \
1847 _("%s is not valid integer: %s"), \
1848 element, string_locale); \
1849 free(string_locale); \
1855 if (number == LONG_MIN || number == LONG_MAX) { \
1856 char *string_locale = utf82locale((char *)string); \
1857 isds_printf_message(context, \
1858 _("%s value out of range of long int: %s"), \
1859 element, string_locale); \
1860 free(string_locale); \
1866 free(string); string = NULL; \
1868 isds_printf_message(context, \
1869 _("%s value is negative: %ld"), element, number); \
1874 if (!(preallocated)) { \
1875 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
1876 if (!(ulongintPtr)) { \
1881 *(ulongintPtr) = number; \
1885 #define EXTRACT_STRING_ATTRIBUTE(attribute, string, required) { \
1886 (string) = (char *) xmlGetNsProp(xpath_ctx->node, ( BAD_CAST attribute), \
1888 if ((required) && (!string)) { \
1889 char *attribute_locale = utf82locale(attribute); \
1890 char *element_locale = utf82locale((char *)xpath_ctx->node->name); \
1891 isds_printf_message(context, \
1892 _("Could not extract required %s attribute value from " \
1893 "%s element"), attribute_locale, element_locale); \
1894 free(element_locale); \
1895 free(attribute_locale); \
1902 #define INSERT_STRING(parent, element, string) \
1904 node = xmlNewTextChild(parent, NULL, BAD_CAST (element), \
1905 (xmlChar *) (string)); \
1907 isds_printf_message(context, \
1908 _("Could not add %s child to %s element"), \
1909 element, (parent)->name); \
1915 #define INSERT_SCALAR_BOOLEAN(parent, element, boolean) \
1917 if (boolean) { INSERT_STRING(parent, element, "true"); } \
1918 else { INSERT_STRING(parent, element, "false"); } \
1921 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
1924 INSERT_SCALAR_BOOLEAN(parent, element, (*(booleanPtr))); \
1926 INSERT_STRING(parent, element, NULL); \
1930 #define INSERT_LONGINT(parent, element, longintPtr, buffer) { \
1931 if ((longintPtr)) { \
1932 /* FIXME: locale sensitive */ \
1933 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
1937 INSERT_STRING(parent, element, buffer) \
1938 free(buffer); (buffer) = NULL; \
1939 } else { INSERT_STRING(parent, element, NULL) } \
1942 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) { \
1943 if ((ulongintPtr)) { \
1944 /* FIXME: locale sensitive */ \
1945 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
1949 INSERT_STRING(parent, element, buffer) \
1950 free(buffer); (buffer) = NULL; \
1951 } else { INSERT_STRING(parent, element, NULL) } \
1954 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
1956 /* FIXME: locale sensitive */ \
1957 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
1961 INSERT_STRING(parent, element, buffer) \
1962 free(buffer); (buffer) = NULL; \
1965 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
1967 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
1968 (xmlChar *) (string)); \
1969 if (!attribute_node) { \
1970 isds_printf_message(context, _("Could not add %s " \
1971 "attribute to %s element"), \
1972 (attribute), (parent)->name); \
1978 #define CHECK_FOR_STRING_LENGTH(string, minimum, maximum, name) { \
1980 int length = xmlUTF8Strlen((xmlChar *) (string)); \
1981 if (length > (maximum)) { \
1982 isds_printf_message(context, \
1983 _("%s has more than %d characters"), (name), (maximum)); \
1987 if (length < (minimum)) { \
1988 isds_printf_message(context, \
1989 _("%s has less than %d characters"), (name), (minimum)); \
1996 #define INSERT_ELEMENT(child, parent, element) \
1998 (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \
2000 isds_printf_message(context, \
2001 _("Could not add %s child to %s element"), \
2002 (element), (parent)->name); \
2009 /* Find child element by name in given XPath context and switch context onto
2010 * it. The child must be uniq and must exist. Otherwise failes.
2011 * @context is ISDS context
2012 * @child is child element name
2013 * @xpath_ctx is XPath context. In success, the @xpath_ctx will be changed
2014 * into it child. In error case, the @xpath_ctx keeps original value. */
2015 static isds_error
move_xpathctx_to_child(struct isds_ctx
*context
,
2016 const xmlChar
*child
, xmlXPathContextPtr xpath_ctx
) {
2017 isds_error err
= IE_SUCCESS
;
2018 xmlXPathObjectPtr result
= NULL
;
2020 if (!context
) return IE_INVALID_CONTEXT
;
2021 if (!child
|| !xpath_ctx
) return IE_INVAL
;
2024 result
= xmlXPathEvalExpression(child
, xpath_ctx
);
2031 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2032 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
2033 char *child_locale
= utf82locale((char*) child
);
2034 isds_printf_message(context
,
2035 _("%s element does not contain %s child"),
2036 parent_locale
, child_locale
);
2038 free(parent_locale
);
2044 if (result
->nodesetval
->nodeNr
> 1) {
2045 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
2046 char *child_locale
= utf82locale((char*) child
);
2047 isds_printf_message(context
,
2048 _("%s element contains multiple %s childs"),
2049 parent_locale
, child_locale
);
2051 free(parent_locale
);
2056 /* Switch context */
2057 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2060 xmlXPathFreeObject(result
);
2066 /* Find and convert XSD:gPersonName group in current node into structure
2067 * @context is ISDS context
2068 * @personName is automically reallocated person name structure. If no member
2069 * value is found, will be freed.
2070 * @xpath_ctx is XPath context with current node as parent for XSD:gPersonName
2072 * In case of error @personName will be freed. */
2073 static isds_error
extract_gPersonName(struct isds_ctx
*context
,
2074 struct isds_PersonName
**personName
, xmlXPathContextPtr xpath_ctx
) {
2075 isds_error err
= IE_SUCCESS
;
2076 xmlXPathObjectPtr result
= NULL
;
2078 if (!context
) return IE_INVALID_CONTEXT
;
2079 if (!personName
) return IE_INVAL
;
2080 isds_PersonName_free(personName
);
2081 if (!xpath_ctx
) return IE_INVAL
;
2084 *personName
= calloc(1, sizeof(**personName
));
2090 EXTRACT_STRING("isds:pnFirstName", (*personName
)->pnFirstName
);
2091 EXTRACT_STRING("isds:pnMiddleName", (*personName
)->pnMiddleName
);
2092 EXTRACT_STRING("isds:pnLastName", (*personName
)->pnLastName
);
2093 EXTRACT_STRING("isds:pnLastNameAtBirth", (*personName
)->pnLastNameAtBirth
);
2095 if (!(*personName
)->pnFirstName
&& !(*personName
)->pnMiddleName
&&
2096 !(*personName
)->pnLastName
&& !(*personName
)->pnLastNameAtBirth
)
2097 isds_PersonName_free(personName
);
2100 if (err
) isds_PersonName_free(personName
);
2101 xmlXPathFreeObject(result
);
2106 /* Find and convert XSD:gAddress group in current node into structure
2107 * @context is ISDS context
2108 * @address is automically reallocated address structure. If no member
2109 * value is found, will be freed.
2110 * @xpath_ctx is XPath context with current node as parent for XSD:gAddress
2112 * In case of error @address will be freed. */
2113 static isds_error
extract_gAddress(struct isds_ctx
*context
,
2114 struct isds_Address
**address
, xmlXPathContextPtr xpath_ctx
) {
2115 isds_error err
= IE_SUCCESS
;
2116 xmlXPathObjectPtr result
= NULL
;
2118 if (!context
) return IE_INVALID_CONTEXT
;
2119 if (!address
) return IE_INVAL
;
2120 isds_Address_free(address
);
2121 if (!xpath_ctx
) return IE_INVAL
;
2124 *address
= calloc(1, sizeof(**address
));
2130 EXTRACT_STRING("isds:adCity", (*address
)->adCity
);
2131 EXTRACT_STRING("isds:adStreet", (*address
)->adStreet
);
2132 EXTRACT_STRING("isds:adNumberInStreet", (*address
)->adNumberInStreet
);
2133 EXTRACT_STRING("isds:adNumberInMunicipality",
2134 (*address
)->adNumberInMunicipality
);
2135 EXTRACT_STRING("isds:adZipCode", (*address
)->adZipCode
);
2136 EXTRACT_STRING("isds:adState", (*address
)->adState
);
2138 if (!(*address
)->adCity
&& !(*address
)->adStreet
&&
2139 !(*address
)->adNumberInStreet
&&
2140 !(*address
)->adNumberInMunicipality
&&
2141 !(*address
)->adZipCode
&& !(*address
)->adState
)
2142 isds_Address_free(address
);
2145 if (err
) isds_Address_free(address
);
2146 xmlXPathFreeObject(result
);
2151 /* Find and convert isds:biDate element in current node into structure
2152 * @context is ISDS context
2153 * @biDate is automically reallocated birth date structure. If no member
2154 * value is found, will be freed.
2155 * @xpath_ctx is XPath context with current node as parent for isds:biDate
2157 * In case of error @biDate will be freed. */
2158 static isds_error
extract_BiDate(struct isds_ctx
*context
,
2159 struct tm
**biDate
, xmlXPathContextPtr xpath_ctx
) {
2160 isds_error err
= IE_SUCCESS
;
2161 xmlXPathObjectPtr result
= NULL
;
2162 char *string
= NULL
;
2164 if (!context
) return IE_INVALID_CONTEXT
;
2165 if (!biDate
) return IE_INVAL
;
2167 if (!xpath_ctx
) return IE_INVAL
;
2169 EXTRACT_STRING("isds:biDate", string
);
2171 *biDate
= calloc(1, sizeof(**biDate
));
2176 err
= datestring2tm((xmlChar
*)string
, *biDate
);
2178 if (err
== IE_NOTSUP
) {
2180 char *string_locale
= utf82locale(string
);
2181 isds_printf_message(context
,
2182 _("Invalid isds:biDate value: %s"), string_locale
);
2183 free(string_locale
);
2190 if (err
) zfree(*biDate
);
2192 xmlXPathFreeObject(result
);
2197 /* Convert isds:dBOwnerInfo XML tree into structure
2198 * @context is ISDS context
2199 * @db_owner_info is automically reallocated box owner info structure
2200 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
2201 * In case of error @db_owner_info will be freed. */
2202 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
2203 struct isds_DbOwnerInfo
**db_owner_info
,
2204 xmlXPathContextPtr xpath_ctx
) {
2205 isds_error err
= IE_SUCCESS
;
2206 xmlXPathObjectPtr result
= NULL
;
2207 char *string
= NULL
;
2209 if (!context
) return IE_INVALID_CONTEXT
;
2210 if (!db_owner_info
) return IE_INVAL
;
2211 isds_DbOwnerInfo_free(db_owner_info
);
2212 if (!xpath_ctx
) return IE_INVAL
;
2215 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
2216 if (!*db_owner_info
) {
2221 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
2223 EXTRACT_STRING("isds:dbType", string
);
2225 (*db_owner_info
)->dbType
=
2226 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
2227 if (!(*db_owner_info
)->dbType
) {
2231 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
2233 zfree((*db_owner_info
)->dbType
);
2234 if (err
== IE_ENUM
) {
2236 char *string_locale
= utf82locale(string
);
2237 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
2239 free(string_locale
);
2246 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
2248 err
= extract_gPersonName(context
, &(*db_owner_info
)->personName
,
2250 if (err
) goto leave
;
2252 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
2254 (*db_owner_info
)->birthInfo
=
2255 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
2256 if (!(*db_owner_info
)->birthInfo
) {
2260 err
= extract_BiDate(context
, &(*db_owner_info
)->birthInfo
->biDate
,
2262 if (err
) goto leave
;
2263 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
2264 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
2265 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
2266 if (!(*db_owner_info
)->birthInfo
->biDate
&&
2267 !(*db_owner_info
)->birthInfo
->biCity
&&
2268 !(*db_owner_info
)->birthInfo
->biCounty
&&
2269 !(*db_owner_info
)->birthInfo
->biState
)
2270 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
2272 err
= extract_gAddress(context
, &(*db_owner_info
)->address
, xpath_ctx
);
2273 if (err
) goto leave
;
2275 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
2276 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
2277 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
2278 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
2279 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
2281 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
2283 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
2284 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
2285 (*db_owner_info
)->dbOpenAddressing
);
2288 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
2290 xmlXPathFreeObject(result
);
2295 /* Insert struct isds_DbOwnerInfo data (box description) into XML tree
2296 * @context is sesstion context
2297 * @owner is libsids structure with box description
2298 * @db_owner_info is XML element of XSD:tDbOwnerInfo */
2299 static isds_error
insert_DbOwnerInfo(struct isds_ctx
*context
,
2300 const struct isds_DbOwnerInfo
*owner
, xmlNodePtr db_owner_info
) {
2302 isds_error err
= IE_SUCCESS
;
2304 xmlChar
*string
= NULL
;
2306 if (!context
) return IE_INVALID_CONTEXT
;
2307 if (!owner
|| !db_owner_info
) return IE_INVAL
;
2310 /* Build XSD:tDbOwnerInfo */
2311 CHECK_FOR_STRING_LENGTH(owner
->dbID
, 0, 7, "dbID")
2312 INSERT_STRING(db_owner_info
, "dbID", owner
->dbID
);
2315 if (owner
->dbType
) {
2316 const xmlChar
*type_string
= isds_DbType2string(*(owner
->dbType
));
2318 isds_printf_message(context
, _("Invalid dbType value: %d"),
2323 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2325 INSERT_STRING(db_owner_info
, "ic", owner
->ic
);
2326 if (owner
->personName
) {
2327 INSERT_STRING(db_owner_info
, "pnFirstName",
2328 owner
->personName
->pnFirstName
);
2329 INSERT_STRING(db_owner_info
, "pnMiddleName",
2330 owner
->personName
->pnMiddleName
);
2331 INSERT_STRING(db_owner_info
, "pnLastName",
2332 owner
->personName
->pnLastName
);
2333 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2334 owner
->personName
->pnLastNameAtBirth
);
2336 INSERT_STRING(db_owner_info
, "firmName", owner
->firmName
);
2337 if (owner
->birthInfo
) {
2338 if (owner
->birthInfo
->biDate
) {
2339 if (!tm2datestring(owner
->birthInfo
->biDate
, &string
))
2340 INSERT_STRING(db_owner_info
, "biDate", string
);
2341 free(string
); string
= NULL
;
2343 INSERT_STRING(db_owner_info
, "biCity", owner
->birthInfo
->biCity
);
2344 INSERT_STRING(db_owner_info
, "biCounty", owner
->birthInfo
->biCounty
);
2345 INSERT_STRING(db_owner_info
, "biState", owner
->birthInfo
->biState
);
2347 if (owner
->address
) {
2348 INSERT_STRING(db_owner_info
, "adCity", owner
->address
->adCity
);
2349 INSERT_STRING(db_owner_info
, "adStreet", owner
->address
->adStreet
);
2350 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2351 owner
->address
->adNumberInStreet
);
2352 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2353 owner
->address
->adNumberInMunicipality
);
2354 INSERT_STRING(db_owner_info
, "adZipCode", owner
->address
->adZipCode
);
2355 INSERT_STRING(db_owner_info
, "adState", owner
->address
->adState
);
2357 INSERT_STRING(db_owner_info
, "nationality", owner
->nationality
);
2358 INSERT_STRING(db_owner_info
, "email", owner
->email
);
2359 INSERT_STRING(db_owner_info
, "telNumber", owner
->telNumber
);
2361 CHECK_FOR_STRING_LENGTH(owner
->identifier
, 0, 20, "identifier")
2362 INSERT_STRING(db_owner_info
, "identifier", owner
->identifier
);
2364 CHECK_FOR_STRING_LENGTH(owner
->registryCode
, 0, 5, "registryCode")
2365 INSERT_STRING(db_owner_info
, "registryCode", owner
->registryCode
);
2367 INSERT_LONGINT(db_owner_info
, "dbState", owner
->dbState
, string
);
2369 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", owner
->dbEffectiveOVM
);
2370 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2371 owner
->dbOpenAddressing
);
2379 /* Convert XSD:tDbUserInfo XML tree into structure
2380 * @context is ISDS context
2381 * @db_user_info is automically reallocated user info structure
2382 * @xpath_ctx is XPath context with current node as XSD:tDbUserInfo element
2383 * In case of error @db_user_info will be freed. */
2384 static isds_error
extract_DbUserInfo(struct isds_ctx
*context
,
2385 struct isds_DbUserInfo
**db_user_info
, xmlXPathContextPtr xpath_ctx
) {
2386 isds_error err
= IE_SUCCESS
;
2387 xmlXPathObjectPtr result
= NULL
;
2388 char *string
= NULL
;
2390 if (!context
) return IE_INVALID_CONTEXT
;
2391 if (!db_user_info
) return IE_INVAL
;
2392 isds_DbUserInfo_free(db_user_info
);
2393 if (!xpath_ctx
) return IE_INVAL
;
2396 *db_user_info
= calloc(1, sizeof(**db_user_info
));
2397 if (!*db_user_info
) {
2402 EXTRACT_STRING("isds:userID", (*db_user_info
)->userID
);
2404 EXTRACT_STRING("isds:userType", string
);
2406 (*db_user_info
)->userType
=
2407 calloc(1, sizeof(*((*db_user_info
)->userType
)));
2408 if (!(*db_user_info
)->userType
) {
2412 err
= string2isds_UserType((xmlChar
*)string
,
2413 (*db_user_info
)->userType
);
2415 zfree((*db_user_info
)->userType
);
2416 if (err
== IE_ENUM
) {
2418 char *string_locale
= utf82locale(string
);
2419 isds_printf_message(context
, _("Unknown isds:userType: %s"),
2421 free(string_locale
);
2428 EXTRACT_LONGINT("isds:userPrivils", (*db_user_info
)->userPrivils
, 0);
2430 (*db_user_info
)->personName
=
2431 calloc(1, sizeof(*((*db_user_info
)->personName
)));
2432 if (!(*db_user_info
)->personName
) {
2437 err
= extract_gPersonName(context
, &(*db_user_info
)->personName
,
2439 if (err
) goto leave
;
2441 err
= extract_gAddress(context
, &(*db_user_info
)->address
, xpath_ctx
);
2442 if (err
) goto leave
;
2444 err
= extract_BiDate(context
, &(*db_user_info
)->biDate
, xpath_ctx
);
2445 if (err
) goto leave
;
2447 EXTRACT_STRING("isds:ic", (*db_user_info
)->ic
);
2448 EXTRACT_STRING("isds:firmName", (*db_user_info
)->firmName
);
2450 EXTRACT_STRING("isds:caStreet", (*db_user_info
)->caStreet
);
2451 EXTRACT_STRING("isds:caCity", (*db_user_info
)->caCity
);
2452 EXTRACT_STRING("isds:caZipCode", (*db_user_info
)->caZipCode
);
2455 if (err
) isds_DbUserInfo_free(db_user_info
);
2457 xmlXPathFreeObject(result
);
2462 /* Insert struct isds_DbUserInfo data (user description) into XML tree
2463 * @context is sesstion context
2464 * @user is libsids structure with user description
2465 * @db_user_info is XML element of XSD:tDbUserInfo */
2466 static isds_error
insert_DbUserInfo(struct isds_ctx
*context
,
2467 const struct isds_DbUserInfo
*user
, xmlNodePtr db_user_info
) {
2469 isds_error err
= IE_SUCCESS
;
2471 xmlChar
*string
= NULL
;
2473 if (!context
) return IE_INVALID_CONTEXT
;
2474 if (!user
|| !db_user_info
) return IE_INVAL
;
2476 /* Build XSD:tDbUserInfo */
2477 if (user
->personName
) {
2478 INSERT_STRING(db_user_info
, "pnFirstName",
2479 user
->personName
->pnFirstName
);
2480 INSERT_STRING(db_user_info
, "pnMiddleName",
2481 user
->personName
->pnMiddleName
);
2482 INSERT_STRING(db_user_info
, "pnLastName",
2483 user
->personName
->pnLastName
);
2484 INSERT_STRING(db_user_info
, "pnLastNameAtBirth",
2485 user
->personName
->pnLastNameAtBirth
);
2487 if (user
->address
) {
2488 INSERT_STRING(db_user_info
, "adCity", user
->address
->adCity
);
2489 INSERT_STRING(db_user_info
, "adStreet", user
->address
->adStreet
);
2490 INSERT_STRING(db_user_info
, "adNumberInStreet",
2491 user
->address
->adNumberInStreet
);
2492 INSERT_STRING(db_user_info
, "adNumberInMunicipality",
2493 user
->address
->adNumberInMunicipality
);
2494 INSERT_STRING(db_user_info
, "adZipCode", user
->address
->adZipCode
);
2495 INSERT_STRING(db_user_info
, "adState", user
->address
->adState
);
2498 if (!tm2datestring(user
->biDate
, &string
))
2499 INSERT_STRING(db_user_info
, "biDate", string
);
2502 CHECK_FOR_STRING_LENGTH(user
->userID
, 6, 12, "userID");
2503 INSERT_STRING(db_user_info
, "userID", user
->userID
);
2506 if (user
->userType
) {
2507 const xmlChar
*type_string
= isds_UserType2string(*(user
->userType
));
2509 isds_printf_message(context
, _("Invalid userType value: %d"),
2514 INSERT_STRING(db_user_info
, "userType", type_string
);
2517 INSERT_LONGINT(db_user_info
, "userPrivils", user
->userPrivils
, string
);
2518 CHECK_FOR_STRING_LENGTH(user
->ic
, 0, 8, "ic")
2519 INSERT_STRING(db_user_info
, "ic", user
->ic
);
2520 CHECK_FOR_STRING_LENGTH(user
->firmName
, 0, 100, "firmName")
2521 INSERT_STRING(db_user_info
, "firmName", user
->firmName
);
2522 INSERT_STRING(db_user_info
, "caStreet", user
->caStreet
);
2523 INSERT_STRING(db_user_info
, "caCity", user
->caCity
);
2524 INSERT_STRING(db_user_info
, "caZipCode", user
->caZipCode
);
2532 /* Convert XSD gMessageEnvelopeSub group of elements from XML tree into
2533 * isds_envelope structure. The envelope is automatically allocated but not
2534 * reallocated. The date are just appended into envelope structure.
2535 * @context is ISDS context
2536 * @envelope is automically allocated message envelope structure
2537 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2538 * In case of error @envelope will be freed. */
2539 static isds_error
append_GMessageEnvelopeSub(struct isds_ctx
*context
,
2540 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2541 isds_error err
= IE_SUCCESS
;
2542 xmlXPathObjectPtr result
= NULL
;
2544 if (!context
) return IE_INVALID_CONTEXT
;
2545 if (!envelope
) return IE_INVAL
;
2546 if (!xpath_ctx
) return IE_INVAL
;
2550 /* Allocate envelope */
2551 *envelope
= calloc(1, sizeof(**envelope
));
2557 /* Else free former data */
2558 zfree((*envelope
)->dmSenderOrgUnit
);
2559 zfree((*envelope
)->dmSenderOrgUnitNum
);
2560 zfree((*envelope
)->dbIDRecipient
);
2561 zfree((*envelope
)->dmRecipientOrgUnit
);
2562 zfree((*envelope
)->dmSenderOrgUnitNum
);
2563 zfree((*envelope
)->dmToHands
);
2564 zfree((*envelope
)->dmAnnotation
);
2565 zfree((*envelope
)->dmRecipientRefNumber
);
2566 zfree((*envelope
)->dmSenderRefNumber
);
2567 zfree((*envelope
)->dmRecipientIdent
);
2568 zfree((*envelope
)->dmSenderIdent
);
2569 zfree((*envelope
)->dmLegalTitleLaw
);
2570 zfree((*envelope
)->dmLegalTitleYear
);
2571 zfree((*envelope
)->dmLegalTitleSect
);
2572 zfree((*envelope
)->dmLegalTitlePar
);
2573 zfree((*envelope
)->dmLegalTitlePoint
);
2574 zfree((*envelope
)->dmPersonalDelivery
);
2575 zfree((*envelope
)->dmAllowSubstDelivery
);
2578 /* Extract envelope elements added by sender or ISDS
2579 * (XSD: gMessageEnvelopeSub type) */
2580 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
2581 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
2582 (*envelope
)->dmSenderOrgUnitNum
, 0);
2583 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
2584 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
2585 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
2586 (*envelope
)->dmSenderOrgUnitNum
, 0);
2587 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
2588 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
2589 EXTRACT_STRING("isds:dmRecipientRefNumber",
2590 (*envelope
)->dmRecipientRefNumber
);
2591 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
2592 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
2593 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
2595 /* Extract envelope elements regarding law refference */
2596 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
2597 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
2598 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
2599 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
2600 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
2602 /* Extract envelope other elements */
2603 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
2604 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
2605 (*envelope
)->dmAllowSubstDelivery
);
2608 if (err
) isds_envelope_free(envelope
);
2609 xmlXPathFreeObject(result
);
2615 /* Convert XSD gMessageEnvelope group of elements from XML tree into
2616 * isds_envelope structure. The envelope is automatically allocated but not
2617 * reallocated. The date are just appended into envelope structure.
2618 * @context is ISDS context
2619 * @envelope is automically allocated message envelope structure
2620 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2621 * In case of error @envelope will be freed. */
2622 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
2623 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2624 isds_error err
= IE_SUCCESS
;
2625 xmlXPathObjectPtr result
= NULL
;
2627 if (!context
) return IE_INVALID_CONTEXT
;
2628 if (!envelope
) return IE_INVAL
;
2629 if (!xpath_ctx
) return IE_INVAL
;
2633 /* Allocate envelope */
2634 *envelope
= calloc(1, sizeof(**envelope
));
2640 /* Else free former data */
2641 zfree((*envelope
)->dmID
);
2642 zfree((*envelope
)->dbIDSender
);
2643 zfree((*envelope
)->dmSender
);
2644 zfree((*envelope
)->dmSenderAddress
);
2645 zfree((*envelope
)->dmSenderType
);
2646 zfree((*envelope
)->dmRecipient
);
2647 zfree((*envelope
)->dmRecipientAddress
);
2648 zfree((*envelope
)->dmAmbiguousRecipient
);
2651 /* Extract envelope elements added by ISDS
2652 * (XSD: gMessageEnvelope type) */
2653 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
2654 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
2655 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
2656 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
2657 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
2658 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
2659 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
2660 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
2661 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
2662 (*envelope
)->dmAmbiguousRecipient
);
2664 /* Extract envelope elements added by sender and ISDS
2665 * (XSD: gMessageEnvelope type) */
2666 err
= append_GMessageEnvelopeSub(context
, envelope
, xpath_ctx
);
2667 if (err
) goto leave
;
2670 if (err
) isds_envelope_free(envelope
);
2671 xmlXPathFreeObject(result
);
2676 /* Convert other envelope elements from XML tree into isds_envelope structure:
2677 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
2678 * The envelope is automatically allocated but not reallocated.
2679 * The data are just appended into envelope structure.
2680 * @context is ISDS context
2681 * @envelope is automically allocated message envelope structure
2682 * @xpath_ctx is XPath context with current node as parent desired elements
2683 * In case of error @envelope will be freed. */
2684 static isds_error
append_status_size_times(struct isds_ctx
*context
,
2685 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2686 isds_error err
= IE_SUCCESS
;
2687 xmlXPathObjectPtr result
= NULL
;
2688 char *string
= NULL
;
2689 unsigned long int *unumber
= NULL
;
2691 if (!context
) return IE_INVALID_CONTEXT
;
2692 if (!envelope
) return IE_INVAL
;
2693 if (!xpath_ctx
) return IE_INVAL
;
2698 *envelope
= calloc(1, sizeof(**envelope
));
2705 zfree((*envelope
)->dmMessageStatus
);
2706 zfree((*envelope
)->dmAttachmentSize
);
2707 zfree((*envelope
)->dmDeliveryTime
);
2708 zfree((*envelope
)->dmAcceptanceTime
);
2712 /* dmMessageStatus element is mandatory */
2713 EXTRACT_ULONGINT("sisds:dmMessageStatus", unumber
, 0);
2715 isds_log_message(context
,
2716 _("Missing mandatory sisds:dmMessageStatus integer"));
2720 err
= uint2isds_message_status(context
, unumber
,
2721 &((*envelope
)->dmMessageStatus
));
2723 if (err
== IE_ENUM
) err
= IE_ISDS
;
2726 free(unumber
); unumber
= NULL
;
2728 EXTRACT_ULONGINT("sisds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
,
2731 EXTRACT_STRING("sisds:dmDeliveryTime", string
);
2733 err
= timestring2timeval((xmlChar
*) string
,
2734 &((*envelope
)->dmDeliveryTime
));
2736 char *string_locale
= utf82locale(string
);
2737 if (err
== IE_DATE
) err
= IE_ISDS
;
2738 isds_printf_message(context
,
2739 _("Could not convert dmDeliveryTime as ISO time: %s"),
2741 free(string_locale
);
2747 EXTRACT_STRING("sisds:dmAcceptanceTime", string
);
2749 err
= timestring2timeval((xmlChar
*) string
,
2750 &((*envelope
)->dmAcceptanceTime
));
2752 char *string_locale
= utf82locale(string
);
2753 if (err
== IE_DATE
) err
= IE_ISDS
;
2754 isds_printf_message(context
,
2755 _("Could not convert dmAcceptanceTime as ISO time: %s"),
2757 free(string_locale
);
2764 if (err
) isds_envelope_free(envelope
);
2767 xmlXPathFreeObject(result
);
2772 /* Convert message type attribute of current element into isds_envelope
2774 * TODO: This function can be incorporated into append_status_size_times() as
2775 * they are called always together.
2776 * The envelope is automatically allocated but not reallocated.
2777 * The data are just appended into envelope structure.
2778 * @context is ISDS context
2779 * @envelope is automically allocated message envelope structure
2780 * @xpath_ctx is XPath context with current node as parent of attribute
2781 * carrying message type
2782 * In case of error @envelope will be freed. */
2783 static isds_error
append_message_type(struct isds_ctx
*context
,
2784 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2785 isds_error err
= IE_SUCCESS
;
2787 if (!context
) return IE_INVALID_CONTEXT
;
2788 if (!envelope
) return IE_INVAL
;
2789 if (!xpath_ctx
) return IE_INVAL
;
2794 *envelope
= calloc(1, sizeof(**envelope
));
2801 zfree((*envelope
)->dmType
);
2805 EXTRACT_STRING_ATTRIBUTE("dmType", (*envelope
)->dmType
, 0);
2807 if (!(*envelope
)->dmType
) {
2808 /* Use default value */
2809 (*envelope
)->dmType
= strdup("V");
2810 if (!(*envelope
)->dmType
) {
2814 } else if (1 != xmlUTF8Strlen((xmlChar
*) (*envelope
)->dmType
)) {
2815 char *type_locale
= utf82locale((*envelope
)->dmType
);
2816 isds_printf_message(context
,
2817 _("Message type in dmType attribute is not 1 character long: "
2826 if (err
) isds_envelope_free(envelope
);
2832 /* Extract message document into reallocated document structure
2833 * @context is ISDS context
2834 * @document is automically reallocated message documents structure
2835 * @xpath_ctx is XPath context with current node as isds:dmFile
2836 * In case of error @document will be freed. */
2837 static isds_error
extract_document(struct isds_ctx
*context
,
2838 struct isds_document
**document
, xmlXPathContextPtr xpath_ctx
) {
2839 isds_error err
= IE_SUCCESS
;
2840 xmlXPathObjectPtr result
= NULL
;
2841 xmlNodePtr file_node
= xpath_ctx
->node
;
2842 char *string
= NULL
;
2844 if (!context
) return IE_INVALID_CONTEXT
;
2845 if (!document
) return IE_INVAL
;
2846 isds_document_free(document
);
2847 if (!xpath_ctx
) return IE_INVAL
;
2849 *document
= calloc(1, sizeof(**document
));
2855 /* Extract document metadata */
2856 EXTRACT_STRING_ATTRIBUTE("dmMimeType", (*document
)->dmMimeType
, 1)
2858 EXTRACT_STRING_ATTRIBUTE("dmFileMetaType", string
, 1)
2859 err
= string2isds_FileMetaType((xmlChar
*)string
,
2860 &((*document
)->dmFileMetaType
));
2862 char *meta_type_locale
= utf82locale(string
);
2863 isds_printf_message(context
,
2864 _("Document has invalid dmFileMetaType attribute value: %s"),
2866 free(meta_type_locale
);
2872 EXTRACT_STRING_ATTRIBUTE("dmFileGuid", (*document
)->dmFileGuid
, 0)
2873 EXTRACT_STRING_ATTRIBUTE("dmUpFileGuid", (*document
)->dmUpFileGuid
, 0)
2874 EXTRACT_STRING_ATTRIBUTE("dmFileDescr", (*document
)->dmFileDescr
, 0)
2875 EXTRACT_STRING_ATTRIBUTE("dmFormat", (*document
)->dmFormat
, 0)
2878 /* Extract document data.
2879 * Base64 encoded blob or XML subtree must be presented. */
2881 /* Check from dmEncodedContent */
2882 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmEncodedContent",
2889 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2890 /* Here we have Base64 blob */
2892 if (result
->nodesetval
->nodeNr
> 1) {
2893 isds_printf_message(context
,
2894 _("Document has more dmEncodedContent elements"));
2899 xmlXPathFreeObject(result
); result
= NULL
;
2900 EXTRACT_STRING("isds:dmEncodedContent", string
);
2902 /* Decode non-emptys document */
2903 if (string
&& string
[0] != '\0') {
2904 (*document
)->data_length
= b64decode(string
, &((*document
)->data
));
2905 if ((*document
)->data_length
== (size_t) -1) {
2906 isds_printf_message(context
,
2907 _("Error while Base64-decoding document content"));
2913 /* No Base64 blob, try XML document */
2914 xmlXPathFreeObject(result
); result
= NULL
;
2915 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmXMLContent",
2922 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2923 /* Here we have XML document */
2925 if (result
->nodesetval
->nodeNr
> 1) {
2926 isds_printf_message(context
,
2927 _("Document has more dmXMLContent elements"));
2932 /* FIXME: Serialize the tree rooted at result's node */
2933 isds_printf_message(context
,
2934 _("XML documents not yet supported"));
2938 /* No bas64 blob, nor XML document */
2939 isds_printf_message(context
,
2940 _("Document has no dmEncodedContent, nor dmXMLContent "
2949 if (err
) isds_document_free(document
);
2951 xmlXPathFreeObject(result
);
2952 xpath_ctx
->node
= file_node
;
2958 /* Extract message documents into reallocated list of documents
2959 * @context is ISDS context
2960 * @documents is automically reallocated message documents list structure
2961 * @xpath_ctx is XPath context with current node as XSD tFilesArray
2962 * In case of error @documents will be freed. */
2963 static isds_error
extract_documents(struct isds_ctx
*context
,
2964 struct isds_list
**documents
, xmlXPathContextPtr xpath_ctx
) {
2965 isds_error err
= IE_SUCCESS
;
2966 xmlXPathObjectPtr result
= NULL
;
2967 xmlNodePtr files_node
= xpath_ctx
->node
;
2968 struct isds_list
*document
, *prev_document
;
2970 if (!context
) return IE_INVALID_CONTEXT
;
2971 if (!documents
) return IE_INVAL
;
2972 isds_list_free(documents
);
2973 if (!xpath_ctx
) return IE_INVAL
;
2975 /* Find documents */
2976 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmFile", xpath_ctx
);
2983 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2984 isds_printf_message(context
,
2985 _("Message does not contain any document"));
2991 /* Iterate over documents */
2992 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2994 /* Allocate and append list item */
2995 document
= calloc(1, sizeof(*document
));
3000 document
->destructor
= (void (*)(void **))isds_document_free
;
3001 if (i
== 0) *documents
= document
;
3002 else prev_document
->next
= document
;
3003 prev_document
= document
;
3005 /* Extract document */
3006 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3007 err
= extract_document(context
,
3008 (struct isds_document
**) &(document
->data
), xpath_ctx
);
3009 if (err
) goto leave
;
3014 if (err
) isds_list_free(documents
);
3015 xmlXPathFreeObject(result
);
3016 xpath_ctx
->node
= files_node
;
3021 /* Convert isds:dmRecord XML tree into structure
3022 * @context is ISDS context
3023 * @envelope is automically reallocated message envelope structure
3024 * @xpath_ctx is XPath context with current node as isds:dmRecord element
3025 * In case of error @envelope will be freed. */
3026 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
3027 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3028 isds_error err
= IE_SUCCESS
;
3029 xmlXPathObjectPtr result
= NULL
;
3031 if (!context
) return IE_INVALID_CONTEXT
;
3032 if (!envelope
) return IE_INVAL
;
3033 isds_envelope_free(envelope
);
3034 if (!xpath_ctx
) return IE_INVAL
;
3037 *envelope
= calloc(1, sizeof(**envelope
));
3044 /* Extract tRecord data */
3045 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
3047 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3048 * dmAcceptanceTime. */
3049 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
3050 if (err
) goto leave
;
3052 /* Extract envelope elements added by sender and ISDS
3053 * (XSD: gMessageEnvelope type) */
3054 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
3055 if (err
) goto leave
;
3056 /* dmOVM can not be obtained from ISDS */
3058 /* Get message type */
3059 err
= append_message_type(context
, envelope
, xpath_ctx
);
3060 if (err
) goto leave
;
3064 if (err
) isds_envelope_free(envelope
);
3065 xmlXPathFreeObject(result
);
3070 /* Find and convert isds:dmHash XML tree into structure
3071 * @context is ISDS context
3072 * @envelope is automically reallocated message hash structure
3073 * @xpath_ctx is XPath context with current node containing isds:dmHash child
3074 * In case of error @hash will be freed. */
3075 static isds_error
find_and_extract_DmHash(struct isds_ctx
*context
,
3076 struct isds_hash
**hash
, xmlXPathContextPtr xpath_ctx
) {
3077 isds_error err
= IE_SUCCESS
;
3078 xmlNodePtr old_ctx_node
;
3079 xmlXPathObjectPtr result
= NULL
;
3080 char *string
= NULL
;
3082 if (!context
) return IE_INVALID_CONTEXT
;
3083 if (!hash
) return IE_INVAL
;
3084 isds_hash_free(hash
);
3085 if (!xpath_ctx
) return IE_INVAL
;
3087 old_ctx_node
= xpath_ctx
->node
;
3089 *hash
= calloc(1, sizeof(**hash
));
3096 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmHash", xpath_ctx
);
3097 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3106 /* Get hash algorithm */
3107 EXTRACT_STRING_ATTRIBUTE("algorithm", string
, 1);
3108 err
= string2isds_hash_algorithm((xmlChar
*) string
, &(*hash
)->algorithm
);
3110 if (err
== IE_ENUM
) {
3111 char *string_locale
= utf82locale(string
);
3112 isds_printf_message(context
, _("Unsported hash algorithm: %s"),
3114 free(string_locale
);
3120 /* Get hash value */
3121 EXTRACT_STRING(".", string
);
3123 isds_printf_message(context
, _("tHash element is missing hash value"));
3127 (*hash
)->length
= b64decode(string
, &((*hash
)->value
));
3128 if ((*hash
)->length
== (size_t) -1) {
3129 isds_printf_message(context
,
3130 _("Error while Base64-decoding hash value"));
3136 if (err
) isds_hash_free(hash
);
3138 xmlXPathFreeObject(result
);
3139 xpath_ctx
->node
= old_ctx_node
;
3144 /* Find and append isds:dmQTimestamp XML tree into envelope
3145 * @context is ISDS context
3146 * @envelope is automically allocated evnelope structure
3147 * @xpath_ctx is XPath context with current node containing isds:dmQTimestamp
3149 * In case of error @envelope will be freed. */
3150 static isds_error
find_and_append_DmQTimestamp(struct isds_ctx
*context
,
3151 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3152 isds_error err
= IE_SUCCESS
;
3153 xmlXPathObjectPtr result
= NULL
;
3154 char *string
= NULL
;
3156 if (!context
) return IE_INVALID_CONTEXT
;
3157 if (!envelope
) return IE_INVAL
;
3159 isds_envelope_free(envelope
);
3164 *envelope
= calloc(1, sizeof(**envelope
));
3170 zfree((*envelope
)->timestamp
);
3171 (*envelope
)->timestamp_length
= 0;
3174 /* Get dmQTimestamp */
3175 EXTRACT_STRING("sisds:dmQTimestamp", string
);
3177 isds_printf_message(context
, _("Missing dmQTimestamp element content"));
3181 (*envelope
)->timestamp_length
=
3182 b64decode(string
, &((*envelope
)->timestamp
));
3183 if ((*envelope
)->timestamp_length
== (size_t) -1) {
3184 isds_printf_message(context
,
3185 _("Error while Base64-decoding timestamp value"));
3191 if (err
) isds_envelope_free(envelope
);
3193 xmlXPathFreeObject(result
);
3198 /* Convert XSD tReturnedMessage XML tree into message structure.
3199 * It doea not store XML tree into message->raw.
3200 * @context is ISDS context
3201 * @include_documents Use true if documents must be extracted
3202 * (tReturnedMessage XSD type), use false if documents shall be ommited
3203 * (tReturnedMessageEnvelope).
3204 * @message is automically reallocated message structure
3205 * @xpath_ctx is XPath context with current node as tReturnedMessage element
3207 * In case of error @message will be freed. */
3208 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
3209 const _Bool include_documents
, struct isds_message
**message
,
3210 xmlXPathContextPtr xpath_ctx
) {
3211 isds_error err
= IE_SUCCESS
;
3212 xmlNodePtr message_node
;
3214 if (!context
) return IE_INVALID_CONTEXT
;
3215 if (!message
) return IE_INVAL
;
3216 isds_message_free(message
);
3217 if (!xpath_ctx
) return IE_INVAL
;
3220 *message
= calloc(1, sizeof(**message
));
3226 /* Save message XPATH context node */
3227 message_node
= xpath_ctx
->node
;
3231 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
3232 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
3233 if (err
) { err
= IE_ERROR
; goto leave
; }
3234 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
3235 if (err
) goto leave
;
3237 if (include_documents
) {
3238 /* Extract dmFiles */
3239 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles",
3241 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3242 err
= IE_ISDS
; goto leave
;
3244 if (err
) { err
= IE_ERROR
; goto leave
; }
3245 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
3246 if (err
) goto leave
;
3250 /* Restore context to message */
3251 xpath_ctx
->node
= message_node
;
3253 /* Extract dmHash */
3254 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
3256 if (err
) goto leave
;
3258 /* Extract dmQTimestamp, */
3259 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
3261 if (err
) goto leave
;
3263 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3264 * dmAcceptanceTime. */
3265 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
3266 if (err
) goto leave
;
3268 /* Get message type */
3269 err
= append_message_type(context
, &((*message
)->envelope
), xpath_ctx
);
3270 if (err
) goto leave
;
3273 if (err
) isds_message_free(message
);
3278 /* Extract message event into reallocated isds_event structure
3279 * @context is ISDS context
3280 * @event is automically reallocated message event structure
3281 * @xpath_ctx is XPath context with current node as isds:dmEvent
3282 * In case of error @event will be freed. */
3283 static isds_error
extract_event(struct isds_ctx
*context
,
3284 struct isds_event
**event
, xmlXPathContextPtr xpath_ctx
) {
3285 isds_error err
= IE_SUCCESS
;
3286 xmlXPathObjectPtr result
= NULL
;
3287 xmlNodePtr event_node
= xpath_ctx
->node
;
3288 char *string
= NULL
;
3290 if (!context
) return IE_INVALID_CONTEXT
;
3291 if (!event
) return IE_INVAL
;
3292 isds_event_free(event
);
3293 if (!xpath_ctx
) return IE_INVAL
;
3295 *event
= calloc(1, sizeof(**event
));
3301 /* Extract event data.
3302 * All elements are optional according XSD. That's funny. */
3303 EXTRACT_STRING("sisds:dmEventTime", string
);
3305 err
= timestring2timeval((xmlChar
*) string
, &((*event
)->time
));
3307 char *string_locale
= utf82locale(string
);
3308 if (err
== IE_DATE
) err
= IE_ISDS
;
3309 isds_printf_message(context
,
3310 _("Could not convert dmEventTime as ISO time: %s"),
3312 free(string_locale
);
3318 /* dmEventDescr element has prefix and the rest */
3319 EXTRACT_STRING("sisds:dmEventDescr", string
);
3321 err
= eventstring2event((xmlChar
*) string
, *event
);
3322 if (err
) goto leave
;
3327 if (err
) isds_event_free(event
);
3329 xmlXPathFreeObject(result
);
3330 xpath_ctx
->node
= event_node
;
3335 /* Convert element of XSD tEventsArray type from XML tree into
3336 * isds_list of isds_event's structure. The list is automatically reallocated.
3337 * @context is ISDS context
3338 * @events is automically reallocated list of event structures
3339 * @xpath_ctx is XPath context with current node as tEventsArray
3340 * In case of error @evnets will be freed. */
3341 static isds_error
extract_events(struct isds_ctx
*context
,
3342 struct isds_list
**events
, xmlXPathContextPtr xpath_ctx
) {
3343 isds_error err
= IE_SUCCESS
;
3344 xmlXPathObjectPtr result
= NULL
;
3345 xmlNodePtr events_node
= xpath_ctx
->node
;
3346 struct isds_list
*event
, *prev_event
= NULL
;
3348 if (!context
) return IE_INVALID_CONTEXT
;
3349 if (!events
) return IE_INVAL
;
3350 if (!xpath_ctx
) return IE_INVAL
;
3353 isds_list_free(events
);
3356 result
= xmlXPathEvalExpression(BAD_CAST
"sisds:dmEvent", xpath_ctx
);
3363 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3364 isds_printf_message(context
,
3365 _("Delivery info does not contain any event"));
3371 /* Iterate over events */
3372 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3374 /* Allocate and append list item */
3375 event
= calloc(1, sizeof(*event
));
3380 event
->destructor
= (void (*)(void **))isds_event_free
;
3381 if (i
== 0) *events
= event
;
3382 else prev_event
->next
= event
;
3386 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3387 err
= extract_event(context
,
3388 (struct isds_event
**) &(event
->data
), xpath_ctx
);
3389 if (err
) goto leave
;
3394 if (err
) isds_list_free(events
);
3395 xmlXPathFreeObject(result
);
3396 xpath_ctx
->node
= events_node
;
3401 /* Convert isds_document structure into XML tree and append to dmFiles node.
3402 * @context is session context
3403 * @document is ISDS document
3404 * @dm_files is XML element the resulting tree will be appended to as a child.
3405 * @return error code, in case of error context' message is filled. */
3406 static isds_error
insert_document(struct isds_ctx
*context
,
3407 struct isds_document
*document
, xmlNodePtr dm_files
) {
3408 isds_error err
= IE_SUCCESS
;
3409 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
3410 xmlAttrPtr attribute_node
;
3411 xmlChar
*base64data
= NULL
;
3413 if (!context
) return IE_INVALID_CONTEXT
;
3414 if (!document
|| !dm_files
) return IE_INVAL
;
3416 /* Allocate new dmFile */
3417 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
3419 isds_printf_message(context
, _("Could not allocate main dmFile"));
3423 /* Append the new dmFile.
3424 * XXX: Main document must go first */
3425 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
3426 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
3428 file
= xmlAddChild(dm_files
, new_file
);
3431 xmlFreeNode(new_file
); new_file
= NULL
;
3432 isds_printf_message(context
, _("Could not add dmFile child to "
3433 "%s element"), dm_files
->name
);
3438 /* @dmMimeType is required */
3439 if (!document
->dmMimeType
) {
3440 isds_log_message(context
,
3441 _("Document is missing mandatory MIME type definition"));
3445 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
3447 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
3449 isds_printf_message(context
,
3450 _("Document has unkown dmFileMetaType: %ld"),
3451 document
->dmFileMetaType
);
3455 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
3457 if (document
->dmFileGuid
) {
3458 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
3460 if (document
->dmUpFileGuid
) {
3461 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
3464 /* @dmFileDescr is required */
3465 if (!document
->dmFileDescr
) {
3466 isds_log_message(context
,
3467 _("Document is missing mandatory description (title)"));
3471 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
3473 if (document
->dmFormat
) {
3474 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
3478 /* Insert content (data) of the document. */
3479 /* XXX; Only base64 is implemented currently. */
3480 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
3482 isds_printf_message(context
,
3483 _("Not enought memory to encode %zd bytes into Base64"),
3484 document
->data_length
);
3488 INSERT_STRING(file
, "dmEncodedContent", base64data
);
3496 /* Append XSD tMStatus XML tree into isds_message_copy structure.
3497 * The copy must pre prealocated, the date are just appended into structure.
3498 * @context is ISDS context
3499 * @copy is message copy struture
3500 * @xpath_ctx is XPath context with current node as tMStatus */
3501 static isds_error
append_TMStatus(struct isds_ctx
*context
,
3502 struct isds_message_copy
*copy
, xmlXPathContextPtr xpath_ctx
) {
3503 isds_error err
= IE_SUCCESS
;
3504 xmlXPathObjectPtr result
= NULL
;
3505 char *code
= NULL
, *message
= NULL
;
3507 if (!context
) return IE_INVALID_CONTEXT
;
3508 if (!copy
|| !xpath_ctx
) return IE_INVAL
;
3510 /* Free old values */
3511 zfree(copy
->dmStatus
);
3514 /* Get error specific to this copy */
3515 EXTRACT_STRING("isds:dmStatus/isds:dmStatusCode", code
);
3517 isds_log_message(context
,
3518 _("Missing isds:dmStatusCode under "
3519 "XSD:tMStatus type element"));
3524 if (xmlStrcmp((const xmlChar
*)code
, BAD_CAST
"0000")) {
3525 /* This copy failed */
3526 copy
->error
= IE_ISDS
;
3527 EXTRACT_STRING("isds:dmStatus/isds:dmStatusMessage", message
);
3529 copy
->dmStatus
= astrcat3(code
, ": ", message
);
3530 if (!copy
->dmStatus
) {
3531 copy
->dmStatus
= code
;
3535 copy
->dmStatus
= code
;
3539 /* This copy succeeded. In this case only, message ID is valid */
3540 copy
->error
= IE_SUCCESS
;
3542 EXTRACT_STRING("isds:dmID", copy
->dmID
);
3544 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3545 "but did not returned assigned message ID\n"));
3553 xmlXPathFreeObject(result
);
3558 /* Build ISDS request of XSD tDummyInput type, sent it and check for error
3560 * @context is session context
3561 * @service_name is name of SERVICE_DB_ACCESS
3562 * @response is server SOAP body response as XML document
3563 * @raw_response is automatically reallocated bitstream with response body. Use
3564 * NULL if you don't care
3565 * @raw_response_length is size of @raw_response in bytes
3566 * @code is ISDS status code
3567 * @status_message is ISDS status message
3568 * @return error coded from lower layer, context message will be set up
3570 static isds_error
build_send_check_dbdummy_request(struct isds_ctx
*context
,
3571 const xmlChar
*service_name
,
3572 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
3573 xmlChar
**code
, xmlChar
**status_message
) {
3575 isds_error err
= IE_SUCCESS
;
3576 char *service_name_locale
= NULL
;
3577 xmlNodePtr request
= NULL
, node
;
3578 xmlNsPtr isds_ns
= NULL
;
3580 if (!context
) return IE_INVALID_CONTEXT
;
3581 if (!service_name
) return IE_INVAL
;
3582 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3583 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
3585 /* Free output argument */
3586 xmlFreeDoc(*response
); *response
= NULL
;
3587 if (raw_response
) zfree(*raw_response
);
3589 free(*status_message
);
3592 /* Check if connection is established
3593 * TODO: This check should be done donwstairs. */
3594 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3596 service_name_locale
= utf82locale((char*)service_name
);
3597 if (!service_name_locale
) {
3603 request
= xmlNewNode(NULL
, service_name
);
3605 isds_printf_message(context
,
3606 _("Could not build %s request"), service_name_locale
);
3610 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3612 isds_log_message(context
, _("Could not create ISDS name space"));
3616 xmlSetNs(request
, isds_ns
);
3619 /* Add XSD:tDummyInput child */
3620 INSERT_STRING(request
, "dbDummy", NULL
);
3623 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
3624 service_name_locale
);
3627 err
= isds(context
, SERVICE_DB_ACCESS
, request
, response
,
3628 raw_response
, raw_response_length
);
3629 xmlFreeNode(request
); request
= NULL
;
3632 isds_log(ILF_ISDS
, ILL_DEBUG
,
3633 _("Processing ISDS response on %s request failed\n"),
3634 service_name_locale
);
3638 /* Check for response status */
3639 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, *response
,
3640 code
, status_message
, NULL
);
3642 isds_log(ILF_ISDS
, ILL_DEBUG
,
3643 _("ISDS response on %s request is missing status\n"),
3644 service_name_locale
);
3648 /* Request processed, but nothing found */
3649 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3650 char *code_locale
= utf82locale((char*) *code
);
3651 char *status_message_locale
= utf82locale((char*) *status_message
);
3652 isds_log(ILF_ISDS
, ILL_DEBUG
,
3653 _("Server refused %s request (code=%s, message=%s)\n"),
3654 service_name_locale
, code_locale
, status_message_locale
);
3655 isds_log_message(context
, status_message_locale
);
3657 free(status_message_locale
);
3663 free(service_name_locale
);
3664 xmlFreeNode(request
);
3669 /* Get data about logged in user and his box. */
3670 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
3671 struct isds_DbOwnerInfo
**db_owner_info
) {
3672 isds_error err
= IE_SUCCESS
;
3673 xmlDocPtr response
= NULL
;
3674 xmlChar
*code
= NULL
, *message
= NULL
;
3675 xmlXPathContextPtr xpath_ctx
= NULL
;
3676 xmlXPathObjectPtr result
= NULL
;
3677 char *string
= NULL
;
3679 if (!context
) return IE_INVALID_CONTEXT
;
3680 if (!db_owner_info
) return IE_INVAL
;
3682 /* Check if connection is established */
3683 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3686 /* Do request and check for success */
3687 err
= build_send_check_dbdummy_request(context
,
3688 BAD_CAST
"GetOwnerInfoFromLogin",
3689 &response
, NULL
, NULL
, &code
, &message
);
3690 if (err
) goto leave
;
3694 /* Prepare stucture */
3695 isds_DbOwnerInfo_free(db_owner_info
);
3696 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
3697 if (!*db_owner_info
) {
3701 xpath_ctx
= xmlXPathNewContext(response
);
3706 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3711 /* Set context node */
3712 result
= xmlXPathEvalExpression(BAD_CAST
3713 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
3718 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3719 isds_log_message(context
, _("Missing dbOwnerInfo element"));
3723 if (result
->nodesetval
->nodeNr
> 1) {
3724 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
3728 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3729 xmlXPathFreeObject(result
); result
= NULL
;
3732 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
3736 isds_DbOwnerInfo_free(db_owner_info
);
3740 xmlXPathFreeObject(result
);
3741 xmlXPathFreeContext(xpath_ctx
);
3745 xmlFreeDoc(response
);
3748 isds_log(ILF_ISDS
, ILL_DEBUG
,
3749 _("GetOwnerInfoFromLogin request processed by server "
3750 "successfully.\n"));
3756 /* Get data about logged in user. */
3757 isds_error
isds_GetUserInfoFromLogin(struct isds_ctx
*context
,
3758 struct isds_DbUserInfo
**db_user_info
) {
3759 isds_error err
= IE_SUCCESS
;
3760 xmlDocPtr response
= NULL
;
3761 xmlChar
*code
= NULL
, *message
= NULL
;
3762 xmlXPathContextPtr xpath_ctx
= NULL
;
3763 xmlXPathObjectPtr result
= NULL
;
3765 if (!context
) return IE_INVALID_CONTEXT
;
3766 if (!db_user_info
) return IE_INVAL
;
3768 /* Check if connection is established */
3769 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3772 /* Do request and check for success */
3773 err
= build_send_check_dbdummy_request(context
,
3774 BAD_CAST
"GetUserInfoFromLogin",
3775 &response
, NULL
, NULL
, &code
, &message
);
3776 if (err
) goto leave
;
3780 /* Prepare stucture */
3781 isds_DbUserInfo_free(db_user_info
);
3782 *db_user_info
= calloc(1, sizeof(**db_user_info
));
3783 if (!*db_user_info
) {
3787 xpath_ctx
= xmlXPathNewContext(response
);
3792 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3797 /* Set context node */
3798 result
= xmlXPathEvalExpression(BAD_CAST
3799 "/isds:GetUserInfoFromLoginResponse/isds:dbUserInfo", xpath_ctx
);
3804 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3805 isds_log_message(context
, _("Missing dbUserInfo element"));
3809 if (result
->nodesetval
->nodeNr
> 1) {
3810 isds_log_message(context
, _("Multiple dbUserInfo element"));
3814 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3815 xmlXPathFreeObject(result
); result
= NULL
;
3818 err
= extract_DbUserInfo(context
, db_user_info
, xpath_ctx
);
3822 isds_DbUserInfo_free(db_user_info
);
3825 xmlXPathFreeObject(result
);
3826 xmlXPathFreeContext(xpath_ctx
);
3830 xmlFreeDoc(response
);
3833 isds_log(ILF_ISDS
, ILL_DEBUG
,
3834 _("GetUserInfoFromLogin request processed by server "
3835 "successfully.\n"));
3841 /* Get expiration time of current password
3842 * @context is session context
3843 * @expiration is automatically reallocated time when password expires, In
3844 * case of error will be nulled. */
3845 isds_error
isds_get_password_expiration(struct isds_ctx
*context
,
3846 struct timeval
**expiration
) {
3847 isds_error err
= IE_SUCCESS
;
3848 xmlDocPtr response
= NULL
;
3849 xmlChar
*code
= NULL
, *message
= NULL
;
3850 xmlXPathContextPtr xpath_ctx
= NULL
;
3851 xmlXPathObjectPtr result
= NULL
;
3852 char *string
= NULL
;
3854 if (!context
) return IE_INVALID_CONTEXT
;
3855 if (!expiration
) return IE_INVAL
;
3857 /* Check if connection is established */
3858 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3861 /* Do request and check for success */
3862 err
= build_send_check_dbdummy_request(context
,
3863 BAD_CAST
"GetPasswordInfo",
3864 &response
, NULL
, NULL
, &code
, &message
);
3865 if (err
) goto leave
;
3869 xpath_ctx
= xmlXPathNewContext(response
);
3874 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3879 /* Set context node */
3880 result
= xmlXPathEvalExpression(BAD_CAST
3881 "/isds:GetPasswordInfoResponse", xpath_ctx
);
3886 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3887 isds_log_message(context
,
3888 _("Missing GetPasswordInfoResponse element"));
3892 if (result
->nodesetval
->nodeNr
> 1) {
3893 isds_log_message(context
,
3894 _("Multiple GetPasswordInfoResponse element"));
3898 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3899 xmlXPathFreeObject(result
); result
= NULL
;
3901 /* Extract expiration date */
3902 EXTRACT_STRING("isds:pswExpDate", string
);
3904 isds_log_message(context
, _("Missing pswExpDate element"));
3909 err
= timestring2timeval((xmlChar
*) string
, expiration
);
3911 char *string_locale
= utf82locale(string
);
3912 if (err
== IE_DATE
) err
= IE_ISDS
;
3913 isds_printf_message(context
,
3914 _("Could not convert pswExpDate as ISO time: %s"),
3916 free(string_locale
);
3928 xmlXPathFreeObject(result
);
3929 xmlXPathFreeContext(xpath_ctx
);
3933 xmlFreeDoc(response
);
3936 isds_log(ILF_ISDS
, ILL_DEBUG
,
3937 _("GetPasswordInfo request processed by server "
3938 "successfully.\n"));
3944 /* Change user password in ISDS.
3945 * User must supply old password, new password will takes effect after some
3946 * time, current session can continue. Password must fulfill some constraints.
3947 * @context is session context
3948 * @old_password is current password.
3949 * @new_password is requested new password */
3950 isds_error
isds_change_password(struct isds_ctx
*context
,
3951 const char *old_password
, const char *new_password
) {
3952 isds_error err
= IE_SUCCESS
;
3953 xmlNsPtr isds_ns
= NULL
;
3954 xmlNodePtr request
= NULL
, node
;
3955 xmlDocPtr response
= NULL
;
3956 xmlChar
*code
= NULL
, *message
= NULL
;
3958 if (!context
) return IE_INVALID_CONTEXT
;
3959 if (!old_password
|| !new_password
) return IE_INVAL
;
3961 /* Check if connection is established
3962 * TODO: This check should be done donwstairs. */
3963 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3966 /* Build ChangeISDSPassword request */
3967 request
= xmlNewNode(NULL
, BAD_CAST
"ChangeISDSPassword");
3969 isds_log_message(context
,
3970 _("Could build ChangeISDSPassword request"));
3973 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3975 isds_log_message(context
, _("Could not create ISDS name space"));
3976 xmlFreeNode(request
);
3979 xmlSetNs(request
, isds_ns
);
3981 INSERT_STRING(request
, "dbOldPassword", old_password
);
3982 INSERT_STRING(request
, "dbNewPassword", new_password
);
3985 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
3988 err
= isds(context
, SERVICE_DB_ACCESS
, request
, &response
, NULL
, NULL
);
3990 /* Destroy request */
3991 xmlFreeNode(request
); request
= NULL
;
3994 isds_log(ILF_ISDS
, ILL_DEBUG
,
3995 _("Processing ISDS response on ChangeISDSPassword "
3996 "request failed\n"));
4000 /* Check for response status */
4001 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, response
,
4002 &code
, &message
, NULL
);
4004 isds_log(ILF_ISDS
, ILL_DEBUG
,
4005 _("ISDS response on ChangeISDSPassword request is missing "
4010 /* Request processed, but empty password refused */
4011 if (!xmlStrcmp(code
, BAD_CAST
"1066")) {
4012 char *code_locale
= utf82locale((char*)code
);
4013 char *message_locale
= utf82locale((char*)message
);
4014 isds_log(ILF_ISDS
, ILL_DEBUG
,
4015 _("Server refused empty password on ChangeISDSPassword "
4016 "request (code=%s, message=%s)\n"),
4017 code_locale
, message_locale
);
4018 isds_log_message(context
, _("Password must not be empty"));
4020 free(message_locale
);
4025 /* Request processed, but new password was reused */
4026 else if (!xmlStrcmp(code
, BAD_CAST
"1067")) {
4027 char *code_locale
= utf82locale((char*)code
);
4028 char *message_locale
= utf82locale((char*)message
);
4029 isds_log(ILF_ISDS
, ILL_DEBUG
,
4030 _("Server refused the same new password on ChangeISDSPassword "
4031 "request (code=%s, message=%s)\n"),
4032 code_locale
, message_locale
);
4033 isds_log_message(context
,
4034 _("New password must differ from the current one"));
4036 free(message_locale
);
4042 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4043 char *code_locale
= utf82locale((char*)code
);
4044 char *message_locale
= utf82locale((char*)message
);
4045 isds_log(ILF_ISDS
, ILL_DEBUG
,
4046 _("Server refused to change password on ChangeISDSPassword "
4047 "request (code=%s, message=%s)\n"),
4048 code_locale
, message_locale
);
4049 isds_log_message(context
, message_locale
);
4051 free(message_locale
);
4056 /* Otherwise password changed successfully */
4061 xmlFreeDoc(response
);
4062 xmlFreeNode(request
);
4065 isds_log(ILF_ISDS
, ILL_DEBUG
,
4066 _("Password changed successfully on ChangeISDSPassword "
4073 /* Generic middle part with request sending and response check.
4074 * It sends prepared request and checks for error code.
4075 * @context is ISDS session context.
4076 * @service is ISDS service handler
4077 * @service_name is name in scope of given @service
4078 * @request is XML tree with request. Will be freed to save memory.
4079 * @response is XML document ouputing ISDS response.
4080 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4081 * NULL, if you don't care. */
4082 static isds_error
send_destroy_request_check_response(
4083 struct isds_ctx
*context
,
4084 const isds_service service
, const xmlChar
*service_name
,
4085 xmlNodePtr
*request
, xmlDocPtr
*response
, xmlChar
**refnumber
) {
4086 isds_error err
= IE_SUCCESS
;
4087 char *service_name_locale
= NULL
;
4088 xmlChar
*code
= NULL
, *message
= NULL
;
4091 if (!context
) return IE_INVALID_CONTEXT
;
4092 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
||
4096 /* Check if connection is established
4097 * TODO: This check should be done donwstairs. */
4098 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4100 service_name_locale
= utf82locale((char*) service_name
);
4101 if (!service_name_locale
) {
4106 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
4107 service_name_locale
);
4110 err
= isds(context
, service
, *request
, response
, NULL
, NULL
);
4111 xmlFreeNode(*request
); *request
= NULL
;
4114 isds_log(ILF_ISDS
, ILL_DEBUG
,
4115 _("Processing ISDS response on %s request failed\n"),
4116 service_name_locale
);
4120 /* Check for response status */
4121 err
= isds_response_status(context
, service
, *response
,
4122 &code
, &message
, refnumber
);
4124 isds_log(ILF_ISDS
, ILL_DEBUG
,
4125 _("ISDS response on %s request is missing status\n"),
4126 service_name_locale
);
4130 /* Request processed, but server failed */
4131 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4132 char *code_locale
= utf82locale((char*) code
);
4133 char *message_locale
= utf82locale((char*) message
);
4134 isds_log(ILF_ISDS
, ILL_DEBUG
,
4135 _("Server refused %s request (code=%s, message=%s)\n"),
4136 service_name_locale
, code_locale
, message_locale
);
4137 isds_log_message(context
, message_locale
);
4139 free(message_locale
);
4148 if (err
&& *response
) {
4149 xmlFreeDoc(*response
);
4153 xmlFreeNode(*request
);
4156 free(service_name_locale
);
4162 /* Generic bottom half with request sending.
4163 * It sends prepared request, checks for error code, destroys response and
4164 * request and log success or failure.
4165 * @context is ISDS session context.
4166 * @service is ISDS service handler
4167 * @service_name is name in scope of given @service
4168 * @request is XML tree with request. Will be freed to save memory.
4169 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4170 * NULL, if you don't care. */
4171 static isds_error
send_request_check_drop_response(
4172 struct isds_ctx
*context
,
4173 const isds_service service
, const xmlChar
*service_name
,
4174 xmlNodePtr
*request
, xmlChar
**refnumber
) {
4175 isds_error err
= IE_SUCCESS
;
4176 char *service_name_locale
= NULL
;
4177 xmlDocPtr response
= NULL
;
4180 if (!context
) return IE_INVALID_CONTEXT
;
4181 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
)
4184 /* Send request and check response*/
4185 err
= send_destroy_request_check_response(context
,
4186 service
, service_name
, request
, &response
, refnumber
);
4188 xmlFreeDoc(response
);
4191 xmlFreeNode(*request
);
4196 isds_log(ILF_ISDS
, ILL_DEBUG
,
4197 _("%s request processed by server successfully.\n"),
4198 service_name_locale
);
4200 free(service_name_locale
);
4206 /* Build XSD:tCreateDBInput request type for box createing.
4207 * @context is session context
4208 * @request outputs built XML tree
4209 * @service_name is request name of SERVICE_DB_MANIPULATION service
4210 * @box is box description to create including single primary user (in case of
4212 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4213 * box, or contact address of PFO box owner)
4214 * @former_names is optional undocumented string. Pass NULL if you don't care.
4215 * @upper_box_id is optional ID of supper box if currently created box is
4217 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4218 * NULL, if you don't care.*/
4219 static isds_error
build_CreateDBInput_request(struct isds_ctx
*context
,
4220 xmlNodePtr
*request
, const xmlChar
*service_name
,
4221 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4222 const xmlChar
*former_names
, const xmlChar
*upper_box_id
,
4223 const xmlChar
*ceo_label
) {
4224 isds_error err
= IE_SUCCESS
;
4225 xmlNsPtr isds_ns
= NULL
;
4226 xmlNodePtr node
, dbPrimaryUsers
;
4227 xmlChar
*string
= NULL
;
4228 const struct isds_list
*item
;
4231 if (!context
) return IE_INVALID_CONTEXT
;
4232 if (!request
|| !service_name
|| service_name
[0] == '\0' || !box
)
4236 /* Build DeleteDataBox request */
4237 *request
= xmlNewNode(NULL
, service_name
);
4239 char *service_name_locale
= utf82locale((char*) service_name
);
4240 isds_printf_message(context
, _("Could build %s request"),
4241 service_name_locale
);
4242 free(service_name_locale
);
4245 isds_ns
= xmlNewNs(*request
, BAD_CAST ISDS_NS
, NULL
);
4247 isds_log_message(context
, _("Could not create ISDS name space"));
4248 xmlFreeNode(*request
);
4251 xmlSetNs(*request
, isds_ns
);
4253 INSERT_ELEMENT(node
, *request
, "dbOwnerInfo");
4254 err
= insert_DbOwnerInfo(context
, box
, node
);
4255 if (err
) goto leave
;
4258 /* XXX: There is bug in XSD: XSD says at least one dbUserInfo must exist,
4259 * verbose documentatiot allows none dbUserInfo */
4260 INSERT_ELEMENT(dbPrimaryUsers
, *request
, "dbPrimaryUsers");
4261 for (item
= users
; item
; item
= item
->next
) {
4263 INSERT_ELEMENT(node
, dbPrimaryUsers
, "dbUserInfo");
4264 err
= insert_DbUserInfo(context
,
4265 (struct isds_DbUserInfo
*) item
->data
, node
);
4266 if (err
) goto leave
;
4270 INSERT_STRING(*request
, "dbFormerNames", former_names
);
4271 INSERT_STRING(*request
, "dbUpperDBId", upper_box_id
);
4272 INSERT_STRING(*request
, "dbCEOLabel", ceo_label
);
4274 /* TODO: gExtApproval */
4278 xmlFreeNode(*request
);
4287 * @context is session context
4288 * @box is box description to create including single primary user (in case of
4289 * FO box type). It outputs box ID assigned by ISDS in dbID element.
4290 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4291 * box, or contact address of PFO box owner)
4292 * @former_names is optional undocumented string. Pass NULL if you don't care.
4293 * @upper_box_id is optional ID of supper box if currently created box is
4295 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4296 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4297 * NULL, if you don't care.*/
4298 isds_error
isds_add_box(struct isds_ctx
*context
,
4299 struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4300 const char *former_names
, const char *upper_box_id
,
4301 const char *ceo_label
, char **refnumber
) {
4302 isds_error err
= IE_SUCCESS
;
4303 xmlNodePtr request
= NULL
;
4304 xmlDocPtr response
= NULL
;
4305 xmlXPathContextPtr xpath_ctx
= NULL
;
4306 xmlXPathObjectPtr result
= NULL
;
4309 if (!context
) return IE_INVALID_CONTEXT
;
4310 if (!box
) return IE_INVAL
;
4312 /* Scratch box ID */
4315 /* Build CreateDataBox request */
4316 err
= build_CreateDBInput_request(context
,
4317 &request
, BAD_CAST
"CreateDataBox",
4318 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4319 (xmlChar
*) ceo_label
);
4320 if (err
) goto leave
;
4322 /* Send it to server and process response */
4323 err
= send_destroy_request_check_response(context
,
4324 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4325 &response
, (xmlChar
**) refnumber
);
4327 /* Extract box ID */
4328 xpath_ctx
= xmlXPathNewContext(response
);
4333 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4337 EXTRACT_STRING("/isds:CreateDataBoxResponse/dbID", box
->dbID
);
4340 xmlXPathFreeObject(result
);
4341 xmlXPathFreeContext(xpath_ctx
);
4342 xmlFreeDoc(response
);
4343 xmlFreeNode(request
);
4346 isds_log(ILF_ISDS
, ILL_DEBUG
,
4347 _("CreateDataBox request processed by server successfully.\n"));
4354 /* Notify ISDS about new PFO entity.
4355 * This function has no real effect.
4356 * @context is session context
4357 * @box is PFO description including single primary user.
4358 * @users is list of struct isds_DbUserInfo (contact address of PFO box owner)
4359 * @former_names is optional undocumented string. Pass NULL if you don't care.
4360 * @upper_box_id is optional ID of supper box if currently created box is
4362 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4363 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4364 * NULL, if you don't care.*/
4365 isds_error
isds_add_pfoinfo(struct isds_ctx
*context
,
4366 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4367 const char *former_names
, const char *upper_box_id
,
4368 const char *ceo_label
, char **refnumber
) {
4369 isds_error err
= IE_SUCCESS
;
4370 xmlNodePtr request
= NULL
;
4372 if (!context
) return IE_INVALID_CONTEXT
;
4373 if (!box
) return IE_INVAL
;
4375 /* Build CreateDataBoxPFOInfo request */
4376 err
= build_CreateDBInput_request(context
,
4377 &request
, BAD_CAST
"CreateDataBoxPFOInfo",
4378 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4379 (xmlChar
*) ceo_label
);
4380 if (err
) goto leave
;
4382 /* Send it to server and process response */
4383 err
= send_request_check_drop_response(context
,
4384 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4385 (xmlChar
**) refnumber
);
4387 xmlFreeNode(request
);
4392 /* Remove given given box permanetly.
4393 * @context is session context
4394 * @box is box description to delete
4395 * @since is date of box owner cancalation. Only tm_year, tm_mon and tm_mday
4397 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4398 * NULL, if you don't care.*/
4399 isds_error
isds_delete_box(struct isds_ctx
*context
,
4400 const struct isds_DbOwnerInfo
*box
, const struct tm
*since
,
4402 isds_error err
= IE_SUCCESS
;
4403 xmlNsPtr isds_ns
= NULL
;
4404 xmlNodePtr request
= NULL
;
4406 xmlChar
*string
= NULL
;
4409 if (!context
) return IE_INVALID_CONTEXT
;
4410 if (!box
|| !since
) return IE_INVAL
;
4413 /* Build DeleteDataBox request */
4414 request
= xmlNewNode(NULL
, BAD_CAST
"DeleteDataBox");
4416 isds_log_message(context
,
4417 _("Could build DeleteDataBox request"));
4420 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4422 isds_log_message(context
, _("Could not create ISDS name space"));
4423 xmlFreeNode(request
);
4426 xmlSetNs(request
, isds_ns
);
4428 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4429 err
= insert_DbOwnerInfo(context
, box
, node
);
4430 if (err
) goto leave
;
4432 err
= tm2datestring(since
, &string
);
4434 isds_log_message(context
,
4435 _("Could not convert `since' argument to ISO date string"));
4438 INSERT_STRING(request
, "dbOwnerTerminationDate", string
);
4441 /* TODO: gExtApproval */
4444 /* Send it to server and process response */
4445 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4446 BAD_CAST
"DeleteDataBox", &request
, (xmlChar
**) refnumber
);
4449 xmlFreeNode(request
);
4455 /* Update data about given box.
4456 * @context is session context
4457 * @old_box current box description
4458 * @new_box are updated data about @old_box
4459 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4460 * NULL, if you don't care.*/
4461 isds_error
isds_UpdateDataBoxDescr(struct isds_ctx
*context
,
4462 const struct isds_DbOwnerInfo
*old_box
,
4463 const struct isds_DbOwnerInfo
*new_box
,
4465 isds_error err
= IE_SUCCESS
;
4466 xmlNsPtr isds_ns
= NULL
;
4467 xmlNodePtr request
= NULL
;
4471 if (!context
) return IE_INVALID_CONTEXT
;
4472 if (!old_box
|| !new_box
) return IE_INVAL
;
4475 /* Build UpdateDataBoxDescr request */
4476 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxDescr");
4478 isds_log_message(context
,
4479 _("Could build UpdateDataBoxDescr request"));
4482 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4484 isds_log_message(context
, _("Could not create ISDS name space"));
4485 xmlFreeNode(request
);
4488 xmlSetNs(request
, isds_ns
);
4490 INSERT_ELEMENT(node
, request
, "dbOldOwnerInfo");
4491 err
= insert_DbOwnerInfo(context
, old_box
, node
);
4492 if (err
) goto leave
;
4494 INSERT_ELEMENT(node
, request
, "dbNewOwnerInfo");
4495 err
= insert_DbOwnerInfo(context
, new_box
, node
);
4496 if (err
) goto leave
;
4498 /* TODO: gExtApproval */
4501 /* Send it to server and process response */
4502 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4503 BAD_CAST
"UpdateDataBoxDescr", &request
, (xmlChar
**) refnumber
);
4506 xmlFreeNode(request
);
4512 /* Build ISDS request of XSD tIdDbInput type, sent it and check for error
4514 * @context is session context
4515 * @service is SOAP service
4516 * @service_name is name of request in @service
4517 * @box_id is box ID of interrest
4518 * @response is server SOAP body response as XML document
4519 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4520 * NULL, if you don't care.
4521 * @return error coded from lower layer, context message will be set up
4523 static isds_error
build_send_dbid_request_check_response(
4524 struct isds_ctx
*context
, const isds_service service
,
4525 const xmlChar
*service_name
, const xmlChar
*box_id
,
4526 xmlDocPtr
*response
, xmlChar
**refnumber
) {
4528 isds_error err
= IE_SUCCESS
;
4529 char *service_name_locale
= NULL
, *box_id_locale
= NULL
;
4530 xmlNodePtr request
= NULL
, node
;
4531 xmlNsPtr isds_ns
= NULL
;
4533 if (!context
) return IE_INVALID_CONTEXT
;
4534 if (!service_name
|| !box_id
) return IE_INVAL
;
4535 if (!response
) return IE_INVAL
;
4537 /* Free output argument */
4538 xmlFreeDoc(*response
); *response
= NULL
;
4540 /* Prepare strings */
4541 service_name_locale
= utf82locale((char*)service_name
);
4542 if (!service_name_locale
) {
4546 box_id_locale
= utf82locale((char*)box_id
);
4547 if (!box_id_locale
) {
4553 request
= xmlNewNode(NULL
, service_name
);
4555 isds_printf_message(context
,
4556 _("Could not build %s request"), service_name_locale
);
4560 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4562 isds_log_message(context
, _("Could not create ISDS name space"));
4566 xmlSetNs(request
, isds_ns
);
4568 /* Add XSD:tIdDbInput childs*/
4569 INSERT_STRING(request
, "dbID", box_id
);
4570 /* TODO: XSD:gExtApproval*/
4572 /* Send request and check response*/
4573 err
= send_destroy_request_check_response(context
,
4574 service
, service_name
, &request
, response
, refnumber
);
4577 free(service_name_locale
);
4578 free(box_id_locale
);
4579 xmlFreeNode(request
);
4584 /* Get data about all users assigned to given box.
4585 * @context is session context
4587 * @users is automatically reallocated list of struct isds_DbUserInfo */
4588 isds_error
isds_GetDataBoxUsers(struct isds_ctx
*context
, const char *box_id
,
4589 struct isds_list
**users
) {
4590 isds_error err
= IE_SUCCESS
;
4591 xmlDocPtr response
= NULL
;
4592 xmlXPathContextPtr xpath_ctx
= NULL
;
4593 xmlXPathObjectPtr result
= NULL
;
4595 struct isds_list
*item
, *prev_item
= NULL
;
4597 if (!context
) return IE_INVALID_CONTEXT
;
4598 if (!users
|| !box_id
) return IE_INVAL
;
4601 /* Do request and check for success */
4602 err
= build_send_dbid_request_check_response(context
,
4603 SERVICE_DB_MANIPULATION
, BAD_CAST
"GetDataBoxUsers",
4604 BAD_CAST box_id
, &response
, NULL
);
4605 if (err
) goto leave
;
4609 /* Prepare stucture */
4610 isds_list_free(users
);
4611 xpath_ctx
= xmlXPathNewContext(response
);
4616 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4621 /* Set context node */
4622 result
= xmlXPathEvalExpression(BAD_CAST
4623 "/isds:GetDataBoxUsersResponse/isds:dbUsers/isds:dbUserInfo",
4629 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4630 isds_log_message(context
, _("Missing dbUserInfo element"));
4635 /* Iterate over all users */
4636 for (i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
4638 /* Prepare structure */
4639 item
= calloc(1, sizeof(*item
));
4644 item
->destructor
= (void(*)(void**))isds_DbUserInfo_free
;
4645 if (i
== 0) *users
= item
;
4646 else prev_item
->next
= item
;
4650 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
4651 err
= extract_DbUserInfo(context
,
4652 (struct isds_DbUserInfo
**) (&item
->data
), xpath_ctx
);
4653 if (err
) goto leave
;
4658 isds_list_free(users
);
4661 xmlXPathFreeObject(result
);
4662 xmlXPathFreeContext(xpath_ctx
);
4663 xmlFreeDoc(response
);
4666 isds_log(ILF_ISDS
, ILL_DEBUG
,
4667 _("GetDataBoxUsers request processed by server "
4668 "successfully.\n"));
4674 /* Update data about user assigned to given box.
4675 * @context is session context
4676 * @box is box identification
4677 * @old_user identifies user to update
4678 * @new_user are updated data about @old_user
4679 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4680 * NULL, if you don't care.*/
4681 isds_error
isds_UpdateDataBoxUser(struct isds_ctx
*context
,
4682 const struct isds_DbOwnerInfo
*box
,
4683 const struct isds_DbUserInfo
*old_user
,
4684 const struct isds_DbUserInfo
*new_user
,
4686 isds_error err
= IE_SUCCESS
;
4687 xmlNsPtr isds_ns
= NULL
;
4688 xmlNodePtr request
= NULL
;
4692 if (!context
) return IE_INVALID_CONTEXT
;
4693 if (!box
|| !old_user
|| !new_user
) return IE_INVAL
;
4696 /* Build UpdateDataBoxUser request */
4697 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxUser");
4699 isds_log_message(context
,
4700 _("Could build UpdateDataBoxUser request"));
4703 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4705 isds_log_message(context
, _("Could not create ISDS name space"));
4706 xmlFreeNode(request
);
4709 xmlSetNs(request
, isds_ns
);
4711 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4712 err
= insert_DbOwnerInfo(context
, box
, node
);
4713 if (err
) goto leave
;
4715 INSERT_ELEMENT(node
, request
, "dbOldUserInfo");
4716 err
= insert_DbUserInfo(context
, old_user
, node
);
4717 if (err
) goto leave
;
4719 INSERT_ELEMENT(node
, request
, "dbNewUserInfo");
4720 err
= insert_DbUserInfo(context
, new_user
, node
);
4721 if (err
) goto leave
;
4723 /* Send it to server and process response */
4724 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4725 BAD_CAST
"UpdateDataBoxUser", &request
, (xmlChar
**) refnumber
);
4728 xmlFreeNode(request
);
4734 /* Reset credentials of user assigned to given box.
4735 * @context is session context
4736 * @box is box identification
4737 * @user identifies user to reset password
4738 * @fee_paid is true if fee has been paid, false otherwise
4739 * @token is NULL if new password should be delivered off-line to the user.
4740 * It is valid pointer if user should obtain new password on-line on dedicated
4741 * web server. Then it output automatically reallocated token user needs to
4742 * use to athtorize on the web server to view his new password.
4743 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4744 * NULL, if you don't care.*/
4745 isds_error
isds_reset_password(struct isds_ctx
*context
,
4746 const struct isds_DbOwnerInfo
*box
,
4747 const struct isds_DbUserInfo
*user
,
4748 const _Bool fee_paid
,
4749 char **token
, char **refnumber
) {
4750 isds_error err
= IE_SUCCESS
;
4751 xmlNsPtr isds_ns
= NULL
;
4752 xmlNodePtr request
= NULL
, node
;
4753 xmlDocPtr response
= NULL
;
4754 xmlXPathContextPtr xpath_ctx
= NULL
;
4755 xmlXPathObjectPtr result
= NULL
;
4758 if (!context
) return IE_INVALID_CONTEXT
;
4759 if (!box
|| !user
) return IE_INVAL
;
4761 if (token
) zfree(*token
);
4764 /* Build NewAccessData request */
4765 request
= xmlNewNode(NULL
, BAD_CAST
"NewAccessData");
4767 isds_log_message(context
,
4768 _("Could build NewAccessData request"));
4771 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4773 isds_log_message(context
, _("Could not create ISDS name space"));
4774 xmlFreeNode(request
);
4777 xmlSetNs(request
, isds_ns
);
4779 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4780 err
= insert_DbOwnerInfo(context
, box
, node
);
4781 if (err
) goto leave
;
4783 INSERT_ELEMENT(node
, request
, "dbUserInfo");
4784 err
= insert_DbUserInfo(context
, user
, node
);
4785 if (err
) goto leave
;
4787 INSERT_SCALAR_BOOLEAN(request
, "dbFeePaid", fee_paid
);
4790 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 1);
4792 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 0);
4795 /* TODO: gExtApproval */
4797 /* Send request and check reposne*/
4798 err
= send_destroy_request_check_response(context
,
4799 SERVICE_DB_MANIPULATION
, BAD_CAST
"NewAccessData", &request
,
4800 &response
, (xmlChar
**) refnumber
);
4801 if (err
) goto leave
;
4804 /* Extract optional token */
4806 xpath_ctx
= xmlXPathNewContext(response
);
4811 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4816 EXTRACT_STRING("/isds:NewAccessDataResponse/dbAccessDataId", *token
);
4820 xmlXPathFreeObject(result
);
4821 xmlXPathFreeContext(xpath_ctx
);
4822 xmlFreeDoc(response
);
4823 xmlFreeNode(request
);
4826 isds_log(ILF_ISDS
, ILL_DEBUG
,
4827 _("NewAccessData request processed by server "
4828 "successfully.\n"));
4834 /* Build ISDS request of XSD tAddDBUserInput type, sent it, check for error
4835 * code, destroy response and log success.
4836 * @context is ISDS session context.
4837 * @service_name is name of SERVICE_DB_MANIPULATION service
4838 * @box is box identification
4839 * @user identifies user to removve
4840 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4841 * NULL, if you don't care. */
4842 static isds_error
build_send_manipulationboxuser_request_check_drop_response(
4843 struct isds_ctx
*context
, const xmlChar
*service_name
,
4844 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4845 xmlChar
**refnumber
) {
4846 isds_error err
= IE_SUCCESS
;
4847 xmlNsPtr isds_ns
= NULL
;
4848 xmlNodePtr request
= NULL
, node
;
4851 if (!context
) return IE_INVALID_CONTEXT
;
4852 if (!service_name
|| service_name
[0] == '\0' || !box
|| !user
)
4856 /* Build NewAccessData request */
4857 request
= xmlNewNode(NULL
, service_name
);
4859 char *service_name_locale
= utf82locale((char *) service_name
);
4860 isds_printf_message(context
, _("Could build %s request"),
4861 service_name_locale
);
4862 free(service_name_locale
);
4865 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4867 isds_log_message(context
, _("Could not create ISDS name space"));
4868 xmlFreeNode(request
);
4871 xmlSetNs(request
, isds_ns
);
4873 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4874 err
= insert_DbOwnerInfo(context
, box
, node
);
4875 if (err
) goto leave
;
4877 INSERT_ELEMENT(node
, request
, "dbUserInfo");
4878 err
= insert_DbUserInfo(context
, user
, node
);
4879 if (err
) goto leave
;
4881 /* TODO: gExtApproval */
4883 /* Send request and check reposne*/
4884 err
= send_request_check_drop_response (context
,
4885 SERVICE_DB_MANIPULATION
, service_name
, &request
, refnumber
);
4888 xmlFreeNode(request
);
4893 /* Assign new user to given box.
4894 * @context is session context
4895 * @box is box identification
4896 * @user defines new user to add
4897 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4898 * NULL, if you don't care.*/
4899 isds_error
isds_add_user(struct isds_ctx
*context
,
4900 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4902 return build_send_manipulationboxuser_request_check_drop_response(context
,
4903 BAD_CAST
"AddDataBoxUser", box
, user
, (xmlChar
**) refnumber
);
4907 /* Remove user assigned to given box.
4908 * @context is session context
4909 * @box is box identification
4910 * @user identifies user to removve
4911 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4912 * NULL, if you don't care.*/
4913 isds_error
isds_delete_user(struct isds_ctx
*context
,
4914 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4916 return build_send_manipulationboxuser_request_check_drop_response(context
,
4917 BAD_CAST
"DeleteDataBoxUser", box
, user
, (xmlChar
**) refnumber
);
4921 /* Find boxes suiting given criteria.
4922 * @criteria is filter. You should fill in at least some memebers.
4923 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
4924 * possibly empty. Input NULL or valid old structure.
4926 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
4927 * IE_NOEXIST if no such box exists, @boxes will be NULL
4928 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
4929 * contains still valid data
4930 * other code if something bad happens. @boxes will be NULL. */
4931 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
4932 const struct isds_DbOwnerInfo
*criteria
,
4933 struct isds_list
**boxes
) {
4934 isds_error err
= IE_SUCCESS
;
4935 _Bool truncated
= 0;
4936 xmlNsPtr isds_ns
= NULL
;
4937 xmlNodePtr request
= NULL
;
4938 xmlDocPtr response
= NULL
;
4939 xmlChar
*code
= NULL
, *message
= NULL
;
4940 xmlNodePtr db_owner_info
;
4941 xmlXPathContextPtr xpath_ctx
= NULL
;
4942 xmlXPathObjectPtr result
= NULL
;
4943 xmlChar
*string
= NULL
;
4946 if (!context
) return IE_INVALID_CONTEXT
;
4947 if (!boxes
) return IE_INVAL
;
4948 isds_list_free(boxes
);
4954 /* Check if connection is established
4955 * TODO: This check should be done donwstairs. */
4956 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4959 /* Build FindDataBox request */
4960 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
4962 isds_log_message(context
,
4963 _("Could build FindDataBox request"));
4966 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4968 isds_log_message(context
, _("Could not create ISDS name space"));
4969 xmlFreeNode(request
);
4972 xmlSetNs(request
, isds_ns
);
4973 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
4974 if (!db_owner_info
) {
4975 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
4976 "FindDataBox element"));
4977 xmlFreeNode(request
);
4981 err
= insert_DbOwnerInfo(context
, criteria
, db_owner_info
);
4982 if (err
) goto leave
;
4985 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
4988 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
4990 /* Destroy request */
4991 xmlFreeNode(request
); request
= NULL
;
4994 isds_log(ILF_ISDS
, ILL_DEBUG
,
4995 _("Processing ISDS response on FindDataBox "
4996 "request failed\n"));
5000 /* Check for response status */
5001 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5002 &code
, &message
, NULL
);
5004 isds_log(ILF_ISDS
, ILL_DEBUG
,
5005 _("ISDS response on FindDataBox request is missing status\n"));
5009 /* Request processed, but nothing found */
5010 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
5011 !xmlStrcmp(code
, BAD_CAST
"5001")) {
5012 char *code_locale
= utf82locale((char*)code
);
5013 char *message_locale
= utf82locale((char*)message
);
5014 isds_log(ILF_ISDS
, ILL_DEBUG
,
5015 _("Server did not found any box on FindDataBox request "
5016 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5017 isds_log_message(context
, message_locale
);
5019 free(message_locale
);
5024 /* Warning, not a error */
5025 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
5026 char *code_locale
= utf82locale((char*)code
);
5027 char *message_locale
= utf82locale((char*)message
);
5028 isds_log(ILF_ISDS
, ILL_DEBUG
,
5029 _("Server truncated response on FindDataBox request "
5030 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5031 isds_log_message(context
, message_locale
);
5033 free(message_locale
);
5038 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5039 char *code_locale
= utf82locale((char*)code
);
5040 char *message_locale
= utf82locale((char*)message
);
5041 isds_log(ILF_ISDS
, ILL_DEBUG
,
5042 _("Server refused FindDataBox request "
5043 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5044 isds_log_message(context
, message_locale
);
5046 free(message_locale
);
5051 xpath_ctx
= xmlXPathNewContext(response
);
5056 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5061 /* Extract boxes if they present */
5062 result
= xmlXPathEvalExpression(BAD_CAST
5063 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
5069 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5070 struct isds_list
*item
, *prev_item
= NULL
;
5071 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
5072 item
= calloc(1, sizeof(*item
));
5078 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
5079 if (i
== 0) *boxes
= item
;
5080 else prev_item
->next
= item
;
5083 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
5084 err
= extract_DbOwnerInfo(context
,
5085 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
5086 if (err
) goto leave
;
5092 isds_list_free(boxes
);
5094 if (truncated
) err
= IE_2BIG
;
5098 xmlFreeNode(request
);
5099 xmlXPathFreeObject(result
);
5100 xmlXPathFreeContext(xpath_ctx
);
5104 xmlFreeDoc(response
);
5107 isds_log(ILF_ISDS
, ILL_DEBUG
,
5108 _("FindDataBox request processed by server successfully.\n"));
5114 /* Get status of a box.
5115 * @context is ISDS session context.
5116 * @box_id is UTF-8 encoded box identifier as zero terminated string
5117 * @box_status is return value of box status.
5119 * IE_SUCCESS if box has been found and its status retrieved
5120 * IE_NOEXIST if box is not known to ISDS server
5121 * or other appropriate error.
5122 * You can use isds_DbState to enumerate box status. However out of enum
5123 * range value can be returned too. This is feature because ISDS
5124 * specification leaves the set of values open.
5125 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
5126 * the box has been deleted, but ISDS still lists its former existence. */
5127 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
5128 long int *box_status
) {
5129 isds_error err
= IE_SUCCESS
;
5130 xmlNsPtr isds_ns
= NULL
;
5131 xmlNodePtr request
= NULL
, db_id
;
5132 xmlDocPtr response
= NULL
;
5133 xmlChar
*code
= NULL
, *message
= NULL
;
5134 xmlXPathContextPtr xpath_ctx
= NULL
;
5135 xmlXPathObjectPtr result
= NULL
;
5136 xmlChar
*string
= NULL
;
5138 if (!context
) return IE_INVALID_CONTEXT
;
5139 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
5141 /* Check if connection is established
5142 * TODO: This check should be done donwstairs. */
5143 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5146 /* Build CheckDataBox request */
5147 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
5149 isds_log_message(context
,
5150 _("Could build CheckDataBox request"));
5153 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5155 isds_log_message(context
, _("Could not create ISDS name space"));
5156 xmlFreeNode(request
);
5159 xmlSetNs(request
, isds_ns
);
5160 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
5162 isds_log_message(context
, _("Could not add dbId Child to "
5163 "CheckDataBox element"));
5164 xmlFreeNode(request
);
5169 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
5172 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
5174 /* Destroy request */
5175 xmlFreeNode(request
);
5178 isds_log(ILF_ISDS
, ILL_DEBUG
,
5179 _("Processing ISDS response on CheckDataBox "
5180 "request failed\n"));
5184 /* Check for response status */
5185 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5186 &code
, &message
, NULL
);
5188 isds_log(ILF_ISDS
, ILL_DEBUG
,
5189 _("ISDS response on CheckDataBox request is missing status\n"));
5193 /* Request processed, but nothing found */
5194 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
5195 char *box_id_locale
= utf82locale((char*)box_id
);
5196 char *code_locale
= utf82locale((char*)code
);
5197 char *message_locale
= utf82locale((char*)message
);
5198 isds_log(ILF_ISDS
, ILL_DEBUG
,
5199 _("Server did not found box %s on CheckDataBox request "
5200 "(code=%s, message=%s)\n"),
5201 box_id_locale
, code_locale
, message_locale
);
5202 isds_log_message(context
, message_locale
);
5203 free(box_id_locale
);
5205 free(message_locale
);
5211 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5212 char *code_locale
= utf82locale((char*)code
);
5213 char *message_locale
= utf82locale((char*)message
);
5214 isds_log(ILF_ISDS
, ILL_DEBUG
,
5215 _("Server refused CheckDataBox request "
5216 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5217 isds_log_message(context
, message_locale
);
5219 free(message_locale
);
5225 xpath_ctx
= xmlXPathNewContext(response
);
5230 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5234 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
5240 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5241 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
5245 if (result
->nodesetval
->nodeNr
> 1) {
5246 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
5250 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5251 xmlXPathFreeObject(result
); result
= NULL
;
5253 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
5258 xmlXPathFreeObject(result
);
5259 xmlXPathFreeContext(xpath_ctx
);
5263 xmlFreeDoc(response
);
5266 isds_log(ILF_ISDS
, ILL_DEBUG
,
5267 _("CheckDataBox request processed by server successfully.\n"));
5273 /* Build ISDS request of XSD tIdDbInput type, sent it, check for error
5274 * code, destroy response and log success.
5275 * @context is ISDS session context.
5276 * @service_name is name of SERVICE_DB_MANIPULATION service
5277 * @box_id is UTF-8 encoded box identifier as zero terminated string
5278 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5279 * NULL, if you don't care. */
5280 static isds_error
build_send_manipulationdbid_request_check_drop_response(
5281 struct isds_ctx
*context
, const xmlChar
*service_name
,
5282 const xmlChar
*box_id
, xmlChar
**refnumber
) {
5283 isds_error err
= IE_SUCCESS
;
5284 xmlDocPtr response
= NULL
;
5286 if (!context
) return IE_INVALID_CONTEXT
;
5287 if (!service_name
|| *service_name
== '\0' || !box_id
) return IE_INVAL
;
5289 /* Check if connection is established */
5290 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5292 /* Do request and check for success */
5293 err
= build_send_dbid_request_check_response(context
,
5294 SERVICE_DB_MANIPULATION
, service_name
, box_id
,
5295 &response
, refnumber
);
5296 xmlFreeDoc(response
);
5299 char *service_name_locale
= utf82locale((char *) service_name
);
5300 isds_log(ILF_ISDS
, ILL_DEBUG
,
5301 _("%s request processed by server successfully.\n"),
5302 service_name_locale
);
5303 free(service_name_locale
);
5310 /* Switch box into state where box can receive commercial messages (off by
5312 * @context is ISDS session context.
5313 * @box_id is UTF-8 encoded box identifier as zero terminated string
5314 * @allow is true for enable, false for disable commercial messages income
5315 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5316 * NULL, if you don't care. */
5317 isds_error
isds_switch_commercial_receiving(struct isds_ctx
*context
,
5318 const char *box_id
, const _Bool allow
, char **refnumber
) {
5319 return build_send_manipulationdbid_request_check_drop_response(context
,
5320 (allow
) ? BAD_CAST
"SetOpenAddressing" :
5321 BAD_CAST
"ClearOpenAddressing",
5322 BAD_CAST box_id
, (xmlChar
**) refnumber
);
5326 /* Switch box into / out of state where non-OVM box can act as OVM (e.g. force
5327 * message acceptance). This is just a box permission. Sender must apply
5328 * such role by sending each message.
5329 * @context is ISDS session context.
5330 * @box_id is UTF-8 encoded box identifier as zero terminated string
5331 * @allow is true for enable, false for disable OVM role permission
5332 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5333 * NULL, if you don't care. */
5334 isds_error
isds_switch_effective_ovm(struct isds_ctx
*context
,
5335 const char *box_id
, const _Bool allow
, char **refnumber
) {
5336 return build_send_manipulationdbid_request_check_drop_response(context
,
5337 (allow
) ? BAD_CAST
"SetEffectiveOVM" :
5338 BAD_CAST
"ClearEffectiveOVM",
5339 BAD_CAST box_id
, (xmlChar
**) refnumber
);
5343 /* Build ISDS request of XSD tOwnerInfoInput type, sent it, check for error
5344 * code, destroy response and log success.
5345 * @context is ISDS session context.
5346 * @service_name is name of SERVICE_DB_MANIPULATION service
5347 * @owner is structure describing box
5348 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5349 * NULL, if you don't care. */
5350 static isds_error
build_send_manipulationdbowner_request_check_drop_response(
5351 struct isds_ctx
*context
, const xmlChar
*service_name
,
5352 const struct isds_DbOwnerInfo
*owner
, xmlChar
**refnumber
) {
5353 isds_error err
= IE_SUCCESS
;
5354 char *service_name_locale
= NULL
;
5355 xmlNodePtr request
= NULL
, db_owner_info
;
5356 xmlNsPtr isds_ns
= NULL
;
5359 if (!context
) return IE_INVALID_CONTEXT
;
5360 if (!service_name
|| *service_name
== '\0' || !owner
) return IE_INVAL
;
5362 service_name_locale
= utf82locale((char*)service_name
);
5363 if (!service_name_locale
) {
5369 request
= xmlNewNode(NULL
, service_name
);
5371 isds_printf_message(context
,
5372 _("Could not build %s request"), service_name_locale
);
5376 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5378 isds_log_message(context
, _("Could not create ISDS name space"));
5382 xmlSetNs(request
, isds_ns
);
5385 /* Add XSD:tOwnerInfoInput child*/
5386 INSERT_ELEMENT(db_owner_info
, request
, "dbOwnerInfo");
5387 err
= insert_DbOwnerInfo(context
, owner
, db_owner_info
);
5388 if (err
) goto leave
;
5389 /* TODO: XSD:gExtApproval*/
5391 /* Send it to server and process response */
5392 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5393 service_name
, &request
, refnumber
);
5396 xmlFreeNode(request
);
5397 free(service_name_locale
);
5403 /* Switch box accessibility state on request of box owner.
5404 * Despite the name, owner must do the requst off-line. This function is
5405 * designed for such off-line meeting points (e.g. Czech POINT).
5406 * @context is ISDS session context.
5407 * @box identifies box to swith accesibilty state.
5408 * @allow is true for making accesibale, false to disallow access.
5409 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5410 * NULL, if you don't care. */
5411 isds_error
isds_switch_box_accessibility_on_owner_request(
5412 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5413 const _Bool allow
, char **refnumber
) {
5414 return build_send_manipulationdbowner_request_check_drop_response(context
,
5415 (allow
) ? BAD_CAST
"EnableOwnDataBox" :
5416 BAD_CAST
"DisableOwnDataBox",
5417 box
, (xmlChar
**) refnumber
);
5421 /* Disable box accessibility on law enforcement (e.g. by prison) since exact
5423 * @context is ISDS session context.
5424 * @box identifies box to swith accesibilty state.
5425 * @since is date since accesseibility has been denied. This can be past too.
5426 * Only tm_year, tm_mon and tm_mday carry sane value.
5427 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5428 * NULL, if you don't care. */
5429 isds_error
isds_disable_box_accessibility_externaly(
5430 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5431 const struct tm
*since
, char **refnumber
) {
5432 isds_error err
= IE_SUCCESS
;
5433 char *service_name_locale
= NULL
;
5434 xmlNodePtr request
= NULL
, node
;
5435 xmlNsPtr isds_ns
= NULL
;
5436 xmlChar
*string
= NULL
;
5439 if (!context
) return IE_INVALID_CONTEXT
;
5440 if (!box
|| !since
) return IE_INVAL
;
5443 request
= xmlNewNode(NULL
, BAD_CAST
"DisableDataBoxExternally");
5445 isds_printf_message(context
,
5446 _("Could not build %s request"), "DisableDataBoxExternally");
5450 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5452 isds_log_message(context
, _("Could not create ISDS name space"));
5456 xmlSetNs(request
, isds_ns
);
5459 /* Add @box identification */
5460 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5461 err
= insert_DbOwnerInfo(context
, box
, node
);
5462 if (err
) goto leave
;
5464 /* Add @since date */
5465 err
= tm2datestring(since
, &string
);
5467 isds_log_message(context
,
5468 _("Could not convert `since' argument to ISO date string"));
5471 INSERT_STRING(request
, "dbOwnerDisableDate", string
);
5474 /* TODO: XSD:gExtApproval*/
5476 /* Send it to server and process response */
5477 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5478 BAD_CAST
"DisableDataBoxExternally", &request
,
5479 (xmlChar
**) refnumber
);
5483 xmlFreeNode(request
);
5484 free(service_name_locale
);
5490 /* Insert struct isds_message data (envelope (recipient data optional) and
5491 * documents) into XML tree
5492 * @context is sesstion context
5493 * @outgoing_message is libsids structure with message data
5494 * @create_message is XML CreateMessage or CreateMultipleMessage element
5495 * @process_recipient true for recipient data serialization, false for no
5497 static isds_error
insert_envelope_files(struct isds_ctx
*context
,
5498 const struct isds_message
*outgoing_message
, xmlNodePtr create_message
,
5499 const _Bool process_recipient
) {
5501 isds_error err
= IE_SUCCESS
;
5502 xmlNodePtr envelope
, dm_files
, node
;
5503 xmlChar
*string
= NULL
;
5505 if (!context
) return IE_INVALID_CONTEXT
;
5506 if (!outgoing_message
|| !create_message
) return IE_INVAL
;
5509 /* Build envelope */
5510 envelope
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
5512 isds_printf_message(context
, _("Could not add dmEnvelope child to "
5513 "%s element"), create_message
->name
);
5517 if (!outgoing_message
->envelope
) {
5518 isds_log_message(context
, _("Outgoing message is missing envelope"));
5523 INSERT_STRING(envelope
, "dmSenderOrgUnit",
5524 outgoing_message
->envelope
->dmSenderOrgUnit
);
5525 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
5526 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
5528 if (process_recipient
) {
5529 if (!outgoing_message
->envelope
->dbIDRecipient
) {
5530 isds_log_message(context
,
5531 _("Outgoing message is missing recipient box identifier"));
5535 INSERT_STRING(envelope
, "dbIDRecipient",
5536 outgoing_message
->envelope
->dbIDRecipient
);
5538 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
5539 outgoing_message
->envelope
->dmRecipientOrgUnit
);
5540 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
5541 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
5542 INSERT_STRING(envelope
, "dmToHands",
5543 outgoing_message
->envelope
->dmToHands
);
5546 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 0, 255,
5548 INSERT_STRING(envelope
, "dmAnnotation",
5549 outgoing_message
->envelope
->dmAnnotation
);
5551 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
5552 0, 50, "dmRecipientRefNumber");
5553 INSERT_STRING(envelope
, "dmRecipientRefNumber",
5554 outgoing_message
->envelope
->dmRecipientRefNumber
);
5556 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
5557 0, 50, "dmSenderRefNumber");
5558 INSERT_STRING(envelope
, "dmSenderRefNumber",
5559 outgoing_message
->envelope
->dmSenderRefNumber
);
5561 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
5562 0, 50, "dmRecipientIdent");
5563 INSERT_STRING(envelope
, "dmRecipientIdent",
5564 outgoing_message
->envelope
->dmRecipientIdent
);
5566 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
5567 0, 50, "dmSenderIdent");
5568 INSERT_STRING(envelope
, "dmSenderIdent",
5569 outgoing_message
->envelope
->dmSenderIdent
);
5571 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
5572 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
5573 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
5574 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
5575 INSERT_STRING(envelope
, "dmLegalTitleSect",
5576 outgoing_message
->envelope
->dmLegalTitleSect
);
5577 INSERT_STRING(envelope
, "dmLegalTitlePar",
5578 outgoing_message
->envelope
->dmLegalTitlePar
);
5579 INSERT_STRING(envelope
, "dmLegalTitlePoint",
5580 outgoing_message
->envelope
->dmLegalTitlePoint
);
5582 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
5583 outgoing_message
->envelope
->dmPersonalDelivery
);
5584 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
5585 outgoing_message
->envelope
->dmAllowSubstDelivery
);
5587 /* ???: Should we require value for dbEffectiveOVM sender?
5588 * ISDS has default as true */
5589 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
5592 /* Append dmFiles */
5593 if (!outgoing_message
->documents
) {
5594 isds_log_message(context
,
5595 _("Outgoing message is missing list of documents"));
5599 dm_files
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmFiles", NULL
);
5601 isds_printf_message(context
, _("Could not add dmFiles child to "
5602 "%s element"), create_message
->name
);
5607 /* Check for document hieararchy */
5608 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
5609 if (err
) goto leave
;
5611 /* Process each document */
5612 for (struct isds_list
*item
=
5613 (struct isds_list
*) outgoing_message
->documents
;
5614 item
; item
= item
->next
) {
5616 isds_log_message(context
,
5617 _("List of documents contains empty item"));
5621 /* FIXME: Check for dmFileMetaType and for document references.
5622 * Only first document can be of MAIN type */
5623 err
= insert_document(context
, (struct isds_document
*) item
->data
,
5626 if (err
) goto leave
;
5635 /* Send a message via ISDS to a recipent
5636 * @context is session context
5637 * @outgoing_message is message to send; Some memebers are mandatory (like
5638 * dbIDRecipient), some are optional and some are irrelevant (especialy data
5639 * about sender). Included pointer to isds_list documents must contain at
5640 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
5641 * members will be filled with valid data from ISDS. Exact list of write
5642 * members is subject to change. Currently dmId is changed.
5643 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
5644 isds_error
isds_send_message(struct isds_ctx
*context
,
5645 struct isds_message
*outgoing_message
) {
5647 isds_error err
= IE_SUCCESS
;
5648 xmlNsPtr isds_ns
= NULL
;
5649 xmlNodePtr request
= NULL
;
5650 xmlDocPtr response
= NULL
;
5651 xmlChar
*code
= NULL
, *message
= NULL
;
5652 xmlXPathContextPtr xpath_ctx
= NULL
;
5653 xmlXPathObjectPtr result
= NULL
;
5654 _Bool message_is_complete
= 0;
5656 if (!context
) return IE_INVALID_CONTEXT
;
5657 if (!outgoing_message
) return IE_INVAL
;
5659 /* Check if connection is established
5660 * TODO: This check should be done donwstairs. */
5661 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5664 /* Build CreateMessage request */
5665 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
5667 isds_log_message(context
,
5668 _("Could build CreateMessage request"));
5671 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5673 isds_log_message(context
, _("Could not create ISDS name space"));
5674 xmlFreeNode(request
);
5677 xmlSetNs(request
, isds_ns
);
5679 /* Append envelope and files */
5680 err
= insert_envelope_files(context
, outgoing_message
, request
, 1);
5681 if (err
) goto leave
;
5684 /* Signal we can serilize message since now */
5685 message_is_complete
= 1;
5688 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
5691 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
5693 /* Dont' destroy request, we want to provide it to application later */
5696 isds_log(ILF_ISDS
, ILL_DEBUG
,
5697 _("Processing ISDS response on CreateMessage "
5698 "request failed\n"));
5702 /* Check for response status */
5703 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
5704 &code
, &message
, NULL
);
5706 isds_log(ILF_ISDS
, ILL_DEBUG
,
5707 _("ISDS response on CreateMessage request "
5708 "is missing status\n"));
5712 /* Request processed, but refused by server or server failed */
5713 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5714 char *box_id_locale
=
5715 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
5716 char *code_locale
= utf82locale((char*)code
);
5717 char *message_locale
= utf82locale((char*)message
);
5718 isds_log(ILF_ISDS
, ILL_DEBUG
,
5719 _("Server did not accept message for %s on CreateMessage "
5720 "request (code=%s, message=%s)\n"),
5721 box_id_locale
, code_locale
, message_locale
);
5722 isds_log_message(context
, message_locale
);
5723 free(box_id_locale
);
5725 free(message_locale
);
5732 xpath_ctx
= xmlXPathNewContext(response
);
5737 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5741 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
5747 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5748 isds_log_message(context
, _("Missing CreateMessageResponse element"));
5752 if (result
->nodesetval
->nodeNr
> 1) {
5753 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
5757 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5758 xmlXPathFreeObject(result
); result
= NULL
;
5760 if (outgoing_message
->envelope
->dmID
) {
5761 free(outgoing_message
->envelope
->dmID
);
5762 outgoing_message
->envelope
->dmID
= NULL
;
5764 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
5765 if (!outgoing_message
->envelope
->dmID
) {
5766 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
5767 "but did not returen assigned message ID\n"));
5771 /* TODO: Serialize message into structure member raw */
5772 /* XXX: Each web service transport message in different format.
5773 * Therefore it's not possible to save them directly.
5774 * To save them, one must figure out common format.
5775 * We can leave it on application, or we can implement the ESS format. */
5776 /*if (message_is_complete) {
5777 if (outgoing_message->envelope->dmID) {
5779 /* Add assigned message ID as first child*/
5780 /*xmlNodePtr dmid_text = xmlNewText(
5781 (xmlChar *) outgoing_message->envelope->dmID);
5782 if (!dmid_text) goto serialization_failed;
5784 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
5786 if (!dmid_element) {
5787 xmlFreeNode(dmid_text);
5788 goto serialization_failed;
5791 xmlNodePtr dmid_element_with_text =
5792 xmlAddChild(dmid_element, dmid_text);
5793 if (!dmid_element_with_text) {
5794 xmlFreeNode(dmid_element);
5795 xmlFreeNode(dmid_text);
5796 goto serialization_failed;
5799 node = xmlAddPrevSibling(envelope->childern,
5800 dmid_element_with_text);
5802 xmlFreeNodeList(dmid_element_with_text);
5803 goto serialization_failed;
5807 /* Serialize message with ID into raw */
5808 /*buffer = serialize_element(envelope)*/
5811 serialization_failed:
5816 xmlXPathFreeObject(result
);
5817 xmlXPathFreeContext(xpath_ctx
);
5821 xmlFreeDoc(response
);
5822 xmlFreeNode(request
);
5825 isds_log(ILF_ISDS
, ILL_DEBUG
,
5826 _("CreateMessage request processed by server "
5827 "successfully.\n"));
5833 /* Send a message via ISDS to a multiple recipents
5834 * @context is session context
5835 * @outgoing_message is message to send; Some memebers are mandatory,
5836 * some are optional and some are irrelevant (especialy data
5837 * about sender). Data about recipient will be substituted by ISDS from
5838 * @copies. Included pointer to isds_list documents must
5839 * contain at least one document of FILEMETATYPE_MAIN.
5840 * @copies is list of isds_message_copy structures addressing all desired
5841 * recipients. This is read-write structure, some members will be filled with
5842 * valid data from ISDS (message IDs, error codes, error descriptions).
5844 * ISDS_SUCCESS if all messages have been sent
5845 * ISDS_PARTIAL_SUCCESS if sending of some messages has failed (failed and
5846 * succesed messages can be identified by copies->data->error),
5847 * or other error code if something other goes wrong. */
5848 isds_error
isds_send_message_to_multiple_recipients(struct isds_ctx
*context
,
5849 const struct isds_message
*outgoing_message
,
5850 struct isds_list
*copies
) {
5852 isds_error err
= IE_SUCCESS
, append_err
;
5853 xmlNsPtr isds_ns
= NULL
;
5854 xmlNodePtr request
= NULL
, recipients
, recipient
, node
;
5855 struct isds_list
*item
;
5856 struct isds_message_copy
*copy
;
5857 xmlDocPtr response
= NULL
;
5858 xmlChar
*code
= NULL
, *message
= NULL
;
5859 xmlXPathContextPtr xpath_ctx
= NULL
;
5860 xmlXPathObjectPtr result
= NULL
;
5861 xmlChar
*string
= NULL
;
5864 if (!context
) return IE_INVALID_CONTEXT
;
5865 if (!outgoing_message
|| !copies
) return IE_INVAL
;
5867 /* Check if connection is established
5868 * TODO: This check should be done donwstairs. */
5869 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5872 /* Build CreateMultipleMessage request */
5873 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMultipleMessage");
5875 isds_log_message(context
,
5876 _("Could build CreateMultipleMessage request"));
5879 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5881 isds_log_message(context
, _("Could not create ISDS name space"));
5882 xmlFreeNode(request
);
5885 xmlSetNs(request
, isds_ns
);
5888 /* Build recipients */
5889 recipients
= xmlNewChild(request
, NULL
, BAD_CAST
"dmRecipients", NULL
);
5891 isds_log_message(context
, _("Could not add dmRecipients child to "
5892 "CreateMultipleMessage element"));
5893 xmlFreeNode(request
);
5897 /* Insert each recipient */
5898 for (item
= copies
; item
; item
= item
->next
) {
5899 copy
= (struct isds_message_copy
*) item
->data
;
5901 isds_log_message(context
,
5902 _("copies list item contains empty data"));
5907 recipient
= xmlNewChild(recipients
, NULL
, BAD_CAST
"dmRecipient", NULL
);
5909 isds_log_message(context
, _("Could not add dmRecipient child to "
5910 "dmRecipient element"));
5915 if (!copy
->dbIDRecipient
) {
5916 isds_log_message(context
,
5917 _("Message copy is missing recipient box identifier"));
5921 INSERT_STRING(recipient
, "dbIDRecipient", copy
->dbIDRecipient
);
5922 INSERT_STRING(recipient
, "dmRecipientOrgUnit",
5923 copy
->dmRecipientOrgUnit
);
5924 INSERT_LONGINT(recipient
, "dmRecipientOrgUnitNum",
5925 copy
->dmRecipientOrgUnitNum
, string
);
5926 INSERT_STRING(recipient
, "dmToHands", copy
->dmToHands
);
5929 /* Append envelope and files */
5930 err
= insert_envelope_files(context
, outgoing_message
, request
, 0);
5931 if (err
) goto leave
;
5934 isds_log(ILF_ISDS
, ILL_DEBUG
,
5935 _("Sending CreateMultipleMessage request to ISDS\n"));
5938 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
5940 isds_log(ILF_ISDS
, ILL_DEBUG
,
5941 _("Processing ISDS response on CreateMultipleMessage "
5942 "request failed\n"));
5946 /* Check for response status */
5947 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
5948 &code
, &message
, NULL
);
5950 isds_log(ILF_ISDS
, ILL_DEBUG
,
5951 _("ISDS response on CreateMultipleMessage request "
5952 "is missing status\n"));
5956 /* Request processed, but some copies failed */
5957 if (!xmlStrcmp(code
, BAD_CAST
"0004")) {
5958 char *box_id_locale
=
5959 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
5960 char *code_locale
= utf82locale((char*)code
);
5961 char *message_locale
= utf82locale((char*)message
);
5962 isds_log(ILF_ISDS
, ILL_DEBUG
,
5963 _("Server did accept message for multiple recipients "
5964 "on CreateMultipleMessage request but delivery to "
5965 "some of them failed (code=%s, message=%s)\n"),
5966 box_id_locale
, code_locale
, message_locale
);
5967 isds_log_message(context
, message_locale
);
5968 free(box_id_locale
);
5970 free(message_locale
);
5971 err
= IE_PARTIAL_SUCCESS
;
5974 /* Request refused by server as whole */
5975 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5976 char *box_id_locale
=
5977 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
5978 char *code_locale
= utf82locale((char*)code
);
5979 char *message_locale
= utf82locale((char*)message
);
5980 isds_log(ILF_ISDS
, ILL_DEBUG
,
5981 _("Server did not accept message for multiple recipients "
5982 "on CreateMultipleMessage request (code=%s, message=%s)\n"),
5983 box_id_locale
, code_locale
, message_locale
);
5984 isds_log_message(context
, message_locale
);
5985 free(box_id_locale
);
5987 free(message_locale
);
5994 xpath_ctx
= xmlXPathNewContext(response
);
5999 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6003 result
= xmlXPathEvalExpression(
6004 BAD_CAST
"/isds:CreateMultipleMessageResponse"
6005 "/isds:dmMultipleStatus/isds:dmSingleStatus",
6011 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6012 isds_log_message(context
, _("Missing isds:dmSingleStatus element"));
6017 /* Extract message ID and delivery status for each copy */
6018 for (item
= copies
, i
= 0; item
&& i
< result
->nodesetval
->nodeNr
;
6019 item
= item
->next
, i
++) {
6020 copy
= (struct isds_message_copy
*) item
->data
;
6021 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
6023 append_err
= append_TMStatus(context
, copy
, xpath_ctx
);
6029 if (item
|| i
< result
->nodesetval
->nodeNr
) {
6030 isds_printf_message(context
, _("ISDS returned unexpected number of "
6031 "message copy delivery states: %d"),
6032 result
->nodesetval
->nodeNr
);
6041 xmlXPathFreeObject(result
);
6042 xmlXPathFreeContext(xpath_ctx
);
6046 xmlFreeDoc(response
);
6047 xmlFreeNode(request
);
6050 isds_log(ILF_ISDS
, ILL_DEBUG
,
6051 _("CreateMultipleMessageResponse request processed by server "
6052 "successfully.\n"));
6058 /* Get list of messages. This is common core for getting sent or received
6060 * Any criterion argument can be NULL, if you don't care about it.
6061 * @context is session context. Must not be NULL.
6062 * @outgoing_direction is true if you want list of outgoing messages,
6063 * it's false if you want incoming messages.
6064 * @from_time is minimal time and date of message sending inclusive.
6065 * @to_time is maximal time and date of message sending inclusive
6066 * @organization_unit_number is number of sender/recipient respectively.
6067 * @status_filter is bit field of isds_message_status values. Use special
6068 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6069 * all values, you can use bitwise arithmetic if you want.)
6070 * @offset is index of first message we are interested in. First message is 1.
6071 * Set to 0 (or 1) if you don't care.
6072 * @number is maximal length of list you want to get as input value, outputs
6073 * number of messages matching these criteria. Can be NULL if you don't care
6074 * (applies to output value either).
6075 * @messages is automatically reallocated list of isds_message's. Be ware that
6076 * it returns only brief overview (envelope and some other fields) about each
6077 * message, not the complete message. FIXME: Specify exact fields.
6078 * The list is sorted by delivery time in ascending order.
6080 * you don't care about don't need the data (useful if you want to know only
6081 * the @number). If you provide &NULL, list will be allocated on heap, if you
6082 * provide pointer to non-NULL, list will be freed automacally at first. Also
6083 * in case of error the list will be NULLed.
6084 * @return IE_SUCCESS or appropriate error code. */
6085 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
6086 _Bool outgoing_direction
,
6087 const struct timeval
*from_time
, const struct timeval
*to_time
,
6088 const long int *organization_unit_number
,
6089 const unsigned int status_filter
,
6090 const unsigned long int offset
, unsigned long int *number
,
6091 struct isds_list
**messages
) {
6093 isds_error err
= IE_SUCCESS
;
6094 xmlNsPtr isds_ns
= NULL
;
6095 xmlNodePtr request
= NULL
, node
;
6096 xmlDocPtr response
= NULL
;
6097 xmlChar
*code
= NULL
, *message
= NULL
;
6098 xmlXPathContextPtr xpath_ctx
= NULL
;
6099 xmlXPathObjectPtr result
= NULL
;
6100 xmlChar
*string
= NULL
;
6101 long unsigned int count
= 0;
6103 if (!context
) return IE_INVALID_CONTEXT
;
6105 /* Free former message list if any */
6106 if (messages
) isds_list_free(messages
);
6108 /* Check if connection is established
6109 * TODO: This check should be done donwstairs. */
6110 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6112 /* Build GetListOf*Messages request */
6113 request
= xmlNewNode(NULL
,
6114 (outgoing_direction
) ?
6115 BAD_CAST
"GetListOfSentMessages" :
6116 BAD_CAST
"GetListOfReceivedMessages"
6119 isds_log_message(context
,
6120 (outgoing_direction
) ?
6121 _("Could not build GetListOfSentMessages request") :
6122 _("Could not build GetListOfReceivedMessages request")
6126 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6128 isds_log_message(context
, _("Could not create ISDS name space"));
6129 xmlFreeNode(request
);
6132 xmlSetNs(request
, isds_ns
);
6136 err
= timeval2timestring(from_time
, &string
);
6137 if (err
) goto leave
;
6139 INSERT_STRING(request
, "dmFromTime", string
);
6140 free(string
); string
= NULL
;
6143 err
= timeval2timestring(to_time
, &string
);
6144 if (err
) goto leave
;
6146 INSERT_STRING(request
, "dmToTime", string
);
6147 free(string
); string
= NULL
;
6149 if (outgoing_direction
) {
6150 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
6151 organization_unit_number
, string
);
6153 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
6154 organization_unit_number
, string
);
6157 if (status_filter
> MESSAGESTATE_ANY
) {
6158 isds_printf_message(context
,
6159 _("Invalid message state filter value: %ld"), status_filter
);
6163 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
6166 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
6168 INSERT_STRING(request
, "dmOffset", "1");
6171 /* number 0 means no limit */
6172 if (number
&& *number
== 0) {
6173 INSERT_STRING(request
, "dmLimit", NULL
);
6175 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
6179 isds_log(ILF_ISDS
, ILL_DEBUG
,
6180 (outgoing_direction
) ?
6181 _("Sending GetListOfSentMessages request to ISDS\n") :
6182 _("Sending GetListOfReceivedMessages request to ISDS\n")
6186 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
, NULL
, NULL
);
6187 xmlFreeNode(request
); request
= NULL
;
6190 isds_log(ILF_ISDS
, ILL_DEBUG
,
6191 (outgoing_direction
) ?
6192 _("Processing ISDS response on GetListOfSentMessages "
6193 "request failed\n") :
6194 _("Processing ISDS response on GetListOfReceivedMessages "
6200 /* Check for response status */
6201 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
6202 &code
, &message
, NULL
);
6204 isds_log(ILF_ISDS
, ILL_DEBUG
,
6205 (outgoing_direction
) ?
6206 _("ISDS response on GetListOfSentMessages request "
6207 "is missing status\n") :
6208 _("ISDS response on GetListOfReceivedMessages request "
6209 "is missing status\n")
6214 /* Request processed, but nothing found */
6215 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6216 char *code_locale
= utf82locale((char*)code
);
6217 char *message_locale
= utf82locale((char*)message
);
6218 isds_log(ILF_ISDS
, ILL_DEBUG
,
6219 (outgoing_direction
) ?
6220 _("Server refused GetListOfSentMessages request "
6221 "(code=%s, message=%s)\n") :
6222 _("Server refused GetListOfReceivedMessages request "
6223 "(code=%s, message=%s)\n"),
6224 code_locale
, message_locale
);
6225 isds_log_message(context
, message_locale
);
6227 free(message_locale
);
6234 xpath_ctx
= xmlXPathNewContext(response
);
6239 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6243 result
= xmlXPathEvalExpression(
6244 (outgoing_direction
) ?
6245 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
6246 "isds:dmRecords/isds:dmRecord" :
6247 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
6248 "isds:dmRecords/isds:dmRecord",
6255 /* Fill output arguments in */
6256 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6257 struct isds_envelope
*envelope
;
6258 struct isds_list
*item
= NULL
, *last_item
= NULL
;
6260 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
6261 /* Create new message */
6262 item
= calloc(1, sizeof(*item
));
6267 item
->destructor
= (void(*)(void**)) &isds_message_free
;
6268 item
->data
= calloc(1, sizeof(struct isds_message
));
6270 isds_list_free(&item
);
6275 /* Extract envelope data */
6276 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
6278 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
6280 isds_list_free(&item
);
6284 /* Attach extracted envelope */
6285 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
6287 /* Append new message into the list */
6289 *messages
= last_item
= item
;
6291 last_item
->next
= item
;
6296 if (number
) *number
= count
;
6300 isds_list_free(messages
);
6304 xmlXPathFreeObject(result
);
6305 xmlXPathFreeContext(xpath_ctx
);
6309 xmlFreeDoc(response
);
6310 xmlFreeNode(request
);
6313 isds_log(ILF_ISDS
, ILL_DEBUG
,
6314 (outgoing_direction
) ?
6315 _("GetListOfSentMessages request processed by server "
6316 "successfully.\n") :
6317 _("GetListOfReceivedMessages request processed by server "
6324 /* Get list of outgoing (already sent) messages.
6325 * Any criterion argument can be NULL, if you don't care about it.
6326 * @context is session context. Must not be NULL.
6327 * @from_time is minimal time and date of message sending inclusive.
6328 * @to_time is maximal time and date of message sending inclusive
6329 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
6330 * @status_filter is bit field of isds_message_status values. Use special
6331 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6332 * all values, you can use bitwise arithmetic if you want.)
6333 * @offset is index of first message we are interested in. First message is 1.
6334 * Set to 0 (or 1) if you don't care.
6335 * @number is maximal length of list you want to get as input value, outputs
6336 * number of messages matching these criteria. Can be NULL if you don't care
6337 * (applies to output value either).
6338 * @messages is automatically reallocated list of isds_message's. Be ware that
6339 * it returns only brief overview (envelope and some other fields) about each
6340 * message, not the complete message. FIXME: Specify exact fields.
6341 * The list is sorted by delivery time in ascending order.
6342 * Use NULL if you don't care about the metadata (useful if you want to know
6343 * only the @number). If you provide &NULL, list will be allocated on heap,
6344 * if you provide pointer to non-NULL, list will be freed automacally at first.
6345 * Also in case of error the list will be NULLed.
6346 * @return IE_SUCCESS or appropriate error code. */
6347 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
6348 const struct timeval
*from_time
, const struct timeval
*to_time
,
6349 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
6350 const unsigned long int offset
, unsigned long int *number
,
6351 struct isds_list
**messages
) {
6353 return isds_get_list_of_messages(
6355 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
6361 /* Get list of incoming (addressed to you) messages.
6362 * Any criterion argument can be NULL, if you don't care about it.
6363 * @context is session context. Must not be NULL.
6364 * @from_time is minimal time and date of message sending inclusive.
6365 * @to_time is maximal time and date of message sending inclusive
6366 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
6367 * @status_filter is bit field of isds_message_status values. Use special
6368 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6369 * all values, you can use bitwise arithmetic if you want.)
6370 * @offset is index of first message we are interested in. First message is 1.
6371 * Set to 0 (or 1) if you don't care.
6372 * @number is maximal length of list you want to get as input value, outputs
6373 * number of messages matching these criteria. Can be NULL if you don't care
6374 * (applies to output value either).
6375 * @messages is automatically reallocated list of isds_message's. Be ware that
6376 * it returns only brief overview (envelope and some other fields) about each
6377 * message, not the complete message. FIXME: Specify exact fields.
6378 * Use NULL if you don't care about the metadata (useful if you want to know
6379 * only the @number). If you provide &NULL, list will be allocated on heap,
6380 * if you provide pointer to non-NULL, list will be freed automacally at first.
6381 * Also in case of error the list will be NULLed.
6382 * @return IE_SUCCESS or appropriate error code. */
6383 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
6384 const struct timeval
*from_time
, const struct timeval
*to_time
,
6385 const long int *dmRecipientOrgUnitNum
,
6386 const unsigned int status_filter
,
6387 const unsigned long int offset
, unsigned long int *number
,
6388 struct isds_list
**messages
) {
6390 return isds_get_list_of_messages(
6392 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
6398 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
6400 * @context is session context
6401 * @service is ISDS WS service handler
6402 * @service_name is name of SERVICE_DM_OPERATIONS
6403 * @message_id is message ID to send as service argument to ISDS
6404 * @response is server SOAP body response as XML document
6405 * @raw_response is automatically reallocated bitstream with response body. Use
6406 * NULL if you don't care
6407 * @raw_response_length is size of @raw_response in bytes
6408 * @code is ISDS status code
6409 * @status_message is ISDS status message
6410 * @return error coded from lower layer, context message will be set up
6412 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
6413 const isds_service service
, const xmlChar
*service_name
,
6414 const char *message_id
,
6415 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
6416 xmlChar
**code
, xmlChar
**status_message
) {
6418 isds_error err
= IE_SUCCESS
;
6419 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
6420 xmlNodePtr request
= NULL
, node
;
6421 xmlNsPtr isds_ns
= NULL
;
6423 if (!context
) return IE_INVALID_CONTEXT
;
6424 if (!service_name
|| !message_id
) return IE_INVAL
;
6425 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
6426 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
6428 /* Free output argument */
6429 xmlFreeDoc(*response
); *response
= NULL
;
6430 if (raw_response
) zfree(*raw_response
);
6432 free(*status_message
);
6435 /* Check if connection is established
6436 * TODO: This check should be done donwstairs. */
6437 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6439 service_name_locale
= utf82locale((char*)service_name
);
6440 message_id_locale
= utf82locale(message_id
);
6441 if (!service_name_locale
|| !message_id_locale
) {
6447 request
= xmlNewNode(NULL
, service_name
);
6449 isds_printf_message(context
,
6450 _("Could not build %s request"), service_name_locale
);
6454 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6456 isds_log_message(context
, _("Could not create ISDS name space"));
6460 xmlSetNs(request
, isds_ns
);
6463 /* Add requested ID */
6464 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
6465 if (err
) goto leave
;
6466 INSERT_STRING(request
, "dmID", message_id
);
6469 isds_log(ILF_ISDS
, ILL_DEBUG
,
6470 _("Sending %s request for %s message ID to ISDS\n"),
6471 service_name_locale
, message_id_locale
);
6474 err
= isds(context
, service
, request
, response
,
6475 raw_response
, raw_response_length
);
6476 xmlFreeNode(request
); request
= NULL
;
6479 isds_log(ILF_ISDS
, ILL_DEBUG
,
6480 _("Processing ISDS response on %s request failed\n"),
6481 service_name_locale
);
6485 /* Check for response status */
6486 err
= isds_response_status(context
, service
, *response
,
6487 code
, status_message
, NULL
);
6489 isds_log(ILF_ISDS
, ILL_DEBUG
,
6490 _("ISDS response on %s request is missing status\n"),
6491 service_name_locale
);
6495 /* Request processed, but nothing found */
6496 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
6497 char *code_locale
= utf82locale((char*) *code
);
6498 char *status_message_locale
= utf82locale((char*) *status_message
);
6499 isds_log(ILF_ISDS
, ILL_DEBUG
,
6500 _("Server refused %s request for %s message ID "
6501 "(code=%s, message=%s)\n"),
6502 service_name_locale
, message_id_locale
,
6503 code_locale
, status_message_locale
);
6504 isds_log_message(context
, status_message_locale
);
6506 free(status_message_locale
);
6512 free(message_id_locale
);
6513 free(service_name_locale
);
6514 xmlFreeNode(request
);
6519 /* Find dmSignature in ISDS response, extract decoded CMS structure, extract
6520 * signed data and free ISDS response.
6521 * @context is session context
6522 * @message_id is UTF-8 encoded message ID for loging purpose
6523 * @response is parsed XML document. It will be freed and NULLed in the middle
6524 * of function run to save memmory. This is not guaranted in case of error.
6525 * @request_name is name of ISDS request used to construct response root
6526 * element name and for logging purpose.
6527 * @raw is reallocated output buffer with DER encoded CMS data
6528 * @raw_length is size of @raw buffer in bytes
6529 * @returns standard error codes, in case of error, @raw will be freed and
6530 * NULLed, @response sometimes. */
6531 static isds_error
find_extract_signed_data_free_response(
6532 struct isds_ctx
*context
, const xmlChar
*message_id
,
6533 xmlDocPtr
*response
, const xmlChar
*request_name
,
6534 void **raw
, size_t *raw_length
) {
6536 isds_error err
= IE_SUCCESS
;
6537 char *xpath_expression
= NULL
;
6538 xmlXPathContextPtr xpath_ctx
= NULL
;
6539 xmlXPathObjectPtr result
= NULL
;
6540 char *encoded_structure
= NULL
;
6542 if (!context
) return IE_INVALID_CONTEXT
;
6543 if (!raw
) return IE_INVAL
;
6545 if (!message_id
|| !response
|| !*response
|| !request_name
|| !raw_length
)
6548 /* Build XPath expression */
6549 xpath_expression
= astrcat3("/isds:", (char *) request_name
,
6550 "Response/isds:dmSignature");
6551 if (!xpath_expression
) return IE_NOMEM
;
6554 xpath_ctx
= xmlXPathNewContext(*response
);
6559 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6563 result
= xmlXPathEvalExpression(BAD_CAST xpath_expression
, xpath_ctx
);
6568 /* Empty response */
6569 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6570 char *message_id_locale
= utf82locale((char*) message_id
);
6571 isds_printf_message(context
,
6572 _("Server did not return any signed data for mesage ID `%s' "
6574 message_id_locale
, request_name
);
6575 free(message_id_locale
);
6580 if (result
->nodesetval
->nodeNr
> 1) {
6581 char *message_id_locale
= utf82locale((char*) message_id
);
6582 isds_printf_message(context
,
6583 _("Server did return more signed data for message ID `%s' "
6585 message_id_locale
, request_name
);
6586 free(message_id_locale
);
6591 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6593 /* Extract PKCS#7 structure */
6594 EXTRACT_STRING(".", encoded_structure
);
6595 if (!encoded_structure
) {
6596 isds_log_message(context
, _("dmSignature element is empty"));
6599 /* Here we have delivery info as standalone CMS in encoded_structure.
6600 * We don't need any other data, free them: */
6601 xmlXPathFreeObject(result
); result
= NULL
;
6602 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
6603 xmlFreeDoc(*response
); *response
= NULL
;
6606 /* Decode PKCS#7 to DER format */
6607 *raw_length
= b64decode(encoded_structure
, raw
);
6608 if (*raw_length
== (size_t) -1) {
6609 isds_log_message(context
,
6610 _("Error while Base64-decoding PKCS#7 structure"));
6621 free(encoded_structure
);
6622 xmlXPathFreeObject(result
);
6623 xmlXPathFreeContext(xpath_ctx
);
6624 free(xpath_expression
);
6630 /* Download incoming message envelope identified by ID.
6631 * @context is session context
6632 * @message_id is message identifier (you can get them from
6633 * isds_get_list_of_received_messages())
6634 * @message is automatically reallocated message retrieved from ISDS.
6635 * It will miss documents per se. Use isds_get_received_message(), if you are
6636 * interrested in documents (content) too.
6637 * Returned hash and timestamp require documents to be verifiable. */
6638 isds_error
isds_get_received_envelope(struct isds_ctx
*context
,
6639 const char *message_id
, struct isds_message
**message
) {
6641 isds_error err
= IE_SUCCESS
;
6642 xmlDocPtr response
= NULL
;
6643 xmlChar
*code
= NULL
, *status_message
= NULL
;
6644 xmlXPathContextPtr xpath_ctx
= NULL
;
6645 xmlXPathObjectPtr result
= NULL
;
6647 if (!context
) return IE_INVALID_CONTEXT
;
6649 /* Free former message if any */
6650 if (!message
) return IE_INVAL
;
6651 isds_message_free(message
);
6653 /* Do request and check for success */
6654 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6655 BAD_CAST
"MessageEnvelopeDownload", message_id
,
6656 &response
, NULL
, NULL
, &code
, &status_message
);
6657 if (err
) goto leave
;
6660 xpath_ctx
= xmlXPathNewContext(response
);
6665 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6669 result
= xmlXPathEvalExpression(
6670 BAD_CAST
"/isds:MessageEnvelopeDownloadResponse/"
6671 "isds:dmReturnedMessageEnvelope",
6677 /* Empty response */
6678 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6679 char *message_id_locale
= utf82locale((char*) message_id
);
6680 isds_printf_message(context
,
6681 _("Server did not return any envelope for ID `%s' "
6682 "on MessageEnvelopeDownload request"), message_id_locale
);
6683 free(message_id_locale
);
6688 if (result
->nodesetval
->nodeNr
> 1) {
6689 char *message_id_locale
= utf82locale((char*) message_id
);
6690 isds_printf_message(context
,
6691 _("Server did return more envelopes for ID `%s' "
6692 "on MessageEnvelopeDownload request"), message_id_locale
);
6693 free(message_id_locale
);
6698 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6700 /* Extract the envelope (= message without documents, hence 0) */
6701 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
6702 if (err
) goto leave
;
6705 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
6706 &(*message
)->raw_length
);
6710 isds_message_free(message
);
6713 xmlXPathFreeObject(result
);
6714 xmlXPathFreeContext(xpath_ctx
);
6717 free(status_message
);
6718 xmlFreeDoc(response
);
6721 isds_log(ILF_ISDS
, ILL_DEBUG
,
6722 _("MessageEnvelopeDownload request processed by server "
6729 /* Load delivery info of any format from buffer.
6730 * @context is session context
6731 * @raw_type advertises format of @buffer content. Only delivery info types
6733 * @buffer is DER encoded PKCS#7 structure with signed delivery info. You can
6734 * retrieve such data from message->raw after calling
6735 * isds_get_signed_delivery_info().
6736 * @length is length of buffer in bytes.
6737 * @message is automatically reallocated message parsed from @buffer.
6738 * @strategy selects how buffer will be attached into raw isds_message member.
6740 isds_error
isds_load_delivery_info(struct isds_ctx
*context
,
6741 const isds_raw_type raw_type
,
6742 const void *buffer
, const size_t length
,
6743 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
6745 isds_error err
= IE_SUCCESS
;
6746 message_ns_type message_ns
;
6747 xmlDocPtr message_doc
= NULL
;
6748 xmlXPathContextPtr xpath_ctx
= NULL
;
6749 xmlXPathObjectPtr result
= NULL
;
6750 void *xml_stream
= NULL
;
6751 size_t xml_stream_length
= 0;
6753 if (!context
) return IE_INVALID_CONTEXT
;
6754 if (!message
) return IE_INVAL
;
6755 isds_message_free(message
);
6756 if (!buffer
) return IE_INVAL
;
6759 /* Select buffer format and extract XML from CMS*/
6761 case RAWTYPE_DELIVERYINFO
:
6762 message_ns
= MESSAGE_NS_UNSIGNED
;
6763 xml_stream
= (void *) buffer
;
6764 xml_stream_length
= length
;
6767 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
6768 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
6769 xml_stream
= (void *) buffer
;
6770 xml_stream_length
= length
;
6773 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
6774 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
6775 err
= extract_cms_data(context
, buffer
, length
,
6776 &xml_stream
, &xml_stream_length
);
6777 if (err
) goto leave
;
6781 isds_log_message(context
, _("Bad raw delivery representation type"));
6786 isds_log(ILF_ISDS
, ILL_DEBUG
,
6787 _("Delivery info content:\n%.*s\nEnd of delivery info\n"),
6788 xml_stream_length
, xml_stream
);
6790 /* Convert delivery info XML stream into XPath context */
6791 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
6796 xpath_ctx
= xmlXPathNewContext(message_doc
);
6801 /* XXX: Name spaces mangled for signed delivery info:
6802 * http://isds.czechpoint.cz/v20/delivery:
6804 * <q:GetDeliveryInfoResponse xmlns:q="http://isds.czechpoint.cz/v20/delivery">
6806 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6807 * <p:dmID>170272</p:dmID>
6810 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6812 * </q:dmEvents>...</q:dmEvents>
6814 * </q:GetDeliveryInfoResponse>
6816 if (register_namespaces(xpath_ctx
, message_ns
)) {
6820 result
= xmlXPathEvalExpression(
6821 BAD_CAST
"/sisds:GetDeliveryInfoResponse/sisds:dmDelivery",
6827 /* Empty delivery info */
6828 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6829 isds_printf_message(context
,
6830 _("XML document ss not sisds:dmDelivery document"));
6834 /* More delivery infos */
6835 if (result
->nodesetval
->nodeNr
> 1) {
6836 isds_printf_message(context
,
6837 _("XML document has more sisds:dmDelivery elements"));
6841 /* One delivery info */
6842 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6844 /* Extract the envelope (= message without documents, hence 0).
6845 * XXX: extract_TReturnedMessage() can obtain attachments size,
6846 * but delivery info carries none. It's coded as option elements,
6847 * so it should work. */
6848 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
6849 if (err
) goto leave
;
6851 /* Extract events */
6852 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmEvents", xpath_ctx
);
6853 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
6854 if (err
) { err
= IE_ERROR
; goto leave
; }
6855 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
6856 if (err
) goto leave
;
6858 /* Append raw CMS structure into message */
6859 (*message
)->raw_type
= raw_type
;
6861 case BUFFER_DONT_STORE
:
6864 (*message
)->raw
= malloc(length
);
6865 if (!(*message
)->raw
) {
6869 memcpy((*message
)->raw
, buffer
, length
);
6870 (*message
)->raw_length
= length
;
6873 (*message
)->raw
= (void *) buffer
;
6874 (*message
)->raw_length
= length
;
6883 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
6884 isds_message_free(message
);
6887 xmlXPathFreeObject(result
);
6888 xmlXPathFreeContext(xpath_ctx
);
6889 xmlFreeDoc(message_doc
);
6890 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
6893 isds_log(ILF_ISDS
, ILL_DEBUG
,
6894 _("Delivery info loaded successfully.\n"));
6899 /* Download signed delivery infosheet of given message identified by ID.
6900 * @context is session context
6901 * @message_id is message identifier (you can get them from
6902 * isds_get_list_of_{sent,received}_messages())
6903 * @message is automatically reallocated message retrieved from ISDS.
6904 * It will miss documents per se. Use isds_get_signed_received_message(),
6905 * if you are interrested in documents (content). OTOH, only this function
6906 * can get list events message has gone through. */
6907 isds_error
isds_get_signed_delivery_info(struct isds_ctx
*context
,
6908 const char *message_id
, struct isds_message
**message
) {
6910 isds_error err
= IE_SUCCESS
;
6911 xmlDocPtr response
= NULL
;
6912 xmlChar
*code
= NULL
, *status_message
= NULL
;
6914 size_t raw_length
= 0;
6916 if (!context
) return IE_INVALID_CONTEXT
;
6918 /* Free former message if any */
6919 if (!message
) return IE_INVAL
;
6920 isds_message_free(message
);
6922 /* Do request and check for success */
6923 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6924 BAD_CAST
"GetSignedDeliveryInfo", message_id
,
6925 &response
, NULL
, NULL
, &code
, &status_message
);
6926 if (err
) goto leave
;
6928 /* Find signed delivery info, extract it into raw and maybe free
6930 err
= find_extract_signed_data_free_response(context
,
6931 (xmlChar
*)message_id
, &response
,
6932 BAD_CAST
"GetSignedDeliveryInfo", &raw
, &raw_length
);
6933 if (err
) goto leave
;
6935 /* Parse delivery info */
6936 err
= isds_load_delivery_info(context
,
6937 RAWTYPE_CMS_SIGNED_DELIVERYINFO
, raw
, raw_length
,
6938 message
, BUFFER_MOVE
);
6939 if (err
) goto leave
;
6945 isds_message_free(message
);
6950 free(status_message
);
6951 xmlFreeDoc(response
);
6954 isds_log(ILF_ISDS
, ILL_DEBUG
,
6955 _("GetSignedDeliveryInfo request processed by server "
6962 /* Download delivery infosheet of given message identified by ID.
6963 * @context is session context
6964 * @message_id is message identifier (you can get them from
6965 * isds_get_list_of_{sent,received}_messages())
6966 * @message is automatically reallocated message retrieved from ISDS.
6967 * It will miss documents per se. Use isds_get_received_message(), if you are
6968 * interrested in documents (content). OTOH, only this function can get list
6969 * events message has gone through. */
6970 isds_error
isds_get_delivery_info(struct isds_ctx
*context
,
6971 const char *message_id
, struct isds_message
**message
) {
6973 isds_error err
= IE_SUCCESS
;
6974 xmlDocPtr response
= NULL
;
6975 xmlChar
*code
= NULL
, *status_message
= NULL
;
6976 xmlXPathContextPtr xpath_ctx
= NULL
;
6977 xmlXPathObjectPtr result
= NULL
;
6978 xmlNodePtr delivery_node
= NULL
;
6980 if (!context
) return IE_INVALID_CONTEXT
;
6982 /* Free former message if any */
6983 if (!message
) return IE_INVAL
;
6984 isds_message_free(message
);
6986 /* Do request and check for success */
6987 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6988 BAD_CAST
"GetDeliveryInfo", message_id
,
6989 &response
, NULL
, NULL
, &code
, &status_message
);
6990 if (err
) goto leave
;
6993 xpath_ctx
= xmlXPathNewContext(response
);
6998 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7002 result
= xmlXPathEvalExpression(
7003 BAD_CAST
"/isds:GetDeliveryInfoResponse/isds:dmDelivery",
7009 /* Empty response */
7010 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7011 char *message_id_locale
= utf82locale((char*) message_id
);
7012 isds_printf_message(context
,
7013 _("Server did not return any delivery info for ID `%s' "
7014 "on GetDeliveryInfo request"), message_id_locale
);
7015 free(message_id_locale
);
7019 /* More delivery infos */
7020 if (result
->nodesetval
->nodeNr
> 1) {
7021 char *message_id_locale
= utf82locale((char*) message_id
);
7022 isds_printf_message(context
,
7023 _("Server did return more delivery infos for ID `%s' "
7024 "on GetDeliveryInfo request"), message_id_locale
);
7025 free(message_id_locale
);
7029 /* One delivery info */
7030 xpath_ctx
->node
= delivery_node
= result
->nodesetval
->nodeTab
[0];
7032 /* Extract the envelope (= message without documents, hence 0).
7033 * XXX: extract_TReturnedMessage() can obtain attachments size,
7034 * but delivery info carries none. It's coded as option elements,
7035 * so it should work. */
7036 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
7037 if (err
) goto leave
;
7039 /* Extract events */
7040 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmEvents", xpath_ctx
);
7041 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
7042 if (err
) { err
= IE_ERROR
; goto leave
; }
7043 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
7044 if (err
) goto leave
;
7047 err
= serialize_subtree(context
, delivery_node
, &(*message
)->raw
,
7048 &(*message
)->raw_length
);
7052 isds_message_free(message
);
7055 xmlXPathFreeObject(result
);
7056 xmlXPathFreeContext(xpath_ctx
);
7059 free(status_message
);
7060 xmlFreeDoc(response
);
7063 isds_log(ILF_ISDS
, ILL_DEBUG
,
7064 _("GetDeliveryInfo request processed by server "
7071 /* Load incoming message from buffer.
7072 * @context is session context
7073 * @buffer XML stream with unsigned message. You can retrieve such data from
7074 * message->raw after calling isds_get_received_message().
7075 * @length is length of buffer in bytes.
7076 * @message is automatically reallocated message parsed from @buffer.
7077 * @strategy selects how buffer will be attached into raw isds_message member.
7079 isds_error
isds_load_received_message(struct isds_ctx
*context
,
7080 const void *buffer
, const size_t length
,
7081 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7083 isds_error err
= IE_SUCCESS
;
7084 xmlDocPtr message_doc
= NULL
;
7085 xmlXPathContextPtr xpath_ctx
= NULL
;
7086 xmlXPathObjectPtr result
= NULL
;
7088 if (!context
) return IE_INVALID_CONTEXT
;
7089 if (!message
) return IE_INVAL
;
7090 isds_message_free(message
);
7091 if (!buffer
) return IE_INVAL
;
7094 isds_log(ILF_ISDS
, ILL_DEBUG
,
7095 _("Incoming message content:\n%.*s\nEnd of message\n"),
7098 /* Convert extracted messages XML stream into XPath context */
7099 message_doc
= xmlParseMemory(buffer
, length
);
7104 xpath_ctx
= xmlXPathNewContext(message_doc
);
7109 /* XXX: Standard name space */
7110 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7114 result
= xmlXPathEvalExpression(
7115 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
7121 /* Missing dmReturnedMessage */
7122 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7123 isds_printf_message(context
,
7124 _("XML document does not contain isds:dmReturnedMessage "
7129 /* More elements. This should never happen. */
7130 if (result
->nodesetval
->nodeNr
> 1) {
7131 isds_printf_message(context
,
7132 _("XML document has more isds:dmReturnedMessage elements"));
7137 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7139 /* Extract the message */
7140 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7141 if (err
) goto leave
;
7143 /* Append XML stream into message */
7144 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7146 case BUFFER_DONT_STORE
:
7149 (*message
)->raw
= malloc(length
);
7150 if (!(*message
)->raw
) {
7154 memcpy((*message
)->raw
, buffer
, length
);
7155 (*message
)->raw_length
= length
;
7158 (*message
)->raw
= (void *) buffer
;
7159 (*message
)->raw_length
= length
;
7168 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7169 isds_message_free(message
);
7172 xmlFreeDoc(message_doc
);
7173 xmlXPathFreeObject(result
);
7174 xmlXPathFreeContext(xpath_ctx
);
7177 isds_log(ILF_ISDS
, ILL_DEBUG
,
7178 _("Incoming message loaded successfully.\n"));
7183 /* Download incoming message identified by ID.
7184 * @context is session context
7185 * @message_id is message identifier (you can get them from
7186 * isds_get_list_of_received_messages())
7187 * @message is automatically reallocated message retrieved from ISDS */
7188 isds_error
isds_get_received_message(struct isds_ctx
*context
,
7189 const char *message_id
, struct isds_message
**message
) {
7191 isds_error err
= IE_SUCCESS
;
7192 xmlDocPtr response
= NULL
;
7193 void *xml_stream
= NULL
;
7194 size_t xml_stream_length
;
7195 xmlChar
*code
= NULL
, *status_message
= NULL
;
7196 xmlXPathContextPtr xpath_ctx
= NULL
;
7197 xmlXPathObjectPtr result
= NULL
;
7198 char *phys_path
= NULL
;
7199 size_t phys_start
, phys_end
;
7201 if (!context
) return IE_INVALID_CONTEXT
;
7203 /* Free former message if any */
7204 if (message
) isds_message_free(message
);
7206 /* Do request and check for success */
7207 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7208 BAD_CAST
"MessageDownload", message_id
,
7209 &response
, &xml_stream
, &xml_stream_length
,
7210 &code
, &status_message
);
7211 if (err
) goto leave
;
7214 xpath_ctx
= xmlXPathNewContext(response
);
7219 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7223 result
= xmlXPathEvalExpression(
7224 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
7230 /* Empty response */
7231 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7232 char *message_id_locale
= utf82locale((char*) message_id
);
7233 isds_printf_message(context
,
7234 _("Server did not return any message for ID `%s' "
7235 "on MessageDownload request"), message_id_locale
);
7236 free(message_id_locale
);
7241 if (result
->nodesetval
->nodeNr
> 1) {
7242 char *message_id_locale
= utf82locale((char*) message_id
);
7243 isds_printf_message(context
,
7244 _("Server did return more messages for ID `%s' "
7245 "on MessageDownload request"), message_id_locale
);
7246 free(message_id_locale
);
7251 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7253 /* Extract the message */
7254 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7255 if (err
) goto leave
;
7257 /* Locate raw XML blob */
7259 SOAP_NS PHYSXML_NS_SEPARATOR
"Envelope"
7260 PHYSXML_ELEMENT_SEPARATOR
7261 SOAP_NS PHYSXML_NS_SEPARATOR
"Body"
7262 PHYSXML_ELEMENT_SEPARATOR
7263 ISDS_NS PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
7269 err
= find_element_boundary(xml_stream
, xml_stream_length
,
7270 phys_path
, &phys_start
, &phys_end
);
7273 isds_log_message(context
,
7274 _("Substring with isds:MessageDownloadResponse element "
7275 "could not be located in raw SOAP message"));
7279 /*err = serialize_subtree(context, xpath_ctx->node, &(*message)->raw,
7280 &(*message)->raw_length);*/
7281 /* TODO: Store name space declarations from ancestors */
7282 /* TODO: Handle non-UTF-8 encoding (XML prologue) */
7283 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7284 (*message
)->raw_length
= phys_end
- phys_start
+ 1;
7285 (*message
)->raw
= malloc((*message
)->raw_length
);
7286 if (!(*message
)->raw
) {
7290 memcpy((*message
)->raw
, xml_stream
+ phys_start
, (*message
)->raw_length
);
7295 isds_message_free(message
);
7300 xmlXPathFreeObject(result
);
7301 xmlXPathFreeContext(xpath_ctx
);
7304 free(status_message
);
7306 xmlFreeDoc(response
);
7309 isds_log(ILF_ISDS
, ILL_DEBUG
,
7310 _("MessageDownload request processed by server "
7317 /* Load signed message from buffer.
7318 * @context is session context
7319 * @outgoing is true if message is outgoing, false if message is incoming
7320 * @buffer is DER encoded PKCS#7 structure with signed message. You can
7321 * retrieve such data from message->raw after calling
7322 * isds_get_signed_{received,sent}_message().
7323 * @length is length of buffer in bytes.
7324 * @message is automatically reallocated message parsed from @buffer.
7325 * @strategy selects how buffer will be attached into raw isds_message member.
7327 isds_error
isds_load_signed_message(struct isds_ctx
*context
,
7328 const _Bool outgoing
, const void *buffer
, const size_t length
,
7329 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7331 isds_error err
= IE_SUCCESS
;
7332 xmlDocPtr message_doc
= NULL
;
7333 xmlXPathContextPtr xpath_ctx
= NULL
;
7334 xmlXPathObjectPtr result
= NULL
;
7335 void *xml_stream
= NULL
;
7336 size_t xml_stream_length
= 0;
7338 if (!context
) return IE_INVALID_CONTEXT
;
7339 if (!message
) return IE_INVAL
;
7340 isds_message_free(message
);
7341 if (!buffer
) return IE_INVAL
;
7344 /* Extract message from PKCS#7 structure */
7345 err
= extract_cms_data(context
, buffer
, length
,
7346 &xml_stream
, &xml_stream_length
);
7347 if (err
) goto leave
;
7349 isds_log(ILF_ISDS
, ILL_DEBUG
, (outgoing
) ?
7350 _("Signed outgoing message content:\n%.*s\nEnd of message\n") :
7351 _("Signed incoming message content:\n%.*s\nEnd of message\n"),
7352 xml_stream_length
, xml_stream
);
7354 /* Convert extracted messages XML stream into XPath context */
7355 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7360 xpath_ctx
= xmlXPathNewContext(message_doc
);
7365 /* XXX: Name spaces mangled for outgoing direction:
7366 * http://isds.czechpoint.cz/v20/SentMessage:
7368 * <q:MessageDownloadResponse
7369 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
7370 * <q:dmReturnedMessage>
7371 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7372 * <p:dmID>151916</p:dmID>
7375 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7377 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7378 * </q:dmReturnedMessage>
7379 * </q:MessageDownloadResponse>
7381 * XXX: Name spaces mangled for incoming direction:
7382 * http://isds.czechpoint.cz/v20/message:
7384 * <q:MessageDownloadResponse
7385 * xmlns:q="http://isds.czechpoint.cz/v20/message">
7386 * <q:dmReturnedMessage>
7387 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7388 * <p:dmID>151916</p:dmID>
7391 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7393 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7394 * </q:dmReturnedMessage>
7395 * </q:MessageDownloadResponse>
7397 * Stupidity of ISDS developers is unlimited */
7398 if (register_namespaces(xpath_ctx
, (outgoing
) ?
7399 MESSAGE_NS_SIGNED_OUTGOING
: MESSAGE_NS_SIGNED_INCOMING
)) {
7403 /* XXX: Embeded message XML document is always rooted as
7404 * /sisds:MessageDownloadResponse (even outgoing message). */
7405 result
= xmlXPathEvalExpression(
7406 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
7412 /* Empty embedded message */
7413 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7414 isds_printf_message(context
,
7415 _("XML document embedded into PKCS#7 structure is not "
7416 "sisds:dmReturnedMessage document"));
7420 /* More embedded messages */
7421 if (result
->nodesetval
->nodeNr
> 1) {
7422 isds_printf_message(context
,
7423 _("Embeded XML document into PKCS#7 structure has more "
7424 "root sisds:dmReturnedMessage elements"));
7428 /* One embedded message */
7429 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7431 /* Extract the message */
7432 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7433 if (err
) goto leave
;
7435 /* Append raw CMS structure into message */
7436 (*message
)->raw_type
= (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7437 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
;
7439 case BUFFER_DONT_STORE
:
7442 (*message
)->raw
= malloc(length
);
7443 if (!(*message
)->raw
) {
7447 memcpy((*message
)->raw
, buffer
, length
);
7448 (*message
)->raw_length
= length
;
7451 (*message
)->raw
= (void *) buffer
;
7452 (*message
)->raw_length
= length
;
7462 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7463 isds_message_free(message
);
7466 xmlFreeDoc(message_doc
);
7467 cms_data_free(xml_stream
);
7468 xmlXPathFreeObject(result
);
7469 xmlXPathFreeContext(xpath_ctx
);
7472 isds_log(ILF_ISDS
, ILL_DEBUG
,
7473 _("Signed message loaded successfully.\n"));
7478 /* Load message of any type from buffer.
7479 * @context is session context
7480 * @raw_type defines content type of @buffer. Only message types are allowed.
7481 * @buffer is message raw representation. Format (CMS, plain signed,
7482 * message direction) is defined in @raw_type. You can retrieve such data
7483 * from message->raw after calling isds_get_[signed]{received,sent}_message().
7484 * @length is length of buffer in bytes.
7485 * @message is automatically reallocated message parsed from @buffer.
7486 * @strategy selects how buffer will be attached into raw isds_message member.
7488 isds_error
isds_load_message(struct isds_ctx
*context
,
7489 const isds_raw_type raw_type
, const void *buffer
, const size_t length
,
7490 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7492 isds_error err
= IE_SUCCESS
;
7493 void *xml_stream
= NULL
;
7494 size_t xml_stream_length
= 0;
7495 message_ns_type message_ns
;
7496 xmlDocPtr message_doc
= NULL
;
7497 xmlXPathContextPtr xpath_ctx
= NULL
;
7498 xmlXPathObjectPtr result
= NULL
;
7500 if (!context
) return IE_INVALID_CONTEXT
;
7501 if (!message
) return IE_INVAL
;
7502 isds_message_free(message
);
7503 if (!buffer
) return IE_INVAL
;
7506 /* Select buffer format and extract XML from CMS*/
7508 case RAWTYPE_INCOMING_MESSAGE
:
7509 message_ns
= MESSAGE_NS_UNSIGNED
;
7510 xml_stream
= (void *) buffer
;
7511 xml_stream_length
= length
;
7514 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
7515 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7516 xml_stream
= (void *) buffer
;
7517 xml_stream_length
= length
;
7520 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
7521 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7522 err
= extract_cms_data(context
, buffer
, length
,
7523 &xml_stream
, &xml_stream_length
);
7524 if (err
) goto leave
;
7527 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
7528 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7529 xml_stream
= (void *) buffer
;
7530 xml_stream_length
= length
;
7533 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7534 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7535 err
= extract_cms_data(context
, buffer
, length
,
7536 &xml_stream
, &xml_stream_length
);
7537 if (err
) goto leave
;
7541 isds_log_message(context
, _("Bad raw message representation type"));
7546 isds_log(ILF_ISDS
, ILL_DEBUG
,
7547 _("Loading message:\n%.*s\nEnd of message\n"),
7548 xml_stream_length
, xml_stream
);
7550 /* Convert messages XML stream into XPath context */
7551 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7556 xpath_ctx
= xmlXPathNewContext(message_doc
);
7561 /* XXX: Standard name space for unsigned icoming direction:
7562 * http://isds.czechpoint.cz/v20/SentMessage
7564 * XXX: Name spaces mangled for signed outgoing direction:
7565 * http://isds.czechpoint.cz/v20/SentMessage:
7567 * <q:MessageDownloadResponse
7568 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
7569 * <q:dmReturnedMessage>
7570 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7571 * <p:dmID>151916</p:dmID>
7574 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7576 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7577 * </q:dmReturnedMessage>
7578 * </q:MessageDownloadResponse>
7580 * XXX: Name spaces mangled for signed incoming direction:
7581 * http://isds.czechpoint.cz/v20/message:
7583 * <q:MessageDownloadResponse
7584 * xmlns:q="http://isds.czechpoint.cz/v20/message">
7585 * <q:dmReturnedMessage>
7586 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7587 * <p:dmID>151916</p:dmID>
7590 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7592 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7593 * </q:dmReturnedMessage>
7594 * </q:MessageDownloadResponse>
7596 * Stupidity of ISDS developers is unlimited */
7597 if (register_namespaces(xpath_ctx
, message_ns
)) {
7601 result
= xmlXPathEvalExpression(
7602 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
7609 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7610 isds_printf_message(context
,
7611 _("XML document does not contain "
7612 "sisds:dmReturnedMessage element"));
7617 if (result
->nodesetval
->nodeNr
> 1) {
7618 isds_printf_message(context
,
7619 _("XML document has more sisds:dmReturnedMessage elements"));
7624 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7626 /* Extract the message */
7627 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7628 if (err
) goto leave
;
7630 /* Append raw buffer into message */
7631 (*message
)->raw_type
= raw_type
;
7633 case BUFFER_DONT_STORE
:
7636 (*message
)->raw
= malloc(length
);
7637 if (!(*message
)->raw
) {
7641 memcpy((*message
)->raw
, buffer
, length
);
7642 (*message
)->raw_length
= length
;
7645 (*message
)->raw
= (void *) buffer
;
7646 (*message
)->raw_length
= length
;
7656 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7657 isds_message_free(message
);
7660 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
7661 xmlXPathFreeObject(result
);
7662 xmlXPathFreeContext(xpath_ctx
);
7663 xmlFreeDoc(message_doc
);
7666 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Message loaded successfully.\n"));
7671 /* Download signed incoming/outgoing message identified by ID.
7672 * @context is session context
7673 * @output is true for outging message, false for incoming message
7674 * @message_id is message identifier (you can get them from
7675 * isds_get_list_of_{sent,received}_messages())
7676 * @message is automatically reallocated message retrieved from ISDS. The raw
7677 * memeber will be filled with PKCS#7 structure in DER format. */
7678 _hidden isds_error
isds_get_signed_message(struct isds_ctx
*context
,
7679 const _Bool outgoing
, const char *message_id
,
7680 struct isds_message
**message
) {
7682 isds_error err
= IE_SUCCESS
;
7683 xmlDocPtr response
= NULL
;
7684 xmlChar
*code
= NULL
, *status_message
= NULL
;
7685 xmlXPathContextPtr xpath_ctx
= NULL
;
7686 xmlXPathObjectPtr result
= NULL
;
7687 char *encoded_structure
= NULL
;
7689 size_t raw_length
= 0;
7691 if (!context
) return IE_INVALID_CONTEXT
;
7692 if (!message
) return IE_INVAL
;
7693 isds_message_free(message
);
7695 /* Do request and check for success */
7696 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7697 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7698 BAD_CAST
"SignedMessageDownload",
7699 message_id
, &response
, NULL
, NULL
, &code
, &status_message
);
7700 if (err
) goto leave
;
7702 /* Find signed message, extract it into raw and maybe free
7704 err
= find_extract_signed_data_free_response(context
,
7705 (xmlChar
*)message_id
, &response
,
7706 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7707 BAD_CAST
"SignedMessageDownload",
7709 if (err
) goto leave
;
7712 err
= isds_load_message(context
,
7713 (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7714 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
,
7715 raw
, raw_length
, message
, BUFFER_MOVE
);
7716 if (err
) goto leave
;
7722 isds_message_free(message
);
7725 free(encoded_structure
);
7726 xmlXPathFreeObject(result
);
7727 xmlXPathFreeContext(xpath_ctx
);
7731 free(status_message
);
7732 xmlFreeDoc(response
);
7735 isds_log(ILF_ISDS
, ILL_DEBUG
,
7737 _("SignedSentMessageDownload request processed by server "
7738 "successfully.\n") :
7739 _("SignedMessageDownload request processed by server "
7746 /* Download signed incoming message identified by ID.
7747 * @context is session context
7748 * @message_id is message identifier (you can get them from
7749 * isds_get_list_of_received_messages())
7750 * @message is automatically reallocated message retrieved from ISDS. The raw
7751 * memeber will be filled with PKCS#7 structure in DER format. */
7752 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
7753 const char *message_id
, struct isds_message
**message
) {
7754 return isds_get_signed_message(context
, 0, message_id
, message
);
7758 /* Download signed outgoing message identified by ID.
7759 * @context is session context
7760 * @message_id is message identifier (you can get them from
7761 * isds_get_list_of_sent_messages())
7762 * @message is automatically reallocated message retrieved from ISDS. The raw
7763 * memeber will be filled with PKCS#7 structure in DER format. */
7764 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
7765 const char *message_id
, struct isds_message
**message
) {
7766 return isds_get_signed_message(context
, 1, message_id
, message
);
7770 /* Retrieve hash of message identified by ID stored in ISDS.
7771 * @context is session context
7772 * @message_id is message identifier
7773 * @hash is automatically reallocated message hash downloaded from ISDS.
7774 * Message must exist in system and must not be deleted. */
7775 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
7776 const char *message_id
, struct isds_hash
**hash
) {
7778 isds_error err
= IE_SUCCESS
;
7779 xmlDocPtr response
= NULL
;
7780 xmlChar
*code
= NULL
, *status_message
= NULL
;
7781 xmlXPathContextPtr xpath_ctx
= NULL
;
7782 xmlXPathObjectPtr result
= NULL
;
7784 if (!context
) return IE_INVALID_CONTEXT
;
7786 isds_hash_free(hash
);
7788 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7789 BAD_CAST
"VerifyMessage", message_id
,
7790 &response
, NULL
, NULL
, &code
, &status_message
);
7791 if (err
) goto leave
;
7795 xpath_ctx
= xmlXPathNewContext(response
);
7800 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7804 result
= xmlXPathEvalExpression(
7805 BAD_CAST
"/isds:VerifyMessageResponse",
7811 /* Empty response */
7812 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7813 char *message_id_locale
= utf82locale((char*) message_id
);
7814 isds_printf_message(context
,
7815 _("Server did not return any response for ID `%s' "
7816 "on VerifyMessage request"), message_id_locale
);
7817 free(message_id_locale
);
7821 /* More responses */
7822 if (result
->nodesetval
->nodeNr
> 1) {
7823 char *message_id_locale
= utf82locale((char*) message_id
);
7824 isds_printf_message(context
,
7825 _("Server did return more responses for ID `%s' "
7826 "on VerifyMessage request"), message_id_locale
);
7827 free(message_id_locale
);
7832 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7834 /* Extract the hash */
7835 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
7839 isds_hash_free(hash
);
7842 xmlXPathFreeObject(result
);
7843 xmlXPathFreeContext(xpath_ctx
);
7846 free(status_message
);
7847 xmlFreeDoc(response
);
7850 isds_log(ILF_ISDS
, ILL_DEBUG
,
7851 _("VerifyMessage request processed by server "
7858 /* Mark message as read. This is a transactional commit function to acknoledge
7859 * to ISDS the message has been downloaded and processed by client properly.
7860 * @context is session context
7861 * @message_id is message identifier. */
7862 isds_error
isds_mark_message_read(struct isds_ctx
*context
,
7863 const char *message_id
) {
7865 isds_error err
= IE_SUCCESS
;
7866 xmlDocPtr response
= NULL
;
7867 xmlChar
*code
= NULL
, *status_message
= NULL
;
7869 if (!context
) return IE_INVALID_CONTEXT
;
7871 /* Do request and check for success */
7872 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7873 BAD_CAST
"MarkMessageAsDownloaded", message_id
,
7874 &response
, NULL
, NULL
, &code
, &status_message
);
7877 free(status_message
);
7878 xmlFreeDoc(response
);
7881 isds_log(ILF_ISDS
, ILL_DEBUG
,
7882 _("MarkMessageAsDownloaded request processed by server "
7888 /* Mark message as received by recipient. This is applicable only to
7889 * commercial message. There is no specified way how to distinguishe
7890 * commercial message from government message yet. Government message is
7891 * received automatically (by law), commenrcial message on recipient request.
7892 * @context is session context
7893 * @message_id is message identifier. */
7894 isds_error
isds_mark_message_received(struct isds_ctx
*context
,
7895 const char *message_id
) {
7897 isds_error err
= IE_SUCCESS
;
7898 xmlDocPtr response
= NULL
;
7899 xmlChar
*code
= NULL
, *status_message
= NULL
;
7901 if (!context
) return IE_INVALID_CONTEXT
;
7903 /* Do request and check for success */
7904 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7905 BAD_CAST
"ConfirmDelivery", message_id
,
7906 &response
, NULL
, NULL
, &code
, &status_message
);
7909 free(status_message
);
7910 xmlFreeDoc(response
);
7913 isds_log(ILF_ISDS
, ILL_DEBUG
,
7914 _("ConfirmDelivery request processed by server "
7921 #undef INSERT_ELEMENT
7922 #undef CHECK_FOR_STRING_LENGTH
7923 #undef INSERT_STRING_ATTRIBUTE
7924 #undef INSERT_ULONGINTNOPTR
7925 #undef INSERT_ULONGINT
7926 #undef INSERT_LONGINT
7927 #undef INSERT_BOOLEAN
7928 #undef INSERT_SCALAR_BOOLEAN
7929 #undef INSERT_STRING
7930 #undef EXTRACT_STRING_ATTRIBUTE
7931 #undef EXTRACT_ULONGINT
7932 #undef EXTRACT_LONGINT
7933 #undef EXTRACT_BOOLEAN
7934 #undef EXTRACT_STRING
7937 /* Compute hash of message from raw representation and store it into envelope.
7938 * Original hash structure will be destroyed in envelope.
7939 * @context is session context
7940 * @message is message carrying raw XML message blob
7941 * @algorithm is desired hash algorithm to use */
7942 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
7943 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
7944 isds_error err
= IE_SUCCESS
;
7946 void *xml_stream
= NULL
;
7947 size_t xml_stream_length
;
7948 size_t phys_start
, phys_end
;
7949 char *phys_path
= NULL
;
7950 struct isds_hash
*new_hash
= NULL
;
7953 if (!context
) return IE_INVALID_CONTEXT
;
7954 if (!message
) return IE_INVAL
;
7956 if (!message
->raw
) {
7957 isds_log_message(context
,
7958 _("Message does not carry raw representation"));
7962 switch (message
->raw_type
) {
7963 case RAWTYPE_INCOMING_MESSAGE
:
7965 xml_stream
= message
->raw
;
7966 xml_stream_length
= message
->raw_length
;
7969 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
7970 nsuri
= SISDS_INCOMING_NS
;
7971 xml_stream
= message
->raw
;
7972 xml_stream_length
= message
->raw_length
;
7975 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
7976 nsuri
= SISDS_INCOMING_NS
;
7977 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
7978 &xml_stream
, &xml_stream_length
);
7979 if (err
) goto leave
;
7982 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
7983 nsuri
= SISDS_OUTGOING_NS
;
7984 xml_stream
= message
->raw
;
7985 xml_stream_length
= message
->raw_length
;
7988 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7989 nsuri
= SISDS_OUTGOING_NS
;
7990 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
7991 &xml_stream
, &xml_stream_length
);
7992 if (err
) goto leave
;
7996 isds_log_message(context
, _("Bad raw representation type"));
8002 /* XXX: Hash is computed from original string represinting isds:dmDm
8003 * subtree. That means no encoding, white space, xmlns attributes changes.
8004 * In other words, input for hash can be invalid XML stream. */
8005 if (-1 == isds_asprintf(&phys_path
, "%s%s%s%s",
8006 nsuri
, PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
8007 PHYSXML_ELEMENT_SEPARATOR
,
8008 nsuri
, PHYSXML_NS_SEPARATOR
"dmReturnedMessage"
8009 PHYSXML_ELEMENT_SEPARATOR
8010 ISDS_NS PHYSXML_NS_SEPARATOR
"dmDm")) {
8014 err
= find_element_boundary(xml_stream
, xml_stream_length
,
8015 phys_path
, &phys_start
, &phys_end
);
8018 isds_log_message(context
,
8019 _("Substring with isds:dmDM element could not be located "
8026 new_hash
= calloc(1, sizeof(*new_hash
));
8031 new_hash
->algorithm
= algorithm
;
8032 err
= compute_hash(xml_stream
+ phys_start
, phys_end
- phys_start
+ 1,
8035 isds_log_message(context
, _("Could not compute message hash"));
8039 /* Save computed hash */
8040 if (!message
->envelope
) {
8041 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
8042 if (!message
->envelope
) {
8047 isds_hash_free(&message
->envelope
->hash
);
8048 message
->envelope
->hash
= new_hash
;
8052 isds_hash_free(&new_hash
);
8056 if (xml_stream
!= message
->raw
) free(xml_stream
);
8061 /* Compare two hashes.
8063 * @h2 is another hash
8065 * IE_SUCCESS if hashes equal
8066 * IE_NOTUNIQ if hashes are comparable, but they don't equal
8067 * IE_ENUM if not comparable, but both structures defined
8068 * IE_INVAL if some of the structures are undefined (NULL)
8069 * IE_ERROR if internal error occurs */
8070 isds_error
isds_hash_cmp(const struct isds_hash
*h1
, const struct isds_hash
*h2
) {
8071 if (h1
== NULL
|| h2
== NULL
) return IE_INVAL
;
8072 if (h1
->algorithm
!= h2
->algorithm
) return IE_ENUM
;
8073 if (h1
->length
!= h2
->length
) return IE_ERROR
;
8074 if (h1
->length
> 0 && !h1
->value
) return IE_ERROR
;
8075 if (h2
->length
> 0 && !h2
->value
) return IE_ERROR
;
8077 for (int i
= 0; i
< h1
->length
; i
++) {
8078 if (((uint8_t *) (h1
->value
))[i
] != ((uint8_t *) (h2
->value
))[i
])
8085 /* Check message has gone through ISDS by comparing message hash stored in
8086 * ISDS and locally computed hash. You must provide message with valid raw
8087 * member (do not use isds_load_message(..., BUFFER_DONT_STORE)).
8088 * This is convenient wrapper for isds_download_message_hash(),
8089 * isds_compute_message_hash(), and isds_hash_cmp() sequence.
8090 * @context is session context
8091 * @message is message with valid raw and envelope member; envelope->hash
8092 * member will be changed during funcion run. Use envelope on heap only.
8094 * IE_SUCCESS if message originates in ISDS
8095 * IE_NOTEQUAL if message is unknown to ISDS
8096 * other code for other errors */
8097 isds_error
isds_verify_message_hash(struct isds_ctx
*context
,
8098 struct isds_message
*message
) {
8099 isds_error err
= IE_SUCCESS
;
8100 struct isds_hash
*downloaded_hash
= NULL
;
8102 if (!context
) return IE_INVALID_CONTEXT
;
8103 if (!message
) return IE_INVAL
;
8105 if (!message
->envelope
) {
8106 isds_log_message(context
,
8107 _("Given message structure is missing envelope"));
8110 if (!message
->raw
) {
8111 isds_log_message(context
,
8112 _("Given message structure is missing raw representation"));
8116 err
= isds_download_message_hash(context
, message
->envelope
->dmID
,
8118 if (err
) goto leave
;
8120 err
= isds_compute_message_hash(context
, message
,
8121 downloaded_hash
->algorithm
);
8122 if (err
) goto leave
;
8124 err
= isds_hash_cmp(downloaded_hash
, message
->envelope
->hash
);
8127 isds_hash_free(&downloaded_hash
);
8132 /* Search for document by document ID in list of documents. IDs are compared
8134 * @documents is list of isds_documents
8135 * @id is document identifier
8136 * @return first matching document or NULL. */
8137 const struct isds_document
*isds_find_document_by_id(
8138 const struct isds_list
*documents
, const char *id
) {
8139 const struct isds_list
*item
;
8140 const struct isds_document
*document
;
8142 for (item
= documents
; item
; item
= item
->next
) {
8143 document
= (struct isds_document
*) item
->data
;
8144 if (!document
) continue;
8146 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
8154 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
8155 struct isds_message **message);
8156 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
8157 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
8158 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
8159 struct isds_address **address);
8161 int isds_message_free(struct isds_message **message);
8162 int isds_address_free(struct isds_address **address);
8166 /* Makes known all relevant namespaces to given XPath context
8167 * @xpat_ctx is XPath context
8168 * @message_ns selects propper message name space. Unsisnged and signed
8170 * prefix and to URI ISDS_NS */
8171 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
,
8172 const message_ns_type message_ns
) {
8173 const xmlChar
*message_namespace
= NULL
;
8175 if (!xpath_ctx
) return IE_ERROR
;
8177 switch(message_ns
) {
8178 case MESSAGE_NS_UNSIGNED
:
8179 message_namespace
= BAD_CAST ISDS_NS
; break;
8180 case MESSAGE_NS_SIGNED_INCOMING
:
8181 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
8182 case MESSAGE_NS_SIGNED_OUTGOING
:
8183 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
8184 case MESSAGE_NS_SIGNED_DELIVERY
:
8185 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
8190 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
8192 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
8194 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
8196 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))