NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
window.c
Go to the documentation of this file.
1
61#include "config.h"
62#include <stdbool.h>
63#include <stdio.h>
64#include "private.h"
65#include "mutt/lib.h"
66#include "address/lib.h"
67#include "config/lib.h"
68#include "email/lib.h"
69#include "core/lib.h"
70#include "gui/lib.h"
71#include "color/lib.h"
72#include "ncrypt/lib.h"
73#include "functions.h"
74#include "globals.h" // IWYU pragma: keep
75#include "wdata.h"
76#ifdef ENABLE_NLS
77#include <libintl.h>
78#endif
79
81#define MAX_ADDR_ROWS 5
82
84#define MAX_USER_HDR_ROWS 5
85
88
89const char *const Prompts[] = {
90 /* L10N: Compose menu field. May not want to translate. */
91 N_("From: "),
92 /* L10N: Compose menu field. May not want to translate. */
93 N_("To: "),
94 /* L10N: Compose menu field. May not want to translate. */
95 N_("Cc: "),
96 /* L10N: Compose menu field. May not want to translate. */
97 N_("Bcc: "),
98 /* L10N: Compose menu field. May not want to translate. */
99 N_("Subject: "),
100 /* L10N: Compose menu field. May not want to translate. */
101 N_("Reply-To: "),
102 /* L10N: Compose menu field. May not want to translate. */
103 N_("Fcc: "),
104#ifdef MIXMASTER
105 /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
106 N_("Mix: "),
107#endif
108 /* L10N: Compose menu field. Holds "Encrypt", "Sign" related information */
109 N_("Security: "),
110 /* L10N: This string is used by the compose menu.
111 Since it is hidden by default, it does not increase the indentation of
112 other compose menu fields. However, if possible, it should not be longer
113 than the other compose menu fields. Since it shares the row with "Encrypt
114 with:", it should not be longer than 15-20 character cells. */
115 N_("Sign as: "),
116#ifdef USE_AUTOCRYPT
117 // L10N: The compose menu autocrypt line
118 N_("Autocrypt: "),
119#endif
120#ifdef USE_NNTP
121 /* L10N: Compose menu field. May not want to translate. */
122 N_("Newsgroups: "),
123 /* L10N: Compose menu field. May not want to translate. */
124 N_("Followup-To: "),
125 /* L10N: Compose menu field. May not want to translate. */
126 N_("X-Comment-To: "),
127#endif
128 N_("Headers: "),
129};
130
131#ifdef USE_AUTOCRYPT
132static const char *const AutocryptRecUiFlags[] = {
133 /* L10N: Autocrypt recommendation flag: off.
134 This is displayed when Autocrypt is turned off. */
135 N_("Off"),
136 /* L10N: Autocrypt recommendation flag: no.
137 This is displayed when Autocrypt cannot encrypt to the recipients. */
138 N_("No"),
139 /* L10N: Autocrypt recommendation flag: discouraged.
140 This is displayed when Autocrypt believes encryption should not be used.
141 This might occur if one of the recipient Autocrypt Keys has not been
142 used recently, or if the only key available is a Gossip Header key. */
143 N_("Discouraged"),
144 /* L10N: Autocrypt recommendation flag: available.
145 This is displayed when Autocrypt believes encryption is possible, but
146 leaves enabling it up to the sender. Probably because "prefer encrypt"
147 is not set in both the sender and recipient keys. */
148 N_("Available"),
149 /* L10N: Autocrypt recommendation flag: yes.
150 This is displayed when Autocrypt would normally enable encryption
151 automatically. */
152 N_("Yes"),
153};
154#endif
155
162static void calc_header_width_padding(int idx, const char *header, bool calc_max)
163{
164 int width;
165
166 HeaderPadding[idx] = mutt_str_len(header);
167 width = mutt_strwidth(header);
168 if (calc_max && (MaxHeaderWidth < width))
169 MaxHeaderWidth = width;
170 HeaderPadding[idx] -= width;
171}
172
181static void init_header_padding(void)
182{
183 static bool done = false;
184
185 if (done)
186 return;
187 done = true;
188
189 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
190 {
191 if (i == HDR_CRYPTINFO)
192 continue;
193 calc_header_width_padding(i, _(Prompts[i]), true);
194 }
195
196 /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
197 * doesn't show up by default, and so can make the indentation of
198 * the other fields look funny. */
200
201 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
202 {
204 if (HeaderPadding[i] < 0)
205 HeaderPadding[i] = 0;
206 }
207}
208
218static int calc_address(struct AddressList *al, short cols, short *srows)
219{
220 struct ListHead slist = STAILQ_HEAD_INITIALIZER(slist);
221 mutt_addrlist_write_list(al, &slist);
222
223 int rows = 1;
224 int addr_len;
225 int width_left = cols;
226 struct ListNode *next = NULL;
227 struct ListNode *np = NULL;
228 STAILQ_FOREACH(np, &slist, entries)
229 {
230 next = STAILQ_NEXT(np, entries);
231 addr_len = mutt_strwidth(np->data);
232 if (next)
233 addr_len += 2; // ", "
234
235 try_again:
236 if (addr_len >= width_left)
237 {
238 if (width_left == cols)
239 break;
240
241 rows++;
242 width_left = cols;
243 goto try_again;
244 }
245
246 if (addr_len < width_left)
247 width_left -= addr_len;
248 }
249
250 mutt_list_free(&slist);
251
252 *srows = MIN(rows, MAX_ADDR_ROWS);
253 return *srows;
254}
255
263static int calc_security(struct Email *e, short *rows, const struct ConfigSubset *sub)
264{
266 *rows = 0; // Neither PGP nor SMIME are built into NeoMutt
267 else if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) != 0)
268 *rows = 2; // 'Security:' and 'Sign as:'
269 else
270 *rows = 1; // Just 'Security:'
271
272#ifdef USE_AUTOCRYPT
273 const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
274 if (c_autocrypt)
275 *rows += 1;
276#endif
277
278 return *rows;
279}
280
286static int calc_user_hdrs(const struct ListHead *hdrs)
287{
288 int rows = 0; /* Don't print at all if no custom headers*/
289 struct ListNode *np = NULL;
290 STAILQ_FOREACH(np, hdrs, entries)
291 {
292 if (rows == MAX_USER_HDR_ROWS)
293 break;
294 rows++;
295 }
296 return rows;
297}
298
305static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
306{
307 int rows = 4; // 'From:', 'Subject:', 'Reply-To:', 'Fcc:'
308#ifdef MIXMASTER
309 rows++;
310#endif
311
312 struct Email *e = wdata->email;
313 struct Envelope *env = e->env;
314 const int cols = win->state.cols - MaxHeaderWidth;
315
316#ifdef USE_NNTP
317 if (wdata->is_news)
318 {
319 rows += 2; // 'Newsgroups:' and 'Followup-To:'
320 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
321 if (c_x_comment_to)
322 rows++;
323 }
324 else
325#endif
326 {
327 rows += calc_address(&env->to, cols, &wdata->to_rows);
328 rows += calc_address(&env->cc, cols, &wdata->cc_rows);
329 rows += calc_address(&env->bcc, cols, &wdata->bcc_rows);
330 }
331 rows += calc_security(e, &wdata->sec_rows, wdata->sub);
332 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
333 if (c_compose_show_user_headers)
334 rows += calc_user_hdrs(&env->userhdrs);
335
336 return rows;
337}
338
346static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
347{
349 mutt_window_mvprintw(win, col, row, "%s", text);
351}
352
359static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
360{
362 mutt_window_mvprintw(win, 0, row, "%*s", HeaderPadding[field], _(Prompts[field]));
364}
365
375static void draw_header_content(struct MuttWindow *win, int row,
376 enum HeaderField field, const char *content)
377{
378 mutt_window_move(win, HeaderPadding[field], row);
379 mutt_paddstr(win, win->state.cols - HeaderPadding[field], content);
380}
381
389static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
390{
391 struct Email *e = wdata->email;
392
393 draw_header(win, row++, HDR_CRYPT);
394
396 return 0;
397
398 // We'll probably need two lines for 'Security:' and 'Sign as:'
399 int used = 2;
400 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) == (SEC_ENCRYPT | SEC_SIGN))
401 {
403 mutt_window_addstr(win, _("Sign, Encrypt"));
404 }
405 else if (e->security & SEC_ENCRYPT)
406 {
408 mutt_window_addstr(win, _("Encrypt"));
409 }
410 else if (e->security & SEC_SIGN)
411 {
413 mutt_window_addstr(win, _("Sign"));
414 }
415 else
416 {
417 /* L10N: This refers to the encryption of the email, e.g. "Security: None" */
419 mutt_window_addstr(win, _("None"));
420 used = 1; // 'Sign as:' won't be needed
421 }
423
424 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)))
425 {
426 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
427 {
428 if ((e->security & SEC_INLINE))
429 mutt_window_addstr(win, _(" (inline PGP)"));
430 else
431 mutt_window_addstr(win, _(" (PGP/MIME)"));
432 }
433 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
434 mutt_window_addstr(win, _(" (S/MIME)"));
435 }
436
437 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(wdata->sub, "crypt_opportunistic_encrypt");
438 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
439 mutt_window_addstr(win, _(" (OppEnc mode)"));
440
442
443 if (((WithCrypto & APPLICATION_PGP) != 0) &&
444 (e->security & APPLICATION_PGP) && (e->security & SEC_SIGN))
445 {
446 draw_header(win, row++, HDR_CRYPTINFO);
447 const char *const c_pgp_sign_as = cs_subset_string(wdata->sub, "pgp_sign_as");
448 mutt_window_printf(win, "%s", c_pgp_sign_as ? c_pgp_sign_as : _("<default>"));
449 }
450
451 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
453 {
454 draw_header(win, row++, HDR_CRYPTINFO);
455 const char *const c_smime_sign_as = cs_subset_string(wdata->sub, "smime_sign_as");
456 mutt_window_printf(win, "%s", c_smime_sign_as ? c_smime_sign_as : _("<default>"));
457 }
458
459 const char *const c_smime_encrypt_with = cs_subset_string(wdata->sub, "smime_encrypt_with");
460 if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME) &&
461 (e->security & SEC_ENCRYPT) && c_smime_encrypt_with)
462 {
463 draw_floating(win, 40, row - 1, _("Encrypt with: "));
464 mutt_window_printf(win, "%s", NONULL(c_smime_encrypt_with));
465 }
466
467#ifdef USE_AUTOCRYPT
468 const bool c_autocrypt = cs_subset_bool(wdata->sub, "autocrypt");
469 if (c_autocrypt)
470 {
471 draw_header(win, row, HDR_AUTOCRYPT);
472 if (e->security & SEC_AUTOCRYPT)
473 {
475 mutt_window_addstr(win, _("Encrypt"));
476 }
477 else
478 {
480 mutt_window_addstr(win, _("Off"));
481 }
482
483 /* L10N: The autocrypt compose menu Recommendation field.
484 Displays the output of the recommendation engine
485 (Off, No, Discouraged, Available, Yes) */
486 draw_floating(win, 40, row, _("Recommendation: "));
488
489 used++;
490 }
491#endif
492 return used;
493}
494
495#ifdef MIXMASTER
502static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
503{
504 char *t = NULL;
505
506 draw_header(win, row, HDR_MIX);
507
508 if (STAILQ_EMPTY(chain))
509 {
510 mutt_window_addstr(win, _("<no chain defined>"));
512 return;
513 }
514
515 int c = 12;
516 struct ListNode *np = NULL;
517 STAILQ_FOREACH(np, chain, entries)
518 {
519 t = np->data;
520 if (t && (t[0] == '0') && (t[1] == '\0'))
521 t = "<random>";
522
523 if (c + mutt_str_len(t) + 2 >= win->state.cols)
524 break;
525
526 mutt_window_addstr(win, NONULL(t));
527 if (STAILQ_NEXT(np, entries))
528 mutt_window_addstr(win, ", ");
529
530 c += mutt_str_len(t) + 2;
531 }
532}
533#endif
534
544static int draw_envelope_addr(int field, struct AddressList *al,
545 struct MuttWindow *win, int row, size_t max_lines)
546{
547 draw_header(win, row, field);
548
549 struct ListHead list = STAILQ_HEAD_INITIALIZER(list);
550 int count = mutt_addrlist_count_recips(al);
551
552 int lines_used = 1;
553 int width_left = win->state.cols - MaxHeaderWidth;
554 char more[32] = { 0 };
555 int more_len = 0;
556
557 struct Buffer *buf = mutt_buffer_pool_get();
558 bool in_group = false;
559 char *sep = NULL;
560 struct Address *addr = NULL;
561 TAILQ_FOREACH(addr, al, entries)
562 {
563 struct Address *next = TAILQ_NEXT(addr, entries);
564
565 if (addr->group)
566 {
567 in_group = true;
568 }
569
571 mutt_addr_write(buf, addr, true);
572 size_t addr_len = mutt_buffer_len(buf);
573
574 sep = "";
575 if (!addr->group)
576 {
577 // group terminator
578 if (in_group && next && !next->mailbox && !next->personal)
579 {
580 sep = ";";
581 addr_len += 1;
582 in_group = false;
583 }
584 else if (next)
585 {
586 sep = ", ";
587 addr_len += 2;
588 }
589 }
590
591 count--;
592 try_again:
593 more_len = snprintf(more, sizeof(more),
594 ngettext("(+%d more)", "(+%d more)", count), count);
595 mutt_debug(LL_DEBUG3, "text: '%s' len: %d\n", more, more_len);
596
597 int reserve = ((count > 0) && (lines_used == max_lines)) ? more_len : 0;
598 mutt_debug(LL_DEBUG3, "processing: %s (al:%d, wl:%d, r:%d, lu:%d)\n", buf,
599 addr_len, width_left, reserve, lines_used);
600 if (addr_len >= (width_left - reserve))
601 {
602 mutt_debug(LL_DEBUG3, "not enough space\n");
603 if (lines_used == max_lines)
604 {
605 mutt_debug(LL_DEBUG3, "no more lines\n");
606 mutt_debug(LL_DEBUG3, "truncating: %s\n", buf);
607 mutt_paddstr(win, width_left, mutt_buffer_string(buf));
608 break;
609 }
610
611 if (width_left == (win->state.cols - MaxHeaderWidth))
612 {
613 mutt_debug(LL_DEBUG3, "couldn't print: %s\n", buf);
614 mutt_paddstr(win, width_left, mutt_buffer_string(buf));
615 break;
616 }
617
618 mutt_debug(LL_DEBUG3, "start a new line\n");
620 row++;
621 lines_used++;
622 width_left = win->state.cols - MaxHeaderWidth;
624 goto try_again;
625 }
626
627 if (addr_len < width_left)
628 {
629 mutt_debug(LL_DEBUG3, "space for: %s\n", buf);
631 mutt_window_addstr(win, sep);
632 width_left -= addr_len;
633 }
634 mutt_debug(LL_DEBUG3, "%d addresses remaining\n", count);
635 mutt_debug(LL_DEBUG3, "%ld lines remaining\n", max_lines - lines_used);
636 }
637 mutt_list_free(&list);
639
640 if (count > 0)
641 {
642 mutt_window_move(win, win->state.cols - more_len, row);
644 mutt_window_addstr(win, more);
646 mutt_debug(LL_DEBUG3, "%d more (len %d)\n", count, more_len);
647 }
648 else
649 {
651 }
652
653 for (int i = lines_used; i < max_lines; i++)
654 {
655 mutt_window_move(win, 0, row + i);
657 }
658
659 mutt_debug(LL_DEBUG3, "used %d lines\n", lines_used);
660 return lines_used;
661}
662
670static int draw_envelope_user_hdrs(struct MuttWindow *win,
671 struct EnvelopeWindowData *wdata, int row)
672{
673 const char *overflow_text = "...";
674 int rows_used = 0;
675
676 struct ListNode *first = STAILQ_FIRST(&wdata->email->env->userhdrs);
677 if (!first)
678 return rows_used;
679
680 /* Draw first entry on same line as prompt */
682 mutt_paddstr(win,
685 first->data);
686 rows_used++;
687
688 /* Draw any following entries on their own line */
689 struct ListNode *np = STAILQ_NEXT(first, entries);
690 if (!np)
691 return rows_used;
692
693 STAILQ_FOREACH_FROM(np, &wdata->email->env->userhdrs, entries)
694 {
695 if ((rows_used == (MAX_USER_HDR_ROWS - 1)) && STAILQ_NEXT(np, entries))
696 {
697 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, overflow_text);
698 rows_used++;
699 break;
700 }
701 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, np->data);
702 rows_used++;
703 }
704 return rows_used;
705}
706
712static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
713{
714 struct Email *e = wdata->email;
715 const char *fcc = mutt_buffer_string(wdata->fcc);
716 const int cols = win->state.cols - MaxHeaderWidth;
717
719 int row = draw_envelope_addr(HDR_FROM, &e->env->from, win, 0, 1);
720
721#ifdef USE_NNTP
722 if (wdata->is_news)
723 {
724 draw_header(win, row++, HDR_NEWSGROUPS);
725 mutt_paddstr(win, cols, NONULL(e->env->newsgroups));
726
727 draw_header(win, row++, HDR_FOLLOWUPTO);
728 mutt_paddstr(win, cols, NONULL(e->env->followup_to));
729
730 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
731 if (c_x_comment_to)
732 {
733 draw_header(win, row++, HDR_XCOMMENTTO);
734 mutt_paddstr(win, cols, NONULL(e->env->x_comment_to));
735 }
736 }
737 else
738#endif
739 {
740 row += draw_envelope_addr(HDR_TO, &e->env->to, win, row, wdata->to_rows);
741 row += draw_envelope_addr(HDR_CC, &e->env->cc, win, row, wdata->cc_rows);
742 row += draw_envelope_addr(HDR_BCC, &e->env->bcc, win, row, wdata->bcc_rows);
743 }
744
745 draw_header(win, row++, HDR_SUBJECT);
746 mutt_paddstr(win, cols, NONULL(e->env->subject));
747
748 row += draw_envelope_addr(HDR_REPLYTO, &e->env->reply_to, win, row, 1);
749
750 draw_header(win, row++, HDR_FCC);
751 mutt_paddstr(win, cols, fcc);
752
753 if (WithCrypto)
754 row += draw_crypt_lines(win, wdata, row);
755
756#ifdef MIXMASTER
757 draw_mix_line(&e->chain, win, row++);
758#endif
759 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
760 if (c_compose_show_user_headers)
761 row += draw_envelope_user_hdrs(win, wdata, row);
762
764}
765
769static int env_recalc(struct MuttWindow *win)
770{
771 struct EnvelopeWindowData *wdata = win->wdata;
772
773 const int cur_rows = win->state.rows;
774 const int new_rows = calc_envelope(win, wdata);
775
776 if (new_rows != cur_rows)
777 {
778 win->req_rows = new_rows;
780 }
781
782 win->actions |= WA_REPAINT;
783 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
784 return 0;
785}
786
790static int env_repaint(struct MuttWindow *win)
791{
792 struct EnvelopeWindowData *wdata = win->wdata;
793
794 draw_envelope(win, wdata);
795 mutt_debug(LL_DEBUG5, "repaint done\n");
796 return 0;
797}
798
802static int env_color_observer(struct NotifyCallback *nc)
803{
804 if (nc->event_type != NT_COLOR)
805 return 0;
806 if (!nc->global_data || !nc->event_data)
807 return -1;
808
809 struct EventColor *ev_c = nc->event_data;
810 struct MuttWindow *win_env = nc->global_data;
811
812 enum ColorId cid = ev_c->cid;
813
814 switch (cid)
815 {
816 case MT_COLOR_BOLD:
822 case MT_COLOR_NORMAL:
823 case MT_COLOR_STATUS:
824 case MT_COLOR_MAX: // Sent on `uncolor *`
825 mutt_debug(LL_DEBUG5, "color done, request WA_REPAINT\n");
826 win_env->actions |= WA_REPAINT;
827 break;
828
829 default:
830 break;
831 }
832 return 0;
833}
834
839{
840 if (nc->event_type != NT_CONFIG)
841 return 0;
842 if (!nc->global_data || !nc->event_data)
843 return -1;
844
845 struct EventConfig *ev_c = nc->event_data;
846 struct MuttWindow *win_env = nc->global_data;
847
848 switch (ev_c->name[0])
849 {
850 case 'a':
851 if (mutt_str_equal(ev_c->name, "autocrypt"))
852 break;
853 return 0;
854 case 'c':
855 if (mutt_str_equal(ev_c->name, "compose_show_user_headers") ||
856 mutt_str_equal(ev_c->name, "crypt_opportunistic_encrypt"))
857 {
858 break;
859 }
860 return 0;
861 case 'p':
862 if (mutt_str_equal(ev_c->name, "pgp_sign_as"))
863 break;
864 return 0;
865 case 's':
866 if (mutt_str_equal(ev_c->name, "smime_encrypt_with") ||
867 mutt_str_equal(ev_c->name, "smime_sign_as"))
868 {
869 break;
870 }
871 return 0;
872 case 'x':
873 if (mutt_str_equal(ev_c->name, "x_comment_to"))
874 break;
875 return 0;
876 default:
877 return 0;
878 }
879
880 win_env->actions |= WA_RECALC;
881 mutt_debug(LL_DEBUG5, "config done, request WA_RECALC\n");
882 return 0;
883}
884
888static int env_email_observer(struct NotifyCallback *nc)
889{
890 if ((nc->event_type != NT_EMAIL) && (nc->event_type != NT_ENVELOPE))
891 return 0;
892 if (!nc->global_data)
893 return -1;
894
895 struct MuttWindow *win_env = nc->global_data;
896
897 // pgp/smime/autocrypt menu, or external change
898 if (nc->event_type == NT_EMAIL)
899 {
900 struct EnvelopeWindowData *wdata = win_env->wdata;
901 update_crypt_info(wdata);
902 }
903
904 win_env->actions |= WA_RECALC;
905 mutt_debug(LL_DEBUG5, "email done, request WA_RECALC\n");
906 return 0;
907}
908
913{
914 if (nc->event_type != NT_HEADER)
915 return 0;
916 if (!nc->global_data || !nc->event_data)
917 return -1;
918
919 const struct EventHeader *ev_h = nc->event_data;
920 struct MuttWindow *win_env = nc->global_data;
921 struct EnvelopeWindowData *wdata = win_env->wdata;
922
923 struct Envelope *env = wdata->email->env;
924
926 {
927 header_set(&env->userhdrs, ev_h->header);
928 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
929 win_env->actions |= WA_RECALC;
930 return 0;
931 }
932
934 {
935 struct ListNode *removed = header_find(&env->userhdrs, ev_h->header);
936 if (removed)
937 {
938 header_free(&env->userhdrs, removed);
939 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
940 win_env->actions |= WA_RECALC;
941 }
942 return 0;
943 }
944
945 return 0;
946}
947
952{
953 if (nc->event_type != NT_WINDOW)
954 return 0;
955 if (!nc->global_data || !nc->event_data)
956 return -1;
957
958 struct MuttWindow *win_env = nc->global_data;
959 struct EventWindow *ev_w = nc->event_data;
960 if (ev_w->win != win_env)
961 return 0;
962
964 {
965 win_env->actions |= WA_RECALC;
966 mutt_debug(LL_DEBUG5, "window state done, request WA_RECALC\n");
967 }
968 else if (nc->event_subtype == NT_WINDOW_DELETE)
969 {
970 struct EnvelopeWindowData *wdata = win_env->wdata;
971
977 mutt_debug(LL_DEBUG5, "window delete done\n");
978 }
979
980 return 0;
981}
982
990struct MuttWindow *env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
991{
993
996 HDR_ATTACH_TITLE - 1);
997
1003
1004 struct EnvelopeWindowData *wdata = env_wdata_new();
1005 wdata->fcc = fcc;
1006 wdata->email = e;
1007 wdata->sub = sub;
1008 wdata->is_news = OptNewsSend;
1009
1010 win_env->wdata = wdata;
1011 win_env->wdata_free = env_wdata_free;
1012 win_env->recalc = env_recalc;
1013 win_env->repaint = env_repaint;
1014
1015 return win_env;
1016}
size_t mutt_addrlist_write_list(const struct AddressList *al, struct ListHead *list)
Write Addresses to a List.
Definition: address.c:1203
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1032
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition: address.c:852
Email Address Handling.
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
Color and attribute parsing.
ColorId
List of all colored objects.
Definition: color.h:38
@ MT_COLOR_COMPOSE_SECURITY_ENCRYPT
Mail will be encrypted.
Definition: color.h:46
@ MT_COLOR_MAX
Definition: color.h:92
@ MT_COLOR_STATUS
Status bar (takes a pattern)
Definition: color.h:75
@ MT_COLOR_COMPOSE_SECURITY_NONE
Mail will not be encrypted or signed.
Definition: color.h:47
@ MT_COLOR_BOLD
Bold text.
Definition: color.h:43
@ MT_COLOR_COMPOSE_SECURITY_BOTH
Mail will be encrypted and signed.
Definition: color.h:45
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:57
@ MT_COLOR_COMPOSE_SECURITY_SIGN
Mail will be signed.
Definition: color.h:48
@ MT_COLOR_COMPOSE_HEADER
Header labels, e.g. From:
Definition: color.h:44
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mutt_paddstr(struct MuttWindow *win, int n, const char *s)
Display a string on screen, padded if necessary.
Definition: curs_lib.c:817
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:908
void header_free(struct ListHead *hdrlist, struct ListNode *target)
Free and remove a header from a header list.
Definition: email.c:245
struct ListNode * header_set(struct ListHead *hdrlist, const char *header)
Set a header value in a list.
Definition: email.c:233
struct ListNode * header_find(const struct ListHead *hdrlist, const char *header)
Find a header, matching on its field, in a list of headers.
Definition: email.c:180
Structs that make up an email.
@ NT_HEADER_CHANGE
An existing header has been changed.
Definition: email.h:174
@ NT_HEADER_ADD
Header has been added.
Definition: email.h:172
@ NT_HEADER_DELETE
Header has been removed.
Definition: email.h:173
void update_crypt_info(struct EnvelopeWindowData *wdata)
Update the crypto info.
Definition: functions.c:146
HeaderField
Ordered list of headers for the compose screen.
Definition: private.h:34
@ HDR_SUBJECT
"Subject:" field
Definition: private.h:39
@ HDR_REPLYTO
"Reply-To:" field
Definition: private.h:40
@ HDR_AUTOCRYPT
"Autocrypt:" and "Recommendation:" fields
Definition: private.h:48
@ HDR_FCC
"Fcc:" (save folder) field
Definition: private.h:41
@ HDR_ATTACH_TITLE
The "-- Attachments" line.
Definition: private.h:56
@ HDR_CRYPT
"Security:" field (encryption/signing info)
Definition: private.h:45
@ HDR_CC
"Cc:" field
Definition: private.h:37
@ HDR_MIX
"Mix:" field (Mixmaster chain)
Definition: private.h:43
@ HDR_TO
"To:" field
Definition: private.h:36
@ HDR_BCC
"Bcc:" field
Definition: private.h:38
@ HDR_CUSTOM_HEADERS
"Headers:" field
Definition: private.h:55
@ HDR_FOLLOWUPTO
"Followup-To:" field
Definition: private.h:52
@ HDR_XCOMMENTTO
"X-Comment-To:" field
Definition: private.h:53
@ HDR_NEWSGROUPS
"Newsgroups:" field
Definition: private.h:51
@ HDR_CRYPTINFO
"Sign as:" field (encryption/signing info)
Definition: private.h:46
@ HDR_FROM
"From:" field
Definition: private.h:35
struct EnvelopeWindowData * env_wdata_new(void)
Create new Envelope Data.
Definition: wdata.c:48
static int draw_envelope_addr(int field, struct AddressList *al, struct MuttWindow *win, int row, size_t max_lines)
Write addresses to the compose window.
Definition: window.c:544
static const char *const AutocryptRecUiFlags[]
Definition: window.c:132
static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
Draw an aligned label.
Definition: window.c:359
int HeaderPadding[HDR_ATTACH_TITLE]
Definition: window.c:86
static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Write the email headers to the compose window.
Definition: window.c:712
static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
Draw a floating label.
Definition: window.c:346
static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
Redraw the Mixmaster chain.
Definition: window.c:502
const char *const Prompts[]
Definition: window.c:89
#define MAX_USER_HDR_ROWS
Maximum number of rows to use for the Headers: field.
Definition: window.c:84
static int draw_envelope_user_hdrs(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
Write user-defined headers to the compose window.
Definition: window.c:670
static int calc_address(struct AddressList *al, short cols, short *srows)
Calculate how many rows an AddressList will need.
Definition: window.c:218
struct MuttWindow * env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
Create the Envelope Window.
Definition: window.c:990
int MaxHeaderWidth
Definition: window.c:87
static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Calculate how many rows the envelope will need.
Definition: window.c:305
static void draw_header_content(struct MuttWindow *win, int row, enum HeaderField field, const char *content)
Draw content on a separate line aligned to header prompt.
Definition: window.c:375
static int calc_user_hdrs(const struct ListHead *hdrs)
Calculate how many rows are needed for user-defined headers.
Definition: window.c:286
static int calc_security(struct Email *e, short *rows, const struct ConfigSubset *sub)
Calculate how many rows the security info will need.
Definition: window.c:263
#define MAX_ADDR_ROWS
Maximum number of rows to use for the To:, Cc:, Bcc: fields.
Definition: window.c:81
static void calc_header_width_padding(int idx, const char *header, bool calc_max)
Calculate the width needed for the compose labels.
Definition: window.c:162
static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
Update the encryption info in the compose window.
Definition: window.c:389
static void init_header_padding(void)
Calculate how much padding the compose table will need.
Definition: window.c:181
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:79
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
static int env_email_observer(struct NotifyCallback *nc)
Notification that the Email has changed - Implements observer_t -.
Definition: window.c:888
static int env_color_observer(struct NotifyCallback *nc)
Notification that a Color has changed - Implements observer_t -.
Definition: window.c:802
static int env_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: window.c:951
static int env_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: window.c:838
static int env_header_observer(struct NotifyCallback *nc)
Notification that a User Header has changed - Implements observer_t -.
Definition: window.c:912
static int env_recalc(struct MuttWindow *win)
Recalculate the Window data - Implements MuttWindow::recalc() -.
Definition: window.c:769
static int env_repaint(struct MuttWindow *win)
Repaint the Window - Implements MuttWindow::repaint() -.
Definition: window.c:790
void env_wdata_free(struct MuttWindow *win, void **ptr)
Free the Envelope Data - Implements MuttWindow::wdata_free() -.
Definition: wdata.c:39
Convenience wrapper for the gui headers.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
#define MIN(a, b)
Definition: memory.h:31
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:228
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
struct AttrColor * mutt_curses_set_normal_backed_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:65
struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:81
void mutt_window_clear(struct MuttWindow *win)
Clear a Window.
Definition: mutt_window.c:696
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:341
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:425
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:180
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:294
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:410
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:241
int mutt_window_mvprintw(struct MuttWindow *win, int col, int row, const char *fmt,...)
Move the cursor and write a formatted string to a Window.
Definition: mutt_window.c:323
#define WA_RECALC
Recalculate the contents of the Window.
Definition: mutt_window.h:110
@ WT_CUSTOM
Window with a custom drawing function.
Definition: mutt_window.h:95
@ MUTT_WIN_ORIENT_VERTICAL
Window uses all available vertical space.
Definition: mutt_window.h:38
@ NT_WINDOW_STATE
Window state has changed, e.g. WN_VISIBLE.
Definition: mutt_window.h:206
@ NT_WINDOW_DELETE
Window is about to be deleted.
Definition: mutt_window.h:205
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
@ MUTT_WIN_SIZE_FIXED
Window has a fixed size.
Definition: mutt_window.h:47
API for encryption/signing of emails.
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:55
@ NT_CONFIG
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:43
@ NT_COLOR
Colour has changed, NotifyColor, EventColor.
Definition: notify_type.h:41
@ NT_EMAIL
Email has changed, NotifyEmail, EventEmail.
Definition: notify_type.h:44
@ NT_ENVELOPE
Envelope has changed, NotifyEnvelope.
Definition: notify_type.h:45
@ NT_HEADER
A header has changed, NotifyHeader EventHeader.
Definition: notify_type.h:47
@ NT_ALL
Register for all notifications.
Definition: notify_type.h:35
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Progress Bar Window Data.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
#define STAILQ_FOREACH_FROM(var, head, field)
Definition: queue.h:357
Sidebar functions.
GUI display the mailboxes in a side panel.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
String manipulation buffer.
Definition: buffer.h:34
A set of inherited config items.
Definition: subset.h:47
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:71
Data to fill the Envelope Window.
Definition: wdata.h:38
bool is_news
Email is a news article.
Definition: wdata.h:49
struct Buffer * fcc
Where the outgoing Email will be saved.
Definition: wdata.h:41
struct Email * email
Email being composed.
Definition: wdata.h:40
short sec_rows
Number of rows used by the security fields.
Definition: wdata.h:46
short cc_rows
Number of rows used by the 'Cc:' field.
Definition: wdata.h:44
struct ConfigSubset * sub
Inherited config items.
Definition: wdata.h:39
enum AutocryptRec autocrypt_rec
Autocrypt recommendation.
Definition: wdata.h:52
short to_rows
Number of rows used by the 'To:' field.
Definition: wdata.h:43
short bcc_rows
Number of rows used by the 'Bcc:' field.
Definition: wdata.h:45
The header of an Email.
Definition: envelope.h:57
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:82
char * newsgroups
List of newsgroups.
Definition: envelope.h:79
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
An Event that happened to a Colour.
Definition: notify2.h:53
enum ColorId cid
Colour ID that has changed.
Definition: notify2.h:54
A config-change event.
Definition: subset.h:70
const char * name
Name of config item that changed.
Definition: subset.h:72
An event that happened to a header.
Definition: email.h:181
char * header
The contents of the header.
Definition: email.h:182
An Event that happened to a Window.
Definition: mutt_window.h:215
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:216
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
int(* repaint)(struct MuttWindow *win)
Definition: mutt_window.h:181
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
short req_rows
Number of rows required.
Definition: mutt_window.h:125
int(* recalc)(struct MuttWindow *win)
Definition: mutt_window.h:170
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:159
struct MuttWindow * parent
Parent Window.
Definition: mutt_window.h:135
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
Data passed to a notification function.
Definition: observer.h:34
void * event_data
Data from notify_send()
Definition: observer.h:38
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:37
void * global_data
Data from notify_observer_add()
Definition: observer.h:39
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61