Commit 27ac3a54 27ac3a545e89bd4aa357d6a624363b4e9a80b859 by Sergey Poznyakoff

Implement SMTP shell in mu.

* include/mailutils/smtp.h (mu_smtp_get_reply_iterator)
(mu_smtp_cmd,mu_smtp_test_param): New protos.
* libproto/mailer/Makefile.am (libmu_mailer_la_SOURCES): Add
smtp_cmd.c
* libproto/mailer/smtp_cmd.c: New file.
* libproto/mailer/smtp_io.c (mu_smtp_get_reply_iterator): New function.
* libproto/mailer/smtp_param.c (mu_smtp_set_param): Accept NULL
parameter value.
(mu_smtp_test_param): New function.
* mu/Makefile.am [MU_COND_SUPPORT_SMTP]: Add smtp.c to MODULES.
(mu_SOURCES): Add getans.c, getyn.c and util.c
* mu/getans.c: New file.
* mu/getyn.c: New file.
* mu/smtp.c: New file.
* mu/util.c: New file.
* mu/mu.h (port_from_sa): New proto.
* mu/pop.c (port_from_sa): Move to util.c
1 parent e04498e5
...@@ -47,7 +47,9 @@ int mu_smtp_write (mu_smtp_t smtp, const char *fmt, ...) MU_PRINTFLIKE(2,3); ...@@ -47,7 +47,9 @@ int mu_smtp_write (mu_smtp_t smtp, const char *fmt, ...) MU_PRINTFLIKE(2,3);
47 47
48 int mu_smtp_replcode (mu_smtp_t smtp, char *buf); 48 int mu_smtp_replcode (mu_smtp_t smtp, char *buf);
49 int mu_smtp_sget_reply (mu_smtp_t smtp, const char **pbuf); 49 int mu_smtp_sget_reply (mu_smtp_t smtp, const char **pbuf);
50 int mu_smtp_get_reply_iterator (mu_smtp_t smtp, mu_iterator_t *pitr);
50 51
52 int mu_smtp_cmd (mu_smtp_t smtp, int argc, char **argv);
51 53
52 #define MU_SMTP_TRACE_CLR 0 54 #define MU_SMTP_TRACE_CLR 0
53 #define MU_SMTP_TRACE_SET 1 55 #define MU_SMTP_TRACE_SET 1
...@@ -59,6 +61,7 @@ int mu_smtp_disconnect (mu_smtp_t smtp); ...@@ -59,6 +61,7 @@ int mu_smtp_disconnect (mu_smtp_t smtp);
59 int mu_smtp_ehlo (mu_smtp_t smtp); 61 int mu_smtp_ehlo (mu_smtp_t smtp);
60 int mu_smtp_set_param (mu_smtp_t smtp, int code, const char *val); 62 int mu_smtp_set_param (mu_smtp_t smtp, int code, const char *val);
61 int mu_smtp_get_param (mu_smtp_t smtp, int code, const char **param); 63 int mu_smtp_get_param (mu_smtp_t smtp, int code, const char **param);
64 int mu_smtp_test_param (mu_smtp_t smtp, int pcode);
62 int mu_smtp_set_url (mu_smtp_t smtp, mu_url_t url); 65 int mu_smtp_set_url (mu_smtp_t smtp, mu_url_t url);
63 int mu_smtp_get_url (mu_smtp_t smtp, mu_url_t *purl); 66 int mu_smtp_get_url (mu_smtp_t smtp, mu_url_t *purl);
64 int mu_smtp_set_secret (mu_smtp_t smtp, mu_secret_t secret); 67 int mu_smtp_set_secret (mu_smtp_t smtp, mu_secret_t secret);
......
...@@ -34,6 +34,7 @@ libmu_mailer_la_SOURCES = \ ...@@ -34,6 +34,7 @@ libmu_mailer_la_SOURCES = \
34 smtp_capa.c\ 34 smtp_capa.c\
35 smtp_capa_itr.c\ 35 smtp_capa_itr.c\
36 smtp_carrier.c\ 36 smtp_carrier.c\
37 smtp_cmd.c\
37 smtp_create.c\ 38 smtp_create.c\
38 smtp_data.c\ 39 smtp_data.c\
39 smtp_disconnect.c\ 40 smtp_disconnect.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2012 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This library 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 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/cctype.h>
27 #include <mailutils/list.h>
28 #include <mailutils/util.h>
29 #include <mailutils/smtp.h>
30 #include <mailutils/stream.h>
31 #include <mailutils/sys/smtp.h>
32
33 /* Send an arbitrary command */
34 int
35 mu_smtp_cmd (mu_smtp_t smtp, int argc, char **argv)
36 {
37 int status, i;
38
39 if (!smtp)
40 return EINVAL;
41 if (MU_SMTP_FISSET (smtp, _MU_SMTP_ERR))
42 return MU_ERR_FAILURE;
43 status = mu_smtp_write (smtp, "%s", argv[0]);
44 MU_SMTP_CHECK_ERROR (smtp, status);
45 for (i = 1; i < argc; i++)
46 {
47 status = mu_smtp_write (smtp, " %s", argv[i]);
48 MU_SMTP_CHECK_ERROR (smtp, status);
49 }
50
51 status = mu_smtp_write (smtp, "\r\n");
52 MU_SMTP_CHECK_ERROR (smtp, status);
53 status = mu_smtp_response (smtp);
54 MU_SMTP_CHECK_ERROR (smtp, status);
55
56 if (smtp->replcode[0] > '3')
57 return MU_ERR_REPLY;
58
59 return 0;
60 }
61
62
...@@ -144,4 +144,10 @@ mu_smtp_sget_reply (mu_smtp_t smtp, const char **pbuf) ...@@ -144,4 +144,10 @@ mu_smtp_sget_reply (mu_smtp_t smtp, const char **pbuf)
144 return 0; 144 return 0;
145 } 145 }
146 146
147 147 int
148 mu_smtp_get_reply_iterator (mu_smtp_t smtp, mu_iterator_t *pitr)
149 {
150 if (!smtp || !pitr)
151 return EINVAL;
152 return mu_list_get_iterator (smtp->mlrepl, pitr);
153 }
......
...@@ -49,6 +49,8 @@ mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam) ...@@ -49,6 +49,8 @@ mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam)
49 mu_secret_password_unref (smtp->secret); 49 mu_secret_password_unref (smtp->secret);
50 mu_secret_destroy (&smtp->secret); 50 mu_secret_destroy (&smtp->secret);
51 } 51 }
52 if (!newparam)
53 return 0;
52 MU_SMTP_FCLR (smtp, _MU_SMTP_CLNPASS); 54 MU_SMTP_FCLR (smtp, _MU_SMTP_CLNPASS);
53 return mu_secret_create (&smtp->secret, newparam, strlen (newparam)); 55 return mu_secret_create (&smtp->secret, newparam, strlen (newparam));
54 } 56 }
...@@ -56,18 +58,28 @@ mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam) ...@@ -56,18 +58,28 @@ mu_smtp_set_param (mu_smtp_t smtp, int pcode, const char *newparam)
56 { 58 {
57 mu_url_t url; 59 mu_url_t url;
58 int rc; 60 int rc;
59 61
60 rc = mu_url_create (&url, newparam); 62 if (!newparam)
61 if (rc) 63 mu_url_destroy (&smtp->url);
62 return rc; 64 else
63 mu_url_destroy (&smtp->url); 65 {
64 smtp->url = url; 66 rc = mu_url_create (&url, newparam);
67 if (rc)
68 return rc;
69 mu_url_destroy (&smtp->url);
70 smtp->url = url;
71 }
65 return 0; 72 return 0;
66 } 73 }
67 74
68 param = strdup (newparam); 75 if (newparam)
69 if (!param) 76 {
70 return ENOMEM; 77 param = strdup (newparam);
78 if (!param)
79 return ENOMEM;
80 }
81 else
82 param = NULL;
71 free (smtp->param[pcode]); 83 free (smtp->param[pcode]);
72 smtp->param[pcode] = param; 84 smtp->param[pcode] = param;
73 return 0; 85 return 0;
...@@ -99,3 +111,24 @@ mu_smtp_get_param (mu_smtp_t smtp, int pcode, const char **pparam) ...@@ -99,3 +111,24 @@ mu_smtp_get_param (mu_smtp_t smtp, int pcode, const char **pparam)
99 return 0; 111 return 0;
100 } 112 }
101 113
114 int
115 mu_smtp_test_param (mu_smtp_t smtp, int pcode)
116 {
117 if (!smtp)
118 return EINVAL;
119 if (pcode < 0 || pcode >= MU_SMTP_MAX_PARAM)
120 return EINVAL;
121 if (pcode == MU_SMTP_PARAM_PASSWORD)
122 {
123 if (smtp->secret)
124 return 0;
125 return MU_ERR_NOENT;
126 }
127 else if (pcode == MU_SMTP_PARAM_URL)
128 {
129 if (smtp->url)
130 return 0;
131 return MU_ERR_NOENT;
132 }
133 return smtp->param[pcode] ? 0 : MU_ERR_NOENT;
134 }
......
...@@ -269,6 +269,9 @@ void mh_global_save_state (void); ...@@ -269,6 +269,9 @@ void mh_global_save_state (void);
269 int mh_interactive_mode_p (void); 269 int mh_interactive_mode_p (void);
270 int mh_getyn (const char *fmt, ...) MU_PRINTFLIKE(1,2); 270 int mh_getyn (const char *fmt, ...) MU_PRINTFLIKE(1,2);
271 int mh_getyn_interactive (const char *fmt, ...) MU_PRINTFLIKE(1,2); 271 int mh_getyn_interactive (const char *fmt, ...) MU_PRINTFLIKE(1,2);
272 int mu_vgetans (const char *variants, const char *fmt, va_list ap);
273 int mu_getans (const char *variants, const char *fmt, ...)
274 MU_PRINTFLIKE(2,3);
272 int mh_check_folder (const char *pathname, int confirm); 275 int mh_check_folder (const char *pathname, int confirm);
273 int mh_makedir (const char *p); 276 int mh_makedir (const char *p);
274 277
......
...@@ -39,6 +39,12 @@ else ...@@ -39,6 +39,12 @@ else
39 IDLE_MODULES+=dbm.c 39 IDLE_MODULES+=dbm.c
40 endif 40 endif
41 41
42 if MU_COND_SUPPORT_SMTP
43 SMTP_C=smtp.c
44 else
45 IDLE_MODULES+=smtp.c
46 endif
47
42 MODULES = \ 48 MODULES = \
43 acl.c\ 49 acl.c\
44 cflags.c\ 50 cflags.c\
...@@ -51,16 +57,20 @@ MODULES = \ ...@@ -51,16 +57,20 @@ MODULES = \
51 ldflags.c\ 57 ldflags.c\
52 logger.c\ 58 logger.c\
53 $(POP_C)\ 59 $(POP_C)\
54 send.c\
55 query.c\ 60 query.c\
61 send.c\
62 $(SMTP_C)\
56 wicket.c 63 wicket.c
57 64
58 mu_SOURCES = \ 65 mu_SOURCES = \
59 dispatch.c\ 66 dispatch.c\
67 getans.c\
60 getarg.c\ 68 getarg.c\
69 getyn.c\
61 mu.h\ 70 mu.h\
62 mu.c\ 71 mu.c\
63 shell.c\ 72 shell.c\
73 util.c\
64 verbose.c\ 74 verbose.c\
65 $(MODULES) 75 $(MODULES)
66 76
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010, 2012 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <mailutils/mailutils.h>
21 #include "mu.h"
22
23 int
24 mu_vgetans (const char *variants, const char *fmt, va_list ap)
25 {
26 char repl[64];
27
28 while (1)
29 {
30 size_t n;
31 char *p;
32
33 mu_stream_vprintf (mu_strout, fmt, ap);
34 mu_stream_write (mu_strout, "? ", 2, NULL);
35 mu_stream_flush (mu_strout);
36 if (mu_stream_read (mu_strin, repl, sizeof repl, &n) || n == 0)
37 return 0;
38 mu_rtrim_class (repl, MU_CTYPE_ENDLN);
39
40 p = strchr (variants, *repl);
41 if (p)
42 return *p;
43
44 mu_stream_printf (mu_strout, _("Please answer one of [%s]: "), variants);
45 }
46 return 0; /* to pacify gcc */
47 }
48
49 int
50 mu_getans (const char *variants, const char *fmt, ...)
51 {
52 va_list ap;
53 int rc;
54
55 va_start (ap, fmt);
56 rc = mu_vgetans (variants, fmt, ap);
57 va_end (ap);
58 return rc;
59 }
60
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010, 2012 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <mailutils/mailutils.h>
21 #include "mu.h"
22
23 int
24 mu_vgetyn (const char *fmt, va_list ap)
25 {
26 char repl[64];
27
28 while (1)
29 {
30 int rc;
31 size_t n;
32
33 mu_stream_vprintf (mu_strout, fmt, ap);
34 mu_stream_write (mu_strout, "? ", 2, NULL);
35 mu_stream_flush (mu_strout);
36 if (mu_stream_read (mu_strin, repl, sizeof repl, &n) || n == 0)
37 return 0;
38 mu_rtrim_class (repl, MU_CTYPE_ENDLN);
39
40 rc = mu_true_answer_p (repl);
41
42 if (rc >= 0)
43 return rc;
44
45 /* TRANSLATORS: See msgids "nN" and "yY". */
46 mu_stream_printf (mu_strout, "%s", _("Please answer yes or no: "));
47 }
48 return 0; /* to pacify gcc */
49 }
50
51 int
52 mu_getyn (const char *fmt, ...)
53 {
54 va_list ap;
55 int rc;
56
57 va_start (ap, fmt);
58 rc = mu_vgetyn (fmt, ap);
59 va_end (ap);
60 return rc;
61 }
62
...@@ -42,6 +42,8 @@ int mu_help (void); ...@@ -42,6 +42,8 @@ int mu_help (void);
42 mutool_action_t dispatch_find_action (const char *name); 42 mutool_action_t dispatch_find_action (const char *name);
43 char *dispatch_docstring (const char *text); 43 char *dispatch_docstring (const char *text);
44 44
45 int port_from_sa (struct mu_sockaddr *sa);
46
45 47
46 #define VERBOSE_MASK(n) (1<<((n)+1)) 48 #define VERBOSE_MASK(n) (1<<((n)+1))
47 #define SET_VERBOSE_MASK(n) (shell_verbose_flags |= VERBOSE_MASK (n)) 49 #define SET_VERBOSE_MASK(n) (shell_verbose_flags |= VERBOSE_MASK (n))
......
...@@ -473,22 +473,6 @@ com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) ...@@ -473,22 +473,6 @@ com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
473 } 473 }
474 474
475 static int 475 static int
476 port_from_sa (struct mu_sockaddr *sa)
477 {
478 switch (sa->addr->sa_family)
479 {
480 case AF_INET:
481 return ntohs (((struct sockaddr_in *)sa->addr)->sin_port);
482
483 #ifdef MAILUTILS_IPV6
484 case AF_INET6:
485 return ntohs (((struct sockaddr_in6 *)sa->addr)->sin6_port);
486 #endif
487 }
488 return 0;
489 }
490
491 static int
492 com_connect (int argc, char **argv) 476 com_connect (int argc, char **argv)
493 { 477 {
494 int status; 478 int status;
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2012 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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #include <mailutils/cctype.h>
26 #include <mailutils/mailutils.h>
27 #include <mailutils/smtp.h>
28 #include <argp.h>
29 #include "mu.h"
30
31 static char smtp_doc[] = N_("mu smtp - run a SMTP session.");
32 char smtp_docstring[] = N_("run a SMTP session");
33 static char smtp_args_doc[] = "";
34
35 static struct argp_option smtp_options[] = {
36 { NULL }
37 };
38
39 static error_t
40 smtp_parse_opt (int key, char *arg, struct argp_state *state)
41 {
42 switch (key)
43 {
44 default:
45 return ARGP_ERR_UNKNOWN;
46 }
47 return 0;
48 }
49
50 static struct argp smtp_argp = {
51 smtp_options,
52 smtp_parse_opt,
53 smtp_args_doc,
54 smtp_doc,
55 NULL,
56 NULL,
57 NULL
58 };
59
60 enum smtp_session_status
61 {
62 smtp_session_disconnected,
63 smtp_session_connected,
64 smtp_session_logged_in
65 };
66
67 static enum smtp_session_status smtp_session_status;
68 static int connect_argc;
69 static char **connect_argv;
70
71 /* Host we are connected to. */
72 #define host connect_argv[0]
73 static int port = 25;
74
75 static char *sender;
76 static mu_list_t recipients;
77
78 static char *msgfile;
79 static int temp_msgfile;
80 static mu_smtp_t smtp;
81
82 const char *
83 smtp_session_str (enum smtp_session_status stat)
84 {
85 switch (stat)
86 {
87 case smtp_session_disconnected:
88 return "disconnected";
89
90 case smtp_session_connected:
91 return "connected";
92
93 case smtp_session_logged_in:
94 return "logged in";
95 }
96 return "unknown";
97 }
98
99 static void
100 smtp_prompt_env ()
101 {
102 const char *value;
103
104 if (!mutool_prompt_env)
105 mutool_prompt_env = mu_calloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
106
107 mutool_prompt_env[0] = "user";
108 mutool_prompt_env[1] = "[nouser]";
109 if (smtp_session_status == smtp_session_logged_in &&
110 mu_smtp_get_param (smtp, MU_SMTP_PARAM_USERNAME, &value) == 0)
111 mutool_prompt_env[1] = (char*) value;
112
113 mutool_prompt_env[2] = "host";
114 mutool_prompt_env[3] = (smtp_session_status != smtp_session_disconnected) ?
115 host : "[nohost]";
116
117 mutool_prompt_env[4] = "program-name";
118 mutool_prompt_env[5] = (char*) mu_program_name;
119
120 mutool_prompt_env[6] = "canonical-program-name";
121 mutool_prompt_env[7] = "mu";
122
123 mutool_prompt_env[8] = "package";
124 mutool_prompt_env[9] = PACKAGE;
125
126 mutool_prompt_env[10] = "version";
127 mutool_prompt_env[11] = PACKAGE_VERSION;
128
129 mutool_prompt_env[12] = "status";
130 mutool_prompt_env[13] = (char*) smtp_session_str (smtp_session_status);
131
132 mutool_prompt_env[14] = NULL;
133 }
134
135 static void
136 smtp_set_verbose (void)
137 {
138 if (smtp)
139 {
140 if (QRY_VERBOSE ())
141 mu_smtp_trace (smtp, MU_SMTP_TRACE_SET);
142 else
143 mu_smtp_trace (smtp, MU_SMTP_TRACE_CLR);
144 }
145 }
146
147 static void
148 smtp_set_verbose_mask (void)
149 {
150 if (smtp)
151 {
152 mu_smtp_trace_mask (smtp, QRY_VERBOSE_MASK (MU_XSCRIPT_SECURE)
153 ? MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR,
154 MU_XSCRIPT_SECURE);
155 mu_smtp_trace_mask (smtp, QRY_VERBOSE_MASK (MU_XSCRIPT_PAYLOAD)
156 ? MU_SMTP_TRACE_SET : MU_SMTP_TRACE_CLR,
157 MU_XSCRIPT_PAYLOAD);
158 }
159 }
160
161 static int
162 com_verbose (int argc, char **argv)
163 {
164 return shell_verbose (argc, argv,
165 smtp_set_verbose, smtp_set_verbose_mask);
166 }
167
168 static int
169 smtp_error_handler (int rc)
170 {
171 if (rc == 0 || rc == MU_ERR_REPLY)
172 {
173 char code[4];
174 const char *repl;
175
176 mu_smtp_replcode (smtp, code);
177 mu_smtp_sget_reply (smtp, &repl);
178 mu_printf ("%s %s\n", code, repl);
179 }
180 return rc;
181 }
182
183 static int
184 com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
185 {
186 if (smtp)
187 {
188 mu_smtp_disconnect (smtp);
189 mu_smtp_destroy (&smtp);
190 smtp = NULL;
191
192 mu_argcv_free (connect_argc, connect_argv);
193 connect_argc = 0;
194 connect_argv = NULL;
195 smtp_session_status = smtp_session_disconnected;
196 smtp_prompt_env ();
197 }
198 return 0;
199 }
200
201 static int
202 com_connect (int argc, char **argv)
203 {
204 int status;
205 int tls = 0;
206 int i = 1;
207 int n;
208
209 for (i = 1; i < argc; i++)
210 {
211 if (strcmp (argv[i], "-tls") == 0)
212 {
213 #ifdef WITH_TLS
214 tls = 1;
215 #else
216 mu_error ("TLS not supported");
217 return 0;
218 #endif
219 }
220 else
221 break;
222 }
223
224 argc -= i;
225 argv += i;
226
227 if (smtp_session_status != smtp_session_disconnected)
228 com_disconnect (0, NULL);
229
230 status = mu_smtp_create (&smtp);
231 if (status == 0)
232 {
233 mu_stream_t tcp;
234 struct mu_sockaddr *sa;
235 struct mu_sockaddr_hints hints;
236
237 if (QRY_VERBOSE ())
238 {
239 smtp_set_verbose ();
240 smtp_set_verbose_mask ();
241 }
242
243 memset (&hints, 0, sizeof (hints));
244 hints.flags = MU_AH_DETECT_FAMILY;
245 hints.port = tls ? 465 : 25;
246 hints.protocol = IPPROTO_TCP;
247 hints.socktype = SOCK_STREAM;
248 status = mu_sockaddr_from_node (&sa, argv[0], argv[1], &hints);
249 if (status == 0)
250 {
251 n = port_from_sa (sa);
252 status = mu_tcp_stream_create_from_sa (&tcp, sa, NULL, 0);
253 if (status)
254 mu_sockaddr_free (sa);
255 }
256 if (status == 0)
257 {
258 #ifdef WITH_TLS
259 if (tls)
260 {
261 mu_stream_t tlsstream;
262
263 status = mu_tls_client_stream_create (&tlsstream, tcp, tcp, 0);
264 mu_stream_unref (tcp);
265 if (status)
266 {
267 mu_error ("cannot create TLS stream: %s",
268 mu_strerror (status));
269 return 0;
270 }
271 tcp = tlsstream;
272 }
273 #endif
274 mu_smtp_set_carrier (smtp, tcp);
275 status = smtp_error_handler (mu_smtp_open (smtp));
276 }
277 else
278 {
279 mu_smtp_destroy (&smtp);
280 smtp = NULL;
281 }
282 }
283
284 if (status)
285 mu_error ("Failed to create smtp: %s", mu_strerror (status));
286 else
287 {
288 connect_argc = argc;
289 connect_argv = mu_calloc (argc, sizeof (*connect_argv));
290 for (i = 0; i < argc; i++)
291 connect_argv[i] = mu_strdup (argv[i]);
292 connect_argv[i] = NULL;
293 port = n;
294 smtp_session_status = smtp_session_connected;
295
296 smtp_prompt_env ();
297 }
298
299 /* Provide a default URL. Authentication functions require it, see comment
300 in smtp_auth.c:119. */
301 mu_smtp_set_param (smtp, MU_SMTP_PARAM_URL, "smtp://");
302
303 return status;
304 }
305
306 static int
307 com_capa (int argc, char **argv)
308 {
309 mu_iterator_t iterator = NULL;
310 int status = 0;
311 int i = 1;
312
313 if (i < argc)
314 {
315 for (; i < argc; i++)
316 {
317 const char *elt;
318 int rc = mu_smtp_capa_test (smtp, argv[i], &elt);
319 switch (rc)
320 {
321 case 0:
322 if (*elt)
323 mu_printf ("%s: %s\n", argv[i], elt);
324 else
325 mu_printf ("%s is set\n", argv[i]);
326 break;
327
328 case MU_ERR_NOENT:
329 mu_printf ("%s is not set\n", argv[i]);
330 break;
331
332 default:
333 return smtp_error_handler (rc);
334 }
335 }
336 }
337 else
338 {
339 status = mu_smtp_capa_iterator (smtp, &iterator);
340
341 if (status == 0)
342 {
343 for (mu_iterator_first (iterator);
344 !mu_iterator_is_done (iterator); mu_iterator_next (iterator))
345 {
346 char *capa = NULL;
347 mu_iterator_current (iterator, (void **) &capa);
348 mu_printf ("CAPA: %s\n", capa ? capa : "");
349 }
350 mu_iterator_destroy (&iterator);
351 }
352 }
353 return status;
354 }
355
356 static int
357 com_ehlo (int argc, char **argv)
358 {
359 if (argc == 1)
360 {
361 if (mu_smtp_test_param (smtp, MU_SMTP_PARAM_DOMAIN))
362 {
363 mu_error (_("no domain set"));
364 return 0;
365 }
366 }
367 else
368 mu_smtp_set_param (smtp, MU_SMTP_PARAM_DOMAIN, argv[1]);
369 return com_capa (1, argv);
370 }
371
372 static int
373 com_rset (int argc, char **argv)
374 {
375 return smtp_error_handler (mu_smtp_rset (smtp));
376 }
377
378 static int
379 com_quit (int argc, char **argv)
380 {
381 int status = 0;
382 if (smtp)
383 {
384 if (smtp_error_handler (mu_smtp_quit (smtp)) == 0)
385 {
386 status = com_disconnect (0, NULL);
387 }
388 else
389 {
390 mu_printf ("Try 'exit' to leave %s\n", mu_program_name);
391 }
392 }
393 else
394 mu_printf ("Try 'exit' to leave %s\n", mu_program_name);
395 return status;
396 }
397
398 static int
399 com_from (int argc, char **argv)
400 {
401 if (argc == 1)
402 {
403 if (!sender)
404 {
405 mu_error (_("no sender address"));
406 return 0;
407 }
408 }
409 else
410 {
411 free (sender);
412 sender = mu_strdup (argv[1]);
413 }
414 return smtp_error_handler (mu_smtp_mail_basic (smtp, sender, NULL));
415 }
416
417 static int
418 send_rcpt_to (void *item, void *data)
419 {
420 return smtp_error_handler (mu_smtp_rcpt_basic (smtp, (char*) item, NULL));
421 }
422
423 static int
424 com_to (int argc, char **argv)
425 {
426 int rc;
427
428 if (argc == 1)
429 {
430 if (mu_list_is_empty (recipients))
431 {
432 mu_error (_("no recipients"));
433 return 1;
434 }
435 mu_list_foreach (recipients, send_rcpt_to, NULL);
436 rc = 0;
437 }
438 else
439 {
440 if (!recipients)
441 mu_list_create (&recipients);
442 mu_list_set_destroy_item (recipients, mu_list_free_item);
443 rc = smtp_error_handler (mu_smtp_rcpt_basic (smtp, argv[1], NULL));
444 if (rc == 0)
445 mu_list_append (recipients, mu_strdup (argv[1]));
446 }
447 return rc;
448 }
449
450 static int
451 edit (const char *file)
452 {
453 char *ed;
454 char *edv[3];
455 int rc, status;
456
457 ed = getenv ("VISUAL");
458 if (!ed)
459 {
460 ed = getenv ("EDITOR");
461 if (!ed)
462 ed = "/bin/ed";
463 }
464
465 edv[0] = ed;
466 edv[1] = (char*) file;
467 edv[2] = NULL;
468
469 rc = mu_spawnvp (edv[0], edv, &status);
470 if (rc)
471 mu_diag_funcall (MU_DIAG_ERROR, "mu_spawnvp", edv[0], rc);
472 return rc;
473 }
474
475 struct rcptout
476 {
477 mu_stream_t str;
478 int n;
479 };
480
481 static int
482 print_rcpt (void *item, void *data)
483 {
484 struct rcptout *p = data;
485 if (p->n++)
486 mu_stream_write (p->str, ", ", 2, NULL);
487 mu_stream_printf (p->str, "%s", (char *)item);
488 return 0;
489 }
490
491 static int
492 edit_file (const char *fname, int inplace)
493 {
494 int rc;
495
496 if (fname && !inplace)
497 {
498 mu_stream_t istr, ostr;
499
500 rc = mu_file_stream_create (&istr, fname, MU_STREAM_READ|MU_STREAM_SEEK);
501 if (rc == 0)
502 {
503 char *tempfile = mu_tempname (NULL);
504 rc = mu_file_stream_create (&ostr, tempfile,
505 MU_STREAM_CREAT|MU_STREAM_WRITE);
506 if (rc)
507 {
508 free (tempfile);
509 mu_error (_("cannot create temporary file: %s"),
510 mu_strerror (rc));
511 return -1;
512 }
513 rc = mu_stream_copy (ostr, istr, 0, NULL);
514 if (rc)
515 {
516 unlink (tempfile);
517 free (tempfile);
518 mu_error (_("error copying to temporary file: %s"),
519 mu_strerror (rc));
520 return -1;
521 }
522 mu_stream_unref (ostr);
523 free (msgfile);
524 msgfile = tempfile;
525 temp_msgfile = 1;
526 }
527 else if (rc != ENOENT)
528 {
529 mu_diag_funcall (MU_DIAG_ERROR, "mu_file_stream_create", fname, rc);
530 return 1;
531 }
532 mu_stream_unref (istr);
533 }
534 else if (!fname)
535 {
536 struct rcptout rcptout;
537
538 if (temp_msgfile)
539 unlink (msgfile);
540 free (msgfile);
541 msgfile = mu_tempname (NULL);
542 temp_msgfile = 1;
543
544 rc = mu_file_stream_create (&rcptout.str, msgfile,
545 MU_STREAM_CREAT|MU_STREAM_WRITE);
546 if (rc)
547 {
548 mu_error (_("cannot open temporary file for writing: %s"),
549 mu_strerror (rc));
550 return 1;
551 }
552 rcptout.n = 0;
553 if (sender)
554 mu_stream_printf (rcptout.str, "From: %s\n", sender);
555 else
556 mu_stream_printf (rcptout.str, "From: \n");
557 mu_stream_printf (rcptout.str, "To: ");
558 mu_list_foreach (recipients, print_rcpt, &rcptout);
559 mu_stream_write (rcptout.str, "\n", 1, NULL);
560 mu_stream_printf (rcptout.str, "Subject: \n\n");
561 mu_stream_unref (rcptout.str);
562 }
563 else
564 {
565 free (msgfile);
566 msgfile = mu_strdup (fname);
567 temp_msgfile = 0;
568 }
569
570 do
571 {
572 if (edit (msgfile))
573 return 1;
574 }
575 while ((rc = mu_getans ("seqSEQ", _("What now: [s]end, [e]dit, [q]uit")))
576 == 'e' || rc == 'E');
577
578 return rc == 'q' || rc == 'Q';
579 }
580
581 static int
582 com_send (int argc, char **argv)
583 {
584 int rc;
585 mu_stream_t instr;
586
587 if (argc == 1)
588 {
589 if (msgfile)
590 {
591 switch (mu_getans ("rReEdD",
592 _("Previous message exists. "
593 "What now: [r]euse, [e]dit, "
594 "[u]se as a template or\n"
595 "[d]rop and start from scratch")))
596 {
597 case 'r':
598 case 'R':
599 rc = 0;
600 break;
601
602 case 'e':
603 case 'E':
604 rc = edit_file (msgfile, 1);
605 break;
606
607 case 'd':
608 case 'D':
609 if (temp_msgfile)
610 unlink (msgfile);
611 free (msgfile);
612 msgfile = NULL;
613 temp_msgfile = 0;
614 rc = edit_file (NULL, 0);
615 break;
616
617 case 'u':
618 case 'U':
619 rc = edit_file (msgfile, 0);
620 }
621 }
622 else
623 rc = edit_file (NULL, 0);
624 if (rc)
625 return 0;
626 }
627 else
628 {
629 if (temp_msgfile)
630 unlink (msgfile);
631 free (msgfile);
632 msgfile = NULL;
633 temp_msgfile = 0;
634 msgfile = mu_strdup (argv[1]);
635 }
636
637 rc = mu_file_stream_create (&instr, msgfile, MU_STREAM_READ|MU_STREAM_SEEK);
638 if (rc)
639 {
640 mu_diag_funcall (MU_DIAG_ERROR, "mu_file_stream_create", msgfile, rc);
641 return 1;
642 }
643
644 rc = mu_smtp_send_stream (smtp, instr);
645 mu_stream_unref (instr);
646
647 if (rc)
648 smtp_error_handler (rc);
649 else
650 rc = smtp_error_handler (mu_smtp_dot (smtp));
651
652 return rc;
653 }
654
655 static int
656 com_starttls (int argc, char **argv)
657 {
658 if (mu_smtp_capa_test (smtp, "STARTTLS", NULL) == 0)
659 return smtp_error_handler (mu_smtp_starttls (smtp));
660 else
661 mu_error (_("remote party does not offer STARTTLS"));
662 return 1;
663 }
664
665 static int
666 com_auth (int argc, char **argv)
667 {
668 int rc, i;
669
670 rc = mu_smtp_clear_auth_mech (smtp);
671 if (rc)
672 {
673 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_clear_auth_mech", NULL, rc);
674 return MU_ERR_FAILURE;
675 }
676 for (i = 1; i < argc; i++)
677 if ((rc = mu_smtp_add_auth_mech (smtp, argv[1])))
678 {
679 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_add_auth_mech", NULL, rc);
680 return MU_ERR_FAILURE;
681 }
682
683 rc = mu_smtp_auth (smtp);
684
685 switch (rc)
686 {
687 case 0:
688 smtp_session_status = smtp_session_logged_in;
689 break;
690
691 case ENOSYS:
692 mu_error (_("authentication not implemented"));
693 break;
694
695 case MU_ERR_NOENT:
696 mu_error (_("no suitable authentication mechanism found"));
697 break;
698
699 default:
700 smtp_error_handler (rc);
701 return rc;
702 }
703 return 0;
704 }
705
706 static struct mu_kwd paramtab[] = {
707 { "domain", MU_SMTP_PARAM_DOMAIN },
708 { "username", MU_SMTP_PARAM_USERNAME },
709 { "password", MU_SMTP_PARAM_PASSWORD },
710 { "service", MU_SMTP_PARAM_SERVICE },
711 { "realm", MU_SMTP_PARAM_REALM },
712 { "host", MU_SMTP_PARAM_HOST },
713 { "url", MU_SMTP_PARAM_URL },
714 { NULL }
715 };
716
717 static int
718 get_param (int param, char *prompt, char **retval)
719 {
720 int rc;
721
722 if (param == MU_SMTP_PARAM_PASSWORD)
723 {
724 rc = mu_getpass (mu_strin, mu_strout, prompt, retval);
725 if (rc)
726 mu_diag_funcall (MU_DIAG_ERROR, "mu_getpass", NULL, rc);
727 }
728 else
729 {
730 char *buf = NULL;
731 size_t size = 0;
732 rc = mu_stream_write (mu_strout, prompt, strlen (prompt), NULL);
733 if (rc)
734 return rc;
735 mu_stream_flush (mu_strout);
736 rc = mu_stream_getline (mu_strin, &buf, &size, NULL);
737 if (rc == 0)
738 {
739 mu_rtrim_cset (buf, "\n");
740 *retval = buf;
741 }
742 }
743 return rc;
744 }
745
746 static int
747 com_set (int argc, char **argv)
748 {
749 int param, i, rc;
750
751 for (i = 1; i < argc; i += 2)
752 {
753 if (mu_kwd_xlat_name (paramtab, argv[i], &param))
754 {
755 mu_error (_("unrecognized parameter: %s"), argv[i]);
756 continue;
757 }
758 if (i + 1 < argc)
759 {
760 rc = mu_smtp_set_param (smtp, param, argv[i+1]);
761 if (rc)
762 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param", argv[i], rc);
763 }
764 else
765 {
766 char *prompt, *value;
767 mu_asprintf (&prompt, "%s: ", argv[i]);
768 rc = get_param (param, prompt, &value);
769 free (prompt);
770 if (rc)
771 mu_error (_("error reading value: %s"), mu_strerror (rc));
772 else
773 {
774 rc = mu_smtp_set_param (smtp, param, value);
775 if (param == MU_SMTP_PARAM_PASSWORD)
776 memset (value, 0, strlen (value));
777 if (rc)
778 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param", argv[i],
779 rc);
780 free (value);
781 }
782 }
783 }
784 return 0;
785 }
786
787 static int
788 com_clear (int argc, char **argv)
789 {
790 int param, i, rc;
791
792 if (argc > 1)
793 {
794 for (i = 1; i < argc; i++)
795 {
796 if (mu_kwd_xlat_name (paramtab, argv[i], &param))
797 {
798 mu_error (_("unrecognized parameter: %s"), argv[i]);
799 continue;
800 }
801 rc = mu_smtp_set_param (smtp, param, NULL);
802 if (rc)
803 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param", argv[i], rc);
804 }
805 }
806 else
807 {
808 for (i = 0; paramtab[i].name; i++)
809 {
810 rc = mu_smtp_set_param (smtp, paramtab[i].tok, NULL);
811 if (rc)
812 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param",
813 paramtab[i].name, rc);
814 }
815 }
816 return 0;
817 }
818
819 static int
820 com_list_param (int argc, char **argv)
821 {
822 int param, i, rc;
823 const char *value;
824
825 if (argc > 1)
826 {
827 for (i = 1; i < argc; i++)
828 {
829 if (mu_kwd_xlat_name (paramtab, argv[i], &param))
830 {
831 mu_error (_("unrecognized parameter: %s"), argv[i]);
832 continue;
833 }
834 rc = mu_smtp_get_param (smtp, param, &value);
835 if (rc)
836 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param", argv[i], rc);
837 else if (value)
838 mu_printf ("%s = %s\n", argv[i], value);
839 else
840 mu_printf (_("%s not set\n"), argv[i]);
841 }
842 }
843 else
844 {
845 for (i = 0; paramtab[i].name; i++)
846 {
847 rc = mu_smtp_get_param (smtp, paramtab[i].tok, &value);
848 if (rc)
849 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_set_param",
850 paramtab[i].name, rc);
851 else if (value)
852 mu_printf ("%s = %s\n", paramtab[i].name, value);
853 else
854 mu_printf (_("%s not set\n"), paramtab[i].name);
855 }
856 }
857 return 0;
858 }
859
860 static int
861 com_smtp_command (int argc, char **argv)
862 {
863 int rc;
864 mu_iterator_t itr;
865
866 rc = mu_smtp_cmd (smtp, argc - 1, argv + 1);
867 smtp_error_handler (rc);
868 if (rc)
869 return rc;
870 rc = mu_smtp_get_reply_iterator (smtp, &itr);
871 if (rc)
872 {
873 mu_diag_funcall (MU_DIAG_ERROR, "mu_smtp_get_reply_iterator", NULL, rc);
874 return 1;
875 }
876
877 for (mu_iterator_first (itr);
878 !mu_iterator_is_done (itr); mu_iterator_next (itr))
879 {
880 char *str = NULL;
881 mu_iterator_current (itr, (void **) &str);
882 mu_printf ("%s\n", str);
883 }
884 mu_iterator_destroy (&itr);
885 return 0;
886 }
887
888 struct mutool_command smtp_comtab[] = {
889 { "connect", 1, 4, 0, com_connect,
890 /* TRANSLATORS: -tls is a keyword. */
891 N_("[-tls] HOSTNAME [PORT]"),
892 N_("open connection") },
893
894 { "set", 2, -1, 0, com_set,
895 N_("PARAM [ARG...]"),
896 N_("Set connection parameter") },
897 { "clear", 1, -1, 0, com_clear,
898 N_("[PARAM...]"),
899 N_("Clear connection parameters") },
900
901 { "list", 1, -1, 0, com_list_param,
902 N_("[PARAM...]"),
903 N_("List connection parameters") },
904
905 { "auth", 2, -1, 0, com_auth,
906 N_("MECH [MECH...]"),
907 N_("Authenticate") },
908
909 { "ehlo", 1, 2, 0, com_ehlo,
910 N_("[DOMAIN]"),
911 N_("Greet the server") },
912
913 { "capa", 1, -1, 0, com_capa,
914 N_("[NAME...]"),
915 N_("list server capabilities") },
916
917 { "starttls", 1, 1, 0, com_starttls,
918 NULL,
919 N_("initiate encrypted connection") },
920
921 { "rset", 1, 1, 0, com_rset,
922 NULL,
923 N_("reset the session state") },
924
925 { "from", 1, 2, 0, com_from,
926 N_("[EMAIL]"),
927 N_("set sender email") },
928
929 { "to", 1, 2, 0, com_to,
930 N_("[EMAIL]"),
931 N_("set recipient email") },
932
933 { "send", 1, 2, 0, com_send,
934 N_("[FILE]"),
935 N_("send message") },
936
937 { "smtp", 2, -1, 0, com_smtp_command,
938 N_("COMMAND [ARGS...]"),
939 N_("send an arbitrary COMMAND") },
940
941 { "quit", 1, 1, 0, com_quit,
942 NULL,
943 N_("quit the session") },
944
945 { "verbose", 1, 4, 0, com_verbose,
946 "[on|off|mask|unmask] [secure [payload]]",
947 N_("control the protocol tracing") },
948
949 { NULL }
950 };
951
952 int
953 mutool_smtp (int argc, char **argv)
954 {
955 int index;
956
957 mu_registrar_record (mu_smtp_record);
958 mu_registrar_record (mu_smtps_record);
959
960 if (argp_parse (&smtp_argp, argc, argv, 0, &index, NULL))
961 return 1;
962
963 argc -= index;
964
965 if (argc)
966 {
967 mu_error (_("bad arguments"));
968 return 1;
969 }
970
971 mutool_shell_prompt = mu_strdup ("smtp> ");
972 smtp_prompt_env ();
973 mutool_shell ("smtp", smtp_comtab);
974
975 if (temp_msgfile)
976 unlink (msgfile);
977
978 return 0;
979 }
980
981 /*
982 MU Setup: smtp
983 mu-handler: mutool_smtp
984 mu-docstring: smtp_docstring
985 End MU Setup:
986 */
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2012 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
21 #include <stdlib.h>
22 #include <arpa/inet.h>
23 #include <mailutils/mailutils.h>
24 #include "mu.h"
25
26 int
27 port_from_sa (struct mu_sockaddr *sa)
28 {
29 switch (sa->addr->sa_family)
30 {
31 case AF_INET:
32 return ntohs (((struct sockaddr_in *)sa->addr)->sin_port);
33
34 #ifdef MAILUTILS_IPV6
35 case AF_INET6:
36 return ntohs (((struct sockaddr_in6 *)sa->addr)->sin6_port);
37 #endif
38 }
39 return 0;
40 }
41