NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
29#include "config.h"
30#ifdef _MAKEDOC
31#include "docs/makedoc_defs.h"
32#else
33#include <errno.h>
34#include <limits.h>
35#include <stdbool.h>
36#include <stdio.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <unistd.h>
40#include "private.h"
41#include "mutt/lib.h"
42#include "config/lib.h"
43#include "email/lib.h"
44#include "core/lib.h"
45#include "conn/lib.h"
46#include "gui/lib.h"
47#include "mutt.h"
48#include "lib.h"
49#include "attach/lib.h"
50#include "browser/lib.h"
51#include "editor/lib.h"
52#include "history/lib.h"
53#include "imap/lib.h"
54#include "index/lib.h"
55#include "key/lib.h"
56#include "menu/lib.h"
57#include "ncrypt/lib.h"
58#include "nntp/lib.h"
59#include "pop/lib.h"
60#include "question/lib.h"
61#include "send/lib.h"
62#include "attach_data.h"
63#include "external.h"
64#include "functions.h"
65#include "globals.h"
66#include "hook.h"
67#include "mutt_header.h"
68#include "mutt_logging.h"
69#include "muttlib.h"
70#include "mview.h"
71#include "mx.h"
72#include "nntp/adata.h" // IWYU pragma: keep
73#include "protos.h"
74#include "rfc3676.h"
75#include "shared_data.h"
76#ifdef ENABLE_NLS
77#include <libintl.h>
78#endif
79#ifdef MIXMASTER
80#include "mixmaster/lib.h"
81#endif
82#endif
83
84// clang-format off
88const struct MenuFuncOp OpCompose[] = { /* map: compose */
89 { "attach-file", OP_ATTACHMENT_ATTACH_FILE },
90 { "attach-key", OP_ATTACHMENT_ATTACH_KEY },
91 { "attach-message", OP_ATTACHMENT_ATTACH_MESSAGE },
92 { "attach-news-message", OP_ATTACHMENT_ATTACH_NEWS_MESSAGE },
93#ifdef USE_AUTOCRYPT
94 { "autocrypt-menu", OP_COMPOSE_AUTOCRYPT_MENU },
95#endif
96 { "copy-file", OP_ATTACHMENT_SAVE },
97 { "detach-file", OP_ATTACHMENT_DETACH },
98 { "display-toggle-weed", OP_DISPLAY_HEADERS },
99 { "edit-bcc", OP_ENVELOPE_EDIT_BCC },
100 { "edit-cc", OP_ENVELOPE_EDIT_CC },
101 { "edit-content-id", OP_ATTACHMENT_EDIT_CONTENT_ID },
102 { "edit-description", OP_ATTACHMENT_EDIT_DESCRIPTION },
103 { "edit-encoding", OP_ATTACHMENT_EDIT_ENCODING },
104 { "edit-fcc", OP_ENVELOPE_EDIT_FCC },
105 { "edit-file", OP_COMPOSE_EDIT_FILE },
106 { "edit-followup-to", OP_ENVELOPE_EDIT_FOLLOWUP_TO },
107 { "edit-from", OP_ENVELOPE_EDIT_FROM },
108 { "edit-headers", OP_ENVELOPE_EDIT_HEADERS },
109 { "edit-language", OP_ATTACHMENT_EDIT_LANGUAGE },
110 { "edit-message", OP_COMPOSE_EDIT_MESSAGE },
111 { "edit-mime", OP_ATTACHMENT_EDIT_MIME },
112 { "edit-newsgroups", OP_ENVELOPE_EDIT_NEWSGROUPS },
113 { "edit-reply-to", OP_ENVELOPE_EDIT_REPLY_TO },
114 { "edit-subject", OP_ENVELOPE_EDIT_SUBJECT },
115 { "edit-to", OP_ENVELOPE_EDIT_TO },
116 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
117 { "edit-x-comment-to", OP_ENVELOPE_EDIT_X_COMMENT_TO },
118 { "exit", OP_EXIT },
119 { "filter-entry", OP_ATTACHMENT_FILTER },
120 { "forget-passphrase", OP_FORGET_PASSPHRASE },
121 { "get-attachment", OP_ATTACHMENT_GET_ATTACHMENT },
122 { "group-alternatives", OP_ATTACHMENT_GROUP_ALTS },
123 { "group-multilingual", OP_ATTACHMENT_GROUP_LINGUAL },
124 { "group-related", OP_ATTACHMENT_GROUP_RELATED },
125 { "ispell", OP_COMPOSE_ISPELL },
126#ifdef MIXMASTER
127 { "mix", OP_COMPOSE_MIX },
128#endif
129 { "move-down", OP_ATTACHMENT_MOVE_DOWN },
130 { "move-up", OP_ATTACHMENT_MOVE_UP },
131 { "new-mime", OP_ATTACHMENT_NEW_MIME },
132 { "pgp-menu", OP_COMPOSE_PGP_MENU },
133 { "pipe-entry", OP_PIPE },
134 { "pipe-message", OP_PIPE },
135 { "postpone-message", OP_COMPOSE_POSTPONE_MESSAGE },
136 { "print-entry", OP_ATTACHMENT_PRINT },
137 { "rename-attachment", OP_ATTACHMENT_RENAME_ATTACHMENT },
138 { "rename-file", OP_COMPOSE_RENAME_FILE },
139 { "send-message", OP_COMPOSE_SEND_MESSAGE },
140 { "smime-menu", OP_COMPOSE_SMIME_MENU },
141 { "toggle-disposition", OP_ATTACHMENT_TOGGLE_DISPOSITION },
142 { "toggle-recode", OP_ATTACHMENT_TOGGLE_RECODE },
143 { "toggle-unlink", OP_ATTACHMENT_TOGGLE_UNLINK },
144 { "ungroup-attachment", OP_ATTACHMENT_UNGROUP },
145 { "update-encoding", OP_ATTACHMENT_UPDATE_ENCODING },
146 { "view-attach", OP_ATTACHMENT_VIEW },
147 { "view-mailcap", OP_ATTACHMENT_VIEW_MAILCAP },
148 { "view-pager", OP_ATTACHMENT_VIEW_PAGER },
149 { "view-text", OP_ATTACHMENT_VIEW_TEXT },
150 { "write-fcc", OP_COMPOSE_WRITE_MESSAGE },
151 { NULL, 0 },
152};
153
157const struct MenuOpSeq ComposeDefaultBindings[] = { /* map: compose */
158 { OP_ATTACHMENT_ATTACH_FILE, "a" },
159 { OP_ATTACHMENT_ATTACH_KEY, "\033k" }, // <Alt-k>
160 { OP_ATTACHMENT_ATTACH_MESSAGE, "A" },
161 { OP_ATTACHMENT_DETACH, "D" },
162 { OP_ATTACHMENT_EDIT_CONTENT_ID, "\033i" }, // <Alt-i>
163 { OP_ATTACHMENT_EDIT_DESCRIPTION, "d" },
164 { OP_ATTACHMENT_EDIT_ENCODING, "\005" }, // <Ctrl-E>
165 { OP_ATTACHMENT_EDIT_LANGUAGE, "\014" }, // <Ctrl-L>
166 { OP_ATTACHMENT_EDIT_MIME, "m" },
167 { OP_ATTACHMENT_EDIT_TYPE, "\024" }, // <Ctrl-T>
168 { OP_ATTACHMENT_FILTER, "F" },
169 { OP_ATTACHMENT_GET_ATTACHMENT, "G" },
170 { OP_ATTACHMENT_GROUP_ALTS, "&" },
171 { OP_ATTACHMENT_GROUP_LINGUAL, "^" },
172 { OP_ATTACHMENT_GROUP_RELATED, "%" },
173 { OP_ATTACHMENT_MOVE_DOWN, "+" },
174 { OP_ATTACHMENT_MOVE_UP, "-" },
175 { OP_ATTACHMENT_NEW_MIME, "n" },
176 { OP_EXIT, "q" },
177 { OP_PIPE, "|" },
178 { OP_ATTACHMENT_PRINT, "l" },
179 { OP_ATTACHMENT_RENAME_ATTACHMENT, "\017" }, // <Ctrl-O>
180 { OP_ATTACHMENT_SAVE, "C" },
181 { OP_ATTACHMENT_TOGGLE_DISPOSITION, "\004" }, // <Ctrl-D>
182 { OP_ATTACHMENT_TOGGLE_UNLINK, "u" },
183 { OP_ATTACHMENT_UNGROUP, "#" },
184 { OP_ATTACHMENT_UPDATE_ENCODING, "U" },
185 { OP_ATTACHMENT_VIEW, "<keypadenter>" },
186 { OP_ATTACHMENT_VIEW, "\n" }, // <Enter>
187 { OP_ATTACHMENT_VIEW, "\r" }, // <Return>
188#ifdef USE_AUTOCRYPT
189 { OP_COMPOSE_AUTOCRYPT_MENU, "o" },
190#endif
191 { OP_COMPOSE_EDIT_FILE, "\033e" }, // <Alt-e>
192 { OP_COMPOSE_EDIT_MESSAGE, "e" },
193 { OP_COMPOSE_ISPELL, "i" },
194#ifdef MIXMASTER
195 { OP_COMPOSE_MIX, "M" },
196#endif
197 { OP_COMPOSE_PGP_MENU, "p" },
198 { OP_COMPOSE_POSTPONE_MESSAGE, "P" },
199 { OP_COMPOSE_RENAME_FILE, "R" },
200 { OP_COMPOSE_SEND_MESSAGE, "y" },
201 { OP_COMPOSE_SMIME_MENU, "S" },
202 { OP_COMPOSE_WRITE_MESSAGE, "w" },
203 { OP_DISPLAY_HEADERS, "h" },
204 { OP_ENVELOPE_EDIT_BCC, "b" },
205 { OP_ENVELOPE_EDIT_CC, "c" },
206 { OP_ENVELOPE_EDIT_FCC, "f" },
207 { OP_ENVELOPE_EDIT_FROM, "\033f" }, // <Alt-f>
208 { OP_ENVELOPE_EDIT_HEADERS, "E" },
209 { OP_ENVELOPE_EDIT_REPLY_TO, "r" },
210 { OP_ENVELOPE_EDIT_SUBJECT, "s" },
211 { OP_ENVELOPE_EDIT_TO, "t" },
212 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
213 { OP_TAG, "T" },
214 { 0, NULL },
215};
216// clang-format on
217
223static bool check_count(struct AttachCtx *actx)
224{
225 if (actx->idxlen == 0)
226 {
227 mutt_error(_("There are no attachments"));
228 return false;
229 }
230
231 return true;
232}
233
240static char *gen_cid(void)
241{
242 char rndid[MUTT_RANDTAG_LEN + 1];
243
244 mutt_rand_base32(rndid, sizeof(rndid) - 1);
245 rndid[MUTT_RANDTAG_LEN] = 0;
246
247 return mutt_str_dup(rndid);
248}
249
256static bool check_cid(const char *cid)
257{
258 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
259
260 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
261
262 const bool valid = mutt_regex_match(check_cid_regex, cid);
263
264 mutt_regex_free(&check_cid_regex);
265
266 return valid;
267}
268
276static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
277{
278 int rc = -1;
279 struct stat st = { 0 };
280 struct Buffer *pretty = NULL, *msg = NULL;
281
282 for (int i = 0; i < actx->idxlen; i++)
283 {
284 if (actx->idx[i]->body->type == TYPE_MULTIPART)
285 continue;
286 if (stat(actx->idx[i]->body->filename, &st) != 0)
287 {
288 if (!pretty)
289 pretty = buf_pool_get();
290 buf_strcpy(pretty, actx->idx[i]->body->filename);
291 buf_pretty_mailbox(pretty);
292 /* L10N: This message is displayed in the compose menu when an attachment
293 doesn't stat. %d is the attachment number and %s is the attachment
294 filename. The filename is located last to avoid a long path hiding
295 the error message. */
296 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
297 goto cleanup;
298 }
299
300 if (actx->idx[i]->body->stamp < st.st_mtime)
301 {
302 if (!pretty)
303 pretty = buf_pool_get();
304 buf_strcpy(pretty, actx->idx[i]->body->filename);
305 buf_pretty_mailbox(pretty);
306
307 if (!msg)
308 msg = buf_pool_get();
309 /* L10N: This message is displayed in the compose menu when an attachment
310 is modified behind the scenes. %d is the attachment number and %s is
311 the attachment filename. The filename is located last to avoid a long
312 path hiding the prompt question. */
313 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
314 i + 1, buf_string(pretty));
315
317 if (ans == MUTT_YES)
318 mutt_update_encoding(actx->idx[i]->body, sub);
319 else if (ans == MUTT_ABORT)
320 goto cleanup;
321 }
322 }
323
324 rc = 0;
325
326cleanup:
327 buf_pool_release(&pretty);
328 buf_pool_release(&msg);
329 return rc;
330}
331
339static int delete_attachment(struct AttachCtx *actx, int aidx)
340{
341 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
342 return -1;
343
344 struct AttachPtr **idx = actx->idx;
345 struct Body *b_previous = NULL;
346 struct Body *b_parent = NULL;
347
348 if (aidx == 0)
349 {
350 struct Body *b = actx->idx[0]->body;
351 if (!b->next) // There's only one attachment left
352 {
353 mutt_error(_("You may not delete the only attachment"));
354 return -1;
355 }
356 }
357
358 if (idx[aidx]->level > 0)
359 {
360 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
361 {
362 if (attach_body_count(b_parent->parts, false) < 3)
363 {
364 mutt_error(_("Can't leave group with only one attachment"));
365 return -1;
366 }
367 }
368 }
369
370 // reorder body pointers
371 if (aidx > 0)
372 {
373 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
374 b_previous->next = idx[aidx]->body->next;
375 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
376 b_parent->parts = idx[aidx]->body->next;
377 }
378
379 // free memory
380 int part_count = 1;
381 if (aidx < (actx->idxlen - 1))
382 {
383 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
384 (idx[aidx + 1]->level > idx[aidx]->level))
385 {
386 part_count += attach_body_count(idx[aidx]->body->parts, true);
387 }
388 }
389 idx[aidx]->body->next = NULL;
390 mutt_body_free(&(idx[aidx]->body));
391 for (int i = 0; i < part_count; i++)
392 {
393 FREE(&idx[aidx + i]->tree);
394 FREE(&idx[aidx + i]);
395 }
396
397 // reorder attachment list
398 for (int i = aidx; i < (actx->idxlen - part_count); i++)
399 idx[i] = idx[i + part_count];
400 for (int i = 0; i < part_count; i++)
401 idx[actx->idxlen - i - 1] = NULL;
402 actx->idxlen -= part_count;
403
404 return 0;
405}
406
413static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
414{
415 ap->level = 0;
416 for (int i = actx->idxlen; i > 0; i--)
417 {
418 if (ap->level == actx->idx[i - 1]->level)
419 {
420 actx->idx[i - 1]->body->next = ap->body;
421 break;
422 }
423 }
424
425 ap->body->aptr = ap;
426 mutt_actx_add_attach(actx, ap);
427 update_menu(actx, menu, false);
428 menu_set_index(menu, actx->vcount - 1);
429}
430
438static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
439{
440 struct AttachPtr **idx = actx->idx;
441
442 // check that attachments really are adjacent
443 if (idx[first]->body->next != idx[second]->body)
444 return;
445
446 // reorder Body pointers
447 if (first == 0)
448 {
449 // first attachment is the fundamental part
450 idx[first]->body->next = idx[second]->body->next;
451 idx[second]->body->next = idx[first]->body;
452 e->body = idx[second]->body;
453 }
454 else
455 {
456 // find previous attachment
457 struct Body *b_previous = NULL;
458 struct Body *b_parent = NULL;
459 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
460 {
461 idx[first]->body->next = idx[second]->body->next;
462 idx[second]->body->next = idx[first]->body;
463 b_previous->next = idx[second]->body;
464 }
465 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
466 {
467 idx[first]->body->next = idx[second]->body->next;
468 idx[second]->body->next = idx[first]->body;
469 b_parent->parts = idx[second]->body;
470 }
471 }
472
473 // reorder attachment list
474 struct AttachPtr *saved = idx[second];
475 for (int i = second; i > first; i--)
476 idx[i] = idx[i - 1];
477 idx[first] = saved;
478
479 // if moved attachment is a group then move subparts too
480 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
481 {
482 int i = second + 1;
483 while (idx[i]->level > idx[first]->level)
484 {
485 saved = idx[i];
486 int destidx = i - second + first;
487 for (int j = i; j > destidx; j--)
488 idx[j] = idx[j - 1];
489 idx[destidx] = saved;
490 i++;
491 if (i >= actx->idxlen)
492 break;
493 }
494 }
495}
496
504static int group_attachments(struct ComposeSharedData *shared, char *subtype)
505{
506 struct AttachCtx *actx = shared->adata->actx;
507 int group_level = -1;
508 struct Body *bptr_parent = NULL;
509
510 // Attachments to be grouped must have the same parent
511 for (int i = 0; i < actx->idxlen; i++)
512 {
513 // check if all tagged attachments are at same level
514 if (actx->idx[i]->body->tagged)
515 {
516 if (group_level == -1)
517 {
518 group_level = actx->idx[i]->level;
519 }
520 else
521 {
522 if (group_level != actx->idx[i]->level)
523 {
524 mutt_error(_("Attachments to be grouped must have the same parent"));
525 return FR_ERROR;
526 }
527 }
528 // if not at top level check if all tagged attachments have same parent
529 if (group_level > 0)
530 {
531 if (bptr_parent)
532 {
533 struct Body *bptr_test = NULL;
534 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
535 mutt_debug(LL_DEBUG5, "can't find parent\n");
536 if (bptr_test != bptr_parent)
537 {
538 mutt_error(_("Attachments to be grouped must have the same parent"));
539 return FR_ERROR;
540 }
541 }
542 else
543 {
544 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
545 mutt_debug(LL_DEBUG5, "can't find parent\n");
546 }
547 }
548 }
549 }
550
551 // Can't group all attachments unless at top level
552 if (bptr_parent)
553 {
554 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
555 {
556 mutt_error(_("Can't leave group with only one attachment"));
557 return FR_ERROR;
558 }
559 }
560
561 struct Body *group = mutt_body_new();
562 group->type = TYPE_MULTIPART;
563 group->subtype = mutt_str_dup(subtype);
564 group->encoding = ENC_7BIT;
565
566 struct Body *bptr_first = NULL; // first tagged attachment
567 struct Body *bptr = NULL; // current tagged attachment
568 struct Body *group_parent = NULL; // parent of group
569 struct Body *group_previous = NULL; // previous body to group
570 struct Body *group_part = NULL; // current attachment in group
571 int group_idx = 0; // index in attachment list where group will be inserted
572 int group_last_idx = 0; // index of last part of previous found group
573 int group_parent_type = TYPE_OTHER;
574
575 for (int i = 0; i < actx->idxlen; i++)
576 {
577 bptr = actx->idx[i]->body;
578 if (bptr->tagged)
579 {
580 // set group properties based on first tagged attachment
581 if (!bptr_first)
582 {
583 group->disposition = bptr->disposition;
584 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
585 group->language = mutt_str_dup(bptr->language);
586 group_parent_type = bptr->aptr->parent_type;
587 bptr_first = bptr;
588 if (i > 0)
589 {
590 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
591 {
592 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
593 }
594 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
595 {
596 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
597 }
598 }
599 }
600
601 shared->adata->menu->num_tagged--;
602 bptr->tagged = false;
603 bptr->aptr->level++;
605
606 // append bptr to the group parts list and remove from email body list
607 struct Body *bptr_previous = NULL;
608 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
609 bptr_previous->next = bptr->next;
610 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
611 bptr_parent->parts = bptr->next;
612 else
613 shared->email->body = bptr->next;
614
615 if (group_part)
616 {
617 // add bptr to group parts list
618 group_part->next = bptr;
619 group_part = group_part->next;
620 group_part->next = NULL;
621
622 // reorder attachments and set levels
623 int bptr_attachments = attach_body_count(bptr, true);
624 for (int j = i + 1; j < (i + bptr_attachments); j++)
625 actx->idx[j]->level++;
626 if (i > (group_last_idx + 1))
627 {
628 for (int j = 0; j < bptr_attachments; j++)
629 {
630 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
631 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
632 actx->idx[k] = actx->idx[k - 1];
633 actx->idx[group_last_idx + 1] = saved;
634 }
635 }
636 i += bptr_attachments - 1;
637 group_last_idx += bptr_attachments;
638 }
639 else
640 {
641 group_idx = i;
642 group->parts = bptr;
643 group_part = bptr;
644 group_part->next = NULL;
645 int bptr_attachments = attach_body_count(bptr, true);
646 for (int j = i + 1; j < (i + bptr_attachments); j++)
647 actx->idx[j]->level++;
648 i += bptr_attachments - 1;
649 group_last_idx = i;
650 }
651 }
652 }
653
654 if (!bptr_first)
655 {
656 mutt_body_free(&group);
657 return FR_ERROR;
658 }
659
660 // set group->next
661 int next_aidx = group_idx + attach_body_count(group->parts, true);
662 if (group_parent)
663 {
664 // find next attachment with the same parent as the group
665 struct Body *b = NULL;
666 struct Body *b_parent = NULL;
667 while (next_aidx < actx->idxlen)
668 {
669 b = actx->idx[next_aidx]->body;
670 b_parent = NULL;
671 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
672 {
673 if (group_parent == b_parent)
674 {
675 group->next = b;
676 break;
677 }
678 }
679 next_aidx++;
680 }
681 }
682 else if (next_aidx < actx->idxlen)
683 {
684 // group is at top level
685 group->next = actx->idx[next_aidx]->body;
686 }
687
688 // set previous or parent for group
689 if (group_previous)
690 group_previous->next = group;
691 else if (group_parent)
692 group_parent->parts = group;
693
695
696 struct AttachPtr *group_ap = mutt_aptr_new();
697 group_ap->body = group;
698 group_ap->body->aptr = group_ap;
699 group_ap->level = group_level;
700 group_ap->parent_type = group_parent_type;
701
702 // insert group into attachment list
703 mutt_actx_ins_attach(actx, group_ap, group_idx);
704
705 // update email body and last attachment pointers
706 shared->email->body = actx->idx[0]->body;
707 actx->idx[actx->idxlen - 1]->body->next = NULL;
708
709 update_menu(actx, shared->adata->menu, false);
710 shared->adata->menu->current = group_idx;
712
714 return FR_SUCCESS;
715}
716
717// -----------------------------------------------------------------------------
718
722static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
723{
724 char *prompt = _("Attach file");
725 int numfiles = 0;
726 char **files = NULL;
727
728 struct Buffer *fname = buf_pool_get();
729 if ((mw_enter_fname(prompt, fname, false, NULL, true, &files, &numfiles,
730 MUTT_SEL_MULTI) == -1) ||
731 buf_is_empty(fname))
732 {
733 for (int i = 0; i < numfiles; i++)
734 FREE(&files[i]);
735
736 FREE(&files);
737 buf_pool_release(&fname);
738 return FR_NO_ACTION;
739 }
740
741 bool error = false;
742 bool added_attachment = false;
743 if (numfiles > 1)
744 {
745 mutt_message(ngettext("Attaching selected file...",
746 "Attaching selected files...", numfiles));
747 }
748 for (int i = 0; i < numfiles; i++)
749 {
750 char *att = files[i];
751 if (!att)
752 continue;
753
754 struct AttachPtr *ap = mutt_aptr_new();
755 ap->unowned = true;
756 ap->body = mutt_make_file_attach(att, shared->sub);
757 if (ap->body)
758 {
759 added_attachment = true;
760 update_idx(shared->adata->menu, shared->adata->actx, ap);
761 }
762 else
763 {
764 error = true;
765 mutt_error(_("Unable to attach %s"), att);
766 mutt_aptr_free(&ap);
767 }
768 FREE(&files[i]);
769 }
770
771 FREE(&files);
772 buf_pool_release(&fname);
773
774 if (!error)
776
779 if (added_attachment)
781 return FR_SUCCESS;
782}
783
787static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
788{
790 return FR_NOT_IMPL;
791 struct AttachPtr *ap = mutt_aptr_new();
793 if (ap->body)
794 {
795 update_idx(shared->adata->menu, shared->adata->actx, ap);
798 }
799 else
800 {
801 mutt_aptr_free(&ap);
802 }
803
805 return FR_SUCCESS;
806}
807
815static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
816{
817 char *prompt = _("Open mailbox to attach message from");
818
819 OptNews = false;
820 if (shared->mailbox && (op == OP_ATTACHMENT_ATTACH_NEWS_MESSAGE))
821 {
822 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
823 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
824 if (!CurrentNewsSrv)
825 return FR_NO_ACTION;
826
827 prompt = _("Open newsgroup to attach message from");
828 OptNews = true;
829 }
830
831 struct Buffer *fname = buf_pool_get();
832 if (shared->mailbox)
833 {
834 if ((op == OP_ATTACHMENT_ATTACH_MESSAGE) ^ (shared->mailbox->type == MUTT_NNTP))
835 {
836 buf_strcpy(fname, mailbox_path(shared->mailbox));
837 buf_pretty_mailbox(fname);
838 }
839 }
840
841 if ((mw_enter_fname(prompt, fname, true, shared->mailbox, false, NULL, NULL,
842 MUTT_SEL_NO_FLAGS) == -1) ||
843 buf_is_empty(fname))
844 {
845 buf_pool_release(&fname);
846 return FR_NO_ACTION;
847 }
848
849 if (OptNews)
851 else
852 buf_expand_path(fname);
853
854 if (imap_path_probe(buf_string(fname), NULL) != MUTT_IMAP)
855 {
856 if (pop_path_probe(buf_string(fname), NULL) != MUTT_POP)
857 {
858 if (!OptNews && (nntp_path_probe(buf_string(fname), NULL) != MUTT_NNTP))
859 {
861 {
862 /* check to make sure the file exists and is readable */
863 if (access(buf_string(fname), R_OK) == -1)
864 {
865 mutt_perror("%s", buf_string(fname));
866 buf_pool_release(&fname);
867 return FR_ERROR;
868 }
869 }
870 }
871 }
872 }
873
875
876 struct Mailbox *m_attach = mx_path_resolve(buf_string(fname));
877 const bool old_readonly = m_attach->readonly;
878 if (!mx_mbox_open(m_attach, MUTT_READONLY))
879 {
880 mutt_error(_("Unable to open mailbox %s"), buf_string(fname));
881 mx_fastclose_mailbox(m_attach, false);
882 m_attach = NULL;
883 buf_pool_release(&fname);
884 return FR_ERROR;
885 }
886 buf_pool_release(&fname);
887
888 if (m_attach->msg_count == 0)
889 {
890 mx_mbox_close(m_attach);
891 mutt_error(_("No messages in that folder"));
892 return FR_NO_ACTION;
893 }
894
895 /* `$sort`, `$sort_aux`, `$use_threads` could be changed in dlg_index() */
896 const enum SortType old_sort = cs_subset_sort(shared->sub, "sort");
897 const enum SortType old_sort_aux = cs_subset_sort(shared->sub, "sort_aux");
898 const unsigned char old_use_threads = cs_subset_enum(shared->sub, "use_threads");
899
900 mutt_message(_("Tag the messages you want to attach"));
901 struct MuttWindow *dlg = index_pager_init();
902 struct IndexSharedData *index_shared = dlg->wdata;
903 index_shared->attach_msg = true;
904 dialog_push(dlg);
905 struct Mailbox *m_attach_new = dlg_index(dlg, m_attach);
906 dialog_pop();
907 mutt_window_free(&dlg);
908
909 if (!shared->mailbox)
910 {
911 /* Restore old $sort variables */
912 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
913 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
914 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
917 return FR_SUCCESS;
918 }
919
920 bool added_attachment = false;
921 for (int i = 0; i < m_attach_new->msg_count; i++)
922 {
923 if (!m_attach_new->emails[i])
924 break;
925 if (!message_is_tagged(m_attach_new->emails[i]))
926 continue;
927
928 struct AttachPtr *ap = mutt_aptr_new();
929 ap->body = mutt_make_message_attach(m_attach_new, m_attach_new->emails[i],
930 true, shared->sub);
931 if (ap->body)
932 {
933 added_attachment = true;
934 update_idx(shared->adata->menu, shared->adata->actx, ap);
935 }
936 else
937 {
938 mutt_error(_("Unable to attach"));
939 mutt_aptr_free(&ap);
940 }
941 }
943
944 if (m_attach_new == m_attach)
945 {
946 m_attach->readonly = old_readonly;
947 }
948 mx_fastclose_mailbox(m_attach_new, false);
949
950 /* Restore old $sort variables */
951 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
952 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
953 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
955 if (added_attachment)
957 return FR_SUCCESS;
958}
959
963static int op_attachment_detach(struct ComposeSharedData *shared, int op)
964{
965 struct AttachCtx *actx = shared->adata->actx;
966 if (!check_count(actx))
967 return FR_NO_ACTION;
968
969 struct Menu *menu = shared->adata->menu;
970 struct AttachPtr *cur_att = current_attachment(actx, menu);
971 if (cur_att->unowned)
972 cur_att->body->unlink = false;
973
974 int index = menu_get_index(menu);
975 if (delete_attachment(actx, index) == -1)
976 return FR_ERROR;
977
978 menu->num_tagged = 0;
979 for (int i = 0; i < actx->idxlen; i++)
980 {
981 if (actx->idx[i]->body->tagged)
982 menu->num_tagged++;
983 }
984
985 update_menu(actx, menu, false);
987
988 index = menu_get_index(menu);
989 if (index == 0)
990 shared->email->body = actx->idx[0]->body;
991
993 return FR_SUCCESS;
994}
995
999static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
1000{
1001 if (!check_count(shared->adata->actx))
1002 return FR_NO_ACTION;
1003
1004 int rc = FR_NO_ACTION;
1005 struct Buffer *buf = buf_pool_get();
1006 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1007 shared->adata->menu);
1008
1009 char *id = mutt_param_get(&cur_att->body->parameter, "content-id");
1010 if (id)
1011 {
1012 buf_strcpy(buf, id);
1013 }
1014 else
1015 {
1016 id = gen_cid();
1017 buf_strcpy(buf, id);
1018 FREE(&id);
1019 }
1020
1021 if (mw_get_field("Content-ID: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1022 {
1023 if (!mutt_str_equal(id, buf_string(buf)))
1024 {
1025 if (check_cid(buf_string(buf)))
1026 {
1027 mutt_param_set(&cur_att->body->parameter, "content-id", buf_string(buf));
1030 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1031 rc = FR_SUCCESS;
1032 }
1033 else
1034 {
1035 mutt_error(_("Content-ID can only contain the characters: -.0-9@A-Z_a-z"));
1036 rc = FR_ERROR;
1037 }
1038 }
1039 }
1040
1041 buf_pool_release(&buf);
1042
1043 if (rc != FR_ERROR)
1045
1046 return rc;
1047}
1048
1052static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
1053{
1054 if (!check_count(shared->adata->actx))
1055 return FR_NO_ACTION;
1056
1057 int rc = FR_NO_ACTION;
1058 struct Buffer *buf = buf_pool_get();
1059
1060 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1061 shared->adata->menu);
1062 buf_strcpy(buf, cur_att->body->description);
1063
1064 /* header names should not be translated */
1065 if (mw_get_field("Description: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1066 {
1067 if (!mutt_str_equal(cur_att->body->description, buf_string(buf)))
1068 {
1069 mutt_str_replace(&cur_att->body->description, buf_string(buf));
1071 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1072 rc = FR_SUCCESS;
1073 }
1074 }
1075
1076 buf_pool_release(&buf);
1077 return rc;
1078}
1079
1083static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
1084{
1085 if (!check_count(shared->adata->actx))
1086 return FR_NO_ACTION;
1087
1088 int rc = FR_NO_ACTION;
1089 struct Buffer *buf = buf_pool_get();
1090
1091 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1092 shared->adata->menu);
1093 buf_strcpy(buf, ENCODING(cur_att->body->encoding));
1094
1095 if ((mw_get_field("Content-Transfer-Encoding: ", buf, MUTT_COMP_NO_FLAGS,
1096 HC_OTHER, NULL, NULL) == 0) &&
1097 !buf_is_empty(buf))
1098 {
1099 int enc = mutt_check_encoding(buf_string(buf));
1100 if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1101 {
1102 if (enc != cur_att->body->encoding)
1103 {
1104 cur_att->body->encoding = enc;
1108 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1109 rc = FR_SUCCESS;
1110 }
1111 }
1112 else
1113 {
1114 mutt_error(_("Invalid encoding"));
1115 rc = FR_ERROR;
1116 }
1117 }
1118
1119 buf_pool_release(&buf);
1120 return rc;
1121}
1122
1126static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
1127{
1128 if (!check_count(shared->adata->actx))
1129 return FR_NO_ACTION;
1130
1131 int rc = FR_NO_ACTION;
1132 struct Buffer *buf = buf_pool_get();
1133 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1134 shared->adata->menu);
1135
1136 buf_strcpy(buf, cur_att->body->language);
1137 if (mw_get_field("Content-Language: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1138 {
1139 if (!mutt_str_equal(cur_att->body->language, buf_string(buf)))
1140 {
1141 mutt_str_replace(&cur_att->body->language, buf_string(buf));
1144 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1145 rc = FR_SUCCESS;
1146 }
1148 }
1149 else
1150 {
1151 mutt_warning(_("Empty 'Content-Language'"));
1152 rc = FR_ERROR;
1153 }
1154
1155 buf_pool_release(&buf);
1156 return rc;
1157}
1158
1162static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
1163{
1164 if (!check_count(shared->adata->actx))
1165 return FR_NO_ACTION;
1166 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1167 shared->adata->menu);
1168 if (!mutt_edit_attachment(cur_att->body))
1169 return FR_NO_ACTION;
1170
1171 mutt_update_encoding(cur_att->body, shared->sub);
1173 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1174 return FR_SUCCESS;
1175}
1176
1180static int op_attachment_edit_type(struct ComposeSharedData *shared, int op)
1181{
1182 if (!check_count(shared->adata->actx))
1183 return FR_NO_ACTION;
1184
1185 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1186 shared->adata->menu);
1187 if (!mutt_edit_content_type(NULL, cur_att->body, NULL))
1188 return FR_NO_ACTION;
1189
1190 /* this may have been a change to text/something */
1191 mutt_update_encoding(cur_att->body, shared->sub);
1193 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1194 return FR_SUCCESS;
1195}
1196
1204static int op_attachment_filter(struct ComposeSharedData *shared, int op)
1205{
1206 struct AttachCtx *actx = shared->adata->actx;
1207 if (!check_count(actx))
1208 return FR_NO_ACTION;
1209
1210 struct Menu *menu = shared->adata->menu;
1211 struct AttachPtr *cur_att = current_attachment(actx, menu);
1212 if (cur_att->body->type == TYPE_MULTIPART)
1213 {
1214 mutt_error(_("Can't filter multipart attachments"));
1215 return FR_ERROR;
1216 }
1217 mutt_pipe_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body,
1218 (op == OP_ATTACHMENT_FILTER));
1219 if (op == OP_ATTACHMENT_FILTER) /* cte might have changed */
1220 {
1222 }
1224 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1225 return FR_SUCCESS;
1226}
1227
1231static int op_attachment_get_attachment(struct ComposeSharedData *shared, int op)
1232{
1233 struct AttachCtx *actx = shared->adata->actx;
1234 if (!check_count(actx))
1235 return FR_NO_ACTION;
1236
1237 int rc = FR_ERROR;
1238 struct Menu *menu = shared->adata->menu;
1239 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1240 ba_add_tagged(&ba, actx, menu);
1241 if (ARRAY_EMPTY(&ba))
1242 goto done;
1243
1244 struct Body **bp = NULL;
1245 ARRAY_FOREACH(bp, &ba)
1246 {
1247 if ((*bp)->type == TYPE_MULTIPART)
1248 {
1249 mutt_warning(_("Can't get multipart attachments"));
1250 continue;
1251 }
1253 }
1254
1256 rc = FR_SUCCESS;
1257
1258done:
1259 ARRAY_FREE(&ba);
1260 /* No send2hook since this doesn't change the message. */
1261 return rc;
1262}
1263
1267static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
1268{
1269 if (shared->adata->menu->num_tagged < 2)
1270 {
1271 mutt_error(_("Grouping 'alternatives' requires at least 2 tagged messages"));
1272 return FR_ERROR;
1273 }
1274
1275 return group_attachments(shared, "alternative");
1276}
1277
1281static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
1282{
1283 if (shared->adata->menu->num_tagged < 2)
1284 {
1285 mutt_error(_("Grouping 'multilingual' requires at least 2 tagged messages"));
1286 return FR_ERROR;
1287 }
1288
1289 /* traverse to see whether all the parts have Content-Language: set */
1290 int tagged_with_lang_num = 0;
1291 for (struct Body *b = shared->email->body; b; b = b->next)
1292 if (b->tagged && b->language && *b->language)
1293 tagged_with_lang_num++;
1294
1295 if (shared->adata->menu->num_tagged != tagged_with_lang_num)
1296 {
1297 if (query_yesorno(_("Not all parts have 'Content-Language' set, continue?"),
1298 MUTT_YES) != MUTT_YES)
1299 {
1300 mutt_message(_("Not sending this message"));
1301 return FR_ERROR;
1302 }
1303 }
1304
1305 return group_attachments(shared, "multilingual");
1306}
1307
1311static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
1312{
1313 if (shared->adata->menu->num_tagged < 2)
1314 {
1315 mutt_error(_("Grouping 'related' requires at least 2 tagged messages"));
1316 return FR_ERROR;
1317 }
1318
1319 // ensure Content-ID is set for tagged attachments
1320 for (struct Body *b = shared->email->body; b; b = b->next)
1321 {
1322 if (!b->tagged || (b->type == TYPE_MULTIPART))
1323 continue;
1324
1325 char *id = mutt_param_get(&b->parameter, "content-id");
1326 if (id)
1327 continue;
1328
1329 id = gen_cid();
1330 if (id)
1331 {
1332 mutt_param_set(&b->parameter, "content-id", id);
1333 FREE(&id);
1334 }
1335 }
1336
1337 return group_attachments(shared, "related");
1338}
1339
1343static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
1344{
1345 int index = menu_get_index(shared->adata->menu);
1346
1347 struct AttachCtx *actx = shared->adata->actx;
1348
1349 if (index < 0)
1350 return FR_ERROR;
1351
1352 if (index == (actx->idxlen - 1))
1353 {
1354 mutt_error(_("Attachment is already at bottom"));
1355 return FR_NO_ACTION;
1356 }
1357 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1358 !actx->idx[index]->body->next)
1359 {
1360 mutt_error(_("Attachment can't be moved out of group"));
1361 return FR_ERROR;
1362 }
1363
1364 // find next attachment at current level
1365 int nextidx = index + 1;
1366 while ((nextidx < actx->idxlen) &&
1367 (actx->idx[nextidx]->level > actx->idx[index]->level))
1368 {
1369 nextidx++;
1370 }
1371 if (nextidx == actx->idxlen)
1372 {
1373 mutt_error(_("Attachment is already at bottom"));
1374 return FR_NO_ACTION;
1375 }
1376
1377 // find final position
1378 int finalidx = index + 1;
1379 if (nextidx < actx->idxlen - 1)
1380 {
1381 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1382 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1383 {
1384 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1385 }
1386 }
1387
1388 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1389 mutt_update_tree(shared->adata->actx);
1391 menu_set_index(shared->adata->menu, finalidx);
1392 return FR_SUCCESS;
1393}
1394
1398static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
1399{
1400 int index = menu_get_index(shared->adata->menu);
1401 if (index < 0)
1402 return FR_ERROR;
1403
1404 struct AttachCtx *actx = shared->adata->actx;
1405
1406 if (index == 0)
1407 {
1408 mutt_error(_("Attachment is already at top"));
1409 return FR_NO_ACTION;
1410 }
1411 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1412 {
1413 mutt_error(_("Attachment can't be moved out of group"));
1414 return FR_ERROR;
1415 }
1416
1417 // find previous attachment at current level
1418 int previdx = index - 1;
1419 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1420 previdx--;
1421
1422 compose_attach_swap(shared->email, actx, previdx, index);
1423 mutt_update_tree(actx);
1425 menu_set_index(shared->adata->menu, previdx);
1426 return FR_SUCCESS;
1427}
1428
1432static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
1433{
1434 int rc = FR_NO_ACTION;
1435 struct Buffer *fname = buf_pool_get();
1436 struct Buffer *type = NULL;
1437 struct AttachPtr *ap = NULL;
1438
1439 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1440 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1441 &CompleteFileOps, &cdata) != 0) ||
1442 buf_is_empty(fname))
1443 {
1444 goto done;
1445 }
1446 buf_expand_path(fname);
1447
1448 /* Call to lookup_mime_type () ? maybe later */
1449 type = buf_pool_get();
1450 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1451 buf_is_empty(type))
1452 {
1453 goto done;
1454 }
1455
1456 rc = FR_ERROR;
1457 char *p = strchr(buf_string(type), '/');
1458 if (!p)
1459 {
1460 mutt_error(_("Content-Type is of the form base/sub"));
1461 goto done;
1462 }
1463 *p++ = 0;
1464 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1465 if (itype == TYPE_OTHER)
1466 {
1467 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1468 goto done;
1469 }
1470
1471 ap = mutt_aptr_new();
1472 /* Touch the file */
1473 FILE *fp = mutt_file_fopen(buf_string(fname), "w");
1474 if (!fp)
1475 {
1476 mutt_error(_("Can't create file %s"), buf_string(fname));
1477 goto done;
1478 }
1479 mutt_file_fclose(&fp);
1480
1481 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1482 if (!ap->body)
1483 {
1484 mutt_error(_("Error attaching file"));
1485 goto done;
1486 }
1487 update_idx(shared->adata->menu, shared->adata->actx, ap);
1488 ap = NULL; // shared->adata->actx has taken ownership
1489
1490 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1491 shared->adata->menu);
1492 cur_att->body->type = itype;
1493 mutt_str_replace(&cur_att->body->subtype, p);
1494 cur_att->body->unlink = true;
1497
1498 if (mutt_compose_attachment(cur_att->body))
1499 {
1500 mutt_update_encoding(cur_att->body, shared->sub);
1502 }
1503 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1504 rc = FR_SUCCESS;
1505
1506done:
1507 mutt_aptr_free(&ap);
1508 buf_pool_release(&type);
1509 buf_pool_release(&fname);
1510 return rc;
1511}
1512
1516static int op_attachment_print(struct ComposeSharedData *shared, int op)
1517{
1518 struct AttachCtx *actx = shared->adata->actx;
1519 if (!check_count(actx))
1520 return FR_NO_ACTION;
1521
1522 struct Menu *menu = shared->adata->menu;
1523 struct AttachPtr *cur_att = current_attachment(actx, menu);
1524 if (cur_att->body->type == TYPE_MULTIPART)
1525 {
1526 mutt_error(_("Can't print multipart attachments"));
1527 return FR_ERROR;
1528 }
1529
1530 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1531 /* no send2hook, since this doesn't modify the message */
1532 return FR_SUCCESS;
1533}
1534
1538static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
1539{
1540 if (!check_count(shared->adata->actx))
1541 return FR_NO_ACTION;
1542 char *src = NULL;
1543 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1544 shared->adata->menu);
1545 if (cur_att->body->d_filename)
1546 src = cur_att->body->d_filename;
1547 else
1548 src = cur_att->body->filename;
1549 struct Buffer *fname = buf_pool_get();
1550 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1551 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1552 int rc = mw_get_field(_("Send attachment with name: "), fname,
1554 if (rc == 0)
1555 {
1556 // It's valid to set an empty string here, to erase what was set
1557 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1559 }
1560 buf_pool_release(&fname);
1561 return FR_SUCCESS;
1562}
1563
1567static int op_attachment_save(struct ComposeSharedData *shared, int op)
1568{
1569 struct AttachCtx *actx = shared->adata->actx;
1570 if (!check_count(actx))
1571 return FR_NO_ACTION;
1572
1573 struct Menu *menu = shared->adata->menu;
1574 struct AttachPtr *cur_att = current_attachment(actx, menu);
1575 if (cur_att->body->type == TYPE_MULTIPART)
1576 {
1577 mutt_error(_("Can't save multipart attachments"));
1578 return FR_ERROR;
1579 }
1580
1581 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1582 /* no send2hook, since this doesn't modify the message */
1583 return FR_SUCCESS;
1584}
1585
1589static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
1590{
1591 /* toggle the content-disposition between inline/attachment */
1592 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1593 shared->adata->menu);
1594 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1595 DISP_ATTACH :
1598 return FR_SUCCESS;
1599}
1600
1604static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
1605{
1606 if (!check_count(shared->adata->actx))
1607 return FR_NO_ACTION;
1608 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1609 shared->adata->menu);
1610 if (!mutt_is_text_part(cur_att->body))
1611 {
1612 mutt_error(_("Recoding only affects text attachments"));
1613 return FR_ERROR;
1614 }
1615 cur_att->body->noconv = !cur_att->body->noconv;
1616 if (cur_att->body->noconv)
1617 mutt_message(_("The current attachment won't be converted"));
1618 else
1619 mutt_message(_("The current attachment will be converted"));
1621 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1622 return FR_SUCCESS;
1623}
1624
1628static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
1629{
1630 if (!check_count(shared->adata->actx))
1631 return FR_NO_ACTION;
1632 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1633 shared->adata->menu);
1634 cur_att->body->unlink = !cur_att->body->unlink;
1635
1637 /* No send2hook since this doesn't change the message. */
1638 return FR_SUCCESS;
1639}
1640
1644static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
1645{
1646 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1647 {
1648 mutt_error(_("Attachment is not 'multipart'"));
1649 return FR_ERROR;
1650 }
1651
1652 int aidx = shared->adata->menu->current;
1653 struct AttachCtx *actx = shared->adata->actx;
1654 struct Body *b = actx->idx[aidx]->body;
1655 struct Body *b_next = b->next;
1656 struct Body *b_previous = NULL;
1657 struct Body *b_parent = NULL;
1658 int parent_type = actx->idx[aidx]->parent_type;
1659 int level = actx->idx[aidx]->level;
1660
1661 // reorder body pointers
1662 if (attach_body_previous(shared->email->body, b, &b_previous))
1663 b_previous->next = b->parts;
1664 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1665 b_parent->parts = b->parts;
1666 else
1667 shared->email->body = b->parts;
1668
1669 // update attachment list
1670 int i = aidx + 1;
1671 while (actx->idx[i]->level > level)
1672 {
1673 actx->idx[i]->level--;
1674 if (actx->idx[i]->level == level)
1675 {
1676 actx->idx[i]->parent_type = parent_type;
1677 // set body->next for final attachment in group
1678 if (!actx->idx[i]->body->next)
1679 actx->idx[i]->body->next = b_next;
1680 }
1681 i++;
1682 if (i == actx->idxlen)
1683 break;
1684 }
1685
1686 // free memory
1687 actx->idx[aidx]->body->parts = NULL;
1688 actx->idx[aidx]->body->next = NULL;
1689 actx->idx[aidx]->body->email = NULL;
1690 mutt_body_free(&actx->idx[aidx]->body);
1691 FREE(&actx->idx[aidx]->tree);
1692 FREE(&actx->idx[aidx]);
1693
1694 // reorder attachment list
1695 for (int j = aidx; j < (actx->idxlen - 1); j++)
1696 actx->idx[j] = actx->idx[j + 1];
1697 actx->idx[actx->idxlen - 1] = NULL;
1698 actx->idxlen--;
1699 update_menu(actx, shared->adata->menu, false);
1700
1701 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1702 return FR_SUCCESS;
1703}
1704
1708static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
1709{
1710 struct AttachCtx *actx = shared->adata->actx;
1711 if (!check_count(actx))
1712 return FR_NO_ACTION;
1713
1714 int rc = FR_NO_ACTION;
1715 struct Menu *menu = shared->adata->menu;
1716 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1717 ba_add_tagged(&ba, actx, menu);
1718 if (ARRAY_EMPTY(&ba))
1719 goto done;
1720
1721 struct Body **bp = NULL;
1722 ARRAY_FOREACH(bp, &ba)
1723 {
1724 mutt_update_encoding(*bp, shared->sub);
1725 }
1726
1729 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1730 rc = FR_SUCCESS;
1731
1732done:
1733 ARRAY_FREE(&ba);
1734 return rc;
1735}
1736
1737// -----------------------------------------------------------------------------
1738
1742static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
1743{
1745 const char *tag = NULL;
1746 char *err = NULL;
1747 mutt_env_to_local(shared->email->env);
1748 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1749 if (shared->email->body->type == TYPE_MULTIPART)
1750 {
1751 struct Body *b = shared->email->body->parts;
1752 while (b->parts)
1753 b = b->parts;
1754 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1755 }
1756 else
1757 {
1758 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1759 shared->email, shared->fcc);
1760 }
1761
1762 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1763 {
1764 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1765 FREE(&err);
1766 }
1768
1770 mutt_update_encoding(shared->email->body, shared->sub);
1771
1772 /* attachments may have been added */
1773 if (shared->adata->actx->idxlen &&
1774 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1775 {
1777 update_menu(shared->adata->actx, shared->adata->menu, true);
1778 }
1779
1781 /* Unconditional hook since editor was invoked */
1782 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1783 return FR_SUCCESS;
1784}
1785
1789static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
1790{
1791 if (!check_count(shared->adata->actx))
1792 return FR_NO_ACTION;
1793 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1794 shared->adata->menu);
1795 if (cur_att->body->type == TYPE_MULTIPART)
1796 {
1797 mutt_error(_("Can't edit multipart attachments"));
1798 return FR_ERROR;
1799 }
1800 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1801 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1802 mutt_update_encoding(cur_att->body, shared->sub);
1805 /* Unconditional hook since editor was invoked */
1806 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1807 return FR_SUCCESS;
1808}
1809
1813static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
1814{
1815 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1816 if (!c_edit_headers)
1817 {
1819 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1820 mutt_edit_file(c_editor, shared->email->body->filename);
1822 mutt_update_encoding(shared->email->body, shared->sub);
1824 /* Unconditional hook since editor was invoked */
1825 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1826 return FR_SUCCESS;
1827 }
1828
1829 return op_envelope_edit_headers(shared, op);
1830}
1831
1835static int op_compose_ispell(struct ComposeSharedData *shared, int op)
1836{
1837 endwin();
1838 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1839 char buf[PATH_MAX] = { 0 };
1840 snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), shared->email->body->filename);
1841 if (mutt_system(buf) == -1)
1842 {
1843 mutt_error(_("Error running \"%s\""), buf);
1844 return FR_ERROR;
1845 }
1846
1847 mutt_update_encoding(shared->email->body, shared->sub);
1849 return FR_SUCCESS;
1850}
1851
1855static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
1856{
1857 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1858 {
1860 return FR_ERROR;
1861 }
1862
1863 shared->rc = 1;
1864 return FR_DONE;
1865}
1866
1870static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
1871{
1872 if (!check_count(shared->adata->actx))
1873 return FR_NO_ACTION;
1874 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1875 shared->adata->menu);
1876 if (cur_att->body->type == TYPE_MULTIPART)
1877 {
1878 mutt_error(_("Can't rename multipart attachments"));
1879 return FR_ERROR;
1880 }
1881 struct Buffer *fname = buf_pool_get();
1882 buf_strcpy(fname, cur_att->body->filename);
1883 buf_pretty_mailbox(fname);
1884 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1885 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1886 &CompleteFileOps, &cdata) == 0) &&
1887 !buf_is_empty(fname))
1888 {
1889 struct stat st = { 0 };
1890 if (stat(cur_att->body->filename, &st) == -1)
1891 {
1892 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1893 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1894 buf_pool_release(&fname);
1895 return FR_ERROR;
1896 }
1897
1898 buf_expand_path(fname);
1899 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1900 {
1901 buf_pool_release(&fname);
1902 return FR_ERROR;
1903 }
1904
1905 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1907
1908 if (cur_att->body->stamp >= st.st_mtime)
1909 mutt_stamp_attachment(cur_att->body);
1910 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1911 }
1912 buf_pool_release(&fname);
1913 return FR_SUCCESS;
1914}
1915
1919static int op_compose_send_message(struct ComposeSharedData *shared, int op)
1920{
1921 /* Note: We don't invoke send2-hook here, since we want to leave
1922 * users an opportunity to change settings from the ":" prompt. */
1923 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1924 {
1926 return FR_NO_ACTION;
1927 }
1928
1929#ifdef MIXMASTER
1930 if (!STAILQ_EMPTY(&shared->email->chain) && (mix_check_message(shared->email) != 0))
1931 return FR_NO_ACTION;
1932#endif
1933
1934 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1935 {
1936 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1937 shared->sub, "copy");
1938 if (ans == MUTT_ABORT)
1939 return FR_NO_ACTION;
1940 else if (ans == MUTT_NO)
1941 buf_reset(shared->fcc);
1942 }
1943
1944 shared->rc = 0;
1945 return FR_DONE;
1946}
1947
1951static int op_compose_write_message(struct ComposeSharedData *shared, int op)
1952{
1953 int rc = FR_NO_ACTION;
1954 struct Buffer *fname = buf_pool_get();
1955 if (shared->mailbox)
1956 {
1957 buf_strcpy(fname, mailbox_path(shared->mailbox));
1958 buf_pretty_mailbox(fname);
1959 }
1960 if (shared->adata->actx->idxlen)
1961 shared->email->body = shared->adata->actx->idx[0]->body;
1962 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
1963 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1964 !buf_is_empty(fname))
1965 {
1966 mutt_message(_("Writing message to %s ..."), buf_string(fname));
1967 buf_expand_path(fname);
1968
1969 if (shared->email->body->next)
1970 shared->email->body = mutt_make_multipart(shared->email->body);
1971
1972 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
1973 NULL, shared->sub) == 0)
1974 mutt_message(_("Message written"));
1975
1976 shared->email->body = mutt_remove_multipart(shared->email->body);
1977 rc = FR_SUCCESS;
1978 }
1979 buf_pool_release(&fname);
1980 return rc;
1981}
1982
1990static int op_display_headers(struct ComposeSharedData *shared, int op)
1991{
1992 if (!check_count(shared->adata->actx))
1993 return FR_NO_ACTION;
1994 mutt_attach_display_loop(shared->sub, shared->adata->menu, op, shared->email,
1995 shared->adata->actx, false);
1997 /* no send2hook, since this doesn't modify the message */
1998 return FR_SUCCESS;
1999}
2000
2004static int op_exit(struct ComposeSharedData *shared, int op)
2005{
2006 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2007 shared->sub, "postpone");
2008 if (ans == MUTT_NO)
2009 {
2010 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2011 if (shared->adata->actx->idx[i]->unowned)
2012 shared->adata->actx->idx[i]->body->unlink = false;
2013
2014 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2015 {
2016 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2017 {
2018 /* avoid freeing other attachments */
2019 shared->adata->actx->idx[i]->body->next = NULL;
2020 if (!shared->adata->actx->idx[i]->body->email)
2021 shared->adata->actx->idx[i]->body->parts = NULL;
2022 mutt_body_free(&shared->adata->actx->idx[i]->body);
2023 }
2024 }
2025 shared->rc = -1;
2026 return FR_DONE;
2027 }
2028 else if (ans == MUTT_ABORT)
2029 {
2030 return FR_NO_ACTION;
2031 }
2032
2033 return op_compose_postpone_message(shared, op);
2034}
2035
2039static int op_forget_passphrase(struct ComposeSharedData *shared, int op)
2040{
2042 return FR_SUCCESS;
2043}
2044
2045// -----------------------------------------------------------------------------
2046
2050static const struct ComposeFunction ComposeFunctions[] = {
2051 // clang-format off
2052 { OP_ATTACHMENT_ATTACH_FILE, op_attachment_attach_file },
2053 { OP_ATTACHMENT_ATTACH_KEY, op_attachment_attach_key },
2054 { OP_ATTACHMENT_ATTACH_MESSAGE, op_attachment_attach_message },
2055 { OP_ATTACHMENT_ATTACH_NEWS_MESSAGE, op_attachment_attach_message },
2056 { OP_ATTACHMENT_DETACH, op_attachment_detach },
2057 { OP_ATTACHMENT_EDIT_CONTENT_ID, op_attachment_edit_content_id },
2058 { OP_ATTACHMENT_EDIT_DESCRIPTION, op_attachment_edit_description },
2059 { OP_ATTACHMENT_EDIT_ENCODING, op_attachment_edit_encoding },
2060 { OP_ATTACHMENT_EDIT_LANGUAGE, op_attachment_edit_language },
2061 { OP_ATTACHMENT_EDIT_MIME, op_attachment_edit_mime },
2062 { OP_ATTACHMENT_EDIT_TYPE, op_attachment_edit_type },
2063 { OP_ATTACHMENT_FILTER, op_attachment_filter },
2064 { OP_ATTACHMENT_GET_ATTACHMENT, op_attachment_get_attachment },
2065 { OP_ATTACHMENT_GROUP_ALTS, op_attachment_group_alts },
2066 { OP_ATTACHMENT_GROUP_LINGUAL, op_attachment_group_lingual },
2067 { OP_ATTACHMENT_GROUP_RELATED, op_attachment_group_related },
2068 { OP_ATTACHMENT_MOVE_DOWN, op_attachment_move_down },
2069 { OP_ATTACHMENT_MOVE_UP, op_attachment_move_up },
2070 { OP_ATTACHMENT_NEW_MIME, op_attachment_new_mime },
2071 { OP_PIPE, op_attachment_filter },
2072 { OP_ATTACHMENT_PRINT, op_attachment_print },
2073 { OP_ATTACHMENT_RENAME_ATTACHMENT, op_attachment_rename_attachment },
2074 { OP_ATTACHMENT_SAVE, op_attachment_save },
2075 { OP_ATTACHMENT_TOGGLE_DISPOSITION, op_attachment_toggle_disposition },
2076 { OP_ATTACHMENT_TOGGLE_RECODE, op_attachment_toggle_recode },
2077 { OP_ATTACHMENT_TOGGLE_UNLINK, op_attachment_toggle_unlink },
2078 { OP_ATTACHMENT_UNGROUP, op_attachment_ungroup },
2079 { OP_ATTACHMENT_UPDATE_ENCODING, op_attachment_update_encoding },
2080 { OP_ATTACHMENT_VIEW, op_display_headers },
2081 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2082 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2083 { OP_COMPOSE_ISPELL, op_compose_ispell },
2084 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2085 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2086 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2087 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2088 { OP_DISPLAY_HEADERS, op_display_headers },
2089 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2090 { OP_EXIT, op_exit },
2091 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2092 { 0, NULL },
2093 // clang-format on
2094};
2095
2100{
2101 if (!win)
2102 return FR_UNKNOWN;
2103
2104 struct MuttWindow *dlg = dialog_find(win);
2105 if (!dlg || !dlg->wdata)
2106 return FR_UNKNOWN;
2107
2108 int rc = FR_UNKNOWN;
2109 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2110 {
2111 const struct ComposeFunction *fn = &ComposeFunctions[i];
2112 if (fn->op == op)
2113 {
2114 struct ComposeSharedData *shared = dlg->wdata;
2115 rc = fn->function(shared, op);
2116 break;
2117 }
2118 }
2119
2120 if (rc == FR_UNKNOWN) // Not our function
2121 return rc;
2122
2123 const char *result = dispatcher_get_retval_name(rc);
2124 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2125
2126 return rc;
2127}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:57
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:173
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition: functions.c:223
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition: functions.c:2050
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition: functions.c:88
static int group_attachments(struct ComposeSharedData *shared, char *subtype)
Group tagged attachments into a multipart group.
Definition: functions.c:504
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attachment to the message.
Definition: functions.c:413
static char * gen_cid(void)
Generate a random Content ID.
Definition: functions.c:240
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:438
static bool check_cid(const char *cid)
Check if a Content-ID is valid.
Definition: functions.c:256
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition: functions.c:276
const struct MenuOpSeq ComposeDefaultBindings[]
Key bindings for the Compose Menu.
Definition: functions.c:157
static int delete_attachment(struct AttachCtx *actx, int aidx)
Delete an attachment.
Definition: functions.c:339
#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:292
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:72
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:267
Convenience wrapper for the config headers.
Connection Library.
Convenience wrapper for the core headers.
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:305
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:113
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:219
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1391
Edit a string.
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Structs that make up an email.
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:325
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:396
@ NT_EMAIL_CHANGE_ATTACH
Email's Attachments have changed.
Definition: email.h:154
@ NT_EMAIL_CHANGE_ENVELOPE
Email's Envelope has changed.
Definition: email.h:153
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:326
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition: envelope.c:288
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: external.c:1072
Manage where the email is piped to external commands.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1412
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:75
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition: functions.c:190
static int op_attachment_print(struct AttachPrivateData *priv, int op)
print the current entry - Implements attach_function_t -
Definition: functions.c:365
static int op_attachment_edit_type(struct AttachPrivateData *priv, int op)
edit attachment content type - Implements attach_function_t -
Definition: functions.c:344
static int op_forget_passphrase(struct AttachPrivateData *priv, int op)
wipe passphrases from memory - Implements attach_function_t -
Definition: functions.c:554
static int op_attachment_save(struct AttachPrivateData *priv, int op)
save message/attachment to a mailbox/file - Implements attach_function_t -
Definition: functions.c:376
static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/multilingual' - Implements compose_function_t -.
Definition: functions.c:1281
static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
Definition: functions.c:1267
static int op_attachment_filter(struct ComposeSharedData *shared, int op)
Filter attachment through a shell command - Implements compose_function_t -.
Definition: functions.c:1204
static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
Rename/move an attached file - Implements compose_function_t -.
Definition: functions.c:1870
static int op_compose_ispell(struct ComposeSharedData *shared, int op)
Run ispell on the message - Implements compose_function_t -.
Definition: functions.c:1835
static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
Edit attachment description - Implements compose_function_t -.
Definition: functions.c:1052
static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
Definition: functions.c:1311
static int op_display_headers(struct ComposeSharedData *shared, int op)
Display message and toggle header weeding - Implements compose_function_t -.
Definition: functions.c:1990
static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
Attach a PGP public key - Implements compose_function_t -.
Definition: functions.c:787
static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
Edit the file to be attached - Implements compose_function_t -.
Definition: functions.c:1789
static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
Send attachment with a different name - Implements compose_function_t -.
Definition: functions.c:1538
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:1343
static int op_compose_send_message(struct ComposeSharedData *shared, int op)
Send the message - Implements compose_function_t -.
Definition: functions.c:1919
static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
Attach files to this message - Implements compose_function_t -.
Definition: functions.c:722
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:1628
static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition: functions.c:1604
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:1398
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:1126
static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
Edit the message with headers - Implements compose_function_t -.
Definition: functions.c:1742
static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition: functions.c:1589
static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
Edit attachment transfer-encoding - Implements compose_function_t -.
Definition: functions.c:1083
static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
Update an attachment's encoding info - Implements compose_function_t -.
Definition: functions.c:1708
static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
Attach messages to this message - Implements compose_function_t -.
Definition: functions.c:815
static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
Ungroup a 'multipart' attachment - Implements compose_function_t -.
Definition: functions.c:1644
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:999
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:1231
static int op_compose_write_message(struct ComposeSharedData *shared, int op)
Write the message to a folder - Implements compose_function_t -.
Definition: functions.c:1951
static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
Edit attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1162
static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
Edit the message - Implements compose_function_t -.
Definition: functions.c:1813
static int op_attachment_detach(struct ComposeSharedData *shared, int op)
Delete the current entry - Implements compose_function_t -.
Definition: functions.c:963
static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
Save this message to send later - Implements compose_function_t -.
Definition: functions.c:1855
static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1432
int compose_function_dispatcher(struct MuttWindow *win, int op)
Perform a Compose function - Implements function_dispatcher_t -.
Definition: functions.c:2099
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1057
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:247
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:275
#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:2738
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:2327
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:666
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
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:210
@ 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
#define FREE(x)
Definition: memory.h:45
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:60
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:57
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:180
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:156
#define MENU_REDRAW_CURRENT
Redraw the current line of the menu.
Definition: lib.h:59
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:170
@ 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
Support of Mixmaster anonymous remailer.
int mix_check_message(struct Email *e)
Safety-check the message before passing it to mixmaster.
Definition: mixmaster.c:50
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:278
struct Regex * mutt_regex_new(const char *str, uint32_t flags, struct Buffer *err)
Create an Regex from a string.
Definition: regex.c:76
void mutt_regex_free(struct Regex **ptr)
Free a Regex object.
Definition: regex.c:114
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:636
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
#define PATH_MAX
Definition: mutt.h:41
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
Definition: mutt_attach.c:261
int mutt_get_tmp_attachment(struct Body *b)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:68
int mutt_compose_attachment(struct Body *b)
Create an attachment.
Definition: mutt_attach.c:116
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:427
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:956
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:719
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition: recvattach.c:882
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:179
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
NeoMutt Logging.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:202
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:556
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:444
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:329
Some miscellaneous functions.
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: mview.c:363
View of a Mailbox.
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:410
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:284
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1326
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1652
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:593
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:91
#define WithCrypto
Definition: lib.h:117
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:564
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:1021
@ 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
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
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:50
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_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:369
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:330
#define STAILQ_EMPTY(head)
Definition: queue.h:348
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:104
struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: recvattach.c:71
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:116
int ba_add_tagged(struct BodyArray *ba, struct AttachCtx *actx, struct Menu *menu)
Get an array of tagged Attachments.
Definition: recvattach.c:1235
void mutt_rfc3676_space_unstuff(struct Email *e)
Remove RFC3676 space stuffing.
Definition: rfc3676.c:496
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition: rfc3676.c:483
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:420
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:605
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:452
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:1051
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:408
#define MUTT_RANDTAG_LEN
Definition: sendlib.h:35
Sidebar functions.
GUI display the mailboxes in a side panel.
SortType
Methods for sorting.
Definition: sort2.h:38
Key value store.
#define NONULL(x)
Definition: string2.h:37
A set of attachments.
Definition: attach.h:51
short vcount
The number of virtual attachments.
Definition: attach.h:60
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:55
short idxlen
Number of attachmentes.
Definition: attach.h:56
An email to which things will be attached.
Definition: attach.h:35
struct Body * body
Attachment.
Definition: attach.h:36
char * tree
Tree characters to display.
Definition: attach.h:39
int level
Nesting depth of attachment.
Definition: attach.h:40
bool unowned
Don't unlink on detach.
Definition: attach.h:42
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
The body of an email.
Definition: body.h:36
char * language
content-language (RFC8255)
Definition: body.h:77
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:72
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:67
time_t stamp
Time stamp of last encoding update.
Definition: body.h:76
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
struct Email * email
header information for message/rfc822
Definition: body.h:73
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:89
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
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:58
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
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:50
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
struct ListHead chain
Mixmaster chain.
Definition: email.h:91
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:71
Input for the file completion function.
Definition: curs_lib.h:39
Data shared between Index, Pager and Sidebar.
Definition: shared_data.h:37
bool attach_msg
Are we in "attach message" mode?
Definition: shared_data.h:46
A mailbox.
Definition: mailbox.h:79
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
bool readonly
Don't allow changes to the mailbox.
Definition: mailbox.h:115
Mapping between a function and an operation.
Definition: lib.h:102
Mapping between an operation and a key sequence.
Definition: lib.h:111
Definition: lib.h:70
int current
Current entry.
Definition: lib.h:71
int num_tagged
Number of tagged entries.
Definition: lib.h:84
bool tag_prefix
User has pressed <tag-prefix>
Definition: lib.h:76
void * wdata
Private data.
Definition: mutt_window.h:145
struct Connection * conn
Connection to NNTP Server.
Definition: adata.h:62
Cached regular expression.
Definition: regex3.h:89
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:304