1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003-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 /* MH send command */
18
19 #include <mh.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23 #include <pwd.h>
24
25 static char prog_doc[] = N_("Send messages");
26 static char args_doc[] = N_("FILE [FILE...]");
27
28 static const char *draftfolder; /* Use this draft folder */
29 static int use_draftfolder = 1;
30 static int use_draft;
31
32 static int append_msgid; /* Append Message-ID: header */
33 static int background; /* Operate in the background */
34
35 static int split_message; /* Split the message */
36 static unsigned long split_interval; /* Interval in seconds between sending two
37 successive partial messages */
38 static size_t split_size = 76*632; /* Size of split parts */
39 static int verbose; /* Produce verbose diagnostics */
40 static int watch; /* Watch the delivery process */
41
42 static int keep_files; /* Keep draft files */
43
44 #define DEFAULT_USER_AGENT "MH (" PACKAGE_STRING ")"
45
46 #define WATCH(c) do {\
47 if (watch)\
48 watch_printf c;\
49 } while (0)
50
51 static int add_file (char const *name);
52 static void mesg_list_fixup (void);
53
54 static void
add_alias(struct mu_parseopt * po,struct mu_option * opt,char const * arg)55 add_alias (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
56 {
57 mh_alias_read (arg, 1);
58 }
59
60 static void
set_draftfolder(struct mu_parseopt * po,struct mu_option * opt,char const * arg)61 set_draftfolder (struct mu_parseopt *po, struct mu_option *opt,
62 char const *arg)
63 {
64 draftfolder = mu_strdup (arg);
65 use_draftfolder = 1;
66 }
67
68 static void
add_draftmessage(struct mu_parseopt * po,struct mu_option * opt,char const * arg)69 add_draftmessage (struct mu_parseopt *po, struct mu_option *opt,
70 char const *arg)
71 {
72 add_file (arg);
73 }
74
75 static void
set_split_opt(struct mu_parseopt * po,struct mu_option * opt,char const * arg)76 set_split_opt (struct mu_parseopt *po, struct mu_option *opt,
77 char const *arg)
78 {
79 char *errmsg;
80 int rc = mu_str_to_c (arg, opt->opt_type, opt->opt_ptr, &errmsg);
81 if (rc)
82 {
83 char const *errtext;
84 if (errmsg)
85 errtext = errmsg;
86 else
87 errtext = mu_strerror (rc);
88
89 mu_parseopt_error (po, "%s%s: %s", po->po_long_opt_start,
90 opt->opt_long, errtext);
91 free (errmsg);
92
93 if (!(po->po_flags & MU_PARSEOPT_NO_ERREXIT))
94 exit (po->po_exit_error);
95 }
96 split_message = 1;
97 }
98
99 static struct mu_option options[] = {
100 { "alias", 0, N_("FILE"), MU_OPTION_DEFAULT,
101 N_("specify additional alias file"),
102 mu_c_string, NULL, add_alias },
103 { "draft", 0, NULL, MU_OPTION_DEFAULT,
104 N_("use prepared draft"),
105 mu_c_bool, &use_draft },
106 { "draftfolder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
107 N_("specify the folder for message drafts"),
108 mu_c_string, NULL, set_draftfolder },
109 { "draftmessage", 0, N_("MSG"), MU_OPTION_DEFAULT,
110 N_("use MSG from the draftfolder as a draft"),
111 mu_c_string, NULL, add_draftmessage },
112 { "nodraftfolder", 0, NULL, MU_OPTION_DEFAULT,
113 N_("undo the effect of the last --draftfolder option"),
114 mu_c_int, &use_draftfolder, NULL, "1" },
115 { "filter", 0, N_("FILE"), MU_OPTION_HIDDEN,
116 N_("use filter FILE to preprocess the body of the message"),
117 mu_c_string, NULL, mh_opt_notimpl },
118 { "nofilter", 0, NULL, MU_OPTION_HIDDEN,
119 N_("undo the effect of the last --filter option"),
120 mu_c_int, NULL, mh_opt_notimpl },
121 { "format", 0, NULL, MU_OPTION_HIDDEN,
122 N_("reformat To: and Cc: addresses"),
123 mu_c_bool, NULL, mh_opt_notimpl_warning },
124 { "noformat", 0, NULL, MU_OPTION_HIDDEN },
125 { "forward", 0, NULL, MU_OPTION_HIDDEN,
126 N_("in case of failure forward the draft along with the failure notice to the sender"),
127 mu_c_bool, NULL, mh_opt_notimpl_warning },
128 { "noforward", 0, NULL, MU_OPTION_HIDDEN, "" },
129 { "mime", 0, NULL, MU_OPTION_HIDDEN,
130 N_("use MIME encapsulation"),
131 mu_c_bool, NULL, mh_opt_notimpl_warning },
132 { "msgid", 0, NULL, MU_OPTION_DEFAULT,
133 N_("add Message-ID: field"),
134 mu_c_bool, &append_msgid },
135 { "push", 0, NULL, MU_OPTION_DEFAULT,
136 N_("run in the background"),
137 mu_c_bool, &background },
138 { "preserve", 0, NULL, MU_OPTION_DEFAULT,
139 N_("keep draft files"),
140 mu_c_bool, &keep_files },
141 { "keep", 0, NULL, MU_OPTION_ALIAS },
142 { "split", 0, N_("SECONDS"), MU_OPTION_DEFAULT,
143 N_("split the draft into several partial messages and send them with SECONDS interval"),
144 mu_c_ulong, &split_interval, set_split_opt },
145 { "chunksize", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
146 N_("set the size of chunk for --split (in bytes)"),
147 mu_c_size, &split_size },
148 { "verbose", 0, NULL, MU_OPTION_DEFAULT,
149 N_("print the transcript of interactions with the transport system"),
150 mu_c_bool, &verbose },
151 { "watch", 0, NULL, MU_OPTION_DEFAULT,
152 N_("monitor the delivery of mail"),
153 mu_c_bool, &watch },
154 { "width", 0, N_("NUMBER"), MU_OPTION_HIDDEN,
155 N_("make header fields no longer than NUMBER columns"),
156 mu_c_uint, NULL, mh_opt_notimpl_warning },
157
158 MU_OPTION_END
159 };
160
161 static void
watch_printf(const char * fmt,...)162 watch_printf (const char *fmt, ...)
163 {
164 va_list ap;
165
166 va_start (ap, fmt);
167 vfprintf (stderr, fmt, ap);
168 fprintf (stderr, "\n");
169 va_end (ap);
170 }
171
172 struct list_elt /* Element of the send list */
173 {
174 const char *file_name; /* Duplicated in msg stream, but there's no way
175 to get it from there */
176 mu_message_t msg; /* Corresponding message */
177 };
178
179 static mu_list_t mesg_list;
180 static mu_property_t mts_profile;
181
182 int
add_file(char const * name)183 add_file (char const *name)
184 {
185 struct list_elt *elt;
186
187 if (!mesg_list && mu_list_create (&mesg_list))
188 {
189 mu_error (_("cannot create message list"));
190 return 1;
191 }
192
193 elt = mu_alloc (sizeof *elt);
194 elt->file_name = name;
195 elt->msg = NULL;
196 return mu_list_append (mesg_list, elt);
197 }
198
199 int
checkdraft(const char * name)200 checkdraft (const char *name)
201 {
202 struct stat st;
203
204 if (stat (name, &st))
205 {
206 mu_error (_("unable to stat draft file %s: %s"), name,
207 mu_strerror (errno));
208 return 1;
209 }
210 return 0;
211 }
212
213 int
elt_fixup(void * item,void * data)214 elt_fixup (void *item, void *data)
215 {
216 struct list_elt *elt = item;
217
218 elt->file_name = mh_expand_name (draftfolder, elt->file_name, NAME_ANY);
219 if (checkdraft (elt->file_name))
220 exit (1);
221 elt->msg = mh_file_to_message (NULL, elt->file_name);
222 if (!elt->msg)
223 return MU_ERR_USER0;
224
225 return 0;
226 }
227
228 void
mesg_list_fixup()229 mesg_list_fixup ()
230 {
231 if (mesg_list && mu_list_foreach (mesg_list, elt_fixup, NULL))
232 exit (1);
233 }
234
235 void
read_mts_profile()236 read_mts_profile ()
237 {
238 char *name;
239 const char *p;
240 char *hostname = NULL;
241 int rc;
242
243 name = getenv ("MTSTAILOR");
244 if (name)
245 mts_profile = mh_read_property_file (name, 1);
246 else
247 {
248 mu_property_t local_profile;
249
250 name = mh_expand_name (MHLIBDIR, "mtstailor", NAME_ANY);
251 mts_profile = mh_read_property_file (name, 1);
252
253 name = mu_tilde_expansion ("~/.mtstailor", MU_HIERARCHY_DELIMITER, NULL);
254 local_profile = mh_read_property_file (name, 1);
255
256 mh_property_merge (mts_profile, local_profile);
257 mu_property_destroy (&local_profile);
258 }
259
260 rc = mu_property_aget_value (mts_profile, "localname", &hostname);
261 if (rc == MU_ERR_NOENT)
262 {
263 rc = mu_get_host_name (&hostname);
264 if (rc)
265 {
266 mu_error (_("cannot get system host name: %s"), mu_strerror (rc));
267 exit (1);
268 }
269 }
270 else if (rc)
271 {
272 mu_diag_funcall (MU_DIAG_ERROR, "mu_profile_aget_value", "localname", rc);
273 exit (1);
274 }
275
276 rc = mu_property_sget_value (mts_profile, "localdomain", &p);
277 if (rc == 0)
278 {
279 hostname = mu_realloc (hostname, strlen (hostname) + 1 + strlen (p) + 1);
280 strcat (hostname, ".");
281 strcat (hostname, p);
282 }
283 else if (rc != MU_ERR_NOENT)
284 {
285 mu_diag_funcall (MU_DIAG_ERROR, "mu_profile_sget_value",
286 "localdomain", rc);
287 exit (1);
288 }
289
290 rc = mu_set_user_email_domain (hostname);
291 free (hostname);
292 if (rc)
293 {
294 mu_error (_("cannot set user mail domain: %s"), mu_strerror (rc));
295 exit (1);
296 }
297
298 rc = mu_property_sget_value (mts_profile, "username", &p);
299 if (rc == 0)
300 {
301 size_t len;
302 const char *domain;
303 char *newemail;
304 int rc;
305
306 rc = mu_get_user_email_domain (&domain);
307 if (rc)
308 {
309 mu_error (_("cannot get user email: %s"), mu_strerror (rc));
310 exit (1);
311 }
312 len = strlen (p) + 1 + strlen (domain) + 1;
313 newemail = mu_alloc (len);
314 strcpy (newemail, p);
315 strcat (newemail, "@");
316 strcat (newemail, domain);
317
318 rc = mu_set_user_email (newemail);
319 if (rc)
320 {
321 mu_error (_("cannot set user email (%s): %s"),
322 newemail, mu_strerror (rc));
323 exit (1);
324 }
325
326 free (newemail);
327 }
328 else if (rc != MU_ERR_NOENT)
329 {
330 mu_diag_funcall (MU_DIAG_ERROR, "mu_profile_sget_value",
331 "username", rc);
332 exit (1);
333 }
334 }
335
336
337 mu_mailer_t
open_mailer()338 open_mailer ()
339 {
340 const char *url = mu_mhprop_get_value (mts_profile,
341 "url",
342 "sendmail:/usr/sbin/sendmail");
343 mu_mailer_t mailer;
344 int status;
345
346 WATCH ((_("Creating mailer %s"), url));
347 status = mu_mailer_create (&mailer, url);
348 if (status)
349 {
350 mu_error (_("cannot create mailer `%s'"), url);
351 return NULL;
352 }
353
354 if (verbose)
355 {
356 mu_debug_set_category_level (MU_DEBCAT_MAILER,
357 MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
358 }
359
360 WATCH ((_("Opening mailer %s"), url));
361 status = mu_mailer_open (mailer, MU_STREAM_RDWR);
362 if (status)
363 {
364 mu_error (_("cannot open mailer `%s': %s"), url, mu_strerror (status));
365 return NULL;
366 }
367 return mailer;
368 }
369
370 static void
create_message_id(mu_header_t hdr)371 create_message_id (mu_header_t hdr)
372 {
373 char *p = mh_create_message_id (0);
374 mu_header_set_value (hdr, MU_HEADER_MESSAGE_ID, p, 1);
375 free (p);
376 }
377
378 static const char *
get_sender_personal()379 get_sender_personal ()
380 {
381 const char *s = mh_global_profile_get ("signature", getenv ("SIGNATURE"));
382 if (!s)
383 {
384 struct passwd *pw = getpwuid (getuid ());
385 if (pw && pw->pw_gecos[0])
386 {
387 char *p = strchr (pw->pw_gecos, ',');
388 if (p)
389 *p = 0;
390 s = pw->pw_gecos;
391 }
392 }
393 return s;
394 }
395
396 static void
set_address_header(mu_header_t hdr,char * name,mu_address_t addr)397 set_address_header (mu_header_t hdr, char *name, mu_address_t addr)
398 {
399 const char *value;
400 if (mu_address_sget_printable (addr, &value) == 0)
401 mu_header_set_value (hdr, name, value, 1);
402 /* FIXME: Error reporting */
403 }
404
405 void
expand_aliases(mu_message_t msg)406 expand_aliases (mu_message_t msg)
407 {
408 mu_header_t hdr;
409 mu_address_t addr_to = NULL,
410 addr_cc = NULL,
411 addr_bcc = NULL;
412
413 mh_expand_aliases (msg, &addr_to, &addr_cc, &addr_bcc);
414
415 mu_message_get_header (msg, &hdr);
416 if (addr_to)
417 {
418 set_address_header (hdr, MU_HEADER_TO, addr_to);
419 mu_address_destroy (&addr_to);
420 }
421
422 if (addr_cc)
423 {
424 set_address_header (hdr, MU_HEADER_CC, addr_cc);
425 mu_address_destroy (&addr_cc);
426 }
427
428 if (addr_bcc)
429 {
430 set_address_header (hdr, MU_HEADER_BCC, addr_bcc);
431 mu_address_destroy (&addr_bcc);
432 }
433 }
434
435 void
fix_fcc(mu_message_t msg)436 fix_fcc (mu_message_t msg)
437 {
438 mu_header_t hdr;
439 char *fcc;
440
441 mu_message_get_header (msg, &hdr);
442 if (mu_header_aget_value (hdr, MU_HEADER_FCC, &fcc) == 0)
443 {
444 struct mu_wordsplit ws;
445 int need_fixup = 0;
446 size_t fixup_len = 0;
447
448 ws.ws_delim = ",";
449 if (mu_wordsplit (fcc, &ws,
450 MU_WRDSF_DEFFLAGS | MU_WRDSF_DELIM | MU_WRDSF_WS))
451 {
452 mu_error (_("cannot split line `%s': %s"), fcc,
453 mu_wordsplit_strerror (&ws));
454 }
455 else
456 {
457 size_t i;
458
459 for (i = 0; i < ws.ws_wordc; i += 2)
460 {
461 if (strchr ("+%~/=", ws.ws_wordv[i][0]) == NULL)
462 {
463 need_fixup++;
464 fixup_len ++;
465 }
466 fixup_len += strlen (ws.ws_wordv[i]);
467 }
468
469 if (need_fixup)
470 {
471 char *p;
472
473 /* the new fcc string contains: folder names - fixup_len
474 characters, ws.ws_wordc - 1 comma-space pairs and a
475 terminating nul */
476 fcc = realloc (fcc, fixup_len + ws.ws_wordc - 1 + 1);
477 for (i = 0, p = fcc; i < ws.ws_wordc; i++)
478 {
479 if (strchr ("+%~/=", ws.ws_wordv[i][0]) == NULL)
480 *p++ = '+';
481 strcpy (p, ws.ws_wordv[i]);
482 p += strlen (p);
483 *p++ = ',';
484 *p++ = ' ';
485 }
486 *p = 0;
487 }
488 }
489
490 mu_wordsplit_free (&ws);
491
492 if (need_fixup)
493 {
494 mu_header_set_value (hdr, MU_HEADER_FCC, fcc, 1);
495 WATCH ((_("Fixed fcc: %s"), fcc));
496 }
497 free (fcc);
498 }
499 }
500
501 /* Convert MH-style DCC headers to normal BCC.
502 FIXME: Normally we should iterate through the headers to catch
503 multiple Dcc occurrences (the same holds true for Fcc as well),
504 however at the time of this writing we have mu_header_get_field_value,
505 but we miss mu_header_set_field_value. */
506 void
fix_dcc(mu_message_t msg)507 fix_dcc (mu_message_t msg)
508 {
509 mu_header_t hdr;
510 char *dcc;
511
512 mu_message_get_header (msg, &hdr);
513 if (mu_header_aget_value (hdr, MU_HEADER_DCC, &dcc) == 0)
514 {
515 char *bcc = NULL;
516
517 mu_header_set_value (hdr, MU_HEADER_DCC, NULL, 1);
518 mu_header_aget_value (hdr, MU_HEADER_BCC, &bcc);
519 if (bcc)
520 {
521 char *newbcc = realloc (bcc, strlen (bcc) + 1 + strlen (dcc) + 1);
522 if (!newbcc)
523 {
524 mu_error (_("not enough memory"));
525 free (dcc);
526 free (bcc);
527 return;
528 }
529 bcc = newbcc;
530 strcat (bcc, ",");
531 strcat (bcc, dcc);
532 free (dcc);
533 }
534 else
535 bcc = dcc;
536
537 WATCH ((_("Fixed bcc: %s"), bcc));
538 mu_header_set_value (hdr, MU_HEADER_BCC, bcc, 1);
539 free (bcc);
540 }
541 }
542
543 void
backup_file(const char * file_name)544 backup_file (const char *file_name)
545 {
546 char *new_name = mu_alloc (strlen (file_name) + 2);
547 char *p = strrchr (file_name, '/');
548 if (p)
549 {
550 size_t len = p - file_name + 1;
551 memcpy (new_name, file_name, len);
552 new_name[len++] = ',';
553 strcpy (new_name + len, p + 1);
554 }
555 else
556 {
557 new_name[0] = ',';
558 strcpy (new_name + 1, file_name);
559 }
560 WATCH ((_("Renaming %s to %s"), file_name, new_name));
561
562 if (unlink (new_name) && errno != ENOENT)
563 mu_diag_funcall (MU_DIAG_ERROR, "unlink", new_name, errno);
564 else
565 {
566 int rc = mu_rename_file (file_name, new_name, MU_COPY_OVERWRITE);
567 if (rc)
568 mu_error (_("cannot rename %s to %s: %s"),
569 file_name, new_name, mu_strerror (errno));
570 }
571 free (new_name);
572 }
573
574 int
_action_send(void * item,void * data)575 _action_send (void *item, void *data)
576 {
577 struct list_elt *elt = item;
578 mu_message_t msg = elt->msg;
579 int rc;
580 mu_mailer_t mailer;
581 mu_header_t hdr;
582 size_t n;
583
584 WATCH ((_("Getting message %s"), elt->file_name));
585
586 if (mu_message_get_header (msg, &hdr) == 0)
587 {
588 char date[80];
589 time_t t = time (NULL);
590 struct tm *tm = localtime (&t);
591
592 mu_strftime (date, sizeof date, "%a, %d %b %Y %H:%M:%S %z", tm);
593 mu_header_set_value (hdr, MU_HEADER_DATE, date, 1);
594
595 if (mu_header_get_value (hdr, MU_HEADER_FROM, NULL, 0, &n))
596 {
597 char *from;
598 char *email = mu_get_user_email (NULL);
599 const char *pers = get_sender_personal ();
600 if (pers)
601 {
602 mu_asprintf (&from, "\"%s\" <%s>", pers, email);
603 free (email);
604 }
605 else
606 from = email;
607
608 mu_header_set_value (hdr, MU_HEADER_FROM, from, 1);
609 free (from);
610 }
611
612 if (append_msgid
613 && mu_header_get_value (hdr, MU_HEADER_MESSAGE_ID, NULL, 0, &n))
614 create_message_id (hdr);
615
616 if (mu_header_get_value (hdr, MU_HEADER_USER_AGENT, NULL, 0, &n))
617 {
618 const char *p = mu_mhprop_get_value (mts_profile,
619 "user-agent",
620 mu_mhprop_get_value (mts_profile,
621 "x-mailer",
622 "yes"));
623
624 if (!strcmp (p, "yes"))
625 mu_header_set_value (hdr, MU_HEADER_USER_AGENT,
626 DEFAULT_USER_AGENT, 0);
627 else if (strcmp (p, "no"))
628 mu_header_remove (hdr, MU_HEADER_USER_AGENT, 1);
629 }
630 }
631
632 expand_aliases (msg);
633 fix_fcc (msg);
634 fix_dcc (msg);
635
636 mailer = open_mailer ();
637 if (!mailer)
638 return MU_ERR_FAILURE;
639
640 WATCH ((_("Sending message %s"), elt->file_name));
641 if (split_message)
642 {
643 struct timeval delay;
644 delay.tv_sec = split_interval;
645 delay.tv_usec = 0;
646 rc = mu_mailer_send_fragments (mailer, msg,
647 split_size, &delay,
648 NULL, NULL);
649 }
650 else
651 rc = mu_mailer_send_message (mailer, msg, NULL, NULL);
652 if (rc)
653 {
654 mu_error(_("cannot send message: %s"), mu_strerror (rc));
655 return MU_ERR_FAILURE;
656 }
657
658 WATCH ((_("Destroying the mailer")));
659 mu_mailer_close (mailer);
660 mu_mailer_destroy (&mailer);
661
662 if (!keep_files)
663 backup_file (elt->file_name);
664
665 return 0;
666 }
667
668 static int
_add_to_mesg_list(size_t num,mu_message_t msg,void * data)669 _add_to_mesg_list (size_t num, mu_message_t msg, void *data)
670 {
671 char const *path = data;
672 struct list_elt *elt;
673 size_t uid;
674 int rc;
675 char *file_name;
676
677 if (!mesg_list && mu_list_create (&mesg_list))
678 {
679 mu_error (_("cannot create message list"));
680 return 1;
681 }
682
683 mu_message_get_uid (msg, &uid);
684 file_name = mu_make_file_name (path, mu_umaxtostr (0, uid));
685 if (!use_draft)
686 {
687 if (!mh_usedraft (file_name))
688 exit (0);
689 }
690
691 elt = mu_alloc (sizeof *elt);
692 elt->msg = msg;
693 elt->file_name = file_name;
694 rc = mu_list_append (mesg_list, elt);
695 if (rc)
696 {
697 mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", NULL, rc);
698 exit (1);
699 }
700 return 0;
701 }
702
703 static void
addfolder(const char * folder,int argc,char ** argv)704 addfolder (const char *folder, int argc, char **argv)
705 {
706 mu_url_t url;
707 const char *path;
708 mu_msgset_t msgset;
709
710 mu_mailbox_t mbox = mh_open_folder (folder, MU_STREAM_READ);
711 if (!mbox)
712 {
713 mu_error (_("cannot open folder %s: %s"), folder,
714 mu_strerror (errno));
715 exit (1);
716 }
717
718 mh_msgset_parse (&msgset, mbox, argc, argv, "cur");
719 if (!use_draft)
720 {
721 size_t count = 0;
722 mu_msgset_count (msgset, &count);
723 if (count > 1)
724 use_draft = 1;
725 }
726
727 mu_mailbox_get_url (mbox, &url);
728 mu_url_sget_path (url, &path);
729 mu_msgset_foreach_message (msgset, _add_to_mesg_list, (void*)path);
730
731 mu_msgset_free (msgset);
732 }
733
734 /* Usage cases:
735 *
736 * 1. send
737 * a) If Draft-Folder is set: ask whether to use "cur" message from that
738 * folder as a draft;
739 * b) If Draft-Folder is not set: ask whether to use $(Path)/draft;
740 * 2. send -draft
741 * Use $(Path)/draft
742 * 3. send MSG
743 * Use $(Path)/MSG
744 * 4. send -draftmessage MSG
745 * Same as (3)
746 * 5. send -draftfolder DIR
747 * Use "cur" from that folder
748 * 6. send -draftfolder DIR MSG
749 * Use MSG from folder DIR
750 * 7. send -draftfolder DIR -draftmessage MSG
751 * Same as 6.
752 */
753
754 int
main(int argc,char ** argv)755 main (int argc, char **argv)
756 {
757 mu_mailbox_t mbox = NULL;
758 char *p;
759 int rc;
760
761 mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL);
762
763 mh_read_aliases ();
764 /* Process the mtstailor file */
765 read_mts_profile ();
766
767 if (!draftfolder)
768 {
769 if (mu_list_is_empty (mesg_list) && argc == 0)
770 {
771 char *dfolder =
772 (!use_draft && use_draftfolder)
773 ? (char*) mh_global_profile_get ("Draft-Folder", NULL)
774 : NULL;
775
776 if (dfolder)
777 addfolder (dfolder, 0, NULL);
778 else
779 {
780 char *df = mh_expand_name (mu_folder_directory (), "draft",
781 NAME_ANY);
782 if (checkdraft (df))
783 exit (1);
784 if (!use_draft && !mh_usedraft (df))
785 exit (0);
786 add_file (df);
787 mesg_list_fixup ();
788 }
789 }
790 else
791 {
792 while (argc--)
793 add_file (*argv++);
794 mesg_list_fixup ();
795 }
796 }
797 else
798 {
799 /* -draftfolder is supplied */
800 draftfolder = mh_expand_name (mu_folder_directory (),
801 draftfolder, NAME_ANY);
802 use_draft = 1;
803 mesg_list_fixup ();
804 if (mu_list_is_empty (mesg_list) || argc != 0)
805 addfolder (draftfolder, argc, argv);
806 }
807
808 /* Detach from the console if required */
809 if (background && (rc = mu_daemon ()) != 0)
810 {
811 mu_error (_("cannot switch to background: %s"), mu_strerror (rc));
812 return 1;
813 }
814
815 /* Prepend url specifier to the folder dir. We won't need this
816 when the default format becomes configurable */
817 mu_asprintf (&p, "mh:%s", mu_folder_directory ());
818 mu_set_folder_directory (p);
819 free (p);
820
821 /* Finally, do the work */
822 rc = mu_list_foreach (mesg_list, _action_send, NULL);
823
824 mu_mailbox_destroy (&mbox);
825 return !!rc;
826 }
827
828