NeoMutt  2025-12-11-980-ge38c27
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;
79 char *q = NULL;
80 char *ct = NULL;
81 char buf[PATH_MAX] = { 0 };
82 char subtype[256] = { 0 };
83 char xtype[256] = { 0 };
84 int sze;
85 int cur_sze = 0;
86 bool found_mimetypes = false;
88
89 int szf = mutt_str_len(path);
90
91 for (int count = 0; count < 4; count++)
92 {
93 /* can't use strtok() because we use it in an inner loop below, so use
94 * a switch statement here instead. */
95 switch (count)
96 {
97 /* last file with last entry to match wins type/xtype */
98 case 0:
99 /* check default unix mimetypes location first */
100 mutt_str_copy(buf, "/etc/mime.types", sizeof(buf));
101 break;
102 case 1:
103 mutt_str_copy(buf, SYSCONFDIR "/mime.types", sizeof(buf));
104 break;
105 case 2:
106 mutt_str_copy(buf, PKGDATADIR "/mime.types", sizeof(buf));
107 break;
108 case 3:
109 snprintf(buf, sizeof(buf), "%s/.mime.types", NONULL(NeoMutt->home_dir));
110 break;
111 default:
112 mutt_debug(LL_DEBUG1, "Internal error, count = %d\n", count);
113 goto bye; /* shouldn't happen */
114 }
115
116 fp = mutt_file_fopen(buf, "r");
117 if (fp)
118 {
119 found_mimetypes = true;
120
121 while (fgets(buf, sizeof(buf) - 1, fp))
122 {
123 /* weed out any comments */
124 p = strchr(buf, '#');
125 if (p)
126 *p = '\0';
127
128 /* remove any leading space. */
129 ct = buf;
130 SKIPWS(ct);
131
132 /* position on the next field in this line */
133 p = strpbrk(ct, " \t");
134 if (!p)
135 continue;
136 *p++ = 0;
137 SKIPWS(p);
138
139 /* cycle through the file extensions */
140 while ((p = strtok(p, " \t\n")))
141 {
142 sze = mutt_str_len(p);
143 if ((sze > cur_sze) && (szf >= sze) && mutt_istr_equal(path + szf - sze, p) &&
144 ((szf == sze) || (path[szf - sze - 1] == '.')))
145 {
146 /* get the content-type */
147
148 p = strchr(ct, '/');
149 if (!p)
150 {
151 /* malformed line, just skip it. */
152 break;
153 }
154 *p++ = 0;
155
156 for (q = p; *q && !mutt_isspace(*q); q++)
157 ; // do nothing
158
159 mutt_strn_copy(subtype, p, q - p, sizeof(subtype));
160
162 if (type == TYPE_OTHER)
163 mutt_str_copy(xtype, ct, sizeof(xtype));
164
165 cur_sze = sze;
166 }
167 p = NULL;
168 }
169 }
170 mutt_file_fclose(&fp);
171 }
172 }
173
174bye:
175
176 /* no mime.types file found */
177 if (!found_mimetypes)
178 {
179 mutt_error(_("Could not find any mime.types file"));
180 }
181
182 if ((type != TYPE_OTHER) || (*xtype != '\0'))
183 {
184 b->type = type;
185 mutt_str_replace(&b->subtype, subtype);
186 mutt_str_replace(&b->xtype, xtype);
187 }
188
189 return type;
190}
191
198static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
199{
200 struct Buffer *buf = NULL;
201 struct State state = { 0 };
202 struct stat st = { 0 };
203
204 for (; b; b = b->next)
205 {
206 if (b->type == TYPE_MULTIPART)
207 {
208 b->encoding = ENC_7BIT;
209 transform_to_7bit(b->parts, fp_in, sub);
210 }
211 else if (mutt_is_message_type(b->type, b->subtype))
212 {
213 mutt_message_to_7bit(b, fp_in, sub);
214 }
215 else
216 {
217 b->noconv = true;
218 b->force_charset = true;
219
220 /* Because of the potential recursion in message types, we
221 * restrict the lifetime of the buffer tightly */
222 buf = buf_pool_get();
223 buf_mktemp(buf);
224 state.fp_out = mutt_file_fopen(buf_string(buf), "w");
225 if (!state.fp_out)
226 {
227 mutt_perror("fopen");
228 buf_pool_release(&buf);
229 return;
230 }
231 state.fp_in = fp_in;
232 mutt_decode_attachment(b, &state);
233 mutt_file_fclose(&state.fp_out);
234 FREE(&b->d_filename);
235 b->d_filename = b->filename;
236 b->filename = buf_strdup(buf);
237 buf_pool_release(&buf);
238 b->unlink = true;
239 if (stat(b->filename, &st) == -1)
240 {
241 mutt_perror("stat");
242 return;
243 }
244 b->length = st.st_size;
245
246 mutt_update_encoding(b, sub);
247 if (b->encoding == ENC_8BIT)
249 else if (b->encoding == ENC_BINARY)
250 b->encoding = ENC_BASE64;
251 }
252 }
253}
254
261void mutt_message_to_7bit(struct Body *b, FILE *fp, struct ConfigSubset *sub)
262{
263 struct Buffer *tempfile = buf_pool_get();
264 FILE *fp_in = NULL;
265 FILE *fp_out = NULL;
266 struct stat st = { 0 };
267
268 if (!b->filename && fp)
269 {
270 fp_in = fp;
271 }
272 else if (!b->filename || !(fp_in = mutt_file_fopen(b->filename, "r")))
273 {
274 mutt_error(_("Could not open %s"), b->filename ? b->filename : "(null)");
275 return;
276 }
277 else
278 {
279 b->offset = 0;
280 if (stat(b->filename, &st) == -1)
281 {
282 mutt_perror("stat");
283 mutt_file_fclose(&fp_in);
284 goto cleanup;
285 }
286 b->length = st.st_size;
287 }
288
289 /* Avoid buffer pool due to recursion */
290 buf_mktemp(tempfile);
291 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
292 if (!fp_out)
293 {
294 mutt_perror("fopen");
295 goto cleanup;
296 }
297
298 if (!mutt_file_seek(fp_in, b->offset, SEEK_SET))
299 {
300 goto cleanup;
301 }
302 b->parts = mutt_rfc822_parse_message(fp_in, b);
303
304 transform_to_7bit(b->parts, fp_in, sub);
305
306 mutt_copy_hdr(fp_in, fp_out, b->offset, b->offset + b->length,
307 CH_MIME | CH_NONEWLINE | CH_XMIT, NULL, 0);
308
309 fputs("MIME-Version: 1.0\n", fp_out);
310 mutt_write_mime_header(b->parts, fp_out, sub);
311 fputc('\n', fp_out);
312 mutt_write_mime_body(b->parts, fp_out, sub);
313
314 if (fp_in != fp)
315 mutt_file_fclose(&fp_in);
316 mutt_file_fclose(&fp_out);
317
318 b->encoding = ENC_7BIT;
319 FREE(&b->d_filename);
320 b->d_filename = b->filename;
321 if (b->filename && b->unlink)
322 unlink(b->filename);
323 b->filename = buf_strdup(tempfile);
324 b->unlink = true;
325 if (stat(b->filename, &st) == -1)
326 {
327 mutt_perror("stat");
328 goto cleanup;
329 }
330 b->length = st.st_size;
332 b->email->body = NULL;
333
334cleanup:
335 if (fp_in && (fp_in != fp))
336 mutt_file_fclose(&fp_in);
337
338 if (fp_out)
339 {
340 mutt_file_fclose(&fp_out);
341 mutt_file_unlink(buf_string(tempfile));
342 }
343
344 buf_pool_release(&tempfile);
345}
346
353static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
354{
355 const bool c_allow_8bit = cs_subset_bool(sub, "allow_8bit");
356 if (b->type == TYPE_TEXT)
357 {
358 const bool c_encode_from = cs_subset_bool(sub, "encode_from");
359 char send_charset[128] = { 0 };
360 char *chsname = mutt_body_get_charset(b, send_charset, sizeof(send_charset));
361 if ((info->lobin && !mutt_istr_startswith(chsname, "iso-2022")) ||
362 (info->linemax > 990) || (info->from && c_encode_from))
363 {
365 }
366 else if (info->hibin)
367 {
368 b->encoding = c_allow_8bit ? ENC_8BIT : ENC_QUOTED_PRINTABLE;
369 }
370 else
371 {
372 b->encoding = ENC_7BIT;
373 }
374 }
375 else if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
376 {
377 if (info->lobin || info->hibin)
378 {
379 if (c_allow_8bit && !info->lobin)
380 b->encoding = ENC_8BIT;
381 else
382 mutt_message_to_7bit(b, NULL, sub);
383 }
384 else
385 {
386 b->encoding = ENC_7BIT;
387 }
388 }
389 else if ((b->type == TYPE_APPLICATION) && mutt_istr_equal(b->subtype, "pgp-keys"))
390 {
391 b->encoding = ENC_7BIT;
392 }
393 else
394 {
395 /* Determine which encoding is smaller */
396 if (1.33f * (float) (info->lobin + info->hibin + info->ascii) <
397 3.0f * (float) (info->lobin + info->hibin) + (float) info->ascii)
398 {
399 b->encoding = ENC_BASE64;
400 }
401 else
402 {
404 }
405 }
406}
407
413{
414 b->stamp = mutt_date_now();
415}
416
424void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
425{
426 struct Content *info = NULL;
427 char chsbuf[256] = { 0 };
428
429 /* override noconv when it's us-ascii */
430 if (mutt_ch_is_us_ascii(mutt_body_get_charset(b, chsbuf, sizeof(chsbuf))))
431 b->noconv = false;
432
433 if (!b->force_charset && !b->noconv)
434 mutt_param_delete(&b->parameter, "charset");
435
436 info = mutt_get_content_info(b->filename, b, sub);
437 if (!info)
438 return;
439
440 set_encoding(b, info, sub);
442
443 FREE(&b->content);
444 b->content = info;
445}
446
456struct Body *mutt_make_message_attach(struct Mailbox *m, struct Email *e,
457 bool attach_msg, struct ConfigSubset *sub)
458{
459 struct Body *body = NULL;
460 FILE *fp = NULL;
461 CopyMessageFlags cmflags;
463
464 /* Ensure we have a valid passphrase before decrypting encrypted messages */
465 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
466 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
467 if (WithCrypto)
468 {
469 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
470 {
472 return NULL;
473 }
474 }
475
476 /* Create a temporary file to hold the serialised message/rfc822 body */
477 struct Buffer *tempfile = buf_pool_get();
478 buf_mktemp(tempfile);
479 fp = mutt_file_fopen_masked(buf_string(tempfile), "w+");
480 if (!fp)
481 {
482 buf_pool_release(&tempfile);
483 return NULL;
484 }
485
486 /* Build a new Body representing the message/rfc822 attachment */
487 body = mutt_body_new();
488 body->type = TYPE_MESSAGE;
489 body->subtype = mutt_str_dup("rfc822");
490 body->filename = mutt_str_dup(buf_string(tempfile));
491 body->unlink = true;
492 body->use_disp = false;
493 body->disposition = DISP_INLINE;
494 body->noconv = true;
495
496 buf_pool_release(&tempfile);
497
498 struct Message *msg = mx_msg_open(m, e);
499 if (!msg)
500 {
501 mutt_body_free(&body);
503 return NULL;
504 }
506
507 /* Determine copy flags based on decode/decrypt config options.
508 * When MIME-forwarding with decode, strip MIME headers and convert charset.
509 * When forwarding encrypted content with decrypt, handle PGP/SMIME separately. */
510 CopyHeaderFlags chflags = CH_XMIT;
511 cmflags = MUTT_CM_NONE;
512
513 /* If we are attaching a message, ignore `$mime_forward_decode` */
514 if (!attach_msg && c_mime_forward_decode)
515 {
516 chflags |= CH_MIME | CH_TXTPLAIN;
519 pgp &= ~PGP_ENCRYPT;
521 pgp &= ~SMIME_ENCRYPT;
522 }
523 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
524 {
526 {
527 chflags |= CH_MIME | CH_NONEWLINE;
528 cmflags = MUTT_CM_DECODE_PGP;
529 pgp &= ~PGP_ENCRYPT;
530 }
531 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
533 {
534 chflags |= CH_MIME | CH_TXTPLAIN;
536 pgp &= ~PGP_ENCRYPT;
537 }
538 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
540 {
541 chflags |= CH_MIME | CH_NONEWLINE;
542 cmflags = MUTT_CM_DECODE_SMIME;
543 pgp &= ~SMIME_ENCRYPT;
544 }
545 }
546
547 /* Copy the message content into the temp file, then reparse the headers */
548 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
549 mx_msg_close(m, &msg);
550
551 fflush(fp);
552 rewind(fp);
553
554 body->email = email_new();
555 body->email->offset = 0;
556 /* we don't need the user headers here */
557 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
558 if (WithCrypto)
559 body->email->security = pgp;
560 mutt_update_encoding(body, sub);
561 body->parts = body->email->body;
562
564
565 return body;
566}
567
575static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
576{
577 FILE *fp = NULL;
578 FILE *fp_err = NULL;
579 char *buf = NULL;
580 size_t buflen = 0;
581 pid_t pid;
582 struct Buffer *cmd = buf_pool_get();
583
584 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
585
586 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
587
588 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, NeoMutt->env);
589 if (pid < 0)
590 {
591 mutt_error(_("Error running \"%s\""), buf_string(cmd));
592 buf_pool_release(&cmd);
593 return;
594 }
595 buf_pool_release(&cmd);
596
597 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NONE);
598 if (buf)
599 {
600 if (strchr(buf, '/'))
602 FREE(&buf);
603 }
604
605 mutt_file_fclose(&fp);
606 mutt_file_fclose(&fp_err);
607 filter_wait(pid);
608}
609
617struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
618{
619 if (!path || (path[0] == '\0'))
620 return NULL;
621
622 struct Body *b = mutt_body_new();
623 b->filename = mutt_str_dup(path);
624
625 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
626 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
627
628 if (c_mime_type_query_command && c_mime_type_query_first)
629 run_mime_type_query(b, sub);
630
631 /* Attempt to determine the appropriate content-type based on the filename
632 * suffix. */
633 if (!b->subtype)
634 mutt_lookup_mime_type(b, path);
635
636 if (!b->subtype && c_mime_type_query_command && !c_mime_type_query_first)
637 {
638 run_mime_type_query(b, sub);
639 }
640
641 struct Content *info = mutt_get_content_info(path, b, sub);
642 if (!info)
643 {
644 mutt_body_free(&b);
645 return NULL;
646 }
647
648 if (!b->subtype)
649 {
650 if ((info->nulbin == 0) &&
651 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
652 {
653 /* Statistically speaking, there should be more than 10% "lobin"
654 * chars if this is really a binary file... */
655 b->type = TYPE_TEXT;
656 b->subtype = mutt_str_dup("plain");
657 }
658 else
659 {
661 b->subtype = mutt_str_dup("octet-stream");
662 }
663 }
664
665 FREE(&info);
666 mutt_update_encoding(b, sub);
667 return b;
668}
669
677static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
678{
679 char *tmp = NULL;
680 char *p = NULL;
681 int i;
682
683 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
684
685 struct ListNode *np = NULL;
686 STAILQ_FOREACH(np, h, entries)
687 {
688 p = strchr(NONULL(np->data), ':');
689 if (!p)
690 continue;
691
692 i = p - np->data;
693 p = mutt_str_skip_email_wsp(p + 1);
694 tmp = mutt_str_dup(p);
695
696 if (!tmp)
697 continue;
698
699 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
700 MUTT_MEM_REALLOC(&np->data, i + 2 + mutt_str_len(tmp) + 1, char);
701
702 sprintf(np->data + i + 2, "%s", tmp);
703
704 FREE(&tmp);
705 }
706}
707
717const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
718{
719 const char *const c_hostname = cs_subset_string(sub, "hostname");
720 if (!c_hostname || (c_hostname[0] == '@'))
721 return NULL;
722
723 const char *p = c_hostname;
724
725 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
726 if (may_hide_host && c_hidden_host)
727 {
728 p = strchr(c_hostname, '.');
729 if (p)
730 p++;
731
732 // sanity check: don't hide the host if the fqdn is something like example.com
733 if (!p || !strchr(p, '.'))
734 p = c_hostname;
735 }
736
737 return p;
738}
739
750void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
751{
752 if (final)
753 {
754 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
755 {
756 /* some MTA's will put an Apparently-To: header field showing the Bcc:
757 * recipients if there is no To: or Cc: field, so attempt to suppress
758 * it by using an empty To: field. */
759 struct Address *to = mutt_addr_new();
760 to->group = true;
761 mutt_addrlist_append(&env->to, to);
763
764 char buf[1024] = { 0 };
765 buf[0] = '\0';
766 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
767
768 buf_strcpy(to->mailbox, buf);
769 }
770
771 mutt_set_followup_to(env, sub);
772
773 if (!env->message_id)
774 env->message_id = msgid_generate();
775 }
776
777 /* Take care of 8-bit => 7-bit conversion. */
779 encode_headers(&env->userhdrs, sub);
780}
781
790{
791 struct ListNode *item = NULL;
792 STAILQ_FOREACH(item, &env->userhdrs, entries)
793 {
794 rfc2047_decode(&item->data);
795 }
796
798
799 /* back conversions */
801}
802
815static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
816 struct AddressList *to, const char *resent_from,
817 struct AddressList *env_from, struct ConfigSubset *sub)
818{
819 if (!e)
820 return -1;
821
822 int rc = 0;
823
824 struct Buffer *tempfile = buf_pool_get();
825 buf_mktemp(tempfile);
826 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
827 if (fp_tmp)
828 {
830
831 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
832 if (!c_bounce_delivered)
833 chflags |= CH_WEED_DELIVERED;
834
835 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
836 {
837 (void) mutt_file_fclose(&fp_tmp);
838 return -1;
839 }
840 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
841
842 struct Buffer *date = buf_pool_get();
843 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
844 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
845 buf_pool_release(&date);
846
847 char *msgid_str = msgid_generate();
848 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
849 FREE(&msgid_str);
850 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
851 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
852 fputc('\n', fp_tmp);
853 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
854 if (mutt_file_fclose(&fp_tmp) != 0)
855 {
856 mutt_perror("%s", buf_string(tempfile));
857 unlink(buf_string(tempfile));
858 return -1;
859 }
860 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
861 if (c_smtp_url)
862 {
863 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
864 (e->body->encoding == ENC_8BIT), sub);
865 }
866 else
867 {
868 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
869 (e->body->encoding == ENC_8BIT), sub);
870 }
871 }
872
873 buf_pool_release(&tempfile);
874 return rc;
875}
876
887int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
888 struct AddressList *to, struct ConfigSubset *sub)
889{
890 if (!fp || !e || !to || TAILQ_EMPTY(to))
891 return -1;
892
893 const char *fqdn = mutt_fqdn(true, sub);
894 char *err = NULL;
895
896 struct Address *from = mutt_default_from(sub);
897 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
898 mutt_addrlist_append(&from_list, from);
899
900 /* mutt_default_from() does not use $real_name if the real name is not set
901 * in $from, so we add it here. The reason it is not added in
902 * mutt_default_from() is that during normal sending, we execute
903 * send-hooks and set the real_name last so that it can be changed based
904 * upon message criteria. */
905 if (!from->personal)
906 {
907 const char *const c_real_name = cs_subset_string(sub, "real_name");
908 if (c_real_name)
909 from->personal = buf_new(c_real_name);
910 }
911
912 mutt_addrlist_qualify(&from_list, fqdn);
913
914 rfc2047_encode_addrlist(&from_list, "Resent-From");
915 if (mutt_addrlist_to_intl(&from_list, &err))
916 {
917 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
918 FREE(&err);
919 mutt_addrlist_clear(&from_list);
920 return -1;
921 }
922 struct Buffer *resent_from = buf_pool_get();
923 mutt_addrlist_write(&from_list, resent_from, false);
924
925 OptNewsSend = false;
926
927 /* prepare recipient list. idna conversion appears to happen before this
928 * function is called, since the user receives confirmation of the address
929 * list being bounced to. */
930 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
931 mutt_addrlist_copy(&resent_to, to, false);
932 rfc2047_encode_addrlist(&resent_to, "Resent-To");
933 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
934 mutt_addrlist_clear(&resent_to);
935 mutt_addrlist_clear(&from_list);
936 buf_pool_release(&resent_from);
937 return rc;
938}
939
945static void set_noconv_flags(struct Body *b, bool flag)
946{
947 for (; b; b = b->next)
948 {
949 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
950 {
951 set_noconv_flags(b->parts, flag);
952 }
953 else if ((b->type == TYPE_TEXT) && b->noconv)
954 {
955 if (flag)
956 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
957 else
958 mutt_param_delete(&b->parameter, "x-mutt-noconv");
959 }
960 }
961}
962
975int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
976 char *fcc, char **finalpath, struct ConfigSubset *sub)
977{
978 char fcc_tok[PATH_MAX] = { 0 };
979
980 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
981
982 char *tok = strtok(fcc_tok, ",");
983 if (!tok)
984 return -1;
985
986 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
987 /* expand_path already called above for the first token */
988 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
989 if (status != 0)
990 return status;
991
992 struct Buffer *fcc_expanded = buf_pool_get();
993 while ((tok = strtok(NULL, ",")))
994 {
995 if (*tok == '\0')
996 continue;
997
998 /* Only call expand_path if tok has some data */
999 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
1000 buf_strcpy(fcc_expanded, tok);
1001 expand_path(fcc_expanded, false);
1002 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n",
1003 buf_string(fcc_expanded));
1004 status = mutt_write_fcc(buf_string(fcc_expanded), e, msgid, post, fcc, finalpath, sub);
1005 if (status != 0)
1006 {
1007 buf_pool_release(&fcc_expanded);
1008 return status;
1009 }
1010 }
1011
1012 buf_pool_release(&fcc_expanded);
1013 return 0;
1014}
1015
1028int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1029 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1030{
1031 struct Message *msg = NULL;
1032 struct Buffer *tempfile = NULL;
1033 FILE *fp_tmp = NULL;
1034 int rc = -1;
1035 bool need_mailbox_cleanup = false;
1036 struct stat st = { 0 };
1037 MsgOpenFlags onm_flags;
1038
1039 if (post)
1040 set_noconv_flags(e->body, true);
1041
1042#ifdef RECORD_FOLDER_HOOK
1043 exec_folder_hook(path, NULL);
1044#endif
1045 struct Mailbox *m_fcc = mx_path_resolve(path);
1046 bool old_append = m_fcc->append;
1047 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1048 {
1049 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1050 goto done;
1051 }
1052
1053 /* We need to add a Content-Length field to avoid problems where a line in
1054 * the message body begins with "From " */
1055 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1056 {
1057 tempfile = buf_pool_get();
1058 buf_mktemp(tempfile);
1059 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1060 if (!fp_tmp)
1061 {
1062 mutt_perror("%s", buf_string(tempfile));
1063 mx_mbox_close(m_fcc);
1064 goto done;
1065 }
1066 /* remember new mail status before appending message */
1067 need_mailbox_cleanup = true;
1068 stat(path, &st);
1069 }
1070
1071 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1072 onm_flags = MUTT_ADD_FROM;
1073 if (post)
1074 onm_flags |= MUTT_SET_DRAFT;
1075 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1076 if (!msg)
1077 {
1078 mutt_file_fclose(&fp_tmp);
1079 mx_mbox_close(m_fcc);
1080 goto done;
1081 }
1082
1083 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1084
1085 /* post == 1 => postpone message.
1086 * post == 0 => Normal mode. */
1087 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1089 c_crypt_protected_headers_read &&
1091 sub);
1092
1093 /* (postponement) if this was a reply of some sort, <msgid> contains the
1094 * Message-ID: of message replied to. Save it using a special X-Mutt-
1095 * header so it can be picked up if the message is recalled at a later
1096 * point in time. This will allow the message to be marked as replied if
1097 * the same mailbox is still open. */
1098 if (post && msgid)
1099 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1100
1101 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1102 * it can be picked up when the message is recalled */
1103 if (post && fcc)
1104 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1105
1106 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1107 fprintf(msg->fp, "Status: RO\n");
1108
1109 /* (postponement) if the mail is to be signed or encrypted, save this info */
1110 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1111 {
1112 fputs("Mutt-PGP: ", msg->fp);
1113 if (e->security & SEC_ENCRYPT)
1114 fputc('E', msg->fp);
1115 if (e->security & SEC_OPPENCRYPT)
1116 fputc('O', msg->fp);
1117 if (e->security & SEC_SIGN)
1118 {
1119 fputc('S', msg->fp);
1120
1121 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1122 if (c_pgp_sign_as)
1123 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1124 }
1125 if (e->security & SEC_INLINE)
1126 fputc('I', msg->fp);
1127#ifdef USE_AUTOCRYPT
1128 if (e->security & SEC_AUTOCRYPT)
1129 fputc('A', msg->fp);
1131 fputc('Z', msg->fp);
1132#endif
1133 fputc('\n', msg->fp);
1134 }
1135
1136 /* (postponement) if the mail is to be signed or encrypted, save this info */
1137 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1138 {
1139 fputs("Mutt-SMIME: ", msg->fp);
1140 if (e->security & SEC_ENCRYPT)
1141 {
1142 fputc('E', msg->fp);
1143
1144 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1145 if (c_smime_encrypt_with)
1146 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1147 }
1148 if (e->security & SEC_OPPENCRYPT)
1149 fputc('O', msg->fp);
1150 if (e->security & SEC_SIGN)
1151 {
1152 fputc('S', msg->fp);
1153
1154 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1155 if (c_smime_sign_as)
1156 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1157 }
1158 if (e->security & SEC_INLINE)
1159 fputc('I', msg->fp);
1160 fputc('\n', msg->fp);
1161 }
1162
1163 if (fp_tmp)
1164 {
1165 mutt_write_mime_body(e->body, fp_tmp, sub);
1166
1167 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1168 * will happen, and it can cause problems parsing the mailbox later. */
1169 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1170 mutt_file_seek(fp_tmp, 0, SEEK_END))
1171 {
1172 fputc('\n', fp_tmp);
1173 }
1174
1175 fflush(fp_tmp);
1176 if (ferror(fp_tmp))
1177 {
1178 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1179 mutt_file_fclose(&fp_tmp);
1180 unlink(buf_string(tempfile));
1181 mx_msg_commit(m_fcc, msg); /* XXX really? */
1182 mx_msg_close(m_fcc, &msg);
1183 mx_mbox_close(m_fcc);
1184 goto done;
1185 }
1186
1187 /* count the number of lines */
1188 int lines = 0;
1189 char line_buf[1024] = { 0 };
1190 rewind(fp_tmp);
1191 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1192 lines++;
1193 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1194 fprintf(msg->fp, "Lines: %d\n\n", lines);
1195
1196 /* copy the body and clean up */
1197 rewind(fp_tmp);
1198 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1199 if (mutt_file_fclose(&fp_tmp) != 0)
1200 rc = -1;
1201 /* if there was an error, leave the temp version */
1202 if (rc >= 0)
1203 {
1204 unlink(buf_string(tempfile));
1205 rc = 0;
1206 }
1207 }
1208 else
1209 {
1210 fputc('\n', msg->fp); /* finish off the header */
1211 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1212 }
1213
1214 if (mx_msg_commit(m_fcc, msg) != 0)
1215 rc = -1;
1216 else if (finalpath)
1217 *finalpath = mutt_str_dup(msg->committed_path);
1218 mx_msg_close(m_fcc, &msg);
1219 mx_mbox_close(m_fcc);
1220
1221 if (!post && need_mailbox_cleanup)
1222 mailbox_restore_timestamp(path, &st);
1223
1224 if (post)
1225 set_noconv_flags(e->body, false);
1226
1227done:
1228 m_fcc->append = old_append;
1229 mailbox_free(&m_fcc);
1230
1231#ifdef RECORD_FOLDER_HOOK
1232 /* We ran a folder hook for the destination mailbox,
1233 * now we run it for the user's current mailbox */
1234 const struct Mailbox *m_cur = get_current_mailbox();
1235 if (m_cur)
1236 exec_folder_hook(m_cur->path, m_cur->desc);
1237#endif
1238
1239 if (fp_tmp)
1240 {
1241 mutt_file_fclose(&fp_tmp);
1242 unlink(buf_string(tempfile));
1243 }
1244 buf_pool_release(&tempfile);
1245
1246 return rc;
1247}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:776
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:687
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1475
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:715
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1496
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:1219
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:1261
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1306
Email Address Handling.
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:628
GUI display the mailboxes in a side panel.
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:311
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
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:920
@ MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:52
@ MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition copy_email.h:51
@ MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:44
@ MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:48
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
uint32_t CopyHeaderFlags
Definition copy_email.h:89
@ CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition copy_email.h:69
@ CH_WEED_DELIVERED
Weed eventual Delivered-To headers.
Definition copy_email.h:79
@ CH_MIME
Ignore MIME fields.
Definition copy_email.h:75
@ CH_TXTPLAIN
Generate text/plain MIME headers.
Definition copy_email.h:77
@ CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:74
@ CH_NOQFROM
Ignore ">From " line.
Definition copy_email.h:81
uint16_t CopyMessageFlags
Definition copy_email.h:55
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:610
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:1106
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:444
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
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:134
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:1964
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:433
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition parse.c:333
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition parse.c:1325
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1620
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:1352
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:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
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:1943
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:725
@ 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:400
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
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:220
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:678
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:614
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:587
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:1185
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:1139
struct Message * mx_msg_open_new(struct Mailbox *m, const struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition mx.c:1044
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition mx.c:1164
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
API for mailboxes.
uint8_t MsgOpenFlags
Definition mx.h:46
@ MUTT_ADD_FROM
add a From_ line
Definition mx.h:43
@ MUTT_SET_DRAFT
set the message draft flag
Definition mx.h:44
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
API for encryption/signing of emails.
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_NONE
No flags are set.
Definition lib.h:91
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_INLINE
Email has an inline signature.
Definition lib.h:99
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
@ SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:101
@ SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition lib.h:102
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define PGP_ENCRYPT
Email is PGP encrypted.
Definition lib.h:112
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define SMIME_ENCRYPT
Email is S/MIME encrypted.
Definition lib.h:118
#define WithCrypto
Definition lib.h:132
#define mutt_file_fopen_masked(PATH, MODE)
Open a file with proper permissions, tracked for debugging.
Definition neomutt.h:92
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:784
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:646
void rfc2047_decode_envelope(struct Envelope *env)
Decode the fields of an Envelope.
Definition rfc2047.c:850
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition rfc2047.c:679
void rfc2047_encode_envelope(struct Envelope *env)
Encode the fields of an Envelope.
Definition rfc2047.c:875
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:304
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:584
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
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:1405
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition send.c:1281
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:945
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:424
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:717
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:887
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:617
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:975
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition sendlib.c:789
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition sendlib.c:677
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition sendlib.c:353
static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition sendlib.c:575
static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition sendlib.c:198
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:750
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:456
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:1028
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:261
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition sendlib.c:412
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:815
Miscellaneous functions for sending an email.
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition sendmail.c:299
Send email using sendmail.
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition smtp.c:1136
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:81
bool append
Mailbox is opened in append mode.
Definition mailbox.h:111
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
struct ConfigSubset * sub
Inherited config items.
Definition mailbox.h:85
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:57
char * home_dir
User's home directory.
Definition neomutt.h:55
String list.
Definition slist.h:37
Keep track when processing files.
Definition state.h:54
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
#define buf_mktemp(buf)
Definition tmp.h:33