1 #define _XOPEN_SOURCE 500 /* strdup from string.h, strptime from time.h */
10 #include "validator.h"
13 /* Free isds_list with all member data.
14 * @list list to free, on return will be NULL */
15 void isds_list_free(struct isds_list
**list
) {
16 struct isds_list
*item
, *next_item
;
18 if (!list
|| !*list
) return;
20 for(item
= *list
; item
; item
= next_item
) {
21 (item
->destructor
)(&(item
->data
));
22 next_item
= item
->next
;
30 /* Deallocate structure isds_PersonName recursively and NULL it */
31 static void isds_PersonName_free(struct isds_PersonName
**person_name
) {
32 if (!person_name
|| !*person_name
) return;
34 free((*person_name
)->pnFirstName
);
35 free((*person_name
)->pnMiddleName
);
36 free((*person_name
)->pnLastName
);
37 free((*person_name
)->pnLastNameAtBirth
);
44 /* Deallocate structure isds_BirthInfo recursively and NULL it */
45 static void isds_BirthInfo_free(struct isds_BirthInfo
**birth_info
) {
46 if (!birth_info
|| !*birth_info
) return;
48 free((*birth_info
)->biDate
);
49 free((*birth_info
)->biCity
);
50 free((*birth_info
)->biCounty
);
51 free((*birth_info
)->biState
);
58 /* Deallocate structure isds_Address recursively and NULL it */
59 static void isds_Address_free(struct isds_Address
**address
) {
60 if (!address
|| !*address
) return;
62 free((*address
)->adCity
);
63 free((*address
)->adStreet
);
64 free((*address
)->adNumberInStreet
);
65 free((*address
)->adNumberInMunicipality
);
66 free((*address
)->adZipCode
);
67 free((*address
)->adState
);
74 /* Deallocate structure isds_DbOwnerInfo recursively and NULL it */
75 void isds_DbOwnerInfo_free(struct isds_DbOwnerInfo
**db_owner_info
) {
76 if (!db_owner_info
|| !*db_owner_info
) return;
78 free((*db_owner_info
)->dbID
);
79 free((*db_owner_info
)->dbType
);
80 free((*db_owner_info
)->ic
);
81 isds_PersonName_free(&((*db_owner_info
)->personName
));
82 free((*db_owner_info
)->firmName
);
83 isds_BirthInfo_free(&((*db_owner_info
)->birthInfo
));
84 isds_Address_free(&((*db_owner_info
)->address
));
85 free((*db_owner_info
)->nationality
);
86 free((*db_owner_info
)->email
);
87 free((*db_owner_info
)->telNumber
);
88 free((*db_owner_info
)->identifier
);
89 free((*db_owner_info
)->registryCode
);
90 free((*db_owner_info
)->dbState
);
91 free((*db_owner_info
)->dbEffectiveOVM
);
94 *db_owner_info
= NULL
;
98 /* Deallocate struct isds_envelope recurisvely and NULL it */
99 void isds_envelope_free(struct isds_envelope
**envelope
) {
100 if (!envelope
|| !*envelope
) return;
102 free((*envelope
)->dmID
);
103 free((*envelope
)->dbIDSender
);
104 free((*envelope
)->dmSender
);
105 free((*envelope
)->dmSenderAddress
);
106 free((*envelope
)->dmSenderType
);
107 free((*envelope
)->dmRecipient
);
108 free((*envelope
)->dmRecipientAddress
);
109 free((*envelope
)->dmAmbiguousRecipient
);
111 free((*envelope
)->dmOrdinal
);
112 free((*envelope
)->dmMessageStatus
);
113 free((*envelope
)->dmDeliveryTime
);
114 free((*envelope
)->dmAcceptanceTime
);
116 free((*envelope
)->dmSenderOrgUnit
);
117 free((*envelope
)->dmSenderOrgUnitNum
);
118 free((*envelope
)->dbIDRecipient
);
119 free((*envelope
)->dmRecipientOrgUnit
);
120 free((*envelope
)->dmRecipientOrgUnitNum
);
121 free((*envelope
)->dmToHands
);
122 free((*envelope
)->dmAnnotation
);
123 free((*envelope
)->dmRecipientRefNumber
);
124 free((*envelope
)->dmSenderRefNumber
);
125 free((*envelope
)->dmRecipientIdent
);
126 free((*envelope
)->dmSenderIdent
);
128 free((*envelope
)->dmLegalTitleLaw
);
129 free((*envelope
)->dmLegalTitleYear
);
130 free((*envelope
)->dmLegalTitleSect
);
131 free((*envelope
)->dmLegalTitlePar
);
132 free((*envelope
)->dmLegalTitlePoint
);
134 free((*envelope
)->dmPersonalDelivery
);
135 free((*envelope
)->dmAllowSubstDelivery
);
136 free((*envelope
)->dmOVM
);
143 /* Deallocate struct isds_message recurisvely and NULL it */
144 void isds_message_free(struct isds_message
**message
) {
145 if (!message
|| !*message
) return;
147 free((*message
)->raw
);
148 isds_envelope_free(&((*message
)->envelope
));
149 isds_list_free(&((*message
)->documents
));
156 /* Deallocate struct isds_document recurisvely and NULL it */
157 void isds_document_free(struct isds_document
**document
) {
158 if (!document
|| !*document
) return;
160 free((*document
)->data
);
161 free((*document
)->dmMimeType
);
162 free((*document
)->dmFileGuid
);
163 free((*document
)->dmUpFileGuid
);
164 free((*document
)->dmFileDescr
);
165 free((*document
)->dmFormat
);
172 /* Initialize ISDS library.
173 * Global function, must be called before other functions.
174 * If it failes you can not use ISDS library and must call isds_cleanup() to
175 * free partially inititialized global variables. */
176 isds_error
isds_init(void) {
177 /* NULL global variables */
180 log_facilities
= ILF_NONE
;
181 log_level
= ILL_NONE
;
183 /* Initialize CURL */
184 if (curl_global_init(CURL_GLOBAL_ALL
)) {
188 /* This can _exit() current program. Find not so assertive check. */
191 /* Allocate global variables */
192 if (!(xml_node
= xmlNewNode(NULL
, BAD_CAST
"global-element")))
194 if (!(soap_ns
= xmlNewNs(NULL
, BAD_CAST SOAP_NS
, BAD_CAST
"soap")))
196 if (!(isds_ns
= xmlNewNs(NULL
, BAD_CAST ISDS_NS
, BAD_CAST
"isds")))
203 /* Deinicialize ISDS library.
204 * Global function, must be called as last library function. */
205 isds_error
isds_cleanup(void) {
209 xmlFreeNode(xml_node
);
213 curl_global_cleanup();
219 /* Return text description of ISDS error */
220 char *isds_strerror(const isds_error error
) {
223 return(_("Success")); break;
225 return(_("Unspecified error")); break;
227 return(_("Not supported")); break;
229 return(_("Invalid value")); break;
230 case IE_INVALID_CONTEXT
:
231 return(_("Invalid context")); break;
232 case IE_NOT_LOGGED_IN
:
233 return(_("Not logged in")); break;
234 case IE_CONNECTION_CLOSED
:
235 return(_("Connection closed")); break;
237 return(_("Timed out")); break;
239 return(_("Not exist")); break;
241 return(_("Out of memory")); break;
243 return(_("Network problem")); break;
245 return(_("SOAP problem")); break;
247 return(_("XML problem")); break;
249 return(_("ISDS server problem")); break;
251 return(_("Invalid enum value")); break;
253 return(_("Invalid date value")); break;
255 return(_("Too big")); break;
257 return(_("Unknown error"));
262 /* Create ISDS context.
263 * Each context can be used for different sessions to (possibly) differnet
264 * ISDS server with different credentials. */
265 struct isds_ctx
*isds_ctx_create(void) {
266 struct isds_ctx
*context
;
267 context
= malloc(sizeof(*context
));
268 if (context
) memset(context
, 0, sizeof(*context
));
273 /* Destroy ISDS context and free memmory.
274 * @context will be NULLed on success. */
275 isds_error
isds_ctx_free(struct isds_ctx
**context
) {
276 if (!context
|| !*context
) {
277 return IE_INVALID_CONTEXT
;
280 /* Discard credentials */
281 isds_logout(*context
);
283 /* Free other structures */
284 free((*context
)->tls_verify_server
);
285 free((*context
)->tls_ca_file
);
286 free((*context
)->tls_ca_dir
);
287 free((*context
)->long_message
);
295 /* Return long message text produced by library fucntion, e.g. detailed error
296 * mesage. Returned pointer is only valid until new library function is
297 * called for the same context. Could be NULL, especially if NULL context is
298 * supplied. Return string is locale encoded. */
299 char *isds_long_message(const struct isds_ctx
*context
) {
300 if (!context
) return NULL
;
301 return context
->long_message
;
305 /* Stores message into context' long_message buffer.
306 * Application can pick the message up using isds_long_message().
307 * NULL @message truncates the buffer but does not deallocate it.
308 * @message is coded in locale encoding */
309 _hidden isds_error
isds_log_message(struct isds_ctx
*context
,
310 const char *message
) {
314 if (!context
) return IE_INVALID_CONTEXT
;
316 /* FIXME: Check for integer overflow */
317 length
= 1 + ((message
) ? strlen(message
) : 0);
318 buffer
= realloc(context
->long_message
, length
);
319 if (!buffer
) return IE_NOMEM
;
322 strcpy(buffer
, message
);
326 context
->long_message
= buffer
;
331 /* Appends message into context' long_message buffer.
332 * Application can pick the message up using isds_long_message().
333 * NULL message has void effect. */
334 _hidden isds_error
isds_append_message(struct isds_ctx
*context
,
335 const char *message
) {
337 size_t old_length
, length
;
339 if (!context
) return IE_INVALID_CONTEXT
;
340 if (!message
) return IE_SUCCESS
;
341 if (!context
->long_message
)
342 return isds_log_message(context
, message
);
344 old_length
= strlen(context
->long_message
);
345 /* FIXME: Check for integer overflow */
346 length
= 1 + old_length
+ strlen(message
);
347 buffer
= realloc(context
->long_message
, length
);
348 if (!buffer
) return IE_NOMEM
;
350 strcpy(buffer
+ old_length
, message
);
352 context
->long_message
= buffer
;
357 /* Stores formated message into context' long_message buffer.
358 * Application can pick the message up using isds_long_message(). */
359 _hidden isds_error
isds_printf_message(struct isds_ctx
*context
,
360 const char *format
, ...) {
364 if (!context
) return IE_INVALID_CONTEXT
;
365 va_start(ap
, format
);
366 length
= isds_vasprintf(&(context
->long_message
), format
, ap
);
369 return (length
< 0) ? IE_ERROR
: IE_SUCCESS
;
374 * @facilities is bitmask of isds_log_facility values,
375 * @level is verbosity level. */
376 void isds_set_logging(const unsigned int facilities
,
377 const isds_log_level level
) {
378 log_facilities
= facilities
;
383 /* Log @message in class @facility with log @level into global log. @message
384 * is printf(3) formating string, variadic arguments may be neccessary.
385 * For debugging purposes. */
386 _hidden isds_error
isds_log(const isds_log_facility facility
,
387 const isds_log_level level
, const char *message
, ...) {
390 if (level
> log_level
) return IE_SUCCESS
;
391 if (!(log_facilities
& facility
)) return IE_SUCCESS
;
392 if (!message
) return IE_INVAL
;
394 /* TODO: Allow to register output function privided by application
395 * (e.g. fprintf to stderr or copy to text area GUI widget). */
397 va_start(ap
, message
);
398 vfprintf(stderr
, message
, ap
);
400 /* Line buffered printf is default.
407 /* Connect to given url.
408 * It just makes TCP connection to ISDS server found in @url hostname part. */
409 /*int isds_connect(struct isds_ctx *context, const char *url);*/
411 /* Set timeout in miliseconds for each network job like connecting to server
412 * or sending message. Use 0 to disable timeout limits. */
413 isds_error
isds_set_timeout(struct isds_ctx
*context
,
414 const unsigned int timeout
) {
415 if (!context
) return IE_INVALID_CONTEXT
;
417 context
->timeout
= timeout
;
422 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_NOSIGNAL
, 1);
424 curl_err
= curl_easy_setopt(context
->curl
, CURLOPT_TIMEOUT_MS
,
426 if (curl_err
) return IE_ERROR
;
433 /* Change SSL/TLS settings.
434 * @context is context which setting vill be applied to
435 * @option is name of option. It determines the type of last argument. See
436 * isds_tls_option definition for more info.
437 * @... is value of new setting. Type is determined by @option
439 isds_error
isds_set_tls(struct isds_ctx
*context
, const isds_tls_option option
,
441 isds_error err
= IE_SUCCESS
;
443 char *pointer
, *string
;
445 if (!context
) return IE_INVALID_CONTEXT
;
447 va_start(ap
, option
);
449 #define REPLACE_VA_STRING(destination) \
450 string = va_arg(ap, char *); \
452 pointer = realloc((destination), 1 + strlen(string)); \
453 if (!pointer) { err = IE_NOMEM; goto leave; } \
454 strcpy(pointer, string); \
455 (destination) = pointer; \
458 (destination) = NULL; \
462 case ITLS_VERIFY_SERVER
:
463 if (!context
->tls_verify_server
) {
464 context
->tls_verify_server
=
465 malloc(sizeof(*context
->tls_verify_server
));
466 if (!context
->tls_verify_server
) {
467 err
= IE_NOMEM
; goto leave
;
470 *context
->tls_verify_server
= (_Bool
) (0 != va_arg(ap
, int));
474 REPLACE_VA_STRING(context
->tls_ca_file
);
476 case ITLS_CA_DIRECTORY
:
477 REPLACE_VA_STRING(context
->tls_ca_dir
);
481 err
= IE_ENUM
; goto leave
;
484 #undef REPLACE_VA_STRING
492 /* Discard credentials.
493 * Only that. It does not cause log out, connection close or similar. */
494 static isds_error
discard_credentials(struct isds_ctx
*context
) {
495 if(!context
) return IE_INVALID_CONTEXT
;
497 if (context
->username
) {
498 memset(context
->username
, 0, strlen(context
->username
));
499 free(context
->username
);
500 context
->username
= NULL
;
502 if (context
->password
) {
503 memset(context
->password
, 0, strlen(context
->password
));
504 free(context
->password
);
505 context
->password
= NULL
;
512 /* Connect and log in into ISDS server.
513 * @url is address of ISDS web service
514 * @username is user name of ISDS user
515 * @password is user's secret password
516 * @certificate is NULL terminated string with PEM formated client's
517 * certificate. Use NULL if only password autentication should be performed.
518 * @key is private key for client's certificate as (base64 encoded?) NULL
519 * terminated string. Use NULL if only password autentication is desired.
521 isds_error
isds_login(struct isds_ctx
*context
, const char *url
,
522 const char *username
, const char *password
,
523 const char *certificate
, const char* key
) {
524 isds_error err
= IE_NOT_LOGGED_IN
;
526 xmlNsPtr isds_ns
= NULL
;
527 xmlNodePtr request
= NULL
;
528 xmlNodePtr response
= NULL
;
530 if (!context
) return IE_INVALID_CONTEXT
;
531 if (!url
|| !username
|| !password
) return IE_INVAL
;
532 if (certificate
|| key
) return IE_NOTSUP
;
534 /* Store configuration */
536 context
->url
= strdup(url
);
540 /* Close connection if already logged in */
542 close_connection(context
);
545 /* Prepare CURL handle */
546 context
->curl
= curl_easy_init();
547 if (!(context
->curl
))
550 /* Build login request */
551 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
553 isds_log_message(context
, _("Could build ISDS login request"));
556 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
558 isds_log_message(context
, _("Could not create ISDS name space"));
559 xmlFreeNode(request
);
562 xmlSetNs(request
, isds_ns
);
564 /* Store credentials */
565 /* FIXME: mlock password
566 * (I have a library) */
567 discard_credentials(context
);
568 context
->username
= strdup(username
);
569 context
->password
= strdup(password
);
570 if (!(context
->username
&& context
->password
)) {
571 discard_credentials(context
);
572 xmlFreeNode(request
);
576 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logging user %s into server %s\n"),
579 /* Send login request */
580 soap_err
= soap(context
, "dz", request
, &response
);
582 /* Remove credentials */
583 discard_credentials(context
);
585 /* Destroy login request */
586 xmlFreeNode(request
);
589 xmlFreeNodeList(response
);
590 close_connection(context
);
594 /* XXX: Until we don't propagate HTTP code 500 or 4xx, we can be sure
595 * authentication succeeded if soap_err == IE_SUCCESS */
598 xmlFreeNodeList(response
);
601 isds_log(ILF_ISDS
, ILL_DEBUG
,
602 _("User %s has been logged into server %s successfully\n"),
608 /* Log out from ISDS server discards credentials and connection configuration. */
609 isds_error
isds_logout(struct isds_ctx
*context
) {
610 if (!context
) return IE_INVALID_CONTEXT
;
612 /* Close connection */
614 close_connection(context
);
616 /* Discard credentials for sure. They should not survive isds_login(),
617 * even successful .*/
618 discard_credentials(context
);
622 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Logged out from ISDS server\n"));
624 discard_credentials(context
);
630 /* Verify connection to ISDS is alive and server is responding.
631 * Sent dumy request to ISDS and expect dummy response. */
632 isds_error
isds_ping(struct isds_ctx
*context
) {
634 xmlNsPtr isds_ns
= NULL
;
635 xmlNodePtr request
= NULL
;
636 xmlNodePtr response
= NULL
;
638 if (!context
) return IE_INVALID_CONTEXT
;
640 /* Check if connection is established */
641 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
644 /* Build dummy request */
645 request
= xmlNewNode(NULL
, BAD_CAST
"DummyOperation");
647 isds_log_message(context
, _("Could build ISDS dummy request"));
650 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
652 isds_log_message(context
, _("Could not create ISDS name space"));
653 xmlFreeNode(request
);
656 xmlSetNs(request
, isds_ns
);
658 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Pinging ISDS server\n"));
660 /* Sent dummy request */
661 soap_err
= soap(context
, "dz", request
, &response
);
663 /* Destroy login request */
664 xmlFreeNode(request
);
667 isds_log(ILF_ISDS
, ILL_DEBUG
,
668 _("ISDS server could not be contacted\n"));
669 xmlFreeNodeList(response
);
670 close_connection(context
);
674 /* XXX: Untill we don't propagate HTTP code 500 or 4xx, we can be sure
675 * authentication succeeded if soap_err == IE_SUCCESS */
676 /* TODO: ISDS documentation does not specify response body.
677 * However real server sends back DummyOperationResponse */
680 xmlFreeNodeList(response
);
682 isds_log(ILF_ISDS
, ILL_DEBUG
, _("ISDS server alive\n"));
688 /* Send bogus request to ISDS.
689 * Just for test purposes */
690 isds_error
isds_bogus_request(struct isds_ctx
*context
) {
692 xmlNsPtr isds_ns
= NULL
;
693 xmlNodePtr request
= NULL
;
694 xmlDocPtr response
= NULL
;
695 xmlChar
*code
= NULL
, *message
= NULL
;
697 if (!context
) return IE_INVALID_CONTEXT
;
699 /* Check if connection is established */
700 if (!context
->curl
) {
701 /* Testing printf message */
702 isds_printf_message(context
, "%s", _("I said connection closed"));
703 return IE_CONNECTION_CLOSED
;
707 /* Build dummy request */
708 request
= xmlNewNode(NULL
, BAD_CAST
"X-BogusOperation");
710 isds_log_message(context
, _("Could build ISDS bogus request"));
713 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
715 isds_log_message(context
, _("Could not create ISDS name space"));
716 xmlFreeNode(request
);
719 xmlSetNs(request
, isds_ns
);
721 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending bogus request to ISDS\n"));
723 /* Sent bogus request */
724 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
726 /* Destroy request */
727 xmlFreeNode(request
);
730 isds_log(ILF_ISDS
, ILL_DEBUG
,
731 _("Processing ISDS response on bogus request failed\n"));
732 xmlFreeDoc(response
);
736 /* Check for response status */
737 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
738 &code
, &message
, NULL
);
740 isds_log(ILF_ISDS
, ILL_DEBUG
,
741 _("ISDS response on bogus request is missing status\n"));
744 xmlFreeDoc(response
);
747 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
748 char *code_locale
= utf82locale((char*)code
);
749 char *message_locale
= utf82locale((char*)message
);
750 isds_log(ILF_ISDS
, ILL_DEBUG
,
751 _("Server refused bogus request (code=%s, message=%s)\n"),
752 code_locale
, message_locale
);
753 /* XXX: Literal error messages from ISDS are Czech mesages
754 * (English sometimes) in UTF-8. It's hard to catch them for
755 * translation. Successfully gettextized would return in locale
756 * encoding, unsuccessfully translated would pass in UTF-8. */
757 isds_log_message(context
, message_locale
);
759 free(message_locale
);
762 xmlFreeDoc(response
);
769 xmlFreeDoc(response
);
771 isds_log(ILF_ISDS
, ILL_DEBUG
,
772 _("Bogus message accepted by server. This should not happen.\n"));
778 /* Convert UTF-8 @string represantion of ISDS dbType to enum @type */
779 static isds_error
string2isds_DbType(xmlChar
*string
, isds_DbType
*type
) {
780 if (!string
|| !type
) return IE_INVAL
;
782 if (!xmlStrcmp(string
, BAD_CAST
"FO"))
784 else if (!xmlStrcmp(string
, BAD_CAST
"PFO"))
786 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_ADVOK"))
787 *type
= DBTYPE_PFO_ADVOK
;
788 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_DANPOR"))
789 *type
= DBTYPE_PFO_DANPOR
;
790 else if (!xmlStrcmp(string
, BAD_CAST
"PFO_INSSPR"))
791 *type
= DBTYPE_PFO_INSSPR
;
792 else if (!xmlStrcmp(string
, BAD_CAST
"PO"))
794 else if (!xmlStrcmp(string
, BAD_CAST
"PO_ZAK"))
795 *type
= DBTYPE_PO_ZAK
;
796 else if (!xmlStrcmp(string
, BAD_CAST
"PO_REQ"))
797 *type
= DBTYPE_PO_REQ
;
798 else if (!xmlStrcmp(string
, BAD_CAST
"OVM"))
800 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_NOTAR"))
801 *type
= DBTYPE_OVM_NOTAR
;
802 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_EXEKUT"))
803 *type
= DBTYPE_OVM_EXEKUT
;
804 else if (!xmlStrcmp(string
, BAD_CAST
"OVM_REQ"))
805 *type
= DBTYPE_OVM_REQ
;
812 /* Convert ISDS dbType enum @type to UTF-8 string.
813 * @Return pointer to static string, or NULL if unkwnow enum value */
814 static const xmlChar
*isds_DbType2string(const isds_DbType type
) {
816 case DBTYPE_FO
: return(BAD_CAST
"FO"); break;
817 case DBTYPE_PFO
: return(BAD_CAST
"PFO"); break;
818 case DBTYPE_PFO_ADVOK
: return(BAD_CAST
"PFO_ADVOK"); break;
819 case DBTYPE_PFO_DANPOR
: return(BAD_CAST
"PFO_DAPOR"); break;
820 case DBTYPE_PFO_INSSPR
: return(BAD_CAST
"PFO_INSSPR"); break;
821 case DBTYPE_PO
: return(BAD_CAST
"PO"); break;
822 case DBTYPE_PO_ZAK
: return(BAD_CAST
"PO_ZAK"); break;
823 case DBTYPE_PO_REQ
: return(BAD_CAST
"PO_REQ"); break;
824 case DBTYPE_OVM
: return(BAD_CAST
"OVM"); break;
825 case DBTYPE_OVM_NOTAR
: return(BAD_CAST
"OVM_NOTAR"); break;
826 case DBTYPE_OVM_EXEKUT
: return(BAD_CAST
"OVM_EXEKUT"); break;
827 case DBTYPE_OVM_REQ
: return(BAD_CAST
"OVM_REQ"); break;
828 default: return NULL
; break;
833 /* Convert ISDS dmFileMetaType enum @type to UTF-8 string.
834 * @Return pointer to static string, or NULL if unkwnow enum value */
835 static const xmlChar
*isds_FileMetaType2string(const isds_FileMetaType type
) {
837 case FILEMETATYPE_MAIN
: return(BAD_CAST
"main"); break;
838 case FILEMETATYPE_ENCLOSURE
: return(BAD_CAST
"enclosure"); break;
839 case FILEMETATYPE_SIGNATURE
: return(BAD_CAST
"signature"); break;
840 case FILEMETATYPE_META
: return(BAD_CAST
"meta"); break;
841 default: return NULL
; break;
846 /* Convert UTF-8 @string represantion of ISO 8601 date to @time.
847 * XXX: Not all ISO formats are supported */
848 static isds_error
datestring2tm(const xmlChar
*string
, struct tm
*time
) {
850 if (!string
|| !time
) return IE_INVAL
;
852 /* xsd:date is ISO 8601 string, thus ASCII */
853 offset
= strptime((char*)string
, "%Y-%m-%d", time
);
854 if (offset
&& *offset
== '\0')
857 offset
= strptime((char*)string
, "%Y%m%d", time
);
858 if (offset
&& *offset
== '\0')
861 offset
= strptime((char*)string
, "%Y-%j", time
);
862 if (offset
&& *offset
== '\0')
869 /* Convert struct tm *@time to UTF-8 ISO 8601 date @string. */
870 static isds_error
tm2datestring(const struct tm
*time
, xmlChar
**string
) {
871 if (!time
|| !string
) return IE_INVAL
;
873 if (-1 == isds_asprintf((char **) string
, "%d-%02d-%02d",
874 time
->tm_year
+ 1900, time
->tm_mon
+ 1, time
->tm_mday
))
881 /* Convert struct timeval * @time to UTF-8 ISO 8601 date-time @string. It
882 * respects the @time microseconds too. */
883 static isds_error
timeval2timestring(const struct timeval
*time
,
887 if (!time
|| !string
) return IE_INVAL
;
889 if (!gmtime_r(&time
->tv_sec
, &broken
)) return IE_DATE
;
890 if (time
->tv_usec
< 0 || time
->tv_usec
> 999999) return IE_DATE
;
892 /* TODO: small negative year should be formated as "-0012". This is not
893 * true for glibc "%04d". We should implement it.
894 * TODO: What's type of time->tv_usec exactly? Unsigned? Absolute?
895 * See <http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#dateTime> */
896 if (-1 == isds_asprintf((char **) string
,
897 "%04d-%02d-%02dT%02d:%02d:%02d.%06ld",
898 broken
.tm_year
+ 1900, broken
.tm_mon
+ 1, broken
.tm_mday
,
899 broken
.tm_hour
, broken
.tm_min
, broken
.tm_sec
,
907 /* Convert UTF-8 ISO 8601 date-time @string to struct timeval.
908 * It respects microseconds too.
909 * In case of error, @time will be freed. */
910 static isds_error
timestring2timeval(const xmlChar
*string
,
911 struct timeval
**time
) {
913 char *offset
, *delim
, *endptr
;
915 int offset_hours
, offset_minutes
;
918 if (!time
) return IE_INVAL
;
920 memset(&broken
, 0, sizeof(broken
));
923 *time
= calloc(1, sizeof(**time
));
924 if (!*time
) return IE_NOMEM
;
926 memset(*time
, 0, sizeof(**time
));
930 /* xsd:date is ISO 8601 string, thus ASCII */
931 /*TODO: negative year */
933 /* Parse date and time without subseconds and offset */
934 offset
= strptime((char*)string
, "%Y-%m-%dT%T", &broken
);
936 free(*time
); *time
= NULL
;
941 if (*offset
== '.' ) {
944 /* Copy first 6 digits, padd it with zeros.
945 * XXX: It truncates longer number, no round.
946 * Current server implementation uses only milisecond resolution. */
947 /* TODO: isdigit() is locale sensitive */
949 i
< sizeof(subseconds
)/sizeof(char) - 1 && isdigit(*offset
);
951 subseconds
[i
] = *offset
;
953 for (; i
< sizeof(subseconds
)/sizeof(char) - 1; i
++) {
956 subseconds
[6] = '\0';
958 /* Convert it into integer */
959 (*time
)->tv_usec
= strtol(subseconds
, &endptr
, 10);
960 if (*endptr
!= '\0' || (*time
)->tv_usec
== LONG_MIN
||
961 (*time
)->tv_usec
== LONG_MAX
) {
962 free(*time
); *time
= NULL
;
966 /* move to the zone offset delimiter */
967 delim
= strchr(offset
, '-');
969 delim
= strchr(offset
, '+');
973 /* Get zone offset */
974 /* ISO allows zone offset string only: "" | "Z" | ("+"|"-" "<HH>:<MM>")
975 * "" equals to "Z" and it means UTC zone. */
976 /* One can not use strptime(, "%z",) becase it's RFC E-MAIL format without
978 if (*offset
== '-' || *offset
== '+') {
980 if (2 != sscanf(offset
, "%2d:%2d", &offset_hours
, &offset_minutes
)) {
981 free(*time
); *time
= NULL
;
984 broken
.tm_hour
-= offset_hours
;
985 broken
.tm_min
-= offset_minutes
* ((offset_hours
<0) ? -1 : 1);
988 /* Convert to time_t */
990 (*time
)->tv_sec
= mktime(&broken
);
991 switch_tz_to_native();
992 if ((*time
)->tv_sec
== (time_t) -1) {
993 free(*time
); *time
= NULL
;
1001 /* Convert unsigned int into isds_message_status.
1002 * @context is session context
1003 * @number is pointer to number value. NULL will be treated as invalid value.
1004 * @status is automatically reallocated status
1005 * @return IE_SUCCESS, or error code and free status */
1006 static isds_error
uint2isds_message_status(struct isds_ctx
*context
,
1007 const unsigned long int *number
, isds_message_status
**status
) {
1008 if (!context
) return IE_INVALID_CONTEXT
;
1009 if (!status
) return IE_INVAL
;
1011 free(*status
); *status
= NULL
;
1012 if (!number
) return IE_INVAL
;
1014 if (*number
< 1 || *number
> 9) {
1015 isds_printf_message(context
, _("Invalid messsage status value: %lu"),
1020 *status
= malloc(sizeof(**status
));
1021 if (!*status
) return IE_NOMEM
;
1023 **status
= 1 << *number
;
1028 /* Following EXTRACT_* macros expects @result, @xpath_ctx, @err, @context
1029 * and leave lable */
1030 #define EXTRACT_STRING(element, string) \
1031 result = xmlXPathEvalExpression(BAD_CAST element "/text()", xpath_ctx); \
1036 if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) { \
1037 if (result->nodesetval->nodeNr > 1) { \
1038 isds_log_message(context, _("Multiple " element " element")); \
1042 (string) = (char *) \
1043 xmlXPathCastNodeSetToString(result->nodesetval); \
1050 #define EXTRACT_BOOLEAN(element, booleanPtr) \
1052 char *string = NULL; \
1053 EXTRACT_STRING(element, string); \
1056 (booleanPtr) = calloc(1, sizeof(*(booleanPtr))); \
1057 if (!(booleanPtr)) { \
1063 if (!xmlStrcmp((xmlChar *)string, BAD_CAST "true") || \
1064 !xmlStrcmp((xmlChar *)string, BAD_CAST "1")) \
1065 *(booleanPtr) = 1; \
1066 else if (!xmlStrcmp((xmlChar *)string, BAD_CAST "false") || \
1067 !xmlStrcmp((xmlChar *)string, BAD_CAST "0")) \
1068 *(booleanPtr) = 0; \
1070 char *string_locale = utf82locale((char*)string); \
1071 isds_printf_message(context, \
1072 _(element " value is not valid boolean: "), \
1074 free(string_locale); \
1084 #define EXTRACT_LONGINT(element, longintPtr, preallocated) \
1086 char *string = NULL; \
1087 EXTRACT_STRING(element, string); \
1092 number = strtol((char*)string, &endptr, 10); \
1094 if (*endptr != '\0') { \
1095 char *string_locale = utf82locale((char *)string); \
1096 isds_printf_message(context, \
1097 _(element" is not valid integer: %s"), \
1099 free(string_locale); \
1105 if (number == LONG_MIN || number == LONG_MAX) { \
1106 char *string_locale = utf82locale((char *)string); \
1107 isds_printf_message(context, \
1108 _(element " value out of range of long int: %s"), \
1110 free(string_locale); \
1116 free(string); string = NULL; \
1118 if (!(preallocated)) { \
1119 (longintPtr) = calloc(1, sizeof(*(longintPtr))); \
1120 if (!(longintPtr)) { \
1125 *(longintPtr) = number; \
1129 #define EXTRACT_ULONGINT(element, ulongintPtr, preallocated) \
1131 char *string = NULL; \
1132 EXTRACT_STRING(element, string); \
1137 number = strtol((char*)string, &endptr, 10); \
1139 if (*endptr != '\0') { \
1140 char *string_locale = utf82locale((char *)string); \
1141 isds_printf_message(context, \
1142 _(element" is not valid integer: %s"), \
1144 free(string_locale); \
1150 if (number == LONG_MIN || number == LONG_MAX) { \
1151 char *string_locale = utf82locale((char *)string); \
1152 isds_printf_message(context, \
1153 _(element " value out of range of long int: %s"), \
1155 free(string_locale); \
1161 free(string); string = NULL; \
1163 isds_printf_message(context, \
1164 _(element " value is negative: %ld"), number); \
1169 if (!(preallocated)) { \
1170 (ulongintPtr) = calloc(1, sizeof(*(ulongintPtr))); \
1171 if (!(ulongintPtr)) { \
1176 *(ulongintPtr) = number; \
1181 #define INSERT_STRING(parent, element, string) \
1182 node = xmlNewTextChild(parent, NULL, BAD_CAST (element), \
1183 (xmlChar *) (string)); \
1185 isds_printf_message(context, _("Could not add " element " child to " \
1186 "%s element"), (parent)->name); \
1191 #define INSERT_BOOLEAN(parent, element, booleanPtr) \
1192 if ((booleanPtr)) { \
1193 if (*(booleanPtr)) { INSERT_STRING(parent, element, "true"); } \
1194 else { INSERT_STRING(parent, element, "false") } \
1195 } else { INSERT_STRING(parent, element, NULL) }
1197 #define INSERT_LONGINT(parent, element, longintPtr, buffer) \
1198 if ((longintPtr)) { \
1199 /* FIXME: locale sensitive */ \
1200 if (-1 == isds_asprintf((char **)&(buffer), "%ld", *(longintPtr))) { \
1204 INSERT_STRING(parent, element, buffer) \
1205 free(buffer); (buffer) = NULL; \
1206 } else { INSERT_STRING(parent, element, NULL) }
1208 #define INSERT_ULONGINT(parent, element, ulongintPtr, buffer) \
1209 if ((ulongintPtr)) { \
1210 /* FIXME: locale sensitive */ \
1211 if (-1 == isds_asprintf((char **)&(buffer), "%lu", *(ulongintPtr))) { \
1215 INSERT_STRING(parent, element, buffer) \
1216 free(buffer); (buffer) = NULL; \
1217 } else { INSERT_STRING(parent, element, NULL) }
1219 #define INSERT_ULONGINTNOPTR(parent, element, ulongint, buffer) \
1220 /* FIXME: locale sensitive */ \
1221 if (-1 == isds_asprintf((char **)&(buffer), "%lu", ulongint)) { \
1225 INSERT_STRING(parent, element, buffer) \
1226 free(buffer); (buffer) = NULL; \
1228 #define INSERT_STRING_ATTRIBUTE(parent, attribute, string) \
1229 attribute_node = xmlNewProp((parent), BAD_CAST (attribute), \
1230 (xmlChar *) (string)); \
1231 if (!attribute_node) { \
1232 isds_printf_message(context, _("Could not add " attribute \
1233 " attribute to %s element"), (parent)->name); \
1239 /* Convert isds:dBOwnerInfo XML tree into structure
1240 * @context is ISDS context
1241 * @db_owner_info is automically reallocated box owner info structure
1242 * @xpath_ctx is XPath context with current node as isds:dBOwnerInfo element
1243 * In case of error @db_owner_info will be freed. */
1244 static isds_error
extract_DbOwnerInfo(struct isds_ctx
*context
,
1245 struct isds_DbOwnerInfo
**db_owner_info
,
1246 xmlXPathContextPtr xpath_ctx
) {
1247 isds_error err
= IE_SUCCESS
;
1248 xmlXPathObjectPtr result
= NULL
;
1249 char *string
= NULL
;
1251 if (!context
) return IE_INVALID_CONTEXT
;
1252 if (!db_owner_info
) return IE_INVAL
;
1253 isds_DbOwnerInfo_free(db_owner_info
);
1254 if (!xpath_ctx
) return IE_INVAL
;
1257 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
1258 if (!*db_owner_info
) {
1263 EXTRACT_STRING("isds:dbID", (*db_owner_info
)->dbID
);
1265 EXTRACT_STRING("isds:dbType", string
);
1267 (*db_owner_info
)->dbType
=
1268 calloc(1, sizeof(*((*db_owner_info
)->dbType
)));
1269 if (!(*db_owner_info
)->dbType
) {
1273 err
= string2isds_DbType((xmlChar
*)string
, (*db_owner_info
)->dbType
);
1275 free((*db_owner_info
)->dbType
);
1276 (*db_owner_info
)->dbType
= NULL
;
1277 if (err
== IE_ENUM
) {
1279 isds_printf_message(context
, _("Unknown isds:dbType: %s"),
1284 free(string
); string
= NULL
;
1287 EXTRACT_STRING("isds:ic", (*db_owner_info
)->ic
);
1289 (*db_owner_info
)->personName
=
1290 calloc(1, sizeof(*((*db_owner_info
)->personName
)));
1291 if (!(*db_owner_info
)->personName
) {
1295 EXTRACT_STRING("isds:pnFirstName",
1296 (*db_owner_info
)->personName
->pnFirstName
);
1297 EXTRACT_STRING("isds:pnMiddleName",
1298 (*db_owner_info
)->personName
->pnMiddleName
);
1299 EXTRACT_STRING("isds:pnLastName",
1300 (*db_owner_info
)->personName
->pnLastName
);
1301 EXTRACT_STRING("isds:pnLastNameAtBirth",
1302 (*db_owner_info
)->personName
->pnLastNameAtBirth
);
1303 if (!(*db_owner_info
)->personName
->pnFirstName
&&
1304 !(*db_owner_info
)->personName
->pnMiddleName
&&
1305 !(*db_owner_info
)->personName
->pnLastName
&&
1306 !(*db_owner_info
)->personName
->pnLastNameAtBirth
)
1307 isds_PersonName_free(&(*db_owner_info
)->personName
);
1309 EXTRACT_STRING("isds:firmName", (*db_owner_info
)->firmName
);
1311 (*db_owner_info
)->birthInfo
=
1312 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
)));
1313 if (!(*db_owner_info
)->birthInfo
) {
1317 EXTRACT_STRING("isds:biDate", string
);
1319 (*db_owner_info
)->birthInfo
->biDate
=
1320 calloc(1, sizeof(*((*db_owner_info
)->birthInfo
->biDate
)));
1321 if (!(*db_owner_info
)->birthInfo
->biDate
) {
1325 err
= datestring2tm((xmlChar
*)string
,
1326 (*db_owner_info
)->birthInfo
->biDate
);
1328 free((*db_owner_info
)->birthInfo
->biDate
);
1329 (*db_owner_info
)->birthInfo
->biDate
= NULL
;
1330 if (err
== IE_NOTSUP
) {
1332 isds_printf_message(context
,
1333 _("Invalid isds:biDate value: %s"), (char *)string
);
1337 free(string
); string
= NULL
;
1339 EXTRACT_STRING("isds:biCity", (*db_owner_info
)->birthInfo
->biCity
);
1340 EXTRACT_STRING("isds:biCounty", (*db_owner_info
)->birthInfo
->biCounty
);
1341 EXTRACT_STRING("isds:biState", (*db_owner_info
)->birthInfo
->biState
);
1342 if (!(*db_owner_info
)->birthInfo
->biDate
&&
1343 !(*db_owner_info
)->birthInfo
->biCity
&&
1344 !(*db_owner_info
)->birthInfo
->biCounty
&&
1345 !(*db_owner_info
)->birthInfo
->biState
)
1346 isds_BirthInfo_free(&(*db_owner_info
)->birthInfo
);
1348 (*db_owner_info
)->address
=
1349 calloc(1, sizeof(*((*db_owner_info
)->address
)));
1350 if (!(*db_owner_info
)->address
) {
1354 EXTRACT_STRING("isds:adCity",
1355 (*db_owner_info
)->address
->adCity
);
1356 EXTRACT_STRING("isds:adStreet",
1357 (*db_owner_info
)->address
->adStreet
);
1358 EXTRACT_STRING("isds:adNumberInStreet",
1359 (*db_owner_info
)->address
->adNumberInStreet
);
1360 EXTRACT_STRING("isds:adNumberInMunicipality",
1361 (*db_owner_info
)->address
->adNumberInMunicipality
);
1362 EXTRACT_STRING("isds:adZipCode",
1363 (*db_owner_info
)->address
->adZipCode
);
1364 EXTRACT_STRING("isds:adState",
1365 (*db_owner_info
)->address
->adState
);
1366 if (!(*db_owner_info
)->address
->adCity
&&
1367 !(*db_owner_info
)->address
->adStreet
&&
1368 !(*db_owner_info
)->address
->adNumberInStreet
&&
1369 !(*db_owner_info
)->address
->adNumberInMunicipality
&&
1370 !(*db_owner_info
)->address
->adZipCode
&&
1371 !(*db_owner_info
)->address
->adState
)
1372 isds_Address_free(&(*db_owner_info
)->address
);
1374 EXTRACT_STRING("isds:nationality", (*db_owner_info
)->nationality
);
1375 EXTRACT_STRING("isds:email", (*db_owner_info
)->email
);
1376 EXTRACT_STRING("isds:telNumber", (*db_owner_info
)->telNumber
);
1377 EXTRACT_STRING("isds:identifier", (*db_owner_info
)->identifier
);
1378 EXTRACT_STRING("isds:registryCode", (*db_owner_info
)->registryCode
);
1380 EXTRACT_LONGINT("isds:dbState", (*db_owner_info
)->dbState
, 0);
1382 EXTRACT_BOOLEAN("isds:dbEffectiveOVM", (*db_owner_info
)->dbEffectiveOVM
);
1383 EXTRACT_BOOLEAN("isds:dbOpenAddressing",
1384 (*db_owner_info
)->dbOpenAddressing
);
1387 if (err
) isds_DbOwnerInfo_free(db_owner_info
);
1389 xmlXPathFreeObject(result
);
1394 /* Convert XSD gMessageEnvelope group of elements from XML tree into
1395 * isds_envelope structure. The envelope is automatically allocated but not
1396 * reallocated. The date are just appended into envelope structure.
1397 * @context is ISDS context
1398 * @envelope is automically allocated message envelope structure
1399 * @xpath_ctx is XPath context with current node as gMessageEnvelope parent
1400 * In case of error @envelope will be freed. */
1401 static isds_error
append_GMessageEnvelope(struct isds_ctx
*context
,
1402 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1403 isds_error err
= IE_SUCCESS
;
1404 xmlXPathObjectPtr result
= NULL
;
1406 if (!context
) return IE_INVALID_CONTEXT
;
1407 if (!envelope
) return IE_INVAL
;
1408 if (!xpath_ctx
) return IE_INVAL
;
1412 /* Allocate envelope */
1413 *envelope
= calloc(1, sizeof(**envelope
));
1419 /* Else free former data */
1420 zfree((*envelope
)->dmID
);
1421 zfree((*envelope
)->dbIDSender
);
1422 zfree((*envelope
)->dmSender
);
1423 zfree((*envelope
)->dmSenderAddress
);
1424 zfree((*envelope
)->dmSenderType
);
1425 zfree((*envelope
)->dmRecipient
);
1426 zfree((*envelope
)->dmRecipientAddress
);
1427 zfree((*envelope
)->dmAmbiguousRecipient
);
1430 /* Extract envelope elements added by ISDS
1431 * (XSD: gMessageEnvelope type) */
1432 EXTRACT_STRING("isds:dmID", (*envelope
)->dmID
);
1433 EXTRACT_STRING("isds:dbIDSender", (*envelope
)->dbIDSender
);
1434 EXTRACT_STRING("isds:dmSender", (*envelope
)->dmSender
);
1435 EXTRACT_STRING("isds:dmSenderAddress", (*envelope
)->dmSenderAddress
);
1436 /* XML Schema does not guaratee enumratation. It's plain xs:int. */
1437 EXTRACT_LONGINT("isds:dmSenderType", (*envelope
)->dmSenderType
, 0);
1438 EXTRACT_STRING("isds:dmRecipient", (*envelope
)->dmRecipient
);
1439 EXTRACT_STRING("isds:dmRecipientAddress", (*envelope
)->dmRecipientAddress
);
1440 EXTRACT_BOOLEAN("isds:dmAmbiguousRecipient",
1441 (*envelope
)->dmAmbiguousRecipient
);
1444 if (err
) isds_envelope_free(envelope
);
1445 xmlXPathFreeObject(result
);
1450 /* Convert other envelope elements from XML tree into isds_envelope structure:
1451 * dmMessageStatus, dmAttachmentSize, dmDeliveryTime, dmAcceptanceTime.
1452 * The envelope is automatically allocated but not reallocated.
1453 * The data are just appended into envelope structure.
1454 * @context is ISDS context
1455 * @envelope is automically allocated message envelope structure
1456 * @xpath_ctx is XPath context with current node as parent desired elements
1457 * In case of error @envelope will be freed. */
1458 static isds_error
append_status_size_times(struct isds_ctx
*context
,
1459 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1460 isds_error err
= IE_SUCCESS
;
1461 xmlXPathObjectPtr result
= NULL
;
1462 char *string
= NULL
;
1463 unsigned long int *unumber
= NULL
;
1465 if (!context
) return IE_INVALID_CONTEXT
;
1466 if (!envelope
) return IE_INVAL
;
1467 if (!xpath_ctx
) return IE_INVAL
;
1472 *envelope
= calloc(1, sizeof(**envelope
));
1479 zfree((*envelope
)->dmMessageStatus
);
1480 zfree((*envelope
)->dmAttachmentSize
);
1481 zfree((*envelope
)->dmDeliveryTime
);
1482 zfree((*envelope
)->dmAcceptanceTime
);
1486 /* dmMessageStatus element is mandatory */
1487 EXTRACT_ULONGINT("isds:dmMessageStatus", unumber
, 0);
1488 err
= uint2isds_message_status(context
, unumber
,
1489 &((*envelope
)->dmMessageStatus
));
1491 if (err
== IE_ENUM
) err
= IE_ISDS
;
1494 free(unumber
); unumber
= NULL
;
1496 EXTRACT_ULONGINT("isds:dmAttachmentSize", (*envelope
)->dmAttachmentSize
, 0);
1498 EXTRACT_STRING("isds:dmDeliveryTime", string
);
1500 err
= timestring2timeval((xmlChar
*) string
,
1501 &((*envelope
)->dmDeliveryTime
));
1503 char *string_locale
= utf82locale(string
);
1504 if (err
== IE_DATE
) err
= IE_ISDS
;
1505 isds_printf_message(context
,
1506 _("Could not convert dmDeliveryTime as ISO time: %s"),
1508 free(string_locale
);
1513 EXTRACT_STRING("isds:dmAcceptanceTime", string
);
1515 err
= timestring2timeval((xmlChar
*) string
,
1516 &((*envelope
)->dmAcceptanceTime
));
1518 char *string_locale
= utf82locale(string
);
1519 if (err
== IE_DATE
) err
= IE_ISDS
;
1520 isds_printf_message(context
,
1521 _("Could not convert dmAcceptanceTime as ISO time: %s"),
1523 free(string_locale
);
1529 if (err
) isds_envelope_free(envelope
);
1532 xmlXPathFreeObject(result
);
1537 /* Convert isds:dmRecord XML tree into structure
1538 * @context is ISDS context
1539 * @envelope is automically reallocated message envelope structure
1540 * @xpath_ctx is XPath context with current node as isds:dmRecord element
1541 * In case of error @envelope will be freed. */
1542 static isds_error
extract_DmRecord(struct isds_ctx
*context
,
1543 struct isds_envelope
**envelope
, xmlXPathContextPtr xpath_ctx
) {
1544 isds_error err
= IE_SUCCESS
;
1545 xmlXPathObjectPtr result
= NULL
;
1547 if (!context
) return IE_INVALID_CONTEXT
;
1548 if (!envelope
) return IE_INVAL
;
1549 isds_envelope_free(envelope
);
1550 if (!xpath_ctx
) return IE_INVAL
;
1553 *envelope
= calloc(1, sizeof(**envelope
));
1560 /* Extract tRecord data */
1561 EXTRACT_ULONGINT("isds:dmOrdinal", (*envelope
)->dmOrdinal
, 0);
1563 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
1564 * dmAcceptanceTime. */
1565 err
= append_status_size_times(context
, envelope
, xpath_ctx
);
1566 if (err
) goto leave
;
1568 /* Extract envelope elements added by ISDS
1569 * (XSD: gMessageEnvelope type) */
1570 err
= append_GMessageEnvelope(context
, envelope
, xpath_ctx
);
1571 if (err
) goto leave
;
1573 /* Extract envelope elements added by sender or ISDS
1574 * (XSD: gMessageEnvelopeSub type) */
1575 EXTRACT_STRING("isds:dmSenderOrgUnit", (*envelope
)->dmSenderOrgUnit
);
1576 EXTRACT_LONGINT("isds:dmSenderOrgUnitNum",
1577 (*envelope
)->dmSenderOrgUnitNum
, 0);
1578 EXTRACT_STRING("isds:dbIDRecipient", (*envelope
)->dbIDRecipient
);
1579 EXTRACT_STRING("isds:dmRecipientOrgUnit", (*envelope
)->dmRecipientOrgUnit
);
1580 EXTRACT_LONGINT("isds:dmRecipientOrgUnitNum",
1581 (*envelope
)->dmSenderOrgUnitNum
, 0);
1582 EXTRACT_STRING("isds:dmToHands", (*envelope
)->dmToHands
);
1583 EXTRACT_STRING("isds:dmAnnotation", (*envelope
)->dmAnnotation
);
1584 EXTRACT_STRING("isds:dmRecipientRefNumber",
1585 (*envelope
)->dmRecipientRefNumber
);
1586 EXTRACT_STRING("isds:dmSenderRefNumber", (*envelope
)->dmSenderRefNumber
);
1587 EXTRACT_STRING("isds:dmRecipientIdent", (*envelope
)->dmRecipientIdent
);
1588 EXTRACT_STRING("isds:dmSenderIdent", (*envelope
)->dmSenderIdent
);
1590 /* Extract envelope elements regarding law refference */
1591 EXTRACT_LONGINT("isds:dmLegalTitleLaw", (*envelope
)->dmLegalTitleLaw
, 0);
1592 EXTRACT_LONGINT("isds:dmLegalTitleYear", (*envelope
)->dmLegalTitleYear
, 0);
1593 EXTRACT_STRING("isds:dmLegalTitleSect", (*envelope
)->dmLegalTitleSect
);
1594 EXTRACT_STRING("isds:dmLegalTitlePar", (*envelope
)->dmLegalTitlePar
);
1595 EXTRACT_STRING("isds:dmLegalTitlePoint", (*envelope
)->dmLegalTitlePoint
);
1597 /* Extract envelope other elements */
1598 EXTRACT_BOOLEAN("isds:dmPersonalDelivery", (*envelope
)->dmPersonalDelivery
);
1599 EXTRACT_BOOLEAN("isds:dmAllowSubstDelivery",
1600 (*envelope
)->dmAllowSubstDelivery
);
1601 /* dmOVM can not be obtained from ISDS */
1604 if (err
) isds_envelope_free(envelope
);
1605 xmlXPathFreeObject(result
);
1610 /* Convert XSD tReturnedMessage XML tree into message structure
1611 * @context is ISDS context
1612 * @message is automically reallocated message structure
1613 * @xpath_ctx is XPath context with current node as tReturnedMessage element
1615 * In case of error @message will be freed. */
1616 static isds_error
extract_TReturnedMessage(struct isds_ctx
*context
,
1617 struct isds_message
**message
, xmlXPathContextPtr xpath_ctx
) {
1618 isds_error err
= IE_SUCCESS
;
1619 xmlXPathObjectPtr result
= NULL
;
1620 xmlNodePtr message_node
;
1622 if (!context
) return IE_INVALID_CONTEXT
;
1623 if (!message
) return IE_INVAL
;
1624 isds_message_free(message
);
1625 if (!xpath_ctx
) return IE_INVAL
;
1628 *message
= calloc(1, sizeof(**message
));
1634 /* Save message XPATH context node */
1635 message_node
= xpath_ctx
->node
;
1639 xmlXPathFreeObject(result
); result
= NULL
;
1640 result
= xmlXPathEvalExpression(BAD_CAST
"isds:dmDm", xpath_ctx
);
1645 /* Empty response */
1646 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
1647 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1648 isds_printf_message(context
,
1649 _("%s element does not contain dmDM child"), parent_locale
);
1650 free(parent_locale
);
1655 if (result
->nodesetval
->nodeNr
> 1) {
1656 char *parent_locale
= utf82locale((char*) xpath_ctx
->node
->name
);
1657 isds_printf_message(context
,
1658 _("%s element contains multiple dmDM childs"), parent_locale
);
1659 free(parent_locale
);
1664 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
1665 xmlXPathFreeObject(result
); result
= NULL
;
1666 err
= append_GMessageEnvelope(context
, &((*message
)->envelope
), xpath_ctx
);
1667 if (err
) goto leave
;
1669 /* TODO: Extract dmFiles */
1672 /* Restore context to message */
1673 xmlXPathFreeObject(result
); result
= NULL
;
1674 xpath_ctx
->node
= message_node
;
1676 /* TODO: dmHash, dmQTimestamp, */
1678 /* Get dmMessageStatus, dmAttachmentSize, dmDeliveryTime,
1679 * dmAcceptanceTime. */
1680 err
= append_status_size_times(context
, &((*message
)->envelope
), xpath_ctx
);
1681 if (err
) goto leave
;
1683 /* TODO: save XML blob */
1685 if (err
) isds_message_free(message
);
1686 xmlXPathFreeObject(result
);
1691 /* Convert isds_document structure into XML tree and append to dmFiles node.
1692 * @context is session context
1693 * @document is ISDS document
1694 * @dm_files is XML element the resulting tree will be appended to as a child.
1695 * @return error code, in case of error context' message is filled. */
1696 static isds_error
insert_document(struct isds_ctx
*context
,
1697 struct isds_document
*document
, xmlNodePtr dm_files
) {
1698 isds_error err
= IE_SUCCESS
;
1699 xmlNodePtr new_file
= NULL
, file
= NULL
, node
;
1700 xmlAttrPtr attribute_node
;
1701 xmlChar
*base64data
= NULL
;
1703 if (!context
) return IE_INVALID_CONTEXT
;
1704 if (!document
|| !dm_files
) return IE_INVAL
;
1706 /* Allocate new dmFile */
1707 new_file
= xmlNewNode(dm_files
->ns
, BAD_CAST
"dmFile");
1709 isds_printf_message(context
, _("Could not allocate main dmFile"));
1713 /* Append the new dmFile.
1714 * XXX: Main document must go first */
1715 if (document
->dmFileMetaType
== FILEMETATYPE_MAIN
&& dm_files
->children
)
1716 file
= xmlAddPrevSibling(dm_files
->children
, new_file
);
1718 file
= xmlAddChild(dm_files
, new_file
);
1721 xmlFreeNode(new_file
); new_file
= NULL
;
1722 isds_printf_message(context
, _("Could not add dmFile child to "
1723 "%s element"), dm_files
->name
);
1728 /* @dmMimeType is required */
1729 if (!document
->dmMimeType
) {
1730 isds_log_message(context
,
1731 _("Document is missing mandatory MIME type definition"));
1735 INSERT_STRING_ATTRIBUTE(file
, "dmMimeType", document
->dmMimeType
);
1737 const xmlChar
*string
= isds_FileMetaType2string(document
->dmFileMetaType
);
1739 isds_printf_message(context
,
1740 _("Document has unkown dmFileMetaType: %ld"),
1741 document
->dmFileMetaType
);
1745 INSERT_STRING_ATTRIBUTE(file
, "dmFileMetaType", string
);
1747 if (document
->dmFileGuid
) {
1748 INSERT_STRING_ATTRIBUTE(file
, "dmFileGuid", document
->dmFileGuid
);
1750 if (document
->dmUpFileGuid
) {
1751 INSERT_STRING_ATTRIBUTE(file
, "dmUpFileGuid", document
->dmUpFileGuid
);
1754 /* @dmFileDescr is required */
1755 if (!document
->dmFileDescr
) {
1756 isds_log_message(context
,
1757 _("Document is missing mandatory description (title)"));
1761 INSERT_STRING_ATTRIBUTE(file
, "dmFileDescr", document
->dmFileDescr
);
1763 if (document
->dmFormat
) {
1764 INSERT_STRING_ATTRIBUTE(file
, "dmFormat", document
->dmFormat
);
1768 /* Insert content (data) of the document. */
1769 /* XXX; Only base64 is implemented currently. */
1770 base64data
= (xmlChar
*) b64encode(document
->data
, document
->data_length
);
1772 isds_printf_message(context
,
1773 _("Not enought memory to encode %zd bytes into Base64"),
1774 document
->data_length
);
1778 INSERT_STRING(file
, "dmEncodedContent", base64data
);
1786 /* Get data about logged in user and his box. */
1787 isds_error
isds_GetOwnerInfoFromLogin(struct isds_ctx
*context
,
1788 struct isds_DbOwnerInfo
**db_owner_info
) {
1789 isds_error err
= IE_SUCCESS
;
1790 xmlNsPtr isds_ns
= NULL
;
1791 xmlNodePtr request
= NULL
;
1792 xmlDocPtr response
= NULL
;
1793 xmlChar
*code
= NULL
, *message
= NULL
;
1795 xmlXPathContextPtr xpath_ctx
= NULL
;
1796 xmlXPathObjectPtr result
= NULL
;
1797 char *string
= NULL
;
1799 if (!context
) return IE_INVALID_CONTEXT
;
1800 if (!db_owner_info
) return IE_INVAL
;
1802 /* Check if connection is established */
1803 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
1806 /* Build GetOwnerInfoFromLogin request */
1807 request
= xmlNewNode(NULL
, BAD_CAST
"GetOwnerInfoFromLogin");
1809 isds_log_message(context
,
1810 _("Could build GetOwnerInfoFromLogin request"));
1813 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1815 isds_log_message(context
, _("Could not create ISDS name space"));
1816 xmlFreeNode(request
);
1819 xmlSetNs(request
, isds_ns
);
1820 node
= xmlNewChild(request
, NULL
, BAD_CAST
"dbDummy", NULL
);
1822 isds_log_message(context
, _("Could nod add dbDummy Child to "
1823 "GetOwnerInfoFromLogin element"));
1824 xmlFreeNode(request
);
1829 isds_log(ILF_ISDS
, ILL_DEBUG
,
1830 _("Sending GetOwnerInfoFromLogin request to ISDS\n"));
1833 err
= isds(context
, SERVICE_DB_SUPPLEMENTARY
, request
, &response
);
1835 /* Destroy request */
1836 xmlFreeNode(request
);
1839 isds_log(ILF_ISDS
, ILL_DEBUG
,
1840 _("Processing ISDS response on GetOwnerInfoFromLogin "
1841 "request failed\n"));
1842 xmlFreeDoc(response
);
1846 /* Check for response status */
1847 err
= isds_response_status(context
, SERVICE_DB_SUPPLEMENTARY
, response
,
1848 &code
, &message
, NULL
);
1850 isds_log(ILF_ISDS
, ILL_DEBUG
,
1851 _("ISDS response on GetOwnerInfoFromLogin request is "
1852 "missing status\n"));
1855 xmlFreeDoc(response
);
1858 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
1859 char *code_locale
= utf82locale((char*)code
);
1860 char *message_locale
= utf82locale((char*)message
);
1861 isds_log(ILF_ISDS
, ILL_DEBUG
,
1862 _("Server refused GetOwnerInfoFromLogin request "
1863 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
1864 isds_log_message(context
, message_locale
);
1866 free(message_locale
);
1869 xmlFreeDoc(response
);
1874 /* Prepare stucture */
1875 isds_DbOwnerInfo_free(db_owner_info
);
1876 *db_owner_info
= calloc(1, sizeof(**db_owner_info
));
1877 if (!*db_owner_info
) {
1881 xpath_ctx
= xmlXPathNewContext(response
);
1886 if (register_namespaces(xpath_ctx
)) {
1891 /* Set context node */
1892 result
= xmlXPathEvalExpression(BAD_CAST
1893 "/isds:GetOwnerInfoFromLoginResponse/isds:dbOwnerInfo", xpath_ctx
);
1898 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
1899 isds_log_message(context
, _("Missing dbOwnerInfo element"));
1903 if (result
->nodesetval
->nodeNr
> 1) {
1904 isds_log_message(context
, _("Multiple dbOwnerInfo element"));
1908 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
1909 xmlXPathFreeObject(result
); result
= NULL
;
1912 err
= extract_DbOwnerInfo(context
, db_owner_info
, xpath_ctx
);
1916 isds_DbOwnerInfo_free(db_owner_info
);
1920 xmlXPathFreeObject(result
);
1921 xmlXPathFreeContext(xpath_ctx
);
1925 xmlFreeDoc(response
);
1928 isds_log(ILF_ISDS
, ILL_DEBUG
,
1929 _("GetOwnerInfoFromLogin request processed by server "
1930 "successfully.\n"));
1936 /* Find boxes suiting given criteria.
1937 * @criteria is filter. You should fill in at least some memebers.
1938 * @boxes is automatically reallocated list of isds_DbOwnerInfo structures,
1939 * possibly empty. Input NULL or valid old structure.
1941 * IE_SUCCESS if search sucseeded, @boxes contains usefull data
1942 * IE_NOEXIST if no such box exists, @boxes will be NULL
1943 * IE_2BIG if too much boxes exist and server truncated the resuluts, @boxes
1944 * contains still valid data
1945 * other code if something bad happens. @boxes will be NULL. */
1946 isds_error
isds_FindDataBox(struct isds_ctx
*context
,
1947 const struct isds_DbOwnerInfo
*criteria
,
1948 struct isds_list
**boxes
) {
1949 isds_error err
= IE_SUCCESS
;
1950 _Bool truncated
= 0;
1951 xmlNsPtr isds_ns
= NULL
;
1952 xmlNodePtr request
= NULL
;
1953 xmlDocPtr response
= NULL
;
1954 xmlChar
*code
= NULL
, *message
= NULL
;
1955 xmlNodePtr db_owner_info
, node
;
1956 xmlXPathContextPtr xpath_ctx
= NULL
;
1957 xmlXPathObjectPtr result
= NULL
;
1958 xmlChar
*string
= NULL
;
1961 if (!context
) return IE_INVALID_CONTEXT
;
1962 if (!boxes
) return IE_INVAL
;
1963 isds_list_free(boxes
);
1969 /* Check if connection is established
1970 * TODO: This check should be done donwstairs. */
1971 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
1974 /* Build FindDataBox request */
1975 request
= xmlNewNode(NULL
, BAD_CAST
"FindDataBox");
1977 isds_log_message(context
,
1978 _("Could build FindDataBox request"));
1981 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
1983 isds_log_message(context
, _("Could not create ISDS name space"));
1984 xmlFreeNode(request
);
1987 xmlSetNs(request
, isds_ns
);
1988 db_owner_info
= xmlNewChild(request
, NULL
, BAD_CAST
"dbOwnerInfo", NULL
);
1989 if (!db_owner_info
) {
1990 isds_log_message(context
, _("Could not add dbOwnerInfo Child to "
1991 "FindDataBox element"));
1992 xmlFreeNode(request
);
1997 INSERT_STRING(db_owner_info
, "dbID", criteria
->dbID
);
2000 if (criteria
->dbType
) {
2001 const xmlChar
*type_string
= isds_DbType2string(*(criteria
->dbType
));
2003 isds_printf_message(context
, _("Invalid dbType value: %d"),
2004 *(criteria
->dbType
));
2008 INSERT_STRING(db_owner_info
, "dbType", type_string
);
2011 INSERT_STRING(db_owner_info
, "firmName", criteria
->firmName
);
2012 INSERT_STRING(db_owner_info
, "ic", criteria
->ic
);
2013 if (criteria
->personName
) {
2014 INSERT_STRING(db_owner_info
, "pnFirstName",
2015 criteria
->personName
->pnFirstName
);
2016 INSERT_STRING(db_owner_info
, "pnMiddleName",
2017 criteria
->personName
->pnMiddleName
);
2018 INSERT_STRING(db_owner_info
, "pnLastName",
2019 criteria
->personName
->pnLastName
);
2020 INSERT_STRING(db_owner_info
, "pnLastNameAtBirth",
2021 criteria
->personName
->pnLastNameAtBirth
);
2023 if (criteria
->birthInfo
) {
2024 if (criteria
->birthInfo
->biDate
) {
2025 if (!tm2datestring(criteria
->birthInfo
->biDate
, &string
))
2026 INSERT_STRING(db_owner_info
, "biDate", string
);
2027 free(string
); string
= NULL
;
2029 INSERT_STRING(db_owner_info
, "biCity", criteria
->birthInfo
->biCity
);
2030 INSERT_STRING(db_owner_info
, "biCounty", criteria
->birthInfo
->biCounty
);
2031 INSERT_STRING(db_owner_info
, "biState", criteria
->birthInfo
->biState
);
2033 if (criteria
->address
) {
2034 INSERT_STRING(db_owner_info
, "adCity", criteria
->address
->adCity
);
2035 INSERT_STRING(db_owner_info
, "adStreet", criteria
->address
->adStreet
);
2036 INSERT_STRING(db_owner_info
, "adNumberInStreet",
2037 criteria
->address
->adNumberInStreet
);
2038 INSERT_STRING(db_owner_info
, "adNumberInMunicipality",
2039 criteria
->address
->adNumberInMunicipality
);
2040 INSERT_STRING(db_owner_info
, "adZipCode", criteria
->address
->adZipCode
);
2041 INSERT_STRING(db_owner_info
, "adState", criteria
->address
->adState
);
2043 INSERT_STRING(db_owner_info
, "nationality", criteria
->nationality
);
2044 INSERT_STRING(db_owner_info
, "email", criteria
->email
);
2045 INSERT_STRING(db_owner_info
, "telNumber", criteria
->telNumber
);
2046 INSERT_STRING(db_owner_info
, "identifier", criteria
->identifier
);
2047 INSERT_STRING(db_owner_info
, "registryCode", criteria
->registryCode
);
2049 INSERT_LONGINT(db_owner_info
, "dbState", criteria
->dbState
, string
);
2051 INSERT_BOOLEAN(db_owner_info
, "dbEffectiveOVM", criteria
->dbEffectiveOVM
);
2052 INSERT_BOOLEAN(db_owner_info
, "dbOpenAddressing",
2053 criteria
->dbOpenAddressing
);
2056 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending FindDataBox request to ISDS\n"));
2059 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2061 /* Destroy request */
2062 xmlFreeNode(request
); request
= NULL
;
2065 isds_log(ILF_ISDS
, ILL_DEBUG
,
2066 _("Processing ISDS response on FindDataBox "
2067 "request failed\n"));
2071 /* Check for response status */
2072 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2073 &code
, &message
, NULL
);
2075 isds_log(ILF_ISDS
, ILL_DEBUG
,
2076 _("ISDS response on FindDataBox request is missing status\n"));
2080 /* Request processed, but nothing found */
2081 if (!xmlStrcmp(code
, BAD_CAST
"0002") ||
2082 !xmlStrcmp(code
, BAD_CAST
"5001")) {
2083 char *code_locale
= utf82locale((char*)code
);
2084 char *message_locale
= utf82locale((char*)message
);
2085 isds_log(ILF_ISDS
, ILL_DEBUG
,
2086 _("Server did not found any box on FindDataBox request "
2087 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2088 isds_log_message(context
, message_locale
);
2090 free(message_locale
);
2095 /* Warning, not a error */
2096 if (!xmlStrcmp(code
, BAD_CAST
"0003")) {
2097 char *code_locale
= utf82locale((char*)code
);
2098 char *message_locale
= utf82locale((char*)message
);
2099 isds_log(ILF_ISDS
, ILL_DEBUG
,
2100 _("Server truncated response on FindDataBox request "
2101 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2102 isds_log_message(context
, message_locale
);
2104 free(message_locale
);
2109 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2110 char *code_locale
= utf82locale((char*)code
);
2111 char *message_locale
= utf82locale((char*)message
);
2112 isds_log(ILF_ISDS
, ILL_DEBUG
,
2113 _("Server refused FindDataBox request "
2114 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2115 isds_log_message(context
, message_locale
);
2117 free(message_locale
);
2122 xpath_ctx
= xmlXPathNewContext(response
);
2127 if (register_namespaces(xpath_ctx
)) {
2132 /* Extract boxes if they present */
2133 result
= xmlXPathEvalExpression(BAD_CAST
2134 "/isds:FindDataBoxResponse/isds:dbResults/isds:dbOwnerInfo",
2140 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2141 struct isds_list
*item
, *prev_item
= NULL
;
2142 for (int i
= 0; i
< result
->nodesetval
->nodeNr
; i
++) {
2143 item
= calloc(1, sizeof(*item
));
2149 item
->destructor
= (void (*)(void **))isds_DbOwnerInfo_free
;
2150 if (i
== 0) *boxes
= item
;
2151 else prev_item
->next
= item
;
2154 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[i
];
2155 err
= extract_DbOwnerInfo(context
,
2156 (struct isds_DbOwnerInfo
**) &(item
->data
), xpath_ctx
);
2157 if (err
) goto leave
;
2163 isds_list_free(boxes
);
2165 if (truncated
) err
= IE_2BIG
;
2169 xmlFreeNode(request
);
2170 xmlXPathFreeObject(result
);
2171 xmlXPathFreeContext(xpath_ctx
);
2175 xmlFreeDoc(response
);
2178 isds_log(ILF_ISDS
, ILL_DEBUG
,
2179 _("FindDataBox request processed by server successfully.\n"));
2185 /* Get status of a box.
2186 * @context is ISDS session context.
2187 * @box_id is UTF-8 encoded box identifier as zero terminated string
2188 * @box_status is return value of box status.
2190 * IE_SUCCESS if box has been found and its status retrieved
2191 * IE_NOEXIST if box is not known to ISDS server
2192 * or other appropriate error.
2193 * You can use isds_DbState to enumerate box status. However out of enum
2194 * range value can be returned too. This is feature because ISDS
2195 * specification leaves the set of values open.
2196 * Be ware that status DBSTATE_REMOVED is signaled as IE_SUCCESS. That means
2197 * the box has been deleted, but ISDS still lists its former existence. */
2198 isds_error
isds_CheckDataBox(struct isds_ctx
*context
, const char *box_id
,
2199 long int *box_status
) {
2200 isds_error err
= IE_SUCCESS
;
2201 xmlNsPtr isds_ns
= NULL
;
2202 xmlNodePtr request
= NULL
, db_id
;
2203 xmlDocPtr response
= NULL
;
2204 xmlChar
*code
= NULL
, *message
= NULL
;
2205 xmlXPathContextPtr xpath_ctx
= NULL
;
2206 xmlXPathObjectPtr result
= NULL
;
2207 xmlChar
*string
= NULL
;
2209 if (!context
) return IE_INVALID_CONTEXT
;
2210 if (!box_status
|| !box_id
|| *box_id
== '\0') return IE_INVAL
;
2212 /* Check if connection is established
2213 * TODO: This check should be done donwstairs. */
2214 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2217 /* Build CheckDataBox request */
2218 request
= xmlNewNode(NULL
, BAD_CAST
"CheckDataBox");
2220 isds_log_message(context
,
2221 _("Could build CheckDataBox request"));
2224 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2226 isds_log_message(context
, _("Could not create ISDS name space"));
2227 xmlFreeNode(request
);
2230 xmlSetNs(request
, isds_ns
);
2231 db_id
= xmlNewTextChild(request
, NULL
, BAD_CAST
"dbID", (xmlChar
*) box_id
);
2233 isds_log_message(context
, _("Could not add dbId Child to "
2234 "CheckDataBox element"));
2235 xmlFreeNode(request
);
2240 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CheckDataBox request to ISDS\n"));
2243 err
= isds(context
, SERVICE_DB_SEARCH
, request
, &response
);
2245 /* Destroy request */
2246 xmlFreeNode(request
);
2249 isds_log(ILF_ISDS
, ILL_DEBUG
,
2250 _("Processing ISDS response on CheckDataBox "
2251 "request failed\n"));
2255 /* Check for response status */
2256 err
= isds_response_status(context
, SERVICE_DB_SEARCH
, response
,
2257 &code
, &message
, NULL
);
2259 isds_log(ILF_ISDS
, ILL_DEBUG
,
2260 _("ISDS response on CheckDataBox request is missing status\n"));
2264 /* Request processed, but nothing found */
2265 if (!xmlStrcmp(code
, BAD_CAST
"5001")) {
2266 char *box_id_locale
= utf82locale((char*)box_id
);
2267 char *code_locale
= utf82locale((char*)code
);
2268 char *message_locale
= utf82locale((char*)message
);
2269 isds_log(ILF_ISDS
, ILL_DEBUG
,
2270 _("Server did not found box %s on CheckDataBox request "
2271 "(code=%s, message=%s)\n"),
2272 box_id_locale
, code_locale
, message_locale
);
2273 isds_log_message(context
, message_locale
);
2274 free(box_id_locale
);
2276 free(message_locale
);
2282 else if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2283 char *code_locale
= utf82locale((char*)code
);
2284 char *message_locale
= utf82locale((char*)message
);
2285 isds_log(ILF_ISDS
, ILL_DEBUG
,
2286 _("Server refused CheckDataBox request "
2287 "(code=%s, message=%s)\n"), code_locale
, message_locale
);
2288 isds_log_message(context
, message_locale
);
2290 free(message_locale
);
2296 xpath_ctx
= xmlXPathNewContext(response
);
2301 if (register_namespaces(xpath_ctx
)) {
2305 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CheckDataBoxResponse",
2311 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2312 isds_log_message(context
, _("Missing CheckDataBoxResponse element"));
2316 if (result
->nodesetval
->nodeNr
> 1) {
2317 isds_log_message(context
, _("Multiple CheckDataBoxResponse element"));
2321 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2322 xmlXPathFreeObject(result
); result
= NULL
;
2324 EXTRACT_LONGINT("isds:dbState", box_status
, 1);
2329 xmlXPathFreeObject(result
);
2330 xmlXPathFreeContext(xpath_ctx
);
2334 xmlFreeDoc(response
);
2337 isds_log(ILF_ISDS
, ILL_DEBUG
,
2338 _("CheckDataBox request processed by server successfully.\n"));
2344 /* Send a message via ISDS to a recipent
2345 * @context is session context
2346 * @outgoing_message is message to send; Some memebers are mandatory (like
2347 * dbIDRecipient), some are optional and some are irrelevant (especialy data
2348 * about sender). Included pointer to isds_list documents must contain at
2349 * least one document of FILEMETATYPE_MAIN. This is read-write structure, some
2350 * members will be filled with valid data from ISDS. Exact list of write
2351 * members is subject to change. Currently dmId is changed.
2352 * @return ISDS_SUCCESS, or other error code if something goes wrong. */
2353 isds_error
isds_send_message(struct isds_ctx
*context
,
2354 struct isds_message
*outgoing_message
) {
2356 isds_error err
= IE_SUCCESS
;
2357 xmlNsPtr isds_ns
= NULL
;
2358 xmlNodePtr request
= NULL
, envelope
, dm_files
, node
;
2359 xmlDocPtr response
= NULL
;
2360 xmlChar
*code
= NULL
, *message
= NULL
;
2361 xmlXPathContextPtr xpath_ctx
= NULL
;
2362 xmlXPathObjectPtr result
= NULL
;
2363 xmlChar
*string
= NULL
;
2364 _Bool message_is_complete
= 0;
2366 if (!context
) return IE_INVALID_CONTEXT
;
2367 if (!outgoing_message
) return IE_INVAL
;
2369 /* Check if connection is established
2370 * TODO: This check should be done donwstairs. */
2371 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2374 /* Build CreateMessage request */
2375 request
= xmlNewNode(NULL
, BAD_CAST
"CreateMessage");
2377 isds_log_message(context
,
2378 _("Could build CreateMessage request"));
2381 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2383 isds_log_message(context
, _("Could not create ISDS name space"));
2384 xmlFreeNode(request
);
2387 xmlSetNs(request
, isds_ns
);
2390 /* Build envelope */
2391 envelope
= xmlNewChild(request
, NULL
, BAD_CAST
"dmEnvelope", NULL
);
2393 isds_log_message(context
, _("Could not add dmEnvelope child to "
2394 "CreateMessage element"));
2395 xmlFreeNode(request
);
2399 if (!outgoing_message
->envelope
) {
2400 isds_log_message(context
, _("outgoing message is missing envelope"));
2405 INSERT_STRING(envelope
, "dmSenderOrgUnit",
2406 outgoing_message
->envelope
->dmSenderOrgUnit
);
2407 INSERT_LONGINT(envelope
, "dmSenderOrgUnitNum",
2408 outgoing_message
->envelope
->dmSenderOrgUnitNum
, string
);
2410 if (!outgoing_message
->envelope
->dbIDRecipient
) {
2411 isds_log_message(context
,
2412 _("outgoing message is missing recipient box identifier"));
2416 INSERT_STRING(envelope
, "dbIDRecipient",
2417 outgoing_message
->envelope
->dbIDRecipient
);
2419 INSERT_STRING(envelope
, "dmRecipientOrgUnit",
2420 outgoing_message
->envelope
->dmRecipientOrgUnit
);
2421 INSERT_LONGINT(envelope
, "dmRecipientOrgUnitNum",
2422 outgoing_message
->envelope
->dmRecipientOrgUnitNum
, string
);
2423 INSERT_STRING(envelope
, "dmToHands", outgoing_message
->envelope
->dmToHands
);
2425 #define CHECK_FOR_STRING_LENGTH(string, limit, name) \
2426 if ((string) && xmlUTF8Strlen((xmlChar *) (string)) > (limit)) { \
2427 isds_printf_message(context, \
2428 _("%s has more than %d characters"), (name), (limit)); \
2433 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmAnnotation
, 255,
2435 INSERT_STRING(envelope
, "dmAnnotation",
2436 outgoing_message
->envelope
->dmAnnotation
);
2438 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientRefNumber
,
2439 50, "dmRecipientRefNumber");
2440 INSERT_STRING(envelope
, "dmRecipientRefNumber",
2441 outgoing_message
->envelope
->dmRecipientRefNumber
);
2443 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderRefNumber
,
2444 50, "dmSenderRefNumber");
2445 INSERT_STRING(envelope
, "dmSenderRefNumber",
2446 outgoing_message
->envelope
->dmSenderRefNumber
);
2448 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmRecipientIdent
,
2449 50, "dmRecipientIdent");
2450 INSERT_STRING(envelope
, "dmRecipientIdent",
2451 outgoing_message
->envelope
->dmRecipientIdent
);
2453 CHECK_FOR_STRING_LENGTH(outgoing_message
->envelope
->dmSenderIdent
,
2454 50, "dmSenderIdent");
2455 INSERT_STRING(envelope
, "dmSenderIdent",
2456 outgoing_message
->envelope
->dmSenderIdent
);
2458 INSERT_LONGINT(envelope
, "dmLegalTitleLaw",
2459 outgoing_message
->envelope
->dmLegalTitleLaw
, string
);
2460 INSERT_LONGINT(envelope
, "dmLegalTitleYear",
2461 outgoing_message
->envelope
->dmLegalTitleYear
, string
);
2462 INSERT_STRING(envelope
, "dmLegalTitleSect",
2463 outgoing_message
->envelope
->dmLegalTitleSect
);
2464 INSERT_STRING(envelope
, "dmLegalTitlePar",
2465 outgoing_message
->envelope
->dmLegalTitlePar
);
2466 INSERT_STRING(envelope
, "dmLegalTitlePoint",
2467 outgoing_message
->envelope
->dmLegalTitlePoint
);
2469 INSERT_BOOLEAN(envelope
, "dmPersonalDelivery",
2470 outgoing_message
->envelope
->dmPersonalDelivery
);
2471 INSERT_BOOLEAN(envelope
, "dmAllowSubstDelivery",
2472 outgoing_message
->envelope
->dmAllowSubstDelivery
);
2474 #undef CHECK_FOR_STRING_LENGTH
2476 /* ???: Should we require value for dbEffectiveOVM sender?
2477 * ISDS has default as true */
2478 INSERT_BOOLEAN(envelope
, "dmOVM", outgoing_message
->envelope
->dmOVM
);
2481 /* Append dmFiles */
2482 if (!outgoing_message
->documents
) {
2483 isds_log_message(context
,
2484 _("outgoing message is missing list of documents"));
2488 dm_files
= xmlNewChild(request
, NULL
, BAD_CAST
"dmFiles", NULL
);
2490 isds_log_message(context
, _("Could not add dmFiles child to "
2491 "CreateMessage element"));
2496 /* Check for document hieararchy */
2497 err
= check_documents_hierarchy(context
, outgoing_message
->documents
);
2498 if (err
) goto leave
;
2500 /* Process each document */
2501 for (struct isds_list
*item
=
2502 (struct isds_list
*) outgoing_message
->documents
;
2503 item
; item
= item
->next
) {
2505 isds_log_message(context
,
2506 _("list of documents contains empty item"));
2510 /* FIXME: Check for dmFileMetaType and for document references.
2511 * Only first document can be of MAIN type */
2512 err
= insert_document(context
, (struct isds_document
*) item
->data
,
2515 if (err
) goto leave
;
2518 /* Signal we can serilize message since now */
2519 message_is_complete
= 1;
2523 isds_log(ILF_ISDS
, ILL_DEBUG
, _("Sending CreateMessage request to ISDS\n"));
2526 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
2528 /* Dont' destroy request, we want to privode it to application later */
2531 isds_log(ILF_ISDS
, ILL_DEBUG
,
2532 _("Processing ISDS response on CreateMessage "
2533 "request failed\n"));
2537 /* Check for response status */
2538 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
2539 &code
, &message
, NULL
);
2541 isds_log(ILF_ISDS
, ILL_DEBUG
,
2542 _("ISDS response on CreateMessage request "
2543 "is missing status\n"));
2547 /* Request processed, but nothing found */
2548 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2549 char *box_id_locale
=
2550 utf82locale((char*)outgoing_message
->envelope
->dbIDRecipient
);
2551 char *code_locale
= utf82locale((char*)code
);
2552 char *message_locale
= utf82locale((char*)message
);
2553 isds_log(ILF_ISDS
, ILL_DEBUG
,
2554 _("Server did not accept message for %s on CreateMessage "
2555 "request (code=%s, message=%s)\n"),
2556 box_id_locale
, code_locale
, message_locale
);
2557 isds_log_message(context
, message_locale
);
2558 free(box_id_locale
);
2560 free(message_locale
);
2567 xpath_ctx
= xmlXPathNewContext(response
);
2572 if (register_namespaces(xpath_ctx
)) {
2576 result
= xmlXPathEvalExpression(BAD_CAST
"/isds:CreateMessageResponse",
2582 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2583 isds_log_message(context
, _("Missing CreateMessageResponse element"));
2587 if (result
->nodesetval
->nodeNr
> 1) {
2588 isds_log_message(context
, _("Multiple CreateMessageResponse element"));
2592 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
2593 xmlXPathFreeObject(result
); result
= NULL
;
2595 if (outgoing_message
->envelope
->dmID
) {
2596 free(outgoing_message
->envelope
->dmID
);
2597 outgoing_message
->envelope
->dmID
= NULL
;
2599 EXTRACT_STRING("isds:dmID", outgoing_message
->envelope
->dmID
);
2600 if (!outgoing_message
->envelope
->dmID
) {
2601 isds_log(ILF_ISDS
, ILL_ERR
, _("Server accepted sent message, "
2602 "but did not returen assigned message ID\n"));
2606 /* TODO: Serialize message into structure member raw */
2607 /* XXX: Each web service transport message in different format.
2608 * Therefore it's not possible to save them directly.
2609 * To save them, one must figure out common format.
2610 * We can leave it on application, or we can implement the ESS format. */
2611 /*if (message_is_complete) {
2612 if (outgoing_message->envelope->dmID) {
2614 /* Add assigned message ID as first child*/
2615 /*xmlNodePtr dmid_text = xmlNewText(
2616 (xmlChar *) outgoing_message->envelope->dmID);
2617 if (!dmid_text) goto serialization_failed;
2619 xmlNodePtr dmid_element = xmlNewNode(envelope->ns,
2621 if (!dmid_element) {
2622 xmlFreeNode(dmid_text);
2623 goto serialization_failed;
2626 xmlNodePtr dmid_element_with_text =
2627 xmlAddChild(dmid_element, dmid_text);
2628 if (!dmid_element_with_text) {
2629 xmlFreeNode(dmid_element);
2630 xmlFreeNode(dmid_text);
2631 goto serialization_failed;
2634 node = xmlAddPrevSibling(envelope->childern,
2635 dmid_element_with_text);
2637 xmlFreeNodeList(dmid_element_with_text);
2638 goto serialization_failed;
2642 /* Serialize message with ID into raw */
2643 /*buffer = serialize_element(envelope)*/
2646 serialization_failed:
2653 xmlXPathFreeObject(result
);
2654 xmlXPathFreeContext(xpath_ctx
);
2658 xmlFreeDoc(response
);
2659 xmlFreeNode(request
);
2662 isds_log(ILF_ISDS
, ILL_DEBUG
,
2663 _("CreateMessage request processed by server "
2664 "successfully.\n"));
2670 /* Get list of messages. This is common core for getting sent or received
2672 * Any criterion argument can be NULL, if you don't care about it.
2673 * @context is session context. Must not be NULL.
2674 * @outgoing_direction is true if you want list of outgoing messages,
2675 * it's false if you want incoming messages.
2676 * @from_time is minimal time and date of message sending inclusive.
2677 * @to_time is maximal time and date of message sending inclusive
2678 * @organization_unit_number is number of sender/recipient respectively.
2679 * @status_filter is bit field of isds_message_status values. Use special
2680 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
2681 * all values, you can use bitwise arithmetic if you want.)
2682 * @offset is index of first message we are interested in. First message is 1.
2683 * Set to 0 (or 1) if you don't care.
2684 * @number is maximal length of list you want to get as input value, outputs
2685 * number of messages matching these criteria. Can be NULL if you don't care
2686 * (applies to output value either).
2687 * @messages is automatically reallocated list of isds_message's. Be ware that
2688 * it returns only brief overview (envelope and some other fields) about each
2689 * message, not the complete message. FIXME: Specify exact fields.
2690 * The list is sorted by delivery time in ascending order.
2692 * you don't care about don't need the data (useful if you want to know only
2693 * the @number). If you provide &NULL, list will be allocated on heap, if you
2694 * provide pointer to non-NULL, list will be freed automacally at first. Also
2695 * in case of error the list will be NULLed.
2696 * @return IE_SUCCESS or appropriate error code. */
2697 static isds_error
isds_get_list_of_messages(struct isds_ctx
*context
,
2698 _Bool outgoing_direction
,
2699 const struct timeval
*from_time
, const struct timeval
*to_time
,
2700 const long int *organization_unit_number
,
2701 const unsigned int status_filter
,
2702 const unsigned long int offset
, unsigned long int *number
,
2703 struct isds_list
**messages
) {
2705 isds_error err
= IE_SUCCESS
;
2706 xmlNsPtr isds_ns
= NULL
;
2707 xmlNodePtr request
= NULL
, node
;
2708 xmlDocPtr response
= NULL
;
2709 xmlChar
*code
= NULL
, *message
= NULL
;
2710 xmlXPathContextPtr xpath_ctx
= NULL
;
2711 xmlXPathObjectPtr result
= NULL
;
2712 xmlChar
*string
= NULL
;
2713 long unsigned int count
= 0;
2715 if (!context
) return IE_INVALID_CONTEXT
;
2717 /* Free former message list if any */
2718 if (messages
) isds_list_free(messages
);
2720 /* Check if connection is established
2721 * TODO: This check should be done donwstairs. */
2722 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
2724 /* Build GetListOf*Messages request */
2725 request
= xmlNewNode(NULL
,
2726 (outgoing_direction
) ?
2727 BAD_CAST
"GetListOfSentMessages" :
2728 BAD_CAST
"GetListOfReceivedMessages"
2731 isds_log_message(context
,
2732 (outgoing_direction
) ?
2733 _("Could not build GetListOfSentMessages request") :
2734 _("Could not build GetListOfReceivedMessages request")
2738 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
2740 isds_log_message(context
, _("Could not create ISDS name space"));
2741 xmlFreeNode(request
);
2744 xmlSetNs(request
, isds_ns
);
2748 err
= timeval2timestring(from_time
, &string
);
2749 if (err
) goto leave
;
2751 INSERT_STRING(request
, "dmFromTime", string
);
2752 free(string
); string
= NULL
;
2755 err
= timeval2timestring(to_time
, &string
);
2756 if (err
) goto leave
;
2758 INSERT_STRING(request
, "dmToTime", string
);
2759 free(string
); string
= NULL
;
2761 if (outgoing_direction
) {
2762 INSERT_LONGINT(request
, "dmSenderOrgUnitNum",
2763 organization_unit_number
, string
);
2765 INSERT_LONGINT(request
, "dmRecipientOrgUnitNum",
2766 organization_unit_number
, string
);
2769 if (status_filter
> MESSAGESTATE_ANY
) {
2770 isds_printf_message(context
,
2771 _("Invalid message state filter value: %ld"), status_filter
);
2775 INSERT_ULONGINTNOPTR(request
, "dmStatusFilter", status_filter
, string
);
2778 INSERT_ULONGINTNOPTR(request
, "dmOffset", offset
, string
);
2780 INSERT_STRING(request
, "dmOffset", "1");
2783 /* number 0 means no limit */
2784 if (number
&& *number
== 0) {
2785 INSERT_STRING(request
, "dmLimit", NULL
);
2787 INSERT_ULONGINT(request
, "dmLimit", number
, string
);
2791 isds_log(ILF_ISDS
, ILL_DEBUG
,
2792 (outgoing_direction
) ?
2793 _("Sending GetListOfSentMessages request to ISDS\n") :
2794 _("Sending GetListOfReceivedMessages request to ISDS\n")
2798 err
= isds(context
, SERVICE_DM_INFO
, request
, &response
);
2799 xmlFreeNode(request
); request
= NULL
;
2802 isds_log(ILF_ISDS
, ILL_DEBUG
,
2803 (outgoing_direction
) ?
2804 _("Processing ISDS response on GetListOfSentMessages "
2805 "request failed\n") :
2806 _("Processing ISDS response on GetListOfReceivedMessages "
2812 /* Check for response status */
2813 err
= isds_response_status(context
, SERVICE_DM_INFO
, response
,
2814 &code
, &message
, NULL
);
2816 isds_log(ILF_ISDS
, ILL_DEBUG
,
2817 (outgoing_direction
) ?
2818 _("ISDS response on GetListOfSentMessages request "
2819 "is missing status\n") :
2820 _("ISDS response on GetListOfReceivedMessages request "
2821 "is missing status\n")
2826 /* Request processed, but nothing found */
2827 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
2828 char *code_locale
= utf82locale((char*)code
);
2829 char *message_locale
= utf82locale((char*)message
);
2830 isds_log(ILF_ISDS
, ILL_DEBUG
,
2831 (outgoing_direction
) ?
2832 _("Server refused GetListOfSentMessages request "
2833 "(code=%s, message=%s)\n") :
2834 _("Server refused GetListOfReceivedMessages request "
2835 "(code=%s, message=%s)\n"),
2836 code_locale
, message_locale
);
2837 isds_log_message(context
, message_locale
);
2839 free(message_locale
);
2846 xpath_ctx
= xmlXPathNewContext(response
);
2851 if (register_namespaces(xpath_ctx
)) {
2855 result
= xmlXPathEvalExpression(
2856 (outgoing_direction
) ?
2857 BAD_CAST
"/isds:GetListOfSentMessagesResponse/"
2858 "isds:dmRecords/isds:dmRecord" :
2859 BAD_CAST
"/isds:GetListOfReceivedMessagesResponse/"
2860 "isds:dmRecords/isds:dmRecord",
2867 /* Fill output arguments in */
2868 if (!xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
2869 struct isds_envelope
*envelope
;
2870 struct isds_list
*item
= NULL
, *last_item
= NULL
;
2872 for (count
= 0; count
< result
->nodesetval
->nodeNr
; count
++) {
2873 /* Create new message */
2874 item
= calloc(1, sizeof(*item
));
2879 item
->destructor
= (void(*)(void**)) &isds_message_free
;
2880 item
->data
= calloc(1, sizeof(struct isds_message
));
2882 isds_list_free(&item
);
2887 /* Extract envelope data */
2888 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[count
];
2890 err
= extract_DmRecord(context
, &envelope
, xpath_ctx
);
2892 isds_list_free(&item
);
2896 /* Attach extracted envelope */
2897 ((struct isds_message
*) item
->data
)->envelope
= envelope
;
2899 /* Append new message into the list */
2901 *messages
= last_item
= item
;
2903 last_item
->next
= item
;
2908 if (number
) *number
= count
;
2912 isds_list_free(messages
);
2916 xmlXPathFreeObject(result
);
2917 xmlXPathFreeContext(xpath_ctx
);
2921 xmlFreeDoc(response
);
2922 xmlFreeNode(request
);
2925 isds_log(ILF_ISDS
, ILL_DEBUG
,
2926 (outgoing_direction
) ?
2927 _("GetListOfSentMessages request processed by server "
2928 "successfully.\n") :
2929 _("GetListOfReceivedMessages request processed by server "
2936 /* Get list of outgoing (already sent) messages.
2937 * Any criterion argument can be NULL, if you don't care about it.
2938 * @context is session context. Must not be NULL.
2939 * @from_time is minimal time and date of message sending inclusive.
2940 * @to_time is maximal time and date of message sending inclusive
2941 * @dmSenderOrgUnitNum is the same as isds_envelope.dmSenderOrgUnitNum
2942 * @status_filter is bit field of isds_message_status values. Use special
2943 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
2944 * all values, you can use bitwise arithmetic if you want.)
2945 * @offset is index of first message we are interested in. First message is 1.
2946 * Set to 0 (or 1) if you don't care.
2947 * @number is maximal length of list you want to get as input value, outputs
2948 * number of messages matching these criteria. Can be NULL if you don't care
2949 * (applies to output value either).
2950 * @messages is automatically reallocated list of isds_message's. Be ware that
2951 * it returns only brief overview (envelope and some other fields) about each
2952 * message, not the complete message. FIXME: Specify exact fields.
2953 * The list is sorted by delivery time in ascending order.
2954 * Use NULL if you don't care about the metadata (useful if you want to know
2955 * only the @number). If you provide &NULL, list will be allocated on heap,
2956 * if you provide pointer to non-NULL, list will be freed automacally at first.
2957 * Also in case of error the list will be NULLed.
2958 * @return IE_SUCCESS or appropriate error code. */
2959 isds_error
isds_get_list_of_sent_messages(struct isds_ctx
*context
,
2960 const struct timeval
*from_time
, const struct timeval
*to_time
,
2961 const long int *dmSenderOrgUnitNum
, const unsigned int status_filter
,
2962 const unsigned long int offset
, unsigned long int *number
,
2963 struct isds_list
**messages
) {
2965 return isds_get_list_of_messages(
2967 from_time
, to_time
, dmSenderOrgUnitNum
, status_filter
,
2973 /* Get list of incoming (addressed to you) messages.
2974 * Any criterion argument can be NULL, if you don't care about it.
2975 * @context is session context. Must not be NULL.
2976 * @from_time is minimal time and date of message sending inclusive.
2977 * @to_time is maximal time and date of message sending inclusive
2978 * @dmRecipientOrgUnitNum is the same as isds_envelope.dmRecipientOrgUnitNum
2979 * @status_filter is bit field of isds_message_status values. Use special
2980 * value MESSAGESTATE_ANY to signal you don't care. (It's defined as union of
2981 * all values, you can use bitwise arithmetic if you want.)
2982 * @offset is index of first message we are interested in. First message is 1.
2983 * Set to 0 (or 1) if you don't care.
2984 * @number is maximal length of list you want to get as input value, outputs
2985 * number of messages matching these criteria. Can be NULL if you don't care
2986 * (applies to output value either).
2987 * @messages is automatically reallocated list of isds_message's. Be ware that
2988 * it returns only brief overview (envelope and some other fields) about each
2989 * message, not the complete message. FIXME: Specify exact fields.
2990 * Use NULL if you don't care about the metadata (useful if you want to know
2991 * only the @number). If you provide &NULL, list will be allocated on heap,
2992 * if you provide pointer to non-NULL, list will be freed automacally at first.
2993 * Also in case of error the list will be NULLed.
2994 * @return IE_SUCCESS or appropriate error code. */
2995 isds_error
isds_get_list_of_received_messages(struct isds_ctx
*context
,
2996 const struct timeval
*from_time
, const struct timeval
*to_time
,
2997 const long int *dmRecipientOrgUnitNum
,
2998 const unsigned int status_filter
,
2999 const unsigned long int offset
, unsigned long int *number
,
3000 struct isds_list
**messages
) {
3002 return isds_get_list_of_messages(
3004 from_time
, to_time
, dmRecipientOrgUnitNum
, status_filter
,
3010 /* Dwwnload incomping message identified by ID.
3011 * @context is session context
3012 * @message_id is message identifier (you can get them from
3013 * isds_get_list_of_received_messages())
3014 * @message is automatically reallocated message retrieved from ISDS */
3015 isds_error
isds_get_received_message(struct isds_ctx
*context
,
3016 const char *message_id
, struct isds_message
**message
) {
3017 /* ???: XSD allows list of @message_id's and list of @message's, but
3018 * documentation talks only about `a message' */
3020 isds_error err
= IE_SUCCESS
;
3021 xmlNsPtr isds_ns
= NULL
;
3022 xmlNodePtr request
= NULL
, node
;
3023 xmlDocPtr response
= NULL
;
3024 xmlChar
*code
= NULL
, *status_message
= NULL
;
3025 xmlXPathContextPtr xpath_ctx
= NULL
;
3026 xmlXPathObjectPtr result
= NULL
;
3028 if (!context
) return IE_INVALID_CONTEXT
;
3030 /* Free former message if any */
3031 if (message
) isds_message_free(message
);
3033 if (!message_id
) return IE_INVAL
;
3035 /* Check if connection is established
3036 * TODO: This check should be done donwstairs. */
3037 if (!context
->curl
) return IE_CONNECTION_CLOSED
;
3039 /* Build MessageDownload request */
3040 request
= xmlNewNode(NULL
, BAD_CAST
"MessageDownload");
3042 isds_log_message(context
,
3043 _("Could not build MessageDownload request"));
3046 isds_ns
= xmlNewNs(request
, BAD_CAST ISDS_NS
, NULL
);
3048 isds_log_message(context
, _("Could not create ISDS name space"));
3049 xmlFreeNode(request
);
3052 xmlSetNs(request
, isds_ns
);
3055 /* Add requested ID */
3056 err
= validate_message_id_length(context
, (xmlChar
*) message_id
);
3057 if (err
) goto leave
;
3058 INSERT_STRING(request
, "dmID", message_id
);
3061 isds_log(ILF_ISDS
, ILL_DEBUG
,
3062 _("Sending MessageDownload request to ISDS\n"));
3065 err
= isds(context
, SERVICE_DM_OPERATIONS
, request
, &response
);
3066 xmlFreeNode(request
); request
= NULL
;
3069 isds_log(ILF_ISDS
, ILL_DEBUG
,
3070 _("Processing ISDS response on MessageDownload "
3071 "request failed\n"));
3075 /* Check for response status */
3076 err
= isds_response_status(context
, SERVICE_DM_OPERATIONS
, response
,
3077 &code
, &status_message
, NULL
);
3079 isds_log(ILF_ISDS
, ILL_DEBUG
,
3080 _("ISDS response on MessageDownload request "
3081 "is missing status\n"));
3085 /* Request processed, but nothing found */
3086 if (xmlStrcmp(code
, BAD_CAST
"0000")) {
3087 char *code_locale
= utf82locale((char*)code
);
3088 char *status_message_locale
= utf82locale((char*)status_message
);
3089 isds_log(ILF_ISDS
, ILL_DEBUG
,
3090 _("Server refused MessageDownload request "
3091 "(code=%s, message=%s)\n"),
3092 code_locale
, status_message_locale
);
3093 isds_log_message(context
, status_message_locale
);
3095 free(status_message_locale
);
3102 xpath_ctx
= xmlXPathNewContext(response
);
3107 if (register_namespaces(xpath_ctx
)) {
3111 result
= xmlXPathEvalExpression(
3112 BAD_CAST
"/isds:MessageDownloadResponse/isds:dmReturnedMessage",
3118 /* Empty response */
3119 if (xmlXPathNodeSetIsEmpty(result
->nodesetval
)) {
3120 char *message_id_locale
= utf82locale((char*) message_id
);
3121 isds_printf_message(context
,
3122 _("Server did not return any message for ID `%s' "
3123 "on MessageDownload request"), message_id
);
3124 free(message_id_locale
);
3129 if (result
->nodesetval
->nodeNr
> 1) {
3130 char *message_id_locale
= utf82locale((char*) message_id
);
3131 isds_printf_message(context
,
3132 _("Server did return more messages for ID `%s' "
3133 "on MessageDownload request"), message_id
);
3134 free(message_id_locale
);
3139 xpath_ctx
->node
= result
->nodesetval
->nodeTab
[0];
3141 /* Extract the message */
3142 err
= extract_TReturnedMessage(context
, message
, xpath_ctx
);
3146 isds_message_free(message
);
3149 xmlXPathFreeObject(result
);
3150 xmlXPathFreeContext(xpath_ctx
);
3153 free(status_message
);
3154 xmlFreeDoc(response
);
3155 xmlFreeNode(request
);
3158 isds_log(ILF_ISDS
, ILL_DEBUG
,
3159 _("MessageDownloadrequest processed by server "
3166 #undef INSERT_STRING_ATTRIBUTE
3167 #undef INSERT_ULONGINTNOPTR
3168 #undef INSERT_ULONGINT
3169 #undef INSERT_LONGINT
3170 #undef INSERT_BOOLEAN
3171 #undef INSERT_STRING
3172 #undef EXTRACT_ULONGINT
3173 #undef EXTRACT_LONGINT
3174 #undef EXTRACT_BOOLEAN
3175 #undef EXTRACT_STRING
3178 /* Search for document by document ID in list of documents. IDs are compared
3180 * @documents is list of isds_documents
3181 * @id is document identifier
3182 * @return first matching document or NULL. */
3183 const struct isds_document
*isds_find_document_by_id(
3184 const struct isds_list
*documents
, const char *id
) {
3185 const struct isds_list
*item
;
3186 const struct isds_document
*document
;
3188 for (item
= documents
; item
; item
= item
->next
) {
3189 document
= (struct isds_document
*) item
->data
;
3190 if (!document
) continue;
3192 if (!xmlStrcmp((xmlChar
*) id
, (xmlChar
*) document
->dmFileGuid
))
3200 /*int isds_get_message(struct isds_ctx *context, const unsigned int id,
3201 struct isds_message **message);
3202 int isds_send_message(struct isds_ctx *context, struct isds_message *message);
3203 int isds_list_messages(struct isds_ctx *context, struct isds_message **message);
3204 int isds_find_recipient(struct isds_ctx *context, const struct address *pattern,
3205 struct isds_address **address);
3207 int isds_message_free(struct isds_message **message);
3208 int isds_address_free(struct isds_address **address);
3212 /* Makes known all relevant namespaces to give @xpat_ctx */
3213 _hidden isds_error
register_namespaces(xmlXPathContextPtr xpath_ctx
) {
3214 if (!xpath_ctx
) return IE_ERROR
;
3216 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"soap", BAD_CAST SOAP_NS
))
3218 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"isds", BAD_CAST ISDS_NS
))
3220 if (xmlXPathRegisterNs(xpath_ctx
, BAD_CAST
"xs", BAD_CAST SCHEMA_NS
))