NeoMutt  2024-12-12-14-g7b49f7
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 <sys/types.h>
41#include <unistd.h>
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "mutt.h"
48#include "sendlib.h"
49#include "attach/lib.h"
50#include "convert/lib.h"
51#include "ncrypt/lib.h"
52#include "body.h"
53#include "copy.h"
54#include "globals.h"
55#include "handler.h"
56#include "header.h"
57#include "mutt_mailbox.h"
58#include "muttlib.h"
59#include "mx.h"
60#include "send.h"
61#include "sendmail.h"
62#include "smtp.h"
63
76enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
77{
78 FILE *fp = NULL;
79 char *p = NULL, *q = NULL, *ct = NULL;
80 char buf[PATH_MAX] = { 0 };
81 char subtype[256] = { 0 };
82 char xtype[256] = { 0 };
83 int sze, cur_sze = 0;
84 bool found_mimetypes = false;
86
87 int szf = mutt_str_len(path);
88
89 for (int count = 0; count < 4; count++)
90 {
91 /* can't use strtok() because we use it in an inner loop below, so use
92 * a switch statement here instead. */
93 switch (count)
94 {
95 /* last file with last entry to match wins type/xtype */
96 case 0:
97 /* check default unix mimetypes location first */
98 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
99 break;
100 case 1:
101 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
102 break;
103 case 2:
104 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
105 break;
106 case 3:
107 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(HomeDir));
108 break;
109 default:
110 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
111 goto bye; /* shouldn't happen */
112 }
113
114 fp = mutt_file_fopen(buf, "r");
115 if (fp)
116 {
117 found_mimetypes = true;
118
119 while (fgets(buf, sizeof(buf) - 1, fp))
120 {
121 /* weed out any comments */
122 p = strchr(buf, '#');
123 if (p)
124 *p = '\0';
125
126 /* remove any leading space. */
127 ct = buf;
128 SKIPWS(ct);
129
130 /* position on the next field in this line */
131 p = strpbrk(ct, " \t");
132 if (!p)
133 continue;
134 *p++ = 0;
135 SKIPWS(p);
136
137 /* cycle through the file extensions */
138 while ((p = strtok(p, " \t\n")))
139 {
140 sze = mutt_str_len(p);
141 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
142 ((szf == sze) || (path[szf - sze - 1] == '.')))
143 {
144 /* get the content-type */
145
146 p = strchr(ct, '/');
147 if (!p)
148 {
149 /* malformed line, just skip it. */
150 break;
151 }
152 *p++ = 0;
153
154 for (q = p; *q && !isspace(*q); q++)
155 ; // do nothing
156
157 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
158
160 if (type == TYPE_OTHER)
161 mutt_str_copy(xtype, ct, sizeof(xtype));
162
163 cur_sze = sze;
164 }
165 p = NULL;
166 }
167 }
168 mutt_file_fclose(&fp);
169 }
170 }
171
172bye:
173
174 /* no mime.types file found */
175 if (!found_mimetypes)
176 {
177 mutt_error(_("Could not find any mime.types file"));
178 }
179
180 if ((type != TYPE_OTHER) || (*xtype != '\0'))
181 {
182 b->type = type;
183 mutt_str_replace(&b->subtype, subtype);
184 mutt_str_replace(&b->xtype, xtype);
185 }
186
187 return type;
188}
189
196static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
197{
198 struct Buffer *buf = NULL;
199 struct State state = { 0 };
200 struct stat st = { 0 };
201
202 for (; b; b = b->next)
203 {
204 if (b->type == TYPE_MULTIPART)
205 {
206 b->encoding = ENC_7BIT;
207 transform_to_7bit(b->parts, fp_in, sub);
208 }
209 else if (mutt_is_message_type(b->type, b->subtype))
210 {
211 mutt_message_to_7bit(b, fp_in, sub);
212 }
213 else
214 {
215 b->noconv = true;
216 b->force_charset = true;
217
218 /* Because of the potential recursion in message types, we
219 * restrict the lifetime of the buffer tightly */
220 buf = buf_pool_get();
221 buf_mktemp(buf);
222 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
223 if (!state.fp_out)
224 {
225 mutt_perror("fopen");
226 buf_pool_release(&buf);
227 return;
228 }
229 state.fp_in = fp_in;
230 mutt_decode_attachment(b, &state);
231 mutt_file_fclose(&state.fp_out);
232 FREE(&b->d_filename);
233 b->d_filename = b->filename;
234 b->filename = buf_strdup(buf);
235 buf_pool_release(&buf);
236 b->unlink = true;
237 if (stat(b->filename, &st) == -1)
238 {
239 mutt_perror("stat");
240 return;
241 }
242 b->length = st.st_size;
243
244 mutt_update_encoding(b, sub);
245 if (b->encoding == ENC_8BIT)
247 else if (b->encoding == ENC_BINARY)
248 b->encoding = ENC_BASE64;
249 }
250 }
251}
252
259void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
260{
261 struct Buffer *tempfile = buf_pool_get();
262 FILE *fp_in = NULL;
263 FILE *fp_out = NULL;
264 struct stat st = { 0 };
265
266 if (!b->filename && fp)
267 {
268 fp_in = fp;
269 }
270 else if (!b->filename || !(fp_in = mutt_file_fopen(b->filename, "r")))
271 {
272 mutt_error(_("Could not open %s"), b->filename ? b->filename : "(null)");
273 return;
274 }
275 else
276 {
277 b->offset = 0;
278 if (stat(b->filename, &st) == -1)
279 {
280 mutt_perror("stat");
281 mutt_file_fclose(&fp_in);
282 goto cleanup;
283 }
284 b->length = st.st_size;
285 }
286
287 /* Avoid buffer pool due to recursion */
288 buf_mktemp(tempfile);
289 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
290 if (!fp_out)
291 {
292 mutt_perror("fopen");
293 goto cleanup;
294 }
295
296 if (!mutt_file_seek(fp_in, b->offset, SEEK_SET))
297 {
298 goto cleanup;
299 }
300 b->parts = mutt_rfc822_parse_message(fp_in, b);
301
302 transform_to_7bit(b->parts, fp_in, sub);
303
304 mutt_copy_hdr(fp_in, fp_out, b->offset, b->offset + b->length,
305 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
306
307 fputs("MIME-Version: 1.0\n", fp_out);
308 mutt_write_mime_header(b->parts, fp_out, sub);
309 fputc('\n', fp_out);
310 mutt_write_mime_body(b->parts, fp_out, sub);
311
312 if (fp_in != fp)
313 mutt_file_fclose(&fp_in);
314 mutt_file_fclose(&fp_out);
315
316 b->encoding = ENC_7BIT;
317 FREE(&b->d_filename);
318 b->d_filename = b->filename;
319 if (b->filename && b->unlink)
320 unlink(b->filename);
321 b->filename = buf_strdup(tempfile);
322 b->unlink = true;
323 if (stat(b->filename, &st) == -1)
324 {
325 mutt_perror("stat");
326 goto cleanup;
327 }
328 b->length = st.st_size;
330 b->email->body = NULL;
331
332cleanup:
333 if (fp_in && (fp_in != fp))
334 mutt_file_fclose(&fp_in);
335
336 if (fp_out)
337 {
338 mutt_file_fclose(&fp_out);
339 mutt_file_unlink(buf_string(tempfile));
340 }
341
342 buf_pool_release(&tempfile);
343}
344
351static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
352{
353 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
354 if (b->type == TYPE_TEXT)
355 {
356 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
357 char send_charset[128] = { 0 };
358 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
359 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
360 (info->linemax > 990) || (info->from && c_encode_from))
361 {
363 }
364 else if (info->hibin)
365 {
366 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
367 }
368 else
369 {
370 b->encoding = ENC_7BIT;
371 }
372 }
373 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
374 {
375 if (info->lobin || info->hibin)
376 {
377 if (c_allow_8bit && !info->lobin)
378 b->encoding = ENC_8BIT;
379 else
380 mutt_message_to_7bit(b, NULL, sub);
381 }
382 else
383 {
384 b->encoding = ENC_7BIT;
385 }
386 }
387 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
388 {
389 b->encoding = ENC_7BIT;
390 }
391 else
392 {
393 /* Determine which encoding is smaller */
394 if (1.33f * (float) (info->lobin + info->hibin + info->ascii) <
395 3.0f * (float) (info->lobin + info->hibin) + (float) info->ascii)
396 {
397 b->encoding = ENC_BASE64;
398 }
399 else
400 {
402 }
403 }
404}
405
411{
412 b->stamp = mutt_date_now();
413}
414
422void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
423{
424 struct Content *info = NULL;
425 char chsbuf[256] = { 0 };
426
427 /* override noconv when it's us-ascii */
428 if (mutt_ch_is_us_ascii(mutt_body_get_charset(b, chsbuf, sizeof(chsbuf))))
429 b->noconv = false;
430
431 if (!b->force_charset && !b->noconv)
432 mutt_param_delete(&b->parameter, "charset");
433
434 info = mutt_get_content_info(b->filename, b, sub);
435 if (!info)
436 return;
437
438 set_encoding(b, info, sub);
440
441 FREE(&b->content);
442 b->content = info;
443}
444
454struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
455 bool attach_msg, struct ConfigSubset *sub)
456{
457 struct Body *body = NULL;
458 FILE *fp = NULL;
459 CopyMessageFlags cmflags;
461
462 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
463 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
464 if (WithCrypto)
465 {
466 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
467 {
469 return NULL;
470 }
471 }
472
473 struct Buffer *tempfile = buf_pool_get();
474 buf_mktemp(tempfile);
475 fp = mutt_file_fopen_masked(buf_string(tempfile), "w+");
476 if (!fp)
477 {
478 buf_pool_release(&tempfile);
479 return NULL;
480 }
481
482 body = mutt_body_new();
483 body->type = TYPE_MESSAGE;
484 body->subtype = mutt_str_dup("rfc822");
485 body->filename = mutt_str_dup(buf_string(tempfile));
486 body->unlink = true;
487 body->use_disp = false;
488 body->disposition = DISP_INLINE;
489 body->noconv = true;
490
491 buf_pool_release(&tempfile);
492
493 struct Message *msg = mx_msg_open(m, e);
494 if (!msg)
495 {
496 mutt_body_free(&body);
498 return NULL;
499 }
501
502 CopyHeaderFlags chflags = CH_XMIT;
503 cmflags = MUTT_CM_NO_FLAGS;
504
505 /* If we are attaching a message, ignore `$mime_forward_decode` */
506 if (!attach_msg && c_mime_forward_decode)
507 {
508 chflags |= CH_MIME | CH_TXTPLAIN;
511 pgp &= ~PGP_ENCRYPT;
513 pgp &= ~SMIME_ENCRYPT;
514 }
515 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
516 {
518 {
519 chflags |= CH_MIME | CH_NONEWLINE;
520 cmflags = MUTT_CM_DECODE_PGP;
521 pgp &= ~PGP_ENCRYPT;
522 }
523 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
525 {
526 chflags |= CH_MIME | CH_TXTPLAIN;
528 pgp &= ~PGP_ENCRYPT;
529 }
530 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
532 {
533 chflags |= CH_MIME | CH_NONEWLINE;
534 cmflags = MUTT_CM_DECODE_SMIME;
535 pgp &= ~SMIME_ENCRYPT;
536 }
537 }
538
539 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
540 mx_msg_close(m, &msg);
541
542 fflush(fp);
543 rewind(fp);
544
545 body->email = email_new();
546 body->email->offset = 0;
547 /* we don't need the user headers here */
548 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
549 if (WithCrypto)
550 body->email->security = pgp;
551 mutt_update_encoding(body, sub);
552 body->parts = body->email->body;
553
555
556 return body;
557}
558
566static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
567{
568 FILE *fp = NULL, *fp_err = NULL;
569 char *buf = NULL;
570 size_t buflen;
571 pid_t pid;
572 struct Buffer *cmd = buf_pool_get();
573
574 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
575
576 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
577
578 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, EnvList);
579 if (pid < 0)
580 {
581 mutt_error(_("Error running \"%s\""), buf_string(cmd));
582 buf_pool_release(&cmd);
583 return;
584 }
585 buf_pool_release(&cmd);
586
587 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
588 if (buf)
589 {
590 if (strchr(buf, '/'))
592 FREE(&buf);
593 }
594
595 mutt_file_fclose(&fp);
596 mutt_file_fclose(&fp_err);
597 filter_wait(pid);
598}
599
607struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
608{
609 if (!path || (path[0] == '\0'))
610 return NULL;
611
612 struct Body *b = mutt_body_new();
613 b->filename = mutt_str_dup(path);
614
615 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
616 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
617
618 if (c_mime_type_query_command && c_mime_type_query_first)
619 run_mime_type_query(b, sub);
620
621 /* Attempt to determine the appropriate content-type based on the filename
622 * suffix. */
623 if (!b->subtype)
624 mutt_lookup_mime_type(b, path);
625
626 if (!b->subtype && c_mime_type_query_command && !c_mime_type_query_first)
627 {
628 run_mime_type_query(b, sub);
629 }
630
631 struct Content *info = mutt_get_content_info(path, b, sub);
632 if (!info)
633 {
634 mutt_body_free(&b);
635 return NULL;
636 }
637
638 if (!b->subtype)
639 {
640 if ((info->nulbin == 0) &&
641 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
642 {
643 /* Statistically speaking, there should be more than 10% "lobin"
644 * chars if this is really a binary file... */
645 b->type = TYPE_TEXT;
646 b->subtype = mutt_str_dup("plain");
647 }
648 else
649 {
651 b->subtype = mutt_str_dup("octet-stream");
652 }
653 }
654
655 FREE(&info);
656 mutt_update_encoding(b, sub);
657 return b;
658}
659
667static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
668{
669 char *tmp = NULL;
670 char *p = NULL;
671 int i;
672
673 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
674
675 struct ListNode *np = NULL;
676 STAILQ_FOREACH(np, h, entries)
677 {
678 p = strchr(NONULL(np->data), ':');
679 if (!p)
680 continue;
681
682 i = p - np->data;
683 p = mutt_str_skip_email_wsp(p + 1);
684 tmp = mutt_str_dup(p);
685
686 if (!tmp)
687 continue;
688
689 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
690 MUTT_MEM_REALLOC(&np->data, i + 2 + mutt_str_len(tmp) + 1, char);
691
692 sprintf(np->data + i + 2, "%s", tmp);
693
694 FREE(&tmp);
695 }
696}
697
707const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
708{
709 const char *const c_hostname = cs_subset_string(sub, "hostname");
710 if (!c_hostname || (c_hostname[0] == '@'))
711 return NULL;
712
713 const char *p = c_hostname;
714
715 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
716 if (may_hide_host && c_hidden_host)
717 {
718 p = strchr(c_hostname, '.');
719 if (p)
720 p++;
721
722 // sanity check: don't hide the host if the fqdn is something like example.com
723 if (!p || !strchr(p, '.'))
724 p = c_hostname;
725 }
726
727 return p;
728}
729
753char *mutt_gen_msgid(void)
754{
755 const int ID_LEFT_LEN = 50;
756 const int ID_RIGHT_LEN = 12;
757 char rnd_id_left[ID_LEFT_LEN + 1];
758 char rnd_id_right[ID_RIGHT_LEN + 1];
759 char buf[128] = { 0 };
760
761 mutt_rand_base32(rnd_id_left, sizeof(rnd_id_left) - 1);
762 mutt_rand_base32(rnd_id_right, sizeof(rnd_id_right) - 1);
763 rnd_id_left[ID_LEFT_LEN] = 0;
764 rnd_id_right[ID_RIGHT_LEN] = 0;
765
766 snprintf(buf, sizeof(buf), "<%s@%s>", rnd_id_left, rnd_id_right);
767 return mutt_str_dup(buf);
768}
769
780void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
781{
782 if (final)
783 {
784 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
785 {
786 /* some MTA's will put an Apparently-To: header field showing the Bcc:
787 * recipients if there is no To: or Cc: field, so attempt to suppress
788 * it by using an empty To: field. */
789 struct Address *to = mutt_addr_new();
790 to->group = true;
791 mutt_addrlist_append(&env->to, to);
793
794 char buf[1024] = { 0 };
795 buf[0] = '\0';
796 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
797
798 buf_strcpy(to->mailbox, buf);
799 }
800
801 mutt_set_followup_to(env, sub);
802
803 if (!env->message_id)
804 env->message_id = mutt_gen_msgid();
805 }
806
807 /* Take care of 8-bit => 7-bit conversion. */
809 encode_headers(&env->userhdrs, sub);
810}
811
820{
821 struct ListNode *item = NULL;
822 STAILQ_FOREACH(item, &env->userhdrs, entries)
823 {
824 rfc2047_decode(&item->data);
825 }
826
828
829 /* back conversions */
831}
832
845static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
846 struct AddressList *to, const char *resent_from,
847 struct AddressList *env_from, struct ConfigSubset *sub)
848{
849 if (!e)
850 return -1;
851
852 int rc = 0;
853
854 struct Buffer *tempfile = buf_pool_get();
855 buf_mktemp(tempfile);
856 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
857 if (fp_tmp)
858 {
860
861 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
862 if (!c_bounce_delivered)
863 chflags |= CH_WEED_DELIVERED;
864
865 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
866 {
867 (void) mutt_file_fclose(&fp_tmp);
868 return -1;
869 }
870 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
871
872 struct Buffer *date = buf_pool_get();
873 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
874 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
875 buf_pool_release(&date);
876
877 char *msgid_str = mutt_gen_msgid();
878 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
879 FREE(&msgid_str);
880 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
881 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
882 fputc('\n', fp_tmp);
883 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
884 if (mutt_file_fclose(&fp_tmp) != 0)
885 {
886 mutt_perror("%s", buf_string(tempfile));
887 unlink(buf_string(tempfile));
888 return -1;
889 }
890 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
891 if (c_smtp_url)
892 {
893 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
894 (e->body->encoding == ENC_8BIT), sub);
895 }
896 else
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 OptNewsSend = false;
956
957 /* prepare recipient list. idna conversion appears to happen before this
958 * function is called, since the user receives confirmation of the address
959 * list being bounced to. */
960 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
961 mutt_addrlist_copy(&resent_to, to, false);
962 rfc2047_encode_addrlist(&resent_to, "Resent-To");
963 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
964 mutt_addrlist_clear(&resent_to);
965 mutt_addrlist_clear(&from_list);
966 buf_pool_release(&resent_from);
967 return rc;
968}
969
975static void set_noconv_flags(struct Body *b, bool flag)
976{
977 for (; b; b = b->next)
978 {
979 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
980 {
981 set_noconv_flags(b->parts, flag);
982 }
983 else if ((b->type == TYPE_TEXT) && b->noconv)
984 {
985 if (flag)
986 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
987 else
988 mutt_param_delete(&b->parameter, "x-mutt-noconv");
989 }
990 }
991}
992
1005int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1006 char *fcc, char **finalpath, struct ConfigSubset *sub)
1007{
1008 char fcc_tok[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 /* buf_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 struct Buffer *fcc_expanded = buf_pool_get();
1023 while ((tok = strtok(NULL, ",")))
1024 {
1025 if (*tok == '\0')
1026 continue;
1027
1028 /* Only call buf_expand_path if tok has some data */
1029 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1030 buf_strcpy(fcc_expanded, tok);
1031 buf_expand_path(fcc_expanded);
1032 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n",
1033 buf_string(fcc_expanded));
1034 status = mutt_write_fcc(buf_string(fcc_expanded), e, msgid, post, fcc, finalpath, sub);
1035 if (status != 0)
1036 {
1037 buf_pool_release(&fcc_expanded);
1038 return status;
1039 }
1040 }
1041
1042 buf_pool_release(&fcc_expanded);
1043 return 0;
1044}
1045
1058int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1059 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1060{
1061 struct Message *msg = NULL;
1062 struct Buffer *tempfile = NULL;
1063 FILE *fp_tmp = NULL;
1064 int rc = -1;
1065 bool need_mailbox_cleanup = false;
1066 struct stat st = { 0 };
1067 MsgOpenFlags onm_flags;
1068
1069 if (post)
1070 set_noconv_flags(e->body, true);
1071
1072#ifdef RECORD_FOLDER_HOOK
1073 mutt_folder_hook(path, NULL);
1074#endif
1075 struct Mailbox *m_fcc = mx_path_resolve(path);
1076 bool old_append = m_fcc->append;
1077 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1078 {
1079 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1080 goto done;
1081 }
1082
1083 /* We need to add a Content-Length field to avoid problems where a line in
1084 * the message body begins with "From " */
1085 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1086 {
1087 tempfile = buf_pool_get();
1088 buf_mktemp(tempfile);
1089 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1090 if (!fp_tmp)
1091 {
1092 mutt_perror("%s", buf_string(tempfile));
1093 mx_mbox_close(m_fcc);
1094 goto done;
1095 }
1096 /* remember new mail status before appending message */
1097 need_mailbox_cleanup = true;
1098 stat(path, &st);
1099 }
1100
1101 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1102 onm_flags = MUTT_ADD_FROM;
1103 if (post)
1104 onm_flags |= MUTT_SET_DRAFT;
1105 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1106 if (!msg)
1107 {
1108 mutt_file_fclose(&fp_tmp);
1109 mx_mbox_close(m_fcc);
1110 goto done;
1111 }
1112
1113 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1114
1115 /* post == 1 => postpone message.
1116 * post == 0 => Normal mode. */
1117 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1119 c_crypt_protected_headers_read &&
1121 sub);
1122
1123 /* (postponement) if this was a reply of some sort, <msgid> contains the
1124 * Message-ID: of message replied to. Save it using a special X-Mutt-
1125 * header so it can be picked up if the message is recalled at a later
1126 * point in time. This will allow the message to be marked as replied if
1127 * the same mailbox is still open. */
1128 if (post && msgid)
1129 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1130
1131 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1132 * it can be picked up when the message is recalled */
1133 if (post && fcc)
1134 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1135
1136 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1137 fprintf(msg->fp, "Status: RO\n");
1138
1139 /* (postponement) if the mail is to be signed or encrypted, save this info */
1140 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1141 {
1142 fputs("Mutt-PGP: ", msg->fp);
1143 if (e->security & SEC_ENCRYPT)
1144 fputc('E', msg->fp);
1145 if (e->security & SEC_OPPENCRYPT)
1146 fputc('O', msg->fp);
1147 if (e->security & SEC_SIGN)
1148 {
1149 fputc('S', msg->fp);
1150
1151 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1152 if (c_pgp_sign_as)
1153 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1154 }
1155 if (e->security & SEC_INLINE)
1156 fputc('I', msg->fp);
1157#ifdef USE_AUTOCRYPT
1158 if (e->security & SEC_AUTOCRYPT)
1159 fputc('A', msg->fp);
1161 fputc('Z', msg->fp);
1162#endif
1163 fputc('\n', msg->fp);
1164 }
1165
1166 /* (postponement) if the mail is to be signed or encrypted, save this info */
1167 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1168 {
1169 fputs("Mutt-SMIME: ", msg->fp);
1170 if (e->security & SEC_ENCRYPT)
1171 {
1172 fputc('E', msg->fp);
1173
1174 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1175 if (c_smime_encrypt_with)
1176 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1177 }
1178 if (e->security & SEC_OPPENCRYPT)
1179 fputc('O', msg->fp);
1180 if (e->security & SEC_SIGN)
1181 {
1182 fputc('S', msg->fp);
1183
1184 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1185 if (c_smime_sign_as)
1186 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1187 }
1188 if (e->security & SEC_INLINE)
1189 fputc('I', msg->fp);
1190 fputc('\n', msg->fp);
1191 }
1192
1193 if (fp_tmp)
1194 {
1195 mutt_write_mime_body(e->body, fp_tmp, sub);
1196
1197 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1198 * will happen, and it can cause problems parsing the mailbox later. */
1199 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1200 mutt_file_seek(fp_tmp, 0, SEEK_END))
1201 {
1202 fputc('\n', fp_tmp);
1203 }
1204
1205 fflush(fp_tmp);
1206 if (ferror(fp_tmp))
1207 {
1208 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1209 mutt_file_fclose(&fp_tmp);
1210 unlink(buf_string(tempfile));
1211 mx_msg_commit(m_fcc, msg); /* XXX really? */
1212 mx_msg_close(m_fcc, &msg);
1213 mx_mbox_close(m_fcc);
1214 goto done;
1215 }
1216
1217 /* count the number of lines */
1218 int lines = 0;
1219 char line_buf[1024] = { 0 };
1220 rewind(fp_tmp);
1221 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1222 lines++;
1223 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1224 fprintf(msg->fp, "Lines: %d\n\n", lines);
1225
1226 /* copy the body and clean up */
1227 rewind(fp_tmp);
1228 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1229 if (mutt_file_fclose(&fp_tmp) != 0)
1230 rc = -1;
1231 /* if there was an error, leave the temp version */
1232 if (rc >= 0)
1233 {
1234 unlink(buf_string(tempfile));
1235 rc = 0;
1236 }
1237 }
1238 else
1239 {
1240 fputc('\n', msg->fp); /* finish off the header */
1241 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1242 }
1243
1244 if (mx_msg_commit(m_fcc, msg) != 0)
1245 rc = -1;
1246 else if (finalpath)
1247 *finalpath = mutt_str_dup(msg->committed_path);
1248 mx_msg_close(m_fcc, &msg);
1249 mx_mbox_close(m_fcc);
1250
1251 if (!post && need_mailbox_cleanup)
1252 mailbox_restore_timestamp(path, &st);
1253
1254 if (post)
1255 set_noconv_flags(e->body, false);
1256
1257done:
1258 m_fcc->append = old_append;
1259 mailbox_free(&m_fcc);
1260
1261#ifdef RECORD_FOLDER_HOOK
1262 /* We ran a folder hook for the destination mailbox,
1263 * now we run it for the user's current mailbox */
1264 const struct Mailbox *m_cur = get_current_mailbox();
1265 if (m_cur)
1266 mutt_folder_hook(m_cur->path, m_cur->desc);
1267#endif
1268
1269 if (fp_tmp)
1270 {
1271 mutt_file_fclose(&fp_tmp);
1272 unlink(buf_string(tempfile));
1273 }
1274 buf_pool_release(&tempfile);
1275
1276 return rc;
1277}
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:596
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
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:291
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:242
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
Convenience wrapper for the config headers.
char * HomeDir
User's home directory.
Definition: globals.c:37
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:424
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:107
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:906
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:89
@ 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:609
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:1100
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:443
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:548
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:133
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
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:1837
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:1205
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1498
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:287
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:808
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:257
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:1456
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:221
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:40
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:68
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:75
#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:1906
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:630
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
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BINARY
Binary.
Definition: mime.h:53
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ ENC_8BIT
8-bit text
Definition: mime.h:50
@ ENC_QUOTED_PRINTABLE
Quoted-printable text.
Definition: mime.h:51
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MESSAGE
Type: 'message/*'.
Definition: mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
#define mutt_ch_is_us_ascii(str)
Definition: charset.h:90
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition: date.c:397
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:456
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
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:672
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:608
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:360
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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:581
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:280
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:407
Mailbox helper functions.
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1040
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1159
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1636
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
API for mailboxes.
uint8_t MsgOpenFlags
Flags for mx_msg_open_new(), e.g. MUTT_ADD_FROM.
Definition: mx.h:37
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:39
#define MUTT_SET_DRAFT
set the message draft flag
Definition: mx.h:40
#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:91
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:93
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:82
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:92
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:96
#define PGP_ENCRYPT
Definition: lib.h:102
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:97
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:83
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:84
#define SMIME_ENCRYPT
Definition: lib.h:108
#define WithCrypto
Definition: lib.h:122
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:94
#define SEC_SIGN
Email is signed.
Definition: lib.h:85
#define mutt_file_fopen_masked(PATH, MODE)
Definition: neomutt.h:75
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:655
#define TAILQ_EMPTY(head)
Definition: queue.h:739
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:106
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition: rfc2047.c:766
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:628
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition: rfc2047.c:832
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:661
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition: rfc2047.c:857
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:1392
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition: send.c:1268
Prepare and send an email.
static void set_noconv_flags(struct Body *b, bool flag)
Set/reset the "x-mutt-noconv" flag.
Definition: sendlib.c:975
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
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
enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:76
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:607
char * mutt_gen_msgid(void)
Generate a random Message ID.
Definition: sendlib.c:753
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:1005
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:819
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition: sendlib.c:667
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition: sendlib.c:351
static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition: sendlib.c:566
static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition: sendlib.c:196
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:780
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:454
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:1058
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:259
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:410
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:845
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:300
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:1099
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:73
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
char * xtype
content-type if x-unknown
Definition: body.h:62
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:68
time_t stamp
Time stamp of last encoding update.
Definition: body.h:77
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:63
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
struct Email * email
header information for message/rfc822
Definition: body.h:74
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Content * content
Detailed info about the content of the attachment.
Definition: body.h:70
struct Body * next
next attachment in the list
Definition: body.h:72
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:61
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:59
String manipulation buffer.
Definition: buffer.h:36
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: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
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:37
char * data
String.
Definition: list.h:38
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