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