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 /* Deallocate struct isds_approval recursively and NULL it */
236 void isds_approval_free(struct isds_approval
**approval
) {
237 if (!approval
|| !*approval
) return;
239 free((*approval
)->refference
);
245 /* *DUP_OR_ERROR macros needs error label */
246 #define STRDUP_OR_ERROR(new, template) { \
250 (new) = strdup(template); \
251 if (!new) goto error; \
255 #define FLATDUP_OR_ERROR(new, template) { \
259 (new) = malloc(sizeof(*(new))); \
260 if (!new) goto error; \
261 memcpy((new), (template), sizeof(*(template))); \
266 /* Copy structure isds_PersonName recursively */
267 struct isds_PersonName
*isds_PersonName_duplicate(
268 const struct isds_PersonName
*template) {
269 struct isds_PersonName
*new = NULL
;
271 if (!template) return NULL
;
273 new = calloc(1, sizeof(*new));
274 if (!new) return NULL
;
276 STRDUP_OR_ERROR(new->pnFirstName
, template->pnFirstName
);
277 STRDUP_OR_ERROR(new->pnMiddleName
, template->pnMiddleName
);
278 STRDUP_OR_ERROR(new->pnLastName
, template->pnLastName
);
279 STRDUP_OR_ERROR(new->pnLastNameAtBirth
, template->pnLastNameAtBirth
);
284 isds_PersonName_free(&new);
289 /* Copy structure isds_BirthInfo recursively */
290 static struct isds_BirthInfo
*isds_BirthInfo_duplicate(
291 const struct isds_BirthInfo
*template) {
292 struct isds_BirthInfo
*new = NULL
;
294 if (!template) return NULL
;
296 new = calloc(1, sizeof(*new));
297 if (!new) return NULL
;
299 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
300 STRDUP_OR_ERROR(new->biCity
, template->biCity
);
301 STRDUP_OR_ERROR(new->biCounty
, template->biCounty
);
302 STRDUP_OR_ERROR(new->biState
, template->biState
);
307 isds_BirthInfo_free(&new);
312 /* Copy structure isds_Address recursively */
313 struct isds_Address
*isds_Address_duplicate(
314 const struct isds_Address
*template) {
315 struct isds_Address
*new = NULL
;
317 if (!template) return NULL
;
319 new = calloc(1, sizeof(*new));
320 if (!new) return NULL
;
322 STRDUP_OR_ERROR(new->adCity
, template->adCity
);
323 STRDUP_OR_ERROR(new->adStreet
, template->adStreet
);
324 STRDUP_OR_ERROR(new->adNumberInStreet
, template->adNumberInStreet
);
325 STRDUP_OR_ERROR(new->adNumberInMunicipality
,
326 template->adNumberInMunicipality
);
327 STRDUP_OR_ERROR(new->adZipCode
, template->adZipCode
);
328 STRDUP_OR_ERROR(new->adState
, template->adState
);
333 isds_Address_free(&new);
338 /* Copy structure isds_DbOwnerInfo recursively */
339 struct isds_DbOwnerInfo
*isds_DbOwnerInfo_duplicate(
340 const struct isds_DbOwnerInfo
*template) {
341 struct isds_DbOwnerInfo
*new = NULL
;
342 if (!template) return NULL
;
344 new = calloc(1, sizeof(*new));
345 if (!new) return NULL
;
347 STRDUP_OR_ERROR(new->dbID
, template->dbID
);
348 FLATDUP_OR_ERROR(new->dbType
, template->dbType
);
349 STRDUP_OR_ERROR(new->ic
, template->ic
);
351 if (template->personName
) {
352 if (!(new->personName
=
353 isds_PersonName_duplicate(template->personName
)))
357 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
359 if (template->birthInfo
) {
360 if (!(new->birthInfo
=
361 isds_BirthInfo_duplicate(template->birthInfo
)))
365 if (template->address
) {
366 if (!(new->address
= isds_Address_duplicate(template->address
)))
370 STRDUP_OR_ERROR(new->nationality
, template->nationality
);
371 STRDUP_OR_ERROR(new->email
, template->email
);
372 STRDUP_OR_ERROR(new->telNumber
, template->telNumber
);
373 STRDUP_OR_ERROR(new->identifier
, template->identifier
);
374 STRDUP_OR_ERROR(new->registryCode
, template->registryCode
);
375 FLATDUP_OR_ERROR(new->dbState
, template->dbState
);
376 FLATDUP_OR_ERROR(new->dbEffectiveOVM
, template->dbEffectiveOVM
);
377 FLATDUP_OR_ERROR(new->dbOpenAddressing
, template->dbOpenAddressing
);
382 isds_DbOwnerInfo_free(&new);
387 /* Copy structure isds_DbUserInfo recursively */
388 struct isds_DbUserInfo
*isds_DbUserInfo_duplicate(
389 const struct isds_DbUserInfo
*template) {
390 struct isds_DbUserInfo
*new = NULL
;
391 if (!template) return NULL
;
393 new = calloc(1, sizeof(*new));
394 if (!new) return NULL
;
396 STRDUP_OR_ERROR(new->userID
, template->userID
);
397 FLATDUP_OR_ERROR(new->userType
, template->userType
);
398 FLATDUP_OR_ERROR(new->userPrivils
, template->userPrivils
);
400 if (template->personName
) {
401 if (!(new->personName
=
402 isds_PersonName_duplicate(template->personName
)))
406 if (template->address
) {
407 if (!(new->address
= isds_Address_duplicate(template->address
)))
411 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
412 STRDUP_OR_ERROR(new->ic
, template->ic
);
413 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
414 STRDUP_OR_ERROR(new->caStreet
, template->caStreet
);
415 STRDUP_OR_ERROR(new->caCity
, template->caCity
);
416 STRDUP_OR_ERROR(new->caZipCode
, template->caZipCode
);
421 isds_DbUserInfo_free(&new);
425 #undef FLATDUP_OR_ERROR
426 #undef STRDUP_OR_ERROR
429 /* Initialize ISDS library.
430 * Global function, must be called before other functions.
431 * If it failes you can not use ISDS library and must call isds_cleanup() to
432 * free partially inititialized global variables. */
433 isds_error
isds_init(void) {
434 /* NULL global variables */
435 log_facilities
= ILF_ALL
;
436 log_level
= ILL_WARNING
;
439 /* Initialize gettext */
440 bindtextdomain(PACKAGE
, LOCALEDIR
);
443 /* Initialize CURL */
444 if (curl_global_init(CURL_GLOBAL_ALL
)) {
445 isds_log(ILF_ISDS
, ILL_CRIT
, _("CURL library initialization failed\n"));
449 /* Inicialize gpg-error because of gpgme and ksba */
450 if (gpg_err_init()) {
451 isds_log(ILF_ISDS
, ILL_CRIT
,
452 _("gpg-error library initialization failed\n"));
456 /* Initialize GPGME */
458 isds_log(ILF_ISDS
, ILL_CRIT
,
459 _("GPGME library initialization failed\n"));
463 /* Initialize gcrypt */
465 isds_log(ILF_ISDS
, ILL_CRIT
,
466 _("gcrypt library initialization failed\n"));
470 /* This can _exit() current program. Find not so assertive check. */
475 isds_log(ILF_ISDS
, ILL_CRIT
,
476 _("expat library initialization failed\n"));
480 /* Allocate global variables */
487 /* Deinicialize ISDS library.
488 * Global function, must be called as last library function. */
489 isds_error
isds_cleanup(void) {
494 curl_global_cleanup();
500 /* Return text description of ISDS error */
501 const char *isds_strerror(const isds_error error
) {
504 return(_("Success")); break;
506 return(_("Unspecified error")); break;
508 return(_("Not supported")); break;
510 return(_("Invalid value")); break;
511 case IE_INVALID_CONTEXT
:
512 return(_("Invalid context")); break;
513 case IE_NOT_LOGGED_IN
:
514 return(_("Not logged in")); break;
515 case IE_CONNECTION_CLOSED
:
516 return(_("Connection closed")); break;
518 return(_("Timed out")); break;
520 return(_("Not exist")); break;
522 return(_("Out of memory")); break;
524 return(_("Network problem")); break;
526 return(_("HTTP problem")); break;
528 return(_("SOAP problem")); break;
530 return(_("XML problem")); break;
532 return(_("ISDS server problem")); break;
534 return(_("Invalid enum value")); break;
536 return(_("Invalid date value")); break;
538 return(_("Too big")); break;
540 return(_("Too small")); break;
542 return(_("Value not unique")); break;
544 return(_("Values not uqual")); break;
545 case IE_PARTIAL_SUCCESS
:
546 return(_("Some suboperations failed")); break;
548 return(_("Unknown error"));
553 /* Create ISDS context.
554 * Each context can be used for different sessions to (possibly) differnet
555 * ISDS server with different credentials. */
556 struct isds_ctx
*isds_ctx_create(void) {
557 struct isds_ctx
*context
;
558 context
= malloc(sizeof(*context
));
559 if (context
) memset(context
, 0, sizeof(*context
));
564 /* Destroy ISDS context and free memmory.
565 * @context will be NULLed on success. */
566 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
567 if (!context
|| !*context
) {
568 return IE_INVALID_CONTEXT
;
571 /* Discard credentials */
572 isds_logout(*context
);
574 /* Free other structures */
575 free((*context
)->tls_verify_server
);
576 free((*context
)->tls_ca_file
);
577 free((*context
)->tls_ca_dir
);
578 free((*context
)->long_message
);
586 /* Return long message text produced by library fucntion, e.g. detailed error
587 * mesage. Returned pointer is only valid until new library function is
588 * called for the same context. Could be NULL, especially if NULL context is
589 * supplied. Return string is locale encoded. */
590 char *isds_long_message(const struct isds_ctx
*context
) {
591 if (!context
) return NULL
;
592 return context
->long_message
;
596 /* Stores message into context' long_message buffer.
597 * Application can pick the message up using isds_long_message().
598 * NULL @message truncates the buffer but does not deallocate it.
599 * @message is coded in locale encoding */
600 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
601 const char *message
) {
605 if (!context
) return IE_INVALID_CONTEXT
;
607 /* FIXME: Check for integer overflow */
608 length
= 1 + ((message
) ? strlen(message
) : 0);
609 buffer
= realloc(context
->long_message
, length
);
610 if (!buffer
) return IE_NOMEM
;
613 strcpy(buffer
, message
);
617 context
->long_message
= buffer
;
622 /* Appends message into context' long_message buffer.
623 * Application can pick the message up using isds_long_message().
624 * NULL message has void effect. */
625 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
626 const char *message
) {
628 size_t old_length
, length
;
630 if (!context
) return IE_INVALID_CONTEXT
;
631 if (!message
) return IE_SUCCESS
;
632 if (!context
->long_message
)
633 return isds_log_message(context
, message
);
635 old_length
= strlen(context
->long_message
);
636 /* FIXME: Check for integer overflow */
637 length
= 1 + old_length
+ strlen(message
);
638 buffer
= realloc(context
->long_message
, length
);
639 if (!buffer
) return IE_NOMEM
;
641 strcpy(buffer
+ old_length
, message
);
643 context
->long_message
= buffer
;
648 /* Stores formated message into context' long_message buffer.
649 * Application can pick the message up using isds_long_message(). */
650 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
651 const char *format
, ...) {
655 if (!context
) return IE_INVALID_CONTEXT
;
656 va_start(ap
, format
);
657 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
660 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
665 * @facilities is bitmask of isds_log_facility values,
666 * @level is verbosity level. */
667 void isds_set_logging(const unsigned int facilities
,
668 const isds_log_level level
) {
669 log_facilities
= facilities
;
674 /* Log @message in class @facility with log @level into global log. @message
675 * is printf(3) formating string, variadic arguments may be neccessary.
676 * For debugging purposes. */
677 _hidden isds_error
isds_log(const isds_log_facility facility
,
678 const isds_log_level level
, const char *message
, ...) {
681 if (level
> log_level
) return IE_SUCCESS
;
682 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
683 if (!message
) return IE_INVAL
;
685 /* TODO: Allow to register output function provided by application
686 * (e.g. fprintf to stderr or copy to text area GUI widget). */
688 va_start(ap
, message
);
689 vfprintf(stderr
, message
, ap
);
691 /* Line buffered printf is default.
698 /* Set timeout in miliseconds for each network job like connecting to server
699 * or sending message. Use 0 to disable timeout limits. */
700 isds_error
isds_set_timeout(struct isds_ctx
*context
,
701 const unsigned int timeout
) {
702 if (!context
) return IE_INVALID_CONTEXT
;
704 context
->timeout
= timeout
;
709 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
711 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
713 if (curl_err
) return IE_ERROR
;
720 /* Register callback function libisds calls periodocally during HTTP data
722 * @context is session context
723 * @callback is function provided by application libsds will call. See type
724 * defition for @callback argument explanation.
725 * @data is application specific data @callback gets as last argument */
726 isds_error
isds_set_progress_callback(struct isds_ctx
*context
,
727 isds_progress_callback callback
, void *data
) {
728 if (!context
) return IE_INVALID_CONTEXT
;
730 context
->progress_callback
= callback
;
731 context
->progress_callback_data
= data
;
737 /* Change SSL/TLS settings.
738 * @context is context which setting will be applied to
739 * @option is name of option. It determines the type of last argument. See
740 * isds_tls_option definition for more info.
741 * @... is value of new setting. Type is determined by @option
743 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
745 isds_error err
= IE_SUCCESS
;
747 char *pointer
, *string
;
749 if (!context
) return IE_INVALID_CONTEXT
;
751 va_start(ap
, option
);
753 #define REPLACE_VA_STRING(destination) \
754 string = va_arg(ap, char *); \
756 pointer = realloc((destination), 1 + strlen(string)); \
757 if (!pointer) { err = IE_NOMEM; goto leave; } \
758 strcpy(pointer, string); \
759 (destination) = pointer; \
762 (destination) = NULL; \
766 case ITLS_VERIFY_SERVER
:
767 if (!context
->tls_verify_server
) {
768 context
->tls_verify_server
=
769 malloc(sizeof(*context
->tls_verify_server
));
770 if (!context
->tls_verify_server
) {
771 err
= IE_NOMEM
; goto leave
;
774 *context
->tls_verify_server
= (_Bool
) (0 != va_arg(ap
, int));
778 REPLACE_VA_STRING(context
->tls_ca_file
);
780 case ITLS_CA_DIRECTORY
:
781 REPLACE_VA_STRING(context
->tls_ca_dir
);
785 err
= IE_ENUM
; goto leave
;
788 #undef REPLACE_VA_STRING
796 /* Discard credentials.
797 * Only that. It does not cause log out, connection close or similar. */
798 static isds_error
discard_credentials(struct isds_ctx
*context
) {
799 if(!context
) return IE_INVALID_CONTEXT
;
801 if (context
->username
) {
802 memset(context
->username
, 0, strlen(context
->username
));
803 free(context
->username
);
804 context
->username
= NULL
;
806 if (context
->password
) {
807 memset(context
->password
, 0, strlen(context
->password
));
808 free(context
->password
);
809 context
->password
= NULL
;
816 /* Connect and log in into ISDS server.
817 * @url is address of ISDS web service
818 * @username is user name of ISDS user
819 * @password is user's secret password
820 * @certificate is NULL terminated string with PEM formated client's
821 * certificate. Use NULL if only password autentication should be performed.
822 * @key is private key for client's certificate as (base64 encoded?) NULL
823 * terminated string. Use NULL if only password autentication is desired.
825 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
826 const char *username
, const char *password
,
827 const char *certificate
, const char* key
) {
828 isds_error err
= IE_NOT_LOGGED_IN
;
830 xmlNsPtr isds_ns
= NULL
;
831 xmlNodePtr request
= NULL
;
832 xmlNodePtr response
= NULL
;
834 if (!context
) return IE_INVALID_CONTEXT
;
835 if (!url
|| !username
|| !password
) return IE_INVAL
;
836 if (certificate
|| key
) return IE_NOTSUP
;
838 /* Store configuration */
840 context
->url
= strdup(url
);
844 /* Close connection if already logged in */
846 close_connection(context
);
849 /* Prepare CURL handle */
850 context
->curl
= curl_easy_init();
851 if (!(context
->curl
))
854 /* Build login request */
855 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
857 isds_log_message(context
, _("Could build ISDS login request"));
860 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
862 isds_log_message(context
, _("Could not create ISDS name space"));
863 xmlFreeNode(request
);
866 xmlSetNs(request
, isds_ns
);
868 /* Store credentials */
869 /* FIXME: mlock password
870 * (I have a library) */
871 discard_credentials(context
);
872 context
->username
= strdup(username
);
873 context
->password
= strdup(password
);
874 if (!(context
->username
&& context
->password
)) {
875 discard_credentials(context
);
876 xmlFreeNode(request
);
880 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
883 /* Send login request */
884 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
886 /* Remove credentials */
887 discard_credentials(context
);
889 /* Destroy login request */
890 xmlFreeNode(request
);
893 xmlFreeNodeList(response
);
894 close_connection(context
);
898 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
899 * authentication succeeded if soap_err == IE_SUCCESS */
902 xmlFreeNodeList(response
);
905 isds_log(ILF_ISDS
, ILL_DEBUG
,
906 _("User %s has been logged into server %s successfully\n"),
912 /* Log out from ISDS server discards credentials and connection configuration. */
913 isds_error
isds_logout(struct isds_ctx
*context
) {
914 if (!context
) return IE_INVALID_CONTEXT
;
916 /* Close connection */
918 close_connection(context
);
920 /* Discard credentials for sure. They should not survive isds_login(),
921 * even successful .*/
922 discard_credentials(context
);
926 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
928 discard_credentials(context
);
934 /* Verify connection to ISDS is alive and server is responding.
935 * Sent dumy request to ISDS and expect dummy response. */
936 isds_error
isds_ping(struct isds_ctx
*context
) {
938 xmlNsPtr isds_ns
= NULL
;
939 xmlNodePtr request
= NULL
;
940 xmlNodePtr response
= NULL
;
942 if (!context
) return IE_INVALID_CONTEXT
;
944 /* Check if connection is established */
945 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
948 /* Build dummy request */
949 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
951 isds_log_message(context
, _("Could build ISDS dummy request"));
954 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
956 isds_log_message(context
, _("Could not create ISDS name space"));
957 xmlFreeNode(request
);
960 xmlSetNs(request
, isds_ns
);
962 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
964 /* Sent dummy request */
965 soap_err
= soap(context
, "dz", request
, &response
, NULL
, NULL
);
967 /* Destroy login request */
968 xmlFreeNode(request
);
971 isds_log(ILF_ISDS
, ILL_DEBUG
,
972 _("ISDS server could not be contacted\n"));
973 xmlFreeNodeList(response
);
974 close_connection(context
);
978 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
979 * authentication succeeded if soap_err == IE_SUCCESS */
980 /* TODO: ISDS documentation does not specify response body.
981 * However real server sends back DummyOperationResponse */
984 xmlFreeNodeList(response
);
986 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
992 /* Send bogus request to ISDS.
993 * Just for test purposes */
994 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
996 xmlNsPtr isds_ns
= NULL
;
997 xmlNodePtr request
= NULL
;
998 xmlDocPtr response
= NULL
;
999 xmlChar
*code
= NULL
, *message
= NULL
;
1001 if (!context
) return IE_INVALID_CONTEXT
;
1003 /* Check if connection is established */
1004 if (!context
->curl
) {
1005 /* Testing printf message */
1006 isds_printf_message(context
, "%s", _("I said connection closed"));
1007 return IE_CONNECTION_CLOSED
;
1011 /* Build dummy request */
1012 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
1014 isds_log_message(context
, _("Could build ISDS bogus request"));
1017 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1019 isds_log_message(context
, _("Could not create ISDS name space"));
1020 xmlFreeNode(request
);
1023 xmlSetNs(request
, isds_ns
);
1025 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
1027 /* Sent bogus request */
1028 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
1030 /* Destroy request */
1031 xmlFreeNode(request
);
1034 isds_log(ILF_ISDS
, ILL_DEBUG
,
1035 _("Processing ISDS response on bogus request failed\n"));
1036 xmlFreeDoc(response
);
1040 /* Check for response status */
1041 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
1042 &code
, &message
, NULL
);
1044 isds_log(ILF_ISDS
, ILL_DEBUG
,
1045 _("ISDS response on bogus request is missing status\n"));
1048 xmlFreeDoc(response
);
1051 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
1052 char *code_locale
= utf82locale((char*)code
);
1053 char *message_locale
= utf82locale((char*)message
);
1054 isds_log(ILF_ISDS
, ILL_DEBUG
,
1055 _("Server refused bogus request (code=%s, message=%s)\n"),
1056 code_locale
, message_locale
);
1057 /* XXX: Literal error messages from ISDS are Czech mesages
1058 * (English sometimes) in UTF-8. It's hard to catch them for
1059 * translation. Successfully gettextized would return in locale
1060 * encoding, unsuccessfully translated would pass in UTF-8. */
1061 isds_log_message(context
, message_locale
);
1063 free(message_locale
);
1066 xmlFreeDoc(response
);
1073 xmlFreeDoc(response
);
1075 isds_log(ILF_ISDS
, ILL_DEBUG
,
1076 _("Bogus message accepted by server. This should not happen.\n"));
1082 /* Serialize XML subtree to buffer preserving XML indentatition.
1083 * @context is session context
1084 * @subtree is XML element to be serialized (with childern)
1085 * @buffer is automatically reallocated buffer where serialize to
1086 * @length is size of serialized stream in bytes
1087 * @return standard error code, free @buffer in case of error */
1088 static isds_error
serialize_subtree(struct isds_ctx
*context
,
1089 xmlNodePtr subtree
, void **buffer
, size_t *length
) {
1090 isds_error err
= IE_SUCCESS
;
1091 xmlBufferPtr xml_buffer
= NULL
;
1092 xmlSaveCtxtPtr save_ctx
= NULL
;
1093 xmlDocPtr subtree_doc
= NULL
;
1094 xmlNodePtr subtree_copy
;
1098 if (!context
) return IE_INVALID_CONTEXT
;
1099 if (!buffer
) return IE_INVAL
;
1101 if (!subtree
|| !length
) return IE_INVAL
;
1103 /* Make temporary XML document with @subtree root element */
1104 /* XXX: We can not use xmlNodeDump() because it dumps the subtree as is.
1105 * It can result in not well-formed on invalid XML tree (e.g. name space
1106 * prefix definition can miss. */
1109 subtree_doc
= xmlNewDoc(BAD_CAST
"1.0");
1111 isds_log_message(context
, _("Could not build temporary document"));
1116 /* XXX: Copy subtree and attach the copy to document.
1117 * One node can not bee attached into more document at the same time.
1118 * XXX: Check xmlDOMWrapRemoveNode(). It could solve NS references
1120 * XXX: Check xmlSaveTree() too. */
1121 subtree_copy
= xmlCopyNodeList(subtree
);
1122 if (!subtree_copy
) {
1123 isds_log_message(context
, _("Could not copy subtree"));
1127 xmlDocSetRootElement(subtree_doc
, subtree_copy
);
1129 /* Only this way we get namespace definition as @xmlns:isds,
1130 * otherwise we get namespace prefix without definition */
1131 /* FIXME: Don't overwrite original default namespace */
1132 isds_ns
= xmlNewNs(subtree_copy
, BAD_CAST ISDS_NS
, NULL
);
1134 isds_log_message(context
, _("Could not create ISDS name space"));
1138 xmlSetNs(subtree_copy
, isds_ns
);
1141 /* Serialize the document into buffer */
1142 xml_buffer
= xmlBufferCreate();
1144 isds_log_message(context
, _("Could not create xmlBuffer"));
1148 /* Last argument 0 means to not format the XML tree */
1149 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8", 0);
1151 isds_log_message(context
, _("Could not create XML serializer"));
1155 /* XXX: According LibXML documentation, this function does not return
1156 * meaningfull value yet */
1157 xmlSaveDoc(save_ctx
, subtree_doc
);
1158 if (-1 == xmlSaveFlush(save_ctx
)) {
1159 isds_log_message(context
,
1160 _("Could not serialize XML subtree"));
1164 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1165 * even after xmlSaveFlush(). Thus close it here */
1166 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1169 /* Store and detach buffer from xml_buffer */
1170 *buffer
= xml_buffer
->content
;
1171 *length
= xml_buffer
->use
;
1172 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1175 new_buffer
= realloc(*buffer
, *length
);
1176 if (new_buffer
) *buffer
= new_buffer
;
1184 xmlSaveClose(save_ctx
);
1185 xmlBufferFree(xml_buffer
);
1186 xmlFreeDoc(subtree_doc
); /* Frees subtree_copy, isds_ns etc. */
1191 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1192 * @context is session context
1193 * @document is original document where @nodeset points to
1194 * @nodeset is XPath node set to dump (recursively)
1195 * @buffer is automarically reallocated buffer where serialize to
1196 * @length is size of serialized stream in bytes
1197 * @return standard error code, free @buffer in case of error */
1198 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1199 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1200 void **buffer
, size_t *length
) {
1201 isds_error err
= IE_SUCCESS
;
1202 xmlBufferPtr xml_buffer
= NULL
;
1205 if (!context
) return IE_INVALID_CONTEXT
;
1206 if (!buffer
) return IE_INVAL
;
1208 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1211 /* Empty node set results into NULL buffer */
1212 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1216 /* Resuling the document into buffer */
1217 xml_buffer
= xmlBufferCreate();
1219 isds_log_message(context
, _("Could not create xmlBuffer"));
1224 /* Itearate over all nodes */
1225 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1227 * XXX: xmlNodeDump() appends to xml_buffer. */
1229 xmlNodeDump(xml_buffer
, document
, nodeset
->nodeTab
[i
], 0, 0)) {
1230 isds_log_message(context
, _("Could not dump XML node"));
1236 /* Store and detach buffer from xml_buffer */
1237 *buffer
= xml_buffer
->content
;
1238 *length
= xml_buffer
->use
;
1239 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1242 new_buffer
= realloc(*buffer
, *length
);
1243 if (new_buffer
) *buffer
= new_buffer
;
1252 xmlBufferFree(xml_buffer
);
1258 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1259 * @context is session context
1260 * @document is original document where @nodeset points to
1261 * @nodeset is XPath node set to dump (recursively)
1262 * @buffer is automarically reallocated buffer where serialize to
1263 * @length is size of serialized stream in bytes
1264 * @return standard error code, free @buffer in case of error */
1265 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1266 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1267 void **buffer
, size_t *length
) {
1268 isds_error err
= IE_SUCCESS
;
1269 xmlBufferPtr xml_buffer
= NULL
;
1270 xmlSaveCtxtPtr save_ctx
= NULL
;
1273 if (!context
) return IE_INVALID_CONTEXT
;
1274 if (!buffer
) return IE_INVAL
;
1276 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1279 /* Empty node set results into NULL buffer */
1280 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1284 /* Resuling the document into buffer */
1285 xml_buffer
= xmlBufferCreate();
1287 isds_log_message(context
, _("Could not create xmlBuffer"));
1291 if (xmlSubstituteEntitiesDefault(1)) {
1292 isds_log_message(context
, _("Could not disable attribute escaping"));
1296 /* Last argument means:
1297 * 0 to not format the XML tree
1298 * XML_SAVE_NO_EMPTY ISDS does not produce shorten tags */
1299 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8",
1300 XML_SAVE_NO_DECL
|XML_SAVE_NO_EMPTY
|XML_SAVE_NO_XHTML
);
1302 isds_log_message(context
, _("Could not create XML serializer"));
1306 /*if (xmlSaveSetAttrEscape(save_ctx, NULL)) {
1307 isds_log_message(context, _("Could not disable attribute escaping"));
1313 /* Itearate over all nodes */
1314 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1316 * XXX: xmlNodeDump() appends to xml_buffer. */
1318 xmlNodeDump(xml_buffer, document, nodeset->nodeTab[i], 0, 0)) {
1320 /* XXX: According LibXML documentation, this function does not return
1321 * meaningfull value yet */
1322 xmlSaveTree(save_ctx
, nodeset
->nodeTab
[i
]);
1323 if (-1 == xmlSaveFlush(save_ctx
)) {
1324 isds_log_message(context
,
1325 _("Could not serialize XML subtree"));
1331 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1332 * even after xmlSaveFlush(). Thus close it here */
1333 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1335 /* Store and detach buffer from xml_buffer */
1336 *buffer
= xml_buffer
->content
;
1337 *length
= xml_buffer
->use
;
1338 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1341 new_buffer
= realloc(*buffer
, *length
);
1342 if (new_buffer
) *buffer
= new_buffer
;
1350 xmlSaveClose(save_ctx
);
1351 xmlBufferFree(xml_buffer
);
1357 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
1358 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
1359 if (!string
|| !type
) return IE_INVAL
;
1361 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
1363 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
1365 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
1366 *type
= DBTYPE_PFO_ADVOK
;
1367 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
1368 *type
= DBTYPE_PFO_DANPOR
;
1369 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
1370 *type
= DBTYPE_PFO_INSSPR
;
1371 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
1373 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
1374 *type
= DBTYPE_PO_ZAK
;
1375 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
1376 *type
= DBTYPE_PO_REQ
;
1377 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
1379 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
1380 *type
= DBTYPE_OVM_NOTAR
;
1381 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
1382 *type
= DBTYPE_OVM_EXEKUT
;
1383 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
1384 *type
= DBTYPE_OVM_REQ
;
1391 /* Convert ISDS dbType enum @type to UTF-8 string.
1392 * @Return pointer to static string, or NULL if unkwnow enum value */
1393 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
1395 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
1396 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
1397 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
1398 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DANPOR"); break;
1399 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
1400 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
1401 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
1402 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
1403 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
1404 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
1405 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
1406 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
1407 default: return NULL
; break;
1412 /* Convert UTF-8 @string represantion of ISDS userType to enum @type */
1413 static isds_error
string2isds_UserType(xmlChar
*string
, isds_UserType
*type
) {
1414 if (!string
|| !type
) return IE_INVAL
;
1416 if (!xmlStrcmp(string
, BAD_CAST
"PRIMARY_USER"))
1417 *type
= USERTYPE_PRIMARY
;
1418 else if (!xmlStrcmp(string
, BAD_CAST
"ENTRUSTED_USER"))
1419 *type
= USERTYPE_ENTRUSTED
;
1420 else if (!xmlStrcmp(string
, BAD_CAST
"ADMINISTRATOR"))
1421 *type
= USERTYPE_ADMINISTRATOR
;
1422 else if (!xmlStrcmp(string
, BAD_CAST
"OFFICIAL"))
1423 *type
= USERTYPE_OFFICIAL
;
1430 /* Convert ISDS userType enum @type to UTF-8 string.
1431 * @Return pointer to static string, or NULL if unkwnow enum value */
1432 static const xmlChar
*isds_UserType2string(const isds_UserType type
) {
1434 case USERTYPE_PRIMARY
: return(BAD_CAST
"PRIMARY_USER"); break;
1435 case USERTYPE_ENTRUSTED
: return(BAD_CAST
"ENTRUSTED_USER"); break;
1436 case USERTYPE_ADMINISTRATOR
: return(BAD_CAST
"ADMINISTRATOR"); break;
1437 case USERTYPE_OFFICIAL
: return(BAD_CAST
"OFFICIAL"); break;
1438 default: return NULL
; break;
1443 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
1444 * @Return pointer to static string, or NULL if unkwnow enum value */
1445 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
1447 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
1448 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
1449 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
1450 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
1451 default: return NULL
; break;
1456 /* Convert UTF-8 @string to ISDS dmFileMetaType enum @type.
1457 * @Return IE_ENUM if @string is not valid enum member */
1458 static isds_error
string2isds_FileMetaType(const xmlChar
*string
,
1459 isds_FileMetaType
*type
) {
1460 if (!string
|| !type
) return IE_INVAL
;
1462 if (!xmlStrcmp(string
, BAD_CAST
"main"))
1463 *type
= FILEMETATYPE_MAIN
;
1464 else if (!xmlStrcmp(string
, BAD_CAST
"enclosure"))
1465 *type
= FILEMETATYPE_ENCLOSURE
;
1466 else if (!xmlStrcmp(string
, BAD_CAST
"signature"))
1467 *type
= FILEMETATYPE_SIGNATURE
;
1468 else if (!xmlStrcmp(string
, BAD_CAST
"meta"))
1469 *type
= FILEMETATYPE_META
;
1476 /* Convert UTF-8 @string to ISDS hash @algorithm.
1477 * @Return IE_ENUM if @string is not valid enum member */
1478 static isds_error
string2isds_hash_algorithm(const xmlChar
*string
,
1479 isds_hash_algorithm
*algorithm
) {
1480 if (!string
|| !algorithm
) return IE_INVAL
;
1482 if (!xmlStrcmp(string
, BAD_CAST
"MD5"))
1483 *algorithm
= HASH_ALGORITHM_MD5
;
1484 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-1"))
1485 *algorithm
= HASH_ALGORITHM_SHA_1
;
1486 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-224"))
1487 *algorithm
= HASH_ALGORITHM_SHA_224
;
1488 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-256"))
1489 *algorithm
= HASH_ALGORITHM_SHA_256
;
1490 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-384"))
1491 *algorithm
= HASH_ALGORITHM_SHA_384
;
1492 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-512"))
1493 *algorithm
= HASH_ALGORITHM_SHA_512
;
1500 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
1501 * XXX: Not all ISO formats are supported */
1502 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
1504 if (!string
|| !time
) return IE_INVAL
;
1506 /* xsd:date is ISO 8601 string, thus ASCII */
1507 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
1508 if (offset
&& *offset
== '\0')
1511 offset
= strptime((char*)string
, "%Y%m%d", time
);
1512 if (offset
&& *offset
== '\0')
1515 offset
= strptime((char*)string
, "%Y-%j", time
);
1516 if (offset
&& *offset
== '\0')
1523 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
1524 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
1525 if (!time
|| !string
) return IE_INVAL
;
1527 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
1528 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
1535 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
1536 * respects the @time microseconds too. */
1537 static isds_error
timeval2timestring(const struct timeval
*time
,
1541 if (!time
|| !string
) return IE_INVAL
;
1543 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
1544 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
1546 /* TODO: small negative year should be formated as "-0012". This is not
1547 * true for glibc "%04d". We should implement it.
1548 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
1549 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
1550 if (-1 == isds_asprintf((char **) string
,
1551 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
1552 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
1553 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
1561 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
1562 * It respects microseconds too.
1563 * In case of error, @time will be freed. */
1564 static isds_error
timestring2timeval(const xmlChar
*string
,
1565 struct timeval
**time
) {
1567 char *offset
, *delim
, *endptr
;
1569 int offset_hours
, offset_minutes
;
1572 if (!time
) return IE_INVAL
;
1574 memset(&broken
, 0, sizeof(broken
));
1577 *time
= calloc(1, sizeof(**time
));
1578 if (!*time
) return IE_NOMEM
;
1580 memset(*time
, 0, sizeof(**time
));
1584 /* xsd:date is ISO 8601 string, thus ASCII */
1585 /*TODO: negative year */
1587 /* Parse date and time without subseconds and offset */
1588 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
1590 free(*time
); *time
= NULL
;
1594 /* Get subseconds */
1595 if (*offset
== '.' ) {
1598 /* Copy first 6 digits, padd it with zeros.
1599 * XXX: It truncates longer number, no round.
1600 * Current server implementation uses only milisecond resolution. */
1601 /* TODO: isdigit() is locale sensitive */
1603 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
1605 subseconds
[i
] = *offset
;
1607 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
1608 subseconds
[i
] = '0';
1610 subseconds
[6] = '\0';
1612 /* Convert it into integer */
1613 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
1614 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
1615 (*time
)->tv_usec
== LONG_MAX
) {
1616 free(*time
); *time
= NULL
;
1620 /* move to the zone offset delimiter */
1621 delim
= strchr(offset
, '-');
1623 delim
= strchr(offset
, '+');
1627 /* Get zone offset */
1628 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
1629 * "" equals to "Z" and it means UTC zone. */
1630 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
1631 * colon separator */
1632 if (*offset
== '-' || *offset
== '+') {
1634 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
1635 free(*time
); *time
= NULL
;
1638 broken
.tm_hour
-= offset_hours
;
1639 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
1642 /* Convert to time_t */
1644 (*time
)->tv_sec
= mktime(&broken
);
1645 switch_tz_to_native();
1646 if ((*time
)->tv_sec
== (time_t) -1) {
1647 free(*time
); *time
= NULL
;
1655 /* Convert unsigned int into isds_message_status.
1656 * @context is session context
1657 * @number is pointer to number value. NULL will be treated as invalid value.
1658 * @status is automatically reallocated status
1659 * @return IE_SUCCESS, or error code and free status */
1660 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1661 const unsigned long int *number
, isds_message_status
**status
) {
1662 if (!context
) return IE_INVALID_CONTEXT
;
1663 if (!status
) return IE_INVAL
;
1665 free(*status
); *status
= NULL
;
1666 if (!number
) return IE_INVAL
;
1668 if (*number
< 1 || *number
> 10) {
1669 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1674 *status
= malloc(sizeof(**status
));
1675 if (!*status
) return IE_NOMEM
;
1677 **status
= 1 << *number
;
1682 /* Convert event description string into isds_event memebers type and
1684 * @string is raw event decsription starting with event prefix
1685 * @event is structure where to store type and stripped description to
1686 * @return standard error code, unkown prefix is not classified as an error. */
1687 static isds_error
eventstring2event(const xmlChar
*string
,
1688 struct isds_event
* event
) {
1689 const xmlChar
*known_prefixes
[] = {
1695 const isds_event_type types
[] = {
1696 EVENT_ACCEPTED_BY_RECIPIENT
,
1697 EVENT_ACCEPTED_BY_FICTION
,
1698 EVENT_UNDELIVERABLE
,
1699 EVENT_COMMERCIAL_ACCEPTED
1704 if (!string
|| !event
) return IE_INVAL
;
1707 event
->type
= malloc(sizeof(*event
->type
));
1708 if (!(event
->type
)) return IE_NOMEM
;
1710 zfree(event
->description
);
1712 for (index
= 0; index
< sizeof(known_prefixes
)/sizeof(known_prefixes
[0]);
1714 length
= xmlUTF8Strlen(known_prefixes
[index
]);
1716 if (!xmlStrncmp(string
, known_prefixes
[index
], length
)) {
1717 /* Prefix is known */
1718 *event
->type
= types
[index
];
1720 /* Strip prefix from description and spaces */
1721 /* TODO: Recognize all wite spaces from UCS blank class and
1722 * operate on UTF-8 chars. */
1723 for (; string
[length
] != '\0' && string
[length
] == ' '; length
++);
1724 event
->description
= strdup((char *) (string
+ length
));
1725 if (!(event
->description
)) return IE_NOMEM
;
1731 /* Unknown event prefix.
1732 * XSD allows any string */
1733 char *string_locale
= utf82locale((char *) string
);
1734 isds_log(ILF_ISDS
, ILL_WARNING
,
1735 _("Uknown delivery info event prefix: %s\n"), string_locale
);
1736 free(string_locale
);
1738 *event
->type
= EVENT_UKNOWN
;
1739 event
->description
= strdup((char *) string
);
1740 if (!(event
->description
)) return IE_NOMEM
;
1746 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1747 * and leave lable */
1748 #define EXTRACT_STRING(element, string) { \
1749 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
1754 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
1755 if (result->nodesetval->nodeNr > 1) { \
1756 isds_printf_message(context, _("Multiple %s element"), element); \
1760 (string) = (char *) \
1761 xmlXPathCastNodeSetToString(result->nodesetval); \
1769 #define EXTRACT_BOOLEAN(element, booleanPtr) \
1771 char *string = NULL; \
1772 EXTRACT_STRING(element, string); \
1775 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
1776 if (!(booleanPtr)) { \
1782 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
1783 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
1784 *(booleanPtr) = 1; \
1785 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
1786 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
1787 *(booleanPtr) = 0; \
1789 char *string_locale = utf82locale((char*)string); \
1790 isds_printf_message(context, \
1791 _("%s value is not valid boolean: "), \
1792 element, string_locale); \
1793 free(string_locale); \
1803 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
1805 char *string = NULL; \
1806 EXTRACT_STRING(element, string); \
1811 number = strtol((char*)string, &endptr, 10); \
1813 if (*endptr != '\0') { \
1814 char *string_locale = utf82locale((char *)string); \
1815 isds_printf_message(context, \
1816 _("%s is not valid integer: %s"), \
1817 element, string_locale); \
1818 free(string_locale); \
1824 if (number == LONG_MIN || number == LONG_MAX) { \
1825 char *string_locale = utf82locale((char *)string); \
1826 isds_printf_message(context, \
1827 _("%s value out of range of long int: %s"), \
1828 element, string_locale); \
1829 free(string_locale); \
1835 free(string); string = NULL; \
1837 if (!(preallocated)) { \
1838 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
1839 if (!(longintPtr)) { \
1844 *(longintPtr) = number; \
1848 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
1850 char *string = NULL; \
1851 EXTRACT_STRING(element, string); \
1856 number = strtol((char*)string, &endptr, 10); \
1858 if (*endptr != '\0') { \
1859 char *string_locale = utf82locale((char *)string); \
1860 isds_printf_message(context, \
1861 _("%s is not valid integer: %s"), \
1862 element, string_locale); \
1863 free(string_locale); \
1869 if (number == LONG_MIN || number == LONG_MAX) { \
1870 char *string_locale = utf82locale((char *)string); \
1871 isds_printf_message(context, \
1872 _("%s value out of range of long int: %s"), \
1873 element, string_locale); \
1874 free(string_locale); \
1880 free(string); string = NULL; \
1882 isds_printf_message(context, \
1883 _("%s value is negative: %ld"), element, number); \
1888 if (!(preallocated)) { \
1889 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
1890 if (!(ulongintPtr)) { \
1895 *(ulongintPtr) = number; \
1899 #define EXTRACT_STRING_ATTRIBUTE(attribute, string, required) { \
1900 (string) = (char *) xmlGetNsProp(xpath_ctx->node, ( BAD_CAST attribute), \
1902 if ((required) && (!string)) { \
1903 char *attribute_locale = utf82locale(attribute); \
1904 char *element_locale = utf82locale((char *)xpath_ctx->node->name); \
1905 isds_printf_message(context, \
1906 _("Could not extract required %s attribute value from " \
1907 "%s element"), attribute_locale, element_locale); \
1908 free(element_locale); \
1909 free(attribute_locale); \
1916 #define INSERT_STRING(parent, element, string) \
1918 node = xmlNewTextChild(parent, NULL, BAD_CAST (element), \
1919 (xmlChar *) (string)); \
1921 isds_printf_message(context, \
1922 _("Could not add %s child to %s element"), \
1923 element, (parent)->name); \
1929 #define INSERT_SCALAR_BOOLEAN(parent, element, boolean) \
1931 if (boolean) { INSERT_STRING(parent, element, "true"); } \
1932 else { INSERT_STRING(parent, element, "false"); } \
1935 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
1938 INSERT_SCALAR_BOOLEAN(parent, element, (*(booleanPtr))); \
1940 INSERT_STRING(parent, element, NULL); \
1944 #define INSERT_LONGINT(parent, element, longintPtr, buffer) { \
1945 if ((longintPtr)) { \
1946 /* FIXME: locale sensitive */ \
1947 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
1951 INSERT_STRING(parent, element, buffer) \
1952 free(buffer); (buffer) = NULL; \
1953 } else { INSERT_STRING(parent, element, NULL) } \
1956 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) { \
1957 if ((ulongintPtr)) { \
1958 /* FIXME: locale sensitive */ \
1959 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
1963 INSERT_STRING(parent, element, buffer) \
1964 free(buffer); (buffer) = NULL; \
1965 } else { INSERT_STRING(parent, element, NULL) } \
1968 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
1970 /* FIXME: locale sensitive */ \
1971 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
1975 INSERT_STRING(parent, element, buffer) \
1976 free(buffer); (buffer) = NULL; \
1979 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
1981 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
1982 (xmlChar *) (string)); \
1983 if (!attribute_node) { \
1984 isds_printf_message(context, _("Could not add %s " \
1985 "attribute to %s element"), \
1986 (attribute), (parent)->name); \
1992 #define CHECK_FOR_STRING_LENGTH(string, minimum, maximum, name) { \
1994 int length = xmlUTF8Strlen((xmlChar *) (string)); \
1995 if (length > (maximum)) { \
1996 isds_printf_message(context, \
1997 _("%s has more than %d characters"), (name), (maximum)); \
2001 if (length < (minimum)) { \
2002 isds_printf_message(context, \
2003 _("%s has less than %d characters"), (name), (minimum)); \
2010 #define INSERT_ELEMENT(child, parent, element) \
2012 (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \
2014 isds_printf_message(context, \
2015 _("Could not add %s child to %s element"), \
2016 (element), (parent)->name); \
2023 /* Find child element by name in given XPath context and switch context onto
2024 * it. The child must be uniq and must exist. Otherwise failes.
2025 * @context is ISDS context
2026 * @child is child element name
2027 * @xpath_ctx is XPath context. In success, the @xpath_ctx will be changed
2028 * into it child. In error case, the @xpath_ctx keeps original value. */
2029 static isds_error
move_xpathctx_to_child(struct isds_ctx
*context
,
2030 const xmlChar
*child
, xmlXPathContextPtr xpath_ctx
) {
2031 isds_error err
= IE_SUCCESS
;
2032 xmlXPathObjectPtr result
= NULL
;
2034 if (!context
) return IE_INVALID_CONTEXT
;
2035 if (!child
|| !xpath_ctx
) return IE_INVAL
;
2038 result
= xmlXPathEvalExpression(child
, xpath_ctx
);
2045 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2046 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
2047 char *child_locale
= utf82locale((char*) child
);
2048 isds_printf_message(context
,
2049 _("%s element does not contain %s child"),
2050 parent_locale
, child_locale
);
2052 free(parent_locale
);
2058 if (result
->nodesetval
->nodeNr
> 1) {
2059 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
2060 char *child_locale
= utf82locale((char*) child
);
2061 isds_printf_message(context
,
2062 _("%s element contains multiple %s childs"),
2063 parent_locale
, child_locale
);
2065 free(parent_locale
);
2070 /* Switch context */
2071 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2074 xmlXPathFreeObject(result
);
2080 /* Find and convert XSD:gPersonName group in current node into structure
2081 * @context is ISDS context
2082 * @personName is automically reallocated person name structure. If no member
2083 * value is found, will be freed.
2084 * @xpath_ctx is XPath context with current node as parent for XSD:gPersonName
2086 * In case of error @personName will be freed. */
2087 static isds_error
extract_gPersonName(struct isds_ctx
*context
,
2088 struct isds_PersonName
**personName
, xmlXPathContextPtr xpath_ctx
) {
2089 isds_error err
= IE_SUCCESS
;
2090 xmlXPathObjectPtr result
= NULL
;
2092 if (!context
) return IE_INVALID_CONTEXT
;
2093 if (!personName
) return IE_INVAL
;
2094 isds_PersonName_free(personName
);
2095 if (!xpath_ctx
) return IE_INVAL
;
2098 *personName
= calloc(1, sizeof(**personName
));
2104 EXTRACT_STRING("isds:pnFirstName", (*personName
)->pnFirstName
);
2105 EXTRACT_STRING("isds:pnMiddleName", (*personName
)->pnMiddleName
);
2106 EXTRACT_STRING("isds:pnLastName", (*personName
)->pnLastName
);
2107 EXTRACT_STRING("isds:pnLastNameAtBirth", (*personName
)->pnLastNameAtBirth
);
2109 if (!(*personName
)->pnFirstName
&& !(*personName
)->pnMiddleName
&&
2110 !(*personName
)->pnLastName
&& !(*personName
)->pnLastNameAtBirth
)
2111 isds_PersonName_free(personName
);
2114 if (err
) isds_PersonName_free(personName
);
2115 xmlXPathFreeObject(result
);
2120 /* Find and convert XSD:gAddress group in current node into structure
2121 * @context is ISDS context
2122 * @address is automically reallocated address structure. If no member
2123 * value is found, will be freed.
2124 * @xpath_ctx is XPath context with current node as parent for XSD:gAddress
2126 * In case of error @address will be freed. */
2127 static isds_error
extract_gAddress(struct isds_ctx
*context
,
2128 struct isds_Address
**address
, xmlXPathContextPtr xpath_ctx
) {
2129 isds_error err
= IE_SUCCESS
;
2130 xmlXPathObjectPtr result
= NULL
;
2132 if (!context
) return IE_INVALID_CONTEXT
;
2133 if (!address
) return IE_INVAL
;
2134 isds_Address_free(address
);
2135 if (!xpath_ctx
) return IE_INVAL
;
2138 *address
= calloc(1, sizeof(**address
));
2144 EXTRACT_STRING("isds:adCity", (*address
)->adCity
);
2145 EXTRACT_STRING("isds:adStreet", (*address
)->adStreet
);
2146 EXTRACT_STRING("isds:adNumberInStreet", (*address
)->adNumberInStreet
);
2147 EXTRACT_STRING("isds:adNumberInMunicipality",
2148 (*address
)->adNumberInMunicipality
);
2149 EXTRACT_STRING("isds:adZipCode", (*address
)->adZipCode
);
2150 EXTRACT_STRING("isds:adState", (*address
)->adState
);
2152 if (!(*address
)->adCity
&& !(*address
)->adStreet
&&
2153 !(*address
)->adNumberInStreet
&&
2154 !(*address
)->adNumberInMunicipality
&&
2155 !(*address
)->adZipCode
&& !(*address
)->adState
)
2156 isds_Address_free(address
);
2159 if (err
) isds_Address_free(address
);
2160 xmlXPathFreeObject(result
);
2165 /* Find and convert isds:biDate element in current node into structure
2166 * @context is ISDS context
2167 * @biDate is automically reallocated birth date structure. If no member
2168 * value is found, will be freed.
2169 * @xpath_ctx is XPath context with current node as parent for isds:biDate
2171 * In case of error @biDate will be freed. */
2172 static isds_error
extract_BiDate(struct isds_ctx
*context
,
2173 struct tm
**biDate
, xmlXPathContextPtr xpath_ctx
) {
2174 isds_error err
= IE_SUCCESS
;
2175 xmlXPathObjectPtr result
= NULL
;
2176 char *string
= NULL
;
2178 if (!context
) return IE_INVALID_CONTEXT
;
2179 if (!biDate
) return IE_INVAL
;
2181 if (!xpath_ctx
) return IE_INVAL
;
2183 EXTRACT_STRING("isds:biDate", string
);
2185 *biDate
= calloc(1, sizeof(**biDate
));
2190 err
= datestring2tm((xmlChar
*)string
, *biDate
);
2192 if (err
== IE_NOTSUP
) {
2194 char *string_locale
= utf82locale(string
);
2195 isds_printf_message(context
,
2196 _("Invalid isds:biDate value: %s"), string_locale
);
2197 free(string_locale
);
2204 if (err
) zfree(*biDate
);
2206 xmlXPathFreeObject(result
);
2211 /* Convert isds:dBOwnerInfo XML tree into structure
2212 * @context is ISDS context
2213 * @db_owner_info is automically reallocated box owner info structure
2214 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
2215 * In case of error @db_owner_info will be freed. */
2216 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
2217 struct isds_DbOwnerInfo
**db_owner_info
,
2218 xmlXPathContextPtr xpath_ctx
) {
2219 isds_error err
= IE_SUCCESS
;
2220 xmlXPathObjectPtr result
= NULL
;
2221 char *string
= NULL
;
2223 if (!context
) return IE_INVALID_CONTEXT
;
2224 if (!db_owner_info
) return IE_INVAL
;
2225 isds_DbOwnerInfo_free(db_owner_info
);
2226 if (!xpath_ctx
) return IE_INVAL
;
2229 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
2230 if (!*db_owner_info
) {
2235 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
2237 EXTRACT_STRING("isds:dbType", string
);
2239 (*db_owner_info
)->dbType
=
2240 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
2241 if (!(*db_owner_info
)->dbType
) {
2245 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
2247 zfree((*db_owner_info
)->dbType
);
2248 if (err
== IE_ENUM
) {
2250 char *string_locale
= utf82locale(string
);
2251 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
2253 free(string_locale
);
2260 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
2262 err
= extract_gPersonName(context
, &(*db_owner_info
)->personName
,
2264 if (err
) goto leave
;
2266 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
2268 (*db_owner_info
)->birthInfo
=
2269 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
2270 if (!(*db_owner_info
)->birthInfo
) {
2274 err
= extract_BiDate(context
, &(*db_owner_info
)->birthInfo
->biDate
,
2276 if (err
) goto leave
;
2277 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
2278 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
2279 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
2280 if (!(*db_owner_info
)->birthInfo
->biDate
&&
2281 !(*db_owner_info
)->birthInfo
->biCity
&&
2282 !(*db_owner_info
)->birthInfo
->biCounty
&&
2283 !(*db_owner_info
)->birthInfo
->biState
)
2284 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
2286 err
= extract_gAddress(context
, &(*db_owner_info
)->address
, xpath_ctx
);
2287 if (err
) goto leave
;
2289 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
2290 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
2291 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
2292 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
2293 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
2295 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
2297 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
2298 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
2299 (*db_owner_info
)->dbOpenAddressing
);
2302 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
2304 xmlXPathFreeObject(result
);
2309 /* Insert struct isds_DbOwnerInfo data (box description) into XML tree
2310 * @context is sesstion context
2311 * @owner is libsids structure with box description
2312 * @db_owner_info is XML element of XSD:tDbOwnerInfo */
2313 static isds_error
insert_DbOwnerInfo(struct isds_ctx
*context
,
2314 const struct isds_DbOwnerInfo
*owner
, xmlNodePtr db_owner_info
) {
2316 isds_error err
= IE_SUCCESS
;
2318 xmlChar
*string
= NULL
;
2320 if (!context
) return IE_INVALID_CONTEXT
;
2321 if (!owner
|| !db_owner_info
) return IE_INVAL
;
2324 /* Build XSD:tDbOwnerInfo */
2325 CHECK_FOR_STRING_LENGTH(owner
->dbID
, 0, 7, "dbID")
2326 INSERT_STRING(db_owner_info
, "dbID", owner
->dbID
);
2329 if (owner
->dbType
) {
2330 const xmlChar
*type_string
= isds_DbType2string(*(owner
->dbType
));
2332 isds_printf_message(context
, _("Invalid dbType value: %d"),
2337 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2339 INSERT_STRING(db_owner_info
, "ic", owner
->ic
);
2340 if (owner
->personName
) {
2341 INSERT_STRING(db_owner_info
, "pnFirstName",
2342 owner
->personName
->pnFirstName
);
2343 INSERT_STRING(db_owner_info
, "pnMiddleName",
2344 owner
->personName
->pnMiddleName
);
2345 INSERT_STRING(db_owner_info
, "pnLastName",
2346 owner
->personName
->pnLastName
);
2347 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2348 owner
->personName
->pnLastNameAtBirth
);
2350 INSERT_STRING(db_owner_info
, "firmName", owner
->firmName
);
2351 if (owner
->birthInfo
) {
2352 if (owner
->birthInfo
->biDate
) {
2353 if (!tm2datestring(owner
->birthInfo
->biDate
, &string
))
2354 INSERT_STRING(db_owner_info
, "biDate", string
);
2355 free(string
); string
= NULL
;
2357 INSERT_STRING(db_owner_info
, "biCity", owner
->birthInfo
->biCity
);
2358 INSERT_STRING(db_owner_info
, "biCounty", owner
->birthInfo
->biCounty
);
2359 INSERT_STRING(db_owner_info
, "biState", owner
->birthInfo
->biState
);
2361 if (owner
->address
) {
2362 INSERT_STRING(db_owner_info
, "adCity", owner
->address
->adCity
);
2363 INSERT_STRING(db_owner_info
, "adStreet", owner
->address
->adStreet
);
2364 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2365 owner
->address
->adNumberInStreet
);
2366 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2367 owner
->address
->adNumberInMunicipality
);
2368 INSERT_STRING(db_owner_info
, "adZipCode", owner
->address
->adZipCode
);
2369 INSERT_STRING(db_owner_info
, "adState", owner
->address
->adState
);
2371 INSERT_STRING(db_owner_info
, "nationality", owner
->nationality
);
2372 INSERT_STRING(db_owner_info
, "email", owner
->email
);
2373 INSERT_STRING(db_owner_info
, "telNumber", owner
->telNumber
);
2375 CHECK_FOR_STRING_LENGTH(owner
->identifier
, 0, 20, "identifier")
2376 INSERT_STRING(db_owner_info
, "identifier", owner
->identifier
);
2378 CHECK_FOR_STRING_LENGTH(owner
->registryCode
, 0, 5, "registryCode")
2379 INSERT_STRING(db_owner_info
, "registryCode", owner
->registryCode
);
2381 INSERT_LONGINT(db_owner_info
, "dbState", owner
->dbState
, string
);
2383 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", owner
->dbEffectiveOVM
);
2384 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2385 owner
->dbOpenAddressing
);
2393 /* Convert XSD:tDbUserInfo XML tree into structure
2394 * @context is ISDS context
2395 * @db_user_info is automically reallocated user info structure
2396 * @xpath_ctx is XPath context with current node as XSD:tDbUserInfo element
2397 * In case of error @db_user_info will be freed. */
2398 static isds_error
extract_DbUserInfo(struct isds_ctx
*context
,
2399 struct isds_DbUserInfo
**db_user_info
, xmlXPathContextPtr xpath_ctx
) {
2400 isds_error err
= IE_SUCCESS
;
2401 xmlXPathObjectPtr result
= NULL
;
2402 char *string
= NULL
;
2404 if (!context
) return IE_INVALID_CONTEXT
;
2405 if (!db_user_info
) return IE_INVAL
;
2406 isds_DbUserInfo_free(db_user_info
);
2407 if (!xpath_ctx
) return IE_INVAL
;
2410 *db_user_info
= calloc(1, sizeof(**db_user_info
));
2411 if (!*db_user_info
) {
2416 EXTRACT_STRING("isds:userID", (*db_user_info
)->userID
);
2418 EXTRACT_STRING("isds:userType", string
);
2420 (*db_user_info
)->userType
=
2421 calloc(1, sizeof(*((*db_user_info
)->userType
)));
2422 if (!(*db_user_info
)->userType
) {
2426 err
= string2isds_UserType((xmlChar
*)string
,
2427 (*db_user_info
)->userType
);
2429 zfree((*db_user_info
)->userType
);
2430 if (err
== IE_ENUM
) {
2432 char *string_locale
= utf82locale(string
);
2433 isds_printf_message(context
, _("Unknown isds:userType: %s"),
2435 free(string_locale
);
2442 EXTRACT_LONGINT("isds:userPrivils", (*db_user_info
)->userPrivils
, 0);
2444 (*db_user_info
)->personName
=
2445 calloc(1, sizeof(*((*db_user_info
)->personName
)));
2446 if (!(*db_user_info
)->personName
) {
2451 err
= extract_gPersonName(context
, &(*db_user_info
)->personName
,
2453 if (err
) goto leave
;
2455 err
= extract_gAddress(context
, &(*db_user_info
)->address
, xpath_ctx
);
2456 if (err
) goto leave
;
2458 err
= extract_BiDate(context
, &(*db_user_info
)->biDate
, xpath_ctx
);
2459 if (err
) goto leave
;
2461 EXTRACT_STRING("isds:ic", (*db_user_info
)->ic
);
2462 EXTRACT_STRING("isds:firmName", (*db_user_info
)->firmName
);
2464 EXTRACT_STRING("isds:caStreet", (*db_user_info
)->caStreet
);
2465 EXTRACT_STRING("isds:caCity", (*db_user_info
)->caCity
);
2466 EXTRACT_STRING("isds:caZipCode", (*db_user_info
)->caZipCode
);
2469 if (err
) isds_DbUserInfo_free(db_user_info
);
2471 xmlXPathFreeObject(result
);
2476 /* Insert struct isds_DbUserInfo data (user description) into XML tree
2477 * @context is sesstion context
2478 * @user is libsids structure with user description
2479 * @db_user_info is XML element of XSD:tDbUserInfo */
2480 static isds_error
insert_DbUserInfo(struct isds_ctx
*context
,
2481 const struct isds_DbUserInfo
*user
, xmlNodePtr db_user_info
) {
2483 isds_error err
= IE_SUCCESS
;
2485 xmlChar
*string
= NULL
;
2487 if (!context
) return IE_INVALID_CONTEXT
;
2488 if (!user
|| !db_user_info
) return IE_INVAL
;
2490 /* Build XSD:tDbUserInfo */
2491 if (user
->personName
) {
2492 INSERT_STRING(db_user_info
, "pnFirstName",
2493 user
->personName
->pnFirstName
);
2494 INSERT_STRING(db_user_info
, "pnMiddleName",
2495 user
->personName
->pnMiddleName
);
2496 INSERT_STRING(db_user_info
, "pnLastName",
2497 user
->personName
->pnLastName
);
2498 INSERT_STRING(db_user_info
, "pnLastNameAtBirth",
2499 user
->personName
->pnLastNameAtBirth
);
2501 if (user
->address
) {
2502 INSERT_STRING(db_user_info
, "adCity", user
->address
->adCity
);
2503 INSERT_STRING(db_user_info
, "adStreet", user
->address
->adStreet
);
2504 INSERT_STRING(db_user_info
, "adNumberInStreet",
2505 user
->address
->adNumberInStreet
);
2506 INSERT_STRING(db_user_info
, "adNumberInMunicipality",
2507 user
->address
->adNumberInMunicipality
);
2508 INSERT_STRING(db_user_info
, "adZipCode", user
->address
->adZipCode
);
2509 INSERT_STRING(db_user_info
, "adState", user
->address
->adState
);
2512 if (!tm2datestring(user
->biDate
, &string
))
2513 INSERT_STRING(db_user_info
, "biDate", string
);
2516 CHECK_FOR_STRING_LENGTH(user
->userID
, 6, 12, "userID");
2517 INSERT_STRING(db_user_info
, "userID", user
->userID
);
2520 if (user
->userType
) {
2521 const xmlChar
*type_string
= isds_UserType2string(*(user
->userType
));
2523 isds_printf_message(context
, _("Invalid userType value: %d"),
2528 INSERT_STRING(db_user_info
, "userType", type_string
);
2531 INSERT_LONGINT(db_user_info
, "userPrivils", user
->userPrivils
, string
);
2532 CHECK_FOR_STRING_LENGTH(user
->ic
, 0, 8, "ic")
2533 INSERT_STRING(db_user_info
, "ic", user
->ic
);
2534 CHECK_FOR_STRING_LENGTH(user
->firmName
, 0, 100, "firmName")
2535 INSERT_STRING(db_user_info
, "firmName", user
->firmName
);
2536 INSERT_STRING(db_user_info
, "caStreet", user
->caStreet
);
2537 INSERT_STRING(db_user_info
, "caCity", user
->caCity
);
2538 INSERT_STRING(db_user_info
, "caZipCode", user
->caZipCode
);
2546 /* Convert XSD gMessageEnvelopeSub group of elements from XML tree into
2547 * isds_envelope structure. The envelope is automatically allocated but not
2548 * reallocated. The date are just appended into envelope structure.
2549 * @context is ISDS context
2550 * @envelope is automically allocated message envelope structure
2551 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2552 * In case of error @envelope will be freed. */
2553 static isds_error
append_GMessageEnvelopeSub(struct isds_ctx
*context
,
2554 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2555 isds_error err
= IE_SUCCESS
;
2556 xmlXPathObjectPtr result
= NULL
;
2558 if (!context
) return IE_INVALID_CONTEXT
;
2559 if (!envelope
) return IE_INVAL
;
2560 if (!xpath_ctx
) return IE_INVAL
;
2564 /* Allocate envelope */
2565 *envelope
= calloc(1, sizeof(**envelope
));
2571 /* Else free former data */
2572 zfree((*envelope
)->dmSenderOrgUnit
);
2573 zfree((*envelope
)->dmSenderOrgUnitNum
);
2574 zfree((*envelope
)->dbIDRecipient
);
2575 zfree((*envelope
)->dmRecipientOrgUnit
);
2576 zfree((*envelope
)->dmSenderOrgUnitNum
);
2577 zfree((*envelope
)->dmToHands
);
2578 zfree((*envelope
)->dmAnnotation
);
2579 zfree((*envelope
)->dmRecipientRefNumber
);
2580 zfree((*envelope
)->dmSenderRefNumber
);
2581 zfree((*envelope
)->dmRecipientIdent
);
2582 zfree((*envelope
)->dmSenderIdent
);
2583 zfree((*envelope
)->dmLegalTitleLaw
);
2584 zfree((*envelope
)->dmLegalTitleYear
);
2585 zfree((*envelope
)->dmLegalTitleSect
);
2586 zfree((*envelope
)->dmLegalTitlePar
);
2587 zfree((*envelope
)->dmLegalTitlePoint
);
2588 zfree((*envelope
)->dmPersonalDelivery
);
2589 zfree((*envelope
)->dmAllowSubstDelivery
);
2592 /* Extract envelope elements added by sender or ISDS
2593 * (XSD: gMessageEnvelopeSub type) */
2594 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
2595 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
2596 (*envelope
)->dmSenderOrgUnitNum
, 0);
2597 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
2598 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
2599 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
2600 (*envelope
)->dmSenderOrgUnitNum
, 0);
2601 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
2602 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
2603 EXTRACT_STRING("isds:dmRecipientRefNumber",
2604 (*envelope
)->dmRecipientRefNumber
);
2605 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
2606 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
2607 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
2609 /* Extract envelope elements regarding law refference */
2610 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
2611 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
2612 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
2613 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
2614 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
2616 /* Extract envelope other elements */
2617 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
2618 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
2619 (*envelope
)->dmAllowSubstDelivery
);
2622 if (err
) isds_envelope_free(envelope
);
2623 xmlXPathFreeObject(result
);
2629 /* Convert XSD gMessageEnvelope group of elements from XML tree into
2630 * isds_envelope structure. The envelope is automatically allocated but not
2631 * reallocated. The date are just appended into envelope structure.
2632 * @context is ISDS context
2633 * @envelope is automically allocated message envelope structure
2634 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2635 * In case of error @envelope will be freed. */
2636 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
2637 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2638 isds_error err
= IE_SUCCESS
;
2639 xmlXPathObjectPtr result
= NULL
;
2641 if (!context
) return IE_INVALID_CONTEXT
;
2642 if (!envelope
) return IE_INVAL
;
2643 if (!xpath_ctx
) return IE_INVAL
;
2647 /* Allocate envelope */
2648 *envelope
= calloc(1, sizeof(**envelope
));
2654 /* Else free former data */
2655 zfree((*envelope
)->dmID
);
2656 zfree((*envelope
)->dbIDSender
);
2657 zfree((*envelope
)->dmSender
);
2658 zfree((*envelope
)->dmSenderAddress
);
2659 zfree((*envelope
)->dmSenderType
);
2660 zfree((*envelope
)->dmRecipient
);
2661 zfree((*envelope
)->dmRecipientAddress
);
2662 zfree((*envelope
)->dmAmbiguousRecipient
);
2665 /* Extract envelope elements added by ISDS
2666 * (XSD: gMessageEnvelope type) */
2667 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
2668 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
2669 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
2670 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
2671 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
2672 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
2673 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
2674 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
2675 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
2676 (*envelope
)->dmAmbiguousRecipient
);
2678 /* Extract envelope elements added by sender and ISDS
2679 * (XSD: gMessageEnvelope type) */
2680 err
= append_GMessageEnvelopeSub(context
, envelope
, xpath_ctx
);
2681 if (err
) goto leave
;
2684 if (err
) isds_envelope_free(envelope
);
2685 xmlXPathFreeObject(result
);
2690 /* Convert other envelope elements from XML tree into isds_envelope structure:
2691 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
2692 * The envelope is automatically allocated but not reallocated.
2693 * The data are just appended into envelope structure.
2694 * @context is ISDS context
2695 * @envelope is automically allocated message envelope structure
2696 * @xpath_ctx is XPath context with current node as parent desired elements
2697 * In case of error @envelope will be freed. */
2698 static isds_error
append_status_size_times(struct isds_ctx
*context
,
2699 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2700 isds_error err
= IE_SUCCESS
;
2701 xmlXPathObjectPtr result
= NULL
;
2702 char *string
= NULL
;
2703 unsigned long int *unumber
= NULL
;
2705 if (!context
) return IE_INVALID_CONTEXT
;
2706 if (!envelope
) return IE_INVAL
;
2707 if (!xpath_ctx
) return IE_INVAL
;
2712 *envelope
= calloc(1, sizeof(**envelope
));
2719 zfree((*envelope
)->dmMessageStatus
);
2720 zfree((*envelope
)->dmAttachmentSize
);
2721 zfree((*envelope
)->dmDeliveryTime
);
2722 zfree((*envelope
)->dmAcceptanceTime
);
2726 /* dmMessageStatus element is mandatory */
2727 EXTRACT_ULONGINT("sisds:dmMessageStatus", unumber
, 0);
2729 isds_log_message(context
,
2730 _("Missing mandatory sisds:dmMessageStatus integer"));
2734 err
= uint2isds_message_status(context
, unumber
,
2735 &((*envelope
)->dmMessageStatus
));
2737 if (err
== IE_ENUM
) err
= IE_ISDS
;
2740 free(unumber
); unumber
= NULL
;
2742 EXTRACT_ULONGINT("sisds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
,
2745 EXTRACT_STRING("sisds:dmDeliveryTime", string
);
2747 err
= timestring2timeval((xmlChar
*) string
,
2748 &((*envelope
)->dmDeliveryTime
));
2750 char *string_locale
= utf82locale(string
);
2751 if (err
== IE_DATE
) err
= IE_ISDS
;
2752 isds_printf_message(context
,
2753 _("Could not convert dmDeliveryTime as ISO time: %s"),
2755 free(string_locale
);
2761 EXTRACT_STRING("sisds:dmAcceptanceTime", string
);
2763 err
= timestring2timeval((xmlChar
*) string
,
2764 &((*envelope
)->dmAcceptanceTime
));
2766 char *string_locale
= utf82locale(string
);
2767 if (err
== IE_DATE
) err
= IE_ISDS
;
2768 isds_printf_message(context
,
2769 _("Could not convert dmAcceptanceTime as ISO time: %s"),
2771 free(string_locale
);
2778 if (err
) isds_envelope_free(envelope
);
2781 xmlXPathFreeObject(result
);
2786 /* Convert message type attribute of current element into isds_envelope
2788 * TODO: This function can be incorporated into append_status_size_times() as
2789 * they are called always together.
2790 * The envelope is automatically allocated but not reallocated.
2791 * The data are just appended into envelope structure.
2792 * @context is ISDS context
2793 * @envelope is automically allocated message envelope structure
2794 * @xpath_ctx is XPath context with current node as parent of attribute
2795 * carrying message type
2796 * In case of error @envelope will be freed. */
2797 static isds_error
append_message_type(struct isds_ctx
*context
,
2798 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2799 isds_error err
= IE_SUCCESS
;
2801 if (!context
) return IE_INVALID_CONTEXT
;
2802 if (!envelope
) return IE_INVAL
;
2803 if (!xpath_ctx
) return IE_INVAL
;
2808 *envelope
= calloc(1, sizeof(**envelope
));
2815 zfree((*envelope
)->dmType
);
2819 EXTRACT_STRING_ATTRIBUTE("dmType", (*envelope
)->dmType
, 0);
2821 if (!(*envelope
)->dmType
) {
2822 /* Use default value */
2823 (*envelope
)->dmType
= strdup("V");
2824 if (!(*envelope
)->dmType
) {
2828 } else if (1 != xmlUTF8Strlen((xmlChar
*) (*envelope
)->dmType
)) {
2829 char *type_locale
= utf82locale((*envelope
)->dmType
);
2830 isds_printf_message(context
,
2831 _("Message type in dmType attribute is not 1 character long: "
2840 if (err
) isds_envelope_free(envelope
);
2846 /* Extract message document into reallocated document structure
2847 * @context is ISDS context
2848 * @document is automically reallocated message documents structure
2849 * @xpath_ctx is XPath context with current node as isds:dmFile
2850 * In case of error @document will be freed. */
2851 static isds_error
extract_document(struct isds_ctx
*context
,
2852 struct isds_document
**document
, xmlXPathContextPtr xpath_ctx
) {
2853 isds_error err
= IE_SUCCESS
;
2854 xmlXPathObjectPtr result
= NULL
;
2855 xmlNodePtr file_node
= xpath_ctx
->node
;
2856 char *string
= NULL
;
2858 if (!context
) return IE_INVALID_CONTEXT
;
2859 if (!document
) return IE_INVAL
;
2860 isds_document_free(document
);
2861 if (!xpath_ctx
) return IE_INVAL
;
2863 *document
= calloc(1, sizeof(**document
));
2869 /* Extract document metadata */
2870 EXTRACT_STRING_ATTRIBUTE("dmMimeType", (*document
)->dmMimeType
, 1)
2872 EXTRACT_STRING_ATTRIBUTE("dmFileMetaType", string
, 1)
2873 err
= string2isds_FileMetaType((xmlChar
*)string
,
2874 &((*document
)->dmFileMetaType
));
2876 char *meta_type_locale
= utf82locale(string
);
2877 isds_printf_message(context
,
2878 _("Document has invalid dmFileMetaType attribute value: %s"),
2880 free(meta_type_locale
);
2886 EXTRACT_STRING_ATTRIBUTE("dmFileGuid", (*document
)->dmFileGuid
, 0)
2887 EXTRACT_STRING_ATTRIBUTE("dmUpFileGuid", (*document
)->dmUpFileGuid
, 0)
2888 EXTRACT_STRING_ATTRIBUTE("dmFileDescr", (*document
)->dmFileDescr
, 0)
2889 EXTRACT_STRING_ATTRIBUTE("dmFormat", (*document
)->dmFormat
, 0)
2892 /* Extract document data.
2893 * Base64 encoded blob or XML subtree must be presented. */
2895 /* Check from dmEncodedContent */
2896 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmEncodedContent",
2903 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2904 /* Here we have Base64 blob */
2906 if (result
->nodesetval
->nodeNr
> 1) {
2907 isds_printf_message(context
,
2908 _("Document has more dmEncodedContent elements"));
2913 xmlXPathFreeObject(result
); result
= NULL
;
2914 EXTRACT_STRING("isds:dmEncodedContent", string
);
2916 /* Decode non-emptys document */
2917 if (string
&& string
[0] != '\0') {
2918 (*document
)->data_length
= b64decode(string
, &((*document
)->data
));
2919 if ((*document
)->data_length
== (size_t) -1) {
2920 isds_printf_message(context
,
2921 _("Error while Base64-decoding document content"));
2927 /* No Base64 blob, try XML document */
2928 xmlXPathFreeObject(result
); result
= NULL
;
2929 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmXMLContent",
2936 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2937 /* Here we have XML document */
2939 if (result
->nodesetval
->nodeNr
> 1) {
2940 isds_printf_message(context
,
2941 _("Document has more dmXMLContent elements"));
2946 /* FIXME: Serialize the tree rooted at result's node */
2947 isds_printf_message(context
,
2948 _("XML documents not yet supported"));
2952 /* No bas64 blob, nor XML document */
2953 isds_printf_message(context
,
2954 _("Document has no dmEncodedContent, nor dmXMLContent "
2963 if (err
) isds_document_free(document
);
2965 xmlXPathFreeObject(result
);
2966 xpath_ctx
->node
= file_node
;
2972 /* Extract message documents into reallocated list of documents
2973 * @context is ISDS context
2974 * @documents is automically reallocated message documents list structure
2975 * @xpath_ctx is XPath context with current node as XSD tFilesArray
2976 * In case of error @documents will be freed. */
2977 static isds_error
extract_documents(struct isds_ctx
*context
,
2978 struct isds_list
**documents
, xmlXPathContextPtr xpath_ctx
) {
2979 isds_error err
= IE_SUCCESS
;
2980 xmlXPathObjectPtr result
= NULL
;
2981 xmlNodePtr files_node
= xpath_ctx
->node
;
2982 struct isds_list
*document
, *prev_document
;
2984 if (!context
) return IE_INVALID_CONTEXT
;
2985 if (!documents
) return IE_INVAL
;
2986 isds_list_free(documents
);
2987 if (!xpath_ctx
) return IE_INVAL
;
2989 /* Find documents */
2990 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmFile", xpath_ctx
);
2997 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2998 isds_printf_message(context
,
2999 _("Message does not contain any document"));
3005 /* Iterate over documents */
3006 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3008 /* Allocate and append list item */
3009 document
= calloc(1, sizeof(*document
));
3014 document
->destructor
= (void (*)(void **))isds_document_free
;
3015 if (i
== 0) *documents
= document
;
3016 else prev_document
->next
= document
;
3017 prev_document
= document
;
3019 /* Extract document */
3020 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3021 err
= extract_document(context
,
3022 (struct isds_document
**) &(document
->data
), xpath_ctx
);
3023 if (err
) goto leave
;
3028 if (err
) isds_list_free(documents
);
3029 xmlXPathFreeObject(result
);
3030 xpath_ctx
->node
= files_node
;
3035 /* Convert isds:dmRecord XML tree into structure
3036 * @context is ISDS context
3037 * @envelope is automically reallocated message envelope structure
3038 * @xpath_ctx is XPath context with current node as isds:dmRecord element
3039 * In case of error @envelope will be freed. */
3040 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
3041 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3042 isds_error err
= IE_SUCCESS
;
3043 xmlXPathObjectPtr result
= NULL
;
3045 if (!context
) return IE_INVALID_CONTEXT
;
3046 if (!envelope
) return IE_INVAL
;
3047 isds_envelope_free(envelope
);
3048 if (!xpath_ctx
) return IE_INVAL
;
3051 *envelope
= calloc(1, sizeof(**envelope
));
3058 /* Extract tRecord data */
3059 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
3061 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3062 * dmAcceptanceTime. */
3063 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
3064 if (err
) goto leave
;
3066 /* Extract envelope elements added by sender and ISDS
3067 * (XSD: gMessageEnvelope type) */
3068 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
3069 if (err
) goto leave
;
3070 /* dmOVM can not be obtained from ISDS */
3072 /* Get message type */
3073 err
= append_message_type(context
, envelope
, xpath_ctx
);
3074 if (err
) goto leave
;
3078 if (err
) isds_envelope_free(envelope
);
3079 xmlXPathFreeObject(result
);
3084 /* Find and convert isds:dmHash XML tree into structure
3085 * @context is ISDS context
3086 * @envelope is automically reallocated message hash structure
3087 * @xpath_ctx is XPath context with current node containing isds:dmHash child
3088 * In case of error @hash will be freed. */
3089 static isds_error
find_and_extract_DmHash(struct isds_ctx
*context
,
3090 struct isds_hash
**hash
, xmlXPathContextPtr xpath_ctx
) {
3091 isds_error err
= IE_SUCCESS
;
3092 xmlNodePtr old_ctx_node
;
3093 xmlXPathObjectPtr result
= NULL
;
3094 char *string
= NULL
;
3096 if (!context
) return IE_INVALID_CONTEXT
;
3097 if (!hash
) return IE_INVAL
;
3098 isds_hash_free(hash
);
3099 if (!xpath_ctx
) return IE_INVAL
;
3101 old_ctx_node
= xpath_ctx
->node
;
3103 *hash
= calloc(1, sizeof(**hash
));
3110 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmHash", xpath_ctx
);
3111 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3120 /* Get hash algorithm */
3121 EXTRACT_STRING_ATTRIBUTE("algorithm", string
, 1);
3122 err
= string2isds_hash_algorithm((xmlChar
*) string
, &(*hash
)->algorithm
);
3124 if (err
== IE_ENUM
) {
3125 char *string_locale
= utf82locale(string
);
3126 isds_printf_message(context
, _("Unsported hash algorithm: %s"),
3128 free(string_locale
);
3134 /* Get hash value */
3135 EXTRACT_STRING(".", string
);
3137 isds_printf_message(context
, _("tHash element is missing hash value"));
3141 (*hash
)->length
= b64decode(string
, &((*hash
)->value
));
3142 if ((*hash
)->length
== (size_t) -1) {
3143 isds_printf_message(context
,
3144 _("Error while Base64-decoding hash value"));
3150 if (err
) isds_hash_free(hash
);
3152 xmlXPathFreeObject(result
);
3153 xpath_ctx
->node
= old_ctx_node
;
3158 /* Find and append isds:dmQTimestamp XML tree into envelope
3159 * @context is ISDS context
3160 * @envelope is automically allocated evnelope structure
3161 * @xpath_ctx is XPath context with current node containing isds:dmQTimestamp
3163 * In case of error @envelope will be freed. */
3164 static isds_error
find_and_append_DmQTimestamp(struct isds_ctx
*context
,
3165 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3166 isds_error err
= IE_SUCCESS
;
3167 xmlXPathObjectPtr result
= NULL
;
3168 char *string
= NULL
;
3170 if (!context
) return IE_INVALID_CONTEXT
;
3171 if (!envelope
) return IE_INVAL
;
3173 isds_envelope_free(envelope
);
3178 *envelope
= calloc(1, sizeof(**envelope
));
3184 zfree((*envelope
)->timestamp
);
3185 (*envelope
)->timestamp_length
= 0;
3188 /* Get dmQTimestamp */
3189 EXTRACT_STRING("sisds:dmQTimestamp", string
);
3191 isds_printf_message(context
, _("Missing dmQTimestamp element content"));
3195 (*envelope
)->timestamp_length
=
3196 b64decode(string
, &((*envelope
)->timestamp
));
3197 if ((*envelope
)->timestamp_length
== (size_t) -1) {
3198 isds_printf_message(context
,
3199 _("Error while Base64-decoding timestamp value"));
3205 if (err
) isds_envelope_free(envelope
);
3207 xmlXPathFreeObject(result
);
3212 /* Convert XSD tReturnedMessage XML tree into message structure.
3213 * It doea not store XML tree into message->raw.
3214 * @context is ISDS context
3215 * @include_documents Use true if documents must be extracted
3216 * (tReturnedMessage XSD type), use false if documents shall be ommited
3217 * (tReturnedMessageEnvelope).
3218 * @message is automically reallocated message structure
3219 * @xpath_ctx is XPath context with current node as tReturnedMessage element
3221 * In case of error @message will be freed. */
3222 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
3223 const _Bool include_documents
, struct isds_message
**message
,
3224 xmlXPathContextPtr xpath_ctx
) {
3225 isds_error err
= IE_SUCCESS
;
3226 xmlNodePtr message_node
;
3228 if (!context
) return IE_INVALID_CONTEXT
;
3229 if (!message
) return IE_INVAL
;
3230 isds_message_free(message
);
3231 if (!xpath_ctx
) return IE_INVAL
;
3234 *message
= calloc(1, sizeof(**message
));
3240 /* Save message XPATH context node */
3241 message_node
= xpath_ctx
->node
;
3245 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
3246 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
3247 if (err
) { err
= IE_ERROR
; goto leave
; }
3248 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
3249 if (err
) goto leave
;
3251 if (include_documents
) {
3252 /* Extract dmFiles */
3253 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles",
3255 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3256 err
= IE_ISDS
; goto leave
;
3258 if (err
) { err
= IE_ERROR
; goto leave
; }
3259 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
3260 if (err
) goto leave
;
3264 /* Restore context to message */
3265 xpath_ctx
->node
= message_node
;
3267 /* Extract dmHash */
3268 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
3270 if (err
) goto leave
;
3272 /* Extract dmQTimestamp, */
3273 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
3275 if (err
) goto leave
;
3277 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3278 * dmAcceptanceTime. */
3279 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
3280 if (err
) goto leave
;
3282 /* Get message type */
3283 err
= append_message_type(context
, &((*message
)->envelope
), xpath_ctx
);
3284 if (err
) goto leave
;
3287 if (err
) isds_message_free(message
);
3292 /* Extract message event into reallocated isds_event structure
3293 * @context is ISDS context
3294 * @event is automically reallocated message event structure
3295 * @xpath_ctx is XPath context with current node as isds:dmEvent
3296 * In case of error @event will be freed. */
3297 static isds_error
extract_event(struct isds_ctx
*context
,
3298 struct isds_event
**event
, xmlXPathContextPtr xpath_ctx
) {
3299 isds_error err
= IE_SUCCESS
;
3300 xmlXPathObjectPtr result
= NULL
;
3301 xmlNodePtr event_node
= xpath_ctx
->node
;
3302 char *string
= NULL
;
3304 if (!context
) return IE_INVALID_CONTEXT
;
3305 if (!event
) return IE_INVAL
;
3306 isds_event_free(event
);
3307 if (!xpath_ctx
) return IE_INVAL
;
3309 *event
= calloc(1, sizeof(**event
));
3315 /* Extract event data.
3316 * All elements are optional according XSD. That's funny. */
3317 EXTRACT_STRING("sisds:dmEventTime", string
);
3319 err
= timestring2timeval((xmlChar
*) string
, &((*event
)->time
));
3321 char *string_locale
= utf82locale(string
);
3322 if (err
== IE_DATE
) err
= IE_ISDS
;
3323 isds_printf_message(context
,
3324 _("Could not convert dmEventTime as ISO time: %s"),
3326 free(string_locale
);
3332 /* dmEventDescr element has prefix and the rest */
3333 EXTRACT_STRING("sisds:dmEventDescr", string
);
3335 err
= eventstring2event((xmlChar
*) string
, *event
);
3336 if (err
) goto leave
;
3341 if (err
) isds_event_free(event
);
3343 xmlXPathFreeObject(result
);
3344 xpath_ctx
->node
= event_node
;
3349 /* Convert element of XSD tEventsArray type from XML tree into
3350 * isds_list of isds_event's structure. The list is automatically reallocated.
3351 * @context is ISDS context
3352 * @events is automically reallocated list of event structures
3353 * @xpath_ctx is XPath context with current node as tEventsArray
3354 * In case of error @evnets will be freed. */
3355 static isds_error
extract_events(struct isds_ctx
*context
,
3356 struct isds_list
**events
, xmlXPathContextPtr xpath_ctx
) {
3357 isds_error err
= IE_SUCCESS
;
3358 xmlXPathObjectPtr result
= NULL
;
3359 xmlNodePtr events_node
= xpath_ctx
->node
;
3360 struct isds_list
*event
, *prev_event
= NULL
;
3362 if (!context
) return IE_INVALID_CONTEXT
;
3363 if (!events
) return IE_INVAL
;
3364 if (!xpath_ctx
) return IE_INVAL
;
3367 isds_list_free(events
);
3370 result
= xmlXPathEvalExpression(BAD_CAST
"sisds:dmEvent", xpath_ctx
);
3377 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3378 isds_printf_message(context
,
3379 _("Delivery info does not contain any event"));
3385 /* Iterate over events */
3386 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3388 /* Allocate and append list item */
3389 event
= calloc(1, sizeof(*event
));
3394 event
->destructor
= (void (*)(void **))isds_event_free
;
3395 if (i
== 0) *events
= event
;
3396 else prev_event
->next
= event
;
3400 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3401 err
= extract_event(context
,
3402 (struct isds_event
**) &(event
->data
), xpath_ctx
);
3403 if (err
) goto leave
;
3408 if (err
) isds_list_free(events
);
3409 xmlXPathFreeObject(result
);
3410 xpath_ctx
->node
= events_node
;
3415 /* Convert isds_document structure into XML tree and append to dmFiles node.
3416 * @context is session context
3417 * @document is ISDS document
3418 * @dm_files is XML element the resulting tree will be appended to as a child.
3419 * @return error code, in case of error context' message is filled. */
3420 static isds_error
insert_document(struct isds_ctx
*context
,
3421 struct isds_document
*document
, xmlNodePtr dm_files
) {
3422 isds_error err
= IE_SUCCESS
;
3423 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
3424 xmlAttrPtr attribute_node
;
3425 xmlChar
*base64data
= NULL
;
3427 if (!context
) return IE_INVALID_CONTEXT
;
3428 if (!document
|| !dm_files
) return IE_INVAL
;
3430 /* Allocate new dmFile */
3431 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
3433 isds_printf_message(context
, _("Could not allocate main dmFile"));
3437 /* Append the new dmFile.
3438 * XXX: Main document must go first */
3439 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
3440 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
3442 file
= xmlAddChild(dm_files
, new_file
);
3445 xmlFreeNode(new_file
); new_file
= NULL
;
3446 isds_printf_message(context
, _("Could not add dmFile child to "
3447 "%s element"), dm_files
->name
);
3452 /* @dmMimeType is required */
3453 if (!document
->dmMimeType
) {
3454 isds_log_message(context
,
3455 _("Document is missing mandatory MIME type definition"));
3459 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
3461 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
3463 isds_printf_message(context
,
3464 _("Document has unkown dmFileMetaType: %ld"),
3465 document
->dmFileMetaType
);
3469 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
3471 if (document
->dmFileGuid
) {
3472 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
3474 if (document
->dmUpFileGuid
) {
3475 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
3478 /* @dmFileDescr is required */
3479 if (!document
->dmFileDescr
) {
3480 isds_log_message(context
,
3481 _("Document is missing mandatory description (title)"));
3485 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
3487 if (document
->dmFormat
) {
3488 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
3492 /* Insert content (data) of the document. */
3493 /* XXX; Only base64 is implemented currently. */
3494 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
3496 isds_printf_message(context
,
3497 _("Not enought memory to encode %zd bytes into Base64"),
3498 document
->data_length
);
3502 INSERT_STRING(file
, "dmEncodedContent", base64data
);
3510 /* Append XSD tMStatus XML tree into isds_message_copy structure.
3511 * The copy must pre prealocated, the date are just appended into structure.
3512 * @context is ISDS context
3513 * @copy is message copy struture
3514 * @xpath_ctx is XPath context with current node as tMStatus */
3515 static isds_error
append_TMStatus(struct isds_ctx
*context
,
3516 struct isds_message_copy
*copy
, xmlXPathContextPtr xpath_ctx
) {
3517 isds_error err
= IE_SUCCESS
;
3518 xmlXPathObjectPtr result
= NULL
;
3519 char *code
= NULL
, *message
= NULL
;
3521 if (!context
) return IE_INVALID_CONTEXT
;
3522 if (!copy
|| !xpath_ctx
) return IE_INVAL
;
3524 /* Free old values */
3525 zfree(copy
->dmStatus
);
3528 /* Get error specific to this copy */
3529 EXTRACT_STRING("isds:dmStatus/isds:dmStatusCode", code
);
3531 isds_log_message(context
,
3532 _("Missing isds:dmStatusCode under "
3533 "XSD:tMStatus type element"));
3538 if (xmlStrcmp((const xmlChar
*)code
, BAD_CAST
"0000")) {
3539 /* This copy failed */
3540 copy
->error
= IE_ISDS
;
3541 EXTRACT_STRING("isds:dmStatus/isds:dmStatusMessage", message
);
3543 copy
->dmStatus
= astrcat3(code
, ": ", message
);
3544 if (!copy
->dmStatus
) {
3545 copy
->dmStatus
= code
;
3549 copy
->dmStatus
= code
;
3553 /* This copy succeeded. In this case only, message ID is valid */
3554 copy
->error
= IE_SUCCESS
;
3556 EXTRACT_STRING("isds:dmID", copy
->dmID
);
3558 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3559 "but did not returned assigned message ID\n"));
3567 xmlXPathFreeObject(result
);
3572 /* Insert struct isds_approval data (box approval) into XML tree
3573 * @context is sesstion context
3574 * @approval is libsids structure with approval description. NULL is
3576 * @parent is XML element to append @approval to */
3577 static isds_error
insert_GExtApproval(struct isds_ctx
*context
,
3578 const struct isds_approval
*approval
, xmlNodePtr parent
) {
3580 isds_error err
= IE_SUCCESS
;
3583 if (!context
) return IE_INVALID_CONTEXT
;
3584 if (!parent
) return IE_INVAL
;
3586 if (!approval
) return IE_SUCCESS
;
3588 /* Build XSD:gExtApproval */
3589 INSERT_SCALAR_BOOLEAN(parent
, "dbApproved", approval
->approved
);
3590 INSERT_STRING(parent
, "dbExternRefNumber", approval
->refference
);
3597 /* Build ISDS request of XSD tDummyInput type, sent it and check for error
3599 * @context is session context
3600 * @service_name is name of SERVICE_DB_ACCESS
3601 * @response is server SOAP body response as XML document
3602 * @raw_response is automatically reallocated bitstream with response body. Use
3603 * NULL if you don't care
3604 * @raw_response_length is size of @raw_response in bytes
3605 * @code is ISDS status code
3606 * @status_message is ISDS status message
3607 * @return error coded from lower layer, context message will be set up
3609 static isds_error
build_send_check_dbdummy_request(struct isds_ctx
*context
,
3610 const xmlChar
*service_name
,
3611 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
3612 xmlChar
**code
, xmlChar
**status_message
) {
3614 isds_error err
= IE_SUCCESS
;
3615 char *service_name_locale
= NULL
;
3616 xmlNodePtr request
= NULL
, node
;
3617 xmlNsPtr isds_ns
= NULL
;
3619 if (!context
) return IE_INVALID_CONTEXT
;
3620 if (!service_name
) return IE_INVAL
;
3621 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3622 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
3624 /* Free output argument */
3625 xmlFreeDoc(*response
); *response
= NULL
;
3626 if (raw_response
) zfree(*raw_response
);
3628 free(*status_message
);
3631 /* Check if connection is established
3632 * TODO: This check should be done donwstairs. */
3633 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3635 service_name_locale
= utf82locale((char*)service_name
);
3636 if (!service_name_locale
) {
3642 request
= xmlNewNode(NULL
, service_name
);
3644 isds_printf_message(context
,
3645 _("Could not build %s request"), service_name_locale
);
3649 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3651 isds_log_message(context
, _("Could not create ISDS name space"));
3655 xmlSetNs(request
, isds_ns
);
3658 /* Add XSD:tDummyInput child */
3659 INSERT_STRING(request
, "dbDummy", NULL
);
3662 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
3663 service_name_locale
);
3666 err
= isds(context
, SERVICE_DB_ACCESS
, request
, response
,
3667 raw_response
, raw_response_length
);
3668 xmlFreeNode(request
); request
= NULL
;
3671 isds_log(ILF_ISDS
, ILL_DEBUG
,
3672 _("Processing ISDS response on %s request failed\n"),
3673 service_name_locale
);
3677 /* Check for response status */
3678 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, *response
,
3679 code
, status_message
, NULL
);
3681 isds_log(ILF_ISDS
, ILL_DEBUG
,
3682 _("ISDS response on %s request is missing status\n"),
3683 service_name_locale
);
3687 /* Request processed, but nothing found */
3688 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3689 char *code_locale
= utf82locale((char*) *code
);
3690 char *status_message_locale
= utf82locale((char*) *status_message
);
3691 isds_log(ILF_ISDS
, ILL_DEBUG
,
3692 _("Server refused %s request (code=%s, message=%s)\n"),
3693 service_name_locale
, code_locale
, status_message_locale
);
3694 isds_log_message(context
, status_message_locale
);
3696 free(status_message_locale
);
3702 free(service_name_locale
);
3703 xmlFreeNode(request
);
3708 /* Get data about logged in user and his box. */
3709 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
3710 struct isds_DbOwnerInfo
**db_owner_info
) {
3711 isds_error err
= IE_SUCCESS
;
3712 xmlDocPtr response
= NULL
;
3713 xmlChar
*code
= NULL
, *message
= NULL
;
3714 xmlXPathContextPtr xpath_ctx
= NULL
;
3715 xmlXPathObjectPtr result
= NULL
;
3716 char *string
= NULL
;
3718 if (!context
) return IE_INVALID_CONTEXT
;
3719 if (!db_owner_info
) return IE_INVAL
;
3721 /* Check if connection is established */
3722 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3725 /* Do request and check for success */
3726 err
= build_send_check_dbdummy_request(context
,
3727 BAD_CAST
"GetOwnerInfoFromLogin",
3728 &response
, NULL
, NULL
, &code
, &message
);
3729 if (err
) goto leave
;
3733 /* Prepare stucture */
3734 isds_DbOwnerInfo_free(db_owner_info
);
3735 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
3736 if (!*db_owner_info
) {
3740 xpath_ctx
= xmlXPathNewContext(response
);
3745 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3750 /* Set context node */
3751 result
= xmlXPathEvalExpression(BAD_CAST
3752 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
3757 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3758 isds_log_message(context
, _("Missing dbOwnerInfo element"));
3762 if (result
->nodesetval
->nodeNr
> 1) {
3763 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
3767 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3768 xmlXPathFreeObject(result
); result
= NULL
;
3771 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
3775 isds_DbOwnerInfo_free(db_owner_info
);
3779 xmlXPathFreeObject(result
);
3780 xmlXPathFreeContext(xpath_ctx
);
3784 xmlFreeDoc(response
);
3787 isds_log(ILF_ISDS
, ILL_DEBUG
,
3788 _("GetOwnerInfoFromLogin request processed by server "
3789 "successfully.\n"));
3795 /* Get data about logged in user. */
3796 isds_error
isds_GetUserInfoFromLogin(struct isds_ctx
*context
,
3797 struct isds_DbUserInfo
**db_user_info
) {
3798 isds_error err
= IE_SUCCESS
;
3799 xmlDocPtr response
= NULL
;
3800 xmlChar
*code
= NULL
, *message
= NULL
;
3801 xmlXPathContextPtr xpath_ctx
= NULL
;
3802 xmlXPathObjectPtr result
= NULL
;
3804 if (!context
) return IE_INVALID_CONTEXT
;
3805 if (!db_user_info
) return IE_INVAL
;
3807 /* Check if connection is established */
3808 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3811 /* Do request and check for success */
3812 err
= build_send_check_dbdummy_request(context
,
3813 BAD_CAST
"GetUserInfoFromLogin",
3814 &response
, NULL
, NULL
, &code
, &message
);
3815 if (err
) goto leave
;
3819 /* Prepare stucture */
3820 isds_DbUserInfo_free(db_user_info
);
3821 *db_user_info
= calloc(1, sizeof(**db_user_info
));
3822 if (!*db_user_info
) {
3826 xpath_ctx
= xmlXPathNewContext(response
);
3831 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3836 /* Set context node */
3837 result
= xmlXPathEvalExpression(BAD_CAST
3838 "/isds:GetUserInfoFromLoginResponse/isds:dbUserInfo", xpath_ctx
);
3843 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3844 isds_log_message(context
, _("Missing dbUserInfo element"));
3848 if (result
->nodesetval
->nodeNr
> 1) {
3849 isds_log_message(context
, _("Multiple dbUserInfo element"));
3853 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3854 xmlXPathFreeObject(result
); result
= NULL
;
3857 err
= extract_DbUserInfo(context
, db_user_info
, xpath_ctx
);
3861 isds_DbUserInfo_free(db_user_info
);
3864 xmlXPathFreeObject(result
);
3865 xmlXPathFreeContext(xpath_ctx
);
3869 xmlFreeDoc(response
);
3872 isds_log(ILF_ISDS
, ILL_DEBUG
,
3873 _("GetUserInfoFromLogin request processed by server "
3874 "successfully.\n"));
3880 /* Get expiration time of current password
3881 * @context is session context
3882 * @expiration is automatically reallocated time when password expires, In
3883 * case of error will be nulled. */
3884 isds_error
isds_get_password_expiration(struct isds_ctx
*context
,
3885 struct timeval
**expiration
) {
3886 isds_error err
= IE_SUCCESS
;
3887 xmlDocPtr response
= NULL
;
3888 xmlChar
*code
= NULL
, *message
= NULL
;
3889 xmlXPathContextPtr xpath_ctx
= NULL
;
3890 xmlXPathObjectPtr result
= NULL
;
3891 char *string
= NULL
;
3893 if (!context
) return IE_INVALID_CONTEXT
;
3894 if (!expiration
) return IE_INVAL
;
3896 /* Check if connection is established */
3897 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3900 /* Do request and check for success */
3901 err
= build_send_check_dbdummy_request(context
,
3902 BAD_CAST
"GetPasswordInfo",
3903 &response
, NULL
, NULL
, &code
, &message
);
3904 if (err
) goto leave
;
3908 xpath_ctx
= xmlXPathNewContext(response
);
3913 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
3918 /* Set context node */
3919 result
= xmlXPathEvalExpression(BAD_CAST
3920 "/isds:GetPasswordInfoResponse", xpath_ctx
);
3925 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3926 isds_log_message(context
,
3927 _("Missing GetPasswordInfoResponse element"));
3931 if (result
->nodesetval
->nodeNr
> 1) {
3932 isds_log_message(context
,
3933 _("Multiple GetPasswordInfoResponse element"));
3937 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3938 xmlXPathFreeObject(result
); result
= NULL
;
3940 /* Extract expiration date */
3941 EXTRACT_STRING("isds:pswExpDate", string
);
3943 isds_log_message(context
, _("Missing pswExpDate element"));
3948 err
= timestring2timeval((xmlChar
*) string
, expiration
);
3950 char *string_locale
= utf82locale(string
);
3951 if (err
== IE_DATE
) err
= IE_ISDS
;
3952 isds_printf_message(context
,
3953 _("Could not convert pswExpDate as ISO time: %s"),
3955 free(string_locale
);
3967 xmlXPathFreeObject(result
);
3968 xmlXPathFreeContext(xpath_ctx
);
3972 xmlFreeDoc(response
);
3975 isds_log(ILF_ISDS
, ILL_DEBUG
,
3976 _("GetPasswordInfo request processed by server "
3977 "successfully.\n"));
3983 /* Change user password in ISDS.
3984 * User must supply old password, new password will takes effect after some
3985 * time, current session can continue. Password must fulfill some constraints.
3986 * @context is session context
3987 * @old_password is current password.
3988 * @new_password is requested new password */
3989 isds_error
isds_change_password(struct isds_ctx
*context
,
3990 const char *old_password
, const char *new_password
) {
3991 isds_error err
= IE_SUCCESS
;
3992 xmlNsPtr isds_ns
= NULL
;
3993 xmlNodePtr request
= NULL
, node
;
3994 xmlDocPtr response
= NULL
;
3995 xmlChar
*code
= NULL
, *message
= NULL
;
3997 if (!context
) return IE_INVALID_CONTEXT
;
3998 if (!old_password
|| !new_password
) return IE_INVAL
;
4000 /* Check if connection is established
4001 * TODO: This check should be done donwstairs. */
4002 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4005 /* Build ChangeISDSPassword request */
4006 request
= xmlNewNode(NULL
, BAD_CAST
"ChangeISDSPassword");
4008 isds_log_message(context
,
4009 _("Could build ChangeISDSPassword request"));
4012 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4014 isds_log_message(context
, _("Could not create ISDS name space"));
4015 xmlFreeNode(request
);
4018 xmlSetNs(request
, isds_ns
);
4020 INSERT_STRING(request
, "dbOldPassword", old_password
);
4021 INSERT_STRING(request
, "dbNewPassword", new_password
);
4024 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
4027 err
= isds(context
, SERVICE_DB_ACCESS
, request
, &response
, NULL
, NULL
);
4029 /* Destroy request */
4030 xmlFreeNode(request
); request
= NULL
;
4033 isds_log(ILF_ISDS
, ILL_DEBUG
,
4034 _("Processing ISDS response on ChangeISDSPassword "
4035 "request failed\n"));
4039 /* Check for response status */
4040 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, response
,
4041 &code
, &message
, NULL
);
4043 isds_log(ILF_ISDS
, ILL_DEBUG
,
4044 _("ISDS response on ChangeISDSPassword request is missing "
4049 /* Request processed, but empty password refused */
4050 if (!xmlStrcmp(code
, BAD_CAST
"1066")) {
4051 char *code_locale
= utf82locale((char*)code
);
4052 char *message_locale
= utf82locale((char*)message
);
4053 isds_log(ILF_ISDS
, ILL_DEBUG
,
4054 _("Server refused empty password on ChangeISDSPassword "
4055 "request (code=%s, message=%s)\n"),
4056 code_locale
, message_locale
);
4057 isds_log_message(context
, _("Password must not be empty"));
4059 free(message_locale
);
4064 /* Request processed, but new password was reused */
4065 else if (!xmlStrcmp(code
, BAD_CAST
"1067")) {
4066 char *code_locale
= utf82locale((char*)code
);
4067 char *message_locale
= utf82locale((char*)message
);
4068 isds_log(ILF_ISDS
, ILL_DEBUG
,
4069 _("Server refused the same new password on ChangeISDSPassword "
4070 "request (code=%s, message=%s)\n"),
4071 code_locale
, message_locale
);
4072 isds_log_message(context
,
4073 _("New password must differ from the current one"));
4075 free(message_locale
);
4081 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4082 char *code_locale
= utf82locale((char*)code
);
4083 char *message_locale
= utf82locale((char*)message
);
4084 isds_log(ILF_ISDS
, ILL_DEBUG
,
4085 _("Server refused to change password on ChangeISDSPassword "
4086 "request (code=%s, message=%s)\n"),
4087 code_locale
, message_locale
);
4088 isds_log_message(context
, message_locale
);
4090 free(message_locale
);
4095 /* Otherwise password changed successfully */
4100 xmlFreeDoc(response
);
4101 xmlFreeNode(request
);
4104 isds_log(ILF_ISDS
, ILL_DEBUG
,
4105 _("Password changed successfully on ChangeISDSPassword "
4112 /* Generic middle part with request sending and response check.
4113 * It sends prepared request and checks for error code.
4114 * @context is ISDS session context.
4115 * @service is ISDS service handler
4116 * @service_name is name in scope of given @service
4117 * @request is XML tree with request. Will be freed to save memory.
4118 * @response is XML document ouputing ISDS response.
4119 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4120 * NULL, if you don't care. */
4121 static isds_error
send_destroy_request_check_response(
4122 struct isds_ctx
*context
,
4123 const isds_service service
, const xmlChar
*service_name
,
4124 xmlNodePtr
*request
, xmlDocPtr
*response
, xmlChar
**refnumber
) {
4125 isds_error err
= IE_SUCCESS
;
4126 char *service_name_locale
= NULL
;
4127 xmlChar
*code
= NULL
, *message
= NULL
;
4130 if (!context
) return IE_INVALID_CONTEXT
;
4131 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
||
4135 /* Check if connection is established
4136 * TODO: This check should be done donwstairs. */
4137 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4139 service_name_locale
= utf82locale((char*) service_name
);
4140 if (!service_name_locale
) {
4145 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
4146 service_name_locale
);
4149 err
= isds(context
, service
, *request
, response
, NULL
, NULL
);
4150 xmlFreeNode(*request
); *request
= NULL
;
4153 isds_log(ILF_ISDS
, ILL_DEBUG
,
4154 _("Processing ISDS response on %s request failed\n"),
4155 service_name_locale
);
4159 /* Check for response status */
4160 err
= isds_response_status(context
, service
, *response
,
4161 &code
, &message
, refnumber
);
4163 isds_log(ILF_ISDS
, ILL_DEBUG
,
4164 _("ISDS response on %s request is missing status\n"),
4165 service_name_locale
);
4169 /* Request processed, but server failed */
4170 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4171 char *code_locale
= utf82locale((char*) code
);
4172 char *message_locale
= utf82locale((char*) message
);
4173 isds_log(ILF_ISDS
, ILL_DEBUG
,
4174 _("Server refused %s request (code=%s, message=%s)\n"),
4175 service_name_locale
, code_locale
, message_locale
);
4176 isds_log_message(context
, message_locale
);
4178 free(message_locale
);
4187 if (err
&& *response
) {
4188 xmlFreeDoc(*response
);
4192 xmlFreeNode(*request
);
4195 free(service_name_locale
);
4201 /* Generic bottom half with request sending.
4202 * It sends prepared request, checks for error code, destroys response and
4203 * request and log success or failure.
4204 * @context is ISDS session context.
4205 * @service is ISDS service handler
4206 * @service_name is name in scope of given @service
4207 * @request is XML tree with request. Will be freed to save memory.
4208 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4209 * NULL, if you don't care. */
4210 static isds_error
send_request_check_drop_response(
4211 struct isds_ctx
*context
,
4212 const isds_service service
, const xmlChar
*service_name
,
4213 xmlNodePtr
*request
, xmlChar
**refnumber
) {
4214 isds_error err
= IE_SUCCESS
;
4215 xmlDocPtr response
= NULL
;
4218 if (!context
) return IE_INVALID_CONTEXT
;
4219 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
)
4222 /* Send request and check response*/
4223 err
= send_destroy_request_check_response(context
,
4224 service
, service_name
, request
, &response
, refnumber
);
4226 xmlFreeDoc(response
);
4229 xmlFreeNode(*request
);
4234 char *service_name_locale
= utf82locale((char *) service_name
);
4235 isds_log(ILF_ISDS
, ILL_DEBUG
,
4236 _("%s request processed by server successfully.\n"),
4237 service_name_locale
);
4238 free(service_name_locale
);
4245 /* Build XSD:tCreateDBInput request type for box createing.
4246 * @context is session context
4247 * @request outputs built XML tree
4248 * @service_name is request name of SERVICE_DB_MANIPULATION service
4249 * @box is box description to create including single primary user (in case of
4251 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4252 * box, or contact address of PFO box owner)
4253 * @former_names is optional undocumented string. Pass NULL if you don't care.
4254 * @upper_box_id is optional ID of supper box if currently created box is
4256 * @ceo_label is optional title of OVM box owner (e.g. mayor) NULL, if you
4258 * @approval is optional external approval of box manipulation */
4259 static isds_error
build_CreateDBInput_request(struct isds_ctx
*context
,
4260 xmlNodePtr
*request
, const xmlChar
*service_name
,
4261 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4262 const xmlChar
*former_names
, const xmlChar
*upper_box_id
,
4263 const xmlChar
*ceo_label
, const struct isds_approval
*approval
) {
4264 isds_error err
= IE_SUCCESS
;
4265 xmlNsPtr isds_ns
= NULL
;
4266 xmlNodePtr node
, dbPrimaryUsers
;
4267 xmlChar
*string
= NULL
;
4268 const struct isds_list
*item
;
4271 if (!context
) return IE_INVALID_CONTEXT
;
4272 if (!request
|| !service_name
|| service_name
[0] == '\0' || !box
)
4276 /* Build DeleteDataBox request */
4277 *request
= xmlNewNode(NULL
, service_name
);
4279 char *service_name_locale
= utf82locale((char*) service_name
);
4280 isds_printf_message(context
, _("Could build %s request"),
4281 service_name_locale
);
4282 free(service_name_locale
);
4285 isds_ns
= xmlNewNs(*request
, BAD_CAST ISDS_NS
, NULL
);
4287 isds_log_message(context
, _("Could not create ISDS name space"));
4288 xmlFreeNode(*request
);
4291 xmlSetNs(*request
, isds_ns
);
4293 INSERT_ELEMENT(node
, *request
, "dbOwnerInfo");
4294 err
= insert_DbOwnerInfo(context
, box
, node
);
4295 if (err
) goto leave
;
4298 /* XXX: There is bug in XSD: XSD says at least one dbUserInfo must exist,
4299 * verbose documentatiot allows none dbUserInfo */
4300 INSERT_ELEMENT(dbPrimaryUsers
, *request
, "dbPrimaryUsers");
4301 for (item
= users
; item
; item
= item
->next
) {
4303 INSERT_ELEMENT(node
, dbPrimaryUsers
, "dbUserInfo");
4304 err
= insert_DbUserInfo(context
,
4305 (struct isds_DbUserInfo
*) item
->data
, node
);
4306 if (err
) goto leave
;
4310 INSERT_STRING(*request
, "dbFormerNames", former_names
);
4311 INSERT_STRING(*request
, "dbUpperDBId", upper_box_id
);
4312 INSERT_STRING(*request
, "dbCEOLabel", ceo_label
);
4314 err
= insert_GExtApproval(context
, approval
, *request
);
4315 if (err
) goto leave
;
4319 xmlFreeNode(*request
);
4328 * @context is session context
4329 * @box is box description to create including single primary user (in case of
4330 * FO box type). It outputs box ID assigned by ISDS in dbID element.
4331 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4332 * box, or contact address of PFO box owner)
4333 * @former_names is optional undocumented string. Pass NULL if you don't care.
4334 * @upper_box_id is optional ID of supper box if currently created box is
4336 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4337 * @approval is optional external approval of box manipulation
4338 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4339 * NULL, if you don't care.*/
4340 isds_error
isds_add_box(struct isds_ctx
*context
,
4341 struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4342 const char *former_names
, const char *upper_box_id
,
4343 const char *ceo_label
, const struct isds_approval
*approval
,
4345 isds_error err
= IE_SUCCESS
;
4346 xmlNodePtr request
= NULL
;
4347 xmlDocPtr response
= NULL
;
4348 xmlXPathContextPtr xpath_ctx
= NULL
;
4349 xmlXPathObjectPtr result
= NULL
;
4352 if (!context
) return IE_INVALID_CONTEXT
;
4353 if (!box
) return IE_INVAL
;
4355 /* Scratch box ID */
4358 /* Build CreateDataBox request */
4359 err
= build_CreateDBInput_request(context
,
4360 &request
, BAD_CAST
"CreateDataBox",
4361 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4362 (xmlChar
*) ceo_label
, approval
);
4363 if (err
) goto leave
;
4365 /* Send it to server and process response */
4366 err
= send_destroy_request_check_response(context
,
4367 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4368 &response
, (xmlChar
**) refnumber
);
4370 /* Extract box ID */
4371 xpath_ctx
= xmlXPathNewContext(response
);
4376 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4380 EXTRACT_STRING("/isds:CreateDataBoxResponse/dbID", box
->dbID
);
4383 xmlXPathFreeObject(result
);
4384 xmlXPathFreeContext(xpath_ctx
);
4385 xmlFreeDoc(response
);
4386 xmlFreeNode(request
);
4389 isds_log(ILF_ISDS
, ILL_DEBUG
,
4390 _("CreateDataBox request processed by server successfully.\n"));
4397 /* Notify ISDS about new PFO entity.
4398 * This function has no real effect.
4399 * @context is session context
4400 * @box is PFO description including single primary user.
4401 * @users is list of struct isds_DbUserInfo (contact address of PFO box owner)
4402 * @former_names is optional undocumented string. Pass NULL if you don't care.
4403 * @upper_box_id is optional ID of supper box if currently created box is
4405 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4406 * @approval is optional external approval of box manipulation
4407 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4408 * NULL, if you don't care.*/
4409 isds_error
isds_add_pfoinfo(struct isds_ctx
*context
,
4410 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4411 const char *former_names
, const char *upper_box_id
,
4412 const char *ceo_label
, const struct isds_approval
*approval
,
4414 isds_error err
= IE_SUCCESS
;
4415 xmlNodePtr request
= NULL
;
4417 if (!context
) return IE_INVALID_CONTEXT
;
4418 if (!box
) return IE_INVAL
;
4420 /* Build CreateDataBoxPFOInfo request */
4421 err
= build_CreateDBInput_request(context
,
4422 &request
, BAD_CAST
"CreateDataBoxPFOInfo",
4423 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4424 (xmlChar
*) ceo_label
, approval
);
4425 if (err
) goto leave
;
4427 /* Send it to server and process response */
4428 err
= send_request_check_drop_response(context
,
4429 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4430 (xmlChar
**) refnumber
);
4432 xmlFreeNode(request
);
4437 /* Remove given given box permanetly.
4438 * @context is session context
4439 * @box is box description to delete
4440 * @since is date of box owner cancalation. Only tm_year, tm_mon and tm_mday
4442 * @approval is optional external approval of box manipulation
4443 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4444 * NULL, if you don't care.*/
4445 isds_error
isds_delete_box(struct isds_ctx
*context
,
4446 const struct isds_DbOwnerInfo
*box
, const struct tm
*since
,
4447 const struct isds_approval
*approval
, char **refnumber
) {
4448 isds_error err
= IE_SUCCESS
;
4449 xmlNsPtr isds_ns
= NULL
;
4450 xmlNodePtr request
= NULL
;
4452 xmlChar
*string
= NULL
;
4455 if (!context
) return IE_INVALID_CONTEXT
;
4456 if (!box
|| !since
) return IE_INVAL
;
4459 /* Build DeleteDataBox request */
4460 request
= xmlNewNode(NULL
, BAD_CAST
"DeleteDataBox");
4462 isds_log_message(context
,
4463 _("Could build DeleteDataBox request"));
4466 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4468 isds_log_message(context
, _("Could not create ISDS name space"));
4469 xmlFreeNode(request
);
4472 xmlSetNs(request
, isds_ns
);
4474 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4475 err
= insert_DbOwnerInfo(context
, box
, node
);
4476 if (err
) goto leave
;
4478 err
= tm2datestring(since
, &string
);
4480 isds_log_message(context
,
4481 _("Could not convert `since' argument to ISO date string"));
4484 INSERT_STRING(request
, "dbOwnerTerminationDate", string
);
4487 err
= insert_GExtApproval(context
, approval
, request
);
4488 if (err
) goto leave
;
4491 /* Send it to server and process response */
4492 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4493 BAD_CAST
"DeleteDataBox", &request
, (xmlChar
**) refnumber
);
4496 xmlFreeNode(request
);
4502 /* Update data about given box.
4503 * @context is session context
4504 * @old_box current box description
4505 * @new_box are updated data about @old_box
4506 * @approval is optional external approval of box manipulation
4507 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4508 * NULL, if you don't care.*/
4509 isds_error
isds_UpdateDataBoxDescr(struct isds_ctx
*context
,
4510 const struct isds_DbOwnerInfo
*old_box
,
4511 const struct isds_DbOwnerInfo
*new_box
,
4512 const struct isds_approval
*approval
, char **refnumber
) {
4513 isds_error err
= IE_SUCCESS
;
4514 xmlNsPtr isds_ns
= NULL
;
4515 xmlNodePtr request
= NULL
;
4519 if (!context
) return IE_INVALID_CONTEXT
;
4520 if (!old_box
|| !new_box
) return IE_INVAL
;
4523 /* Build UpdateDataBoxDescr request */
4524 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxDescr");
4526 isds_log_message(context
,
4527 _("Could build UpdateDataBoxDescr request"));
4530 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4532 isds_log_message(context
, _("Could not create ISDS name space"));
4533 xmlFreeNode(request
);
4536 xmlSetNs(request
, isds_ns
);
4538 INSERT_ELEMENT(node
, request
, "dbOldOwnerInfo");
4539 err
= insert_DbOwnerInfo(context
, old_box
, node
);
4540 if (err
) goto leave
;
4542 INSERT_ELEMENT(node
, request
, "dbNewOwnerInfo");
4543 err
= insert_DbOwnerInfo(context
, new_box
, node
);
4544 if (err
) goto leave
;
4546 err
= insert_GExtApproval(context
, approval
, request
);
4547 if (err
) goto leave
;
4550 /* Send it to server and process response */
4551 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4552 BAD_CAST
"UpdateDataBoxDescr", &request
, (xmlChar
**) refnumber
);
4555 xmlFreeNode(request
);
4561 /* Build ISDS request of XSD tIdDbInput type, sent it and check for error
4563 * @context is session context
4564 * @service is SOAP service
4565 * @service_name is name of request in @service
4566 * @box_id is box ID of interrest
4567 * @approval is optional external approval of box manipulation
4568 * @response is server SOAP body response as XML document
4569 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4570 * NULL, if you don't care.
4571 * @return error coded from lower layer, context message will be set up
4573 static isds_error
build_send_dbid_request_check_response(
4574 struct isds_ctx
*context
, const isds_service service
,
4575 const xmlChar
*service_name
, const xmlChar
*box_id
,
4576 const struct isds_approval
*approval
,
4577 xmlDocPtr
*response
, xmlChar
**refnumber
) {
4579 isds_error err
= IE_SUCCESS
;
4580 char *service_name_locale
= NULL
, *box_id_locale
= NULL
;
4581 xmlNodePtr request
= NULL
, node
;
4582 xmlNsPtr isds_ns
= NULL
;
4584 if (!context
) return IE_INVALID_CONTEXT
;
4585 if (!service_name
|| !box_id
) return IE_INVAL
;
4586 if (!response
) return IE_INVAL
;
4588 /* Free output argument */
4589 xmlFreeDoc(*response
); *response
= NULL
;
4591 /* Prepare strings */
4592 service_name_locale
= utf82locale((char*)service_name
);
4593 if (!service_name_locale
) {
4597 box_id_locale
= utf82locale((char*)box_id
);
4598 if (!box_id_locale
) {
4604 request
= xmlNewNode(NULL
, service_name
);
4606 isds_printf_message(context
,
4607 _("Could not build %s request"), service_name_locale
);
4611 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4613 isds_log_message(context
, _("Could not create ISDS name space"));
4617 xmlSetNs(request
, isds_ns
);
4619 /* Add XSD:tIdDbInput childs*/
4620 INSERT_STRING(request
, "dbID", box_id
);
4621 err
= insert_GExtApproval(context
, approval
, request
);
4622 if (err
) goto leave
;
4624 /* Send request and check response*/
4625 err
= send_destroy_request_check_response(context
,
4626 service
, service_name
, &request
, response
, refnumber
);
4629 free(service_name_locale
);
4630 free(box_id_locale
);
4631 xmlFreeNode(request
);
4636 /* Get data about all users assigned to given box.
4637 * @context is session context
4639 * @users is automatically reallocated list of struct isds_DbUserInfo */
4640 isds_error
isds_GetDataBoxUsers(struct isds_ctx
*context
, const char *box_id
,
4641 struct isds_list
**users
) {
4642 isds_error err
= IE_SUCCESS
;
4643 xmlDocPtr response
= NULL
;
4644 xmlXPathContextPtr xpath_ctx
= NULL
;
4645 xmlXPathObjectPtr result
= NULL
;
4647 struct isds_list
*item
, *prev_item
= NULL
;
4649 if (!context
) return IE_INVALID_CONTEXT
;
4650 if (!users
|| !box_id
) return IE_INVAL
;
4653 /* Do request and check for success */
4654 err
= build_send_dbid_request_check_response(context
,
4655 SERVICE_DB_MANIPULATION
, BAD_CAST
"GetDataBoxUsers",
4656 BAD_CAST box_id
, NULL
, &response
, NULL
);
4657 if (err
) goto leave
;
4661 /* Prepare stucture */
4662 isds_list_free(users
);
4663 xpath_ctx
= xmlXPathNewContext(response
);
4668 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4673 /* Set context node */
4674 result
= xmlXPathEvalExpression(BAD_CAST
4675 "/isds:GetDataBoxUsersResponse/isds:dbUsers/isds:dbUserInfo",
4681 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4682 isds_log_message(context
, _("Missing dbUserInfo element"));
4687 /* Iterate over all users */
4688 for (i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
4690 /* Prepare structure */
4691 item
= calloc(1, sizeof(*item
));
4696 item
->destructor
= (void(*)(void**))isds_DbUserInfo_free
;
4697 if (i
== 0) *users
= item
;
4698 else prev_item
->next
= item
;
4702 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
4703 err
= extract_DbUserInfo(context
,
4704 (struct isds_DbUserInfo
**) (&item
->data
), xpath_ctx
);
4705 if (err
) goto leave
;
4710 isds_list_free(users
);
4713 xmlXPathFreeObject(result
);
4714 xmlXPathFreeContext(xpath_ctx
);
4715 xmlFreeDoc(response
);
4718 isds_log(ILF_ISDS
, ILL_DEBUG
,
4719 _("GetDataBoxUsers request processed by server "
4720 "successfully.\n"));
4726 /* Update data about user assigned to given box.
4727 * @context is session context
4728 * @box is box identification
4729 * @old_user identifies user to update
4730 * @new_user are updated data about @old_user
4731 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4732 * NULL, if you don't care.*/
4733 isds_error
isds_UpdateDataBoxUser(struct isds_ctx
*context
,
4734 const struct isds_DbOwnerInfo
*box
,
4735 const struct isds_DbUserInfo
*old_user
,
4736 const struct isds_DbUserInfo
*new_user
,
4738 isds_error err
= IE_SUCCESS
;
4739 xmlNsPtr isds_ns
= NULL
;
4740 xmlNodePtr request
= NULL
;
4744 if (!context
) return IE_INVALID_CONTEXT
;
4745 if (!box
|| !old_user
|| !new_user
) return IE_INVAL
;
4748 /* Build UpdateDataBoxUser request */
4749 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxUser");
4751 isds_log_message(context
,
4752 _("Could build UpdateDataBoxUser request"));
4755 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4757 isds_log_message(context
, _("Could not create ISDS name space"));
4758 xmlFreeNode(request
);
4761 xmlSetNs(request
, isds_ns
);
4763 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4764 err
= insert_DbOwnerInfo(context
, box
, node
);
4765 if (err
) goto leave
;
4767 INSERT_ELEMENT(node
, request
, "dbOldUserInfo");
4768 err
= insert_DbUserInfo(context
, old_user
, node
);
4769 if (err
) goto leave
;
4771 INSERT_ELEMENT(node
, request
, "dbNewUserInfo");
4772 err
= insert_DbUserInfo(context
, new_user
, node
);
4773 if (err
) goto leave
;
4775 /* Send it to server and process response */
4776 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4777 BAD_CAST
"UpdateDataBoxUser", &request
, (xmlChar
**) refnumber
);
4780 xmlFreeNode(request
);
4786 /* Reset credentials of user assigned to given box.
4787 * @context is session context
4788 * @box is box identification
4789 * @user identifies user to reset password
4790 * @fee_paid is true if fee has been paid, false otherwise
4791 * @approval is optional external approval of box manipulation
4792 * @token is NULL if new password should be delivered off-line to the user.
4793 * It is valid pointer if user should obtain new password on-line on dedicated
4794 * web server. Then it output automatically reallocated token user needs to
4795 * use to athtorize on the web server to view his new password.
4796 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4797 * NULL, if you don't care.*/
4798 isds_error
isds_reset_password(struct isds_ctx
*context
,
4799 const struct isds_DbOwnerInfo
*box
,
4800 const struct isds_DbUserInfo
*user
,
4801 const _Bool fee_paid
, const struct isds_approval
*approval
,
4802 char **token
, char **refnumber
) {
4803 isds_error err
= IE_SUCCESS
;
4804 xmlNsPtr isds_ns
= NULL
;
4805 xmlNodePtr request
= NULL
, node
;
4806 xmlDocPtr response
= NULL
;
4807 xmlXPathContextPtr xpath_ctx
= NULL
;
4808 xmlXPathObjectPtr result
= NULL
;
4811 if (!context
) return IE_INVALID_CONTEXT
;
4812 if (!box
|| !user
) return IE_INVAL
;
4814 if (token
) zfree(*token
);
4817 /* Build NewAccessData request */
4818 request
= xmlNewNode(NULL
, BAD_CAST
"NewAccessData");
4820 isds_log_message(context
,
4821 _("Could build NewAccessData request"));
4824 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4826 isds_log_message(context
, _("Could not create ISDS name space"));
4827 xmlFreeNode(request
);
4830 xmlSetNs(request
, isds_ns
);
4832 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4833 err
= insert_DbOwnerInfo(context
, box
, node
);
4834 if (err
) goto leave
;
4836 INSERT_ELEMENT(node
, request
, "dbUserInfo");
4837 err
= insert_DbUserInfo(context
, user
, node
);
4838 if (err
) goto leave
;
4840 INSERT_SCALAR_BOOLEAN(request
, "dbFeePaid", fee_paid
);
4843 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 1);
4845 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 0);
4848 err
= insert_GExtApproval(context
, approval
, request
);
4849 if (err
) goto leave
;
4851 /* Send request and check reposne*/
4852 err
= send_destroy_request_check_response(context
,
4853 SERVICE_DB_MANIPULATION
, BAD_CAST
"NewAccessData", &request
,
4854 &response
, (xmlChar
**) refnumber
);
4855 if (err
) goto leave
;
4858 /* Extract optional token */
4860 xpath_ctx
= xmlXPathNewContext(response
);
4865 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4870 EXTRACT_STRING("/isds:NewAccessDataResponse/dbAccessDataId", *token
);
4874 xmlXPathFreeObject(result
);
4875 xmlXPathFreeContext(xpath_ctx
);
4876 xmlFreeDoc(response
);
4877 xmlFreeNode(request
);
4880 isds_log(ILF_ISDS
, ILL_DEBUG
,
4881 _("NewAccessData request processed by server "
4882 "successfully.\n"));
4888 /* Build ISDS request of XSD tAddDBUserInput type, sent it, check for error
4889 * code, destroy response and log success.
4890 * @context is ISDS session context.
4891 * @service_name is name of SERVICE_DB_MANIPULATION service
4892 * @box is box identification
4893 * @user identifies user to removve
4894 * @approval is optional external approval of box manipulation
4895 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4896 * NULL, if you don't care. */
4897 static isds_error
build_send_manipulationboxuser_request_check_drop_response(
4898 struct isds_ctx
*context
, const xmlChar
*service_name
,
4899 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4900 const struct isds_approval
*approval
, xmlChar
**refnumber
) {
4901 isds_error err
= IE_SUCCESS
;
4902 xmlNsPtr isds_ns
= NULL
;
4903 xmlNodePtr request
= NULL
, node
;
4906 if (!context
) return IE_INVALID_CONTEXT
;
4907 if (!service_name
|| service_name
[0] == '\0' || !box
|| !user
)
4911 /* Build NewAccessData request */
4912 request
= xmlNewNode(NULL
, service_name
);
4914 char *service_name_locale
= utf82locale((char *) service_name
);
4915 isds_printf_message(context
, _("Could build %s request"),
4916 service_name_locale
);
4917 free(service_name_locale
);
4920 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4922 isds_log_message(context
, _("Could not create ISDS name space"));
4923 xmlFreeNode(request
);
4926 xmlSetNs(request
, isds_ns
);
4928 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4929 err
= insert_DbOwnerInfo(context
, box
, node
);
4930 if (err
) goto leave
;
4932 INSERT_ELEMENT(node
, request
, "dbUserInfo");
4933 err
= insert_DbUserInfo(context
, user
, node
);
4934 if (err
) goto leave
;
4936 err
= insert_GExtApproval(context
, approval
, request
);
4937 if (err
) goto leave
;
4939 /* Send request and check reposne*/
4940 err
= send_request_check_drop_response (context
,
4941 SERVICE_DB_MANIPULATION
, service_name
, &request
, refnumber
);
4944 xmlFreeNode(request
);
4949 /* Assign new user to given box.
4950 * @context is session context
4951 * @box is box identification
4952 * @user defines new user to add
4953 * @approval is optional external approval of box manipulation
4954 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4955 * NULL, if you don't care.*/
4956 isds_error
isds_add_user(struct isds_ctx
*context
,
4957 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4958 const struct isds_approval
*approval
, char **refnumber
) {
4959 return build_send_manipulationboxuser_request_check_drop_response(context
,
4960 BAD_CAST
"AddDataBoxUser", box
, user
, approval
,
4961 (xmlChar
**) refnumber
);
4965 /* Remove user assigned to given box.
4966 * @context is session context
4967 * @box is box identification
4968 * @user identifies user to removve
4969 * @approval is optional external approval of box manipulation
4970 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4971 * NULL, if you don't care.*/
4972 isds_error
isds_delete_user(struct isds_ctx
*context
,
4973 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
4974 const struct isds_approval
*approval
, char **refnumber
) {
4975 return build_send_manipulationboxuser_request_check_drop_response(context
,
4976 BAD_CAST
"DeleteDataBoxUser", box
, user
, approval
,
4977 (xmlChar
**) refnumber
);
4981 /* Find boxes suiting given criteria.
4982 * @criteria is filter. You should fill in at least some memebers.
4983 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
4984 * possibly empty. Input NULL or valid old structure.
4986 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
4987 * IE_NOEXIST if no such box exists, @boxes will be NULL
4988 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
4989 * contains still valid data
4990 * other code if something bad happens. @boxes will be NULL. */
4991 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
4992 const struct isds_DbOwnerInfo
*criteria
,
4993 struct isds_list
**boxes
) {
4994 isds_error err
= IE_SUCCESS
;
4995 _Bool truncated
= 0;
4996 xmlNsPtr isds_ns
= NULL
;
4997 xmlNodePtr request
= NULL
;
4998 xmlDocPtr response
= NULL
;
4999 xmlChar
*code
= NULL
, *message
= NULL
;
5000 xmlNodePtr db_owner_info
;
5001 xmlXPathContextPtr xpath_ctx
= NULL
;
5002 xmlXPathObjectPtr result
= NULL
;
5003 xmlChar
*string
= NULL
;
5006 if (!context
) return IE_INVALID_CONTEXT
;
5007 if (!boxes
) return IE_INVAL
;
5008 isds_list_free(boxes
);
5014 /* Check if connection is established
5015 * TODO: This check should be done donwstairs. */
5016 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5019 /* Build FindDataBox request */
5020 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
5022 isds_log_message(context
,
5023 _("Could build FindDataBox request"));
5026 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5028 isds_log_message(context
, _("Could not create ISDS name space"));
5029 xmlFreeNode(request
);
5032 xmlSetNs(request
, isds_ns
);
5033 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
5034 if (!db_owner_info
) {
5035 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
5036 "FindDataBox element"));
5037 xmlFreeNode(request
);
5041 err
= insert_DbOwnerInfo(context
, criteria
, db_owner_info
);
5042 if (err
) goto leave
;
5045 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
5048 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
5050 /* Destroy request */
5051 xmlFreeNode(request
); request
= NULL
;
5054 isds_log(ILF_ISDS
, ILL_DEBUG
,
5055 _("Processing ISDS response on FindDataBox "
5056 "request failed\n"));
5060 /* Check for response status */
5061 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5062 &code
, &message
, NULL
);
5064 isds_log(ILF_ISDS
, ILL_DEBUG
,
5065 _("ISDS response on FindDataBox request is missing status\n"));
5069 /* Request processed, but nothing found */
5070 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
5071 !xmlStrcmp(code
, BAD_CAST
"5001")) {
5072 char *code_locale
= utf82locale((char*)code
);
5073 char *message_locale
= utf82locale((char*)message
);
5074 isds_log(ILF_ISDS
, ILL_DEBUG
,
5075 _("Server did not found any box on FindDataBox request "
5076 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5077 isds_log_message(context
, message_locale
);
5079 free(message_locale
);
5084 /* Warning, not a error */
5085 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
5086 char *code_locale
= utf82locale((char*)code
);
5087 char *message_locale
= utf82locale((char*)message
);
5088 isds_log(ILF_ISDS
, ILL_DEBUG
,
5089 _("Server truncated response on FindDataBox request "
5090 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5091 isds_log_message(context
, message_locale
);
5093 free(message_locale
);
5098 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5099 char *code_locale
= utf82locale((char*)code
);
5100 char *message_locale
= utf82locale((char*)message
);
5101 isds_log(ILF_ISDS
, ILL_DEBUG
,
5102 _("Server refused FindDataBox request "
5103 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5104 isds_log_message(context
, message_locale
);
5106 free(message_locale
);
5111 xpath_ctx
= xmlXPathNewContext(response
);
5116 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5121 /* Extract boxes if they present */
5122 result
= xmlXPathEvalExpression(BAD_CAST
5123 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
5129 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5130 struct isds_list
*item
, *prev_item
= NULL
;
5131 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
5132 item
= calloc(1, sizeof(*item
));
5138 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
5139 if (i
== 0) *boxes
= item
;
5140 else prev_item
->next
= item
;
5143 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
5144 err
= extract_DbOwnerInfo(context
,
5145 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
5146 if (err
) goto leave
;
5152 isds_list_free(boxes
);
5154 if (truncated
) err
= IE_2BIG
;
5158 xmlFreeNode(request
);
5159 xmlXPathFreeObject(result
);
5160 xmlXPathFreeContext(xpath_ctx
);
5164 xmlFreeDoc(response
);
5167 isds_log(ILF_ISDS
, ILL_DEBUG
,
5168 _("FindDataBox request processed by server successfully.\n"));
5174 /* Get status of a box.
5175 * @context is ISDS session context.
5176 * @box_id is UTF-8 encoded box identifier as zero terminated string
5177 * @box_status is return value of box status.
5179 * IE_SUCCESS if box has been found and its status retrieved
5180 * IE_NOEXIST if box is not known to ISDS server
5181 * or other appropriate error.
5182 * You can use isds_DbState to enumerate box status. However out of enum
5183 * range value can be returned too. This is feature because ISDS
5184 * specification leaves the set of values open.
5185 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
5186 * the box has been deleted, but ISDS still lists its former existence. */
5187 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
5188 long int *box_status
) {
5189 isds_error err
= IE_SUCCESS
;
5190 xmlNsPtr isds_ns
= NULL
;
5191 xmlNodePtr request
= NULL
, db_id
;
5192 xmlDocPtr response
= NULL
;
5193 xmlChar
*code
= NULL
, *message
= NULL
;
5194 xmlXPathContextPtr xpath_ctx
= NULL
;
5195 xmlXPathObjectPtr result
= NULL
;
5196 xmlChar
*string
= NULL
;
5198 if (!context
) return IE_INVALID_CONTEXT
;
5199 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
5201 /* Check if connection is established
5202 * TODO: This check should be done donwstairs. */
5203 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5206 /* Build CheckDataBox request */
5207 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
5209 isds_log_message(context
,
5210 _("Could build CheckDataBox request"));
5213 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5215 isds_log_message(context
, _("Could not create ISDS name space"));
5216 xmlFreeNode(request
);
5219 xmlSetNs(request
, isds_ns
);
5220 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
5222 isds_log_message(context
, _("Could not add dbId Child to "
5223 "CheckDataBox element"));
5224 xmlFreeNode(request
);
5229 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
5232 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
5234 /* Destroy request */
5235 xmlFreeNode(request
);
5238 isds_log(ILF_ISDS
, ILL_DEBUG
,
5239 _("Processing ISDS response on CheckDataBox "
5240 "request failed\n"));
5244 /* Check for response status */
5245 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5246 &code
, &message
, NULL
);
5248 isds_log(ILF_ISDS
, ILL_DEBUG
,
5249 _("ISDS response on CheckDataBox request is missing status\n"));
5253 /* Request processed, but nothing found */
5254 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
5255 char *box_id_locale
= utf82locale((char*)box_id
);
5256 char *code_locale
= utf82locale((char*)code
);
5257 char *message_locale
= utf82locale((char*)message
);
5258 isds_log(ILF_ISDS
, ILL_DEBUG
,
5259 _("Server did not found box %s on CheckDataBox request "
5260 "(code=%s, message=%s)\n"),
5261 box_id_locale
, code_locale
, message_locale
);
5262 isds_log_message(context
, message_locale
);
5263 free(box_id_locale
);
5265 free(message_locale
);
5271 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5272 char *code_locale
= utf82locale((char*)code
);
5273 char *message_locale
= utf82locale((char*)message
);
5274 isds_log(ILF_ISDS
, ILL_DEBUG
,
5275 _("Server refused CheckDataBox request "
5276 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5277 isds_log_message(context
, message_locale
);
5279 free(message_locale
);
5285 xpath_ctx
= xmlXPathNewContext(response
);
5290 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5294 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
5300 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5301 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
5305 if (result
->nodesetval
->nodeNr
> 1) {
5306 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
5310 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5311 xmlXPathFreeObject(result
); result
= NULL
;
5313 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
5318 xmlXPathFreeObject(result
);
5319 xmlXPathFreeContext(xpath_ctx
);
5323 xmlFreeDoc(response
);
5326 isds_log(ILF_ISDS
, ILL_DEBUG
,
5327 _("CheckDataBox request processed by server successfully.\n"));
5333 /* Build ISDS request of XSD tIdDbInput type, sent it, check for error
5334 * code, destroy response and log success.
5335 * @context is ISDS session context.
5336 * @service_name is name of SERVICE_DB_MANIPULATION service
5337 * @box_id is UTF-8 encoded box identifier as zero terminated string
5338 * @approval is optional external approval of box manipulation
5339 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5340 * NULL, if you don't care. */
5341 static isds_error
build_send_manipulationdbid_request_check_drop_response(
5342 struct isds_ctx
*context
, const xmlChar
*service_name
,
5343 const xmlChar
*box_id
, const struct isds_approval
*approval
,
5344 xmlChar
**refnumber
) {
5345 isds_error err
= IE_SUCCESS
;
5346 xmlDocPtr response
= NULL
;
5348 if (!context
) return IE_INVALID_CONTEXT
;
5349 if (!service_name
|| *service_name
== '\0' || !box_id
) return IE_INVAL
;
5351 /* Check if connection is established */
5352 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5354 /* Do request and check for success */
5355 err
= build_send_dbid_request_check_response(context
,
5356 SERVICE_DB_MANIPULATION
, service_name
, box_id
, approval
,
5357 &response
, refnumber
);
5358 xmlFreeDoc(response
);
5361 char *service_name_locale
= utf82locale((char *) service_name
);
5362 isds_log(ILF_ISDS
, ILL_DEBUG
,
5363 _("%s request processed by server successfully.\n"),
5364 service_name_locale
);
5365 free(service_name_locale
);
5372 /* Switch box into state where box can receive commercial messages (off by
5374 * @context is ISDS session context.
5375 * @box_id is UTF-8 encoded box identifier as zero terminated string
5376 * @allow is true for enable, false for disable commercial messages income
5377 * @approval is optional external approval of box manipulation
5378 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5379 * NULL, if you don't care. */
5380 isds_error
isds_switch_commercial_receiving(struct isds_ctx
*context
,
5381 const char *box_id
, const _Bool allow
,
5382 const struct isds_approval
*approval
, char **refnumber
) {
5383 return build_send_manipulationdbid_request_check_drop_response(context
,
5384 (allow
) ? BAD_CAST
"SetOpenAddressing" :
5385 BAD_CAST
"ClearOpenAddressing",
5386 BAD_CAST box_id
, approval
, (xmlChar
**) refnumber
);
5390 /* Switch box into / out of state where non-OVM box can act as OVM (e.g. force
5391 * message acceptance). This is just a box permission. Sender must apply
5392 * such role by sending each message.
5393 * @context is ISDS session context.
5394 * @box_id is UTF-8 encoded box identifier as zero terminated string
5395 * @allow is true for enable, false for disable OVM role permission
5396 * @approval is optional external approval of box manipulation
5397 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5398 * NULL, if you don't care. */
5399 isds_error
isds_switch_effective_ovm(struct isds_ctx
*context
,
5400 const char *box_id
, const _Bool allow
,
5401 const struct isds_approval
*approval
, char **refnumber
) {
5402 return build_send_manipulationdbid_request_check_drop_response(context
,
5403 (allow
) ? BAD_CAST
"SetEffectiveOVM" :
5404 BAD_CAST
"ClearEffectiveOVM",
5405 BAD_CAST box_id
, approval
, (xmlChar
**) refnumber
);
5409 /* Build ISDS request of XSD tOwnerInfoInput type, sent it, check for error
5410 * code, destroy response and log success.
5411 * @context is ISDS session context.
5412 * @service_name is name of SERVICE_DB_MANIPULATION service
5413 * @owner is structure describing box
5414 * @approval is optional external approval of box manipulation
5415 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5416 * NULL, if you don't care. */
5417 static isds_error
build_send_manipulationdbowner_request_check_drop_response(
5418 struct isds_ctx
*context
, const xmlChar
*service_name
,
5419 const struct isds_DbOwnerInfo
*owner
,
5420 const struct isds_approval
*approval
, xmlChar
**refnumber
) {
5421 isds_error err
= IE_SUCCESS
;
5422 char *service_name_locale
= NULL
;
5423 xmlNodePtr request
= NULL
, db_owner_info
;
5424 xmlNsPtr isds_ns
= NULL
;
5427 if (!context
) return IE_INVALID_CONTEXT
;
5428 if (!service_name
|| *service_name
== '\0' || !owner
) return IE_INVAL
;
5430 service_name_locale
= utf82locale((char*)service_name
);
5431 if (!service_name_locale
) {
5437 request
= xmlNewNode(NULL
, service_name
);
5439 isds_printf_message(context
,
5440 _("Could not build %s request"), service_name_locale
);
5444 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5446 isds_log_message(context
, _("Could not create ISDS name space"));
5450 xmlSetNs(request
, isds_ns
);
5453 /* Add XSD:tOwnerInfoInput child*/
5454 INSERT_ELEMENT(db_owner_info
, request
, "dbOwnerInfo");
5455 err
= insert_DbOwnerInfo(context
, owner
, db_owner_info
);
5456 if (err
) goto leave
;
5458 /* Add XSD:gExtApproval*/
5459 err
= insert_GExtApproval(context
, approval
, request
);
5460 if (err
) goto leave
;
5462 /* Send it to server and process response */
5463 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5464 service_name
, &request
, refnumber
);
5467 xmlFreeNode(request
);
5468 free(service_name_locale
);
5474 /* Switch box accessibility state on request of box owner.
5475 * Despite the name, owner must do the request off-line. This function is
5476 * designed for such off-line meeting points (e.g. Czech POINT).
5477 * @context is ISDS session context.
5478 * @box identifies box to swith accesibilty state.
5479 * @allow is true for making accesibale, false to disallow access.
5480 * @approval is optional external approval of box manipulation
5481 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5482 * NULL, if you don't care. */
5483 isds_error
isds_switch_box_accessibility_on_owner_request(
5484 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5485 const _Bool allow
, const struct isds_approval
*approval
,
5487 return build_send_manipulationdbowner_request_check_drop_response(context
,
5488 (allow
) ? BAD_CAST
"EnableOwnDataBox" :
5489 BAD_CAST
"DisableOwnDataBox",
5490 box
, approval
, (xmlChar
**) refnumber
);
5494 /* Disable box accessibility on law enforcement (e.g. by prison) since exact
5496 * @context is ISDS session context.
5497 * @box identifies box to swith accesibilty state.
5498 * @since is date since accesseibility has been denied. This can be past too.
5499 * Only tm_year, tm_mon and tm_mday carry sane value.
5500 * @approval is optional external approval of box manipulation
5501 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5502 * NULL, if you don't care. */
5503 isds_error
isds_disable_box_accessibility_externaly(
5504 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5505 const struct tm
*since
, const struct isds_approval
*approval
,
5507 isds_error err
= IE_SUCCESS
;
5508 char *service_name_locale
= NULL
;
5509 xmlNodePtr request
= NULL
, node
;
5510 xmlNsPtr isds_ns
= NULL
;
5511 xmlChar
*string
= NULL
;
5514 if (!context
) return IE_INVALID_CONTEXT
;
5515 if (!box
|| !since
) return IE_INVAL
;
5518 request
= xmlNewNode(NULL
, BAD_CAST
"DisableDataBoxExternally");
5520 isds_printf_message(context
,
5521 _("Could not build %s request"), "DisableDataBoxExternally");
5525 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5527 isds_log_message(context
, _("Could not create ISDS name space"));
5531 xmlSetNs(request
, isds_ns
);
5534 /* Add @box identification */
5535 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5536 err
= insert_DbOwnerInfo(context
, box
, node
);
5537 if (err
) goto leave
;
5539 /* Add @since date */
5540 err
= tm2datestring(since
, &string
);
5542 isds_log_message(context
,
5543 _("Could not convert `since' argument to ISO date string"));
5546 INSERT_STRING(request
, "dbOwnerDisableDate", string
);
5550 err
= insert_GExtApproval(context
, approval
, request
);
5551 if (err
) goto leave
;
5553 /* Send it to server and process response */
5554 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5555 BAD_CAST
"DisableDataBoxExternally", &request
,
5556 (xmlChar
**) refnumber
);
5560 xmlFreeNode(request
);
5561 free(service_name_locale
);
5567 /* Insert struct isds_message data (envelope (recipient data optional) and
5568 * documents) into XML tree
5569 * @context is sesstion context
5570 * @outgoing_message is libsids structure with message data
5571 * @create_message is XML CreateMessage or CreateMultipleMessage element
5572 * @process_recipient true for recipient data serialization, false for no
5574 static isds_error
insert_envelope_files(struct isds_ctx
*context
,
5575 const struct isds_message
*outgoing_message
, xmlNodePtr create_message
,
5576 const _Bool process_recipient
) {
5578 isds_error err
= IE_SUCCESS
;
5579 xmlNodePtr envelope
, dm_files
, node
;
5580 xmlChar
*string
= NULL
;
5582 if (!context
) return IE_INVALID_CONTEXT
;
5583 if (!outgoing_message
|| !create_message
) return IE_INVAL
;
5586 /* Build envelope */
5587 envelope
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
5589 isds_printf_message(context
, _("Could not add dmEnvelope child to "
5590 "%s element"), create_message
->name
);
5594 if (!outgoing_message
->envelope
) {
5595 isds_log_message(context
, _("Outgoing message is missing envelope"));
5600 INSERT_STRING(envelope
, "dmSenderOrgUnit",
5601 outgoing_message
->envelope
->dmSenderOrgUnit
);
5602 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
5603 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
5605 if (process_recipient
) {
5606 if (!outgoing_message
->envelope
->dbIDRecipient
) {
5607 isds_log_message(context
,
5608 _("Outgoing message is missing recipient box identifier"));
5612 INSERT_STRING(envelope
, "dbIDRecipient",
5613 outgoing_message
->envelope
->dbIDRecipient
);
5615 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
5616 outgoing_message
->envelope
->dmRecipientOrgUnit
);
5617 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
5618 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
5619 INSERT_STRING(envelope
, "dmToHands",
5620 outgoing_message
->envelope
->dmToHands
);
5623 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 0, 255,
5625 INSERT_STRING(envelope
, "dmAnnotation",
5626 outgoing_message
->envelope
->dmAnnotation
);
5628 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
5629 0, 50, "dmRecipientRefNumber");
5630 INSERT_STRING(envelope
, "dmRecipientRefNumber",
5631 outgoing_message
->envelope
->dmRecipientRefNumber
);
5633 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
5634 0, 50, "dmSenderRefNumber");
5635 INSERT_STRING(envelope
, "dmSenderRefNumber",
5636 outgoing_message
->envelope
->dmSenderRefNumber
);
5638 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
5639 0, 50, "dmRecipientIdent");
5640 INSERT_STRING(envelope
, "dmRecipientIdent",
5641 outgoing_message
->envelope
->dmRecipientIdent
);
5643 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
5644 0, 50, "dmSenderIdent");
5645 INSERT_STRING(envelope
, "dmSenderIdent",
5646 outgoing_message
->envelope
->dmSenderIdent
);
5648 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
5649 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
5650 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
5651 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
5652 INSERT_STRING(envelope
, "dmLegalTitleSect",
5653 outgoing_message
->envelope
->dmLegalTitleSect
);
5654 INSERT_STRING(envelope
, "dmLegalTitlePar",
5655 outgoing_message
->envelope
->dmLegalTitlePar
);
5656 INSERT_STRING(envelope
, "dmLegalTitlePoint",
5657 outgoing_message
->envelope
->dmLegalTitlePoint
);
5659 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
5660 outgoing_message
->envelope
->dmPersonalDelivery
);
5661 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
5662 outgoing_message
->envelope
->dmAllowSubstDelivery
);
5664 /* ???: Should we require value for dbEffectiveOVM sender?
5665 * ISDS has default as true */
5666 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
5669 /* Append dmFiles */
5670 if (!outgoing_message
->documents
) {
5671 isds_log_message(context
,
5672 _("Outgoing message is missing list of documents"));
5676 dm_files
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmFiles", NULL
);
5678 isds_printf_message(context
, _("Could not add dmFiles child to "
5679 "%s element"), create_message
->name
);
5684 /* Check for document hieararchy */
5685 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
5686 if (err
) goto leave
;
5688 /* Process each document */
5689 for (struct isds_list
*item
=
5690 (struct isds_list
*) outgoing_message
->documents
;
5691 item
; item
= item
->next
) {
5693 isds_log_message(context
,
5694 _("List of documents contains empty item"));
5698 /* FIXME: Check for dmFileMetaType and for document references.
5699 * Only first document can be of MAIN type */
5700 err
= insert_document(context
, (struct isds_document
*) item
->data
,
5703 if (err
) goto leave
;
5712 /* Send a message via ISDS to a recipent
5713 * @context is session context
5714 * @outgoing_message is message to send; Some memebers are mandatory (like
5715 * dbIDRecipient), some are optional and some are irrelevant (especialy data
5716 * about sender). Included pointer to isds_list documents must contain at
5717 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
5718 * members will be filled with valid data from ISDS. Exact list of write
5719 * members is subject to change. Currently dmId is changed.
5720 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
5721 isds_error
isds_send_message(struct isds_ctx
*context
,
5722 struct isds_message
*outgoing_message
) {
5724 isds_error err
= IE_SUCCESS
;
5725 xmlNsPtr isds_ns
= NULL
;
5726 xmlNodePtr request
= NULL
;
5727 xmlDocPtr response
= NULL
;
5728 xmlChar
*code
= NULL
, *message
= NULL
;
5729 xmlXPathContextPtr xpath_ctx
= NULL
;
5730 xmlXPathObjectPtr result
= NULL
;
5731 _Bool message_is_complete
= 0;
5733 if (!context
) return IE_INVALID_CONTEXT
;
5734 if (!outgoing_message
) return IE_INVAL
;
5736 /* Check if connection is established
5737 * TODO: This check should be done donwstairs. */
5738 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5741 /* Build CreateMessage request */
5742 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
5744 isds_log_message(context
,
5745 _("Could build CreateMessage request"));
5748 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5750 isds_log_message(context
, _("Could not create ISDS name space"));
5751 xmlFreeNode(request
);
5754 xmlSetNs(request
, isds_ns
);
5756 /* Append envelope and files */
5757 err
= insert_envelope_files(context
, outgoing_message
, request
, 1);
5758 if (err
) goto leave
;
5761 /* Signal we can serilize message since now */
5762 message_is_complete
= 1;
5765 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
5768 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
5770 /* Dont' destroy request, we want to provide it to application later */
5773 isds_log(ILF_ISDS
, ILL_DEBUG
,
5774 _("Processing ISDS response on CreateMessage "
5775 "request failed\n"));
5779 /* Check for response status */
5780 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
5781 &code
, &message
, NULL
);
5783 isds_log(ILF_ISDS
, ILL_DEBUG
,
5784 _("ISDS response on CreateMessage request "
5785 "is missing status\n"));
5789 /* Request processed, but refused by server or server failed */
5790 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5791 char *box_id_locale
=
5792 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
5793 char *code_locale
= utf82locale((char*)code
);
5794 char *message_locale
= utf82locale((char*)message
);
5795 isds_log(ILF_ISDS
, ILL_DEBUG
,
5796 _("Server did not accept message for %s on CreateMessage "
5797 "request (code=%s, message=%s)\n"),
5798 box_id_locale
, code_locale
, message_locale
);
5799 isds_log_message(context
, message_locale
);
5800 free(box_id_locale
);
5802 free(message_locale
);
5809 xpath_ctx
= xmlXPathNewContext(response
);
5814 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5818 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
5824 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5825 isds_log_message(context
, _("Missing CreateMessageResponse element"));
5829 if (result
->nodesetval
->nodeNr
> 1) {
5830 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
5834 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5835 xmlXPathFreeObject(result
); result
= NULL
;
5837 if (outgoing_message
->envelope
->dmID
) {
5838 free(outgoing_message
->envelope
->dmID
);
5839 outgoing_message
->envelope
->dmID
= NULL
;
5841 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
5842 if (!outgoing_message
->envelope
->dmID
) {
5843 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
5844 "but did not returen assigned message ID\n"));
5848 /* TODO: Serialize message into structure member raw */
5849 /* XXX: Each web service transport message in different format.
5850 * Therefore it's not possible to save them directly.
5851 * To save them, one must figure out common format.
5852 * We can leave it on application, or we can implement the ESS format. */
5853 /*if (message_is_complete) {
5854 if (outgoing_message->envelope->dmID) {
5856 /* Add assigned message ID as first child*/
5857 /*xmlNodePtr dmid_text = xmlNewText(
5858 (xmlChar *) outgoing_message->envelope->dmID);
5859 if (!dmid_text) goto serialization_failed;
5861 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
5863 if (!dmid_element) {
5864 xmlFreeNode(dmid_text);
5865 goto serialization_failed;
5868 xmlNodePtr dmid_element_with_text =
5869 xmlAddChild(dmid_element, dmid_text);
5870 if (!dmid_element_with_text) {
5871 xmlFreeNode(dmid_element);
5872 xmlFreeNode(dmid_text);
5873 goto serialization_failed;
5876 node = xmlAddPrevSibling(envelope->childern,
5877 dmid_element_with_text);
5879 xmlFreeNodeList(dmid_element_with_text);
5880 goto serialization_failed;
5884 /* Serialize message with ID into raw */
5885 /*buffer = serialize_element(envelope)*/
5888 serialization_failed:
5893 xmlXPathFreeObject(result
);
5894 xmlXPathFreeContext(xpath_ctx
);
5898 xmlFreeDoc(response
);
5899 xmlFreeNode(request
);
5902 isds_log(ILF_ISDS
, ILL_DEBUG
,
5903 _("CreateMessage request processed by server "
5904 "successfully.\n"));
5910 /* Send a message via ISDS to a multiple recipents
5911 * @context is session context
5912 * @outgoing_message is message to send; Some memebers are mandatory,
5913 * some are optional and some are irrelevant (especialy data
5914 * about sender). Data about recipient will be substituted by ISDS from
5915 * @copies. Included pointer to isds_list documents must
5916 * contain at least one document of FILEMETATYPE_MAIN.
5917 * @copies is list of isds_message_copy structures addressing all desired
5918 * recipients. This is read-write structure, some members will be filled with
5919 * valid data from ISDS (message IDs, error codes, error descriptions).
5921 * ISDS_SUCCESS if all messages have been sent
5922 * ISDS_PARTIAL_SUCCESS if sending of some messages has failed (failed and
5923 * succesed messages can be identified by copies->data->error),
5924 * or other error code if something other goes wrong. */
5925 isds_error
isds_send_message_to_multiple_recipients(struct isds_ctx
*context
,
5926 const struct isds_message
*outgoing_message
,
5927 struct isds_list
*copies
) {
5929 isds_error err
= IE_SUCCESS
, append_err
;
5930 xmlNsPtr isds_ns
= NULL
;
5931 xmlNodePtr request
= NULL
, recipients
, recipient
, node
;
5932 struct isds_list
*item
;
5933 struct isds_message_copy
*copy
;
5934 xmlDocPtr response
= NULL
;
5935 xmlChar
*code
= NULL
, *message
= NULL
;
5936 xmlXPathContextPtr xpath_ctx
= NULL
;
5937 xmlXPathObjectPtr result
= NULL
;
5938 xmlChar
*string
= NULL
;
5941 if (!context
) return IE_INVALID_CONTEXT
;
5942 if (!outgoing_message
|| !copies
) return IE_INVAL
;
5944 /* Check if connection is established
5945 * TODO: This check should be done donwstairs. */
5946 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5949 /* Build CreateMultipleMessage request */
5950 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMultipleMessage");
5952 isds_log_message(context
,
5953 _("Could build CreateMultipleMessage request"));
5956 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5958 isds_log_message(context
, _("Could not create ISDS name space"));
5959 xmlFreeNode(request
);
5962 xmlSetNs(request
, isds_ns
);
5965 /* Build recipients */
5966 recipients
= xmlNewChild(request
, NULL
, BAD_CAST
"dmRecipients", NULL
);
5968 isds_log_message(context
, _("Could not add dmRecipients child to "
5969 "CreateMultipleMessage element"));
5970 xmlFreeNode(request
);
5974 /* Insert each recipient */
5975 for (item
= copies
; item
; item
= item
->next
) {
5976 copy
= (struct isds_message_copy
*) item
->data
;
5978 isds_log_message(context
,
5979 _("copies list item contains empty data"));
5984 recipient
= xmlNewChild(recipients
, NULL
, BAD_CAST
"dmRecipient", NULL
);
5986 isds_log_message(context
, _("Could not add dmRecipient child to "
5987 "dmRecipient element"));
5992 if (!copy
->dbIDRecipient
) {
5993 isds_log_message(context
,
5994 _("Message copy is missing recipient box identifier"));
5998 INSERT_STRING(recipient
, "dbIDRecipient", copy
->dbIDRecipient
);
5999 INSERT_STRING(recipient
, "dmRecipientOrgUnit",
6000 copy
->dmRecipientOrgUnit
);
6001 INSERT_LONGINT(recipient
, "dmRecipientOrgUnitNum",
6002 copy
->dmRecipientOrgUnitNum
, string
);
6003 INSERT_STRING(recipient
, "dmToHands", copy
->dmToHands
);
6006 /* Append envelope and files */
6007 err
= insert_envelope_files(context
, outgoing_message
, request
, 0);
6008 if (err
) goto leave
;
6011 isds_log(ILF_ISDS
, ILL_DEBUG
,
6012 _("Sending CreateMultipleMessage request to ISDS\n"));
6015 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
6017 isds_log(ILF_ISDS
, ILL_DEBUG
,
6018 _("Processing ISDS response on CreateMultipleMessage "
6019 "request failed\n"));
6023 /* Check for response status */
6024 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
6025 &code
, &message
, NULL
);
6027 isds_log(ILF_ISDS
, ILL_DEBUG
,
6028 _("ISDS response on CreateMultipleMessage request "
6029 "is missing status\n"));
6033 /* Request processed, but some copies failed */
6034 if (!xmlStrcmp(code
, BAD_CAST
"0004")) {
6035 char *box_id_locale
=
6036 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
6037 char *code_locale
= utf82locale((char*)code
);
6038 char *message_locale
= utf82locale((char*)message
);
6039 isds_log(ILF_ISDS
, ILL_DEBUG
,
6040 _("Server did accept message for multiple recipients "
6041 "on CreateMultipleMessage request but delivery to "
6042 "some of them failed (code=%s, message=%s)\n"),
6043 box_id_locale
, code_locale
, message_locale
);
6044 isds_log_message(context
, message_locale
);
6045 free(box_id_locale
);
6047 free(message_locale
);
6048 err
= IE_PARTIAL_SUCCESS
;
6051 /* Request refused by server as whole */
6052 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6053 char *box_id_locale
=
6054 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
6055 char *code_locale
= utf82locale((char*)code
);
6056 char *message_locale
= utf82locale((char*)message
);
6057 isds_log(ILF_ISDS
, ILL_DEBUG
,
6058 _("Server did not accept message for multiple recipients "
6059 "on CreateMultipleMessage request (code=%s, message=%s)\n"),
6060 box_id_locale
, code_locale
, message_locale
);
6061 isds_log_message(context
, message_locale
);
6062 free(box_id_locale
);
6064 free(message_locale
);
6071 xpath_ctx
= xmlXPathNewContext(response
);
6076 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6080 result
= xmlXPathEvalExpression(
6081 BAD_CAST
"/isds:CreateMultipleMessageResponse"
6082 "/isds:dmMultipleStatus/isds:dmSingleStatus",
6088 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6089 isds_log_message(context
, _("Missing isds:dmSingleStatus element"));
6094 /* Extract message ID and delivery status for each copy */
6095 for (item
= copies
, i
= 0; item
&& i
< result
->nodesetval
->nodeNr
;
6096 item
= item
->next
, i
++) {
6097 copy
= (struct isds_message_copy
*) item
->data
;
6098 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
6100 append_err
= append_TMStatus(context
, copy
, xpath_ctx
);
6106 if (item
|| i
< result
->nodesetval
->nodeNr
) {
6107 isds_printf_message(context
, _("ISDS returned unexpected number of "
6108 "message copy delivery states: %d"),
6109 result
->nodesetval
->nodeNr
);
6118 xmlXPathFreeObject(result
);
6119 xmlXPathFreeContext(xpath_ctx
);
6123 xmlFreeDoc(response
);
6124 xmlFreeNode(request
);
6127 isds_log(ILF_ISDS
, ILL_DEBUG
,
6128 _("CreateMultipleMessageResponse request processed by server "
6129 "successfully.\n"));
6135 /* Get list of messages. This is common core for getting sent or received
6137 * Any criterion argument can be NULL, if you don't care about it.
6138 * @context is session context. Must not be NULL.
6139 * @outgoing_direction is true if you want list of outgoing messages,
6140 * it's false if you want incoming messages.
6141 * @from_time is minimal time and date of message sending inclusive.
6142 * @to_time is maximal time and date of message sending inclusive
6143 * @organization_unit_number is number of sender/recipient respectively.
6144 * @status_filter is bit field of isds_message_status values. Use special
6145 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6146 * all values, you can use bitwise arithmetic if you want.)
6147 * @offset is index of first message we are interested in. First message is 1.
6148 * Set to 0 (or 1) if you don't care.
6149 * @number is maximal length of list you want to get as input value, outputs
6150 * number of messages matching these criteria. Can be NULL if you don't care
6151 * (applies to output value either).
6152 * @messages is automatically reallocated list of isds_message's. Be ware that
6153 * it returns only brief overview (envelope and some other fields) about each
6154 * message, not the complete message. FIXME: Specify exact fields.
6155 * The list is sorted by delivery time in ascending order.
6157 * you don't care about don't need the data (useful if you want to know only
6158 * the @number). If you provide &NULL, list will be allocated on heap, if you
6159 * provide pointer to non-NULL, list will be freed automacally at first. Also
6160 * in case of error the list will be NULLed.
6161 * @return IE_SUCCESS or appropriate error code. */
6162 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
6163 _Bool outgoing_direction
,
6164 const struct timeval
*from_time
, const struct timeval
*to_time
,
6165 const long int *organization_unit_number
,
6166 const unsigned int status_filter
,
6167 const unsigned long int offset
, unsigned long int *number
,
6168 struct isds_list
**messages
) {
6170 isds_error err
= IE_SUCCESS
;
6171 xmlNsPtr isds_ns
= NULL
;
6172 xmlNodePtr request
= NULL
, node
;
6173 xmlDocPtr response
= NULL
;
6174 xmlChar
*code
= NULL
, *message
= NULL
;
6175 xmlXPathContextPtr xpath_ctx
= NULL
;
6176 xmlXPathObjectPtr result
= NULL
;
6177 xmlChar
*string
= NULL
;
6178 long unsigned int count
= 0;
6180 if (!context
) return IE_INVALID_CONTEXT
;
6182 /* Free former message list if any */
6183 if (messages
) isds_list_free(messages
);
6185 /* Check if connection is established
6186 * TODO: This check should be done donwstairs. */
6187 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6189 /* Build GetListOf*Messages request */
6190 request
= xmlNewNode(NULL
,
6191 (outgoing_direction
) ?
6192 BAD_CAST
"GetListOfSentMessages" :
6193 BAD_CAST
"GetListOfReceivedMessages"
6196 isds_log_message(context
,
6197 (outgoing_direction
) ?
6198 _("Could not build GetListOfSentMessages request") :
6199 _("Could not build GetListOfReceivedMessages request")
6203 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6205 isds_log_message(context
, _("Could not create ISDS name space"));
6206 xmlFreeNode(request
);
6209 xmlSetNs(request
, isds_ns
);
6213 err
= timeval2timestring(from_time
, &string
);
6214 if (err
) goto leave
;
6216 INSERT_STRING(request
, "dmFromTime", string
);
6217 free(string
); string
= NULL
;
6220 err
= timeval2timestring(to_time
, &string
);
6221 if (err
) goto leave
;
6223 INSERT_STRING(request
, "dmToTime", string
);
6224 free(string
); string
= NULL
;
6226 if (outgoing_direction
) {
6227 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
6228 organization_unit_number
, string
);
6230 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
6231 organization_unit_number
, string
);
6234 if (status_filter
> MESSAGESTATE_ANY
) {
6235 isds_printf_message(context
,
6236 _("Invalid message state filter value: %ld"), status_filter
);
6240 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
6243 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
6245 INSERT_STRING(request
, "dmOffset", "1");
6248 /* number 0 means no limit */
6249 if (number
&& *number
== 0) {
6250 INSERT_STRING(request
, "dmLimit", NULL
);
6252 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
6256 isds_log(ILF_ISDS
, ILL_DEBUG
,
6257 (outgoing_direction
) ?
6258 _("Sending GetListOfSentMessages request to ISDS\n") :
6259 _("Sending GetListOfReceivedMessages request to ISDS\n")
6263 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
, NULL
, NULL
);
6264 xmlFreeNode(request
); request
= NULL
;
6267 isds_log(ILF_ISDS
, ILL_DEBUG
,
6268 (outgoing_direction
) ?
6269 _("Processing ISDS response on GetListOfSentMessages "
6270 "request failed\n") :
6271 _("Processing ISDS response on GetListOfReceivedMessages "
6277 /* Check for response status */
6278 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
6279 &code
, &message
, NULL
);
6281 isds_log(ILF_ISDS
, ILL_DEBUG
,
6282 (outgoing_direction
) ?
6283 _("ISDS response on GetListOfSentMessages request "
6284 "is missing status\n") :
6285 _("ISDS response on GetListOfReceivedMessages request "
6286 "is missing status\n")
6291 /* Request processed, but nothing found */
6292 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6293 char *code_locale
= utf82locale((char*)code
);
6294 char *message_locale
= utf82locale((char*)message
);
6295 isds_log(ILF_ISDS
, ILL_DEBUG
,
6296 (outgoing_direction
) ?
6297 _("Server refused GetListOfSentMessages request "
6298 "(code=%s, message=%s)\n") :
6299 _("Server refused GetListOfReceivedMessages request "
6300 "(code=%s, message=%s)\n"),
6301 code_locale
, message_locale
);
6302 isds_log_message(context
, message_locale
);
6304 free(message_locale
);
6311 xpath_ctx
= xmlXPathNewContext(response
);
6316 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6320 result
= xmlXPathEvalExpression(
6321 (outgoing_direction
) ?
6322 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
6323 "isds:dmRecords/isds:dmRecord" :
6324 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
6325 "isds:dmRecords/isds:dmRecord",
6332 /* Fill output arguments in */
6333 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6334 struct isds_envelope
*envelope
;
6335 struct isds_list
*item
= NULL
, *last_item
= NULL
;
6337 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
6338 /* Create new message */
6339 item
= calloc(1, sizeof(*item
));
6344 item
->destructor
= (void(*)(void**)) &isds_message_free
;
6345 item
->data
= calloc(1, sizeof(struct isds_message
));
6347 isds_list_free(&item
);
6352 /* Extract envelope data */
6353 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
6355 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
6357 isds_list_free(&item
);
6361 /* Attach extracted envelope */
6362 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
6364 /* Append new message into the list */
6366 *messages
= last_item
= item
;
6368 last_item
->next
= item
;
6373 if (number
) *number
= count
;
6377 isds_list_free(messages
);
6381 xmlXPathFreeObject(result
);
6382 xmlXPathFreeContext(xpath_ctx
);
6386 xmlFreeDoc(response
);
6387 xmlFreeNode(request
);
6390 isds_log(ILF_ISDS
, ILL_DEBUG
,
6391 (outgoing_direction
) ?
6392 _("GetListOfSentMessages request processed by server "
6393 "successfully.\n") :
6394 _("GetListOfReceivedMessages request processed by server "
6401 /* Get list of outgoing (already sent) messages.
6402 * Any criterion argument can be NULL, if you don't care about it.
6403 * @context is session context. Must not be NULL.
6404 * @from_time is minimal time and date of message sending inclusive.
6405 * @to_time is maximal time and date of message sending inclusive
6406 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
6407 * @status_filter is bit field of isds_message_status values. Use special
6408 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6409 * all values, you can use bitwise arithmetic if you want.)
6410 * @offset is index of first message we are interested in. First message is 1.
6411 * Set to 0 (or 1) if you don't care.
6412 * @number is maximal length of list you want to get as input value, outputs
6413 * number of messages matching these criteria. Can be NULL if you don't care
6414 * (applies to output value either).
6415 * @messages is automatically reallocated list of isds_message's. Be ware that
6416 * it returns only brief overview (envelope and some other fields) about each
6417 * message, not the complete message. FIXME: Specify exact fields.
6418 * The list is sorted by delivery time in ascending order.
6419 * Use NULL if you don't care about the metadata (useful if you want to know
6420 * only the @number). If you provide &NULL, list will be allocated on heap,
6421 * if you provide pointer to non-NULL, list will be freed automacally at first.
6422 * Also in case of error the list will be NULLed.
6423 * @return IE_SUCCESS or appropriate error code. */
6424 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
6425 const struct timeval
*from_time
, const struct timeval
*to_time
,
6426 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
6427 const unsigned long int offset
, unsigned long int *number
,
6428 struct isds_list
**messages
) {
6430 return isds_get_list_of_messages(
6432 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
6438 /* Get list of incoming (addressed to you) messages.
6439 * Any criterion argument can be NULL, if you don't care about it.
6440 * @context is session context. Must not be NULL.
6441 * @from_time is minimal time and date of message sending inclusive.
6442 * @to_time is maximal time and date of message sending inclusive
6443 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
6444 * @status_filter is bit field of isds_message_status values. Use special
6445 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6446 * all values, you can use bitwise arithmetic if you want.)
6447 * @offset is index of first message we are interested in. First message is 1.
6448 * Set to 0 (or 1) if you don't care.
6449 * @number is maximal length of list you want to get as input value, outputs
6450 * number of messages matching these criteria. Can be NULL if you don't care
6451 * (applies to output value either).
6452 * @messages is automatically reallocated list of isds_message's. Be ware that
6453 * it returns only brief overview (envelope and some other fields) about each
6454 * message, not the complete message. FIXME: Specify exact fields.
6455 * Use NULL if you don't care about the metadata (useful if you want to know
6456 * only the @number). If you provide &NULL, list will be allocated on heap,
6457 * if you provide pointer to non-NULL, list will be freed automacally at first.
6458 * Also in case of error the list will be NULLed.
6459 * @return IE_SUCCESS or appropriate error code. */
6460 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
6461 const struct timeval
*from_time
, const struct timeval
*to_time
,
6462 const long int *dmRecipientOrgUnitNum
,
6463 const unsigned int status_filter
,
6464 const unsigned long int offset
, unsigned long int *number
,
6465 struct isds_list
**messages
) {
6467 return isds_get_list_of_messages(
6469 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
6475 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
6477 * @context is session context
6478 * @service is ISDS WS service handler
6479 * @service_name is name of SERVICE_DM_OPERATIONS
6480 * @message_id is message ID to send as service argument to ISDS
6481 * @response is server SOAP body response as XML document
6482 * @raw_response is automatically reallocated bitstream with response body. Use
6483 * NULL if you don't care
6484 * @raw_response_length is size of @raw_response in bytes
6485 * @code is ISDS status code
6486 * @status_message is ISDS status message
6487 * @return error coded from lower layer, context message will be set up
6489 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
6490 const isds_service service
, const xmlChar
*service_name
,
6491 const char *message_id
,
6492 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
6493 xmlChar
**code
, xmlChar
**status_message
) {
6495 isds_error err
= IE_SUCCESS
;
6496 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
6497 xmlNodePtr request
= NULL
, node
;
6498 xmlNsPtr isds_ns
= NULL
;
6500 if (!context
) return IE_INVALID_CONTEXT
;
6501 if (!service_name
|| !message_id
) return IE_INVAL
;
6502 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
6503 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
6505 /* Free output argument */
6506 xmlFreeDoc(*response
); *response
= NULL
;
6507 if (raw_response
) zfree(*raw_response
);
6509 free(*status_message
);
6512 /* Check if connection is established
6513 * TODO: This check should be done donwstairs. */
6514 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6516 service_name_locale
= utf82locale((char*)service_name
);
6517 message_id_locale
= utf82locale(message_id
);
6518 if (!service_name_locale
|| !message_id_locale
) {
6524 request
= xmlNewNode(NULL
, service_name
);
6526 isds_printf_message(context
,
6527 _("Could not build %s request"), service_name_locale
);
6531 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6533 isds_log_message(context
, _("Could not create ISDS name space"));
6537 xmlSetNs(request
, isds_ns
);
6540 /* Add requested ID */
6541 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
6542 if (err
) goto leave
;
6543 INSERT_STRING(request
, "dmID", message_id
);
6546 isds_log(ILF_ISDS
, ILL_DEBUG
,
6547 _("Sending %s request for %s message ID to ISDS\n"),
6548 service_name_locale
, message_id_locale
);
6551 err
= isds(context
, service
, request
, response
,
6552 raw_response
, raw_response_length
);
6553 xmlFreeNode(request
); request
= NULL
;
6556 isds_log(ILF_ISDS
, ILL_DEBUG
,
6557 _("Processing ISDS response on %s request failed\n"),
6558 service_name_locale
);
6562 /* Check for response status */
6563 err
= isds_response_status(context
, service
, *response
,
6564 code
, status_message
, NULL
);
6566 isds_log(ILF_ISDS
, ILL_DEBUG
,
6567 _("ISDS response on %s request is missing status\n"),
6568 service_name_locale
);
6572 /* Request processed, but nothing found */
6573 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
6574 char *code_locale
= utf82locale((char*) *code
);
6575 char *status_message_locale
= utf82locale((char*) *status_message
);
6576 isds_log(ILF_ISDS
, ILL_DEBUG
,
6577 _("Server refused %s request for %s message ID "
6578 "(code=%s, message=%s)\n"),
6579 service_name_locale
, message_id_locale
,
6580 code_locale
, status_message_locale
);
6581 isds_log_message(context
, status_message_locale
);
6583 free(status_message_locale
);
6589 free(message_id_locale
);
6590 free(service_name_locale
);
6591 xmlFreeNode(request
);
6596 /* Find dmSignature in ISDS response, extract decoded CMS structure, extract
6597 * signed data and free ISDS response.
6598 * @context is session context
6599 * @message_id is UTF-8 encoded message ID for loging purpose
6600 * @response is parsed XML document. It will be freed and NULLed in the middle
6601 * of function run to save memmory. This is not guaranted in case of error.
6602 * @request_name is name of ISDS request used to construct response root
6603 * element name and for logging purpose.
6604 * @raw is reallocated output buffer with DER encoded CMS data
6605 * @raw_length is size of @raw buffer in bytes
6606 * @returns standard error codes, in case of error, @raw will be freed and
6607 * NULLed, @response sometimes. */
6608 static isds_error
find_extract_signed_data_free_response(
6609 struct isds_ctx
*context
, const xmlChar
*message_id
,
6610 xmlDocPtr
*response
, const xmlChar
*request_name
,
6611 void **raw
, size_t *raw_length
) {
6613 isds_error err
= IE_SUCCESS
;
6614 char *xpath_expression
= NULL
;
6615 xmlXPathContextPtr xpath_ctx
= NULL
;
6616 xmlXPathObjectPtr result
= NULL
;
6617 char *encoded_structure
= NULL
;
6619 if (!context
) return IE_INVALID_CONTEXT
;
6620 if (!raw
) return IE_INVAL
;
6622 if (!message_id
|| !response
|| !*response
|| !request_name
|| !raw_length
)
6625 /* Build XPath expression */
6626 xpath_expression
= astrcat3("/isds:", (char *) request_name
,
6627 "Response/isds:dmSignature");
6628 if (!xpath_expression
) return IE_NOMEM
;
6631 xpath_ctx
= xmlXPathNewContext(*response
);
6636 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6640 result
= xmlXPathEvalExpression(BAD_CAST xpath_expression
, xpath_ctx
);
6645 /* Empty response */
6646 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6647 char *message_id_locale
= utf82locale((char*) message_id
);
6648 isds_printf_message(context
,
6649 _("Server did not return any signed data for mesage ID `%s' "
6651 message_id_locale
, request_name
);
6652 free(message_id_locale
);
6657 if (result
->nodesetval
->nodeNr
> 1) {
6658 char *message_id_locale
= utf82locale((char*) message_id
);
6659 isds_printf_message(context
,
6660 _("Server did return more signed data for message ID `%s' "
6662 message_id_locale
, request_name
);
6663 free(message_id_locale
);
6668 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6670 /* Extract PKCS#7 structure */
6671 EXTRACT_STRING(".", encoded_structure
);
6672 if (!encoded_structure
) {
6673 isds_log_message(context
, _("dmSignature element is empty"));
6676 /* Here we have delivery info as standalone CMS in encoded_structure.
6677 * We don't need any other data, free them: */
6678 xmlXPathFreeObject(result
); result
= NULL
;
6679 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
6680 xmlFreeDoc(*response
); *response
= NULL
;
6683 /* Decode PKCS#7 to DER format */
6684 *raw_length
= b64decode(encoded_structure
, raw
);
6685 if (*raw_length
== (size_t) -1) {
6686 isds_log_message(context
,
6687 _("Error while Base64-decoding PKCS#7 structure"));
6698 free(encoded_structure
);
6699 xmlXPathFreeObject(result
);
6700 xmlXPathFreeContext(xpath_ctx
);
6701 free(xpath_expression
);
6707 /* Download incoming message envelope identified by ID.
6708 * @context is session context
6709 * @message_id is message identifier (you can get them from
6710 * isds_get_list_of_received_messages())
6711 * @message is automatically reallocated message retrieved from ISDS.
6712 * It will miss documents per se. Use isds_get_received_message(), if you are
6713 * interrested in documents (content) too.
6714 * Returned hash and timestamp require documents to be verifiable. */
6715 isds_error
isds_get_received_envelope(struct isds_ctx
*context
,
6716 const char *message_id
, struct isds_message
**message
) {
6718 isds_error err
= IE_SUCCESS
;
6719 xmlDocPtr response
= NULL
;
6720 xmlChar
*code
= NULL
, *status_message
= NULL
;
6721 xmlXPathContextPtr xpath_ctx
= NULL
;
6722 xmlXPathObjectPtr result
= NULL
;
6724 if (!context
) return IE_INVALID_CONTEXT
;
6726 /* Free former message if any */
6727 if (!message
) return IE_INVAL
;
6728 isds_message_free(message
);
6730 /* Do request and check for success */
6731 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
6732 BAD_CAST
"MessageEnvelopeDownload", message_id
,
6733 &response
, NULL
, NULL
, &code
, &status_message
);
6734 if (err
) goto leave
;
6737 xpath_ctx
= xmlXPathNewContext(response
);
6742 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6746 result
= xmlXPathEvalExpression(
6747 BAD_CAST
"/isds:MessageEnvelopeDownloadResponse/"
6748 "isds:dmReturnedMessageEnvelope",
6754 /* Empty response */
6755 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6756 char *message_id_locale
= utf82locale((char*) message_id
);
6757 isds_printf_message(context
,
6758 _("Server did not return any envelope for ID `%s' "
6759 "on MessageEnvelopeDownload request"), message_id_locale
);
6760 free(message_id_locale
);
6765 if (result
->nodesetval
->nodeNr
> 1) {
6766 char *message_id_locale
= utf82locale((char*) message_id
);
6767 isds_printf_message(context
,
6768 _("Server did return more envelopes for ID `%s' "
6769 "on MessageEnvelopeDownload request"), message_id_locale
);
6770 free(message_id_locale
);
6775 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6777 /* Extract the envelope (= message without documents, hence 0) */
6778 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
6779 if (err
) goto leave
;
6782 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
6783 &(*message
)->raw_length
);
6787 isds_message_free(message
);
6790 xmlXPathFreeObject(result
);
6791 xmlXPathFreeContext(xpath_ctx
);
6794 free(status_message
);
6795 xmlFreeDoc(response
);
6798 isds_log(ILF_ISDS
, ILL_DEBUG
,
6799 _("MessageEnvelopeDownload request processed by server "
6806 /* Load delivery info of any format from buffer.
6807 * @context is session context
6808 * @raw_type advertises format of @buffer content. Only delivery info types
6810 * @buffer is DER encoded PKCS#7 structure with signed delivery info. You can
6811 * retrieve such data from message->raw after calling
6812 * isds_get_signed_delivery_info().
6813 * @length is length of buffer in bytes.
6814 * @message is automatically reallocated message parsed from @buffer.
6815 * @strategy selects how buffer will be attached into raw isds_message member.
6817 isds_error
isds_load_delivery_info(struct isds_ctx
*context
,
6818 const isds_raw_type raw_type
,
6819 const void *buffer
, const size_t length
,
6820 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
6822 isds_error err
= IE_SUCCESS
;
6823 message_ns_type message_ns
;
6824 xmlDocPtr message_doc
= NULL
;
6825 xmlXPathContextPtr xpath_ctx
= NULL
;
6826 xmlXPathObjectPtr result
= NULL
;
6827 void *xml_stream
= NULL
;
6828 size_t xml_stream_length
= 0;
6830 if (!context
) return IE_INVALID_CONTEXT
;
6831 if (!message
) return IE_INVAL
;
6832 isds_message_free(message
);
6833 if (!buffer
) return IE_INVAL
;
6836 /* Select buffer format and extract XML from CMS*/
6838 case RAWTYPE_DELIVERYINFO
:
6839 message_ns
= MESSAGE_NS_UNSIGNED
;
6840 xml_stream
= (void *) buffer
;
6841 xml_stream_length
= length
;
6844 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
6845 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
6846 xml_stream
= (void *) buffer
;
6847 xml_stream_length
= length
;
6850 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
6851 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
6852 err
= extract_cms_data(context
, buffer
, length
,
6853 &xml_stream
, &xml_stream_length
);
6854 if (err
) goto leave
;
6858 isds_log_message(context
, _("Bad raw delivery representation type"));
6863 isds_log(ILF_ISDS
, ILL_DEBUG
,
6864 _("Delivery info content:\n%.*s\nEnd of delivery info\n"),
6865 xml_stream_length
, xml_stream
);
6867 /* Convert delivery info XML stream into XPath context */
6868 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
6873 xpath_ctx
= xmlXPathNewContext(message_doc
);
6878 /* XXX: Name spaces mangled for signed delivery info:
6879 * http://isds.czechpoint.cz/v20/delivery:
6881 * <q:GetDeliveryInfoResponse xmlns:q="http://isds.czechpoint.cz/v20/delivery">
6883 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
6884 * <p:dmID>170272</p:dmID>
6887 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
6889 * </q:dmEvents>...</q:dmEvents>
6891 * </q:GetDeliveryInfoResponse>
6893 if (register_namespaces(xpath_ctx
, message_ns
)) {
6897 result
= xmlXPathEvalExpression(
6898 BAD_CAST
"/sisds:GetDeliveryInfoResponse/sisds:dmDelivery",
6904 /* Empty delivery info */
6905 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6906 isds_printf_message(context
,
6907 _("XML document ss not sisds:dmDelivery document"));
6911 /* More delivery infos */
6912 if (result
->nodesetval
->nodeNr
> 1) {
6913 isds_printf_message(context
,
6914 _("XML document has more sisds:dmDelivery elements"));
6918 /* One delivery info */
6919 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6921 /* Extract the envelope (= message without documents, hence 0).
6922 * XXX: extract_TReturnedMessage() can obtain attachments size,
6923 * but delivery info carries none. It's coded as option elements,
6924 * so it should work. */
6925 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
6926 if (err
) goto leave
;
6928 /* Extract events */
6929 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmEvents", xpath_ctx
);
6930 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
6931 if (err
) { err
= IE_ERROR
; goto leave
; }
6932 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
6933 if (err
) goto leave
;
6935 /* Append raw CMS structure into message */
6936 (*message
)->raw_type
= raw_type
;
6938 case BUFFER_DONT_STORE
:
6941 (*message
)->raw
= malloc(length
);
6942 if (!(*message
)->raw
) {
6946 memcpy((*message
)->raw
, buffer
, length
);
6947 (*message
)->raw_length
= length
;
6950 (*message
)->raw
= (void *) buffer
;
6951 (*message
)->raw_length
= length
;
6960 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
6961 isds_message_free(message
);
6964 xmlXPathFreeObject(result
);
6965 xmlXPathFreeContext(xpath_ctx
);
6966 xmlFreeDoc(message_doc
);
6967 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
6970 isds_log(ILF_ISDS
, ILL_DEBUG
,
6971 _("Delivery info loaded successfully.\n"));
6976 /* Download signed delivery infosheet of given message identified by ID.
6977 * @context is session context
6978 * @message_id is message identifier (you can get them from
6979 * isds_get_list_of_{sent,received}_messages())
6980 * @message is automatically reallocated message retrieved from ISDS.
6981 * It will miss documents per se. Use isds_get_signed_received_message(),
6982 * if you are interrested in documents (content). OTOH, only this function
6983 * can get list events message has gone through. */
6984 isds_error
isds_get_signed_delivery_info(struct isds_ctx
*context
,
6985 const char *message_id
, struct isds_message
**message
) {
6987 isds_error err
= IE_SUCCESS
;
6988 xmlDocPtr response
= NULL
;
6989 xmlChar
*code
= NULL
, *status_message
= NULL
;
6991 size_t raw_length
= 0;
6993 if (!context
) return IE_INVALID_CONTEXT
;
6995 /* Free former message if any */
6996 if (!message
) return IE_INVAL
;
6997 isds_message_free(message
);
6999 /* Do request and check for success */
7000 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7001 BAD_CAST
"GetSignedDeliveryInfo", message_id
,
7002 &response
, NULL
, NULL
, &code
, &status_message
);
7003 if (err
) goto leave
;
7005 /* Find signed delivery info, extract it into raw and maybe free
7007 err
= find_extract_signed_data_free_response(context
,
7008 (xmlChar
*)message_id
, &response
,
7009 BAD_CAST
"GetSignedDeliveryInfo", &raw
, &raw_length
);
7010 if (err
) goto leave
;
7012 /* Parse delivery info */
7013 err
= isds_load_delivery_info(context
,
7014 RAWTYPE_CMS_SIGNED_DELIVERYINFO
, raw
, raw_length
,
7015 message
, BUFFER_MOVE
);
7016 if (err
) goto leave
;
7022 isds_message_free(message
);
7027 free(status_message
);
7028 xmlFreeDoc(response
);
7031 isds_log(ILF_ISDS
, ILL_DEBUG
,
7032 _("GetSignedDeliveryInfo request processed by server "
7039 /* Download delivery infosheet of given message identified by ID.
7040 * @context is session context
7041 * @message_id is message identifier (you can get them from
7042 * isds_get_list_of_{sent,received}_messages())
7043 * @message is automatically reallocated message retrieved from ISDS.
7044 * It will miss documents per se. Use isds_get_received_message(), if you are
7045 * interrested in documents (content). OTOH, only this function can get list
7046 * events message has gone through. */
7047 isds_error
isds_get_delivery_info(struct isds_ctx
*context
,
7048 const char *message_id
, struct isds_message
**message
) {
7050 isds_error err
= IE_SUCCESS
;
7051 xmlDocPtr response
= NULL
;
7052 xmlChar
*code
= NULL
, *status_message
= NULL
;
7053 xmlXPathContextPtr xpath_ctx
= NULL
;
7054 xmlXPathObjectPtr result
= NULL
;
7055 xmlNodePtr delivery_node
= NULL
;
7057 if (!context
) return IE_INVALID_CONTEXT
;
7059 /* Free former message if any */
7060 if (!message
) return IE_INVAL
;
7061 isds_message_free(message
);
7063 /* Do request and check for success */
7064 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7065 BAD_CAST
"GetDeliveryInfo", message_id
,
7066 &response
, NULL
, NULL
, &code
, &status_message
);
7067 if (err
) goto leave
;
7070 xpath_ctx
= xmlXPathNewContext(response
);
7075 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7079 result
= xmlXPathEvalExpression(
7080 BAD_CAST
"/isds:GetDeliveryInfoResponse/isds:dmDelivery",
7086 /* Empty response */
7087 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7088 char *message_id_locale
= utf82locale((char*) message_id
);
7089 isds_printf_message(context
,
7090 _("Server did not return any delivery info for ID `%s' "
7091 "on GetDeliveryInfo request"), message_id_locale
);
7092 free(message_id_locale
);
7096 /* More delivery infos */
7097 if (result
->nodesetval
->nodeNr
> 1) {
7098 char *message_id_locale
= utf82locale((char*) message_id
);
7099 isds_printf_message(context
,
7100 _("Server did return more delivery infos for ID `%s' "
7101 "on GetDeliveryInfo request"), message_id_locale
);
7102 free(message_id_locale
);
7106 /* One delivery info */
7107 xpath_ctx
->node
= delivery_node
= result
->nodesetval
->nodeTab
[0];
7109 /* Extract the envelope (= message without documents, hence 0).
7110 * XXX: extract_TReturnedMessage() can obtain attachments size,
7111 * but delivery info carries none. It's coded as option elements,
7112 * so it should work. */
7113 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
7114 if (err
) goto leave
;
7116 /* Extract events */
7117 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmEvents", xpath_ctx
);
7118 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
7119 if (err
) { err
= IE_ERROR
; goto leave
; }
7120 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
7121 if (err
) goto leave
;
7124 err
= serialize_subtree(context
, delivery_node
, &(*message
)->raw
,
7125 &(*message
)->raw_length
);
7129 isds_message_free(message
);
7132 xmlXPathFreeObject(result
);
7133 xmlXPathFreeContext(xpath_ctx
);
7136 free(status_message
);
7137 xmlFreeDoc(response
);
7140 isds_log(ILF_ISDS
, ILL_DEBUG
,
7141 _("GetDeliveryInfo request processed by server "
7148 /* Load incoming message from buffer.
7149 * @context is session context
7150 * @buffer XML stream with unsigned message. You can retrieve such data from
7151 * message->raw after calling isds_get_received_message().
7152 * @length is length of buffer in bytes.
7153 * @message is automatically reallocated message parsed from @buffer.
7154 * @strategy selects how buffer will be attached into raw isds_message member.
7156 isds_error
isds_load_received_message(struct isds_ctx
*context
,
7157 const void *buffer
, const size_t length
,
7158 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7160 isds_error err
= IE_SUCCESS
;
7161 xmlDocPtr message_doc
= NULL
;
7162 xmlXPathContextPtr xpath_ctx
= NULL
;
7163 xmlXPathObjectPtr result
= NULL
;
7165 if (!context
) return IE_INVALID_CONTEXT
;
7166 if (!message
) return IE_INVAL
;
7167 isds_message_free(message
);
7168 if (!buffer
) return IE_INVAL
;
7171 isds_log(ILF_ISDS
, ILL_DEBUG
,
7172 _("Incoming message content:\n%.*s\nEnd of message\n"),
7175 /* Convert extracted messages XML stream into XPath context */
7176 message_doc
= xmlParseMemory(buffer
, length
);
7181 xpath_ctx
= xmlXPathNewContext(message_doc
);
7186 /* XXX: Standard name space */
7187 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7191 result
= xmlXPathEvalExpression(
7192 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
7198 /* Missing dmReturnedMessage */
7199 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7200 isds_printf_message(context
,
7201 _("XML document does not contain isds:dmReturnedMessage "
7206 /* More elements. This should never happen. */
7207 if (result
->nodesetval
->nodeNr
> 1) {
7208 isds_printf_message(context
,
7209 _("XML document has more isds:dmReturnedMessage elements"));
7214 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7216 /* Extract the message */
7217 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7218 if (err
) goto leave
;
7220 /* Append XML stream into message */
7221 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7223 case BUFFER_DONT_STORE
:
7226 (*message
)->raw
= malloc(length
);
7227 if (!(*message
)->raw
) {
7231 memcpy((*message
)->raw
, buffer
, length
);
7232 (*message
)->raw_length
= length
;
7235 (*message
)->raw
= (void *) buffer
;
7236 (*message
)->raw_length
= length
;
7245 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7246 isds_message_free(message
);
7249 xmlFreeDoc(message_doc
);
7250 xmlXPathFreeObject(result
);
7251 xmlXPathFreeContext(xpath_ctx
);
7254 isds_log(ILF_ISDS
, ILL_DEBUG
,
7255 _("Incoming message loaded successfully.\n"));
7260 /* Download incoming message identified by ID.
7261 * @context is session context
7262 * @message_id is message identifier (you can get them from
7263 * isds_get_list_of_received_messages())
7264 * @message is automatically reallocated message retrieved from ISDS */
7265 isds_error
isds_get_received_message(struct isds_ctx
*context
,
7266 const char *message_id
, struct isds_message
**message
) {
7268 isds_error err
= IE_SUCCESS
;
7269 xmlDocPtr response
= NULL
;
7270 void *xml_stream
= NULL
;
7271 size_t xml_stream_length
;
7272 xmlChar
*code
= NULL
, *status_message
= NULL
;
7273 xmlXPathContextPtr xpath_ctx
= NULL
;
7274 xmlXPathObjectPtr result
= NULL
;
7275 char *phys_path
= NULL
;
7276 size_t phys_start
, phys_end
;
7278 if (!context
) return IE_INVALID_CONTEXT
;
7280 /* Free former message if any */
7281 if (message
) isds_message_free(message
);
7283 /* Do request and check for success */
7284 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7285 BAD_CAST
"MessageDownload", message_id
,
7286 &response
, &xml_stream
, &xml_stream_length
,
7287 &code
, &status_message
);
7288 if (err
) goto leave
;
7291 xpath_ctx
= xmlXPathNewContext(response
);
7296 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7300 result
= xmlXPathEvalExpression(
7301 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
7307 /* Empty response */
7308 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7309 char *message_id_locale
= utf82locale((char*) message_id
);
7310 isds_printf_message(context
,
7311 _("Server did not return any message for ID `%s' "
7312 "on MessageDownload request"), message_id_locale
);
7313 free(message_id_locale
);
7318 if (result
->nodesetval
->nodeNr
> 1) {
7319 char *message_id_locale
= utf82locale((char*) message_id
);
7320 isds_printf_message(context
,
7321 _("Server did return more messages for ID `%s' "
7322 "on MessageDownload request"), message_id_locale
);
7323 free(message_id_locale
);
7328 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7330 /* Extract the message */
7331 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7332 if (err
) goto leave
;
7334 /* Locate raw XML blob */
7336 SOAP_NS PHYSXML_NS_SEPARATOR
"Envelope"
7337 PHYSXML_ELEMENT_SEPARATOR
7338 SOAP_NS PHYSXML_NS_SEPARATOR
"Body"
7339 PHYSXML_ELEMENT_SEPARATOR
7340 ISDS_NS PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
7346 err
= find_element_boundary(xml_stream
, xml_stream_length
,
7347 phys_path
, &phys_start
, &phys_end
);
7350 isds_log_message(context
,
7351 _("Substring with isds:MessageDownloadResponse element "
7352 "could not be located in raw SOAP message"));
7356 /*err = serialize_subtree(context, xpath_ctx->node, &(*message)->raw,
7357 &(*message)->raw_length);*/
7358 /* TODO: Store name space declarations from ancestors */
7359 /* TODO: Handle non-UTF-8 encoding (XML prologue) */
7360 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7361 (*message
)->raw_length
= phys_end
- phys_start
+ 1;
7362 (*message
)->raw
= malloc((*message
)->raw_length
);
7363 if (!(*message
)->raw
) {
7367 memcpy((*message
)->raw
, xml_stream
+ phys_start
, (*message
)->raw_length
);
7372 isds_message_free(message
);
7377 xmlXPathFreeObject(result
);
7378 xmlXPathFreeContext(xpath_ctx
);
7381 free(status_message
);
7383 xmlFreeDoc(response
);
7386 isds_log(ILF_ISDS
, ILL_DEBUG
,
7387 _("MessageDownload request processed by server "
7394 /* Load signed message from buffer.
7395 * @context is session context
7396 * @outgoing is true if message is outgoing, false if message is incoming
7397 * @buffer is DER encoded PKCS#7 structure with signed message. You can
7398 * retrieve such data from message->raw after calling
7399 * isds_get_signed_{received,sent}_message().
7400 * @length is length of buffer in bytes.
7401 * @message is automatically reallocated message parsed from @buffer.
7402 * @strategy selects how buffer will be attached into raw isds_message member.
7404 isds_error
isds_load_signed_message(struct isds_ctx
*context
,
7405 const _Bool outgoing
, const void *buffer
, const size_t length
,
7406 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7408 isds_error err
= IE_SUCCESS
;
7409 xmlDocPtr message_doc
= NULL
;
7410 xmlXPathContextPtr xpath_ctx
= NULL
;
7411 xmlXPathObjectPtr result
= NULL
;
7412 void *xml_stream
= NULL
;
7413 size_t xml_stream_length
= 0;
7415 if (!context
) return IE_INVALID_CONTEXT
;
7416 if (!message
) return IE_INVAL
;
7417 isds_message_free(message
);
7418 if (!buffer
) return IE_INVAL
;
7421 /* Extract message from PKCS#7 structure */
7422 err
= extract_cms_data(context
, buffer
, length
,
7423 &xml_stream
, &xml_stream_length
);
7424 if (err
) goto leave
;
7426 isds_log(ILF_ISDS
, ILL_DEBUG
, (outgoing
) ?
7427 _("Signed outgoing message content:\n%.*s\nEnd of message\n") :
7428 _("Signed incoming message content:\n%.*s\nEnd of message\n"),
7429 xml_stream_length
, xml_stream
);
7431 /* Convert extracted messages XML stream into XPath context */
7432 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7437 xpath_ctx
= xmlXPathNewContext(message_doc
);
7442 /* XXX: Name spaces mangled for outgoing direction:
7443 * http://isds.czechpoint.cz/v20/SentMessage:
7445 * <q:MessageDownloadResponse
7446 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
7447 * <q:dmReturnedMessage>
7448 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7449 * <p:dmID>151916</p:dmID>
7452 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7454 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7455 * </q:dmReturnedMessage>
7456 * </q:MessageDownloadResponse>
7458 * XXX: Name spaces mangled for incoming direction:
7459 * http://isds.czechpoint.cz/v20/message:
7461 * <q:MessageDownloadResponse
7462 * xmlns:q="http://isds.czechpoint.cz/v20/message">
7463 * <q:dmReturnedMessage>
7464 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7465 * <p:dmID>151916</p:dmID>
7468 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7470 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7471 * </q:dmReturnedMessage>
7472 * </q:MessageDownloadResponse>
7474 * Stupidity of ISDS developers is unlimited */
7475 if (register_namespaces(xpath_ctx
, (outgoing
) ?
7476 MESSAGE_NS_SIGNED_OUTGOING
: MESSAGE_NS_SIGNED_INCOMING
)) {
7480 /* XXX: Embeded message XML document is always rooted as
7481 * /sisds:MessageDownloadResponse (even outgoing message). */
7482 result
= xmlXPathEvalExpression(
7483 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
7489 /* Empty embedded message */
7490 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7491 isds_printf_message(context
,
7492 _("XML document embedded into PKCS#7 structure is not "
7493 "sisds:dmReturnedMessage document"));
7497 /* More embedded messages */
7498 if (result
->nodesetval
->nodeNr
> 1) {
7499 isds_printf_message(context
,
7500 _("Embeded XML document into PKCS#7 structure has more "
7501 "root sisds:dmReturnedMessage elements"));
7505 /* One embedded message */
7506 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7508 /* Extract the message */
7509 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7510 if (err
) goto leave
;
7512 /* Append raw CMS structure into message */
7513 (*message
)->raw_type
= (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7514 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
;
7516 case BUFFER_DONT_STORE
:
7519 (*message
)->raw
= malloc(length
);
7520 if (!(*message
)->raw
) {
7524 memcpy((*message
)->raw
, buffer
, length
);
7525 (*message
)->raw_length
= length
;
7528 (*message
)->raw
= (void *) buffer
;
7529 (*message
)->raw_length
= length
;
7539 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7540 isds_message_free(message
);
7543 xmlFreeDoc(message_doc
);
7544 cms_data_free(xml_stream
);
7545 xmlXPathFreeObject(result
);
7546 xmlXPathFreeContext(xpath_ctx
);
7549 isds_log(ILF_ISDS
, ILL_DEBUG
,
7550 _("Signed message loaded successfully.\n"));
7555 /* Load message of any type from buffer.
7556 * @context is session context
7557 * @raw_type defines content type of @buffer. Only message types are allowed.
7558 * @buffer is message raw representation. Format (CMS, plain signed,
7559 * message direction) is defined in @raw_type. You can retrieve such data
7560 * from message->raw after calling isds_get_[signed]{received,sent}_message().
7561 * @length is length of buffer in bytes.
7562 * @message is automatically reallocated message parsed from @buffer.
7563 * @strategy selects how buffer will be attached into raw isds_message member.
7565 isds_error
isds_load_message(struct isds_ctx
*context
,
7566 const isds_raw_type raw_type
, const void *buffer
, const size_t length
,
7567 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7569 isds_error err
= IE_SUCCESS
;
7570 void *xml_stream
= NULL
;
7571 size_t xml_stream_length
= 0;
7572 message_ns_type message_ns
;
7573 xmlDocPtr message_doc
= NULL
;
7574 xmlXPathContextPtr xpath_ctx
= NULL
;
7575 xmlXPathObjectPtr result
= NULL
;
7577 if (!context
) return IE_INVALID_CONTEXT
;
7578 if (!message
) return IE_INVAL
;
7579 isds_message_free(message
);
7580 if (!buffer
) return IE_INVAL
;
7583 /* Select buffer format and extract XML from CMS*/
7585 case RAWTYPE_INCOMING_MESSAGE
:
7586 message_ns
= MESSAGE_NS_UNSIGNED
;
7587 xml_stream
= (void *) buffer
;
7588 xml_stream_length
= length
;
7591 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
7592 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7593 xml_stream
= (void *) buffer
;
7594 xml_stream_length
= length
;
7597 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
7598 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7599 err
= extract_cms_data(context
, buffer
, length
,
7600 &xml_stream
, &xml_stream_length
);
7601 if (err
) goto leave
;
7604 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
7605 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7606 xml_stream
= (void *) buffer
;
7607 xml_stream_length
= length
;
7610 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7611 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7612 err
= extract_cms_data(context
, buffer
, length
,
7613 &xml_stream
, &xml_stream_length
);
7614 if (err
) goto leave
;
7618 isds_log_message(context
, _("Bad raw message representation type"));
7623 isds_log(ILF_ISDS
, ILL_DEBUG
,
7624 _("Loading message:\n%.*s\nEnd of message\n"),
7625 xml_stream_length
, xml_stream
);
7627 /* Convert messages XML stream into XPath context */
7628 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7633 xpath_ctx
= xmlXPathNewContext(message_doc
);
7638 /* XXX: Standard name space for unsigned icoming direction:
7639 * http://isds.czechpoint.cz/v20/SentMessage
7641 * XXX: Name spaces mangled for signed outgoing direction:
7642 * http://isds.czechpoint.cz/v20/SentMessage:
7644 * <q:MessageDownloadResponse
7645 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
7646 * <q:dmReturnedMessage>
7647 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7648 * <p:dmID>151916</p:dmID>
7651 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7653 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7654 * </q:dmReturnedMessage>
7655 * </q:MessageDownloadResponse>
7657 * XXX: Name spaces mangled for signed incoming direction:
7658 * http://isds.czechpoint.cz/v20/message:
7660 * <q:MessageDownloadResponse
7661 * xmlns:q="http://isds.czechpoint.cz/v20/message">
7662 * <q:dmReturnedMessage>
7663 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7664 * <p:dmID>151916</p:dmID>
7667 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7669 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7670 * </q:dmReturnedMessage>
7671 * </q:MessageDownloadResponse>
7673 * Stupidity of ISDS developers is unlimited */
7674 if (register_namespaces(xpath_ctx
, message_ns
)) {
7678 result
= xmlXPathEvalExpression(
7679 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
7686 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7687 isds_printf_message(context
,
7688 _("XML document does not contain "
7689 "sisds:dmReturnedMessage element"));
7694 if (result
->nodesetval
->nodeNr
> 1) {
7695 isds_printf_message(context
,
7696 _("XML document has more sisds:dmReturnedMessage elements"));
7701 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7703 /* Extract the message */
7704 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7705 if (err
) goto leave
;
7707 /* Append raw buffer into message */
7708 (*message
)->raw_type
= raw_type
;
7710 case BUFFER_DONT_STORE
:
7713 (*message
)->raw
= malloc(length
);
7714 if (!(*message
)->raw
) {
7718 memcpy((*message
)->raw
, buffer
, length
);
7719 (*message
)->raw_length
= length
;
7722 (*message
)->raw
= (void *) buffer
;
7723 (*message
)->raw_length
= length
;
7733 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7734 isds_message_free(message
);
7737 if (xml_stream
!= buffer
) cms_data_free(xml_stream
);
7738 xmlXPathFreeObject(result
);
7739 xmlXPathFreeContext(xpath_ctx
);
7740 xmlFreeDoc(message_doc
);
7743 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Message loaded successfully.\n"));
7748 /* Download signed incoming/outgoing message identified by ID.
7749 * @context is session context
7750 * @output is true for outging message, false for incoming message
7751 * @message_id is message identifier (you can get them from
7752 * isds_get_list_of_{sent,received}_messages())
7753 * @message is automatically reallocated message retrieved from ISDS. The raw
7754 * memeber will be filled with PKCS#7 structure in DER format. */
7755 _hidden isds_error
isds_get_signed_message(struct isds_ctx
*context
,
7756 const _Bool outgoing
, const char *message_id
,
7757 struct isds_message
**message
) {
7759 isds_error err
= IE_SUCCESS
;
7760 xmlDocPtr response
= NULL
;
7761 xmlChar
*code
= NULL
, *status_message
= NULL
;
7762 xmlXPathContextPtr xpath_ctx
= NULL
;
7763 xmlXPathObjectPtr result
= NULL
;
7764 char *encoded_structure
= NULL
;
7766 size_t raw_length
= 0;
7768 if (!context
) return IE_INVALID_CONTEXT
;
7769 if (!message
) return IE_INVAL
;
7770 isds_message_free(message
);
7772 /* Do request and check for success */
7773 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7774 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7775 BAD_CAST
"SignedMessageDownload",
7776 message_id
, &response
, NULL
, NULL
, &code
, &status_message
);
7777 if (err
) goto leave
;
7779 /* Find signed message, extract it into raw and maybe free
7781 err
= find_extract_signed_data_free_response(context
,
7782 (xmlChar
*)message_id
, &response
,
7783 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7784 BAD_CAST
"SignedMessageDownload",
7786 if (err
) goto leave
;
7789 err
= isds_load_message(context
,
7790 (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7791 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
,
7792 raw
, raw_length
, message
, BUFFER_MOVE
);
7793 if (err
) goto leave
;
7799 isds_message_free(message
);
7802 free(encoded_structure
);
7803 xmlXPathFreeObject(result
);
7804 xmlXPathFreeContext(xpath_ctx
);
7808 free(status_message
);
7809 xmlFreeDoc(response
);
7812 isds_log(ILF_ISDS
, ILL_DEBUG
,
7814 _("SignedSentMessageDownload request processed by server "
7815 "successfully.\n") :
7816 _("SignedMessageDownload request processed by server "
7823 /* Download signed incoming message identified by ID.
7824 * @context is session context
7825 * @message_id is message identifier (you can get them from
7826 * isds_get_list_of_received_messages())
7827 * @message is automatically reallocated message retrieved from ISDS. The raw
7828 * memeber will be filled with PKCS#7 structure in DER format. */
7829 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
7830 const char *message_id
, struct isds_message
**message
) {
7831 return isds_get_signed_message(context
, 0, message_id
, message
);
7835 /* Download signed outgoing message identified by ID.
7836 * @context is session context
7837 * @message_id is message identifier (you can get them from
7838 * isds_get_list_of_sent_messages())
7839 * @message is automatically reallocated message retrieved from ISDS. The raw
7840 * memeber will be filled with PKCS#7 structure in DER format. */
7841 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
7842 const char *message_id
, struct isds_message
**message
) {
7843 return isds_get_signed_message(context
, 1, message_id
, message
);
7847 /* Retrieve hash of message identified by ID stored in ISDS.
7848 * @context is session context
7849 * @message_id is message identifier
7850 * @hash is automatically reallocated message hash downloaded from ISDS.
7851 * Message must exist in system and must not be deleted. */
7852 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
7853 const char *message_id
, struct isds_hash
**hash
) {
7855 isds_error err
= IE_SUCCESS
;
7856 xmlDocPtr response
= NULL
;
7857 xmlChar
*code
= NULL
, *status_message
= NULL
;
7858 xmlXPathContextPtr xpath_ctx
= NULL
;
7859 xmlXPathObjectPtr result
= NULL
;
7861 if (!context
) return IE_INVALID_CONTEXT
;
7863 isds_hash_free(hash
);
7865 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7866 BAD_CAST
"VerifyMessage", message_id
,
7867 &response
, NULL
, NULL
, &code
, &status_message
);
7868 if (err
) goto leave
;
7872 xpath_ctx
= xmlXPathNewContext(response
);
7877 if (register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7881 result
= xmlXPathEvalExpression(
7882 BAD_CAST
"/isds:VerifyMessageResponse",
7888 /* Empty response */
7889 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7890 char *message_id_locale
= utf82locale((char*) message_id
);
7891 isds_printf_message(context
,
7892 _("Server did not return any response for ID `%s' "
7893 "on VerifyMessage request"), message_id_locale
);
7894 free(message_id_locale
);
7898 /* More responses */
7899 if (result
->nodesetval
->nodeNr
> 1) {
7900 char *message_id_locale
= utf82locale((char*) message_id
);
7901 isds_printf_message(context
,
7902 _("Server did return more responses for ID `%s' "
7903 "on VerifyMessage request"), message_id_locale
);
7904 free(message_id_locale
);
7909 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7911 /* Extract the hash */
7912 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
7916 isds_hash_free(hash
);
7919 xmlXPathFreeObject(result
);
7920 xmlXPathFreeContext(xpath_ctx
);
7923 free(status_message
);
7924 xmlFreeDoc(response
);
7927 isds_log(ILF_ISDS
, ILL_DEBUG
,
7928 _("VerifyMessage request processed by server "
7935 /* Mark message as read. This is a transactional commit function to acknoledge
7936 * to ISDS the message has been downloaded and processed by client properly.
7937 * @context is session context
7938 * @message_id is message identifier. */
7939 isds_error
isds_mark_message_read(struct isds_ctx
*context
,
7940 const char *message_id
) {
7942 isds_error err
= IE_SUCCESS
;
7943 xmlDocPtr response
= NULL
;
7944 xmlChar
*code
= NULL
, *status_message
= NULL
;
7946 if (!context
) return IE_INVALID_CONTEXT
;
7948 /* Do request and check for success */
7949 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7950 BAD_CAST
"MarkMessageAsDownloaded", message_id
,
7951 &response
, NULL
, NULL
, &code
, &status_message
);
7954 free(status_message
);
7955 xmlFreeDoc(response
);
7958 isds_log(ILF_ISDS
, ILL_DEBUG
,
7959 _("MarkMessageAsDownloaded request processed by server "
7965 /* Mark message as received by recipient. This is applicable only to
7966 * commercial message. There is no specified way how to distinguishe
7967 * commercial message from government message yet. Government message is
7968 * received automatically (by law), commenrcial message on recipient request.
7969 * @context is session context
7970 * @message_id is message identifier. */
7971 isds_error
isds_mark_message_received(struct isds_ctx
*context
,
7972 const char *message_id
) {
7974 isds_error err
= IE_SUCCESS
;
7975 xmlDocPtr response
= NULL
;
7976 xmlChar
*code
= NULL
, *status_message
= NULL
;
7978 if (!context
) return IE_INVALID_CONTEXT
;
7980 /* Do request and check for success */
7981 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7982 BAD_CAST
"ConfirmDelivery", message_id
,
7983 &response
, NULL
, NULL
, &code
, &status_message
);
7986 free(status_message
);
7987 xmlFreeDoc(response
);
7990 isds_log(ILF_ISDS
, ILL_DEBUG
,
7991 _("ConfirmDelivery request processed by server "
7998 #undef INSERT_ELEMENT
7999 #undef CHECK_FOR_STRING_LENGTH
8000 #undef INSERT_STRING_ATTRIBUTE
8001 #undef INSERT_ULONGINTNOPTR
8002 #undef INSERT_ULONGINT
8003 #undef INSERT_LONGINT
8004 #undef INSERT_BOOLEAN
8005 #undef INSERT_SCALAR_BOOLEAN
8006 #undef INSERT_STRING
8007 #undef EXTRACT_STRING_ATTRIBUTE
8008 #undef EXTRACT_ULONGINT
8009 #undef EXTRACT_LONGINT
8010 #undef EXTRACT_BOOLEAN
8011 #undef EXTRACT_STRING
8014 /* Compute hash of message from raw representation and store it into envelope.
8015 * Original hash structure will be destroyed in envelope.
8016 * @context is session context
8017 * @message is message carrying raw XML message blob
8018 * @algorithm is desired hash algorithm to use */
8019 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
8020 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
8021 isds_error err
= IE_SUCCESS
;
8023 void *xml_stream
= NULL
;
8024 size_t xml_stream_length
;
8025 size_t phys_start
, phys_end
;
8026 char *phys_path
= NULL
;
8027 struct isds_hash
*new_hash
= NULL
;
8030 if (!context
) return IE_INVALID_CONTEXT
;
8031 if (!message
) return IE_INVAL
;
8033 if (!message
->raw
) {
8034 isds_log_message(context
,
8035 _("Message does not carry raw representation"));
8039 switch (message
->raw_type
) {
8040 case RAWTYPE_INCOMING_MESSAGE
:
8042 xml_stream
= message
->raw
;
8043 xml_stream_length
= message
->raw_length
;
8046 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
8047 nsuri
= SISDS_INCOMING_NS
;
8048 xml_stream
= message
->raw
;
8049 xml_stream_length
= message
->raw_length
;
8052 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
8053 nsuri
= SISDS_INCOMING_NS
;
8054 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
8055 &xml_stream
, &xml_stream_length
);
8056 if (err
) goto leave
;
8059 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
8060 nsuri
= SISDS_OUTGOING_NS
;
8061 xml_stream
= message
->raw
;
8062 xml_stream_length
= message
->raw_length
;
8065 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
8066 nsuri
= SISDS_OUTGOING_NS
;
8067 err
= extract_cms_data(context
, message
->raw
, message
->raw_length
,
8068 &xml_stream
, &xml_stream_length
);
8069 if (err
) goto leave
;
8073 isds_log_message(context
, _("Bad raw representation type"));
8079 /* XXX: Hash is computed from original string represinting isds:dmDm
8080 * subtree. That means no encoding, white space, xmlns attributes changes.
8081 * In other words, input for hash can be invalid XML stream. */
8082 if (-1 == isds_asprintf(&phys_path
, "%s%s%s%s",
8083 nsuri
, PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
8084 PHYSXML_ELEMENT_SEPARATOR
,
8085 nsuri
, PHYSXML_NS_SEPARATOR
"dmReturnedMessage"
8086 PHYSXML_ELEMENT_SEPARATOR
8087 ISDS_NS PHYSXML_NS_SEPARATOR
"dmDm")) {
8091 err
= find_element_boundary(xml_stream
, xml_stream_length
,
8092 phys_path
, &phys_start
, &phys_end
);
8095 isds_log_message(context
,
8096 _("Substring with isds:dmDM element could not be located "
8103 new_hash
= calloc(1, sizeof(*new_hash
));
8108 new_hash
->algorithm
= algorithm
;
8109 err
= compute_hash(xml_stream
+ phys_start
, phys_end
- phys_start
+ 1,
8112 isds_log_message(context
, _("Could not compute message hash"));
8116 /* Save computed hash */
8117 if (!message
->envelope
) {
8118 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
8119 if (!message
->envelope
) {
8124 isds_hash_free(&message
->envelope
->hash
);
8125 message
->envelope
->hash
= new_hash
;
8129 isds_hash_free(&new_hash
);
8133 if (xml_stream
!= message
->raw
) free(xml_stream
);
8138 /* Compare two hashes.
8140 * @h2 is another hash
8142 * IE_SUCCESS if hashes equal
8143 * IE_NOTUNIQ if hashes are comparable, but they don't equal
8144 * IE_ENUM if not comparable, but both structures defined
8145 * IE_INVAL if some of the structures are undefined (NULL)
8146 * IE_ERROR if internal error occurs */
8147 isds_error
isds_hash_cmp(const struct isds_hash
*h1
, const struct isds_hash
*h2
) {
8148 if (h1
== NULL
|| h2
== NULL
) return IE_INVAL
;
8149 if (h1
->algorithm
!= h2
->algorithm
) return IE_ENUM
;
8150 if (h1
->length
!= h2
->length
) return IE_ERROR
;
8151 if (h1
->length
> 0 && !h1
->value
) return IE_ERROR
;
8152 if (h2
->length
> 0 && !h2
->value
) return IE_ERROR
;
8154 for (int i
= 0; i
< h1
->length
; i
++) {
8155 if (((uint8_t *) (h1
->value
))[i
] != ((uint8_t *) (h2
->value
))[i
])
8162 /* Check message has gone through ISDS by comparing message hash stored in
8163 * ISDS and locally computed hash. You must provide message with valid raw
8164 * member (do not use isds_load_message(..., BUFFER_DONT_STORE)).
8165 * This is convenient wrapper for isds_download_message_hash(),
8166 * isds_compute_message_hash(), and isds_hash_cmp() sequence.
8167 * @context is session context
8168 * @message is message with valid raw and envelope member; envelope->hash
8169 * member will be changed during funcion run. Use envelope on heap only.
8171 * IE_SUCCESS if message originates in ISDS
8172 * IE_NOTEQUAL if message is unknown to ISDS
8173 * other code for other errors */
8174 isds_error
isds_verify_message_hash(struct isds_ctx
*context
,
8175 struct isds_message
*message
) {
8176 isds_error err
= IE_SUCCESS
;
8177 struct isds_hash
*downloaded_hash
= NULL
;
8179 if (!context
) return IE_INVALID_CONTEXT
;
8180 if (!message
) return IE_INVAL
;
8182 if (!message
->envelope
) {
8183 isds_log_message(context
,
8184 _("Given message structure is missing envelope"));
8187 if (!message
->raw
) {
8188 isds_log_message(context
,
8189 _("Given message structure is missing raw representation"));
8193 err
= isds_download_message_hash(context
, message
->envelope
->dmID
,
8195 if (err
) goto leave
;
8197 err
= isds_compute_message_hash(context
, message
,
8198 downloaded_hash
->algorithm
);
8199 if (err
) goto leave
;
8201 err
= isds_hash_cmp(downloaded_hash
, message
->envelope
->hash
);
8204 isds_hash_free(&downloaded_hash
);
8209 /* Search for document by document ID in list of documents. IDs are compared
8211 * @documents is list of isds_documents
8212 * @id is document identifier
8213 * @return first matching document or NULL. */
8214 const struct isds_document
*isds_find_document_by_id(
8215 const struct isds_list
*documents
, const char *id
) {
8216 const struct isds_list
*item
;
8217 const struct isds_document
*document
;
8219 for (item
= documents
; item
; item
= item
->next
) {
8220 document
= (struct isds_document
*) item
->data
;
8221 if (!document
) continue;
8223 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
8231 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
8232 struct isds_message **message);
8233 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
8234 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
8235 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
8236 struct isds_address **address);
8238 int isds_message_free(struct isds_message **message);
8239 int isds_address_free(struct isds_address **address);
8243 /* Makes known all relevant namespaces to given XPath context
8244 * @xpat_ctx is XPath context
8245 * @message_ns selects propper message name space. Unsisnged and signed
8247 * prefix and to URI ISDS_NS */
8248 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
,
8249 const message_ns_type message_ns
) {
8250 const xmlChar
*message_namespace
= NULL
;
8252 if (!xpath_ctx
) return IE_ERROR
;
8254 switch(message_ns
) {
8255 case MESSAGE_NS_UNSIGNED
:
8256 message_namespace
= BAD_CAST ISDS_NS
; break;
8257 case MESSAGE_NS_SIGNED_INCOMING
:
8258 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
8259 case MESSAGE_NS_SIGNED_OUTGOING
:
8260 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
8261 case MESSAGE_NS_SIGNED_DELIVERY
:
8262 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
8267 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
8269 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
8271 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
8273 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))