NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
sendlib.c
Go to the documentation of this file.
1
31#include "config.h"
32#include <ctype.h>
33#include <inttypes.h> // IWYU pragma: keep
34#include <limits.h>
35#include <stdbool.h>
36#include <stdio.h>
37#include <string.h>
38#include <sys/stat.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 "attach/lib.h"
48#include "convert/lib.h"
49#include "ncrypt/lib.h"
50#include "body.h"
51#include "copy.h"
52#include "globals.h" // IWYU pragma: keep
53#include "handler.h"
54#include "header.h"
55#include "mutt_mailbox.h"
56#include "muttlib.h"
57#include "mx.h"
58#include "send.h"
59#include "sendmail.h"
60#include "smtp.h"
61
74enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
75{
76 FILE *fp = NULL;
77 char *p = NULL, *q = NULL, *ct = NULL;
78 char buf[PATH_MAX] = { 0 };
79 char subtype[256] = { 0 };
80 char xtype[256] = { 0 };
81 int sze, cur_sze = 0;
82 bool found_mimetypes = false;
84
85 int szf = mutt_str_len(path);
86
87 for (int count = 0; count < 4; count++)
88 {
89 /* can't use strtok() because we use it in an inner loop below, so use
90 * a switch statement here instead. */
91 switch (count)
92 {
93 /* last file with last entry to match wins type/xtype */
94 case 0:
95 /* check default unix mimetypes location first */
96 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
97 break;
98 case 1:
99 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
100 break;
101 case 2:
102 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
103 break;
104 case 3:
105 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
106 break;
107 default:
108 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
109 goto bye; /* shouldn't happen */
110 }
111
112 fp = fopen(buf, "r");
113 if (fp)
114 {
115 found_mimetypes = true;
116
117 while (fgets(buf, sizeof(buf) - 1, fp))
118 {
119 /* weed out any comments */
120 p = strchr(buf, '#');
121 if (p)
122 *p = '\0';
123
124 /* remove any leading space. */
125 ct = buf;
126 SKIPWS(ct);
127
128 /* position on the next field in this line */
129 p = strpbrk(ct, " \t");
130 if (!p)
131 continue;
132 *p++ = 0;
133 SKIPWS(p);
134
135 /* cycle through the file extensions */
136 while ((p = strtok(p, " \t\n")))
137 {
138 sze = mutt_str_len(p);
139 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
140 ((szf == sze) || (path[szf - sze - 1] == '.')))
141 {
142 /* get the content-type */
143
144 p = strchr(ct, '/');
145 if (!p)
146 {
147 /* malformed line, just skip it. */
148 break;
149 }
150 *p++ = 0;
151
152 for (q = p; *q && !isspace(*q); q++)
153 ; // do nothing
154
155 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
156
158 if (type == TYPE_OTHER)
159 mutt_str_copy(xtype, ct, sizeof(xtype));
160
161 cur_sze = sze;
162 }
163 p = NULL;
164 }
165 }
166 mutt_file_fclose(&fp);
167 }
168 }
169
170bye:
171
172 /* no mime.types file found */
173 if (!found_mimetypes)
174 {
175 mutt_error(_("Could not find any mime.types file"));
176 }
177
178 if ((type != TYPE_OTHER) || (*xtype != '\0'))
179 {
180 att->type = type;
181 mutt_str_replace(&att->subtype, subtype);
182 mutt_str_replace(&att->xtype, xtype);
183 }
184
185 return type;
186}
187
194static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
195{
196 struct Buffer *buf = NULL;
197 struct State state = { 0 };
198 struct stat st = { 0 };
199
200 for (; a; a = a->next)
201 {
202 if (a->type == TYPE_MULTIPART)
203 {
204 a->encoding = ENC_7BIT;
205 transform_to_7bit(a->parts, fp_in, sub);
206 }
207 else if (mutt_is_message_type(a->type, a->subtype))
208 {
209 mutt_message_to_7bit(a, fp_in, sub);
210 }
211 else
212 {
213 a->noconv = true;
214 a->force_charset = true;
215
216 /* Because of the potential recursion in message types, we
217 * restrict the lifetime of the buffer tightly */
218 buf = buf_pool_get();
219 buf_mktemp(buf);
220 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
221 if (!state.fp_out)
222 {
223 mutt_perror("fopen");
224 buf_pool_release(&buf);
225 return;
226 }
227 state.fp_in = fp_in;
228 mutt_decode_attachment(a, &state);
229 mutt_file_fclose(&state.fp_out);
230 FREE(&a->d_filename);
231 a->d_filename = a->filename;
232 a->filename = buf_strdup(buf);
233 buf_pool_release(&buf);
234 a->unlink = true;
235 if (stat(a->filename, &st) == -1)
236 {
237 mutt_perror("stat");
238 return;
239 }
240 a->length = st.st_size;
241
242 mutt_update_encoding(a, sub);
243 if (a->encoding == ENC_8BIT)
245 else if (a->encoding == ENC_BINARY)
246 a->encoding = ENC_BASE64;
247 }
248 }
249}
250
257void mutt_message_to_7bit(struct Body *a, FILE *fp, struct ConfigSubset *sub)
258{
259 struct Buffer temp = buf_make(0);
260 FILE *fp_in = NULL;
261 FILE *fp_out = NULL;
262 struct stat st = { 0 };
263
264 if (!a->filename && fp)
265 {
266 fp_in = fp;
267 }
268 else if (!a->filename || !(fp_in = fopen(a->filename, "r")))
269 {
270 mutt_error(_("Could not open %s"), a->filename ? a->filename : "(null)");
271 return;
272 }
273 else
274 {
275 a->offset = 0;
276 if (stat(a->filename, &st) == -1)
277 {
278 mutt_perror("stat");
279 mutt_file_fclose(&fp_in);
280 goto cleanup;
281 }
282 a->length = st.st_size;
283 }
284
285 /* Avoid buffer pool due to recursion */
286 buf_mktemp(&temp);
287 fp_out = mutt_file_fopen(buf_string(&temp), "w+");
288 if (!fp_out)
289 {
290 mutt_perror("fopen");
291 goto cleanup;
292 }
293
294 if (!mutt_file_seek(fp_in, a->offset, SEEK_SET))
295 {
296 goto cleanup;
297 }
298 a->parts = mutt_rfc822_parse_message(fp_in, a);
299
300 transform_to_7bit(a->parts, fp_in, sub);
301
302 mutt_copy_hdr(fp_in, fp_out, a->offset, a->offset + a->length,
303 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
304
305 fputs("MIME-Version: 1.0\n", fp_out);
306 mutt_write_mime_header(a->parts, fp_out, sub);
307 fputc('\n', fp_out);
308 mutt_write_mime_body(a->parts, fp_out, sub);
309
310 if (fp_in != fp)
311 mutt_file_fclose(&fp_in);
312 mutt_file_fclose(&fp_out);
313
314 a->encoding = ENC_7BIT;
315 FREE(&a->d_filename);
316 a->d_filename = a->filename;
317 if (a->filename && a->unlink)
318 unlink(a->filename);
319 a->filename = buf_strdup(&temp);
320 a->unlink = true;
321 if (stat(a->filename, &st) == -1)
322 {
323 mutt_perror("stat");
324 goto cleanup;
325 }
326 a->length = st.st_size;
328 a->email->body = NULL;
329
330cleanup:
331 if (fp_in && (fp_in != fp))
332 mutt_file_fclose(&fp_in);
333
334 if (fp_out)
335 {
336 mutt_file_fclose(&fp_out);
338 }
339
340 buf_dealloc(&temp);
341}
342
349static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
350{
351 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
352 if (b->type == TYPE_TEXT)
353 {
354 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
355 char send_charset[128] = { 0 };
356 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
357 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
358 (info->linemax > 990) || (info->from && c_encode_from))
359 {
361 }
362 else if (info->hibin)
363 {
364 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
365 }
366 else
367 {
368 b->encoding = ENC_7BIT;
369 }
370 }
371 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
372 {
373 if (info->lobin || info->hibin)
374 {
375 if (c_allow_8bit && !info->lobin)
376 b->encoding = ENC_8BIT;
377 else
378 mutt_message_to_7bit(b, NULL, sub);
379 }
380 else
381 {
382 b->encoding = ENC_7BIT;
383 }
384 }
385 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
386 {
387 b->encoding = ENC_7BIT;
388 }
389 else
390 {
391 /* Determine which encoding is smaller */
392 if (1.33 * (float) (info->lobin + info->hibin + info->ascii) <
393 3.0 * (float) (info->lobin + info->hibin) + (float) info->ascii)
394 {
395 b->encoding = ENC_BASE64;
396 }
397 else
398 {
400 }
401 }
402}
403
409{
410 a->stamp = mutt_date_now();
411}
412
420void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
421{
422 struct Content *info = NULL;
423 char chsbuf[256] = { 0 };
424
425 /* override noconv when it's us-ascii */
426 if (mutt_ch_is_us_ascii(mutt_body_get_charset(a, chsbuf, sizeof(chsbuf))))
427 a->noconv = false;
428
429 if (!a->force_charset && !a->noconv)
430 mutt_param_delete(&a->parameter, "charset");
431
432 info = mutt_get_content_info(a->filename, a, sub);
433 if (!info)
434 return;
435
436 set_encoding(a, info, sub);
438
439 FREE(&a->content);
440 a->content = info;
441}
442
452struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
453 bool attach_msg, struct ConfigSubset *sub)
454{
455 struct Body *body = NULL;
456 FILE *fp = NULL;
457 CopyMessageFlags cmflags;
459
460 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
461 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
462 if (WithCrypto)
463 {
464 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
465 {
467 return NULL;
468 }
469 }
470
471 struct Buffer *buf = buf_pool_get();
472 buf_mktemp(buf);
473 fp = mutt_file_fopen(buf_string(buf), "w+");
474 if (!fp)
475 {
476 buf_pool_release(&buf);
477 return NULL;
478 }
479
480 body = mutt_body_new();
481 body->type = TYPE_MESSAGE;
482 body->subtype = mutt_str_dup("rfc822");
483 body->filename = mutt_str_dup(buf_string(buf));
484 body->unlink = true;
485 body->use_disp = false;
486 body->disposition = DISP_INLINE;
487 body->noconv = true;
488
489 buf_pool_release(&buf);
490
491 struct Message *msg = mx_msg_open(m, e);
492 if (!msg)
493 {
494 mutt_body_free(&body);
496 return NULL;
497 }
499
500 CopyHeaderFlags chflags = CH_XMIT;
501 cmflags = MUTT_CM_NO_FLAGS;
502
503 /* If we are attaching a message, ignore `$mime_forward_decode` */
504 if (!attach_msg && c_mime_forward_decode)
505 {
506 chflags |= CH_MIME | CH_TXTPLAIN;
509 pgp &= ~PGP_ENCRYPT;
511 pgp &= ~SMIME_ENCRYPT;
512 }
513 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
514 {
516 {
517 chflags |= CH_MIME | CH_NONEWLINE;
518 cmflags = MUTT_CM_DECODE_PGP;
519 pgp &= ~PGP_ENCRYPT;
520 }
521 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
523 {
524 chflags |= CH_MIME | CH_TXTPLAIN;
526 pgp &= ~PGP_ENCRYPT;
527 }
528 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
530 {
531 chflags |= CH_MIME | CH_TXTPLAIN;
533 pgp &= ~SMIME_ENCRYPT;
534 }
535 }
536
537 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
538 mx_msg_close(m, &msg);
539
540 fflush(fp);
541 rewind(fp);
542
543 body->email = email_new();
544 body->email->offset = 0;
545 /* we don't need the user headers here */
546 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
547 if (WithCrypto)
548 body->email->security = pgp;
549 mutt_update_encoding(body, sub);
550 body->parts = body->email->body;
551
553
554 return body;
555}
556
564static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
565{
566 FILE *fp = NULL, *fp_err = NULL;
567 char *buf = NULL;
568 size_t buflen;
569 pid_t pid;
570 struct Buffer *cmd = buf_pool_get();
571
572 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
573
574 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, att->filename);
575
576 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, EnvList);
577 if (pid < 0)
578 {
579 mutt_error(_("Error running \"%s\""), buf_string(cmd));
580 buf_pool_release(&cmd);
581 return;
582 }
583 buf_pool_release(&cmd);
584
585 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
586 if (buf)
587 {
588 if (strchr(buf, '/'))
589 mutt_parse_content_type(buf, att);
590 FREE(&buf);
591 }
592
593 mutt_file_fclose(&fp);
594 mutt_file_fclose(&fp_err);
595 filter_wait(pid);
596}
597
605struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
606{
607 if (!path || (path[0] == '\0'))
608 return NULL;
609
610 struct Body *att = mutt_body_new();
611 att->filename = mutt_str_dup(path);
612
613 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
614 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
615
616 if (c_mime_type_query_command && c_mime_type_query_first)
617 run_mime_type_query(att, sub);
618
619 /* Attempt to determine the appropriate content-type based on the filename
620 * suffix. */
621 if (!att->subtype)
622 mutt_lookup_mime_type(att, path);
623
624 if (!att->subtype && c_mime_type_query_command && !c_mime_type_query_first)
625 {
626 run_mime_type_query(att, sub);
627 }
628
629 struct Content *info = mutt_get_content_info(path, att, sub);
630 if (!info)
631 {
632 mutt_body_free(&att);
633 return NULL;
634 }
635
636 if (!att->subtype)
637 {
638 if ((info->nulbin == 0) &&
639 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
640 {
641 /* Statistically speaking, there should be more than 10% "lobin"
642 * chars if this is really a binary file... */
643 att->type = TYPE_TEXT;
644 att->subtype = mutt_str_dup("plain");
645 }
646 else
647 {
648 att->type = TYPE_APPLICATION;
649 att->subtype = mutt_str_dup("octet-stream");
650 }
651 }
652
653 FREE(&info);
654 mutt_update_encoding(att, sub);
655 return att;
656}
657
665static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
666{
667 char *tmp = NULL;
668 char *p = NULL;
669 int i;
670
671 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
672
673 struct ListNode *np = NULL;
674 STAILQ_FOREACH(np, h, entries)
675 {
676 p = strchr(NONULL(np->data), ':');
677 if (!p)
678 continue;
679
680 i = p - np->data;
681 p = mutt_str_skip_email_wsp(p + 1);
682 tmp = mutt_str_dup(p);
683
684 if (!tmp)
685 continue;
686
687 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
688 mutt_mem_realloc(&np->data, i + 2 + mutt_str_len(tmp) + 1);
689
690 sprintf(np->data + i + 2, "%s", tmp);
691
692 FREE(&tmp);
693 }
694}
695
705const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
706{
707 const char *const c_hostname = cs_subset_string(sub, "hostname");
708 if (!c_hostname || (c_hostname[0] == '@'))
709 return NULL;
710
711 const char *p = c_hostname;
712
713 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
714 if (may_hide_host && c_hidden_host)
715 {
716 p = strchr(c_hostname, '.');
717 if (p)
718 p++;
719
720 // sanity check: don't hide the host if the fqdn is something like example.com
721 if (!p || !strchr(p, '.'))
722 p = c_hostname;
723 }
724
725 return p;
726}
727
751static char *gen_msgid(void)
752{
753 const int ID_LEFT_LEN = 50;
754 const int ID_RIGHT_LEN = 12;
755 char rnd_id_left[ID_LEFT_LEN + 1];
756 char rnd_id_right[ID_RIGHT_LEN + 1];
757 char buf[128] = { 0 };
758
759 mutt_rand_base32(rnd_id_left, sizeof(rnd_id_left) - 1);
760 mutt_rand_base32(rnd_id_right, sizeof(rnd_id_right) - 1);
761 rnd_id_left[ID_LEFT_LEN] = 0;
762 rnd_id_right[ID_RIGHT_LEN] = 0;
763
764 snprintf(buf, sizeof(buf), "<%s@%s>", rnd_id_left, rnd_id_right);
765 return mutt_str_dup(buf);
766}
767
778void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
779{
780 if (final)
781 {
782 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
783 {
784 /* some MTA's will put an Apparently-To: header field showing the Bcc:
785 * recipients if there is no To: or Cc: field, so attempt to suppress
786 * it by using an empty To: field. */
787 struct Address *to = mutt_addr_new();
788 to->group = true;
789 mutt_addrlist_append(&env->to, to);
791
792 char buf[1024] = { 0 };
793 buf[0] = '\0';
794 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
795
796 buf_strcpy(to->mailbox, buf);
797 }
798
799 mutt_set_followup_to(env, sub);
800
801 if (!env->message_id)
802 env->message_id = gen_msgid();
803 }
804
805 /* Take care of 8-bit => 7-bit conversion. */
807 encode_headers(&env->userhdrs, sub);
808}
809
818{
819 struct ListNode *item = NULL;
820 STAILQ_FOREACH(item, &env->userhdrs, entries)
821 {
822 rfc2047_decode(&item->data);
823 }
824
826
827 /* back conversions */
829}
830
843static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
844 struct AddressList *to, const char *resent_from,
845 struct AddressList *env_from, struct ConfigSubset *sub)
846{
847 if (!e)
848 return -1;
849
850 int rc = 0;
851
852 struct Buffer *tempfile = buf_pool_get();
853 buf_mktemp(tempfile);
854 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
855 if (fp_tmp)
856 {
858
859 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
860 if (!c_bounce_delivered)
861 chflags |= CH_WEED_DELIVERED;
862
863 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
864 {
865 (void) mutt_file_fclose(&fp_tmp);
866 return -1;
867 }
868 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
869
870 struct Buffer *date = buf_pool_get();
871 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
872 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
873 buf_pool_release(&date);
874
875 char *msgid_str = gen_msgid();
876 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
877 FREE(&msgid_str);
878 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
879 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
880 fputc('\n', fp_tmp);
881 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
882 if (mutt_file_fclose(&fp_tmp) != 0)
883 {
884 mutt_perror("%s", buf_string(tempfile));
885 unlink(buf_string(tempfile));
886 return -1;
887 }
888#ifdef USE_SMTP
889 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
890 if (c_smtp_url)
891 {
892 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
893 (e->body->encoding == ENC_8BIT), sub);
894 }
895 else
896#endif
897 {
898 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
899 (e->body->encoding == ENC_8BIT), sub);
900 }
901 }
902
903 buf_pool_release(&tempfile);
904 return rc;
905}
906
917int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
918 struct AddressList *to, struct ConfigSubset *sub)
919{
920 if (!fp || !e || !to || TAILQ_EMPTY(to))
921 return -1;
922
923 const char *fqdn = mutt_fqdn(true, sub);
924 char *err = NULL;
925
926 struct Address *from = mutt_default_from(sub);
927 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
928 mutt_addrlist_append(&from_list, from);
929
930 /* mutt_default_from() does not use $real_name if the real name is not set
931 * in $from, so we add it here. The reason it is not added in
932 * mutt_default_from() is that during normal sending, we execute
933 * send-hooks and set the real_name last so that it can be changed based
934 * upon message criteria. */
935 if (!from->personal)
936 {
937 const char *const c_real_name = cs_subset_string(sub, "real_name");
938 if (c_real_name)
939 from->personal = buf_new(c_real_name);
940 }
941
942 mutt_addrlist_qualify(&from_list, fqdn);
943
944 rfc2047_encode_addrlist(&from_list, "Resent-From");
945 if (mutt_addrlist_to_intl(&from_list, &err))
946 {
947 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
948 FREE(&err);
949 mutt_addrlist_clear(&from_list);
950 return -1;
951 }
952 struct Buffer *resent_from = buf_pool_get();
953 mutt_addrlist_write(&from_list, resent_from, false);
954
955#ifdef USE_NNTP
956 OptNewsSend = false;
957#endif
958
959 /* prepare recipient list. idna conversion appears to happen before this
960 * function is called, since the user receives confirmation of the address
961 * list being bounced to. */
962 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
963 mutt_addrlist_copy(&resent_to, to, false);
964 rfc2047_encode_addrlist(&resent_to, "Resent-To");
965 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
966 mutt_addrlist_clear(&resent_to);
967 mutt_addrlist_clear(&from_list);
968 buf_pool_release(&resent_from);
969 return rc;
970}
971
977static void set_noconv_flags(struct Body *b, bool flag)
978{
979 for (; b; b = b->next)
980 {
981 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
982 {
983 set_noconv_flags(b->parts, flag);
984 }
985 else if ((b->type == TYPE_TEXT) && b->noconv)
986 {
987 if (flag)
988 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
989 else
990 mutt_param_delete(&b->parameter, "x-mutt-noconv");
991 }
992 }
993}
994
1007int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1008 char *fcc, char **finalpath, struct ConfigSubset *sub)
1009{
1010 char fcc_tok[PATH_MAX] = { 0 };
1011 char fcc_expanded[PATH_MAX] = { 0 };
1012
1013 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
1014
1015 char *tok = strtok(fcc_tok, ",");
1016 if (!tok)
1017 return -1;
1018
1019 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
1020 /* mutt_expand_path already called above for the first token */
1021 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
1022 if (status != 0)
1023 return status;
1024
1025 while ((tok = strtok(NULL, ",")))
1026 {
1027 if (*tok == '\0')
1028 continue;
1029
1030 /* Only call mutt_expand_path if tok has some data */
1031 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1032 mutt_str_copy(fcc_expanded, tok, sizeof(fcc_expanded));
1033 mutt_expand_path(fcc_expanded, sizeof(fcc_expanded));
1034 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n", fcc_expanded);
1035 status = mutt_write_fcc(fcc_expanded, e, msgid, post, fcc, finalpath, sub);
1036 if (status != 0)
1037 return status;
1038 }
1039
1040 return 0;
1041}
1042
1055int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1056 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1057{
1058 struct Message *msg = NULL;
1059 struct Buffer *tempfile = NULL;
1060 FILE *fp_tmp = NULL;
1061 int rc = -1;
1062 bool need_mailbox_cleanup = false;
1063 struct stat st = { 0 };
1064 MsgOpenFlags onm_flags;
1065
1066 if (post)
1067 set_noconv_flags(e->body, true);
1068
1069#ifdef RECORD_FOLDER_HOOK
1070 mutt_folder_hook(path, NULL);
1071#endif
1072 struct Mailbox *m_fcc = mx_path_resolve(path);
1073 bool old_append = m_fcc->append;
1074 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1075 {
1076 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1077 goto done;
1078 }
1079
1080 /* We need to add a Content-Length field to avoid problems where a line in
1081 * the message body begins with "From " */
1082 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1083 {
1084 tempfile = buf_pool_get();
1085 buf_mktemp(tempfile);
1086 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1087 if (!fp_tmp)
1088 {
1089 mutt_perror("%s", buf_string(tempfile));
1090 mx_mbox_close(m_fcc);
1091 goto done;
1092 }
1093 /* remember new mail status before appending message */
1094 need_mailbox_cleanup = true;
1095 stat(path, &st);
1096 }
1097
1098 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1099 onm_flags = MUTT_ADD_FROM;
1100 if (post)
1101 onm_flags |= MUTT_SET_DRAFT;
1102 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1103 if (!msg)
1104 {
1105 mutt_file_fclose(&fp_tmp);
1106 mx_mbox_close(m_fcc);
1107 goto done;
1108 }
1109
1110 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1111
1112 /* post == 1 => postpone message.
1113 * post == 0 => Normal mode. */
1114 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1116 c_crypt_protected_headers_read &&
1118 sub);
1119
1120 /* (postponement) if this was a reply of some sort, <msgid> contains the
1121 * Message-ID: of message replied to. Save it using a special X-Mutt-
1122 * header so it can be picked up if the message is recalled at a later
1123 * point in time. This will allow the message to be marked as replied if
1124 * the same mailbox is still open. */
1125 if (post && msgid)
1126 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1127
1128 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1129 * it can be picked up when the message is recalled */
1130 if (post && fcc)
1131 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1132
1133 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1134 fprintf(msg->fp, "Status: RO\n");
1135
1136 /* (postponement) if the mail is to be signed or encrypted, save this info */
1137 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1138 {
1139 fputs("Mutt-PGP: ", msg->fp);
1140 if (e->security & SEC_ENCRYPT)
1141 fputc('E', msg->fp);
1142 if (e->security & SEC_OPPENCRYPT)
1143 fputc('O', msg->fp);
1144 if (e->security & SEC_SIGN)
1145 {
1146 fputc('S', msg->fp);
1147
1148 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1149 if (c_pgp_sign_as)
1150 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1151 }
1152 if (e->security & SEC_INLINE)
1153 fputc('I', msg->fp);
1154#ifdef USE_AUTOCRYPT
1155 if (e->security & SEC_AUTOCRYPT)
1156 fputc('A', msg->fp);
1158 fputc('Z', msg->fp);
1159#endif
1160 fputc('\n', msg->fp);
1161 }
1162
1163 /* (postponement) if the mail is to be signed or encrypted, save this info */
1164 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1165 {
1166 fputs("Mutt-SMIME: ", msg->fp);
1167 if (e->security & SEC_ENCRYPT)
1168 {
1169 fputc('E', msg->fp);
1170
1171 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1172 if (c_smime_encrypt_with)
1173 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1174 }
1175 if (e->security & SEC_OPPENCRYPT)
1176 fputc('O', msg->fp);
1177 if (e->security & SEC_SIGN)
1178 {
1179 fputc('S', msg->fp);
1180
1181 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1182 if (c_smime_sign_as)
1183 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1184 }
1185 if (e->security & SEC_INLINE)
1186 fputc('I', msg->fp);
1187 fputc('\n', msg->fp);
1188 }
1189
1190#ifdef MIXMASTER
1191 /* (postponement) if the mail is to be sent through a mixmaster
1192 * chain, save that information */
1193
1194 if (post && !STAILQ_EMPTY(&e->chain))
1195 {
1196 fputs("Mutt-Mix:", msg->fp);
1197 struct ListNode *p = NULL;
1198 STAILQ_FOREACH(p, &e->chain, entries)
1199 {
1200 fprintf(msg->fp, " %s", (char *) p->data);
1201 }
1202
1203 fputc('\n', msg->fp);
1204 }
1205#endif
1206
1207 if (fp_tmp)
1208 {
1209 mutt_write_mime_body(e->body, fp_tmp, sub);
1210
1211 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1212 * will happen, and it can cause problems parsing the mailbox later. */
1213 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1214 mutt_file_seek(fp_tmp, 0, SEEK_END))
1215 {
1216 fputc('\n', fp_tmp);
1217 }
1218
1219 fflush(fp_tmp);
1220 if (ferror(fp_tmp))
1221 {
1222 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1223 mutt_file_fclose(&fp_tmp);
1224 unlink(buf_string(tempfile));
1225 mx_msg_commit(m_fcc, msg); /* XXX really? */
1226 mx_msg_close(m_fcc, &msg);
1227 mx_mbox_close(m_fcc);
1228 goto done;
1229 }
1230
1231 /* count the number of lines */
1232 int lines = 0;
1233 char line_buf[1024] = { 0 };
1234 rewind(fp_tmp);
1235 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1236 lines++;
1237 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1238 fprintf(msg->fp, "Lines: %d\n\n", lines);
1239
1240 /* copy the body and clean up */
1241 rewind(fp_tmp);
1242 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1243 if (mutt_file_fclose(&fp_tmp) != 0)
1244 rc = -1;
1245 /* if there was an error, leave the temp version */
1246 if (rc >= 0)
1247 {
1248 unlink(buf_string(tempfile));
1249 rc = 0;
1250 }
1251 }
1252 else
1253 {
1254 fputc('\n', msg->fp); /* finish off the header */
1255 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1256 }
1257
1258 if (mx_msg_commit(m_fcc, msg) != 0)
1259 rc = -1;
1260 else if (finalpath)
1261 *finalpath = mutt_str_dup(msg->committed_path);
1262 mx_msg_close(m_fcc, &msg);
1263 mx_mbox_close(m_fcc);
1264
1265 if (!post && need_mailbox_cleanup)
1266 mailbox_restore_timestamp(path, &st);
1267
1268 if (post)
1269 set_noconv_flags(e->body, false);
1270
1271done:
1272 m_fcc->append = old_append;
1273 mailbox_free(&m_fcc);
1274
1275#ifdef RECORD_FOLDER_HOOK
1276 /* We ran a folder hook for the destination mailbox,
1277 * now we run it for the user's current mailbox */
1278 const struct Mailbox *m_cur = get_current_mailbox();
1279 if (m_cur)
1280 mutt_folder_hook(m_cur->path, m_cur->desc);
1281#endif
1282
1283 if (fp_tmp)
1284 {
1285 mutt_file_fclose(&fp_tmp);
1286 unlink(buf_string(tempfile));
1287 }
1288 buf_pool_release(&tempfile);
1289
1290 return rc;
1291}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:762
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:677
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
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:705
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1481
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:399
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1207
const char AddressSpecials[]
Characters with special meaning for email addresses.
Definition: address.c:43
void mutt_addrlist_write_file(const struct AddressList *al, FILE *fp, const char *header)
Wrapper for mutt_write_address()
Definition: address.c:1249
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1294
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:596
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:316
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:542
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:243
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:39
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:187
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:423
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:106
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:884
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:537
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:598
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1089
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:432
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.
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:426
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:325
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1170
struct Body * mutt_rfc822_parse_message(FILE *fp, struct Body *parent)
Parse a Message/RFC822 body.
Definition: parse.c:1794
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1482
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
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:763
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
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:232
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
void buf_file_expand_fmt_quote(struct Buffer *dest, const char *fmt, const char *src)
Replace s in a string with a filename.
Definition: file.c:1497
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:733
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
#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:218
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition: filter.c:207
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:78
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:86
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1892
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:575
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:758
Convenience wrapper for the send headers.
@ 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:588
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:662
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:90
@ 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:45
@ 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:97
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:387
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:446
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:810
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:680
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:432
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
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:653
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
Many unsorted constants and some structs.
#define PATH_MAX
Definition: mutt.h:41
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:416
Mailbox helper functions.
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:126
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1206
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, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1160
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1066
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1185
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1697
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:38
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:40
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:41
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mxapi.h:42
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:44
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
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#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:104
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:762
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:626
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:828
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:659
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:848
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:301
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1463
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1337
Prepare and send an email.
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:408
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:74
static char * gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:751
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:977
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:705
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:917
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:605
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:1007
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:257
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:817
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:665
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:349
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:778
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:452
static void transform_to_7bit(struct Body *a, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:194
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:1055
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:420
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:843
static void run_mime_type_query(struct Body *att, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:564
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:297
Send email using sendmail.
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:1107
Send email to an SMTP server.
#define NONULL(x)
Definition: string2.h:37
#define SKIPWS(ch)
Definition: string2.h:45
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
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
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:108
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: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
char * committed_path
the final path generated by mx_msg_commit()
Definition: message.h:37
String list.
Definition: slist.h:47
Keep track when processing files.
Definition: state.h:47
FILE * fp_out
File to write to.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:48
#define buf_mktemp(buf)
Definition: tmp.h:33