NeoMutt  2024-04-25-91-gb0e085
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 char *id = b->content_id;
1335 if (id)
1336 continue;
1337
1338 id = gen_cid();
1339 if (id)
1340 {
1341 mutt_str_replace(&b->content_id, id);
1342 }
1343 }
1344
1345 return group_attachments(shared, "related");
1346}
1347
1351static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
1352{
1353 int index = menu_get_index(shared->adata->menu);
1354
1355 struct AttachCtx *actx = shared->adata->actx;
1356
1357 if (index < 0)
1358 return FR_ERROR;
1359
1360 if (index == (actx->idxlen - 1))
1361 {
1362 mutt_error(_("Attachment is already at bottom"));
1363 return FR_NO_ACTION;
1364 }
1365 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1366 !actx->idx[index]->body->next)
1367 {
1368 mutt_error(_("Attachment can't be moved out of group"));
1369 return FR_ERROR;
1370 }
1371
1372 // find next attachment at current level
1373 int nextidx = index + 1;
1374 while ((nextidx < actx->idxlen) &&
1375 (actx->idx[nextidx]->level > actx->idx[index]->level))
1376 {
1377 nextidx++;
1378 }
1379 if (nextidx == actx->idxlen)
1380 {
1381 mutt_error(_("Attachment is already at bottom"));
1382 return FR_NO_ACTION;
1383 }
1384
1385 // find final position
1386 int finalidx = index + 1;
1387 if (nextidx < actx->idxlen - 1)
1388 {
1389 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1390 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1391 {
1392 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1393 }
1394 }
1395
1396 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1397 mutt_update_tree(shared->adata->actx);
1399 menu_set_index(shared->adata->menu, finalidx);
1400 return FR_SUCCESS;
1401}
1402
1406static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
1407{
1408 int index = menu_get_index(shared->adata->menu);
1409 if (index < 0)
1410 return FR_ERROR;
1411
1412 struct AttachCtx *actx = shared->adata->actx;
1413
1414 if (index == 0)
1415 {
1416 mutt_error(_("Attachment is already at top"));
1417 return FR_NO_ACTION;
1418 }
1419 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1420 {
1421 mutt_error(_("Attachment can't be moved out of group"));
1422 return FR_ERROR;
1423 }
1424
1425 // find previous attachment at current level
1426 int previdx = index - 1;
1427 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1428 previdx--;
1429
1430 compose_attach_swap(shared->email, actx, previdx, index);
1431 mutt_update_tree(actx);
1433 menu_set_index(shared->adata->menu, previdx);
1434 return FR_SUCCESS;
1435}
1436
1440static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
1441{
1442 int rc = FR_NO_ACTION;
1443 struct Buffer *fname = buf_pool_get();
1444 struct Buffer *type = NULL;
1445 struct AttachPtr *ap = NULL;
1446
1447 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1448 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1449 &CompleteFileOps, &cdata) != 0) ||
1450 buf_is_empty(fname))
1451 {
1452 goto done;
1453 }
1454 buf_expand_path(fname);
1455
1456 /* Call to lookup_mime_type () ? maybe later */
1457 type = buf_pool_get();
1458 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1459 buf_is_empty(type))
1460 {
1461 goto done;
1462 }
1463
1464 rc = FR_ERROR;
1465 char *p = strchr(buf_string(type), '/');
1466 if (!p)
1467 {
1468 mutt_error(_("Content-Type is of the form base/sub"));
1469 goto done;
1470 }
1471 *p++ = 0;
1472 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1473 if (itype == TYPE_OTHER)
1474 {
1475 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1476 goto done;
1477 }
1478
1479 ap = mutt_aptr_new();
1480 /* Touch the file */
1481 FILE *fp = mutt_file_fopen(buf_string(fname), "w");
1482 if (!fp)
1483 {
1484 mutt_error(_("Can't create file %s"), buf_string(fname));
1485 goto done;
1486 }
1487 mutt_file_fclose(&fp);
1488
1489 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1490 if (!ap->body)
1491 {
1492 mutt_error(_("Error attaching file"));
1493 goto done;
1494 }
1495 update_idx(shared->adata->menu, shared->adata->actx, ap);
1496 ap = NULL; // shared->adata->actx has taken ownership
1497
1498 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1499 shared->adata->menu);
1500 cur_att->body->type = itype;
1501 mutt_str_replace(&cur_att->body->subtype, p);
1502 cur_att->body->unlink = true;
1505
1506 if (mutt_compose_attachment(cur_att->body))
1507 {
1508 mutt_update_encoding(cur_att->body, shared->sub);
1510 }
1511 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1512 rc = FR_SUCCESS;
1513
1514done:
1515 mutt_aptr_free(&ap);
1516 buf_pool_release(&type);
1517 buf_pool_release(&fname);
1518 return rc;
1519}
1520
1524static int op_attachment_print(struct ComposeSharedData *shared, int op)
1525{
1526 struct AttachCtx *actx = shared->adata->actx;
1527 if (!check_count(actx))
1528 return FR_NO_ACTION;
1529
1530 struct Menu *menu = shared->adata->menu;
1531 struct AttachPtr *cur_att = current_attachment(actx, menu);
1532 if (cur_att->body->type == TYPE_MULTIPART)
1533 {
1534 mutt_error(_("Can't print multipart attachments"));
1535 return FR_ERROR;
1536 }
1537
1538 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1539 /* no send2hook, since this doesn't modify the message */
1540 return FR_SUCCESS;
1541}
1542
1546static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
1547{
1548 if (!check_count(shared->adata->actx))
1549 return FR_NO_ACTION;
1550 char *src = NULL;
1551 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1552 shared->adata->menu);
1553 if (cur_att->body->d_filename)
1554 src = cur_att->body->d_filename;
1555 else
1556 src = cur_att->body->filename;
1557 struct Buffer *fname = buf_pool_get();
1558 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1559 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1560 int rc = mw_get_field(_("Send attachment with name: "), fname,
1562 if (rc == 0)
1563 {
1564 // It's valid to set an empty string here, to erase what was set
1565 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1567 }
1568 buf_pool_release(&fname);
1569 return FR_SUCCESS;
1570}
1571
1575static int op_attachment_save(struct ComposeSharedData *shared, int op)
1576{
1577 struct AttachCtx *actx = shared->adata->actx;
1578 if (!check_count(actx))
1579 return FR_NO_ACTION;
1580
1581 struct Menu *menu = shared->adata->menu;
1582 struct AttachPtr *cur_att = current_attachment(actx, menu);
1583 if (cur_att->body->type == TYPE_MULTIPART)
1584 {
1585 mutt_error(_("Can't save multipart attachments"));
1586 return FR_ERROR;
1587 }
1588
1589 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1590 /* no send2hook, since this doesn't modify the message */
1591 return FR_SUCCESS;
1592}
1593
1597static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
1598{
1599 /* toggle the content-disposition between inline/attachment */
1600 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1601 shared->adata->menu);
1602 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1603 DISP_ATTACH :
1606 return FR_SUCCESS;
1607}
1608
1612static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
1613{
1614 if (!check_count(shared->adata->actx))
1615 return FR_NO_ACTION;
1616 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1617 shared->adata->menu);
1618 if (!mutt_is_text_part(cur_att->body))
1619 {
1620 mutt_error(_("Recoding only affects text attachments"));
1621 return FR_ERROR;
1622 }
1623 cur_att->body->noconv = !cur_att->body->noconv;
1624 if (cur_att->body->noconv)
1625 mutt_message(_("The current attachment won't be converted"));
1626 else
1627 mutt_message(_("The current attachment will be converted"));
1629 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1630 return FR_SUCCESS;
1631}
1632
1636static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
1637{
1638 if (!check_count(shared->adata->actx))
1639 return FR_NO_ACTION;
1640 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1641 shared->adata->menu);
1642 cur_att->body->unlink = !cur_att->body->unlink;
1643
1645 /* No send2hook since this doesn't change the message. */
1646 return FR_SUCCESS;
1647}
1648
1652static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
1653{
1654 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1655 {
1656 mutt_error(_("Attachment is not 'multipart'"));
1657 return FR_ERROR;
1658 }
1659
1660 int aidx = shared->adata->menu->current;
1661 struct AttachCtx *actx = shared->adata->actx;
1662 struct Body *b = actx->idx[aidx]->body;
1663 struct Body *b_next = b->next;
1664 struct Body *b_previous = NULL;
1665 struct Body *b_parent = NULL;
1666 int parent_type = actx->idx[aidx]->parent_type;
1667 int level = actx->idx[aidx]->level;
1668
1669 // reorder body pointers
1670 if (attach_body_previous(shared->email->body, b, &b_previous))
1671 b_previous->next = b->parts;
1672 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1673 b_parent->parts = b->parts;
1674 else
1675 shared->email->body = b->parts;
1676
1677 // update attachment list
1678 int i = aidx + 1;
1679 while (actx->idx[i]->level > level)
1680 {
1681 actx->idx[i]->level--;
1682 if (actx->idx[i]->level == level)
1683 {
1684 actx->idx[i]->parent_type = parent_type;
1685 // set body->next for final attachment in group
1686 if (!actx->idx[i]->body->next)
1687 actx->idx[i]->body->next = b_next;
1688 }
1689 i++;
1690 if (i == actx->idxlen)
1691 break;
1692 }
1693
1694 // free memory
1695 actx->idx[aidx]->body->parts = NULL;
1696 actx->idx[aidx]->body->next = NULL;
1697 actx->idx[aidx]->body->email = NULL;
1698 mutt_body_free(&actx->idx[aidx]->body);
1699 FREE(&actx->idx[aidx]->tree);
1700 FREE(&actx->idx[aidx]);
1701
1702 // reorder attachment list
1703 for (int j = aidx; j < (actx->idxlen - 1); j++)
1704 actx->idx[j] = actx->idx[j + 1];
1705 actx->idx[actx->idxlen - 1] = NULL;
1706 actx->idxlen--;
1707 update_menu(actx, shared->adata->menu, false);
1708
1709 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1710 return FR_SUCCESS;
1711}
1712
1716static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
1717{
1718 struct AttachCtx *actx = shared->adata->actx;
1719 if (!check_count(actx))
1720 return FR_NO_ACTION;
1721
1722 int rc = FR_NO_ACTION;
1723 struct Menu *menu = shared->adata->menu;
1724 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1725 ba_add_tagged(&ba, actx, menu);
1726 if (ARRAY_EMPTY(&ba))
1727 goto done;
1728
1729 struct Body **bp = NULL;
1730 ARRAY_FOREACH(bp, &ba)
1731 {
1732 mutt_update_encoding(*bp, shared->sub);
1733 }
1734
1737 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1738 rc = FR_SUCCESS;
1739
1740done:
1741 ARRAY_FREE(&ba);
1742 return rc;
1743}
1744
1745// -----------------------------------------------------------------------------
1746
1750static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
1751{
1753 const char *tag = NULL;
1754 char *err = NULL;
1755 mutt_env_to_local(shared->email->env);
1756 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1757 if (shared->email->body->type == TYPE_MULTIPART)
1758 {
1759 struct Body *b = shared->email->body->parts;
1760 while (b->parts)
1761 b = b->parts;
1762 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1763 }
1764 else
1765 {
1766 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1767 shared->email, shared->fcc);
1768 }
1769
1770 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1771 {
1772 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1773 FREE(&err);
1774 }
1776
1778 mutt_update_encoding(shared->email->body, shared->sub);
1779
1780 /* attachments may have been added */
1781 if (shared->adata->actx->idxlen &&
1782 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1783 {
1785 update_menu(shared->adata->actx, shared->adata->menu, true);
1786 }
1787
1789 /* Unconditional hook since editor was invoked */
1790 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1791 return FR_SUCCESS;
1792}
1793
1797static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
1798{
1799 if (!check_count(shared->adata->actx))
1800 return FR_NO_ACTION;
1801 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1802 shared->adata->menu);
1803 if (cur_att->body->type == TYPE_MULTIPART)
1804 {
1805 mutt_error(_("Can't edit multipart attachments"));
1806 return FR_ERROR;
1807 }
1808 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1809 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1810 mutt_update_encoding(cur_att->body, shared->sub);
1813 /* Unconditional hook since editor was invoked */
1814 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1815 return FR_SUCCESS;
1816}
1817
1821static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
1822{
1823 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1824 if (!c_edit_headers)
1825 {
1827 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1828 mutt_edit_file(c_editor, shared->email->body->filename);
1830 mutt_update_encoding(shared->email->body, shared->sub);
1832 /* Unconditional hook since editor was invoked */
1833 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1834 return FR_SUCCESS;
1835 }
1836
1837 return op_envelope_edit_headers(shared, op);
1838}
1839
1843static int op_compose_ispell(struct ComposeSharedData *shared, int op)
1844{
1845 endwin();
1846 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1847 char buf[PATH_MAX] = { 0 };
1848 snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), shared->email->body->filename);
1849 if (mutt_system(buf) == -1)
1850 {
1851 mutt_error(_("Error running \"%s\""), buf);
1852 return FR_ERROR;
1853 }
1854
1855 mutt_update_encoding(shared->email->body, shared->sub);
1857 return FR_SUCCESS;
1858}
1859
1863static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
1864{
1865 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1866 {
1868 return FR_ERROR;
1869 }
1870
1871 shared->rc = 1;
1872 return FR_DONE;
1873}
1874
1878static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
1879{
1880 if (!check_count(shared->adata->actx))
1881 return FR_NO_ACTION;
1882 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1883 shared->adata->menu);
1884 if (cur_att->body->type == TYPE_MULTIPART)
1885 {
1886 mutt_error(_("Can't rename multipart attachments"));
1887 return FR_ERROR;
1888 }
1889 struct Buffer *fname = buf_pool_get();
1890 buf_strcpy(fname, cur_att->body->filename);
1891 buf_pretty_mailbox(fname);
1892 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1893 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1894 &CompleteFileOps, &cdata) == 0) &&
1895 !buf_is_empty(fname))
1896 {
1897 struct stat st = { 0 };
1898 if (stat(cur_att->body->filename, &st) == -1)
1899 {
1900 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1901 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1902 buf_pool_release(&fname);
1903 return FR_ERROR;
1904 }
1905
1906 buf_expand_path(fname);
1907 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1908 {
1909 buf_pool_release(&fname);
1910 return FR_ERROR;
1911 }
1912
1913 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1915
1916 if (cur_att->body->stamp >= st.st_mtime)
1917 mutt_stamp_attachment(cur_att->body);
1918 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1919 }
1920 buf_pool_release(&fname);
1921 return FR_SUCCESS;
1922}
1923
1927static int op_compose_send_message(struct ComposeSharedData *shared, int op)
1928{
1929 /* Note: We don't invoke send2-hook here, since we want to leave
1930 * users an opportunity to change settings from the ":" prompt. */
1931 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1932 {
1934 return FR_NO_ACTION;
1935 }
1936
1937 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1938 {
1939 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1940 shared->sub, "copy");
1941 if (ans == MUTT_ABORT)
1942 return FR_NO_ACTION;
1943 else if (ans == MUTT_NO)
1944 buf_reset(shared->fcc);
1945 }
1946
1947 shared->rc = 0;
1948 return FR_DONE;
1949}
1950
1954static int op_compose_write_message(struct ComposeSharedData *shared, int op)
1955{
1956 int rc = FR_NO_ACTION;
1957 struct Buffer *fname = buf_pool_get();
1958 if (shared->mailbox)
1959 {
1960 buf_strcpy(fname, mailbox_path(shared->mailbox));
1961 buf_pretty_mailbox(fname);
1962 }
1963 if (shared->adata->actx->idxlen)
1964 shared->email->body = shared->adata->actx->idx[0]->body;
1965 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
1966 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1967 !buf_is_empty(fname))
1968 {
1969 mutt_message(_("Writing message to %s ..."), buf_string(fname));
1970 buf_expand_path(fname);
1971
1972 if (shared->email->body->next)
1973 shared->email->body = mutt_make_multipart(shared->email->body);
1974
1975 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
1976 NULL, shared->sub) == 0)
1977 mutt_message(_("Message written"));
1978
1979 shared->email->body = mutt_remove_multipart(shared->email->body);
1980 rc = FR_SUCCESS;
1981 }
1982 buf_pool_release(&fname);
1983 return rc;
1984}
1985
1996static int op_display_headers(struct ComposeSharedData *shared, int op)
1997{
1998 if (!check_count(shared->adata->actx))
1999 return FR_NO_ACTION;
2000
2001 enum ViewAttachMode mode = MUTT_VA_REGULAR;
2002
2003 switch (op)
2004 {
2005 case OP_ATTACHMENT_VIEW:
2006 case OP_DISPLAY_HEADERS:
2007 break;
2008
2009 case OP_ATTACHMENT_VIEW_MAILCAP:
2010 mode = MUTT_VA_MAILCAP;
2011 break;
2012
2013 case OP_ATTACHMENT_VIEW_PAGER:
2014 mode = MUTT_VA_PAGER;
2015 break;
2016
2017 case OP_ATTACHMENT_VIEW_TEXT:
2018 mode = MUTT_VA_AS_TEXT;
2019 break;
2020 }
2021
2022 if (mode == MUTT_VA_REGULAR)
2023 {
2024 mutt_attach_display_loop(shared->sub, shared->adata->menu, op,
2025 shared->email, shared->adata->actx, false);
2026 }
2027 else
2028 {
2029 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
2030 shared->adata->menu);
2031 mutt_view_attachment(NULL, cur_att->body, mode, shared->email,
2032 shared->adata->actx, shared->adata->menu->win);
2033 }
2034
2036 /* no send2hook, since this doesn't modify the message */
2037 return FR_SUCCESS;
2038}
2039
2043static int op_exit(struct ComposeSharedData *shared, int op)
2044{
2045 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2046 shared->sub, "postpone");
2047 if (ans == MUTT_NO)
2048 {
2049 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2050 if (shared->adata->actx->idx[i]->unowned)
2051 shared->adata->actx->idx[i]->body->unlink = false;
2052
2053 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2054 {
2055 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2056 {
2057 /* avoid freeing other attachments */
2058 shared->adata->actx->idx[i]->body->next = NULL;
2059 if (!shared->adata->actx->idx[i]->body->email)
2060 shared->adata->actx->idx[i]->body->parts = NULL;
2061 mutt_body_free(&shared->adata->actx->idx[i]->body);
2062 }
2063 }
2064 shared->rc = -1;
2065 return FR_DONE;
2066 }
2067 else if (ans == MUTT_ABORT)
2068 {
2069 return FR_NO_ACTION;
2070 }
2071
2072 return op_compose_postpone_message(shared, op);
2073}
2074
2078static int op_forget_passphrase(struct ComposeSharedData *shared, int op)
2079{
2081 return FR_SUCCESS;
2082}
2083
2084// -----------------------------------------------------------------------------
2085
2089static const struct ComposeFunction ComposeFunctions[] = {
2090 // clang-format off
2091 { OP_ATTACHMENT_ATTACH_FILE, op_attachment_attach_file },
2092 { OP_ATTACHMENT_ATTACH_KEY, op_attachment_attach_key },
2093 { OP_ATTACHMENT_ATTACH_MESSAGE, op_attachment_attach_message },
2094 { OP_ATTACHMENT_ATTACH_NEWS_MESSAGE, op_attachment_attach_message },
2095 { OP_ATTACHMENT_DETACH, op_attachment_detach },
2096 { OP_ATTACHMENT_EDIT_CONTENT_ID, op_attachment_edit_content_id },
2097 { OP_ATTACHMENT_EDIT_DESCRIPTION, op_attachment_edit_description },
2098 { OP_ATTACHMENT_EDIT_ENCODING, op_attachment_edit_encoding },
2099 { OP_ATTACHMENT_EDIT_LANGUAGE, op_attachment_edit_language },
2100 { OP_ATTACHMENT_EDIT_MIME, op_attachment_edit_mime },
2101 { OP_ATTACHMENT_EDIT_TYPE, op_attachment_edit_type },
2102 { OP_ATTACHMENT_FILTER, op_attachment_filter },
2103 { OP_ATTACHMENT_GET_ATTACHMENT, op_attachment_get_attachment },
2104 { OP_ATTACHMENT_GROUP_ALTS, op_attachment_group_alts },
2105 { OP_ATTACHMENT_GROUP_LINGUAL, op_attachment_group_lingual },
2106 { OP_ATTACHMENT_GROUP_RELATED, op_attachment_group_related },
2107 { OP_ATTACHMENT_MOVE_DOWN, op_attachment_move_down },
2108 { OP_ATTACHMENT_MOVE_UP, op_attachment_move_up },
2109 { OP_ATTACHMENT_NEW_MIME, op_attachment_new_mime },
2110 { OP_PIPE, op_attachment_filter },
2111 { OP_ATTACHMENT_PRINT, op_attachment_print },
2112 { OP_ATTACHMENT_RENAME_ATTACHMENT, op_attachment_rename_attachment },
2113 { OP_ATTACHMENT_SAVE, op_attachment_save },
2114 { OP_ATTACHMENT_TOGGLE_DISPOSITION, op_attachment_toggle_disposition },
2115 { OP_ATTACHMENT_TOGGLE_RECODE, op_attachment_toggle_recode },
2116 { OP_ATTACHMENT_TOGGLE_UNLINK, op_attachment_toggle_unlink },
2117 { OP_ATTACHMENT_UNGROUP, op_attachment_ungroup },
2118 { OP_ATTACHMENT_UPDATE_ENCODING, op_attachment_update_encoding },
2119 { OP_ATTACHMENT_VIEW, op_display_headers },
2120 { OP_ATTACHMENT_VIEW_MAILCAP, op_display_headers },
2121 { OP_ATTACHMENT_VIEW_PAGER, op_display_headers },
2122 { OP_ATTACHMENT_VIEW_TEXT, op_display_headers },
2123 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2124 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2125 { OP_COMPOSE_ISPELL, op_compose_ispell },
2126 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2127 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2128 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2129 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2130 { OP_DISPLAY_HEADERS, op_display_headers },
2131 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2132 { OP_EXIT, op_exit },
2133 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2134 { 0, NULL },
2135 // clang-format on
2136};
2137
2142{
2143 if (!win)
2144 return FR_UNKNOWN;
2145
2146 struct MuttWindow *dlg = dialog_find(win);
2147 if (!dlg || !dlg->wdata)
2148 return FR_UNKNOWN;
2149
2150 int rc = FR_UNKNOWN;
2151 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2152 {
2153 const struct ComposeFunction *fn = &ComposeFunctions[i];
2154 if (fn->op == op)
2155 {
2156 struct ComposeSharedData *shared = dlg->wdata;
2157 rc = fn->function(shared, op);
2158 break;
2159 }
2160 }
2161
2162 if (rc == FR_UNKNOWN) // Not our function
2163 return rc;
2164
2165 const char *result = dispatcher_get_retval_name(rc);
2166 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2167
2168 return rc;
2169}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:65
void mutt_actx_ins_attach(struct AttachCtx *actx, struct AttachPtr *attach, int aidx)
Insert an Attachment into an Attachment Context at Specified Index.
Definition: attach.c:91
struct AttachPtr * mutt_aptr_new(void)
Create a new Attachment Pointer.
Definition: attach.c:40
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:162
void mutt_aptr_free(struct AttachPtr **ptr)
Free an Attachment Pointer.
Definition: attach.c:49
bool attach_body_parent(struct Body *start, struct Body *start_parent, struct Body *body, struct Body **body_parent)
Find the parent of a body.
Definition: lib.c:71
int attach_body_count(struct Body *body, bool recurse)
Count bodies.
Definition: lib.c:42
bool attach_body_previous(struct Body *start, struct Body *body, struct Body **previous)
Find the previous body of a body.
Definition: lib.c:142
GUI display the mailboxes in a side panel.
Compose Attach Data.
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
Select a Mailbox from a list.
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: lib.h:59
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition: functions.c:216
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition: functions.c:2089
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition: functions.c:87
static int group_attachments(struct ComposeSharedData *shared, char *subtype)
Group tagged attachments into a multipart group.
Definition: functions.c: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:149
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:148
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:70
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:1878
static int op_compose_ispell(struct ComposeSharedData *shared, int op)
Run ispell on the message - Implements compose_function_t -.
Definition: functions.c:1843
static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
Edit attachment description - Implements compose_function_t -.
Definition: functions.c: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:1996
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:1797
static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
Send attachment with a different name - Implements compose_function_t -.
Definition: functions.c:1546
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:1351
static int op_compose_send_message(struct ComposeSharedData *shared, int op)
Send the message - Implements compose_function_t -.
Definition: functions.c:1927
static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
Attach files to this message - Implements compose_function_t -.
Definition: functions.c: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:1636
static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition: functions.c:1612
static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
Move an attachment up in the attachment list - Implements compose_function_t -.
Definition: functions.c:1406
static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
Edit the 'Content-Language' of the attachment - Implements compose_function_t -.
Definition: functions.c:1135
static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
Edit the message with headers - Implements compose_function_t -.
Definition: functions.c:1750
static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition: functions.c:1597
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:1716
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:1652
static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
Edit the 'Content-ID' of the attachment - Implements compose_function_t -.
Definition: functions.c: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:1954
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:1821
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:1863
static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1440
int compose_function_dispatcher(struct MuttWindow *win, int op)
Perform a Compose function - Implements function_dispatcher_t -.
Definition: functions.c:2141
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c: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:692
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:182
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:341
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:365
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: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:85
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