NeoMutt  2025-12-11-117-gc1a713
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#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 "hooks/lib.h"
56#include "imap/lib.h"
57#include "index/lib.h"
58#include "key/lib.h"
59#include "menu/lib.h"
60#include "ncrypt/lib.h"
61#include "nntp/lib.h"
62#include "pop/lib.h"
63#include "question/lib.h"
64#include "send/lib.h"
65#include "attach_data.h"
66#include "external.h"
67#include "functions.h"
68#include "globals.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
87static const 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
155static const 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
218void compose_init_keys(struct SubMenu *sm_generic)
219{
220 struct MenuDefinition *md = NULL;
221 struct SubMenu *sm = NULL;
222
224 md = km_register_menu(MENU_COMPOSE, "compose");
225 km_menu_add_submenu(md, sm);
226 km_menu_add_submenu(md, sm_generic);
228}
229
235static bool check_count(struct AttachCtx *actx)
236{
237 if (actx->idxlen == 0)
238 {
239 mutt_error(_("There are no attachments"));
240 return false;
241 }
242
243 return true;
244}
245
252static char *gen_cid(void)
253{
254 char rndid[MUTT_RANDTAG_LEN + 1];
255
256 mutt_rand_base32(rndid, sizeof(rndid) - 1);
257 rndid[MUTT_RANDTAG_LEN] = 0;
258
259 return mutt_str_dup(rndid);
260}
261
268static bool check_cid(const char *cid)
269{
270 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
271
272 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
273
274 const bool valid = mutt_regex_match(check_cid_regex, cid);
275
276 mutt_regex_free(&check_cid_regex);
277
278 return valid;
279}
280
288static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
289{
290 int rc = -1;
291 struct stat st = { 0 };
292 struct Buffer *pretty = NULL, *msg = NULL;
293
294 for (int i = 0; i < actx->idxlen; i++)
295 {
296 if (actx->idx[i]->body->type == TYPE_MULTIPART)
297 continue;
298 if (stat(actx->idx[i]->body->filename, &st) != 0)
299 {
300 if (!pretty)
301 pretty = buf_pool_get();
302 buf_strcpy(pretty, actx->idx[i]->body->filename);
303 buf_pretty_mailbox(pretty);
304 /* L10N: This message is displayed in the compose menu when an attachment
305 doesn't stat. %d is the attachment number and %s is the attachment
306 filename. The filename is located last to avoid a long path hiding
307 the error message. */
308 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
309 goto cleanup;
310 }
311
312 if (actx->idx[i]->body->stamp < st.st_mtime)
313 {
314 if (!pretty)
315 pretty = buf_pool_get();
316 buf_strcpy(pretty, actx->idx[i]->body->filename);
317 buf_pretty_mailbox(pretty);
318
319 if (!msg)
320 msg = buf_pool_get();
321 /* L10N: This message is displayed in the compose menu when an attachment
322 is modified behind the scenes. %d is the attachment number and %s is
323 the attachment filename. The filename is located last to avoid a long
324 path hiding the prompt question. */
325 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
326 i + 1, buf_string(pretty));
327
329 if (ans == MUTT_YES)
330 mutt_update_encoding(actx->idx[i]->body, sub);
331 else if (ans == MUTT_ABORT)
332 goto cleanup;
333 }
334 }
335
336 rc = 0;
337
338cleanup:
339 buf_pool_release(&pretty);
340 buf_pool_release(&msg);
341 return rc;
342}
343
351static int delete_attachment(struct AttachCtx *actx, int aidx)
352{
353 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
354 return -1;
355
356 struct AttachPtr **idx = actx->idx;
357 struct Body *b_previous = NULL;
358 struct Body *b_parent = NULL;
359
360 if (aidx == 0)
361 {
362 struct Body *b = actx->idx[0]->body;
363 if (!b->next) // There's only one attachment left
364 {
365 mutt_error(_("You may not delete the only attachment"));
366 return -1;
367 }
368
369 if (cs_subset_bool(NeoMutt->sub, "compose_confirm_detach_first"))
370 {
371 /* L10N: Prompt when trying to hit <detach-file> on the first entry in
372 the compose menu. This entry is most likely the message they just
373 typed. Hitting yes will remove the entry and unlink the file, so
374 it's worth confirming they really meant to do it. */
375 enum QuadOption ans = query_yesorno_help(_("Really delete the main message?"),
377 "compose_confirm_detach_first");
378 if (ans == MUTT_NO)
379 {
380 idx[aidx]->body->tagged = false;
381 return -1;
382 }
383 }
384 }
385
386 if (idx[aidx]->level > 0)
387 {
388 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
389 {
390 if (attach_body_count(b_parent->parts, false) < 3)
391 {
392 mutt_error(_("Can't leave group with only one attachment"));
393 return -1;
394 }
395 }
396 }
397
398 // reorder body pointers
399 if (aidx > 0)
400 {
401 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
402 b_previous->next = idx[aidx]->body->next;
403 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
404 b_parent->parts = idx[aidx]->body->next;
405 }
406
407 // free memory
408 int part_count = 1;
409 if (aidx < (actx->idxlen - 1))
410 {
411 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
412 (idx[aidx + 1]->level > idx[aidx]->level))
413 {
414 part_count += attach_body_count(idx[aidx]->body->parts, true);
415 }
416 }
417 idx[aidx]->body->next = NULL;
418 mutt_body_free(&(idx[aidx]->body));
419 for (int i = 0; i < part_count; i++)
420 {
421 FREE(&idx[aidx + i]->tree);
422 FREE(&idx[aidx + i]);
423 }
424
425 // reorder attachment list
426 for (int i = aidx; i < (actx->idxlen - part_count); i++)
427 idx[i] = idx[i + part_count];
428 for (int i = 0; i < part_count; i++)
429 idx[actx->idxlen - i - 1] = NULL;
430 actx->idxlen -= part_count;
431
432 return 0;
433}
434
441static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
442{
443 ap->level = 0;
444 for (int i = actx->idxlen; i > 0; i--)
445 {
446 if (ap->level == actx->idx[i - 1]->level)
447 {
448 actx->idx[i - 1]->body->next = ap->body;
449 break;
450 }
451 }
452
453 ap->body->aptr = ap;
454 mutt_actx_add_attach(actx, ap);
455 update_menu(actx, menu, false);
456 menu_set_index(menu, actx->vcount - 1);
457}
458
466static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
467{
468 struct AttachPtr **idx = actx->idx;
469
470 // check that attachments really are adjacent
471 if (idx[first]->body->next != idx[second]->body)
472 return;
473
474 // reorder Body pointers
475 if (first == 0)
476 {
477 // first attachment is the fundamental part
478 idx[first]->body->next = idx[second]->body->next;
479 idx[second]->body->next = idx[first]->body;
480 e->body = idx[second]->body;
481 }
482 else
483 {
484 // find previous attachment
485 struct Body *b_previous = NULL;
486 struct Body *b_parent = NULL;
487 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
488 {
489 idx[first]->body->next = idx[second]->body->next;
490 idx[second]->body->next = idx[first]->body;
491 b_previous->next = idx[second]->body;
492 }
493 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
494 {
495 idx[first]->body->next = idx[second]->body->next;
496 idx[second]->body->next = idx[first]->body;
497 b_parent->parts = idx[second]->body;
498 }
499 }
500
501 // reorder attachment list
502 struct AttachPtr *saved = idx[second];
503 for (int i = second; i > first; i--)
504 idx[i] = idx[i - 1];
505 idx[first] = saved;
506
507 // if moved attachment is a group then move subparts too
508 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
509 {
510 int i = second + 1;
511 while (idx[i]->level > idx[first]->level)
512 {
513 saved = idx[i];
514 int destidx = i - second + first;
515 for (int j = i; j > destidx; j--)
516 idx[j] = idx[j - 1];
517 idx[destidx] = saved;
518 i++;
519 if (i >= actx->idxlen)
520 break;
521 }
522 }
523}
524
532static int group_attachments(struct ComposeSharedData *shared, char *subtype)
533{
534 struct AttachCtx *actx = shared->adata->actx;
535 int group_level = -1;
536 struct Body *bptr_parent = NULL;
537
538 // Attachments to be grouped must have the same parent
539 for (int i = 0; i < actx->idxlen; i++)
540 {
541 // check if all tagged attachments are at same level
542 if (actx->idx[i]->body->tagged)
543 {
544 if (group_level == -1)
545 {
546 group_level = actx->idx[i]->level;
547 }
548 else
549 {
550 if (group_level != actx->idx[i]->level)
551 {
552 mutt_error(_("Attachments to be grouped must have the same parent"));
553 return FR_ERROR;
554 }
555 }
556 // if not at top level check if all tagged attachments have same parent
557 if (group_level > 0)
558 {
559 if (bptr_parent)
560 {
561 struct Body *bptr_test = NULL;
562 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
563 mutt_debug(LL_DEBUG5, "can't find parent\n");
564 if (bptr_test != bptr_parent)
565 {
566 mutt_error(_("Attachments to be grouped must have the same parent"));
567 return FR_ERROR;
568 }
569 }
570 else
571 {
572 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
573 mutt_debug(LL_DEBUG5, "can't find parent\n");
574 }
575 }
576 }
577 }
578
579 // Can't group all attachments unless at top level
580 if (bptr_parent)
581 {
582 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
583 {
584 mutt_error(_("Can't leave group with only one attachment"));
585 return FR_ERROR;
586 }
587 }
588
589 struct Body *group = mutt_body_new();
590 group->type = TYPE_MULTIPART;
591 group->subtype = mutt_str_dup(subtype);
592 group->encoding = ENC_7BIT;
593
594 struct Body *bptr_first = NULL; // first tagged attachment
595 struct Body *bptr = NULL; // current tagged attachment
596 struct Body *group_parent = NULL; // parent of group
597 struct Body *group_previous = NULL; // previous body to group
598 struct Body *group_part = NULL; // current attachment in group
599 int group_idx = 0; // index in attachment list where group will be inserted
600 int group_last_idx = 0; // index of last part of previous found group
601 int group_parent_type = TYPE_OTHER;
602
603 for (int i = 0; i < actx->idxlen; i++)
604 {
605 bptr = actx->idx[i]->body;
606 if (bptr->tagged)
607 {
608 // set group properties based on first tagged attachment
609 if (!bptr_first)
610 {
611 group->disposition = bptr->disposition;
612 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
613 group->language = mutt_str_dup(bptr->language);
614 group_parent_type = bptr->aptr->parent_type;
615 bptr_first = bptr;
616 if (i > 0)
617 {
618 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
619 {
620 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
621 }
622 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
623 {
624 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
625 }
626 }
627 }
628
629 shared->adata->menu->num_tagged--;
630 bptr->tagged = false;
631 bptr->aptr->level++;
633
634 // append bptr to the group parts list and remove from email body list
635 struct Body *bptr_previous = NULL;
636 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
637 bptr_previous->next = bptr->next;
638 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
639 bptr_parent->parts = bptr->next;
640 else
641 shared->email->body = bptr->next;
642
643 if (group_part)
644 {
645 // add bptr to group parts list
646 group_part->next = bptr;
647 group_part = group_part->next;
648 group_part->next = NULL;
649
650 // reorder attachments and set levels
651 int bptr_attachments = attach_body_count(bptr, true);
652 for (int j = i + 1; j < (i + bptr_attachments); j++)
653 actx->idx[j]->level++;
654 if (i > (group_last_idx + 1))
655 {
656 for (int j = 0; j < bptr_attachments; j++)
657 {
658 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
659 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
660 actx->idx[k] = actx->idx[k - 1];
661 actx->idx[group_last_idx + 1] = saved;
662 }
663 }
664 i += bptr_attachments - 1;
665 group_last_idx += bptr_attachments;
666 }
667 else
668 {
669 group_idx = i;
670 group->parts = bptr;
671 group_part = bptr;
672 group_part->next = NULL;
673 int bptr_attachments = attach_body_count(bptr, true);
674 for (int j = i + 1; j < (i + bptr_attachments); j++)
675 actx->idx[j]->level++;
676 i += bptr_attachments - 1;
677 group_last_idx = i;
678 }
679 }
680 }
681
682 if (!bptr_first)
683 {
684 mutt_body_free(&group);
685 return FR_ERROR;
686 }
687
688 // set group->next
689 int next_aidx = group_idx + attach_body_count(group->parts, true);
690 if (group_parent)
691 {
692 // find next attachment with the same parent as the group
693 struct Body *b = NULL;
694 struct Body *b_parent = NULL;
695 while (next_aidx < actx->idxlen)
696 {
697 b = actx->idx[next_aidx]->body;
698 b_parent = NULL;
699 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
700 {
701 if (group_parent == b_parent)
702 {
703 group->next = b;
704 break;
705 }
706 }
707 next_aidx++;
708 }
709 }
710 else if (next_aidx < actx->idxlen)
711 {
712 // group is at top level
713 group->next = actx->idx[next_aidx]->body;
714 }
715
716 // set previous or parent for group
717 if (group_previous)
718 group_previous->next = group;
719 else if (group_parent)
720 group_parent->parts = group;
721
723
724 struct AttachPtr *group_ap = mutt_aptr_new();
725 group_ap->body = group;
726 group_ap->body->aptr = group_ap;
727 group_ap->level = group_level;
728 group_ap->parent_type = group_parent_type;
729
730 // insert group into attachment list
731 mutt_actx_ins_attach(actx, group_ap, group_idx);
732
733 // update email body and last attachment pointers
734 shared->email->body = actx->idx[0]->body;
735 actx->idx[actx->idxlen - 1]->body->next = NULL;
736
737 update_menu(actx, shared->adata->menu, false);
738 shared->adata->menu->current = group_idx;
740
741 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
742 return FR_SUCCESS;
743}
744
745// -----------------------------------------------------------------------------
746
750static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
751{
752 char *prompt = _("Attach file");
753 int numfiles = 0;
754 char **files = NULL;
755
756 struct Buffer *fname = buf_pool_get();
757 if ((mw_enter_fname(prompt, fname, false, NULL, true, &files, &numfiles,
758 MUTT_SEL_MULTI) == -1) ||
759 buf_is_empty(fname))
760 {
761 for (int i = 0; i < numfiles; i++)
762 FREE(&files[i]);
763
764 FREE(&files);
765 buf_pool_release(&fname);
766 return FR_NO_ACTION;
767 }
768
769 bool error = false;
770 bool added_attachment = false;
771 if (numfiles > 1)
772 {
773 mutt_message(ngettext("Attaching selected file...",
774 "Attaching selected files...", numfiles));
775 }
776 for (int i = 0; i < numfiles; i++)
777 {
778 char *att = files[i];
779 if (!att)
780 continue;
781
782 struct AttachPtr *ap = mutt_aptr_new();
783 ap->unowned = true;
784 ap->body = mutt_make_file_attach(att, shared->sub);
785 if (ap->body)
786 {
787 added_attachment = true;
788 update_idx(shared->adata->menu, shared->adata->actx, ap);
789 }
790 else
791 {
792 error = true;
793 mutt_error(_("Unable to attach %s"), att);
794 mutt_aptr_free(&ap);
795 }
796 FREE(&files[i]);
797 }
798
799 FREE(&files);
800 buf_pool_release(&fname);
801
802 if (!error)
804
807 if (added_attachment)
808 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
809 return FR_SUCCESS;
810}
811
815static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
816{
818 return FR_NOT_IMPL;
819 struct AttachPtr *ap = mutt_aptr_new();
821 if (ap->body)
822 {
823 update_idx(shared->adata->menu, shared->adata->actx, ap);
825 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
826 }
827 else
828 {
829 mutt_aptr_free(&ap);
830 }
831
833 return FR_SUCCESS;
834}
835
843static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
844{
845 char *prompt = _("Open mailbox to attach message from");
846
847 OptNews = false;
848 if (shared->mailbox && (op == OP_ATTACHMENT_ATTACH_NEWS_MESSAGE))
849 {
850 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
851 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
852 if (!CurrentNewsSrv)
853 return FR_NO_ACTION;
854
855 prompt = _("Open newsgroup to attach message from");
856 OptNews = true;
857 }
858
859 struct Buffer *fname = buf_pool_get();
860 if (shared->mailbox)
861 {
862 if ((op == OP_ATTACHMENT_ATTACH_MESSAGE) ^ (shared->mailbox->type == MUTT_NNTP))
863 {
864 buf_strcpy(fname, mailbox_path(shared->mailbox));
865 buf_pretty_mailbox(fname);
866 }
867 }
868
869 if ((mw_enter_fname(prompt, fname, true, shared->mailbox, false, NULL, NULL,
870 MUTT_SEL_NO_FLAGS) == -1) ||
871 buf_is_empty(fname))
872 {
873 buf_pool_release(&fname);
874 return FR_NO_ACTION;
875 }
876
877 if (OptNews)
878 nntp_expand_path(fname->data, fname->dsize, &CurrentNewsSrv->conn->account);
879 else
880 buf_expand_path(fname);
881
882 if (imap_path_probe(buf_string(fname), NULL) != MUTT_IMAP)
883 {
884 if (pop_path_probe(buf_string(fname), NULL) != MUTT_POP)
885 {
886 if (!OptNews && (nntp_path_probe(buf_string(fname), NULL) != MUTT_NNTP))
887 {
889 {
890 /* check to make sure the file exists and is readable */
891 if (access(buf_string(fname), R_OK) == -1)
892 {
893 mutt_perror("%s", buf_string(fname));
894 buf_pool_release(&fname);
895 return FR_ERROR;
896 }
897 }
898 }
899 }
900 }
901
903
904 struct Mailbox *m_attach = mx_path_resolve(buf_string(fname));
905 const bool old_readonly = m_attach->readonly;
906 if (!mx_mbox_open(m_attach, MUTT_READONLY))
907 {
908 mutt_error(_("Unable to open mailbox %s"), buf_string(fname));
909 mx_fastclose_mailbox(m_attach, false);
910 m_attach = NULL;
911 buf_pool_release(&fname);
912 return FR_ERROR;
913 }
914 buf_pool_release(&fname);
915
916 if (m_attach->msg_count == 0)
917 {
918 mx_mbox_close(m_attach);
919 mutt_error(_("No messages in that folder"));
920 return FR_NO_ACTION;
921 }
922
923 /* `$sort`, `$sort_aux`, `$use_threads` could be changed in dlg_index() */
924 const enum EmailSortType old_sort = cs_subset_sort(shared->sub, "sort");
925 const enum EmailSortType old_sort_aux = cs_subset_sort(shared->sub, "sort_aux");
926 const unsigned char old_use_threads = cs_subset_enum(shared->sub, "use_threads");
927
928 mutt_message(_("Tag the messages you want to attach"));
929 struct MuttWindow *dlg = index_pager_init();
930 struct IndexSharedData *index_shared = dlg->wdata;
931 index_shared->attach_msg = true;
932 dialog_push(dlg);
933 struct Mailbox *m_attach_new = dlg_index(dlg, m_attach);
934 dialog_pop();
935 mutt_window_free(&dlg);
936
937 if (!shared->mailbox)
938 {
939 /* Restore old $sort variables */
940 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
941 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
942 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
945 return FR_SUCCESS;
946 }
947
948 bool added_attachment = false;
949 for (int i = 0; i < m_attach_new->msg_count; i++)
950 {
951 if (!m_attach_new->emails[i])
952 break;
953 if (!message_is_tagged(m_attach_new->emails[i]))
954 continue;
955
956 struct AttachPtr *ap = mutt_aptr_new();
957 ap->body = mutt_make_message_attach(m_attach_new, m_attach_new->emails[i],
958 true, shared->sub);
959 if (ap->body)
960 {
961 added_attachment = true;
962 update_idx(shared->adata->menu, shared->adata->actx, ap);
963 }
964 else
965 {
966 mutt_error(_("Unable to attach"));
967 mutt_aptr_free(&ap);
968 }
969 }
971
972 if (m_attach_new == m_attach)
973 {
974 m_attach->readonly = old_readonly;
975 }
976 mx_fastclose_mailbox(m_attach_new, false);
977
978 /* Restore old $sort variables */
979 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
980 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
981 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
983 if (added_attachment)
984 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
985 return FR_SUCCESS;
986}
987
991static int op_attachment_detach(struct ComposeSharedData *shared, int op)
992{
993 struct AttachCtx *actx = shared->adata->actx;
994 if (!check_count(actx))
995 return FR_NO_ACTION;
996
997 struct Menu *menu = shared->adata->menu;
998 struct AttachPtr *cur_att = current_attachment(actx, menu);
999 if (cur_att->unowned)
1000 cur_att->body->unlink = false;
1001
1002 int index = menu_get_index(menu);
1003 if (delete_attachment(actx, index) == -1)
1004 return FR_ERROR;
1005
1006 menu->num_tagged = 0;
1007 for (int i = 0; i < actx->idxlen; i++)
1008 {
1009 if (actx->idx[i]->body->tagged)
1010 menu->num_tagged++;
1011 }
1012
1013 update_menu(actx, menu, false);
1015
1016 index = menu_get_index(menu);
1017 if (index == 0)
1018 shared->email->body = actx->idx[0]->body;
1019
1020 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1021 return FR_SUCCESS;
1022}
1023
1027static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
1028{
1029 if (!check_count(shared->adata->actx))
1030 return FR_NO_ACTION;
1031
1032 int rc = FR_NO_ACTION;
1033 struct Buffer *buf = buf_pool_get();
1034 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1035 shared->adata->menu);
1036
1037 char *id = cur_att->body->content_id;
1038 if (id)
1039 {
1040 buf_strcpy(buf, id);
1041 }
1042 else
1043 {
1044 id = gen_cid();
1045 buf_strcpy(buf, id);
1046 FREE(&id);
1047 }
1048
1049 if (mw_get_field("Content-ID: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1050 {
1051 if (!mutt_str_equal(id, buf_string(buf)))
1052 {
1053 if (check_cid(buf_string(buf)))
1054 {
1055 mutt_str_replace(&cur_att->body->content_id, buf_string(buf));
1058 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1059 rc = FR_SUCCESS;
1060 }
1061 else
1062 {
1063 mutt_error(_("Content-ID can only contain the characters: -.0-9@A-Z_a-z"));
1064 rc = FR_ERROR;
1065 }
1066 }
1067 }
1068
1069 buf_pool_release(&buf);
1070
1071 if (rc != FR_ERROR)
1073
1074 return rc;
1075}
1076
1080static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
1081{
1082 if (!check_count(shared->adata->actx))
1083 return FR_NO_ACTION;
1084
1085 int rc = FR_NO_ACTION;
1086 struct Buffer *buf = buf_pool_get();
1087
1088 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1089 shared->adata->menu);
1090 buf_strcpy(buf, cur_att->body->description);
1091
1092 /* header names should not be translated */
1093 if (mw_get_field("Description: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1094 {
1095 if (!mutt_str_equal(cur_att->body->description, buf_string(buf)))
1096 {
1097 mutt_str_replace(&cur_att->body->description, buf_string(buf));
1099 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1100 rc = FR_SUCCESS;
1101 }
1102 }
1103
1104 buf_pool_release(&buf);
1105 return rc;
1106}
1107
1111static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
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 mutt_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
1154static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
1155{
1156 if (!check_count(shared->adata->actx))
1157 return FR_NO_ACTION;
1158
1159 int rc = FR_NO_ACTION;
1160 struct Buffer *buf = buf_pool_get();
1161 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1162 shared->adata->menu);
1163
1164 buf_strcpy(buf, cur_att->body->language);
1165 if (mw_get_field("Content-Language: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1166 {
1167 if (!mutt_str_equal(cur_att->body->language, buf_string(buf)))
1168 {
1169 mutt_str_replace(&cur_att->body->language, buf_string(buf));
1172 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1173 rc = FR_SUCCESS;
1174 }
1176 }
1177 else
1178 {
1179 mutt_warning(_("Empty 'Content-Language'"));
1180 rc = FR_ERROR;
1181 }
1182
1183 buf_pool_release(&buf);
1184 return rc;
1185}
1186
1190static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
1191{
1192 if (!check_count(shared->adata->actx))
1193 return FR_NO_ACTION;
1194 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1195 shared->adata->menu);
1196 if (!mutt_edit_attachment(cur_att->body))
1197 return FR_NO_ACTION;
1198
1199 mutt_update_encoding(cur_att->body, shared->sub);
1201 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1202 return FR_SUCCESS;
1203}
1204
1208static int op_attachment_edit_type(struct ComposeSharedData *shared, int op)
1209{
1210 if (!check_count(shared->adata->actx))
1211 return FR_NO_ACTION;
1212
1213 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1214 shared->adata->menu);
1215 if (!mutt_edit_content_type(NULL, cur_att->body, NULL))
1216 return FR_NO_ACTION;
1217
1218 /* this may have been a change to text/something */
1219 mutt_update_encoding(cur_att->body, shared->sub);
1221 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1222 return FR_SUCCESS;
1223}
1224
1232static int op_attachment_filter(struct ComposeSharedData *shared, int op)
1233{
1234 struct AttachCtx *actx = shared->adata->actx;
1235 if (!check_count(actx))
1236 return FR_NO_ACTION;
1237
1238 struct Menu *menu = shared->adata->menu;
1239 struct AttachPtr *cur_att = current_attachment(actx, menu);
1240 if (cur_att->body->type == TYPE_MULTIPART)
1241 {
1242 mutt_error(_("Can't filter multipart attachments"));
1243 return FR_ERROR;
1244 }
1245 mutt_pipe_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body,
1246 (op == OP_ATTACHMENT_FILTER));
1247 if (op == OP_ATTACHMENT_FILTER) /* cte might have changed */
1248 {
1250 }
1252 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1253 return FR_SUCCESS;
1254}
1255
1259static int op_attachment_get_attachment(struct ComposeSharedData *shared, int op)
1260{
1261 struct AttachCtx *actx = shared->adata->actx;
1262 if (!check_count(actx))
1263 return FR_NO_ACTION;
1264
1265 int rc = FR_ERROR;
1266 struct Menu *menu = shared->adata->menu;
1267 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1268 ba_add_tagged(&ba, actx, menu);
1269 if (ARRAY_EMPTY(&ba))
1270 goto done;
1271
1272 struct Body **bp = NULL;
1273 ARRAY_FOREACH(bp, &ba)
1274 {
1275 if ((*bp)->type == TYPE_MULTIPART)
1276 {
1277 mutt_warning(_("Can't get multipart attachments"));
1278 continue;
1279 }
1281 }
1282
1284 rc = FR_SUCCESS;
1285
1286done:
1287 ARRAY_FREE(&ba);
1288 /* No send2hook since this doesn't change the message. */
1289 return rc;
1290}
1291
1295static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
1296{
1297 if (shared->adata->menu->num_tagged < 2)
1298 {
1299 mutt_error(_("Grouping 'alternatives' requires at least 2 tagged messages"));
1300 return FR_ERROR;
1301 }
1302
1303 return group_attachments(shared, "alternative");
1304}
1305
1309static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
1310{
1311 if (shared->adata->menu->num_tagged < 2)
1312 {
1313 mutt_error(_("Grouping 'multilingual' requires at least 2 tagged messages"));
1314 return FR_ERROR;
1315 }
1316
1317 /* traverse to see whether all the parts have Content-Language: set */
1318 int tagged_with_lang_num = 0;
1319 for (struct Body *b = shared->email->body; b; b = b->next)
1320 if (b->tagged && b->language && *b->language)
1321 tagged_with_lang_num++;
1322
1323 if (shared->adata->menu->num_tagged != tagged_with_lang_num)
1324 {
1325 if (query_yesorno(_("Not all parts have 'Content-Language' set, continue?"),
1326 MUTT_YES) != MUTT_YES)
1327 {
1328 mutt_message(_("Not sending this message"));
1329 return FR_ERROR;
1330 }
1331 }
1332
1333 return group_attachments(shared, "multilingual");
1334}
1335
1339static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
1340{
1341 if (shared->adata->menu->num_tagged < 2)
1342 {
1343 mutt_error(_("Grouping 'related' requires at least 2 tagged messages"));
1344 return FR_ERROR;
1345 }
1346
1347 // ensure Content-ID is set for tagged attachments
1348 for (struct Body *b = shared->email->body; b; b = b->next)
1349 {
1350 if (!b->tagged || (b->type == TYPE_MULTIPART))
1351 continue;
1352
1353 if (!b->content_id)
1354 {
1355 b->content_id = gen_cid();
1356 }
1357 }
1358
1359 return group_attachments(shared, "related");
1360}
1361
1365static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
1366{
1367 int index = menu_get_index(shared->adata->menu);
1368
1369 struct AttachCtx *actx = shared->adata->actx;
1370
1371 if (index < 0)
1372 return FR_ERROR;
1373
1374 if (index == (actx->idxlen - 1))
1375 {
1376 mutt_error(_("Attachment is already at bottom"));
1377 return FR_NO_ACTION;
1378 }
1379 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1380 !actx->idx[index]->body->next)
1381 {
1382 mutt_error(_("Attachment can't be moved out of group"));
1383 return FR_ERROR;
1384 }
1385
1386 // find next attachment at current level
1387 int nextidx = index + 1;
1388 while ((nextidx < actx->idxlen) &&
1389 (actx->idx[nextidx]->level > actx->idx[index]->level))
1390 {
1391 nextidx++;
1392 }
1393 if (nextidx == actx->idxlen)
1394 {
1395 mutt_error(_("Attachment is already at bottom"));
1396 return FR_NO_ACTION;
1397 }
1398
1399 // find final position
1400 int finalidx = index + 1;
1401 if (nextidx < actx->idxlen - 1)
1402 {
1403 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1404 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1405 {
1406 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1407 }
1408 }
1409
1410 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1411 mutt_update_tree(shared->adata->actx);
1414 menu_set_index(shared->adata->menu, finalidx);
1415 return FR_SUCCESS;
1416}
1417
1421static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
1422{
1423 int index = menu_get_index(shared->adata->menu);
1424 if (index < 0)
1425 return FR_ERROR;
1426
1427 struct AttachCtx *actx = shared->adata->actx;
1428
1429 if (index == 0)
1430 {
1431 mutt_error(_("Attachment is already at top"));
1432 return FR_NO_ACTION;
1433 }
1434 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1435 {
1436 mutt_error(_("Attachment can't be moved out of group"));
1437 return FR_ERROR;
1438 }
1439
1440 // find previous attachment at current level
1441 int previdx = index - 1;
1442 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1443 previdx--;
1444
1445 compose_attach_swap(shared->email, actx, previdx, index);
1446 mutt_update_tree(actx);
1449 menu_set_index(shared->adata->menu, previdx);
1450 return FR_SUCCESS;
1451}
1452
1456static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
1457{
1458 int rc = FR_NO_ACTION;
1459 struct Buffer *fname = buf_pool_get();
1460 struct Buffer *type = NULL;
1461 struct AttachPtr *ap = NULL;
1462
1463 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1464 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1465 &CompleteFileOps, &cdata) != 0) ||
1466 buf_is_empty(fname))
1467 {
1468 goto done;
1469 }
1470 buf_expand_path(fname);
1471
1472 /* Call to lookup_mime_type () ? maybe later */
1473 type = buf_pool_get();
1474 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1475 buf_is_empty(type))
1476 {
1477 goto done;
1478 }
1479
1480 rc = FR_ERROR;
1481 char *p = strchr(buf_string(type), '/');
1482 if (!p)
1483 {
1484 mutt_error(_("Content-Type is of the form base/sub"));
1485 goto done;
1486 }
1487 *p++ = 0;
1488 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1489 if (itype == TYPE_OTHER)
1490 {
1491 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1492 goto done;
1493 }
1494
1495 ap = mutt_aptr_new();
1496 /* Touch the file */
1497 if (!mutt_file_touch(buf_string(fname)))
1498 {
1499 mutt_error(_("Can't create file %s"), buf_string(fname));
1500 goto done;
1501 }
1502
1503 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1504 if (!ap->body)
1505 {
1506 mutt_error(_("Error attaching file"));
1507 goto done;
1508 }
1509 update_idx(shared->adata->menu, shared->adata->actx, ap);
1510 ap = NULL; // shared->adata->actx has taken ownership
1511
1512 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1513 shared->adata->menu);
1514 cur_att->body->type = itype;
1515 mutt_str_replace(&cur_att->body->subtype, p);
1516 cur_att->body->unlink = true;
1519
1520 if (mutt_compose_attachment(cur_att->body))
1521 {
1522 mutt_update_encoding(cur_att->body, shared->sub);
1524 }
1525 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1526 rc = FR_SUCCESS;
1527
1528done:
1529 mutt_aptr_free(&ap);
1530 buf_pool_release(&type);
1531 buf_pool_release(&fname);
1532 return rc;
1533}
1534
1538static int op_attachment_print(struct ComposeSharedData *shared, int op)
1539{
1540 struct AttachCtx *actx = shared->adata->actx;
1541 if (!check_count(actx))
1542 return FR_NO_ACTION;
1543
1544 struct Menu *menu = shared->adata->menu;
1545 struct AttachPtr *cur_att = current_attachment(actx, menu);
1546 if (cur_att->body->type == TYPE_MULTIPART)
1547 {
1548 mutt_error(_("Can't print multipart attachments"));
1549 return FR_ERROR;
1550 }
1551
1552 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1553 /* no send2hook, since this doesn't modify the message */
1554 return FR_SUCCESS;
1555}
1556
1560static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
1561{
1562 if (!check_count(shared->adata->actx))
1563 return FR_NO_ACTION;
1564 char *src = NULL;
1565 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1566 shared->adata->menu);
1567 if (cur_att->body->d_filename)
1568 src = cur_att->body->d_filename;
1569 else
1570 src = cur_att->body->filename;
1571 struct Buffer *fname = buf_pool_get();
1572 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1573 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1574 int rc = mw_get_field(_("Send attachment with name: "), fname,
1576 if (rc == 0)
1577 {
1578 // It's valid to set an empty string here, to erase what was set
1579 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1581 }
1582 buf_pool_release(&fname);
1583 return FR_SUCCESS;
1584}
1585
1589static int op_attachment_save(struct ComposeSharedData *shared, int op)
1590{
1591 struct AttachCtx *actx = shared->adata->actx;
1592 if (!check_count(actx))
1593 return FR_NO_ACTION;
1594
1595 struct Menu *menu = shared->adata->menu;
1596 struct AttachPtr *cur_att = current_attachment(actx, menu);
1597 if (cur_att->body->type == TYPE_MULTIPART)
1598 {
1599 mutt_error(_("Can't save multipart attachments"));
1600 return FR_ERROR;
1601 }
1602
1603 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1604 /* no send2hook, since this doesn't modify the message */
1605 return FR_SUCCESS;
1606}
1607
1611static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
1612{
1613 /* toggle the content-disposition between inline/attachment */
1614 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1615 shared->adata->menu);
1616 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1617 DISP_ATTACH :
1621 return FR_SUCCESS;
1622}
1623
1627static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
1628{
1629 if (!check_count(shared->adata->actx))
1630 return FR_NO_ACTION;
1631 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1632 shared->adata->menu);
1633 if (!mutt_is_text_part(cur_att->body))
1634 {
1635 mutt_error(_("Recoding only affects text attachments"));
1636 return FR_ERROR;
1637 }
1638 cur_att->body->noconv = !cur_att->body->noconv;
1639 if (cur_att->body->noconv)
1640 mutt_message(_("The current attachment won't be converted"));
1641 else
1642 mutt_message(_("The current attachment will be converted"));
1644 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1645 return FR_SUCCESS;
1646}
1647
1651static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
1652{
1653 if (!check_count(shared->adata->actx))
1654 return FR_NO_ACTION;
1655 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1656 shared->adata->menu);
1657 cur_att->body->unlink = !cur_att->body->unlink;
1658
1660 /* No send2hook since this doesn't change the message. */
1661 return FR_SUCCESS;
1662}
1663
1667static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
1668{
1669 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1670 {
1671 mutt_error(_("Attachment is not 'multipart'"));
1672 return FR_ERROR;
1673 }
1674
1675 int aidx = shared->adata->menu->current;
1676 struct AttachCtx *actx = shared->adata->actx;
1677 struct Body *b = actx->idx[aidx]->body;
1678 struct Body *b_next = b->next;
1679 struct Body *b_previous = NULL;
1680 struct Body *b_parent = NULL;
1681 int parent_type = actx->idx[aidx]->parent_type;
1682 int level = actx->idx[aidx]->level;
1683
1684 // reorder body pointers
1685 if (attach_body_previous(shared->email->body, b, &b_previous))
1686 b_previous->next = b->parts;
1687 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1688 b_parent->parts = b->parts;
1689 else
1690 shared->email->body = b->parts;
1691
1692 // update attachment list
1693 int i = aidx + 1;
1694 while (actx->idx[i]->level > level)
1695 {
1696 actx->idx[i]->level--;
1697 if (actx->idx[i]->level == level)
1698 {
1699 actx->idx[i]->parent_type = parent_type;
1700 // set body->next for final attachment in group
1701 if (!actx->idx[i]->body->next)
1702 actx->idx[i]->body->next = b_next;
1703 }
1704 i++;
1705 if (i == actx->idxlen)
1706 break;
1707 }
1708
1709 // free memory
1710 actx->idx[aidx]->body->parts = NULL;
1711 actx->idx[aidx]->body->next = NULL;
1712 actx->idx[aidx]->body->email = NULL;
1713 mutt_body_free(&actx->idx[aidx]->body);
1714 FREE(&actx->idx[aidx]->tree);
1715 FREE(&actx->idx[aidx]);
1716
1717 // reorder attachment list
1718 for (int j = aidx; j < (actx->idxlen - 1); j++)
1719 actx->idx[j] = actx->idx[j + 1];
1720 actx->idx[actx->idxlen - 1] = NULL;
1721 actx->idxlen--;
1722 update_menu(actx, shared->adata->menu, false);
1723
1724 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1725 return FR_SUCCESS;
1726}
1727
1731static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
1732{
1733 struct AttachCtx *actx = shared->adata->actx;
1734 if (!check_count(actx))
1735 return FR_NO_ACTION;
1736
1737 int rc = FR_NO_ACTION;
1738 struct Menu *menu = shared->adata->menu;
1739 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1740 ba_add_tagged(&ba, actx, menu);
1741 if (ARRAY_EMPTY(&ba))
1742 goto done;
1743
1744 struct Body **bp = NULL;
1745 ARRAY_FOREACH(bp, &ba)
1746 {
1747 mutt_update_encoding(*bp, shared->sub);
1748 }
1749
1752 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1753 rc = FR_SUCCESS;
1754
1755done:
1756 ARRAY_FREE(&ba);
1757 return rc;
1758}
1759
1760// -----------------------------------------------------------------------------
1761
1765static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
1766{
1768 const char *tag = NULL;
1769 char *err = NULL;
1770 mutt_env_to_local(shared->email->env);
1771 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1772 if (shared->email->body->type == TYPE_MULTIPART)
1773 {
1774 struct Body *b = shared->email->body->parts;
1775 while (b->parts)
1776 b = b->parts;
1777 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1778 }
1779 else
1780 {
1781 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1782 shared->email, shared->fcc);
1783 }
1784
1785 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1786 {
1787 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1788 FREE(&err);
1789 }
1791
1793 mutt_update_encoding(shared->email->body, shared->sub);
1794
1795 /* attachments may have been added */
1796 if (shared->adata->actx->idxlen &&
1797 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1798 {
1800 update_menu(shared->adata->actx, shared->adata->menu, true);
1801 }
1802
1804 /* Unconditional hook since editor was invoked */
1805 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1806 return FR_SUCCESS;
1807}
1808
1812static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
1813{
1814 if (!check_count(shared->adata->actx))
1815 return FR_NO_ACTION;
1816 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1817 shared->adata->menu);
1818 if (cur_att->body->type == TYPE_MULTIPART)
1819 {
1820 mutt_error(_("Can't edit multipart attachments"));
1821 return FR_ERROR;
1822 }
1823 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1824 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1825 mutt_update_encoding(cur_att->body, shared->sub);
1828 /* Unconditional hook since editor was invoked */
1829 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1830 return FR_SUCCESS;
1831}
1832
1836static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
1837{
1838 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1839 if (!c_edit_headers)
1840 {
1842 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1843 mutt_edit_file(c_editor, shared->email->body->filename);
1845 mutt_update_encoding(shared->email->body, shared->sub);
1847 /* Unconditional hook since editor was invoked */
1848 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1849 return FR_SUCCESS;
1850 }
1851
1852 return op_envelope_edit_headers(shared, op);
1853}
1854
1858static int op_compose_ispell(struct ComposeSharedData *shared, int op)
1859{
1860 endwin();
1861 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1862 char buf[PATH_MAX] = { 0 };
1863 snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), shared->email->body->filename);
1864 if (mutt_system(buf) == -1)
1865 {
1866 mutt_error(_("Error running \"%s\""), buf);
1867 return FR_ERROR;
1868 }
1869
1870 mutt_update_encoding(shared->email->body, shared->sub);
1872 return FR_SUCCESS;
1873}
1874
1878static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
1879{
1880 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1881 {
1883 return FR_ERROR;
1884 }
1885
1886 shared->rc = 1;
1887 return FR_DONE;
1888}
1889
1893static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
1894{
1895 if (!check_count(shared->adata->actx))
1896 return FR_NO_ACTION;
1897 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1898 shared->adata->menu);
1899 if (cur_att->body->type == TYPE_MULTIPART)
1900 {
1901 mutt_error(_("Can't rename multipart attachments"));
1902 return FR_ERROR;
1903 }
1904 struct Buffer *fname = buf_pool_get();
1905 buf_strcpy(fname, cur_att->body->filename);
1906 buf_pretty_mailbox(fname);
1907 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL, NULL };
1908 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1909 &CompleteFileOps, &cdata) == 0) &&
1910 !buf_is_empty(fname))
1911 {
1912 struct stat st = { 0 };
1913 if (stat(cur_att->body->filename, &st) == -1)
1914 {
1915 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1916 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1917 buf_pool_release(&fname);
1918 return FR_ERROR;
1919 }
1920
1921 buf_expand_path(fname);
1922 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1923 {
1924 buf_pool_release(&fname);
1925 return FR_ERROR;
1926 }
1927
1928 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1930
1931 if (cur_att->body->stamp >= st.st_mtime)
1932 mutt_stamp_attachment(cur_att->body);
1933 mutt_message_hook(NULL, shared->email, CMD_SEND2_HOOK);
1934 }
1935 buf_pool_release(&fname);
1936 return FR_SUCCESS;
1937}
1938
1942static int op_compose_send_message(struct ComposeSharedData *shared, int op)
1943{
1944 /* Note: We don't invoke send2-hook here, since we want to leave
1945 * users an opportunity to change settings from the ":" prompt. */
1946 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1947 {
1949 return FR_NO_ACTION;
1950 }
1951
1952 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1953 {
1954 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1955 shared->sub, "copy");
1956 if (ans == MUTT_ABORT)
1957 return FR_NO_ACTION;
1958 else if (ans == MUTT_NO)
1959 buf_reset(shared->fcc);
1960 }
1961
1962 shared->rc = 0;
1963 return FR_DONE;
1964}
1965
1969static int op_compose_write_message(struct ComposeSharedData *shared, int op)
1970{
1971 int rc = FR_NO_ACTION;
1972 struct Buffer *fname = buf_pool_get();
1973 if (shared->mailbox)
1974 {
1975 buf_strcpy(fname, mailbox_path(shared->mailbox));
1976 buf_pretty_mailbox(fname);
1977 }
1978 if (shared->adata->actx->idxlen)
1979 shared->email->body = shared->adata->actx->idx[0]->body;
1980 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
1981 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1982 !buf_is_empty(fname))
1983 {
1984 mutt_message(_("Writing message to %s ..."), buf_string(fname));
1985 buf_expand_path(fname);
1986
1987 if (shared->email->body->next)
1988 shared->email->body = mutt_make_multipart(shared->email->body);
1989
1990 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
1991 NULL, shared->sub) == 0)
1992 mutt_message(_("Message written"));
1993
1994 shared->email->body = mutt_remove_multipart(shared->email->body);
1995 rc = FR_SUCCESS;
1996 }
1997 buf_pool_release(&fname);
1998 return rc;
1999}
2000
2011static int op_display_headers(struct ComposeSharedData *shared, int op)
2012{
2013 if (!check_count(shared->adata->actx))
2014 return FR_NO_ACTION;
2015
2016 enum ViewAttachMode mode = MUTT_VA_REGULAR;
2017
2018 switch (op)
2019 {
2020 case OP_ATTACHMENT_VIEW:
2021 case OP_DISPLAY_HEADERS:
2022 break;
2023
2024 case OP_ATTACHMENT_VIEW_MAILCAP:
2025 mode = MUTT_VA_MAILCAP;
2026 break;
2027
2028 case OP_ATTACHMENT_VIEW_PAGER:
2029 mode = MUTT_VA_PAGER;
2030 break;
2031
2032 case OP_ATTACHMENT_VIEW_TEXT:
2033 mode = MUTT_VA_AS_TEXT;
2034 break;
2035 }
2036
2037 if (mode == MUTT_VA_REGULAR)
2038 {
2039 mutt_attach_display_loop(shared->sub, shared->adata->menu, op,
2040 shared->email, shared->adata->actx, false);
2041 }
2042 else
2043 {
2044 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
2045 shared->adata->menu);
2046 mutt_view_attachment(NULL, cur_att->body, mode, shared->email,
2047 shared->adata->actx, shared->adata->menu->win);
2048 }
2049
2051 /* no send2hook, since this doesn't modify the message */
2052 return FR_SUCCESS;
2053}
2054
2058static int op_exit(struct ComposeSharedData *shared, int op)
2059{
2060 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2061 shared->sub, "postpone");
2062 if (ans == MUTT_NO)
2063 {
2064 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2065 if (shared->adata->actx->idx[i]->unowned)
2066 shared->adata->actx->idx[i]->body->unlink = false;
2067
2068 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2069 {
2070 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2071 {
2072 /* avoid freeing other attachments */
2073 shared->adata->actx->idx[i]->body->next = NULL;
2074 if (!shared->adata->actx->idx[i]->body->email)
2075 shared->adata->actx->idx[i]->body->parts = NULL;
2076 mutt_body_free(&shared->adata->actx->idx[i]->body);
2077 }
2078 }
2079 shared->rc = -1;
2080 return FR_DONE;
2081 }
2082 else if (ans == MUTT_ABORT)
2083 {
2084 return FR_NO_ACTION;
2085 }
2086
2087 return op_compose_postpone_message(shared, op);
2088}
2089
2093static int op_forget_passphrase(struct ComposeSharedData *shared, int op)
2094{
2096 return FR_SUCCESS;
2097}
2098
2099// -----------------------------------------------------------------------------
2100
2104static const struct ComposeFunction ComposeFunctions[] = {
2105 // clang-format off
2106 { OP_ATTACHMENT_ATTACH_FILE, op_attachment_attach_file },
2107 { OP_ATTACHMENT_ATTACH_KEY, op_attachment_attach_key },
2108 { OP_ATTACHMENT_ATTACH_MESSAGE, op_attachment_attach_message },
2109 { OP_ATTACHMENT_ATTACH_NEWS_MESSAGE, op_attachment_attach_message },
2110 { OP_ATTACHMENT_DETACH, op_attachment_detach },
2111 { OP_ATTACHMENT_EDIT_CONTENT_ID, op_attachment_edit_content_id },
2112 { OP_ATTACHMENT_EDIT_DESCRIPTION, op_attachment_edit_description },
2113 { OP_ATTACHMENT_EDIT_ENCODING, op_attachment_edit_encoding },
2114 { OP_ATTACHMENT_EDIT_LANGUAGE, op_attachment_edit_language },
2115 { OP_ATTACHMENT_EDIT_MIME, op_attachment_edit_mime },
2116 { OP_ATTACHMENT_EDIT_TYPE, op_attachment_edit_type },
2117 { OP_ATTACHMENT_FILTER, op_attachment_filter },
2118 { OP_ATTACHMENT_GET_ATTACHMENT, op_attachment_get_attachment },
2119 { OP_ATTACHMENT_GROUP_ALTS, op_attachment_group_alts },
2120 { OP_ATTACHMENT_GROUP_LINGUAL, op_attachment_group_lingual },
2121 { OP_ATTACHMENT_GROUP_RELATED, op_attachment_group_related },
2122 { OP_ATTACHMENT_MOVE_DOWN, op_attachment_move_down },
2123 { OP_ATTACHMENT_MOVE_UP, op_attachment_move_up },
2124 { OP_ATTACHMENT_NEW_MIME, op_attachment_new_mime },
2125 { OP_PIPE, op_attachment_filter },
2126 { OP_ATTACHMENT_PRINT, op_attachment_print },
2127 { OP_ATTACHMENT_RENAME_ATTACHMENT, op_attachment_rename_attachment },
2128 { OP_ATTACHMENT_SAVE, op_attachment_save },
2129 { OP_ATTACHMENT_TOGGLE_DISPOSITION, op_attachment_toggle_disposition },
2130 { OP_ATTACHMENT_TOGGLE_RECODE, op_attachment_toggle_recode },
2131 { OP_ATTACHMENT_TOGGLE_UNLINK, op_attachment_toggle_unlink },
2132 { OP_ATTACHMENT_UNGROUP, op_attachment_ungroup },
2133 { OP_ATTACHMENT_UPDATE_ENCODING, op_attachment_update_encoding },
2134 { OP_ATTACHMENT_VIEW, op_display_headers },
2135 { OP_ATTACHMENT_VIEW_MAILCAP, op_display_headers },
2136 { OP_ATTACHMENT_VIEW_PAGER, op_display_headers },
2137 { OP_ATTACHMENT_VIEW_TEXT, op_display_headers },
2138 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2139 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2140 { OP_COMPOSE_ISPELL, op_compose_ispell },
2141 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2142 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2143 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2144 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2145 { OP_DISPLAY_HEADERS, op_display_headers },
2146 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2147 { OP_EXIT, op_exit },
2148 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2149 { 0, NULL },
2150 // clang-format on
2151};
2152
2157{
2158 // The Dispatcher may be called on any Window in the Dialog
2159 struct MuttWindow *dlg = dialog_find(win);
2160 if (!dlg || !dlg->wdata)
2161 return FR_ERROR;
2162
2163 int rc = FR_UNKNOWN;
2164 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2165 {
2166 const struct ComposeFunction *fn = &ComposeFunctions[i];
2167 if (fn->op == op)
2168 {
2169 struct ComposeSharedData *shared = dlg->wdata;
2170 rc = fn->function(shared, op);
2171 break;
2172 }
2173 }
2174
2175 if (rc == FR_UNKNOWN) // Not our function
2176 return rc;
2177
2178 const char *result = dispatcher_get_retval_name(rc);
2179 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2180
2181 return rc;
2182}
#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:61
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition lib.h:59
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:104
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition functions.c:235
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition functions.c:2104
static 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:532
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attachment to the message.
Definition functions.c:441
static char * gen_cid(void)
Generate a random Content ID.
Definition functions.c:252
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:466
static bool check_cid(const char *cid)
Check if a Content-ID is valid.
Definition functions.c:268
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition functions.c:288
static 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:351
void compose_init_keys(struct SubMenu *sm_generic)
Initialise the Compose Keybindings - Implements ::init_keys_api.
Definition functions.c:218
Compose functions.
GUI editor for an email's headers.
#define MUTT_COMPOSE_NOFREEHEADER
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:214
@ 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:91
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.
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:354
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:1073
Manage where the email is piped to external commands.
bool mutt_file_touch(const char *path)
Make sure a file exists.
Definition file.c:982
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition file.c:1265
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:64
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition functions.c:221
static int op_attachment_print(struct AttachPrivateData *priv, int op)
print the current entry - Implements attach_function_t -
Definition functions.c:379
static int op_attachment_edit_type(struct AttachPrivateData *priv, int op)
edit attachment content type - Implements attach_function_t -
Definition functions.c:358
static int op_forget_passphrase(struct AttachPrivateData *priv, int op)
wipe passphrases from memory - Implements attach_function_t -
Definition functions.c:568
static int op_attachment_save(struct AttachPrivateData *priv, int op)
save message/attachment to a mailbox/file - Implements attach_function_t -
Definition functions.c:390
static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/multilingual' - Implements compose_function_t -.
Definition functions.c:1309
static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
Definition functions.c:1295
static int op_attachment_filter(struct ComposeSharedData *shared, int op)
Filter attachment through a shell command - Implements compose_function_t -.
Definition functions.c:1232
static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
Rename/move an attached file - Implements compose_function_t -.
Definition functions.c:1893
static int op_compose_ispell(struct ComposeSharedData *shared, int op)
Run ispell on the message - Implements compose_function_t -.
Definition functions.c:1858
static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
Edit attachment description - Implements compose_function_t -.
Definition functions.c:1080
static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
Definition functions.c:1339
static int op_display_headers(struct ComposeSharedData *shared, int op)
Display message and toggle header weeding - Implements compose_function_t -.
Definition functions.c:2011
static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
Attach a PGP public key - Implements compose_function_t -.
Definition functions.c:815
static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
Edit the file to be attached - Implements compose_function_t -.
Definition functions.c:1812
static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
Send attachment with a different name - Implements compose_function_t -.
Definition functions.c:1560
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:1365
static int op_compose_send_message(struct ComposeSharedData *shared, int op)
Send the message - Implements compose_function_t -.
Definition functions.c:1942
static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
Attach files to this message - Implements compose_function_t -.
Definition functions.c:750
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:1651
static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition functions.c:1627
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:1421
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:1154
static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
Edit the message with headers - Implements compose_function_t -.
Definition functions.c:1765
static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition functions.c:1611
static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
Edit attachment transfer-encoding - Implements compose_function_t -.
Definition functions.c:1111
static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
Update an attachment's encoding info - Implements compose_function_t -.
Definition functions.c:1731
static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
Attach messages to this message - Implements compose_function_t -.
Definition functions.c:843
static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
Ungroup a 'multipart' attachment - Implements compose_function_t -.
Definition functions.c:1667
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:1027
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:1259
static int op_compose_write_message(struct ComposeSharedData *shared, int op)
Write the message to a folder - Implements compose_function_t -.
Definition functions.c:1969
static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
Edit attachment using mailcap entry - Implements compose_function_t -.
Definition functions.c:1190
static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
Edit the message - Implements compose_function_t -.
Definition functions.c:1836
static int op_attachment_detach(struct ComposeSharedData *shared, int op)
Delete the current entry - Implements compose_function_t -.
Definition functions.c:991
static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
Save this message to send later - Implements compose_function_t -.
Definition functions.c:1878
static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition functions.c:1456
int compose_function_dispatcher(struct MuttWindow *win, int op)
Perform a Compose function - Implements function_dispatcher_t -.
Definition functions.c:2156
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:272
#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:2786
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox?
Definition pop.c:1156
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2470
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
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)
Definition memory.h:63
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:185
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:161
#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:175
@ 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:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
#define 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.
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.
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:431
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:723
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.
Representation of the email's header.
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: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:1326
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c: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: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: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:354
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:378
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
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:76
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition recvattach.c:121
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:499
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition rfc3676.c:486
RFC3676 Format Flowed routines.
void mutt_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition run.c:132
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:423
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition sendlib.c:608
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:455
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:1019
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition sendlib.c:411
#define MUTT_RANDTAG_LEN
Definition sendlib.h:35
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: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
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
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
Functions for a Dialog or Window.
Definition menu.h:81
Mapping between a function and an operation.
Definition menu.h:39
Mapping between an operation and a key sequence.
Definition menu.h:49
Definition lib.h:79
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:87
int current
Current entry.
Definition lib.h:80
int num_tagged
Number of tagged entries.
Definition lib.h:94
bool tag_prefix
User has pressed <tag-prefix>
Definition lib.h:85
void * wdata
Private data.
Container for Accounts, Notifications.
Definition neomutt.h:128
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
Cached regular expression.
Definition regex3.h:86
Collection of related functions.
Definition menu.h:69
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