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