NeoMutt  2023-03-22
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 <unistd.h>
39#include "mutt/lib.h"
40#include "address/lib.h"
41#include "config/lib.h"
42#include "email/lib.h"
43#include "core/lib.h"
44#include "mutt.h"
45#include "sendlib.h"
46#include "lib.h"
47#include "attach/lib.h"
48#include "convert/lib.h"
49#include "ncrypt/lib.h"
50#include "copy.h"
51#include "globals.h" // IWYU pragma: keep
52#include "handler.h"
53#include "mutt_mailbox.h"
54#include "muttlib.h"
55#include "mx.h"
56
69enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
70{
71 FILE *fp = NULL;
72 char *p = NULL, *q = NULL, *ct = NULL;
73 char buf[PATH_MAX] = { 0 };
74 char subtype[256] = { 0 };
75 char xtype[256] = { 0 };
76 int sze, cur_sze = 0;
77 bool found_mimetypes = false;
79
80 int szf = mutt_str_len(path);
81
82 for (int count = 0; count < 4; count++)
83 {
84 /* can't use strtok() because we use it in an inner loop below, so use
85 * a switch statement here instead. */
86 switch (count)
87 {
88 /* last file with last entry to match wins type/xtype */
89 case 0:
90 /* check default unix mimetypes location first */
91 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
92 break;
93 case 1:
94 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
95 break;
96 case 2:
97 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
98 break;
99 case 3:
100 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
101 break;
102 default:
103 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
104 goto bye; /* shouldn't happen */
105 }
106
107 fp = fopen(buf, "r");
108 if (fp)
109 {
110 found_mimetypes = true;
111
112 while (fgets(buf, sizeof(buf) - 1, fp))
113 {
114 /* weed out any comments */
115 p = strchr(buf, '#');
116 if (p)
117 *p = '\0';
118
119 /* remove any leading space. */
120 ct = buf;
121 SKIPWS(ct);
122
123 /* position on the next field in this line */
124 p = strpbrk(ct, " \t");
125 if (!p)
126 continue;
127 *p++ = 0;
128 SKIPWS(p);
129
130 /* cycle through the file extensions */
131 while ((p = strtok(p, " \t\n")))
132 {
133 sze = mutt_str_len(p);
134 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
135 ((szf == sze) || (path[szf - sze - 1] == '.')))
136 {
137 /* get the content-type */
138
139 p = strchr(ct, '/');
140 if (!p)
141 {
142 /* malformed line, just skip it. */
143 break;
144 }
145 *p++ = 0;
146
147 for (q = p; *q && !IS_SPACE(*q); q++)
148 ; // do nothing
149
150 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
151
153 if (type == TYPE_OTHER)
154 mutt_str_copy(xtype, ct, sizeof(xtype));
155
156 cur_sze = sze;
157 }
158 p = NULL;
159 }
160 }
161 mutt_file_fclose(&fp);
162 }
163 }
164
165bye:
166
167 /* no mime.types file found */
168 if (!found_mimetypes)
169 {
170 mutt_error(_("Could not find any mime.types file"));
171 }
172
173 if ((type != TYPE_OTHER) || (*xtype != '\0'))
174 {
175 att->type = type;
176 mutt_str_replace(&att->subtype, subtype);
177 mutt_str_replace(&att->xtype, xtype);
178 }
179
180 return type;
181}
182
189static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
190{
191 struct Buffer *buf = NULL;
192 struct State state = { 0 };
193 struct stat st = { 0 };
194
195 for (; a; a = a->next)
196 {
197 if (a->type == TYPE_MULTIPART)
198 {
199 a->encoding = ENC_7BIT;
200 transform_to_7bit(a->parts, fp_in, sub);
201 }
202 else if (mutt_is_message_type(a->type, a->subtype))
203 {
204 mutt_message_to_7bit(a, fp_in, sub);
205 }
206 else
207 {
208 a->noconv = true;
209 a->force_charset = true;
210
211 /* Because of the potential recursion in message types, we
212 * restrict the lifetime of the buffer tightly */
213 buf = mutt_buffer_pool_get();
215 state.fp_out = mutt_file_fopen(mutt_buffer_string(buf), "w");
216 if (!state.fp_out)
217 {
218 mutt_perror("fopen");
220 return;
221 }
222 state.fp_in = fp_in;
223 mutt_decode_attachment(a, &state);
224 mutt_file_fclose(&state.fp_out);
225 FREE(&a->d_filename);
226 a->d_filename = a->filename;
229 a->unlink = true;
230 if (stat(a->filename, &st) == -1)
231 {
232 mutt_perror("stat");
233 return;
234 }
235 a->length = st.st_size;
236
237 mutt_update_encoding(a, sub);
238 if (a->encoding == ENC_8BIT)
240 else if (a->encoding == ENC_BINARY)
241 a->encoding = ENC_BASE64;
242 }
243 }
244}
245
252void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
253{
254 struct Buffer temp = mutt_buffer_make(0);
255 FILE *fp_in = NULL;
256 FILE *fp_out = NULL;
257 struct stat st = { 0 };
258
259 if (!a->filename && fp)
260 fp_in = fp;
261 else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
262 {
263 mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
264 return;
265 }
266 else
267 {
268 a->offset = 0;
269 if (stat(a->filename, &st) == -1)
270 {
271 mutt_perror("stat");
272 mutt_file_fclose(&fp_in);
273 goto cleanup;
274 }
275 a->length = st.st_size;
276 }
277
278 /* Avoid buffer pool due to recursion */
279 mutt_buffer_mktemp(&temp);
280 fp_out = mutt_file_fopen(mutt_buffer_string(&temp), "w+");
281 if (!fp_out)
282 {
283 mutt_perror("fopen");
284 goto cleanup;
285 }
286
287 if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
288 {
289 goto cleanup;
290 }
291 a->parts = mutt_rfc822_parse_message(fp_in, a);
292
293 transform_to_7bit(a->parts, fp_in, sub);
294
295 mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
296 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
297
298 fputs("MIME-Version: 1.0\n", fp_out);
299 mutt_write_mime_header(a->parts, fp_out, sub);
300 fputc('\n', fp_out);
301 mutt_write_mime_body(a->parts, fp_out, sub);
302
303 if (fp_in != fp)
304 mutt_file_fclose(&fp_in);
305 mutt_file_fclose(&fp_out);
306
307 a->encoding = ENC_7BIT;
308 FREE(&a->d_filename);
309 a->d_filename = a->filename;
310 if (a->filename && a->unlink)
311 unlink(a->filename);
312 a->filename = mutt_buffer_strdup(&temp);
313 a->unlink = true;
314 if (stat(a->filename, &st) == -1)
315 {
316 mutt_perror("stat");
317 goto cleanup;
318 }
319 a->length = st.st_size;
321 a->email->body = NULL;
322
323cleanup:
324 if (fp_in && (fp_in != fp))
325 mutt_file_fclose(&fp_in);
326
327 if (fp_out)
328 {
329 mutt_file_fclose(&fp_out);
331 }
332
333 mutt_buffer_dealloc(&temp);
334}
335
342static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
343{
344 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
345 if (b->type == TYPE_TEXT)
346 {
347 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
348 char send_charset[128] = { 0 };
349 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
350 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
351 (info->linemax > 990) || (info->from && c_encode_from))
352 {
354 }
355 else if (info->hibin)
356 {
357 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
358 }
359 else
360 {
361 b->encoding = ENC_7BIT;
362 }
363 }
364 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
365 {
366 if (info->lobin || info->hibin)
367 {
368 if (c_allow_8bit && !info->lobin)
369 b->encoding = ENC_8BIT;
370 else
371 mutt_message_to_7bit(b, NULL, sub);
372 }
373 else
374 b->encoding = ENC_7BIT;
375 }
376 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
377 {
378 b->encoding = ENC_7BIT;
379 }
380 else
381 {
382 /* Determine which encoding is smaller */
383 if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
384 3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
385 {
386 b->encoding = ENC_BASE64;
387 }
388 else
389 {
391 }
392 }
393}
394
400{
401 a->stamp = mutt_date_now();
402}
403
411void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
412{
413 struct Content *info = NULL;
414 char chsbuf[256] = { 0 };
415
416 /* override noconv when it's us-ascii */
417 if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
418 a->noconv = false;
419
420 if (!a->force_charset && !a->noconv)
421 mutt_param_delete(&a->parameter, "charset");
422
423 info = mutt_get_content_info(a->filename, a, sub);
424 if (!info)
425 return;
426
427 set_encoding(a, info, sub);
429
430 FREE(&a->content);
431 a->content = info;
432}
433
443struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
444 bool attach_msg, struct ConfigSubset *sub)
445{
446 struct Body *body = NULL;
447 FILE *fp = NULL;
448 CopyMessageFlags cmflags;
450
451 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
452 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
453 if (WithCrypto)
454 {
455 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
456 {
458 return NULL;
459 }
460 }
461
462 struct Buffer *buf = mutt_buffer_pool_get();
464 fp = mutt_file_fopen(mutt_buffer_string(buf), "w+");
465 if (!fp)
466 {
468 return NULL;
469 }
470
471 body = mutt_body_new();
472 body->type = TYPE_MESSAGE;
473 body->subtype = mutt_str_dup("rfc822");
475 body->unlink = true;
476 body->use_disp = false;
477 body->disposition = DISP_INLINE;
478 body->noconv = true;
479
481
482 struct Message *msg = mx_msg_open(m, e->msgno);
483 if (!msg)
484 {
485 mutt_body_free(&body);
487 return NULL;
488 }
490
491 CopyHeaderFlags chflags = CH_XMIT;
492 cmflags = MUTT_CM_NO_FLAGS;
493
494 /* If we are attaching a message, ignore `$mime_forward_decode` */
495 if (!attach_msg && c_mime_forward_decode)
496 {
497 chflags |= CH_MIME | CH_TXTPLAIN;
500 pgp &= ~PGP_ENCRYPT;
502 pgp &= ~SMIME_ENCRYPT;
503 }
504 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
505 {
507 {
508 chflags |= CH_MIME | CH_NONEWLINE;
509 cmflags = MUTT_CM_DECODE_PGP;
510 pgp &= ~PGP_ENCRYPT;
511 }
512 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
514 {
515 chflags |= CH_MIME | CH_TXTPLAIN;
517 pgp &= ~PGP_ENCRYPT;
518 }
519 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
521 {
522 chflags |= CH_MIME | CH_TXTPLAIN;
524 pgp &= ~SMIME_ENCRYPT;
525 }
526 }
527
528 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
529 mx_msg_close(m, &msg);
530
531 fflush(fp);
532 rewind(fp);
533
534 body->email = email_new();
535 body->email->offset = 0;
536 /* we don't need the user headers here */
537 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
538 if (WithCrypto)
539 body->email->security = pgp;
540 mutt_update_encoding(body, sub);
541 body->parts = body->email->body;
542
544
545 return body;
546}
547
555static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
556{
557 FILE *fp = NULL, *fp_err = NULL;
558 char *buf = NULL;
559 size_t buflen;
560 pid_t pid;
561 struct Buffer *cmd = mutt_buffer_pool_get();
562
563 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
564
565 mutt_buffer_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
566
567 pid = filter_create(mutt_buffer_string(cmd), NULL, &fp, &fp_err);
568 if (pid < 0)
569 {
570 mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
572 return;
573 }
575
576 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
577 if (buf)
578 {
579 if (strchr(buf, '/'))
580 mutt_parse_content_type(buf, att);
581 FREE(&buf);
582 }
583
584 mutt_file_fclose(&fp);
585 mutt_file_fclose(&fp_err);
586 filter_wait(pid);
587}
588
596struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
597{
598 if (!path || (path[0] == '\0'))
599 return NULL;
600
601 struct Body *att = mutt_body_new();
602 att->filename = mutt_str_dup(path);
603
604 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
605 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
606
607 if (c_mime_type_query_command && c_mime_type_query_first)
608 run_mime_type_query(att, sub);
609
610 /* Attempt to determine the appropriate content-type based on the filename
611 * suffix. */
612 if (!att->subtype)
613 mutt_lookup_mime_type(att, path);
614
615 if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
616 {
617 run_mime_type_query(att, sub);
618 }
619
620 struct Content *info = mutt_get_content_info(path, att, sub);
621 if (!info)
622 {
623 mutt_body_free(&att);
624 return NULL;
625 }
626
627 if (!att->subtype)
628 {
629 if ((info->nulbin == 0) &&
630 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
631 {
632 /* Statistically speaking, there should be more than 10% "lobin"
633 * chars if this is really a binary file... */
634 att->type = TYPE_TEXT;
635 att->subtype = mutt_str_dup("plain");
636 }
637 else
638 {
639 att->type = TYPE_APPLICATION;
640 att->subtype = mutt_str_dup("octet-stream");
641 }
642 }
643
644 FREE(&info);
645 mutt_update_encoding(att, sub);
646 return att;
647}
648
656static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
657{
658 char *tmp = NULL;
659 char *p = NULL;
660 int i;
661
662 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
663
664 struct ListNode *np = NULL;
665 STAILQ_FOREACH(np, h, entries)
666 {
667 p = strchr(np->data, ':');
668 if (!p)
669 continue;
670
671 i = p - np->data;
672 p = mutt_str_skip_email_wsp(p + 1);
673 tmp = mutt_str_dup(p);
674
675 if (!tmp)
676 continue;
677
678 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
679 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
680
681 sprintf(np->data + i + 2, "%s", tmp);
682
683 FREE(&tmp);
684 }
685}
686
696const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
697{
698 const char *const c_hostname = cs_subset_string(sub, "hostname");
699 if (!c_hostname || (c_hostname[0] == '@'))
700 return NULL;
701
702 const char *p = c_hostname;
703
704 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
705 if (may_hide_host && c_hidden_host)
706 {
707 p = strchr(c_hostname, '.');
708 if (p)
709 p++;
710
711 // sanity check: don't hide the host if the fqdn is something like example.com
712 if (!p || !strchr(p, '.'))
713 p = c_hostname;
714 }
715
716 return p;
717}
718
742static char *gen_msgid(void)
743{
744 const int ID_LEFT_LEN = 50;
745 const int ID_RIGHT_LEN = 12;
746 char rnd_id_left[ID_LEFT_LEN + 1];
747 char rnd_id_right[ID_RIGHT_LEN + 1];
748 char buf[128] = { 0 };
749
750 mutt_rand_base32(rnd_id_left, sizeof(rnd_id_left) - 1);
751 mutt_rand_base32(rnd_id_right, sizeof(rnd_id_right) - 1);
752 rnd_id_left[ID_LEFT_LEN] = 0;
753 rnd_id_right[ID_RIGHT_LEN] = 0;
754
755 snprintf(buf, sizeof(buf), "<%s@%s>", rnd_id_left, rnd_id_right);
756 return mutt_str_dup(buf);
757}
758
769void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
770{
771 if (final)
772 {
773 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
774 {
775 /* some MTA's will put an Apparently-To: header field showing the Bcc:
776 * recipients if there is no To: or Cc: field, so attempt to suppress
777 * it by using an empty To: field. */
778 struct Address *to = mutt_addr_new();
779 to->group = true;
780 mutt_addrlist_append(&env->to, to);
782
783 char buf[1024] = { 0 };
784 buf[0] = '\0';
785 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
786
787 to->mailbox = mutt_str_dup(buf);
788 }
789
790 mutt_set_followup_to(env, sub);
791
792 if (!env->message_id)
793 env->message_id = gen_msgid();
794 }
795
796 /* Take care of 8-bit => 7-bit conversion. */
798 encode_headers(&env->userhdrs, sub);
799}
800
809{
810 struct ListNode *item = NULL;
811 STAILQ_FOREACH(item, &env->userhdrs, entries)
812 {
813 rfc2047_decode(&item->data);
814 }
815
817
818 /* back conversions */
820}
821
834static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
835 struct AddressList *to, const char *resent_from,
836 struct AddressList *env_from, struct ConfigSubset *sub)
837{
838 if (!e)
839 return -1;
840
841 int rc = 0;
842
843 struct Buffer *tempfile = mutt_buffer_pool_get();
844 mutt_buffer_mktemp(tempfile);
845 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
846 if (fp_tmp)
847 {
849
850 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
851 if (!c_bounce_delivered)
852 chflags |= CH_WEED_DELIVERED;
853
854 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
855 {
856 (void) mutt_file_fclose(&fp_tmp);
857 return -1;
858 }
859 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
860
861 struct Buffer *date = mutt_buffer_pool_get();
862 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
863 fprintf(fp_tmp, "Resent-Date: %s\n", mutt_buffer_string(date));
865
866 char *msgid_str = gen_msgid();
867 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
868 FREE(&msgid_str);
869 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
870 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
871 fputc('\n', fp_tmp);
872 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
873 if (mutt_file_fclose(&fp_tmp) != 0)
874 {
876 unlink(mutt_buffer_string(tempfile));
877 return -1;
878 }
879#ifdef USE_SMTP
880 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
881 if (c_smtp_url)
882 {
883 rc = mutt_smtp_send(env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
884 (e->body->encoding == ENC_8BIT), sub);
885 }
886 else
887#endif
888 {
889 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, mutt_buffer_string(tempfile),
890 (e->body->encoding == ENC_8BIT), sub);
891 }
892 }
893
894 mutt_buffer_pool_release(&tempfile);
895 return rc;
896}
897
908int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
909 struct AddressList *to, struct ConfigSubset *sub)
910{
911 if (!fp || !e || !to || TAILQ_EMPTY(to))
912 return -1;
913
914 const char *fqdn = mutt_fqdn(true, sub);
915 char *err = NULL;
916
917 struct Address *from = mutt_default_from(sub);
918 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
919 mutt_addrlist_append(&from_list, from);
920
921 /* mutt_default_from() does not use $real_name if the real name is not set
922 * in $from, so we add it here. The reason it is not added in
923 * mutt_default_from() is that during normal sending, we execute
924 * send-hooks and set the real_name last so that it can be changed based
925 * upon message criteria. */
926 if (!from->personal)
927 {
928 const char *const c_real_name = cs_subset_string(sub, "real_name");
929 from->personal = mutt_str_dup(c_real_name);
930 }
931
932 mutt_addrlist_qualify(&from_list, fqdn);
933
934 rfc2047_encode_addrlist(&from_list, "Resent-From");
935 if (mutt_addrlist_to_intl(&from_list, &err))
936 {
937 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
938 FREE(&err);
939 mutt_addrlist_clear(&from_list);
940 return -1;
941 }
942 struct Buffer *resent_from = mutt_buffer_pool_get();
943 mutt_addrlist_write(&from_list, resent_from, false);
944
945#ifdef USE_NNTP
946 OptNewsSend = false;
947#endif
948
949 /* prepare recipient list. idna conversion appears to happen before this
950 * function is called, since the user receives confirmation of the address
951 * list being bounced to. */
952 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
953 mutt_addrlist_copy(&resent_to, to, false);
954 rfc2047_encode_addrlist(&resent_to, "Resent-To");
955 int rc = bounce_message(fp, m, e, &resent_to, mutt_buffer_string(resent_from),
956 &from_list, sub);
957 mutt_addrlist_clear(&resent_to);
958 mutt_addrlist_clear(&from_list);
959 mutt_buffer_pool_release(&resent_from);
960 return rc;
961}
962
968static void set_noconv_flags(struct Body *b, bool flag)
969{
970 for (; b; b = b->next)
971 {
972 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
973 set_noconv_flags(b->parts, flag);
974 else if ((b->type == TYPE_TEXT) && b->noconv)
975 {
976 if (flag)
977 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
978 else
979 mutt_param_delete(&b->parameter, "x-mutt-noconv");
980 }
981 }
982}
983
996int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
997 char *fcc, char **finalpath, struct ConfigSubset *sub)
998{
999 char fcc_tok[PATH_MAX] = { 0 };
1000 char fcc_expanded[PATH_MAX] = { 0 };
1001
1002 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1003
1004 char *tok = strtok(fcc_tok, ",");
1005 if (!tok)
1006 return -1;
1007
1008 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1009 /* mutt_expand_path already called above for the first token */
1010 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1011 if (status != 0)
1012 return status;
1013
1014 while ((tok = strtok(NULL, ",")))
1015 {
1016 if (*tok == '\0')
1017 continue;
1018
1019 /* Only call mutt_expand_path if tok has some data */
1020 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1021 mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1022 mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1023 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1024 status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1025 if (status != 0)
1026 return status;
1027 }
1028
1029 return 0;
1030}
1031
1044int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1045 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1046{
1047 struct Message *msg = NULL;
1048 struct Buffer *tempfile = NULL;
1049 FILE *fp_tmp = NULL;
1050 int rc = -1;
1051 bool need_mailbox_cleanup = false;
1052 struct stat st = { 0 };
1053 MsgOpenFlags onm_flags;
1054
1055 if (post)
1056 set_noconv_flags(e->body, true);
1057
1058#ifdef RECORD_FOLDER_HOOK
1059 mutt_folder_hook(path, NULL);
1060#endif
1061 struct Mailbox *m_fcc = mx_path_resolve(path);
1062 bool old_append = m_fcc->append;
1063 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1064 {
1065 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1066 goto done;
1067 }
1068
1069 /* We need to add a Content-Length field to avoid problems where a line in
1070 * the message body begins with "From " */
1071 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1072 {
1073 tempfile = mutt_buffer_pool_get();
1074 mutt_buffer_mktemp(tempfile);
1075 fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1076 if (!fp_tmp)
1077 {
1079 mx_mbox_close(m_fcc);
1080 goto done;
1081 }
1082 /* remember new mail status before appending message */
1083 need_mailbox_cleanup = true;
1084 stat(path, &st);
1085 }
1086
1087 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1088 onm_flags = MUTT_ADD_FROM;
1089 if (post)
1090 onm_flags |= MUTT_SET_DRAFT;
1091 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1092 if (!msg)
1093 {
1094 mutt_file_fclose(&fp_tmp);
1095 mx_mbox_close(m_fcc);
1096 goto done;
1097 }
1098
1099 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1100
1101 /* post == 1 => postpone message.
1102 * post == 0 => Normal mode. */
1103 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1105 c_crypt_protected_headers_read &&
1107 sub);
1108
1109 /* (postponement) if this was a reply of some sort, <msgid> contains the
1110 * Message-ID: of message replied to. Save it using a special X-Mutt-
1111 * header so it can be picked up if the message is recalled at a later
1112 * point in time. This will allow the message to be marked as replied if
1113 * the same mailbox is still open. */
1114 if (post && msgid)
1115 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1116
1117 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1118 * it can be picked up when the message is recalled */
1119 if (post && fcc)
1120 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1121
1122 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1123 fprintf(msg->fp, "Status: RO\n");
1124
1125 /* (postponement) if the mail is to be signed or encrypted, save this info */
1126 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1127 {
1128 fputs("Mutt-PGP: ", msg->fp);
1129 if (e->security & SEC_ENCRYPT)
1130 fputc('E', msg->fp);
1131 if (e->security & SEC_OPPENCRYPT)
1132 fputc('O', msg->fp);
1133 if (e->security & SEC_SIGN)
1134 {
1135 fputc('S', msg->fp);
1136
1137 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1138 if (c_pgp_sign_as)
1139 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1140 }
1141 if (e->security & SEC_INLINE)
1142 fputc('I', msg->fp);
1143#ifdef USE_AUTOCRYPT
1144 if (e->security & SEC_AUTOCRYPT)
1145 fputc('A', msg->fp);
1147 fputc('Z', msg->fp);
1148#endif
1149 fputc('\n', msg->fp);
1150 }
1151
1152 /* (postponement) if the mail is to be signed or encrypted, save this info */
1153 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1154 {
1155 fputs("Mutt-SMIME: ", msg->fp);
1156 if (e->security & SEC_ENCRYPT)
1157 {
1158 fputc('E', msg->fp);
1159
1160 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1161 if (c_smime_encrypt_with)
1162 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1163 }
1164 if (e->security & SEC_OPPENCRYPT)
1165 fputc('O', msg->fp);
1166 if (e->security & SEC_SIGN)
1167 {
1168 fputc('S', msg->fp);
1169
1170 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1171 if (c_smime_sign_as)
1172 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1173 }
1174 if (e->security & SEC_INLINE)
1175 fputc('I', msg->fp);
1176 fputc('\n', msg->fp);
1177 }
1178
1179#ifdef MIXMASTER
1180 /* (postponement) if the mail is to be sent through a mixmaster
1181 * chain, save that information */
1182
1183 if (post && !STAILQ_EMPTY(&e->chain))
1184 {
1185 fputs("Mutt-Mix:", msg->fp);
1186 struct ListNode *p = NULL;
1187 STAILQ_FOREACH(p, &e->chain, entries)
1188 {
1189 fprintf(msg->fp, " %s", (char *) p->data);
1190 }
1191
1192 fputc('\n', msg->fp);
1193 }
1194#endif
1195
1196 if (fp_tmp)
1197 {
1198 mutt_write_mime_body(e->body, fp_tmp, sub);
1199
1200 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1201 * will happen, and it can cause problems parsing the mailbox later. */
1202 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1203 mutt_file_seek(fp_tmp, 0, SEEK_END))
1204 {
1205 fputc('\n', fp_tmp);
1206 }
1207
1208 fflush(fp_tmp);
1209 if (ferror(fp_tmp))
1210 {
1211 mutt_debug(LL_DEBUG1, "%s: write failed\n", mutt_buffer_string(tempfile));
1212 mutt_file_fclose(&fp_tmp);
1213 unlink(mutt_buffer_string(tempfile));
1214 mx_msg_commit(m_fcc, msg); /* XXX really? */
1215 mx_msg_close(m_fcc, &msg);
1216 mx_mbox_close(m_fcc);
1217 goto done;
1218 }
1219
1220 /* count the number of lines */
1221 int lines = 0;
1222 char line_buf[1024] = { 0 };
1223 rewind(fp_tmp);
1224 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1225 lines++;
1226 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1227 fprintf(msg->fp, "Lines: %d\n\n", lines);
1228
1229 /* copy the body and clean up */
1230 rewind(fp_tmp);
1231 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1232 if (mutt_file_fclose(&fp_tmp) != 0)
1233 rc = -1;
1234 /* if there was an error, leave the temp version */
1235 if (rc >= 0)
1236 {
1237 unlink(mutt_buffer_string(tempfile));
1238 rc = 0;
1239 }
1240 }
1241 else
1242 {
1243 fputc('\n', msg->fp); /* finish off the header */
1244 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1245 }
1246
1247 if (mx_msg_commit(m_fcc, msg) != 0)
1248 rc = -1;
1249 else if (finalpath)
1250 *finalpath = mutt_str_dup(msg->committed_path);
1251 mx_msg_close(m_fcc, &msg);
1252 mx_mbox_close(m_fcc);
1253
1254 if (!post && need_mailbox_cleanup)
1255 mutt_mailbox_cleanup(path, &st);
1256
1257 if (post)
1258 set_noconv_flags(e->body, false);
1259
1260done:
1261 m_fcc->append = old_append;
1262 mailbox_free(&m_fcc);
1263
1264#ifdef RECORD_FOLDER_HOOK
1265 /* We ran a folder hook for the destination mailbox,
1266 * now we run it for the user's current mailbox */
1267 const struct Mailbox *m_cur = get_current_mailbox();
1268 if (m_cur)
1269 mutt_folder_hook(m_cur->path, m_cur->desc);
1270#endif
1271
1272 if (fp_tmp)
1273 {
1274 mutt_file_fclose(&fp_tmp);
1275 unlink(mutt_buffer_string(tempfile));
1276 }
1277 mutt_buffer_pool_release(&tempfile);
1278
1279 return rc;
1280}
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:1435
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:1455
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1184
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, const char *header)
Wrapper for mutt_write_address()
Definition: address.c:1226
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1270
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:590
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:347
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:485
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
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: globals.c:38
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:415
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:105
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:868
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:542
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
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:1076
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:437
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:380
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
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:259
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:736
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
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:229
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:706
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:193
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:1504
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:39
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
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:79
#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 *state)
Decode an email's attachment.
Definition: handler.c:1871
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:571
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:748
@ 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:587
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:41
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:1192
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1146
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1056
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1171
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1676
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:614
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
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:1462
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1337
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:399
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:69
static char * gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:742
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:968
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:696
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:908
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:596
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:996
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:252
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:808
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:656
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:342
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:769
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:443
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:189
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:1044
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:411
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:834
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:555
Miscellaneous functions for sending an email.
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:295
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:1092
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:89
int msgno
Number displayed to the user.
Definition: email.h:110
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