1 #define _XOPEN_SOURCE 600
6 #include <readline/readline.h>
7 #include <readline/history.h>
17 #include "shigofumi.h"
18 #include "completition.h"
23 #define CONFIG_FILE ".shigofumirc"
24 #define CONFIG_SERVER "base_url"
25 #define CONFIG_USERNAME "username"
26 #define CONFIG_PASSWORD "password"
27 #define CONFIG_DEBUGLEVEL "debug_level"
28 #define CONFIG_VERIFYSERVER "verify_server"
29 #define CONFIG_CAFILE "ca_file"
30 #define CONFIG_CADIRECTORY "ca_directory"
31 #define CONFIG_CRLFILE "crl_file"
32 #define CONFIG_TIMEOUT "timeout"
33 #define CONFIG_LOGFACILITIES "log_facilities"
34 #define CONFIG_LOGFILE "log_file"
35 #define CONFIG_LOGLEVEL "log_level"
36 #define CONFIG_NORMALIZEMIMETYPE "normalize_mime_type"
37 #define CZPDEPOSIT_URL "https://www.czechpoint.cz/uschovna/"
43 cfg_opt_t configuration_syntax
[] = {
44 CFG_STR(CONFIG_SERVER
, (char *)isds_locator
, CFGF_NONE
),
45 CFG_STR(CONFIG_USERNAME
, NULL
, CFGF_NODEFAULT
),
46 CFG_STR(CONFIG_PASSWORD
, NULL
, CFGF_NODEFAULT
),
47 /*CFG_STR(CONFIG_DEBUGLEVEL, NULL, CFGF_NODEFAULT),*/
48 CFG_BOOL(CONFIG_VERIFYSERVER
, cfg_true
, CFGF_NONE
),
49 CFG_STR(CONFIG_CAFILE
, NULL
, CFGF_NODEFAULT
),
50 CFG_STR(CONFIG_CADIRECTORY
, NULL
, CFGF_NODEFAULT
),
51 CFG_STR(CONFIG_CRLFILE
, NULL
, CFGF_NODEFAULT
),
52 CFG_INT(CONFIG_TIMEOUT
, TIMEOUT
, CFGF_NONE
),
53 CFG_STR_LIST(CONFIG_LOGFACILITIES
, "{none}", CFGF_NONE
),
54 CFG_STR(CONFIG_LOGFILE
, NULL
, CFGF_NODEFAULT
),
55 CFG_INT(CONFIG_LOGLEVEL
, LOG_LEVEL
, CFGF_NONE
),
56 CFG_BOOL(CONFIG_NORMALIZEMIMETYPE
, cfg_true
, CFGF_NONE
),
67 struct command (*commands
)[] = NULL
;
70 struct isds_ctx
*cisds
= NULL
;
72 char *username
= NULL
;
73 char *password
= NULL
;
74 struct isds_list
*boxes
= NULL
;
75 struct isds_message
*message
= NULL
;
76 _Bool messages_are_outgoing
= 0;
77 struct isds_list
*messages
= NULL
;
78 unsigned long int total_messages
= 0;
79 struct isds_ctx
*czechpoint
= NULL
;
81 static void discard_credentials(void) {
88 /* Do the cleanup and exit */
89 static void shi_exit(int exit_code
) {
91 discard_credentials();
92 isds_list_free(&boxes
);
93 isds_message_free(&message
);
94 isds_list_free(&messages
);
97 printf(_("Logging out...\n"));
99 isds_ctx_free(&cisds
);
101 isds_ctx_free(&czechpoint
);
105 cfg_free(configuration
);
114 /* Set prompt. if @format is NULL, switch to default prompt */
115 static void set_prompt(const char *format
, ...) {
119 va_start(ap
, format
);
120 shi_vasprintf(&buffer
, format
, ap
);
124 shi_asprintf(&prompt
, _("%s> "), buffer
);
133 prompt
= strdup(_("> "));
141 static int shi_load_configuration(const char *config_file
) {
142 char *config_name
= NULL
;
145 /* Get config file */
147 config_name
= (char *) config_file
;
149 if (-1 == shi_asprintf(&config_name
, "%s/%s", getenv("HOME"),
151 fprintf(stderr
, _("Could not build configuration file name\n"));
156 /* Parse configuration */
157 configuration
= cfg_init(configuration_syntax
, CFGF_NONE
);
158 ret
= cfg_parse(configuration
, config_name
);
160 if (ret
== CFG_FILE_ERROR
) {
162 _("Error while opening configuration file `%s': %s\n"),
163 config_name
, strerror(errno
));
165 fprintf(stderr
, _("Error while parsing configuration file `%s'\n"),
168 printf(_("Using default configuration\n"));
171 if (config_name
!= config_file
) free(config_name
);
176 static void finish_isds_operation(struct isds_ctx
*ctx
, isds_error err
) {
177 shi_progressbar_finish();
179 if (isds_long_message(ctx
))
180 printf(_("Error occured: %s: %s\n"), isds_strerror(err
),
181 isds_long_message(ctx
));
183 printf(_("Error occured: %s\n"), isds_strerror(err
));
188 void logger(isds_log_facility facility
, isds_log_level level
,
189 const char *message
, int length
, void *data
) {
191 ssize_t written
, left
= length
;
194 fd
= *((int *) data
);
195 /*printf("\033[32mLOG(%02d,%02d): ", facility, level);
196 printf("%.*s", length, message);
200 written
= write(fd
, message
+ length
- left
, left
);
203 _("Could not save log message into log file: %s\n"
204 "Log message discarded!\n"),
215 /* Redirect ISDS log to file if @file is not NULL. */
216 static int do_log_to_file(const char *file
) {
218 logger_fd
= open_file_for_writing(file
, 0);
219 if (logger_fd
== -1) return -1;
220 isds_set_log_callback(logger
, &logger_fd
);
226 /* Add log facility based on its name. */
227 static int add_log_facility(isds_log_facility
*facilities
, const char *name
) {
228 if (!facilities
) return -1;
230 if (!strcmp(name
, "none")) *facilities
|= ILF_NONE
;
231 else if (!strcmp(name
, "http")) *facilities
|= ILF_HTTP
;
232 else if (!strcmp(name
, "soap")) *facilities
|= ILF_SOAP
;
233 else if (!strcmp(name
, "isds")) *facilities
|= ILF_ISDS
;
234 else if (!strcmp(name
, "file")) *facilities
|= ILF_FILE
;
235 else if (!strcmp(name
, "sec")) *facilities
|= ILF_SEC
;
236 else if (!strcmp(name
, "xml")) *facilities
|= ILF_XML
;
237 else if (!strcmp(name
, "all")) *facilities
|= ILF_ALL
;
239 printf(_("%s: Unknown log facility\n"), name
);
247 /* Clamp long int to unsigned int */
248 static unsigned int normalize_timeout(long int raw
) {
250 printf(_("Configured network timeout is less then 0. Clamped to 0.\n"));
253 if (raw
> UINT_MAX
) {
254 printf(_("Configured network timeout is greater then %1$u. "
255 "Clamped to %1$u.\n"), UINT_MAX
);
258 return (unsigned int) raw
;
262 /* Clamp long int to <0;100> */
263 static unsigned int normalize_log_level(long int raw
) {
265 printf(_("Configured log level is less then 0. Clamped to 0.\n"));
269 printf(_("Configured log level is greater then %1$u. "
270 "Clamped to %1$u.\n"), ILL_ALL
);
273 if (raw
> UINT_MAX
) {
274 printf(_("Configured log level is greater then %1$u. "
275 "Clamped to %1$u.\n"), UINT_MAX
);
278 return (unsigned int) raw
;
282 static int shi_init(const char *config_file
) {
285 unsigned int timeout
, log_level
;
286 isds_log_facility log_facility
= ILF_NONE
;
288 printf(_("This is Shigofumi, an ISDS client. Have a nice e-government.\n"));
290 /* Do not permute arguments in getopt() */
291 if (setenv("POSIXLY_CORRECT", "", 1)) {
293 _("Could not set POSIXLY_CORRECT environment variable\n"));
297 /* Load configuration */
298 if (shi_load_configuration(config_file
))
300 timeout
= normalize_timeout(cfg_getint(configuration
, CONFIG_TIMEOUT
));
301 log_level
= normalize_log_level(cfg_getint(configuration
, CONFIG_LOGLEVEL
));
304 rl_readline_name
= "shigofumi";
305 rl_filename_quote_characters
= "\\ >";
306 rl_filename_quoting_function
= shi_quote_filename
;
307 rl_filename_dequoting_function
= shi_dequote_filename
;
308 rl_char_is_quoted_p
= shi_char_is_quoted
;
310 /* Initialize ISDS */
313 fprintf(stderr
, _("Could not initialize libisds library: %s\n"),
318 /* Set ISDS logging */
319 value
= cfg_getstr(configuration
, CONFIG_LOGFILE
);
320 if (do_log_to_file(value
)) {
321 fprintf(stderr
, _("Could not redirect ISDS log to file `%s'\n"), value
);
324 for (int i
= 0; i
< cfg_size(configuration
, CONFIG_LOGFACILITIES
); i
++) {
325 if (add_log_facility(&log_facility
,
326 cfg_getnstr(configuration
, CONFIG_LOGFACILITIES
, i
)))
330 isds_set_logging(log_facility
, log_level
);
332 /* Set ISDS context up */
333 cisds
= isds_ctx_create();
335 fprintf(stderr
, _("Could not create ISDS context\n"));
338 err
= isds_set_timeout(cisds
, timeout
);
340 fprintf(stderr
, _("Could not set ISDS network timeout: %s\n"),
343 err
= isds_set_progress_callback(cisds
, shi_progressbar
, NULL
);
345 fprintf(stderr
, _("Could not register network progress bar: %s: %s\n"),
346 isds_strerror(err
), isds_long_message(cisds
));
348 err
= isds_set_opt(cisds
, IOPT_NORMALIZE_MIME_TYPE
,
349 cfg_getbool(configuration
, CONFIG_NORMALIZEMIMETYPE
));
352 cfg_getbool(configuration
, CONFIG_NORMALIZEMIMETYPE
) ?
353 _("Could not enable MIME type normalization: %s: %s\n") :
354 _("Could not enable MIME type normalization: %s: %s\n"),
355 isds_strerror(err
), isds_long_message(cisds
));
357 if (!cfg_getbool(configuration
, CONFIG_VERIFYSERVER
)) {
358 printf(_("Warning: Shigofumi disabled server identity verification "
359 "on user request!\n"));
360 err
= isds_set_opt(cisds
, IOPT_TLS_VERIFY_SERVER
, 0);
363 _("Could not disable server identity verification: "
365 isds_strerror(err
), isds_long_message(cisds
));
368 if ((value
= cfg_getstr(configuration
, CONFIG_CAFILE
))) {
369 err
= isds_set_opt(cisds
, IOPT_TLS_CA_FILE
, value
);
372 _("Could not set file with CA certificates: %s: %s: %s\n"),
373 value
, isds_strerror(err
), isds_long_message(cisds
));
376 if ((value
= cfg_getstr(configuration
, CONFIG_CADIRECTORY
))) {
377 err
= isds_set_opt(cisds
, IOPT_TLS_CA_DIRECTORY
, value
);
380 _("Could not set directory with CA certificates: "
382 value
, isds_strerror(err
), isds_long_message(cisds
));
385 if ((value
= cfg_getstr(configuration
, CONFIG_CRLFILE
))) {
386 err
= isds_set_opt(cisds
, IOPT_TLS_CRL_FILE
, value
);
388 fprintf(stderr
, _("Could not set file with CRL: %s: %s: %s\n"),
389 value
, isds_strerror(err
), isds_long_message(cisds
));
394 /* Set Czech POINT context up */
395 czechpoint
= isds_ctx_create();
397 fprintf(stderr
, _("Could not create Czech POINT context\n"));
400 err
= isds_set_timeout(czechpoint
, timeout
);
402 fprintf(stderr
, _("Could not set Czech POINT network timeout: %s\n"),
405 err
= isds_set_progress_callback(czechpoint
, shi_progressbar
, NULL
);
407 fprintf(stderr
, "Could not register network progress bar: %s: %s\n",
408 isds_strerror(err
), isds_long_message(cisds
));
415 static int shi_quit(int argc
, const char **argv
) {
416 shi_exit(EXIT_SUCCESS
);
422 static void shi_help_usage(const char *command
) {
424 "Usage: %s [COMMAND]\n"
425 "Show COMMAND manual or list of currently available commands.\n"
431 static int shi_help(int argc
, const char **argv
) {
432 size_t command_width
= 14;
436 printf(_("No command is available\n"));
440 if (argc
== 2 && argv
[1] && *argv
[1]) {
441 /* Show usage for given command */
442 for (i
= 0; (*commands
)[i
].name
; i
++) {
443 if (!strcmp((*commands
)[i
].name
, argv
[1])) {
444 if ((*commands
)[i
].usage
)
445 (*commands
)[i
].usage((*commands
)[i
].name
);
446 else if ((*commands
)[i
].description
) {
447 fhprint(stdout
, (*commands
)[i
].name
, command_width
);
448 printf(" %s\n", _((*commands
)[i
].description
));
451 printf(_("%s: %s: Command description not defined\n"),
456 printf(_("%s: %s: No such command exists\n"), argv
[0], argv
[1]);
460 /* Or list all commands */
461 printf(_("Following commands are available:\n"));
462 for (i
= 0; (*commands
)[i
].name
; i
++) {
463 fhprint(stdout
, (*commands
)[i
].name
, command_width
);
464 printf(" %s\n", _((*commands
)[i
].description
));
471 static void show_version(void) {
472 char *libisds_version
= isds_version();
474 printf(_("This is Shigofumi version %s.\n"), PACKAGE_VERSION
);
480 rl_library_version
, libisds_version
);
481 free(libisds_version
);
485 static int shi_version(int argc
, const char **argv
) {
490 "It's a shigofumi. A letter delivered from the afterlife. (Fumika)\n"
491 "A message can not be delivered to dead person. (ISDS specification)\n"
492 "Virtual and real world. They can be compatible. (Program author)\n"
498 static int shi_copying(int argc
, const char **argv
) {
500 "This is Shigofumi, an ISDS client.\n"
501 "Copyright (C) 2010 Petr Pisar\n"
503 "This program is free software: you can redistribute it and/or modify\n"
504 "it under the terms of the GNU General Public License as published by\n"
505 "the Free Software Foundation, either version 3 of the License, or\n"
506 "(at your option) any later version.\n"
508 "This program is distributed in the hope that it will be useful,\n"
509 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
510 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
511 "GNU General Public License for more details.\n"
513 "You should have received a copy of the GNU General Public License\n"
514 "along with this program. If not, see <http://www.gnu.org/licenses/>.\n"
520 static int shi_cache(int argc
, const char **argv
) {
521 const struct isds_list
*item
;
525 for (item
= boxes
, i
= 0; item
; item
= item
->next
, i
++);
527 "Cached box list: %zu\n"),
533 "Cached message list:\n"
535 "\tMessages: %'lu\n"),
536 (messages_are_outgoing
) ? _("Outgoing") : _("Incoming"),
541 printf(_("Cached message: %s\n"),
542 (message
->envelope
&& message
->envelope
->dmID
) ?
543 message
->envelope
->dmID
: _("<Uknown ID>"));
550 static void shi_chdir_usage(const char *command
) {
552 "Usage: %s [DIRECTORY]\n"
553 "Change working directory to DIRECTORY.\n"
554 "If no DIRECTORY is supplied, HOME directory will be used.\n"),
559 static int shi_chdir(int argc
, const char **argv
) {
560 const char *directory
= NULL
;
562 if (!argv
|| argc
> 2) {
563 shi_chdir_usage((argv
) ? argv
[0] : NULL
);
567 if (argc
== 2 && argv
[1] && *argv
[1])
570 directory
= getenv("HOME");
572 printf("Environment variable HOME does not exist\n");
576 if (chdir(directory
)) {
577 printf(_("Could not change working directory: %s: %s\n"), directory
,
586 static int shi_pwd(int argc
, const char **argv
) {
587 char *buffer
= NULL
, *newbuffer
;
590 while (length
+= 1024) {
591 newbuffer
= realloc(buffer
, length
);
593 printf(_("Error: Not enough memory\n"));
599 if (getcwd(buffer
, length
)) {
600 printf("%s\n", buffer
);
606 printf(_("Error: Current directory string is tooo long\n"));
613 static int do_login(void) {
617 printf(_("Unattended mode detected. "
618 "Make sure credentials have been preset.\n"));
620 printf(_("You are going to insert credentials for your account.\n"
621 "Leave blank line to choose default value.\n"));
623 select_completition(COMPL_NONE
);
625 /* Ask for server base URL */
626 shi_replace_string(&server
, _("Input ISDS base URL: "),
627 cfg_getstr(configuration
, CONFIG_SERVER
), batch_mode
);
629 /* Ask for username */
630 shi_replace_string(&username
, _("Input ISDS user name: "),
631 cfg_getstr(configuration
, CONFIG_USERNAME
), batch_mode
);
634 password = ask_for_password(_("Input ISDS password: "));
637 fprintf(stderr, _("Could not read ISDS password\n"));
638 shi_exit(EXIT_FAILURE);
641 shi_replace_password(&password
, _("Input ISDS password: "),
642 cfg_getstr(configuration
, CONFIG_PASSWORD
), batch_mode
);
644 select_completition(COMPL_COMMAND
);
647 printf(_("Logging in...\n"));
648 err
= isds_login(cisds
, server
, username
, password
, NULL
);
649 finish_isds_operation(cisds
, err
);
651 printf(_("Login failed\n"));
655 printf(_("Logged in.\n"));
660 static struct isds_DbOwnerInfo
*do_box(void) {
662 struct isds_DbOwnerInfo
*box
= NULL
;
664 printf(_("Getting box details you are logged in...\n"));
665 err
= isds_GetOwnerInfoFromLogin(cisds
, &box
);
666 finish_isds_operation(cisds
, err
);
672 static int shi_box(int argc
, const char **argv
) {
673 struct isds_DbOwnerInfo
*box
= NULL
;
678 format_DbOwnerInfo(box
);
680 isds_DbOwnerInfo_free(&box
);
685 /* Get info about box with @id.
686 * @id is UTF-8 encoded
687 * Return NULL in case of error, otherwise box description that caller must
689 static struct isds_DbOwnerInfo
*stat_box(const char *id
) {
691 struct isds_DbOwnerInfo criteria
;
692 struct isds_list
*boxes
= NULL
, *item
;
693 struct isds_DbOwnerInfo
*box
= NULL
;
694 char *id_locale
= NULL
;
696 if (!id
|| !*id
) return NULL
;
698 id_locale
= utf82locale(id
);
699 memset(&criteria
, 0, sizeof(criteria
));
700 criteria
.dbID
= (char *) id
;
702 printf(_("Getting details about box with ID `%s'...\n"), id_locale
);
703 err
= isds_FindDataBox(cisds
, &criteria
, &boxes
);
704 finish_isds_operation(cisds
, err
);
707 for(item
= boxes
; item
; item
= item
->next
) {
708 if (!item
->data
) continue;
711 printf(_("Error: More boxes match ID `%s'\n"), id_locale
);
715 box
= (struct isds_DbOwnerInfo
*) item
->data
;
722 isds_list_free(&boxes
);
728 static void shi_commercial_usage(const char *command
) {
730 "Usage: %s [-0|-1] [BOX_ID]\n"
731 "Manipulate commercial receiving box status.\n"
732 " -O switch off receving of commercial messages\n"
733 " -1 switch on receving of commercial messages\n"
734 " BOX_ID affects box with ID BOX_ID; default is box you are logged in\n"
735 "If no option is given, show current commercial receiving status.\n"),
740 /* Manipulate commercial receiving box status */
741 static int shi_commercial(int argc
, const char **argv
) {
743 struct isds_DbOwnerInfo
*box
= NULL
;
746 char *box_id
= NULL
, *box_id_locale
= NULL
;
751 while ((opt
= getopt(argc
, (char * const *)argv
, "01")) != -1) {
760 shi_commercial_usage((argv
)?argv
[0]:NULL
);
764 if (optind
+ 1 < argc
) {
765 printf(_("Bad invocation\n"));
766 shi_commercial_usage((argv
)?argv
[0]:NULL
);
770 if (!argv
[optind
] || !*argv
[optind
]) {
771 /* Get current box ID */
773 if (!box
|| !box
->dbID
|| !*box
->dbID
) {
774 isds_DbOwnerInfo_free(&box
);
775 printf(_("Could not get current box ID\n"));
778 box_id
= box
->dbID
; static_box_id
= 1;
779 box_id_locale
= utf82locale(box_id
);
781 /* Box ID supplied as argument */
782 box_id_locale
= (char *) argv
[optind
];
783 box_id
= locale2utf8(box_id_locale
); static_box_id
= 0;
785 printf(_("Could not convert box ID `%s' to UTF-8\n"),
792 if (!box
) box
= stat_box(box_id
);
794 printf(_("Could not get details about box ID `%s'\n"),
800 printf(_("Commercial receiving status of box `%s': "), box_id_locale
);
801 if (!box
->dbOpenAddressing
)
802 printf(_("Unknown\n"));
803 else if (*box
->dbOpenAddressing
)
804 printf(_("Positive\n"));
806 printf(_("Negative\n"));
808 char *refnumber
= NULL
;
810 _("Switching `%s' box commercial receiving on...\n"):
811 _("Switching `%s' box commercial receiving off...\n"),
813 err
= isds_switch_commercial_receiving(cisds
, box_id
, action
,
815 finish_isds_operation(cisds
, err
);
818 char *refnumber_locale
= utf82locale(refnumber
);
819 printf(_("Commercial receiving status successfully changed. "
820 "Assigned refference number: %s\n"),
823 printf(_("Commercial receiving status has not been changed.\n"));
830 if (!static_box_id
) free(box_id
);
831 else free(box_id_locale
);
832 isds_DbOwnerInfo_free(&box
);
837 static int shi_user(int argc
, const char **argv
) {
839 struct isds_DbUserInfo
*user
= NULL
;
841 printf(_("Getting user details you are logged as...\n"));
842 err
= isds_GetUserInfoFromLogin(cisds
, &user
);
843 finish_isds_operation(cisds
, err
);
846 format_DbUserInfo(user
);
848 isds_DbUserInfo_free(&user
);
853 static void shi_users_usage(const char *command
) {
856 "Get list of users having access to box with BOX_ID.\n"),
861 static int shi_users(int argc
, const char **argv
) {
863 struct isds_list
*users
= NULL
, *item
;
866 if (!argv
|| !argv
[1] || !*argv
[1]) {
867 shi_users_usage((argv
)?argv
[0]:NULL
);
871 printf(_("Getting users of box with ID `%s'...\n"), argv
[1]);
872 err
= isds_GetDataBoxUsers(cisds
, argv
[1], &users
);
873 finish_isds_operation(cisds
, err
);
876 for (item
= users
, ordinar
= 0; item
; item
=item
->next
) {
877 if (!item
->data
) continue;
879 printf(_("\n* User #%d:\n"), ordinar
);
880 format_DbUserInfo(item
->data
);
883 printf(_("Empty list of users returned.\n"));
885 isds_list_free(&users
);
890 static int show_password_expiration(void) {
892 struct timeval
*expiration
= NULL
;
894 err
= isds_get_password_expiration(cisds
, &expiration
);
895 finish_isds_operation(cisds
, err
);
897 fprintf(stderr
, "Could not get password expiration time\n");
901 print_header_timeval(_("Your password expires at"), expiration
);
907 /* Change password in ISDS */
908 static int do_passwd(void) {
909 char *old_password
= NULL
;
910 char *new_password
= NULL
;
911 char *new_password2
= NULL
;
912 isds_error err
= IE_ERROR
;
915 select_completition(COMPL_NONE
);
918 "You are going to change your password. If you don't want to change your\n"
919 "password, insert empty string or EOF.\n"
921 "You will be asked for your current (old) password and then for new password.\n"
922 "ISDS forces some criteria new password must fulfill. Current rules are:\n"
923 "\tLength: minimal 8, maximal 32 characters\n"
924 "\tMust contain at least: 1 upper case letter, 1 lower case letter, 1 digit\n"
925 "\tAllowed alphabet: [a-z][A-Z][0-9][!#$%%&()*+,-.:=?@[]_{}|~]\n"
926 "\tMust differ from last 255 passwords\n"
927 "\tMust not contain user ID\n"
928 "\tMust not contain sequence of three or more same characters\n"
929 "\tMust not start with `qwert', `asdgf', or `12345'\n"
930 "Finally, you must repeat your new password to avoid mistakes.\n"
931 "After password change will be confirmed, you must log in again as password\n"
932 "is transmitted to server on each request.\n"
935 old_password
= ask_for_password(_("Old password: "));
936 if (!old_password
|| *old_password
== '\0') {
937 fprintf(stderr
, _("No pasword supplied\n"));
941 new_password
= ask_for_password(_("New password: "));
942 if (!new_password
|| *new_password
== '\0') {
943 fprintf(stderr
, _("No pasword supplied\n"));
947 new_password2
= ask_for_password(_("Repeat new password: "));
948 if (!new_password2
|| new_password2
== '\0') {
949 fprintf(stderr
, _("No pasword supplied\n"));
953 if (strcmp(new_password
, new_password2
)) {
954 fprintf(stderr
, _("New passwords differ\n"));
958 printf(_("Changing password...\n"));
959 err
= isds_change_password(cisds
, old_password
, new_password
);
960 finish_isds_operation(cisds
, err
);
962 printf(_("Password change failed\n"));
965 printf(_("Password HAS been successfully changed.\n"));
971 printf(_("Password has NOT been changed!\n"));
979 select_completition(COMPL_COMMAND
);
982 "Remember, ISDS password has limited life time.\n"));
987 static void shi_passwd_usage(const char *command
) {
990 "Manipulate user password or change it if no option given.\n"
993 " -S show password expiration time\n"
998 static int shi_passwd(int argc
, const char **argv
) {
1002 while ((opt
= getopt(argc
, (char * const *)argv
, "S")) != -1) {
1005 return show_password_expiration();
1007 shi_passwd_usage(argv
[0]);
1011 if (optind
!= argc
|| argc
> 1) {
1012 printf(_("Bad invocation\n"));
1013 shi_passwd_usage((argv
)?argv
[0]:NULL
);
1021 static int shi_login(int argc
, const char **argv
) {
1022 discard_credentials();
1023 if (do_login()) return -1;
1024 show_password_expiration();
1029 static void shi_debug_usage(const char *command
) {
1031 "Usage: %s -l LEVEL [-f FACILITY...] [{-e | -o FILE}]\n"
1032 "Debug FACILTIES on LEVEL.\n"
1034 "-l LEVEL set log level, valid interval <%d,%d>, default is %d\n"
1035 " %d is no logging, %d critical, %d errors,\n"
1036 " %d warnings, %d info, %d debug, %d all\n"
1037 "-f FACILITY debug only given facily, repeat this option to debug\n"
1038 " more facilities; valid values: none, http, soap, isds,\n"
1039 " file, sec, xml, all; default is none\n"
1040 "-e write debug log into stderr\n"
1041 "-o FILE append debug log to FILE\n"
1044 ILL_NONE
, ILL_ALL
, ILL_NONE
,
1045 ILL_NONE
, ILL_CRIT
, ILL_ERR
, ILL_WARNING
,
1046 ILL_INFO
, ILL_DEBUG
, ILL_ALL
);
1049 static int shi_debug(int argc
, const char **argv
) {
1051 int log_level
= ILL_NONE
;
1052 isds_log_facility log_facility
= ILF_NONE
;
1054 _Bool close_log
= 0;
1057 while ((opt
= getopt(argc
, (char * const *)argv
, "l:f:eo:")) != -1) {
1060 log_level
= normalize_log_level(atoi(optarg
));
1063 if (add_log_facility(&log_facility
, optarg
)) return -1;
1071 shi_debug_usage(argv
[0]);
1075 if (optind
== 1 || optind
!= argc
) {
1076 printf(_("Bad invocation\n"));
1077 shi_debug_usage(argv
[0]);
1083 isds_set_log_callback(NULL
, NULL
);
1085 if (logger_fd
!= -1) {
1086 if (-1 == close(logger_fd
)) {
1087 fprintf(stderr
, _("Closing log file failed: %s\n"),
1093 if (do_log_to_file(file
))
1096 /* Set log levels */
1097 isds_set_logging(log_facility
, log_level
);
1102 static void shi_find_box_usage(const char *command
) {
1104 "Usage: %s {OPTION... | BOX_ID}\n"
1105 "Get information about box with BOX_ID or boxes meeting other criteria.\n"
1106 "Each search option requires an argument:\n"
1107 " -t box type; accepted values:\n"
1108 " FO Private individual\n"
1109 " PFO Self-employed individual\n"
1110 " PFO_ADVOK Lawyer\n"
1111 " PFO_DANPOR Tax advisor\n"
1112 " PFO_INSSPR Insolvency administrator\n"
1113 " PO Organisation\n"
1114 " PO_ZAK Organization based by law\n"
1115 " PO_REQ Organization based on request\n"
1116 " OVM Public authority\n"
1117 " OVM_NOTAR Notary\n"
1118 " OVM_EXEKUT Executor\n"
1119 " OVM_REQ Public authority based on request\n"
1120 " -j identity number\n"
1122 "Person name options:\n"
1126 " -b last name at birth\n"
1127 " -s subject name\n"
1130 " -d birth date (locale or full ISO 8601 date)\n"
1132 " -y birth county\n"
1138 " -z number in street\n"
1139 " -Z number in municipality\n"
1146 " -p phone number\n"
1148 " -r registry code\n"
1149 " -a box status; accepted values:\n"
1150 " ACCESSIBLE Accessible\n"
1151 " TEMP_UNACCESSIBLE Temporary unaccessible\n"
1152 " NOT_YET_ACCESSIBLE Not yet accessible\n"
1153 " PERM_UNACCESSIBLE Permanently unaccessible\n"
1154 " REMOVED Deleted\n"
1155 " -o act as public authority; boolean values: 0 is false, 1 is true\n"
1156 " -k receive commerical messages; boolean values\n"
1158 "Not all option combinations are meaningfull or allowed. For example box\n"
1159 "type is always required (except direct box ID query).\n"
1160 "ISDS can refuse to answer to much broad query. Not all boxes are searchable\n"
1167 /* Allow reassignment */
1168 #define FILL_OR_LEAVE(variable, locale) { \
1170 (variable) = locale2utf8(locale); \
1171 if (!(variable)) { \
1172 printf(_("Error: Not enough memory\n")); \
1178 #define CALLOC_OR_LEAVE(structure) { \
1179 if (!(structure)) { \
1180 (structure) = calloc(1, sizeof(*(structure))); \
1181 if (!(structure)) { \
1182 printf(_("Error: Not enough memory\n")); \
1189 #define FILL_BOOLEAN_OR_LEAVE(variable, locale) { \
1191 (variable) = malloc(sizeof(*(variable))); \
1192 if (!(variable)) { \
1193 printf(_("Error: Not enough memory\n")); \
1197 if (!strcmp((locale), "0")) *(variable) = 0; \
1198 else if (!strcmp((locale), "1")) *(variable) = 1; \
1200 printf(_("%s: %s: Unknown boolean value\n"), argv[0], (locale)); \
1206 #define FILL_LONGINT_OR_LEAVE(variable, locale) { \
1207 if (!(locale) || !*(locale)) { \
1208 printf(_("%s: Empty integer value\n"), argv[0]); \
1214 (variable) = malloc(sizeof(*(variable))); \
1215 if (!(variable)) { \
1216 printf(_("Error: Not enough memory\n")); \
1220 (*variable) = strtol((locale), &endptr, 0); \
1222 printf(_("%s: %s: Invalid integer value\n"), argv[0], (locale)); \
1228 static int shi_find_box(int argc
, const char **argv
) {
1231 struct isds_DbOwnerInfo
*criteria
= NULL
;
1232 struct isds_list
*item
;
1236 if (!argv
|| !argv
[1] || !*argv
[1]) {
1237 printf(_("Error: No argument supplied\n"));
1238 shi_find_box_usage((argv
)?argv
[0]:NULL
);
1242 criteria
= calloc(1, sizeof(*criteria
));
1244 printf(_("Error: Not enough memory\n"));
1251 while ((opt
= getopt(argc
, (char * const *)argv
, "t:j:s:"
1252 "f:m:l:b:s:" "d:w:y:c:" "W:S:z:Z:P:C:"
1253 "n:e:p:i:r:a:o:k:")) != -1) {
1256 criteria
->dbType
= malloc(sizeof(*criteria
->dbType
));
1257 if (!criteria
->dbType
) {
1258 printf(_("Error: Not enough memory\n"));
1262 if (!strcmp(optarg
, "FO"))
1263 *criteria
->dbType
= DBTYPE_FO
;
1264 else if (!strcmp(optarg
, "PFO"))
1265 *criteria
->dbType
= DBTYPE_PFO
;
1266 else if (!strcmp(optarg
, "PFO_ADVOK"))
1267 *criteria
->dbType
= DBTYPE_PFO_ADVOK
;
1268 else if (!strcmp(optarg
, "PFO_DANPOR"))
1269 *criteria
->dbType
= DBTYPE_PFO_DANPOR
;
1270 else if (!strcmp(optarg
, "PFO_INSSPR"))
1271 *criteria
->dbType
= DBTYPE_PFO_INSSPR
;
1272 else if (!strcmp(optarg
, "PO"))
1273 *criteria
->dbType
= DBTYPE_PO
;
1274 else if (!strcmp(optarg
, "PO_ZAK"))
1275 *criteria
->dbType
= DBTYPE_PO_ZAK
;
1276 else if (!strcmp(optarg
, "PO_REQ"))
1277 *criteria
->dbType
= DBTYPE_PO_REQ
;
1278 else if (!strcmp(optarg
, "OVM"))
1279 *criteria
->dbType
= DBTYPE_OVM
;
1280 else if (!strcmp(optarg
, "OVM_NOTAR"))
1281 *criteria
->dbType
= DBTYPE_OVM_NOTAR
;
1282 else if (!strcmp(optarg
, "OVM_EXEKUT"))
1283 *criteria
->dbType
= DBTYPE_OVM_EXEKUT
;
1284 else if (!strcmp(optarg
, "OVM_REQ"))
1285 *criteria
->dbType
= DBTYPE_OVM_REQ
;
1287 printf(_("%s: %s: Unknown box type\n"), argv
[0], optarg
);
1294 FILL_OR_LEAVE(criteria
->ic
, optarg
);
1299 CALLOC_OR_LEAVE(criteria
->personName
);
1300 FILL_OR_LEAVE(criteria
->personName
->pnFirstName
, optarg
);
1303 CALLOC_OR_LEAVE(criteria
->personName
);
1304 FILL_OR_LEAVE(criteria
->personName
->pnMiddleName
, optarg
);
1307 CALLOC_OR_LEAVE(criteria
->personName
);
1308 FILL_OR_LEAVE(criteria
->personName
->pnLastName
, optarg
);
1311 CALLOC_OR_LEAVE(criteria
->personName
);
1312 FILL_OR_LEAVE(criteria
->personName
->pnLastNameAtBirth
, optarg
);
1315 FILL_OR_LEAVE(criteria
->firmName
, optarg
);
1320 CALLOC_OR_LEAVE(criteria
->birthInfo
);
1321 criteria
->birthInfo
->biDate
= datestring2tm(optarg
);
1322 if (!criteria
->birthInfo
->biDate
) {
1323 printf(_("Error: Could not parse date: %s\n"), optarg
);
1329 CALLOC_OR_LEAVE(criteria
->birthInfo
);
1330 FILL_OR_LEAVE(criteria
->birthInfo
->biCity
, optarg
);
1333 CALLOC_OR_LEAVE(criteria
->birthInfo
);
1334 FILL_OR_LEAVE(criteria
->birthInfo
->biCounty
, optarg
);
1337 CALLOC_OR_LEAVE(criteria
->birthInfo
);
1338 FILL_OR_LEAVE(criteria
->birthInfo
->biState
, optarg
);
1343 CALLOC_OR_LEAVE(criteria
->address
);
1344 FILL_OR_LEAVE(criteria
->address
->adCity
, optarg
);
1347 CALLOC_OR_LEAVE(criteria
->address
);
1348 FILL_OR_LEAVE(criteria
->address
->adStreet
, optarg
);
1351 CALLOC_OR_LEAVE(criteria
->address
);
1352 FILL_OR_LEAVE(criteria
->address
->adNumberInStreet
, optarg
);
1355 CALLOC_OR_LEAVE(criteria
->address
);
1356 FILL_OR_LEAVE(criteria
->address
->adNumberInMunicipality
,
1360 CALLOC_OR_LEAVE(criteria
->address
);
1361 FILL_OR_LEAVE(criteria
->address
->adZipCode
, optarg
);
1364 CALLOC_OR_LEAVE(criteria
->address
);
1365 FILL_OR_LEAVE(criteria
->address
->adState
, optarg
);
1370 FILL_OR_LEAVE(criteria
->nationality
, optarg
);
1373 FILL_OR_LEAVE(criteria
->email
, optarg
);
1376 FILL_OR_LEAVE(criteria
->telNumber
, optarg
);
1379 FILL_OR_LEAVE(criteria
->identifier
, optarg
);
1382 FILL_OR_LEAVE(criteria
->registryCode
, optarg
);
1385 criteria
->dbState
= malloc(sizeof(*criteria
->dbState
));
1386 if (!criteria
->dbState
) {
1387 printf(_("Error: Not enough memory\n"));
1391 if (!strcmp(optarg
, "ACCESSIBLE"))
1392 *criteria
->dbState
= DBSTATE_ACCESSIBLE
;
1393 else if (!strcmp(optarg
, "TEMP_UNACCESSIBLE"))
1394 *criteria
->dbState
= DBSTATE_TEMP_UNACCESSIBLE
;
1395 else if (!strcmp(optarg
, "NOT_YET_ACCESSIBLE"))
1396 *criteria
->dbState
= DBSTATE_NOT_YET_ACCESSIBLE
;
1397 else if (!strcmp(optarg
, "PERM_UNACCESSIBLE"))
1398 *criteria
->dbState
= DBSTATE_PERM_UNACCESSIBLE
;
1399 else if (!strcmp(optarg
, "REMOVED"))
1400 *criteria
->dbState
= DBSTATE_REMOVED
;
1402 printf(_("%s: %s: Unknown box status\n"), argv
[0], optarg
);
1408 FILL_BOOLEAN_OR_LEAVE(criteria
->dbEffectiveOVM
, optarg
);
1411 FILL_BOOLEAN_OR_LEAVE(criteria
->dbOpenAddressing
, optarg
);
1415 shi_find_box_usage(argv
[0]);
1421 /* There must be an option and all of them must be recognized, if not only
1422 * BOX_ID supplied */
1423 if (argc
> 2 && optind
!= argc
) {
1424 printf(_("Error: Superfluous argument\n"));
1425 shi_find_box_usage(argv
[0]);
1430 /* If only box ID is supplied use it */
1431 if (argc
== 2 && argv
[1] && *argv
[1]) {
1432 criteria
->dbID
= locale2utf8(argv
[1]);
1433 if (!criteria
->dbID
) {
1434 printf(_("Error: Not enough memory\n"));
1440 printf(_("Searching boxes...\n"));
1441 err
= isds_FindDataBox(cisds
, criteria
, &boxes
);
1442 finish_isds_operation(cisds
, err
);
1445 for(item
= boxes
; item
; item
= item
->next
) {
1446 if (!item
->data
) continue;
1449 printf(_("\n* Result #%d:\n"), order
);
1450 format_DbOwnerInfo(item
->data
);
1454 isds_DbOwnerInfo_free(&criteria
);
1459 static void shi_stat_box_usage(const char *command
) {
1461 "Usage: %s BOX_ID...\n"
1462 "Get status of box with BOX_ID. More boxes can be specified.\n"),
1467 /* Get boxes status */
1468 static int shi_stat_box(int argc
, const char **argv
) {
1473 if (!argv
|| !*argv
|| argc
< 2 || !argv
[1]) {
1474 printf(_("Missing box ID\n"));
1475 shi_stat_box_usage((argv
[0])?argv
[0]:NULL
);
1479 for (int i
= 1; i
< argc
; i
++) {
1480 if (!argv
[i
] || !*argv
[i
]) continue;
1483 id
= locale2utf8(argv
[i
]);
1485 printf(_("%s: Could not covert box ID to UTF-8\n"), argv
[i
]);
1489 printf(_("Getting status of box `%s'...\n"), argv
[i
]);
1490 err
= isds_CheckDataBox(cisds
, id
, &status
);
1491 finish_isds_operation(cisds
, err
);
1494 printf(_("Status of box `%s': %s\n"),
1495 argv
[i
], DbState2string(&status
));
1502 static void shi_compose_usage(const char *command
) {
1504 "Usage: %s OPTION...\n"
1505 "Compose and send a message to recipient defined by his BOX_ID.\n"
1506 "Each option requires an argument (if not stated otherwise):\n"
1507 " -s * message subject\n"
1509 "Recpient options:\n"
1510 " -b * recipient box ID\n"
1511 " -U organisation unit name\n"
1512 " -N organisation unit number\n"
1513 " -P to hands of given person\n"
1515 "Sender organisation structure options:\n"
1519 "Message identifier options:\n"
1520 " -r sender reference number\n"
1521 " -f sender file ID\n"
1522 " -R recipient reference number\n"
1523 " -F recipient file ID\n"
1525 "Legal title options:\n"
1526 " -y year act has been issued\n"
1527 " -a ordinar number of act in a yead\n"
1528 " -e section of the act\n"
1529 " -o paragraph of the act\n"
1530 " -i point of the paragraph of the act\n"
1532 "Delivery options:\n"
1533 " -p personal delivery required\n"
1534 " -t allow substitutable delivery\n"
1535 " -A non-OVM sender acts as public authority\n"
1537 "Document options:\n"
1538 " -d * read document from local file\n"
1539 " -D document name (defaults to base local file name)\n"
1540 " -m override MIME type (guessed on -d)\n"
1541 " -g document ID (must be unique per message)\n"
1542 " -G reference to other document using its ID\n"
1543 " -c document is digital signature of other document (NO argument\n"
1546 "Options marked with asterisk are mandatory, other are optional. Another soft\n"
1547 "dependecies can emerge upon using specific option. They are not mandated by\n"
1548 "ISDS currently, but client library or this program can force them to assure\n"
1549 "semantically complete message. Following soft dependecies are recommended:\n"
1550 " -y <=> -a act number and year must be used at the same time\n"
1551 " -i => -o act point requires act parahraph\n"
1552 " -o => -e act paragraph requires act section\n"
1553 " -e => -a act section requires act number\n"
1554 " -G => -g document with referenced ID must exist\n"
1555 " -c => -G signature must refer to signed document\n"
1556 " -c first document cannot be signature\n"
1558 "More documents can be attached to a message by repeating `-d' option.\n"
1559 "Document order will be preserved. Other document options affect immediately\n"
1560 "preceding `-d' document only. E.g. `-d /tmp/foo.pdf -m application/pdf\n"
1561 "-d /tmp/bar.txt -m text/plain' attaches first PDF file, then textual file.\n"
1563 "The same applies to recipient options that must start with box ID (-b).\n"
1564 "If more recipients specified, each of them will get a copy of composed\n"
1565 "message. ISDS will assign message identifier to each copy in turn.\n"
1571 static int shi_compose(int argc
, const char **argv
) {
1575 struct isds_message
*message
= NULL
;
1576 struct isds_envelope
*envelope
= NULL
;
1577 struct isds_list
*documents
= NULL
;
1578 struct isds_document
*document
= NULL
;
1579 struct isds_list
*copies
= NULL
, *copy_item
= NULL
;
1580 struct isds_message_copy
*copy
= NULL
;
1581 char *message_id_locale
= NULL
, *recipient_id_locale
= NULL
,
1582 *dmStatus_locale
= NULL
;
1584 if (!argv
|| !argv
[1] || !*argv
[1]) {
1585 printf(_("Error: No argument supplied\n"));
1586 shi_compose_usage((argv
)?argv
[0]:NULL
);
1590 message
= calloc(1, sizeof(*message
));
1592 printf(_("Error: Not enough memory\n"));
1596 envelope
= calloc(1, sizeof(*envelope
));
1598 printf(_("Error: Not enough memory\n"));
1602 message
->envelope
= envelope
;
1606 while ((opt
= getopt(argc
, (char * const *)argv
, "s:" "b:U:N:P:" "u:n:"
1607 "r:f:R:F:" "y:a:e:o:i:" "p:t:A:" "d:D:m:g:G:c"
1611 FILL_OR_LEAVE(envelope
->dmAnnotation
, optarg
);
1614 /* Recipient options */
1618 /* First recipient */
1619 CALLOC_OR_LEAVE(copies
);
1620 copies
->destructor
=
1621 (void(*)(void **)) isds_message_copy_free
;
1624 /* Next recipient */
1625 CALLOC_OR_LEAVE(copy_item
->next
);
1626 copy_item
->next
->destructor
=
1627 (void(*)(void **)) isds_message_copy_free
;
1628 copy_item
= copy_item
->next
;
1630 CALLOC_OR_LEAVE(copy
);
1631 copy_item
->data
= copy
;
1633 /* Copy recipient box ID */
1634 FILL_OR_LEAVE(copy
->dbIDRecipient
, optarg
);
1638 printf(_("Error: %s: Recipient box ID (-b) must precede "
1639 "recipient organisation unit name (-%c)\n"),
1644 FILL_OR_LEAVE(copy
->dmRecipientOrgUnit
, optarg
);
1648 printf(_("Error: %s: Recipient box ID (-b) must precede "
1649 "recipient organisation unit number (-%c)\n"),
1654 FILL_LONGINT_OR_LEAVE(copy
->dmRecipientOrgUnitNum
, optarg
);
1658 printf(_("Error: %s: Recipient box ID (-b) must precede "
1659 "to-hands option (-%c)\n"), optarg
, opt
);
1663 FILL_OR_LEAVE(copy
->dmToHands
, optarg
);
1666 /* Sender organisation structure options */
1668 FILL_OR_LEAVE(envelope
->dmSenderOrgUnit
, optarg
);
1671 FILL_LONGINT_OR_LEAVE(envelope
->dmSenderOrgUnitNum
, optarg
);
1674 /* Messae identifier options */
1676 FILL_OR_LEAVE(envelope
->dmSenderRefNumber
, optarg
);
1679 FILL_OR_LEAVE(envelope
->dmSenderIdent
, optarg
);
1682 FILL_OR_LEAVE(envelope
->dmRecipientRefNumber
, optarg
);
1685 FILL_OR_LEAVE(envelope
->dmRecipientIdent
, optarg
);
1688 /* Legal title options */
1690 FILL_LONGINT_OR_LEAVE(envelope
->dmLegalTitleYear
, optarg
);
1693 FILL_LONGINT_OR_LEAVE(envelope
->dmLegalTitleLaw
, optarg
);
1696 FILL_OR_LEAVE(envelope
->dmLegalTitleSect
, optarg
);
1699 FILL_OR_LEAVE(envelope
->dmLegalTitlePar
, optarg
);
1702 FILL_OR_LEAVE(envelope
->dmLegalTitlePoint
, optarg
);
1705 /* Delivery options */
1707 FILL_BOOLEAN_OR_LEAVE(envelope
->dmPersonalDelivery
, optarg
);
1710 FILL_BOOLEAN_OR_LEAVE(envelope
->dmAllowSubstDelivery
, optarg
);
1713 FILL_BOOLEAN_OR_LEAVE(envelope
->dmOVM
, optarg
);
1716 /* Document options */
1720 /* First document */
1721 CALLOC_OR_LEAVE(message
->documents
);
1722 message
->documents
->destructor
=
1723 (void(*)(void **)) isds_document_free
;
1724 documents
= message
->documents
;
1725 CALLOC_OR_LEAVE(document
);
1726 documents
->data
= document
;
1727 document
->dmFileMetaType
= FILEMETATYPE_MAIN
;
1730 CALLOC_OR_LEAVE(documents
->next
);
1731 documents
->next
->destructor
=
1732 (void(*)(void **)) isds_document_free
;
1733 documents
= documents
->next
;
1734 CALLOC_OR_LEAVE(document
);
1735 documents
->data
= document
;
1736 document
->dmFileMetaType
= FILEMETATYPE_ENCLOSURE
;
1739 if (load_data_from_file(optarg
, &document
->data
,
1740 &document
->data_length
, &document
->dmMimeType
)) {
1744 /* XXX: POSIX basename() modifies argument */
1745 FILL_OR_LEAVE(document
->dmFileDescr
, basename(optarg
));
1749 printf(_("Error: %s: Document file (-d) must precede "
1750 "document name (-%c)\n"), optarg
, opt
);
1754 FILL_OR_LEAVE(document
->dmFileDescr
, optarg
);
1758 printf(_("Error: %s: Document file (-d) must precede "
1759 "MIME type (-%c)\n"), optarg
, opt
);
1763 FILL_OR_LEAVE(document
->dmMimeType
, optarg
);
1767 printf(_("Error: %s: Document file (-d) must precede "
1768 "document ID (-%c)\n"), optarg
, opt
);
1772 FILL_OR_LEAVE(document
->dmFileGuid
, optarg
);
1776 printf(_("Error: %s: Document file (-d) must precede "
1777 "document reference (-%c)\n"), optarg
, opt
);
1781 FILL_OR_LEAVE(document
->dmUpFileGuid
, optarg
);
1785 printf(_("Error: Document file (-d) must precede "
1786 "document signature type (-%c)\n"), opt
);
1790 document
->dmFileMetaType
= FILEMETATYPE_SIGNATURE
;
1794 shi_compose_usage(argv
[0]);
1800 /* All options must be recognized */
1801 if (optind
!= argc
) {
1802 printf(_("Error: Superfluous argument\n"));
1803 shi_compose_usage(argv
[0]);
1809 printf(_("Error: No recipient box ID specified\n"));
1810 shi_compose_usage(argv
[0]);
1815 /* TODO: Check Legal Title soft dependencies */
1818 printf(_("Following message has been composed:\n"));
1819 format_message(message
);
1820 printf(_("Following recipients have been specified:\n"));
1821 format_copies(copies
);
1822 /* TODO: Confirmation, correction */
1824 /* Send a message */
1825 printf(_("Sending message...\n"));
1826 err
= isds_send_message_to_multiple_recipients(cisds
, message
, copies
);
1827 finish_isds_operation(cisds
, err
);
1828 if (err
&& err
!= IE_PARTIAL_SUCCESS
) {
1833 /* Show results for each copy */
1834 for (copy_item
= copies
; copy_item
; copy_item
= copy_item
->next
) {
1835 if (!copy_item
->data
) continue;
1836 copy
= (struct isds_message_copy
*) copy_item
->data
;
1837 recipient_id_locale
= utf82locale(copy
->dbIDRecipient
);
1841 if (copy
->dmStatus
) dmStatus_locale
= utf82locale(copy
->dmStatus
);
1842 if (dmStatus_locale
)
1843 printf(_("%s: Failed: %s: %s\n"),
1844 recipient_id_locale
,
1845 isds_strerror(copy
->error
), dmStatus_locale
);
1847 printf(_("%s: Failed: %s\n"), recipient_id_locale
,
1848 isds_strerror(copy
->error
));
1849 zfree(dmStatus_locale
);
1851 message_id_locale
= utf82locale(copy
->dmID
);
1852 printf(_("%s: Succeded. Assigned message ID: %s\n"),
1853 recipient_id_locale
, message_id_locale
);
1854 free(message_id_locale
);
1857 free(recipient_id_locale
);
1861 isds_message_free(&message
);
1862 isds_list_free(&copies
);
1866 #undef FILL_LONGINT_OR_LEAVE
1867 #undef FILL_BOOLEAN_OR_LEAVE
1868 #undef CALLOC_OR_LEAVE
1869 #undef FILL_OR_LEAVE
1872 static void shi_delivery_usage(const char *command
) {
1874 "Usage: %s MESSAGE_ID\n"
1875 "Get delivery data about message with MESSAGE_ID.\n"),
1880 static int shi_delivery(int argc
, const char **argv
) {
1884 if (!argv
|| !argv
[1] || !*argv
[1]) {
1885 shi_delivery_usage(argv
[0]);
1890 printf(_("Getting delivery info...\n"));
1891 err
= isds_get_signed_delivery_info(cisds
, id
, &message
);
1892 finish_isds_operation(cisds
, err
);
1895 select_completition(COMPL_COMMAND
);
1899 format_message(message
);
1901 if (message
->envelope
&& message
->envelope
->dmID
)
1902 set_prompt(_("%s %s"), argv
[0], message
->envelope
->dmID
);
1904 set_prompt("%s", argv
[0]);
1905 select_completition(COMPL_MSG
);
1910 static int shi_dump_message(int argc
, const char **argv
) {
1912 printf(_("No message loaded\n"));
1916 print_message(message
);
1921 static void shi_hash_usage(const char *command
) {
1923 "Usage: %s [MESSAGE_ID]\n"
1924 "Retrieve message hash stored in ISDS.\n"
1925 "If MESSAGE_ID is defined, query for that message.\n"
1926 "Otherwise use current message.\n"),
1931 static int shi_hash(int argc
, const char **argv
) {
1933 const char *id
= NULL
;
1934 struct isds_hash
*hash
= NULL
;
1935 char *hash_string
= NULL
;
1937 if (!argv
|| argc
> 2) {
1938 shi_hash_usage((argv
)?argv
[0]:NULL
);
1941 if (argc
== 2 && argv
[1] && *argv
[1])
1945 printf(_("No message loaded\n"));
1948 if (!message
->envelope
|| !message
->envelope
->dmID
) {
1949 printf(_("Current message is missing ID\n"));
1952 id
= message
->envelope
->dmID
;
1955 printf(_("Getting message hash...\n"));
1956 err
= isds_download_message_hash(cisds
, id
, &hash
);
1957 finish_isds_operation(cisds
, err
);
1960 hash_string
= hash2string(hash
);
1961 printf(_("ISDS states message with `%s' ID has following hash:\n%s\n"),
1965 isds_hash_free(&hash
);
1970 static int shi_verify(int argc
, const char **argv
) {
1973 struct isds_hash
*retrieved_hash
= NULL
, *stored_hash
= NULL
;
1974 char *hash_string
= NULL
;
1978 printf(_("No message loaded\n"));
1982 if (!message
->envelope
) {
1983 printf(_("Current message is missing envelope\n"));
1986 stored_hash
= message
->envelope
->hash
;
1987 message
->envelope
->hash
= NULL
;
1989 if (message
->envelope
->dmID
) {
1990 /* Verify remote hash */
1991 printf(_("Remote hash check:\n"));
1993 printf(_("Getting message hash...\n"));
1994 err
= isds_download_message_hash(cisds
, message
->envelope
->dmID
,
1996 finish_isds_operation(cisds
, err
);
1998 if (retrieved_hash
) {
1999 hash_string
= hash2string(retrieved_hash
);
2000 fhprint(stdout
, _("Retrieved:"), width
);
2001 printf("%s\n", hash_string
);
2005 if (retrieved_hash
&& message
->raw
) {
2006 err
= isds_compute_message_hash(cisds
, message
,
2007 retrieved_hash
->algorithm
);
2008 finish_isds_operation(cisds
, err
);
2011 hash_string
= hash2string(message
->envelope
->hash
);
2012 fhprint(stdout
, _("Computed:"), width
);
2013 printf("%s\n", hash_string
);
2018 err
= isds_hash_cmp(retrieved_hash
, message
->envelope
->hash
);
2021 printf(_("Hashes match.\n")); break;
2023 printf(_("Hashes do not match.\n"));
2027 printf(_("Hashes could not be compared.\n"));
2032 free(retrieved_hash
);
2037 /* Verify stored hash */
2038 printf(_("Stored hash check:\n"));
2040 hash_string
= hash2string(stored_hash
);
2041 fhprint(stdout
, _("Stored:"), width
);
2042 printf("%s\n", hash_string
);
2046 err
= isds_compute_message_hash(cisds
, message
,
2047 stored_hash
->algorithm
);
2048 finish_isds_operation(cisds
, err
);
2051 hash_string
= hash2string(message
->envelope
->hash
);
2052 fhprint(stdout
, _("Computed:"), width
);
2053 printf("%s\n", hash_string
);
2058 err
= isds_hash_cmp(stored_hash
, message
->envelope
->hash
);
2061 printf(_("Hashes match.\n")); break;
2063 printf(_("Hashes do not match.\n"));
2067 printf(_("Hashes could not be compared.\n"));
2072 isds_hash_free(&message
->envelope
->hash
);
2075 message
->envelope
->hash
= stored_hash
;
2080 static int shi_authenticate(int argc
, const char **argv
) {
2085 printf(_("No message loaded\n"));
2088 if (!message
->raw
|| message
->raw_length
== 0) {
2089 printf(_("Current message is missing raw representation\n"));
2093 printf(_("Submitting message to authenticity check...\n"));
2094 err
= isds_authenticate_message(cisds
, message
->raw
, message
->raw_length
);
2095 finish_isds_operation(cisds
, (err
== IE_NOTUNIQ
) ? IE_SUCCESS
: err
);
2099 printf(_("Message originates in ISDS.\n")); break;
2101 printf(_("Message is unknown to ISDS or has been tampered.\n"));
2113 static void shi_accept_message_usage(const char *command
) {
2115 "Usage: %s [MESSAGE_ID...]\n"
2116 "Accept commercial message moving its state to received.\n"
2117 "If MESSAGE_ID is defined, accept that message. More messages can be specified.\n"
2118 "Otherwise accept all commercial incoming messages.\n"),
2123 static int shi_accept_message(int argc
, const char **argv
) {
2127 /* Proeccess messages named in argv */
2128 for (int i
= 1; i
< argc
; i
++) {
2129 if (!argv
[i
] || !*argv
[i
]) continue;
2131 id
= locale2utf8(argv
[i
]);
2133 printf(_("Error: Could not convert message ID to UTF-8: %s\n"),
2138 printf(_("Accepting message `%s'...\n"), argv
[i
]);
2139 err
= isds_mark_message_received(cisds
, id
);
2140 finish_isds_operation(cisds
, err
);
2146 printf(_("Message `%s' accepted\n"), argv
[i
]);
2151 /* TODO: list commercial not receievd messages and accept all of them
2153 printf(_("Error: No message ID supplied. Accepting all commercial "
2154 "messages not implemented yet.\n"));
2162 /* Mark message as read. At one form of ID must be provided.
2163 * @id is UTF-8 encoded message ID
2164 * @id_locale is locale encoded message ID. @id takes preference. */
2165 static int do_read_message(const char *id
, const char *id_locale
) {
2169 if ((!id
|| !*id
) && (!id_locale
|| !*id_locale
)) return -1;
2173 id_locale
= utf82locale(id
);
2176 id
= locale2utf8(id_locale
);
2178 printf(_("Error: Could not convert message ID to UTF-8: %s\n"),
2184 printf(_("Marking message `%s' as read...\n"), id_locale
);
2185 err
= isds_mark_message_read(cisds
, id
);
2186 finish_isds_operation(cisds
, err
);
2189 printf(_("Message `%s' marked as read\n"), id_locale
);
2191 if (static_id
) free((char *) id_locale
);
2192 else free((char *) id
);
2194 return (err
) ? -1 : 0;
2198 static void shi_read_message_usage(const char *command
) {
2200 "Usage: %s [MESSAGE_ID...]\n"
2201 "Mark message as read moving its state to read.\n"
2203 "When new incoming message is download, its state is not changed on server.\n"
2204 "Client must mark such message as read explicitely. You can use this command\n"
2205 "to do so, if not done automatically at download time by your client.\n"
2207 "If MESSAGE_ID is defined, mark that message. More messages can be specified.\n"
2208 "Otherwise marks currently loaded message.\n"),
2213 static int shi_read_message(int argc
, const char **argv
) {
2214 for (int i
= 1; i
< argc
; i
++) {
2215 if (!argv
[i
] || !*argv
[i
]) continue;
2216 if (do_read_message(NULL
, argv
[i
]))
2222 printf(_("No message loaded\n"));
2225 if (!message
->envelope
) {
2226 printf(_("Loaded message is missing envelope\n"));
2229 if (!message
->envelope
->dmID
|| !*message
->envelope
->dmID
) {
2230 printf(_("Loaded message is missing ID\n"));
2233 return do_read_message(message
->envelope
->dmID
, NULL
);
2240 static int shi_show_message(int argc
, const char **argv
) {
2242 printf(_("No message loaded\n"));
2246 format_message(message
);
2251 static void shi_incoming_message_usage(const char *command
) {
2253 "Usage: %s MESSAGE_ID\n"
2254 "Get incomming message with MESSAGE_ID.\n"),
2259 static int shi_incoming_message(int argc
, const char **argv
) {
2263 if (!argv
|| !argv
[1] || !*argv
[1]) {
2264 shi_incoming_message_usage(argv
[0]);
2269 printf(_("Getting incoming message...\n"));
2270 err
= isds_get_signed_received_message(cisds
, id
, &message
);
2271 finish_isds_operation(cisds
, err
);
2274 select_completition(COMPL_COMMAND
);
2278 format_message(message
);
2280 if (message
->envelope
&& message
->envelope
->dmID
)
2281 set_prompt(_("%s %s"), argv
[0], message
->envelope
->dmID
);
2283 set_prompt("%s", argv
[0]);
2284 select_completition(COMPL_MSG
);
2289 static void shi_outgoing_message_usage(const char *command
) {
2291 "Usage: %s MESSAGE_ID\n"
2292 "Get outgoing message with MESSAGE_ID.\n"),
2297 static int shi_outgoing_message(int argc
, const char **argv
) {
2301 if (!argv
|| !argv
[1] || !*argv
[1]) {
2302 shi_outgoing_message_usage(argv
[0]);
2307 printf(_("Getting outgoing message...\n"));
2308 err
= isds_get_signed_sent_message(cisds
, id
, &message
);
2309 finish_isds_operation(cisds
, err
);
2312 select_completition(COMPL_COMMAND
);
2316 format_message(message
);
2317 if (message
->envelope
&& message
->envelope
->dmID
)
2318 set_prompt(_("%s %s"), argv
[0], message
->envelope
->dmID
);
2320 set_prompt("%s", argv
[0]);
2321 select_completition(COMPL_MSG
);
2326 static void shi_load_anything_usage(const char *command
) {
2329 "Load message or message delivery details from local FILE.\n"),
2334 static int shi_load_anything(int argc
, const char **argv
) {
2336 void *buffer
= NULL
;
2338 isds_raw_type raw_type
;
2340 char *type_name
= NULL
;
2342 if (!argv
|| !argv
[1] || !*argv
[1]) {
2343 shi_load_anything_usage((argv
)?argv
[0]:NULL
);
2347 printf(_("Loading file `%s'...\n"), argv
[1]);
2349 if (mmap_file(argv
[1], &fd
, &buffer
, &length
)) return -1;
2351 printf(_("Detecting file format...\n"));
2352 err
= isds_guess_raw_type(cisds
, &raw_type
, buffer
, length
);
2353 finish_isds_operation(cisds
, err
);
2356 if (err
== IE_NOTSUP
)
2357 printf(_("Unknown format. Could not parse the file.\n"));
2359 printf(_("Error while detecting format. "
2360 "Could not parse the file.\n"));
2363 case RAWTYPE_INCOMING_MESSAGE
:
2364 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
2365 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
2366 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
2367 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
2368 err
= isds_load_message(cisds
, raw_type
,
2369 buffer
, length
, &message
, BUFFER_COPY
);
2370 finish_isds_operation(cisds
, err
);
2371 type_name
= N_("message");
2374 case RAWTYPE_DELIVERYINFO
:
2375 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
2376 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
2377 err
= isds_load_delivery_info(cisds
, raw_type
,
2378 buffer
, length
, &message
, BUFFER_COPY
);
2379 finish_isds_operation(cisds
, err
);
2380 type_name
= N_("delivery");
2384 printf(_("Unsupported format. Could not parse the file.\n"));
2389 munmap_file(fd
, buffer
, length
);
2393 select_completition(COMPL_COMMAND
);
2397 format_message(message
);
2399 if (message
->envelope
&& message
->envelope
->dmID
)
2400 set_prompt(_("%s %s"), _(type_name
), message
->envelope
->dmID
);
2402 set_prompt("%s", _(type_name
));
2403 select_completition(COMPL_MSG
);
2408 static void shi_save_message_usage(const char *command
) {
2411 "Save message into local FILE.\n"),
2416 static const char *raw_type2mime(isds_raw_type raw_type
) {
2418 case RAWTYPE_INCOMING_MESSAGE
:
2419 case RAWTYPE_PLAIN_SIGNED_INCOMING_MESSAGE
:
2420 case RAWTYPE_PLAIN_SIGNED_OUTGOING_MESSAGE
:
2421 case RAWTYPE_DELIVERYINFO
:
2422 case RAWTYPE_PLAIN_SIGNED_DELIVERYINFO
:
2425 case RAWTYPE_CMS_SIGNED_INCOMING_MESSAGE
:
2426 case RAWTYPE_CMS_SIGNED_OUTGOING_MESSAGE
:
2427 case RAWTYPE_CMS_SIGNED_DELIVERYINFO
:
2428 return "application/pkcs7-mime";
2436 static int shi_save_message(int argc
, const char **argv
) {
2437 if (!argv
|| !argv
[1] || !*argv
[1]) {
2438 shi_save_message_usage(argv
[0]);
2443 printf(_("No message loaded\n"));
2446 if (!message
->raw
|| message
->raw_length
== 0) {
2447 printf(_("Loaded message is missing raw represantion\n"));
2451 return save_data_to_file(argv
[1], message
->raw
, message
->raw_length
,
2452 raw_type2mime(message
->raw_type
));
2456 /* Return document of current message identified by ordinar number expressed
2457 * as string. In case of error return NULL. */
2458 static const struct isds_document
*locate_document_by_ordinal_string(
2459 const char *number
) {
2460 const struct isds_list
*item
;
2461 const struct isds_document
*document
= NULL
;
2464 if (!number
) return NULL
;
2466 ordinar
= atoi(number
);
2468 printf(_("%s: Document number must be positive number\n"), number
);
2473 printf(_("No message loaded\n"));
2478 for (item
= message
->documents
, i
= 0; item
; item
= item
->next
) {
2479 if (!item
->data
) continue;
2480 if (++i
== ordinar
) {
2481 document
= (const struct isds_document
*) item
->data
;
2486 printf(_("Message does not contain document #%d\n"), ordinar
);
2494 static void shi_save_document_usage(const char *command
) {
2496 "Usage: %s NUMBER [DESTINATION]\n"
2497 "Save document having ordinar NUMBER within current message into local file.\n"
2498 "If DESTINATION is file (or does not exist yet), document will be saved into\n"
2500 "If DESTINATION is existing directory, file name equaled to document name\n"
2501 "will be saved into DESTINATION.\n"
2502 "If DESTINATION is missing, document name will be used as file name and\n"
2503 "saved into working directory.\n"
2504 "Be aware that document name does not embed malicious characters (slashes).\n"
2510 static int shi_save_document(int argc
, const char **argv
) {
2511 const struct isds_document
*document
;
2512 const char *dirname
= NULL
;
2513 char *filename
= NULL
, *path
= NULL
;
2516 if (!argv
|| !argv
[1] || !*argv
[1] || argc
> 3) {
2517 shi_save_document_usage(argv
[0]);
2521 document
= locate_document_by_ordinal_string(argv
[1]);
2522 if (!document
) return -1;
2524 /* Select directory and file name */
2525 if (argv
[2] && *argv
[2]) {
2526 if (!is_directory(argv
[2])) {
2529 filename
= strdup(argv
[2]);
2531 printf(_("Not enough memory\n"));
2536 if (!filename
&& document
->dmFileDescr
&& &document
->dmFileDescr
) {
2537 filename
= utf82locale(document
->dmFileDescr
);
2539 printf(_("Not enough memory\n"));
2544 printf(_("File name neither supplied, nor document name exists\n"
2545 "Please, supply one.\n"));
2551 path
= astrcat3(dirname
, "/", filename
);
2558 printf(_("Not enough memory\n"));
2563 retval
= save_data_to_file(path
, document
->data
, document
->data_length
,
2564 document
->dmMimeType
);
2570 static void shi_save_stamp_usage(const char *command
) {
2573 "Save message time stamp into local FILE.\n"),
2578 static int shi_save_stamp(int argc
, const char **argv
) {
2579 if (!argv
|| !argv
[1] || !*argv
[1]) {
2580 shi_save_message_usage(argv
[0]);
2585 printf(_("No message loaded\n"));
2588 if (!message
->envelope
|| !message
->envelope
->timestamp
||
2589 message
->envelope
->timestamp_length
== 0) {
2590 printf(_("Loaded message is missing time stamp\n"));
2594 return save_data_to_file(argv
[1],
2595 message
->envelope
->timestamp
, message
->envelope
->timestamp_length
,
2596 "application/timestamp-reply");
2600 static int shi_show_list(int argc
, const char **argv
) {
2602 printf(_("No message list loaded\n"));
2606 printf((messages_are_outgoing
) ?
2607 ngettext("You have %'lu outgoing message\n",
2608 "You have %'lu outgoing messages\n", total_messages
) :
2609 ngettext("You have %'lu incomming message\n",
2610 "You have %'lu incomming messages\n", total_messages
),
2612 print_message_list(messages
, messages_are_outgoing
);
2617 static int shi_list_incoming(int argc
, const char **argv
) {
2620 printf(_("Listing incoming messages...\n"));
2621 err
= isds_get_list_of_received_messages(cisds
, NULL
, NULL
, NULL
,
2622 MESSAGESTATE_ANY
, 0, &total_messages
, &messages
);
2623 finish_isds_operation(cisds
, err
);
2626 select_completition(COMPL_COMMAND
);
2629 messages_are_outgoing
= 0;
2631 shi_show_list(0, NULL
);
2633 set_prompt(_("%s %'lu"), argv
[0], total_messages
);
2634 select_completition(COMPL_LIST
);
2639 static int shi_list_outgoing(int argc
, const char **argv
) {
2642 printf(_("Listing outgoing messages...\n"));
2643 err
= isds_get_list_of_sent_messages(cisds
, NULL
, NULL
, NULL
,
2644 MESSAGESTATE_ANY
, 0, &total_messages
, &messages
);
2645 finish_isds_operation(cisds
, err
);
2648 select_completition(COMPL_COMMAND
);
2651 messages_are_outgoing
= 1;
2653 shi_show_list(0, NULL
);
2655 set_prompt(_("%s %'lu"), argv
[0], total_messages
);
2656 select_completition(COMPL_LIST
);
2661 /* Submit document for conversion and print assigned identifier */
2662 static int do_convert(const struct isds_document
*document
) {
2665 struct tm
*date
= NULL
;
2667 if (!document
) return -1;
2669 printf(_("Submitting document for authorized conversion...\n"));
2671 err
= czp_convert_document(czechpoint
, document
, &id
, &date
);
2672 finish_isds_operation(czechpoint
, err
);
2675 char *name_locale
= utf82locale(document
->dmFileDescr
);
2676 char *date_string
= tm2string(date
);
2677 char *id_locale
= utf82locale(id
);
2679 "Document submitted for authorized conversion successfully under name\n"
2681 "Submit identifier assigned by Czech POINT deposit is `%s'.\n"),
2682 name_locale
, date_string
, id_locale
);
2686 printf(_("Be ware that submitted document has restricted lifetime "
2688 printf(_("See <%s> for more details.\n"), CZPDEPOSIT_URL
);
2691 free(id
); free(date
);
2692 return (err
) ? -1 : 0;
2696 static void shi_convert_file_usage(const char *command
) {
2698 "Usage: %s FILE [NAME]\n"
2699 "Submit local FILE to authorized conversion under NAME. If NAME is missing,\n"
2700 "it will use FILE name.\n"), command
);
2703 "If Czech POINT deposit accepts document, it will return document identifier\n"
2704 "that user is supposed to provide to officer at Czech POINT contact place.\n"
2705 "Currently only PDF 1.3 and higher version files are accepted.\n"));
2706 printf(_("See <%s> for more details.\n"), CZPDEPOSIT_URL
);
2710 static int shi_convert_file(int argc
, const char **argv
) {
2712 struct isds_document document
;
2715 if (!argv
|| argc
> 3 || !argv
[1] || !*argv
[1]) {
2716 shi_convert_file_usage((argv
)?argv
[0]:NULL
);
2720 memset(&document
, 0, sizeof(document
));
2722 if (argc
== 3 && argv
[2] && *argv
[2])
2723 document
.dmFileDescr
= locale2utf8(argv
[2]);
2725 document
.dmFileDescr
= locale2utf8(argv
[1]);
2726 if (!document
.dmFileDescr
) {
2727 printf(_("Could not convert document name to UTF-8\n"));
2731 printf(_("Loading document from file `%s'...\n"), argv
[1]);
2732 if (mmap_file(argv
[1], &fd
, &document
.data
, &document
.data_length
)) {
2733 free(document
.dmFileDescr
);
2737 retval
= do_convert(&document
);
2739 munmap_file(fd
, document
.data
, document
.data_length
);
2740 free(document
.dmFileDescr
);
2745 static void shi_convert_document_usage(const char *command
) {
2747 "Usage: %s NUMBER\n"
2748 "Submit message document with ordinal NUMBER to authorized conversion.\n"),
2752 "If Czech POINT deposit accepts document, it will return document identifier\n"
2753 "that user is supposed to provide to officer at Czech POINT contact place.\n"
2754 "Currently only PDF 1.3 and higher version files are accepted.\n"));
2755 printf(_("See <%s> for more details.\n"), CZPDEPOSIT_URL
);
2759 static int shi_convert_document(int argc
, const char **argv
) {
2760 const struct isds_document
*document
;
2762 if (!argv
|| !argv
[1] || !*argv
[1]) {
2763 shi_convert_document_usage((argv
)?argv
[0]:NULL
);
2767 document
= locate_document_by_ordinal_string(argv
[1]);
2768 if (!document
) return -1;
2770 return do_convert(document
);
2775 static void shi_print_usage(const char *command
) {
2777 "Usage: %s STRING LENGTH\n"
2778 "Prints STRING into LENGTH columns. Negative LENGHT means not to cut\n"
2779 "overflowing string.\n"
2780 "This should be locale and terminal agnostic.\n"),
2785 static int shi_print(int argc
, const char **argv
) {
2788 if (!argv
|| !argv
[1] || !argv
[2]) {
2789 shi_print_usage((argv
)?argv
[0]:NULL
);
2793 width
= strtol(argv
[2], NULL
, 10);
2794 if (width
< INT_MIN
) {
2796 _("Length argument must not lesser than %d.\n"), INT_MIN
);
2799 if (width
> INT_MAX
) {
2801 _("Length argument must not be greater than %d.\n"), INT_MAX
);
2806 fnprint(stdout
, argv
[1], width
);
2813 static int shi_tokenize(int argc
, const char **argv
) {
2815 if (!argv
) return 0;
2817 for (int i
= 0; i
< argc
; i
++) {
2818 printf(_(">%s<\n"), argv
[i
]);
2824 static int shi_quote(int argc
, const char **argv
) {
2825 char *escaped
, *unescaped
;
2827 if (!argv
) return 0;
2829 printf(_("Original\tQuoted\tDequoted\n"));
2830 for (int i
= 0; i
< argc
; i
++) {
2831 escaped
= shi_quote_filename((char *) argv
[i
], 0, NULL
);
2832 unescaped
= shi_dequote_filename((char *) argv
[i
], 0);
2833 printf(_(">%s<\t>%s<\t>%s<\n"), argv
[i
], escaped
, unescaped
);
2842 /* Interactive loop */
2843 void shi_loop(void) {
2844 char *command_line
= NULL
;
2845 char **command_argv
= NULL
;
2847 struct command
*command
= NULL
;
2849 printf(_("Use `help' command to get list of available commands.\n"));
2851 select_completition(COMPL_COMMAND
);
2855 command_line
= readline((prompt
) ? prompt
: _("shigofumi> "));
2856 /* Remeber not parsable commands too to user be able to get back to
2858 if (command_line
&& *command_line
) {
2859 /* TODO: Ommit blank lines */
2860 add_history(command_line
);
2863 command_argv
= tokenize(command_line
, &command_argc
);
2865 if (command_argv
&& command_argv
[0]) {
2866 command
= find_command(command_argv
[0]);
2869 fprintf(stderr
, _("Command not understood\n"));
2871 command
->function(command_argc
, (const char **) command_argv
);
2875 argv_free(command_argv
);
2876 zfree(command_line
);
2881 /* Non-interactive mode. Commands from @lines are processed until any command
2882 * lines remains or no error occured. First failure terminates processing.
2883 * @lines is sequence of commands seperated by '\n' or '\r'. The content is
2884 * modified during this call.
2885 * @return 0 if all command succeed, otherwose non-zero value
2887 int shi_batch(char *lines
) {
2889 char **command_argv
= NULL
;
2891 struct command
*command
= NULL
;
2894 printf(_("Batch mode started.\n"));
2896 select_completition(COMPL_COMMAND
);
2898 while (!retval
&& (command_line
= strtok(lines
, "\n\r"))) {
2899 lines
= NULL
; /* strtok(3) requires it for subsequent calls */
2901 printf(_("Processing command: %s\n"), command_line
);
2903 command_argv
= tokenize(command_line
, &command_argc
);
2905 if (command_argv
&& command_argv
[0]) {
2906 command
= find_command(command_argv
[0]);
2909 fprintf(stderr
, _("Command not understood\n"));
2912 retval
= command
->function(command_argc
,
2913 (const char **) command_argv
);
2917 argv_free(command_argv
);
2921 fprintf(stderr
, _("Command failed!\n"));
2926 #define COMMON_COMMANDS \
2927 { "accept", shi_accept_message, N_("accept commercial message"), \
2928 shi_accept_message_usage, ARGTYPE_MSGID }, \
2929 { "box", shi_box, N_("show current box details"), NULL, \
2931 { "cache", shi_cache, N_("show cache details"), NULL, \
2933 { "cd", shi_chdir, N_("change working directory"), shi_chdir_usage, \
2935 { "commercial", shi_commercial, \
2936 N_("manipulate commerical receiving box status"), \
2937 shi_commercial_usage, ARGTYPE_BOXID }, \
2938 { "compose", shi_compose, N_("compose a message"), shi_compose_usage, \
2940 { "convert", shi_convert_file, \
2941 N_("submit local document for authorized conversion"), \
2942 shi_convert_file_usage, ARGTYPE_FILE }, \
2943 { "copying", shi_copying, N_("show this program licence excerpt"), NULL, \
2945 { "debug", shi_debug, N_("set debugging"), shi_debug_usage, \
2947 { "delivery", shi_delivery, N_("get message delivery details"), \
2948 shi_delivery_usage, ARGTYPE_MSGID }, \
2949 { "findbox", shi_find_box, N_("search for a box"), shi_find_box_usage, \
2951 { "hash", shi_hash, N_("query ISDS for message hash"), \
2952 shi_hash_usage, ARGTYPE_MSGID }, \
2953 { "help", shi_help, N_("describe commands"), shi_help_usage, \
2954 ARGTYPE_COMMAND }, \
2955 { "load", shi_load_anything, \
2956 N_("load message or message delivery details from local file"), \
2957 shi_load_anything_usage, ARGTYPE_FILE }, \
2958 { "login", shi_login, N_("log into ISDS"), NULL, ARGTYPE_NONE }, \
2959 { "lsi", shi_list_incoming, N_("list received messages"), NULL, \
2961 { "lso", shi_list_outgoing, N_("list sent messages"), NULL, \
2963 { "msgi", shi_incoming_message, N_("get incoming message"), \
2964 shi_incoming_message_usage, ARGTYPE_MSGID }, \
2965 { "msgo", shi_outgoing_message, N_("get outgoing message"), \
2966 shi_outgoing_message_usage, ARGTYPE_MSGID }, \
2967 { "passwd", shi_passwd, N_("manipulate user password"), shi_passwd_usage, \
2969 { "pwd", shi_pwd, N_("print working directory"), NULL, ARGTYPE_NONE }, \
2970 { "quit", shi_quit, N_("exit shigofumi"), NULL, ARGTYPE_NONE }, \
2971 { "read", shi_read_message, N_("mark message as read"), \
2972 shi_read_message_usage, ARGTYPE_MSGID }, \
2973 { "statbox", shi_stat_box, N_("get status of a box"), shi_stat_box_usage, \
2975 { "user", shi_user, N_("show current user details"), NULL, \
2977 { "users", shi_users, N_("show box users"), shi_users_usage, \
2979 { "version", shi_version, N_("show version of this program"), NULL, \
2981 { NULL, NULL, NULL, NULL, ARGTYPE_NONE }
2983 struct command base_commands
[] = {
2985 { "quote", shi_quote
, N_("demonstrate argument escaping"), NULL
,
2987 { "print", shi_print
, N_("print string into given width"),
2988 shi_print_usage
, ARGTYPE_NONE
},
2989 { "tokenize", shi_tokenize
, N_("demonstrate arguments tokenization"), NULL
,
2995 struct command message_commands
[] = {
2996 { "authenticate", shi_authenticate
, N_("check message authenticity"),
2997 NULL
, ARGTYPE_NONE
},
2998 { "convertdoc", shi_convert_document
,
2999 N_("submit document of current message for authorized conversion"),
3000 shi_convert_document_usage
, ARGTYPE_DOCID
},
3001 { "dump", shi_dump_message
, N_("dump current message structure"),
3002 NULL
, ARGTYPE_NONE
},
3003 { "savestamp", shi_save_stamp
,
3004 N_("save time stamp of current message into local file"),
3005 shi_save_stamp_usage
, ARGTYPE_FILE
},
3006 { "savedoc", shi_save_document
,
3007 N_("save document of current message into local file"),
3008 shi_save_document_usage
, ARGTYPE_FILE
},
3009 { "save", shi_save_message
, N_("save current message into local file"),
3010 shi_save_message_usage
, ARGTYPE_FILE
},
3011 { "show", shi_show_message
, N_("show current message"), NULL
,
3013 { "verify", shi_verify
, N_("verify current message hash"), NULL
,
3018 struct command list_commands
[] = {
3019 { "show", shi_show_list
, N_("show current message list"), NULL
,
3024 #undef COMMON_COMMANDS
3027 static void main_version(void) {
3032 shi_copying(0, NULL
);
3036 static void main_usage(const char *command
) {
3038 "Usage: %s [OPTION...]\n"
3039 "Access ISDS, proccess local data box messages or delivery details, submit\n"
3040 "document to authorized conversion.\n"
3043 " -c FILE use the FILE as configuration file instead of ~/%s\n"
3044 " -e COMMANDS execute COMMANDS (new line separated) and exit\n"
3045 " -V show version info and exit\n"
3047 (command
) ? command
: "shigofumi",
3052 int main(int argc
, char **argv
) {
3054 char *config_file
= NULL
;
3055 char *batch_commands
= NULL
;
3056 int retval
= EXIT_SUCCESS
;
3058 setlocale(LC_ALL
, "");
3060 /* Initialize gettext */
3061 bindtextdomain(PACKAGE
, LOCALEDIR
);
3062 textdomain(PACKAGE
);
3065 /* Parse arguments */
3067 while ((opt
= getopt(argc
, (char * const *)argv
, "c:e:V")) != -1) {
3070 config_file
= optarg
;
3073 batch_commands
= optarg
;
3077 shi_exit(EXIT_SUCCESS
);
3080 main_usage((argv
[0]) ? basename(argv
[0]): NULL
);
3081 shi_exit(EXIT_FAILURE
);
3086 if (shi_init(config_file
)) {
3087 shi_exit(EXIT_FAILURE
);
3090 /*shi_login(NULL);*/
3092 if (batch_commands
) {
3093 if (shi_batch(batch_commands
))
3094 retval
= EXIT_FAILURE
;