NeoMutt  2022-04-29-247-gc6aae8
Teaching an old dog new tricks
DOXYGEN
sendlib.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <inttypes.h> // IWYU pragma: keep
33#include <limits.h>
34#include <stdbool.h>
35#include <stdio.h>
36#include <string.h>
37#include <sys/stat.h>
38#include <time.h>
39#include <unistd.h>
40#include "mutt/lib.h"
41#include "address/lib.h"
42#include "config/lib.h"
43#include "email/lib.h"
44#include "core/lib.h"
45#include "mutt.h"
46#include "sendlib.h"
47#include "lib.h"
48#include "attach/lib.h"
49#include "convert/lib.h"
50#include "ncrypt/lib.h"
51#include "copy.h"
52#include "handler.h"
53#include "mutt_globals.h"
54#include "mutt_mailbox.h"
55#include "muttlib.h"
56#include "mx.h"
57#include "options.h"
58
71enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
72{
73 FILE *fp = NULL;
74 char *p = NULL, *q = NULL, *ct = NULL;
75 char buf[PATH_MAX] = { 0 };
76 char subtype[256] = { 0 };
77 char xtype[256] = { 0 };
78 int sze, cur_sze = 0;
79 bool found_mimetypes = false;
81
82 int szf = mutt_str_len(path);
83
84 for (int count = 0; count < 4; count++)
85 {
86 /* can't use strtok() because we use it in an inner loop below, so use
87 * a switch statement here instead. */
88 switch (count)
89 {
90 /* last file with last entry to match wins type/xtype */
91 case 0:
92 /* check default unix mimetypes location first */
93 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
94 break;
95 case 1:
96 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
97 break;
98 case 2:
99 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
100 break;
101 case 3:
102 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
103 break;
104 default:
105 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
106 goto bye; /* shouldn't happen */
107 }
108
109 fp = fopen(buf, "r");
110 if (fp)
111 {
112 found_mimetypes = true;
113
114 while (fgets(buf, sizeof(buf) - 1, fp))
115 {
116 /* weed out any comments */
117 p = strchr(buf, '#');
118 if (p)
119 *p = '\0';
120
121 /* remove any leading space. */
122 ct = buf;
123 SKIPWS(ct);
124
125 /* position on the next field in this line */
126 p = strpbrk(ct, " \t");
127 if (!p)
128 continue;
129 *p++ = 0;
130 SKIPWS(p);
131
132 /* cycle through the file extensions */
133 while ((p = strtok(p, " \t\n")))
134 {
135 sze = mutt_str_len(p);
136 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
137 ((szf == sze) || (path[szf - sze - 1] == '.')))
138 {
139 /* get the content-type */
140
141 p = strchr(ct, '/');
142 if (!p)
143 {
144 /* malformed line, just skip it. */
145 break;
146 }
147 *p++ = 0;
148
149 for (q = p; *q && !IS_SPACE(*q); q++)
150 ; // do nothing
151
152 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
153
155 if (type == TYPE_OTHER)
156 mutt_str_copy(xtype, ct, sizeof(xtype));
157
158 cur_sze = sze;
159 }
160 p = NULL;
161 }
162 }
163 mutt_file_fclose(&fp);
164 }
165 }
166
167bye:
168
169 /* no mime.types file found */
170 if (!found_mimetypes)
171 {
172 mutt_error(_("Could not find any mime.types file"));
173 }
174
175 if ((type != TYPE_OTHER) || (*xtype != '\0'))
176 {
177 att->type = type;
178 mutt_str_replace(&att->subtype, subtype);
179 mutt_str_replace(&att->xtype, xtype);
180 }
181
182 return type;
183}
184
191static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
192{
193 struct Buffer *buf = NULL;
194 struct State s = { 0 };
195 struct stat st = { 0 };
196
197 for (; a; a = a->next)
198 {
199 if (a->type == TYPE_MULTIPART)
200 {
201 a->encoding = ENC_7BIT;
202 transform_to_7bit(a->parts, fp_in, sub);
203 }
204 else if (mutt_is_message_type(a->type, a->subtype))
205 {
206 mutt_message_to_7bit(a, fp_in, sub);
207 }
208 else
209 {
210 a->noconv = true;
211 a->force_charset = true;
212
213 /* Because of the potential recursion in message types, we
214 * restrict the lifetime of the buffer tightly */
215 buf = mutt_buffer_pool_get();
218 if (!s.fp_out)
219 {
220 mutt_perror("fopen");
222 return;
223 }
224 s.fp_in = fp_in;
227 FREE(&a->d_filename);
228 a->d_filename = a->filename;
231 a->unlink = true;
232 if (stat(a->filename, &st) == -1)
233 {
234 mutt_perror("stat");
235 return;
236 }
237 a->length = st.st_size;
238
239 mutt_update_encoding(a, sub);
240 if (a->encoding == ENC_8BIT)
242 else if (a->encoding == ENC_BINARY)
243 a->encoding = ENC_BASE64;
244 }
245 }
246}
247
254void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
255{
256 struct Buffer temp = mutt_buffer_make(0);
257 FILE *fp_in = NULL;
258 FILE *fp_out = NULL;
259 struct stat st = { 0 };
260
261 if (!a->filename && fp)
262 fp_in = fp;
263 else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
264 {
265 mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
266 return;
267 }
268 else
269 {
270 a->offset = 0;
271 if (stat(a->filename, &st) == -1)
272 {
273 mutt_perror("stat");
274 mutt_file_fclose(&fp_in);
275 goto cleanup;
276 }
277 a->length = st.st_size;
278 }
279
280 /* Avoid buffer pool due to recursion */
281 mutt_buffer_mktemp(&temp);
282 fp_out = mutt_file_fopen(mutt_buffer_string(&temp), "w+");
283 if (!fp_out)
284 {
285 mutt_perror("fopen");
286 goto cleanup;
287 }
288
289 if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
290 {
291 goto cleanup;
292 }
293 a->parts = mutt_rfc822_parse_message(fp_in, a);
294
295 transform_to_7bit(a->parts, fp_in, sub);
296
297 mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
298 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
299
300 fputs("MIME-Version: 1.0\n", fp_out);
301 mutt_write_mime_header(a->parts, fp_out, sub);
302 fputc('\n', fp_out);
303 mutt_write_mime_body(a->parts, fp_out, sub);
304
305 if (fp_in != fp)
306 mutt_file_fclose(&fp_in);
307 mutt_file_fclose(&fp_out);
308
309 a->encoding = ENC_7BIT;
310 FREE(&a->d_filename);
311 a->d_filename = a->filename;
312 if (a->filename && a->unlink)
313 unlink(a->filename);
314 a->filename = mutt_buffer_strdup(&temp);
315 a->unlink = true;
316 if (stat(a->filename, &st) == -1)
317 {
318 mutt_perror("stat");
319 goto cleanup;
320 }
321 a->length = st.st_size;
323 a->email->body = NULL;
324
325cleanup:
326 if (fp_in && (fp_in != fp))
327 mutt_file_fclose(&fp_in);
328
329 if (fp_out)
330 {
331 mutt_file_fclose(&fp_out);
333 }
334
335 mutt_buffer_dealloc(&temp);
336}
337
344static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
345{
346 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
347 if (b->type == TYPE_TEXT)
348 {
349 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
350 char send_charset[128] = { 0 };
351 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
352 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
353 (info->linemax > 990) || (info->from && c_encode_from))
354 {
356 }
357 else if (info->hibin)
358 {
359 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
360 }
361 else
362 {
363 b->encoding = ENC_7BIT;
364 }
365 }
366 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
367 {
368 if (info->lobin || info->hibin)
369 {
370 if (c_allow_8bit && !info->lobin)
371 b->encoding = ENC_8BIT;
372 else
373 mutt_message_to_7bit(b, NULL, sub);
374 }
375 else
376 b->encoding = ENC_7BIT;
377 }
378 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
379 {
380 b->encoding = ENC_7BIT;
381 }
382 else
383 {
384 /* Determine which encoding is smaller */
385 if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
386 3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
387 {
388 b->encoding = ENC_BASE64;
389 }
390 else
391 {
393 }
394 }
395}
396
402{
403 a->stamp = mutt_date_epoch();
404}
405
413void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
414{
415 struct Content *info = NULL;
416 char chsbuf[256] = { 0 };
417
418 /* override noconv when it's us-ascii */
419 if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
420 a->noconv = false;
421
422 if (!a->force_charset && !a->noconv)
423 mutt_param_delete(&a->parameter, "charset");
424
425 info = mutt_get_content_info(a->filename, a, sub);
426 if (!info)
427 return;
428
429 set_encoding(a, info, sub);
431
432 FREE(&a->content);
433 a->content = info;
434}
435
445struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
446 bool attach_msg, struct ConfigSubset *sub)
447{
448 struct Body *body = NULL;
449 FILE *fp = NULL;
450 CopyMessageFlags cmflags;
452
453 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
454 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
455 if (WithCrypto)
456 {
457 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
458 {
460 return NULL;
461 }
462 }
463
464 struct Buffer *buf = mutt_buffer_pool_get();
466 fp = mutt_file_fopen(mutt_buffer_string(buf), "w+");
467 if (!fp)
468 {
470 return NULL;
471 }
472
473 body = mutt_body_new();
474 body->type = TYPE_MESSAGE;
475 body->subtype = mutt_str_dup("rfc822");
477 body->unlink = true;
478 body->use_disp = false;
479 body->disposition = DISP_INLINE;
480 body->noconv = true;
481
483
484 struct Message *msg = mx_msg_open(m, e->msgno);
485 if (!msg)
486 {
487 mutt_body_free(&body);
489 return NULL;
490 }
492
493 CopyHeaderFlags chflags = CH_XMIT;
494 cmflags = MUTT_CM_NO_FLAGS;
495
496 /* If we are attaching a message, ignore `$mime_forward_decode` */
497 if (!attach_msg && c_mime_forward_decode)
498 {
499 chflags |= CH_MIME | CH_TXTPLAIN;
502 pgp &= ~PGP_ENCRYPT;
504 pgp &= ~SMIME_ENCRYPT;
505 }
506 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
507 {
509 {
510 chflags |= CH_MIME | CH_NONEWLINE;
511 cmflags = MUTT_CM_DECODE_PGP;
512 pgp &= ~PGP_ENCRYPT;
513 }
514 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
516 {
517 chflags |= CH_MIME | CH_TXTPLAIN;
519 pgp &= ~PGP_ENCRYPT;
520 }
521 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
523 {
524 chflags |= CH_MIME | CH_TXTPLAIN;
526 pgp &= ~SMIME_ENCRYPT;
527 }
528 }
529
530 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
531 mx_msg_close(m, &msg);
532
533 fflush(fp);
534 rewind(fp);
535
536 body->email = email_new();
537 body->email->offset = 0;
538 /* we don't need the user headers here */
539 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
540 if (WithCrypto)
541 body->email->security = pgp;
542 mutt_update_encoding(body, sub);
543 body->parts = body->email->body;
544
546
547 return body;
548}
549
557static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
558{
559 FILE *fp = NULL, *fp_err = NULL;
560 char *buf = NULL;
561 size_t buflen;
562 pid_t pid;
563 struct Buffer *cmd = mutt_buffer_pool_get();
564
565 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
566
567 mutt_buffer_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
568
569 pid = filter_create(mutt_buffer_string(cmd), NULL, &fp, &fp_err);
570 if (pid < 0)
571 {
572 mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
574 return;
575 }
577
578 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
579 if (buf)
580 {
581 if (strchr(buf, '/'))
582 mutt_parse_content_type(buf, att);
583 FREE(&buf);
584 }
585
586 mutt_file_fclose(&fp);
587 mutt_file_fclose(&fp_err);
588 filter_wait(pid);
589}
590
598struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
599{
600 if (!path || (path[0] == '\0'))
601 return NULL;
602
603 struct Body *att = mutt_body_new();
604 att->filename = mutt_str_dup(path);
605
606 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
607 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
608
609 if (c_mime_type_query_command && c_mime_type_query_first)
610 run_mime_type_query(att, sub);
611
612 /* Attempt to determine the appropriate content-type based on the filename
613 * suffix. */
614 if (!att->subtype)
615 mutt_lookup_mime_type(att, path);
616
617 if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
618 {
619 run_mime_type_query(att, sub);
620 }
621
622 struct Content *info = mutt_get_content_info(path, att, sub);
623 if (!info)
624 {
625 mutt_body_free(&att);
626 return NULL;
627 }
628
629 if (!att->subtype)
630 {
631 if ((info->nulbin == 0) &&
632 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
633 {
634 /* Statistically speaking, there should be more than 10% "lobin"
635 * chars if this is really a binary file... */
636 att->type = TYPE_TEXT;
637 att->subtype = mutt_str_dup("plain");
638 }
639 else
640 {
641 att->type = TYPE_APPLICATION;
642 att->subtype = mutt_str_dup("octet-stream");
643 }
644 }
645
646 FREE(&info);
647 mutt_update_encoding(att, sub);
648 return att;
649}
650
658static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
659{
660 char *tmp = NULL;
661 char *p = NULL;
662 int i;
663
664 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
665
666 struct ListNode *np = NULL;
667 STAILQ_FOREACH(np, h, entries)
668 {
669 p = strchr(np->data, ':');
670 if (!p)
671 continue;
672
673 i = p - np->data;
674 p = mutt_str_skip_email_wsp(p + 1);
675 tmp = mutt_str_dup(p);
676
677 if (!tmp)
678 continue;
679
680 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
681 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
682
683 sprintf(np->data + i + 2, "%s", tmp);
684
685 FREE(&tmp);
686 }
687}
688
698const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
699{
700 const char *const c_hostname = cs_subset_string(sub, "hostname");
701 if (!c_hostname || (c_hostname[0] == '@'))
702 return NULL;
703
704 const char *p = c_hostname;
705
706 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
707 if (may_hide_host && c_hidden_host)
708 {
709 p = strchr(c_hostname, '.');
710 if (p)
711 p++;
712
713 // sanity check: don't hide the host if the fqdn is something like example.com
714 if (!p || !strchr(p, '.'))
715 p = c_hostname;
716 }
717
718 return p;
719}
720
727static char *gen_msgid(struct ConfigSubset *sub)
728{
729 char buf[128] = { 0 };
730 char rndid[MUTT_RANDTAG_LEN + 1];
731
732 mutt_rand_base32(rndid, sizeof(rndid) - 1);
733 rndid[MUTT_RANDTAG_LEN] = 0;
734 const char *fqdn = mutt_fqdn(false, sub);
735 if (!fqdn)
736 fqdn = NONULL(ShortHostname);
737
738 struct tm tm = mutt_date_gmtime(MUTT_DATE_NOW);
739 snprintf(buf, sizeof(buf), "<%d%02d%02d%02d%02d%02d.%s@%s>", tm.tm_year + 1900,
740 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, rndid, fqdn);
741 return mutt_str_dup(buf);
742}
743
754void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
755{
756 if (final)
757 {
758 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
759 {
760 /* some MTA's will put an Apparently-To: header field showing the Bcc:
761 * recipients if there is no To: or Cc: field, so attempt to suppress
762 * it by using an empty To: field. */
763 struct Address *to = mutt_addr_new();
764 to->group = true;
765 mutt_addrlist_append(&env->to, to);
767
768 char buf[1024] = { 0 };
769 buf[0] = '\0';
770 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
771
772 to->mailbox = mutt_str_dup(buf);
773 }
774
775 mutt_set_followup_to(env, sub);
776
777 if (!env->message_id)
778 env->message_id = gen_msgid(sub);
779 }
780
781 /* Take care of 8-bit => 7-bit conversion. */
783 encode_headers(&env->userhdrs, sub);
784}
785
794{
795 struct ListNode *item = NULL;
796 STAILQ_FOREACH(item, &env->userhdrs, entries)
797 {
798 rfc2047_decode(&item->data);
799 }
800
802
803 /* back conversions */
805}
806
819static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
820 struct AddressList *to, const char *resent_from,
821 struct AddressList *env_from, struct ConfigSubset *sub)
822{
823 if (!e)
824 return -1;
825
826 int rc = 0;
827
828 struct Buffer *tempfile = mutt_buffer_pool_get();
829 mutt_buffer_mktemp(tempfile);
830 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
831 if (fp_tmp)
832 {
834
835 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
836 if (!c_bounce_delivered)
837 chflags |= CH_WEED_DELIVERED;
838
839 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
840 {
841 (void) mutt_file_fclose(&fp_tmp);
842 return -1;
843 }
844 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
845
846 struct Buffer *date = mutt_buffer_pool_get();
847 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
848 fprintf(fp_tmp, "Resent-Date: %s\n", mutt_buffer_string(date));
850
851 char *msgid_str = gen_msgid(sub);
852 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
853 FREE(&msgid_str);
854 fputs("Resent-To: ", fp_tmp);
855 mutt_addrlist_write_file(to, fp_tmp, 11, false);
856 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
857 fputc('\n', fp_tmp);
858 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
859 if (mutt_file_fclose(&fp_tmp) != 0)
860 {
862 unlink(mutt_buffer_string(tempfile));
863 return -1;
864 }
865#ifdef USE_SMTP
866 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
867 if (c_smtp_url)
868 {
869 rc = mutt_smtp_send(env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
870 (e->body->encoding == ENC_8BIT), sub);
871 }
872 else
873#endif
874 {
875 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
876 (e->body->encoding == ENC_8BIT), sub);
877 }
878 }
879
880 mutt_buffer_pool_release(&tempfile);
881 return rc;
882}
883
894int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
895 struct AddressList *to, struct ConfigSubset *sub)
896{
897 if (!fp || !e || !to || TAILQ_EMPTY(to))
898 return -1;
899
900 const char *fqdn = mutt_fqdn(true, sub);
901 char resent_from[256] = { 0 };
902 char *err = NULL;
903
904 resent_from[0] = '\0';
905 struct Address *from = mutt_default_from(sub);
906 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
907 mutt_addrlist_append(&from_list, from);
908
909 /* mutt_default_from() does not use $real_name if the real name is not set
910 * in $from, so we add it here. The reason it is not added in
911 * mutt_default_from() is that during normal sending, we execute
912 * send-hooks and set the real_name last so that it can be changed based
913 * upon message criteria. */
914 if (!from->personal)
915 {
916 const char *const c_real_name = cs_subset_string(sub, "real_name");
917 from->personal = mutt_str_dup(c_real_name);
918 }
919
920 mutt_addrlist_qualify(&from_list, fqdn);
921
922 rfc2047_encode_addrlist(&from_list, "Resent-From");
923 if (mutt_addrlist_to_intl(&from_list, &err))
924 {
925 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
926 FREE(&err);
927 mutt_addrlist_clear(&from_list);
928 return -1;
929 }
930 mutt_addrlist_write(&from_list, resent_from, sizeof(resent_from), false);
931
932#ifdef USE_NNTP
933 OptNewsSend = false;
934#endif
935
936 /* prepare recipient list. idna conversion appears to happen before this
937 * function is called, since the user receives confirmation of the address
938 * list being bounced to. */
939 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
940 mutt_addrlist_copy(&resent_to, to, false);
941 rfc2047_encode_addrlist(&resent_to, "Resent-To");
942 int rc = bounce_message(fp, m, e, &resent_to, resent_from, &from_list, sub);
943 mutt_addrlist_clear(&resent_to);
944 mutt_addrlist_clear(&from_list);
945
946 return rc;
947}
948
954static void set_noconv_flags(struct Body *b, bool flag)
955{
956 for (; b; b = b->next)
957 {
958 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
959 set_noconv_flags(b->parts, flag);
960 else if ((b->type == TYPE_TEXT) && b->noconv)
961 {
962 if (flag)
963 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
964 else
965 mutt_param_delete(&b->parameter, "x-mutt-noconv");
966 }
967 }
968}
969
982int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
983 char *fcc, char **finalpath, struct ConfigSubset *sub)
984{
985 char fcc_tok[PATH_MAX] = { 0 };
986 char fcc_expanded[PATH_MAX] = { 0 };
987
988 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
989
990 char *tok = strtok(fcc_tok, ",");
991 if (!tok)
992 return -1;
993
994 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
995 /* mutt_expand_path already called above for the first token */
996 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
997 if (status != 0)
998 return status;
999
1000 while ((tok = strtok(NULL, ",")))
1001 {
1002 if (*tok == '\0')
1003 continue;
1004
1005 /* Only call mutt_expand_path if tok has some data */
1006 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1007 mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1008 mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1009 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1010 status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1011 if (status != 0)
1012 return status;
1013 }
1014
1015 return 0;
1016}
1017
1030int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1031 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1032{
1033 struct Message *msg = NULL;
1034 struct Buffer *tempfile = NULL;
1035 FILE *fp_tmp = NULL;
1036 int rc = -1;
1037 bool need_mailbox_cleanup = false;
1038 struct stat st = { 0 };
1039 MsgOpenFlags onm_flags;
1040
1041 if (post)
1042 set_noconv_flags(e->body, true);
1043
1044#ifdef RECORD_FOLDER_HOOK
1045 mutt_folder_hook(path, NULL);
1046#endif
1047 struct Mailbox *m_fcc = mx_path_resolve(path);
1048 bool old_append = m_fcc->append;
1049 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1050 {
1051 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1052 goto done;
1053 }
1054
1055 /* We need to add a Content-Length field to avoid problems where a line in
1056 * the message body begins with "From " */
1057 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1058 {
1059 tempfile = mutt_buffer_pool_get();
1060 mutt_buffer_mktemp(tempfile);
1061 fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1062 if (!fp_tmp)
1063 {
1065 mx_mbox_close(m_fcc);
1066 goto done;
1067 }
1068 /* remember new mail status before appending message */
1069 need_mailbox_cleanup = true;
1070 stat(path, &st);
1071 }
1072
1073 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1074 onm_flags = MUTT_ADD_FROM;
1075 if (post)
1076 onm_flags |= MUTT_SET_DRAFT;
1077 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1078 if (!msg)
1079 {
1080 mutt_file_fclose(&fp_tmp);
1081 mx_mbox_close(m_fcc);
1082 goto done;
1083 }
1084
1085 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1086
1087 /* post == 1 => postpone message.
1088 * post == 0 => Normal mode. */
1089 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1091 c_crypt_protected_headers_read &&
1093 sub);
1094
1095 /* (postponement) if this was a reply of some sort, <msgid> contains the
1096 * Message-ID: of message replied to. Save it using a special X-Mutt-
1097 * header so it can be picked up if the message is recalled at a later
1098 * point in time. This will allow the message to be marked as replied if
1099 * the same mailbox is still open. */
1100 if (post && msgid)
1101 fprintf(msg->fp, "X-Mutt-References: %s\n", msgid);
1102
1103 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1104 * it can be picked up when the message is recalled */
1105 if (post && fcc)
1106 fprintf(msg->fp, "X-Mutt-Fcc: %s\n", fcc);
1107
1108 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1109 fprintf(msg->fp, "Status: RO\n");
1110
1111 /* (postponement) if the mail is to be signed or encrypted, save this info */
1112 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1113 {
1114 fputs("X-Mutt-PGP: ", msg->fp);
1115 if (e->security & SEC_ENCRYPT)
1116 fputc('E', msg->fp);
1117 if (e->security & SEC_OPPENCRYPT)
1118 fputc('O', msg->fp);
1119 if (e->security & SEC_SIGN)
1120 {
1121 fputc('S', msg->fp);
1122
1123 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1124 if (c_pgp_sign_as)
1125 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1126 }
1127 if (e->security & SEC_INLINE)
1128 fputc('I', msg->fp);
1129#ifdef USE_AUTOCRYPT
1130 if (e->security & SEC_AUTOCRYPT)
1131 fputc('A', msg->fp);
1133 fputc('Z', msg->fp);
1134#endif
1135 fputc('\n', msg->fp);
1136 }
1137
1138 /* (postponement) if the mail is to be signed or encrypted, save this info */
1139 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1140 {
1141 fputs("X-Mutt-SMIME: ", msg->fp);
1142 if (e->security & SEC_ENCRYPT)
1143 {
1144 fputc('E', msg->fp);
1145
1146 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1147 if (c_smime_encrypt_with)
1148 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1149 }
1150 if (e->security & SEC_OPPENCRYPT)
1151 fputc('O', msg->fp);
1152 if (e->security & SEC_SIGN)
1153 {
1154 fputc('S', msg->fp);
1155
1156 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1157 if (c_smime_sign_as)
1158 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1159 }
1160 if (e->security & SEC_INLINE)
1161 fputc('I', msg->fp);
1162 fputc('\n', msg->fp);
1163 }
1164
1165#ifdef MIXMASTER
1166 /* (postponement) if the mail is to be sent through a mixmaster
1167 * chain, save that information */
1168
1169 if (post && !STAILQ_EMPTY(&e->chain))
1170 {
1171 fputs("X-Mutt-Mix:", msg->fp);
1172 struct ListNode *p = NULL;
1173 STAILQ_FOREACH(p, &e->chain, entries)
1174 {
1175 fprintf(msg->fp, " %s", (char *) p->data);
1176 }
1177
1178 fputc('\n', msg->fp);
1179 }
1180#endif
1181
1182 if (fp_tmp)
1183 {
1184 mutt_write_mime_body(e->body, fp_tmp, sub);
1185
1186 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1187 * will happen, and it can cause problems parsing the mailbox later. */
1188 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1189 mutt_file_seek(fp_tmp, 0, SEEK_END))
1190 {
1191 fputc('\n', fp_tmp);
1192 }
1193
1194 fflush(fp_tmp);
1195 if (ferror(fp_tmp))
1196 {
1197 mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_buffer_string(tempfile));
1198 mutt_file_fclose(&fp_tmp);
1199 unlink(mutt_buffer_string(tempfile));
1200 mx_msg_commit(m_fcc, msg); /* XXX really? */
1201 mx_msg_close(m_fcc, &msg);
1202 mx_mbox_close(m_fcc);
1203 goto done;
1204 }
1205
1206 /* count the number of lines */
1207 int lines = 0;
1208 char line_buf[1024] = { 0 };
1209 rewind(fp_tmp);
1210 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1211 lines++;
1212 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1213 fprintf(msg->fp, "Lines: %d\n\n", lines);
1214
1215 /* copy the body and clean up */
1216 rewind(fp_tmp);
1217 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1218 if (mutt_file_fclose(&fp_tmp) != 0)
1219 rc = -1;
1220 /* if there was an error, leave the temp version */
1221 if (rc >= 0)
1222 {
1223 unlink(mutt_buffer_string(tempfile));
1224 rc = 0;
1225 }
1226 }
1227 else
1228 {
1229 fputc('\n', msg->fp); /* finish off the header */
1230 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1231 }
1232
1233 if (mx_msg_commit(m_fcc, msg) != 0)
1234 rc = -1;
1235 else if (finalpath)
1236 *finalpath = mutt_str_dup(msg->committed_path);
1237 mx_msg_close(m_fcc, &msg);
1238 mx_mbox_close(m_fcc);
1239
1240 if (!post && need_mailbox_cleanup)
1241 mutt_mailbox_cleanup(path, &st);
1242
1243 if (post)
1244 set_noconv_flags(e->body, false);
1245
1246done:
1247 m_fcc->append = old_append;
1248 mailbox_free(&m_fcc);
1249
1250#ifdef RECORD_FOLDER_HOOK
1251 /* We ran a folder hook for the destination mailbox,
1252 * now we run it for the user's current mailbox */
1253 const struct Mailbox *m_cur = get_current_mailbox();
1254 if (m_cur)
1255 mutt_folder_hook(m_cur->path, m_cur->desc);
1256#endif
1257
1258 if (fp_tmp)
1259 {
1260 mutt_file_fclose(&fp_tmp);
1261 unlink(mutt_buffer_string(tempfile));
1262 }
1263 mutt_buffer_pool_release(&tempfile);
1264
1265 return rc;
1266}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:42
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, int start_col, bool display)
Wrapper for mutt_write_address()
Definition: address.c:1231
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
Email Address Handling.
GUI display the mailboxes in a side panel.
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: mutt_globals.h:49
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
Definition: content_info.c:180
Conversion between different character encodings.
int mutt_copy_header(FILE *fp_in, struct Email *e, FILE *fp_out, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy Email header.
Definition: copy.c:414
int mutt_copy_hdr(FILE *fp_in, FILE *fp_out, LOFF_T off_start, LOFF_T off_end, CopyHeaderFlags chflags, const char *prefix, int wraplen)
Copy header from one file to another.
Definition: copy.c:104
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
Duplicate the structure of an entire email.
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition: copy.h:65
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define CH_NOQFROM
Ignore ">From " line.
Definition: copy.h:67
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:34
Convenience wrapper for the core headers.
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:544
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:601
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1078
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:439
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:380
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:673
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
#define MUTT_DATE_NOW
Constant representing the 'current time', see: mutt_date_gmtime(), mutt_date_localtime()
Definition: date.h:39
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:131
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
Structs that make up an email.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:720
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:230
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
void mutt_buffer_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1488
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1867
Decide how to display email content.
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:572
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition: header.h:41
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition: header.h:42
void mutt_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition: hook.c:589
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:618
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:43
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BINARY
Binary.
Definition: mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:96
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:679
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition: string.c:431
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:652
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
Many unsorted constants and some structs.
#define PATH_MAX
Definition: mutt.h:40
Hundreds of global variables to back the user variables.
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:424
Mailbox helper functions.
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
Some miscellaneous functions.
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1193
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1147
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1057
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1172
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
API for mailboxes.
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:41
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:43
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:44
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:63
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
API for encryption/signing of emails.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define PGP_ENCRYPT
Definition: lib.h:96
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SMIME_ENCRYPT
Definition: lib.h:102
#define WithCrypto
Definition: lib.h:116
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:88
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
Handling of global boolean variables.
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:51
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:424
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:323
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1157
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1751
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1441
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:102
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:750
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:619
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:793
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:649
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:813
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1459
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1334
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:401
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:71
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:954
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:698
static char * gen_msgid(struct ConfigSubset *sub)
Generate a unique Message ID.
Definition: sendlib.c:727
int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:894
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:598
int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath, struct ConfigSubset *sub)
Handle FCC with multiple, comma separated entries.
Definition: sendlib.c:982
void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Convert an email's MIME parts to 7-bit.
Definition: sendlib.c:254
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:793
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:658
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:344
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:754
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:445
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:191
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1030
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:413
static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, const char *resent_from, struct AddressList *env_from, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:819
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:557
Miscellaneous functions for sending an email.
#define MUTT_RANDTAG_LEN
Definition: sendlib.h:35
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition: sendmail.c:292
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition: smtp.c:1086
Key value store.
#define NONULL(x)
Definition: string2.h:37
#define IS_SPACE(ch)
Definition: string2.h:38
#define SKIPWS(ch)
Definition: string2.h:46
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
char * xtype
content-type if x-unknown
Definition: body.h:61
bool noconv
Don't do character set conversion.
Definition: body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
time_t stamp
Time stamp of last encoding update.
Definition: body.h:76
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
struct Email * email
header information for message/rfc822
Definition: body.h:73
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:69
struct Body * next
next attachment in the list
Definition: body.h:71
bool force_charset
Send mode: don't adjust the character set when in send-mode.
Definition: body.h:44
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:34
A set of inherited config items.
Definition: subset.h:47
Info about an attachment.
Definition: content.h:35
long hibin
8-bit characters
Definition: content.h:36
long ascii
Number of ascii chars.
Definition: content.h:40
bool from
Has a line beginning with "From "?
Definition: content.h:44
long nulbin
Null characters (0x0)
Definition: content.h:38
long linemax
Length of the longest line in the file.
Definition: content.h:41
long lobin
Unprintable 7-bit chars (eg., control chars)
Definition: content.h:37
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
struct ListHead chain
Mixmaster chain.
Definition: email.h:90
int msgno
Number displayed to the user.
Definition: email.h:111
The header of an Email.
Definition: envelope.h:57
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
char * message_id
Message ID.
Definition: envelope.h:73
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
A mailbox.
Definition: mailbox.h:79
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
struct ConfigSubset * sub
Inherited config items.
Definition: mailbox.h:83
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
char * committed_path
the final path generated by mx_msg_commit()
Definition: mxapi.h:46
String list.
Definition: slist.h:47
Keep track when processing files.
Definition: state.h:46
FILE * fp_out
File to write to.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:47