NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
sendlib.c
Go to the documentation of this file.
1
26
32
33#include "config.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 "expando_msgid.h"
54#include "globals.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(NeoMutt->home_dir));
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 && !mutt_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 *tempfile = 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(tempfile);
288 fp_out = mutt_file_fopen(buf_string(tempfile), "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(tempfile);
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);
338 mutt_file_unlink(buf_string(tempfile));
339 }
340
341 buf_pool_release(&tempfile);
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.33f * (float) (info->lobin + info->hibin + info->ascii) <
394 3.0f * (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 /* Ensure we have a valid passphrase before decrypting encrypted messages */
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 /* Create a temporary file to hold the serialised message/rfc822 body */
474 struct Buffer *tempfile = buf_pool_get();
475 buf_mktemp(tempfile);
476 fp = mutt_file_fopen_masked(buf_string(tempfile), "w+");
477 if (!fp)
478 {
479 buf_pool_release(&tempfile);
480 return NULL;
481 }
482
483 /* Build a new Body representing the message/rfc822 attachment */
484 body = mutt_body_new();
485 body->type = TYPE_MESSAGE;
486 body->subtype = mutt_str_dup("rfc822");
487 body->filename = mutt_str_dup(buf_string(tempfile));
488 body->unlink = true;
489 body->use_disp = false;
490 body->disposition = DISP_INLINE;
491 body->noconv = true;
492
493 buf_pool_release(&tempfile);
494
495 struct Message *msg = mx_msg_open(m, e);
496 if (!msg)
497 {
498 mutt_body_free(&body);
500 return NULL;
501 }
503
504 /* Determine copy flags based on decode/decrypt config options.
505 * When MIME-forwarding with decode, strip MIME headers and convert charset.
506 * When forwarding encrypted content with decrypt, handle PGP/SMIME separately. */
507 CopyHeaderFlags chflags = CH_XMIT;
508 cmflags = MUTT_CM_NO_FLAGS;
509
510 /* If we are attaching a message, ignore `$mime_forward_decode` */
511 if (!attach_msg && c_mime_forward_decode)
512 {
513 chflags |= CH_MIME | CH_TXTPLAIN;
516 pgp &= ~PGP_ENCRYPT;
518 pgp &= ~SMIME_ENCRYPT;
519 }
520 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
521 {
523 {
524 chflags |= CH_MIME | CH_NONEWLINE;
525 cmflags = MUTT_CM_DECODE_PGP;
526 pgp &= ~PGP_ENCRYPT;
527 }
528 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
530 {
531 chflags |= CH_MIME | CH_TXTPLAIN;
533 pgp &= ~PGP_ENCRYPT;
534 }
535 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
537 {
538 chflags |= CH_MIME | CH_NONEWLINE;
539 cmflags = MUTT_CM_DECODE_SMIME;
540 pgp &= ~SMIME_ENCRYPT;
541 }
542 }
543
544 /* Copy the message content into the temp file, then reparse the headers */
545 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
546 mx_msg_close(m, &msg);
547
548 fflush(fp);
549 rewind(fp);
550
551 body->email = email_new();
552 body->email->offset = 0;
553 /* we don't need the user headers here */
554 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
555 if (WithCrypto)
556 body->email->security = pgp;
557 mutt_update_encoding(body, sub);
558 body->parts = body->email->body;
559
561
562 return body;
563}
564
572static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
573{
574 FILE *fp = NULL, *fp_err = NULL;
575 char *buf = NULL;
576 size_t buflen;
577 pid_t pid;
578 struct Buffer *cmd = buf_pool_get();
579
580 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
581
582 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
583
584 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, NeoMutt->env);
585 if (pid < 0)
586 {
587 mutt_error(_("Error running \"%s\""), buf_string(cmd));
588 buf_pool_release(&cmd);
589 return;
590 }
591 buf_pool_release(&cmd);
592
593 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
594 if (buf)
595 {
596 if (strchr(buf, '/'))
598 FREE(&buf);
599 }
600
601 mutt_file_fclose(&fp);
602 mutt_file_fclose(&fp_err);
603 filter_wait(pid);
604}
605
613struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
614{
615 if (!path || (path[0] == '\0'))
616 return NULL;
617
618 struct Body *b = mutt_body_new();
619 b->filename = mutt_str_dup(path);
620
621 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
622 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
623
624 if (c_mime_type_query_command && c_mime_type_query_first)
625 run_mime_type_query(b, sub);
626
627 /* Attempt to determine the appropriate content-type based on the filename
628 * suffix. */
629 if (!b->subtype)
630 mutt_lookup_mime_type(b, path);
631
632 if (!b->subtype && c_mime_type_query_command && !c_mime_type_query_first)
633 {
634 run_mime_type_query(b, sub);
635 }
636
637 struct Content *info = mutt_get_content_info(path, b, sub);
638 if (!info)
639 {
640 mutt_body_free(&b);
641 return NULL;
642 }
643
644 if (!b->subtype)
645 {
646 if ((info->nulbin == 0) &&
647 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
648 {
649 /* Statistically speaking, there should be more than 10% "lobin"
650 * chars if this is really a binary file... */
651 b->type = TYPE_TEXT;
652 b->subtype = mutt_str_dup("plain");
653 }
654 else
655 {
657 b->subtype = mutt_str_dup("octet-stream");
658 }
659 }
660
661 FREE(&info);
662 mutt_update_encoding(b, sub);
663 return b;
664}
665
673static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
674{
675 char *tmp = NULL;
676 char *p = NULL;
677 int i;
678
679 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
680
681 struct ListNode *np = NULL;
682 STAILQ_FOREACH(np, h, entries)
683 {
684 p = strchr(NONULL(np->data), ':');
685 if (!p)
686 continue;
687
688 i = p - np->data;
689 p = mutt_str_skip_email_wsp(p + 1);
690 tmp = mutt_str_dup(p);
691
692 if (!tmp)
693 continue;
694
695 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
696 MUTT_MEM_REALLOC(&np->data, i + 2 + mutt_str_len(tmp) + 1, char);
697
698 sprintf(np->data + i + 2, "%s", tmp);
699
700 FREE(&tmp);
701 }
702}
703
713const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
714{
715 const char *const c_hostname = cs_subset_string(sub, "hostname");
716 if (!c_hostname || (c_hostname[0] == '@'))
717 return NULL;
718
719 const char *p = c_hostname;
720
721 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
722 if (may_hide_host && c_hidden_host)
723 {
724 p = strchr(c_hostname, '.');
725 if (p)
726 p++;
727
728 // sanity check: don't hide the host if the fqdn is something like example.com
729 if (!p || !strchr(p, '.'))
730 p = c_hostname;
731 }
732
733 return p;
734}
735
746void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
747{
748 if (final)
749 {
750 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
751 {
752 /* some MTA's will put an Apparently-To: header field showing the Bcc:
753 * recipients if there is no To: or Cc: field, so attempt to suppress
754 * it by using an empty To: field. */
755 struct Address *to = mutt_addr_new();
756 to->group = true;
757 mutt_addrlist_append(&env->to, to);
759
760 char buf[1024] = { 0 };
761 buf[0] = '\0';
762 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
763
764 buf_strcpy(to->mailbox, buf);
765 }
766
767 mutt_set_followup_to(env, sub);
768
769 if (!env->message_id)
770 env->message_id = msgid_generate();
771 }
772
773 /* Take care of 8-bit => 7-bit conversion. */
775 encode_headers(&env->userhdrs, sub);
776}
777
786{
787 struct ListNode *item = NULL;
788 STAILQ_FOREACH(item, &env->userhdrs, entries)
789 {
790 rfc2047_decode(&item->data);
791 }
792
794
795 /* back conversions */
797}
798
811static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
812 struct AddressList *to, const char *resent_from,
813 struct AddressList *env_from, struct ConfigSubset *sub)
814{
815 if (!e)
816 return -1;
817
818 int rc = 0;
819
820 struct Buffer *tempfile = buf_pool_get();
821 buf_mktemp(tempfile);
822 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
823 if (fp_tmp)
824 {
826
827 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
828 if (!c_bounce_delivered)
829 chflags |= CH_WEED_DELIVERED;
830
831 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
832 {
833 (void) mutt_file_fclose(&fp_tmp);
834 return -1;
835 }
836 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
837
838 struct Buffer *date = buf_pool_get();
839 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
840 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
841 buf_pool_release(&date);
842
843 char *msgid_str = msgid_generate();
844 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
845 FREE(&msgid_str);
846 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
847 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
848 fputc('\n', fp_tmp);
849 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
850 if (mutt_file_fclose(&fp_tmp) != 0)
851 {
852 mutt_perror("%s", buf_string(tempfile));
853 unlink(buf_string(tempfile));
854 return -1;
855 }
856 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
857 if (c_smtp_url)
858 {
859 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
860 (e->body->encoding == ENC_8BIT), sub);
861 }
862 else
863 {
864 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
865 (e->body->encoding == ENC_8BIT), sub);
866 }
867 }
868
869 buf_pool_release(&tempfile);
870 return rc;
871}
872
883int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
884 struct AddressList *to, struct ConfigSubset *sub)
885{
886 if (!fp || !e || !to || TAILQ_EMPTY(to))
887 return -1;
888
889 const char *fqdn = mutt_fqdn(true, sub);
890 char *err = NULL;
891
892 struct Address *from = mutt_default_from(sub);
893 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
894 mutt_addrlist_append(&from_list, from);
895
896 /* mutt_default_from() does not use $real_name if the real name is not set
897 * in $from, so we add it here. The reason it is not added in
898 * mutt_default_from() is that during normal sending, we execute
899 * send-hooks and set the real_name last so that it can be changed based
900 * upon message criteria. */
901 if (!from->personal)
902 {
903 const char *const c_real_name = cs_subset_string(sub, "real_name");
904 if (c_real_name)
905 from->personal = buf_new(c_real_name);
906 }
907
908 mutt_addrlist_qualify(&from_list, fqdn);
909
910 rfc2047_encode_addrlist(&from_list, "Resent-From");
911 if (mutt_addrlist_to_intl(&from_list, &err))
912 {
913 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
914 FREE(&err);
915 mutt_addrlist_clear(&from_list);
916 return -1;
917 }
918 struct Buffer *resent_from = buf_pool_get();
919 mutt_addrlist_write(&from_list, resent_from, false);
920
921 OptNewsSend = false;
922
923 /* prepare recipient list. idna conversion appears to happen before this
924 * function is called, since the user receives confirmation of the address
925 * list being bounced to. */
926 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
927 mutt_addrlist_copy(&resent_to, to, false);
928 rfc2047_encode_addrlist(&resent_to, "Resent-To");
929 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
930 mutt_addrlist_clear(&resent_to);
931 mutt_addrlist_clear(&from_list);
932 buf_pool_release(&resent_from);
933 return rc;
934}
935
941static void set_noconv_flags(struct Body *b, bool flag)
942{
943 for (; b; b = b->next)
944 {
945 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
946 {
947 set_noconv_flags(b->parts, flag);
948 }
949 else if ((b->type == TYPE_TEXT) && b->noconv)
950 {
951 if (flag)
952 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
953 else
954 mutt_param_delete(&b->parameter, "x-mutt-noconv");
955 }
956 }
957}
958
971int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
972 char *fcc, char **finalpath, struct ConfigSubset *sub)
973{
974 char fcc_tok[PATH_MAX] = { 0 };
975
976 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
977
978 char *tok = strtok(fcc_tok, ",");
979 if (!tok)
980 return -1;
981
982 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
983 /* expand_path already called above for the first token */
984 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
985 if (status != 0)
986 return status;
987
988 struct Buffer *fcc_expanded = buf_pool_get();
989 while ((tok = strtok(NULL, ",")))
990 {
991 if (*tok == '\0')
992 continue;
993
994 /* Only call expand_path if tok has some data */
995 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
996 buf_strcpy(fcc_expanded, tok);
997 expand_path(fcc_expanded, false);
998 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n",
999 buf_string(fcc_expanded));
1000 status = mutt_write_fcc(buf_string(fcc_expanded), e, msgid, post, fcc, finalpath, sub);
1001 if (status != 0)
1002 {
1003 buf_pool_release(&fcc_expanded);
1004 return status;
1005 }
1006 }
1007
1008 buf_pool_release(&fcc_expanded);
1009 return 0;
1010}
1011
1024int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1025 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1026{
1027 struct Message *msg = NULL;
1028 struct Buffer *tempfile = NULL;
1029 FILE *fp_tmp = NULL;
1030 int rc = -1;
1031 bool need_mailbox_cleanup = false;
1032 struct stat st = { 0 };
1033 MsgOpenFlags onm_flags;
1034
1035 if (post)
1036 set_noconv_flags(e->body, true);
1037
1038#ifdef RECORD_FOLDER_HOOK
1039 exec_folder_hook(path, NULL);
1040#endif
1041 struct Mailbox *m_fcc = mx_path_resolve(path);
1042 bool old_append = m_fcc->append;
1043 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1044 {
1045 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1046 goto done;
1047 }
1048
1049 /* We need to add a Content-Length field to avoid problems where a line in
1050 * the message body begins with "From " */
1051 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1052 {
1053 tempfile = buf_pool_get();
1054 buf_mktemp(tempfile);
1055 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1056 if (!fp_tmp)
1057 {
1058 mutt_perror("%s", buf_string(tempfile));
1059 mx_mbox_close(m_fcc);
1060 goto done;
1061 }
1062 /* remember new mail status before appending message */
1063 need_mailbox_cleanup = true;
1064 stat(path, &st);
1065 }
1066
1067 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1068 onm_flags = MUTT_ADD_FROM;
1069 if (post)
1070 onm_flags |= MUTT_SET_DRAFT;
1071 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1072 if (!msg)
1073 {
1074 mutt_file_fclose(&fp_tmp);
1075 mx_mbox_close(m_fcc);
1076 goto done;
1077 }
1078
1079 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1080
1081 /* post == 1 => postpone message.
1082 * post == 0 => Normal mode. */
1083 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1085 c_crypt_protected_headers_read &&
1087 sub);
1088
1089 /* (postponement) if this was a reply of some sort, <msgid> contains the
1090 * Message-ID: of message replied to. Save it using a special X-Mutt-
1091 * header so it can be picked up if the message is recalled at a later
1092 * point in time. This will allow the message to be marked as replied if
1093 * the same mailbox is still open. */
1094 if (post && msgid)
1095 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1096
1097 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1098 * it can be picked up when the message is recalled */
1099 if (post && fcc)
1100 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1101
1102 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1103 fprintf(msg->fp, "Status: RO\n");
1104
1105 /* (postponement) if the mail is to be signed or encrypted, save this info */
1106 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1107 {
1108 fputs("Mutt-PGP: ", msg->fp);
1109 if (e->security & SEC_ENCRYPT)
1110 fputc('E', msg->fp);
1111 if (e->security & SEC_OPPENCRYPT)
1112 fputc('O', msg->fp);
1113 if (e->security & SEC_SIGN)
1114 {
1115 fputc('S', msg->fp);
1116
1117 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1118 if (c_pgp_sign_as)
1119 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1120 }
1121 if (e->security & SEC_INLINE)
1122 fputc('I', msg->fp);
1123#ifdef USE_AUTOCRYPT
1124 if (e->security & SEC_AUTOCRYPT)
1125 fputc('A', msg->fp);
1127 fputc('Z', msg->fp);
1128#endif
1129 fputc('\n', msg->fp);
1130 }
1131
1132 /* (postponement) if the mail is to be signed or encrypted, save this info */
1133 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1134 {
1135 fputs("Mutt-SMIME: ", msg->fp);
1136 if (e->security & SEC_ENCRYPT)
1137 {
1138 fputc('E', msg->fp);
1139
1140 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1141 if (c_smime_encrypt_with)
1142 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1143 }
1144 if (e->security & SEC_OPPENCRYPT)
1145 fputc('O', msg->fp);
1146 if (e->security & SEC_SIGN)
1147 {
1148 fputc('S', msg->fp);
1149
1150 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1151 if (c_smime_sign_as)
1152 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1153 }
1154 if (e->security & SEC_INLINE)
1155 fputc('I', msg->fp);
1156 fputc('\n', msg->fp);
1157 }
1158
1159 if (fp_tmp)
1160 {
1161 mutt_write_mime_body(e->body, fp_tmp, sub);
1162
1163 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1164 * will happen, and it can cause problems parsing the mailbox later. */
1165 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1166 mutt_file_seek(fp_tmp, 0, SEEK_END))
1167 {
1168 fputc('\n', fp_tmp);
1169 }
1170
1171 fflush(fp_tmp);
1172 if (ferror(fp_tmp))
1173 {
1174 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1175 mutt_file_fclose(&fp_tmp);
1176 unlink(buf_string(tempfile));
1177 mx_msg_commit(m_fcc, msg); /* XXX really? */
1178 mx_msg_close(m_fcc, &msg);
1179 mx_mbox_close(m_fcc);
1180 goto done;
1181 }
1182
1183 /* count the number of lines */
1184 int lines = 0;
1185 char line_buf[1024] = { 0 };
1186 rewind(fp_tmp);
1187 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1188 lines++;
1189 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1190 fprintf(msg->fp, "Lines: %d\n\n", lines);
1191
1192 /* copy the body and clean up */
1193 rewind(fp_tmp);
1194 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1195 if (mutt_file_fclose(&fp_tmp) != 0)
1196 rc = -1;
1197 /* if there was an error, leave the temp version */
1198 if (rc >= 0)
1199 {
1200 unlink(buf_string(tempfile));
1201 rc = 0;
1202 }
1203 }
1204 else
1205 {
1206 fputc('\n', msg->fp); /* finish off the header */
1207 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1208 }
1209
1210 if (mx_msg_commit(m_fcc, msg) != 0)
1211 rc = -1;
1212 else if (finalpath)
1213 *finalpath = mutt_str_dup(msg->committed_path);
1214 mx_msg_close(m_fcc, &msg);
1215 mx_mbox_close(m_fcc);
1216
1217 if (!post && need_mailbox_cleanup)
1218 mailbox_restore_timestamp(path, &st);
1219
1220 if (post)
1221 set_noconv_flags(e->body, false);
1222
1223done:
1224 m_fcc->append = old_append;
1225 mailbox_free(&m_fcc);
1226
1227#ifdef RECORD_FOLDER_HOOK
1228 /* We ran a folder hook for the destination mailbox,
1229 * now we run it for the user's current mailbox */
1230 const struct Mailbox *m_cur = get_current_mailbox();
1231 if (m_cur)
1232 exec_folder_hook(m_cur->path, m_cur->desc);
1233#endif
1234
1235 if (fp_tmp)
1236 {
1237 mutt_file_fclose(&fp_tmp);
1238 unlink(buf_string(tempfile));
1239 }
1240 buf_pool_release(&tempfile);
1241
1242 return rc;
1243}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:685
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
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:713
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1489
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:1215
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:1257
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1302
Email Address Handling.
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:627
GUI display the mailboxes in a side panel.
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.
struct Content * mutt_get_content_info(const char *fname, struct Body *b, struct ConfigSubset *sub)
Analyze file to determine MIME encoding to use.
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_email.c:432
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_email.c:112
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_email.c:917
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition copy_email.h:59
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition copy_email.h:47
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:40
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:64
#define CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition copy_email.h:69
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:44
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:48
#define CH_MIME
Ignore MIME fields.
Definition copy_email.h:65
#define CH_NOQFROM
Ignore ">From " line.
Definition copy_email.h:71
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition copy_email.h:54
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition copy_email.h:37
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition copy_email.h:67
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition copy_email.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:45
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
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:131
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
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
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:1848
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:468
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition parse.c:371
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1210
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1506
char * msgid_generate(void)
Generate a Message-ID.
Message Id Expando definitions.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
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:678
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:192
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:1351
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
#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:54
Global variables.
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1938
void exec_folder_hook(const char *path, const char *desc)
Perform a folder hook.
Definition exec.c:64
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:721
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
@ 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:108
void mutt_date_make_date(struct Buffer *buf, bool local)
Write a date in RFC822 format to a buffer.
Definition date.c:398
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:457
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:228
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:217
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:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition string.c:613
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:364
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:586
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
#define PATH_MAX
Definition mutt.h:49
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Mailbox helper functions.
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1182
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1136
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1041
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1161
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
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:41
#define MUTT_QUIET
Do not print any messages.
Definition mxapi.h:43
API for encryption/signing of emails.
#define SEC_INLINE
Email has an inline signature.
Definition lib.h:93
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:95
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition lib.h:84
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:94
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:104
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:99
#define SEC_NO_FLAGS
No flags are set.
Definition lib.h:85
#define SEC_ENCRYPT
Email is encrypted.
Definition lib.h:86
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:110
#define WithCrypto
Definition lib.h:124
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition lib.h:96
#define SEC_SIGN
Email is signed.
Definition lib.h:87
#define mutt_file_fopen_masked(PATH, MODE)
Open a file with proper permissions, tracked for debugging.
Definition neomutt.h:90
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:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define TAILQ_EMPTY(head)
Definition queue.h:778
void rfc2047_encode_addrlist(struct AddressList *al, const char *tag)
Encode any RFC2047 headers, where required, in an Address list.
Definition rfc2047.c:770
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:632
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition rfc2047.c:836
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:665
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition rfc2047.c:861
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:302
Convenience wrapper for the send headers.
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:578
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:757
Convenience wrapper for the send headers.
@ MUTT_WRITE_HEADER_FCC
fcc mode, like normal mode but for Bcc header
Definition header.h:39
@ MUTT_WRITE_HEADER_POSTPONE
A postponed Email, just the envelope info.
Definition header.h:40
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1404
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition send.c:1280
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:941
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:713
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:883
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:613
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:971
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition sendlib.c:785
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition sendlib.c:673
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:572
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:746
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:1024
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:811
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:298
Send email using sendmail.
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition smtp.c:1107
Send email to an SMTP server.
#define NONULL(x)
Definition string2.h:44
#define SKIPWS(ch)
Definition string2.h:52
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
The body of an email.
Definition body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h: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:46
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:78
bool append
Mailbox is opened in append mode.
Definition mailbox.h:108
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
struct ConfigSubset * sub
Inherited config items.
Definition mailbox.h:82
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
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:58
char * home_dir
User's home directory.
Definition neomutt.h:56
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