NeoMutt  2024-04-16-36-g75b6fb
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#ifdef MIXMASTER
82#include "mixmaster/lib.h"
83#endif
84#endif
85
86// clang-format off
90const struct MenuFuncOp OpCompose[] = { /* map: compose */
91 { "attach-file", OP_ATTACHMENT_ATTACH_FILE },
92 { "attach-key", OP_ATTACHMENT_ATTACH_KEY },
93 { "attach-message", OP_ATTACHMENT_ATTACH_MESSAGE },
94 { "attach-news-message", OP_ATTACHMENT_ATTACH_NEWS_MESSAGE },
95#ifdef USE_AUTOCRYPT
96 { "autocrypt-menu", OP_COMPOSE_AUTOCRYPT_MENU },
97#endif
98 { "copy-file", OP_ATTACHMENT_SAVE },
99 { "detach-file", OP_ATTACHMENT_DETACH },
100 { "display-toggle-weed", OP_DISPLAY_HEADERS },
101 { "edit-bcc", OP_ENVELOPE_EDIT_BCC },
102 { "edit-cc", OP_ENVELOPE_EDIT_CC },
103 { "edit-content-id", OP_ATTACHMENT_EDIT_CONTENT_ID },
104 { "edit-description", OP_ATTACHMENT_EDIT_DESCRIPTION },
105 { "edit-encoding", OP_ATTACHMENT_EDIT_ENCODING },
106 { "edit-fcc", OP_ENVELOPE_EDIT_FCC },
107 { "edit-file", OP_COMPOSE_EDIT_FILE },
108 { "edit-followup-to", OP_ENVELOPE_EDIT_FOLLOWUP_TO },
109 { "edit-from", OP_ENVELOPE_EDIT_FROM },
110 { "edit-headers", OP_ENVELOPE_EDIT_HEADERS },
111 { "edit-language", OP_ATTACHMENT_EDIT_LANGUAGE },
112 { "edit-message", OP_COMPOSE_EDIT_MESSAGE },
113 { "edit-mime", OP_ATTACHMENT_EDIT_MIME },
114 { "edit-newsgroups", OP_ENVELOPE_EDIT_NEWSGROUPS },
115 { "edit-reply-to", OP_ENVELOPE_EDIT_REPLY_TO },
116 { "edit-subject", OP_ENVELOPE_EDIT_SUBJECT },
117 { "edit-to", OP_ENVELOPE_EDIT_TO },
118 { "edit-type", OP_ATTACHMENT_EDIT_TYPE },
119 { "edit-x-comment-to", OP_ENVELOPE_EDIT_X_COMMENT_TO },
120 { "exit", OP_EXIT },
121 { "filter-entry", OP_ATTACHMENT_FILTER },
122 { "forget-passphrase", OP_FORGET_PASSPHRASE },
123 { "get-attachment", OP_ATTACHMENT_GET_ATTACHMENT },
124 { "group-alternatives", OP_ATTACHMENT_GROUP_ALTS },
125 { "group-multilingual", OP_ATTACHMENT_GROUP_LINGUAL },
126 { "group-related", OP_ATTACHMENT_GROUP_RELATED },
127 { "ispell", OP_COMPOSE_ISPELL },
128#ifdef MIXMASTER
129 { "mix", OP_COMPOSE_MIX },
130#endif
131 { "move-down", OP_ATTACHMENT_MOVE_DOWN },
132 { "move-up", OP_ATTACHMENT_MOVE_UP },
133 { "new-mime", OP_ATTACHMENT_NEW_MIME },
134 { "pgp-menu", OP_COMPOSE_PGP_MENU },
135 { "pipe-entry", OP_PIPE },
136 { "pipe-message", OP_PIPE },
137 { "postpone-message", OP_COMPOSE_POSTPONE_MESSAGE },
138 { "print-entry", OP_ATTACHMENT_PRINT },
139 { "rename-attachment", OP_ATTACHMENT_RENAME_ATTACHMENT },
140 { "rename-file", OP_COMPOSE_RENAME_FILE },
141 { "send-message", OP_COMPOSE_SEND_MESSAGE },
142 { "smime-menu", OP_COMPOSE_SMIME_MENU },
143 { "toggle-disposition", OP_ATTACHMENT_TOGGLE_DISPOSITION },
144 { "toggle-recode", OP_ATTACHMENT_TOGGLE_RECODE },
145 { "toggle-unlink", OP_ATTACHMENT_TOGGLE_UNLINK },
146 { "ungroup-attachment", OP_ATTACHMENT_UNGROUP },
147 { "update-encoding", OP_ATTACHMENT_UPDATE_ENCODING },
148 { "view-attach", OP_ATTACHMENT_VIEW },
149 { "view-mailcap", OP_ATTACHMENT_VIEW_MAILCAP },
150 { "view-pager", OP_ATTACHMENT_VIEW_PAGER },
151 { "view-text", OP_ATTACHMENT_VIEW_TEXT },
152 { "write-fcc", OP_COMPOSE_WRITE_MESSAGE },
153 { NULL, 0 },
154};
155
159const struct MenuOpSeq ComposeDefaultBindings[] = { /* map: compose */
160 { OP_ATTACHMENT_ATTACH_FILE, "a" },
161 { OP_ATTACHMENT_ATTACH_KEY, "\033k" }, // <Alt-k>
162 { OP_ATTACHMENT_ATTACH_MESSAGE, "A" },
163 { OP_ATTACHMENT_DETACH, "D" },
164 { OP_ATTACHMENT_EDIT_CONTENT_ID, "\033i" }, // <Alt-i>
165 { OP_ATTACHMENT_EDIT_DESCRIPTION, "d" },
166 { OP_ATTACHMENT_EDIT_ENCODING, "\005" }, // <Ctrl-E>
167 { OP_ATTACHMENT_EDIT_LANGUAGE, "\014" }, // <Ctrl-L>
168 { OP_ATTACHMENT_EDIT_MIME, "m" },
169 { OP_ATTACHMENT_EDIT_TYPE, "\024" }, // <Ctrl-T>
170 { OP_ATTACHMENT_FILTER, "F" },
171 { OP_ATTACHMENT_GET_ATTACHMENT, "G" },
172 { OP_ATTACHMENT_GROUP_ALTS, "&" },
173 { OP_ATTACHMENT_GROUP_LINGUAL, "^" },
174 { OP_ATTACHMENT_GROUP_RELATED, "%" },
175 { OP_ATTACHMENT_MOVE_DOWN, "+" },
176 { OP_ATTACHMENT_MOVE_UP, "-" },
177 { OP_ATTACHMENT_NEW_MIME, "n" },
178 { OP_EXIT, "q" },
179 { OP_PIPE, "|" },
180 { OP_ATTACHMENT_PRINT, "l" },
181 { OP_ATTACHMENT_RENAME_ATTACHMENT, "\017" }, // <Ctrl-O>
182 { OP_ATTACHMENT_SAVE, "C" },
183 { OP_ATTACHMENT_TOGGLE_DISPOSITION, "\004" }, // <Ctrl-D>
184 { OP_ATTACHMENT_TOGGLE_UNLINK, "u" },
185 { OP_ATTACHMENT_UNGROUP, "#" },
186 { OP_ATTACHMENT_UPDATE_ENCODING, "U" },
187 { OP_ATTACHMENT_VIEW, "<keypadenter>" },
188 { OP_ATTACHMENT_VIEW, "\n" }, // <Enter>
189 { OP_ATTACHMENT_VIEW, "\r" }, // <Return>
190#ifdef USE_AUTOCRYPT
191 { OP_COMPOSE_AUTOCRYPT_MENU, "o" },
192#endif
193 { OP_COMPOSE_EDIT_FILE, "\033e" }, // <Alt-e>
194 { OP_COMPOSE_EDIT_MESSAGE, "e" },
195 { OP_COMPOSE_ISPELL, "i" },
196#ifdef MIXMASTER
197 { OP_COMPOSE_MIX, "M" },
198#endif
199 { OP_COMPOSE_PGP_MENU, "p" },
200 { OP_COMPOSE_POSTPONE_MESSAGE, "P" },
201 { OP_COMPOSE_RENAME_FILE, "R" },
202 { OP_COMPOSE_SEND_MESSAGE, "y" },
203 { OP_COMPOSE_SMIME_MENU, "S" },
204 { OP_COMPOSE_WRITE_MESSAGE, "w" },
205 { OP_DISPLAY_HEADERS, "h" },
206 { OP_ENVELOPE_EDIT_BCC, "b" },
207 { OP_ENVELOPE_EDIT_CC, "c" },
208 { OP_ENVELOPE_EDIT_FCC, "f" },
209 { OP_ENVELOPE_EDIT_FROM, "\033f" }, // <Alt-f>
210 { OP_ENVELOPE_EDIT_HEADERS, "E" },
211 { OP_ENVELOPE_EDIT_REPLY_TO, "r" },
212 { OP_ENVELOPE_EDIT_SUBJECT, "s" },
213 { OP_ENVELOPE_EDIT_TO, "t" },
214 { OP_FORGET_PASSPHRASE, "\006" }, // <Ctrl-F>
215 { OP_TAG, "T" },
216 { 0, NULL },
217};
218// clang-format on
219
225static bool check_count(struct AttachCtx *actx)
226{
227 if (actx->idxlen == 0)
228 {
229 mutt_error(_("There are no attachments"));
230 return false;
231 }
232
233 return true;
234}
235
242static char *gen_cid(void)
243{
244 char rndid[MUTT_RANDTAG_LEN + 1];
245
246 mutt_rand_base32(rndid, sizeof(rndid) - 1);
247 rndid[MUTT_RANDTAG_LEN] = 0;
248
249 return mutt_str_dup(rndid);
250}
251
258static bool check_cid(const char *cid)
259{
260 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
261
262 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
263
264 const bool valid = mutt_regex_match(check_cid_regex, cid);
265
266 mutt_regex_free(&check_cid_regex);
267
268 return valid;
269}
270
278static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
279{
280 int rc = -1;
281 struct stat st = { 0 };
282 struct Buffer *pretty = NULL, *msg = NULL;
283
284 for (int i = 0; i < actx->idxlen; i++)
285 {
286 if (actx->idx[i]->body->type == TYPE_MULTIPART)
287 continue;
288 if (stat(actx->idx[i]->body->filename, &st) != 0)
289 {
290 if (!pretty)
291 pretty = buf_pool_get();
292 buf_strcpy(pretty, actx->idx[i]->body->filename);
293 buf_pretty_mailbox(pretty);
294 /* L10N: This message is displayed in the compose menu when an attachment
295 doesn't stat. %d is the attachment number and %s is the attachment
296 filename. The filename is located last to avoid a long path hiding
297 the error message. */
298 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
299 goto cleanup;
300 }
301
302 if (actx->idx[i]->body->stamp < st.st_mtime)
303 {
304 if (!pretty)
305 pretty = buf_pool_get();
306 buf_strcpy(pretty, actx->idx[i]->body->filename);
307 buf_pretty_mailbox(pretty);
308
309 if (!msg)
310 msg = buf_pool_get();
311 /* L10N: This message is displayed in the compose menu when an attachment
312 is modified behind the scenes. %d is the attachment number and %s is
313 the attachment filename. The filename is located last to avoid a long
314 path hiding the prompt question. */
315 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
316 i + 1, buf_string(pretty));
317
319 if (ans == MUTT_YES)
320 mutt_update_encoding(actx->idx[i]->body, sub);
321 else if (ans == MUTT_ABORT)
322 goto cleanup;
323 }
324 }
325
326 rc = 0;
327
328cleanup:
329 buf_pool_release(&pretty);
330 buf_pool_release(&msg);
331 return rc;
332}
333
341static int delete_attachment(struct AttachCtx *actx, int aidx)
342{
343 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
344 return -1;
345
346 struct AttachPtr **idx = actx->idx;
347 struct Body *b_previous = NULL;
348 struct Body *b_parent = NULL;
349
350 if (aidx == 0)
351 {
352 struct Body *b = actx->idx[0]->body;
353 if (!b->next) // There's only one attachment left
354 {
355 mutt_error(_("You may not delete the only attachment"));
356 return -1;
357 }
358
359 /* L10N: Prompt when trying to hit <detach-file> on the first entry in
360 the compose menu. This entry is most likely the message they just
361 typed. Hitting yes will remove the entry and unlink the file, so
362 it's worth confirming they really meant to do it. */
363 enum QuadOption ans = query_yesorno_help(_("Really delete the main message?"),
365 "compose_confirm_detach_first");
366 if (ans == MUTT_NO)
367 {
368 idx[aidx]->body->tagged = false;
369 return -1;
370 }
371 }
372
373 if (idx[aidx]->level > 0)
374 {
375 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
376 {
377 if (attach_body_count(b_parent->parts, false) < 3)
378 {
379 mutt_error(_("Can't leave group with only one attachment"));
380 return -1;
381 }
382 }
383 }
384
385 // reorder body pointers
386 if (aidx > 0)
387 {
388 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
389 b_previous->next = idx[aidx]->body->next;
390 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
391 b_parent->parts = idx[aidx]->body->next;
392 }
393
394 // free memory
395 int part_count = 1;
396 if (aidx < (actx->idxlen - 1))
397 {
398 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
399 (idx[aidx + 1]->level > idx[aidx]->level))
400 {
401 part_count += attach_body_count(idx[aidx]->body->parts, true);
402 }
403 }
404 idx[aidx]->body->next = NULL;
405 mutt_body_free(&(idx[aidx]->body));
406 for (int i = 0; i < part_count; i++)
407 {
408 FREE(&idx[aidx + i]->tree);
409 FREE(&idx[aidx + i]);
410 }
411
412 // reorder attachment list
413 for (int i = aidx; i < (actx->idxlen - part_count); i++)
414 idx[i] = idx[i + part_count];
415 for (int i = 0; i < part_count; i++)
416 idx[actx->idxlen - i - 1] = NULL;
417 actx->idxlen -= part_count;
418
419 return 0;
420}
421
428static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
429{
430 ap->level = 0;
431 for (int i = actx->idxlen; i > 0; i--)
432 {
433 if (ap->level == actx->idx[i - 1]->level)
434 {
435 actx->idx[i - 1]->body->next = ap->body;
436 break;
437 }
438 }
439
440 ap->body->aptr = ap;
441 mutt_actx_add_attach(actx, ap);
442 update_menu(actx, menu, false);
443 menu_set_index(menu, actx->vcount - 1);
444}
445
453static void compose_attach_swap(struct Email *e, struct AttachCtx *actx, int first, int second)
454{
455 struct AttachPtr **idx = actx->idx;
456
457 // check that attachments really are adjacent
458 if (idx[first]->body->next != idx[second]->body)
459 return;
460
461 // reorder Body pointers
462 if (first == 0)
463 {
464 // first attachment is the fundamental part
465 idx[first]->body->next = idx[second]->body->next;
466 idx[second]->body->next = idx[first]->body;
467 e->body = idx[second]->body;
468 }
469 else
470 {
471 // find previous attachment
472 struct Body *b_previous = NULL;
473 struct Body *b_parent = NULL;
474 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
475 {
476 idx[first]->body->next = idx[second]->body->next;
477 idx[second]->body->next = idx[first]->body;
478 b_previous->next = idx[second]->body;
479 }
480 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
481 {
482 idx[first]->body->next = idx[second]->body->next;
483 idx[second]->body->next = idx[first]->body;
484 b_parent->parts = idx[second]->body;
485 }
486 }
487
488 // reorder attachment list
489 struct AttachPtr *saved = idx[second];
490 for (int i = second; i > first; i--)
491 idx[i] = idx[i - 1];
492 idx[first] = saved;
493
494 // if moved attachment is a group then move subparts too
495 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
496 {
497 int i = second + 1;
498 while (idx[i]->level > idx[first]->level)
499 {
500 saved = idx[i];
501 int destidx = i - second + first;
502 for (int j = i; j > destidx; j--)
503 idx[j] = idx[j - 1];
504 idx[destidx] = saved;
505 i++;
506 if (i >= actx->idxlen)
507 break;
508 }
509 }
510}
511
519static int group_attachments(struct ComposeSharedData *shared, char *subtype)
520{
521 struct AttachCtx *actx = shared->adata->actx;
522 int group_level = -1;
523 struct Body *bptr_parent = NULL;
524
525 // Attachments to be grouped must have the same parent
526 for (int i = 0; i < actx->idxlen; i++)
527 {
528 // check if all tagged attachments are at same level
529 if (actx->idx[i]->body->tagged)
530 {
531 if (group_level == -1)
532 {
533 group_level = actx->idx[i]->level;
534 }
535 else
536 {
537 if (group_level != actx->idx[i]->level)
538 {
539 mutt_error(_("Attachments to be grouped must have the same parent"));
540 return FR_ERROR;
541 }
542 }
543 // if not at top level check if all tagged attachments have same parent
544 if (group_level > 0)
545 {
546 if (bptr_parent)
547 {
548 struct Body *bptr_test = NULL;
549 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
550 mutt_debug(LL_DEBUG5, "can't find parent\n");
551 if (bptr_test != bptr_parent)
552 {
553 mutt_error(_("Attachments to be grouped must have the same parent"));
554 return FR_ERROR;
555 }
556 }
557 else
558 {
559 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
560 mutt_debug(LL_DEBUG5, "can't find parent\n");
561 }
562 }
563 }
564 }
565
566 // Can't group all attachments unless at top level
567 if (bptr_parent)
568 {
569 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
570 {
571 mutt_error(_("Can't leave group with only one attachment"));
572 return FR_ERROR;
573 }
574 }
575
576 struct Body *group = mutt_body_new();
577 group->type = TYPE_MULTIPART;
578 group->subtype = mutt_str_dup(subtype);
579 group->encoding = ENC_7BIT;
580
581 struct Body *bptr_first = NULL; // first tagged attachment
582 struct Body *bptr = NULL; // current tagged attachment
583 struct Body *group_parent = NULL; // parent of group
584 struct Body *group_previous = NULL; // previous body to group
585 struct Body *group_part = NULL; // current attachment in group
586 int group_idx = 0; // index in attachment list where group will be inserted
587 int group_last_idx = 0; // index of last part of previous found group
588 int group_parent_type = TYPE_OTHER;
589
590 for (int i = 0; i < actx->idxlen; i++)
591 {
592 bptr = actx->idx[i]->body;
593 if (bptr->tagged)
594 {
595 // set group properties based on first tagged attachment
596 if (!bptr_first)
597 {
598 group->disposition = bptr->disposition;
599 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
600 group->language = mutt_str_dup(bptr->language);
601 group_parent_type = bptr->aptr->parent_type;
602 bptr_first = bptr;
603 if (i > 0)
604 {
605 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
606 {
607 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
608 }
609 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
610 {
611 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
612 }
613 }
614 }
615
616 shared->adata->menu->num_tagged--;
617 bptr->tagged = false;
618 bptr->aptr->level++;
620
621 // append bptr to the group parts list and remove from email body list
622 struct Body *bptr_previous = NULL;
623 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
624 bptr_previous->next = bptr->next;
625 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
626 bptr_parent->parts = bptr->next;
627 else
628 shared->email->body = bptr->next;
629
630 if (group_part)
631 {
632 // add bptr to group parts list
633 group_part->next = bptr;
634 group_part = group_part->next;
635 group_part->next = NULL;
636
637 // reorder attachments and set levels
638 int bptr_attachments = attach_body_count(bptr, true);
639 for (int j = i + 1; j < (i + bptr_attachments); j++)
640 actx->idx[j]->level++;
641 if (i > (group_last_idx + 1))
642 {
643 for (int j = 0; j < bptr_attachments; j++)
644 {
645 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
646 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
647 actx->idx[k] = actx->idx[k - 1];
648 actx->idx[group_last_idx + 1] = saved;
649 }
650 }
651 i += bptr_attachments - 1;
652 group_last_idx += bptr_attachments;
653 }
654 else
655 {
656 group_idx = i;
657 group->parts = bptr;
658 group_part = bptr;
659 group_part->next = NULL;
660 int bptr_attachments = attach_body_count(bptr, true);
661 for (int j = i + 1; j < (i + bptr_attachments); j++)
662 actx->idx[j]->level++;
663 i += bptr_attachments - 1;
664 group_last_idx = i;
665 }
666 }
667 }
668
669 if (!bptr_first)
670 {
671 mutt_body_free(&group);
672 return FR_ERROR;
673 }
674
675 // set group->next
676 int next_aidx = group_idx + attach_body_count(group->parts, true);
677 if (group_parent)
678 {
679 // find next attachment with the same parent as the group
680 struct Body *b = NULL;
681 struct Body *b_parent = NULL;
682 while (next_aidx < actx->idxlen)
683 {
684 b = actx->idx[next_aidx]->body;
685 b_parent = NULL;
686 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
687 {
688 if (group_parent == b_parent)
689 {
690 group->next = b;
691 break;
692 }
693 }
694 next_aidx++;
695 }
696 }
697 else if (next_aidx < actx->idxlen)
698 {
699 // group is at top level
700 group->next = actx->idx[next_aidx]->body;
701 }
702
703 // set previous or parent for group
704 if (group_previous)
705 group_previous->next = group;
706 else if (group_parent)
707 group_parent->parts = group;
708
710
711 struct AttachPtr *group_ap = mutt_aptr_new();
712 group_ap->body = group;
713 group_ap->body->aptr = group_ap;
714 group_ap->level = group_level;
715 group_ap->parent_type = group_parent_type;
716
717 // insert group into attachment list
718 mutt_actx_ins_attach(actx, group_ap, group_idx);
719
720 // update email body and last attachment pointers
721 shared->email->body = actx->idx[0]->body;
722 actx->idx[actx->idxlen - 1]->body->next = NULL;
723
724 update_menu(actx, shared->adata->menu, false);
725 shared->adata->menu->current = group_idx;
727
729 return FR_SUCCESS;
730}
731
732// -----------------------------------------------------------------------------
733
737static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
738{
739 char *prompt = _("Attach file");
740 int numfiles = 0;
741 char **files = NULL;
742
743 struct Buffer *fname = buf_pool_get();
744 if ((mw_enter_fname(prompt, fname, false, NULL, true, &files, &numfiles,
745 MUTT_SEL_MULTI) == -1) ||
746 buf_is_empty(fname))
747 {
748 for (int i = 0; i < numfiles; i++)
749 FREE(&files[i]);
750
751 FREE(&files);
752 buf_pool_release(&fname);
753 return FR_NO_ACTION;
754 }
755
756 bool error = false;
757 bool added_attachment = false;
758 if (numfiles > 1)
759 {
760 mutt_message(ngettext("Attaching selected file...",
761 "Attaching selected files...", numfiles));
762 }
763 for (int i = 0; i < numfiles; i++)
764 {
765 char *att = files[i];
766 if (!att)
767 continue;
768
769 struct AttachPtr *ap = mutt_aptr_new();
770 ap->unowned = true;
771 ap->body = mutt_make_file_attach(att, shared->sub);
772 if (ap->body)
773 {
774 added_attachment = true;
775 update_idx(shared->adata->menu, shared->adata->actx, ap);
776 }
777 else
778 {
779 error = true;
780 mutt_error(_("Unable to attach %s"), att);
781 mutt_aptr_free(&ap);
782 }
783 FREE(&files[i]);
784 }
785
786 FREE(&files);
787 buf_pool_release(&fname);
788
789 if (!error)
791
794 if (added_attachment)
796 return FR_SUCCESS;
797}
798
802static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
803{
805 return FR_NOT_IMPL;
806 struct AttachPtr *ap = mutt_aptr_new();
808 if (ap->body)
809 {
810 update_idx(shared->adata->menu, shared->adata->actx, ap);
813 }
814 else
815 {
816 mutt_aptr_free(&ap);
817 }
818
820 return FR_SUCCESS;
821}
822
830static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
831{
832 char *prompt = _("Open mailbox to attach message from");
833
834 OptNews = false;
835 if (shared->mailbox && (op == OP_ATTACHMENT_ATTACH_NEWS_MESSAGE))
836 {
837 const char *const c_news_server = cs_subset_string(shared->sub, "news_server");
838 CurrentNewsSrv = nntp_select_server(shared->mailbox, c_news_server, false);
839 if (!CurrentNewsSrv)
840 return FR_NO_ACTION;
841
842 prompt = _("Open newsgroup to attach message from");
843 OptNews = true;
844 }
845
846 struct Buffer *fname = buf_pool_get();
847 if (shared->mailbox)
848 {
849 if ((op == OP_ATTACHMENT_ATTACH_MESSAGE) ^ (shared->mailbox->type == MUTT_NNTP))
850 {
851 buf_strcpy(fname, mailbox_path(shared->mailbox));
852 buf_pretty_mailbox(fname);
853 }
854 }
855
856 if ((mw_enter_fname(prompt, fname, true, shared->mailbox, false, NULL, NULL,
857 MUTT_SEL_NO_FLAGS) == -1) ||
858 buf_is_empty(fname))
859 {
860 buf_pool_release(&fname);
861 return FR_NO_ACTION;
862 }
863
864 if (OptNews)
866 else
867 buf_expand_path(fname);
868
869 if (imap_path_probe(buf_string(fname), NULL) != MUTT_IMAP)
870 {
871 if (pop_path_probe(buf_string(fname), NULL) != MUTT_POP)
872 {
873 if (!OptNews && (nntp_path_probe(buf_string(fname), NULL) != MUTT_NNTP))
874 {
876 {
877 /* check to make sure the file exists and is readable */
878 if (access(buf_string(fname), R_OK) == -1)
879 {
880 mutt_perror("%s", buf_string(fname));
881 buf_pool_release(&fname);
882 return FR_ERROR;
883 }
884 }
885 }
886 }
887 }
888
890
891 struct Mailbox *m_attach = mx_path_resolve(buf_string(fname));
892 const bool old_readonly = m_attach->readonly;
893 if (!mx_mbox_open(m_attach, MUTT_READONLY))
894 {
895 mutt_error(_("Unable to open mailbox %s"), buf_string(fname));
896 mx_fastclose_mailbox(m_attach, false);
897 m_attach = NULL;
898 buf_pool_release(&fname);
899 return FR_ERROR;
900 }
901 buf_pool_release(&fname);
902
903 if (m_attach->msg_count == 0)
904 {
905 mx_mbox_close(m_attach);
906 mutt_error(_("No messages in that folder"));
907 return FR_NO_ACTION;
908 }
909
910 /* `$sort`, `$sort_aux`, `$use_threads` could be changed in dlg_index() */
911 const enum SortType old_sort = cs_subset_sort(shared->sub, "sort");
912 const enum SortType old_sort_aux = cs_subset_sort(shared->sub, "sort_aux");
913 const unsigned char old_use_threads = cs_subset_enum(shared->sub, "use_threads");
914
915 mutt_message(_("Tag the messages you want to attach"));
916 struct MuttWindow *dlg = index_pager_init();
917 struct IndexSharedData *index_shared = dlg->wdata;
918 index_shared->attach_msg = true;
919 dialog_push(dlg);
920 struct Mailbox *m_attach_new = dlg_index(dlg, m_attach);
921 dialog_pop();
922 mutt_window_free(&dlg);
923
924 if (!shared->mailbox)
925 {
926 /* Restore old $sort variables */
927 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
928 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
929 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
932 return FR_SUCCESS;
933 }
934
935 bool added_attachment = false;
936 for (int i = 0; i < m_attach_new->msg_count; i++)
937 {
938 if (!m_attach_new->emails[i])
939 break;
940 if (!message_is_tagged(m_attach_new->emails[i]))
941 continue;
942
943 struct AttachPtr *ap = mutt_aptr_new();
944 ap->body = mutt_make_message_attach(m_attach_new, m_attach_new->emails[i],
945 true, shared->sub);
946 if (ap->body)
947 {
948 added_attachment = true;
949 update_idx(shared->adata->menu, shared->adata->actx, ap);
950 }
951 else
952 {
953 mutt_error(_("Unable to attach"));
954 mutt_aptr_free(&ap);
955 }
956 }
958
959 if (m_attach_new == m_attach)
960 {
961 m_attach->readonly = old_readonly;
962 }
963 mx_fastclose_mailbox(m_attach_new, false);
964
965 /* Restore old $sort variables */
966 cs_subset_str_native_set(shared->sub, "sort", old_sort, NULL);
967 cs_subset_str_native_set(shared->sub, "sort_aux", old_sort_aux, NULL);
968 cs_subset_str_native_set(shared->sub, "use_threads", old_use_threads, NULL);
970 if (added_attachment)
972 return FR_SUCCESS;
973}
974
978static int op_attachment_detach(struct ComposeSharedData *shared, int op)
979{
980 struct AttachCtx *actx = shared->adata->actx;
981 if (!check_count(actx))
982 return FR_NO_ACTION;
983
984 struct Menu *menu = shared->adata->menu;
985 struct AttachPtr *cur_att = current_attachment(actx, menu);
986 if (cur_att->unowned)
987 cur_att->body->unlink = false;
988
989 int index = menu_get_index(menu);
990 if (delete_attachment(actx, index) == -1)
991 return FR_ERROR;
992
993 menu->num_tagged = 0;
994 for (int i = 0; i < actx->idxlen; i++)
995 {
996 if (actx->idx[i]->body->tagged)
997 menu->num_tagged++;
998 }
999
1000 update_menu(actx, menu, false);
1002
1003 index = menu_get_index(menu);
1004 if (index == 0)
1005 shared->email->body = actx->idx[0]->body;
1006
1007 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1008 return FR_SUCCESS;
1009}
1010
1014static int op_attachment_edit_content_id(struct ComposeSharedData *shared, int op)
1015{
1016 if (!check_count(shared->adata->actx))
1017 return FR_NO_ACTION;
1018
1019 int rc = FR_NO_ACTION;
1020 struct Buffer *buf = buf_pool_get();
1021 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1022 shared->adata->menu);
1023
1024 char *id = mutt_param_get(&cur_att->body->parameter, "content-id");
1025 if (id)
1026 {
1027 buf_strcpy(buf, id);
1028 }
1029 else
1030 {
1031 id = gen_cid();
1032 buf_strcpy(buf, id);
1033 FREE(&id);
1034 }
1035
1036 if (mw_get_field("Content-ID: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1037 {
1038 if (!mutt_str_equal(id, buf_string(buf)))
1039 {
1040 if (check_cid(buf_string(buf)))
1041 {
1042 mutt_param_set(&cur_att->body->parameter, "content-id", buf_string(buf));
1045 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1046 rc = FR_SUCCESS;
1047 }
1048 else
1049 {
1050 mutt_error(_("Content-ID can only contain the characters: -.0-9@A-Z_a-z"));
1051 rc = FR_ERROR;
1052 }
1053 }
1054 }
1055
1056 buf_pool_release(&buf);
1057
1058 if (rc != FR_ERROR)
1060
1061 return rc;
1062}
1063
1067static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
1068{
1069 if (!check_count(shared->adata->actx))
1070 return FR_NO_ACTION;
1071
1072 int rc = FR_NO_ACTION;
1073 struct Buffer *buf = buf_pool_get();
1074
1075 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1076 shared->adata->menu);
1077 buf_strcpy(buf, cur_att->body->description);
1078
1079 /* header names should not be translated */
1080 if (mw_get_field("Description: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1081 {
1082 if (!mutt_str_equal(cur_att->body->description, buf_string(buf)))
1083 {
1084 mutt_str_replace(&cur_att->body->description, buf_string(buf));
1086 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1087 rc = FR_SUCCESS;
1088 }
1089 }
1090
1091 buf_pool_release(&buf);
1092 return rc;
1093}
1094
1098static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
1099{
1100 if (!check_count(shared->adata->actx))
1101 return FR_NO_ACTION;
1102
1103 int rc = FR_NO_ACTION;
1104 struct Buffer *buf = buf_pool_get();
1105
1106 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1107 shared->adata->menu);
1108 buf_strcpy(buf, ENCODING(cur_att->body->encoding));
1109
1110 if ((mw_get_field("Content-Transfer-Encoding: ", buf, MUTT_COMP_NO_FLAGS,
1111 HC_OTHER, NULL, NULL) == 0) &&
1112 !buf_is_empty(buf))
1113 {
1114 int enc = mutt_check_encoding(buf_string(buf));
1115 if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1116 {
1117 if (enc != cur_att->body->encoding)
1118 {
1119 cur_att->body->encoding = enc;
1123 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1124 rc = FR_SUCCESS;
1125 }
1126 }
1127 else
1128 {
1129 mutt_error(_("Invalid encoding"));
1130 rc = FR_ERROR;
1131 }
1132 }
1133
1134 buf_pool_release(&buf);
1135 return rc;
1136}
1137
1141static int op_attachment_edit_language(struct ComposeSharedData *shared, int op)
1142{
1143 if (!check_count(shared->adata->actx))
1144 return FR_NO_ACTION;
1145
1146 int rc = FR_NO_ACTION;
1147 struct Buffer *buf = buf_pool_get();
1148 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1149 shared->adata->menu);
1150
1151 buf_strcpy(buf, cur_att->body->language);
1152 if (mw_get_field("Content-Language: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
1153 {
1154 if (!mutt_str_equal(cur_att->body->language, buf_string(buf)))
1155 {
1156 mutt_str_replace(&cur_att->body->language, buf_string(buf));
1159 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1160 rc = FR_SUCCESS;
1161 }
1163 }
1164 else
1165 {
1166 mutt_warning(_("Empty 'Content-Language'"));
1167 rc = FR_ERROR;
1168 }
1169
1170 buf_pool_release(&buf);
1171 return rc;
1172}
1173
1177static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
1178{
1179 if (!check_count(shared->adata->actx))
1180 return FR_NO_ACTION;
1181 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1182 shared->adata->menu);
1183 if (!mutt_edit_attachment(cur_att->body))
1184 return FR_NO_ACTION;
1185
1186 mutt_update_encoding(cur_att->body, shared->sub);
1188 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1189 return FR_SUCCESS;
1190}
1191
1195static int op_attachment_edit_type(struct ComposeSharedData *shared, int op)
1196{
1197 if (!check_count(shared->adata->actx))
1198 return FR_NO_ACTION;
1199
1200 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1201 shared->adata->menu);
1202 if (!mutt_edit_content_type(NULL, cur_att->body, NULL))
1203 return FR_NO_ACTION;
1204
1205 /* this may have been a change to text/something */
1206 mutt_update_encoding(cur_att->body, shared->sub);
1208 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1209 return FR_SUCCESS;
1210}
1211
1219static int op_attachment_filter(struct ComposeSharedData *shared, int op)
1220{
1221 struct AttachCtx *actx = shared->adata->actx;
1222 if (!check_count(actx))
1223 return FR_NO_ACTION;
1224
1225 struct Menu *menu = shared->adata->menu;
1226 struct AttachPtr *cur_att = current_attachment(actx, menu);
1227 if (cur_att->body->type == TYPE_MULTIPART)
1228 {
1229 mutt_error(_("Can't filter multipart attachments"));
1230 return FR_ERROR;
1231 }
1232 mutt_pipe_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body,
1233 (op == OP_ATTACHMENT_FILTER));
1234 if (op == OP_ATTACHMENT_FILTER) /* cte might have changed */
1235 {
1237 }
1239 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1240 return FR_SUCCESS;
1241}
1242
1246static int op_attachment_get_attachment(struct ComposeSharedData *shared, int op)
1247{
1248 struct AttachCtx *actx = shared->adata->actx;
1249 if (!check_count(actx))
1250 return FR_NO_ACTION;
1251
1252 int rc = FR_ERROR;
1253 struct Menu *menu = shared->adata->menu;
1254 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1255 ba_add_tagged(&ba, actx, menu);
1256 if (ARRAY_EMPTY(&ba))
1257 goto done;
1258
1259 struct Body **bp = NULL;
1260 ARRAY_FOREACH(bp, &ba)
1261 {
1262 if ((*bp)->type == TYPE_MULTIPART)
1263 {
1264 mutt_warning(_("Can't get multipart attachments"));
1265 continue;
1266 }
1268 }
1269
1271 rc = FR_SUCCESS;
1272
1273done:
1274 ARRAY_FREE(&ba);
1275 /* No send2hook since this doesn't change the message. */
1276 return rc;
1277}
1278
1282static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
1283{
1284 if (shared->adata->menu->num_tagged < 2)
1285 {
1286 mutt_error(_("Grouping 'alternatives' requires at least 2 tagged messages"));
1287 return FR_ERROR;
1288 }
1289
1290 return group_attachments(shared, "alternative");
1291}
1292
1296static int op_attachment_group_lingual(struct ComposeSharedData *shared, int op)
1297{
1298 if (shared->adata->menu->num_tagged < 2)
1299 {
1300 mutt_error(_("Grouping 'multilingual' requires at least 2 tagged messages"));
1301 return FR_ERROR;
1302 }
1303
1304 /* traverse to see whether all the parts have Content-Language: set */
1305 int tagged_with_lang_num = 0;
1306 for (struct Body *b = shared->email->body; b; b = b->next)
1307 if (b->tagged && b->language && *b->language)
1308 tagged_with_lang_num++;
1309
1310 if (shared->adata->menu->num_tagged != tagged_with_lang_num)
1311 {
1312 if (query_yesorno(_("Not all parts have 'Content-Language' set, continue?"),
1313 MUTT_YES) != MUTT_YES)
1314 {
1315 mutt_message(_("Not sending this message"));
1316 return FR_ERROR;
1317 }
1318 }
1319
1320 return group_attachments(shared, "multilingual");
1321}
1322
1326static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
1327{
1328 if (shared->adata->menu->num_tagged < 2)
1329 {
1330 mutt_error(_("Grouping 'related' requires at least 2 tagged messages"));
1331 return FR_ERROR;
1332 }
1333
1334 // ensure Content-ID is set for tagged attachments
1335 for (struct Body *b = shared->email->body; b; b = b->next)
1336 {
1337 if (!b->tagged || (b->type == TYPE_MULTIPART))
1338 continue;
1339
1340 char *id = mutt_param_get(&b->parameter, "content-id");
1341 if (id)
1342 continue;
1343
1344 id = gen_cid();
1345 if (id)
1346 {
1347 mutt_param_set(&b->parameter, "content-id", id);
1348 FREE(&id);
1349 }
1350 }
1351
1352 return group_attachments(shared, "related");
1353}
1354
1358static int op_attachment_move_down(struct ComposeSharedData *shared, int op)
1359{
1360 int index = menu_get_index(shared->adata->menu);
1361
1362 struct AttachCtx *actx = shared->adata->actx;
1363
1364 if (index < 0)
1365 return FR_ERROR;
1366
1367 if (index == (actx->idxlen - 1))
1368 {
1369 mutt_error(_("Attachment is already at bottom"));
1370 return FR_NO_ACTION;
1371 }
1372 if ((actx->idx[index]->parent_type == TYPE_MULTIPART) &&
1373 !actx->idx[index]->body->next)
1374 {
1375 mutt_error(_("Attachment can't be moved out of group"));
1376 return FR_ERROR;
1377 }
1378
1379 // find next attachment at current level
1380 int nextidx = index + 1;
1381 while ((nextidx < actx->idxlen) &&
1382 (actx->idx[nextidx]->level > actx->idx[index]->level))
1383 {
1384 nextidx++;
1385 }
1386 if (nextidx == actx->idxlen)
1387 {
1388 mutt_error(_("Attachment is already at bottom"));
1389 return FR_NO_ACTION;
1390 }
1391
1392 // find final position
1393 int finalidx = index + 1;
1394 if (nextidx < actx->idxlen - 1)
1395 {
1396 if ((actx->idx[nextidx]->body->type == TYPE_MULTIPART) &&
1397 (actx->idx[nextidx + 1]->level > actx->idx[nextidx]->level))
1398 {
1399 finalidx += attach_body_count(actx->idx[nextidx]->body->parts, true);
1400 }
1401 }
1402
1403 compose_attach_swap(shared->email, shared->adata->actx, index, nextidx);
1404 mutt_update_tree(shared->adata->actx);
1406 menu_set_index(shared->adata->menu, finalidx);
1407 return FR_SUCCESS;
1408}
1409
1413static int op_attachment_move_up(struct ComposeSharedData *shared, int op)
1414{
1415 int index = menu_get_index(shared->adata->menu);
1416 if (index < 0)
1417 return FR_ERROR;
1418
1419 struct AttachCtx *actx = shared->adata->actx;
1420
1421 if (index == 0)
1422 {
1423 mutt_error(_("Attachment is already at top"));
1424 return FR_NO_ACTION;
1425 }
1426 if (actx->idx[index - 1]->level < actx->idx[index]->level)
1427 {
1428 mutt_error(_("Attachment can't be moved out of group"));
1429 return FR_ERROR;
1430 }
1431
1432 // find previous attachment at current level
1433 int previdx = index - 1;
1434 while ((previdx > 0) && (actx->idx[previdx]->level > actx->idx[index]->level))
1435 previdx--;
1436
1437 compose_attach_swap(shared->email, actx, previdx, index);
1438 mutt_update_tree(actx);
1440 menu_set_index(shared->adata->menu, previdx);
1441 return FR_SUCCESS;
1442}
1443
1447static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
1448{
1449 int rc = FR_NO_ACTION;
1450 struct Buffer *fname = buf_pool_get();
1451 struct Buffer *type = NULL;
1452 struct AttachPtr *ap = NULL;
1453
1454 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1455 if ((mw_get_field(_("New file: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1456 &CompleteFileOps, &cdata) != 0) ||
1457 buf_is_empty(fname))
1458 {
1459 goto done;
1460 }
1461 buf_expand_path(fname);
1462
1463 /* Call to lookup_mime_type () ? maybe later */
1464 type = buf_pool_get();
1465 if ((mw_get_field("Content-Type: ", type, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1466 buf_is_empty(type))
1467 {
1468 goto done;
1469 }
1470
1471 rc = FR_ERROR;
1472 char *p = strchr(buf_string(type), '/');
1473 if (!p)
1474 {
1475 mutt_error(_("Content-Type is of the form base/sub"));
1476 goto done;
1477 }
1478 *p++ = 0;
1479 enum ContentType itype = mutt_check_mime_type(buf_string(type));
1480 if (itype == TYPE_OTHER)
1481 {
1482 mutt_error(_("Unknown Content-Type %s"), buf_string(type));
1483 goto done;
1484 }
1485
1486 ap = mutt_aptr_new();
1487 /* Touch the file */
1488 FILE *fp = mutt_file_fopen(buf_string(fname), "w");
1489 if (!fp)
1490 {
1491 mutt_error(_("Can't create file %s"), buf_string(fname));
1492 goto done;
1493 }
1494 mutt_file_fclose(&fp);
1495
1496 ap->body = mutt_make_file_attach(buf_string(fname), shared->sub);
1497 if (!ap->body)
1498 {
1499 mutt_error(_("Error attaching file"));
1500 goto done;
1501 }
1502 update_idx(shared->adata->menu, shared->adata->actx, ap);
1503 ap = NULL; // shared->adata->actx has taken ownership
1504
1505 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1506 shared->adata->menu);
1507 cur_att->body->type = itype;
1508 mutt_str_replace(&cur_att->body->subtype, p);
1509 cur_att->body->unlink = true;
1512
1513 if (mutt_compose_attachment(cur_att->body))
1514 {
1515 mutt_update_encoding(cur_att->body, shared->sub);
1517 }
1518 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1519 rc = FR_SUCCESS;
1520
1521done:
1522 mutt_aptr_free(&ap);
1523 buf_pool_release(&type);
1524 buf_pool_release(&fname);
1525 return rc;
1526}
1527
1531static int op_attachment_print(struct ComposeSharedData *shared, int op)
1532{
1533 struct AttachCtx *actx = shared->adata->actx;
1534 if (!check_count(actx))
1535 return FR_NO_ACTION;
1536
1537 struct Menu *menu = shared->adata->menu;
1538 struct AttachPtr *cur_att = current_attachment(actx, menu);
1539 if (cur_att->body->type == TYPE_MULTIPART)
1540 {
1541 mutt_error(_("Can't print multipart attachments"));
1542 return FR_ERROR;
1543 }
1544
1545 mutt_print_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body);
1546 /* no send2hook, since this doesn't modify the message */
1547 return FR_SUCCESS;
1548}
1549
1553static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
1554{
1555 if (!check_count(shared->adata->actx))
1556 return FR_NO_ACTION;
1557 char *src = NULL;
1558 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1559 shared->adata->menu);
1560 if (cur_att->body->d_filename)
1561 src = cur_att->body->d_filename;
1562 else
1563 src = cur_att->body->filename;
1564 struct Buffer *fname = buf_pool_get();
1565 buf_strcpy(fname, mutt_path_basename(NONULL(src)));
1566 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1567 int rc = mw_get_field(_("Send attachment with name: "), fname,
1569 if (rc == 0)
1570 {
1571 // It's valid to set an empty string here, to erase what was set
1572 mutt_str_replace(&cur_att->body->d_filename, buf_string(fname));
1574 }
1575 buf_pool_release(&fname);
1576 return FR_SUCCESS;
1577}
1578
1582static int op_attachment_save(struct ComposeSharedData *shared, int op)
1583{
1584 struct AttachCtx *actx = shared->adata->actx;
1585 if (!check_count(actx))
1586 return FR_NO_ACTION;
1587
1588 struct Menu *menu = shared->adata->menu;
1589 struct AttachPtr *cur_att = current_attachment(actx, menu);
1590 if (cur_att->body->type == TYPE_MULTIPART)
1591 {
1592 mutt_error(_("Can't save multipart attachments"));
1593 return FR_ERROR;
1594 }
1595
1596 mutt_save_attachment_list(actx, NULL, menu->tag_prefix, cur_att->body, NULL, menu);
1597 /* no send2hook, since this doesn't modify the message */
1598 return FR_SUCCESS;
1599}
1600
1604static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
1605{
1606 /* toggle the content-disposition between inline/attachment */
1607 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1608 shared->adata->menu);
1609 cur_att->body->disposition = (cur_att->body->disposition == DISP_INLINE) ?
1610 DISP_ATTACH :
1613 return FR_SUCCESS;
1614}
1615
1619static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
1620{
1621 if (!check_count(shared->adata->actx))
1622 return FR_NO_ACTION;
1623 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1624 shared->adata->menu);
1625 if (!mutt_is_text_part(cur_att->body))
1626 {
1627 mutt_error(_("Recoding only affects text attachments"));
1628 return FR_ERROR;
1629 }
1630 cur_att->body->noconv = !cur_att->body->noconv;
1631 if (cur_att->body->noconv)
1632 mutt_message(_("The current attachment won't be converted"));
1633 else
1634 mutt_message(_("The current attachment will be converted"));
1636 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1637 return FR_SUCCESS;
1638}
1639
1643static int op_attachment_toggle_unlink(struct ComposeSharedData *shared, int op)
1644{
1645 if (!check_count(shared->adata->actx))
1646 return FR_NO_ACTION;
1647 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1648 shared->adata->menu);
1649 cur_att->body->unlink = !cur_att->body->unlink;
1650
1652 /* No send2hook since this doesn't change the message. */
1653 return FR_SUCCESS;
1654}
1655
1659static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
1660{
1661 if (shared->adata->actx->idx[shared->adata->menu->current]->body->type != TYPE_MULTIPART)
1662 {
1663 mutt_error(_("Attachment is not 'multipart'"));
1664 return FR_ERROR;
1665 }
1666
1667 int aidx = shared->adata->menu->current;
1668 struct AttachCtx *actx = shared->adata->actx;
1669 struct Body *b = actx->idx[aidx]->body;
1670 struct Body *b_next = b->next;
1671 struct Body *b_previous = NULL;
1672 struct Body *b_parent = NULL;
1673 int parent_type = actx->idx[aidx]->parent_type;
1674 int level = actx->idx[aidx]->level;
1675
1676 // reorder body pointers
1677 if (attach_body_previous(shared->email->body, b, &b_previous))
1678 b_previous->next = b->parts;
1679 else if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
1680 b_parent->parts = b->parts;
1681 else
1682 shared->email->body = b->parts;
1683
1684 // update attachment list
1685 int i = aidx + 1;
1686 while (actx->idx[i]->level > level)
1687 {
1688 actx->idx[i]->level--;
1689 if (actx->idx[i]->level == level)
1690 {
1691 actx->idx[i]->parent_type = parent_type;
1692 // set body->next for final attachment in group
1693 if (!actx->idx[i]->body->next)
1694 actx->idx[i]->body->next = b_next;
1695 }
1696 i++;
1697 if (i == actx->idxlen)
1698 break;
1699 }
1700
1701 // free memory
1702 actx->idx[aidx]->body->parts = NULL;
1703 actx->idx[aidx]->body->next = NULL;
1704 actx->idx[aidx]->body->email = NULL;
1705 mutt_body_free(&actx->idx[aidx]->body);
1706 FREE(&actx->idx[aidx]->tree);
1707 FREE(&actx->idx[aidx]);
1708
1709 // reorder attachment list
1710 for (int j = aidx; j < (actx->idxlen - 1); j++)
1711 actx->idx[j] = actx->idx[j + 1];
1712 actx->idx[actx->idxlen - 1] = NULL;
1713 actx->idxlen--;
1714 update_menu(actx, shared->adata->menu, false);
1715
1716 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1717 return FR_SUCCESS;
1718}
1719
1723static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
1724{
1725 struct AttachCtx *actx = shared->adata->actx;
1726 if (!check_count(actx))
1727 return FR_NO_ACTION;
1728
1729 int rc = FR_NO_ACTION;
1730 struct Menu *menu = shared->adata->menu;
1731 struct BodyArray ba = ARRAY_HEAD_INITIALIZER;
1732 ba_add_tagged(&ba, actx, menu);
1733 if (ARRAY_EMPTY(&ba))
1734 goto done;
1735
1736 struct Body **bp = NULL;
1737 ARRAY_FOREACH(bp, &ba)
1738 {
1739 mutt_update_encoding(*bp, shared->sub);
1740 }
1741
1744 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1745 rc = FR_SUCCESS;
1746
1747done:
1748 ARRAY_FREE(&ba);
1749 return rc;
1750}
1751
1752// -----------------------------------------------------------------------------
1753
1757static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
1758{
1760 const char *tag = NULL;
1761 char *err = NULL;
1762 mutt_env_to_local(shared->email->env);
1763 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1764 if (shared->email->body->type == TYPE_MULTIPART)
1765 {
1766 struct Body *b = shared->email->body->parts;
1767 while (b->parts)
1768 b = b->parts;
1769 mutt_edit_headers(NONULL(c_editor), b->filename, shared->email, shared->fcc);
1770 }
1771 else
1772 {
1773 mutt_edit_headers(NONULL(c_editor), shared->email->body->filename,
1774 shared->email, shared->fcc);
1775 }
1776
1777 if (mutt_env_to_intl(shared->email->env, &tag, &err))
1778 {
1779 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
1780 FREE(&err);
1781 }
1783
1785 mutt_update_encoding(shared->email->body, shared->sub);
1786
1787 /* attachments may have been added */
1788 if (shared->adata->actx->idxlen &&
1789 shared->adata->actx->idx[shared->adata->actx->idxlen - 1]->body->next)
1790 {
1792 update_menu(shared->adata->actx, shared->adata->menu, true);
1793 }
1794
1796 /* Unconditional hook since editor was invoked */
1797 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1798 return FR_SUCCESS;
1799}
1800
1804static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
1805{
1806 if (!check_count(shared->adata->actx))
1807 return FR_NO_ACTION;
1808 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1809 shared->adata->menu);
1810 if (cur_att->body->type == TYPE_MULTIPART)
1811 {
1812 mutt_error(_("Can't edit multipart attachments"));
1813 return FR_ERROR;
1814 }
1815 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1816 mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1817 mutt_update_encoding(cur_att->body, shared->sub);
1820 /* Unconditional hook since editor was invoked */
1821 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1822 return FR_SUCCESS;
1823}
1824
1828static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
1829{
1830 const bool c_edit_headers = cs_subset_bool(shared->sub, "edit_headers");
1831 if (!c_edit_headers)
1832 {
1834 const char *const c_editor = cs_subset_string(shared->sub, "editor");
1835 mutt_edit_file(c_editor, shared->email->body->filename);
1837 mutt_update_encoding(shared->email->body, shared->sub);
1839 /* Unconditional hook since editor was invoked */
1840 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1841 return FR_SUCCESS;
1842 }
1843
1844 return op_envelope_edit_headers(shared, op);
1845}
1846
1850static int op_compose_ispell(struct ComposeSharedData *shared, int op)
1851{
1852 endwin();
1853 const char *const c_ispell = cs_subset_string(shared->sub, "ispell");
1854 char buf[PATH_MAX] = { 0 };
1855 snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), shared->email->body->filename);
1856 if (mutt_system(buf) == -1)
1857 {
1858 mutt_error(_("Error running \"%s\""), buf);
1859 return FR_ERROR;
1860 }
1861
1862 mutt_update_encoding(shared->email->body, shared->sub);
1864 return FR_SUCCESS;
1865}
1866
1870static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
1871{
1872 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1873 {
1875 return FR_ERROR;
1876 }
1877
1878 shared->rc = 1;
1879 return FR_DONE;
1880}
1881
1885static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
1886{
1887 if (!check_count(shared->adata->actx))
1888 return FR_NO_ACTION;
1889 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
1890 shared->adata->menu);
1891 if (cur_att->body->type == TYPE_MULTIPART)
1892 {
1893 mutt_error(_("Can't rename multipart attachments"));
1894 return FR_ERROR;
1895 }
1896 struct Buffer *fname = buf_pool_get();
1897 buf_strcpy(fname, cur_att->body->filename);
1898 buf_pretty_mailbox(fname);
1899 struct FileCompletionData cdata = { false, shared->mailbox, NULL, NULL };
1900 if ((mw_get_field(_("Rename to: "), fname, MUTT_COMP_NO_FLAGS, HC_FILE,
1901 &CompleteFileOps, &cdata) == 0) &&
1902 !buf_is_empty(fname))
1903 {
1904 struct stat st = { 0 };
1905 if (stat(cur_att->body->filename, &st) == -1)
1906 {
1907 /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1908 mutt_error(_("Can't stat %s: %s"), buf_string(fname), strerror(errno));
1909 buf_pool_release(&fname);
1910 return FR_ERROR;
1911 }
1912
1913 buf_expand_path(fname);
1914 if (mutt_file_rename(cur_att->body->filename, buf_string(fname)))
1915 {
1916 buf_pool_release(&fname);
1917 return FR_ERROR;
1918 }
1919
1920 mutt_str_replace(&cur_att->body->filename, buf_string(fname));
1922
1923 if (cur_att->body->stamp >= st.st_mtime)
1924 mutt_stamp_attachment(cur_att->body);
1925 mutt_message_hook(NULL, shared->email, MUTT_SEND2_HOOK);
1926 }
1927 buf_pool_release(&fname);
1928 return FR_SUCCESS;
1929}
1930
1934static int op_compose_send_message(struct ComposeSharedData *shared, int op)
1935{
1936 /* Note: We don't invoke send2-hook here, since we want to leave
1937 * users an opportunity to change settings from the ":" prompt. */
1938 if (check_attachments(shared->adata->actx, shared->sub) != 0)
1939 {
1941 return FR_NO_ACTION;
1942 }
1943
1944#ifdef MIXMASTER
1945 if (!STAILQ_EMPTY(&shared->email->chain) && (mix_check_message(shared->email) != 0))
1946 return FR_NO_ACTION;
1947#endif
1948
1949 if (!shared->fcc_set && !buf_is_empty(shared->fcc))
1950 {
1951 enum QuadOption ans = query_quadoption(_("Save a copy of this message?"),
1952 shared->sub, "copy");
1953 if (ans == MUTT_ABORT)
1954 return FR_NO_ACTION;
1955 else if (ans == MUTT_NO)
1956 buf_reset(shared->fcc);
1957 }
1958
1959 shared->rc = 0;
1960 return FR_DONE;
1961}
1962
1966static int op_compose_write_message(struct ComposeSharedData *shared, int op)
1967{
1968 int rc = FR_NO_ACTION;
1969 struct Buffer *fname = buf_pool_get();
1970 if (shared->mailbox)
1971 {
1972 buf_strcpy(fname, mailbox_path(shared->mailbox));
1973 buf_pretty_mailbox(fname);
1974 }
1975 if (shared->adata->actx->idxlen)
1976 shared->email->body = shared->adata->actx->idx[0]->body;
1977 if ((mw_enter_fname(_("Write message to mailbox"), fname, true, shared->mailbox,
1978 false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1979 !buf_is_empty(fname))
1980 {
1981 mutt_message(_("Writing message to %s ..."), buf_string(fname));
1982 buf_expand_path(fname);
1983
1984 if (shared->email->body->next)
1985 shared->email->body = mutt_make_multipart(shared->email->body);
1986
1987 if (mutt_write_fcc(buf_string(fname), shared->email, NULL, false, NULL,
1988 NULL, shared->sub) == 0)
1989 mutt_message(_("Message written"));
1990
1991 shared->email->body = mutt_remove_multipart(shared->email->body);
1992 rc = FR_SUCCESS;
1993 }
1994 buf_pool_release(&fname);
1995 return rc;
1996}
1997
2008static int op_display_headers(struct ComposeSharedData *shared, int op)
2009{
2010 if (!check_count(shared->adata->actx))
2011 return FR_NO_ACTION;
2012
2013 enum ViewAttachMode mode = MUTT_VA_REGULAR;
2014
2015 switch (op)
2016 {
2017 case OP_ATTACHMENT_VIEW:
2018 case OP_DISPLAY_HEADERS:
2019 break;
2020
2021 case OP_ATTACHMENT_VIEW_MAILCAP:
2022 mode = MUTT_VA_MAILCAP;
2023 break;
2024
2025 case OP_ATTACHMENT_VIEW_PAGER:
2026 mode = MUTT_VA_PAGER;
2027 break;
2028
2029 case OP_ATTACHMENT_VIEW_TEXT:
2030 mode = MUTT_VA_AS_TEXT;
2031 break;
2032 }
2033
2034 if (mode == MUTT_VA_REGULAR)
2035 {
2036 mutt_attach_display_loop(shared->sub, shared->adata->menu, op,
2037 shared->email, shared->adata->actx, false);
2038 }
2039 else
2040 {
2041 struct AttachPtr *cur_att = current_attachment(shared->adata->actx,
2042 shared->adata->menu);
2043 mutt_view_attachment(NULL, cur_att->body, mode, shared->email,
2044 shared->adata->actx, shared->adata->menu->win);
2045 }
2046
2048 /* no send2hook, since this doesn't modify the message */
2049 return FR_SUCCESS;
2050}
2051
2055static int op_exit(struct ComposeSharedData *shared, int op)
2056{
2057 enum QuadOption ans = query_quadoption(_("Save (postpone) draft message?"),
2058 shared->sub, "postpone");
2059 if (ans == MUTT_NO)
2060 {
2061 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2062 if (shared->adata->actx->idx[i]->unowned)
2063 shared->adata->actx->idx[i]->body->unlink = false;
2064
2065 if (!(shared->flags & MUTT_COMPOSE_NOFREEHEADER))
2066 {
2067 for (int i = 0; i < shared->adata->actx->idxlen; i++)
2068 {
2069 /* avoid freeing other attachments */
2070 shared->adata->actx->idx[i]->body->next = NULL;
2071 if (!shared->adata->actx->idx[i]->body->email)
2072 shared->adata->actx->idx[i]->body->parts = NULL;
2073 mutt_body_free(&shared->adata->actx->idx[i]->body);
2074 }
2075 }
2076 shared->rc = -1;
2077 return FR_DONE;
2078 }
2079 else if (ans == MUTT_ABORT)
2080 {
2081 return FR_NO_ACTION;
2082 }
2083
2084 return op_compose_postpone_message(shared, op);
2085}
2086
2090static int op_forget_passphrase(struct ComposeSharedData *shared, int op)
2091{
2093 return FR_SUCCESS;
2094}
2095
2096// -----------------------------------------------------------------------------
2097
2101static const struct ComposeFunction ComposeFunctions[] = {
2102 // clang-format off
2103 { OP_ATTACHMENT_ATTACH_FILE, op_attachment_attach_file },
2104 { OP_ATTACHMENT_ATTACH_KEY, op_attachment_attach_key },
2105 { OP_ATTACHMENT_ATTACH_MESSAGE, op_attachment_attach_message },
2106 { OP_ATTACHMENT_ATTACH_NEWS_MESSAGE, op_attachment_attach_message },
2107 { OP_ATTACHMENT_DETACH, op_attachment_detach },
2108 { OP_ATTACHMENT_EDIT_CONTENT_ID, op_attachment_edit_content_id },
2109 { OP_ATTACHMENT_EDIT_DESCRIPTION, op_attachment_edit_description },
2110 { OP_ATTACHMENT_EDIT_ENCODING, op_attachment_edit_encoding },
2111 { OP_ATTACHMENT_EDIT_LANGUAGE, op_attachment_edit_language },
2112 { OP_ATTACHMENT_EDIT_MIME, op_attachment_edit_mime },
2113 { OP_ATTACHMENT_EDIT_TYPE, op_attachment_edit_type },
2114 { OP_ATTACHMENT_FILTER, op_attachment_filter },
2115 { OP_ATTACHMENT_GET_ATTACHMENT, op_attachment_get_attachment },
2116 { OP_ATTACHMENT_GROUP_ALTS, op_attachment_group_alts },
2117 { OP_ATTACHMENT_GROUP_LINGUAL, op_attachment_group_lingual },
2118 { OP_ATTACHMENT_GROUP_RELATED, op_attachment_group_related },
2119 { OP_ATTACHMENT_MOVE_DOWN, op_attachment_move_down },
2120 { OP_ATTACHMENT_MOVE_UP, op_attachment_move_up },
2121 { OP_ATTACHMENT_NEW_MIME, op_attachment_new_mime },
2122 { OP_PIPE, op_attachment_filter },
2123 { OP_ATTACHMENT_PRINT, op_attachment_print },
2124 { OP_ATTACHMENT_RENAME_ATTACHMENT, op_attachment_rename_attachment },
2125 { OP_ATTACHMENT_SAVE, op_attachment_save },
2126 { OP_ATTACHMENT_TOGGLE_DISPOSITION, op_attachment_toggle_disposition },
2127 { OP_ATTACHMENT_TOGGLE_RECODE, op_attachment_toggle_recode },
2128 { OP_ATTACHMENT_TOGGLE_UNLINK, op_attachment_toggle_unlink },
2129 { OP_ATTACHMENT_UNGROUP, op_attachment_ungroup },
2130 { OP_ATTACHMENT_UPDATE_ENCODING, op_attachment_update_encoding },
2131 { OP_ATTACHMENT_VIEW, op_display_headers },
2132 { OP_ATTACHMENT_VIEW_MAILCAP, op_display_headers },
2133 { OP_ATTACHMENT_VIEW_PAGER, op_display_headers },
2134 { OP_ATTACHMENT_VIEW_TEXT, op_display_headers },
2135 { OP_COMPOSE_EDIT_FILE, op_compose_edit_file },
2136 { OP_COMPOSE_EDIT_MESSAGE, op_compose_edit_message },
2137 { OP_COMPOSE_ISPELL, op_compose_ispell },
2138 { OP_COMPOSE_POSTPONE_MESSAGE, op_compose_postpone_message },
2139 { OP_COMPOSE_RENAME_FILE, op_compose_rename_file },
2140 { OP_COMPOSE_SEND_MESSAGE, op_compose_send_message },
2141 { OP_COMPOSE_WRITE_MESSAGE, op_compose_write_message },
2142 { OP_DISPLAY_HEADERS, op_display_headers },
2143 { OP_ENVELOPE_EDIT_HEADERS, op_envelope_edit_headers },
2144 { OP_EXIT, op_exit },
2145 { OP_FORGET_PASSPHRASE, op_forget_passphrase },
2146 { 0, NULL },
2147 // clang-format on
2148};
2149
2154{
2155 if (!win)
2156 return FR_UNKNOWN;
2157
2158 struct MuttWindow *dlg = dialog_find(win);
2159 if (!dlg || !dlg->wdata)
2160 return FR_UNKNOWN;
2161
2162 int rc = FR_UNKNOWN;
2163 for (size_t i = 0; ComposeFunctions[i].op != OP_NULL; i++)
2164 {
2165 const struct ComposeFunction *fn = &ComposeFunctions[i];
2166 if (fn->op == op)
2167 {
2168 struct ComposeSharedData *shared = dlg->wdata;
2169 rc = fn->function(shared, op);
2170 break;
2171 }
2172 }
2173
2174 if (rc == FR_UNKNOWN) // Not our function
2175 return rc;
2176
2177 const char *result = dispatcher_get_retval_name(rc);
2178 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
2179
2180 return rc;
2181}
#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:155
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:160
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
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:225
static const struct ComposeFunction ComposeFunctions[]
All the NeoMutt functions that the Compose supports.
Definition: functions.c:2101
const struct MenuFuncOp OpCompose[]
Functions for the Compose Menu.
Definition: functions.c:90
static int group_attachments(struct ComposeSharedData *shared, char *subtype)
Group tagged attachments into a multipart group.
Definition: functions.c:519
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attachment to the message.
Definition: functions.c:428
static char * gen_cid(void)
Generate a random Content ID.
Definition: functions.c:242
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:453
static bool check_cid(const char *cid)
Check if a Content-ID is valid.
Definition: functions.c:258
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition: functions.c:278
const struct MenuOpSeq ComposeDefaultBindings[]
Key bindings for the Compose Menu.
Definition: functions.c:159
static int delete_attachment(struct AttachCtx *actx, int aidx)
Delete an attachment.
Definition: functions.c:341
#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.
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:1405
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:191
@ NT_EMAIL_CHANGE_ENVELOPE
Email's Envelope has changed.
Definition: email.h:190
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:1071
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:1368
#define mutt_file_fclose(FP)
Definition: file.h:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
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:1296
static int op_attachment_group_alts(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
Definition: functions.c:1282
static int op_attachment_filter(struct ComposeSharedData *shared, int op)
Filter attachment through a shell command - Implements compose_function_t -.
Definition: functions.c:1219
static int op_compose_rename_file(struct ComposeSharedData *shared, int op)
Rename/move an attached file - Implements compose_function_t -.
Definition: functions.c:1885
static int op_compose_ispell(struct ComposeSharedData *shared, int op)
Run ispell on the message - Implements compose_function_t -.
Definition: functions.c:1850
static int op_attachment_edit_description(struct ComposeSharedData *shared, int op)
Edit attachment description - Implements compose_function_t -.
Definition: functions.c:1067
static int op_attachment_group_related(struct ComposeSharedData *shared, int op)
Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
Definition: functions.c:1326
static int op_display_headers(struct ComposeSharedData *shared, int op)
Display message and toggle header weeding - Implements compose_function_t -.
Definition: functions.c:2008
static int op_attachment_attach_key(struct ComposeSharedData *shared, int op)
Attach a PGP public key - Implements compose_function_t -.
Definition: functions.c:802
static int op_compose_edit_file(struct ComposeSharedData *shared, int op)
Edit the file to be attached - Implements compose_function_t -.
Definition: functions.c:1804
static int op_attachment_rename_attachment(struct ComposeSharedData *shared, int op)
Send attachment with a different name - Implements compose_function_t -.
Definition: functions.c:1553
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:1358
static int op_compose_send_message(struct ComposeSharedData *shared, int op)
Send the message - Implements compose_function_t -.
Definition: functions.c:1934
static int op_attachment_attach_file(struct ComposeSharedData *shared, int op)
Attach files to this message - Implements compose_function_t -.
Definition: functions.c:737
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:1643
static int op_attachment_toggle_recode(struct ComposeSharedData *shared, int op)
Toggle recoding of this attachment - Implements compose_function_t -.
Definition: functions.c:1619
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:1413
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:1141
static int op_envelope_edit_headers(struct ComposeSharedData *shared, int op)
Edit the message with headers - Implements compose_function_t -.
Definition: functions.c:1757
static int op_attachment_toggle_disposition(struct ComposeSharedData *shared, int op)
Toggle disposition between inline/attachment - Implements compose_function_t -.
Definition: functions.c:1604
static int op_attachment_edit_encoding(struct ComposeSharedData *shared, int op)
Edit attachment transfer-encoding - Implements compose_function_t -.
Definition: functions.c:1098
static int op_attachment_update_encoding(struct ComposeSharedData *shared, int op)
Update an attachment's encoding info - Implements compose_function_t -.
Definition: functions.c:1723
static int op_attachment_attach_message(struct ComposeSharedData *shared, int op)
Attach messages to this message - Implements compose_function_t -.
Definition: functions.c:830
static int op_attachment_ungroup(struct ComposeSharedData *shared, int op)
Ungroup a 'multipart' attachment - Implements compose_function_t -.
Definition: functions.c:1659
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:1014
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:1246
static int op_compose_write_message(struct ComposeSharedData *shared, int op)
Write the message to a folder - Implements compose_function_t -.
Definition: functions.c:1966
static int op_attachment_edit_mime(struct ComposeSharedData *shared, int op)
Edit attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1177
static int op_compose_edit_message(struct ComposeSharedData *shared, int op)
Edit the message - Implements compose_function_t -.
Definition: functions.c:1828
static int op_attachment_detach(struct ComposeSharedData *shared, int op)
Delete the current entry - Implements compose_function_t -.
Definition: functions.c:978
static int op_compose_postpone_message(struct ComposeSharedData *shared, int op)
Save this message to send later - Implements compose_function_t -.
Definition: functions.c:1870
static int op_attachment_new_mime(struct ComposeSharedData *shared, int op)
Compose new attachment using mailcap entry - Implements compose_function_t -.
Definition: functions.c:1447
int compose_function_dispatcher(struct MuttWindow *win, int op)
Perform a Compose function - Implements function_dispatcher_t -.
Definition: functions.c:2153
struct Mailbox * dlg_index(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails -.
Definition: dlg_index.c:1071
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:2758
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
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: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:654
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
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:264
int mutt_get_tmp_attachment(struct Body *b)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:71
int mutt_compose_attachment(struct Body *b)
Create an attachment.
Definition: mutt_attach.c:119
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:418
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:433
ViewAttachMode
Options for mutt_view_attachment()
Definition: mutt_attach.h:43
@ MUTT_VA_MAILCAP
Force viewing using mailcap entry.
Definition: mutt_attach.h:45
@ MUTT_VA_REGULAR
View using default method.
Definition: mutt_attach.h:44
@ MUTT_VA_PAGER
View attachment in pager using copiousoutput mailcap.
Definition: mutt_attach.h:47
@ MUTT_VA_AS_TEXT
Force viewing as text.
Definition: mutt_attach.h:46
int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
Event loop for the Attachment menu.
Definition: recvattach.c:962
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:725
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *b)
Print a list of Attachments.
Definition: recvattach.c:888
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:181
Representation of the email's header.
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:202
bool mutt_is_text_part(const struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:442
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:554
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:328
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:412
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:286
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1319
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1634
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:596
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:559
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:1064
@ 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:85
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:111
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:51
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:342
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition: question.c:366
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
#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:105
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:421
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:606
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:453
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1052
void mutt_stamp_attachment(struct Body *b)
Timestamp an Attachment.
Definition: sendlib.c:409
#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: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: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: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 ListHead chain
Mixmaster chain.
Definition: email.h:93
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:145
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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