NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
24
30
31#include "config.h"
32#include <errno.h>
33#include <stdbool.h>
34#include <string.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include "private.h"
38#include "mutt/lib.h"
39#include "config/lib.h"
40#include "email/lib.h"
41#include "core/lib.h"
42#include "conn/lib.h"
43#include "gui/lib.h"
44#include "mutt.h"
45#include "functions.h"
46#include "lib.h"
47#include "attach/lib.h"
48#include "browser/lib.h"
49#include "editor/lib.h"
50#include "history/lib.h"
51#include "hooks/lib.h"
52#include "imap/lib.h"
53#include "index/lib.h"
54#include "key/lib.h"
55#include "menu/lib.h"
56#include "ncrypt/lib.h"
57#include "nntp/lib.h"
58#include "pop/lib.h"
59#include "question/lib.h"
60#include "send/lib.h"
61#include "attach_data.h"
62#include "external.h"
63#include "globals.h"
64#include "mutt_logging.h"
65#include "muttlib.h"
66#include "mx.h"
67#include "nntp/adata.h" // IWYU pragma: keep
68#include "shared_data.h"
69#ifdef ENABLE_NLS
70#include <libintl.h>
71#endif
72
75
76// clang-format off
80static const struct MenuFuncOp OpCompose[] = { /* map: compose */
81 { "attach-file", OP_ATTACH_ATTACH_FILE },
82 { "attach-key", OP_ATTACH_ATTACH_KEY },
83 { "attach-message", OP_ATTACH_ATTACH_MESSAGE },
84 { "attach-news-message", OP_ATTACH_ATTACH_NEWS_MESSAGE },
85#ifdef USE_AUTOCRYPT
86 { "autocrypt-menu", OP_COMPOSE_AUTOCRYPT_MENU },
87#endif
88 { "copy-file", OP_ATTACH_SAVE },
89 { "detach-file", OP_ATTACH_DETACH },
90 { "display-toggle-weed", OP_DISPLAY_HEADERS },
91 { "edit-bcc", OP_ENVELOPE_EDIT_BCC },
92 { "edit-cc", OP_ENVELOPE_EDIT_CC },
93 { "edit-content-id", OP_ATTACH_EDIT_CONTENT_ID },
94 { "edit-description", OP_ATTACH_EDIT_DESCRIPTION },
95 { "edit-encoding", OP_ATTACH_EDIT_ENCODING },
96 { "edit-fcc", OP_ENVELOPE_EDIT_FCC },
97 { "edit-file", OP_COMPOSE_EDIT_FILE },
98 { "edit-followup-to", OP_ENVELOPE_EDIT_FOLLOWUP_TO },
99 { "edit-from", OP_ENVELOPE_EDIT_FROM },
100 { "edit-headers", OP_ENVELOPE_EDIT_HEADERS },
101 { "edit-language", OP_ATTACH_EDIT_LANGUAGE },
102 { "edit-message", OP_COMPOSE_EDIT_MESSAGE },
103 { "edit-mime", OP_ATTACH_EDIT_MIME },
104 { "edit-newsgroups", OP_ENVELOPE_EDIT_NEWSGROUPS },
105 { "edit-reply-to", OP_ENVELOPE_EDIT_REPLY_TO },
106 { "edit-subject", OP_ENVELOPE_EDIT_SUBJECT },
107 { "edit-to", OP_ENVELOPE_EDIT_TO },
108 { "edit-type", OP_ATTACH_EDIT_TYPE },
109 { "edit-x-comment-to", OP_ENVELOPE_EDIT_X_COMMENT_TO },
110 { "exit", OP_EXIT },
111 { "filter-entry", OP_ATTACH_FILTER },
112 { "forget-passphrase", OP_FORGET_PASSPHRASE },
113 { "get-attachment", OP_ATTACH_GET_ATTACHMENT },
114 { "group-alternatives", OP_ATTACH_GROUP_ALTS },
115 { "group-multilingual", OP_ATTACH_GROUP_LINGUAL },
116 { "group-related", OP_ATTACH_GROUP_RELATED },
117 { "ispell", OP_COMPOSE_ISPELL },
118 { "move-down", OP_ATTACH_MOVE_DOWN },
119 { "move-up", OP_ATTACH_MOVE_UP },
120 { "new-mime", OP_ATTACH_NEW_MIME },
121 { "pgp-menu", OP_COMPOSE_PGP_MENU },
122 { "pipe-entry", OP_PIPE },
123 { "pipe-message", OP_PIPE },
124 { "postpone-message", OP_COMPOSE_POSTPONE_MESSAGE },
125 { "preview-page-down", OP_PREVIEW_PAGE_DOWN },
126 { "preview-page-up", OP_PREVIEW_PAGE_UP },
127 { "print-entry", OP_ATTACH_PRINT },
128 { "rename-attachment", OP_ATTACH_RENAME_ATTACHMENT },
129 { "rename-file", OP_COMPOSE_RENAME_FILE },
130 { "send-message", OP_COMPOSE_SEND_MESSAGE },
131 { "smime-menu", OP_COMPOSE_SMIME_MENU },
132 { "toggle-disposition", OP_ATTACH_TOGGLE_DISPOSITION },
133 { "toggle-recode", OP_ATTACH_TOGGLE_RECODE },
134 { "toggle-unlink", OP_ATTACH_TOGGLE_UNLINK },
135 { "ungroup-attachment", OP_ATTACH_UNGROUP },
136 { "update-encoding", OP_ATTACH_UPDATE_ENCODING },
137 { "view-attach", OP_ATTACH_VIEW },
138 { "view-mailcap", OP_ATTACH_VIEW_MAILCAP },
139 { "view-pager", OP_ATTACH_VIEW_PAGER },
140 { "view-text", OP_ATTACH_VIEW_TEXT },
141 { "write-fcc", OP_COMPOSE_WRITE_MESSAGE },
142 { NULL, 0 },
143};
144
148static const struct MenuOpSeq ComposeDefaultBindings[] = { /* map: compose */
149 { OP_ATTACH_ATTACH_FILE, "a" },
150 { OP_ATTACH_ATTACH_KEY, "\033k" }, // <Alt-k>
151 { OP_ATTACH_ATTACH_MESSAGE, "A" },
152 { OP_ATTACH_DETACH, "D" },
153 { OP_ATTACH_EDIT_CONTENT_ID, "\033i" }, // <Alt-i>
154 { OP_ATTACH_EDIT_DESCRIPTION, "d" },
155 { OP_ATTACH_EDIT_ENCODING, "\005" }, // <Ctrl-E>
156 { OP_ATTACH_EDIT_LANGUAGE, "\014" }, // <Ctrl-L>
157 { OP_ATTACH_EDIT_MIME, "m" },
158 { OP_ATTACH_EDIT_TYPE, "\024" }, // <Ctrl-T>
159 { OP_ATTACH_FILTER, "F" },
160 { OP_ATTACH_GET_ATTACHMENT, "G" },
161 { OP_ATTACH_GROUP_ALTS, "&" },
162 { OP_ATTACH_GROUP_LINGUAL, "^" },
163 { OP_ATTACH_GROUP_RELATED, "%" },
164 { OP_ATTACH_MOVE_DOWN, "+" },
165 { OP_ATTACH_MOVE_UP, "-" },
166 { OP_ATTACH_NEW_MIME, "n" },
167 { OP_EXIT, "q" },
168 { OP_PIPE, "|" },
169 { OP_ATTACH_PRINT, "l" },
170 { OP_ATTACH_RENAME_ATTACHMENT, "\017" }, // <Ctrl-O>
171 { OP_ATTACH_SAVE, "C" },
172 { OP_ATTACH_TOGGLE_DISPOSITION, "\004" }, // <Ctrl-D>
173 { OP_ATTACH_TOGGLE_UNLINK, "u" },
174 { OP_ATTACH_UNGROUP, "#" },
175 { OP_ATTACH_UPDATE_ENCODING, "U" },
176 { OP_ATTACH_VIEW, "<keypadenter>" },
177 { OP_ATTACH_VIEW, "\n" }, // <Enter>
178 { OP_ATTACH_VIEW, "\r" }, // <Return>
179#ifdef USE_AUTOCRYPT
180 { OP_COMPOSE_AUTOCRYPT_MENU, "o" },
181#endif
182 { OP_COMPOSE_EDIT_FILE, "\033e" }, // <Alt-e>
183 { OP_COMPOSE_EDIT_MESSAGE, "e" },
184 { OP_COMPOSE_ISPELL, "i" },
185 { OP_COMPOSE_PGP_MENU, "p" },
186 { OP_COMPOSE_POSTPONE_MESSAGE, "P" },
187 { OP_COMPOSE_RENAME_FILE, "R" },
188 { OP_COMPOSE_SEND_MESSAGE, "y" },
189 { OP_COMPOSE_SMIME_MENU, "S" },
190 { OP_COMPOSE_WRITE_MESSAGE, "w" },
191 { OP_DISPLAY_HEADERS, "h" },
192 { OP_ENVELOPE_EDIT_BCC, "b" },
193 { OP_ENVELOPE_EDIT_CC, "c" },
194 { OP_ENVELOPE_EDIT_FCC, "f" },
195 { OP_ENVELOPE_EDIT_FROM, "\033f" }, // <Alt-f>
196 { OP_ENVELOPE_EDIT_HEADERS, "E" },
197 { OP_ENVELOPE_EDIT_REPLY_TO, "r" },
198 { OP_ENVELOPE_EDIT_SUBJECT, "s" },
199 { OP_ENVELOPE_EDIT_TO, "t" },
200 { OP_PREVIEW_PAGE_DOWN, "<pagedown>" },
201 { OP_PREVIEW_PAGE_UP, "<pageup>" },
202 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
203 { OP_TAG, "T" },
204 { 0, NULL },
205};
206// clang-format on
207
211void compose_init_keys(struct SubMenu *sm_generic)
212{
213 struct MenuDefinition *md = NULL;
214 struct SubMenu *sm = NULL;
215
217 md = km_register_menu(MENU_COMPOSE, "compose");
218 km_menu_add_submenu(md, sm);
219 km_menu_add_submenu(md, sm_generic);
221
222 MdCompose = md;
223}
224
230static bool check_count(struct AttachCtx *actx)
231{
232 if (actx->idxlen == 0)
233 {
234 mutt_error(_("There are no attachments"));
235 return false;
236 }
237
238 return true;
239}
240
247static char *gen_cid(void)
248{
249 char rndid[MUTT_RANDTAG_LEN + 1];
250
251 mutt_rand_base32(rndid, sizeof(rndid) - 1);
252 rndid[MUTT_RANDTAG_LEN] = 0;
253
254 return mutt_str_dup(rndid);
255}
256
263static bool check_cid(const char *cid)
264{
265 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
266
267 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
268
269 const bool valid = mutt_regex_match(check_cid_regex, cid);
270
271 mutt_regex_free(&check_cid_regex);
272
273 return valid;
274}
275
283static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
284{
285 int rc = -1;
286 struct stat st = { 0 };
287 struct Buffer *pretty = NULL, *msg = NULL;
288
289 for (int i = 0; i < actx->idxlen; i++)
290 {
291 if (actx->idx[i]->body->type == TYPE_MULTIPART)
292 continue;
293 if (stat(actx->idx[i]->body->filename, &st) != 0)
294 {
295 if (!pretty)
296 pretty = buf_pool_get();
297 buf_strcpy(pretty, actx->idx[i]->body->filename);
298 pretty_mailbox(pretty);
299 /* L10N: This message is displayed in the compose menu when an attachment
300 doesn't stat. %d is the attachment number and %s is the attachment
301 filename. The filename is located last to avoid a long path hiding
302 the error message. */
303 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
304 goto cleanup;
305 }
306
307 if (actx->idx[i]->body->stamp < st.st_mtime)
308 {
309 if (!pretty)
310 pretty = buf_pool_get();
311 buf_strcpy(pretty, actx->idx[i]->body->filename);
312 pretty_mailbox(pretty);
313
314 if (!msg)
315 msg = buf_pool_get();
316 /* L10N: This message is displayed in the compose menu when an attachment
317 is modified behind the scenes. %d is the attachment number and %s is
318 the attachment filename. The filename is located last to avoid a long
319 path hiding the prompt question. */
320 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
321 i + 1, buf_string(pretty));
322
324 if (ans == MUTT_YES)
325 mutt_update_encoding(actx->idx[i]->body, sub);
326 else if (ans == MUTT_ABORT)
327 goto cleanup;
328 }
329 }
330
331 rc = 0;
332
333cleanup:
334 buf_pool_release(&pretty);
335 buf_pool_release(&msg);
336 return rc;
337}
338
346static int delete_attachment(struct AttachCtx *actx, int aidx)
347{
348 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
349 return -1;
350
351 struct AttachPtr **idx = actx->idx;
352 struct Body *b_previous = NULL;
353 struct Body *b_parent = NULL;
354
355 if (aidx == 0)
356 {
357 struct Body *b = actx->idx[0]->body;
358 if (!b->next) // There's only one attachment left
359 {
360 mutt_error(_("You may not delete the only attachment"));
361 return -1;
362 }
363
364 if (cs_subset_bool(NeoMutt->sub, "compose_confirm_detach_first"))
365 {
366 /* L10N: Prompt when trying to hit <detach-file> on the first entry in
367 the compose menu. This entry is most likely the message they just
368 typed. Hitting yes will remove the entry and unlink the file, so
369 it's worth confirming they really meant to do it. */
370 enum QuadOption ans = query_yesorno_help(_("Really delete the main message?"),
372 "compose_confirm_detach_first");
373 if (ans == MUTT_NO)
374 {
375 idx[aidx]->body->tagged = false;
376 return -1;
377 }
378 }
379 }
380
381 if (idx[aidx]->level > 0)
382 {
383 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
384 {
385 if (attach_body_count(b_parent->parts, false) < 3)
386 {
387 mutt_error(_("Can't leave group with only one attachment"));
388 return -1;
389 }
390 }
391 }
392
393 // reorder body pointers
394 if (aidx > 0)
395 {
396 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
397 b_previous->next = idx[aidx]->body->next;
398 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
399 b_parent->parts = idx[aidx]->body->next;
400 }
401
402 // free memory
403 int part_count = 1;
404 if (aidx < (actx->idxlen - 1))
405 {
406 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
407 (idx[aidx + 1]->level > idx[aidx]->level))
408 {
409 part_count += attach_body_count(idx[aidx]->body->parts, true);
410 }
411 }
412 idx[aidx]->body->next = NULL;
413 mutt_body_free(&(idx[aidx]->body));
414 for (int i = 0; i < part_count; i++)
415 {
416 FREE(&idx[aidx + i]->tree);
417 FREE(&idx[aidx + i]);
418 }
419
420 // reorder attachment list
421 for (int i = aidx; i < (actx->idxlen - part_count); i++)
422 idx[i] = idx[i + part_count];
423 for (int i = 0; i < part_count; i++)
424 idx[actx->idxlen - i - 1] = NULL;
425 actx->idxlen -= part_count;
426
427 return 0;
428}
429
436static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
437{
438 ap->level = 0;
439 for (int i = actx->idxlen; i > 0; i--)
440 {
441 if (ap->level == actx->idx[i - 1]->level)
442 {
443 actx->idx[i - 1]->body->next = ap->body;
444 break;
445 }
446 }
447
448 ap->body->aptr = ap;
449 mutt_actx_add_attach(actx, ap);
450 update_menu(actx, menu, false);
451 menu_set_index(menu, actx->vcount - 1);
452}
453
461static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
462{
463 struct AttachPtr **idx = actx->idx;
464
465 // check that attachments really are adjacent
466 if (idx[first]->body->next != idx[second]->body)
467 return;
468
469 // reorder Body pointers
470 if (first == 0)
471 {
472 // first attachment is the fundamental part
473 idx[first]->body->next = idx[second]->body->next;
474 idx[second]->body->next = idx[first]->body;
475 e->body = idx[second]->body;
476 }
477 else
478 {
479 // find previous attachment
480 struct Body *b_previous = NULL;
481 struct Body *b_parent = NULL;
482 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
483 {
484 idx[first]->body->next = idx[second]->body->next;
485 idx[second]->body->next = idx[first]->body;
486 b_previous->next = idx[second]->body;
487 }
488 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
489 {
490 idx[first]->body->next = idx[second]->body->next;
491 idx[second]->body->next = idx[first]->body;
492 b_parent->parts = idx[second]->body;
493 }
494 }
495
496 // reorder attachment list
497 struct AttachPtr *saved = idx[second];
498 for (int i = second; i > first; i--)
499 idx[i] = idx[i - 1];
500 idx[first] = saved;
501
502 // if moved attachment is a group then move subparts too
503 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
504 {
505 int i = second + 1;
506 while (idx[i]->level > idx[first]->level)
507 {
508 saved = idx[i];
509 int destidx = i - second + first;
510 for (int j = i; j > destidx; j--)
511 idx[j] = idx[j - 1];
512 idx[destidx] = saved;
513 i++;
514 if (i >= actx->idxlen)
515 break;
516 }
517 }
518}
519
527static int group_attachments(struct ComposeSharedData *shared, char *subtype)
528{
529 struct AttachCtx *actx = shared->adata->actx;
530 int group_level = -1;
531 struct Body *bptr_parent = NULL;
532
533 // Attachments to be grouped must have the same parent
534 for (int i = 0; i < actx->idxlen; i++)
535 {
536 // check if all tagged attachments are at same level
537 if (actx->idx[i]->body->tagged)
538 {
539 if (group_level == -1)
540 {
541 group_level = actx->idx[i]->level;
542 }
543 else
544 {
545 if (group_level != actx->idx[i]->level)
546 {
547 mutt_error(_("Attachments to be grouped must have the same parent"));
548 return FR_ERROR;
549 }
550 }
551 // if not at top level check if all tagged attachments have same parent
552 if (group_level > 0)
553 {
554 if (bptr_parent)
555 {
556 struct Body *bptr_test = NULL;
557 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
558 mutt_debug(LL_DEBUG5, "can't find parent\n");
559 if (bptr_test != bptr_parent)
560 {
561 mutt_error(_("Attachments to be grouped must have the same parent"));
562 return FR_ERROR;
563 }
564 }
565 else
566 {
567 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
568 mutt_debug(LL_DEBUG5, "can't find parent\n");
569 }
570 }
571 }
572 }
573
574 // Can't group all attachments unless at top level
575 if (bptr_parent)
576 {
577 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
578 {
579 mutt_error(_("Can't leave group with only one attachment"));
580 return FR_ERROR;
581 }
582 }
583
584 struct Body *group = mutt_body_new();
585 group->type = TYPE_MULTIPART;
586 group->subtype = mutt_str_dup(subtype);
587 group->encoding = ENC_7BIT;
588
589 struct Body *bptr_first = NULL; // first tagged attachment
590 struct Body *bptr = NULL; // current tagged attachment
591 struct Body *group_parent = NULL; // parent of group
592 struct Body *group_previous = NULL; // previous body to group
593 struct Body *group_part = NULL; // current attachment in group
594 int group_idx = 0; // index in attachment list where group will be inserted
595 int group_last_idx = 0; // index of last part of previous found group
596 int group_parent_type = TYPE_OTHER;
597
598 for (int i = 0; i < actx->idxlen; i++)
599 {
600 bptr = actx->idx[i]->body;
601 if (bptr->tagged)
602 {
603 // set group properties based on first tagged attachment
604 if (!bptr_first)
605 {
606 group->disposition = bptr->disposition;
607 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
608 group->language = mutt_str_dup(bptr->language);
609 group_parent_type = bptr->aptr->parent_type;
610 bptr_first = bptr;
611 if (i > 0)
612 {
613 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
614 {
615 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
616 }
617 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
618 {
619 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
620 }
621 }
622 }
623
624 shared->adata->menu->num_tagged--;
625 bptr->tagged = false;
626 bptr->aptr->level++;
628
629 // append bptr to the group parts list and remove from email body list
630 struct Body *bptr_previous = NULL;
631 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
632 bptr_previous->next = bptr->next;
633 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
634 bptr_parent->parts = bptr->next;
635 else
636 shared->email->body = bptr->next;
637
638 if (group_part)
639 {
640 // add bptr to group parts list
641 group_part->next = bptr;
642 group_part = group_part->next;
643 group_part->next = NULL;
644
645 // reorder attachments and set levels
646 int bptr_attachments = attach_body_count(bptr, true);
647 for (int j = i + 1; j < (i + bptr_attachments); j++)
648 actx->idx[j]->level++;
649 if (i > (group_last_idx + 1))
650 {
651 for (int j = 0; j < bptr_attachments; j++)
652 {
653 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
654 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
655 actx->idx[k] = actx->idx[k - 1];
656 actx->idx[group_last_idx + 1] = saved;
657 }
658 }
659 i += bptr_attachments - 1;
660 group_last_idx += bptr_attachments;
661 }
662 else
663 {
664 group_idx = i;
665 group->parts = bptr;
666 group_part = bptr;
667 group_part->next = NULL;
668 int bptr_attachments = attach_body_count(bptr, true);
669 for (int j = i + 1; j < (i + bptr_attachments); j++)
670 actx->idx[j]->level++;
671 i += bptr_attachments - 1;
672 group_last_idx = i;
673 }
674 }
675 }
676
677 if (!bptr_first)
678 {
679 mutt_body_free(&group);
680 return FR_ERROR;
681 }
682
683 // set group->next
684 int next_aidx = group_idx + attach_body_count(group->parts, true);
685 if (group_parent)
686 {
687 // find next attachment with the same parent as the group
688 struct Body *b = NULL;
689 struct Body *b_parent = NULL;
690 while (next_aidx < actx->idxlen)
691 {
692 b = actx->idx[next_aidx]->body;
693 b_parent = NULL;
694 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
695 {
696 if (group_parent == b_parent)
697 {
698 group->next = b;
699 break;
700 }
701 }
702 next_aidx++;
703 }
704 }
705 else if (next_aidx < actx->idxlen)
706 {
707 // group is at top level
708 group->next = actx->idx[next_aidx]->body;
709 }
710
711 // set previous or parent for group
712 if (group_previous)
713 group_previous->next = group;
714 else if (group_parent)
715 group_parent->parts = group;
716
718
719 struct AttachPtr *group_ap = mutt_aptr_new();
720 group_ap->body = group;
721 group_ap->body->aptr = group_ap;
722 group_ap->level = group_level;
723 group_ap->parent_type = group_parent_type;
724
725 // insert group into attachment list
726 mutt_actx_ins_attach(actx, group_ap, group_idx);
727
728 // update email body and last attachment pointers
729 shared->email->body = actx->idx[0]->body;
730 actx->idx[actx->idxlen - 1]->body->next = NULL;
731
732 update_menu(actx, shared->adata->menu, false);
733 shared->adata->menu->current = group_idx;
735
736 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
737 return FR_SUCCESS;
738}
739
740// -----------------------------------------------------------------------------
741
745static int op_attach_attach_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
746{
747 char *prompt = _("Attach file");
748 int numfiles = 0;
749 char **files = NULL;
750
751 struct Buffer *fname = buf_pool_get();
752 if ((mw_enter_fname(prompt, fname, false, NULL, true, &files, &numfiles,
753 MUTT_SEL_MULTI) == -1) ||
754 buf_is_empty(fname))
755 {
756 for (int i = 0; i < numfiles; i++)
757 FREE(&files[i]);
758
759 FREE(&files);
760 buf_pool_release(&fname);
761 return FR_NO_ACTION;
762 }
763
764 bool error = false;
765 bool added_attachment = false;
766 if (numfiles > 1)
767 {
768 mutt_message(ngettext("Attaching selected file...",
769 "Attaching selected files...", numfiles));
770 }
771 for (int i = 0; i < numfiles; i++)
772 {
773 char *att = files[i];
774 if (!att)
775 continue;
776
777 struct AttachPtr *ap = mutt_aptr_new();
778 ap->unowned = true;
779 ap->body = mutt_make_file_attach(att, shared->sub);
780 if (ap->body)
781 {
782 added_attachment = true;
783 update_idx(shared->adata->menu, shared->adata->actx, ap);
784 }
785 else
786 {
787 error = true;
788 mutt_error(_("Unable to attach %s"), att);
789 mutt_aptr_free(&ap);
790 }
791 FREE(&files[i]);
792 }
793
794 FREE(&files);
795 buf_pool_release(&fname);
796
797 if (!error)
799
802 if (added_attachment)
803 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
804 return FR_SUCCESS;
805}
806
810static int op_attach_attach_key(struct ComposeSharedData *shared, const struct KeyEvent *event)
811{
813 return FR_NOT_IMPL;
814 struct AttachPtr *ap = mutt_aptr_new();
816 if (ap->body)
817 {
818 update_idx(shared->adata->menu, shared->adata->actx, ap);
820 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
821 }
822 else
823 {
824 mutt_aptr_free(&ap);
825 }
826
828 return FR_SUCCESS;
829}
830
839 const struct KeyEvent *event)
840{
841 char *prompt = _("Open mailbox to attach message from");
842
843 OptNews = false;
844 const int op = event->op;
845 if (shared->mailbox && (op == OP_ATTACH_ATTACH_NEWS_MESSAGE))
846 {
847 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
848 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
849 if (!CurrentNewsSrv)
850 return FR_NO_ACTION;
851
852 prompt = _("Open newsgroup to attach message from");
853 OptNews = true;
854 }
855
856 struct Buffer *fname = buf_pool_get();
857 if (shared->mailbox)
858 {
859 if ((op == OP_ATTACH_ATTACH_MESSAGE) ^ (shared->mailbox->type == MUTT_NNTP))
860 {
861 buf_strcpy(fname, mailbox_path(shared->mailbox));
862 pretty_mailbox(fname);
863 }
864 }
865
866 if ((mw_enter_fname(prompt, fname, true, shared->mailbox, false, NULL, NULL,
867 MUTT_SEL_NO_FLAGS) == -1) ||
868 buf_is_empty(fname))
869 {
870 buf_pool_release(&fname);
871 return FR_NO_ACTION;
872 }
873
874 if (OptNews)
875 nntp_expand_path(fname->data, fname->dsize, &CurrentNewsSrv->conn->account);
876 else
877 expand_path(fname, false);
878
879 if (imap_path_probe(buf_string(fname), NULL) != MUTT_IMAP)
880 {
881 if (pop_path_probe(buf_string(fname), NULL) != MUTT_POP)
882 {
883 if (!OptNews && (nntp_path_probe(buf_string(fname), NULL) != MUTT_NNTP))
884 {
886 {
887 /* check to make sure the file exists and is readable */
888 if (access(buf_string(fname), R_OK) == -1)
889 {
890 mutt_perror("%s", buf_string(fname));
891 buf_pool_release(&fname);
892 return FR_ERROR;
893 }
894 }
895 }
896 }
897 }
898
900
901 struct Mailbox *m_attach = mx_path_resolve(buf_string(fname));
902 const bool old_readonly = m_attach->readonly;
903 if (!mx_mbox_open(m_attach, MUTT_READONLY))
904 {
905 mutt_error(_("Unable to open mailbox %s"), buf_string(fname));
906 mx_fastclose_mailbox(m_attach, false);
907 m_attach = NULL;
908 buf_pool_release(&fname);
909 return FR_ERROR;
910 }
911 buf_pool_release(&fname);
912
913 if (m_attach->msg_count == 0)
914 {
915 mx_mbox_close(m_attach);
916 mutt_error(_("No messages in that folder"));
917 return FR_NO_ACTION;
918 }
919
920 /* `$sort`, `$sort_aux`, `$use_threads` could be changed in dlg_index() */
921 const enum EmailSortType old_sort = cs_subset_sort(shared->sub, "sort");
922 const enum EmailSortType old_sort_aux = cs_subset_sort(shared->sub, "sort_aux");
923 const unsigned char old_use_threads = cs_subset_enum(shared->sub, "use_threads");
924
925 mutt_message(_("Tag the messages you want to attach"));
926 struct MuttWindow *dlg = index_pager_init();
927 struct IndexSharedData *index_shared = dlg->wdata;
928 index_shared->attach_msg = true;
929 dialog_push(dlg);
930 struct Mailbox *m_attach_new = dlg_index(dlg, m_attach);
931 dialog_pop();
932 mutt_window_free(&dlg);
933
934 if (!shared->mailbox)
935 {
936 /* Restore old $sort variables */
937 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
938 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
939 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
942 return FR_SUCCESS;
943 }
944
945 bool added_attachment = false;
946 for (int i = 0; i < m_attach_new->msg_count; i++)
947 {
948 if (!m_attach_new->emails[i])
949 break;
950 if (!message_is_tagged(m_attach_new->emails[i]))
951 continue;
952
953 struct AttachPtr *ap = mutt_aptr_new();
954 ap->body = mutt_make_message_attach(m_attach_new, m_attach_new->emails[i],
955 true, shared->sub);
956 if (ap->body)
957 {
958 added_attachment = true;
959 update_idx(shared->adata->menu, shared->adata->actx, ap);
960 }
961 else
962 {
963 mutt_error(_("Unable to attach"));
964 mutt_aptr_free(&ap);
965 }
966 }
968
969 if (m_attach_new == m_attach)
970 {
971 m_attach->readonly = old_readonly;
972 }
973 mx_fastclose_mailbox(m_attach_new, false);
974
975 /* Restore old $sort variables */
976 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
977 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
978 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
980 if (added_attachment)
981 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
982 return FR_SUCCESS;
983}
984
988static int op_attach_detach(struct ComposeSharedData *shared, const struct KeyEvent *event)
989{
990 struct AttachCtx *actx = shared->adata->actx;
991 if (!check_count(actx))
992 return FR_NO_ACTION;
993
994 struct Menu *menu = shared->adata->menu;
995 struct AttachPtr *cur_att = current_attachment(actx, menu);
996 if (cur_att->unowned)
997 cur_att->body->unlink = false;
998
999 int index = menu_get_index(menu);
1000 if (delete_attachment(actx, index) == -1)
1001 return FR_ERROR;
1002
1003 menu->num_tagged = 0;
1004 for (int i = 0; i < actx->idxlen; i++)
1005 {
1006 if (actx->idx[i]->body->tagged)
1007 menu->num_tagged++;
1008 }
1009
1010 update_menu(actx, menu, false);
1012
1013 index = menu_get_index(menu);
1014 if (index == 0)
1015 shared->email->body = actx->idx[0]->body;
1016
1017 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1018 return FR_SUCCESS;
1019}
1020
1025 const struct KeyEvent *event)
1026{
1027 if (!check_count(shared->adata->actx))
1028 return FR_NO_ACTION;
1029
1030 int rc = FR_NO_ACTION;
1031 struct Buffer *buf = buf_pool_get();
1032 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1033 shared->adata->menu);
1034
1035 char *id = cur_att->body->content_id;
1036 if (id)
1037 {
1038 buf_strcpy(buf, id);
1039 }
1040 else
1041 {
1042 id = gen_cid();
1043 buf_strcpy(buf, id);
1044 FREE(&id);
1045 }
1046
1047 if (mw_get_field("Content-ID: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1048 {
1049 if (!mutt_str_equal(id, buf_string(buf)))
1050 {
1051 if (check_cid(buf_string(buf)))
1052 {
1053 mutt_str_replace(&cur_att->body->content_id, buf_string(buf));
1056 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1057 rc = FR_SUCCESS;
1058 }
1059 else
1060 {
1061 mutt_error(_("Content-ID can only contain the characters: -.0-9@A-Z_a-z"));
1062 rc = FR_ERROR;
1063 }
1064 }
1065 }
1066
1067 buf_pool_release(&buf);
1068
1069 if (rc != FR_ERROR)
1071
1072 return rc;
1073}
1074
1079 const struct KeyEvent *event)
1080{
1081 if (!check_count(shared->adata->actx))
1082 return FR_NO_ACTION;
1083
1084 int rc = FR_NO_ACTION;
1085 struct Buffer *buf = buf_pool_get();
1086
1087 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1088 shared->adata->menu);
1089 buf_strcpy(buf, cur_att->body->description);
1090
1091 /* header names should not be translated */
1092 if (mw_get_field("Description: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1093 {
1094 if (!mutt_str_equal(cur_att->body->description, buf_string(buf)))
1095 {
1096 mutt_str_replace(&cur_att->body->description, buf_string(buf));
1098 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1099 rc = FR_SUCCESS;
1100 }
1101 }
1102
1103 buf_pool_release(&buf);
1104 return rc;
1105}
1106
1111 const struct KeyEvent *event)
1112{
1113 if (!check_count(shared->adata->actx))
1114 return FR_NO_ACTION;
1115
1116 int rc = FR_NO_ACTION;
1117 struct Buffer *buf = buf_pool_get();
1118
1119 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1120 shared->adata->menu);
1121 buf_strcpy(buf, ENCODING(cur_att->body->encoding));
1122
1123 if ((mw_get_field("Content-Transfer-Encoding: ", buf, MUTT_COMP_NO_FLAGS,
1124 HC_OTHER, NULL, NULL) == 0) &&
1125 !buf_is_empty(buf))
1126 {
1127 int enc = mutt_check_encoding(buf_string(buf));
1128 if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1129 {
1130 if (enc != cur_att->body->encoding)
1131 {
1132 cur_att->body->encoding = enc;
1136 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1137 rc = FR_SUCCESS;
1138 }
1139 }
1140 else
1141 {
1142 mutt_error(_("Invalid encoding"));
1143 rc = FR_ERROR;
1144 }
1145 }
1146
1147 buf_pool_release(&buf);
1148 return rc;
1149}
1150
1155 const struct KeyEvent *event)
1156{
1157 if (!check_count(shared->adata->actx))
1158 return FR_NO_ACTION;
1159
1160 int rc = FR_NO_ACTION;
1161 struct Buffer *buf = buf_pool_get();
1162 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1163 shared->adata->menu);
1164
1165 buf_strcpy(buf, cur_att->body->language);
1166 if (mw_get_field("Content-Language: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1167 {
1168 if (!mutt_str_equal(cur_att->body->language, buf_string(buf)))
1169 {
1170 mutt_str_replace(&cur_att->body->language, buf_string(buf));
1173 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1174 rc = FR_SUCCESS;
1175 }
1177 }
1178 else
1179 {
1180 mutt_warning(_("Empty 'Content-Language'"));
1181 rc = FR_ERROR;
1182 }
1183
1184 buf_pool_release(&buf);
1185 return rc;
1186}
1187
1191static int op_attach_edit_mime(struct ComposeSharedData *shared, const struct KeyEvent *event)
1192{
1193 if (!check_count(shared->adata->actx))
1194 return FR_NO_ACTION;
1195 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1196 shared->adata->menu);
1197 if (!mutt_edit_attachment(cur_att->body))
1198 return FR_NO_ACTION;
1199
1200 mutt_update_encoding(cur_att->body, shared->sub);
1202 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1203 return FR_SUCCESS;
1204}
1205
1209static int op_attach_edit_type(struct ComposeSharedData *shared, const struct KeyEvent *event)
1210{
1211 if (!check_count(shared->adata->actx))
1212 return FR_NO_ACTION;
1213
1214 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1215 shared->adata->menu);
1216 if (!mutt_edit_content_type(NULL, cur_att->body, NULL))
1217 return FR_NO_ACTION;
1218
1219 /* this may have been a change to text/something */
1220 mutt_update_encoding(cur_att->body, shared->sub);
1222 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1223 return FR_SUCCESS;
1224}
1225
1233static int op_attach_filter(struct ComposeSharedData *shared, const struct KeyEvent *event)
1234{
1235 struct AttachCtx *actx = shared->adata->actx;
1236 if (!check_count(actx))
1237 return FR_NO_ACTION;
1238
1239 struct Menu *menu = shared->adata->menu;
1240 struct AttachPtr *cur_att = current_attachment(actx, menu);
1241 if (cur_att->body->type == TYPE_MULTIPART)
1242 {
1243 mutt_error(_("Can't filter multipart attachments"));
1244 return FR_ERROR;
1245 }
1246
1247 const int op = event->op;
1248 mutt_pipe_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body,
1249 (op == OP_ATTACH_FILTER));
1250 if (op == OP_ATTACH_FILTER) /* cte might have changed */
1251 {
1253 }
1255 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1256 return FR_SUCCESS;
1257}
1258
1263 const struct KeyEvent *event)
1264{
1265 struct AttachCtx *actx = shared->adata->actx;
1266 if (!check_count(actx))
1267 return FR_NO_ACTION;
1268
1269 int rc = FR_ERROR;
1270 struct Menu *menu = shared->adata->menu;
1271 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1272 ba_add_tagged(&ba, actx, menu);
1273 if (ARRAY_EMPTY(&ba))
1274 goto done;
1275
1276 struct Body **bp = NULL;
1277 ARRAY_FOREACH(bp, &ba)
1278 {
1279 if ((*bp)->type == TYPE_MULTIPART)
1280 {
1281 mutt_warning(_("Can't get multipart attachments"));
1282 continue;
1283 }
1285 }
1286
1288 rc = FR_SUCCESS;
1289
1290done:
1291 ARRAY_FREE(&ba);
1292 /* No send2hook since this doesn't change the message. */
1293 return rc;
1294}
1295
1299static int op_attach_group_alts(struct ComposeSharedData *shared, const struct KeyEvent *event)
1300{
1301 if (shared->adata->menu->num_tagged < 2)
1302 {
1303 mutt_error(_("Grouping 'alternatives' requires at least 2 tagged messages"));
1304 return FR_ERROR;
1305 }
1306
1307 return group_attachments(shared, "alternative");
1308}
1309
1314 const struct KeyEvent *event)
1315{
1316 if (shared->adata->menu->num_tagged < 2)
1317 {
1318 mutt_error(_("Grouping 'multilingual' requires at least 2 tagged messages"));
1319 return FR_ERROR;
1320 }
1321
1322 /* traverse to see whether all the parts have Content-Language: set */
1323 int tagged_with_lang_num = 0;
1324 for (struct Body *b = shared->email->body; b; b = b->next)
1325 if (b->tagged && b->language && *b->language)
1326 tagged_with_lang_num++;
1327
1328 if (shared->adata->menu->num_tagged != tagged_with_lang_num)
1329 {
1330 if (query_yesorno(_("Not all parts have 'Content-Language' set, continue?"),
1331 MUTT_YES) != MUTT_YES)
1332 {
1333 mutt_message(_("Not sending this message"));
1334 return FR_ERROR;
1335 }
1336 }
1337
1338 return group_attachments(shared, "multilingual");
1339}
1340
1345 const struct KeyEvent *event)
1346{
1347 if (shared->adata->menu->num_tagged < 2)
1348 {
1349 mutt_error(_("Grouping 'related' requires at least 2 tagged messages"));
1350 return FR_ERROR;
1351 }
1352
1353 // ensure Content-ID is set for tagged attachments
1354 for (struct Body *b = shared->email->body; b; b = b->next)
1355 {
1356 if (!b->tagged || (b->type == TYPE_MULTIPART))
1357 continue;
1358
1359 if (!b->content_id)
1360 {
1361 b->content_id = gen_cid();
1362 }
1363 }
1364
1365 return group_attachments(shared, "related");
1366}
1367
1371static int op_attach_move_down(struct ComposeSharedData *shared, const struct KeyEvent *event)
1372{
1373 int index = menu_get_index(shared->adata->menu);
1374
1375 struct AttachCtx *actx = shared->adata->actx;
1376
1377 if (index < 0)
1378 return FR_ERROR;
1379
1380 if (index == (actx->idxlen - 1))
1381 {
1382 mutt_error(_("Attachment is already at bottom"));
1383 return FR_NO_ACTION;
1384 }
1385 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1386 !actx->idx[index]->body->next)
1387 {
1388 mutt_error(_("Attachment can't be moved out of group"));
1389 return FR_ERROR;
1390 }
1391
1392 // find next attachment at current level
1393 int nextidx = index + 1;
1394 while ((nextidx < actx->idxlen) &&
1395 (actx->idx[nextidx]->level > actx->idx[index]->level))
1396 {
1397 nextidx++;
1398 }
1399 if (nextidx == actx->idxlen)
1400 {
1401 mutt_error(_("Attachment is already at bottom"));
1402 return FR_NO_ACTION;
1403 }
1404
1405 // find final position
1406 int finalidx = index + 1;
1407 if (nextidx < actx->idxlen - 1)
1408 {
1409 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1410 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1411 {
1412 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1413 }
1414 }
1415
1416 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1417 mutt_update_tree(shared->adata->actx);
1420 menu_set_index(shared->adata->menu, finalidx);
1421 return FR_SUCCESS;
1422}
1423
1427static int op_attach_move_up(struct ComposeSharedData *shared, const struct KeyEvent *event)
1428{
1429 int index = menu_get_index(shared->adata->menu);
1430 if (index < 0)
1431 return FR_ERROR;
1432
1433 struct AttachCtx *actx = shared->adata->actx;
1434
1435 if (index == 0)
1436 {
1437 mutt_error(_("Attachment is already at top"));
1438 return FR_NO_ACTION;
1439 }
1440 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1441 {
1442 mutt_error(_("Attachment can't be moved out of group"));
1443 return FR_ERROR;
1444 }
1445
1446 // find previous attachment at current level
1447 int previdx = index - 1;
1448 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1449 previdx--;
1450
1451 compose_attach_swap(shared->email, actx, previdx, index);
1452 mutt_update_tree(actx);
1455 menu_set_index(shared->adata->menu, previdx);
1456 return FR_SUCCESS;
1457}
1458
1462static int op_attach_new_mime(struct ComposeSharedData *shared, const struct KeyEvent *event)
1463{
1464 int rc = FR_NO_ACTION;
1465 struct Buffer *fname = buf_pool_get();
1466 struct Buffer *type = NULL;
1467 struct AttachPtr *ap = NULL;
1468
1469 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1470 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1471 &CompleteFileOps, &cdata) != 0) ||
1472 buf_is_empty(fname))
1473 {
1474 goto done;
1475 }
1476 expand_path(fname, false);
1477
1478 /* Call to lookup_mime_type () ? maybe later */
1479 type = buf_pool_get();
1480 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1481 buf_is_empty(type))
1482 {
1483 goto done;
1484 }
1485
1486 rc = FR_ERROR;
1487 char *p = strchr(buf_string(type), '/');
1488 if (!p)
1489 {
1490 mutt_error(_("Content-Type is of the form base/sub"));
1491 goto done;
1492 }
1493 *p++ = 0;
1494 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1495 if (itype == TYPE_OTHER)
1496 {
1497 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1498 goto done;
1499 }
1500
1501 ap = mutt_aptr_new();
1502 /* Touch the file */
1503 if (!mutt_file_touch(buf_string(fname)))
1504 {
1505 mutt_error(_("Can't create file %s"), buf_string(fname));
1506 goto done;
1507 }
1508
1509 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1510 if (!ap->body)
1511 {
1512 mutt_error(_("Error attaching file"));
1513 goto done;
1514 }
1515 update_idx(shared->adata->menu, shared->adata->actx, ap);
1516 ap = NULL; // shared->adata->actx has taken ownership
1517
1518 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1519 shared->adata->menu);
1520 cur_att->body->type = itype;
1521 mutt_str_replace(&cur_att->body->subtype, p);
1522 cur_att->body->unlink = true;
1525
1526 if (mutt_compose_attachment(cur_att->body))
1527 {
1528 mutt_update_encoding(cur_att->body, shared->sub);
1530 }
1531 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1532 rc = FR_SUCCESS;
1533
1534done:
1535 mutt_aptr_free(&ap);
1536 buf_pool_release(&type);
1537 buf_pool_release(&fname);
1538 return rc;
1539}
1540
1544static int op_attach_print(struct ComposeSharedData *shared, const struct KeyEvent *event)
1545{
1546 struct AttachCtx *actx = shared->adata->actx;
1547 if (!check_count(actx))
1548 return FR_NO_ACTION;
1549
1550 struct Menu *menu = shared->adata->menu;
1551 struct AttachPtr *cur_att = current_attachment(actx, menu);
1552 if (cur_att->body->type == TYPE_MULTIPART)
1553 {
1554 mutt_error(_("Can't print multipart attachments"));
1555 return FR_ERROR;
1556 }
1557
1558 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1559 /* no send2hook, since this doesn't modify the message */
1560 return FR_SUCCESS;
1561}
1562
1567 const struct KeyEvent *event)
1568{
1569 if (!check_count(shared->adata->actx))
1570 return FR_NO_ACTION;
1571 char *src = NULL;
1572 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1573 shared->adata->menu);
1574 if (cur_att->body->d_filename)
1575 src = cur_att->body->d_filename;
1576 else
1577 src = cur_att->body->filename;
1578 struct Buffer *fname = buf_pool_get();
1579 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1580 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1581 int rc = mw_get_field(_("Send attachment with name: "), fname,
1583 if (rc == 0)
1584 {
1585 // It's valid to set an empty string here, to erase what was set
1586 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1588 }
1589 buf_pool_release(&fname);
1590 return FR_SUCCESS;
1591}
1592
1596static int op_attach_save(struct ComposeSharedData *shared, const struct KeyEvent *event)
1597{
1598 struct AttachCtx *actx = shared->adata->actx;
1599 if (!check_count(actx))
1600 return FR_NO_ACTION;
1601
1602 struct Menu *menu = shared->adata->menu;
1603 struct AttachPtr *cur_att = current_attachment(actx, menu);
1604 if (cur_att->body->type == TYPE_MULTIPART)
1605 {
1606 mutt_error(_("Can't save multipart attachments"));
1607 return FR_ERROR;
1608 }
1609
1610 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1611 /* no send2hook, since this doesn't modify the message */
1612 return FR_SUCCESS;
1613}
1614
1619 const struct KeyEvent *event)
1620{
1621 /* toggle the content-disposition between inline/attachment */
1622 if (!check_count(shared->adata->actx))
1623 return FR_NO_ACTION;
1624 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1625 shared->adata->menu);
1626 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1627 DISP_ATTACH :
1631 return FR_SUCCESS;
1632}
1633
1638 const struct KeyEvent *event)
1639{
1640 if (!check_count(shared->adata->actx))
1641 return FR_NO_ACTION;
1642 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1643 shared->adata->menu);
1644 if (!mutt_is_text_part(cur_att->body))
1645 {
1646 mutt_error(_("Recoding only affects text attachments"));
1647 return FR_ERROR;
1648 }
1649 cur_att->body->noconv = !cur_att->body->noconv;
1650 if (cur_att->body->noconv)
1651 mutt_message(_("The current attachment won't be converted"));
1652 else
1653 mutt_message(_("The current attachment will be converted"));
1655 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1656 return FR_SUCCESS;
1657}
1658
1663 const struct KeyEvent *event)
1664{
1665 if (!check_count(shared->adata->actx))
1666 return FR_NO_ACTION;
1667 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1668 shared->adata->menu);
1669 cur_att->body->unlink = !cur_att->body->unlink;
1670
1672 /* No send2hook since this doesn't change the message. */
1673 return FR_SUCCESS;
1674}
1675
1679static int op_attach_ungroup(struct ComposeSharedData *shared, const struct KeyEvent *event)
1680{
1681 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1682 {
1683 mutt_error(_("Attachment is not 'multipart'"));
1684 return FR_ERROR;
1685 }
1686
1687 int aidx = shared->adata->menu->current;
1688 struct AttachCtx *actx = shared->adata->actx;
1689 struct Body *b = actx->idx[aidx]->body;
1690 struct Body *b_next = b->next;
1691 struct Body *b_previous = NULL;
1692 struct Body *b_parent = NULL;
1693 int parent_type = actx->idx[aidx]->parent_type;
1694 int level = actx->idx[aidx]->level;
1695
1696 // reorder body pointers
1697 if (attach_body_previous(shared->email->body, b, &b_previous))
1698 b_previous->next = b->parts;
1699 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1700 b_parent->parts = b->parts;
1701 else
1702 shared->email->body = b->parts;
1703
1704 // update attachment list
1705 int i = aidx + 1;
1706 while ((i < actx->idxlen) && (actx->idx[i]->level > level))
1707 {
1708 actx->idx[i]->level--;
1709 if (actx->idx[i]->level == level)
1710 {
1711 actx->idx[i]->parent_type = parent_type;
1712 // set body->next for final attachment in group
1713 if (!actx->idx[i]->body->next)
1714 actx->idx[i]->body->next = b_next;
1715 }
1716 i++;
1717 }
1718
1719 // free memory
1720 actx->idx[aidx]->body->parts = NULL;
1721 actx->idx[aidx]->body->next = NULL;
1722 actx->idx[aidx]->body->email = NULL;
1723 mutt_body_free(&actx->idx[aidx]->body);
1724 FREE(&actx->idx[aidx]->tree);
1725 FREE(&actx->idx[aidx]);
1726
1727 // reorder attachment list
1728 for (int j = aidx; j < (actx->idxlen - 1); j++)
1729 actx->idx[j] = actx->idx[j + 1];
1730 actx->idx[actx->idxlen - 1] = NULL;
1731 actx->idxlen--;
1732 update_menu(actx, shared->adata->menu, false);
1733
1734 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1735 return FR_SUCCESS;
1736}
1737
1742 const struct KeyEvent *event)
1743{
1744 struct AttachCtx *actx = shared->adata->actx;
1745 if (!check_count(actx))
1746 return FR_NO_ACTION;
1747
1748 int rc = FR_NO_ACTION;
1749 struct Menu *menu = shared->adata->menu;
1750 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1751 ba_add_tagged(&ba, actx, menu);
1752 if (ARRAY_EMPTY(&ba))
1753 goto done;
1754
1755 struct Body **bp = NULL;
1756 ARRAY_FOREACH(bp, &ba)
1757 {
1758 mutt_update_encoding(*bp, shared->sub);
1759 }
1760
1763 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1764 rc = FR_SUCCESS;
1765
1766done:
1767 ARRAY_FREE(&ba);
1768 return rc;
1769}
1770
1771// -----------------------------------------------------------------------------
1772
1777 const struct KeyEvent *event)
1778{
1780 const char *tag = NULL;
1781 char *err = NULL;
1782 mutt_env_to_local(shared->email->env);
1783 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1784 if (shared->email->body->type == TYPE_MULTIPART)
1785 {
1786 struct Body *b = shared->email->body->parts;
1787 while (b && b->parts)
1788 b = b->parts;
1789 if (b)
1790 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1791 }
1792 else
1793 {
1794 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1795 shared->email, shared->fcc);
1796 }
1797
1798 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1799 {
1800 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1801 FREE(&err);
1802 }
1804
1806 mutt_update_encoding(shared->email->body, shared->sub);
1807
1808 /* attachments may have been added */
1809 if (shared->adata->actx->idxlen &&
1810 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1811 {
1813 update_menu(shared->adata->actx, shared->adata->menu, true);
1814 }
1815
1817 /* Unconditional hook since editor was invoked */
1818 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1819 return FR_SUCCESS;
1820}
1821
1825static int op_compose_edit_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
1826{
1827 if (!check_count(shared->adata->actx))
1828 return FR_NO_ACTION;
1829 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1830 shared->adata->menu);
1831 if (cur_att->body->type == TYPE_MULTIPART)
1832 {
1833 mutt_error(_("Can't edit multipart attachments"));
1834 return FR_ERROR;
1835 }
1836 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1837 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1838 mutt_update_encoding(cur_att->body, shared->sub);
1841 /* Unconditional hook since editor was invoked */
1842 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1843 return FR_SUCCESS;
1844}
1845
1850 const struct KeyEvent *event)
1851{
1852 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1853 if (!c_edit_headers)
1854 {
1856 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1857 mutt_edit_file(c_editor, shared->email->body->filename);
1859 mutt_update_encoding(shared->email->body, shared->sub);
1861 /* Unconditional hook since editor was invoked */
1862 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1863 return FR_SUCCESS;
1864 }
1865
1866 return op_envelope_edit_headers(shared, event);
1867}
1868
1872static int op_compose_ispell(struct ComposeSharedData *shared, const struct KeyEvent *event)
1873{
1874 endwin();
1875 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1876 struct Buffer *cmd = buf_pool_get();
1877 struct Buffer *quoted = buf_pool_get();
1878 buf_quote_filename(quoted, shared->email->body->filename, true);
1879 buf_printf(cmd, "%s -x %s", NONULL(c_ispell), buf_string(quoted));
1880 buf_pool_release(&quoted);
1881 if (mutt_system(buf_string(cmd)) == -1)
1882 {
1883 mutt_error(_("Error running \"%s\""), buf_string(cmd));
1884 buf_pool_release(&cmd);
1885 return FR_ERROR;
1886 }
1887 buf_pool_release(&cmd);
1888
1889 mutt_update_encoding(shared->email->body, shared->sub);
1891 return FR_SUCCESS;
1892}
1893
1898 const struct KeyEvent *event)
1899{
1900 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1901 {
1903 return FR_ERROR;
1904 }
1905
1906 shared->rc = 1;
1907 return FR_DONE;
1908}
1909
1913static int op_compose_rename_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
1914{
1915 if (!check_count(shared->adata->actx))
1916 return FR_NO_ACTION;
1917 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1918 shared->adata->menu);
1919 if (cur_att->body->type == TYPE_MULTIPART)
1920 {
1921 mutt_error(_("Can't rename multipart attachments"));
1922 return FR_ERROR;
1923 }
1924 struct Buffer *fname = buf_pool_get();
1925 buf_strcpy(fname, cur_att->body->filename);
1926 pretty_mailbox(fname);
1927 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1928 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1929 &CompleteFileOps, &cdata) == 0) &&
1930 !buf_is_empty(fname))
1931 {
1932 struct stat st = { 0 };
1933 if (stat(cur_att->body->filename, &st) == -1)
1934 {
1935 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1936 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1937 buf_pool_release(&fname);
1938 return FR_ERROR;
1939 }
1940
1941 expand_path(fname, false);
1942 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1943 {
1944 buf_pool_release(&fname);
1945 return FR_ERROR;
1946 }
1947
1948 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1950
1951 if (cur_att->body->stamp >= st.st_mtime)
1952 mutt_stamp_attachment(cur_att->body);
1953 exec_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1954 }
1955 buf_pool_release(&fname);
1956 return FR_SUCCESS;
1957}
1958
1963 const struct KeyEvent *event)
1964{
1965 /* Note: We don't invoke send2-hook here, since we want to leave
1966 * users an opportunity to change settings from the ":" prompt. */
1967 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1968 {
1970 return FR_NO_ACTION;
1971 }
1972
1973 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1974 {
1975 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1976 shared->sub, "copy");
1977 if (ans == MUTT_ABORT)
1978 return FR_NO_ACTION;
1979 else if (ans == MUTT_NO)
1980 buf_reset(shared->fcc);
1981 }
1982
1983 shared->rc = 0;
1984 return FR_DONE;
1985}
1986
1991 const struct KeyEvent *event)
1992{
1993 int rc = FR_NO_ACTION;
1994 struct Buffer *fname = buf_pool_get();
1995 if (shared->mailbox)
1996 {
1997 buf_strcpy(fname, mailbox_path(shared->mailbox));
1998 pretty_mailbox(fname);
1999 }
2000 if (shared->adata->actx->idxlen)
2001 shared->email->body = shared->adata->actx->idx[0]->body;
2002 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
2003 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
2004 !buf_is_empty(fname))
2005 {
2006 mutt_message(_("Writing message to %s ..."), buf_string(fname));
2007 expand_path(fname, false);
2008
2009 if (shared->email->body->next)
2010 shared->email->body = mutt_make_multipart(shared->email->body);
2011
2012 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
2013 NULL, shared->sub) == 0)
2014 mutt_message(_("Message written"));
2015
2016 shared->email->body = mutt_remove_multipart(shared->email->body);
2017 rc = FR_SUCCESS;
2018 }
2019 buf_pool_release(&fname);
2020 return rc;
2021}
2022
2033static int op_display_headers(struct ComposeSharedData *shared, const struct KeyEvent *event)
2034{
2035 if (!check_count(shared->adata->actx))
2036 return FR_NO_ACTION;
2037
2038 enum ViewAttachMode mode = MUTT_VA_REGULAR;
2039
2040 const int op = event->op;
2041 switch (op)
2042 {
2043 case OP_ATTACH_VIEW:
2044 case OP_DISPLAY_HEADERS:
2045 break;
2046
2047 case OP_ATTACH_VIEW_MAILCAP:
2048 mode = MUTT_VA_MAILCAP;
2049 break;
2050
2051 case OP_ATTACH_VIEW_PAGER:
2052 mode = MUTT_VA_PAGER;
2053 break;
2054
2055 case OP_ATTACH_VIEW_TEXT:
2056 mode = MUTT_VA_AS_TEXT;
2057 break;
2058 }
2059
2060 if (mode == MUTT_VA_REGULAR)
2061 {
2062 mutt_attach_display_loop(shared->sub, shared->adata->menu, op,
2063 shared->email, shared->adata->actx, false);
2064 }
2065 else
2066 {
2067 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
2068 shared->adata->menu);
2069 mutt_view_attachment(NULL, cur_att->body, mode, shared->email,
2070 shared->adata->actx, shared->adata->menu->win);
2071 }
2072
2074 /* no send2hook, since this doesn't modify the message */
2075 return FR_SUCCESS;
2076}
2077
2081static int op_exit(struct ComposeSharedData *shared, const struct KeyEvent *event)
2082{
2083 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2084 shared->sub, "postpone");
2085 if (ans == MUTT_NO)
2086 {
2087 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2088 if (shared->adata->actx->idx[i]->unowned)
2089 shared->adata->actx->idx[i]->body->unlink = false;
2090
2091 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2092 {
2093 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2094 {
2095 /* avoid freeing other attachments */
2096 shared->adata->actx->idx[i]->body->next = NULL;
2097 if (!shared->adata->actx->idx[i]->body->email)
2098 shared->adata->actx->idx[i]->body->parts = NULL;
2099 mutt_body_free(&shared->adata->actx->idx[i]->body);
2100 }
2101 }
2102 shared->rc = -1;
2103 return FR_DONE;
2104 }
2105 else if (ans == MUTT_ABORT)
2106 {
2107 return FR_NO_ACTION;
2108 }
2109
2110 return op_compose_postpone_message(shared, event);
2111}
2112
2116static int op_forget_passphrase(struct ComposeSharedData *shared, const struct KeyEvent *event)
2117{
2119 return FR_SUCCESS;
2120}
2121
2122// -----------------------------------------------------------------------------
2123
2127static const struct ComposeFunction ComposeFunctions[] = {
2128 // clang-format off
2129 { OP_ATTACH_ATTACH_FILE, op_attach_attach_file },
2130 { OP_ATTACH_ATTACH_KEY, op_attach_attach_key },
2131 { OP_ATTACH_ATTACH_MESSAGE, op_attach_attach_message },
2132 { OP_ATTACH_ATTACH_NEWS_MESSAGE, op_attach_attach_message },
2133 { OP_ATTACH_DETACH, op_attach_detach },
2134 { OP_ATTACH_EDIT_CONTENT_ID, op_attach_edit_content_id },
2135 { OP_ATTACH_EDIT_DESCRIPTION, op_attach_edit_description },
2136 { OP_ATTACH_EDIT_ENCODING, op_attach_edit_encoding },
2137 { OP_ATTACH_EDIT_LANGUAGE, op_attach_edit_language },
2138 { OP_ATTACH_EDIT_MIME, op_attach_edit_mime },
2139 { OP_ATTACH_EDIT_TYPE, op_attach_edit_type },
2140 { OP_ATTACH_FILTER, op_attach_filter },
2141 { OP_ATTACH_GET_ATTACHMENT, op_attach_get_attachment },
2142 { OP_ATTACH_GROUP_ALTS, op_attach_group_alts },
2143 { OP_ATTACH_GROUP_LINGUAL, op_attach_group_lingual },
2144 { OP_ATTACH_GROUP_RELATED, op_attach_group_related },
2145 { OP_ATTACH_MOVE_DOWN, op_attach_move_down },
2146 { OP_ATTACH_MOVE_UP, op_attach_move_up },
2147 { OP_ATTACH_NEW_MIME, op_attach_new_mime },
2148 { OP_ATTACH_PRINT, op_attach_print },
2149 { OP_ATTACH_RENAME_ATTACHMENT, op_attach_rename_attachment },
2150 { OP_ATTACH_SAVE, op_attach_save },
2151 { OP_ATTACH_TOGGLE_DISPOSITION, op_attach_toggle_disposition },
2152 { OP_ATTACH_TOGGLE_RECODE, op_attach_toggle_recode },
2153 { OP_ATTACH_TOGGLE_UNLINK, op_attach_toggle_unlink },
2154 { OP_ATTACH_UNGROUP, op_attach_ungroup },
2155 { OP_ATTACH_UPDATE_ENCODING, op_attach_update_encoding },
2156 { OP_ATTACH_VIEW, op_display_headers },
2157 { OP_ATTACH_VIEW_MAILCAP, op_display_headers },
2158 { OP_ATTACH_VIEW_PAGER, op_display_headers },
2159 { OP_ATTACH_VIEW_TEXT, op_display_headers },
2160 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2161 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2162 { OP_COMPOSE_ISPELL, op_compose_ispell },
2163 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2164 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2165 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2166 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2167 { OP_DISPLAY_HEADERS, op_display_headers },
2168 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2169 { OP_EXIT, op_exit },
2170 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2171 { OP_PIPE, op_attach_filter },
2172 { 0, NULL },
2173 // clang-format on
2174};
2175
2179int compose_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
2180{
2181 // The Dispatcher may be called on any Window in the Dialog
2182 struct MuttWindow *dlg = dialog_find(win);
2183 if (!event || !dlg || !dlg->wdata)
2184 return FR_ERROR;
2185
2186 const int op = event->op;
2187 int rc = FR_UNKNOWN;
2188 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2189 {
2190 const struct ComposeFunction *fn = &ComposeFunctions[i];
2191 if (fn->op == op)
2192 {
2193 struct ComposeSharedData *shared = dlg->wdata;
2194 rc = fn->function(shared, event);
2195 break;
2196 }
2197 }
2198
2199 if (rc == FR_UNKNOWN) // Not our function
2200 return rc;
2201
2202 const char *result = dispatcher_get_retval_name(rc);
2203 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2204
2205 return rc;
2206}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#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:152
Select a Mailbox from a list.
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition lib.h:60
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition lib.h:58
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
@ CMD_SEND2_HOOK
:send2-hook
Definition command.h:106
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition functions.c:230
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition functions.c:2127
static const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition functions.c:80
static int group_attachments(struct ComposeSharedData *shared, char *subtype)
Group tagged attachments into a multipart group.
Definition functions.c:527
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attachment to the message.
Definition functions.c:436
static char * gen_cid(void)
Generate a random Content ID.
Definition functions.c:247
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:461
static bool check_cid(const char *cid)
Check if a Content-ID is valid.
Definition functions.c:263
struct MenuDefinition * MdCompose
Compose Menu Definition.
Definition functions.c:74
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition functions.c:283
static const struct MenuOpSeq ComposeDefaultBindings[]
Key bindings for the Compose Menu.
Definition functions.c:148
static int delete_attachment(struct AttachCtx *actx, int aidx)
Delete an attachment.
Definition functions.c:346
void compose_init_keys(struct SubMenu *sm_generic)
Initialise the Compose Keybindings - Implements ::init_keys_api.
Definition functions.c:211
Compose functions.
GUI editor for an email's headers.
#define MUTT_COMPOSE_NOFREEHEADER
Don't free the header when closing compose dialog.
Definition lib.h:54
Compose Private Data.
Compose Shared Data.
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:213
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_POP
'POP3' Mailbox type
Definition mailbox.h:51
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition crypt.c:89
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:116
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:40
@ FR_DONE
Exit the Dialog.
Definition dispatcher.h:36
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NOT_IMPL
Invalid function - feature not enabled.
Definition dispatcher.h:37
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
void update_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition dlg_index.c:1456
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
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
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 header.c:181
Structs that make up an email.
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition parse.c:371
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition parse.c:442
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:350
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition envelope.c:316
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition external.c:1072
Manage where the email is piped to external commands.
bool mutt_file_touch(const char *path)
Make sure a file exists.
Definition file.c:974
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition file.c:803
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1257
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
Global variables.
static int op_exit(struct AliasMenuData *mdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:234
static int op_attach_print(struct AttachPrivateData *priv, const struct KeyEvent *event)
print the current entry - Implements attach_function_t -
Definition functions.c:380
static int op_forget_passphrase(struct AttachPrivateData *priv, const struct KeyEvent *event)
wipe passphrases from memory - Implements attach_function_t -
Definition functions.c:569
static int op_attach_save(struct AttachPrivateData *priv, const struct KeyEvent *event)
save message/attachment to a mailbox/file - Implements attach_function_t -
Definition functions.c:391
static int op_attach_edit_type(struct AttachPrivateData *priv, const struct KeyEvent *event)
edit attachment content type - Implements attach_function_t -
Definition functions.c:359
static int op_attach_group_related(struct ComposeSharedData *shared, const struct KeyEvent *event)
Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
Definition functions.c:1344
static int op_attach_attach_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
Attach files to this message - Implements compose_function_t -.
Definition functions.c:745
static int op_display_headers(struct ComposeSharedData *shared, const struct KeyEvent *event)
Display message and toggle header weeding - Implements compose_function_t -.
Definition functions.c:2033
static int op_attach_edit_language(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit the 'Content-Language' of the attachment - Implements compose_function_t -.
Definition functions.c:1154
static int op_attach_detach(struct ComposeSharedData *shared, const struct KeyEvent *event)
Delete the current entry - Implements compose_function_t -.
Definition functions.c:988
static int op_attach_edit_content_id(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit the 'Content-ID' of the attachment - Implements compose_function_t -.
Definition functions.c:1024
static int op_compose_ispell(struct ComposeSharedData *shared, const struct KeyEvent *event)
Run ispell on the message - Implements compose_function_t -.
Definition functions.c:1872
static int op_attach_filter(struct ComposeSharedData *shared, const struct KeyEvent *event)
Filter attachment through a shell command - Implements compose_function_t -.
Definition functions.c:1233
static int op_attach_edit_encoding(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit attachment transfer-encoding - Implements compose_function_t -.
Definition functions.c:1110
static int op_attach_ungroup(struct ComposeSharedData *shared, const struct KeyEvent *event)
Ungroup a 'multipart' attachment - Implements compose_function_t -.
Definition functions.c:1679
static int op_attach_group_alts(struct ComposeSharedData *shared, const struct KeyEvent *event)
Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
Definition functions.c:1299
static int op_attach_move_up(struct ComposeSharedData *shared, const struct KeyEvent *event)
Move an attachment up in the attachment list - Implements compose_function_t -.
Definition functions.c:1427
static int op_compose_rename_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
Rename/move an attached file - Implements compose_function_t -.
Definition functions.c:1913
static int op_envelope_edit_headers(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit the message with headers - Implements compose_function_t -.
Definition functions.c:1776
static int op_compose_postpone_message(struct ComposeSharedData *shared, const struct KeyEvent *event)
Save this message to send later - Implements compose_function_t -.
Definition functions.c:1897
static int op_attach_toggle_recode(struct ComposeSharedData *shared, const struct KeyEvent *event)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition functions.c:1637
static int op_compose_write_message(struct ComposeSharedData *shared, const struct KeyEvent *event)
Write the message to a folder - Implements compose_function_t -.
Definition functions.c:1990
static int op_attach_group_lingual(struct ComposeSharedData *shared, const struct KeyEvent *event)
Group tagged attachments as 'multipart/multilingual' - Implements compose_function_t -.
Definition functions.c:1313
static int op_attach_move_down(struct ComposeSharedData *shared, const struct KeyEvent *event)
Move an attachment down in the attachment list - Implements compose_function_t -.
Definition functions.c:1371
static int op_attach_toggle_disposition(struct ComposeSharedData *shared, const struct KeyEvent *event)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition functions.c:1618
static int op_compose_send_message(struct ComposeSharedData *shared, const struct KeyEvent *event)
Send the message - Implements compose_function_t -.
Definition functions.c:1962
static int op_attach_rename_attachment(struct ComposeSharedData *shared, const struct KeyEvent *event)
Send attachment with a different name - Implements compose_function_t -.
Definition functions.c:1566
static int op_attach_attach_message(struct ComposeSharedData *shared, const struct KeyEvent *event)
Attach messages to this message - Implements compose_function_t -.
Definition functions.c:838
static int op_attach_edit_description(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit attachment description - Implements compose_function_t -.
Definition functions.c:1078
static int op_attach_update_encoding(struct ComposeSharedData *shared, const struct KeyEvent *event)
Update an attachment's encoding info - Implements compose_function_t -.
Definition functions.c:1741
static int op_attach_toggle_unlink(struct ComposeSharedData *shared, const struct KeyEvent *event)
Toggle whether to delete file after sending it - Implements compose_function_t -.
Definition functions.c:1662
static int op_attach_new_mime(struct ComposeSharedData *shared, const struct KeyEvent *event)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition functions.c:1462
static int op_attach_edit_mime(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit attachment using mailcap entry - Implements compose_function_t -.
Definition functions.c:1191
static int op_compose_edit_message(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit the message - Implements compose_function_t -.
Definition functions.c:1849
static int op_attach_get_attachment(struct ComposeSharedData *shared, const struct KeyEvent *event)
Get a temporary copy of an attachment - Implements compose_function_t -.
Definition functions.c:1262
static int op_compose_edit_file(struct ComposeSharedData *shared, const struct KeyEvent *event)
Edit the file to be attached - Implements compose_function_t -.
Definition functions.c:1825
static int op_attach_attach_key(struct ComposeSharedData *shared, const struct KeyEvent *event)
Attach a PGP public key - Implements compose_function_t -.
Definition functions.c:810
int compose_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Compose function - Implements function_dispatcher_t -.
Definition functions.c:2179
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition dlg_index.c:1118
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:236
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:463
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox?
Definition nntp.c:2787
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox?
Definition pop.c:1162
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2546
Convenience wrapper for the gui headers.
Read/write command history from/to a file.
@ HC_FILE
Files.
Definition lib.h:58
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:135
Hook Commands.
IMAP network mailbox.
GUI manage the main index (list of emails)
void km_menu_add_submenu(struct MenuDefinition *md, struct SubMenu *sm)
Add a SubMenu to a Menu Definition.
Definition init.c:123
struct SubMenu * km_register_submenu(const struct MenuFuncOp functions[])
Register a submenu.
Definition init.c:91
struct MenuDefinition * km_register_menu(int menu, const char *name)
Register a menu.
Definition init.c:107
void km_menu_add_bindings(struct MenuDefinition *md, const struct MenuOpSeq bindings[])
Add Keybindings to a Menu.
Definition init.c:136
Manage keymappings.
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ 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
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:188
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:164
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition lib.h:59
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
@ 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)
Get the encoding name for an encoding type.
Definition mime.h:97
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition multipart.c:133
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition multipart.c:107
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
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:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
int mutt_system(const char *cmd)
Run an external command.
Definition system.c:51
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
int mutt_get_tmp_attachment(struct Body *b)
Get a temporary copy of an attachment.
Definition mutt_attach.c:68
int mutt_compose_attachment(struct Body *b)
Create an attachment.
int mutt_view_attachment(FILE *fp, struct Body *b, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
View an attachment.
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:426
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:962
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:721
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_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
bool mutt_is_text_part(const struct Body *b)
Is this part of an email in plain text?
Definition muttlib.c:396
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:428
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
Some miscellaneous functions.
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition mview.c:361
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition mx.c:411
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition mx.c:1323
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.
#define MUTT_READONLY
Open in read-only mode.
Definition mxapi.h:42
API for encryption/signing of emails.
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:98
#define WithCrypto
Definition lib.h:124
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:555
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition nntp.c:74
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition newsrc.c:951
@ 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:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
POP network mailbox.
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:357
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
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:71
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition recvattach.c:116
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
void mutt_rfc3676_space_unstuff(struct Email *e)
Remove RFC3676 space stuffing.
Definition rfc3676.c:503
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition rfc3676.c:490
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:421
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition sendlib.c:613
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition sendlib.c:453
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition sendlib.c:1024
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition sendlib.c:409
#define MUTT_RANDTAG_LEN
Length of random tag for message boundaries.
Definition sendlib.h:36
int endwin(void)
#define NONULL(x)
Definition string2.h:44
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:51
int op
Op code, e.g. OP_COMPOSE_WRITE_MESSAGE.
Definition functions.h:52
compose_function_t function
Function to call.
Definition functions.h:53
Shared Compose Data.
Definition shared_data.h:35
struct ConfigSubset * sub
Config set to use.
Definition shared_data.h:36
struct Mailbox * mailbox
Current Mailbox.
Definition shared_data.h:37
int flags
Flags, e.g. MUTT_COMPOSE_NOFREEHEADER.
Definition shared_data.h:45
bool fcc_set
User has edited the Fcc: field.
Definition shared_data.h:46
int rc
Return code to leave compose.
Definition shared_data.h:47
struct ComposeAttachData * adata
Attachments.
Definition shared_data.h:39
struct Email * email
Email being composed.
Definition shared_data.h:38
struct Buffer * fcc
Buffer to save FCC.
Definition shared_data.h:44
A set of inherited config items.
Definition subset.h:46
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:39
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
An event such as a keypress.
Definition get.h:50
A mailbox.
Definition mailbox.h:78
int msg_count
Total number of messages.
Definition mailbox.h:87
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
bool readonly
Don't allow changes to the mailbox.
Definition mailbox.h:115
Functions for a Dialog or Window.
Definition menu.h:80
Mapping between a function and an operation.
Definition menu.h:38
Mapping between an operation and a key sequence.
Definition menu.h:48
Definition lib.h:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
int current
Current entry.
Definition lib.h:81
int num_tagged
Number of tagged entries.
Definition lib.h:95
bool tag_prefix
User has pressed <tag-prefix>
Definition lib.h:86
void * wdata
Private data.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Cached regular expression.
Definition regex3.h:85
Collection of related functions.
Definition menu.h:68
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:303
@ MENU_COMPOSE
Compose an email.
Definition type.h:40