NeoMutt  2025-01-09-81-g753ae0
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
31#include "config.h"
32#ifdef _MAKEDOC
33#include "docs/makedoc_defs.h"
34#else
35#include <errno.h>
36#include <limits.h>
37#include <stdbool.h>
38#include <stdio.h>
39#include <string.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include "private.h"
43#include "mutt/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "conn/lib.h"
48#include "gui/lib.h"
49#include "mutt.h"
50#include "lib.h"
51#include "attach/lib.h"
52#include "browser/lib.h"
53#include "editor/lib.h"
54#include "history/lib.h"
55#include "imap/lib.h"
56#include "index/lib.h"
57#include "key/lib.h"
58#include "menu/lib.h"
59#include "ncrypt/lib.h"
60#include "nntp/lib.h"
61#include "pop/lib.h"
62#include "question/lib.h"
63#include "send/lib.h"
64#include "attach_data.h"
65#include "external.h"
66#include "functions.h"
67#include "globals.h"
68#include "hook.h"
69#include "mutt_header.h"
70#include "mutt_logging.h"
71#include "muttlib.h"
72#include "mview.h"
73#include "mx.h"
74#include "nntp/adata.h" // IWYU pragma: keep
75#include "protos.h"
76#include "rfc3676.h"
77#include "shared_data.h"
78#ifdef ENABLE_NLS
79#include <libintl.h>
80#endif
81#endif
82
83// clang-format off
87const struct MenuFuncOp OpCompose[] = { /* map: compose */
88 { "attach-file", OP_ATTACHMENT_ATTACH_FILE },
89 { "attach-key", OP_ATTACHMENT_ATTACH_KEY },
90 { "attach-message", OP_ATTACHMENT_ATTACH_MESSAGE },
91 { "attach-news-message", OP_ATTACHMENT_ATTACH_NEWS_MESSAGE },
92#ifdef USE_AUTOCRYPT
93 { "autocrypt-menu", OP_COMPOSE_AUTOCRYPT_MENU },
94#endif
95 { "copy-file", OP_ATTACHMENT_SAVE },
96 { "detach-file", OP_ATTACHMENT_DETACH },
97 { "display-toggle-weed", OP_DISPLAY_HEADERS },
98 { "edit-bcc", OP_ENVELOPE_EDIT_BCC },
99 { "edit-cc", OP_ENVELOPE_EDIT_CC },
100 { "edit-content-id", OP_ATTACHMENT_EDIT_CONTENT_ID },
101 { "edit-description", OP_ATTACHMENT_EDIT_DESCRIPTION },
102 { "edit-encoding", OP_ATTACHMENT_EDIT_ENCODING },
103 { "edit-fcc", OP_ENVELOPE_EDIT_FCC },
104 { "edit-file", OP_COMPOSE_EDIT_FILE },
105 { "edit-followup-to", OP_ENVELOPE_EDIT_FOLLOWUP_TO },
106 { "edit-from", OP_ENVELOPE_EDIT_FROM },
107 { "edit-headers", OP_ENVELOPE_EDIT_HEADERS },
108 { "edit-language", OP_ATTACHMENT_EDIT_LANGUAGE },
109 { "edit-message", OP_COMPOSE_EDIT_MESSAGE },
110 { "edit-mime", OP_ATTACHMENT_EDIT_MIME },
111 { "edit-newsgroups", OP_ENVELOPE_EDIT_NEWSGROUPS },
112 { "edit-reply-to", OP_ENVELOPE_EDIT_REPLY_TO },
113 { "edit-subject", OP_ENVELOPE_EDIT_SUBJECT },
114 { "edit-to", OP_ENVELOPE_EDIT_TO },
115 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
116 { "edit-x-comment-to", OP_ENVELOPE_EDIT_X_COMMENT_TO },
117 { "exit", OP_EXIT },
118 { "filter-entry", OP_ATTACHMENT_FILTER },
119 { "forget-passphrase", OP_FORGET_PASSPHRASE },
120 { "get-attachment", OP_ATTACHMENT_GET_ATTACHMENT },
121 { "group-alternatives", OP_ATTACHMENT_GROUP_ALTS },
122 { "group-multilingual", OP_ATTACHMENT_GROUP_LINGUAL },
123 { "group-related", OP_ATTACHMENT_GROUP_RELATED },
124 { "ispell", OP_COMPOSE_ISPELL },
125 { "move-down", OP_ATTACHMENT_MOVE_DOWN },
126 { "move-up", OP_ATTACHMENT_MOVE_UP },
127 { "new-mime", OP_ATTACHMENT_NEW_MIME },
128 { "pgp-menu", OP_COMPOSE_PGP_MENU },
129 { "pipe-entry", OP_PIPE },
130 { "pipe-message", OP_PIPE },
131 { "postpone-message", OP_COMPOSE_POSTPONE_MESSAGE },
132 { "preview-page-down", OP_PREVIEW_PAGE_DOWN },
133 { "preview-page-up", OP_PREVIEW_PAGE_UP },
134 { "print-entry", OP_ATTACHMENT_PRINT },
135 { "rename-attachment", OP_ATTACHMENT_RENAME_ATTACHMENT },
136 { "rename-file", OP_COMPOSE_RENAME_FILE },
137 { "send-message", OP_COMPOSE_SEND_MESSAGE },
138 { "smime-menu", OP_COMPOSE_SMIME_MENU },
139 { "toggle-disposition", OP_ATTACHMENT_TOGGLE_DISPOSITION },
140 { "toggle-recode", OP_ATTACHMENT_TOGGLE_RECODE },
141 { "toggle-unlink", OP_ATTACHMENT_TOGGLE_UNLINK },
142 { "ungroup-attachment", OP_ATTACHMENT_UNGROUP },
143 { "update-encoding", OP_ATTACHMENT_UPDATE_ENCODING },
144 { "view-attach", OP_ATTACHMENT_VIEW },
145 { "view-mailcap", OP_ATTACHMENT_VIEW_MAILCAP },
146 { "view-pager", OP_ATTACHMENT_VIEW_PAGER },
147 { "view-text", OP_ATTACHMENT_VIEW_TEXT },
148 { "write-fcc", OP_COMPOSE_WRITE_MESSAGE },
149 { NULL, 0 },
150};
151
155const struct MenuOpSeq ComposeDefaultBindings[] = { /* map: compose */
156 { OP_ATTACHMENT_ATTACH_FILE, "a" },
157 { OP_ATTACHMENT_ATTACH_KEY, "\033k" }, // <Alt-k>
158 { OP_ATTACHMENT_ATTACH_MESSAGE, "A" },
159 { OP_ATTACHMENT_DETACH, "D" },
160 { OP_ATTACHMENT_EDIT_CONTENT_ID, "\033i" }, // <Alt-i>
161 { OP_ATTACHMENT_EDIT_DESCRIPTION, "d" },
162 { OP_ATTACHMENT_EDIT_ENCODING, "\005" }, // <Ctrl-E>
163 { OP_ATTACHMENT_EDIT_LANGUAGE, "\014" }, // <Ctrl-L>
164 { OP_ATTACHMENT_EDIT_MIME, "m" },
165 { OP_ATTACHMENT_EDIT_TYPE, "\024" }, // <Ctrl-T>
166 { OP_ATTACHMENT_FILTER, "F" },
167 { OP_ATTACHMENT_GET_ATTACHMENT, "G" },
168 { OP_ATTACHMENT_GROUP_ALTS, "&" },
169 { OP_ATTACHMENT_GROUP_LINGUAL, "^" },
170 { OP_ATTACHMENT_GROUP_RELATED, "%" },
171 { OP_ATTACHMENT_MOVE_DOWN, "+" },
172 { OP_ATTACHMENT_MOVE_UP, "-" },
173 { OP_ATTACHMENT_NEW_MIME, "n" },
174 { OP_EXIT, "q" },
175 { OP_PIPE, "|" },
176 { OP_ATTACHMENT_PRINT, "l" },
177 { OP_ATTACHMENT_RENAME_ATTACHMENT, "\017" }, // <Ctrl-O>
178 { OP_ATTACHMENT_SAVE, "C" },
179 { OP_ATTACHMENT_TOGGLE_DISPOSITION, "\004" }, // <Ctrl-D>
180 { OP_ATTACHMENT_TOGGLE_UNLINK, "u" },
181 { OP_ATTACHMENT_UNGROUP, "#" },
182 { OP_ATTACHMENT_UPDATE_ENCODING, "U" },
183 { OP_ATTACHMENT_VIEW, "<keypadenter>" },
184 { OP_ATTACHMENT_VIEW, "\n" }, // <Enter>
185 { OP_ATTACHMENT_VIEW, "\r" }, // <Return>
186#ifdef USE_AUTOCRYPT
187 { OP_COMPOSE_AUTOCRYPT_MENU, "o" },
188#endif
189 { OP_COMPOSE_EDIT_FILE, "\033e" }, // <Alt-e>
190 { OP_COMPOSE_EDIT_MESSAGE, "e" },
191 { OP_COMPOSE_ISPELL, "i" },
192 { OP_COMPOSE_PGP_MENU, "p" },
193 { OP_COMPOSE_POSTPONE_MESSAGE, "P" },
194 { OP_COMPOSE_RENAME_FILE, "R" },
195 { OP_COMPOSE_SEND_MESSAGE, "y" },
196 { OP_COMPOSE_SMIME_MENU, "S" },
197 { OP_COMPOSE_WRITE_MESSAGE, "w" },
198 { OP_DISPLAY_HEADERS, "h" },
199 { OP_ENVELOPE_EDIT_BCC, "b" },
200 { OP_ENVELOPE_EDIT_CC, "c" },
201 { OP_ENVELOPE_EDIT_FCC, "f" },
202 { OP_ENVELOPE_EDIT_FROM, "\033f" }, // <Alt-f>
203 { OP_ENVELOPE_EDIT_HEADERS, "E" },
204 { OP_ENVELOPE_EDIT_REPLY_TO, "r" },
205 { OP_ENVELOPE_EDIT_SUBJECT, "s" },
206 { OP_ENVELOPE_EDIT_TO, "t" },
207 { OP_PREVIEW_PAGE_DOWN, "<pagedown>" },
208 { OP_PREVIEW_PAGE_UP, "<pageup>" },
209 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
210 { OP_TAG, "T" },
211 { 0, NULL },
212};
213// clang-format on
214
220static bool check_count(struct AttachCtx *actx)
221{
222 if (actx->idxlen == 0)
223 {
224 mutt_error(_("There are no attachments"));
225 return false;
226 }
227
228 return true;
229}
230
237static char *gen_cid(void)
238{
239 char rndid[MUTT_RANDTAG_LEN + 1];
240
241 mutt_rand_base32(rndid, sizeof(rndid) - 1);
242 rndid[MUTT_RANDTAG_LEN] = 0;
243
244 return mutt_str_dup(rndid);
245}
246
253static bool check_cid(const char *cid)
254{
255 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
256
257 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
258
259 const bool valid = mutt_regex_match(check_cid_regex, cid);
260
261 mutt_regex_free(&check_cid_regex);
262
263 return valid;
264}
265
273static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
274{
275 int rc = -1;
276 struct stat st = { 0 };
277 struct Buffer *pretty = NULL, *msg = NULL;
278
279 for (int i = 0; i < actx->idxlen; i++)
280 {
281 if (actx->idx[i]->body->type == TYPE_MULTIPART)
282 continue;
283 if (stat(actx->idx[i]->body->filename, &st) != 0)
284 {
285 if (!pretty)
286 pretty = buf_pool_get();
287 buf_strcpy(pretty, actx->idx[i]->body->filename);
288 buf_pretty_mailbox(pretty);
289 /* L10N: This message is displayed in the compose menu when an attachment
290 doesn't stat. %d is the attachment number and %s is the attachment
291 filename. The filename is located last to avoid a long path hiding
292 the error message. */
293 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
294 goto cleanup;
295 }
296
297 if (actx->idx[i]->body->stamp < st.st_mtime)
298 {
299 if (!pretty)
300 pretty = buf_pool_get();
301 buf_strcpy(pretty, actx->idx[i]->body->filename);
302 buf_pretty_mailbox(pretty);
303
304 if (!msg)
305 msg = buf_pool_get();
306 /* L10N: This message is displayed in the compose menu when an attachment
307 is modified behind the scenes. %d is the attachment number and %s is
308 the attachment filename. The filename is located last to avoid a long
309 path hiding the prompt question. */
310 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
311 i + 1, buf_string(pretty));
312
314 if (ans == MUTT_YES)
315 mutt_update_encoding(actx->idx[i]->body, sub);
316 else if (ans == MUTT_ABORT)
317 goto cleanup;
318 }
319 }
320
321 rc = 0;
322
323cleanup:
324 buf_pool_release(&pretty);
325 buf_pool_release(&msg);
326 return rc;
327}
328
336static int delete_attachment(struct AttachCtx *actx, int aidx)
337{
338 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
339 return -1;
340
341 struct AttachPtr **idx = actx->idx;
342 struct Body *b_previous = NULL;
343 struct Body *b_parent = NULL;
344
345 if (aidx == 0)
346 {
347 struct Body *b = actx->idx[0]->body;
348 if (!b->next) // There's only one attachment left
349 {
350 mutt_error(_("You may not delete the only attachment"));
351 return -1;
352 }
353
354 if (cs_subset_bool(NeoMutt->sub, "compose_confirm_detach_first"))
355 {
356 /* L10N: Prompt when trying to hit <detach-file> on the first entry in
357 the compose menu. This entry is most likely the message they just
358 typed. Hitting yes will remove the entry and unlink the file, so
359 it's worth confirming they really meant to do it. */
360 enum QuadOption ans = query_yesorno_help(_("Really delete the main message?"),
362 "compose_confirm_detach_first");
363 if (ans == MUTT_NO)
364 {
365 idx[aidx]->body->tagged = false;
366 return -1;
367 }
368 }
369 }
370
371 if (idx[aidx]->level > 0)
372 {
373 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
374 {
375 if (attach_body_count(b_parent->parts, false) < 3)
376 {
377 mutt_error(_("Can't leave group with only one attachment"));
378 return -1;
379 }
380 }
381 }
382
383 // reorder body pointers
384 if (aidx > 0)
385 {
386 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
387 b_previous->next = idx[aidx]->body->next;
388 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
389 b_parent->parts = idx[aidx]->body->next;
390 }
391
392 // free memory
393 int part_count = 1;
394 if (aidx < (actx->idxlen - 1))
395 {
396 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
397 (idx[aidx + 1]->level > idx[aidx]->level))
398 {
399 part_count += attach_body_count(idx[aidx]->body->parts, true);
400 }
401 }
402 idx[aidx]->body->next = NULL;
403 mutt_body_free(&(idx[aidx]->body));
404 for (int i = 0; i < part_count; i++)
405 {
406 FREE(&idx[aidx + i]->tree);
407 FREE(&idx[aidx + i]);
408 }
409
410 // reorder attachment list
411 for (int i = aidx; i < (actx->idxlen - part_count); i++)
412 idx[i] = idx[i + part_count];
413 for (int i = 0; i < part_count; i++)
414 idx[actx->idxlen - i - 1] = NULL;
415 actx->idxlen -= part_count;
416
417 return 0;
418}
419
426static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
427{
428 ap->level = 0;
429 for (int i = actx->idxlen; i > 0; i--)
430 {
431 if (ap->level == actx->idx[i - 1]->level)
432 {
433 actx->idx[i - 1]->body->next = ap->body;
434 break;
435 }
436 }
437
438 ap->body->aptr = ap;
439 mutt_actx_add_attach(actx, ap);
440 update_menu(actx, menu, false);
441 menu_set_index(menu, actx->vcount - 1);
442}
443
451static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
452{
453 struct AttachPtr **idx = actx->idx;
454
455 // check that attachments really are adjacent
456 if (idx[first]->body->next != idx[second]->body)
457 return;
458
459 // reorder Body pointers
460 if (first == 0)
461 {
462 // first attachment is the fundamental part
463 idx[first]->body->next = idx[second]->body->next;
464 idx[second]->body->next = idx[first]->body;
465 e->body = idx[second]->body;
466 }
467 else
468 {
469 // find previous attachment
470 struct Body *b_previous = NULL;
471 struct Body *b_parent = NULL;
472 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
473 {
474 idx[first]->body->next = idx[second]->body->next;
475 idx[second]->body->next = idx[first]->body;
476 b_previous->next = idx[second]->body;
477 }
478 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
479 {
480 idx[first]->body->next = idx[second]->body->next;
481 idx[second]->body->next = idx[first]->body;
482 b_parent->parts = idx[second]->body;
483 }
484 }
485
486 // reorder attachment list
487 struct AttachPtr *saved = idx[second];
488 for (int i = second; i > first; i--)
489 idx[i] = idx[i - 1];
490 idx[first] = saved;
491
492 // if moved attachment is a group then move subparts too
493 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
494 {
495 int i = second + 1;
496 while (idx[i]->level > idx[first]->level)
497 {
498 saved = idx[i];
499 int destidx = i - second + first;
500 for (int j = i; j > destidx; j--)
501 idx[j] = idx[j - 1];
502 idx[destidx] = saved;
503 i++;
504 if (i >= actx->idxlen)
505 break;
506 }
507 }
508}
509
517static int group_attachments(struct ComposeSharedData *shared, char *subtype)
518{
519 struct AttachCtx *actx = shared->adata->actx;
520 int group_level = -1;
521 struct Body *bptr_parent = NULL;
522
523 // Attachments to be grouped must have the same parent
524 for (int i = 0; i < actx->idxlen; i++)
525 {
526 // check if all tagged attachments are at same level
527 if (actx->idx[i]->body->tagged)
528 {
529 if (group_level == -1)
530 {
531 group_level = actx->idx[i]->level;
532 }
533 else
534 {
535 if (group_level != actx->idx[i]->level)
536 {
537 mutt_error(_("Attachments to be grouped must have the same parent"));
538 return FR_ERROR;
539 }
540 }
541 // if not at top level check if all tagged attachments have same parent
542 if (group_level > 0)
543 {
544 if (bptr_parent)
545 {
546 struct Body *bptr_test = NULL;
547 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
548 mutt_debug(LL_DEBUG5, "can't find parent\n");
549 if (bptr_test != bptr_parent)
550 {
551 mutt_error(_("Attachments to be grouped must have the same parent"));
552 return FR_ERROR;
553 }
554 }
555 else
556 {
557 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
558 mutt_debug(LL_DEBUG5, "can't find parent\n");
559 }
560 }
561 }
562 }
563
564 // Can't group all attachments unless at top level
565 if (bptr_parent)
566 {
567 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
568 {
569 mutt_error(_("Can't leave group with only one attachment"));
570 return FR_ERROR;
571 }
572 }
573
574 struct Body *group = mutt_body_new();
575 group->type = TYPE_MULTIPART;
576 group->subtype = mutt_str_dup(subtype);
577 group->encoding = ENC_7BIT;
578
579 struct Body *bptr_first = NULL; // first tagged attachment
580 struct Body *bptr = NULL; // current tagged attachment
581 struct Body *group_parent = NULL; // parent of group
582 struct Body *group_previous = NULL; // previous body to group
583 struct Body *group_part = NULL; // current attachment in group
584 int group_idx = 0; // index in attachment list where group will be inserted
585 int group_last_idx = 0; // index of last part of previous found group
586 int group_parent_type = TYPE_OTHER;
587
588 for (int i = 0; i < actx->idxlen; i++)
589 {
590 bptr = actx->idx[i]->body;
591 if (bptr->tagged)
592 {
593 // set group properties based on first tagged attachment
594 if (!bptr_first)
595 {
596 group->disposition = bptr->disposition;
597 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
598 group->language = mutt_str_dup(bptr->language);
599 group_parent_type = bptr->aptr->parent_type;
600 bptr_first = bptr;
601 if (i > 0)
602 {
603 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
604 {
605 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
606 }
607 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
608 {
609 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
610 }
611 }
612 }
613
614 shared->adata->menu->num_tagged--;
615 bptr->tagged = false;
616 bptr->aptr->level++;
618
619 // append bptr to the group parts list and remove from email body list
620 struct Body *bptr_previous = NULL;
621 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
622 bptr_previous->next = bptr->next;
623 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
624 bptr_parent->parts = bptr->next;
625 else
626 shared->email->body = bptr->next;
627
628 if (group_part)
629 {
630 // add bptr to group parts list
631 group_part->next = bptr;
632 group_part = group_part->next;
633 group_part->next = NULL;
634
635 // reorder attachments and set levels
636 int bptr_attachments = attach_body_count(bptr, true);
637 for (int j = i + 1; j < (i + bptr_attachments); j++)
638 actx->idx[j]->level++;
639 if (i > (group_last_idx + 1))
640 {
641 for (int j = 0; j < bptr_attachments; j++)
642 {
643 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
644 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
645 actx->idx[k] = actx->idx[k - 1];
646 actx->idx[group_last_idx + 1] = saved;
647 }
648 }
649 i += bptr_attachments - 1;
650 group_last_idx += bptr_attachments;
651 }
652 else
653 {
654 group_idx = i;
655 group->parts = bptr;
656 group_part = bptr;
657 group_part->next = NULL;
658 int bptr_attachments = attach_body_count(bptr, true);
659 for (int j = i + 1; j < (i + bptr_attachments); j++)
660 actx->idx[j]->level++;
661 i += bptr_attachments - 1;
662 group_last_idx = i;
663 }
664 }
665 }
666
667 if (!bptr_first)
668 {
669 mutt_body_free(&group);
670 return FR_ERROR;
671 }
672
673 // set group->next
674 int next_aidx = group_idx + attach_body_count(group->parts, true);
675 if (group_parent)
676 {
677 // find next attachment with the same parent as the group
678 struct Body *b = NULL;
679 struct Body *b_parent = NULL;
680 while (next_aidx < actx->idxlen)
681 {
682 b = actx->idx[next_aidx]->body;
683 b_parent = NULL;
684 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
685 {
686 if (group_parent == b_parent)
687 {
688 group->next = b;
689 break;
690 }
691 }
692 next_aidx++;
693 }
694 }
695 else if (next_aidx < actx->idxlen)
696 {
697 // group is at top level
698 group->next = actx->idx[next_aidx]->body;
699 }
700
701 // set previous or parent for group
702 if (group_previous)
703 group_previous->next = group;
704 else if (group_parent)
705 group_parent->parts = group;
706
708
709 struct AttachPtr *group_ap = mutt_aptr_new();
710 group_ap->body = group;
711 group_ap->body->aptr = group_ap;
712 group_ap->level = group_level;
713 group_ap->parent_type = group_parent_type;
714
715 // insert group into attachment list
716 mutt_actx_ins_attach(actx, group_ap, group_idx);
717
718 // update email body and last attachment pointers
719 shared->email->body = actx->idx[0]->body;
720 actx->idx[actx->idxlen - 1]->body->next = NULL;
721
722 update_menu(actx, shared->adata->menu, false);
723 shared->adata->menu->current = group_idx;
725
727 return FR_SUCCESS;
728}
729
730// -----------------------------------------------------------------------------
731
735static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
736{
737 char *prompt = _("Attach file");
738 int numfiles = 0;
739 char **files = NULL;
740
741 struct Buffer *fname = buf_pool_get();
742 if ((mw_enter_fname(prompt, fname, false, NULL, true, &files, &numfiles,
743 MUTT_SEL_MULTI) == -1) ||
744 buf_is_empty(fname))
745 {
746 for (int i = 0; i < numfiles; i++)
747 FREE(&files[i]);
748
749 FREE(&files);
750 buf_pool_release(&fname);
751 return FR_NO_ACTION;
752 }
753
754 bool error = false;
755 bool added_attachment = false;
756 if (numfiles > 1)
757 {
758 mutt_message(ngettext("Attaching selected file...",
759 "Attaching selected files...", numfiles));
760 }
761 for (int i = 0; i < numfiles; i++)
762 {
763 char *att = files[i];
764 if (!att)
765 continue;
766
767 struct AttachPtr *ap = mutt_aptr_new();
768 ap->unowned = true;
769 ap->body = mutt_make_file_attach(att, shared->sub);
770 if (ap->body)
771 {
772 added_attachment = true;
773 update_idx(shared->adata->menu, shared->adata->actx, ap);
774 }
775 else
776 {
777 error = true;
778 mutt_error(_("Unable to attach %s"), att);
779 mutt_aptr_free(&ap);
780 }
781 FREE(&files[i]);
782 }
783
784 FREE(&files);
785 buf_pool_release(&fname);
786
787 if (!error)
789
792 if (added_attachment)
794 return FR_SUCCESS;
795}
796
800static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
801{
803 return FR_NOT_IMPL;
804 struct AttachPtr *ap = mutt_aptr_new();
806 if (ap->body)
807 {
808 update_idx(shared->adata->menu, shared->adata->actx, ap);
811 }
812 else
813 {
814 mutt_aptr_free(&ap);
815 }
816
818 return FR_SUCCESS;
819}
820
828static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
829{
830 char *prompt = _("Open mailbox to attach message from");
831
832 OptNews = false;
833 if (shared->mailbox && (op == OP_ATTACHMENT_ATTACH_NEWS_MESSAGE))
834 {
835 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
836 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
837 if (!CurrentNewsSrv)
838 return FR_NO_ACTION;
839
840 prompt = _("Open newsgroup to attach message from");
841 OptNews = true;
842 }
843
844 struct Buffer *fname = buf_pool_get();
845 if (shared->mailbox)
846 {
847 if ((op == OP_ATTACHMENT_ATTACH_MESSAGE) ^ (shared->mailbox->type == MUTT_NNTP))
848 {
849 buf_strcpy(fname, mailbox_path(shared->mailbox));
850 buf_pretty_mailbox(fname);
851 }
852 }
853
854 if ((mw_enter_fname(prompt, fname, true, shared->mailbox, false, NULL, NULL,
855 MUTT_SEL_NO_FLAGS) == -1) ||
856 buf_is_empty(fname))
857 {
858 buf_pool_release(&fname);
859 return FR_NO_ACTION;
860 }
861
862 if (OptNews)
864 else
865 buf_expand_path(fname);
866
867 if (imap_path_probe(buf_string(fname), NULL) != MUTT_IMAP)
868 {
869 if (pop_path_probe(buf_string(fname), NULL) != MUTT_POP)
870 {
871 if (!OptNews && (nntp_path_probe(buf_string(fname), NULL) != MUTT_NNTP))
872 {
874 {
875 /* check to make sure the file exists and is readable */
876 if (access(buf_string(fname), R_OK) == -1)
877 {
878 mutt_perror("%s", buf_string(fname));
879 buf_pool_release(&fname);
880 return FR_ERROR;
881 }
882 }
883 }
884 }
885 }
886
888
889 struct Mailbox *m_attach = mx_path_resolve(buf_string(fname));
890 const bool old_readonly = m_attach->readonly;
891 if (!mx_mbox_open(m_attach, MUTT_READONLY))
892 {
893 mutt_error(_("Unable to open mailbox %s"), buf_string(fname));
894 mx_fastclose_mailbox(m_attach, false);
895 m_attach = NULL;
896 buf_pool_release(&fname);
897 return FR_ERROR;
898 }
899 buf_pool_release(&fname);
900
901 if (m_attach->msg_count == 0)
902 {
903 mx_mbox_close(m_attach);
904 mutt_error(_("No messages in that folder"));
905 return FR_NO_ACTION;
906 }
907
908 /* `$sort`, `$sort_aux`, `$use_threads` could be changed in dlg_index() */
909 const enum EmailSortType old_sort = cs_subset_sort(shared->sub, "sort");
910 const enum EmailSortType old_sort_aux = cs_subset_sort(shared->sub, "sort_aux");
911 const unsigned char old_use_threads = cs_subset_enum(shared->sub, "use_threads");
912
913 mutt_message(_("Tag the messages you want to attach"));
914 struct MuttWindow *dlg = index_pager_init();
915 struct IndexSharedData *index_shared = dlg->wdata;
916 index_shared->attach_msg = true;
917 dialog_push(dlg);
918 struct Mailbox *m_attach_new = dlg_index(dlg, m_attach);
919 dialog_pop();
920 mutt_window_free(&dlg);
921
922 if (!shared->mailbox)
923 {
924 /* Restore old $sort variables */
925 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
926 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
927 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
930 return FR_SUCCESS;
931 }
932
933 bool added_attachment = false;
934 for (int i = 0; i < m_attach_new->msg_count; i++)
935 {
936 if (!m_attach_new->emails[i])
937 break;
938 if (!message_is_tagged(m_attach_new->emails[i]))
939 continue;
940
941 struct AttachPtr *ap = mutt_aptr_new();
942 ap->body = mutt_make_message_attach(m_attach_new, m_attach_new->emails[i],
943 true, shared->sub);
944 if (ap->body)
945 {
946 added_attachment = true;
947 update_idx(shared->adata->menu, shared->adata->actx, ap);
948 }
949 else
950 {
951 mutt_error(_("Unable to attach"));
952 mutt_aptr_free(&ap);
953 }
954 }
956
957 if (m_attach_new == m_attach)
958 {
959 m_attach->readonly = old_readonly;
960 }
961 mx_fastclose_mailbox(m_attach_new, false);
962
963 /* Restore old $sort variables */
964 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
965 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
966 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
968 if (added_attachment)
970 return FR_SUCCESS;
971}
972
976static int op_attachment_detach(struct ComposeSharedData *shared, int op)
977{
978 struct AttachCtx *actx = shared->adata->actx;
979 if (!check_count(actx))
980 return FR_NO_ACTION;
981
982 struct Menu *menu = shared->adata->menu;
983 struct AttachPtr *cur_att = current_attachment(actx, menu);
984 if (cur_att->unowned)
985 cur_att->body->unlink = false;
986
987 int index = menu_get_index(menu);
988 if (delete_attachment(actx, index) == -1)
989 return FR_ERROR;
990
991 menu->num_tagged = 0;
992 for (int i = 0; i < actx->idxlen; i++)
993 {
994 if (actx->idx[i]->body->tagged)
995 menu->num_tagged++;
996 }
997
998 update_menu(actx, menu, false);
1000
1001 index = menu_get_index(menu);
1002 if (index == 0)
1003 shared->email->body = actx->idx[0]->body;
1004
1005 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1006 return FR_SUCCESS;
1007}
1008
1012static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
1013{
1014 if (!check_count(shared->adata->actx))
1015 return FR_NO_ACTION;
1016
1017 int rc = FR_NO_ACTION;
1018 struct Buffer *buf = buf_pool_get();
1019 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1020 shared->adata->menu);
1021
1022 char *id = cur_att->body->content_id;
1023 if (id)
1024 {
1025 buf_strcpy(buf, id);
1026 }
1027 else
1028 {
1029 id = gen_cid();
1030 buf_strcpy(buf, id);
1031 FREE(&id);
1032 }
1033
1034 if (mw_get_field("Content-ID: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1035 {
1036 if (!mutt_str_equal(id, buf_string(buf)))
1037 {
1038 if (check_cid(buf_string(buf)))
1039 {
1040 mutt_str_replace(&cur_att->body->content_id, buf_string(buf));
1043 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1044 rc = FR_SUCCESS;
1045 }
1046 else
1047 {
1048 mutt_error(_("Content-ID can only contain the characters: -.0-9@A-Z_a-z"));
1049 rc = FR_ERROR;
1050 }
1051 }
1052 }
1053
1054 buf_pool_release(&buf);
1055
1056 if (rc != FR_ERROR)
1058
1059 return rc;
1060}
1061
1065static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
1066{
1067 if (!check_count(shared->adata->actx))
1068 return FR_NO_ACTION;
1069
1070 int rc = FR_NO_ACTION;
1071 struct Buffer *buf = buf_pool_get();
1072
1073 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1074 shared->adata->menu);
1075 buf_strcpy(buf, cur_att->body->description);
1076
1077 /* header names should not be translated */
1078 if (mw_get_field("Description: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1079 {
1080 if (!mutt_str_equal(cur_att->body->description, buf_string(buf)))
1081 {
1082 mutt_str_replace(&cur_att->body->description, buf_string(buf));
1084 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1085 rc = FR_SUCCESS;
1086 }
1087 }
1088
1089 buf_pool_release(&buf);
1090 return rc;
1091}
1092
1096static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
1097{
1098 if (!check_count(shared->adata->actx))
1099 return FR_NO_ACTION;
1100
1101 int rc = FR_NO_ACTION;
1102 struct Buffer *buf = buf_pool_get();
1103
1104 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1105 shared->adata->menu);
1106 buf_strcpy(buf, ENCODING(cur_att->body->encoding));
1107
1108 if ((mw_get_field("Content-Transfer-Encoding: ", buf, MUTT_COMP_NO_FLAGS,
1109 HC_OTHER, NULL, NULL) == 0) &&
1110 !buf_is_empty(buf))
1111 {
1112 int enc = mutt_check_encoding(buf_string(buf));
1113 if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1114 {
1115 if (enc != cur_att->body->encoding)
1116 {
1117 cur_att->body->encoding = enc;
1121 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1122 rc = FR_SUCCESS;
1123 }
1124 }
1125 else
1126 {
1127 mutt_error(_("Invalid encoding"));
1128 rc = FR_ERROR;
1129 }
1130 }
1131
1132 buf_pool_release(&buf);
1133 return rc;
1134}
1135
1139static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
1140{
1141 if (!check_count(shared->adata->actx))
1142 return FR_NO_ACTION;
1143
1144 int rc = FR_NO_ACTION;
1145 struct Buffer *buf = buf_pool_get();
1146 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1147 shared->adata->menu);
1148
1149 buf_strcpy(buf, cur_att->body->language);
1150 if (mw_get_field("Content-Language: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1151 {
1152 if (!mutt_str_equal(cur_att->body->language, buf_string(buf)))
1153 {
1154 mutt_str_replace(&cur_att->body->language, buf_string(buf));
1157 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1158 rc = FR_SUCCESS;
1159 }
1161 }
1162 else
1163 {
1164 mutt_warning(_("Empty 'Content-Language'"));
1165 rc = FR_ERROR;
1166 }
1167
1168 buf_pool_release(&buf);
1169 return rc;
1170}
1171
1175static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
1176{
1177 if (!check_count(shared->adata->actx))
1178 return FR_NO_ACTION;
1179 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1180 shared->adata->menu);
1181 if (!mutt_edit_attachment(cur_att->body))
1182 return FR_NO_ACTION;
1183
1184 mutt_update_encoding(cur_att->body, shared->sub);
1186 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1187 return FR_SUCCESS;
1188}
1189
1193static int op_attachment_edit_type(struct ComposeSharedData *shared, int op)
1194{
1195 if (!check_count(shared->adata->actx))
1196 return FR_NO_ACTION;
1197
1198 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1199 shared->adata->menu);
1200 if (!mutt_edit_content_type(NULL, cur_att->body, NULL))
1201 return FR_NO_ACTION;
1202
1203 /* this may have been a change to text/something */
1204 mutt_update_encoding(cur_att->body, shared->sub);
1206 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1207 return FR_SUCCESS;
1208}
1209
1217static int op_attachment_filter(struct ComposeSharedData *shared, int op)
1218{
1219 struct AttachCtx *actx = shared->adata->actx;
1220 if (!check_count(actx))
1221 return FR_NO_ACTION;
1222
1223 struct Menu *menu = shared->adata->menu;
1224 struct AttachPtr *cur_att = current_attachment(actx, menu);
1225 if (cur_att->body->type == TYPE_MULTIPART)
1226 {
1227 mutt_error(_("Can't filter multipart attachments"));
1228 return FR_ERROR;
1229 }
1230 mutt_pipe_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body,
1231 (op == OP_ATTACHMENT_FILTER));
1232 if (op == OP_ATTACHMENT_FILTER) /* cte might have changed */
1233 {
1235 }
1237 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1238 return FR_SUCCESS;
1239}
1240
1244static int op_attachment_get_attachment(struct ComposeSharedData *shared, int op)
1245{
1246 struct AttachCtx *actx = shared->adata->actx;
1247 if (!check_count(actx))
1248 return FR_NO_ACTION;
1249
1250 int rc = FR_ERROR;
1251 struct Menu *menu = shared->adata->menu;
1252 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1253 ba_add_tagged(&ba, actx, menu);
1254 if (ARRAY_EMPTY(&ba))
1255 goto done;
1256
1257 struct Body **bp = NULL;
1258 ARRAY_FOREACH(bp, &ba)
1259 {
1260 if ((*bp)->type == TYPE_MULTIPART)
1261 {
1262 mutt_warning(_("Can't get multipart attachments"));
1263 continue;
1264 }
1266 }
1267
1269 rc = FR_SUCCESS;
1270
1271done:
1272 ARRAY_FREE(&ba);
1273 /* No send2hook since this doesn't change the message. */
1274 return rc;
1275}
1276
1280static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
1281{
1282 if (shared->adata->menu->num_tagged < 2)
1283 {
1284 mutt_error(_("Grouping 'alternatives' requires at least 2 tagged messages"));
1285 return FR_ERROR;
1286 }
1287
1288 return group_attachments(shared, "alternative");
1289}
1290
1294static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
1295{
1296 if (shared->adata->menu->num_tagged < 2)
1297 {
1298 mutt_error(_("Grouping 'multilingual' requires at least 2 tagged messages"));
1299 return FR_ERROR;
1300 }
1301
1302 /* traverse to see whether all the parts have Content-Language: set */
1303 int tagged_with_lang_num = 0;
1304 for (struct Body *b = shared->email->body; b; b = b->next)
1305 if (b->tagged && b->language && *b->language)
1306 tagged_with_lang_num++;
1307
1308 if (shared->adata->menu->num_tagged != tagged_with_lang_num)
1309 {
1310 if (query_yesorno(_("Not all parts have 'Content-Language' set, continue?"),
1311 MUTT_YES) != MUTT_YES)
1312 {
1313 mutt_message(_("Not sending this message"));
1314 return FR_ERROR;
1315 }
1316 }
1317
1318 return group_attachments(shared, "multilingual");
1319}
1320
1324static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
1325{
1326 if (shared->adata->menu->num_tagged < 2)
1327 {
1328 mutt_error(_("Grouping 'related' requires at least 2 tagged messages"));
1329 return FR_ERROR;
1330 }
1331
1332 // ensure Content-ID is set for tagged attachments
1333 for (struct Body *b = shared->email->body; b; b = b->next)
1334 {
1335 if (!b->tagged || (b->type == TYPE_MULTIPART))
1336 continue;
1337
1338 if (!b->content_id)
1339 {
1340 b->content_id = gen_cid();
1341 }
1342 }
1343
1344 return group_attachments(shared, "related");
1345}
1346
1350static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
1351{
1352 int index = menu_get_index(shared->adata->menu);
1353
1354 struct AttachCtx *actx = shared->adata->actx;
1355
1356 if (index < 0)
1357 return FR_ERROR;
1358
1359 if (index == (actx->idxlen - 1))
1360 {
1361 mutt_error(_("Attachment is already at bottom"));
1362 return FR_NO_ACTION;
1363 }
1364 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1365 !actx->idx[index]->body->next)
1366 {
1367 mutt_error(_("Attachment can't be moved out of group"));
1368 return FR_ERROR;
1369 }
1370
1371 // find next attachment at current level
1372 int nextidx = index + 1;
1373 while ((nextidx < actx->idxlen) &&
1374 (actx->idx[nextidx]->level > actx->idx[index]->level))
1375 {
1376 nextidx++;
1377 }
1378 if (nextidx == actx->idxlen)
1379 {
1380 mutt_error(_("Attachment is already at bottom"));
1381 return FR_NO_ACTION;
1382 }
1383
1384 // find final position
1385 int finalidx = index + 1;
1386 if (nextidx < actx->idxlen - 1)
1387 {
1388 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1389 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1390 {
1391 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1392 }
1393 }
1394
1395 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1396 mutt_update_tree(shared->adata->actx);
1399 menu_set_index(shared->adata->menu, finalidx);
1400 return FR_SUCCESS;
1401}
1402
1406static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
1407{
1408 int index = menu_get_index(shared->adata->menu);
1409 if (index < 0)
1410 return FR_ERROR;
1411
1412 struct AttachCtx *actx = shared->adata->actx;
1413
1414 if (index == 0)
1415 {
1416 mutt_error(_("Attachment is already at top"));
1417 return FR_NO_ACTION;
1418 }
1419 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1420 {
1421 mutt_error(_("Attachment can't be moved out of group"));
1422 return FR_ERROR;
1423 }
1424
1425 // find previous attachment at current level
1426 int previdx = index - 1;
1427 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1428 previdx--;
1429
1430 compose_attach_swap(shared->email, actx, previdx, index);
1431 mutt_update_tree(actx);
1434 menu_set_index(shared->adata->menu, previdx);
1435 return FR_SUCCESS;
1436}
1437
1441static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
1442{
1443 int rc = FR_NO_ACTION;
1444 struct Buffer *fname = buf_pool_get();
1445 struct Buffer *type = NULL;
1446 struct AttachPtr *ap = NULL;
1447
1448 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1449 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1450 &CompleteFileOps, &cdata) != 0) ||
1451 buf_is_empty(fname))
1452 {
1453 goto done;
1454 }
1455 buf_expand_path(fname);
1456
1457 /* Call to lookup_mime_type () ? maybe later */
1458 type = buf_pool_get();
1459 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1460 buf_is_empty(type))
1461 {
1462 goto done;
1463 }
1464
1465 rc = FR_ERROR;
1466 char *p = strchr(buf_string(type), '/');
1467 if (!p)
1468 {
1469 mutt_error(_("Content-Type is of the form base/sub"));
1470 goto done;
1471 }
1472 *p++ = 0;
1473 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1474 if (itype == TYPE_OTHER)
1475 {
1476 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1477 goto done;
1478 }
1479
1480 ap = mutt_aptr_new();
1481 /* Touch the file */
1482 if (!mutt_file_touch(buf_string(fname)))
1483 {
1484 mutt_error(_("Can't create file %s"), buf_string(fname));
1485 goto done;
1486 }
1487
1488 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1489 if (!ap->body)
1490 {
1491 mutt_error(_("Error attaching file"));
1492 goto done;
1493 }
1494 update_idx(shared->adata->menu, shared->adata->actx, ap);
1495 ap = NULL; // shared->adata->actx has taken ownership
1496
1497 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1498 shared->adata->menu);
1499 cur_att->body->type = itype;
1500 mutt_str_replace(&cur_att->body->subtype, p);
1501 cur_att->body->unlink = true;
1504
1505 if (mutt_compose_attachment(cur_att->body))
1506 {
1507 mutt_update_encoding(cur_att->body, shared->sub);
1509 }
1510 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1511 rc = FR_SUCCESS;
1512
1513done:
1514 mutt_aptr_free(&ap);
1515 buf_pool_release(&type);
1516 buf_pool_release(&fname);
1517 return rc;
1518}
1519
1523static int op_attachment_print(struct ComposeSharedData *shared, int op)
1524{
1525 struct AttachCtx *actx = shared->adata->actx;
1526 if (!check_count(actx))
1527 return FR_NO_ACTION;
1528
1529 struct Menu *menu = shared->adata->menu;
1530 struct AttachPtr *cur_att = current_attachment(actx, menu);
1531 if (cur_att->body->type == TYPE_MULTIPART)
1532 {
1533 mutt_error(_("Can't print multipart attachments"));
1534 return FR_ERROR;
1535 }
1536
1537 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1538 /* no send2hook, since this doesn't modify the message */
1539 return FR_SUCCESS;
1540}
1541
1545static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
1546{
1547 if (!check_count(shared->adata->actx))
1548 return FR_NO_ACTION;
1549 char *src = NULL;
1550 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1551 shared->adata->menu);
1552 if (cur_att->body->d_filename)
1553 src = cur_att->body->d_filename;
1554 else
1555 src = cur_att->body->filename;
1556 struct Buffer *fname = buf_pool_get();
1557 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1558 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1559 int rc = mw_get_field(_("Send attachment with name: "), fname,
1561 if (rc == 0)
1562 {
1563 // It's valid to set an empty string here, to erase what was set
1564 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1566 }
1567 buf_pool_release(&fname);
1568 return FR_SUCCESS;
1569}
1570
1574static int op_attachment_save(struct ComposeSharedData *shared, int op)
1575{
1576 struct AttachCtx *actx = shared->adata->actx;
1577 if (!check_count(actx))
1578 return FR_NO_ACTION;
1579
1580 struct Menu *menu = shared->adata->menu;
1581 struct AttachPtr *cur_att = current_attachment(actx, menu);
1582 if (cur_att->body->type == TYPE_MULTIPART)
1583 {
1584 mutt_error(_("Can't save multipart attachments"));
1585 return FR_ERROR;
1586 }
1587
1588 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1589 /* no send2hook, since this doesn't modify the message */
1590 return FR_SUCCESS;
1591}
1592
1596static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
1597{
1598 /* toggle the content-disposition between inline/attachment */
1599 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1600 shared->adata->menu);
1601 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1602 DISP_ATTACH :
1606 return FR_SUCCESS;
1607}
1608
1612static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
1613{
1614 if (!check_count(shared->adata->actx))
1615 return FR_NO_ACTION;
1616 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1617 shared->adata->menu);
1618 if (!mutt_is_text_part(cur_att->body))
1619 {
1620 mutt_error(_("Recoding only affects text attachments"));
1621 return FR_ERROR;
1622 }
1623 cur_att->body->noconv = !cur_att->body->noconv;
1624 if (cur_att->body->noconv)
1625 mutt_message(_("The current attachment won't be converted"));
1626 else
1627 mutt_message(_("The current attachment will be converted"));
1629 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1630 return FR_SUCCESS;
1631}
1632
1636static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
1637{
1638 if (!check_count(shared->adata->actx))
1639 return FR_NO_ACTION;
1640 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1641 shared->adata->menu);
1642 cur_att->body->unlink = !cur_att->body->unlink;
1643
1645 /* No send2hook since this doesn't change the message. */
1646 return FR_SUCCESS;
1647}
1648
1652static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
1653{
1654 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1655 {
1656 mutt_error(_("Attachment is not 'multipart'"));
1657 return FR_ERROR;
1658 }
1659
1660 int aidx = shared->adata->menu->current;
1661 struct AttachCtx *actx = shared->adata->actx;
1662 struct Body *b = actx->idx[aidx]->body;
1663 struct Body *b_next = b->next;
1664 struct Body *b_previous = NULL;
1665 struct Body *b_parent = NULL;
1666 int parent_type = actx->idx[aidx]->parent_type;
1667 int level = actx->idx[aidx]->level;
1668
1669 // reorder body pointers
1670 if (attach_body_previous(shared->email->body, b, &b_previous))
1671 b_previous->next = b->parts;
1672 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1673 b_parent->parts = b->parts;
1674 else
1675 shared->email->body = b->parts;
1676
1677 // update attachment list
1678 int i = aidx + 1;
1679 while (actx->idx[i]->level > level)
1680 {
1681 actx->idx[i]->level--;
1682 if (actx->idx[i]->level == level)
1683 {
1684 actx->idx[i]->parent_type = parent_type;
1685 // set body->next for final attachment in group
1686 if (!actx->idx[i]->body->next)
1687 actx->idx[i]->body->next = b_next;
1688 }
1689 i++;
1690 if (i == actx->idxlen)
1691 break;
1692 }
1693
1694 // free memory
1695 actx->idx[aidx]->body->parts = NULL;
1696 actx->idx[aidx]->body->next = NULL;
1697 actx->idx[aidx]->body->email = NULL;
1698 mutt_body_free(&actx->idx[aidx]->body);
1699 FREE(&actx->idx[aidx]->tree);
1700 FREE(&actx->idx[aidx]);
1701
1702 // reorder attachment list
1703 for (int j = aidx; j < (actx->idxlen - 1); j++)
1704 actx->idx[j] = actx->idx[j + 1];
1705 actx->idx[actx->idxlen - 1] = NULL;
1706 actx->idxlen--;
1707 update_menu(actx, shared->adata->menu, false);
1708
1709 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1710 return FR_SUCCESS;
1711}
1712
1716static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
1717{
1718 struct AttachCtx *actx = shared->adata->actx;
1719 if (!check_count(actx))
1720 return FR_NO_ACTION;
1721
1722 int rc = FR_NO_ACTION;
1723 struct Menu *menu = shared->adata->menu;
1724 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1725 ba_add_tagged(&ba, actx, menu);
1726 if (ARRAY_EMPTY(&ba))
1727 goto done;
1728
1729 struct Body **bp = NULL;
1730 ARRAY_FOREACH(bp, &ba)
1731 {
1732 mutt_update_encoding(*bp, shared->sub);
1733 }
1734
1737 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1738 rc = FR_SUCCESS;
1739
1740done:
1741 ARRAY_FREE(&ba);
1742 return rc;
1743}
1744
1745// -----------------------------------------------------------------------------
1746
1750static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
1751{
1753 const char *tag = NULL;
1754 char *err = NULL;
1755 mutt_env_to_local(shared->email->env);
1756 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1757 if (shared->email->body->type == TYPE_MULTIPART)
1758 {
1759 struct Body *b = shared->email->body->parts;
1760 while (b->parts)
1761 b = b->parts;
1762 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1763 }
1764 else
1765 {
1766 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1767 shared->email, shared->fcc);
1768 }
1769
1770 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1771 {
1772 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1773 FREE(&err);
1774 }
1776
1778 mutt_update_encoding(shared->email->body, shared->sub);
1779
1780 /* attachments may have been added */
1781 if (shared->adata->actx->idxlen &&
1782 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1783 {
1785 update_menu(shared->adata->actx, shared->adata->menu, true);
1786 }
1787
1789 /* Unconditional hook since editor was invoked */
1790 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1791 return FR_SUCCESS;
1792}
1793
1797static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
1798{
1799 if (!check_count(shared->adata->actx))
1800 return FR_NO_ACTION;
1801 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1802 shared->adata->menu);
1803 if (cur_att->body->type == TYPE_MULTIPART)
1804 {
1805 mutt_error(_("Can't edit multipart attachments"));
1806 return FR_ERROR;
1807 }
1808 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1809 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1810 mutt_update_encoding(cur_att->body, shared->sub);
1813 /* Unconditional hook since editor was invoked */
1814 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1815 return FR_SUCCESS;
1816}
1817
1821static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
1822{
1823 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1824 if (!c_edit_headers)
1825 {
1827 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1828 mutt_edit_file(c_editor, shared->email->body->filename);
1830 mutt_update_encoding(shared->email->body, shared->sub);
1832 /* Unconditional hook since editor was invoked */
1833 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1834 return FR_SUCCESS;
1835 }
1836
1837 return op_envelope_edit_headers(shared, op);
1838}
1839
1843static int op_compose_ispell(struct ComposeSharedData *shared, int op)
1844{
1845 endwin();
1846 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1847 char buf[PATH_MAX] = { 0 };
1848 snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), shared->email->body->filename);
1849 if (mutt_system(buf) == -1)
1850 {
1851 mutt_error(_("Error running \"%s\""), buf);
1852 return FR_ERROR;
1853 }
1854
1855 mutt_update_encoding(shared->email->body, shared->sub);
1857 return FR_SUCCESS;
1858}
1859
1863static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
1864{
1865 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1866 {
1868 return FR_ERROR;
1869 }
1870
1871 shared->rc = 1;
1872 return FR_DONE;
1873}
1874
1878static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
1879{
1880 if (!check_count(shared->adata->actx))
1881 return FR_NO_ACTION;
1882 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1883 shared->adata->menu);
1884 if (cur_att->body->type == TYPE_MULTIPART)
1885 {
1886 mutt_error(_("Can't rename multipart attachments"));
1887 return FR_ERROR;
1888 }
1889 struct Buffer *fname = buf_pool_get();
1890 buf_strcpy(fname, cur_att->body->filename);
1891 buf_pretty_mailbox(fname);
1892 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1893 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1894 &CompleteFileOps, &cdata) == 0) &&
1895 !buf_is_empty(fname))
1896 {
1897 struct stat st = { 0 };
1898 if (stat(cur_att->body->filename, &st) == -1)
1899 {
1900 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1901 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1902 buf_pool_release(&fname);
1903 return FR_ERROR;
1904 }
1905
1906 buf_expand_path(fname);
1907 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1908 {
1909 buf_pool_release(&fname);
1910 return FR_ERROR;
1911 }
1912
1913 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1915
1916 if (cur_att->body->stamp >= st.st_mtime)
1917 mutt_stamp_attachment(cur_att->body);
1918 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1919 }
1920 buf_pool_release(&fname);
1921 return FR_SUCCESS;
1922}
1923
1927static int op_compose_send_message(struct ComposeSharedData *shared, int op)
1928{
1929 /* Note: We don't invoke send2-hook here, since we want to leave
1930 * users an opportunity to change settings from the ":" prompt. */
1931 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1932 {
1934 return FR_NO_ACTION;
1935 }
1936
1937 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1938 {
1939 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1940 shared->sub, "copy");
1941 if (ans == MUTT_ABORT)
1942 return FR_NO_ACTION;
1943 else if (ans == MUTT_NO)
1944 buf_reset(shared->fcc);
1945 }
1946
1947 shared->rc = 0;
1948 return FR_DONE;
1949}
1950
1954static int op_compose_write_message(struct ComposeSharedData *shared, int op)
1955{
1956 int rc = FR_NO_ACTION;
1957 struct Buffer *fname = buf_pool_get();
1958 if (shared->mailbox)
1959 {
1960 buf_strcpy(fname, mailbox_path(shared->mailbox));
1961 buf_pretty_mailbox(fname);
1962 }
1963 if (shared->adata->actx->idxlen)
1964 shared->email->body = shared->adata->actx->idx[0]->body;
1965 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
1966 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1967 !buf_is_empty(fname))
1968 {
1969 mutt_message(_("Writing message to %s ..."), buf_string(fname));
1970 buf_expand_path(fname);
1971
1972 if (shared->email->body->next)
1973 shared->email->body = mutt_make_multipart(shared->email->body);
1974
1975 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
1976 NULL, shared->sub) == 0)
1977 mutt_message(_("Message written"));
1978
1979 shared->email->body = mutt_remove_multipart(shared->email->body);
1980 rc = FR_SUCCESS;
1981 }
1982 buf_pool_release(&fname);
1983 return rc;
1984}
1985
1996static int op_display_headers(struct ComposeSharedData *shared, int op)
1997{
1998 if (!check_count(shared->adata->actx))
1999 return FR_NO_ACTION;
2000
2001 enum ViewAttachMode mode = MUTT_VA_REGULAR;
2002
2003 switch (op)
2004 {
2005 case OP_ATTACHMENT_VIEW:
2006 case OP_DISPLAY_HEADERS:
2007 break;
2008
2009 case OP_ATTACHMENT_VIEW_MAILCAP:
2010 mode = MUTT_VA_MAILCAP;
2011 break;
2012
2013 case OP_ATTACHMENT_VIEW_PAGER:
2014 mode = MUTT_VA_PAGER;
2015 break;
2016
2017 case OP_ATTACHMENT_VIEW_TEXT:
2018 mode = MUTT_VA_AS_TEXT;
2019 break;
2020 }
2021
2022 if (mode == MUTT_VA_REGULAR)
2023 {
2024 mutt_attach_display_loop(shared->sub, shared->adata->menu, op,
2025 shared->email, shared->adata->actx, false);
2026 }
2027 else
2028 {
2029 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
2030 shared->adata->menu);
2031 mutt_view_attachment(NULL, cur_att->body, mode, shared->email,
2032 shared->adata->actx, shared->adata->menu->win);
2033 }
2034
2036 /* no send2hook, since this doesn't modify the message */
2037 return FR_SUCCESS;
2038}
2039
2043static int op_exit(struct ComposeSharedData *shared, int op)
2044{
2045 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2046 shared->sub, "postpone");
2047 if (ans == MUTT_NO)
2048 {
2049 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2050 if (shared->adata->actx->idx[i]->unowned)
2051 shared->adata->actx->idx[i]->body->unlink = false;
2052
2053 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2054 {
2055 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2056 {
2057 /* avoid freeing other attachments */
2058 shared->adata->actx->idx[i]->body->next = NULL;
2059 if (!shared->adata->actx->idx[i]->body->email)
2060 shared->adata->actx->idx[i]->body->parts = NULL;
2061 mutt_body_free(&shared->adata->actx->idx[i]->body);
2062 }
2063 }
2064 shared->rc = -1;
2065 return FR_DONE;
2066 }
2067 else if (ans == MUTT_ABORT)
2068 {
2069 return FR_NO_ACTION;
2070 }
2071
2072 return op_compose_postpone_message(shared, op);
2073}
2074
2078static int op_forget_passphrase(struct ComposeSharedData *shared, int op)
2079{
2081 return FR_SUCCESS;
2082}
2083
2084// -----------------------------------------------------------------------------
2085
2089static const struct ComposeFunction ComposeFunctions[] = {
2090 // clang-format off
2091 { OP_ATTACHMENT_ATTACH_FILE, op_attachment_attach_file },
2092 { OP_ATTACHMENT_ATTACH_KEY, op_attachment_attach_key },
2093 { OP_ATTACHMENT_ATTACH_MESSAGE, op_attachment_attach_message },
2094 { OP_ATTACHMENT_ATTACH_NEWS_MESSAGE, op_attachment_attach_message },
2095 { OP_ATTACHMENT_DETACH, op_attachment_detach },
2096 { OP_ATTACHMENT_EDIT_CONTENT_ID, op_attachment_edit_content_id },
2097 { OP_ATTACHMENT_EDIT_DESCRIPTION, op_attachment_edit_description },
2098 { OP_ATTACHMENT_EDIT_ENCODING, op_attachment_edit_encoding },
2099 { OP_ATTACHMENT_EDIT_LANGUAGE, op_attachment_edit_language },
2100 { OP_ATTACHMENT_EDIT_MIME, op_attachment_edit_mime },
2101 { OP_ATTACHMENT_EDIT_TYPE, op_attachment_edit_type },
2102 { OP_ATTACHMENT_FILTER, op_attachment_filter },
2103 { OP_ATTACHMENT_GET_ATTACHMENT, op_attachment_get_attachment },
2104 { OP_ATTACHMENT_GROUP_ALTS, op_attachment_group_alts },
2105 { OP_ATTACHMENT_GROUP_LINGUAL, op_attachment_group_lingual },
2106 { OP_ATTACHMENT_GROUP_RELATED, op_attachment_group_related },
2107 { OP_ATTACHMENT_MOVE_DOWN, op_attachment_move_down },
2108 { OP_ATTACHMENT_MOVE_UP, op_attachment_move_up },
2109 { OP_ATTACHMENT_NEW_MIME, op_attachment_new_mime },
2110 { OP_PIPE, op_attachment_filter },
2111 { OP_ATTACHMENT_PRINT, op_attachment_print },
2112 { OP_ATTACHMENT_RENAME_ATTACHMENT, op_attachment_rename_attachment },
2113 { OP_ATTACHMENT_SAVE, op_attachment_save },
2114 { OP_ATTACHMENT_TOGGLE_DISPOSITION, op_attachment_toggle_disposition },
2115 { OP_ATTACHMENT_TOGGLE_RECODE, op_attachment_toggle_recode },
2116 { OP_ATTACHMENT_TOGGLE_UNLINK, op_attachment_toggle_unlink },
2117 { OP_ATTACHMENT_UNGROUP, op_attachment_ungroup },
2118 { OP_ATTACHMENT_UPDATE_ENCODING, op_attachment_update_encoding },
2119 { OP_ATTACHMENT_VIEW, op_display_headers },
2120 { OP_ATTACHMENT_VIEW_MAILCAP, op_display_headers },
2121 { OP_ATTACHMENT_VIEW_PAGER, op_display_headers },
2122 { OP_ATTACHMENT_VIEW_TEXT, op_display_headers },
2123 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2124 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2125 { OP_COMPOSE_ISPELL, op_compose_ispell },
2126 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2127 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2128 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2129 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2130 { OP_DISPLAY_HEADERS, op_display_headers },
2131 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2132 { OP_EXIT, op_exit },
2133 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2134 { 0, NULL },
2135 // clang-format on
2136};
2137
2142{
2143 // The Dispatcher may be called on any Window in the Dialog
2144 struct MuttWindow *dlg = dialog_find(win);
2145 if (!dlg || !dlg->wdata)
2146 return FR_ERROR;
2147
2148 int rc = FR_UNKNOWN;
2149 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2150 {
2151 const struct ComposeFunction *fn = &ComposeFunctions[i];
2152 if (fn->op == op)
2153 {
2154 struct ComposeSharedData *shared = dlg->wdata;
2155 rc = fn->function(shared, op);
2156 break;
2157 }
2158 }
2159
2160 if (rc == FR_UNKNOWN) // Not our function
2161 return rc;
2162
2163 const char *result = dispatcher_get_retval_name(rc);
2164 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2165
2166 return rc;
2167}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:65
void mutt_actx_ins_attach(struct AttachCtx *actx, struct AttachPtr *attach, int aidx)
Insert an Attachment into an Attachment Context at Specified Index.
Definition: attach.c:91
struct AttachPtr * mutt_aptr_new(void)
Create a new Attachment Pointer.
Definition: attach.c:40
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:162
void mutt_aptr_free(struct AttachPtr **ptr)
Free an Attachment Pointer.
Definition: attach.c:49
bool attach_body_parent(struct Body *start, struct Body *start_parent, struct Body *body, struct Body **body_parent)
Find the parent of a body.
Definition: lib.c:71
int attach_body_count(struct Body *body, bool recurse)
Count bodies.
Definition: lib.c:42
bool attach_body_previous(struct Body *start, struct Body *body, struct Body **previous)
Find the previous body of a body.
Definition: lib.c:142
GUI display the mailboxes in a side panel.
Compose Attach Data.
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
Select a Mailbox from a list.
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: lib.h:59
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition: functions.c:220
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition: functions.c:2089
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition: functions.c:87
static int group_attachments(struct ComposeSharedData *shared, char *subtype)
Group tagged attachments into a multipart group.
Definition: functions.c:517
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attachment to the message.
Definition: functions.c:426
static char * gen_cid(void)
Generate a random Content ID.
Definition: functions.c:237
static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
Swap two adjacent entries in the attachment list.
Definition: functions.c:451
static bool check_cid(const char *cid)
Check if a Content-ID is valid.
Definition: functions.c:253
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition: functions.c:273
const struct MenuOpSeq ComposeDefaultBindings[]
Key bindings for the Compose Menu.
Definition: functions.c:155
static int delete_attachment(struct AttachCtx *actx, int aidx)
Delete an attachment.
Definition: functions.c:336
#define MUTT_COMPOSE_NOFREEHEADER
Definition: lib.h:52
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:71
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:266
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:223
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_POP
'POP3' Mailbox type
Definition: mailbox.h:52
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:90
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:304
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:117
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:109
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:142
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition: dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_DONE
Exit the Dialog.
Definition: dispatcher.h:35
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition: dispatcher.h:36
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
void update_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
Definition: dlg_compose.c:282
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1436
Edit a string.
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
Structs that make up an email.
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:366
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:437
EmailSortType
Methods for sorting Emails.
Definition: sort.h:53
@ NT_EMAIL_CHANGE_ATTACH
Email's Attachments have changed.
Definition: email.h:188
@ NT_EMAIL_CHANGE_ENVELOPE
Email's Envelope has changed.
Definition: email.h:187
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition: envelope.c:355
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition: envelope.c:317
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1070
Manage where the email is piped to external commands.
bool mutt_file_touch(const char *path)
Make sure a file exists.
Definition: file.c:981
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1264
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:67
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:201
static int op_attachment_print(struct AttachPrivateData *priv, int op)
print the current entry - Implements attach_function_t -
Definition: functions.c:364
static int op_attachment_edit_type(struct AttachPrivateData *priv, int op)
edit attachment content type - Implements attach_function_t -
Definition: functions.c:343
static int op_forget_passphrase(struct AttachPrivateData *priv, int op)
wipe passphrases from memory - Implements attach_function_t -
Definition: functions.c:553
static int op_attachment_save(struct AttachPrivateData *priv, int op)
save message/attachment to a mailbox/file - Implements attach_function_t -
Definition: functions.c:375
static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/multilingual' - Implements compose_function_t -.
Definition: functions.c:1294
static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
Definition: functions.c:1280
static int op_attachment_filter(struct ComposeSharedData *shared, int op)
Filter attachment through a shell command - Implements compose_function_t -.
Definition: functions.c:1217
static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
Rename/move an attached file - Implements compose_function_t -.
Definition: functions.c:1878
static int op_compose_ispell(struct ComposeSharedData *shared, int op)
Run ispell on the message - Implements compose_function_t -.
Definition: functions.c:1843
static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
Edit attachment description - Implements compose_function_t -.
Definition: functions.c:1065
static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
Definition: functions.c:1324
static int op_display_headers(struct ComposeSharedData *shared, int op)
Display message and toggle header weeding - Implements compose_function_t -.
Definition: functions.c:1996
static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
Attach a PGP public key - Implements compose_function_t -.
Definition: functions.c:800
static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
Edit the file to be attached - Implements compose_function_t -.
Definition: functions.c:1797
static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
Send attachment with a different name - Implements compose_function_t -.
Definition: functions.c:1545
static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
Move an attachment down in the attachment list - Implements compose_function_t -.
Definition: functions.c:1350
static int op_compose_send_message(struct ComposeSharedData *shared, int op)
Send the message - Implements compose_function_t -.
Definition: functions.c:1927
static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
Attach files to this message - Implements compose_function_t -.
Definition: functions.c:735
static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
Toggle whether to delete file after sending it - Implements compose_function_t -.
Definition: functions.c:1636
static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition: functions.c:1612
static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
Move an attachment up in the attachment list - Implements compose_function_t -.
Definition: functions.c:1406
static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
Edit the 'Content-Language' of the attachment - Implements compose_function_t -.
Definition: functions.c:1139
static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
Edit the message with headers - Implements compose_function_t -.
Definition: functions.c:1750
static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition: functions.c:1596
static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
Edit attachment transfer-encoding - Implements compose_function_t -.
Definition: functions.c:1096
static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
Update an attachment's encoding info - Implements compose_function_t -.
Definition: functions.c:1716
static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
Attach messages to this message - Implements compose_function_t -.
Definition: functions.c:828
static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
Ungroup a 'multipart' attachment - Implements compose_function_t -.
Definition: functions.c:1652
static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
Edit the 'Content-ID' of the attachment - Implements compose_function_t -.
Definition: functions.c:1012
static int op_attachment_get_attachment(struct ComposeSharedData *shared, int op)
Get a temporary copy of an attachment - Implements compose_function_t -.
Definition: functions.c:1244
static int op_compose_write_message(struct ComposeSharedData *shared, int op)
Write the message to a folder - Implements compose_function_t -.
Definition: functions.c:1954
static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
Edit attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1175
static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
Edit the message - Implements compose_function_t -.
Definition: functions.c:1821
static int op_attachment_detach(struct ComposeSharedData *shared, int op)
Delete the current entry - Implements compose_function_t -.
Definition: functions.c:976
static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
Save this message to send later - Implements compose_function_t -.
Definition: functions.c:1863
static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1441
int compose_function_dispatcher(struct MuttWindow *win, int op)
Perform a Compose function - Implements function_dispatcher_t -.
Definition: functions.c:2141
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1099
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition: curs_lib.c:237
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:273
#define mutt_warning(...)
Definition: logging2.h:90
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2786
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1156
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2344
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition: lib.h:56
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:699
Parse and execute user-defined hooks.
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:48
IMAP network mailbox.
GUI manage the main index (list of emails)
Data shared between Index, Pager and Sidebar.
Manage keymappings.
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:55
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:58
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_UUENCODED
UUEncoded text.
Definition: mime.h:54
@ ENC_OTHER
Encoding unknown.
Definition: mime.h:48
ContentType
Content-Type.
Definition: mime.h:30
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
#define ENCODING(x)
Definition: mime.h:92
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
const char * mutt_path_basename(const char *path)
Find the last component for a pathname.
Definition: path.c:282
struct Regex * mutt_regex_new(const char *str, uint32_t flags, struct Buffer *err)
Create an Regex from a string.
Definition: regex.c:80
void mutt_regex_free(struct Regex **ptr)
Free a Regex object.
Definition: regex.c:118
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:614
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:661
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
#define PATH_MAX
Definition: mutt.h:42
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
Definition: mutt_attach.c:265
int mutt_get_tmp_attachment(struct Body *b)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:72
int mutt_compose_attachment(struct Body *b)
Create an attachment.
Definition: mutt_attach.c:120
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
Definition: mutt_attach.c:419
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:432
ViewAttachMode
Options for mutt_view_attachment()
Definition: mutt_attach.h:43
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:45
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:44
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:47
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:46
int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
Event loop for the Attachment menu.
Definition: recvattach.c:961
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:724
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition: recvattach.c:887
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:181
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:205
bool mutt_is_text_part(const struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:407
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:519
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
Some miscellaneous functions.
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: mview.c:363
View of a Mailbox.
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:414
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1325
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1640
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
API for mailboxes.
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:43
API for encryption/signing of emails.
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:96
#define WithCrypto
Definition: lib.h:122
Nntp-specific Account data.
Usenet network mailbox type; talk to an NNTP server.
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:556
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:77
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:945
@ NT_EMAIL
Email has changed, NotifyEmail, EventEmail.
Definition: notify_type.h:44
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
POP network mailbox.
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:355
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:379
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:106
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:77
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:122
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Definition: recvattach.c:1240
void mutt_rfc3676_space_unstuff(struct Email *e)
Remove RFC3676 space stuffing.
Definition: rfc3676.c:499
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition: rfc3676.c:486
RFC3676 Format Flowed routines.
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:607
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:454
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1058
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:410
#define MUTT_RANDTAG_LEN
Definition: sendlib.h:35
Sidebar functions.
GUI display the mailboxes in a side panel.
int endwin(void)
Key value store.
#define NONULL(x)
Definition: string2.h:37
A set of attachments.
Definition: attach.h:63
short vcount
The number of virtual attachments.
Definition: attach.h:72
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:67
short idxlen
Number of attachmentes.
Definition: attach.h:68
An email to which things will be attached.
Definition: attach.h:35
struct Body * body
Attachment.
Definition: attach.h:36
char * tree
Tree characters to display.
Definition: attach.h:39
int level
Nesting depth of attachment.
Definition: attach.h:40
bool unowned
Don't unlink on detach.
Definition: attach.h:42
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
The body of an email.
Definition: body.h:36
char * language
content-language (RFC8255)
Definition: body.h:78
char * content_id
Content-Id (RFC2392)
Definition: body.h:58
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
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
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:63
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:75
struct Email * email
header information for message/rfc822
Definition: body.h:74
char * description
content-description
Definition: body.h:55
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
bool tagged
This attachment is tagged.
Definition: body.h:90
struct Body * next
next attachment in the list
Definition: body.h:72
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
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
struct Menu * menu
Menu displaying the attachments.
Definition: attach_data.h:35
struct AttachCtx * actx
Set of attachments.
Definition: attach_data.h:34
A NeoMutt function.
Definition: functions.h:45
int op
Op code, e.g. OP_COMPOSE_WRITE_MESSAGE.
Definition: functions.h:46
compose_function_t function
Function to call.
Definition: functions.h:47
Shared Compose Data.
Definition: shared_data.h:36
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:37
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:38
int flags
Flags, e.g. MUTT_COMPOSE_NOFREEHEADER.
Definition: shared_data.h:46
bool fcc_set
User has edited the Fcc: field.
Definition: shared_data.h:47
int rc
Return code to leave compose.
Definition: shared_data.h:48
struct ComposeAttachData * adata
Attachments.
Definition: shared_data.h:40
struct Email * email
Email being composed.
Definition: shared_data.h:39
struct Buffer * fcc
Buffer to save FCC.
Definition: shared_data.h:45
A set of inherited config items.
Definition: subset.h:46
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:49
The envelope/body of an email.
Definition: email.h:39
struct Envelope * env
Envelope information.
Definition: email.h:68
struct Body * body
List of MIME parts.
Definition: email.h:69
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:73
Input for the file completion function.
Definition: curs_lib.h:40
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
bool attach_msg
Are we in "attach message" mode?
Definition: shared_data.h:46
A mailbox.
Definition: mailbox.h:79
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:116
Mapping between a function and an operation.
Definition: lib.h:102
Mapping between an operation and a key sequence.
Definition: lib.h:111
Definition: lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:86
int current
Current entry.
Definition: lib.h:80
int num_tagged
Number of tagged entries.
Definition: lib.h:93
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:85
void * wdata
Private data.
Definition: mutt_window.h:145
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
Cached regular expression.
Definition: regex3.h:86
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:299