2 * Copyright (C) 1996-2000,2002,2007,2010,2012 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 2004 g10 Code GmbH
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 #include "mutt_curses.h"
27 #include "mutt_idna.h"
28 #include "mutt_menu.h"
29 #include "mutt_crypt.h"
44 #include "autocrypt/autocrypt.h"
54 static const char* There_are_no_attachments = N_("There are no attachments.");
56 #define CHECK_COUNT if (actx->idxlen == 0) { mutt_error _(There_are_no_attachments); break; }
58 #define CURATTACH actx->idx[actx->v2r[menu->current]]
81 HDR_ATTACH_TITLE, /* the "-- Attachments" line */
82 HDR_ATTACH /* where to start printing the attachments */
85 int HeaderPadding[HDR_ATTACH_TITLE] = {0};
86 int MaxHeaderWidth = 0;
88 #define HDR_XOFFSET MaxHeaderWidth
89 #define W (MuttIndexWindow->cols - MaxHeaderWidth)
91 static const char * const Prompts[] =
93 /* L10N: Compose menu field. May not want to translate. */
95 /* L10N: Compose menu field. May not want to translate. */
97 /* L10N: Compose menu field. May not want to translate. */
99 /* L10N: Compose menu field. May not want to translate. */
101 /* L10N: Compose menu field. May not want to translate. */
103 /* L10N: Compose menu field. May not want to translate. */
105 /* L10N: Compose menu field. May not want to translate. */
108 /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
111 /* L10N: Compose menu field. Holds "Encrypt", "Sign" related information */
114 * This string is used by the compose menu.
115 * Since it is hidden by default, it does not increase the
116 * indentation of other compose menu fields. However, if possible,
117 * it should not be longer than the other compose menu fields.
119 * Since it shares the row with "Encrypt with:", it should not be longer
120 * than 15-20 character cells.
125 The compose menu autocrypt line
131 static const struct mapping_t ComposeHelp[] = {
132 { N_("Send"), OP_COMPOSE_SEND_MESSAGE },
133 { N_("Abort"), OP_EXIT },
134 /* L10N: compose menu help line entry */
135 { N_("To"), OP_COMPOSE_EDIT_TO },
136 /* L10N: compose menu help line entry */
137 { N_("CC"), OP_COMPOSE_EDIT_CC },
138 /* L10N: compose menu help line entry */
139 { N_("Subj"), OP_COMPOSE_EDIT_SUBJECT },
140 { N_("Attach file"), OP_COMPOSE_ATTACH_FILE },
141 { N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
142 { N_("Help"), OP_HELP },
147 static const char *AutocryptRecUiFlags[] = {
148 /* L10N: Autocrypt recommendation flag: off.
149 * This is displayed when Autocrypt is turned off. */
151 /* L10N: Autocrypt recommendation flag: no.
152 * This is displayed when Autocrypt cannot encrypt to the recipients. */
154 /* L10N: Autocrypt recommendation flag: discouraged.
155 * This is displayed when Autocrypt believes encryption should not be used.
156 * This might occur if one of the recipient Autocrypt Keys has not been
157 * used recently, or if the only key available is a Gossip Header key. */
159 /* L10N: Autocrypt recommendation flag: available.
160 * This is displayed when Autocrypt believes encryption is possible, but
161 * leaves enabling it up to the sender. Probably because "prefer encrypt"
162 * is not set in both the sender and recipient keys. */
164 /* L10N: Autocrypt recommendation flag: yes.
165 * This is displayed when Autocrypt would normally enable encryption
176 autocrypt_rec_t autocrypt_rec;
177 int autocrypt_rec_override;
179 } compose_redraw_data_t;
181 static void calc_header_width_padding (int idx, const char *header, int calc_max)
185 HeaderPadding[idx] = mutt_strlen (header);
186 width = mutt_strwidth (header);
187 if (calc_max && MaxHeaderWidth < width)
188 MaxHeaderWidth = width;
189 HeaderPadding[idx] -= width;
193 /* The padding needed for each header is strlen() + max_width - strwidth().
195 * calc_header_width_padding sets each entry in HeaderPadding to
196 * strlen - width. Then, afterwards, we go through and add max_width
199 static void init_header_padding (void)
201 static short done = 0;
208 for (i = 0; i < HDR_ATTACH_TITLE; i++)
210 if (i == HDR_CRYPTINFO)
212 calc_header_width_padding (i, _(Prompts[i]), 1);
215 /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
216 * doesn't show up by default, and so can make the indentation of
217 * the other fields look funny. */
218 calc_header_width_padding (HDR_CRYPTINFO, _(Prompts[HDR_CRYPTINFO]), 0);
220 for (i = 0; i < HDR_ATTACH_TITLE; i++)
222 HeaderPadding[i] += MaxHeaderWidth;
223 if (HeaderPadding[i] < 0)
224 HeaderPadding[i] = 0;
228 static void snd_entry (char *b, size_t blen, MUTTMENU *menu, int num)
230 ATTACH_CONTEXT *actx = (ATTACH_CONTEXT *)menu->data;
232 mutt_FormatString (b, blen, 0, MuttIndexWindow->cols, NONULL (AttachFormat), mutt_attach_fmt,
233 (unsigned long)(actx->idx[actx->v2r[num]]),
234 MUTT_FORMAT_STAT_FILE | MUTT_FORMAT_ARROWCURSOR);
238 static void autocrypt_compose_menu (HEADER *msg)
240 char *prompt, *letters;
244 The compose menu autocrypt prompt.
245 (e)ncrypt enables encryption via autocrypt.
246 (c)lear sets cleartext.
247 (a)utomatic defers to the recommendation.
249 prompt = _("Autocrypt: (e)ncrypt, (c)lear, (a)utomatic? ");
252 The letter corresponding to the compose menu autocrypt prompt
253 (e)ncrypt, (c)lear, (a)utomatic
257 choice = mutt_multi_choice (prompt, letters);
261 msg->security |= (AUTOCRYPT | AUTOCRYPT_OVERRIDE);
262 msg->security &= ~(ENCRYPT | SIGN | OPPENCRYPT | INLINE);
265 msg->security &= ~AUTOCRYPT;
266 msg->security |= AUTOCRYPT_OVERRIDE;
269 msg->security &= ~AUTOCRYPT_OVERRIDE;
270 if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
271 msg->security |= OPPENCRYPT;
277 static void redraw_crypt_lines (compose_redraw_data_t *rd)
279 HEADER *msg = rd->msg;
281 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
282 mutt_window_mvprintw (MuttIndexWindow, HDR_CRYPT, 0,
283 "%*s", HeaderPadding[HDR_CRYPT], _(Prompts[HDR_CRYPT]));
286 if ((WithCrypto & (APPLICATION_PGP | APPLICATION_SMIME)) == 0)
288 addstr(_("Not supported"));
292 if ((msg->security & (ENCRYPT | SIGN)) == (ENCRYPT | SIGN))
294 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_BOTH);
295 addstr (_("Sign, Encrypt"));
297 else if (msg->security & ENCRYPT)
299 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
300 addstr (_("Encrypt"));
302 else if (msg->security & SIGN)
304 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_SIGN);
309 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_NONE);
314 if ((msg->security & (ENCRYPT | SIGN)))
316 if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP))
318 if ((msg->security & INLINE))
319 addstr (_(" (inline PGP)"));
321 addstr (_(" (PGP/MIME)"));
323 else if ((WithCrypto & APPLICATION_SMIME) &&
324 (msg->security & APPLICATION_SMIME))
325 addstr (_(" (S/MIME)"));
328 if (option (OPTCRYPTOPPORTUNISTICENCRYPT) && (msg->security & OPPENCRYPT))
329 addstr (_(" (OppEnc mode)"));
331 mutt_window_clrtoeol (MuttIndexWindow);
332 mutt_window_move (MuttIndexWindow, HDR_CRYPTINFO, 0);
333 mutt_window_clrtoeol (MuttIndexWindow);
335 if ((WithCrypto & APPLICATION_PGP)
336 && (msg->security & APPLICATION_PGP) && (msg->security & SIGN))
338 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
339 printw ("%*s", HeaderPadding[HDR_CRYPTINFO], _(Prompts[HDR_CRYPTINFO]));
341 printw ("%s", PgpSignAs ? PgpSignAs : _("<default>"));
344 if ((WithCrypto & APPLICATION_SMIME)
345 && (msg->security & APPLICATION_SMIME) && (msg->security & SIGN))
347 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
348 printw ("%*s", HeaderPadding[HDR_CRYPTINFO], _(Prompts[HDR_CRYPTINFO]));
350 printw ("%s", SmimeSignAs ? SmimeSignAs : _("<default>"));
353 if ((WithCrypto & APPLICATION_SMIME)
354 && (msg->security & APPLICATION_SMIME)
355 && (msg->security & ENCRYPT)
358 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
359 mutt_window_mvprintw (MuttIndexWindow, HDR_CRYPTINFO, 40, "%s", _("Encrypt with: "));
361 printw ("%s", NONULL(SmimeCryptAlg));
365 mutt_window_move (MuttIndexWindow, HDR_AUTOCRYPT, 0);
366 mutt_window_clrtoeol (MuttIndexWindow);
367 if (option (OPTAUTOCRYPT))
369 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
370 printw ("%*s", HeaderPadding[HDR_AUTOCRYPT], _(Prompts[HDR_AUTOCRYPT]));
372 if (msg->security & AUTOCRYPT)
374 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_ENCRYPT);
375 addstr (_("Encrypt"));
379 SETCOLOR (MT_COLOR_COMPOSE_SECURITY_NONE);
383 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
384 mutt_window_mvprintw (MuttIndexWindow, HDR_AUTOCRYPT, 40, "%s",
386 The autocrypt compose menu Recommendation field.
387 Displays the output of the recommendation engine
388 (Off, No, Discouraged, Available, Yes)
390 _("Recommendation: "));
392 printw ("%s", _(AutocryptRecUiFlags[rd->autocrypt_rec]));
397 static void update_crypt_info (compose_redraw_data_t *rd)
399 HEADER *msg = rd->msg;
401 if (option (OPTCRYPTOPPORTUNISTICENCRYPT))
402 crypt_opportunistic_encrypt (msg);
405 if (option (OPTAUTOCRYPT))
407 rd->autocrypt_rec = mutt_autocrypt_ui_recommendation (msg, NULL);
409 /* Anything that enables ENCRYPT or SIGN, or turns on SMIME
410 * overrides autocrypt, be it oppenc or the user having turned on
411 * those flags manually. */
412 if (msg->security & (ENCRYPT | SIGN | APPLICATION_SMIME))
413 msg->security &= ~(AUTOCRYPT | AUTOCRYPT_OVERRIDE);
416 if (!(msg->security & AUTOCRYPT_OVERRIDE))
418 if (rd->autocrypt_rec == AUTOCRYPT_REC_YES)
420 msg->security |= AUTOCRYPT;
421 msg->security &= ~INLINE;
424 msg->security &= ~AUTOCRYPT;
430 redraw_crypt_lines (rd);
436 static void redraw_mix_line (LIST *chain)
441 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
442 mutt_window_mvprintw (MuttIndexWindow, HDR_MIX, 0,
443 "%*s", HeaderPadding[HDR_MIX], _(Prompts[HDR_MIX]));
448 addstr ("<no chain defined>");
449 mutt_window_clrtoeol (MuttIndexWindow);
453 for (c = 12; chain; chain = chain->next)
456 if (t && t[0] == '0' && t[1] == '\0')
459 if (c + mutt_strlen (t) + 2 >= MuttIndexWindow->cols)
466 c += mutt_strlen (t) + 2;
469 #endif /* MIXMASTER */
472 check_attachments(ATTACH_CONTEXT *actx)
476 BUFFER *pretty = NULL, *msg = NULL;
478 for (i = 0; i < actx->idxlen; i++)
480 if (stat(actx->idx[i]->content->filename, &st) != 0)
483 pretty = mutt_buffer_pool_get ();
484 mutt_buffer_strcpy (pretty, actx->idx[i]->content->filename);
485 mutt_buffer_pretty_mailbox (pretty);
487 This message is displayed in the compose menu when an attachment
488 doesn't stat. %d is the attachment number and %s is the
490 The filename is located last to avoid a long path hiding the
493 mutt_error (_("Attachment #%d no longer exists: %s"),
494 i+1, mutt_b2s (pretty));
498 if (actx->idx[i]->content->stamp < st.st_mtime)
501 pretty = mutt_buffer_pool_get ();
502 mutt_buffer_strcpy (pretty, actx->idx[i]->content->filename);
503 mutt_buffer_pretty_mailbox (pretty);
506 msg = mutt_buffer_pool_get ();
508 This message is displayed in the compose menu when an attachment
509 is modified behind the scenes. %d is the attachment number
510 and %s is the attachment filename.
511 The filename is located last to avoid a long path hiding the
514 mutt_buffer_printf (msg, _("Attachment #%d modified. Update encoding for %s?"),
515 i+1, mutt_b2s (pretty));
517 if ((r = mutt_yesorno (mutt_b2s (msg), MUTT_YES)) == MUTT_YES)
518 mutt_update_encoding (actx->idx[i]->content);
527 mutt_buffer_pool_release (&pretty);
528 mutt_buffer_pool_release (&msg);
532 static void draw_envelope_addr (int line, ADDRESS *addr)
534 char buf[LONG_STRING];
537 rfc822_write_address (buf, sizeof (buf), addr, 1);
538 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
539 mutt_window_mvprintw (MuttIndexWindow, line, 0,
540 "%*s", HeaderPadding[line], _(Prompts[line]));
542 mutt_paddstr (W, buf);
545 static void draw_envelope (compose_redraw_data_t *rd)
547 HEADER *msg = rd->msg;
550 draw_envelope_addr (HDR_FROM, msg->env->from);
551 draw_envelope_addr (HDR_TO, msg->env->to);
552 draw_envelope_addr (HDR_CC, msg->env->cc);
553 draw_envelope_addr (HDR_BCC, msg->env->bcc);
555 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
556 mutt_window_mvprintw (MuttIndexWindow, HDR_SUBJECT, 0,
557 "%*s", HeaderPadding[HDR_SUBJECT], _(Prompts[HDR_SUBJECT]));
559 mutt_paddstr (W, NONULL (msg->env->subject));
561 draw_envelope_addr (HDR_REPLYTO, msg->env->reply_to);
563 SETCOLOR (MT_COLOR_COMPOSE_HEADER);
564 mutt_window_mvprintw (MuttIndexWindow, HDR_FCC, 0,
565 "%*s", HeaderPadding[HDR_FCC], _(Prompts[HDR_FCC]));
567 mutt_paddstr (W, fcc);
570 redraw_crypt_lines (rd);
573 redraw_mix_line (msg->chain);
576 SETCOLOR (MT_COLOR_STATUS);
577 mutt_window_mvaddstr (MuttIndexWindow, HDR_ATTACH_TITLE, 0, _("-- Attachments"));
578 mutt_window_clrtoeol (MuttIndexWindow);
583 static void edit_address_list (int line, ADDRESS **addr)
585 char buf[HUGE_STRING] = ""; /* needs to be large for alias expansion */
588 mutt_addrlist_to_local (*addr);
589 rfc822_write_address (buf, sizeof (buf), *addr, 0);
590 if (mutt_get_field (_(Prompts[line]), buf, sizeof (buf), MUTT_ALIAS) == 0)
592 rfc822_free_address (addr);
593 *addr = mutt_parse_adrlist (*addr, buf);
594 *addr = mutt_expand_aliases (*addr);
597 if (mutt_addrlist_to_intl (*addr, &err) != 0)
599 mutt_error (_("Warning: '%s' is a bad IDN."), err);
604 /* redraw the expanded list so the user can see the result */
606 rfc822_write_address (buf, sizeof (buf), *addr, 1);
607 mutt_window_move (MuttIndexWindow, line, HDR_XOFFSET);
608 mutt_paddstr (W, buf);
611 static int delete_attachment (ATTACH_CONTEXT *actx, int x)
613 ATTACHPTR **idx = actx->idx;
614 int rindex = actx->v2r[x];
617 if (rindex == 0 && actx->idxlen == 1)
619 mutt_error _("You may not delete the only attachment.");
620 idx[rindex]->content->tagged = 0;
624 for (y = 0; y < actx->idxlen; y++)
626 if (idx[y]->content->next == idx[rindex]->content)
628 idx[y]->content->next = idx[rindex]->content->next;
633 idx[rindex]->content->next = NULL;
634 /* mutt_make_message_attach() creates body->parts, shared by
635 * body->hdr->content. If we NULL out that, it creates a memory
636 * leak because mutt_free_body() frees body->parts, not
637 * body->hdr->content.
639 * Other ci_send_message() message constructors are careful to free
640 * any body->parts, removing depth:
641 * - mutt_prepare_template() used by postponed, resent, and draft files
642 * - mutt_copy_body() used by the recvattach menu and $forward_attachments.
644 * I believe it is safe to completely remove the "content->parts =
645 * NULL" statement. But for safety, am doing so only for the case
646 * it must be avoided: message attachments.
648 if (!idx[rindex]->content->hdr)
649 idx[rindex]->content->parts = NULL;
650 mutt_free_body (&(idx[rindex]->content));
651 FREE (&idx[rindex]->tree);
653 for (; rindex < actx->idxlen - 1; rindex++)
654 idx[rindex] = idx[rindex+1];
655 idx[actx->idxlen - 1] = NULL;
661 static void mutt_gen_compose_attach_list (ATTACH_CONTEXT *actx,
668 for (; m; m = m->next)
670 if (m->type == TYPEMULTIPART && m->parts
671 && (!(WithCrypto & APPLICATION_PGP) || !mutt_is_multipart_encrypted(m))
674 mutt_gen_compose_attach_list (actx, m->parts, m->type, level);
678 new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
679 mutt_actx_add_attach (actx, new);
682 new->parent_type = parent_type;
685 /* We don't support multipart messages in the compose menu yet */
690 static void mutt_update_compose_menu (ATTACH_CONTEXT *actx, MUTTMENU *menu, int init)
694 mutt_gen_compose_attach_list (actx, actx->hdr->content, -1, 0);
695 mutt_attach_init (actx);
699 mutt_update_tree (actx);
701 menu->max = actx->vcount;
704 if (menu->current >= menu->max)
705 menu->current = menu->max - 1;
710 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
713 static void update_idx (MUTTMENU *menu, ATTACH_CONTEXT *actx, ATTACHPTR *new)
715 new->level = (actx->idxlen > 0) ? actx->idx[actx->idxlen-1]->level : 0;
717 actx->idx[actx->idxlen - 1]->content->next = new->content;
718 new->content->aptr = new;
719 mutt_actx_add_attach (actx, new);
720 mutt_update_compose_menu (actx, menu, 0);
721 menu->current = actx->vcount - 1;
726 * cum_attachs_size: Cumulative Attachments Size
728 * Returns the total number of bytes used by the attachments in the
729 * attachment list _after_ content-transfer-encodings have been
734 static unsigned long cum_attachs_size (MUTTMENU *menu)
738 ATTACH_CONTEXT *actx = menu->data;
739 ATTACHPTR **idx = actx->idx;
743 for (i = 0, s = 0; i < actx->idxlen; i++)
748 b->content = mutt_get_content_info (b->filename, b);
750 if ((info = b->content))
754 case ENCQUOTEDPRINTABLE:
755 s += 3 * (info->lobin + info->hibin) + info->ascii + info->crlf;
758 s += (4 * (info->lobin + info->hibin + info->ascii + info->crlf)) / 3;
761 s += info->lobin + info->hibin + info->ascii + info->crlf;
770 /* prototype for use below */
771 static void compose_status_line (char *buf, size_t buflen, size_t col, int cols, MUTTMENU *menu,
775 * compose_format_str()
777 * %a = total number of attachments
778 * %h = hostname [option]
779 * %l = approx. length of current message (in bytes)
782 * This function is similar to status_format_str(). Look at that function for
783 * help when modifying this function.
787 compose_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src,
788 const char *prefix, const char *ifstring,
789 const char *elsestring,
790 unsigned long data, format_flag flags)
792 char fmt[SHORT_STRING], tmp[SHORT_STRING];
793 int optional = (flags & MUTT_FORMAT_OPTIONAL);
794 MUTTMENU *menu = (MUTTMENU *) data;
799 case 'a': /* total number of attachments */
800 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
801 snprintf (buf, buflen, fmt, menu->max);
804 case 'h': /* hostname */
805 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
806 snprintf (buf, buflen, fmt, NONULL(Hostname));
809 case 'l': /* approx length of current message in bytes */
810 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
811 mutt_pretty_size (tmp, sizeof (tmp), menu ? cum_attachs_size(menu) : 0);
812 snprintf (buf, buflen, fmt, tmp);
816 snprintf (fmt, sizeof (fmt), "Mutt %%s");
817 snprintf (buf, buflen, fmt, MUTT_VERSION);
825 snprintf (buf, buflen, "%%%s%c", prefix, op);
830 compose_status_line (buf, buflen, col, cols, menu, ifstring);
831 else if (flags & MUTT_FORMAT_OPTIONAL)
832 compose_status_line (buf, buflen, col, cols, menu, elsestring);
837 static void compose_status_line (char *buf, size_t buflen, size_t col, int cols,
838 MUTTMENU *menu, const char *p)
840 mutt_FormatString (buf, buflen, col, cols, p, compose_format_str,
841 (unsigned long) menu, 0);
844 static void compose_menu_redraw (MUTTMENU *menu)
846 char buf[LONG_STRING];
847 compose_redraw_data_t *rd = menu->redraw_data;
852 if (menu->redraw & REDRAW_FULL)
854 menu_redraw_full (menu);
857 menu->offset = HDR_ATTACH;
858 menu->pagelen = MuttIndexWindow->rows - HDR_ATTACH;
861 menu_check_recenter (menu);
863 if (menu->redraw & REDRAW_STATUS)
865 compose_status_line (buf, sizeof (buf), 0, MuttStatusWindow->cols, menu, NONULL(ComposeFormat));
866 mutt_window_move (MuttStatusWindow, 0, 0);
867 SETCOLOR (MT_COLOR_STATUS);
868 mutt_paddstr (MuttStatusWindow->cols, buf);
870 menu->redraw &= ~REDRAW_STATUS;
874 if (menu->redraw & REDRAW_SIDEBAR)
875 menu_redraw_sidebar (menu);
878 if (menu->redraw & REDRAW_INDEX)
879 menu_redraw_index (menu);
880 else if (menu->redraw & (REDRAW_MOTION | REDRAW_MOTION_RESYNCH))
881 menu_redraw_motion (menu);
882 else if (menu->redraw == REDRAW_CURRENT)
883 menu_redraw_current (menu);
889 * 1 message should be postponed
893 int mutt_compose_menu (HEADER *msg, /* structure for new message */
894 char *fcc, /* where to save a copy of the message */
896 HEADER *cur, /* current message */
899 char helpstr[LONG_STRING];
900 char buf[LONG_STRING];
901 BUFFER *fname = NULL;
903 ATTACH_CONTEXT *actx;
906 int r = -1; /* return value */
909 int fccSet = 0; /* has the user edited the Fcc: field ? */
910 CONTEXT *ctx = NULL, *this = NULL;
911 /* Sort, SortAux could be changed in mutt_index_menu() */
912 int oldSort, oldSortAux;
914 compose_redraw_data_t rd = {0};
916 init_header_padding ();
921 menu = mutt_new_menu (MENU_COMPOSE);
922 menu->offset = HDR_ATTACH;
923 menu->make_entry = snd_entry;
924 menu->tag = mutt_tag_attach;
925 menu->help = mutt_compile_help (helpstr, sizeof (helpstr), MENU_COMPOSE, ComposeHelp);
926 menu->custom_menu_redraw = compose_menu_redraw;
927 menu->redraw_data = &rd;
928 mutt_push_current_menu (menu);
930 actx = safe_calloc (sizeof(ATTACH_CONTEXT), 1);
932 mutt_update_compose_menu (actx, menu, 1);
934 update_crypt_info (&rd);
936 /* Since this is rather long lived, we don't use the pool */
937 fname = mutt_buffer_new ();
938 mutt_buffer_increase_size (fname, LONG_STRING);
942 switch (op = mutt_menuLoop (menu))
944 case OP_COMPOSE_EDIT_FROM:
945 edit_address_list (HDR_FROM, &msg->env->from);
946 update_crypt_info (&rd);
947 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
949 case OP_COMPOSE_EDIT_TO:
950 edit_address_list (HDR_TO, &msg->env->to);
951 update_crypt_info (&rd);
952 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
954 case OP_COMPOSE_EDIT_BCC:
955 edit_address_list (HDR_BCC, &msg->env->bcc);
956 update_crypt_info (&rd);
957 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
959 case OP_COMPOSE_EDIT_CC:
960 edit_address_list (HDR_CC, &msg->env->cc);
961 update_crypt_info (&rd);
962 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
964 case OP_COMPOSE_EDIT_SUBJECT:
965 if (msg->env->subject)
966 strfcpy (buf, msg->env->subject, sizeof (buf));
969 if (mutt_get_field (_("Subject: "), buf, sizeof (buf), 0) == 0)
971 mutt_str_replace (&msg->env->subject, buf);
972 mutt_window_move (MuttIndexWindow, HDR_SUBJECT, HDR_XOFFSET);
973 if (msg->env->subject)
974 mutt_paddstr (W, msg->env->subject);
976 mutt_window_clrtoeol(MuttIndexWindow);
978 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
980 case OP_COMPOSE_EDIT_REPLY_TO:
981 edit_address_list (HDR_REPLYTO, &msg->env->reply_to);
982 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
984 case OP_COMPOSE_EDIT_FCC:
985 strfcpy (buf, fcc, sizeof (buf));
986 if (mutt_get_field (_("Fcc: "), buf, sizeof (buf), MUTT_FILE | MUTT_CLEAR) == 0)
988 strfcpy (fcc, buf, fcclen);
989 mutt_pretty_mailbox (fcc, fcclen);
990 mutt_window_move (MuttIndexWindow, HDR_FCC, HDR_XOFFSET);
991 mutt_paddstr (W, fcc);
994 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
996 case OP_COMPOSE_EDIT_MESSAGE:
997 if (Editor && (mutt_strcmp ("builtin", Editor) != 0) && !option (OPTEDITHDRS))
999 mutt_rfc3676_space_unstuff (msg);
1000 mutt_edit_file (Editor, msg->content->filename);
1001 mutt_rfc3676_space_stuff (msg);
1002 mutt_update_encoding (msg->content);
1003 menu->redraw = REDRAW_FULL;
1004 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1008 case OP_COMPOSE_EDIT_HEADERS:
1009 mutt_rfc3676_space_unstuff (msg);
1011 if (mutt_strcmp ("builtin", Editor) != 0 &&
1012 (op == OP_COMPOSE_EDIT_HEADERS ||
1013 (op == OP_COMPOSE_EDIT_MESSAGE && option (OPTEDITHDRS))))
1015 char *tag = NULL, *err = NULL;
1016 mutt_env_to_local (msg->env);
1017 mutt_edit_headers (NONULL (Editor), msg->content->filename, msg,
1019 if (mutt_env_to_intl (msg->env, &tag, &err))
1021 mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err);
1024 update_crypt_info (&rd);
1028 /* this is grouped with OP_COMPOSE_EDIT_HEADERS because the
1029 attachment list could change if the user invokes ~v to edit
1030 the message with headers, in which we need to execute the
1031 code below to regenerate the index array */
1032 mutt_builtin_editor (msg->content->filename, msg, cur);
1035 mutt_rfc3676_space_stuff (msg);
1036 mutt_update_encoding (msg->content);
1038 /* attachments may have been added */
1039 if (actx->idxlen && actx->idx[actx->idxlen - 1]->content->next)
1041 mutt_actx_free_entries (actx);
1042 mutt_update_compose_menu (actx, menu, 1);
1045 menu->redraw = REDRAW_FULL;
1046 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1051 case OP_COMPOSE_ATTACH_KEY:
1052 if (!(WithCrypto & APPLICATION_PGP))
1055 new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
1056 if ((new->content = crypt_pgp_make_key_attachment(NULL)) != NULL)
1058 update_idx (menu, actx, new);
1059 menu->redraw |= REDRAW_INDEX;
1064 menu->redraw |= REDRAW_STATUS;
1066 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1070 case OP_COMPOSE_ATTACH_FILE:
1072 char *prompt, **files;
1073 int error, numfiles;
1075 mutt_buffer_clear (fname);
1076 prompt = _("Attach file");
1080 if ((_mutt_buffer_enter_fname (prompt, fname, 0, 1, &files, &numfiles) == -1) ||
1081 !mutt_buffer_len (fname))
1086 mutt_message _("Attaching selected files...");
1087 for (i = 0; i < numfiles; i++)
1089 char *att = files[i];
1090 new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
1092 new->content = mutt_make_file_attach (att);
1093 if (new->content != NULL)
1094 update_idx (menu, actx, new);
1098 mutt_error (_("Unable to attach %s!"), att);
1105 if (!error) mutt_clear_error ();
1107 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1109 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1112 case OP_COMPOSE_ATTACH_MESSAGE:
1117 mutt_buffer_clear (fname);
1118 prompt = _("Open mailbox to attach message from");
1122 mutt_buffer_strcpy (fname, NONULL (Context->path));
1123 mutt_buffer_pretty_mailbox (fname);
1126 if ((mutt_buffer_enter_fname (prompt, fname, 1) == -1) ||
1127 !mutt_buffer_len (fname))
1130 mutt_buffer_expand_path (fname);
1132 if (!mx_is_imap (mutt_b2s (fname)))
1135 if (!mx_is_pop (mutt_b2s (fname)))
1137 /* check to make sure the file exists and is readable */
1138 if (access (mutt_b2s (fname), R_OK) == -1)
1140 mutt_perror (mutt_b2s (fname));
1144 menu->redraw = REDRAW_FULL;
1146 ctx = mx_open_mailbox (mutt_b2s (fname), MUTT_READONLY, NULL);
1149 mutt_error (_("Unable to open mailbox %s"), mutt_b2s (fname));
1155 mx_close_mailbox (ctx, NULL);
1157 mutt_error _("No messages in that folder.");
1161 this = Context; /* remember current folder and sort methods*/
1162 oldSort = Sort; oldSortAux = SortAux;
1165 set_option(OPTATTACHMSG);
1166 mutt_message _("Tag the messages you want to attach!");
1167 close = mutt_index_menu ();
1168 unset_option(OPTATTACHMSG);
1172 /* go back to the folder we started from */
1174 /* Restore old $sort and $sort_aux */
1176 SortAux = oldSortAux;
1177 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1181 for (i = 0; i < Context->msgcount; i++)
1183 h = Context->hdrs[i];
1186 new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
1187 new->content = mutt_make_message_attach (Context, h, 1);
1188 if (new->content != NULL)
1189 update_idx (menu, actx, new);
1192 mutt_error _("Unable to attach!");
1197 menu->redraw |= REDRAW_FULL;
1199 if (close == OP_QUIT)
1200 mx_close_mailbox (Context, NULL);
1202 mx_fastclose_mailbox (Context);
1205 /* go back to the folder we started from */
1207 /* Restore old $sort and $sort_aux */
1209 SortAux = oldSortAux;
1211 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1216 if (CURATTACH->unowned)
1217 CURATTACH->content->unlink = 0;
1218 if (delete_attachment (actx, menu->current) == -1)
1220 mutt_update_compose_menu (actx, menu, 0);
1221 if (menu->current == 0)
1222 msg->content = actx->idx[0]->content;
1224 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1227 case OP_COMPOSE_TOGGLE_RECODE:
1230 if (!mutt_is_text_part (CURATTACH->content))
1232 mutt_error (_("Recoding only affects text attachments."));
1235 CURATTACH->content->noconv = !CURATTACH->content->noconv;
1236 if (CURATTACH->content->noconv)
1237 mutt_message (_("The current attachment won't be converted."));
1239 mutt_message (_("The current attachment will be converted."));
1240 menu->redraw = REDRAW_CURRENT;
1241 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1245 case OP_COMPOSE_EDIT_DESCRIPTION:
1248 CURATTACH->content->description ?
1249 CURATTACH->content->description : "",
1251 /* header names should not be translated */
1252 if (mutt_get_field ("Description: ", buf, sizeof (buf), 0) == 0)
1254 mutt_str_replace (&CURATTACH->content->description, buf);
1255 menu->redraw = REDRAW_CURRENT;
1257 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1260 case OP_COMPOSE_UPDATE_ENCODING:
1262 if (menu->tagprefix)
1265 for (top = msg->content; top; top = top->next)
1268 mutt_update_encoding (top);
1270 menu->redraw = REDRAW_FULL;
1274 mutt_update_encoding(CURATTACH->content);
1275 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1277 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1280 case OP_COMPOSE_TOGGLE_DISPOSITION:
1281 /* toggle the content-disposition between inline/attachment */
1282 CURATTACH->content->disposition = (CURATTACH->content->disposition == DISPINLINE) ? DISPATTACH : DISPINLINE;
1283 menu->redraw = REDRAW_CURRENT;
1289 mutt_edit_content_type (NULL, CURATTACH->content, NULL);
1291 /* this may have been a change to text/something */
1292 mutt_update_encoding (CURATTACH->content);
1294 menu->redraw = REDRAW_CURRENT;
1296 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1299 case OP_COMPOSE_EDIT_ENCODING:
1301 strfcpy (buf, ENCODING (CURATTACH->content->encoding),
1303 if (mutt_get_field ("Content-Transfer-Encoding: ", buf,
1304 sizeof (buf), 0) == 0 && buf[0])
1306 if ((i = mutt_check_encoding (buf)) != ENCOTHER && i != ENCUUENCODED)
1308 CURATTACH->content->encoding = i;
1309 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1313 mutt_error _("Invalid encoding.");
1315 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1318 case OP_COMPOSE_SEND_MESSAGE:
1320 /* Note: We don't invoke send2-hook here, since we want to leave
1321 * users an opportunity to change settings from the ":" prompt.
1324 if (check_attachments(actx) != 0)
1326 menu->redraw = REDRAW_FULL;
1332 if (msg->chain && mix_check_message (msg) != 0)
1336 if (!fccSet && *fcc)
1338 if ((i = query_quadoption (OPT_COPY,
1339 _("Save a copy of this message?"))) == -1)
1341 else if (i == MUTT_NO)
1349 case OP_COMPOSE_EDIT_FILE:
1351 mutt_edit_file (NONULL(Editor), CURATTACH->content->filename);
1352 mutt_update_encoding (CURATTACH->content);
1353 menu->redraw = REDRAW_CURRENT | REDRAW_STATUS;
1354 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1357 case OP_COMPOSE_TOGGLE_UNLINK:
1359 CURATTACH->content->unlink = !CURATTACH->content->unlink;
1360 menu->redraw = REDRAW_INDEX;
1361 /* No send2hook since this doesn't change the message. */
1364 case OP_COMPOSE_GET_ATTACHMENT:
1366 if (menu->tagprefix)
1369 for (top = msg->content; top; top = top->next)
1372 mutt_get_tmp_attachment(top);
1374 menu->redraw = REDRAW_FULL;
1376 else if (mutt_get_tmp_attachment(CURATTACH->content) == 0)
1377 menu->redraw = REDRAW_CURRENT;
1379 /* No send2hook since this doesn't change the message. */
1382 case OP_COMPOSE_RENAME_ATTACHMENT:
1388 if (CURATTACH->content->d_filename)
1389 src = CURATTACH->content->d_filename;
1391 src = CURATTACH->content->filename;
1392 mutt_buffer_strcpy (fname, mutt_basename (NONULL (src)));
1393 ret = mutt_buffer_get_field (_("Send attachment with name: "),
1398 * As opposed to RENAME_FILE, we don't check fname[0] because it's
1399 * valid to set an empty string here, to erase what was set
1401 mutt_str_replace (&CURATTACH->content->d_filename, mutt_b2s (fname));
1402 menu->redraw = REDRAW_CURRENT;
1407 case OP_COMPOSE_RENAME_FILE:
1409 mutt_buffer_strcpy (fname, CURATTACH->content->filename);
1410 mutt_buffer_pretty_mailbox (fname);
1412 if ((mutt_buffer_get_field (_("Rename to: "), fname, MUTT_FILE) == 0) &&
1413 mutt_buffer_len (fname))
1415 if (stat(CURATTACH->content->filename, &st) == -1)
1418 "stat" is a system call. Do "man 2 stat" for more information. */
1419 mutt_error (_("Can't stat %s: %s"), mutt_b2s (fname), strerror (errno));
1423 mutt_buffer_expand_path (fname);
1424 if (mutt_rename_file (CURATTACH->content->filename, mutt_b2s (fname)))
1427 mutt_str_replace (&CURATTACH->content->filename, mutt_b2s (fname));
1428 menu->redraw = REDRAW_CURRENT;
1430 if (CURATTACH->content->stamp >= st.st_mtime)
1431 mutt_stamp_attachment(CURATTACH->content);
1434 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1437 case OP_COMPOSE_NEW_MIME:
1444 mutt_window_clearline (MuttMessageWindow, 0);
1445 mutt_buffer_clear (fname);
1446 if ((mutt_buffer_get_field (_("New file: "), fname, MUTT_FILE) != 0) ||
1447 !mutt_buffer_len (fname))
1449 mutt_buffer_expand_path (fname);
1451 /* Call to lookup_mime_type () ? maybe later */
1453 if (mutt_get_field ("Content-Type: ", type, sizeof (type), 0) != 0
1457 if (!(p = strchr (type, '/')))
1459 mutt_error _("Content-Type is of the form base/sub");
1463 if ((itype = mutt_check_mime_type (type)) == TYPEOTHER)
1465 mutt_error (_("Unknown Content-Type %s"), type);
1469 new = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
1470 /* Touch the file */
1471 if (!(fp = safe_fopen (mutt_b2s (fname), "w")))
1473 mutt_error (_("Can't create file %s"), mutt_b2s (fname));
1479 if ((new->content = mutt_make_file_attach (mutt_b2s (fname))) == NULL)
1481 mutt_error _("What we have here is a failure to make an attachment");
1485 update_idx (menu, actx, new);
1487 CURATTACH->content->type = itype;
1488 mutt_str_replace (&CURATTACH->content->subtype, p);
1489 CURATTACH->content->unlink = 1;
1490 menu->redraw |= REDRAW_INDEX | REDRAW_STATUS;
1492 if (mutt_compose_attachment (CURATTACH->content))
1494 mutt_update_encoding (CURATTACH->content);
1495 menu->redraw = REDRAW_FULL;
1498 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1501 case OP_COMPOSE_EDIT_MIME:
1503 if (mutt_edit_attachment (CURATTACH->content))
1505 mutt_update_encoding (CURATTACH->content);
1506 menu->redraw = REDRAW_FULL;
1508 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1511 case OP_VIEW_ATTACH:
1512 case OP_DISPLAY_HEADERS:
1514 mutt_attach_display_loop (menu, op, NULL, actx, 0);
1515 menu->redraw = REDRAW_FULL;
1516 /* no send2hook, since this doesn't modify the message */
1521 mutt_save_attachment_list (actx, NULL, menu->tagprefix, CURATTACH->content, NULL, menu);
1522 /* no send2hook, since this doesn't modify the message */
1527 mutt_print_attachment_list (actx, NULL, menu->tagprefix, CURATTACH->content);
1528 /* no send2hook, since this doesn't modify the message */
1534 mutt_pipe_attachment_list (actx, NULL, menu->tagprefix, CURATTACH->content, op == OP_FILTER);
1535 if (op == OP_FILTER) /* cte might have changed */
1536 menu->redraw = menu->tagprefix ? REDRAW_FULL : REDRAW_CURRENT;
1537 menu->redraw |= REDRAW_STATUS;
1538 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1542 if ((i = query_quadoption (OPT_POSTPONE, _("Postpone this message?"))) == MUTT_NO)
1544 for (i = 0; i < actx->idxlen; i++)
1545 if (actx->idx[i]->unowned)
1546 actx->idx[i]->content->unlink = 0;
1548 if (!(flags & MUTT_COMPOSE_NOFREEHEADER))
1550 for (i = 0; i < actx->idxlen; i++)
1552 /* avoid freeing other attachments */
1553 actx->idx[i]->content->next = NULL;
1554 /* See the comment in delete_attachment() */
1555 if (!actx->idx[i]->content->hdr)
1556 actx->idx[i]->content->parts = NULL;
1557 mutt_free_body (&actx->idx[i]->content);
1567 /* fall through to postpone! */
1569 case OP_COMPOSE_POSTPONE_MESSAGE:
1571 if (check_attachments(actx) != 0)
1573 menu->redraw = REDRAW_FULL;
1581 case OP_COMPOSE_ISPELL:
1583 snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename);
1584 if (mutt_system (buf) == -1)
1585 mutt_error (_("Error running \"%s\"!"), buf);
1588 mutt_update_encoding (msg->content);
1589 menu->redraw |= REDRAW_STATUS;
1593 case OP_COMPOSE_WRITE_MESSAGE:
1595 mutt_buffer_clear (fname);
1598 mutt_buffer_strcpy (fname, NONULL (Context->path));
1599 mutt_buffer_pretty_mailbox (fname);
1602 msg->content = actx->idx[0]->content;
1603 if ((mutt_buffer_enter_fname (_("Write message to mailbox"), fname,
1605 mutt_buffer_len (fname))
1607 mutt_message (_("Writing message to %s ..."), mutt_b2s (fname));
1608 mutt_buffer_expand_path (fname);
1610 if (msg->content->next)
1611 msg->content = mutt_make_multipart (msg->content);
1613 if (mutt_write_fcc (mutt_b2s (fname), msg, NULL, 0, NULL) == 0)
1614 mutt_message _("Message written.");
1616 msg->content = mutt_remove_multipart (msg->content);
1622 case OP_COMPOSE_PGP_MENU:
1623 if (!(WithCrypto & APPLICATION_PGP))
1625 if (!crypt_has_module_backend (APPLICATION_PGP))
1627 mutt_error _("No PGP backend configured");
1630 if ((WithCrypto & APPLICATION_SMIME)
1631 && (msg->security & APPLICATION_SMIME))
1633 if (msg->security & (ENCRYPT | SIGN))
1635 if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
1636 MUTT_YES) != MUTT_YES)
1638 mutt_clear_error ();
1641 msg->security &= ~(ENCRYPT | SIGN);
1643 msg->security &= ~APPLICATION_SMIME;
1644 msg->security |= APPLICATION_PGP;
1645 update_crypt_info (&rd);
1647 msg->security = crypt_pgp_send_menu (msg);
1648 update_crypt_info (&rd);
1649 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1653 case OP_FORGET_PASSPHRASE:
1654 crypt_forget_passphrase ();
1658 case OP_COMPOSE_SMIME_MENU:
1659 if (!(WithCrypto & APPLICATION_SMIME))
1661 if (!crypt_has_module_backend (APPLICATION_SMIME))
1663 mutt_error _("No S/MIME backend configured");
1667 if ((WithCrypto & APPLICATION_PGP)
1668 && (msg->security & APPLICATION_PGP))
1670 if (msg->security & (ENCRYPT | SIGN))
1672 if (mutt_yesorno (_("PGP already selected. Clear & continue ? "),
1673 MUTT_YES) != MUTT_YES)
1675 mutt_clear_error ();
1678 msg->security &= ~(ENCRYPT | SIGN);
1680 msg->security &= ~APPLICATION_PGP;
1681 msg->security |= APPLICATION_SMIME;
1682 update_crypt_info (&rd);
1684 msg->security = crypt_smime_send_menu(msg);
1685 update_crypt_info (&rd);
1686 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1691 case OP_COMPOSE_MIX:
1693 mix_make_chain (&msg->chain);
1694 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1698 #ifdef USE_AUTOCRYPT
1699 case OP_COMPOSE_AUTOCRYPT_MENU:
1700 if (!option (OPTAUTOCRYPT))
1703 if ((WithCrypto & APPLICATION_SMIME)
1704 && (msg->security & APPLICATION_SMIME))
1706 if (msg->security & (ENCRYPT | SIGN))
1708 if (mutt_yesorno (_("S/MIME already selected. Clear & continue ? "),
1709 MUTT_YES) != MUTT_YES)
1711 mutt_clear_error ();
1714 msg->security &= ~(ENCRYPT | SIGN);
1716 msg->security &= ~APPLICATION_SMIME;
1717 msg->security |= APPLICATION_PGP;
1718 update_crypt_info (&rd);
1720 autocrypt_compose_menu (msg);
1721 update_crypt_info (&rd);
1722 mutt_message_hook (NULL, msg, MUTT_SEND2HOOK);
1728 mutt_buffer_free (&fname);
1730 #ifdef USE_AUTOCRYPT
1731 /* This is a fail-safe to make sure the bit isn't somehow turned
1732 * on. The user could have disabled the option after setting AUTOCRYPT,
1733 * or perhaps resuming or replying to an autocrypt message.
1735 if (!option (OPTAUTOCRYPT))
1736 msg->security &= ~AUTOCRYPT;
1739 mutt_pop_current_menu (menu);
1740 mutt_menuDestroy (&menu);
1743 msg->content = actx->idx[0]->content;
1745 msg->content = NULL;
1747 mutt_free_attach_context (&actx);