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