NeoMutt  2025-12-11-435-g4ac674
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 const bool c_mime_forward_decode = cs_subset_bool(sub, "mime_forward_decode");
462 const bool c_forward_decrypt = cs_subset_bool(sub, "forward_decrypt");
463 if (WithCrypto)
464 {
465 if ((c_mime_forward_decode || c_forward_decrypt) && (e->security & SEC_ENCRYPT))
466 {
468 return NULL;
469 }
470 }
471
472 struct Buffer *tempfile = buf_pool_get();
473 buf_mktemp(tempfile);
474 fp = mutt_file_fopen_masked(buf_string(tempfile), "w+");
475 if (!fp)
476 {
477 buf_pool_release(&tempfile);
478 return NULL;
479 }
480
481 body = mutt_body_new();
482 body->type = TYPE_MESSAGE;
483 body->subtype = mutt_str_dup("rfc822");
484 body->filename = mutt_str_dup(buf_string(tempfile));
485 body->unlink = true;
486 body->use_disp = false;
487 body->disposition = DISP_INLINE;
488 body->noconv = true;
489
490 buf_pool_release(&tempfile);
491
492 struct Message *msg = mx_msg_open(m, e);
493 if (!msg)
494 {
495 mutt_body_free(&body);
497 return NULL;
498 }
500
501 CopyHeaderFlags chflags = CH_XMIT;
502 cmflags = MUTT_CM_NO_FLAGS;
503
504 /* If we are attaching a message, ignore `$mime_forward_decode` */
505 if (!attach_msg && c_mime_forward_decode)
506 {
507 chflags |= CH_MIME | CH_TXTPLAIN;
510 pgp &= ~PGP_ENCRYPT;
512 pgp &= ~SMIME_ENCRYPT;
513 }
514 else if ((WithCrypto != 0) && c_forward_decrypt && (e->security & SEC_ENCRYPT))
515 {
517 {
518 chflags |= CH_MIME | CH_NONEWLINE;
519 cmflags = MUTT_CM_DECODE_PGP;
520 pgp &= ~PGP_ENCRYPT;
521 }
522 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
524 {
525 chflags |= CH_MIME | CH_TXTPLAIN;
527 pgp &= ~PGP_ENCRYPT;
528 }
529 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
531 {
532 chflags |= CH_MIME | CH_NONEWLINE;
533 cmflags = MUTT_CM_DECODE_SMIME;
534 pgp &= ~SMIME_ENCRYPT;
535 }
536 }
537
538 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
539 mx_msg_close(m, &msg);
540
541 fflush(fp);
542 rewind(fp);
543
544 body->email = email_new();
545 body->email->offset = 0;
546 /* we don't need the user headers here */
547 body->email->env = mutt_rfc822_read_header(fp, body->email, false, false);
548 if (WithCrypto)
549 body->email->security = pgp;
550 mutt_update_encoding(body, sub);
551 body->parts = body->email->body;
552
554
555 return body;
556}
557
565static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
566{
567 FILE *fp = NULL, *fp_err = NULL;
568 char *buf = NULL;
569 size_t buflen;
570 pid_t pid;
571 struct Buffer *cmd = buf_pool_get();
572
573 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
574
575 buf_file_expand_fmt_quote(cmd, c_mime_type_query_command, b->filename);
576
577 pid = filter_create(buf_string(cmd), NULL, &fp, &fp_err, NeoMutt->env);
578 if (pid < 0)
579 {
580 mutt_error(_("Error running \"%s\""), buf_string(cmd));
581 buf_pool_release(&cmd);
582 return;
583 }
584 buf_pool_release(&cmd);
585
586 buf = mutt_file_read_line(buf, &buflen, fp, NULL, MUTT_RL_NO_FLAGS);
587 if (buf)
588 {
589 if (strchr(buf, '/'))
591 FREE(&buf);
592 }
593
594 mutt_file_fclose(&fp);
595 mutt_file_fclose(&fp_err);
596 filter_wait(pid);
597}
598
606struct Body *mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
607{
608 if (!path || (path[0] == '\0'))
609 return NULL;
610
611 struct Body *b = mutt_body_new();
612 b->filename = mutt_str_dup(path);
613
614 const char *const c_mime_type_query_command = cs_subset_string(sub, "mime_type_query_command");
615 const bool c_mime_type_query_first = cs_subset_bool(sub, "mime_type_query_first");
616
617 if (c_mime_type_query_command && c_mime_type_query_first)
618 run_mime_type_query(b, sub);
619
620 /* Attempt to determine the appropriate content-type based on the filename
621 * suffix. */
622 if (!b->subtype)
623 mutt_lookup_mime_type(b, path);
624
625 if (!b->subtype && c_mime_type_query_command && !c_mime_type_query_first)
626 {
627 run_mime_type_query(b, sub);
628 }
629
630 struct Content *info = mutt_get_content_info(path, b, sub);
631 if (!info)
632 {
633 mutt_body_free(&b);
634 return NULL;
635 }
636
637 if (!b->subtype)
638 {
639 if ((info->nulbin == 0) &&
640 ((info->lobin == 0) || ((info->lobin + info->hibin + info->ascii) / info->lobin >= 10)))
641 {
642 /* Statistically speaking, there should be more than 10% "lobin"
643 * chars if this is really a binary file... */
644 b->type = TYPE_TEXT;
645 b->subtype = mutt_str_dup("plain");
646 }
647 else
648 {
650 b->subtype = mutt_str_dup("octet-stream");
651 }
652 }
653
654 FREE(&info);
655 mutt_update_encoding(b, sub);
656 return b;
657}
658
666static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
667{
668 char *tmp = NULL;
669 char *p = NULL;
670 int i;
671
672 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
673
674 struct ListNode *np = NULL;
675 STAILQ_FOREACH(np, h, entries)
676 {
677 p = strchr(NONULL(np->data), ':');
678 if (!p)
679 continue;
680
681 i = p - np->data;
682 p = mutt_str_skip_email_wsp(p + 1);
683 tmp = mutt_str_dup(p);
684
685 if (!tmp)
686 continue;
687
688 rfc2047_encode(&tmp, NULL, i + 2, c_send_charset);
689 MUTT_MEM_REALLOC(&np->data, i + 2 + mutt_str_len(tmp) + 1, char);
690
691 sprintf(np->data + i + 2, "%s", tmp);
692
693 FREE(&tmp);
694 }
695}
696
706const char *mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
707{
708 const char *const c_hostname = cs_subset_string(sub, "hostname");
709 if (!c_hostname || (c_hostname[0] == '@'))
710 return NULL;
711
712 const char *p = c_hostname;
713
714 const bool c_hidden_host = cs_subset_bool(sub, "hidden_host");
715 if (may_hide_host && c_hidden_host)
716 {
717 p = strchr(c_hostname, '.');
718 if (p)
719 p++;
720
721 // sanity check: don't hide the host if the fqdn is something like example.com
722 if (!p || !strchr(p, '.'))
723 p = c_hostname;
724 }
725
726 return p;
727}
728
739void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
740{
741 if (final)
742 {
743 if (!TAILQ_EMPTY(&env->bcc) && TAILQ_EMPTY(&env->to) && TAILQ_EMPTY(&env->cc))
744 {
745 /* some MTA's will put an Apparently-To: header field showing the Bcc:
746 * recipients if there is no To: or Cc: field, so attempt to suppress
747 * it by using an empty To: field. */
748 struct Address *to = mutt_addr_new();
749 to->group = true;
750 mutt_addrlist_append(&env->to, to);
752
753 char buf[1024] = { 0 };
754 buf[0] = '\0';
755 mutt_addr_cat(buf, sizeof(buf), "undisclosed-recipients", AddressSpecials);
756
757 buf_strcpy(to->mailbox, buf);
758 }
759
760 mutt_set_followup_to(env, sub);
761
762 if (!env->message_id)
763 env->message_id = msgid_generate();
764 }
765
766 /* Take care of 8-bit => 7-bit conversion. */
768 encode_headers(&env->userhdrs, sub);
769}
770
779{
780 struct ListNode *item = NULL;
781 STAILQ_FOREACH(item, &env->userhdrs, entries)
782 {
783 rfc2047_decode(&item->data);
784 }
785
787
788 /* back conversions */
790}
791
804static int bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
805 struct AddressList *to, const char *resent_from,
806 struct AddressList *env_from, struct ConfigSubset *sub)
807{
808 if (!e)
809 return -1;
810
811 int rc = 0;
812
813 struct Buffer *tempfile = buf_pool_get();
814 buf_mktemp(tempfile);
815 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
816 if (fp_tmp)
817 {
819
820 const bool c_bounce_delivered = cs_subset_bool(sub, "bounce_delivered");
821 if (!c_bounce_delivered)
822 chflags |= CH_WEED_DELIVERED;
823
824 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
825 {
826 (void) mutt_file_fclose(&fp_tmp);
827 return -1;
828 }
829 fprintf(fp_tmp, "Resent-From: %s\n", resent_from);
830
831 struct Buffer *date = buf_pool_get();
832 mutt_date_make_date(date, cs_subset_bool(sub, "local_date_header"));
833 fprintf(fp_tmp, "Resent-Date: %s\n", buf_string(date));
834 buf_pool_release(&date);
835
836 char *msgid_str = msgid_generate();
837 fprintf(fp_tmp, "Resent-Message-ID: %s\n", msgid_str);
838 FREE(&msgid_str);
839 mutt_addrlist_write_file(to, fp_tmp, "Resent-To");
840 mutt_copy_header(fp, e, fp_tmp, chflags, NULL, 0);
841 fputc('\n', fp_tmp);
842 mutt_file_copy_bytes(fp, fp_tmp, e->body->length);
843 if (mutt_file_fclose(&fp_tmp) != 0)
844 {
845 mutt_perror("%s", buf_string(tempfile));
846 unlink(buf_string(tempfile));
847 return -1;
848 }
849 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
850 if (c_smtp_url)
851 {
852 rc = mutt_smtp_send(env_from, to, NULL, NULL, buf_string(tempfile),
853 (e->body->encoding == ENC_8BIT), sub);
854 }
855 else
856 {
857 rc = mutt_invoke_sendmail(m, env_from, to, NULL, NULL, buf_string(tempfile),
858 (e->body->encoding == ENC_8BIT), sub);
859 }
860 }
861
862 buf_pool_release(&tempfile);
863 return rc;
864}
865
876int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e,
877 struct AddressList *to, struct ConfigSubset *sub)
878{
879 if (!fp || !e || !to || TAILQ_EMPTY(to))
880 return -1;
881
882 const char *fqdn = mutt_fqdn(true, sub);
883 char *err = NULL;
884
885 struct Address *from = mutt_default_from(sub);
886 struct AddressList from_list = TAILQ_HEAD_INITIALIZER(from_list);
887 mutt_addrlist_append(&from_list, from);
888
889 /* mutt_default_from() does not use $real_name if the real name is not set
890 * in $from, so we add it here. The reason it is not added in
891 * mutt_default_from() is that during normal sending, we execute
892 * send-hooks and set the real_name last so that it can be changed based
893 * upon message criteria. */
894 if (!from->personal)
895 {
896 const char *const c_real_name = cs_subset_string(sub, "real_name");
897 if (c_real_name)
898 from->personal = buf_new(c_real_name);
899 }
900
901 mutt_addrlist_qualify(&from_list, fqdn);
902
903 rfc2047_encode_addrlist(&from_list, "Resent-From");
904 if (mutt_addrlist_to_intl(&from_list, &err))
905 {
906 mutt_error(_("Bad IDN %s while preparing resent-from"), err);
907 FREE(&err);
908 mutt_addrlist_clear(&from_list);
909 return -1;
910 }
911 struct Buffer *resent_from = buf_pool_get();
912 mutt_addrlist_write(&from_list, resent_from, false);
913
914 OptNewsSend = false;
915
916 /* prepare recipient list. idna conversion appears to happen before this
917 * function is called, since the user receives confirmation of the address
918 * list being bounced to. */
919 struct AddressList resent_to = TAILQ_HEAD_INITIALIZER(resent_to);
920 mutt_addrlist_copy(&resent_to, to, false);
921 rfc2047_encode_addrlist(&resent_to, "Resent-To");
922 int rc = bounce_message(fp, m, e, &resent_to, buf_string(resent_from), &from_list, sub);
923 mutt_addrlist_clear(&resent_to);
924 mutt_addrlist_clear(&from_list);
925 buf_pool_release(&resent_from);
926 return rc;
927}
928
934static void set_noconv_flags(struct Body *b, bool flag)
935{
936 for (; b; b = b->next)
937 {
938 if ((b->type == TYPE_MESSAGE) || (b->type == TYPE_MULTIPART))
939 {
940 set_noconv_flags(b->parts, flag);
941 }
942 else if ((b->type == TYPE_TEXT) && b->noconv)
943 {
944 if (flag)
945 mutt_param_set(&b->parameter, "x-mutt-noconv", "yes");
946 else
947 mutt_param_delete(&b->parameter, "x-mutt-noconv");
948 }
949 }
950}
951
964int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post,
965 char *fcc, char **finalpath, struct ConfigSubset *sub)
966{
967 char fcc_tok[PATH_MAX] = { 0 };
968
969 mutt_str_copy(fcc_tok, path, sizeof(fcc_tok));
970
971 char *tok = strtok(fcc_tok, ",");
972 if (!tok)
973 return -1;
974
975 mutt_debug(LL_DEBUG1, "Fcc: initial mailbox = '%s'\n", tok);
976 /* expand_path already called above for the first token */
977 int status = mutt_write_fcc(tok, e, msgid, post, fcc, finalpath, sub);
978 if (status != 0)
979 return status;
980
981 struct Buffer *fcc_expanded = buf_pool_get();
982 while ((tok = strtok(NULL, ",")))
983 {
984 if (*tok == '\0')
985 continue;
986
987 /* Only call expand_path if tok has some data */
988 mutt_debug(LL_DEBUG1, "Fcc: additional mailbox token = '%s'\n", tok);
989 buf_strcpy(fcc_expanded, tok);
990 expand_path(fcc_expanded, false);
991 mutt_debug(LL_DEBUG1, " Additional mailbox expanded = '%s'\n",
992 buf_string(fcc_expanded));
993 status = mutt_write_fcc(buf_string(fcc_expanded), e, msgid, post, fcc, finalpath, sub);
994 if (status != 0)
995 {
996 buf_pool_release(&fcc_expanded);
997 return status;
998 }
999 }
1000
1001 buf_pool_release(&fcc_expanded);
1002 return 0;
1003}
1004
1017int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post,
1018 const char *fcc, char **finalpath, struct ConfigSubset *sub)
1019{
1020 struct Message *msg = NULL;
1021 struct Buffer *tempfile = NULL;
1022 FILE *fp_tmp = NULL;
1023 int rc = -1;
1024 bool need_mailbox_cleanup = false;
1025 struct stat st = { 0 };
1026 MsgOpenFlags onm_flags;
1027
1028 if (post)
1029 set_noconv_flags(e->body, true);
1030
1031#ifdef RECORD_FOLDER_HOOK
1032 exec_folder_hook(path, NULL);
1033#endif
1034 struct Mailbox *m_fcc = mx_path_resolve(path);
1035 bool old_append = m_fcc->append;
1036 if (!mx_mbox_open(m_fcc, MUTT_APPEND | MUTT_QUIET))
1037 {
1038 mutt_debug(LL_DEBUG1, "unable to open mailbox %s in append-mode, aborting\n", path);
1039 goto done;
1040 }
1041
1042 /* We need to add a Content-Length field to avoid problems where a line in
1043 * the message body begins with "From " */
1044 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1045 {
1046 tempfile = buf_pool_get();
1047 buf_mktemp(tempfile);
1048 fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
1049 if (!fp_tmp)
1050 {
1051 mutt_perror("%s", buf_string(tempfile));
1052 mx_mbox_close(m_fcc);
1053 goto done;
1054 }
1055 /* remember new mail status before appending message */
1056 need_mailbox_cleanup = true;
1057 stat(path, &st);
1058 }
1059
1060 e->read = !post; /* make sure to put it in the 'cur' directory (maildir) */
1061 onm_flags = MUTT_ADD_FROM;
1062 if (post)
1063 onm_flags |= MUTT_SET_DRAFT;
1064 msg = mx_msg_open_new(m_fcc, e, onm_flags);
1065 if (!msg)
1066 {
1067 mutt_file_fclose(&fp_tmp);
1068 mx_mbox_close(m_fcc);
1069 goto done;
1070 }
1071
1072 const bool c_crypt_protected_headers_read = cs_subset_bool(sub, "crypt_protected_headers_read");
1073
1074 /* post == 1 => postpone message.
1075 * post == 0 => Normal mode. */
1076 mutt_rfc822_write_header(msg->fp, e->env, e->body,
1078 c_crypt_protected_headers_read &&
1080 sub);
1081
1082 /* (postponement) if this was a reply of some sort, <msgid> contains the
1083 * Message-ID: of message replied to. Save it using a special X-Mutt-
1084 * header so it can be picked up if the message is recalled at a later
1085 * point in time. This will allow the message to be marked as replied if
1086 * the same mailbox is still open. */
1087 if (post && msgid)
1088 fprintf(msg->fp, "Mutt-References: %s\n", msgid);
1089
1090 /* (postponement) save the Fcc: using a special X-Mutt- header so that
1091 * it can be picked up when the message is recalled */
1092 if (post && fcc)
1093 fprintf(msg->fp, "Mutt-Fcc: %s\n", fcc);
1094
1095 if ((m_fcc->type == MUTT_MMDF) || (m_fcc->type == MUTT_MBOX))
1096 fprintf(msg->fp, "Status: RO\n");
1097
1098 /* (postponement) if the mail is to be signed or encrypted, save this info */
1099 if (((WithCrypto & APPLICATION_PGP) != 0) && post && (e->security & APPLICATION_PGP))
1100 {
1101 fputs("Mutt-PGP: ", msg->fp);
1102 if (e->security & SEC_ENCRYPT)
1103 fputc('E', msg->fp);
1104 if (e->security & SEC_OPPENCRYPT)
1105 fputc('O', msg->fp);
1106 if (e->security & SEC_SIGN)
1107 {
1108 fputc('S', msg->fp);
1109
1110 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
1111 if (c_pgp_sign_as)
1112 fprintf(msg->fp, "<%s>", c_pgp_sign_as);
1113 }
1114 if (e->security & SEC_INLINE)
1115 fputc('I', msg->fp);
1116#ifdef USE_AUTOCRYPT
1117 if (e->security & SEC_AUTOCRYPT)
1118 fputc('A', msg->fp);
1120 fputc('Z', msg->fp);
1121#endif
1122 fputc('\n', msg->fp);
1123 }
1124
1125 /* (postponement) if the mail is to be signed or encrypted, save this info */
1126 if (((WithCrypto & APPLICATION_SMIME) != 0) && post && (e->security & APPLICATION_SMIME))
1127 {
1128 fputs("Mutt-SMIME: ", msg->fp);
1129 if (e->security & SEC_ENCRYPT)
1130 {
1131 fputc('E', msg->fp);
1132
1133 const char *const c_smime_encrypt_with = cs_subset_string(sub, "smime_encrypt_with");
1134 if (c_smime_encrypt_with)
1135 fprintf(msg->fp, "C<%s>", c_smime_encrypt_with);
1136 }
1137 if (e->security & SEC_OPPENCRYPT)
1138 fputc('O', msg->fp);
1139 if (e->security & SEC_SIGN)
1140 {
1141 fputc('S', msg->fp);
1142
1143 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
1144 if (c_smime_sign_as)
1145 fprintf(msg->fp, "<%s>", c_smime_sign_as);
1146 }
1147 if (e->security & SEC_INLINE)
1148 fputc('I', msg->fp);
1149 fputc('\n', msg->fp);
1150 }
1151
1152 if (fp_tmp)
1153 {
1154 mutt_write_mime_body(e->body, fp_tmp, sub);
1155
1156 /* make sure the last line ends with a newline. Emacs doesn't ensure this
1157 * will happen, and it can cause problems parsing the mailbox later. */
1158 if (mutt_file_seek(fp_tmp, -1, SEEK_END) && (fgetc(fp_tmp) != '\n') &&
1159 mutt_file_seek(fp_tmp, 0, SEEK_END))
1160 {
1161 fputc('\n', fp_tmp);
1162 }
1163
1164 fflush(fp_tmp);
1165 if (ferror(fp_tmp))
1166 {
1167 mutt_debug(LL_DEBUG1, "%s: write failed\n", buf_string(tempfile));
1168 mutt_file_fclose(&fp_tmp);
1169 unlink(buf_string(tempfile));
1170 mx_msg_commit(m_fcc, msg); /* XXX really? */
1171 mx_msg_close(m_fcc, &msg);
1172 mx_mbox_close(m_fcc);
1173 goto done;
1174 }
1175
1176 /* count the number of lines */
1177 int lines = 0;
1178 char line_buf[1024] = { 0 };
1179 rewind(fp_tmp);
1180 while (fgets(line_buf, sizeof(line_buf), fp_tmp))
1181 lines++;
1182 fprintf(msg->fp, "Content-Length: " OFF_T_FMT "\n", (LOFF_T) ftello(fp_tmp));
1183 fprintf(msg->fp, "Lines: %d\n\n", lines);
1184
1185 /* copy the body and clean up */
1186 rewind(fp_tmp);
1187 rc = mutt_file_copy_stream(fp_tmp, msg->fp);
1188 if (mutt_file_fclose(&fp_tmp) != 0)
1189 rc = -1;
1190 /* if there was an error, leave the temp version */
1191 if (rc >= 0)
1192 {
1193 unlink(buf_string(tempfile));
1194 rc = 0;
1195 }
1196 }
1197 else
1198 {
1199 fputc('\n', msg->fp); /* finish off the header */
1200 rc = mutt_write_mime_body(e->body, msg->fp, sub);
1201 }
1202
1203 if (mx_msg_commit(m_fcc, msg) != 0)
1204 rc = -1;
1205 else if (finalpath)
1206 *finalpath = mutt_str_dup(msg->committed_path);
1207 mx_msg_close(m_fcc, &msg);
1208 mx_mbox_close(m_fcc);
1209
1210 if (!post && need_mailbox_cleanup)
1211 mailbox_restore_timestamp(path, &st);
1212
1213 if (post)
1214 set_noconv_flags(e->body, false);
1215
1216done:
1217 m_fcc->append = old_append;
1218 mailbox_free(&m_fcc);
1219
1220#ifdef RECORD_FOLDER_HOOK
1221 /* We ran a folder hook for the destination mailbox,
1222 * now we run it for the user's current mailbox */
1223 const struct Mailbox *m_cur = get_current_mailbox();
1224 if (m_cur)
1225 exec_folder_hook(m_cur->path, m_cur->desc);
1226#endif
1227
1228 if (fp_tmp)
1229 {
1230 mutt_file_fclose(&fp_tmp);
1231 unlink(buf_string(tempfile));
1232 }
1233 buf_pool_release(&tempfile);
1234
1235 return rc;
1236}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:769
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:680
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1464
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition address.c:708
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1484
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:1210
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:1252
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1297
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:222
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:682
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:1346
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:652
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:1933
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:220
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:209
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
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:610
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:500
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:583
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:121
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:300
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:1396
void mutt_set_followup_to(struct Envelope *env, struct ConfigSubset *sub)
Set followup-to field.
Definition send.c:1272
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:934
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:421
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:706
int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition sendlib.c:876
enum ContentType mutt_lookup_mime_type(struct Body *b, const char *path)
Find the MIME type for an attachment.
Definition sendlib.c:75
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition sendlib.c:606
int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath, struct ConfigSubset *sub)
Handle FCC with multiple, comma separated entries.
Definition sendlib.c:964
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition sendlib.c:778
static void encode_headers(struct ListHead *h, struct ConfigSubset *sub)
RFC2047-encode a list of headers.
Definition sendlib.c:666
static void set_encoding(struct Body *b, struct Content *info, struct ConfigSubset *sub)
Determine which Content-Transfer-Encoding to use.
Definition sendlib.c:350
static void run_mime_type_query(struct Body *b, struct ConfigSubset *sub)
Run an external command to determine the MIME type.
Definition sendlib.c:565
static void transform_to_7bit(struct Body *b, FILE *fp_in, struct ConfigSubset *sub)
Convert MIME parts to 7-bit.
Definition sendlib.c:195
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:739
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:1017
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:804
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:1100
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