NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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
87static int HeaderPadding[HDR_ATTACH_TITLE] = { 0 };
89static int MaxHeaderWidth = 0;
90
92const char *const Prompts[] = {
93 /* L10N: Compose menu field. May not want to translate. */
94 N_("From: "),
95 /* L10N: Compose menu field. May not want to translate. */
96 N_("To: "),
97 /* L10N: Compose menu field. May not want to translate. */
98 N_("Cc: "),
99 /* L10N: Compose menu field. May not want to translate. */
100 N_("Bcc: "),
101 /* L10N: Compose menu field. May not want to translate. */
102 N_("Subject: "),
103 /* L10N: Compose menu field. May not want to translate. */
104 N_("Reply-To: "),
105 /* L10N: Compose menu field. May not want to translate. */
106 N_("Fcc: "),
107#ifdef MIXMASTER
108 /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
109 N_("Mix: "),
110#endif
111 /* L10N: Compose menu field. Holds "Encrypt", "Sign" related information */
112 N_("Security: "),
113 /* L10N: This string is used by the compose menu.
114 Since it is hidden by default, it does not increase the indentation of
115 other compose menu fields. However, if possible, it should not be longer
116 than the other compose menu fields. Since it shares the row with "Encrypt
117 with:", it should not be longer than 15-20 character cells. */
118 N_("Sign as: "),
119#ifdef USE_AUTOCRYPT
120 // L10N: The compose menu autocrypt line
121 N_("Autocrypt: "),
122#endif
123#ifdef USE_NNTP
124 /* L10N: Compose menu field. May not want to translate. */
125 N_("Newsgroups: "),
126 /* L10N: Compose menu field. May not want to translate. */
127 N_("Followup-To: "),
128 /* L10N: Compose menu field. May not want to translate. */
129 N_("X-Comment-To: "),
130#endif
131 N_("Headers: "),
132};
133
134#ifdef USE_AUTOCRYPT
136static const char *const AutocryptRecUiFlags[] = {
137 /* L10N: Autocrypt recommendation flag: off.
138 This is displayed when Autocrypt is turned off. */
139 N_("Off"),
140 /* L10N: Autocrypt recommendation flag: no.
141 This is displayed when Autocrypt cannot encrypt to the recipients. */
142 N_("No"),
143 /* L10N: Autocrypt recommendation flag: discouraged.
144 This is displayed when Autocrypt believes encryption should not be used.
145 This might occur if one of the recipient Autocrypt Keys has not been
146 used recently, or if the only key available is a Gossip Header key. */
147 N_("Discouraged"),
148 /* L10N: Autocrypt recommendation flag: available.
149 This is displayed when Autocrypt believes encryption is possible, but
150 leaves enabling it up to the sender. Probably because "prefer encrypt"
151 is not set in both the sender and recipient keys. */
152 N_("Available"),
153 /* L10N: Autocrypt recommendation flag: yes.
154 This is displayed when Autocrypt would normally enable encryption
155 automatically. */
156 N_("Yes"),
157};
158#endif
159
166static void calc_header_width_padding(int idx, const char *header, bool calc_max)
167{
168 int width;
169
170 HeaderPadding[idx] = mutt_str_len(header);
171 width = mutt_strwidth(header);
172 if (calc_max && (MaxHeaderWidth < width))
173 MaxHeaderWidth = width;
174 HeaderPadding[idx] -= width;
175}
176
185static void init_header_padding(void)
186{
187 static bool done = false;
188
189 if (done)
190 return;
191 done = true;
192
193 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
194 {
195 if (i == HDR_CRYPTINFO)
196 continue;
197 calc_header_width_padding(i, _(Prompts[i]), true);
198 }
199
200 /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
201 * doesn't show up by default, and so can make the indentation of
202 * the other fields look funny. */
204
205 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
206 {
208 if (HeaderPadding[i] < 0)
209 HeaderPadding[i] = 0;
210 }
211}
212
222static int calc_address(struct AddressList *al, short cols, short *srows)
223{
224 struct ListHead slist = STAILQ_HEAD_INITIALIZER(slist);
225 mutt_addrlist_write_list(al, &slist);
226
227 int rows = 1;
228 int addr_len;
229 int width_left = cols;
230 struct ListNode *next = NULL;
231 struct ListNode *np = NULL;
232 STAILQ_FOREACH(np, &slist, entries)
233 {
234 next = STAILQ_NEXT(np, entries);
235 addr_len = mutt_strwidth(np->data);
236 if (next)
237 addr_len += 2; // ", "
238
239 try_again:
240 if (addr_len >= width_left)
241 {
242 if (width_left == cols)
243 break;
244
245 rows++;
246 width_left = cols;
247 goto try_again;
248 }
249
250 if (addr_len < width_left)
251 width_left -= addr_len;
252 }
253
254 mutt_list_free(&slist);
255
256 *srows = MIN(rows, MAX_ADDR_ROWS);
257 return *srows;
258}
259
267static int calc_security(struct Email *e, short *rows, const struct ConfigSubset *sub)
268{
270 *rows = 0; // Neither PGP nor SMIME are built into NeoMutt
271 else if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) != 0)
272 *rows = 2; // 'Security:' and 'Sign as:'
273 else
274 *rows = 1; // Just 'Security:'
275
276#ifdef USE_AUTOCRYPT
277 const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
278 if (c_autocrypt)
279 *rows += 1;
280#endif
281
282 return *rows;
283}
284
290static int calc_user_hdrs(const struct ListHead *hdrs)
291{
292 int rows = 0; /* Don't print at all if no custom headers*/
293 struct ListNode *np = NULL;
294 STAILQ_FOREACH(np, hdrs, entries)
295 {
296 if (rows == MAX_USER_HDR_ROWS)
297 break;
298 rows++;
299 }
300 return rows;
301}
302
309static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
310{
311 int rows = 4; // 'From:', 'Subject:', 'Reply-To:', 'Fcc:'
312#ifdef MIXMASTER
313 rows++;
314#endif
315
316 struct Email *e = wdata->email;
317 struct Envelope *env = e->env;
318 const int cols = win->state.cols - MaxHeaderWidth;
319
320#ifdef USE_NNTP
321 if (wdata->is_news)
322 {
323 rows += 2; // 'Newsgroups:' and 'Followup-To:'
324 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
325 if (c_x_comment_to)
326 rows++;
327 }
328 else
329#endif
330 {
331 rows += calc_address(&env->to, cols, &wdata->to_rows);
332 rows += calc_address(&env->cc, cols, &wdata->cc_rows);
333 rows += calc_address(&env->bcc, cols, &wdata->bcc_rows);
334 }
335 rows += calc_security(e, &wdata->sec_rows, wdata->sub);
336 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
337 if (c_compose_show_user_headers)
338 rows += calc_user_hdrs(&env->userhdrs);
339
340 return rows;
341}
342
350static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
351{
353 mutt_window_mvprintw(win, col, row, "%s", text);
355}
356
363static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
364{
366 mutt_window_mvprintw(win, 0, row, "%*s", HeaderPadding[field], _(Prompts[field]));
368}
369
379static void draw_header_content(struct MuttWindow *win, int row,
380 enum HeaderField field, const char *content)
381{
382 mutt_window_move(win, HeaderPadding[field], row);
383 mutt_paddstr(win, win->state.cols - HeaderPadding[field], content);
384}
385
393static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
394{
395 struct Email *e = wdata->email;
396
397 draw_header(win, row++, HDR_CRYPT);
398
400 return 0;
401
402 // We'll probably need two lines for 'Security:' and 'Sign as:'
403 int used = 2;
404 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) == (SEC_ENCRYPT | SEC_SIGN))
405 {
407 mutt_window_addstr(win, _("Sign, Encrypt"));
408 }
409 else if (e->security & SEC_ENCRYPT)
410 {
412 mutt_window_addstr(win, _("Encrypt"));
413 }
414 else if (e->security & SEC_SIGN)
415 {
417 mutt_window_addstr(win, _("Sign"));
418 }
419 else
420 {
421 /* L10N: This refers to the encryption of the email, e.g. "Security: None" */
423 mutt_window_addstr(win, _("None"));
424 used = 1; // 'Sign as:' won't be needed
425 }
427
428 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)))
429 {
430 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
431 {
432 if ((e->security & SEC_INLINE))
433 mutt_window_addstr(win, _(" (inline PGP)"));
434 else
435 mutt_window_addstr(win, _(" (PGP/MIME)"));
436 }
437 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
438 {
439 mutt_window_addstr(win, _(" (S/MIME)"));
440 }
441 }
442
443 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(wdata->sub, "crypt_opportunistic_encrypt");
444 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
445 mutt_window_addstr(win, _(" (OppEnc mode)"));
446
448
449 if (((WithCrypto & APPLICATION_PGP) != 0) &&
450 (e->security & APPLICATION_PGP) && (e->security & SEC_SIGN))
451 {
452 draw_header(win, row++, HDR_CRYPTINFO);
453 const char *const c_pgp_sign_as = cs_subset_string(wdata->sub, "pgp_sign_as");
454 mutt_window_printf(win, "%s", c_pgp_sign_as ? c_pgp_sign_as : _("<default>"));
455 }
456
457 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
459 {
460 draw_header(win, row++, HDR_CRYPTINFO);
461 const char *const c_smime_sign_as = cs_subset_string(wdata->sub, "smime_sign_as");
462 mutt_window_printf(win, "%s", c_smime_sign_as ? c_smime_sign_as : _("<default>"));
463 }
464
465 const char *const c_smime_encrypt_with = cs_subset_string(wdata->sub, "smime_encrypt_with");
466 if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME) &&
467 (e->security & SEC_ENCRYPT) && c_smime_encrypt_with)
468 {
469 draw_floating(win, 40, row - 1, _("Encrypt with: "));
470 mutt_window_printf(win, "%s", NONULL(c_smime_encrypt_with));
471 }
472
473#ifdef USE_AUTOCRYPT
474 const bool c_autocrypt = cs_subset_bool(wdata->sub, "autocrypt");
475 if (c_autocrypt)
476 {
477 draw_header(win, row, HDR_AUTOCRYPT);
478 if (e->security & SEC_AUTOCRYPT)
479 {
481 mutt_window_addstr(win, _("Encrypt"));
482 }
483 else
484 {
486 mutt_window_addstr(win, _("Off"));
487 }
488
489 /* L10N: The autocrypt compose menu Recommendation field.
490 Displays the output of the recommendation engine
491 (Off, No, Discouraged, Available, Yes) */
492 draw_floating(win, 40, row, _("Recommendation: "));
494
495 used++;
496 }
497#endif
498 return used;
499}
500
501#ifdef MIXMASTER
508static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
509{
510 char *t = NULL;
511
512 draw_header(win, row, HDR_MIX);
513
514 if (STAILQ_EMPTY(chain))
515 {
516 mutt_window_addstr(win, _("<no chain defined>"));
518 return;
519 }
520
521 int c = 12;
522 struct ListNode *np = NULL;
523 STAILQ_FOREACH(np, chain, entries)
524 {
525 t = np->data;
526 if (t && (t[0] == '0') && (t[1] == '\0'))
527 t = "<random>";
528
529 if ((c + mutt_str_len(t) + 2) >= win->state.cols)
530 break;
531
532 mutt_window_addstr(win, NONULL(t));
533 if (STAILQ_NEXT(np, entries))
534 mutt_window_addstr(win, ", ");
535
536 c += mutt_str_len(t) + 2;
537 }
538}
539#endif
540
550static int draw_envelope_addr(int field, struct AddressList *al,
551 struct MuttWindow *win, int row, size_t max_lines)
552{
553 draw_header(win, row, field);
554
555 struct ListHead list = STAILQ_HEAD_INITIALIZER(list);
556 int count = mutt_addrlist_count_recips(al);
557
558 int lines_used = 1;
559 int width_left = win->state.cols - MaxHeaderWidth;
560 char more[32] = { 0 };
561 int more_len = 0;
562
563 struct Buffer *buf = buf_pool_get();
564 bool in_group = false;
565 char *sep = NULL;
566 struct Address *addr = NULL;
567 TAILQ_FOREACH(addr, al, entries)
568 {
569 struct Address *next = TAILQ_NEXT(addr, entries);
570
571 if (addr->group)
572 {
573 in_group = true;
574 }
575
576 buf_reset(buf);
577 mutt_addr_write(buf, addr, true);
578 size_t addr_len = buf_len(buf);
579
580 sep = "";
581 if (!addr->group)
582 {
583 // group terminator
584 if (in_group && next && !next->mailbox && !next->personal)
585 {
586 sep = ";";
587 addr_len += 1;
588 in_group = false;
589 }
590 else if (next)
591 {
592 sep = ", ";
593 addr_len += 2;
594 }
595 }
596
597 count--;
598 try_again:
599 more_len = snprintf(more, sizeof(more),
600 ngettext("(+%d more)", "(+%d more)", count), count);
601 mutt_debug(LL_DEBUG3, "text: '%s' len: %d\n", more, more_len);
602
603 int reserve = ((count > 0) && (lines_used == max_lines)) ? more_len : 0;
604 mutt_debug(LL_DEBUG3, "processing: %s (al:%zu, wl:%d, r:%d, lu:%d)\n",
605 buf_string(buf), addr_len, width_left, reserve, lines_used);
606 if (addr_len >= (width_left - reserve))
607 {
608 mutt_debug(LL_DEBUG3, "not enough space\n");
609 if (lines_used == max_lines)
610 {
611 mutt_debug(LL_DEBUG3, "no more lines\n");
612 mutt_debug(LL_DEBUG3, "truncating: %s\n", buf_string(buf));
613 mutt_paddstr(win, width_left, buf_string(buf));
614 break;
615 }
616
617 if (width_left == (win->state.cols - MaxHeaderWidth))
618 {
619 mutt_debug(LL_DEBUG3, "couldn't print: %s\n", buf_string(buf));
620 mutt_paddstr(win, width_left, buf_string(buf));
621 break;
622 }
623
624 mutt_debug(LL_DEBUG3, "start a new line\n");
626 row++;
627 lines_used++;
628 width_left = win->state.cols - MaxHeaderWidth;
630 goto try_again;
631 }
632
633 if (addr_len < width_left)
634 {
635 mutt_debug(LL_DEBUG3, "space for: %s\n", buf_string(buf));
637 mutt_window_addstr(win, sep);
638 width_left -= addr_len;
639 }
640 mutt_debug(LL_DEBUG3, "%d addresses remaining\n", count);
641 mutt_debug(LL_DEBUG3, "%ld lines remaining\n", max_lines - lines_used);
642 }
643 mutt_list_free(&list);
644 buf_pool_release(&buf);
645
646 if (count > 0)
647 {
648 mutt_window_move(win, win->state.cols - more_len, row);
650 mutt_window_addstr(win, more);
652 mutt_debug(LL_DEBUG3, "%d more (len %d)\n", count, more_len);
653 }
654 else
655 {
657 }
658
659 for (int i = lines_used; i < max_lines; i++)
660 {
661 mutt_window_move(win, 0, row + i);
663 }
664
665 mutt_debug(LL_DEBUG3, "used %d lines\n", lines_used);
666 return lines_used;
667}
668
676static int draw_envelope_user_hdrs(struct MuttWindow *win,
677 struct EnvelopeWindowData *wdata, int row)
678{
679 const char *overflow_text = "...";
680 int rows_used = 0;
681
682 struct ListNode *first = STAILQ_FIRST(&wdata->email->env->userhdrs);
683 if (!first)
684 return rows_used;
685
686 /* Draw first entry on same line as prompt */
688 mutt_paddstr(win,
691 first->data);
692 rows_used++;
693
694 /* Draw any following entries on their own line */
695 struct ListNode *np = STAILQ_NEXT(first, entries);
696 if (!np)
697 return rows_used;
698
699 STAILQ_FOREACH_FROM(np, &wdata->email->env->userhdrs, entries)
700 {
701 if ((rows_used == (MAX_USER_HDR_ROWS - 1)) && STAILQ_NEXT(np, entries))
702 {
703 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, overflow_text);
704 rows_used++;
705 break;
706 }
707 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, np->data);
708 rows_used++;
709 }
710 return rows_used;
711}
712
718static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
719{
720 struct Email *e = wdata->email;
721 const char *fcc = buf_string(wdata->fcc);
722 const int cols = win->state.cols - MaxHeaderWidth;
723
725 int row = draw_envelope_addr(HDR_FROM, &e->env->from, win, 0, 1);
726
727#ifdef USE_NNTP
728 if (wdata->is_news)
729 {
730 draw_header(win, row++, HDR_NEWSGROUPS);
731 mutt_paddstr(win, cols, NONULL(e->env->newsgroups));
732
733 draw_header(win, row++, HDR_FOLLOWUPTO);
734 mutt_paddstr(win, cols, NONULL(e->env->followup_to));
735
736 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
737 if (c_x_comment_to)
738 {
739 draw_header(win, row++, HDR_XCOMMENTTO);
740 mutt_paddstr(win, cols, NONULL(e->env->x_comment_to));
741 }
742 }
743 else
744#endif
745 {
746 row += draw_envelope_addr(HDR_TO, &e->env->to, win, row, wdata->to_rows);
747 row += draw_envelope_addr(HDR_CC, &e->env->cc, win, row, wdata->cc_rows);
748 row += draw_envelope_addr(HDR_BCC, &e->env->bcc, win, row, wdata->bcc_rows);
749 }
750
751 draw_header(win, row++, HDR_SUBJECT);
752 mutt_paddstr(win, cols, NONULL(e->env->subject));
753
754 row += draw_envelope_addr(HDR_REPLYTO, &e->env->reply_to, win, row, 1);
755
756 draw_header(win, row++, HDR_FCC);
757 mutt_paddstr(win, cols, fcc);
758
759 if (WithCrypto)
760 row += draw_crypt_lines(win, wdata, row);
761
762#ifdef MIXMASTER
763 draw_mix_line(&e->chain, win, row++);
764#endif
765 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
766 if (c_compose_show_user_headers)
767 row += draw_envelope_user_hdrs(win, wdata, row);
768
770}
771
775static int env_recalc(struct MuttWindow *win)
776{
777 struct EnvelopeWindowData *wdata = win->wdata;
778
779 const int cur_rows = win->state.rows;
780 const int new_rows = calc_envelope(win, wdata);
781
782 if (new_rows != cur_rows)
783 {
784 win->req_rows = new_rows;
786 }
787
788 win->actions |= WA_REPAINT;
789 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
790 return 0;
791}
792
796static int env_repaint(struct MuttWindow *win)
797{
798 struct EnvelopeWindowData *wdata = win->wdata;
799
800 draw_envelope(win, wdata);
801 mutt_debug(LL_DEBUG5, "repaint done\n");
802 return 0;
803}
804
808static int env_color_observer(struct NotifyCallback *nc)
809{
810 if (nc->event_type != NT_COLOR)
811 return 0;
812 if (!nc->global_data || !nc->event_data)
813 return -1;
814
815 struct EventColor *ev_c = nc->event_data;
816 struct MuttWindow *win_env = nc->global_data;
817
818 enum ColorId cid = ev_c->cid;
819
820 switch (cid)
821 {
822 case MT_COLOR_BOLD:
828 case MT_COLOR_NORMAL:
829 case MT_COLOR_STATUS:
830 case MT_COLOR_MAX: // Sent on `uncolor *`
831 mutt_debug(LL_DEBUG5, "color done, request WA_REPAINT\n");
832 win_env->actions |= WA_REPAINT;
833 break;
834
835 default:
836 break;
837 }
838 return 0;
839}
840
845{
846 if (nc->event_type != NT_CONFIG)
847 return 0;
848 if (!nc->global_data || !nc->event_data)
849 return -1;
850
851 struct EventConfig *ev_c = nc->event_data;
852 if (!ev_c->name)
853 return 0;
854
855 struct MuttWindow *win_env = nc->global_data;
856
857 switch (ev_c->name[0])
858 {
859 case 'a':
860 if (mutt_str_equal(ev_c->name, "autocrypt"))
861 break;
862 return 0;
863 case 'c':
864 if (mutt_str_equal(ev_c->name, "compose_show_user_headers") ||
865 mutt_str_equal(ev_c->name, "crypt_opportunistic_encrypt"))
866 {
867 break;
868 }
869 return 0;
870 case 'p':
871 if (mutt_str_equal(ev_c->name, "pgp_sign_as"))
872 break;
873 return 0;
874 case 's':
875 if (mutt_str_equal(ev_c->name, "smime_encrypt_with") ||
876 mutt_str_equal(ev_c->name, "smime_sign_as"))
877 {
878 break;
879 }
880 return 0;
881 case 'x':
882 if (mutt_str_equal(ev_c->name, "x_comment_to"))
883 break;
884 return 0;
885 default:
886 return 0;
887 }
888
889 win_env->actions |= WA_RECALC;
890 mutt_debug(LL_DEBUG5, "config done, request WA_RECALC\n");
891 return 0;
892}
893
897static int env_email_observer(struct NotifyCallback *nc)
898{
899 if ((nc->event_type != NT_EMAIL) && (nc->event_type != NT_ENVELOPE))
900 return 0;
901 if (!nc->global_data)
902 return -1;
903
904 struct MuttWindow *win_env = nc->global_data;
905
906 // pgp/smime/autocrypt menu, or external change
907 if (nc->event_type == NT_EMAIL)
908 {
909 struct EnvelopeWindowData *wdata = win_env->wdata;
910 update_crypt_info(wdata);
911 }
912
913 win_env->actions |= WA_RECALC;
914 mutt_debug(LL_DEBUG5, "email done, request WA_RECALC\n");
915 return 0;
916}
917
922{
923 if (nc->event_type != NT_HEADER)
924 return 0;
925 if (!nc->global_data || !nc->event_data)
926 return -1;
927
928 const struct EventHeader *ev_h = nc->event_data;
929 struct MuttWindow *win_env = nc->global_data;
930 struct EnvelopeWindowData *wdata = win_env->wdata;
931
932 struct Envelope *env = wdata->email->env;
933
935 {
936 header_set(&env->userhdrs, ev_h->header);
937 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
938 win_env->actions |= WA_RECALC;
939 return 0;
940 }
941
943 {
944 struct ListNode *removed = header_find(&env->userhdrs, ev_h->header);
945 if (removed)
946 {
947 header_free(&env->userhdrs, removed);
948 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
949 win_env->actions |= WA_RECALC;
950 }
951 return 0;
952 }
953
954 return 0;
955}
956
961{
962 if (nc->event_type != NT_WINDOW)
963 return 0;
964 if (!nc->global_data || !nc->event_data)
965 return -1;
966
967 struct MuttWindow *win_env = nc->global_data;
968 struct EventWindow *ev_w = nc->event_data;
969 if (ev_w->win != win_env)
970 return 0;
971
973 {
974 win_env->actions |= WA_RECALC;
975 mutt_debug(LL_DEBUG5, "window state done, request WA_RECALC\n");
976 }
977 else if (nc->event_subtype == NT_WINDOW_DELETE)
978 {
979 struct EnvelopeWindowData *wdata = win_env->wdata;
980
986 mutt_debug(LL_DEBUG5, "window delete done\n");
987 }
988
989 return 0;
990}
991
999struct MuttWindow *env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
1000{
1002
1005 HDR_ATTACH_TITLE - 1);
1006
1012
1013 struct EnvelopeWindowData *wdata = env_wdata_new();
1014 wdata->fcc = fcc;
1015 wdata->email = e;
1016 wdata->sub = sub;
1017 wdata->is_news = OptNewsSend;
1018
1019 win_env->wdata = wdata;
1020 win_env->wdata_free = env_wdata_free;
1021 win_env->recalc = env_recalc;
1022 win_env->repaint = env_repaint;
1023
1024 return win_env;
1025}
size_t mutt_addrlist_write_list(const struct AddressList *al, struct ListHead *list)
Write Addresses to a List.
Definition: address.c:1218
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1047
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition: address.c:869
Email Address Handling.
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
Color and attribute parsing.
void mutt_color_observer_remove(observer_t callback, void *global_data)
Remove an observer.
Definition: notify.c:69
void mutt_color_observer_add(observer_t callback, void *global_data)
Add an observer.
Definition: notify.c:59
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:94
@ 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:292
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
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:545
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:647
void header_free(struct ListHead *hdrlist, struct ListNode *target)
Free and remove a header from a header list.
Definition: email.c:206
struct ListNode * header_set(struct ListHead *hdrlist, const char *header)
Set a header value in a list.
Definition: email.c:194
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:141
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:147
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:51
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:550
static const char *const AutocryptRecUiFlags[]
Autocrypt "recommendation" strings.
Definition: window.c:136
static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
Draw an aligned label.
Definition: window.c:363
static int HeaderPadding[HDR_ATTACH_TITLE]
Number of padding spaces needed after each of the strings in Prompts after translation.
Definition: window.c:87
static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Write the email headers to the compose window.
Definition: window.c:718
static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
Draw a floating label.
Definition: window.c:350
static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
Redraw the Mixmaster chain.
Definition: window.c:508
const char *const Prompts[]
Names of header fields used in the envelope, e.g. From:, To:
Definition: window.c:92
#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:676
static int calc_address(struct AddressList *al, short cols, short *srows)
Calculate how many rows an AddressList will need.
Definition: window.c:222
struct MuttWindow * env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
Create the Envelope Window.
Definition: window.c:999
static int MaxHeaderWidth
Widest of the Prompts strings after translation.
Definition: window.c:89
static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Calculate how many rows the envelope will need.
Definition: window.c:309
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:379
static int calc_user_hdrs(const struct ListHead *hdrs)
Calculate how many rows are needed for user-defined headers.
Definition: window.c:290
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:267
#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:166
static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
Update the encryption info in the compose window.
Definition: window.c:393
static void init_header_padding(void)
Calculate how much padding the compose table will need.
Definition: window.c:185
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:77
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
static int env_email_observer(struct NotifyCallback *nc)
Notification that the Email has changed - Implements observer_t -.
Definition: window.c:897
static int env_color_observer(struct NotifyCallback *nc)
Notification that a Color has changed - Implements observer_t -.
Definition: window.c:808
static int env_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: window.c:960
static int env_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: window.c:844
static int env_header_observer(struct NotifyCallback *nc)
Notification that a User Header has changed - Implements observer_t -.
Definition: window.c:921
static int env_recalc(struct MuttWindow *win)
Recalculate the Window data - Implements MuttWindow::recalc() -.
Definition: window.c:775
static int env_repaint(struct MuttWindow *win)
Repaint the Window - Implements MuttWindow::repaint() -.
Definition: window.c:796
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: logging2.h:45
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
#define MIN(a, b)
Definition: memory.h:32
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:230
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:191
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
const 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
const 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:720
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:344
int mutt_window_printf(struct MuttWindow *win, const char *fmt,...)
Write a formatted string to a Window.
Definition: mutt_window.c:431
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:182
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
int mutt_window_addstr(struct MuttWindow *win, const char *str)
Write a string to a Window.
Definition: mutt_window.c:416
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
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:326
#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:230
@ NT_WINDOW_DELETE
Window is about to be deleted.
Definition: mutt_window.h:229
#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:86
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:88
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:87
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:79
#define WithCrypto
Definition: lib.h:117
#define SEC_SIGN
Email is signed.
Definition: lib.h:80
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:57
@ 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
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
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
struct Buffer * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
String manipulation buffer.
Definition: buffer.h:34
A set of inherited config items.
Definition: subset.h:47
struct Notify * notify
Notifications: NotifyConfig, EventConfig.
Definition: subset.h:52
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:71
const char * name
Name of config item that changed.
Definition: subset.h:73
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:239
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:240
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:187
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:173
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:41
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
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