Commit a29af229 a29af229e7675aaabe28bdabf6cc2bd4b549e2cb by Sergey Poznyakoff

Convert mail to mu_cli

1 parent ee71e771
...@@ -25,7 +25,7 @@ mailbindir=@MAILBINDIR@ ...@@ -25,7 +25,7 @@ mailbindir=@MAILBINDIR@
25 mailbin_PROGRAMS = mail 25 mailbin_PROGRAMS = mail
26 26
27 mail_LDADD = \ 27 mail_LDADD = \
28 ${MU_APP_LIBRARIES}\ 28 ${MU_APP_NEW_LIBRARIES}\
29 ${MU_LIB_MBOX}\ 29 ${MU_LIB_MBOX}\
30 ${MU_LIB_IMAP}\ 30 ${MU_LIB_IMAP}\
31 ${MU_LIB_POP}\ 31 ${MU_LIB_POP}\
......
...@@ -16,108 +16,47 @@ ...@@ -16,108 +16,47 @@
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ 16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17 17
18 #include "mail.h" 18 #include "mail.h"
19 #include "mailutils/libargp.h" 19 #include "mailutils/cli.h"
20 20
21 /* Global variables and constants*/ 21 /* Global variables and constants*/
22 mu_mailbox_t mbox; /* Mailbox being operated upon */ 22 mu_mailbox_t mbox; /* Mailbox being operated upon */
23 size_t total; /* Total number of messages in the mailbox */ 23 size_t total; /* Total number of messages in the mailbox */
24 int interactive; /* Is the session interactive */ 24 int interactive; /* Is the session interactive */
25 25
26 static mu_list_t command_list; /* List of commands to be executed after parsing 26 static mu_list_t command_list;/* List of commands to be executed after parsing
27 command line */ 27 command line */
28
29 const char *program_version = "mail (" PACKAGE_STRING ")"; 28 const char *program_version = "mail (" PACKAGE_STRING ")";
30 static char doc[] = N_("GNU mail -- process mail messages.\n"
31 "If -f or --file is given, mail operates on the mailbox named "
32 "by the first argument, or the user's mbox, if no argument given.\n");
33 static char args_doc[] = N_("[address...]\n-f [OPTION...] [file]\n--file [OPTION...] [file]\n--file=file [OPTION...]");
34
35 #define F_OPTION 256
36 #define F_ENCODING 257
37 #define F_CONTENT_TYPE 258
38
39 static struct argp_option options[] = {
40 { NULL, 'f', NULL, OPTION_HIDDEN, NULL, 0 },
41 {"file", F_OPTION, "FILE", OPTION_ARG_OPTIONAL|OPTION_HIDDEN, 0},
42
43 {"exist", 'e', NULL, 0, N_("return true if mail exists"), 0},
44 {"byname", 'F', NULL, 0, N_("save messages according to sender"), 0},
45 {"headers", 'H', NULL, 0, N_("write a header summary and exit"), 0},
46 {"ignore", 'i', NULL, 0, N_("ignore interrupts"), 0},
47 {"norc", 'n', NULL, 0, N_("do not read the system mailrc file"), 0},
48 {"nosum", 'N', NULL, 0,
49 N_("do not display initial header summary"), 0},
50 {"print", 'p', NULL, 0, N_("print all mail to standard output"), 0},
51 {"read", 0, NULL, OPTION_ALIAS },
52 {"return-address", 'r', N_("ADDRESS"), 0,
53 N_("use address as the return address when sending mail"), 0},
54 {"quit", 'q', NULL, 0,
55 N_("cause interrupts to terminate program"), 0},
56 {"subject", 's', N_("SUBJ"), 0,
57 N_("send a message with the given SUBJECT"), 0},
58 {"to", 't', NULL, 0,
59 N_("precede message by a list of addresses"), 0},
60 {"user", 'u', N_("USER"), 0, N_("operate on USER's mailbox"), 0},
61 {"append", 'a', N_("HEADER: VALUE"), 0,
62 N_("append given header to the message being sent"), 0},
63 {"exec", 'E', N_("COMMAND"), 0,
64 N_("execute COMMAND"), 0 },
65 {"encoding", F_ENCODING, N_("NAME"), 0,
66 N_("set encoding for subsequent --attach options"), 0 },
67 {"content-type", F_CONTENT_TYPE, N_("TYPE"), 0,
68 N_("set content type for subsequent --attach options"), 0 },
69 {"attach", 'A', N_("FILE"), 0,
70 N_("attach FILE"), 0 },
71 { NULL, 0, NULL, 0, NULL, 0 }
72 };
73
74 29
30
75 #define HINT_SEND_MODE 0x1 31 #define HINT_SEND_MODE 0x1
76 #define HINT_FILE_OPTION 0x2 32 #define HINT_FILE_OPTION 0x2
77 33 int hint;
78 struct arguments 34 char *file;
35 char *user;
36
37 static void
38 cli_f_option (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
79 { 39 {
80 int argc; 40 hint |= HINT_FILE_OPTION;
81 char **argv; 41 }
82 char *file;
83 char *user;
84 int hint;
85 };
86 42
87 static error_t 43 static void
88 parse_opt (int key, char *arg, struct argp_state *state) 44 cli_file_option (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
89 { 45 {
90 struct arguments *args = state->input; 46 if (arg)
47 file = mu_strdup (arg);
48 hint |= HINT_FILE_OPTION;
49 }
91 50
92 switch (key) 51 static void
52 cli_command_option (struct mu_parseopt *po, struct mu_option *opt,
53 char const *arg)
54 {
55 switch (opt->opt_short)
93 { 56 {
94 case 'a':
95 args->hint |= HINT_SEND_MODE;
96 send_append_header (arg);
97 break;
98
99 case 'A':
100 args->hint |= HINT_SEND_MODE;
101 if (send_attach_file_default (arg))
102 exit (1);
103 break;
104
105 case F_CONTENT_TYPE:
106 free (default_content_type);
107 default_content_type = mu_strdup (arg);
108 break;
109
110 case 'e': 57 case 'e':
111 util_cache_command (&command_list, "setq mode=exist"); 58 util_cache_command (&command_list, "setq mode=exist");
112 break; 59 break;
113
114 case F_OPTION:
115 if (arg)
116 args->file = arg;
117 /* fall through */
118 case 'f':
119 args->hint |= HINT_FILE_OPTION;
120 break;
121 60
122 case 'p': 61 case 'p':
123 util_cache_command (&command_list, "setq mode=print"); 62 util_cache_command (&command_list, "setq mode=print");
...@@ -151,90 +90,157 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -151,90 +90,157 @@ parse_opt (int key, char *arg, struct argp_state *state)
151 util_cache_command (&command_list, "set noheader"); 90 util_cache_command (&command_list, "set noheader");
152 break; 91 break;
153 92
154 case 's':
155 args->hint |= HINT_SEND_MODE;
156 send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE);
157 util_cache_command (&command_list, "set noasksub");
158 break;
159
160 case 'u':
161 args->user = arg;
162 break;
163
164 case 'E': 93 case 'E':
165 util_cache_command (&command_list, "%s", arg); 94 util_cache_command (&command_list, "%s", arg);
166 break; 95 break;
167 96
168 case F_ENCODING:
169 free (default_encoding);
170 default_encoding = mu_strdup (arg);
171 break;
172
173 case 'F': 97 case 'F':
174 util_cache_command (&command_list, "set byname"); 98 util_cache_command (&command_list, "set byname");
175 break; 99 break;
176 100
177 case ARGP_KEY_ARG: 101 case 0:
178 args->argv = realloc (args->argv, 102 mu_parseopt_error (po,
179 sizeof (char *) * (state->arg_num + 2)); 103 _("--%s: option should have been recognized"),
180 args->argv[state->arg_num] = arg; 104 opt->opt_long);
181 args->argv[state->arg_num + 1] = NULL; 105 exit (po->po_exit_error);
182 args->argc = state->arg_num + 1;
183 break;
184
185 case ARGP_KEY_FINI:
186 if ((args->hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
187 (HINT_SEND_MODE|HINT_FILE_OPTION))
188 argp_error (state, _("conflicting options"));
189 else if (args->hint & HINT_FILE_OPTION)
190 {
191 if (args->file)
192 {
193 if (args->argc > 1)
194 argp_error (state,
195 _("-f requires at most one command line argument"));
196 }
197 else if (args->argc)
198 {
199 args->file = args->argv[0];
200
201 if (args->argc > 1)
202 argp_error (state,
203 _("-f requires at most one command line argument"));
204 }
205 else if (args->user)
206 mu_asprintf (&args->file, "~/%s/mbox", args->user);
207 else
208 args->file = "~/mbox";
209 }
210 else if (args->argc || (args->hint & HINT_SEND_MODE))
211 util_cache_command (&command_list, "setq mode=send");
212 else if (args->user)
213 mu_asprintf (&args->file, "%%%s", args->user);
214 break;
215 106
216 default: 107 default:
217 return ARGP_ERR_UNKNOWN; 108 mu_parseopt_error (po,
218 } 109 _("-%c: option should have been recognized"),
219 return 0; 110 opt->opt_short);
111 exit (po->po_exit_error);
112 }
220 } 113 }
221 114
222 static struct argp argp = { 115 static void
116 cli_subject (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
117 {
118 hint |= HINT_SEND_MODE;
119 send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE);
120 util_cache_command (&command_list, "set noasksub");
121 }
122
123 static void
124 cli_append (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
125 {
126 hint |= HINT_SEND_MODE;
127 send_append_header (arg);
128 }
129
130 static void
131 cli_attach (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
132 {
133 hint |= HINT_SEND_MODE;
134 if (send_attach_file_default (arg))
135 exit (1);
136 }
137
138 static struct mu_option mail_options[] = {
139 { NULL, 'f', NULL, MU_OPTION_HIDDEN,
140 NULL,
141 mu_c_string, NULL, cli_f_option },
142 { "file", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL|MU_OPTION_HIDDEN,
143 NULL,
144 mu_c_string, NULL, cli_file_option },
145
146 { "exist", 'e', NULL, MU_OPTION_DEFAULT,
147 N_("return true if mail exists"),
148 mu_c_string, NULL, cli_command_option },
149
150 { "byname", 'F', NULL, MU_OPTION_DEFAULT,
151 N_("save messages according to sender"),
152 mu_c_string, NULL, cli_command_option },
153
154 { "headers", 'H', NULL, MU_OPTION_DEFAULT,
155 N_("write a header summary and exit"),
156 mu_c_string, NULL, cli_command_option },
157
158 { "ignore", 'i', NULL, MU_OPTION_DEFAULT,
159 N_("ignore interrupts"),
160 mu_c_string, NULL, cli_command_option },
161
162 { "norc", 'n', NULL, MU_OPTION_DEFAULT,
163 N_("do not read the system mailrc file"),
164 mu_c_string, NULL, cli_command_option },
165
166 { "nosum", 'N', NULL, MU_OPTION_DEFAULT,
167 N_("do not display initial header summary"),
168 mu_c_string, NULL, cli_command_option },
169
170 { "print", 'p', NULL, MU_OPTION_DEFAULT,
171 N_("print all mail to standard output"),
172 mu_c_string, NULL, cli_command_option },
173 { "read", 0, NULL, MU_OPTION_ALIAS },
174
175 { "return-address", 'r', N_("ADDRESS"), MU_OPTION_DEFAULT,
176 N_("use address as the return address when sending mail"),
177 mu_c_string, NULL, cli_command_option },
178
179 { "quit", 'q', NULL, MU_OPTION_DEFAULT,
180 N_("cause interrupts to terminate program"),
181 mu_c_string, NULL, cli_command_option },
182
183 { "subject", 's', N_("SUBJ"), MU_OPTION_DEFAULT,
184 N_("send a message with the given SUBJECT"),
185 mu_c_string, NULL, cli_subject },
186
187 { "to", 't', NULL, MU_OPTION_DEFAULT,
188 N_("precede message by a list of addresses"),
189 mu_c_string, NULL, cli_command_option },
190
191 { "user", 'u', N_("USER"), MU_OPTION_DEFAULT,
192 N_("operate on USER's mailbox"),
193 mu_c_string, &user },
194
195 { "append", 'a', N_("HEADER: VALUE"), MU_OPTION_DEFAULT,
196 N_("append given header to the message being sent"),
197 mu_c_string, NULL, cli_append },
198
199 { "exec" , 'E', N_("COMMAND"), MU_OPTION_DEFAULT,
200 N_("execute COMMAND"),
201 mu_c_string, NULL, cli_command_option },
202
203 { "encoding", 0, N_("NAME"), MU_OPTION_DEFAULT,
204 N_("set encoding for subsequent --attach options"),
205 mu_c_string, &default_encoding },
206
207 { "content-type", 0, N_("TYPE"), MU_OPTION_DEFAULT,
208 N_("set content type for subsequent --attach options"),
209 mu_c_string, &default_content_type },
210
211 { "attach", 'A', N_("FILE"), MU_OPTION_DEFAULT,
212 N_("attach FILE"),
213 mu_c_string, NULL, cli_attach },
214
215 MU_OPTION_END
216 }, *options[] = { mail_options, NULL };
217
218 static const char *alt_args[] = {
219 N_("[OPTION...] [file]"),
220 N_("--file [OPTION...] [file]"),
221 N_("--file=file [OPTION...]"),
222 NULL
223 };
224
225 static struct mu_cli_setup cli = {
223 options, 226 options,
224 parse_opt,
225 args_doc,
226 doc,
227 NULL, 227 NULL,
228 NULL, NULL 228 N_("GNU mail -- process mail messages.\n"
229 "If -f or --file is given, mail operates on the mailbox named "
230 "by the first argument, or the user's mbox, if no argument given."),
231 N_("[address...]"),
232 alt_args,
233 NULL,
234 1,
235 1
229 }; 236 };
230 237
231 static const char *mail_capa[] = { 238 static char *mail_capa[] = {
232 "mailutils",
233 "common",
234 "address", 239 "address",
235 "debug", 240 "debug",
236 "mailbox", 241 "mailbox",
237 "locking", 242 "locking",
243 "tls",
238 NULL 244 NULL
239 }; 245 };
240 246
...@@ -351,7 +357,6 @@ int ...@@ -351,7 +357,6 @@ int
351 main (int argc, char **argv) 357 main (int argc, char **argv)
352 { 358 {
353 char *mode = NULL, *prompt = NULL, *p; 359 char *mode = NULL, *prompt = NULL, *p;
354 struct arguments args;
355 int i, rc; 360 int i, rc;
356 361
357 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); 362 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
...@@ -411,19 +416,45 @@ main (int argc, char **argv) ...@@ -411,19 +416,45 @@ main (int argc, char **argv)
411 mu_strdup ("sendmail:" PATH_SENDMAIL), mailvar_type_string, 416 mu_strdup ("sendmail:" PATH_SENDMAIL), mailvar_type_string,
412 MOPTF_OVERWRITE); 417 MOPTF_OVERWRITE);
413 418
414 args.argc = 0;
415 args.argv = NULL;
416 args.file = NULL;
417 args.user = NULL;
418 args.hint = 0;
419
420 /* argument parsing */ 419 /* argument parsing */
421 #ifdef WITH_TLS 420 mu_cli_capa_register (&mu_cli_capa_tls);
422 mu_gocs_register ("tls", mu_tls_module_init); 421 mu_cli (argc, argv, &cli, mail_capa, NULL, &argc, &argv);
423 #endif 422
424 mu_argp_init (NULL, NULL); 423 if ((hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
425 if (mu_app_init (&argp, mail_capa, NULL, argc, argv, 0, NULL, &args)) 424 (HINT_SEND_MODE|HINT_FILE_OPTION))
426 exit (1); 425 {
426 mu_error (_("conflicting options"));
427 exit (1);
428 }
429 else if (hint & HINT_FILE_OPTION)
430 {
431 if (file)
432 {
433 if (argc)
434 {
435 mu_error (_("-f requires at most one command line argument"));
436 exit (1);
437 }
438 }
439 else if (argc)
440 {
441 if (argc > 1)
442 {
443 mu_error (_("-f requires at most one command line argument"));
444 exit (1);
445 }
446 file = argv[0];
447 }
448 else if (user)
449 mu_asprintf (&file, "~/%s/mbox", user);
450 else
451 file = "~/mbox";
452 }
453 else if (argc || (hint & HINT_SEND_MODE))
454 util_cache_command (&command_list, "setq mode=send");
455 else if (user)
456 mu_asprintf (&file, "%%%s", user);
457
427 458
428 /* read system-wide mail.rc and user's .mailrc */ 459 /* read system-wide mail.rc and user's .mailrc */
429 if (mailvar_get (NULL, "rc", mailvar_type_boolean, 0) == 0) 460 if (mailvar_get (NULL, "rc", mailvar_type_boolean, 0) == 0)
...@@ -461,7 +492,7 @@ main (int argc, char **argv) ...@@ -461,7 +492,7 @@ main (int argc, char **argv)
461 /* Interactive mode */ 492 /* Interactive mode */
462 493
463 ml_readline_init (); 494 ml_readline_init ();
464 mail_set_my_name (args.user); 495 mail_set_my_name (user);
465 496
466 /* Mode is just sending */ 497 /* Mode is just sending */
467 if (strcmp (mode, "send") == 0) 498 if (strcmp (mode, "send") == 0)
...@@ -469,17 +500,17 @@ main (int argc, char **argv) ...@@ -469,17 +500,17 @@ main (int argc, char **argv)
469 char *buf = NULL; 500 char *buf = NULL;
470 int rc; 501 int rc;
471 502
472 mu_argcv_string (args.argc, args.argv, &buf); 503 mu_argcv_string (argc, argv, &buf);
473 rc = util_do_command ("mail %s", buf); 504 rc = util_do_command ("mail %s", buf);
474 return mailvar_get (NULL, "mailx", mailvar_type_boolean, 0) ? rc : 0; 505 return mailvar_get (NULL, "mailx", mailvar_type_boolean, 0) ? rc : 0;
475 } 506 }
476 /* Or acting as a normal reader */ 507 /* Or acting as a normal reader */
477 else 508 else
478 { 509 {
479 if ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0) 510 if ((rc = mu_mailbox_create_default (&mbox, file)) != 0)
480 { 511 {
481 if (args.file) 512 if (file)
482 mu_error (_("Cannot create mailbox %s: %s"), args.file, 513 mu_error (_("Cannot create mailbox %s: %s"), file,
483 mu_strerror (rc)); 514 mu_strerror (rc));
484 else 515 else
485 mu_error (_("Cannot create mailbox: %s"), 516 mu_error (_("Cannot create mailbox: %s"),
...@@ -530,11 +561,10 @@ main (int argc, char **argv) ...@@ -530,11 +561,10 @@ main (int argc, char **argv)
530 && (strcmp (mode, "read") 561 && (strcmp (mode, "read")
531 || mailvar_get (NULL, "emptystart", mailvar_type_boolean, 0))) 562 || mailvar_get (NULL, "emptystart", mailvar_type_boolean, 0)))
532 { 563 {
533 if (args.file) 564 if (file)
534 mu_printf (_("%s: 0 messages\n"), args.file); 565 mu_printf (_("%s: 0 messages\n"), file);
535 else 566 else
536 mu_printf (_("No mail for %s\n"), 567 mu_printf (_("No mail for %s\n"), user ? user : mail_whoami ());
537 args.user ? args.user : mail_whoami ());
538 return 1; 568 return 1;
539 } 569 }
540 570
......
...@@ -256,8 +256,8 @@ extern int mail_header_is_unfoldable (const char *str); ...@@ -256,8 +256,8 @@ extern int mail_header_is_unfoldable (const char *str);
256 extern int mail_mbox_close (void); 256 extern int mail_mbox_close (void);
257 extern char *mail_expand_name (const char *name); 257 extern char *mail_expand_name (const char *name);
258 258
259 extern void send_append_header (char *text); 259 extern void send_append_header (char const *text);
260 extern void send_append_header2 (char *name, char *value, int mode); 260 extern void send_append_header2 (char const *name, char const *value, int mode);
261 extern int send_attach_file_default (const char *name); 261 extern int send_attach_file_default (const char *name);
262 262
263 extern int escape_check_args (int argc, char **argv, int minargs, int maxargs); 263 extern int escape_check_args (int argc, char **argv, int minargs, int maxargs);
......
...@@ -81,7 +81,7 @@ add_header (char *name, char *value, int mode) ...@@ -81,7 +81,7 @@ add_header (char *name, char *value, int mode)
81 } 81 }
82 82
83 void 83 void
84 send_append_header (char *text) 84 send_append_header (char const *text)
85 { 85 {
86 char *p; 86 char *p;
87 size_t len; 87 size_t len;
...@@ -104,7 +104,7 @@ send_append_header (char *text) ...@@ -104,7 +104,7 @@ send_append_header (char *text)
104 } 104 }
105 105
106 void 106 void
107 send_append_header2 (char *name, char *value, int mode) 107 send_append_header2 (char const *name, char const *value, int mode)
108 { 108 {
109 add_header (mu_strdup (name), mu_strdup (value), mode); 109 add_header (mu_strdup (name), mu_strdup (value), mode);
110 } 110 }
......