Commit aa082652 aa0826526df4dc51cafc2297b7b8306831c38f98 by Sergey Poznyakoff

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.
1 parent af4665d4
...@@ -109,6 +109,7 @@ SUBDIRS = . \ ...@@ -109,6 +109,7 @@ SUBDIRS = . \
109 doc\ 109 doc\
110 config\ 110 config\
111 examples\ 111 examples\
112 mu\
112 $(FRM_DIR)\ 113 $(FRM_DIR)\
113 $(POP3D_DIR)\ 114 $(POP3D_DIR)\
114 $(IMAP4D_DIR)\ 115 $(IMAP4D_DIR)\
......
...@@ -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
......
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@
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 }
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 }
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 }
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
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);
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 }
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
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], &quote);
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 }
...@@ -197,5 +197,13 @@ sieve/sieve.c ...@@ -197,5 +197,13 @@ sieve/sieve.c
197 197
198 sql/mysql.c 198 sql/mysql.c
199 199
200 mu/filter.c
201 mu/flt2047.c
202 mu/info.c
203 mu/mu.c
204 mu/pop.c
205 mu/query.c
206 mu/shell.c
207
200 # EOF 208 # EOF
201 209
......