New utility: mu
The `mu' program is a multi-purpose tool for doing various mail- and mailutils-related operations. It includes a pop3 shell, a coder/decoder for all filter formats supported by Mailutils, a utility to extract arbitrary values from the MU configuration files, a configuration information utility and many more, in the short run. It supercedes examples/pop3client and (partially) mailutils-config, both of which will be removed in the future. * Makefile.am (SUBDIRS): Add mu. * configure.ac: Likewise. * po/POTFILES.in: Add new files. * mu/.gitignore: New file. * mu/Makefile.am: New file. * mu/filter.c: New file. * mu/flt2047.c: New file. * mu/info.c: New file. * mu/mu.c: New file. * mu/mu.h: New file. * mu/pop.c: New file. * mu/query.c: New file. * mu/shell.c: New file.
Showing
13 changed files
with
2040 additions
and
0 deletions
... | @@ -1389,6 +1389,7 @@ AC_CONFIG_FILES([ | ... | @@ -1389,6 +1389,7 @@ AC_CONFIG_FILES([ |
1389 | mu-aux/Makefile | 1389 | mu-aux/Makefile |
1390 | mu-aux/mailutils.spec | 1390 | mu-aux/mailutils.spec |
1391 | sieve/Makefile | 1391 | sieve/Makefile |
1392 | mu/Makefile | ||
1392 | ]) | 1393 | ]) |
1393 | AC_OUTPUT | 1394 | AC_OUTPUT |
1394 | 1395 | ... | ... |
mu/.gitignore
0 → 100644
1 | mu |
mu/Makefile.am
0 → 100644
1 | ## This file is part of GNU Mailutils. | ||
2 | ## Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010 Free | ||
3 | ## Software Foundation, Inc. | ||
4 | ## | ||
5 | ## GNU Mailutils is free software; you can redistribute it and/or | ||
6 | ## modify it under the terms of the GNU General Public License as | ||
7 | ## published by the Free Software Foundation; either version 2, or (at | ||
8 | ## your option) any later version. | ||
9 | ## | ||
10 | ## This program is distributed in the hope that it will be useful, but | ||
11 | ## WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | ## General Public License for more details. | ||
14 | ## | ||
15 | ## You should have received a copy of the GNU General Public License | ||
16 | ## along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | bin_PROGRAMS = mu | ||
19 | mu_SOURCES = \ | ||
20 | info.c\ | ||
21 | mu.h\ | ||
22 | mu.c\ | ||
23 | filter.c\ | ||
24 | flt2047.c\ | ||
25 | pop.c\ | ||
26 | query.c\ | ||
27 | shell.c | ||
28 | |||
29 | mu_LDADD = \ | ||
30 | ${MU_APP_LIBRARIES}\ | ||
31 | ${MU_LIB_MBOX}\ | ||
32 | ${MU_LIB_IMAP}\ | ||
33 | ${MU_LIB_POP}\ | ||
34 | ${MU_LIB_NNTP}\ | ||
35 | ${MU_LIB_MH}\ | ||
36 | ${MU_LIB_MAILDIR}\ | ||
37 | ${MU_LIB_MAILER}\ | ||
38 | ${MU_LIB_AUTH}\ | ||
39 | @MU_AUTHLIBS@\ | ||
40 | ${MU_LIB_MAILUTILS}\ | ||
41 | @READLINE_LIBS@ @MU_COMMON_LIBRARIES@ | ||
42 | |||
43 | INCLUDES = @MU_APP_COMMON_INCLUDES@ @MU_AUTHINCS@ |
mu/filter.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include "argp.h" | ||
24 | #include "mu.h" | ||
25 | |||
26 | static char filter_doc[] = N_("mu filter"); | ||
27 | static char filter_args_doc[] = N_("[OPTIONS] NAME"); | ||
28 | |||
29 | static struct argp_option filter_options[] = { | ||
30 | { "encode", 'e', NULL, 0, N_("encode the input (default)") }, | ||
31 | { "decode", 'd', NULL, 0, N_("decode the input") }, | ||
32 | { "line-length", 'l', NULL, 0, N_("limit output line length") }, | ||
33 | { "newline", 'n', NULL, 0, N_("print additional newline") }, | ||
34 | { NULL } | ||
35 | }; | ||
36 | |||
37 | static int filter_mode = MU_FILTER_ENCODE; | ||
38 | static int newline_option = 0; | ||
39 | static size_t line_length; | ||
40 | static int line_length_option = 0; | ||
41 | |||
42 | static error_t | ||
43 | filter_parse_opt (int key, char *arg, struct argp_state *state) | ||
44 | { | ||
45 | char *p; | ||
46 | |||
47 | switch (key) | ||
48 | { | ||
49 | case 'e': | ||
50 | filter_mode = MU_FILTER_ENCODE; | ||
51 | break; | ||
52 | |||
53 | case 'd': | ||
54 | filter_mode = MU_FILTER_DECODE; | ||
55 | break; | ||
56 | |||
57 | case 'n': | ||
58 | newline_option = 1; | ||
59 | break; | ||
60 | |||
61 | case 'l': | ||
62 | line_length = strtoul (arg, &p, 10); | ||
63 | if (*p) | ||
64 | argp_error (state, N_("not a number")); | ||
65 | line_length_option = 1; | ||
66 | break; | ||
67 | |||
68 | default: | ||
69 | return ARGP_ERR_UNKNOWN; | ||
70 | } | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static struct argp filter_argp = { | ||
75 | filter_options, | ||
76 | filter_parse_opt, | ||
77 | filter_args_doc, | ||
78 | filter_doc, | ||
79 | NULL, | ||
80 | NULL, | ||
81 | NULL | ||
82 | }; | ||
83 | |||
84 | /* FIXME: This is definitely a kludge. The API should provide a function | ||
85 | for that. */ | ||
86 | static void | ||
87 | reset_line_length (const char *name, size_t length) | ||
88 | { | ||
89 | mu_list_t list; | ||
90 | int status; | ||
91 | mu_filter_record_t frec; | ||
92 | |||
93 | mu_filter_get_list (&list); | ||
94 | status = mu_list_locate (list, (void*)name, (void**)&frec); | ||
95 | if (status == 0) | ||
96 | frec->max_line_length = length; | ||
97 | /* don't bail out, leave that to mu_filter_create */ | ||
98 | } | ||
99 | |||
100 | int | ||
101 | mutool_filter (int argc, char **argv) | ||
102 | { | ||
103 | int rc, index; | ||
104 | mu_stream_t in, out, flt; | ||
105 | const char *fltname; | ||
106 | |||
107 | if (argp_parse (&filter_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
108 | return 1; | ||
109 | |||
110 | argc -= index; | ||
111 | argv += index; | ||
112 | |||
113 | if (argc != 1) | ||
114 | { | ||
115 | mu_error (_("what filter do you want?")); | ||
116 | return 1; | ||
117 | } | ||
118 | |||
119 | fltname = argv[0]; | ||
120 | |||
121 | rc = mu_stdio_stream_create (&in, MU_STDIN_FD, 0); | ||
122 | if (rc) | ||
123 | { | ||
124 | mu_error (_("cannot open input stream: %s"), mu_strerror (rc)); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | rc = mu_stdio_stream_create (&out, MU_STDOUT_FD, 0); | ||
129 | if (rc) | ||
130 | { | ||
131 | mu_error (_("cannot open output stream: %s"), mu_strerror (rc)); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | if (line_length_option) | ||
136 | reset_line_length (fltname, line_length); | ||
137 | |||
138 | rc = mu_filter_create (&flt, in, fltname, filter_mode, MU_STREAM_READ); | ||
139 | if (rc) | ||
140 | { | ||
141 | mu_error (_("cannot open filter stream: %s"), mu_strerror (rc)); | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | rc = mu_stream_copy (out, flt, 0, NULL); | ||
146 | |||
147 | if (rc) | ||
148 | { | ||
149 | mu_error ("%s", mu_strerror (rc)); | ||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | if (newline_option) | ||
154 | mu_stream_write (out, "\n", 1, NULL); | ||
155 | |||
156 | mu_stream_flush (out); | ||
157 | |||
158 | return 0; | ||
159 | } |
mu/flt2047.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include "argp.h" | ||
24 | #include "mu.h" | ||
25 | |||
26 | static char flt2047_doc[] = N_("mu 2047 - decode/encode message headers"); | ||
27 | static char flt2047_args_doc[] = N_("[OPTIONS] [text]"); | ||
28 | |||
29 | static struct argp_option flt2047_options[] = { | ||
30 | { "encode", 'e', NULL, 0, N_("encode the input (default)") }, | ||
31 | { "decode", 'd', NULL, 0, N_("decode the input") }, | ||
32 | { "newline", 'n', NULL, 0, N_("print additional newline") }, | ||
33 | { "charset", 'c', NULL, 0, N_("set charset (default: iso-8859-1)") }, | ||
34 | { "encoding", 'E', NULL, 0, N_("set encoding (default: quoted-printable)") }, | ||
35 | { NULL } | ||
36 | }; | ||
37 | |||
38 | static int decode_mode = 0; | ||
39 | static int newline_option = 0; | ||
40 | static const char *charset = "iso-8859-1"; | ||
41 | static const char *encoding = "quoted-printable"; | ||
42 | |||
43 | static error_t | ||
44 | flt2047_parse_opt (int key, char *arg, struct argp_state *state) | ||
45 | { | ||
46 | switch (key) | ||
47 | { | ||
48 | case 'c': | ||
49 | charset = arg; | ||
50 | break; | ||
51 | |||
52 | case 'e': | ||
53 | decode_mode = 0; | ||
54 | break; | ||
55 | |||
56 | case 'E': | ||
57 | encoding = arg; | ||
58 | break; | ||
59 | |||
60 | case 'd': | ||
61 | decode_mode = 1; | ||
62 | break; | ||
63 | |||
64 | case 'n': | ||
65 | newline_option = 0; | ||
66 | break; | ||
67 | |||
68 | default: | ||
69 | return ARGP_ERR_UNKNOWN; | ||
70 | } | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static struct argp flt2047_argp = { | ||
75 | flt2047_options, | ||
76 | flt2047_parse_opt, | ||
77 | flt2047_args_doc, | ||
78 | flt2047_doc, | ||
79 | NULL, | ||
80 | NULL, | ||
81 | NULL | ||
82 | }; | ||
83 | |||
84 | int | ||
85 | mutool_flt2047 (int argc, char **argv) | ||
86 | { | ||
87 | int rc, index; | ||
88 | mu_stream_t in, out; | ||
89 | char *p; | ||
90 | |||
91 | if (argp_parse (&flt2047_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
92 | return 1; | ||
93 | |||
94 | argc -= index; | ||
95 | argv += index; | ||
96 | |||
97 | rc = mu_stdio_stream_create (&in, MU_STDIN_FD, 0); | ||
98 | if (rc) | ||
99 | { | ||
100 | mu_error (_("cannot open input stream: %s"), mu_strerror (rc)); | ||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | rc = mu_stdio_stream_create (&out, MU_STDOUT_FD, 0); | ||
105 | if (rc) | ||
106 | { | ||
107 | mu_error (_("cannot open output stream: %s"), mu_strerror (rc)); | ||
108 | return 1; | ||
109 | } | ||
110 | |||
111 | if (argc) | ||
112 | { | ||
113 | char *p; | ||
114 | |||
115 | while (argc--) | ||
116 | { | ||
117 | const char *text = *argv++; | ||
118 | if (decode_mode) | ||
119 | rc = mu_rfc2047_decode (charset, text, &p); | ||
120 | else | ||
121 | rc = mu_rfc2047_encode (charset, encoding, text, &p); | ||
122 | if (rc) | ||
123 | { | ||
124 | mu_error ("%s", mu_strerror (rc)); | ||
125 | return 1; | ||
126 | } | ||
127 | mu_stream_printf (out, "%s\n", p); | ||
128 | } | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | size_t size = 0, n; | ||
133 | char *buf = NULL; | ||
134 | |||
135 | while ((rc = mu_stream_getline (in, &buf, &size, &n)) == 0 && n > 0) | ||
136 | { | ||
137 | mu_rtrim_class (buf, MU_CTYPE_SPACE); | ||
138 | if (decode_mode) | ||
139 | rc = mu_rfc2047_decode (charset, buf, &p); | ||
140 | else | ||
141 | rc = mu_rfc2047_encode (charset, encoding, buf, &p); | ||
142 | if (rc) | ||
143 | { | ||
144 | mu_error ("%s", mu_strerror (rc)); | ||
145 | return 1; | ||
146 | } | ||
147 | mu_stream_printf (out, "%s\n", p); | ||
148 | } | ||
149 | } | ||
150 | mu_stream_flush (out); | ||
151 | |||
152 | return 0; | ||
153 | } |
mu/info.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include "argp.h" | ||
24 | #include "mu.h" | ||
25 | |||
26 | static char info_doc[] = N_("mu info - print a list of configuration\ | ||
27 | options used to build mailutils; optional arguments are interpreted\ | ||
28 | as a list of configuration options to check for."); | ||
29 | static char info_args_doc[] = N_("[OPTIONS] [capa...]"); | ||
30 | |||
31 | static struct argp_option info_options[] = { | ||
32 | { "verbose", 'v', NULL, 0, | ||
33 | N_("increase output verbosity"), 0}, | ||
34 | { NULL } | ||
35 | }; | ||
36 | |||
37 | static int verbose; | ||
38 | |||
39 | static error_t | ||
40 | info_parse_opt (int key, char *arg, struct argp_state *state) | ||
41 | { | ||
42 | switch (key) | ||
43 | { | ||
44 | case 'v': | ||
45 | verbose++; | ||
46 | break; | ||
47 | |||
48 | default: | ||
49 | return ARGP_ERR_UNKNOWN; | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct argp info_argp = { | ||
55 | info_options, | ||
56 | info_parse_opt, | ||
57 | info_args_doc, | ||
58 | info_doc, | ||
59 | NULL, | ||
60 | NULL, | ||
61 | NULL | ||
62 | }; | ||
63 | |||
64 | int | ||
65 | mutool_info (int argc, char **argv) | ||
66 | { | ||
67 | int index; | ||
68 | |||
69 | if (argp_parse (&info_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
70 | return 1; | ||
71 | |||
72 | argc -= index; | ||
73 | argv += index; | ||
74 | |||
75 | if (argc == 0) | ||
76 | mu_fprint_options (stdout, verbose); | ||
77 | else | ||
78 | { | ||
79 | int i, found = 0; | ||
80 | |||
81 | for (i = 0; i < argc; i++) | ||
82 | { | ||
83 | const struct mu_conf_option *opt = mu_check_option (argv[i]); | ||
84 | if (opt) | ||
85 | { | ||
86 | found++; | ||
87 | mu_fprint_conf_option (stdout, opt, verbose); | ||
88 | } | ||
89 | } | ||
90 | return found == argc ? 0 : 1; | ||
91 | } | ||
92 | return 0; | ||
93 | } |
mu/mu.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include <mailutils/tls.h> | ||
24 | #include "mailutils/libargp.h" | ||
25 | #include "mu.h" | ||
26 | |||
27 | static char args_doc[] = N_("[OPTIONS] COMMAND [CMDOPTS]"); | ||
28 | static char doc[] = N_("mu -- GNU Mailutils test tool.\n\ | ||
29 | Commands are:\n\ | ||
30 | mu info - show Mailutils configuration\n\ | ||
31 | mu query - query configuration values\n\ | ||
32 | mu pop - POP3 client program\n\ | ||
33 | mu filter - filter program\n\ | ||
34 | mu 2047 - decode/encode message headers as per RFC 2047\n\ | ||
35 | \n\ | ||
36 | Try `mu COMMAND --help' to get help on a particular COMMAND\n\ | ||
37 | \n\ | ||
38 | Options are:\n"); | ||
39 | /* FIXME: add | ||
40 | mu imap | ||
41 | mu send [opts] | ||
42 | */ | ||
43 | |||
44 | static struct argp_option options[] = { | ||
45 | { NULL } | ||
46 | }; | ||
47 | |||
48 | static error_t | ||
49 | parse_opt (int key, char *arg, struct argp_state *state) | ||
50 | { | ||
51 | switch (key) | ||
52 | { | ||
53 | default: | ||
54 | return ARGP_ERR_UNKNOWN; | ||
55 | } | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static struct argp argp = { | ||
60 | options, | ||
61 | parse_opt, | ||
62 | args_doc, | ||
63 | doc, | ||
64 | NULL, | ||
65 | NULL, | ||
66 | NULL | ||
67 | }; | ||
68 | |||
69 | static const char *mu_tool_capa[] = { | ||
70 | "common", | ||
71 | "debug", | ||
72 | "license", | ||
73 | "locking", | ||
74 | "mailbox", | ||
75 | "auth", | ||
76 | NULL | ||
77 | }; | ||
78 | |||
79 | struct mu_cfg_param mu_tool_param[] = { | ||
80 | { NULL } | ||
81 | }; | ||
82 | |||
83 | struct mutool_action_tab | ||
84 | { | ||
85 | const char *name; | ||
86 | mutool_action_t action; | ||
87 | }; | ||
88 | |||
89 | struct mutool_action_tab mutool_action_tab[] = { | ||
90 | { "info", mutool_info }, | ||
91 | { "pop", mutool_pop }, | ||
92 | { "filter", mutool_filter }, | ||
93 | { "2047", mutool_flt2047 }, | ||
94 | { "query", mutool_query }, | ||
95 | { NULL } | ||
96 | }; | ||
97 | |||
98 | static mutool_action_t | ||
99 | find_action (const char *name) | ||
100 | { | ||
101 | struct mutool_action_tab *p; | ||
102 | |||
103 | for (p = mutool_action_tab; p->name; p++) | ||
104 | if (strcmp (p->name, name) == 0) | ||
105 | return p->action; | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | int | ||
110 | main (int argc, char **argv) | ||
111 | { | ||
112 | int index; | ||
113 | mutool_action_t action; | ||
114 | |||
115 | /* Native Language Support */ | ||
116 | MU_APP_INIT_NLS (); | ||
117 | MU_AUTH_REGISTER_ALL_MODULES (); | ||
118 | |||
119 | /* Register the desired mailbox formats. */ | ||
120 | mu_register_all_mbox_formats (); | ||
121 | |||
122 | #ifdef WITH_TLS | ||
123 | mu_gocs_register ("tls", mu_tls_module_init); | ||
124 | #endif | ||
125 | mu_argp_init (NULL, NULL); | ||
126 | if (mu_app_init (&argp, mu_tool_capa, mu_tool_param, | ||
127 | argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
128 | exit (1); | ||
129 | |||
130 | argc -= index; | ||
131 | argv += index; | ||
132 | |||
133 | if (argc < 1) | ||
134 | { | ||
135 | mu_error (_("what do you want me to do?")); | ||
136 | exit (1); | ||
137 | } | ||
138 | |||
139 | action = find_action (argv[0]); | ||
140 | if (!action) | ||
141 | { | ||
142 | mu_error (_("don't know what %s is"), argv[0]); | ||
143 | exit (1); | ||
144 | } | ||
145 | |||
146 | exit (action (argc, argv)); | ||
147 | } | ||
148 | |||
149 | |||
150 |
mu/mu.h
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | typedef int (*mutool_action_t) (int argc, char **argv); | ||
18 | |||
19 | struct mutool_command | ||
20 | { | ||
21 | const char *name; /* User printable name of the function. */ | ||
22 | int argmin; /* Min. acceptable number of arguments (-1 means | ||
23 | pass all arguments as a single string */ | ||
24 | int argmax; /* Max. allowed number of arguments (-1 means not | ||
25 | limited */ | ||
26 | mutool_action_t func; /* Function to call to do the job. */ | ||
27 | const char *doc; /* Documentation for this function. */ | ||
28 | }; | ||
29 | |||
30 | |||
31 | int mutool_pop (int argc, char **argv); | ||
32 | int mutool_filter (int argc, char **argv); | ||
33 | int mutool_flt2047 (int argc, char **argv); | ||
34 | int mutool_info (int argc, char **argv); | ||
35 | int mutool_query (int argc, char **argv); | ||
36 | |||
37 | extern char *mutool_shell_prompt; | ||
38 | extern mu_vartab_t mutool_prompt_vartab; | ||
39 | |||
40 | int mutool_shell (const char *name, struct mutool_command *cmd); |
mu/pop.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <termios.h> | ||
23 | #include <unistd.h> | ||
24 | #include <netdb.h> | ||
25 | #include <mailutils/mailutils.h> | ||
26 | #include "mu.h" | ||
27 | #include "argp.h" | ||
28 | #include "xalloc.h" | ||
29 | |||
30 | static char pop_doc[] = N_("mu pop - POP3 client shell"); | ||
31 | static char pop_args_doc[] = ""; | ||
32 | |||
33 | static struct argp_option pop_options[] = { | ||
34 | { NULL } | ||
35 | }; | ||
36 | |||
37 | static error_t | ||
38 | pop_parse_opt (int key, char *arg, struct argp_state *state) | ||
39 | { | ||
40 | switch (key) | ||
41 | { | ||
42 | default: | ||
43 | return ARGP_ERR_UNKNOWN; | ||
44 | } | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static struct argp pop_argp = { | ||
49 | pop_options, | ||
50 | pop_parse_opt, | ||
51 | pop_args_doc, | ||
52 | pop_doc, | ||
53 | NULL, | ||
54 | NULL, | ||
55 | NULL | ||
56 | }; | ||
57 | |||
58 | int | ||
59 | get_bool (const char *str, int *pb) | ||
60 | { | ||
61 | if (mu_c_strcasecmp (str, "yes") == 0 | ||
62 | || mu_c_strcasecmp (str, "on") == 0 | ||
63 | || mu_c_strcasecmp (str, "true") == 0) | ||
64 | *pb = 1; | ||
65 | else if (mu_c_strcasecmp (str, "no") == 0 | ||
66 | || mu_c_strcasecmp (str, "off") == 0 | ||
67 | || mu_c_strcasecmp (str, "false") == 0) | ||
68 | *pb = 0; | ||
69 | else | ||
70 | return 1; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | int | ||
76 | get_port (const char *port_str, int *pn) | ||
77 | { | ||
78 | short port_num; | ||
79 | long num; | ||
80 | char *p; | ||
81 | |||
82 | num = port_num = strtol (port_str, &p, 0); | ||
83 | if (*p == 0) | ||
84 | { | ||
85 | if (num != port_num) | ||
86 | { | ||
87 | mu_error ("bad port number: %s", port_str); | ||
88 | return 1; | ||
89 | } | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | struct servent *sp = getservbyname (port_str, "tcp"); | ||
94 | if (!sp) | ||
95 | { | ||
96 | mu_error ("unknown port name"); | ||
97 | return 1; | ||
98 | } | ||
99 | port_num = ntohs (sp->s_port); | ||
100 | } | ||
101 | *pn = port_num; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | |||
106 | /* Global handle for pop3. */ | ||
107 | mu_pop3_t pop3; | ||
108 | |||
109 | /* Flag if verbosity is needed. */ | ||
110 | int verbose; | ||
111 | #define VERBOSE_MASK(n) (1<<((n)+1)) | ||
112 | #define SET_VERBOSE_MASK(n) (verbose |= VERBOSE_MASK (n)) | ||
113 | #define CLR_VERBOSE_MASK(n) (verbose &= VERBOSE_MASK (n)) | ||
114 | #define QRY_VERBOSE_MASK(n) (verbose & VERBOSE_MASK (n)) | ||
115 | #define HAS_VERBOSE_MASK(n) (verbose & ~1) | ||
116 | #define SET_VERBOSE() (verbose |= 1) | ||
117 | #define CLR_VERBOSE() (verbose &= ~1) | ||
118 | #define QRY_VERBOSE() (verbose & 1) | ||
119 | |||
120 | enum pop_session_status | ||
121 | { | ||
122 | pop_session_disconnected, | ||
123 | pop_session_connected, | ||
124 | pop_session_logged_in | ||
125 | }; | ||
126 | |||
127 | enum pop_session_status pop_session_status; | ||
128 | |||
129 | int connect_argc; | ||
130 | char **connect_argv; | ||
131 | |||
132 | /* Host we are connected to. */ | ||
133 | #define host connect_argv[0] | ||
134 | int port = 110; | ||
135 | char *username; | ||
136 | |||
137 | const char * | ||
138 | pop_session_str (enum pop_session_status stat) | ||
139 | { | ||
140 | switch (stat) | ||
141 | { | ||
142 | case pop_session_disconnected: | ||
143 | return "disconnected"; | ||
144 | |||
145 | case pop_session_connected: | ||
146 | return "connected"; | ||
147 | |||
148 | case pop_session_logged_in: | ||
149 | return "logged in"; | ||
150 | } | ||
151 | return "unknown"; | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | pop_prompt_vartab () | ||
156 | { | ||
157 | mu_vartab_t vtab; | ||
158 | |||
159 | if (mu_vartab_create (&vtab)) | ||
160 | return; | ||
161 | mu_vartab_define (vtab, "user", | ||
162 | (pop_session_status == pop_session_logged_in) ? | ||
163 | username : "not logged in", 1); | ||
164 | mu_vartab_define (vtab, "host", | ||
165 | (pop_session_status != pop_session_disconnected) ? | ||
166 | host : "not connected", 1); | ||
167 | mu_vartab_define (vtab, "program-name", mu_program_name, 1); | ||
168 | mu_vartab_define (vtab, "canonical-program-name", "mu", 1); | ||
169 | mu_vartab_define (vtab, "package", PACKAGE, 1); | ||
170 | mu_vartab_define (vtab, "version", PACKAGE_VERSION, 1); | ||
171 | mu_vartab_define (vtab, "status", pop_session_str (pop_session_status), 1); | ||
172 | |||
173 | mu_vartab_destroy (&mutool_prompt_vartab); | ||
174 | mutool_prompt_vartab = vtab; | ||
175 | } | ||
176 | |||
177 | |||
178 | static int | ||
179 | string_to_xlev (const char *name, int *pv) | ||
180 | { | ||
181 | if (strcmp (name, "secure") == 0) | ||
182 | *pv = MU_XSCRIPT_SECURE; | ||
183 | else if (strcmp (name, "payload") == 0) | ||
184 | *pv = MU_XSCRIPT_PAYLOAD; | ||
185 | else | ||
186 | return 1; | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int | ||
191 | change_verbose_mask (int set, int argc, char **argv) | ||
192 | { | ||
193 | int i; | ||
194 | |||
195 | for (i = 0; i < argc; i++) | ||
196 | { | ||
197 | int lev; | ||
198 | |||
199 | if (string_to_xlev (argv[i], &lev)) | ||
200 | { | ||
201 | mu_error ("unknown level: %s", argv[i]); | ||
202 | return 1; | ||
203 | } | ||
204 | if (set) | ||
205 | SET_VERBOSE_MASK (lev); | ||
206 | else | ||
207 | CLR_VERBOSE_MASK (lev); | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | void | ||
213 | set_verbose (mu_pop3_t p) | ||
214 | { | ||
215 | if (p) | ||
216 | { | ||
217 | if (QRY_VERBOSE ()) | ||
218 | { | ||
219 | mu_pop3_trace (p, MU_POP3_TRACE_SET); | ||
220 | } | ||
221 | else | ||
222 | mu_pop3_trace (p, MU_POP3_TRACE_CLR); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | void | ||
227 | set_verbose_mask (mu_pop3_t p) | ||
228 | { | ||
229 | if (p) | ||
230 | { | ||
231 | mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE) | ||
232 | ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR, | ||
233 | MU_XSCRIPT_SECURE); | ||
234 | mu_pop3_trace_mask (p, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD) | ||
235 | ? MU_POP3_TRACE_SET : MU_POP3_TRACE_CLR, | ||
236 | MU_XSCRIPT_PAYLOAD); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static int | ||
241 | com_verbose (int argc, char **argv) | ||
242 | { | ||
243 | if (argc == 1) | ||
244 | { | ||
245 | if (QRY_VERBOSE ()) | ||
246 | { | ||
247 | printf ("verbose is on"); | ||
248 | if (HAS_VERBOSE_MASK ()) | ||
249 | { | ||
250 | char *delim = " ("; | ||
251 | |||
252 | if (QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)) | ||
253 | { | ||
254 | printf("%ssecure", delim); | ||
255 | delim = ", "; | ||
256 | } | ||
257 | if (QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)) | ||
258 | printf("%spayload", delim); | ||
259 | printf (")"); | ||
260 | } | ||
261 | printf ("\n"); | ||
262 | } | ||
263 | else | ||
264 | printf ("verbose is off\n"); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | int bv; | ||
269 | |||
270 | if (get_bool (argv[1], &bv) == 0) | ||
271 | { | ||
272 | verbose |= bv; | ||
273 | if (argc > 2) | ||
274 | change_verbose_mask (verbose, argc - 2, argv + 2); | ||
275 | set_verbose (pop3); | ||
276 | } | ||
277 | else if (strcmp (argv[1], "mask") == 0) | ||
278 | change_verbose_mask (1, argc - 2, argv + 2); | ||
279 | else if (strcmp (argv[1], "unmask") == 0) | ||
280 | change_verbose_mask (0, argc - 2, argv + 2); | ||
281 | else | ||
282 | mu_error ("unknown subcommand"); | ||
283 | set_verbose_mask (pop3); | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int | ||
290 | com_user (int argc, char **argv) | ||
291 | { | ||
292 | int status; | ||
293 | |||
294 | status = mu_pop3_user (pop3, argv[1]); | ||
295 | if (status == 0) | ||
296 | { | ||
297 | username = strdup (argv[1]); | ||
298 | pop_prompt_vartab (); | ||
299 | } | ||
300 | return status; | ||
301 | } | ||
302 | |||
303 | static int | ||
304 | com_apop (int argc, char **argv) | ||
305 | { | ||
306 | int status; | ||
307 | |||
308 | status = mu_pop3_apop (pop3, argv[1], argv[2]); | ||
309 | if (status == 0) | ||
310 | { | ||
311 | username = strdup (argv[1]); | ||
312 | pop_session_status = pop_session_logged_in; | ||
313 | } | ||
314 | return status; | ||
315 | } | ||
316 | |||
317 | static int | ||
318 | com_capa (int argc, char **argv) | ||
319 | { | ||
320 | mu_iterator_t iterator = NULL; | ||
321 | int status = 0; | ||
322 | int reread = 0; | ||
323 | int i = 1; | ||
324 | |||
325 | for (i = 1; i < argc; i++) | ||
326 | { | ||
327 | if (strcmp (argv[i], "-reread") == 0) | ||
328 | reread = 1; | ||
329 | else | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | if (i < argc) | ||
334 | { | ||
335 | if (reread) | ||
336 | { | ||
337 | status = mu_pop3_capa (pop3, 1, NULL); | ||
338 | if (status) | ||
339 | return status; | ||
340 | } | ||
341 | for (; i < argc; i++) | ||
342 | { | ||
343 | const char *elt; | ||
344 | int rc = mu_pop3_capa_test (pop3, argv[i], &elt); | ||
345 | switch (rc) | ||
346 | { | ||
347 | case 0: | ||
348 | if (*elt) | ||
349 | printf ("%s: %s\n", argv[i], elt); | ||
350 | else | ||
351 | printf ("%s is set\n", argv[i]); | ||
352 | break; | ||
353 | |||
354 | case MU_ERR_NOENT: | ||
355 | printf ("%s is not set\n", argv[i]); | ||
356 | break; | ||
357 | |||
358 | default: | ||
359 | return rc; | ||
360 | } | ||
361 | } | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | status = mu_pop3_capa (pop3, reread, &iterator); | ||
366 | |||
367 | if (status == 0) | ||
368 | { | ||
369 | for (mu_iterator_first (iterator); | ||
370 | !mu_iterator_is_done (iterator); mu_iterator_next (iterator)) | ||
371 | { | ||
372 | char *capa = NULL; | ||
373 | mu_iterator_current (iterator, (void **) &capa); | ||
374 | printf ("CAPA: %s\n", capa ? capa : ""); | ||
375 | } | ||
376 | mu_iterator_destroy (&iterator); | ||
377 | } | ||
378 | } | ||
379 | return status; | ||
380 | } | ||
381 | |||
382 | static int | ||
383 | com_uidl (int argc, char **argv) | ||
384 | { | ||
385 | int status = 0; | ||
386 | if (argc == 1) | ||
387 | { | ||
388 | mu_iterator_t uidl_iterator = NULL; | ||
389 | status = mu_pop3_uidl_all (pop3, &uidl_iterator); | ||
390 | if (status == 0) | ||
391 | { | ||
392 | for (mu_iterator_first (uidl_iterator); | ||
393 | !mu_iterator_is_done (uidl_iterator); | ||
394 | mu_iterator_next (uidl_iterator)) | ||
395 | { | ||
396 | char *uidl = NULL; | ||
397 | mu_iterator_current (uidl_iterator, (void **) &uidl); | ||
398 | printf ("UIDL: %s\n", uidl ? uidl : ""); | ||
399 | } | ||
400 | mu_iterator_destroy (&uidl_iterator); | ||
401 | } | ||
402 | } | ||
403 | else | ||
404 | { | ||
405 | char *uidl = NULL; | ||
406 | unsigned int msgno = strtoul (argv[1], NULL, 10); | ||
407 | status = mu_pop3_uidl (pop3, msgno, &uidl); | ||
408 | if (status == 0) | ||
409 | printf ("Msg: %d UIDL: %s\n", msgno, uidl ? uidl : ""); | ||
410 | free (uidl); | ||
411 | } | ||
412 | return status; | ||
413 | } | ||
414 | |||
415 | static int | ||
416 | com_list (int argc, char **argv) | ||
417 | { | ||
418 | int status = 0; | ||
419 | if (argc == 1) | ||
420 | { | ||
421 | mu_iterator_t list_iterator; | ||
422 | status = mu_pop3_list_all (pop3, &list_iterator); | ||
423 | if (status == 0) | ||
424 | { | ||
425 | for (mu_iterator_first (list_iterator); | ||
426 | !mu_iterator_is_done (list_iterator); | ||
427 | mu_iterator_next (list_iterator)) | ||
428 | { | ||
429 | char *list = NULL; | ||
430 | mu_iterator_current (list_iterator, (void **) &list); | ||
431 | printf ("LIST: %s\n", (list) ? list : ""); | ||
432 | } | ||
433 | mu_iterator_destroy (&list_iterator); | ||
434 | } | ||
435 | } | ||
436 | else | ||
437 | { | ||
438 | size_t size = 0; | ||
439 | unsigned int msgno = strtoul (argv[1], NULL, 10); | ||
440 | status = mu_pop3_list (pop3, msgno, &size); | ||
441 | if (status == 0) | ||
442 | printf ("Msg: %u Size: %lu\n", msgno, (unsigned long) size); | ||
443 | } | ||
444 | return status; | ||
445 | } | ||
446 | |||
447 | static int | ||
448 | com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
449 | { | ||
450 | return mu_pop3_noop (pop3); | ||
451 | } | ||
452 | |||
453 | static void | ||
454 | echo_off (struct termios *stored_settings) | ||
455 | { | ||
456 | struct termios new_settings; | ||
457 | tcgetattr (0, stored_settings); | ||
458 | new_settings = *stored_settings; | ||
459 | new_settings.c_lflag &= (~ECHO); | ||
460 | tcsetattr (0, TCSANOW, &new_settings); | ||
461 | } | ||
462 | |||
463 | static void | ||
464 | echo_on (struct termios *stored_settings) | ||
465 | { | ||
466 | tcsetattr (0, TCSANOW, stored_settings); | ||
467 | } | ||
468 | |||
469 | static int | ||
470 | com_pass (int argc, char **argv) | ||
471 | { | ||
472 | int status; | ||
473 | char pass[256]; | ||
474 | char *pwd; | ||
475 | |||
476 | if (argc == 1) | ||
477 | { | ||
478 | struct termios stored_settings; | ||
479 | |||
480 | printf ("passwd:"); | ||
481 | fflush (stdout); | ||
482 | echo_off (&stored_settings); | ||
483 | fgets (pass, sizeof pass, stdin); | ||
484 | echo_on (&stored_settings); | ||
485 | putchar ('\n'); | ||
486 | fflush (stdout); | ||
487 | pass[strlen (pass) - 1] = '\0'; /* nuke the trailing line. */ | ||
488 | pwd = pass; | ||
489 | } | ||
490 | else | ||
491 | pwd = argv[1]; | ||
492 | status = mu_pop3_pass (pop3, pwd); | ||
493 | if (status == 0) | ||
494 | { | ||
495 | pop_session_status = pop_session_logged_in; | ||
496 | pop_prompt_vartab (); | ||
497 | } | ||
498 | return status; | ||
499 | } | ||
500 | |||
501 | static int | ||
502 | com_stat (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
503 | { | ||
504 | size_t count = 0; | ||
505 | mu_off_t size = 0; | ||
506 | int status = 0; | ||
507 | |||
508 | status = mu_pop3_stat (pop3, &count, &size); | ||
509 | printf ("Mesgs: %lu Size %lu\n", | ||
510 | (unsigned long) count, (unsigned long) size); | ||
511 | return status; | ||
512 | } | ||
513 | |||
514 | static int | ||
515 | com_stls (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
516 | { | ||
517 | return mu_pop3_stls (pop3); | ||
518 | } | ||
519 | |||
520 | static int | ||
521 | com_dele (int argc, char **argv) | ||
522 | { | ||
523 | unsigned msgno; | ||
524 | msgno = strtoul (argv[1], NULL, 10); | ||
525 | return mu_pop3_dele (pop3, msgno); | ||
526 | } | ||
527 | |||
528 | static int | ||
529 | com_rset (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
530 | { | ||
531 | return mu_pop3_rset (pop3); | ||
532 | } | ||
533 | |||
534 | static int | ||
535 | com_top (int argc, char **argv) | ||
536 | { | ||
537 | mu_stream_t stream; | ||
538 | unsigned int msgno; | ||
539 | unsigned int lines; | ||
540 | int status; | ||
541 | |||
542 | msgno = strtoul (argv[1], NULL, 10); | ||
543 | if (argc == 3) | ||
544 | lines = strtoul (argv[2], NULL, 10); | ||
545 | else | ||
546 | lines = 5; | ||
547 | |||
548 | status = mu_pop3_top (pop3, msgno, lines, &stream); | ||
549 | |||
550 | if (status == 0) | ||
551 | { | ||
552 | size_t n = 0; | ||
553 | char buf[128]; | ||
554 | while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n) | ||
555 | printf ("%s", buf); | ||
556 | mu_stream_destroy (&stream); | ||
557 | } | ||
558 | return status; | ||
559 | } | ||
560 | |||
561 | static int | ||
562 | com_retr (int argc, char **argv) | ||
563 | { | ||
564 | mu_stream_t stream; | ||
565 | unsigned int msgno; | ||
566 | int status; | ||
567 | |||
568 | msgno = strtoul (argv[1], NULL, 10); | ||
569 | status = mu_pop3_retr (pop3, msgno, &stream); | ||
570 | |||
571 | if (status == 0) | ||
572 | { | ||
573 | size_t n = 0; | ||
574 | char buf[128]; | ||
575 | while ((mu_stream_readline (stream, buf, sizeof buf, &n) == 0) && n) | ||
576 | printf ("%s", buf); | ||
577 | mu_stream_destroy (&stream); | ||
578 | } | ||
579 | return status; | ||
580 | } | ||
581 | |||
582 | static int | ||
583 | com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
584 | { | ||
585 | if (pop3) | ||
586 | { | ||
587 | mu_pop3_disconnect (pop3); | ||
588 | mu_pop3_destroy (&pop3); | ||
589 | pop3 = NULL; | ||
590 | |||
591 | mu_argcv_free (connect_argc, connect_argv); | ||
592 | connect_argc = 0; | ||
593 | connect_argv = NULL; | ||
594 | pop_session_status = pop_session_disconnected; | ||
595 | pop_prompt_vartab (); | ||
596 | } | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int | ||
601 | com_connect (int argc, char **argv) | ||
602 | { | ||
603 | int status; | ||
604 | int n = 0; | ||
605 | int tls = 0; | ||
606 | int i = 1; | ||
607 | |||
608 | for (i = 1; i < argc; i++) | ||
609 | { | ||
610 | if (strcmp (argv[i], "-tls") == 0) | ||
611 | { | ||
612 | if (WITH_TLS) | ||
613 | tls = 1; | ||
614 | else | ||
615 | { | ||
616 | mu_error ("TLS not supported"); | ||
617 | return 0; | ||
618 | } | ||
619 | } | ||
620 | else | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | argc -= i; | ||
625 | argv += i; | ||
626 | |||
627 | if (argc >= 2) | ||
628 | { | ||
629 | if (get_port (argv[1], &n)) | ||
630 | return 0; | ||
631 | } | ||
632 | else if (tls) | ||
633 | n = MU_POP3_DEFAULT_SSL_PORT; | ||
634 | else | ||
635 | n = MU_POP3_DEFAULT_PORT; | ||
636 | |||
637 | if (pop_session_status != pop_session_disconnected) | ||
638 | com_disconnect (0, NULL); | ||
639 | |||
640 | status = mu_pop3_create (&pop3); | ||
641 | if (status == 0) | ||
642 | { | ||
643 | mu_stream_t tcp; | ||
644 | |||
645 | if (QRY_VERBOSE ()) | ||
646 | { | ||
647 | set_verbose (pop3); | ||
648 | set_verbose_mask (pop3); | ||
649 | } | ||
650 | status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ); | ||
651 | if (status == 0) | ||
652 | { | ||
653 | #ifdef WITH_TLS | ||
654 | if (tls) | ||
655 | { | ||
656 | mu_stream_t tlsstream; | ||
657 | |||
658 | status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0); | ||
659 | mu_stream_unref (tcp); | ||
660 | if (status) | ||
661 | { | ||
662 | mu_error ("cannot create TLS stream: %s", | ||
663 | mu_strerror (status)); | ||
664 | return 0; | ||
665 | } | ||
666 | tcp = tlsstream; | ||
667 | } | ||
668 | #endif | ||
669 | mu_pop3_set_carrier (pop3, tcp); | ||
670 | status = mu_pop3_connect (pop3); | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | mu_pop3_destroy (&pop3); | ||
675 | pop3 = NULL; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | if (status) | ||
680 | mu_error ("Failed to create pop3: %s", mu_strerror (status)); | ||
681 | else | ||
682 | { | ||
683 | connect_argc = argc; | ||
684 | connect_argv = xcalloc (argc, sizeof (*connect_argv)); | ||
685 | for (i = 0; i < argc; i++) | ||
686 | connect_argv[i] = xstrdup (argv[i]); | ||
687 | connect_argv[i] = NULL; | ||
688 | port = n; | ||
689 | pop_session_status = pop_session_connected; | ||
690 | |||
691 | pop_prompt_vartab (); | ||
692 | } | ||
693 | |||
694 | return status; | ||
695 | } | ||
696 | |||
697 | static int | ||
698 | com_quit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
699 | { | ||
700 | int status = 0; | ||
701 | if (pop3) | ||
702 | { | ||
703 | if (mu_pop3_quit (pop3) == 0) | ||
704 | { | ||
705 | status = com_disconnect (0, NULL); | ||
706 | } | ||
707 | else | ||
708 | { | ||
709 | printf ("Try 'exit' to leave %s\n", mu_program_name); | ||
710 | } | ||
711 | } | ||
712 | else | ||
713 | printf ("Try 'exit' to leave %s\n", mu_program_name); | ||
714 | return status; | ||
715 | } | ||
716 | |||
717 | struct mutool_command pop_comtab[] = { | ||
718 | { "apop", 3, 3, com_apop, | ||
719 | "Authenticate with APOP: APOP user secret" }, | ||
720 | { "capa", 1, -1, com_capa, | ||
721 | "List capabilities: capa [-reread] [names...]" }, | ||
722 | { "disconnect", 1, 1, | ||
723 | com_disconnect, "Close connection: disconnect" }, | ||
724 | { "dele", 2, 2, com_dele, | ||
725 | "Mark message: DELE msgno" }, | ||
726 | { "list", 1, 2, com_list, | ||
727 | "List messages: LIST [msgno]" }, | ||
728 | { "noop", 1, 1, com_noop, | ||
729 | "Send no operation: NOOP" }, | ||
730 | { "pass", 1, 2, com_pass, | ||
731 | "Send passwd: PASS [passwd]" }, | ||
732 | { "connect", 1, 4, com_connect, | ||
733 | "Open connection: connect [-tls] hostname port" }, | ||
734 | { "quit", 1, 1, com_quit, | ||
735 | "Go to Update state : QUIT" }, | ||
736 | { "retr", 2, 2, com_retr, | ||
737 | "Dowload message: RETR msgno" }, | ||
738 | { "rset", 1, 1, com_rset, | ||
739 | "Unmark all messages: RSET" }, | ||
740 | { "stat", 1, 1, com_stat, | ||
741 | "Get the size and count of mailbox : STAT" }, | ||
742 | { "stls", 1, 1, com_stls, | ||
743 | "Start TLS negotiation" }, | ||
744 | { "top", 2, 3, com_top, | ||
745 | "Get the header of message: TOP msgno [lines]" }, | ||
746 | { "uidl", 1, 2, com_uidl, | ||
747 | "Get the unique id of message: UIDL [msgno]" }, | ||
748 | { "user", 2, 2, com_user, | ||
749 | "send login: USER user" }, | ||
750 | { "verbose", 1, 4, com_verbose, | ||
751 | "Enable Protocol tracing: verbose [on|off|mask|unmask] [x1 [x2]]" }, | ||
752 | { NULL } | ||
753 | }; | ||
754 | |||
755 | |||
756 | int | ||
757 | mutool_pop (int argc, char **argv) | ||
758 | { | ||
759 | int index; | ||
760 | |||
761 | if (argp_parse (&pop_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
762 | return 1; | ||
763 | |||
764 | argc -= index; | ||
765 | argv += index; | ||
766 | |||
767 | if (argc) | ||
768 | { | ||
769 | mu_error (_("too many arguments")); | ||
770 | return 1; | ||
771 | } | ||
772 | |||
773 | /* Command line prompt */ | ||
774 | mutool_shell_prompt = xstrdup ("pop> "); | ||
775 | pop_prompt_vartab (); | ||
776 | mutool_shell ("pop", pop_comtab); | ||
777 | return 0; | ||
778 | } |
mu/query.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include <mailutils/libcfg.h> | ||
24 | #include "argp.h" | ||
25 | #include "mu.h" | ||
26 | |||
27 | static char query_doc[] = N_("mu query - query configuration values."); | ||
28 | static char query_args_doc[] = N_("[OPTIONS]"); | ||
29 | |||
30 | char *file_name; | ||
31 | int verbose_option; | ||
32 | |||
33 | static struct argp_option query_options[] = { | ||
34 | { "file", 'f', N_("FILE"), 0, | ||
35 | N_("query configuration values from FILE (default mailutils.rc)"), | ||
36 | 0 }, | ||
37 | { "verbose", 'v', NULL, 0, | ||
38 | N_("increase output verbosity"), 0}, | ||
39 | { NULL } | ||
40 | }; | ||
41 | |||
42 | static error_t | ||
43 | query_parse_opt (int key, char *arg, struct argp_state *state) | ||
44 | { | ||
45 | switch (key) | ||
46 | { | ||
47 | case 'f': | ||
48 | file_name = arg; | ||
49 | break; | ||
50 | |||
51 | case 'v': | ||
52 | verbose_option++; | ||
53 | break; | ||
54 | |||
55 | default: | ||
56 | return ARGP_ERR_UNKNOWN; | ||
57 | } | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static struct argp query_argp = { | ||
62 | query_options, | ||
63 | query_parse_opt, | ||
64 | query_args_doc, | ||
65 | query_doc, | ||
66 | NULL, | ||
67 | NULL, | ||
68 | NULL | ||
69 | }; | ||
70 | |||
71 | int | ||
72 | mutool_query (int argc, char **argv) | ||
73 | { | ||
74 | int rc, index; | ||
75 | mu_cfg_tree_t *tree = NULL; | ||
76 | int fmtflags = 0; | ||
77 | mu_stream_t stream; | ||
78 | |||
79 | if (argp_parse (&query_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) | ||
80 | return 1; | ||
81 | |||
82 | argc -= index; | ||
83 | argv += index; | ||
84 | |||
85 | if (argc == 0) | ||
86 | { | ||
87 | mu_error (_("query what?")); | ||
88 | return 1; | ||
89 | } | ||
90 | |||
91 | if (file_name) | ||
92 | { | ||
93 | mu_load_site_rcfile = 0; | ||
94 | mu_load_user_rcfile = 0; | ||
95 | mu_load_rcfile = file_name; | ||
96 | } | ||
97 | |||
98 | if (mu_libcfg_parse_config (&tree)) | ||
99 | return 1; | ||
100 | if (!tree) | ||
101 | return 0; | ||
102 | rc = mu_stdio_stream_create (&stream, MU_STDOUT_FD, 0); | ||
103 | if (rc) | ||
104 | { | ||
105 | mu_error ("mu_stdio_stream_create: %s", mu_strerror (rc)); | ||
106 | return 1; | ||
107 | } | ||
108 | if (verbose_option) | ||
109 | fmtflags = MU_CFG_FMT_LOCUS; | ||
110 | for ( ; argc > 0; argc--, argv++) | ||
111 | { | ||
112 | char *path = *argv; | ||
113 | mu_cfg_node_t *node; | ||
114 | |||
115 | if (mu_cfg_find_node (tree, path, &node) == 0) | ||
116 | mu_cfg_format_node (stream, node, fmtflags); | ||
117 | } | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 |
mu/shell.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #if defined(HAVE_CONFIG_H) | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <stdlib.h> | ||
21 | #include <string.h> | ||
22 | #include <mailutils/mailutils.h> | ||
23 | #include <mailutils/tls.h> | ||
24 | #include "mailutils/libargp.h" | ||
25 | #include "mu.h" | ||
26 | #include "xalloc.h" | ||
27 | |||
28 | #ifdef WITH_READLINE | ||
29 | # include <readline/readline.h> | ||
30 | # include <readline/history.h> | ||
31 | #endif | ||
32 | |||
33 | char *mutool_shell_prompt; | ||
34 | mu_vartab_t mutool_prompt_vartab; | ||
35 | |||
36 | static char * | ||
37 | expand_prompt () | ||
38 | { | ||
39 | char *str; | ||
40 | |||
41 | if (!mutool_prompt_vartab | ||
42 | || mu_vartab_expand (mutool_prompt_vartab, mutool_shell_prompt, &str)) | ||
43 | str = strdup (mutool_shell_prompt); | ||
44 | return str; | ||
45 | } | ||
46 | |||
47 | |||
48 | static int shell_exit (int, char **); | ||
49 | static int shell_help (int, char **); | ||
50 | static int shell_prompt (int, char **); | ||
51 | #ifdef WITH_READLINE | ||
52 | static int shell_history (int, char **); | ||
53 | #endif | ||
54 | |||
55 | struct mutool_command default_comtab[] = { | ||
56 | { "prompt", -1, -1, shell_prompt, "set command prompt" }, | ||
57 | { "exit", 1, 1, shell_exit, "exit program" }, | ||
58 | { "help", 1, 2, shell_help, "display this text" }, | ||
59 | { "?", 1, 1, shell_help, "synonym for `help'" }, | ||
60 | #ifdef WITH_READLINE | ||
61 | { "history", 1, 1, shell_history, "show command history" }, | ||
62 | #endif | ||
63 | { NULL } | ||
64 | }; | ||
65 | |||
66 | /* Print a single comtab entry */ | ||
67 | static void | ||
68 | print_comtab (struct mutool_command *tab) | ||
69 | { | ||
70 | printf ("%s\t\t%s\n", tab->name, tab->doc); | ||
71 | } | ||
72 | |||
73 | /* Print a single comtab entry. | ||
74 | FIXME: Way too primitive. Rewrite. */ | ||
75 | int | ||
76 | print_help (struct mutool_command *tab, size_t n) | ||
77 | { | ||
78 | if (n) | ||
79 | { | ||
80 | for (; n > 0 && tab->name; tab++, n--) | ||
81 | print_comtab (tab); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | for (; tab->name; tab++) | ||
86 | print_comtab (tab); | ||
87 | } | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* Print all commands from TAB matching NAME. | ||
92 | FIXME: Way too primitive. Rewrite. */ | ||
93 | void | ||
94 | list_commands (struct mutool_command *tab, const char *name) | ||
95 | { | ||
96 | size_t namelen = strlen (name); | ||
97 | int printed = 0; | ||
98 | |||
99 | for (; tab->name; tab++) | ||
100 | { | ||
101 | /* Print in six columns. */ | ||
102 | if (printed == 6) | ||
103 | { | ||
104 | printed = 0; | ||
105 | printf ("\n"); | ||
106 | } | ||
107 | if (mu_c_strncasecmp (tab->name, name, namelen) == 0) | ||
108 | { | ||
109 | printf ("%s\t", tab->name); | ||
110 | printed++; | ||
111 | } | ||
112 | } | ||
113 | if (printed && printed < 6) | ||
114 | printf ("\n"); | ||
115 | } | ||
116 | |||
117 | static struct mutool_command * | ||
118 | simple_find_command (struct mutool_command *cp, const char *name) | ||
119 | { | ||
120 | for (; cp->name; cp++) | ||
121 | if (strcmp (cp->name, name) == 0) | ||
122 | return cp; | ||
123 | return NULL; | ||
124 | } | ||
125 | |||
126 | |||
127 | static struct mutool_command *shell_comtab; | ||
128 | static size_t user_command_count; | ||
129 | |||
130 | static struct mutool_command * | ||
131 | find_command (const char *name) | ||
132 | { | ||
133 | return simple_find_command (shell_comtab, name); | ||
134 | } | ||
135 | |||
136 | /* Print out help for ARG, or for all of the commands if ARG is | ||
137 | not present. */ | ||
138 | int | ||
139 | shell_help (int argc, char **argv) | ||
140 | { | ||
141 | char *name = argv[1]; | ||
142 | if (name) | ||
143 | { | ||
144 | struct mutool_command *com = find_command (argv[1]); | ||
145 | |||
146 | if (com) | ||
147 | print_comtab (com); | ||
148 | else | ||
149 | { | ||
150 | printf ("No commands match `%s'. Possibilties are:\n", name); | ||
151 | list_commands (shell_comtab, name); | ||
152 | } | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | print_help (shell_comtab, user_command_count); | ||
157 | printf ("\n"); | ||
158 | print_help (shell_comtab + user_command_count, 0); | ||
159 | } | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int | ||
164 | shell_prompt (int argc, char **argv) | ||
165 | { | ||
166 | int quote; | ||
167 | size_t size; | ||
168 | |||
169 | free (mutool_shell_prompt); | ||
170 | size = mu_argcv_quoted_length (argv[1], "e); | ||
171 | mutool_shell_prompt = xmalloc (size + 1); | ||
172 | mu_argcv_unquote_copy (mutool_shell_prompt, argv[1], size); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | |||
178 | #ifdef WITH_READLINE | ||
179 | #define HISTFILE_PREFIX "~/.mu_" | ||
180 | #define HISTFILE_SUFFIX "_history" | ||
181 | |||
182 | static char * | ||
183 | get_history_file_name () | ||
184 | { | ||
185 | static char *filename = NULL; | ||
186 | |||
187 | if (!filename) | ||
188 | { | ||
189 | char *hname; | ||
190 | |||
191 | hname = xmalloc(sizeof HISTFILE_PREFIX + strlen (rl_readline_name) + | ||
192 | sizeof HISTFILE_SUFFIX - 1); | ||
193 | strcpy (hname, "~/.mu_"); | ||
194 | strcat (hname, rl_readline_name); | ||
195 | strcat (hname, HISTFILE_SUFFIX); | ||
196 | filename = mu_tilde_expansion (hname, "/", NULL); | ||
197 | free(hname); | ||
198 | } | ||
199 | return filename; | ||
200 | } | ||
201 | |||
202 | /* Interface to Readline Completion */ | ||
203 | |||
204 | static char *shell_command_generator (const char *, int); | ||
205 | static char **shell_completion (char *, int, int); | ||
206 | |||
207 | /* Tell the GNU Readline library how to complete. We want to try to complete | ||
208 | on command names if this is the first word in the line, or on filenames | ||
209 | if not. */ | ||
210 | void | ||
211 | mutool_initialize_readline (const char *name) | ||
212 | { | ||
213 | /* Allow conditional parsing of the ~/.inputrc file. */ | ||
214 | rl_readline_name = (char *) name; | ||
215 | rl_attempted_completion_function = (CPPFunction *) shell_completion; | ||
216 | read_history (get_history_file_name ()); | ||
217 | } | ||
218 | |||
219 | static void | ||
220 | finish_readline () | ||
221 | { | ||
222 | write_history (get_history_file_name()); | ||
223 | } | ||
224 | |||
225 | /* Attempt to complete on the contents of TEXT. START and END bound the | ||
226 | region of rl_line_buffer that contains the word to complete. TEXT is | ||
227 | the word to complete. We can use the entire contents of rl_line_buffer | ||
228 | in case we want to do some simple parsing. Return the array of matches, | ||
229 | or NULL if there aren't any. */ | ||
230 | static char ** | ||
231 | shell_completion (char *text, int start, int end MU_ARG_UNUSED) | ||
232 | { | ||
233 | char **matches; | ||
234 | |||
235 | matches = (char **) NULL; | ||
236 | |||
237 | /* If this word is at the start of the line, then it is a command | ||
238 | to complete. Otherwise it is the name of a file in the current | ||
239 | directory. */ | ||
240 | if (start == 0) | ||
241 | matches = rl_completion_matches (text, shell_command_generator); | ||
242 | |||
243 | return (matches); | ||
244 | } | ||
245 | |||
246 | /* Generator function for command completion. STATE lets us know whether | ||
247 | to start from scratch; without any state (i.e. STATE == 0), then we | ||
248 | start at the top of the list. */ | ||
249 | static char * | ||
250 | shell_command_generator (const char *text, int state) | ||
251 | { | ||
252 | const char *name; | ||
253 | static int len; | ||
254 | static struct mutool_command *cmd; | ||
255 | |||
256 | /* If this is a new word to complete, initialize now. This includes | ||
257 | saving the length of TEXT for efficiency, and initializing the index | ||
258 | variable to 0. */ | ||
259 | if (!state) | ||
260 | { | ||
261 | cmd = shell_comtab; | ||
262 | len = strlen (text); | ||
263 | } | ||
264 | |||
265 | if (!cmd->name) | ||
266 | return NULL; | ||
267 | |||
268 | |||
269 | /* Return the next name which partially matches from the command list. */ | ||
270 | while ((name = cmd->name)) | ||
271 | { | ||
272 | cmd++; | ||
273 | if (strncmp (name, text, len) == 0) | ||
274 | return xstrdup (name); | ||
275 | } | ||
276 | |||
277 | /* If no names matched, then return NULL. */ | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | static char *pre_input_line; | ||
282 | |||
283 | static int | ||
284 | pre_input (void) | ||
285 | { | ||
286 | rl_insert_text (pre_input_line); | ||
287 | free (pre_input_line); | ||
288 | rl_pre_input_hook = NULL; | ||
289 | rl_redisplay (); | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int | ||
294 | retrieve_history (char *str) | ||
295 | { | ||
296 | char *out; | ||
297 | int rc; | ||
298 | |||
299 | rc = history_expand (str, &out); | ||
300 | switch (rc) | ||
301 | { | ||
302 | case -1: | ||
303 | mu_error ("%s", out); | ||
304 | free (out); | ||
305 | return 1; | ||
306 | |||
307 | case 0: | ||
308 | break; | ||
309 | |||
310 | case 1: | ||
311 | pre_input_line = out; | ||
312 | rl_pre_input_hook = pre_input; | ||
313 | return 1; | ||
314 | |||
315 | case 2: | ||
316 | printf ("%s\n", out); | ||
317 | free (out); | ||
318 | return 1; | ||
319 | } | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int | ||
324 | shell_history (int argc, char **argv) | ||
325 | { | ||
326 | int i; | ||
327 | HIST_ENTRY **hlist; | ||
328 | |||
329 | hlist = history_list (); | ||
330 | for (i = 0; i < history_length; i++) | ||
331 | printf ("%4d) %s\n", i + 1, hlist[i]->line); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | #else | ||
337 | # define finish_readline() | ||
338 | # define mutool_initialize_readline (const char *name) | ||
339 | |||
340 | char * | ||
341 | readline (char *prompt) | ||
342 | { | ||
343 | static size_t size = 0; | ||
344 | static char *buf = NULL; | ||
345 | |||
346 | if (prompt) | ||
347 | { | ||
348 | printf ("%s", prompt); | ||
349 | fflush (stdout); | ||
350 | } | ||
351 | if (getline (&buf, &size, stdin) <= 0) | ||
352 | return NULL; | ||
353 | return buf; | ||
354 | } | ||
355 | |||
356 | void | ||
357 | add_history (const char *s MU_ARG_UNUSED) | ||
358 | { | ||
359 | } | ||
360 | #endif | ||
361 | |||
362 | /* Parse and execute a command line. */ | ||
363 | int | ||
364 | execute_line (char *line) | ||
365 | { | ||
366 | int argc; | ||
367 | char **argv; | ||
368 | int status = 0; | ||
369 | |||
370 | if (mu_argcv_get (line, NULL, "#", &argc, &argv)) | ||
371 | { | ||
372 | mu_error("cannot parse input line"); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | if (argc >= 0) | ||
377 | { | ||
378 | struct mutool_command *cmd = find_command (argv[0]); | ||
379 | |||
380 | if (!cmd) | ||
381 | mu_error ("%s: no such command.", argv[0]); | ||
382 | else if (cmd->argmin > 0 && argc < cmd->argmin) | ||
383 | mu_error ("%s: too few arguments", argv[0]); | ||
384 | else if (cmd->argmax > 0 && argc > cmd->argmax) | ||
385 | mu_error ("%s: too many arguments", argv[0]); | ||
386 | else | ||
387 | { | ||
388 | if (cmd->argmin <= 0 && argc != 2) | ||
389 | { | ||
390 | char *word = mu_str_skip_class (line, MU_CTYPE_SPACE); | ||
391 | char *arg = mu_str_skip_class_comp (word, MU_CTYPE_SPACE); | ||
392 | if (*arg) | ||
393 | { | ||
394 | *arg++ = 0; | ||
395 | arg = mu_str_skip_class (arg, MU_CTYPE_SPACE); | ||
396 | } | ||
397 | |||
398 | mu_argcv_free (argc, argv); | ||
399 | argc = 2; | ||
400 | argv = xcalloc (argc + 1, sizeof (argv[0])); | ||
401 | argv[0] = xstrdup (word); | ||
402 | argv[1] = xstrdup (arg); | ||
403 | argv[2] = NULL; | ||
404 | } | ||
405 | status = cmd->func (argc, argv); | ||
406 | } | ||
407 | } | ||
408 | mu_argcv_free (argc, argv); | ||
409 | return status; | ||
410 | } | ||
411 | |||
412 | static char * | ||
413 | input_line_interactive () | ||
414 | { | ||
415 | char *p = expand_prompt (); | ||
416 | char *line = readline (p); | ||
417 | free (p); | ||
418 | return line; | ||
419 | } | ||
420 | |||
421 | static char * | ||
422 | input_line_script () | ||
423 | { | ||
424 | size_t size = 0; | ||
425 | char *buf = NULL; | ||
426 | if (getline (&buf, &size, stdin) <= 0) | ||
427 | return NULL; | ||
428 | return buf; | ||
429 | } | ||
430 | |||
431 | static int done; | ||
432 | |||
433 | static int | ||
434 | shell_exit (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) | ||
435 | { | ||
436 | done = 1; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | int | ||
441 | mutool_shell (const char *name, struct mutool_command *cmd) | ||
442 | { | ||
443 | size_t n; | ||
444 | int interactive = isatty (0); | ||
445 | char *(*input_line) () = interactive ? | ||
446 | input_line_interactive : input_line_script; | ||
447 | |||
448 | for (n = 0; cmd[n].name; n++) | ||
449 | ; | ||
450 | |||
451 | user_command_count = n; | ||
452 | shell_comtab = xcalloc (n + MU_ARRAY_SIZE (default_comtab), | ||
453 | sizeof (shell_comtab[0])); | ||
454 | memcpy (shell_comtab, cmd, n * sizeof (shell_comtab[0])); | ||
455 | memcpy (shell_comtab + n, default_comtab, sizeof (default_comtab)); | ||
456 | |||
457 | mutool_initialize_readline (name); | ||
458 | while (!done) | ||
459 | { | ||
460 | char *s, *line = input_line (); | ||
461 | if (!line) | ||
462 | break; | ||
463 | |||
464 | /* Remove leading and trailing whitespace from the line. | ||
465 | Then, if there is anything left, add it to the history list | ||
466 | and execute it. */ | ||
467 | s = mu_str_stripws (line); | ||
468 | |||
469 | if (*s) | ||
470 | { | ||
471 | int status; | ||
472 | |||
473 | #ifdef WITH_READLINE | ||
474 | if (interactive) | ||
475 | { | ||
476 | if (retrieve_history (s)) | ||
477 | continue; | ||
478 | add_history (s); | ||
479 | } | ||
480 | #endif | ||
481 | |||
482 | status = execute_line (s); | ||
483 | if (status != 0) | ||
484 | mu_error ("Error: %s", mu_strerror (status)); | ||
485 | } | ||
486 | |||
487 | free (line); | ||
488 | } | ||
489 | if (interactive) | ||
490 | finish_readline (); | ||
491 | return 0; | ||
492 | } |
-
Please register or sign in to post a comment