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 /* Base URL of production ISDS instance */
18 const char isds_locator
[] = "https://www.mojedatovaschranka.cz/";
20 /* Base URL of production ISDS instance */
21 const char isds_testing_locator
[] = "https://www.czebox.cz/";
23 /* Extension to MIME type map */
24 static xmlChar
*extension_map_mime
[] = {
25 BAD_CAST
"pdf", BAD_CAST
"application/pdf",
26 BAD_CAST
"xml", BAD_CAST
"application/xml",
27 BAD_CAST
"fo", BAD_CAST
"application/vnd.software602.filler.xml+form",
28 BAD_CAST
"zfo", BAD_CAST
"application/vnd.software602.filler.xml+zip+form",
29 BAD_CAST
"html", BAD_CAST
"text/html",
30 BAD_CAST
"htm", BAD_CAST
"text/html",
31 BAD_CAST
"odt", BAD_CAST
"application/vnd.oasis.opendocument.text",
32 BAD_CAST
"ods", BAD_CAST
"application/vnd.oasis.opendocument.spreadsheet",
33 BAD_CAST
"odp", BAD_CAST
"application/vnd.oasis.opendocument.presentation",
34 BAD_CAST
"txt", BAD_CAST
"text/plain",
35 BAD_CAST
"rtf", BAD_CAST
"application/rtf",
36 BAD_CAST
"doc", BAD_CAST
"application/msword",
37 BAD_CAST
"xls", BAD_CAST
"application/vnd.ms-excel",
38 BAD_CAST
"ppt", BAD_CAST
"application/vnd.ms-powerpoint",
39 BAD_CAST
"jpg", BAD_CAST
"image/jpeg",
40 BAD_CAST
"jpeg", BAD_CAST
"image/jpeg",
41 BAD_CAST
"jfif", BAD_CAST
"image/jpeg",
42 BAD_CAST
"png", BAD_CAST
"image/png",
43 BAD_CAST
"tiff", BAD_CAST
"image/tiff",
44 BAD_CAST
"gif", BAD_CAST
"image/gif",
45 BAD_CAST
"mpeg1", BAD_CAST
"video/mpeg",
46 BAD_CAST
"mpeg2", BAD_CAST
"video/mpeg2",
47 BAD_CAST
"wav", BAD_CAST
"audio/x-wav",
48 BAD_CAST
"mp2", BAD_CAST
"audio/mpeg",
49 BAD_CAST
"mp3", BAD_CAST
"audio/mpeg",
50 /* TODO: Add MIME types for ISDOC, X.509 certificates, CMS and TST */
53 /* Deallocate structure isds_pki_credentials and NULL it.
54 * Passphrase is discarded.
55 * @pki credentials to to free */
56 void isds_pki_credentials_free(struct isds_pki_credentials
**pki
) {
57 if(!pki
|| !*pki
) return;
60 free((*pki
)->certificate
);
63 if ((*pki
)->passphrase
) {
64 memset((*pki
)->passphrase
, 0, strlen((*pki
)->passphrase
));
65 free((*pki
)->passphrase
);
72 /* Free isds_list with all member data.
73 * @list list to free, on return will be NULL */
74 void isds_list_free(struct isds_list
**list
) {
75 struct isds_list
*item
, *next_item
;
77 if (!list
|| !*list
) return;
79 for(item
= *list
; item
; item
= next_item
) {
80 (item
->destructor
)(&(item
->data
));
81 next_item
= item
->next
;
89 /* Deallocate structure isds_hash and NULL it.
90 * @hash hash to to free */
91 void isds_hash_free(struct isds_hash
**hash
) {
92 if(!hash
|| !*hash
) return;
98 /* Deallocate structure isds_PersonName recursively and NULL it */
99 static void isds_PersonName_free(struct isds_PersonName
**person_name
) {
100 if (!person_name
|| !*person_name
) return;
102 free((*person_name
)->pnFirstName
);
103 free((*person_name
)->pnMiddleName
);
104 free((*person_name
)->pnLastName
);
105 free((*person_name
)->pnLastNameAtBirth
);
112 /* Deallocate structure isds_BirthInfo recursively and NULL it */
113 static void isds_BirthInfo_free(struct isds_BirthInfo
**birth_info
) {
114 if (!birth_info
|| !*birth_info
) return;
116 free((*birth_info
)->biDate
);
117 free((*birth_info
)->biCity
);
118 free((*birth_info
)->biCounty
);
119 free((*birth_info
)->biState
);
126 /* Deallocate structure isds_Address recursively and NULL it */
127 static void isds_Address_free(struct isds_Address
**address
) {
128 if (!address
|| !*address
) return;
130 free((*address
)->adCity
);
131 free((*address
)->adStreet
);
132 free((*address
)->adNumberInStreet
);
133 free((*address
)->adNumberInMunicipality
);
134 free((*address
)->adZipCode
);
135 free((*address
)->adState
);
142 /* Deallocate structure isds_DbOwnerInfo recursively and NULL it */
143 void isds_DbOwnerInfo_free(struct isds_DbOwnerInfo
**db_owner_info
) {
144 if (!db_owner_info
|| !*db_owner_info
) return;
146 free((*db_owner_info
)->dbID
);
147 free((*db_owner_info
)->dbType
);
148 free((*db_owner_info
)->ic
);
149 isds_PersonName_free(&((*db_owner_info
)->personName
));
150 free((*db_owner_info
)->firmName
);
151 isds_BirthInfo_free(&((*db_owner_info
)->birthInfo
));
152 isds_Address_free(&((*db_owner_info
)->address
));
153 free((*db_owner_info
)->nationality
);
154 free((*db_owner_info
)->email
);
155 free((*db_owner_info
)->telNumber
);
156 free((*db_owner_info
)->identifier
);
157 free((*db_owner_info
)->registryCode
);
158 free((*db_owner_info
)->dbState
);
159 free((*db_owner_info
)->dbEffectiveOVM
);
161 free(*db_owner_info
);
162 *db_owner_info
= NULL
;
165 /* Deallocate structure isds_DbUserInfo recursively and NULL it */
166 void isds_DbUserInfo_free(struct isds_DbUserInfo
**db_user_info
) {
167 if (!db_user_info
|| !*db_user_info
) return;
169 free((*db_user_info
)->userID
);
170 free((*db_user_info
)->userType
);
171 free((*db_user_info
)->userPrivils
);
172 isds_PersonName_free(&((*db_user_info
)->personName
));
173 isds_Address_free(&((*db_user_info
)->address
));
174 free((*db_user_info
)->biDate
);
175 free((*db_user_info
)->ic
);
176 free((*db_user_info
)->firmName
);
177 free((*db_user_info
)->caStreet
);
178 free((*db_user_info
)->caCity
);
179 free((*db_user_info
)->caZipCode
);
180 free((*db_user_info
)->caState
);
182 zfree(*db_user_info
);
186 /* Deallocate struct isds_event recursively and NULL it */
187 void isds_event_free(struct isds_event
**event
) {
188 if (!event
|| !*event
) return;
190 free((*event
)->time
);
191 free((*event
)->type
);
192 free((*event
)->description
);
197 /* Deallocate struct isds_envelope recursively and NULL it */
198 void isds_envelope_free(struct isds_envelope
**envelope
) {
199 if (!envelope
|| !*envelope
) return;
201 free((*envelope
)->dmID
);
202 free((*envelope
)->dbIDSender
);
203 free((*envelope
)->dmSender
);
204 free((*envelope
)->dmSenderAddress
);
205 free((*envelope
)->dmSenderType
);
206 free((*envelope
)->dmRecipient
);
207 free((*envelope
)->dmRecipientAddress
);
208 free((*envelope
)->dmAmbiguousRecipient
);
209 free((*envelope
)->dmType
);
211 free((*envelope
)->dmOrdinal
);
212 free((*envelope
)->dmMessageStatus
);
213 free((*envelope
)->dmDeliveryTime
);
214 free((*envelope
)->dmAcceptanceTime
);
215 isds_hash_free(&(*envelope
)->hash
);
216 free((*envelope
)->timestamp
);
217 isds_list_free(&(*envelope
)->events
);
219 free((*envelope
)->dmSenderOrgUnit
);
220 free((*envelope
)->dmSenderOrgUnitNum
);
221 free((*envelope
)->dbIDRecipient
);
222 free((*envelope
)->dmRecipientOrgUnit
);
223 free((*envelope
)->dmRecipientOrgUnitNum
);
224 free((*envelope
)->dmToHands
);
225 free((*envelope
)->dmAnnotation
);
226 free((*envelope
)->dmRecipientRefNumber
);
227 free((*envelope
)->dmSenderRefNumber
);
228 free((*envelope
)->dmRecipientIdent
);
229 free((*envelope
)->dmSenderIdent
);
231 free((*envelope
)->dmLegalTitleLaw
);
232 free((*envelope
)->dmLegalTitleYear
);
233 free((*envelope
)->dmLegalTitleSect
);
234 free((*envelope
)->dmLegalTitlePar
);
235 free((*envelope
)->dmLegalTitlePoint
);
237 free((*envelope
)->dmPersonalDelivery
);
238 free((*envelope
)->dmAllowSubstDelivery
);
239 free((*envelope
)->dmOVM
);
246 /* Deallocate struct isds_message recursively and NULL it */
247 void isds_message_free(struct isds_message
**message
) {
248 if (!message
|| !*message
) return;
250 free((*message
)->raw
);
251 isds_envelope_free(&((*message
)->envelope
));
252 isds_list_free(&((*message
)->documents
));
253 xmlFreeDoc((*message
)->xml
); (*message
)->xml
= NULL
;
260 /* Deallocate struct isds_document recursively and NULL it */
261 void isds_document_free(struct isds_document
**document
) {
262 if (!document
|| !*document
) return;
264 free((*document
)->data
);
265 free((*document
)->dmMimeType
);
266 free((*document
)->dmFileGuid
);
267 free((*document
)->dmUpFileGuid
);
268 free((*document
)->dmFileDescr
);
269 free((*document
)->dmFormat
);
276 /* Deallocate struct isds_message_copy recursively and NULL it */
277 void isds_message_copy_free(struct isds_message_copy
**copy
) {
278 if (!copy
|| !*copy
) return;
280 free((*copy
)->dbIDRecipient
);
281 free((*copy
)->dmRecipientOrgUnit
);
282 free((*copy
)->dmRecipientOrgUnitNum
);
283 free((*copy
)->dmToHands
);
285 free((*copy
)->dmStatus
);
292 /* Deallocate struct isds_approval recursively and NULL it */
293 void isds_approval_free(struct isds_approval
**approval
) {
294 if (!approval
|| !*approval
) return;
296 free((*approval
)->refference
);
302 /* *DUP_OR_ERROR macros needs error label */
303 #define STRDUP_OR_ERROR(new, template) { \
307 (new) = strdup(template); \
308 if (!new) goto error; \
312 #define FLATDUP_OR_ERROR(new, template) { \
316 (new) = malloc(sizeof(*(new))); \
317 if (!new) goto error; \
318 memcpy((new), (template), sizeof(*(template))); \
322 /* Copy structure isds_pki_credentials recursively. */
323 struct isds_pki_credentials
*isds_pki_credentials_duplicate(
324 const struct isds_pki_credentials
*template) {
325 struct isds_pki_credentials
*new = NULL
;
327 if(!template) return NULL
;
329 new = calloc(1, sizeof(*new));
330 if (!new) return NULL
;
332 STRDUP_OR_ERROR(new->engine
, template->engine
);
333 new->certificate_format
= template->certificate_format
;
334 STRDUP_OR_ERROR(new->certificate
, template->certificate
);
335 new->key_format
= template->key_format
;
336 STRDUP_OR_ERROR(new->key
, template->key
);
337 STRDUP_OR_ERROR(new->passphrase
, template->passphrase
);
342 isds_pki_credentials_free(&new);
347 /* Copy structure isds_PersonName recursively */
348 struct isds_PersonName
*isds_PersonName_duplicate(
349 const struct isds_PersonName
*template) {
350 struct isds_PersonName
*new = NULL
;
352 if (!template) return NULL
;
354 new = calloc(1, sizeof(*new));
355 if (!new) return NULL
;
357 STRDUP_OR_ERROR(new->pnFirstName
, template->pnFirstName
);
358 STRDUP_OR_ERROR(new->pnMiddleName
, template->pnMiddleName
);
359 STRDUP_OR_ERROR(new->pnLastName
, template->pnLastName
);
360 STRDUP_OR_ERROR(new->pnLastNameAtBirth
, template->pnLastNameAtBirth
);
365 isds_PersonName_free(&new);
370 /* Copy structure isds_BirthInfo recursively */
371 static struct isds_BirthInfo
*isds_BirthInfo_duplicate(
372 const struct isds_BirthInfo
*template) {
373 struct isds_BirthInfo
*new = NULL
;
375 if (!template) return NULL
;
377 new = calloc(1, sizeof(*new));
378 if (!new) return NULL
;
380 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
381 STRDUP_OR_ERROR(new->biCity
, template->biCity
);
382 STRDUP_OR_ERROR(new->biCounty
, template->biCounty
);
383 STRDUP_OR_ERROR(new->biState
, template->biState
);
388 isds_BirthInfo_free(&new);
393 /* Copy structure isds_Address recursively */
394 struct isds_Address
*isds_Address_duplicate(
395 const struct isds_Address
*template) {
396 struct isds_Address
*new = NULL
;
398 if (!template) return NULL
;
400 new = calloc(1, sizeof(*new));
401 if (!new) return NULL
;
403 STRDUP_OR_ERROR(new->adCity
, template->adCity
);
404 STRDUP_OR_ERROR(new->adStreet
, template->adStreet
);
405 STRDUP_OR_ERROR(new->adNumberInStreet
, template->adNumberInStreet
);
406 STRDUP_OR_ERROR(new->adNumberInMunicipality
,
407 template->adNumberInMunicipality
);
408 STRDUP_OR_ERROR(new->adZipCode
, template->adZipCode
);
409 STRDUP_OR_ERROR(new->adState
, template->adState
);
414 isds_Address_free(&new);
419 /* Copy structure isds_DbOwnerInfo recursively */
420 struct isds_DbOwnerInfo
*isds_DbOwnerInfo_duplicate(
421 const struct isds_DbOwnerInfo
*template) {
422 struct isds_DbOwnerInfo
*new = NULL
;
423 if (!template) return NULL
;
425 new = calloc(1, sizeof(*new));
426 if (!new) return NULL
;
428 STRDUP_OR_ERROR(new->dbID
, template->dbID
);
429 FLATDUP_OR_ERROR(new->dbType
, template->dbType
);
430 STRDUP_OR_ERROR(new->ic
, template->ic
);
432 if (template->personName
) {
433 if (!(new->personName
=
434 isds_PersonName_duplicate(template->personName
)))
438 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
440 if (template->birthInfo
) {
441 if (!(new->birthInfo
=
442 isds_BirthInfo_duplicate(template->birthInfo
)))
446 if (template->address
) {
447 if (!(new->address
= isds_Address_duplicate(template->address
)))
451 STRDUP_OR_ERROR(new->nationality
, template->nationality
);
452 STRDUP_OR_ERROR(new->email
, template->email
);
453 STRDUP_OR_ERROR(new->telNumber
, template->telNumber
);
454 STRDUP_OR_ERROR(new->identifier
, template->identifier
);
455 STRDUP_OR_ERROR(new->registryCode
, template->registryCode
);
456 FLATDUP_OR_ERROR(new->dbState
, template->dbState
);
457 FLATDUP_OR_ERROR(new->dbEffectiveOVM
, template->dbEffectiveOVM
);
458 FLATDUP_OR_ERROR(new->dbOpenAddressing
, template->dbOpenAddressing
);
463 isds_DbOwnerInfo_free(&new);
468 /* Copy structure isds_DbUserInfo recursively */
469 struct isds_DbUserInfo
*isds_DbUserInfo_duplicate(
470 const struct isds_DbUserInfo
*template) {
471 struct isds_DbUserInfo
*new = NULL
;
472 if (!template) return NULL
;
474 new = calloc(1, sizeof(*new));
475 if (!new) return NULL
;
477 STRDUP_OR_ERROR(new->userID
, template->userID
);
478 FLATDUP_OR_ERROR(new->userType
, template->userType
);
479 FLATDUP_OR_ERROR(new->userPrivils
, template->userPrivils
);
481 if (template->personName
) {
482 if (!(new->personName
=
483 isds_PersonName_duplicate(template->personName
)))
487 if (template->address
) {
488 if (!(new->address
= isds_Address_duplicate(template->address
)))
492 FLATDUP_OR_ERROR(new->biDate
, template->biDate
);
493 STRDUP_OR_ERROR(new->ic
, template->ic
);
494 STRDUP_OR_ERROR(new->firmName
, template->firmName
);
495 STRDUP_OR_ERROR(new->caStreet
, template->caStreet
);
496 STRDUP_OR_ERROR(new->caCity
, template->caCity
);
497 STRDUP_OR_ERROR(new->caZipCode
, template->caZipCode
);
498 STRDUP_OR_ERROR(new->caState
, template->caState
);
503 isds_DbUserInfo_free(&new);
507 #undef FLATDUP_OR_ERROR
508 #undef STRDUP_OR_ERROR
511 /* Initialize ISDS library.
512 * Global function, must be called before other functions.
513 * If it failes you can not use ISDS library and must call isds_cleanup() to
514 * free partially inititialized global variables. */
515 isds_error
isds_init(void) {
516 /* NULL global variables */
517 log_facilities
= ILF_ALL
;
518 log_level
= ILL_WARNING
;
520 log_callback_data
= NULL
;
523 /* Initialize gettext */
524 bindtextdomain(PACKAGE
, LOCALEDIR
);
527 /* Initialize CURL */
528 if (curl_global_init(CURL_GLOBAL_ALL
)) {
529 isds_log(ILF_ISDS
, ILL_CRIT
, _("CURL library initialization failed\n"));
533 /* Inicialize gpg-error because of gpgme and ksba */
534 if (gpg_err_init()) {
535 isds_log(ILF_ISDS
, ILL_CRIT
,
536 _("gpg-error library initialization failed\n"));
540 /* Initialize GPGME */
541 if (_isds_init_gpgme(&version_gpgme
)) {
542 isds_log(ILF_ISDS
, ILL_CRIT
,
543 _("GPGME library initialization failed\n"));
547 /* Initialize gcrypt */
548 if (_isds_init_gcrypt(&version_gcrypt
)) {
549 isds_log(ILF_ISDS
, ILL_CRIT
,
550 _("gcrypt library initialization failed\n"));
554 /* This can _exit() current program. Find not so assertive check. */
558 if (_isds_init_expat(&version_expat
)) {
559 isds_log(ILF_ISDS
, ILL_CRIT
,
560 _("expat library initialization failed\n"));
564 /* Allocate global variables */
571 /* Deinicialize ISDS library.
572 * Global function, must be called as last library function. */
573 isds_error
isds_cleanup(void) {
578 curl_global_cleanup();
584 /* Return version string of this library. Version of dependecies can be
585 * embedded. Do no try to parse it. You must free it. */
586 char *isds_version(void) {
589 isds_asprintf(&buffer
, _("%s (%s, GPGME %s, gcrypt %s, %s, libxml2 %s)"),
590 PACKAGE_VERSION
, curl_version(), version_gpgme
, version_gcrypt
,
591 version_expat
, xmlParserVersion
);
596 /* Return text description of ISDS error */
597 const char *isds_strerror(const isds_error error
) {
600 return(_("Success")); break;
602 return(_("Unspecified error")); break;
604 return(_("Not supported")); break;
606 return(_("Invalid value")); break;
607 case IE_INVALID_CONTEXT
:
608 return(_("Invalid context")); break;
609 case IE_NOT_LOGGED_IN
:
610 return(_("Not logged in")); break;
611 case IE_CONNECTION_CLOSED
:
612 return(_("Connection closed")); break;
614 return(_("Timed out")); break;
616 return(_("Not exist")); break;
618 return(_("Out of memory")); break;
620 return(_("Network problem")); break;
622 return(_("HTTP problem")); break;
624 return(_("SOAP problem")); break;
626 return(_("XML problem")); break;
628 return(_("ISDS server problem")); break;
630 return(_("Invalid enum value")); break;
632 return(_("Invalid date value")); break;
634 return(_("Too big")); break;
636 return(_("Too small")); break;
638 return(_("Value not unique")); break;
640 return(_("Values not uqual")); break;
641 case IE_PARTIAL_SUCCESS
:
642 return(_("Some suboperations failed")); break;
644 return(_("Operation aborted")); break;
646 return(_("Unknown error"));
651 /* Create ISDS context.
652 * Each context can be used for different sessions to (possibly) differnet
653 * ISDS server with different credentials. */
654 struct isds_ctx
*isds_ctx_create(void) {
655 struct isds_ctx
*context
;
656 context
= malloc(sizeof(*context
));
657 if (context
) memset(context
, 0, sizeof(*context
));
662 /* Close possibly opened connection to Czech POINT document deposit without
663 * reseting long_message buffer.
664 * XXX: Do not use czp_close_connection() if you do not want to destroy log
666 * @context is Czech POINT session context. */
667 static isds_error
czp_do_close_connection(struct isds_ctx
*context
) {
668 if (!context
) return IE_INVALID_CONTEXT
;
669 _isds_close_connection(context
);
674 /* Discard credentials.
675 * Only that. It does not cause log out, connection close or similar. */
676 static isds_error
discard_credentials(struct isds_ctx
*context
) {
677 if(!context
) return IE_INVALID_CONTEXT
;
679 if (context
->username
) {
680 memset(context
->username
, 0, strlen(context
->username
));
681 zfree(context
->username
);
683 if (context
->password
) {
684 memset(context
->password
, 0, strlen(context
->password
));
685 zfree(context
->password
);
687 isds_pki_credentials_free(&context
->pki_credentials
);
693 /* Destroy ISDS context and free memmory.
694 * @context will be NULLed on success. */
695 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
696 if (!context
|| !*context
) {
697 return IE_INVALID_CONTEXT
;
700 /* Discard credentials and close connection */
701 switch ((*context
)->type
) {
702 case CTX_TYPE_NONE
: break;
703 case CTX_TYPE_ISDS
: isds_logout(*context
); break;
705 case CTX_TYPE_TESTING_REQUEST_COLLECTOR
:
706 czp_do_close_connection(*context
); break;
710 discard_credentials(*context
);
712 /* Free other structures */
713 free((*context
)->tls_verify_server
);
714 free((*context
)->tls_ca_file
);
715 free((*context
)->tls_ca_dir
);
716 free((*context
)->tls_crl_file
);
717 free((*context
)->long_message
);
725 /* Return long message text produced by library fucntion, e.g. detailed error
726 * mesage. Returned pointer is only valid until new library function is
727 * called for the same context. Could be NULL, especially if NULL context is
728 * supplied. Return string is locale encoded. */
729 char *isds_long_message(const struct isds_ctx
*context
) {
730 if (!context
) return NULL
;
731 return context
->long_message
;
735 /* Stores message into context' long_message buffer.
736 * Application can pick the message up using isds_long_message().
737 * NULL @message truncates the buffer but does not deallocate it.
738 * @message is coded in locale encoding */
739 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
740 const char *message
) {
744 if (!context
) return IE_INVALID_CONTEXT
;
746 /* FIXME: Check for integer overflow */
747 length
= 1 + ((message
) ? strlen(message
) : 0);
748 buffer
= realloc(context
->long_message
, length
);
749 if (!buffer
) return IE_NOMEM
;
752 strcpy(buffer
, message
);
756 context
->long_message
= buffer
;
761 /* Appends message into context' long_message buffer.
762 * Application can pick the message up using isds_long_message().
763 * NULL message has void effect. */
764 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
765 const char *message
) {
767 size_t old_length
, length
;
769 if (!context
) return IE_INVALID_CONTEXT
;
770 if (!message
) return IE_SUCCESS
;
771 if (!context
->long_message
)
772 return isds_log_message(context
, message
);
774 old_length
= strlen(context
->long_message
);
775 /* FIXME: Check for integer overflow */
776 length
= 1 + old_length
+ strlen(message
);
777 buffer
= realloc(context
->long_message
, length
);
778 if (!buffer
) return IE_NOMEM
;
780 strcpy(buffer
+ old_length
, message
);
782 context
->long_message
= buffer
;
787 /* Stores formated message into context' long_message buffer.
788 * Application can pick the message up using isds_long_message(). */
789 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
790 const char *format
, ...) {
794 if (!context
) return IE_INVALID_CONTEXT
;
795 va_start(ap
, format
);
796 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
799 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
804 * @facilities is bitmask of isds_log_facility values,
805 * @level is verbosity level. */
806 void isds_set_logging(const unsigned int facilities
,
807 const isds_log_level level
) {
808 log_facilities
= facilities
;
813 /* Register callback function libisds calls when new global log message is
814 * produced by library. Library logs to stderr by default.
815 * @callback is function provided by application libsds will call. See type
816 * defition for @callback argument explanation. Pass NULL to revert logging to
818 * @data is application specific data @callback gets as last argument */
819 void isds_set_log_callback(isds_log_callback callback
, void *data
) {
820 log_callback
= callback
;
821 log_callback_data
= data
;
825 /* Log @message in class @facility with log @level into global log. @message
826 * is printf(3) formating string, variadic arguments may be neccessary.
827 * For debugging purposes. */
828 _hidden isds_error
isds_log(const isds_log_facility facility
,
829 const isds_log_level level
, const char *message
, ...) {
834 if (level
> log_level
) return IE_SUCCESS
;
835 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
836 if (!message
) return IE_INVAL
;
839 /* Pass message to application supplied callback function */
840 va_start(ap
, message
);
841 length
= isds_vasprintf(&buffer
, message
, ap
);
848 log_callback(facility
, level
, buffer
, length
, log_callback_data
);
852 /* Default: Log it to stderr */
853 va_start(ap
, message
);
854 vfprintf(stderr
, message
, ap
);
856 /* Line buffered printf is default.
864 /* Set timeout in miliseconds for each network job like connecting to server
865 * or sending message. Use 0 to disable timeout limits. */
866 isds_error
isds_set_timeout(struct isds_ctx
*context
,
867 const unsigned int timeout
) {
868 if (!context
) return IE_INVALID_CONTEXT
;
869 zfree(context
->long_message
);
871 context
->timeout
= timeout
;
876 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
878 #if HAVE_DECL_CURLOPT_TIMEOUT_MS /* Since curl-7.16.2 */
879 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
882 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT
,
883 context
->timeout
/ 1000);
884 #endif /* not HAVE_DECL_CURLOPT_TIMEOUT_MS */
885 if (curl_err
) return IE_ERROR
;
892 /* Register callback function libisds calls periodocally during HTTP data
894 * @context is session context
895 * @callback is function provided by application libsds will call. See type
896 * defition for @callback argument explanation.
897 * @data is application specific data @callback gets as last argument */
898 isds_error
isds_set_progress_callback(struct isds_ctx
*context
,
899 isds_progress_callback callback
, void *data
) {
900 if (!context
) return IE_INVALID_CONTEXT
;
901 zfree(context
->long_message
);
903 context
->progress_callback
= callback
;
904 context
->progress_callback_data
= data
;
910 /* Change context settings.
911 * @context is context which setting vill be applied to
912 * @option is name of option. It determines the type of last argument. See
913 * isds_option definition for more info.
914 * @... is value of new setting. Type is determined by @option
916 isds_error
isds_set_opt(struct isds_ctx
*context
, const isds_option option
,
918 isds_error err
= IE_SUCCESS
;
920 char *pointer
, *string
;
922 if (!context
) return IE_INVALID_CONTEXT
;
923 zfree(context
->long_message
);
925 va_start(ap
, option
);
927 #define REPLACE_VA_BOOLEAN(destination) { \
928 if (!(destination)) { \
929 (destination) = malloc(sizeof(*(destination))); \
930 if (!(destination)) { \
931 err = IE_NOMEM; goto leave; \
934 *(destination) = (_Bool) !!va_arg(ap, int); \
937 #define REPLACE_VA_STRING(destination) { \
938 string = va_arg(ap, char *); \
940 pointer = realloc((destination), 1 + strlen(string)); \
941 if (!pointer) { err = IE_NOMEM; goto leave; } \
942 strcpy(pointer, string); \
943 (destination) = pointer; \
946 (destination) = NULL; \
951 case IOPT_TLS_VERIFY_SERVER
:
952 REPLACE_VA_BOOLEAN(context
->tls_verify_server
);
954 case IOPT_TLS_CA_FILE
:
955 REPLACE_VA_STRING(context
->tls_ca_file
);
957 case IOPT_TLS_CA_DIRECTORY
:
958 REPLACE_VA_STRING(context
->tls_ca_dir
);
960 case IOPT_TLS_CRL_FILE
:
961 #if HAVE_DECL_CURLOPT_CRLFILE /* Since curl-7.19.0 */
962 REPLACE_VA_STRING(context
->tls_crl_file
);
964 isds_log_message(context
,
965 _("Curl library does not support CRL definition"));
967 #endif /* not HAVE_DECL_CURLOPT_CRLFILE */
969 case IOPT_NORMALIZE_MIME_TYPE
:
970 context
->normalize_mime_type
= (_Bool
) !!va_arg(ap
, int);
973 err
= IE_ENUM
; goto leave
;
976 #undef REPLACE_VA_STRING
977 #undef REPLACE_VA_BOOLEAN
985 /* Deprecated: Use isds_set_opt() instead.
986 * Change SSL/TLS settings.
987 * @context is context which setting will be applied to
988 * @option is name of option. It determines the type of last argument. See
989 * isds_tls_option definition for more info.
990 * @... is value of new setting. Type is determined by @option
992 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
994 isds_error err
= IE_ENUM
;
997 va_start(ap
, option
);
1000 case ITLS_VERIFY_SERVER
:
1001 err
= isds_set_opt(context
, option
, va_arg(ap
, int));
1004 case ITLS_CA_DIRECTORY
:
1006 err
= isds_set_opt(context
, option
, va_arg(ap
, char*));
1014 /* Connect and log in into ISDS server.
1015 * All required arguments will be copied, you do not have to keep them after
1017 * ISDS supports four different authentication methods. Exact method is
1018 * selected on @username, @passwors and @pki_credentials arguments:
1019 * - If @pki_credentials == NULL, @username and @password must be supplied
1020 * - If @pki_credentials != NULL, then
1021 * - If @username == NULL, only certificate will be used
1022 * - If @username != NULL, then
1023 * - If @password == NULL, then certificate will be used and
1024 * @username shifts meaning to box ID. This is used for hosted
1026 * - Otherwise all three arguments will be used.
1027 * Please note, that differen cases requires different certificate type
1028 * (system qualified one or commercial non qualified one). This library does
1029 * not check such political issues. Please see ISDS Specification for more
1031 * @url is base address of ISDS web service. Pass NULL or extern isds_locator
1032 * variable to use production ISDS instance. You can pass extern
1033 * isds_testing_locator variable to select testing instance.
1034 * @username is user name of ISDS user or box ID
1035 * @password is user's secret password
1036 * @pki_credentials defines public key cryptographic material to use in client
1037 * authentication. */
1038 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
1039 const char *username
, const char *password
,
1040 const struct isds_pki_credentials
*pki_credentials
) {
1041 isds_error err
= IE_NOT_LOGGED_IN
;
1042 isds_error soap_err
;
1043 xmlNsPtr isds_ns
= NULL
;
1044 xmlNodePtr request
= NULL
;
1045 xmlNodePtr response
= NULL
;
1047 if (!context
) return IE_INVALID_CONTEXT
;
1048 zfree(context
->long_message
);
1050 /* Close connection if already logged in */
1051 if (context
->curl
) {
1052 _isds_close_connection(context
);
1055 /* Default locator is offical system */
1056 if (!url
) url
= isds_locator
;
1058 /* Store configuration */
1059 context
->type
= CTX_TYPE_ISDS
;
1060 zfree(context
->url
);
1062 /* Mangle base URI according requested authentication method */
1063 if (!pki_credentials
) {
1064 isds_log(ILF_SEC
, ILL_INFO
,
1065 _("Selected authentication method: no certificate, "
1066 "username and password\n"));
1067 if (!username
|| !password
) {
1068 isds_log_message(context
,
1069 _("Both username and password must be supplied"));
1072 context
->url
= strdup(url
);
1075 isds_log(ILF_SEC
, ILL_INFO
,
1076 _("Selected authentication method: system certificate, "
1077 "no username and no password\n"));
1079 context
->url
= _isds_astrcat(url
, "cert/");
1082 isds_log(ILF_SEC
, ILL_INFO
,
1083 _("Selected authentication method: system certificate, "
1084 "box ID and no password\n"));
1085 context
->url
= _isds_astrcat(url
, "hspis/");
1087 isds_log(ILF_SEC
, ILL_INFO
,
1088 _("Selected authentication method: commercial "
1089 "certificate, username and password\n"));
1090 context
->url
= _isds_astrcat(url
, "cert/");
1094 if (!(context
->url
))
1097 /* Prepare CURL handle */
1098 context
->curl
= curl_easy_init();
1099 if (!(context
->curl
))
1102 /* Build login request */
1103 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
1105 isds_log_message(context
, _("Could build ISDS login request"));
1108 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1110 isds_log_message(context
, _("Could not create ISDS name space"));
1111 xmlFreeNode(request
);
1114 xmlSetNs(request
, isds_ns
);
1116 /* Store credentials */
1117 /* FIXME: mlock password
1118 * (I have a library) */
1119 discard_credentials(context
);
1120 if (username
) context
->username
= strdup(username
);
1121 if (password
) context
->password
= strdup(password
);
1122 context
->pki_credentials
= isds_pki_credentials_duplicate(pki_credentials
);
1123 if ((username
&& !context
->username
) || (password
&& !context
->password
) ||
1124 (pki_credentials
&& !context
->pki_credentials
)) {
1125 discard_credentials(context
);
1126 xmlFreeNode(request
);
1130 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
1133 /* Send login request */
1134 soap_err
= _isds_soap(context
, "DS/dz", request
, &response
, NULL
, NULL
);
1136 /* Remove credentials */
1137 discard_credentials(context
);
1139 /* Destroy login request */
1140 xmlFreeNode(request
);
1143 xmlFreeNodeList(response
);
1144 _isds_close_connection(context
);
1148 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
1149 * authentication succeeded if soap_err == IE_SUCCESS */
1152 xmlFreeNodeList(response
);
1155 isds_log(ILF_ISDS
, ILL_DEBUG
,
1156 _("User %s has been logged into server %s successfully\n"),
1162 /* Log out from ISDS server discards credentials and connection configuration. */
1163 isds_error
isds_logout(struct isds_ctx
*context
) {
1164 if (!context
) return IE_INVALID_CONTEXT
;
1165 zfree(context
->long_message
);
1167 /* Close connection */
1168 if (context
->curl
) {
1169 _isds_close_connection(context
);
1171 /* Discard credentials for sure. They should not survive isds_login(),
1172 * even successful .*/
1173 discard_credentials(context
);
1174 zfree(context
->url
);
1176 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
1178 discard_credentials(context
);
1184 /* Verify connection to ISDS is alive and server is responding.
1185 * Sent dumy request to ISDS and expect dummy response. */
1186 isds_error
isds_ping(struct isds_ctx
*context
) {
1187 isds_error soap_err
;
1188 xmlNsPtr isds_ns
= NULL
;
1189 xmlNodePtr request
= NULL
;
1190 xmlNodePtr response
= NULL
;
1192 if (!context
) return IE_INVALID_CONTEXT
;
1193 zfree(context
->long_message
);
1195 /* Check if connection is established */
1196 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
1199 /* Build dummy request */
1200 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
1202 isds_log_message(context
, _("Could build ISDS dummy request"));
1205 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1207 isds_log_message(context
, _("Could not create ISDS name space"));
1208 xmlFreeNode(request
);
1211 xmlSetNs(request
, isds_ns
);
1213 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
1215 /* Sent dummy request */
1216 soap_err
= _isds_soap(context
, "DS/dz", request
, &response
, NULL
, NULL
);
1218 /* Destroy login request */
1219 xmlFreeNode(request
);
1222 isds_log(ILF_ISDS
, ILL_DEBUG
,
1223 _("ISDS server could not be contacted\n"));
1224 xmlFreeNodeList(response
);
1228 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
1229 * authentication succeeded if soap_err == IE_SUCCESS */
1230 /* TODO: ISDS documentation does not specify response body.
1231 * However real server sends back DummyOperationResponse */
1234 xmlFreeNodeList(response
);
1236 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
1242 /* Send bogus request to ISDS.
1243 * Just for test purposes */
1244 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
1246 xmlNsPtr isds_ns
= NULL
;
1247 xmlNodePtr request
= NULL
;
1248 xmlDocPtr response
= NULL
;
1249 xmlChar
*code
= NULL
, *message
= NULL
;
1251 if (!context
) return IE_INVALID_CONTEXT
;
1252 zfree(context
->long_message
);
1254 /* Check if connection is established */
1255 if (!context
->curl
) {
1256 /* Testing printf message */
1257 isds_printf_message(context
, "%s", _("I said connection closed"));
1258 return IE_CONNECTION_CLOSED
;
1262 /* Build dummy request */
1263 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
1265 isds_log_message(context
, _("Could build ISDS bogus request"));
1268 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1270 isds_log_message(context
, _("Could not create ISDS name space"));
1271 xmlFreeNode(request
);
1274 xmlSetNs(request
, isds_ns
);
1276 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
1278 /* Sent bogus request */
1279 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
1281 /* Destroy request */
1282 xmlFreeNode(request
);
1285 isds_log(ILF_ISDS
, ILL_DEBUG
,
1286 _("Processing ISDS response on bogus request failed\n"));
1287 xmlFreeDoc(response
);
1291 /* Check for response status */
1292 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
1293 &code
, &message
, NULL
);
1295 isds_log(ILF_ISDS
, ILL_DEBUG
,
1296 _("ISDS response on bogus request is missing status\n"));
1299 xmlFreeDoc(response
);
1302 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
1303 char *code_locale
= _isds_utf82locale((char*)code
);
1304 char *message_locale
= _isds_utf82locale((char*)message
);
1305 isds_log(ILF_ISDS
, ILL_DEBUG
,
1306 _("Server refused bogus request (code=%s, message=%s)\n"),
1307 code_locale
, message_locale
);
1308 /* XXX: Literal error messages from ISDS are Czech mesages
1309 * (English sometimes) in UTF-8. It's hard to catch them for
1310 * translation. Successfully gettextized would return in locale
1311 * encoding, unsuccessfully translated would pass in UTF-8. */
1312 isds_log_message(context
, message_locale
);
1314 free(message_locale
);
1317 xmlFreeDoc(response
);
1324 xmlFreeDoc(response
);
1326 isds_log(ILF_ISDS
, ILL_DEBUG
,
1327 _("Bogus message accepted by server. This should not happen.\n"));
1333 /* Serialize XML subtree to buffer preserving XML indentatition.
1334 * @context is session context
1335 * @subtree is XML element to be serialized (with childern)
1336 * @buffer is automatically reallocated buffer where serialize to
1337 * @length is size of serialized stream in bytes
1338 * @return standard error code, free @buffer in case of error */
1339 static isds_error
serialize_subtree(struct isds_ctx
*context
,
1340 xmlNodePtr subtree
, void **buffer
, size_t *length
) {
1341 isds_error err
= IE_SUCCESS
;
1342 xmlBufferPtr xml_buffer
= NULL
;
1343 xmlSaveCtxtPtr save_ctx
= NULL
;
1344 xmlDocPtr subtree_doc
= NULL
;
1345 xmlNodePtr subtree_copy
;
1349 if (!context
) return IE_INVALID_CONTEXT
;
1350 if (!buffer
) return IE_INVAL
;
1352 if (!subtree
|| !length
) return IE_INVAL
;
1354 /* Make temporary XML document with @subtree root element */
1355 /* XXX: We can not use xmlNodeDump() because it dumps the subtree as is.
1356 * It can result in not well-formed on invalid XML tree (e.g. name space
1357 * prefix definition can miss. */
1360 subtree_doc
= xmlNewDoc(BAD_CAST
"1.0");
1362 isds_log_message(context
, _("Could not build temporary document"));
1367 /* XXX: Copy subtree and attach the copy to document.
1368 * One node can not bee attached into more document at the same time.
1369 * XXX: Check xmlDOMWrapRemoveNode(). It could solve NS references
1371 * XXX: Check xmlSaveTree() too. */
1372 subtree_copy
= xmlCopyNodeList(subtree
);
1373 if (!subtree_copy
) {
1374 isds_log_message(context
, _("Could not copy subtree"));
1378 xmlDocSetRootElement(subtree_doc
, subtree_copy
);
1380 /* Only this way we get namespace definition as @xmlns:isds,
1381 * otherwise we get namespace prefix without definition */
1382 /* FIXME: Don't overwrite original default namespace */
1383 isds_ns
= xmlNewNs(subtree_copy
, BAD_CAST ISDS_NS
, NULL
);
1385 isds_log_message(context
, _("Could not create ISDS name space"));
1389 xmlSetNs(subtree_copy
, isds_ns
);
1392 /* Serialize the document into buffer */
1393 xml_buffer
= xmlBufferCreate();
1395 isds_log_message(context
, _("Could not create xmlBuffer"));
1399 /* Last argument 0 means to not format the XML tree */
1400 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8", 0);
1402 isds_log_message(context
, _("Could not create XML serializer"));
1406 /* XXX: According LibXML documentation, this function does not return
1407 * meaningfull value yet */
1408 xmlSaveDoc(save_ctx
, subtree_doc
);
1409 if (-1 == xmlSaveFlush(save_ctx
)) {
1410 isds_log_message(context
,
1411 _("Could not serialize XML subtree"));
1415 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1416 * even after xmlSaveFlush(). Thus close it here */
1417 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1420 /* Store and detach buffer from xml_buffer */
1421 *buffer
= xml_buffer
->content
;
1422 *length
= xml_buffer
->use
;
1423 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1426 new_buffer
= realloc(*buffer
, *length
);
1427 if (new_buffer
) *buffer
= new_buffer
;
1435 xmlSaveClose(save_ctx
);
1436 xmlBufferFree(xml_buffer
);
1437 xmlFreeDoc(subtree_doc
); /* Frees subtree_copy, isds_ns etc. */
1442 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1443 * @context is session context
1444 * @document is original document where @nodeset points to
1445 * @nodeset is XPath node set to dump (recursively)
1446 * @buffer is automarically reallocated buffer where serialize to
1447 * @length is size of serialized stream in bytes
1448 * @return standard error code, free @buffer in case of error */
1449 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1450 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1451 void **buffer
, size_t *length
) {
1452 isds_error err
= IE_SUCCESS
;
1453 xmlBufferPtr xml_buffer
= NULL
;
1456 if (!context
) return IE_INVALID_CONTEXT
;
1457 if (!buffer
) return IE_INVAL
;
1459 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1462 /* Empty node set results into NULL buffer */
1463 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1467 /* Resuling the document into buffer */
1468 xml_buffer
= xmlBufferCreate();
1470 isds_log_message(context
, _("Could not create xmlBuffer"));
1475 /* Itearate over all nodes */
1476 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1478 * XXX: xmlNodeDump() appends to xml_buffer. */
1480 xmlNodeDump(xml_buffer
, document
, nodeset
->nodeTab
[i
], 0, 0)) {
1481 isds_log_message(context
, _("Could not dump XML node"));
1487 /* Store and detach buffer from xml_buffer */
1488 *buffer
= xml_buffer
->content
;
1489 *length
= xml_buffer
->use
;
1490 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1493 new_buffer
= realloc(*buffer
, *length
);
1494 if (new_buffer
) *buffer
= new_buffer
;
1503 xmlBufferFree(xml_buffer
);
1509 /* Dump XML subtree to buffer as literral string, not valid XML possibly.
1510 * @context is session context
1511 * @document is original document where @nodeset points to
1512 * @nodeset is XPath node set to dump (recursively)
1513 * @buffer is automarically reallocated buffer where serialize to
1514 * @length is size of serialized stream in bytes
1515 * @return standard error code, free @buffer in case of error */
1516 static isds_error
dump_nodeset(struct isds_ctx
*context
,
1517 const xmlDocPtr document
, const xmlNodeSetPtr nodeset
,
1518 void **buffer
, size_t *length
) {
1519 isds_error err
= IE_SUCCESS
;
1520 xmlBufferPtr xml_buffer
= NULL
;
1521 xmlSaveCtxtPtr save_ctx
= NULL
;
1524 if (!context
) return IE_INVALID_CONTEXT
;
1525 if (!buffer
) return IE_INVAL
;
1527 if (!document
|| !nodeset
|| !length
) return IE_INVAL
;
1530 /* Empty node set results into NULL buffer */
1531 if (xmlXPathNodeSetIsEmpty(nodeset
)) {
1535 /* Resuling the document into buffer */
1536 xml_buffer
= xmlBufferCreate();
1538 isds_log_message(context
, _("Could not create xmlBuffer"));
1542 if (xmlSubstituteEntitiesDefault(1)) {
1543 isds_log_message(context
, _("Could not disable attribute escaping"));
1547 /* Last argument means:
1548 * 0 to not format the XML tree
1549 * XML_SAVE_NO_EMPTY ISDS does not produce shorten tags */
1550 save_ctx
= xmlSaveToBuffer(xml_buffer
, "UTF-8",
1551 XML_SAVE_NO_DECL
|XML_SAVE_NO_EMPTY
|XML_SAVE_NO_XHTML
);
1553 isds_log_message(context
, _("Could not create XML serializer"));
1557 /*if (xmlSaveSetAttrEscape(save_ctx, NULL)) {
1558 isds_log_message(context, _("Could not disable attribute escaping"));
1564 /* Itearate over all nodes */
1565 for (int i
= 0; i
< nodeset
->nodeNr
; i
++) {
1567 * XXX: xmlNodeDump() appends to xml_buffer. */
1569 xmlNodeDump(xml_buffer, document, nodeset->nodeTab[i], 0, 0)) {
1571 /* XXX: According LibXML documentation, this function does not return
1572 * meaningfull value yet */
1573 xmlSaveTree(save_ctx
, nodeset
->nodeTab
[i
]);
1574 if (-1 == xmlSaveFlush(save_ctx
)) {
1575 isds_log_message(context
,
1576 _("Could not serialize XML subtree"));
1582 /* XXX: libxml-2.7.4 complains when xmlSaveClose() on immutable buffer
1583 * even after xmlSaveFlush(). Thus close it here */
1584 xmlSaveClose(save_ctx
); save_ctx
= NULL
;
1586 /* Store and detach buffer from xml_buffer */
1587 *buffer
= xml_buffer
->content
;
1588 *length
= xml_buffer
->use
;
1589 xmlBufferSetAllocationScheme(xml_buffer
, XML_BUFFER_ALLOC_IMMUTABLE
);
1592 new_buffer
= realloc(*buffer
, *length
);
1593 if (new_buffer
) *buffer
= new_buffer
;
1601 xmlSaveClose(save_ctx
);
1602 xmlBufferFree(xml_buffer
);
1608 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
1609 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
1610 if (!string
|| !type
) return IE_INVAL
;
1612 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
1614 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
1616 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
1617 *type
= DBTYPE_PFO_ADVOK
;
1618 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
1619 *type
= DBTYPE_PFO_DANPOR
;
1620 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
1621 *type
= DBTYPE_PFO_INSSPR
;
1622 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
1624 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
1625 *type
= DBTYPE_PO_ZAK
;
1626 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
1627 *type
= DBTYPE_PO_REQ
;
1628 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
1630 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
1631 *type
= DBTYPE_OVM_NOTAR
;
1632 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
1633 *type
= DBTYPE_OVM_EXEKUT
;
1634 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
1635 *type
= DBTYPE_OVM_REQ
;
1642 /* Convert ISDS dbType enum @type to UTF-8 string.
1643 * @Return pointer to static string, or NULL if unkwnow enum value */
1644 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
1646 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
1647 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
1648 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
1649 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DANPOR"); break;
1650 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
1651 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
1652 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
1653 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
1654 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
1655 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
1656 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
1657 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
1658 default: return NULL
; break;
1663 /* Convert UTF-8 @string represantion of ISDS userType to enum @type */
1664 static isds_error
string2isds_UserType(xmlChar
*string
, isds_UserType
*type
) {
1665 if (!string
|| !type
) return IE_INVAL
;
1667 if (!xmlStrcmp(string
, BAD_CAST
"PRIMARY_USER"))
1668 *type
= USERTYPE_PRIMARY
;
1669 else if (!xmlStrcmp(string
, BAD_CAST
"ENTRUSTED_USER"))
1670 *type
= USERTYPE_ENTRUSTED
;
1671 else if (!xmlStrcmp(string
, BAD_CAST
"ADMINISTRATOR"))
1672 *type
= USERTYPE_ADMINISTRATOR
;
1673 else if (!xmlStrcmp(string
, BAD_CAST
"OFFICIAL"))
1674 *type
= USERTYPE_OFFICIAL
;
1681 /* Convert ISDS userType enum @type to UTF-8 string.
1682 * @Return pointer to static string, or NULL if unkwnow enum value */
1683 static const xmlChar
*isds_UserType2string(const isds_UserType type
) {
1685 case USERTYPE_PRIMARY
: return(BAD_CAST
"PRIMARY_USER"); break;
1686 case USERTYPE_ENTRUSTED
: return(BAD_CAST
"ENTRUSTED_USER"); break;
1687 case USERTYPE_ADMINISTRATOR
: return(BAD_CAST
"ADMINISTRATOR"); break;
1688 case USERTYPE_OFFICIAL
: return(BAD_CAST
"OFFICIAL"); break;
1689 default: return NULL
; break;
1694 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
1695 * @Return pointer to static string, or NULL if unkwnow enum value */
1696 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
1698 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
1699 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
1700 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
1701 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
1702 default: return NULL
; break;
1707 /* Convert UTF-8 @string to ISDS dmFileMetaType enum @type.
1708 * @Return IE_ENUM if @string is not valid enum member */
1709 static isds_error
string2isds_FileMetaType(const xmlChar
*string
,
1710 isds_FileMetaType
*type
) {
1711 if (!string
|| !type
) return IE_INVAL
;
1713 if (!xmlStrcmp(string
, BAD_CAST
"main"))
1714 *type
= FILEMETATYPE_MAIN
;
1715 else if (!xmlStrcmp(string
, BAD_CAST
"enclosure"))
1716 *type
= FILEMETATYPE_ENCLOSURE
;
1717 else if (!xmlStrcmp(string
, BAD_CAST
"signature"))
1718 *type
= FILEMETATYPE_SIGNATURE
;
1719 else if (!xmlStrcmp(string
, BAD_CAST
"meta"))
1720 *type
= FILEMETATYPE_META
;
1727 /* Convert UTF-8 @string to ISDS hash @algorithm.
1728 * @Return IE_ENUM if @string is not valid enum member */
1729 static isds_error
string2isds_hash_algorithm(const xmlChar
*string
,
1730 isds_hash_algorithm
*algorithm
) {
1731 if (!string
|| !algorithm
) return IE_INVAL
;
1733 if (!xmlStrcmp(string
, BAD_CAST
"MD5"))
1734 *algorithm
= HASH_ALGORITHM_MD5
;
1735 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-1"))
1736 *algorithm
= HASH_ALGORITHM_SHA_1
;
1737 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-224"))
1738 *algorithm
= HASH_ALGORITHM_SHA_224
;
1739 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-256"))
1740 *algorithm
= HASH_ALGORITHM_SHA_256
;
1741 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-384"))
1742 *algorithm
= HASH_ALGORITHM_SHA_384
;
1743 else if (!xmlStrcmp(string
, BAD_CAST
"SHA-512"))
1744 *algorithm
= HASH_ALGORITHM_SHA_512
;
1751 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
1752 * XXX: Not all ISO formats are supported */
1753 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
1755 if (!string
|| !time
) return IE_INVAL
;
1757 /* xsd:date is ISO 8601 string, thus ASCII */
1758 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
1759 if (offset
&& *offset
== '\0')
1762 offset
= strptime((char*)string
, "%Y%m%d", time
);
1763 if (offset
&& *offset
== '\0')
1766 offset
= strptime((char*)string
, "%Y-%j", time
);
1767 if (offset
&& *offset
== '\0')
1774 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
1775 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
1776 if (!time
|| !string
) return IE_INVAL
;
1778 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
1779 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
1786 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
1787 * respects the @time microseconds too. */
1788 static isds_error
timeval2timestring(const struct timeval
*time
,
1792 if (!time
|| !string
) return IE_INVAL
;
1794 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
1795 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
1797 /* TODO: small negative year should be formated as "-0012". This is not
1798 * true for glibc "%04d". We should implement it.
1799 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
1800 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
1801 if (-1 == isds_asprintf((char **) string
,
1802 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
1803 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
1804 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
1812 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
1813 * It respects microseconds too.
1814 * In case of error, @time will be freed. */
1815 static isds_error
timestring2timeval(const xmlChar
*string
,
1816 struct timeval
**time
) {
1818 char *offset
, *delim
, *endptr
;
1820 int offset_hours
, offset_minutes
;
1823 if (!time
) return IE_INVAL
;
1825 memset(&broken
, 0, sizeof(broken
));
1828 *time
= calloc(1, sizeof(**time
));
1829 if (!*time
) return IE_NOMEM
;
1831 memset(*time
, 0, sizeof(**time
));
1835 /* xsd:date is ISO 8601 string, thus ASCII */
1836 /*TODO: negative year */
1838 /* Parse date and time without subseconds and offset */
1839 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
1841 free(*time
); *time
= NULL
;
1845 /* Get subseconds */
1846 if (*offset
== '.' ) {
1849 /* Copy first 6 digits, padd it with zeros.
1850 * XXX: It truncates longer number, no round.
1851 * Current server implementation uses only milisecond resolution. */
1852 /* TODO: isdigit() is locale sensitive */
1854 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
1856 subseconds
[i
] = *offset
;
1858 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
1859 subseconds
[i
] = '0';
1861 subseconds
[6] = '\0';
1863 /* Convert it into integer */
1864 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
1865 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
1866 (*time
)->tv_usec
== LONG_MAX
) {
1867 free(*time
); *time
= NULL
;
1871 /* move to the zone offset delimiter */
1872 delim
= strchr(offset
, '-');
1874 delim
= strchr(offset
, '+');
1878 /* Get zone offset */
1879 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
1880 * "" equals to "Z" and it means UTC zone. */
1881 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
1882 * colon separator */
1883 if (*offset
== '-' || *offset
== '+') {
1885 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
1886 free(*time
); *time
= NULL
;
1889 broken
.tm_hour
-= offset_hours
;
1890 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
1893 /* Convert to time_t */
1894 _isds_switch_tz_to_utc();
1895 (*time
)->tv_sec
= mktime(&broken
);
1896 _isds_switch_tz_to_native();
1897 if ((*time
)->tv_sec
== (time_t) -1) {
1898 free(*time
); *time
= NULL
;
1906 /* Convert unsigned int into isds_message_status.
1907 * @context is session context
1908 * @number is pointer to number value. NULL will be treated as invalid value.
1909 * @status is automatically reallocated status
1910 * @return IE_SUCCESS, or error code and free status */
1911 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1912 const unsigned long int *number
, isds_message_status
**status
) {
1913 if (!context
) return IE_INVALID_CONTEXT
;
1914 if (!status
) return IE_INVAL
;
1916 free(*status
); *status
= NULL
;
1917 if (!number
) return IE_INVAL
;
1919 if (*number
< 1 || *number
> 10) {
1920 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1925 *status
= malloc(sizeof(**status
));
1926 if (!*status
) return IE_NOMEM
;
1928 **status
= 1 << *number
;
1933 /* Convert event description string into isds_event memebers type and
1935 * @string is raw event decsription starting with event prefix
1936 * @event is structure where to store type and stripped description to
1937 * @return standard error code, unknown prefix is not classified as an error.
1939 static isds_error
eventstring2event(const xmlChar
*string
,
1940 struct isds_event
* event
) {
1941 const xmlChar
*known_prefixes
[] = {
1947 const isds_event_type types
[] = {
1948 EVENT_ACCEPTED_BY_RECIPIENT
,
1949 EVENT_ACCEPTED_BY_FICTION
,
1950 EVENT_UNDELIVERABLE
,
1951 EVENT_COMMERCIAL_ACCEPTED
1956 if (!string
|| !event
) return IE_INVAL
;
1959 event
->type
= malloc(sizeof(*event
->type
));
1960 if (!(event
->type
)) return IE_NOMEM
;
1962 zfree(event
->description
);
1964 for (index
= 0; index
< sizeof(known_prefixes
)/sizeof(known_prefixes
[0]);
1966 length
= xmlUTF8Strlen(known_prefixes
[index
]);
1968 if (!xmlStrncmp(string
, known_prefixes
[index
], length
)) {
1969 /* Prefix is known */
1970 *event
->type
= types
[index
];
1972 /* Strip prefix from description and spaces */
1973 /* TODO: Recognize all wite spaces from UCS blank class and
1974 * operate on UTF-8 chars. */
1975 for (; string
[length
] != '\0' && string
[length
] == ' '; length
++);
1976 event
->description
= strdup((char *) (string
+ length
));
1977 if (!(event
->description
)) return IE_NOMEM
;
1983 /* Unknown event prefix.
1984 * XSD allows any string */
1985 char *string_locale
= _isds_utf82locale((char *) string
);
1986 isds_log(ILF_ISDS
, ILL_WARNING
,
1987 _("Uknown delivery info event prefix: %s\n"), string_locale
);
1988 free(string_locale
);
1990 *event
->type
= EVENT_UKNOWN
;
1991 event
->description
= strdup((char *) string
);
1992 if (!(event
->description
)) return IE_NOMEM
;
1998 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1999 * and leave lable */
2000 #define EXTRACT_STRING(element, string) { \
2001 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
2006 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
2007 if (result->nodesetval->nodeNr > 1) { \
2008 isds_printf_message(context, _("Multiple %s element"), element); \
2012 (string) = (char *) \
2013 xmlXPathCastNodeSetToString(result->nodesetval); \
2021 #define EXTRACT_BOOLEAN(element, booleanPtr) \
2023 char *string = NULL; \
2024 EXTRACT_STRING(element, string); \
2027 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
2028 if (!(booleanPtr)) { \
2034 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
2035 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
2036 *(booleanPtr) = 1; \
2037 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
2038 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
2039 *(booleanPtr) = 0; \
2041 char *string_locale = _isds_utf82locale((char*)string); \
2042 isds_printf_message(context, \
2043 _("%s value is not valid boolean: %s"), \
2044 element, string_locale); \
2045 free(string_locale); \
2055 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
2057 char *string = NULL; \
2058 EXTRACT_STRING(element, string); \
2063 number = strtol((char*)string, &endptr, 10); \
2065 if (*endptr != '\0') { \
2066 char *string_locale = _isds_utf82locale((char *)string); \
2067 isds_printf_message(context, \
2068 _("%s is not valid integer: %s"), \
2069 element, string_locale); \
2070 free(string_locale); \
2076 if (number == LONG_MIN || number == LONG_MAX) { \
2077 char *string_locale = _isds_utf82locale((char *)string); \
2078 isds_printf_message(context, \
2079 _("%s value out of range of long int: %s"), \
2080 element, string_locale); \
2081 free(string_locale); \
2087 free(string); string = NULL; \
2089 if (!(preallocated)) { \
2090 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
2091 if (!(longintPtr)) { \
2096 *(longintPtr) = number; \
2100 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
2102 char *string = NULL; \
2103 EXTRACT_STRING(element, string); \
2108 number = strtol((char*)string, &endptr, 10); \
2110 if (*endptr != '\0') { \
2111 char *string_locale = _isds_utf82locale((char *)string); \
2112 isds_printf_message(context, \
2113 _("%s is not valid integer: %s"), \
2114 element, string_locale); \
2115 free(string_locale); \
2121 if (number == LONG_MIN || number == LONG_MAX) { \
2122 char *string_locale = _isds_utf82locale((char *)string); \
2123 isds_printf_message(context, \
2124 _("%s value out of range of long int: %s"), \
2125 element, string_locale); \
2126 free(string_locale); \
2132 free(string); string = NULL; \
2134 isds_printf_message(context, \
2135 _("%s value is negative: %ld"), element, number); \
2140 if (!(preallocated)) { \
2141 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
2142 if (!(ulongintPtr)) { \
2147 *(ulongintPtr) = number; \
2151 #define EXTRACT_STRING_ATTRIBUTE(attribute, string, required) { \
2152 (string) = (char *) xmlGetNsProp(xpath_ctx->node, ( BAD_CAST attribute), \
2154 if ((required) && (!string)) { \
2155 char *attribute_locale = _isds_utf82locale(attribute); \
2156 char *element_locale = \
2157 _isds_utf82locale((char *)xpath_ctx->node->name); \
2158 isds_printf_message(context, \
2159 _("Could not extract required %s attribute value from " \
2160 "%s element"), attribute_locale, element_locale); \
2161 free(element_locale); \
2162 free(attribute_locale); \
2169 #define INSERT_STRING_WITH_NS(parent, ns, element, string) \
2171 node = xmlNewTextChild(parent, ns, BAD_CAST (element), \
2172 (xmlChar *) (string)); \
2174 isds_printf_message(context, \
2175 _("Could not add %s child to %s element"), \
2176 element, (parent)->name); \
2182 #define INSERT_STRING(parent, element, string) \
2183 { INSERT_STRING_WITH_NS(parent, NULL, element, string) }
2185 #define INSERT_SCALAR_BOOLEAN(parent, element, boolean) \
2187 if (boolean) { INSERT_STRING(parent, element, "true"); } \
2188 else { INSERT_STRING(parent, element, "false"); } \
2191 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
2194 INSERT_SCALAR_BOOLEAN(parent, element, (*(booleanPtr))); \
2196 INSERT_STRING(parent, element, NULL); \
2200 #define INSERT_LONGINT(parent, element, longintPtr, buffer) { \
2201 if ((longintPtr)) { \
2202 /* FIXME: locale sensitive */ \
2203 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
2207 INSERT_STRING(parent, element, buffer) \
2208 free(buffer); (buffer) = NULL; \
2209 } else { INSERT_STRING(parent, element, NULL) } \
2212 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) { \
2213 if ((ulongintPtr)) { \
2214 /* FIXME: locale sensitive */ \
2215 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
2219 INSERT_STRING(parent, element, buffer) \
2220 free(buffer); (buffer) = NULL; \
2221 } else { INSERT_STRING(parent, element, NULL) } \
2224 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
2226 /* FIXME: locale sensitive */ \
2227 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
2231 INSERT_STRING(parent, element, buffer) \
2232 free(buffer); (buffer) = NULL; \
2235 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
2237 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
2238 (xmlChar *) (string)); \
2239 if (!attribute_node) { \
2240 isds_printf_message(context, _("Could not add %s " \
2241 "attribute to %s element"), \
2242 (attribute), (parent)->name); \
2248 #define CHECK_FOR_STRING_LENGTH(string, minimum, maximum, name) { \
2250 int length = xmlUTF8Strlen((xmlChar *) (string)); \
2251 if (length > (maximum)) { \
2252 isds_printf_message(context, \
2253 ngettext("%s has more than %d characters", \
2254 "%s has more than %d characters", (maximum)), \
2255 (name), (maximum)); \
2259 if (length < (minimum)) { \
2260 isds_printf_message(context, \
2261 ngettext("%s has less than %d characters", \
2262 "%s has less than %d characters", (minimum)), \
2263 (name), (minimum)); \
2270 #define INSERT_ELEMENT(child, parent, element) \
2272 (child) = xmlNewChild((parent), NULL, BAD_CAST (element), NULL); \
2274 isds_printf_message(context, \
2275 _("Could not add %s child to %s element"), \
2276 (element), (parent)->name); \
2283 /* Find child element by name in given XPath context and switch context onto
2284 * it. The child must be uniq and must exist. Otherwise failes.
2285 * @context is ISDS context
2286 * @child is child element name
2287 * @xpath_ctx is XPath context. In success, the @xpath_ctx will be changed
2288 * into it child. In error case, the @xpath_ctx keeps original value. */
2289 static isds_error
move_xpathctx_to_child(struct isds_ctx
*context
,
2290 const xmlChar
*child
, xmlXPathContextPtr xpath_ctx
) {
2291 isds_error err
= IE_SUCCESS
;
2292 xmlXPathObjectPtr result
= NULL
;
2294 if (!context
) return IE_INVALID_CONTEXT
;
2295 if (!child
|| !xpath_ctx
) return IE_INVAL
;
2298 result
= xmlXPathEvalExpression(child
, xpath_ctx
);
2305 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2306 char *parent_locale
= _isds_utf82locale((char*) xpath_ctx
->node
->name
);
2307 char *child_locale
= _isds_utf82locale((char*) child
);
2308 isds_printf_message(context
,
2309 _("%s element does not contain %s child"),
2310 parent_locale
, child_locale
);
2312 free(parent_locale
);
2318 if (result
->nodesetval
->nodeNr
> 1) {
2319 char *parent_locale
= _isds_utf82locale((char*) xpath_ctx
->node
->name
);
2320 char *child_locale
= _isds_utf82locale((char*) child
);
2321 isds_printf_message(context
,
2322 _("%s element contains multiple %s children"),
2323 parent_locale
, child_locale
);
2325 free(parent_locale
);
2330 /* Switch context */
2331 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2334 xmlXPathFreeObject(result
);
2340 /* Find and convert XSD:gPersonName group in current node into structure
2341 * @context is ISDS context
2342 * @personName is automically reallocated person name structure. If no member
2343 * value is found, will be freed.
2344 * @xpath_ctx is XPath context with current node as parent for XSD:gPersonName
2346 * In case of error @personName will be freed. */
2347 static isds_error
extract_gPersonName(struct isds_ctx
*context
,
2348 struct isds_PersonName
**personName
, xmlXPathContextPtr xpath_ctx
) {
2349 isds_error err
= IE_SUCCESS
;
2350 xmlXPathObjectPtr result
= NULL
;
2352 if (!context
) return IE_INVALID_CONTEXT
;
2353 if (!personName
) return IE_INVAL
;
2354 isds_PersonName_free(personName
);
2355 if (!xpath_ctx
) return IE_INVAL
;
2358 *personName
= calloc(1, sizeof(**personName
));
2364 EXTRACT_STRING("isds:pnFirstName", (*personName
)->pnFirstName
);
2365 EXTRACT_STRING("isds:pnMiddleName", (*personName
)->pnMiddleName
);
2366 EXTRACT_STRING("isds:pnLastName", (*personName
)->pnLastName
);
2367 EXTRACT_STRING("isds:pnLastNameAtBirth", (*personName
)->pnLastNameAtBirth
);
2369 if (!(*personName
)->pnFirstName
&& !(*personName
)->pnMiddleName
&&
2370 !(*personName
)->pnLastName
&& !(*personName
)->pnLastNameAtBirth
)
2371 isds_PersonName_free(personName
);
2374 if (err
) isds_PersonName_free(personName
);
2375 xmlXPathFreeObject(result
);
2380 /* Find and convert XSD:gAddress group in current node into structure
2381 * @context is ISDS context
2382 * @address is automically reallocated address structure. If no member
2383 * value is found, will be freed.
2384 * @xpath_ctx is XPath context with current node as parent for XSD:gAddress
2386 * In case of error @address will be freed. */
2387 static isds_error
extract_gAddress(struct isds_ctx
*context
,
2388 struct isds_Address
**address
, xmlXPathContextPtr xpath_ctx
) {
2389 isds_error err
= IE_SUCCESS
;
2390 xmlXPathObjectPtr result
= NULL
;
2392 if (!context
) return IE_INVALID_CONTEXT
;
2393 if (!address
) return IE_INVAL
;
2394 isds_Address_free(address
);
2395 if (!xpath_ctx
) return IE_INVAL
;
2398 *address
= calloc(1, sizeof(**address
));
2404 EXTRACT_STRING("isds:adCity", (*address
)->adCity
);
2405 EXTRACT_STRING("isds:adStreet", (*address
)->adStreet
);
2406 EXTRACT_STRING("isds:adNumberInStreet", (*address
)->adNumberInStreet
);
2407 EXTRACT_STRING("isds:adNumberInMunicipality",
2408 (*address
)->adNumberInMunicipality
);
2409 EXTRACT_STRING("isds:adZipCode", (*address
)->adZipCode
);
2410 EXTRACT_STRING("isds:adState", (*address
)->adState
);
2412 if (!(*address
)->adCity
&& !(*address
)->adStreet
&&
2413 !(*address
)->adNumberInStreet
&&
2414 !(*address
)->adNumberInMunicipality
&&
2415 !(*address
)->adZipCode
&& !(*address
)->adState
)
2416 isds_Address_free(address
);
2419 if (err
) isds_Address_free(address
);
2420 xmlXPathFreeObject(result
);
2425 /* Find and convert isds:biDate element in current node into structure
2426 * @context is ISDS context
2427 * @biDate is automically reallocated birth date structure. If no member
2428 * value is found, will be freed.
2429 * @xpath_ctx is XPath context with current node as parent for isds:biDate
2431 * In case of error @biDate will be freed. */
2432 static isds_error
extract_BiDate(struct isds_ctx
*context
,
2433 struct tm
**biDate
, xmlXPathContextPtr xpath_ctx
) {
2434 isds_error err
= IE_SUCCESS
;
2435 xmlXPathObjectPtr result
= NULL
;
2436 char *string
= NULL
;
2438 if (!context
) return IE_INVALID_CONTEXT
;
2439 if (!biDate
) return IE_INVAL
;
2441 if (!xpath_ctx
) return IE_INVAL
;
2443 EXTRACT_STRING("isds:biDate", string
);
2445 *biDate
= calloc(1, sizeof(**biDate
));
2450 err
= datestring2tm((xmlChar
*)string
, *biDate
);
2452 if (err
== IE_NOTSUP
) {
2454 char *string_locale
= _isds_utf82locale(string
);
2455 isds_printf_message(context
,
2456 _("Invalid isds:biDate value: %s"), string_locale
);
2457 free(string_locale
);
2464 if (err
) zfree(*biDate
);
2466 xmlXPathFreeObject(result
);
2471 /* Convert isds:dBOwnerInfo XML tree into structure
2472 * @context is ISDS context
2473 * @db_owner_info is automically reallocated box owner info structure
2474 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
2475 * In case of error @db_owner_info will be freed. */
2476 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
2477 struct isds_DbOwnerInfo
**db_owner_info
,
2478 xmlXPathContextPtr xpath_ctx
) {
2479 isds_error err
= IE_SUCCESS
;
2480 xmlXPathObjectPtr result
= NULL
;
2481 char *string
= NULL
;
2483 if (!context
) return IE_INVALID_CONTEXT
;
2484 if (!db_owner_info
) return IE_INVAL
;
2485 isds_DbOwnerInfo_free(db_owner_info
);
2486 if (!xpath_ctx
) return IE_INVAL
;
2489 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
2490 if (!*db_owner_info
) {
2495 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
2497 EXTRACT_STRING("isds:dbType", string
);
2499 (*db_owner_info
)->dbType
=
2500 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
2501 if (!(*db_owner_info
)->dbType
) {
2505 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
2507 zfree((*db_owner_info
)->dbType
);
2508 if (err
== IE_ENUM
) {
2510 char *string_locale
= _isds_utf82locale(string
);
2511 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
2513 free(string_locale
);
2520 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
2522 err
= extract_gPersonName(context
, &(*db_owner_info
)->personName
,
2524 if (err
) goto leave
;
2526 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
2528 (*db_owner_info
)->birthInfo
=
2529 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
2530 if (!(*db_owner_info
)->birthInfo
) {
2534 err
= extract_BiDate(context
, &(*db_owner_info
)->birthInfo
->biDate
,
2536 if (err
) goto leave
;
2537 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
2538 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
2539 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
2540 if (!(*db_owner_info
)->birthInfo
->biDate
&&
2541 !(*db_owner_info
)->birthInfo
->biCity
&&
2542 !(*db_owner_info
)->birthInfo
->biCounty
&&
2543 !(*db_owner_info
)->birthInfo
->biState
)
2544 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
2546 err
= extract_gAddress(context
, &(*db_owner_info
)->address
, xpath_ctx
);
2547 if (err
) goto leave
;
2549 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
2550 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
2551 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
2552 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
2553 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
2555 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
2557 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
2558 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
2559 (*db_owner_info
)->dbOpenAddressing
);
2562 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
2564 xmlXPathFreeObject(result
);
2569 /* Insert struct isds_DbOwnerInfo data (box description) into XML tree
2570 * @context is sesstion context
2571 * @owner is libsids structure with box description
2572 * @db_owner_info is XML element of XSD:tDbOwnerInfo */
2573 static isds_error
insert_DbOwnerInfo(struct isds_ctx
*context
,
2574 const struct isds_DbOwnerInfo
*owner
, xmlNodePtr db_owner_info
) {
2576 isds_error err
= IE_SUCCESS
;
2578 xmlChar
*string
= NULL
;
2580 if (!context
) return IE_INVALID_CONTEXT
;
2581 if (!owner
|| !db_owner_info
) return IE_INVAL
;
2584 /* Build XSD:tDbOwnerInfo */
2585 CHECK_FOR_STRING_LENGTH(owner
->dbID
, 0, 7, "dbID")
2586 INSERT_STRING(db_owner_info
, "dbID", owner
->dbID
);
2589 if (owner
->dbType
) {
2590 const xmlChar
*type_string
= isds_DbType2string(*(owner
->dbType
));
2592 isds_printf_message(context
, _("Invalid dbType value: %d"),
2597 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2599 INSERT_STRING(db_owner_info
, "ic", owner
->ic
);
2600 if (owner
->personName
) {
2601 INSERT_STRING(db_owner_info
, "pnFirstName",
2602 owner
->personName
->pnFirstName
);
2603 INSERT_STRING(db_owner_info
, "pnMiddleName",
2604 owner
->personName
->pnMiddleName
);
2605 INSERT_STRING(db_owner_info
, "pnLastName",
2606 owner
->personName
->pnLastName
);
2607 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2608 owner
->personName
->pnLastNameAtBirth
);
2610 INSERT_STRING(db_owner_info
, "firmName", owner
->firmName
);
2611 if (owner
->birthInfo
) {
2612 if (owner
->birthInfo
->biDate
) {
2613 if (!tm2datestring(owner
->birthInfo
->biDate
, &string
))
2614 INSERT_STRING(db_owner_info
, "biDate", string
);
2615 free(string
); string
= NULL
;
2617 INSERT_STRING(db_owner_info
, "biCity", owner
->birthInfo
->biCity
);
2618 INSERT_STRING(db_owner_info
, "biCounty", owner
->birthInfo
->biCounty
);
2619 INSERT_STRING(db_owner_info
, "biState", owner
->birthInfo
->biState
);
2621 if (owner
->address
) {
2622 INSERT_STRING(db_owner_info
, "adCity", owner
->address
->adCity
);
2623 INSERT_STRING(db_owner_info
, "adStreet", owner
->address
->adStreet
);
2624 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2625 owner
->address
->adNumberInStreet
);
2626 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2627 owner
->address
->adNumberInMunicipality
);
2628 INSERT_STRING(db_owner_info
, "adZipCode", owner
->address
->adZipCode
);
2629 INSERT_STRING(db_owner_info
, "adState", owner
->address
->adState
);
2631 INSERT_STRING(db_owner_info
, "nationality", owner
->nationality
);
2632 INSERT_STRING(db_owner_info
, "email", owner
->email
);
2633 INSERT_STRING(db_owner_info
, "telNumber", owner
->telNumber
);
2635 CHECK_FOR_STRING_LENGTH(owner
->identifier
, 0, 20, "identifier")
2636 INSERT_STRING(db_owner_info
, "identifier", owner
->identifier
);
2638 CHECK_FOR_STRING_LENGTH(owner
->registryCode
, 0, 5, "registryCode")
2639 INSERT_STRING(db_owner_info
, "registryCode", owner
->registryCode
);
2641 INSERT_LONGINT(db_owner_info
, "dbState", owner
->dbState
, string
);
2643 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", owner
->dbEffectiveOVM
);
2644 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2645 owner
->dbOpenAddressing
);
2653 /* Convert XSD:tDbUserInfo XML tree into structure
2654 * @context is ISDS context
2655 * @db_user_info is automically reallocated user info structure
2656 * @xpath_ctx is XPath context with current node as XSD:tDbUserInfo element
2657 * In case of error @db_user_info will be freed. */
2658 static isds_error
extract_DbUserInfo(struct isds_ctx
*context
,
2659 struct isds_DbUserInfo
**db_user_info
, xmlXPathContextPtr xpath_ctx
) {
2660 isds_error err
= IE_SUCCESS
;
2661 xmlXPathObjectPtr result
= NULL
;
2662 char *string
= NULL
;
2664 if (!context
) return IE_INVALID_CONTEXT
;
2665 if (!db_user_info
) return IE_INVAL
;
2666 isds_DbUserInfo_free(db_user_info
);
2667 if (!xpath_ctx
) return IE_INVAL
;
2670 *db_user_info
= calloc(1, sizeof(**db_user_info
));
2671 if (!*db_user_info
) {
2676 EXTRACT_STRING("isds:userID", (*db_user_info
)->userID
);
2678 EXTRACT_STRING("isds:userType", string
);
2680 (*db_user_info
)->userType
=
2681 calloc(1, sizeof(*((*db_user_info
)->userType
)));
2682 if (!(*db_user_info
)->userType
) {
2686 err
= string2isds_UserType((xmlChar
*)string
,
2687 (*db_user_info
)->userType
);
2689 zfree((*db_user_info
)->userType
);
2690 if (err
== IE_ENUM
) {
2692 char *string_locale
= _isds_utf82locale(string
);
2693 isds_printf_message(context
,
2694 _("Unknown isds:userType value: %s"), string_locale
);
2695 free(string_locale
);
2702 EXTRACT_LONGINT("isds:userPrivils", (*db_user_info
)->userPrivils
, 0);
2704 (*db_user_info
)->personName
=
2705 calloc(1, sizeof(*((*db_user_info
)->personName
)));
2706 if (!(*db_user_info
)->personName
) {
2711 err
= extract_gPersonName(context
, &(*db_user_info
)->personName
,
2713 if (err
) goto leave
;
2715 err
= extract_gAddress(context
, &(*db_user_info
)->address
, xpath_ctx
);
2716 if (err
) goto leave
;
2718 err
= extract_BiDate(context
, &(*db_user_info
)->biDate
, xpath_ctx
);
2719 if (err
) goto leave
;
2721 EXTRACT_STRING("isds:ic", (*db_user_info
)->ic
);
2722 EXTRACT_STRING("isds:firmName", (*db_user_info
)->firmName
);
2724 EXTRACT_STRING("isds:caStreet", (*db_user_info
)->caStreet
);
2725 EXTRACT_STRING("isds:caCity", (*db_user_info
)->caCity
);
2726 EXTRACT_STRING("isds:caZipCode", (*db_user_info
)->caZipCode
);
2728 /* ???: Default value is "CZ" according specification. Should we provide
2730 EXTRACT_STRING("isds:caState", (*db_user_info
)->caState
);
2733 if (err
) isds_DbUserInfo_free(db_user_info
);
2735 xmlXPathFreeObject(result
);
2740 /* Insert struct isds_DbUserInfo data (user description) into XML tree
2741 * @context is sesstion context
2742 * @user is libsids structure with user description
2743 * @db_user_info is XML element of XSD:tDbUserInfo */
2744 static isds_error
insert_DbUserInfo(struct isds_ctx
*context
,
2745 const struct isds_DbUserInfo
*user
, xmlNodePtr db_user_info
) {
2747 isds_error err
= IE_SUCCESS
;
2749 xmlChar
*string
= NULL
;
2751 if (!context
) return IE_INVALID_CONTEXT
;
2752 if (!user
|| !db_user_info
) return IE_INVAL
;
2754 /* Build XSD:tDbUserInfo */
2755 if (user
->personName
) {
2756 INSERT_STRING(db_user_info
, "pnFirstName",
2757 user
->personName
->pnFirstName
);
2758 INSERT_STRING(db_user_info
, "pnMiddleName",
2759 user
->personName
->pnMiddleName
);
2760 INSERT_STRING(db_user_info
, "pnLastName",
2761 user
->personName
->pnLastName
);
2762 INSERT_STRING(db_user_info
, "pnLastNameAtBirth",
2763 user
->personName
->pnLastNameAtBirth
);
2765 if (user
->address
) {
2766 INSERT_STRING(db_user_info
, "adCity", user
->address
->adCity
);
2767 INSERT_STRING(db_user_info
, "adStreet", user
->address
->adStreet
);
2768 INSERT_STRING(db_user_info
, "adNumberInStreet",
2769 user
->address
->adNumberInStreet
);
2770 INSERT_STRING(db_user_info
, "adNumberInMunicipality",
2771 user
->address
->adNumberInMunicipality
);
2772 INSERT_STRING(db_user_info
, "adZipCode", user
->address
->adZipCode
);
2773 INSERT_STRING(db_user_info
, "adState", user
->address
->adState
);
2776 if (!tm2datestring(user
->biDate
, &string
))
2777 INSERT_STRING(db_user_info
, "biDate", string
);
2780 CHECK_FOR_STRING_LENGTH(user
->userID
, 6, 12, "userID");
2781 INSERT_STRING(db_user_info
, "userID", user
->userID
);
2784 if (user
->userType
) {
2785 const xmlChar
*type_string
= isds_UserType2string(*(user
->userType
));
2787 isds_printf_message(context
, _("Invalid userType value: %d"),
2792 INSERT_STRING(db_user_info
, "userType", type_string
);
2795 INSERT_LONGINT(db_user_info
, "userPrivils", user
->userPrivils
, string
);
2796 CHECK_FOR_STRING_LENGTH(user
->ic
, 0, 8, "ic")
2797 INSERT_STRING(db_user_info
, "ic", user
->ic
);
2798 CHECK_FOR_STRING_LENGTH(user
->firmName
, 0, 100, "firmName")
2799 INSERT_STRING(db_user_info
, "firmName", user
->firmName
);
2800 INSERT_STRING(db_user_info
, "caStreet", user
->caStreet
);
2801 INSERT_STRING(db_user_info
, "caCity", user
->caCity
);
2802 INSERT_STRING(db_user_info
, "caZipCode", user
->caZipCode
);
2803 INSERT_STRING(db_user_info
, "caState", user
->caState
);
2811 /* Convert XSD gMessageEnvelopeSub group of elements from XML tree into
2812 * isds_envelope structure. The envelope is automatically allocated but not
2813 * reallocated. The date are just appended into envelope structure.
2814 * @context is ISDS context
2815 * @envelope is automically allocated message envelope structure
2816 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2817 * In case of error @envelope will be freed. */
2818 static isds_error
append_GMessageEnvelopeSub(struct isds_ctx
*context
,
2819 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2820 isds_error err
= IE_SUCCESS
;
2821 xmlXPathObjectPtr result
= NULL
;
2823 if (!context
) return IE_INVALID_CONTEXT
;
2824 if (!envelope
) return IE_INVAL
;
2825 if (!xpath_ctx
) return IE_INVAL
;
2829 /* Allocate envelope */
2830 *envelope
= calloc(1, sizeof(**envelope
));
2836 /* Else free former data */
2837 zfree((*envelope
)->dmSenderOrgUnit
);
2838 zfree((*envelope
)->dmSenderOrgUnitNum
);
2839 zfree((*envelope
)->dbIDRecipient
);
2840 zfree((*envelope
)->dmRecipientOrgUnit
);
2841 zfree((*envelope
)->dmSenderOrgUnitNum
);
2842 zfree((*envelope
)->dmToHands
);
2843 zfree((*envelope
)->dmAnnotation
);
2844 zfree((*envelope
)->dmRecipientRefNumber
);
2845 zfree((*envelope
)->dmSenderRefNumber
);
2846 zfree((*envelope
)->dmRecipientIdent
);
2847 zfree((*envelope
)->dmSenderIdent
);
2848 zfree((*envelope
)->dmLegalTitleLaw
);
2849 zfree((*envelope
)->dmLegalTitleYear
);
2850 zfree((*envelope
)->dmLegalTitleSect
);
2851 zfree((*envelope
)->dmLegalTitlePar
);
2852 zfree((*envelope
)->dmLegalTitlePoint
);
2853 zfree((*envelope
)->dmPersonalDelivery
);
2854 zfree((*envelope
)->dmAllowSubstDelivery
);
2857 /* Extract envelope elements added by sender or ISDS
2858 * (XSD: gMessageEnvelopeSub type) */
2859 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
2860 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
2861 (*envelope
)->dmSenderOrgUnitNum
, 0);
2862 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
2863 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
2864 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
2865 (*envelope
)->dmSenderOrgUnitNum
, 0);
2866 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
2867 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
2868 EXTRACT_STRING("isds:dmRecipientRefNumber",
2869 (*envelope
)->dmRecipientRefNumber
);
2870 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
2871 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
2872 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
2874 /* Extract envelope elements regarding law refference */
2875 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
2876 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
2877 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
2878 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
2879 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
2881 /* Extract envelope other elements */
2882 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
2883 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
2884 (*envelope
)->dmAllowSubstDelivery
);
2887 if (err
) isds_envelope_free(envelope
);
2888 xmlXPathFreeObject(result
);
2894 /* Convert XSD gMessageEnvelope group of elements from XML tree into
2895 * isds_envelope structure. The envelope is automatically allocated but not
2896 * reallocated. The date are just appended into envelope structure.
2897 * @context is ISDS context
2898 * @envelope is automically allocated message envelope structure
2899 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
2900 * In case of error @envelope will be freed. */
2901 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
2902 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2903 isds_error err
= IE_SUCCESS
;
2904 xmlXPathObjectPtr result
= NULL
;
2906 if (!context
) return IE_INVALID_CONTEXT
;
2907 if (!envelope
) return IE_INVAL
;
2908 if (!xpath_ctx
) return IE_INVAL
;
2912 /* Allocate envelope */
2913 *envelope
= calloc(1, sizeof(**envelope
));
2919 /* Else free former data */
2920 zfree((*envelope
)->dmID
);
2921 zfree((*envelope
)->dbIDSender
);
2922 zfree((*envelope
)->dmSender
);
2923 zfree((*envelope
)->dmSenderAddress
);
2924 zfree((*envelope
)->dmSenderType
);
2925 zfree((*envelope
)->dmRecipient
);
2926 zfree((*envelope
)->dmRecipientAddress
);
2927 zfree((*envelope
)->dmAmbiguousRecipient
);
2930 /* Extract envelope elements added by ISDS
2931 * (XSD: gMessageEnvelope type) */
2932 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
2933 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
2934 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
2935 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
2936 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
2937 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
2938 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
2939 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
2940 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
2941 (*envelope
)->dmAmbiguousRecipient
);
2943 /* Extract envelope elements added by sender and ISDS
2944 * (XSD: gMessageEnvelope type) */
2945 err
= append_GMessageEnvelopeSub(context
, envelope
, xpath_ctx
);
2946 if (err
) goto leave
;
2949 if (err
) isds_envelope_free(envelope
);
2950 xmlXPathFreeObject(result
);
2955 /* Convert other envelope elements from XML tree into isds_envelope structure:
2956 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
2957 * The envelope is automatically allocated but not reallocated.
2958 * The data are just appended into envelope structure.
2959 * @context is ISDS context
2960 * @envelope is automically allocated message envelope structure
2961 * @xpath_ctx is XPath context with current node as parent desired elements
2962 * In case of error @envelope will be freed. */
2963 static isds_error
append_status_size_times(struct isds_ctx
*context
,
2964 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
2965 isds_error err
= IE_SUCCESS
;
2966 xmlXPathObjectPtr result
= NULL
;
2967 char *string
= NULL
;
2968 unsigned long int *unumber
= NULL
;
2970 if (!context
) return IE_INVALID_CONTEXT
;
2971 if (!envelope
) return IE_INVAL
;
2972 if (!xpath_ctx
) return IE_INVAL
;
2977 *envelope
= calloc(1, sizeof(**envelope
));
2984 zfree((*envelope
)->dmMessageStatus
);
2985 zfree((*envelope
)->dmAttachmentSize
);
2986 zfree((*envelope
)->dmDeliveryTime
);
2987 zfree((*envelope
)->dmAcceptanceTime
);
2991 /* dmMessageStatus element is mandatory */
2992 EXTRACT_ULONGINT("sisds:dmMessageStatus", unumber
, 0);
2994 isds_log_message(context
,
2995 _("Missing mandatory sisds:dmMessageStatus integer"));
2999 err
= uint2isds_message_status(context
, unumber
,
3000 &((*envelope
)->dmMessageStatus
));
3002 if (err
== IE_ENUM
) err
= IE_ISDS
;
3005 free(unumber
); unumber
= NULL
;
3007 EXTRACT_ULONGINT("sisds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
,
3010 EXTRACT_STRING("sisds:dmDeliveryTime", string
);
3012 err
= timestring2timeval((xmlChar
*) string
,
3013 &((*envelope
)->dmDeliveryTime
));
3015 char *string_locale
= _isds_utf82locale(string
);
3016 if (err
== IE_DATE
) err
= IE_ISDS
;
3017 isds_printf_message(context
,
3018 _("Could not convert dmDeliveryTime as ISO time: %s"),
3020 free(string_locale
);
3026 EXTRACT_STRING("sisds:dmAcceptanceTime", string
);
3028 err
= timestring2timeval((xmlChar
*) string
,
3029 &((*envelope
)->dmAcceptanceTime
));
3031 char *string_locale
= _isds_utf82locale(string
);
3032 if (err
== IE_DATE
) err
= IE_ISDS
;
3033 isds_printf_message(context
,
3034 _("Could not convert dmAcceptanceTime as ISO time: %s"),
3036 free(string_locale
);
3043 if (err
) isds_envelope_free(envelope
);
3046 xmlXPathFreeObject(result
);
3051 /* Convert message type attribute of current element into isds_envelope
3053 * TODO: This function can be incorporated into append_status_size_times() as
3054 * they are called always together.
3055 * The envelope is automatically allocated but not reallocated.
3056 * The data are just appended into envelope structure.
3057 * @context is ISDS context
3058 * @envelope is automically allocated message envelope structure
3059 * @xpath_ctx is XPath context with current node as parent of attribute
3060 * carrying message type
3061 * In case of error @envelope will be freed. */
3062 static isds_error
append_message_type(struct isds_ctx
*context
,
3063 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3064 isds_error err
= IE_SUCCESS
;
3066 if (!context
) return IE_INVALID_CONTEXT
;
3067 if (!envelope
) return IE_INVAL
;
3068 if (!xpath_ctx
) return IE_INVAL
;
3073 *envelope
= calloc(1, sizeof(**envelope
));
3080 zfree((*envelope
)->dmType
);
3084 EXTRACT_STRING_ATTRIBUTE("dmType", (*envelope
)->dmType
, 0);
3086 if (!(*envelope
)->dmType
) {
3087 /* Use default value */
3088 (*envelope
)->dmType
= strdup("V");
3089 if (!(*envelope
)->dmType
) {
3093 } else if (1 != xmlUTF8Strlen((xmlChar
*) (*envelope
)->dmType
)) {
3094 char *type_locale
= _isds_utf82locale((*envelope
)->dmType
);
3095 isds_printf_message(context
,
3096 _("Message type in dmType attribute is not 1 character long: "
3105 if (err
) isds_envelope_free(envelope
);
3111 /* Extract message document into reallocated document structure
3112 * @context is ISDS context
3113 * @document is automically reallocated message documents structure
3114 * @xpath_ctx is XPath context with current node as isds:dmFile
3115 * In case of error @document will be freed. */
3116 static isds_error
extract_document(struct isds_ctx
*context
,
3117 struct isds_document
**document
, xmlXPathContextPtr xpath_ctx
) {
3118 isds_error err
= IE_SUCCESS
;
3119 xmlXPathObjectPtr result
= NULL
;
3120 xmlNodePtr file_node
= xpath_ctx
->node
;
3121 char *string
= NULL
;
3123 if (!context
) return IE_INVALID_CONTEXT
;
3124 if (!document
) return IE_INVAL
;
3125 isds_document_free(document
);
3126 if (!xpath_ctx
) return IE_INVAL
;
3128 *document
= calloc(1, sizeof(**document
));
3134 /* Extract document metadata */
3135 EXTRACT_STRING_ATTRIBUTE("dmMimeType", (*document
)->dmMimeType
, 1)
3136 if (context
->normalize_mime_type
) {
3137 char *normalized_type
=
3138 isds_normalize_mime_type((*document
)->dmMimeType
);
3139 if (normalized_type
&& normalized_type
!= (*document
)->dmMimeType
) {
3140 char *new_type
= strdup(normalized_type
);
3142 isds_printf_message(context
,
3143 _("No enough memory to normalize document MIME type"));
3147 free((*document
)->dmMimeType
);
3148 (*document
)->dmMimeType
= new_type
;
3152 EXTRACT_STRING_ATTRIBUTE("dmFileMetaType", string
, 1)
3153 err
= string2isds_FileMetaType((xmlChar
*)string
,
3154 &((*document
)->dmFileMetaType
));
3156 char *meta_type_locale
= _isds_utf82locale(string
);
3157 isds_printf_message(context
,
3158 _("Document has invalid dmFileMetaType attribute value: %s"),
3160 free(meta_type_locale
);
3166 EXTRACT_STRING_ATTRIBUTE("dmFileGuid", (*document
)->dmFileGuid
, 0)
3167 EXTRACT_STRING_ATTRIBUTE("dmUpFileGuid", (*document
)->dmUpFileGuid
, 0)
3168 EXTRACT_STRING_ATTRIBUTE("dmFileDescr", (*document
)->dmFileDescr
, 0)
3169 EXTRACT_STRING_ATTRIBUTE("dmFormat", (*document
)->dmFormat
, 0)
3172 /* Extract document data.
3173 * Base64 encoded blob or XML subtree must be presented. */
3175 /* Check from dmEncodedContent */
3176 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmEncodedContent",
3183 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3184 /* Here we have Base64 blob */
3186 if (result
->nodesetval
->nodeNr
> 1) {
3187 isds_printf_message(context
,
3188 _("Document has more dmEncodedContent elements"));
3193 xmlXPathFreeObject(result
); result
= NULL
;
3194 EXTRACT_STRING("isds:dmEncodedContent", string
);
3196 /* Decode non-emptys document */
3197 if (string
&& string
[0] != '\0') {
3198 (*document
)->data_length
=
3199 _isds_b64decode(string
, &((*document
)->data
));
3200 if ((*document
)->data_length
== (size_t) -1) {
3201 isds_printf_message(context
,
3202 _("Error while Base64-decoding document content"));
3208 /* No Base64 blob, try XML document */
3209 xmlXPathFreeObject(result
); result
= NULL
;
3210 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmXMLContent",
3217 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3218 /* Here we have XML document */
3220 if (result
->nodesetval
->nodeNr
> 1) {
3221 isds_printf_message(context
,
3222 _("Document has more dmXMLContent elements"));
3227 /* FIXME: Serialize the tree rooted at result's node */
3228 isds_printf_message(context
,
3229 _("XML documents not yet supported"));
3233 /* No bas64 blob, nor XML document */
3234 isds_printf_message(context
,
3235 _("Document has no dmEncodedContent, nor dmXMLContent "
3244 if (err
) isds_document_free(document
);
3246 xmlXPathFreeObject(result
);
3247 xpath_ctx
->node
= file_node
;
3253 /* Extract message documents into reallocated list of documents
3254 * @context is ISDS context
3255 * @documents is automically reallocated message documents list structure
3256 * @xpath_ctx is XPath context with current node as XSD tFilesArray
3257 * In case of error @documents will be freed. */
3258 static isds_error
extract_documents(struct isds_ctx
*context
,
3259 struct isds_list
**documents
, xmlXPathContextPtr xpath_ctx
) {
3260 isds_error err
= IE_SUCCESS
;
3261 xmlXPathObjectPtr result
= NULL
;
3262 xmlNodePtr files_node
= xpath_ctx
->node
;
3263 struct isds_list
*document
, *prev_document
;
3265 if (!context
) return IE_INVALID_CONTEXT
;
3266 if (!documents
) return IE_INVAL
;
3267 isds_list_free(documents
);
3268 if (!xpath_ctx
) return IE_INVAL
;
3270 /* Find documents */
3271 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmFile", xpath_ctx
);
3278 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3279 isds_printf_message(context
,
3280 _("Message does not contain any document"));
3286 /* Iterate over documents */
3287 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3289 /* Allocate and append list item */
3290 document
= calloc(1, sizeof(*document
));
3295 document
->destructor
= (void (*)(void **))isds_document_free
;
3296 if (i
== 0) *documents
= document
;
3297 else prev_document
->next
= document
;
3298 prev_document
= document
;
3300 /* Extract document */
3301 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3302 err
= extract_document(context
,
3303 (struct isds_document
**) &(document
->data
), xpath_ctx
);
3304 if (err
) goto leave
;
3309 if (err
) isds_list_free(documents
);
3310 xmlXPathFreeObject(result
);
3311 xpath_ctx
->node
= files_node
;
3316 /* Convert isds:dmRecord XML tree into structure
3317 * @context is ISDS context
3318 * @envelope is automically reallocated message envelope structure
3319 * @xpath_ctx is XPath context with current node as isds:dmRecord element
3320 * In case of error @envelope will be freed. */
3321 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
3322 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3323 isds_error err
= IE_SUCCESS
;
3324 xmlXPathObjectPtr result
= NULL
;
3326 if (!context
) return IE_INVALID_CONTEXT
;
3327 if (!envelope
) return IE_INVAL
;
3328 isds_envelope_free(envelope
);
3329 if (!xpath_ctx
) return IE_INVAL
;
3332 *envelope
= calloc(1, sizeof(**envelope
));
3339 /* Extract tRecord data */
3340 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
3342 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3343 * dmAcceptanceTime. */
3344 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
3345 if (err
) goto leave
;
3347 /* Extract envelope elements added by sender and ISDS
3348 * (XSD: gMessageEnvelope type) */
3349 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
3350 if (err
) goto leave
;
3351 /* dmOVM can not be obtained from ISDS */
3353 /* Get message type */
3354 err
= append_message_type(context
, envelope
, xpath_ctx
);
3355 if (err
) goto leave
;
3359 if (err
) isds_envelope_free(envelope
);
3360 xmlXPathFreeObject(result
);
3365 /* Find and convert isds:dmHash XML tree into structure
3366 * @context is ISDS context
3367 * @envelope is automically reallocated message hash structure
3368 * @xpath_ctx is XPath context with current node containing isds:dmHash child
3369 * In case of error @hash will be freed. */
3370 static isds_error
find_and_extract_DmHash(struct isds_ctx
*context
,
3371 struct isds_hash
**hash
, xmlXPathContextPtr xpath_ctx
) {
3372 isds_error err
= IE_SUCCESS
;
3373 xmlNodePtr old_ctx_node
;
3374 xmlXPathObjectPtr result
= NULL
;
3375 char *string
= NULL
;
3377 if (!context
) return IE_INVALID_CONTEXT
;
3378 if (!hash
) return IE_INVAL
;
3379 isds_hash_free(hash
);
3380 if (!xpath_ctx
) return IE_INVAL
;
3382 old_ctx_node
= xpath_ctx
->node
;
3384 *hash
= calloc(1, sizeof(**hash
));
3391 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmHash", xpath_ctx
);
3392 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3401 /* Get hash algorithm */
3402 EXTRACT_STRING_ATTRIBUTE("algorithm", string
, 1);
3403 err
= string2isds_hash_algorithm((xmlChar
*) string
, &(*hash
)->algorithm
);
3405 if (err
== IE_ENUM
) {
3406 char *string_locale
= _isds_utf82locale(string
);
3407 isds_printf_message(context
, _("Unsported hash algorithm: %s"),
3409 free(string_locale
);
3415 /* Get hash value */
3416 EXTRACT_STRING(".", string
);
3418 isds_printf_message(context
,
3419 _("sisds:dmHash element is missing hash value"));
3423 (*hash
)->length
= _isds_b64decode(string
, &((*hash
)->value
));
3424 if ((*hash
)->length
== (size_t) -1) {
3425 isds_printf_message(context
,
3426 _("Error while Base64-decoding hash value"));
3432 if (err
) isds_hash_free(hash
);
3434 xmlXPathFreeObject(result
);
3435 xpath_ctx
->node
= old_ctx_node
;
3440 /* Find and append isds:dmQTimestamp XML tree into envelope
3441 * @context is ISDS context
3442 * @envelope is automically allocated evnelope structure
3443 * @xpath_ctx is XPath context with current node containing isds:dmQTimestamp
3445 * In case of error @envelope will be freed. */
3446 static isds_error
find_and_append_DmQTimestamp(struct isds_ctx
*context
,
3447 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
3448 isds_error err
= IE_SUCCESS
;
3449 xmlXPathObjectPtr result
= NULL
;
3450 char *string
= NULL
;
3452 if (!context
) return IE_INVALID_CONTEXT
;
3453 if (!envelope
) return IE_INVAL
;
3455 isds_envelope_free(envelope
);
3460 *envelope
= calloc(1, sizeof(**envelope
));
3466 zfree((*envelope
)->timestamp
);
3467 (*envelope
)->timestamp_length
= 0;
3470 /* Get dmQTimestamp */
3471 EXTRACT_STRING("sisds:dmQTimestamp", string
);
3473 isds_printf_message(context
, _("Missing dmQTimestamp element content"));
3477 (*envelope
)->timestamp_length
=
3478 _isds_b64decode(string
, &((*envelope
)->timestamp
));
3479 if ((*envelope
)->timestamp_length
== (size_t) -1) {
3480 isds_printf_message(context
,
3481 _("Error while Base64-decoding timestamp value"));
3487 if (err
) isds_envelope_free(envelope
);
3489 xmlXPathFreeObject(result
);
3494 /* Convert XSD tReturnedMessage XML tree into message structure.
3495 * It does not store serialized XML tree into message->raw.
3496 * It does store (pointer to) parsed XML tree into message->xml if needed.
3497 * @context is ISDS context
3498 * @include_documents Use true if documents must be extracted
3499 * (tReturnedMessage XSD type), use false if documents shall be ommited
3500 * (tReturnedMessageEnvelope).
3501 * @message is automically reallocated message structure
3502 * @xpath_ctx is XPath context with current node as tReturnedMessage element
3504 * In case of error @message will be freed. */
3505 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
3506 const _Bool include_documents
, struct isds_message
**message
,
3507 xmlXPathContextPtr xpath_ctx
) {
3508 isds_error err
= IE_SUCCESS
;
3509 xmlNodePtr message_node
;
3511 if (!context
) return IE_INVALID_CONTEXT
;
3512 if (!message
) return IE_INVAL
;
3513 isds_message_free(message
);
3514 if (!xpath_ctx
) return IE_INVAL
;
3517 *message
= calloc(1, sizeof(**message
));
3523 /* Save message XPATH context node */
3524 message_node
= xpath_ctx
->node
;
3528 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmDm", xpath_ctx
);
3529 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
3530 if (err
) { err
= IE_ERROR
; goto leave
; }
3531 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
3532 if (err
) goto leave
;
3534 if (include_documents
) {
3535 /* Extract dmFiles */
3536 err
= move_xpathctx_to_child(context
, BAD_CAST
"isds:dmFiles",
3538 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) {
3539 err
= IE_ISDS
; goto leave
;
3541 if (err
) { err
= IE_ERROR
; goto leave
; }
3542 err
= extract_documents(context
, &((*message
)->documents
), xpath_ctx
);
3543 if (err
) goto leave
;
3544 /* Store xmlDoc of this message if needed */
3545 /* FIXME: Only if needed */
3546 (*message
)->xml
= xpath_ctx
->doc
;
3550 /* Restore context to message */
3551 xpath_ctx
->node
= message_node
;
3553 /* Extract dmHash */
3554 err
= find_and_extract_DmHash(context
, &(*message
)->envelope
->hash
,
3556 if (err
) goto leave
;
3558 /* Extract dmQTimestamp, */
3559 err
= find_and_append_DmQTimestamp(context
, &(*message
)->envelope
,
3561 if (err
) goto leave
;
3563 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
3564 * dmAcceptanceTime. */
3565 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
3566 if (err
) goto leave
;
3568 /* Get message type */
3569 err
= append_message_type(context
, &((*message
)->envelope
), xpath_ctx
);
3570 if (err
) goto leave
;
3573 if (err
) isds_message_free(message
);
3578 /* Extract message event into reallocated isds_event structure
3579 * @context is ISDS context
3580 * @event is automically reallocated message event structure
3581 * @xpath_ctx is XPath context with current node as isds:dmEvent
3582 * In case of error @event will be freed. */
3583 static isds_error
extract_event(struct isds_ctx
*context
,
3584 struct isds_event
**event
, xmlXPathContextPtr xpath_ctx
) {
3585 isds_error err
= IE_SUCCESS
;
3586 xmlXPathObjectPtr result
= NULL
;
3587 xmlNodePtr event_node
= xpath_ctx
->node
;
3588 char *string
= NULL
;
3590 if (!context
) return IE_INVALID_CONTEXT
;
3591 if (!event
) return IE_INVAL
;
3592 isds_event_free(event
);
3593 if (!xpath_ctx
) return IE_INVAL
;
3595 *event
= calloc(1, sizeof(**event
));
3601 /* Extract event data.
3602 * All elements are optional according XSD. That's funny. */
3603 EXTRACT_STRING("sisds:dmEventTime", string
);
3605 err
= timestring2timeval((xmlChar
*) string
, &((*event
)->time
));
3607 char *string_locale
= _isds_utf82locale(string
);
3608 if (err
== IE_DATE
) err
= IE_ISDS
;
3609 isds_printf_message(context
,
3610 _("Could not convert dmEventTime as ISO time: %s"),
3612 free(string_locale
);
3618 /* dmEventDescr element has prefix and the rest */
3619 EXTRACT_STRING("sisds:dmEventDescr", string
);
3621 err
= eventstring2event((xmlChar
*) string
, *event
);
3622 if (err
) goto leave
;
3627 if (err
) isds_event_free(event
);
3629 xmlXPathFreeObject(result
);
3630 xpath_ctx
->node
= event_node
;
3635 /* Convert element of XSD tEventsArray type from XML tree into
3636 * isds_list of isds_event's structure. The list is automatically reallocated.
3637 * @context is ISDS context
3638 * @events is automically reallocated list of event structures
3639 * @xpath_ctx is XPath context with current node as tEventsArray
3640 * In case of error @evnets will be freed. */
3641 static isds_error
extract_events(struct isds_ctx
*context
,
3642 struct isds_list
**events
, xmlXPathContextPtr xpath_ctx
) {
3643 isds_error err
= IE_SUCCESS
;
3644 xmlXPathObjectPtr result
= NULL
;
3645 xmlNodePtr events_node
= xpath_ctx
->node
;
3646 struct isds_list
*event
, *prev_event
= NULL
;
3648 if (!context
) return IE_INVALID_CONTEXT
;
3649 if (!events
) return IE_INVAL
;
3650 if (!xpath_ctx
) return IE_INVAL
;
3653 isds_list_free(events
);
3656 result
= xmlXPathEvalExpression(BAD_CAST
"sisds:dmEvent", xpath_ctx
);
3663 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3664 isds_printf_message(context
,
3665 _("Delivery info does not contain any event"));
3671 /* Iterate over events */
3672 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
3674 /* Allocate and append list item */
3675 event
= calloc(1, sizeof(*event
));
3680 event
->destructor
= (void (*)(void **))isds_event_free
;
3681 if (i
== 0) *events
= event
;
3682 else prev_event
->next
= event
;
3686 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
3687 err
= extract_event(context
,
3688 (struct isds_event
**) &(event
->data
), xpath_ctx
);
3689 if (err
) goto leave
;
3694 if (err
) isds_list_free(events
);
3695 xmlXPathFreeObject(result
);
3696 xpath_ctx
->node
= events_node
;
3701 /* Convert isds_document structure into XML tree and append to dmFiles node.
3702 * @context is session context
3703 * @document is ISDS document
3704 * @dm_files is XML element the resulting tree will be appended to as a child.
3705 * @return error code, in case of error context' message is filled. */
3706 static isds_error
insert_document(struct isds_ctx
*context
,
3707 struct isds_document
*document
, xmlNodePtr dm_files
) {
3708 isds_error err
= IE_SUCCESS
;
3709 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
3710 xmlAttrPtr attribute_node
;
3711 xmlChar
*base64data
= NULL
;
3713 if (!context
) return IE_INVALID_CONTEXT
;
3714 if (!document
|| !dm_files
) return IE_INVAL
;
3716 /* Allocate new dmFile */
3717 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
3719 isds_printf_message(context
, _("Could not allocate main dmFile"));
3723 /* Append the new dmFile.
3724 * XXX: Main document must go first */
3725 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
3726 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
3728 file
= xmlAddChild(dm_files
, new_file
);
3731 xmlFreeNode(new_file
); new_file
= NULL
;
3732 isds_printf_message(context
, _("Could not add dmFile child to "
3733 "%s element"), dm_files
->name
);
3738 /* @dmMimeType is required */
3739 if (!document
->dmMimeType
) {
3740 isds_log_message(context
,
3741 _("Document is missing mandatory MIME type definition"));
3745 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
3747 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
3749 isds_printf_message(context
,
3750 _("Document has unknown dmFileMetaType: %ld"),
3751 document
->dmFileMetaType
);
3755 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
3757 if (document
->dmFileGuid
) {
3758 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
3760 if (document
->dmUpFileGuid
) {
3761 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
3764 /* @dmFileDescr is required */
3765 if (!document
->dmFileDescr
) {
3766 isds_log_message(context
,
3767 _("Document is missing mandatory description (title)"));
3771 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
3773 if (document
->dmFormat
) {
3774 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
3778 /* Insert content (data) of the document. */
3779 /* XXX; Only base64 is implemented currently. */
3780 base64data
= (xmlChar
*) _isds_b64encode(document
->data
,
3781 document
->data_length
);
3783 isds_printf_message(context
,
3784 ngettext("Not enought memory to encode %zd bytes into Base64",
3785 "Not enought memory to encode %zd bytes into Base64",
3786 document
->data_length
),
3787 document
->data_length
);
3791 INSERT_STRING(file
, "dmEncodedContent", base64data
);
3799 /* Append XSD tMStatus XML tree into isds_message_copy structure.
3800 * The copy must pre prealocated, the date are just appended into structure.
3801 * @context is ISDS context
3802 * @copy is message copy struture
3803 * @xpath_ctx is XPath context with current node as tMStatus */
3804 static isds_error
append_TMStatus(struct isds_ctx
*context
,
3805 struct isds_message_copy
*copy
, xmlXPathContextPtr xpath_ctx
) {
3806 isds_error err
= IE_SUCCESS
;
3807 xmlXPathObjectPtr result
= NULL
;
3808 char *code
= NULL
, *message
= NULL
;
3810 if (!context
) return IE_INVALID_CONTEXT
;
3811 if (!copy
|| !xpath_ctx
) return IE_INVAL
;
3813 /* Free old values */
3814 zfree(copy
->dmStatus
);
3817 /* Get error specific to this copy */
3818 EXTRACT_STRING("isds:dmStatus/isds:dmStatusCode", code
);
3820 isds_log_message(context
,
3821 _("Missing isds:dmStatusCode under "
3822 "XSD:tMStatus type element"));
3827 if (xmlStrcmp((const xmlChar
*)code
, BAD_CAST
"0000")) {
3828 /* This copy failed */
3829 copy
->error
= IE_ISDS
;
3830 EXTRACT_STRING("isds:dmStatus/isds:dmStatusMessage", message
);
3832 copy
->dmStatus
= _isds_astrcat3(code
, ": ", message
);
3833 if (!copy
->dmStatus
) {
3834 copy
->dmStatus
= code
;
3838 copy
->dmStatus
= code
;
3842 /* This copy succeeded. In this case only, message ID is valid */
3843 copy
->error
= IE_SUCCESS
;
3845 EXTRACT_STRING("isds:dmID", copy
->dmID
);
3847 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
3848 "but did not returned assigned message ID\n"));
3856 xmlXPathFreeObject(result
);
3861 /* Insert struct isds_approval data (box approval) into XML tree
3862 * @context is sesstion context
3863 * @approval is libsids structure with approval description. NULL is
3865 * @parent is XML element to append @approval to */
3866 static isds_error
insert_GExtApproval(struct isds_ctx
*context
,
3867 const struct isds_approval
*approval
, xmlNodePtr parent
) {
3869 isds_error err
= IE_SUCCESS
;
3872 if (!context
) return IE_INVALID_CONTEXT
;
3873 if (!parent
) return IE_INVAL
;
3875 if (!approval
) return IE_SUCCESS
;
3877 /* Build XSD:gExtApproval */
3878 INSERT_SCALAR_BOOLEAN(parent
, "dbApproved", approval
->approved
);
3879 INSERT_STRING(parent
, "dbExternRefNumber", approval
->refference
);
3886 /* Build ISDS request of XSD tDummyInput type, sent it and check for error
3888 * @context is session context
3889 * @service_name is name of SERVICE_DB_ACCESS
3890 * @response is server SOAP body response as XML document
3891 * @raw_response is automatically reallocated bitstream with response body. Use
3892 * NULL if you don't care
3893 * @raw_response_length is size of @raw_response in bytes
3894 * @code is ISDS status code
3895 * @status_message is ISDS status message
3896 * @return error coded from lower layer, context message will be set up
3898 static isds_error
build_send_check_dbdummy_request(struct isds_ctx
*context
,
3899 const xmlChar
*service_name
,
3900 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
3901 xmlChar
**code
, xmlChar
**status_message
) {
3903 isds_error err
= IE_SUCCESS
;
3904 char *service_name_locale
= NULL
;
3905 xmlNodePtr request
= NULL
, node
;
3906 xmlNsPtr isds_ns
= NULL
;
3908 if (!context
) return IE_INVALID_CONTEXT
;
3909 if (!service_name
) return IE_INVAL
;
3910 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
3911 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
3913 /* Free output argument */
3914 xmlFreeDoc(*response
); *response
= NULL
;
3915 if (raw_response
) zfree(*raw_response
);
3917 free(*status_message
);
3920 /* Check if connection is established
3921 * TODO: This check should be done donwstairs. */
3922 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3924 service_name_locale
= _isds_utf82locale((char*)service_name
);
3925 if (!service_name_locale
) {
3931 request
= xmlNewNode(NULL
, service_name
);
3933 isds_printf_message(context
,
3934 _("Could not build %s request"), service_name_locale
);
3938 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3940 isds_log_message(context
, _("Could not create ISDS name space"));
3944 xmlSetNs(request
, isds_ns
);
3947 /* Add XSD:tDummyInput child */
3948 INSERT_STRING(request
, "dbDummy", NULL
);
3951 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
3952 service_name_locale
);
3955 err
= isds(context
, SERVICE_DB_ACCESS
, request
, response
,
3956 raw_response
, raw_response_length
);
3957 xmlFreeNode(request
); request
= NULL
;
3960 isds_log(ILF_ISDS
, ILL_DEBUG
,
3961 _("Processing ISDS response on %s request failed\n"),
3962 service_name_locale
);
3966 /* Check for response status */
3967 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, *response
,
3968 code
, status_message
, NULL
);
3970 isds_log(ILF_ISDS
, ILL_DEBUG
,
3971 _("ISDS response on %s request is missing status\n"),
3972 service_name_locale
);
3976 /* Request processed, but nothing found */
3977 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
3978 char *code_locale
= _isds_utf82locale((char*) *code
);
3979 char *status_message_locale
=
3980 _isds_utf82locale((char*) *status_message
);
3981 isds_log(ILF_ISDS
, ILL_DEBUG
,
3982 _("Server refused %s request (code=%s, message=%s)\n"),
3983 service_name_locale
, code_locale
, status_message_locale
);
3984 isds_log_message(context
, status_message_locale
);
3986 free(status_message_locale
);
3992 free(service_name_locale
);
3993 xmlFreeNode(request
);
3998 /* Get data about logged in user and his box. */
3999 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
4000 struct isds_DbOwnerInfo
**db_owner_info
) {
4001 isds_error err
= IE_SUCCESS
;
4002 xmlDocPtr response
= NULL
;
4003 xmlChar
*code
= NULL
, *message
= NULL
;
4004 xmlXPathContextPtr xpath_ctx
= NULL
;
4005 xmlXPathObjectPtr result
= NULL
;
4006 char *string
= NULL
;
4008 if (!context
) return IE_INVALID_CONTEXT
;
4009 zfree(context
->long_message
);
4010 if (!db_owner_info
) return IE_INVAL
;
4012 /* Check if connection is established */
4013 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4016 /* Do request and check for success */
4017 err
= build_send_check_dbdummy_request(context
,
4018 BAD_CAST
"GetOwnerInfoFromLogin",
4019 &response
, NULL
, NULL
, &code
, &message
);
4020 if (err
) goto leave
;
4024 /* Prepare stucture */
4025 isds_DbOwnerInfo_free(db_owner_info
);
4026 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
4027 if (!*db_owner_info
) {
4031 xpath_ctx
= xmlXPathNewContext(response
);
4036 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4041 /* Set context node */
4042 result
= xmlXPathEvalExpression(BAD_CAST
4043 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
4048 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4049 isds_log_message(context
, _("Missing dbOwnerInfo element"));
4053 if (result
->nodesetval
->nodeNr
> 1) {
4054 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
4058 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4059 xmlXPathFreeObject(result
); result
= NULL
;
4062 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
4066 isds_DbOwnerInfo_free(db_owner_info
);
4070 xmlXPathFreeObject(result
);
4071 xmlXPathFreeContext(xpath_ctx
);
4075 xmlFreeDoc(response
);
4078 isds_log(ILF_ISDS
, ILL_DEBUG
,
4079 _("GetOwnerInfoFromLogin request processed by server "
4080 "successfully.\n"));
4086 /* Get data about logged in user. */
4087 isds_error
isds_GetUserInfoFromLogin(struct isds_ctx
*context
,
4088 struct isds_DbUserInfo
**db_user_info
) {
4089 isds_error err
= IE_SUCCESS
;
4090 xmlDocPtr response
= NULL
;
4091 xmlChar
*code
= NULL
, *message
= NULL
;
4092 xmlXPathContextPtr xpath_ctx
= NULL
;
4093 xmlXPathObjectPtr result
= NULL
;
4095 if (!context
) return IE_INVALID_CONTEXT
;
4096 zfree(context
->long_message
);
4097 if (!db_user_info
) return IE_INVAL
;
4099 /* Check if connection is established */
4100 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4103 /* Do request and check for success */
4104 err
= build_send_check_dbdummy_request(context
,
4105 BAD_CAST
"GetUserInfoFromLogin",
4106 &response
, NULL
, NULL
, &code
, &message
);
4107 if (err
) goto leave
;
4111 /* Prepare stucture */
4112 isds_DbUserInfo_free(db_user_info
);
4113 *db_user_info
= calloc(1, sizeof(**db_user_info
));
4114 if (!*db_user_info
) {
4118 xpath_ctx
= xmlXPathNewContext(response
);
4123 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4128 /* Set context node */
4129 result
= xmlXPathEvalExpression(BAD_CAST
4130 "/isds:GetUserInfoFromLoginResponse/isds:dbUserInfo", xpath_ctx
);
4135 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4136 isds_log_message(context
, _("Missing dbUserInfo element"));
4140 if (result
->nodesetval
->nodeNr
> 1) {
4141 isds_log_message(context
, _("Multiple dbUserInfo element"));
4145 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4146 xmlXPathFreeObject(result
); result
= NULL
;
4149 err
= extract_DbUserInfo(context
, db_user_info
, xpath_ctx
);
4153 isds_DbUserInfo_free(db_user_info
);
4156 xmlXPathFreeObject(result
);
4157 xmlXPathFreeContext(xpath_ctx
);
4161 xmlFreeDoc(response
);
4164 isds_log(ILF_ISDS
, ILL_DEBUG
,
4165 _("GetUserInfoFromLogin request processed by server "
4166 "successfully.\n"));
4172 /* Get expiration time of current password
4173 * @context is session context
4174 * @expiration is automatically reallocated time when password expires, In
4175 * case of error will be nulled. */
4176 isds_error
isds_get_password_expiration(struct isds_ctx
*context
,
4177 struct timeval
**expiration
) {
4178 isds_error err
= IE_SUCCESS
;
4179 xmlDocPtr response
= NULL
;
4180 xmlChar
*code
= NULL
, *message
= NULL
;
4181 xmlXPathContextPtr xpath_ctx
= NULL
;
4182 xmlXPathObjectPtr result
= NULL
;
4183 char *string
= NULL
;
4185 if (!context
) return IE_INVALID_CONTEXT
;
4186 zfree(context
->long_message
);
4187 if (!expiration
) return IE_INVAL
;
4189 /* Check if connection is established */
4190 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4193 /* Do request and check for success */
4194 err
= build_send_check_dbdummy_request(context
,
4195 BAD_CAST
"GetPasswordInfo",
4196 &response
, NULL
, NULL
, &code
, &message
);
4197 if (err
) goto leave
;
4201 xpath_ctx
= xmlXPathNewContext(response
);
4206 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4211 /* Set context node */
4212 result
= xmlXPathEvalExpression(BAD_CAST
4213 "/isds:GetPasswordInfoResponse", xpath_ctx
);
4218 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4219 isds_log_message(context
,
4220 _("Missing GetPasswordInfoResponse element"));
4224 if (result
->nodesetval
->nodeNr
> 1) {
4225 isds_log_message(context
,
4226 _("Multiple GetPasswordInfoResponse element"));
4230 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
4231 xmlXPathFreeObject(result
); result
= NULL
;
4233 /* Extract expiration date */
4234 EXTRACT_STRING("isds:pswExpDate", string
);
4236 isds_log_message(context
, _("Missing pswExpDate element"));
4241 err
= timestring2timeval((xmlChar
*) string
, expiration
);
4243 char *string_locale
= _isds_utf82locale(string
);
4244 if (err
== IE_DATE
) err
= IE_ISDS
;
4245 isds_printf_message(context
,
4246 _("Could not convert pswExpDate as ISO time: %s"),
4248 free(string_locale
);
4260 xmlXPathFreeObject(result
);
4261 xmlXPathFreeContext(xpath_ctx
);
4265 xmlFreeDoc(response
);
4268 isds_log(ILF_ISDS
, ILL_DEBUG
,
4269 _("GetPasswordInfo request processed by server "
4270 "successfully.\n"));
4276 /* Change user password in ISDS.
4277 * User must supply old password, new password will takes effect after some
4278 * time, current session can continue. Password must fulfill some constraints.
4279 * @context is session context
4280 * @old_password is current password.
4281 * @new_password is requested new password */
4282 isds_error
isds_change_password(struct isds_ctx
*context
,
4283 const char *old_password
, const char *new_password
) {
4284 isds_error err
= IE_SUCCESS
;
4285 xmlNsPtr isds_ns
= NULL
;
4286 xmlNodePtr request
= NULL
, node
;
4287 xmlDocPtr response
= NULL
;
4288 xmlChar
*code
= NULL
, *message
= NULL
;
4290 if (!context
) return IE_INVALID_CONTEXT
;
4291 zfree(context
->long_message
);
4292 if (!old_password
|| !new_password
) return IE_INVAL
;
4294 /* Check if connection is established
4295 * TODO: This check should be done donwstairs. */
4296 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4299 /* Build ChangeISDSPassword request */
4300 request
= xmlNewNode(NULL
, BAD_CAST
"ChangeISDSPassword");
4302 isds_log_message(context
,
4303 _("Could not build ChangeISDSPassword request"));
4306 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4308 isds_log_message(context
, _("Could not create ISDS name space"));
4309 xmlFreeNode(request
);
4312 xmlSetNs(request
, isds_ns
);
4314 INSERT_STRING(request
, "dbOldPassword", old_password
);
4315 INSERT_STRING(request
, "dbNewPassword", new_password
);
4318 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
4321 err
= isds(context
, SERVICE_DB_ACCESS
, request
, &response
, NULL
, NULL
);
4323 /* Destroy request */
4324 xmlFreeNode(request
); request
= NULL
;
4327 isds_log(ILF_ISDS
, ILL_DEBUG
,
4328 _("Processing ISDS response on ChangeISDSPassword "
4329 "request failed\n"));
4333 /* Check for response status */
4334 err
= isds_response_status(context
, SERVICE_DB_ACCESS
, response
,
4335 &code
, &message
, NULL
);
4337 isds_log(ILF_ISDS
, ILL_DEBUG
,
4338 _("ISDS response on ChangeISDSPassword request is missing "
4343 /* Request processed, but empty password refused */
4344 if (!xmlStrcmp(code
, BAD_CAST
"1066")) {
4345 char *code_locale
= _isds_utf82locale((char*)code
);
4346 char *message_locale
= _isds_utf82locale((char*)message
);
4347 isds_log(ILF_ISDS
, ILL_DEBUG
,
4348 _("Server refused empty password on ChangeISDSPassword "
4349 "request (code=%s, message=%s)\n"),
4350 code_locale
, message_locale
);
4351 isds_log_message(context
, _("Password must not be empty"));
4353 free(message_locale
);
4358 /* Request processed, but new password was reused */
4359 else if (!xmlStrcmp(code
, BAD_CAST
"1067")) {
4360 char *code_locale
= _isds_utf82locale((char*)code
);
4361 char *message_locale
= _isds_utf82locale((char*)message
);
4362 isds_log(ILF_ISDS
, ILL_DEBUG
,
4363 _("Server refused the same new password on ChangeISDSPassword "
4364 "request (code=%s, message=%s)\n"),
4365 code_locale
, message_locale
);
4366 isds_log_message(context
,
4367 _("New password must differ from the current one"));
4369 free(message_locale
);
4375 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4376 char *code_locale
= _isds_utf82locale((char*)code
);
4377 char *message_locale
= _isds_utf82locale((char*)message
);
4378 isds_log(ILF_ISDS
, ILL_DEBUG
,
4379 _("Server refused to change password on ChangeISDSPassword "
4380 "request (code=%s, message=%s)\n"),
4381 code_locale
, message_locale
);
4382 isds_log_message(context
, message_locale
);
4384 free(message_locale
);
4389 /* Otherwise password changed successfully */
4394 xmlFreeDoc(response
);
4395 xmlFreeNode(request
);
4398 isds_log(ILF_ISDS
, ILL_DEBUG
,
4399 _("Password changed successfully on ChangeISDSPassword "
4406 /* Generic middle part with request sending and response check.
4407 * It sends prepared request and checks for error code.
4408 * @context is ISDS session context.
4409 * @service is ISDS service handler
4410 * @service_name is name in scope of given @service
4411 * @request is XML tree with request. Will be freed to save memory.
4412 * @response is XML document ouputing ISDS response.
4413 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4414 * NULL, if you don't care. */
4415 static isds_error
send_destroy_request_check_response(
4416 struct isds_ctx
*context
,
4417 const isds_service service
, const xmlChar
*service_name
,
4418 xmlNodePtr
*request
, xmlDocPtr
*response
, xmlChar
**refnumber
) {
4419 isds_error err
= IE_SUCCESS
;
4420 char *service_name_locale
= NULL
;
4421 xmlChar
*code
= NULL
, *message
= NULL
;
4424 if (!context
) return IE_INVALID_CONTEXT
;
4425 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
||
4429 /* Check if connection is established
4430 * TODO: This check should be done donwstairs. */
4431 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
4433 service_name_locale
= _isds_utf82locale((char*) service_name
);
4434 if (!service_name_locale
) {
4439 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending %s request to ISDS\n"),
4440 service_name_locale
);
4443 err
= isds(context
, service
, *request
, response
, NULL
, NULL
);
4444 xmlFreeNode(*request
); *request
= NULL
;
4447 isds_log(ILF_ISDS
, ILL_DEBUG
,
4448 _("Processing ISDS response on %s request failed\n"),
4449 service_name_locale
);
4453 /* Check for response status */
4454 err
= isds_response_status(context
, service
, *response
,
4455 &code
, &message
, refnumber
);
4457 isds_log(ILF_ISDS
, ILL_DEBUG
,
4458 _("ISDS response on %s request is missing status\n"),
4459 service_name_locale
);
4463 /* Request processed, but server failed */
4464 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
4465 char *code_locale
= _isds_utf82locale((char*) code
);
4466 char *message_locale
= _isds_utf82locale((char*) message
);
4467 isds_log(ILF_ISDS
, ILL_DEBUG
,
4468 _("Server refused %s request (code=%s, message=%s)\n"),
4469 service_name_locale
, code_locale
, message_locale
);
4470 isds_log_message(context
, message_locale
);
4472 free(message_locale
);
4481 if (err
&& *response
) {
4482 xmlFreeDoc(*response
);
4486 xmlFreeNode(*request
);
4489 free(service_name_locale
);
4495 /* Generic bottom half with request sending.
4496 * It sends prepared request, checks for error code, destroys response and
4497 * request and log success or failure.
4498 * @context is ISDS session context.
4499 * @service is ISDS service handler
4500 * @service_name is name in scope of given @service
4501 * @request is XML tree with request. Will be freed to save memory.
4502 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4503 * NULL, if you don't care. */
4504 static isds_error
send_request_check_drop_response(
4505 struct isds_ctx
*context
,
4506 const isds_service service
, const xmlChar
*service_name
,
4507 xmlNodePtr
*request
, xmlChar
**refnumber
) {
4508 isds_error err
= IE_SUCCESS
;
4509 xmlDocPtr response
= NULL
;
4512 if (!context
) return IE_INVALID_CONTEXT
;
4513 if (!service_name
|| *service_name
== '\0' || !request
|| !*request
)
4516 /* Send request and check response*/
4517 err
= send_destroy_request_check_response(context
,
4518 service
, service_name
, request
, &response
, refnumber
);
4520 xmlFreeDoc(response
);
4523 xmlFreeNode(*request
);
4528 char *service_name_locale
= _isds_utf82locale((char *) service_name
);
4529 isds_log(ILF_ISDS
, ILL_DEBUG
,
4530 _("%s request processed by server successfully.\n"),
4531 service_name_locale
);
4532 free(service_name_locale
);
4539 /* Build XSD:tCreateDBInput request type for box createing.
4540 * @context is session context
4541 * @request outputs built XML tree
4542 * @service_name is request name of SERVICE_DB_MANIPULATION service
4543 * @box is box description to create including single primary user (in case of
4545 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4546 * box, or contact address of PFO box owner)
4547 * @former_names is optional undocumented string. Pass NULL if you don't care.
4548 * @upper_box_id is optional ID of supper box if currently created box is
4550 * @ceo_label is optional title of OVM box owner (e.g. mayor) NULL, if you
4552 * @approval is optional external approval of box manipulation */
4553 static isds_error
build_CreateDBInput_request(struct isds_ctx
*context
,
4554 xmlNodePtr
*request
, const xmlChar
*service_name
,
4555 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4556 const xmlChar
*former_names
, const xmlChar
*upper_box_id
,
4557 const xmlChar
*ceo_label
, const struct isds_approval
*approval
) {
4558 isds_error err
= IE_SUCCESS
;
4559 xmlNsPtr isds_ns
= NULL
;
4560 xmlNodePtr node
, dbPrimaryUsers
;
4561 xmlChar
*string
= NULL
;
4562 const struct isds_list
*item
;
4565 if (!context
) return IE_INVALID_CONTEXT
;
4566 if (!request
|| !service_name
|| service_name
[0] == '\0' || !box
)
4570 /* Build DeleteDataBox request */
4571 *request
= xmlNewNode(NULL
, service_name
);
4573 char *service_name_locale
= _isds_utf82locale((char*) service_name
);
4574 isds_printf_message(context
, _("Could build %s request"),
4575 service_name_locale
);
4576 free(service_name_locale
);
4579 if (context
->type
== CTX_TYPE_TESTING_REQUEST_COLLECTOR
) {
4580 isds_ns
= xmlNewNs(*request
, BAD_CAST ISDS1_NS
, NULL
);
4582 isds_log_message(context
, _("Could not create ISDS1 name space"));
4583 xmlFreeNode(*request
);
4587 isds_ns
= xmlNewNs(*request
, BAD_CAST ISDS_NS
, NULL
);
4589 isds_log_message(context
, _("Could not create ISDS name space"));
4590 xmlFreeNode(*request
);
4594 xmlSetNs(*request
, isds_ns
);
4596 INSERT_ELEMENT(node
, *request
, "dbOwnerInfo");
4597 err
= insert_DbOwnerInfo(context
, box
, node
);
4598 if (err
) goto leave
;
4601 /* XXX: There is bug in XSD: XSD says at least one dbUserInfo must exist,
4602 * verbose documentatiot allows none dbUserInfo */
4603 INSERT_ELEMENT(dbPrimaryUsers
, *request
, "dbPrimaryUsers");
4604 for (item
= users
; item
; item
= item
->next
) {
4606 INSERT_ELEMENT(node
, dbPrimaryUsers
, "dbUserInfo");
4607 err
= insert_DbUserInfo(context
,
4608 (struct isds_DbUserInfo
*) item
->data
, node
);
4609 if (err
) goto leave
;
4613 INSERT_STRING(*request
, "dbFormerNames", former_names
);
4614 INSERT_STRING(*request
, "dbUpperDBId", upper_box_id
);
4615 INSERT_STRING(*request
, "dbCEOLabel", ceo_label
);
4617 err
= insert_GExtApproval(context
, approval
, *request
);
4618 if (err
) goto leave
;
4622 xmlFreeNode(*request
);
4631 * @context is session context
4632 * @box is box description to create including single primary user (in case of
4633 * FO box type). It outputs box ID assigned by ISDS in dbID element.
4634 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
4635 * box, or contact address of PFO box owner)
4636 * @former_names is optional undocumented string. Pass NULL if you don't care.
4637 * @upper_box_id is optional ID of supper box if currently created box is
4639 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4640 * @approval is optional external approval of box manipulation
4641 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4642 * NULL, if you don't care.*/
4643 isds_error
isds_add_box(struct isds_ctx
*context
,
4644 struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4645 const char *former_names
, const char *upper_box_id
,
4646 const char *ceo_label
, const struct isds_approval
*approval
,
4648 isds_error err
= IE_SUCCESS
;
4649 xmlNodePtr request
= NULL
;
4650 xmlDocPtr response
= NULL
;
4651 xmlXPathContextPtr xpath_ctx
= NULL
;
4652 xmlXPathObjectPtr result
= NULL
;
4655 if (!context
) return IE_INVALID_CONTEXT
;
4656 zfree(context
->long_message
);
4657 if (!box
) return IE_INVAL
;
4659 /* Scratch box ID */
4662 /* Build CreateDataBox request */
4663 err
= build_CreateDBInput_request(context
,
4664 &request
, BAD_CAST
"CreateDataBox",
4665 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4666 (xmlChar
*) ceo_label
, approval
);
4667 if (err
) goto leave
;
4669 /* Send it to server and process response */
4670 err
= send_destroy_request_check_response(context
,
4671 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4672 &response
, (xmlChar
**) refnumber
);
4674 /* Extract box ID */
4675 xpath_ctx
= xmlXPathNewContext(response
);
4680 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4684 EXTRACT_STRING("/isds:CreateDataBoxResponse/dbID", box
->dbID
);
4687 xmlXPathFreeObject(result
);
4688 xmlXPathFreeContext(xpath_ctx
);
4689 xmlFreeDoc(response
);
4690 xmlFreeNode(request
);
4693 isds_log(ILF_ISDS
, ILL_DEBUG
,
4694 _("CreateDataBox request processed by server successfully.\n"));
4701 /* Notify ISDS about new PFO entity.
4702 * This function has no real effect.
4703 * @context is session context
4704 * @box is PFO description including single primary user.
4705 * @users is list of struct isds_DbUserInfo (contact address of PFO box owner)
4706 * @former_names is optional undocumented string. Pass NULL if you don't care.
4707 * @upper_box_id is optional ID of supper box if currently created box is
4709 * @ceo_label is optional title of OVM box owner (e.g. mayor)
4710 * @approval is optional external approval of box manipulation
4711 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4712 * NULL, if you don't care.*/
4713 isds_error
isds_add_pfoinfo(struct isds_ctx
*context
,
4714 const struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
4715 const char *former_names
, const char *upper_box_id
,
4716 const char *ceo_label
, const struct isds_approval
*approval
,
4718 isds_error err
= IE_SUCCESS
;
4719 xmlNodePtr request
= NULL
;
4721 if (!context
) return IE_INVALID_CONTEXT
;
4722 zfree(context
->long_message
);
4723 if (!box
) return IE_INVAL
;
4725 /* Build CreateDataBoxPFOInfo request */
4726 err
= build_CreateDBInput_request(context
,
4727 &request
, BAD_CAST
"CreateDataBoxPFOInfo",
4728 box
, users
, (xmlChar
*) former_names
, (xmlChar
*) upper_box_id
,
4729 (xmlChar
*) ceo_label
, approval
);
4730 if (err
) goto leave
;
4732 /* Send it to server and process response */
4733 err
= send_request_check_drop_response(context
,
4734 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
4735 (xmlChar
**) refnumber
);
4737 xmlFreeNode(request
);
4742 /* Remove given given box permanetly.
4743 * @context is session context
4744 * @box is box description to delete
4745 * @since is date of box owner cancalation. Only tm_year, tm_mon and tm_mday
4747 * @approval is optional external approval of box manipulation
4748 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4749 * NULL, if you don't care.*/
4750 isds_error
isds_delete_box(struct isds_ctx
*context
,
4751 const struct isds_DbOwnerInfo
*box
, const struct tm
*since
,
4752 const struct isds_approval
*approval
, char **refnumber
) {
4753 isds_error err
= IE_SUCCESS
;
4754 xmlNsPtr isds_ns
= NULL
;
4755 xmlNodePtr request
= NULL
;
4757 xmlChar
*string
= NULL
;
4760 if (!context
) return IE_INVALID_CONTEXT
;
4761 zfree(context
->long_message
);
4762 if (!box
|| !since
) return IE_INVAL
;
4765 /* Build DeleteDataBox request */
4766 request
= xmlNewNode(NULL
, BAD_CAST
"DeleteDataBox");
4768 isds_log_message(context
,
4769 _("Could build DeleteDataBox request"));
4772 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4774 isds_log_message(context
, _("Could not create ISDS name space"));
4775 xmlFreeNode(request
);
4778 xmlSetNs(request
, isds_ns
);
4780 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
4781 err
= insert_DbOwnerInfo(context
, box
, node
);
4782 if (err
) goto leave
;
4784 err
= tm2datestring(since
, &string
);
4786 isds_log_message(context
,
4787 _("Could not convert `since' argument to ISO date string"));
4790 INSERT_STRING(request
, "dbOwnerTerminationDate", string
);
4793 err
= insert_GExtApproval(context
, approval
, request
);
4794 if (err
) goto leave
;
4797 /* Send it to server and process response */
4798 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4799 BAD_CAST
"DeleteDataBox", &request
, (xmlChar
**) refnumber
);
4802 xmlFreeNode(request
);
4808 /* Update data about given box.
4809 * @context is session context
4810 * @old_box current box description
4811 * @new_box are updated data about @old_box
4812 * @approval is optional external approval of box manipulation
4813 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4814 * NULL, if you don't care.*/
4815 isds_error
isds_UpdateDataBoxDescr(struct isds_ctx
*context
,
4816 const struct isds_DbOwnerInfo
*old_box
,
4817 const struct isds_DbOwnerInfo
*new_box
,
4818 const struct isds_approval
*approval
, char **refnumber
) {
4819 isds_error err
= IE_SUCCESS
;
4820 xmlNsPtr isds_ns
= NULL
;
4821 xmlNodePtr request
= NULL
;
4825 if (!context
) return IE_INVALID_CONTEXT
;
4826 zfree(context
->long_message
);
4827 if (!old_box
|| !new_box
) return IE_INVAL
;
4830 /* Build UpdateDataBoxDescr request */
4831 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxDescr");
4833 isds_log_message(context
,
4834 _("Could build UpdateDataBoxDescr request"));
4837 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4839 isds_log_message(context
, _("Could not create ISDS name space"));
4840 xmlFreeNode(request
);
4843 xmlSetNs(request
, isds_ns
);
4845 INSERT_ELEMENT(node
, request
, "dbOldOwnerInfo");
4846 err
= insert_DbOwnerInfo(context
, old_box
, node
);
4847 if (err
) goto leave
;
4849 INSERT_ELEMENT(node
, request
, "dbNewOwnerInfo");
4850 err
= insert_DbOwnerInfo(context
, new_box
, node
);
4851 if (err
) goto leave
;
4853 err
= insert_GExtApproval(context
, approval
, request
);
4854 if (err
) goto leave
;
4857 /* Send it to server and process response */
4858 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
4859 BAD_CAST
"UpdateDataBoxDescr", &request
, (xmlChar
**) refnumber
);
4862 xmlFreeNode(request
);
4868 /* Build ISDS request of XSD tIdDbInput type, sent it and check for error
4870 * @context is session context
4871 * @service is SOAP service
4872 * @service_name is name of request in @service
4873 * @box_id is box ID of interrest
4874 * @approval is optional external approval of box manipulation
4875 * @response is server SOAP body response as XML document
4876 * @refnumber is reallocated serial number of request assigned by ISDS. Use
4877 * NULL, if you don't care.
4878 * @return error coded from lower layer, context message will be set up
4880 static isds_error
build_send_dbid_request_check_response(
4881 struct isds_ctx
*context
, const isds_service service
,
4882 const xmlChar
*service_name
, const xmlChar
*box_id
,
4883 const struct isds_approval
*approval
,
4884 xmlDocPtr
*response
, xmlChar
**refnumber
) {
4886 isds_error err
= IE_SUCCESS
;
4887 char *service_name_locale
= NULL
, *box_id_locale
= NULL
;
4888 xmlNodePtr request
= NULL
, node
;
4889 xmlNsPtr isds_ns
= NULL
;
4891 if (!context
) return IE_INVALID_CONTEXT
;
4892 if (!service_name
|| !box_id
) return IE_INVAL
;
4893 if (!response
) return IE_INVAL
;
4895 /* Free output argument */
4896 xmlFreeDoc(*response
); *response
= NULL
;
4898 /* Prepare strings */
4899 service_name_locale
= _isds_utf82locale((char*)service_name
);
4900 if (!service_name_locale
) {
4904 box_id_locale
= _isds_utf82locale((char*)box_id
);
4905 if (!box_id_locale
) {
4911 request
= xmlNewNode(NULL
, service_name
);
4913 isds_printf_message(context
,
4914 _("Could not build %s request"), service_name_locale
);
4918 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
4920 isds_log_message(context
, _("Could not create ISDS name space"));
4924 xmlSetNs(request
, isds_ns
);
4926 /* Add XSD:tIdDbInput children */
4927 INSERT_STRING(request
, "dbID", box_id
);
4928 err
= insert_GExtApproval(context
, approval
, request
);
4929 if (err
) goto leave
;
4931 /* Send request and check response*/
4932 err
= send_destroy_request_check_response(context
,
4933 service
, service_name
, &request
, response
, refnumber
);
4936 free(service_name_locale
);
4937 free(box_id_locale
);
4938 xmlFreeNode(request
);
4943 /* Get data about all users assigned to given box.
4944 * @context is session context
4946 * @users is automatically reallocated list of struct isds_DbUserInfo */
4947 isds_error
isds_GetDataBoxUsers(struct isds_ctx
*context
, const char *box_id
,
4948 struct isds_list
**users
) {
4949 isds_error err
= IE_SUCCESS
;
4950 xmlDocPtr response
= NULL
;
4951 xmlXPathContextPtr xpath_ctx
= NULL
;
4952 xmlXPathObjectPtr result
= NULL
;
4954 struct isds_list
*item
, *prev_item
= NULL
;
4956 if (!context
) return IE_INVALID_CONTEXT
;
4957 zfree(context
->long_message
);
4958 if (!users
|| !box_id
) return IE_INVAL
;
4961 /* Do request and check for success */
4962 err
= build_send_dbid_request_check_response(context
,
4963 SERVICE_DB_MANIPULATION
, BAD_CAST
"GetDataBoxUsers",
4964 BAD_CAST box_id
, NULL
, &response
, NULL
);
4965 if (err
) goto leave
;
4969 /* Prepare stucture */
4970 isds_list_free(users
);
4971 xpath_ctx
= xmlXPathNewContext(response
);
4976 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
4981 /* Set context node */
4982 result
= xmlXPathEvalExpression(BAD_CAST
4983 "/isds:GetDataBoxUsersResponse/isds:dbUsers/isds:dbUserInfo",
4989 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
4990 isds_log_message(context
, _("Missing dbUserInfo element"));
4995 /* Iterate over all users */
4996 for (i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
4998 /* Prepare structure */
4999 item
= calloc(1, sizeof(*item
));
5004 item
->destructor
= (void(*)(void**))isds_DbUserInfo_free
;
5005 if (i
== 0) *users
= item
;
5006 else prev_item
->next
= item
;
5010 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
5011 err
= extract_DbUserInfo(context
,
5012 (struct isds_DbUserInfo
**) (&item
->data
), xpath_ctx
);
5013 if (err
) goto leave
;
5018 isds_list_free(users
);
5021 xmlXPathFreeObject(result
);
5022 xmlXPathFreeContext(xpath_ctx
);
5023 xmlFreeDoc(response
);
5026 isds_log(ILF_ISDS
, ILL_DEBUG
,
5027 _("GetDataBoxUsers request processed by server "
5028 "successfully.\n"));
5034 /* Update data about user assigned to given box.
5035 * @context is session context
5036 * @box is box identification
5037 * @old_user identifies user to update
5038 * @new_user are updated data about @old_user
5039 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5040 * NULL, if you don't care.*/
5041 isds_error
isds_UpdateDataBoxUser(struct isds_ctx
*context
,
5042 const struct isds_DbOwnerInfo
*box
,
5043 const struct isds_DbUserInfo
*old_user
,
5044 const struct isds_DbUserInfo
*new_user
,
5046 isds_error err
= IE_SUCCESS
;
5047 xmlNsPtr isds_ns
= NULL
;
5048 xmlNodePtr request
= NULL
;
5052 if (!context
) return IE_INVALID_CONTEXT
;
5053 zfree(context
->long_message
);
5054 if (!box
|| !old_user
|| !new_user
) return IE_INVAL
;
5057 /* Build UpdateDataBoxUser request */
5058 request
= xmlNewNode(NULL
, BAD_CAST
"UpdateDataBoxUser");
5060 isds_log_message(context
,
5061 _("Could build UpdateDataBoxUser request"));
5064 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5066 isds_log_message(context
, _("Could not create ISDS name space"));
5067 xmlFreeNode(request
);
5070 xmlSetNs(request
, isds_ns
);
5072 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5073 err
= insert_DbOwnerInfo(context
, box
, node
);
5074 if (err
) goto leave
;
5076 INSERT_ELEMENT(node
, request
, "dbOldUserInfo");
5077 err
= insert_DbUserInfo(context
, old_user
, node
);
5078 if (err
) goto leave
;
5080 INSERT_ELEMENT(node
, request
, "dbNewUserInfo");
5081 err
= insert_DbUserInfo(context
, new_user
, node
);
5082 if (err
) goto leave
;
5084 /* Send it to server and process response */
5085 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5086 BAD_CAST
"UpdateDataBoxUser", &request
, (xmlChar
**) refnumber
);
5089 xmlFreeNode(request
);
5095 /* Reset credentials of user assigned to given box.
5096 * @context is session context
5097 * @box is box identification
5098 * @user identifies user to reset password
5099 * @fee_paid is true if fee has been paid, false otherwise
5100 * @approval is optional external approval of box manipulation
5101 * @token is NULL if new password should be delivered off-line to the user.
5102 * It is valid pointer if user should obtain new password on-line on dedicated
5103 * web server. Then it output automatically reallocated token user needs to
5104 * use to athtorize on the web server to view his new password.
5105 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5106 * NULL, if you don't care.*/
5107 isds_error
isds_reset_password(struct isds_ctx
*context
,
5108 const struct isds_DbOwnerInfo
*box
,
5109 const struct isds_DbUserInfo
*user
,
5110 const _Bool fee_paid
, const struct isds_approval
*approval
,
5111 char **token
, char **refnumber
) {
5112 isds_error err
= IE_SUCCESS
;
5113 xmlNsPtr isds_ns
= NULL
;
5114 xmlNodePtr request
= NULL
, node
;
5115 xmlDocPtr response
= NULL
;
5116 xmlXPathContextPtr xpath_ctx
= NULL
;
5117 xmlXPathObjectPtr result
= NULL
;
5120 if (!context
) return IE_INVALID_CONTEXT
;
5121 zfree(context
->long_message
);
5122 if (!box
|| !user
) return IE_INVAL
;
5124 if (token
) zfree(*token
);
5127 /* Build NewAccessData request */
5128 request
= xmlNewNode(NULL
, BAD_CAST
"NewAccessData");
5130 isds_log_message(context
,
5131 _("Could build NewAccessData request"));
5134 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5136 isds_log_message(context
, _("Could not create ISDS name space"));
5137 xmlFreeNode(request
);
5140 xmlSetNs(request
, isds_ns
);
5142 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5143 err
= insert_DbOwnerInfo(context
, box
, node
);
5144 if (err
) goto leave
;
5146 INSERT_ELEMENT(node
, request
, "dbUserInfo");
5147 err
= insert_DbUserInfo(context
, user
, node
);
5148 if (err
) goto leave
;
5150 INSERT_SCALAR_BOOLEAN(request
, "dbFeePaid", fee_paid
);
5153 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 1);
5155 INSERT_SCALAR_BOOLEAN(request
, "dbVirtual", 0);
5158 err
= insert_GExtApproval(context
, approval
, request
);
5159 if (err
) goto leave
;
5161 /* Send request and check reposne*/
5162 err
= send_destroy_request_check_response(context
,
5163 SERVICE_DB_MANIPULATION
, BAD_CAST
"NewAccessData", &request
,
5164 &response
, (xmlChar
**) refnumber
);
5165 if (err
) goto leave
;
5168 /* Extract optional token */
5170 xpath_ctx
= xmlXPathNewContext(response
);
5175 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5180 EXTRACT_STRING("/isds:NewAccessDataResponse/dbAccessDataId", *token
);
5184 xmlXPathFreeObject(result
);
5185 xmlXPathFreeContext(xpath_ctx
);
5186 xmlFreeDoc(response
);
5187 xmlFreeNode(request
);
5190 isds_log(ILF_ISDS
, ILL_DEBUG
,
5191 _("NewAccessData request processed by server "
5192 "successfully.\n"));
5198 /* Build ISDS request of XSD tAddDBUserInput type, sent it, check for error
5199 * code, destroy response and log success.
5200 * @context is ISDS session context.
5201 * @service_name is name of SERVICE_DB_MANIPULATION service
5202 * @box is box identification
5203 * @user identifies user to removve
5204 * @approval is optional external approval of box manipulation
5205 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5206 * NULL, if you don't care. */
5207 static isds_error
build_send_manipulationboxuser_request_check_drop_response(
5208 struct isds_ctx
*context
, const xmlChar
*service_name
,
5209 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
5210 const struct isds_approval
*approval
, xmlChar
**refnumber
) {
5211 isds_error err
= IE_SUCCESS
;
5212 xmlNsPtr isds_ns
= NULL
;
5213 xmlNodePtr request
= NULL
, node
;
5216 if (!context
) return IE_INVALID_CONTEXT
;
5217 zfree(context
->long_message
);
5218 if (!service_name
|| service_name
[0] == '\0' || !box
|| !user
)
5222 /* Build NewAccessData request */
5223 request
= xmlNewNode(NULL
, service_name
);
5225 char *service_name_locale
= _isds_utf82locale((char *) service_name
);
5226 isds_printf_message(context
, _("Could build %s request"),
5227 service_name_locale
);
5228 free(service_name_locale
);
5231 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5233 isds_log_message(context
, _("Could not create ISDS name space"));
5234 xmlFreeNode(request
);
5237 xmlSetNs(request
, isds_ns
);
5239 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5240 err
= insert_DbOwnerInfo(context
, box
, node
);
5241 if (err
) goto leave
;
5243 INSERT_ELEMENT(node
, request
, "dbUserInfo");
5244 err
= insert_DbUserInfo(context
, user
, node
);
5245 if (err
) goto leave
;
5247 err
= insert_GExtApproval(context
, approval
, request
);
5248 if (err
) goto leave
;
5250 /* Send request and check reposne*/
5251 err
= send_request_check_drop_response (context
,
5252 SERVICE_DB_MANIPULATION
, service_name
, &request
, refnumber
);
5255 xmlFreeNode(request
);
5260 /* Assign new user to given box.
5261 * @context is session context
5262 * @box is box identification
5263 * @user defines new user to add
5264 * @approval is optional external approval of box manipulation
5265 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5266 * NULL, if you don't care.*/
5267 isds_error
isds_add_user(struct isds_ctx
*context
,
5268 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
5269 const struct isds_approval
*approval
, char **refnumber
) {
5270 return build_send_manipulationboxuser_request_check_drop_response(context
,
5271 BAD_CAST
"AddDataBoxUser", box
, user
, approval
,
5272 (xmlChar
**) refnumber
);
5276 /* Remove user assigned to given box.
5277 * @context is session context
5278 * @box is box identification
5279 * @user identifies user to removve
5280 * @approval is optional external approval of box manipulation
5281 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5282 * NULL, if you don't care.*/
5283 isds_error
isds_delete_user(struct isds_ctx
*context
,
5284 const struct isds_DbOwnerInfo
*box
, const struct isds_DbUserInfo
*user
,
5285 const struct isds_approval
*approval
, char **refnumber
) {
5286 return build_send_manipulationboxuser_request_check_drop_response(context
,
5287 BAD_CAST
"DeleteDataBoxUser", box
, user
, approval
,
5288 (xmlChar
**) refnumber
);
5292 /* Find boxes suiting given criteria.
5293 * @criteria is filter. You should fill in at least some memebers.
5294 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
5295 * possibly empty. Input NULL or valid old structure.
5297 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
5298 * IE_NOEXIST if no such box exists, @boxes will be NULL
5299 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
5300 * contains still valid data
5301 * other code if something bad happens. @boxes will be NULL. */
5302 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
5303 const struct isds_DbOwnerInfo
*criteria
,
5304 struct isds_list
**boxes
) {
5305 isds_error err
= IE_SUCCESS
;
5306 _Bool truncated
= 0;
5307 xmlNsPtr isds_ns
= NULL
;
5308 xmlNodePtr request
= NULL
;
5309 xmlDocPtr response
= NULL
;
5310 xmlChar
*code
= NULL
, *message
= NULL
;
5311 xmlNodePtr db_owner_info
;
5312 xmlXPathContextPtr xpath_ctx
= NULL
;
5313 xmlXPathObjectPtr result
= NULL
;
5314 xmlChar
*string
= NULL
;
5317 if (!context
) return IE_INVALID_CONTEXT
;
5318 zfree(context
->long_message
);
5319 if (!boxes
) return IE_INVAL
;
5320 isds_list_free(boxes
);
5326 /* Check if connection is established
5327 * TODO: This check should be done donwstairs. */
5328 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5331 /* Build FindDataBox request */
5332 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
5334 isds_log_message(context
,
5335 _("Could build FindDataBox request"));
5338 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5340 isds_log_message(context
, _("Could not create ISDS name space"));
5341 xmlFreeNode(request
);
5344 xmlSetNs(request
, isds_ns
);
5345 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
5346 if (!db_owner_info
) {
5347 isds_log_message(context
, _("Could not add dbOwnerInfo child to "
5348 "FindDataBox element"));
5349 xmlFreeNode(request
);
5353 err
= insert_DbOwnerInfo(context
, criteria
, db_owner_info
);
5354 if (err
) goto leave
;
5357 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
5360 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
5362 /* Destroy request */
5363 xmlFreeNode(request
); request
= NULL
;
5366 isds_log(ILF_ISDS
, ILL_DEBUG
,
5367 _("Processing ISDS response on FindDataBox "
5368 "request failed\n"));
5372 /* Check for response status */
5373 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5374 &code
, &message
, NULL
);
5376 isds_log(ILF_ISDS
, ILL_DEBUG
,
5377 _("ISDS response on FindDataBox request is missing status\n"));
5381 /* Request processed, but nothing found */
5382 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
5383 !xmlStrcmp(code
, BAD_CAST
"5001")) {
5384 char *code_locale
= _isds_utf82locale((char*)code
);
5385 char *message_locale
= _isds_utf82locale((char*)message
);
5386 isds_log(ILF_ISDS
, ILL_DEBUG
,
5387 _("Server did not found any box on FindDataBox request "
5388 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5389 isds_log_message(context
, message_locale
);
5391 free(message_locale
);
5396 /* Warning, not a error */
5397 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
5398 char *code_locale
= _isds_utf82locale((char*)code
);
5399 char *message_locale
= _isds_utf82locale((char*)message
);
5400 isds_log(ILF_ISDS
, ILL_DEBUG
,
5401 _("Server truncated response on FindDataBox request "
5402 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5403 isds_log_message(context
, message_locale
);
5405 free(message_locale
);
5410 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5411 char *code_locale
= _isds_utf82locale((char*)code
);
5412 char *message_locale
= _isds_utf82locale((char*)message
);
5413 isds_log(ILF_ISDS
, ILL_DEBUG
,
5414 _("Server refused FindDataBox request "
5415 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5416 isds_log_message(context
, message_locale
);
5418 free(message_locale
);
5423 xpath_ctx
= xmlXPathNewContext(response
);
5428 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5433 /* Extract boxes if they present */
5434 result
= xmlXPathEvalExpression(BAD_CAST
5435 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
5441 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5442 struct isds_list
*item
, *prev_item
= NULL
;
5443 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
5444 item
= calloc(1, sizeof(*item
));
5450 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
5451 if (i
== 0) *boxes
= item
;
5452 else prev_item
->next
= item
;
5455 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
5456 err
= extract_DbOwnerInfo(context
,
5457 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
5458 if (err
) goto leave
;
5464 isds_list_free(boxes
);
5466 if (truncated
) err
= IE_2BIG
;
5470 xmlFreeNode(request
);
5471 xmlXPathFreeObject(result
);
5472 xmlXPathFreeContext(xpath_ctx
);
5476 xmlFreeDoc(response
);
5479 isds_log(ILF_ISDS
, ILL_DEBUG
,
5480 _("FindDataBox request processed by server successfully.\n"));
5486 /* Get status of a box.
5487 * @context is ISDS session context.
5488 * @box_id is UTF-8 encoded box identifier as zero terminated string
5489 * @box_status is return value of box status.
5491 * IE_SUCCESS if box has been found and its status retrieved
5492 * IE_NOEXIST if box is not known to ISDS server
5493 * or other appropriate error.
5494 * You can use isds_DbState to enumerate box status. However out of enum
5495 * range value can be returned too. This is feature because ISDS
5496 * specification leaves the set of values open.
5497 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
5498 * the box has been deleted, but ISDS still lists its former existence. */
5499 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
5500 long int *box_status
) {
5501 isds_error err
= IE_SUCCESS
;
5502 xmlNsPtr isds_ns
= NULL
;
5503 xmlNodePtr request
= NULL
, db_id
;
5504 xmlDocPtr response
= NULL
;
5505 xmlChar
*code
= NULL
, *message
= NULL
;
5506 xmlXPathContextPtr xpath_ctx
= NULL
;
5507 xmlXPathObjectPtr result
= NULL
;
5508 xmlChar
*string
= NULL
;
5510 if (!context
) return IE_INVALID_CONTEXT
;
5511 zfree(context
->long_message
);
5512 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
5514 /* Check if connection is established
5515 * TODO: This check should be done donwstairs. */
5516 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5519 /* Build CheckDataBox request */
5520 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
5522 isds_log_message(context
,
5523 _("Could build CheckDataBox request"));
5526 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5528 isds_log_message(context
, _("Could not create ISDS name space"));
5529 xmlFreeNode(request
);
5532 xmlSetNs(request
, isds_ns
);
5533 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
5535 isds_log_message(context
, _("Could not add dbID child to "
5536 "CheckDataBox element"));
5537 xmlFreeNode(request
);
5542 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
5545 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
, NULL
, NULL
);
5547 /* Destroy request */
5548 xmlFreeNode(request
);
5551 isds_log(ILF_ISDS
, ILL_DEBUG
,
5552 _("Processing ISDS response on CheckDataBox "
5553 "request failed\n"));
5557 /* Check for response status */
5558 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
5559 &code
, &message
, NULL
);
5561 isds_log(ILF_ISDS
, ILL_DEBUG
,
5562 _("ISDS response on CheckDataBox request is missing status\n"));
5566 /* Request processed, but nothing found */
5567 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
5568 char *box_id_locale
= _isds_utf82locale((char*)box_id
);
5569 char *code_locale
= _isds_utf82locale((char*)code
);
5570 char *message_locale
= _isds_utf82locale((char*)message
);
5571 isds_log(ILF_ISDS
, ILL_DEBUG
,
5572 _("Server did not found box %s on CheckDataBox request "
5573 "(code=%s, message=%s)\n"),
5574 box_id_locale
, code_locale
, message_locale
);
5575 isds_log_message(context
, message_locale
);
5576 free(box_id_locale
);
5578 free(message_locale
);
5584 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
5585 char *code_locale
= _isds_utf82locale((char*)code
);
5586 char *message_locale
= _isds_utf82locale((char*)message
);
5587 isds_log(ILF_ISDS
, ILL_DEBUG
,
5588 _("Server refused CheckDataBox request "
5589 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
5590 isds_log_message(context
, message_locale
);
5592 free(message_locale
);
5598 xpath_ctx
= xmlXPathNewContext(response
);
5603 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
5607 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
5613 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
5614 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
5618 if (result
->nodesetval
->nodeNr
> 1) {
5619 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
5623 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
5624 xmlXPathFreeObject(result
); result
= NULL
;
5626 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
5631 xmlXPathFreeObject(result
);
5632 xmlXPathFreeContext(xpath_ctx
);
5636 xmlFreeDoc(response
);
5639 isds_log(ILF_ISDS
, ILL_DEBUG
,
5640 _("CheckDataBox request processed by server successfully.\n"));
5646 /* Build ISDS request of XSD tIdDbInput type, sent it, check for error
5647 * code, destroy response and log success.
5648 * @context is ISDS session context.
5649 * @service_name is name of SERVICE_DB_MANIPULATION service
5650 * @box_id is UTF-8 encoded box identifier as zero terminated string
5651 * @approval is optional external approval of box manipulation
5652 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5653 * NULL, if you don't care. */
5654 static isds_error
build_send_manipulationdbid_request_check_drop_response(
5655 struct isds_ctx
*context
, const xmlChar
*service_name
,
5656 const xmlChar
*box_id
, const struct isds_approval
*approval
,
5657 xmlChar
**refnumber
) {
5658 isds_error err
= IE_SUCCESS
;
5659 xmlDocPtr response
= NULL
;
5661 if (!context
) return IE_INVALID_CONTEXT
;
5662 zfree(context
->long_message
);
5663 if (!service_name
|| *service_name
== '\0' || !box_id
) return IE_INVAL
;
5665 /* Check if connection is established */
5666 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
5668 /* Do request and check for success */
5669 err
= build_send_dbid_request_check_response(context
,
5670 SERVICE_DB_MANIPULATION
, service_name
, box_id
, approval
,
5671 &response
, refnumber
);
5672 xmlFreeDoc(response
);
5675 char *service_name_locale
= _isds_utf82locale((char *) service_name
);
5676 isds_log(ILF_ISDS
, ILL_DEBUG
,
5677 _("%s request processed by server successfully.\n"),
5678 service_name_locale
);
5679 free(service_name_locale
);
5686 /* Switch box into state where box can receive commercial messages (off by
5688 * @context is ISDS session context.
5689 * @box_id is UTF-8 encoded box identifier as zero terminated string
5690 * @allow is true for enable, false for disable commercial messages income
5691 * @approval is optional external approval of box manipulation
5692 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5693 * NULL, if you don't care. */
5694 isds_error
isds_switch_commercial_receiving(struct isds_ctx
*context
,
5695 const char *box_id
, const _Bool allow
,
5696 const struct isds_approval
*approval
, char **refnumber
) {
5697 return build_send_manipulationdbid_request_check_drop_response(context
,
5698 (allow
) ? BAD_CAST
"SetOpenAddressing" :
5699 BAD_CAST
"ClearOpenAddressing",
5700 BAD_CAST box_id
, approval
, (xmlChar
**) refnumber
);
5704 /* Switch box into / out of state where non-OVM box can act as OVM (e.g. force
5705 * message acceptance). This is just a box permission. Sender must apply
5706 * such role by sending each message.
5707 * @context is ISDS session context.
5708 * @box_id is UTF-8 encoded box identifier as zero terminated string
5709 * @allow is true for enable, false for disable OVM role permission
5710 * @approval is optional external approval of box manipulation
5711 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5712 * NULL, if you don't care. */
5713 isds_error
isds_switch_effective_ovm(struct isds_ctx
*context
,
5714 const char *box_id
, const _Bool allow
,
5715 const struct isds_approval
*approval
, char **refnumber
) {
5716 return build_send_manipulationdbid_request_check_drop_response(context
,
5717 (allow
) ? BAD_CAST
"SetEffectiveOVM" :
5718 BAD_CAST
"ClearEffectiveOVM",
5719 BAD_CAST box_id
, approval
, (xmlChar
**) refnumber
);
5723 /* Build ISDS request of XSD tOwnerInfoInput type, sent it, check for error
5724 * code, destroy response and log success.
5725 * @context is ISDS session context.
5726 * @service_name is name of SERVICE_DB_MANIPULATION service
5727 * @owner is structure describing box
5728 * @approval is optional external approval of box manipulation
5729 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5730 * NULL, if you don't care. */
5731 static isds_error
build_send_manipulationdbowner_request_check_drop_response(
5732 struct isds_ctx
*context
, const xmlChar
*service_name
,
5733 const struct isds_DbOwnerInfo
*owner
,
5734 const struct isds_approval
*approval
, xmlChar
**refnumber
) {
5735 isds_error err
= IE_SUCCESS
;
5736 char *service_name_locale
= NULL
;
5737 xmlNodePtr request
= NULL
, db_owner_info
;
5738 xmlNsPtr isds_ns
= NULL
;
5741 if (!context
) return IE_INVALID_CONTEXT
;
5742 zfree(context
->long_message
);
5743 if (!service_name
|| *service_name
== '\0' || !owner
) return IE_INVAL
;
5745 service_name_locale
= _isds_utf82locale((char*)service_name
);
5746 if (!service_name_locale
) {
5752 request
= xmlNewNode(NULL
, service_name
);
5754 isds_printf_message(context
,
5755 _("Could not build %s request"), service_name_locale
);
5759 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5761 isds_log_message(context
, _("Could not create ISDS name space"));
5765 xmlSetNs(request
, isds_ns
);
5768 /* Add XSD:tOwnerInfoInput child*/
5769 INSERT_ELEMENT(db_owner_info
, request
, "dbOwnerInfo");
5770 err
= insert_DbOwnerInfo(context
, owner
, db_owner_info
);
5771 if (err
) goto leave
;
5773 /* Add XSD:gExtApproval*/
5774 err
= insert_GExtApproval(context
, approval
, request
);
5775 if (err
) goto leave
;
5777 /* Send it to server and process response */
5778 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5779 service_name
, &request
, refnumber
);
5782 xmlFreeNode(request
);
5783 free(service_name_locale
);
5789 /* Switch box accessibility state on request of box owner.
5790 * Despite the name, owner must do the request off-line. This function is
5791 * designed for such off-line meeting points (e.g. Czech POINT).
5792 * @context is ISDS session context.
5793 * @box identifies box to swith accesibilty state.
5794 * @allow is true for making accesibale, false to disallow access.
5795 * @approval is optional external approval of box manipulation
5796 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5797 * NULL, if you don't care. */
5798 isds_error
isds_switch_box_accessibility_on_owner_request(
5799 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5800 const _Bool allow
, const struct isds_approval
*approval
,
5802 return build_send_manipulationdbowner_request_check_drop_response(context
,
5803 (allow
) ? BAD_CAST
"EnableOwnDataBox" :
5804 BAD_CAST
"DisableOwnDataBox",
5805 box
, approval
, (xmlChar
**) refnumber
);
5809 /* Disable box accessibility on law enforcement (e.g. by prison) since exact
5811 * @context is ISDS session context.
5812 * @box identifies box to swith accesibilty state.
5813 * @since is date since accesseibility has been denied. This can be past too.
5814 * Only tm_year, tm_mon and tm_mday carry sane value.
5815 * @approval is optional external approval of box manipulation
5816 * @refnumber is reallocated serial number of request assigned by ISDS. Use
5817 * NULL, if you don't care. */
5818 isds_error
isds_disable_box_accessibility_externaly(
5819 struct isds_ctx
*context
, const struct isds_DbOwnerInfo
*box
,
5820 const struct tm
*since
, const struct isds_approval
*approval
,
5822 isds_error err
= IE_SUCCESS
;
5823 char *service_name_locale
= NULL
;
5824 xmlNodePtr request
= NULL
, node
;
5825 xmlNsPtr isds_ns
= NULL
;
5826 xmlChar
*string
= NULL
;
5829 if (!context
) return IE_INVALID_CONTEXT
;
5830 zfree(context
->long_message
);
5831 if (!box
|| !since
) return IE_INVAL
;
5834 request
= xmlNewNode(NULL
, BAD_CAST
"DisableDataBoxExternally");
5836 isds_printf_message(context
,
5837 _("Could not build %s request"), "DisableDataBoxExternally");
5841 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
5843 isds_log_message(context
, _("Could not create ISDS name space"));
5847 xmlSetNs(request
, isds_ns
);
5850 /* Add @box identification */
5851 INSERT_ELEMENT(node
, request
, "dbOwnerInfo");
5852 err
= insert_DbOwnerInfo(context
, box
, node
);
5853 if (err
) goto leave
;
5855 /* Add @since date */
5856 err
= tm2datestring(since
, &string
);
5858 isds_log_message(context
,
5859 _("Could not convert `since' argument to ISO date string"));
5862 INSERT_STRING(request
, "dbOwnerDisableDate", string
);
5866 err
= insert_GExtApproval(context
, approval
, request
);
5867 if (err
) goto leave
;
5869 /* Send it to server and process response */
5870 err
= send_request_check_drop_response(context
, SERVICE_DB_MANIPULATION
,
5871 BAD_CAST
"DisableDataBoxExternally", &request
,
5872 (xmlChar
**) refnumber
);
5876 xmlFreeNode(request
);
5877 free(service_name_locale
);
5883 /* Insert struct isds_message data (envelope (recipient data optional) and
5884 * documents) into XML tree
5885 * @context is sesstion context
5886 * @outgoing_message is libsids structure with message data
5887 * @create_message is XML CreateMessage or CreateMultipleMessage element
5888 * @process_recipient true for recipient data serialization, false for no
5890 static isds_error
insert_envelope_files(struct isds_ctx
*context
,
5891 const struct isds_message
*outgoing_message
, xmlNodePtr create_message
,
5892 const _Bool process_recipient
) {
5894 isds_error err
= IE_SUCCESS
;
5895 xmlNodePtr envelope
, dm_files
, node
;
5896 xmlChar
*string
= NULL
;
5898 if (!context
) return IE_INVALID_CONTEXT
;
5899 if (!outgoing_message
|| !create_message
) return IE_INVAL
;
5902 /* Build envelope */
5903 envelope
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
5905 isds_printf_message(context
, _("Could not add dmEnvelope child to "
5906 "%s element"), create_message
->name
);
5910 if (!outgoing_message
->envelope
) {
5911 isds_log_message(context
, _("Outgoing message is missing envelope"));
5916 INSERT_STRING(envelope
, "dmSenderOrgUnit",
5917 outgoing_message
->envelope
->dmSenderOrgUnit
);
5918 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
5919 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
5921 if (process_recipient
) {
5922 if (!outgoing_message
->envelope
->dbIDRecipient
) {
5923 isds_log_message(context
,
5924 _("Outgoing message is missing recipient box identifier"));
5928 INSERT_STRING(envelope
, "dbIDRecipient",
5929 outgoing_message
->envelope
->dbIDRecipient
);
5931 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
5932 outgoing_message
->envelope
->dmRecipientOrgUnit
);
5933 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
5934 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
5935 INSERT_STRING(envelope
, "dmToHands",
5936 outgoing_message
->envelope
->dmToHands
);
5939 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 0, 255,
5941 INSERT_STRING(envelope
, "dmAnnotation",
5942 outgoing_message
->envelope
->dmAnnotation
);
5944 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
5945 0, 50, "dmRecipientRefNumber");
5946 INSERT_STRING(envelope
, "dmRecipientRefNumber",
5947 outgoing_message
->envelope
->dmRecipientRefNumber
);
5949 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
5950 0, 50, "dmSenderRefNumber");
5951 INSERT_STRING(envelope
, "dmSenderRefNumber",
5952 outgoing_message
->envelope
->dmSenderRefNumber
);
5954 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
5955 0, 50, "dmRecipientIdent");
5956 INSERT_STRING(envelope
, "dmRecipientIdent",
5957 outgoing_message
->envelope
->dmRecipientIdent
);
5959 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
5960 0, 50, "dmSenderIdent");
5961 INSERT_STRING(envelope
, "dmSenderIdent",
5962 outgoing_message
->envelope
->dmSenderIdent
);
5964 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
5965 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
5966 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
5967 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
5968 INSERT_STRING(envelope
, "dmLegalTitleSect",
5969 outgoing_message
->envelope
->dmLegalTitleSect
);
5970 INSERT_STRING(envelope
, "dmLegalTitlePar",
5971 outgoing_message
->envelope
->dmLegalTitlePar
);
5972 INSERT_STRING(envelope
, "dmLegalTitlePoint",
5973 outgoing_message
->envelope
->dmLegalTitlePoint
);
5975 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
5976 outgoing_message
->envelope
->dmPersonalDelivery
);
5977 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
5978 outgoing_message
->envelope
->dmAllowSubstDelivery
);
5980 /* ???: Should we require value for dbEffectiveOVM sender?
5981 * ISDS has default as true */
5982 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
5985 /* Append dmFiles */
5986 if (!outgoing_message
->documents
) {
5987 isds_log_message(context
,
5988 _("Outgoing message is missing list of documents"));
5992 dm_files
= xmlNewChild(create_message
, NULL
, BAD_CAST
"dmFiles", NULL
);
5994 isds_printf_message(context
, _("Could not add dmFiles child to "
5995 "%s element"), create_message
->name
);
6000 /* Check for document hieararchy */
6001 err
= _isds_check_documents_hierarchy(context
, outgoing_message
->documents
);
6002 if (err
) goto leave
;
6004 /* Process each document */
6005 for (struct isds_list
*item
=
6006 (struct isds_list
*) outgoing_message
->documents
;
6007 item
; item
= item
->next
) {
6009 isds_log_message(context
,
6010 _("List of documents contains empty item"));
6014 /* FIXME: Check for dmFileMetaType and for document references.
6015 * Only first document can be of MAIN type */
6016 err
= insert_document(context
, (struct isds_document
*) item
->data
,
6019 if (err
) goto leave
;
6028 /* Send a message via ISDS to a recipent
6029 * @context is session context
6030 * @outgoing_message is message to send; Some memebers are mandatory (like
6031 * dbIDRecipient), some are optional and some are irrelevant (especialy data
6032 * about sender). Included pointer to isds_list documents must contain at
6033 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
6034 * members will be filled with valid data from ISDS. Exact list of write
6035 * members is subject to change. Currently dmId is changed.
6036 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
6037 isds_error
isds_send_message(struct isds_ctx
*context
,
6038 struct isds_message
*outgoing_message
) {
6040 isds_error err
= IE_SUCCESS
;
6041 xmlNsPtr isds_ns
= NULL
;
6042 xmlNodePtr request
= NULL
;
6043 xmlDocPtr response
= NULL
;
6044 xmlChar
*code
= NULL
, *message
= NULL
;
6045 xmlXPathContextPtr xpath_ctx
= NULL
;
6046 xmlXPathObjectPtr result
= NULL
;
6047 _Bool message_is_complete
= 0;
6049 if (!context
) return IE_INVALID_CONTEXT
;
6050 zfree(context
->long_message
);
6051 if (!outgoing_message
) return IE_INVAL
;
6053 /* Check if connection is established
6054 * TODO: This check should be done donwstairs. */
6055 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6058 /* Build CreateMessage request */
6059 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
6061 isds_log_message(context
,
6062 _("Could build CreateMessage request"));
6065 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6067 isds_log_message(context
, _("Could not create ISDS name space"));
6068 xmlFreeNode(request
);
6071 xmlSetNs(request
, isds_ns
);
6073 /* Append envelope and files */
6074 err
= insert_envelope_files(context
, outgoing_message
, request
, 1);
6075 if (err
) goto leave
;
6078 /* Signal we can serilize message since now */
6079 message_is_complete
= 1;
6082 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
6085 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
6087 /* Dont' destroy request, we want to provide it to application later */
6090 isds_log(ILF_ISDS
, ILL_DEBUG
,
6091 _("Processing ISDS response on CreateMessage "
6092 "request failed\n"));
6096 /* Check for response status */
6097 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
6098 &code
, &message
, NULL
);
6100 isds_log(ILF_ISDS
, ILL_DEBUG
,
6101 _("ISDS response on CreateMessage request "
6102 "is missing status\n"));
6106 /* Request processed, but refused by server or server failed */
6107 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6108 char *box_id_locale
=
6109 _isds_utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
6110 char *code_locale
= _isds_utf82locale((char*)code
);
6111 char *message_locale
= _isds_utf82locale((char*)message
);
6112 isds_log(ILF_ISDS
, ILL_DEBUG
,
6113 _("Server did not accept message for %s on CreateMessage "
6114 "request (code=%s, message=%s)\n"),
6115 box_id_locale
, code_locale
, message_locale
);
6116 isds_log_message(context
, message_locale
);
6117 free(box_id_locale
);
6119 free(message_locale
);
6126 xpath_ctx
= xmlXPathNewContext(response
);
6131 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6135 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
6141 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6142 isds_log_message(context
, _("Missing CreateMessageResponse element"));
6146 if (result
->nodesetval
->nodeNr
> 1) {
6147 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
6151 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6152 xmlXPathFreeObject(result
); result
= NULL
;
6154 if (outgoing_message
->envelope
->dmID
) {
6155 free(outgoing_message
->envelope
->dmID
);
6156 outgoing_message
->envelope
->dmID
= NULL
;
6158 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
6159 if (!outgoing_message
->envelope
->dmID
) {
6160 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
6161 "but did not return assigned message ID\n"));
6165 /* TODO: Serialize message into structure member raw */
6166 /* XXX: Each web service transport message in different format.
6167 * Therefore it's not possible to save them directly.
6168 * To save them, one must figure out common format.
6169 * We can leave it on application, or we can implement the ESS format. */
6170 /*if (message_is_complete) {
6171 if (outgoing_message->envelope->dmID) {
6173 /* Add assigned message ID as first child*/
6174 /*xmlNodePtr dmid_text = xmlNewText(
6175 (xmlChar *) outgoing_message->envelope->dmID);
6176 if (!dmid_text) goto serialization_failed;
6178 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
6180 if (!dmid_element) {
6181 xmlFreeNode(dmid_text);
6182 goto serialization_failed;
6185 xmlNodePtr dmid_element_with_text =
6186 xmlAddChild(dmid_element, dmid_text);
6187 if (!dmid_element_with_text) {
6188 xmlFreeNode(dmid_element);
6189 xmlFreeNode(dmid_text);
6190 goto serialization_failed;
6193 node = xmlAddPrevSibling(envelope->childern,
6194 dmid_element_with_text);
6196 xmlFreeNodeList(dmid_element_with_text);
6197 goto serialization_failed;
6201 /* Serialize message with ID into raw */
6202 /*buffer = serialize_element(envelope)*/
6205 serialization_failed:
6210 xmlXPathFreeObject(result
);
6211 xmlXPathFreeContext(xpath_ctx
);
6215 xmlFreeDoc(response
);
6216 xmlFreeNode(request
);
6219 isds_log(ILF_ISDS
, ILL_DEBUG
,
6220 _("CreateMessage request processed by server "
6221 "successfully.\n"));
6227 /* Send a message via ISDS to a multiple recipents
6228 * @context is session context
6229 * @outgoing_message is message to send; Some memebers are mandatory,
6230 * some are optional and some are irrelevant (especialy data
6231 * about sender). Data about recipient will be substituted by ISDS from
6232 * @copies. Included pointer to isds_list documents must
6233 * contain at least one document of FILEMETATYPE_MAIN.
6234 * @copies is list of isds_message_copy structures addressing all desired
6235 * recipients. This is read-write structure, some members will be filled with
6236 * valid data from ISDS (message IDs, error codes, error descriptions).
6238 * ISDS_SUCCESS if all messages have been sent
6239 * ISDS_PARTIAL_SUCCESS if sending of some messages has failed (failed and
6240 * succesed messages can be identified by copies->data->error),
6241 * or other error code if something other goes wrong. */
6242 isds_error
isds_send_message_to_multiple_recipients(struct isds_ctx
*context
,
6243 const struct isds_message
*outgoing_message
,
6244 struct isds_list
*copies
) {
6246 isds_error err
= IE_SUCCESS
, append_err
;
6247 xmlNsPtr isds_ns
= NULL
;
6248 xmlNodePtr request
= NULL
, recipients
, recipient
, node
;
6249 struct isds_list
*item
;
6250 struct isds_message_copy
*copy
;
6251 xmlDocPtr response
= NULL
;
6252 xmlChar
*code
= NULL
, *message
= NULL
;
6253 xmlXPathContextPtr xpath_ctx
= NULL
;
6254 xmlXPathObjectPtr result
= NULL
;
6255 xmlChar
*string
= NULL
;
6258 if (!context
) return IE_INVALID_CONTEXT
;
6259 zfree(context
->long_message
);
6260 if (!outgoing_message
|| !copies
) return IE_INVAL
;
6262 /* Check if connection is established
6263 * TODO: This check should be done donwstairs. */
6264 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6267 /* Build CreateMultipleMessage request */
6268 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMultipleMessage");
6270 isds_log_message(context
,
6271 _("Could not build CreateMultipleMessage request"));
6274 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6276 isds_log_message(context
, _("Could not create ISDS name space"));
6277 xmlFreeNode(request
);
6280 xmlSetNs(request
, isds_ns
);
6283 /* Build recipients */
6284 recipients
= xmlNewChild(request
, NULL
, BAD_CAST
"dmRecipients", NULL
);
6286 isds_log_message(context
, _("Could not add dmRecipients child to "
6287 "CreateMultipleMessage element"));
6288 xmlFreeNode(request
);
6292 /* Insert each recipient */
6293 for (item
= copies
; item
; item
= item
->next
) {
6294 copy
= (struct isds_message_copy
*) item
->data
;
6296 isds_log_message(context
,
6297 _("`copies' list item contains empty data"));
6302 recipient
= xmlNewChild(recipients
, NULL
, BAD_CAST
"dmRecipient", NULL
);
6304 isds_log_message(context
, _("Could not add dmRecipient child to "
6305 "dmRecipients element"));
6310 if (!copy
->dbIDRecipient
) {
6311 isds_log_message(context
,
6312 _("Message copy is missing recipient box identifier"));
6316 INSERT_STRING(recipient
, "dbIDRecipient", copy
->dbIDRecipient
);
6317 INSERT_STRING(recipient
, "dmRecipientOrgUnit",
6318 copy
->dmRecipientOrgUnit
);
6319 INSERT_LONGINT(recipient
, "dmRecipientOrgUnitNum",
6320 copy
->dmRecipientOrgUnitNum
, string
);
6321 INSERT_STRING(recipient
, "dmToHands", copy
->dmToHands
);
6324 /* Append envelope and files */
6325 err
= insert_envelope_files(context
, outgoing_message
, request
, 0);
6326 if (err
) goto leave
;
6329 isds_log(ILF_ISDS
, ILL_DEBUG
,
6330 _("Sending CreateMultipleMessage request to ISDS\n"));
6333 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
, NULL
, NULL
);
6335 isds_log(ILF_ISDS
, ILL_DEBUG
,
6336 _("Processing ISDS response on CreateMultipleMessage "
6337 "request failed\n"));
6341 /* Check for response status */
6342 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
6343 &code
, &message
, NULL
);
6345 isds_log(ILF_ISDS
, ILL_DEBUG
,
6346 _("ISDS response on CreateMultipleMessage request "
6347 "is missing status\n"));
6351 /* Request processed, but some copies failed */
6352 if (!xmlStrcmp(code
, BAD_CAST
"0004")) {
6353 char *box_id_locale
=
6354 _isds_utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
6355 char *code_locale
= _isds_utf82locale((char*)code
);
6356 char *message_locale
= _isds_utf82locale((char*)message
);
6357 isds_log(ILF_ISDS
, ILL_DEBUG
,
6358 _("Server did accept message for multiple recipients "
6359 "on CreateMultipleMessage request but delivery to "
6360 "some of them failed (code=%s, message=%s)\n"),
6361 box_id_locale
, code_locale
, message_locale
);
6362 isds_log_message(context
, message_locale
);
6363 free(box_id_locale
);
6365 free(message_locale
);
6366 err
= IE_PARTIAL_SUCCESS
;
6369 /* Request refused by server as whole */
6370 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6371 char *box_id_locale
=
6372 _isds_utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
6373 char *code_locale
= _isds_utf82locale((char*)code
);
6374 char *message_locale
= _isds_utf82locale((char*)message
);
6375 isds_log(ILF_ISDS
, ILL_DEBUG
,
6376 _("Server did not accept message for multiple recipients "
6377 "on CreateMultipleMessage request (code=%s, message=%s)\n"),
6378 box_id_locale
, code_locale
, message_locale
);
6379 isds_log_message(context
, message_locale
);
6380 free(box_id_locale
);
6382 free(message_locale
);
6389 xpath_ctx
= xmlXPathNewContext(response
);
6394 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6398 result
= xmlXPathEvalExpression(
6399 BAD_CAST
"/isds:CreateMultipleMessageResponse"
6400 "/isds:dmMultipleStatus/isds:dmSingleStatus",
6406 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6407 isds_log_message(context
, _("Missing isds:dmSingleStatus element"));
6412 /* Extract message ID and delivery status for each copy */
6413 for (item
= copies
, i
= 0; item
&& i
< result
->nodesetval
->nodeNr
;
6414 item
= item
->next
, i
++) {
6415 copy
= (struct isds_message_copy
*) item
->data
;
6416 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
6418 append_err
= append_TMStatus(context
, copy
, xpath_ctx
);
6424 if (item
|| i
< result
->nodesetval
->nodeNr
) {
6425 isds_printf_message(context
, _("ISDS returned unexpected number of "
6426 "message copy delivery states: %d"),
6427 result
->nodesetval
->nodeNr
);
6436 xmlXPathFreeObject(result
);
6437 xmlXPathFreeContext(xpath_ctx
);
6441 xmlFreeDoc(response
);
6442 xmlFreeNode(request
);
6445 isds_log(ILF_ISDS
, ILL_DEBUG
,
6446 _("CreateMultipleMessageResponse request processed by server "
6447 "successfully.\n"));
6453 /* Get list of messages. This is common core for getting sent or received
6455 * Any criterion argument can be NULL, if you don't care about it.
6456 * @context is session context. Must not be NULL.
6457 * @outgoing_direction is true if you want list of outgoing messages,
6458 * it's false if you want incoming messages.
6459 * @from_time is minimal time and date of message sending inclusive.
6460 * @to_time is maximal time and date of message sending inclusive
6461 * @organization_unit_number is number of sender/recipient respectively.
6462 * @status_filter is bit field of isds_message_status values. Use special
6463 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6464 * all values, you can use bitwise arithmetic if you want.)
6465 * @offset is index of first message we are interested in. First message is 1.
6466 * Set to 0 (or 1) if you don't care.
6467 * @number is maximal length of list you want to get as input value, outputs
6468 * number of messages matching these criteria. Can be NULL if you don't care
6469 * (applies to output value either).
6470 * @messages is automatically reallocated list of isds_message's. Be ware that
6471 * it returns only brief overview (envelope and some other fields) about each
6472 * message, not the complete message. FIXME: Specify exact fields.
6473 * The list is sorted by delivery time in ascending order.
6475 * you don't care about don't need the data (useful if you want to know only
6476 * the @number). If you provide &NULL, list will be allocated on heap, if you
6477 * provide pointer to non-NULL, list will be freed automacally at first. Also
6478 * in case of error the list will be NULLed.
6479 * @return IE_SUCCESS or appropriate error code. */
6480 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
6481 _Bool outgoing_direction
,
6482 const struct timeval
*from_time
, const struct timeval
*to_time
,
6483 const long int *organization_unit_number
,
6484 const unsigned int status_filter
,
6485 const unsigned long int offset
, unsigned long int *number
,
6486 struct isds_list
**messages
) {
6488 isds_error err
= IE_SUCCESS
;
6489 xmlNsPtr isds_ns
= NULL
;
6490 xmlNodePtr request
= NULL
, node
;
6491 xmlDocPtr response
= NULL
;
6492 xmlChar
*code
= NULL
, *message
= NULL
;
6493 xmlXPathContextPtr xpath_ctx
= NULL
;
6494 xmlXPathObjectPtr result
= NULL
;
6495 xmlChar
*string
= NULL
;
6496 long unsigned int count
= 0;
6498 if (!context
) return IE_INVALID_CONTEXT
;
6499 zfree(context
->long_message
);
6501 /* Free former message list if any */
6502 if (messages
) isds_list_free(messages
);
6504 /* Check if connection is established
6505 * TODO: This check should be done donwstairs. */
6506 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6508 /* Build GetListOf*Messages request */
6509 request
= xmlNewNode(NULL
,
6510 (outgoing_direction
) ?
6511 BAD_CAST
"GetListOfSentMessages" :
6512 BAD_CAST
"GetListOfReceivedMessages"
6515 isds_log_message(context
,
6516 (outgoing_direction
) ?
6517 _("Could not build GetListOfSentMessages request") :
6518 _("Could not build GetListOfReceivedMessages request")
6522 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6524 isds_log_message(context
, _("Could not create ISDS name space"));
6525 xmlFreeNode(request
);
6528 xmlSetNs(request
, isds_ns
);
6532 err
= timeval2timestring(from_time
, &string
);
6533 if (err
) goto leave
;
6535 INSERT_STRING(request
, "dmFromTime", string
);
6536 free(string
); string
= NULL
;
6539 err
= timeval2timestring(to_time
, &string
);
6540 if (err
) goto leave
;
6542 INSERT_STRING(request
, "dmToTime", string
);
6543 free(string
); string
= NULL
;
6545 if (outgoing_direction
) {
6546 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
6547 organization_unit_number
, string
);
6549 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
6550 organization_unit_number
, string
);
6553 if (status_filter
> MESSAGESTATE_ANY
) {
6554 isds_printf_message(context
,
6555 _("Invalid message state filter value: %ld"), status_filter
);
6559 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
6562 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
6564 INSERT_STRING(request
, "dmOffset", "1");
6567 /* number 0 means no limit */
6568 if (number
&& *number
== 0) {
6569 INSERT_STRING(request
, "dmLimit", NULL
);
6571 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
6575 isds_log(ILF_ISDS
, ILL_DEBUG
,
6576 (outgoing_direction
) ?
6577 _("Sending GetListOfSentMessages request to ISDS\n") :
6578 _("Sending GetListOfReceivedMessages request to ISDS\n")
6582 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
, NULL
, NULL
);
6583 xmlFreeNode(request
); request
= NULL
;
6586 isds_log(ILF_ISDS
, ILL_DEBUG
,
6587 (outgoing_direction
) ?
6588 _("Processing ISDS response on GetListOfSentMessages "
6589 "request failed\n") :
6590 _("Processing ISDS response on GetListOfReceivedMessages "
6596 /* Check for response status */
6597 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
6598 &code
, &message
, NULL
);
6600 isds_log(ILF_ISDS
, ILL_DEBUG
,
6601 (outgoing_direction
) ?
6602 _("ISDS response on GetListOfSentMessages request "
6603 "is missing status\n") :
6604 _("ISDS response on GetListOfReceivedMessages request "
6605 "is missing status\n")
6610 /* Request processed, but nothing found */
6611 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
6612 char *code_locale
= _isds_utf82locale((char*)code
);
6613 char *message_locale
= _isds_utf82locale((char*)message
);
6614 isds_log(ILF_ISDS
, ILL_DEBUG
,
6615 (outgoing_direction
) ?
6616 _("Server refused GetListOfSentMessages request "
6617 "(code=%s, message=%s)\n") :
6618 _("Server refused GetListOfReceivedMessages request "
6619 "(code=%s, message=%s)\n"),
6620 code_locale
, message_locale
);
6621 isds_log_message(context
, message_locale
);
6623 free(message_locale
);
6630 xpath_ctx
= xmlXPathNewContext(response
);
6635 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6639 result
= xmlXPathEvalExpression(
6640 (outgoing_direction
) ?
6641 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
6642 "isds:dmRecords/isds:dmRecord" :
6643 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
6644 "isds:dmRecords/isds:dmRecord",
6651 /* Fill output arguments in */
6652 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6653 struct isds_envelope
*envelope
;
6654 struct isds_list
*item
= NULL
, *last_item
= NULL
;
6656 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
6657 /* Create new message */
6658 item
= calloc(1, sizeof(*item
));
6663 item
->destructor
= (void(*)(void**)) &isds_message_free
;
6664 item
->data
= calloc(1, sizeof(struct isds_message
));
6666 isds_list_free(&item
);
6671 /* Extract envelope data */
6672 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
6674 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
6676 isds_list_free(&item
);
6680 /* Attach extracted envelope */
6681 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
6683 /* Append new message into the list */
6685 *messages
= last_item
= item
;
6687 last_item
->next
= item
;
6692 if (number
) *number
= count
;
6696 isds_list_free(messages
);
6700 xmlXPathFreeObject(result
);
6701 xmlXPathFreeContext(xpath_ctx
);
6705 xmlFreeDoc(response
);
6706 xmlFreeNode(request
);
6709 isds_log(ILF_ISDS
, ILL_DEBUG
,
6710 (outgoing_direction
) ?
6711 _("GetListOfSentMessages request processed by server "
6712 "successfully.\n") :
6713 _("GetListOfReceivedMessages request processed by server "
6720 /* Get list of outgoing (already sent) messages.
6721 * Any criterion argument can be NULL, if you don't care about it.
6722 * @context is session context. Must not be NULL.
6723 * @from_time is minimal time and date of message sending inclusive.
6724 * @to_time is maximal time and date of message sending inclusive
6725 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
6726 * @status_filter is bit field of isds_message_status values. Use special
6727 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6728 * all values, you can use bitwise arithmetic if you want.)
6729 * @offset is index of first message we are interested in. First message is 1.
6730 * Set to 0 (or 1) if you don't care.
6731 * @number is maximal length of list you want to get as input value, outputs
6732 * number of messages matching these criteria. Can be NULL if you don't care
6733 * (applies to output value either).
6734 * @messages is automatically reallocated list of isds_message's. Be ware that
6735 * it returns only brief overview (envelope and some other fields) about each
6736 * message, not the complete message. FIXME: Specify exact fields.
6737 * The list is sorted by delivery time in ascending order.
6738 * Use NULL if you don't care about the metadata (useful if you want to know
6739 * only the @number). If you provide &NULL, list will be allocated on heap,
6740 * if you provide pointer to non-NULL, list will be freed automacally at first.
6741 * Also in case of error the list will be NULLed.
6742 * @return IE_SUCCESS or appropriate error code. */
6743 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
6744 const struct timeval
*from_time
, const struct timeval
*to_time
,
6745 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
6746 const unsigned long int offset
, unsigned long int *number
,
6747 struct isds_list
**messages
) {
6749 return isds_get_list_of_messages(
6751 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
6757 /* Get list of incoming (addressed to you) messages.
6758 * Any criterion argument can be NULL, if you don't care about it.
6759 * @context is session context. Must not be NULL.
6760 * @from_time is minimal time and date of message sending inclusive.
6761 * @to_time is maximal time and date of message sending inclusive
6762 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
6763 * @status_filter is bit field of isds_message_status values. Use special
6764 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
6765 * all values, you can use bitwise arithmetic if you want.)
6766 * @offset is index of first message we are interested in. First message is 1.
6767 * Set to 0 (or 1) if you don't care.
6768 * @number is maximal length of list you want to get as input value, outputs
6769 * number of messages matching these criteria. Can be NULL if you don't care
6770 * (applies to output value either).
6771 * @messages is automatically reallocated list of isds_message's. Be ware that
6772 * it returns only brief overview (envelope and some other fields) about each
6773 * message, not the complete message. FIXME: Specify exact fields.
6774 * Use NULL if you don't care about the metadata (useful if you want to know
6775 * only the @number). If you provide &NULL, list will be allocated on heap,
6776 * if you provide pointer to non-NULL, list will be freed automacally at first.
6777 * Also in case of error the list will be NULLed.
6778 * @return IE_SUCCESS or appropriate error code. */
6779 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
6780 const struct timeval
*from_time
, const struct timeval
*to_time
,
6781 const long int *dmRecipientOrgUnitNum
,
6782 const unsigned int status_filter
,
6783 const unsigned long int offset
, unsigned long int *number
,
6784 struct isds_list
**messages
) {
6786 return isds_get_list_of_messages(
6788 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
6794 /* Build ISDS request of XSD tIDMessInput type, sent it and check for error
6796 * @context is session context
6797 * @service is ISDS WS service handler
6798 * @service_name is name of SERVICE_DM_OPERATIONS
6799 * @message_id is message ID to send as service argument to ISDS
6800 * @response is server SOAP body response as XML document
6801 * @raw_response is automatically reallocated bitstream with response body. Use
6802 * NULL if you don't care
6803 * @raw_response_length is size of @raw_response in bytes
6804 * @code is ISDS status code
6805 * @status_message is ISDS status message
6806 * @return error coded from lower layer, context message will be set up
6808 static isds_error
build_send_check_message_request(struct isds_ctx
*context
,
6809 const isds_service service
, const xmlChar
*service_name
,
6810 const char *message_id
,
6811 xmlDocPtr
*response
, void **raw_response
, size_t *raw_response_length
,
6812 xmlChar
**code
, xmlChar
**status_message
) {
6814 isds_error err
= IE_SUCCESS
;
6815 char *service_name_locale
= NULL
, *message_id_locale
= NULL
;
6816 xmlNodePtr request
= NULL
, node
;
6817 xmlNsPtr isds_ns
= NULL
;
6819 if (!context
) return IE_INVALID_CONTEXT
;
6820 if (!service_name
|| !message_id
) return IE_INVAL
;
6821 if (!response
|| !code
|| !status_message
) return IE_INVAL
;
6822 if (!raw_response_length
&& raw_response
) return IE_INVAL
;
6824 /* Free output argument */
6825 xmlFreeDoc(*response
); *response
= NULL
;
6826 if (raw_response
) zfree(*raw_response
);
6828 free(*status_message
);
6831 /* Check if connection is established
6832 * TODO: This check should be done donwstairs. */
6833 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
6835 service_name_locale
= _isds_utf82locale((char*)service_name
);
6836 message_id_locale
= _isds_utf82locale(message_id
);
6837 if (!service_name_locale
|| !message_id_locale
) {
6843 request
= xmlNewNode(NULL
, service_name
);
6845 isds_printf_message(context
,
6846 _("Could not build %s request"), service_name_locale
);
6850 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
6852 isds_log_message(context
, _("Could not create ISDS name space"));
6856 xmlSetNs(request
, isds_ns
);
6859 /* Add requested ID */
6860 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
6861 if (err
) goto leave
;
6862 INSERT_STRING(request
, "dmID", message_id
);
6865 isds_log(ILF_ISDS
, ILL_DEBUG
,
6866 _("Sending %s request for %s message ID to ISDS\n"),
6867 service_name_locale
, message_id_locale
);
6870 err
= isds(context
, service
, request
, response
,
6871 raw_response
, raw_response_length
);
6872 xmlFreeNode(request
); request
= NULL
;
6875 isds_log(ILF_ISDS
, ILL_DEBUG
,
6876 _("Processing ISDS response on %s request failed\n"),
6877 service_name_locale
);
6881 /* Check for response status */
6882 err
= isds_response_status(context
, service
, *response
,
6883 code
, status_message
, NULL
);
6885 isds_log(ILF_ISDS
, ILL_DEBUG
,
6886 _("ISDS response on %s request is missing status\n"),
6887 service_name_locale
);
6891 /* Request processed, but nothing found */
6892 if (xmlStrcmp(*code
, BAD_CAST
"0000")) {
6893 char *code_locale
= _isds_utf82locale((char*) *code
);
6894 char *status_message_locale
= _isds_utf82locale((char*) *status_message
);
6895 isds_log(ILF_ISDS
, ILL_DEBUG
,
6896 _("Server refused %s request for %s message ID "
6897 "(code=%s, message=%s)\n"),
6898 service_name_locale
, message_id_locale
,
6899 code_locale
, status_message_locale
);
6900 isds_log_message(context
, status_message_locale
);
6902 free(status_message_locale
);
6908 free(message_id_locale
);
6909 free(service_name_locale
);
6910 xmlFreeNode(request
);
6915 /* Find dmSignature in ISDS response, extract decoded CMS structure, extract
6916 * signed data and free ISDS response.
6917 * @context is session context
6918 * @message_id is UTF-8 encoded message ID for loging purpose
6919 * @response is parsed XML document. It will be freed and NULLed in the middle
6920 * of function run to save memmory. This is not guaranted in case of error.
6921 * @request_name is name of ISDS request used to construct response root
6922 * element name and for logging purpose.
6923 * @raw is reallocated output buffer with DER encoded CMS data
6924 * @raw_length is size of @raw buffer in bytes
6925 * @returns standard error codes, in case of error, @raw will be freed and
6926 * NULLed, @response sometimes. */
6927 static isds_error
find_extract_signed_data_free_response(
6928 struct isds_ctx
*context
, const xmlChar
*message_id
,
6929 xmlDocPtr
*response
, const xmlChar
*request_name
,
6930 void **raw
, size_t *raw_length
) {
6932 isds_error err
= IE_SUCCESS
;
6933 char *xpath_expression
= NULL
;
6934 xmlXPathContextPtr xpath_ctx
= NULL
;
6935 xmlXPathObjectPtr result
= NULL
;
6936 char *encoded_structure
= NULL
;
6938 if (!context
) return IE_INVALID_CONTEXT
;
6939 if (!raw
) return IE_INVAL
;
6941 if (!message_id
|| !response
|| !*response
|| !request_name
|| !raw_length
)
6944 /* Build XPath expression */
6945 xpath_expression
= _isds_astrcat3("/isds:", (char *) request_name
,
6946 "Response/isds:dmSignature");
6947 if (!xpath_expression
) return IE_NOMEM
;
6950 xpath_ctx
= xmlXPathNewContext(*response
);
6955 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
6959 result
= xmlXPathEvalExpression(BAD_CAST xpath_expression
, xpath_ctx
);
6964 /* Empty response */
6965 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
6966 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
6967 isds_printf_message(context
,
6968 _("Server did not return any signed data for mesage ID `%s' "
6970 message_id_locale
, request_name
);
6971 free(message_id_locale
);
6976 if (result
->nodesetval
->nodeNr
> 1) {
6977 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
6978 isds_printf_message(context
,
6979 _("Server did return more signed data for message ID `%s' "
6981 message_id_locale
, request_name
);
6982 free(message_id_locale
);
6987 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
6989 /* Extract PKCS#7 structure */
6990 EXTRACT_STRING(".", encoded_structure
);
6991 if (!encoded_structure
) {
6992 isds_log_message(context
, _("dmSignature element is empty"));
6995 /* Here we have delivery info as standalone CMS in encoded_structure.
6996 * We don't need any other data, free them: */
6997 xmlXPathFreeObject(result
); result
= NULL
;
6998 xmlXPathFreeContext(xpath_ctx
); xpath_ctx
= NULL
;
6999 xmlFreeDoc(*response
); *response
= NULL
;
7002 /* Decode PKCS#7 to DER format */
7003 *raw_length
= _isds_b64decode(encoded_structure
, raw
);
7004 if (*raw_length
== (size_t) -1) {
7005 isds_log_message(context
,
7006 _("Error while Base64-decoding PKCS#7 structure"));
7017 free(encoded_structure
);
7018 xmlXPathFreeObject(result
);
7019 xmlXPathFreeContext(xpath_ctx
);
7020 free(xpath_expression
);
7026 /* Download incoming message envelope identified by ID.
7027 * @context is session context
7028 * @message_id is message identifier (you can get them from
7029 * isds_get_list_of_received_messages())
7030 * @message is automatically reallocated message retrieved from ISDS.
7031 * It will miss documents per se. Use isds_get_received_message(), if you are
7032 * interrested in documents (content) too.
7033 * Returned hash and timestamp require documents to be verifiable. */
7034 isds_error
isds_get_received_envelope(struct isds_ctx
*context
,
7035 const char *message_id
, struct isds_message
**message
) {
7037 isds_error err
= IE_SUCCESS
;
7038 xmlDocPtr response
= NULL
;
7039 xmlChar
*code
= NULL
, *status_message
= NULL
;
7040 xmlXPathContextPtr xpath_ctx
= NULL
;
7041 xmlXPathObjectPtr result
= NULL
;
7043 if (!context
) return IE_INVALID_CONTEXT
;
7044 zfree(context
->long_message
);
7046 /* Free former message if any */
7047 if (!message
) return IE_INVAL
;
7048 isds_message_free(message
);
7050 /* Do request and check for success */
7051 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7052 BAD_CAST
"MessageEnvelopeDownload", message_id
,
7053 &response
, NULL
, NULL
, &code
, &status_message
);
7054 if (err
) goto leave
;
7057 xpath_ctx
= xmlXPathNewContext(response
);
7062 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7066 result
= xmlXPathEvalExpression(
7067 BAD_CAST
"/isds:MessageEnvelopeDownloadResponse/"
7068 "isds:dmReturnedMessageEnvelope",
7074 /* Empty response */
7075 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7076 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
7077 isds_printf_message(context
,
7078 _("Server did not return any envelope for ID `%s' "
7079 "on MessageEnvelopeDownload request"), message_id_locale
);
7080 free(message_id_locale
);
7085 if (result
->nodesetval
->nodeNr
> 1) {
7086 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
7087 isds_printf_message(context
,
7088 _("Server did return more envelopes for ID `%s' "
7089 "on MessageEnvelopeDownload request"), message_id_locale
);
7090 free(message_id_locale
);
7095 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7097 /* Extract the envelope (= message without documents, hence 0) */
7098 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
7099 if (err
) goto leave
;
7102 err
= serialize_subtree(context
, xpath_ctx
->node
, &(*message
)->raw
,
7103 &(*message
)->raw_length
);
7107 isds_message_free(message
);
7110 xmlXPathFreeObject(result
);
7111 xmlXPathFreeContext(xpath_ctx
);
7114 free(status_message
);
7115 if (!*message
|| !(*message
)->xml
) {
7116 xmlFreeDoc(response
);
7120 isds_log(ILF_ISDS
, ILL_DEBUG
,
7121 _("MessageEnvelopeDownload request processed by server "
7128 /* Load delivery info of any format from buffer.
7129 * @context is session context
7130 * @raw_type advertises format of @buffer content. Only delivery info types
7132 * @buffer is DER encoded PKCS#7 structure with signed delivery info. You can
7133 * retrieve such data from message->raw after calling
7134 * isds_get_signed_delivery_info().
7135 * @length is length of buffer in bytes.
7136 * @message is automatically reallocated message parsed from @buffer.
7137 * @strategy selects how buffer will be attached into raw isds_message member.
7139 isds_error
isds_load_delivery_info(struct isds_ctx
*context
,
7140 const isds_raw_type raw_type
,
7141 const void *buffer
, const size_t length
,
7142 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7144 isds_error err
= IE_SUCCESS
;
7145 message_ns_type message_ns
;
7146 xmlDocPtr message_doc
= NULL
;
7147 xmlXPathContextPtr xpath_ctx
= NULL
;
7148 xmlXPathObjectPtr result
= NULL
;
7149 void *xml_stream
= NULL
;
7150 size_t xml_stream_length
= 0;
7152 if (!context
) return IE_INVALID_CONTEXT
;
7153 zfree(context
->long_message
);
7154 if (!message
) return IE_INVAL
;
7155 isds_message_free(message
);
7156 if (!buffer
) return IE_INVAL
;
7159 /* Select buffer format and extract XML from CMS*/
7161 case RAWTYPE_DELIVERYINFO
:
7162 message_ns
= MESSAGE_NS_UNSIGNED
;
7163 xml_stream
= (void *) buffer
;
7164 xml_stream_length
= length
;
7167 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
7168 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
7169 xml_stream
= (void *) buffer
;
7170 xml_stream_length
= length
;
7173 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
7174 message_ns
= MESSAGE_NS_SIGNED_DELIVERY
;
7175 err
= _isds_extract_cms_data(context
, buffer
, length
,
7176 &xml_stream
, &xml_stream_length
);
7177 if (err
) goto leave
;
7181 isds_log_message(context
, _("Bad raw delivery representation type"));
7186 isds_log(ILF_ISDS
, ILL_DEBUG
,
7187 _("Delivery info content:\n%.*s\nEnd of delivery info\n"),
7188 xml_stream_length
, xml_stream
);
7190 /* Convert delivery info XML stream into XPath context */
7191 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7196 xpath_ctx
= xmlXPathNewContext(message_doc
);
7201 /* XXX: Name spaces mangled for signed delivery info:
7202 * http://isds.czechpoint.cz/v20/delivery:
7204 * <q:GetDeliveryInfoResponse xmlns:q="http://isds.czechpoint.cz/v20/delivery">
7206 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7207 * <p:dmID>170272</p:dmID>
7210 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7212 * </q:dmEvents>...</q:dmEvents>
7214 * </q:GetDeliveryInfoResponse>
7216 if (_isds_register_namespaces(xpath_ctx
, message_ns
)) {
7220 result
= xmlXPathEvalExpression(
7221 BAD_CAST
"/sisds:GetDeliveryInfoResponse/sisds:dmDelivery",
7227 /* Empty delivery info */
7228 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7229 isds_printf_message(context
,
7230 _("XML document is not sisds:dmDelivery document"));
7234 /* More delivery infos */
7235 if (result
->nodesetval
->nodeNr
> 1) {
7236 isds_printf_message(context
,
7237 _("XML document has more sisds:dmDelivery elements"));
7241 /* One delivery info */
7242 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7244 /* Extract the envelope (= message without documents, hence 0).
7245 * XXX: extract_TReturnedMessage() can obtain attachments size,
7246 * but delivery info carries none. It's coded as option elements,
7247 * so it should work. */
7248 err
= extract_TReturnedMessage(context
, 0, message
, xpath_ctx
);
7249 if (err
) goto leave
;
7251 /* Extract events */
7252 err
= move_xpathctx_to_child(context
, BAD_CAST
"sisds:dmEvents", xpath_ctx
);
7253 if (err
== IE_NOEXIST
|| err
== IE_NOTUNIQ
) { err
= IE_ISDS
; goto leave
; }
7254 if (err
) { err
= IE_ERROR
; goto leave
; }
7255 err
= extract_events(context
, &(*message
)->envelope
->events
, xpath_ctx
);
7256 if (err
) goto leave
;
7258 /* Append raw CMS structure into message */
7259 (*message
)->raw_type
= raw_type
;
7261 case BUFFER_DONT_STORE
:
7264 (*message
)->raw
= malloc(length
);
7265 if (!(*message
)->raw
) {
7269 memcpy((*message
)->raw
, buffer
, length
);
7270 (*message
)->raw_length
= length
;
7273 (*message
)->raw
= (void *) buffer
;
7274 (*message
)->raw_length
= length
;
7283 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7284 isds_message_free(message
);
7287 xmlXPathFreeObject(result
);
7288 xmlXPathFreeContext(xpath_ctx
);
7289 if (!*message
|| !(*message
)->xml
) {
7290 xmlFreeDoc(message_doc
);
7292 if (xml_stream
!= buffer
) _isds_cms_data_free(xml_stream
);
7295 isds_log(ILF_ISDS
, ILL_DEBUG
,
7296 _("Delivery info loaded successfully.\n"));
7301 /* Download signed delivery infosheet of given message identified by ID.
7302 * @context is session context
7303 * @message_id is message identifier (you can get them from
7304 * isds_get_list_of_{sent,received}_messages())
7305 * @message is automatically reallocated message retrieved from ISDS.
7306 * It will miss documents per se. Use isds_get_signed_received_message(),
7307 * if you are interrested in documents (content). OTOH, only this function
7308 * can get list events message has gone through. */
7309 isds_error
isds_get_signed_delivery_info(struct isds_ctx
*context
,
7310 const char *message_id
, struct isds_message
**message
) {
7312 isds_error err
= IE_SUCCESS
;
7313 xmlDocPtr response
= NULL
;
7314 xmlChar
*code
= NULL
, *status_message
= NULL
;
7316 size_t raw_length
= 0;
7318 if (!context
) return IE_INVALID_CONTEXT
;
7319 zfree(context
->long_message
);
7321 /* Free former message if any */
7322 if (!message
) return IE_INVAL
;
7323 isds_message_free(message
);
7325 /* Do request and check for success */
7326 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7327 BAD_CAST
"GetSignedDeliveryInfo", message_id
,
7328 &response
, NULL
, NULL
, &code
, &status_message
);
7329 if (err
) goto leave
;
7331 /* Find signed delivery info, extract it into raw and maybe free
7333 err
= find_extract_signed_data_free_response(context
,
7334 (xmlChar
*)message_id
, &response
,
7335 BAD_CAST
"GetSignedDeliveryInfo", &raw
, &raw_length
);
7336 if (err
) goto leave
;
7338 /* Parse delivery info */
7339 err
= isds_load_delivery_info(context
,
7340 RAWTYPE_CMS_SIGNED_DELIVERYINFO
, raw
, raw_length
,
7341 message
, BUFFER_MOVE
);
7342 if (err
) goto leave
;
7348 isds_message_free(message
);
7353 free(status_message
);
7354 xmlFreeDoc(response
);
7357 isds_log(ILF_ISDS
, ILL_DEBUG
,
7358 _("GetSignedDeliveryInfo request processed by server "
7365 /* Download delivery infosheet of given message identified by ID.
7366 * @context is session context
7367 * @message_id is message identifier (you can get them from
7368 * isds_get_list_of_{sent,received}_messages())
7369 * @message is automatically reallocated message retrieved from ISDS.
7370 * It will miss documents per se. Use isds_get_received_message(), if you are
7371 * interrested in documents (content). OTOH, only this function can get list
7372 * of events message has gone through. */
7373 isds_error
isds_get_delivery_info(struct isds_ctx
*context
,
7374 const char *message_id
, struct isds_message
**message
) {
7376 isds_error err
= IE_SUCCESS
;
7377 xmlDocPtr response
= NULL
;
7378 xmlChar
*code
= NULL
, *status_message
= NULL
;
7379 xmlNodePtr delivery_node
= NULL
;
7381 size_t raw_length
= 0;
7383 if (!context
) return IE_INVALID_CONTEXT
;
7384 zfree(context
->long_message
);
7386 /* Free former message if any */
7387 if (!message
) return IE_INVAL
;
7388 isds_message_free(message
);
7390 /* Do request and check for success */
7391 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7392 BAD_CAST
"GetDeliveryInfo", message_id
,
7393 &response
, NULL
, NULL
, &code
, &status_message
);
7394 if (err
) goto leave
;
7397 /* Serialize delivery info */
7398 delivery_node
= xmlDocGetRootElement(response
);
7399 if (!delivery_node
) {
7400 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
7401 isds_printf_message(context
,
7402 _("Server did not return any delivery info for ID `%s' "
7403 "on GetDeliveryInfo request"), message_id_locale
);
7404 free(message_id_locale
);
7408 err
= serialize_subtree(context
, delivery_node
, &raw
, &raw_length
);
7409 if (err
) goto leave
;
7411 /* Parse delivery info */
7412 /* TODO: Here we parse the reponse second time. We could single delivery
7413 * parser from isds_load_delivery_info() to make things faster. */
7414 err
= isds_load_delivery_info(context
,
7415 RAWTYPE_DELIVERYINFO
, raw
, raw_length
,
7416 message
, BUFFER_MOVE
);
7417 if (err
) goto leave
;
7424 isds_message_free(message
);
7429 free(status_message
);
7430 xmlFreeDoc(response
);
7433 isds_log(ILF_ISDS
, ILL_DEBUG
,
7434 _("GetDeliveryInfo request processed by server "
7441 /* Download incoming message identified by ID.
7442 * @context is session context
7443 * @message_id is message identifier (you can get them from
7444 * isds_get_list_of_received_messages())
7445 * @message is automatically reallocated message retrieved from ISDS */
7446 isds_error
isds_get_received_message(struct isds_ctx
*context
,
7447 const char *message_id
, struct isds_message
**message
) {
7449 isds_error err
= IE_SUCCESS
;
7450 xmlDocPtr response
= NULL
;
7451 void *xml_stream
= NULL
;
7452 size_t xml_stream_length
;
7453 xmlChar
*code
= NULL
, *status_message
= NULL
;
7454 xmlXPathContextPtr xpath_ctx
= NULL
;
7455 xmlXPathObjectPtr result
= NULL
;
7456 char *phys_path
= NULL
;
7457 size_t phys_start
, phys_end
;
7459 if (!context
) return IE_INVALID_CONTEXT
;
7460 zfree(context
->long_message
);
7462 /* Free former message if any */
7463 if (message
) isds_message_free(message
);
7465 /* Do request and check for success */
7466 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7467 BAD_CAST
"MessageDownload", message_id
,
7468 &response
, &xml_stream
, &xml_stream_length
,
7469 &code
, &status_message
);
7470 if (err
) goto leave
;
7473 xpath_ctx
= xmlXPathNewContext(response
);
7478 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
7482 result
= xmlXPathEvalExpression(
7483 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
7489 /* Empty response */
7490 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7491 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
7492 isds_printf_message(context
,
7493 _("Server did not return any message for ID `%s' "
7494 "on MessageDownload request"), message_id_locale
);
7495 free(message_id_locale
);
7500 if (result
->nodesetval
->nodeNr
> 1) {
7501 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
7502 isds_printf_message(context
,
7503 _("Server did return more messages for ID `%s' "
7504 "on MessageDownload request"), message_id_locale
);
7505 free(message_id_locale
);
7510 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7512 /* Extract the message */
7513 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7514 if (err
) goto leave
;
7516 /* Locate raw XML blob */
7518 SOAP_NS PHYSXML_NS_SEPARATOR
"Envelope"
7519 PHYSXML_ELEMENT_SEPARATOR
7520 SOAP_NS PHYSXML_NS_SEPARATOR
"Body"
7521 PHYSXML_ELEMENT_SEPARATOR
7522 ISDS_NS PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
7528 err
= _isds_find_element_boundary(xml_stream
, xml_stream_length
,
7529 phys_path
, &phys_start
, &phys_end
);
7532 isds_log_message(context
,
7533 _("Substring with isds:MessageDownloadResponse element "
7534 "could not be located in raw SOAP message"));
7538 /*err = serialize_subtree(context, xpath_ctx->node, &(*message)->raw,
7539 &(*message)->raw_length);*/
7540 /* TODO: Store name space declarations from ancestors */
7541 /* TODO: Handle non-UTF-8 encoding (XML prologue) */
7542 (*message
)->raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7543 (*message
)->raw_length
= phys_end
- phys_start
+ 1;
7544 (*message
)->raw
= malloc((*message
)->raw_length
);
7545 if (!(*message
)->raw
) {
7549 memcpy((*message
)->raw
, xml_stream
+ phys_start
, (*message
)->raw_length
);
7554 isds_message_free(message
);
7559 xmlXPathFreeObject(result
);
7560 xmlXPathFreeContext(xpath_ctx
);
7563 free(status_message
);
7565 if (!*message
|| !(*message
)->xml
) {
7566 xmlFreeDoc(response
);
7570 isds_log(ILF_ISDS
, ILL_DEBUG
,
7571 _("MessageDownload request processed by server "
7578 /* Load message of any type from buffer.
7579 * @context is session context
7580 * @raw_type defines content type of @buffer. Only message types are allowed.
7581 * @buffer is message raw representation. Format (CMS, plain signed,
7582 * message direction) is defined in @raw_type. You can retrieve such data
7583 * from message->raw after calling isds_get_[signed]{received,sent}_message().
7584 * @length is length of buffer in bytes.
7585 * @message is automatically reallocated message parsed from @buffer.
7586 * @strategy selects how buffer will be attached into raw isds_message member.
7588 isds_error
isds_load_message(struct isds_ctx
*context
,
7589 const isds_raw_type raw_type
, const void *buffer
, const size_t length
,
7590 struct isds_message
**message
, const isds_buffer_strategy strategy
) {
7592 isds_error err
= IE_SUCCESS
;
7593 void *xml_stream
= NULL
;
7594 size_t xml_stream_length
= 0;
7595 message_ns_type message_ns
;
7596 xmlDocPtr message_doc
= NULL
;
7597 xmlXPathContextPtr xpath_ctx
= NULL
;
7598 xmlXPathObjectPtr result
= NULL
;
7600 if (!context
) return IE_INVALID_CONTEXT
;
7601 zfree(context
->long_message
);
7602 if (!message
) return IE_INVAL
;
7603 isds_message_free(message
);
7604 if (!buffer
) return IE_INVAL
;
7607 /* Select buffer format and extract XML from CMS*/
7609 case RAWTYPE_INCOMING_MESSAGE
:
7610 message_ns
= MESSAGE_NS_UNSIGNED
;
7611 xml_stream
= (void *) buffer
;
7612 xml_stream_length
= length
;
7615 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
7616 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7617 xml_stream
= (void *) buffer
;
7618 xml_stream_length
= length
;
7621 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
7622 message_ns
= MESSAGE_NS_SIGNED_INCOMING
;
7623 err
= _isds_extract_cms_data(context
, buffer
, length
,
7624 &xml_stream
, &xml_stream_length
);
7625 if (err
) goto leave
;
7628 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
7629 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7630 xml_stream
= (void *) buffer
;
7631 xml_stream_length
= length
;
7634 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7635 message_ns
= MESSAGE_NS_SIGNED_OUTGOING
;
7636 err
= _isds_extract_cms_data(context
, buffer
, length
,
7637 &xml_stream
, &xml_stream_length
);
7638 if (err
) goto leave
;
7642 isds_log_message(context
, _("Bad raw message representation type"));
7647 isds_log(ILF_ISDS
, ILL_DEBUG
,
7648 _("Loading message:\n%.*s\nEnd of message\n"),
7649 xml_stream_length
, xml_stream
);
7651 /* Convert messages XML stream into XPath context */
7652 message_doc
= xmlParseMemory(xml_stream
, xml_stream_length
);
7657 xpath_ctx
= xmlXPathNewContext(message_doc
);
7662 /* XXX: Standard name space for unsigned incoming direction:
7663 * http://isds.czechpoint.cz/v20/
7665 * XXX: Name spaces mangled for signed outgoing direction:
7666 * http://isds.czechpoint.cz/v20/SentMessage:
7668 * <q:MessageDownloadResponse
7669 * xmlns:q="http://isds.czechpoint.cz/v20/SentMessage">
7670 * <q:dmReturnedMessage>
7671 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7672 * <p:dmID>151916</p:dmID>
7675 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7677 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7678 * </q:dmReturnedMessage>
7679 * </q:MessageDownloadResponse>
7681 * XXX: Name spaces mangled for signed incoming direction:
7682 * http://isds.czechpoint.cz/v20/message:
7684 * <q:MessageDownloadResponse
7685 * xmlns:q="http://isds.czechpoint.cz/v20/message">
7686 * <q:dmReturnedMessage>
7687 * <p:dmDm xmlns:p="http://isds.czechpoint.cz/v20">
7688 * <p:dmID>151916</p:dmID>
7691 * <q:dmHash algorithm="SHA-1">...</q:dmHash>
7693 * <q:dmAttachmentSize>260</q:dmAttachmentSize>
7694 * </q:dmReturnedMessage>
7695 * </q:MessageDownloadResponse>
7697 * Stupidity of ISDS developers is unlimited */
7698 if (_isds_register_namespaces(xpath_ctx
, message_ns
)) {
7702 result
= xmlXPathEvalExpression(
7703 BAD_CAST
"/sisds:MessageDownloadResponse/sisds:dmReturnedMessage",
7710 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
7711 isds_printf_message(context
,
7712 _("XML document does not contain "
7713 "sisds:dmReturnedMessage element"));
7718 if (result
->nodesetval
->nodeNr
> 1) {
7719 isds_printf_message(context
,
7720 _("XML document has more sisds:dmReturnedMessage elements"));
7725 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
7727 /* Extract the message */
7728 err
= extract_TReturnedMessage(context
, 1, message
, xpath_ctx
);
7729 if (err
) goto leave
;
7731 /* Append raw buffer into message */
7732 (*message
)->raw_type
= raw_type
;
7734 case BUFFER_DONT_STORE
:
7737 (*message
)->raw
= malloc(length
);
7738 if (!(*message
)->raw
) {
7742 memcpy((*message
)->raw
, buffer
, length
);
7743 (*message
)->raw_length
= length
;
7746 (*message
)->raw
= (void *) buffer
;
7747 (*message
)->raw_length
= length
;
7757 if (*message
&& strategy
== BUFFER_MOVE
) (*message
)->raw
= NULL
;
7758 isds_message_free(message
);
7761 if (xml_stream
!= buffer
) _isds_cms_data_free(xml_stream
);
7762 xmlXPathFreeObject(result
);
7763 xmlXPathFreeContext(xpath_ctx
);
7764 if (!*message
|| !(*message
)->xml
) {
7765 xmlFreeDoc(message_doc
);
7769 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Message loaded successfully.\n"));
7774 /* Determine type of raw message or delivery info according some heuristics.
7775 * It does not validate the raw blob.
7776 * @context is session context
7777 * @raw_type returns content type of @buffer. Valid only if exit code of this
7778 * function is IE_SUCCESS. The pointer must be valid. This is no automatically
7779 * reallocted memory.
7780 * @buffer is message raw representation.
7781 * @length is length of buffer in bytes. */
7782 isds_error
isds_guess_raw_type(struct isds_ctx
*context
,
7783 isds_raw_type
*raw_type
, const void *buffer
, const size_t length
) {
7785 void *xml_stream
= NULL
;
7786 size_t xml_stream_length
= 0;
7787 xmlDocPtr document
= NULL
;
7788 xmlNodePtr root
= NULL
;
7790 if (!context
) return IE_INVALID_CONTEXT
;
7791 zfree(context
->long_message
);
7792 if (length
== 0 || !buffer
) return IE_INVAL
;
7793 if (!raw_type
) return IE_INVAL
;
7796 err
= _isds_extract_cms_data(context
, buffer
, length
,
7797 &xml_stream
, &xml_stream_length
);
7799 xml_stream
= (void *) buffer
;
7800 xml_stream_length
= (size_t) length
;
7805 document
= xmlParseMemory(xml_stream
, xml_stream_length
);
7807 isds_printf_message(context
,
7808 _("Could not parse data as XML document"));
7813 /* Get root element */
7814 root
= xmlDocGetRootElement(document
);
7816 isds_printf_message(context
,
7817 _("XML document is missing root element"));
7822 if (!root
->ns
|| !root
->ns
->href
) {
7823 isds_printf_message(context
,
7824 _("Root element does not belong to any name space"));
7829 /* Test name space */
7830 if (!xmlStrcmp(root
->ns
->href
, BAD_CAST SISDS_INCOMING_NS
)) {
7831 if (xml_stream
== buffer
)
7832 *raw_type
= RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
;
7834 *raw_type
= RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
;
7835 } else if (!xmlStrcmp(root
->ns
->href
, BAD_CAST SISDS_OUTGOING_NS
)) {
7836 if (xml_stream
== buffer
)
7837 *raw_type
= RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
;
7839 *raw_type
= RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
;
7840 } else if (!xmlStrcmp(root
->ns
->href
, BAD_CAST SISDS_DELIVERY_NS
)) {
7841 if (xml_stream
== buffer
)
7842 *raw_type
= RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
;
7844 *raw_type
= RAWTYPE_CMS_SIGNED_DELIVERYINFO
;
7845 } else if (!xmlStrcmp(root
->ns
->href
, BAD_CAST ISDS_NS
)) {
7846 if (xml_stream
!= buffer
) {
7847 isds_printf_message(context
,
7848 _("Document in ISDS name space is encapsulated into CMS" ));
7850 } else if (!xmlStrcmp(root
->name
, BAD_CAST
"MessageDownloadResponse"))
7851 *raw_type
= RAWTYPE_INCOMING_MESSAGE
;
7852 else if (!xmlStrcmp(root
->name
, BAD_CAST
"GetDeliveryInfoResponse"))
7853 *raw_type
= RAWTYPE_DELIVERYINFO
;
7855 isds_printf_message(context
,
7856 _("Unknown root element in ISDS name space"));
7860 isds_printf_message(context
,
7861 _("Uknown namespace"));
7866 if (xml_stream
!= buffer
) _isds_cms_data_free(xml_stream
);
7867 xmlFreeDoc(document
);
7872 /* Download signed incoming/outgoing message identified by ID.
7873 * @context is session context
7874 * @output is true for outging message, false for incoming message
7875 * @message_id is message identifier (you can get them from
7876 * isds_get_list_of_{sent,received}_messages())
7877 * @message is automatically reallocated message retrieved from ISDS. The raw
7878 * memeber will be filled with PKCS#7 structure in DER format. */
7879 static isds_error
isds_get_signed_message(struct isds_ctx
*context
,
7880 const _Bool outgoing
, const char *message_id
,
7881 struct isds_message
**message
) {
7883 isds_error err
= IE_SUCCESS
;
7884 xmlDocPtr response
= NULL
;
7885 xmlChar
*code
= NULL
, *status_message
= NULL
;
7886 xmlXPathContextPtr xpath_ctx
= NULL
;
7887 xmlXPathObjectPtr result
= NULL
;
7888 char *encoded_structure
= NULL
;
7890 size_t raw_length
= 0;
7892 if (!context
) return IE_INVALID_CONTEXT
;
7893 zfree(context
->long_message
);
7894 if (!message
) return IE_INVAL
;
7895 isds_message_free(message
);
7897 /* Do request and check for success */
7898 err
= build_send_check_message_request(context
, SERVICE_DM_OPERATIONS
,
7899 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7900 BAD_CAST
"SignedMessageDownload",
7901 message_id
, &response
, NULL
, NULL
, &code
, &status_message
);
7902 if (err
) goto leave
;
7904 /* Find signed message, extract it into raw and maybe free
7906 err
= find_extract_signed_data_free_response(context
,
7907 (xmlChar
*)message_id
, &response
,
7908 (outgoing
) ? BAD_CAST
"SignedSentMessageDownload" :
7909 BAD_CAST
"SignedMessageDownload",
7911 if (err
) goto leave
;
7914 err
= isds_load_message(context
,
7915 (outgoing
) ? RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
7916 RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
,
7917 raw
, raw_length
, message
, BUFFER_MOVE
);
7918 if (err
) goto leave
;
7924 isds_message_free(message
);
7927 free(encoded_structure
);
7928 xmlXPathFreeObject(result
);
7929 xmlXPathFreeContext(xpath_ctx
);
7933 free(status_message
);
7934 xmlFreeDoc(response
);
7937 isds_log(ILF_ISDS
, ILL_DEBUG
,
7939 _("SignedSentMessageDownload request processed by server "
7940 "successfully.\n") :
7941 _("SignedMessageDownload request processed by server "
7948 /* Download signed incoming message identified by ID.
7949 * @context is session context
7950 * @message_id is message identifier (you can get them from
7951 * isds_get_list_of_received_messages())
7952 * @message is automatically reallocated message retrieved from ISDS. The raw
7953 * memeber will be filled with PKCS#7 structure in DER format. */
7954 isds_error
isds_get_signed_received_message(struct isds_ctx
*context
,
7955 const char *message_id
, struct isds_message
**message
) {
7956 return isds_get_signed_message(context
, 0, message_id
, message
);
7960 /* Download signed outgoing message identified by ID.
7961 * @context is session context
7962 * @message_id is message identifier (you can get them from
7963 * isds_get_list_of_sent_messages())
7964 * @message is automatically reallocated message retrieved from ISDS. The raw
7965 * memeber will be filled with PKCS#7 structure in DER format. */
7966 isds_error
isds_get_signed_sent_message(struct isds_ctx
*context
,
7967 const char *message_id
, struct isds_message
**message
) {
7968 return isds_get_signed_message(context
, 1, message_id
, message
);
7972 /* Retrieve hash of message identified by ID stored in ISDS.
7973 * @context is session context
7974 * @message_id is message identifier
7975 * @hash is automatically reallocated message hash downloaded from ISDS.
7976 * Message must exist in system and must not be deleted. */
7977 isds_error
isds_download_message_hash(struct isds_ctx
*context
,
7978 const char *message_id
, struct isds_hash
**hash
) {
7980 isds_error err
= IE_SUCCESS
;
7981 xmlDocPtr response
= NULL
;
7982 xmlChar
*code
= NULL
, *status_message
= NULL
;
7983 xmlXPathContextPtr xpath_ctx
= NULL
;
7984 xmlXPathObjectPtr result
= NULL
;
7986 if (!context
) return IE_INVALID_CONTEXT
;
7987 zfree(context
->long_message
);
7989 isds_hash_free(hash
);
7991 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
7992 BAD_CAST
"VerifyMessage", message_id
,
7993 &response
, NULL
, NULL
, &code
, &status_message
);
7994 if (err
) goto leave
;
7998 xpath_ctx
= xmlXPathNewContext(response
);
8003 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
8007 result
= xmlXPathEvalExpression(
8008 BAD_CAST
"/isds:VerifyMessageResponse",
8014 /* Empty response */
8015 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
8016 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
8017 isds_printf_message(context
,
8018 _("Server did not return any response for ID `%s' "
8019 "on VerifyMessage request"), message_id_locale
);
8020 free(message_id_locale
);
8024 /* More responses */
8025 if (result
->nodesetval
->nodeNr
> 1) {
8026 char *message_id_locale
= _isds_utf82locale((char*) message_id
);
8027 isds_printf_message(context
,
8028 _("Server did return more responses for ID `%s' "
8029 "on VerifyMessage request"), message_id_locale
);
8030 free(message_id_locale
);
8035 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
8037 /* Extract the hash */
8038 err
= find_and_extract_DmHash(context
, hash
, xpath_ctx
);
8042 isds_hash_free(hash
);
8045 xmlXPathFreeObject(result
);
8046 xmlXPathFreeContext(xpath_ctx
);
8049 free(status_message
);
8050 xmlFreeDoc(response
);
8053 isds_log(ILF_ISDS
, ILL_DEBUG
,
8054 _("VerifyMessage request processed by server "
8061 /* Mark message as read. This is a transactional commit function to acknoledge
8062 * to ISDS the message has been downloaded and processed by client properly.
8063 * @context is session context
8064 * @message_id is message identifier. */
8065 isds_error
isds_mark_message_read(struct isds_ctx
*context
,
8066 const char *message_id
) {
8068 isds_error err
= IE_SUCCESS
;
8069 xmlDocPtr response
= NULL
;
8070 xmlChar
*code
= NULL
, *status_message
= NULL
;
8072 if (!context
) return IE_INVALID_CONTEXT
;
8073 zfree(context
->long_message
);
8075 /* Do request and check for success */
8076 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
8077 BAD_CAST
"MarkMessageAsDownloaded", message_id
,
8078 &response
, NULL
, NULL
, &code
, &status_message
);
8081 free(status_message
);
8082 xmlFreeDoc(response
);
8085 isds_log(ILF_ISDS
, ILL_DEBUG
,
8086 _("MarkMessageAsDownloaded request processed by server "
8092 /* Mark message as received by recipient. This is applicable only to
8093 * commercial message. There is no specified way how to distinguishe
8094 * commercial message from government message yet. Government message is
8095 * received automatically (by law), commenrcial message on recipient request.
8096 * @context is session context
8097 * @message_id is message identifier. */
8098 isds_error
isds_mark_message_received(struct isds_ctx
*context
,
8099 const char *message_id
) {
8101 isds_error err
= IE_SUCCESS
;
8102 xmlDocPtr response
= NULL
;
8103 xmlChar
*code
= NULL
, *status_message
= NULL
;
8105 if (!context
) return IE_INVALID_CONTEXT
;
8106 zfree(context
->long_message
);
8108 /* Do request and check for success */
8109 err
= build_send_check_message_request(context
, SERVICE_DM_INFO
,
8110 BAD_CAST
"ConfirmDelivery", message_id
,
8111 &response
, NULL
, NULL
, &code
, &status_message
);
8114 free(status_message
);
8115 xmlFreeDoc(response
);
8118 isds_log(ILF_ISDS
, ILL_DEBUG
,
8119 _("ConfirmDelivery request processed by server "
8126 /* Send document for authorize conversion into Czech POINT system.
8127 * This is public anonymous service, no login necessary. Special context is
8128 * used to reuse keep-a-live HTTPS connection.
8129 * @context is Czech POINT session context. DO NOT use context connected to
8130 * ISDS server. Use new context or context used by this function previously.
8131 * @document is document to convert. Only data, data_length and dmFileDescr
8132 * memebers are signifact. Be ware that not all document formats can be
8133 * converted (signed PDF 1.3 and higher only (2010-02 state)).
8134 * @id is reallocated identifier assigned by Czech POINT system to
8135 * your document on submit. Use is to tell it to Czech POINT officer.
8136 * @date is reallocated document submit date (submitted documents
8137 * expires after some period). Only tm_year, tm_mon and tm_mday carry sane
8139 isds_error
czp_convert_document(struct isds_ctx
*context
,
8140 const struct isds_document
*document
,
8141 char **id
, struct tm
**date
) {
8142 isds_error err
= IE_SUCCESS
;
8143 xmlNsPtr deposit_ns
= NULL
, empty_ns
= NULL
;
8144 xmlNodePtr request
= NULL
, node
;
8145 xmlDocPtr response
= NULL
;
8146 xmlChar
*base64data
= NULL
;
8148 xmlXPathContextPtr xpath_ctx
= NULL
;
8149 xmlXPathObjectPtr result
= NULL
;
8150 long int status
= -1;
8151 long int *status_ptr
= &status
;
8152 char *string
= NULL
;
8155 if (!context
) return IE_INVALID_CONTEXT
;
8156 zfree(context
->long_message
);
8157 if (!document
|| !id
|| !date
) return IE_INVAL
;
8159 /* Free output arguments */
8163 /* Store configuration */
8164 context
->type
= CTX_TYPE_CZP
;
8166 context
->url
= strdup("https://www.czechpoint.cz/uschovna/services.php");
8167 if (!(context
->url
))
8170 /* Prepare CURL handle if not yet connected */
8171 if (!context
->curl
) {
8172 context
->curl
= curl_easy_init();
8173 if (!(context
->curl
))
8177 /* Build conversion request */
8178 request
= xmlNewNode(NULL
, BAD_CAST
"saveDocument");
8180 isds_log_message(context
,
8181 _("Could not build Czech POINT conversion request"));
8184 deposit_ns
= xmlNewNs(request
, BAD_CAST DEPOSIT_NS
, BAD_CAST
"dep");
8186 isds_log_message(context
,
8187 _("Could not create Czech POINT deposit name space"));
8188 xmlFreeNode(request
);
8191 xmlSetNs(request
, deposit_ns
);
8193 /* Insert childern. They are in empty namespace! */
8194 empty_ns
= xmlNewNs(request
, BAD_CAST
"", NULL
);
8196 isds_log_message(context
, _("Could not create empty name space"));
8200 INSERT_STRING_WITH_NS(request
, empty_ns
, "conversionID", "0");
8201 INSERT_STRING_WITH_NS(request
, empty_ns
, "fileName",
8202 document
->dmFileDescr
);
8204 /* Document encoded in Base64 */
8205 base64data
= (xmlChar
*) _isds_b64encode(document
->data
, document
->data_length
);
8207 isds_printf_message(context
,
8208 ngettext("Not enought memory to encode %zd bytes into Base64",
8209 "Not enought memory to encode %zd bytes into Base64",
8210 document
->data_length
),
8211 document
->data_length
);
8215 INSERT_STRING_WITH_NS(request
, empty_ns
, "document", base64data
);
8218 isds_log(ILF_ISDS
, ILL_DEBUG
,
8219 _("Submitting document for conversion into Czech POINT deposit"));
8221 /* Send conversion request */
8222 err
= _czp_czpdeposit(context
, request
, &response
);
8223 xmlFreeNode(request
); request
= NULL
;
8226 czp_do_close_connection(context
);
8231 /* Extract response */
8232 xpath_ctx
= xmlXPathNewContext(response
);
8237 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
8241 result
= xmlXPathEvalExpression(
8242 BAD_CAST
"/deposit:saveDocumentResponse/return",
8248 /* Empty response */
8249 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
8250 isds_printf_message(context
,
8251 _("Missing `return' element in Czech POINT deposit response"));
8255 /* More responses */
8256 if (result
->nodesetval
->nodeNr
> 1) {
8257 isds_printf_message(context
,
8258 _("Multiple `return' element in Czech POINT deposit response"));
8263 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
8266 EXTRACT_LONGINT("status", status_ptr
, 1);
8268 EXTRACT_STRING("statusMsg", string
);
8269 char *string_locale
= _isds_utf82locale(string
);
8270 isds_printf_message(context
,
8271 _("Czech POINT deposit refused document for conversion "
8272 "(code=%ld, message=%s)"),
8273 status
, string_locale
);
8274 free(string_locale
);
8279 /* Get docuement ID */
8280 EXTRACT_STRING("documentID", *id
);
8282 /* Get submit date */
8283 EXTRACT_STRING("dateInserted", string
);
8285 *date
= calloc(1, sizeof(**date
));
8290 err
= datestring2tm((xmlChar
*)string
, *date
);
8292 if (err
== IE_NOTSUP
) {
8294 char *string_locale
= _isds_utf82locale(string
);
8295 isds_printf_message(context
,
8296 _("Invalid dateInserted value: %s"), string_locale
);
8297 free(string_locale
);
8305 xmlXPathFreeObject(result
);
8306 xmlXPathFreeContext(xpath_ctx
);
8308 xmlFreeDoc(response
);
8310 xmlFreeNode(request
);
8313 char *id_locale
= _isds_utf82locale((char *) *id
);
8314 isds_log(ILF_ISDS
, ILL_DEBUG
,
8315 _("Document %s has been submitted for conversion "
8316 "to server successfully\n"), id_locale
);
8323 /* Close possibly opened connection to Czech POINT document deposit.
8324 * @context is Czech POINT session context. */
8325 isds_error
czp_close_connection(struct isds_ctx
*context
) {
8326 if (!context
) return IE_INVALID_CONTEXT
;
8327 zfree(context
->long_message
);
8328 return czp_do_close_connection(context
);
8332 /* Send request for new box creation in testing ISDS instance.
8333 * It's not possible to requst for a production box currently, as it
8334 * communicates via e-mail.
8335 * XXX: This function does not work either. Server complains about invalid
8337 * XXX: Remove context->type hacks in isds.c and validator.c when removing
8339 * @context is special session context for box creation request. DO NOT use
8340 * standard context as it could reveal your password. Use fresh new context or
8341 * context previously used by this function.
8342 * @box is box description to create including single primary user (in case of
8343 * FO box type). It outputs box ID assigned by ISDS in dbID element.
8344 * @users is list of struct isds_DbUserInfo (primary users in case of non-FO
8345 * box, or contact address of PFO box owner). The email member is mandatory as
8346 * it will be used to deliver credentials.
8347 * @former_names is optional undocumented string. Pass NULL if you don't care.
8348 * @approval is optional external approval of box manipulation
8349 * @refnumber is reallocated serial number of request assigned by ISDS. Use
8350 * NULL, if you don't care.*/
8351 isds_error
isds_request_new_testing_box(struct isds_ctx
*context
,
8352 struct isds_DbOwnerInfo
*box
, const struct isds_list
*users
,
8353 const char *former_names
, const struct isds_approval
*approval
,
8355 isds_error err
= IE_SUCCESS
;
8356 xmlNodePtr request
= NULL
;
8357 xmlDocPtr response
= NULL
;
8358 xmlXPathContextPtr xpath_ctx
= NULL
;
8359 xmlXPathObjectPtr result
= NULL
;
8362 if (!context
) return IE_INVALID_CONTEXT
;
8363 zfree(context
->long_message
);
8364 if (!box
) return IE_INVAL
;
8366 if (!box
->email
|| box
->email
[0] == '\0') {
8367 isds_log_message(context
, _("E-mail field is mandatory"));
8371 /* Scratch box ID */
8374 /* Store configuration */
8375 context
->type
= CTX_TYPE_TESTING_REQUEST_COLLECTOR
;
8377 context
->url
= strdup("http://78.102.19.203/testbox/request_box.php");
8378 if (!(context
->url
))
8381 /* Prepare CURL handle if not yet connected */
8382 if (!context
->curl
) {
8383 context
->curl
= curl_easy_init();
8384 if (!(context
->curl
))
8388 /* Build CreateDataBox request */
8389 err
= build_CreateDBInput_request(context
,
8390 &request
, BAD_CAST
"CreateDataBox",
8391 box
, users
, (xmlChar
*) former_names
, NULL
, NULL
, approval
);
8392 if (err
) goto leave
;
8394 /* Send it to server and process response */
8395 err
= send_destroy_request_check_response(context
,
8396 SERVICE_DB_MANIPULATION
, BAD_CAST
"CreateDataBox", &request
,
8397 &response
, (xmlChar
**) refnumber
);
8399 /* Extract box ID */
8400 xpath_ctx
= xmlXPathNewContext(response
);
8405 if (_isds_register_namespaces(xpath_ctx
, MESSAGE_NS_UNSIGNED
)) {
8409 EXTRACT_STRING("/isds:CreateDataBoxResponse/dbID", box
->dbID
);
8412 xmlXPathFreeObject(result
);
8413 xmlXPathFreeContext(xpath_ctx
);
8414 xmlFreeDoc(response
);
8415 xmlFreeNode(request
);
8418 isds_log(ILF_ISDS
, ILL_DEBUG
,
8419 _("CreateDataBox request processed by server successfully.\n"));
8425 #undef INSERT_ELEMENT
8426 #undef CHECK_FOR_STRING_LENGTH
8427 #undef INSERT_STRING_ATTRIBUTE
8428 #undef INSERT_ULONGINTNOPTR
8429 #undef INSERT_ULONGINT
8430 #undef INSERT_LONGINT
8431 #undef INSERT_BOOLEAN
8432 #undef INSERT_SCALAR_BOOLEAN
8433 #undef INSERT_STRING
8434 #undef INSERT_STRING_WITH_NS
8435 #undef EXTRACT_STRING_ATTRIBUTE
8436 #undef EXTRACT_ULONGINT
8437 #undef EXTRACT_LONGINT
8438 #undef EXTRACT_BOOLEAN
8439 #undef EXTRACT_STRING
8442 /* Compute hash of message from raw representation and store it into envelope.
8443 * Original hash structure will be destroyed in envelope.
8444 * @context is session context
8445 * @message is message carrying raw XML message blob
8446 * @algorithm is desired hash algorithm to use */
8447 isds_error
isds_compute_message_hash(struct isds_ctx
*context
,
8448 struct isds_message
*message
, const isds_hash_algorithm algorithm
) {
8449 isds_error err
= IE_SUCCESS
;
8451 void *xml_stream
= NULL
;
8452 size_t xml_stream_length
;
8453 size_t phys_start
, phys_end
;
8454 char *phys_path
= NULL
;
8455 struct isds_hash
*new_hash
= NULL
;
8458 if (!context
) return IE_INVALID_CONTEXT
;
8459 zfree(context
->long_message
);
8460 if (!message
) return IE_INVAL
;
8462 if (!message
->raw
) {
8463 isds_log_message(context
,
8464 _("Message does not carry raw representation"));
8468 switch (message
->raw_type
) {
8469 case RAWTYPE_INCOMING_MESSAGE
:
8471 xml_stream
= message
->raw
;
8472 xml_stream_length
= message
->raw_length
;
8475 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
8476 nsuri
= SISDS_INCOMING_NS
;
8477 xml_stream
= message
->raw
;
8478 xml_stream_length
= message
->raw_length
;
8481 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
8482 nsuri
= SISDS_INCOMING_NS
;
8483 err
= _isds_extract_cms_data(context
,
8484 message
->raw
, message
->raw_length
,
8485 &xml_stream
, &xml_stream_length
);
8486 if (err
) goto leave
;
8489 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
8490 nsuri
= SISDS_OUTGOING_NS
;
8491 xml_stream
= message
->raw
;
8492 xml_stream_length
= message
->raw_length
;
8495 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
8496 nsuri
= SISDS_OUTGOING_NS
;
8497 err
= _isds_extract_cms_data(context
,
8498 message
->raw
, message
->raw_length
,
8499 &xml_stream
, &xml_stream_length
);
8500 if (err
) goto leave
;
8504 isds_log_message(context
, _("Bad raw representation type"));
8510 /* XXX: Hash is computed from original string represinting isds:dmDm
8511 * subtree. That means no encoding, white space, xmlns attributes changes.
8512 * In other words, input for hash can be invalid XML stream. */
8513 if (-1 == isds_asprintf(&phys_path
, "%s%s%s%s",
8514 nsuri
, PHYSXML_NS_SEPARATOR
"MessageDownloadResponse"
8515 PHYSXML_ELEMENT_SEPARATOR
,
8516 nsuri
, PHYSXML_NS_SEPARATOR
"dmReturnedMessage"
8517 PHYSXML_ELEMENT_SEPARATOR
8518 ISDS_NS PHYSXML_NS_SEPARATOR
"dmDm")) {
8522 err
= _isds_find_element_boundary(xml_stream
, xml_stream_length
,
8523 phys_path
, &phys_start
, &phys_end
);
8526 isds_log_message(context
,
8527 _("Substring with isds:dmDM element could not be located "
8534 new_hash
= calloc(1, sizeof(*new_hash
));
8539 new_hash
->algorithm
= algorithm
;
8540 err
= _isds_compute_hash(xml_stream
+ phys_start
, phys_end
- phys_start
+ 1,
8543 isds_log_message(context
, _("Could not compute message hash"));
8547 /* Save computed hash */
8548 if (!message
->envelope
) {
8549 message
->envelope
= calloc(1, sizeof(*message
->envelope
));
8550 if (!message
->envelope
) {
8555 isds_hash_free(&message
->envelope
->hash
);
8556 message
->envelope
->hash
= new_hash
;
8560 isds_hash_free(&new_hash
);
8564 if (xml_stream
!= message
->raw
) free(xml_stream
);
8569 /* Compare two hashes.
8571 * @h2 is another hash
8573 * IE_SUCCESS if hashes equal
8574 * IE_NOTUNIQ if hashes are comparable, but they don't equal
8575 * IE_ENUM if not comparable, but both structures defined
8576 * IE_INVAL if some of the structures are undefined (NULL)
8577 * IE_ERROR if internal error occurs */
8578 isds_error
isds_hash_cmp(const struct isds_hash
*h1
, const struct isds_hash
*h2
) {
8579 if (h1
== NULL
|| h2
== NULL
) return IE_INVAL
;
8580 if (h1
->algorithm
!= h2
->algorithm
) return IE_ENUM
;
8581 if (h1
->length
!= h2
->length
) return IE_ERROR
;
8582 if (h1
->length
> 0 && !h1
->value
) return IE_ERROR
;
8583 if (h2
->length
> 0 && !h2
->value
) return IE_ERROR
;
8585 for (int i
= 0; i
< h1
->length
; i
++) {
8586 if (((uint8_t *) (h1
->value
))[i
] != ((uint8_t *) (h2
->value
))[i
])
8593 /* Check message has gone through ISDS by comparing message hash stored in
8594 * ISDS and locally computed hash. You must provide message with valid raw
8595 * member (do not use isds_load_message(..., BUFFER_DONT_STORE)).
8596 * This is convenient wrapper for isds_download_message_hash(),
8597 * isds_compute_message_hash(), and isds_hash_cmp() sequence.
8598 * @context is session context
8599 * @message is message with valid raw and envelope member; envelope->hash
8600 * member will be changed during funcion run. Use envelope on heap only.
8602 * IE_SUCCESS if message originates in ISDS
8603 * IE_NOTEQUAL if message is unknown to ISDS
8604 * other code for other errors */
8605 isds_error
isds_verify_message_hash(struct isds_ctx
*context
,
8606 struct isds_message
*message
) {
8607 isds_error err
= IE_SUCCESS
;
8608 struct isds_hash
*downloaded_hash
= NULL
;
8610 if (!context
) return IE_INVALID_CONTEXT
;
8611 zfree(context
->long_message
);
8612 if (!message
) return IE_INVAL
;
8614 if (!message
->envelope
) {
8615 isds_log_message(context
,
8616 _("Given message structure is missing envelope"));
8619 if (!message
->raw
) {
8620 isds_log_message(context
,
8621 _("Given message structure is missing raw representation"));
8625 err
= isds_download_message_hash(context
, message
->envelope
->dmID
,
8627 if (err
) goto leave
;
8629 err
= isds_compute_message_hash(context
, message
,
8630 downloaded_hash
->algorithm
);
8631 if (err
) goto leave
;
8633 err
= isds_hash_cmp(downloaded_hash
, message
->envelope
->hash
);
8636 isds_hash_free(&downloaded_hash
);
8641 /* Search for document by document ID in list of documents. IDs are compared
8643 * @documents is list of isds_documents
8644 * @id is document identifier
8645 * @return first matching document or NULL. */
8646 const struct isds_document
*isds_find_document_by_id(
8647 const struct isds_list
*documents
, const char *id
) {
8648 const struct isds_list
*item
;
8649 const struct isds_document
*document
;
8651 for (item
= documents
; item
; item
= item
->next
) {
8652 document
= (struct isds_document
*) item
->data
;
8653 if (!document
) continue;
8655 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
8663 /* Normalize @mime_type to be proper MIME type.
8664 * ISDS servers passes invalid MIME types (e.g. "pdf"). This function tries to
8665 * guess regular MIME type (e.g. "application/pdf").
8666 * @mime_type is UTF-8 encoded MIME type to fix
8667 * @return original @mime_type if no better interpretation exists, or array to
8668 * constant static UTF-8 encoded string with proper MIME type. */
8669 char *isds_normalize_mime_type(const char* mime_type
) {
8670 if (!mime_type
) return NULL
;
8672 for (int offset
= 0;
8673 offset
< sizeof(extension_map_mime
)/sizeof(extension_map_mime
[0]);
8675 if (!xmlStrcmp((const xmlChar
*) mime_type
, extension_map_mime
[offset
]))
8676 return (char *) extension_map_mime
[offset
+ 1];
8679 return (char *) mime_type
;
8683 /* Switch MIME type normalization while message loading. Default state for new
8684 * context is no normalization.
8685 * @normalize use true to switch normalization on, false to switch off */
8686 isds_error
isds_set_mime_type_normalization(struct isds_ctx
*context
,
8688 if (!context
) return IE_INVALID_CONTEXT
;
8689 zfree(context
->long_message
);
8691 context
->normalize_mime_type
= normalize
;
8692 isds_log(ILF_FILE
, ILL_INFO
, (context
->normalize_mime_type
) ?
8693 _("MIME type normalization switched on\n") :
8694 _("MIME type normalization switched off\n"));
8699 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
8700 struct isds_message **message);
8701 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
8702 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
8703 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
8704 struct isds_address **address);
8706 int isds_message_free(struct isds_message **message);
8707 int isds_address_free(struct isds_address **address);
8711 /* Makes known all relevant namespaces to given XPath context
8712 * @xpath_ctx is XPath context
8713 * @message_ns selects propper message name space. Unsisnged and signed
8714 * messages and delivery infos differ in prefix and URI. */
8715 _hidden isds_error
_isds_register_namespaces(xmlXPathContextPtr xpath_ctx
,
8716 const message_ns_type message_ns
) {
8717 const xmlChar
*message_namespace
= NULL
;
8719 if (!xpath_ctx
) return IE_ERROR
;
8721 switch(message_ns
) {
8723 message_namespace
= BAD_CAST ISDS1_NS
; break;
8724 case MESSAGE_NS_UNSIGNED
:
8725 message_namespace
= BAD_CAST ISDS_NS
; break;
8726 case MESSAGE_NS_SIGNED_INCOMING
:
8727 message_namespace
= BAD_CAST SISDS_INCOMING_NS
; break;
8728 case MESSAGE_NS_SIGNED_OUTGOING
:
8729 message_namespace
= BAD_CAST SISDS_OUTGOING_NS
; break;
8730 case MESSAGE_NS_SIGNED_DELIVERY
:
8731 message_namespace
= BAD_CAST SISDS_DELIVERY_NS
; break;
8736 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
8738 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
8740 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"sisds", message_namespace
))
8742 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))
8744 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"deposit", BAD_CAST DEPOSIT_NS
))