NeoMutt  2024-03-23-23-gec7045
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
window.c
Go to the documentation of this file.
1
62#include "config.h"
63#include <stdbool.h>
64#include <stdio.h>
65#include "private.h"
66#include "mutt/lib.h"
67#include "address/lib.h"
68#include "config/lib.h"
69#include "email/lib.h"
70#include "core/lib.h"
71#include "gui/lib.h"
72#include "color/lib.h"
73#include "ncrypt/lib.h"
74#include "functions.h"
75#include "globals.h"
76#include "wdata.h"
77#ifdef ENABLE_NLS
78#include <libintl.h>
79#endif
80
82#define MAX_ADDR_ROWS 5
83
85#define MAX_USER_HDR_ROWS 5
86
88static int HeaderPadding[HDR_ATTACH_TITLE] = { 0 };
90static int MaxHeaderWidth = 0;
91
93const char *const Prompts[] = {
94 /* L10N: Compose menu field. May not want to translate. */
95 N_("From: "),
96 /* L10N: Compose menu field. May not want to translate. */
97 N_("To: "),
98 /* L10N: Compose menu field. May not want to translate. */
99 N_("Cc: "),
100 /* L10N: Compose menu field. May not want to translate. */
101 N_("Bcc: "),
102 /* L10N: Compose menu field. May not want to translate. */
103 N_("Subject: "),
104 /* L10N: Compose menu field. May not want to translate. */
105 N_("Reply-To: "),
106 /* L10N: Compose menu field. May not want to translate. */
107 N_("Fcc: "),
108#ifdef MIXMASTER
109 /* L10N: "Mix" refers to the MixMaster chain for anonymous email */
110 N_("Mix: "),
111#endif
112 /* L10N: Compose menu field. Holds "Encrypt", "Sign" related information */
113 N_("Security: "),
114 /* L10N: This string is used by the compose menu.
115 Since it is hidden by default, it does not increase the indentation of
116 other compose menu fields. However, if possible, it should not be longer
117 than the other compose menu fields. Since it shares the row with "Encrypt
118 with:", it should not be longer than 15-20 character cells. */
119 N_("Sign as: "),
120#ifdef USE_AUTOCRYPT
121 // L10N: The compose menu autocrypt line
122 N_("Autocrypt: "),
123#endif
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 N_("Headers: "),
131};
132
133#ifdef USE_AUTOCRYPT
135static const char *const AutocryptRecUiFlags[] = {
136 /* L10N: Autocrypt recommendation flag: off.
137 This is displayed when Autocrypt is turned off. */
138 N_("Off"),
139 /* L10N: Autocrypt recommendation flag: no.
140 This is displayed when Autocrypt cannot encrypt to the recipients. */
141 N_("No"),
142 /* L10N: Autocrypt recommendation flag: discouraged.
143 This is displayed when Autocrypt believes encryption should not be used.
144 This might occur if one of the recipient Autocrypt Keys has not been
145 used recently, or if the only key available is a Gossip Header key. */
146 N_("Discouraged"),
147 /* L10N: Autocrypt recommendation flag: available.
148 This is displayed when Autocrypt believes encryption is possible, but
149 leaves enabling it up to the sender. Probably because "prefer encrypt"
150 is not set in both the sender and recipient keys. */
151 N_("Available"),
152 /* L10N: Autocrypt recommendation flag: yes.
153 This is displayed when Autocrypt would normally enable encryption
154 automatically. */
155 N_("Yes"),
156};
157#endif
158
165static void calc_header_width_padding(int idx, const char *header, bool calc_max)
166{
167 int width;
168
169 HeaderPadding[idx] = mutt_str_len(header);
170 width = mutt_strwidth(header);
171 if (calc_max && (MaxHeaderWidth < width))
172 MaxHeaderWidth = width;
173 HeaderPadding[idx] -= width;
174}
175
184static void init_header_padding(void)
185{
186 static bool done = false;
187
188 if (done)
189 return;
190 done = true;
191
192 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
193 {
194 if (i == HDR_CRYPTINFO)
195 continue;
196 calc_header_width_padding(i, _(Prompts[i]), true);
197 }
198
199 /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
200 * doesn't show up by default, and so can make the indentation of
201 * the other fields look funny. */
203
204 for (int i = 0; i < HDR_ATTACH_TITLE; i++)
205 {
207 if (HeaderPadding[i] < 0)
208 HeaderPadding[i] = 0;
209 }
210}
211
221static int calc_address(struct AddressList *al, short cols, short *srows)
222{
223 struct ListHead slist = STAILQ_HEAD_INITIALIZER(slist);
224 mutt_addrlist_write_list(al, &slist);
225
226 int rows = 1;
227 int addr_len;
228 int width_left = cols;
229 struct ListNode *next = NULL;
230 struct ListNode *np = NULL;
231 STAILQ_FOREACH(np, &slist, entries)
232 {
233 next = STAILQ_NEXT(np, entries);
234 addr_len = mutt_strwidth(np->data);
235 if (next)
236 addr_len += 2; // ", "
237
238 try_again:
239 if (addr_len >= width_left)
240 {
241 if (width_left == cols)
242 break;
243
244 rows++;
245 width_left = cols;
246 goto try_again;
247 }
248
249 if (addr_len < width_left)
250 width_left -= addr_len;
251 }
252
253 mutt_list_free(&slist);
254
255 *srows = MIN(rows, MAX_ADDR_ROWS);
256 return *srows;
257}
258
266static int calc_security(struct Email *e, short *rows, const struct ConfigSubset *sub)
267{
269 *rows = 0; // Neither PGP nor SMIME are built into NeoMutt
270 else if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) != 0)
271 *rows = 2; // 'Security:' and 'Sign as:'
272 else
273 *rows = 1; // Just 'Security:'
274
275#ifdef USE_AUTOCRYPT
276 const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
277 if (c_autocrypt)
278 *rows += 1;
279#endif
280
281 return *rows;
282}
283
289static int calc_user_hdrs(const struct ListHead *hdrs)
290{
291 int rows = 0; /* Don't print at all if no custom headers*/
292 struct ListNode *np = NULL;
293 STAILQ_FOREACH(np, hdrs, entries)
294 {
295 if (rows == MAX_USER_HDR_ROWS)
296 break;
297 rows++;
298 }
299 return rows;
300}
301
308static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
309{
310 int rows = 4; // 'From:', 'Subject:', 'Reply-To:', 'Fcc:'
311#ifdef MIXMASTER
312 rows++;
313#endif
314
315 struct Email *e = wdata->email;
316 struct Envelope *env = e->env;
317 const int cols = win->state.cols - MaxHeaderWidth;
318
319 if (wdata->is_news)
320 {
321 rows += 2; // 'Newsgroups:' and 'Followup-To:'
322 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
323 if (c_x_comment_to)
324 rows++;
325 }
326 else
327 {
328 rows += calc_address(&env->to, cols, &wdata->to_rows);
329 rows += calc_address(&env->cc, cols, &wdata->cc_rows);
330 rows += calc_address(&env->bcc, cols, &wdata->bcc_rows);
331 }
332 rows += calc_security(e, &wdata->sec_rows, wdata->sub);
333 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
334 if (c_compose_show_user_headers)
335 rows += calc_user_hdrs(&env->userhdrs);
336
337 return rows;
338}
339
347static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
348{
350 mutt_window_mvprintw(win, col, row, "%s", text);
352}
353
360static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
361{
363 mutt_window_mvprintw(win, 0, row, "%*s", HeaderPadding[field], _(Prompts[field]));
365}
366
376static void draw_header_content(struct MuttWindow *win, int row,
377 enum HeaderField field, const char *content)
378{
379 mutt_window_move(win, HeaderPadding[field], row);
380 mutt_paddstr(win, win->state.cols - HeaderPadding[field], content);
381}
382
390static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
391{
392 struct Email *e = wdata->email;
393
394 draw_header(win, row++, HDR_CRYPT);
395
397 return 0;
398
399 // We'll probably need two lines for 'Security:' and 'Sign as:'
400 int used = 2;
401 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)) == (SEC_ENCRYPT | SEC_SIGN))
402 {
404 mutt_window_addstr(win, _("Sign, Encrypt"));
405 }
406 else if (e->security & SEC_ENCRYPT)
407 {
409 mutt_window_addstr(win, _("Encrypt"));
410 }
411 else if (e->security & SEC_SIGN)
412 {
414 mutt_window_addstr(win, _("Sign"));
415 }
416 else
417 {
418 /* L10N: This refers to the encryption of the email, e.g. "Security: None" */
420 mutt_window_addstr(win, _("None"));
421 used = 1; // 'Sign as:' won't be needed
422 }
424
425 if ((e->security & (SEC_ENCRYPT | SEC_SIGN)))
426 {
427 if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
428 {
429 if ((e->security & SEC_INLINE))
430 mutt_window_addstr(win, _(" (inline PGP)"));
431 else
432 mutt_window_addstr(win, _(" (PGP/MIME)"));
433 }
434 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
435 {
436 mutt_window_addstr(win, _(" (S/MIME)"));
437 }
438 }
439
440 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(wdata->sub, "crypt_opportunistic_encrypt");
441 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
442 mutt_window_addstr(win, _(" (OppEnc mode)"));
443
445
446 if (((WithCrypto & APPLICATION_PGP) != 0) &&
447 (e->security & APPLICATION_PGP) && (e->security & SEC_SIGN))
448 {
449 draw_header(win, row++, HDR_CRYPTINFO);
450 const char *const c_pgp_sign_as = cs_subset_string(wdata->sub, "pgp_sign_as");
451 mutt_window_printf(win, "%s", c_pgp_sign_as ? c_pgp_sign_as : _("<default>"));
452 }
453
454 if (((WithCrypto & APPLICATION_SMIME) != 0) &&
456 {
457 draw_header(win, row++, HDR_CRYPTINFO);
458 const char *const c_smime_sign_as = cs_subset_string(wdata->sub, "smime_sign_as");
459 mutt_window_printf(win, "%s", c_smime_sign_as ? c_smime_sign_as : _("<default>"));
460 }
461
462 const char *const c_smime_encrypt_with = cs_subset_string(wdata->sub, "smime_encrypt_with");
463 if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME) &&
464 (e->security & SEC_ENCRYPT) && c_smime_encrypt_with)
465 {
466 draw_floating(win, 40, row - 1, _("Encrypt with: "));
467 mutt_window_printf(win, "%s", NONULL(c_smime_encrypt_with));
468 }
469
470#ifdef USE_AUTOCRYPT
471 const bool c_autocrypt = cs_subset_bool(wdata->sub, "autocrypt");
472 if (c_autocrypt)
473 {
474 draw_header(win, row, HDR_AUTOCRYPT);
475 if (e->security & SEC_AUTOCRYPT)
476 {
478 mutt_window_addstr(win, _("Encrypt"));
479 }
480 else
481 {
483 mutt_window_addstr(win, _("Off"));
484 }
485
486 /* L10N: The autocrypt compose menu Recommendation field.
487 Displays the output of the recommendation engine
488 (Off, No, Discouraged, Available, Yes) */
489 draw_floating(win, 40, row, _("Recommendation: "));
491
492 used++;
493 }
494#endif
495 return used;
496}
497
498#ifdef MIXMASTER
505static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
506{
507 char *t = NULL;
508
509 draw_header(win, row, HDR_MIX);
510
511 if (STAILQ_EMPTY(chain))
512 {
513 mutt_window_addstr(win, _("<no chain defined>"));
515 return;
516 }
517
518 int c = 12;
519 struct ListNode *np = NULL;
520 STAILQ_FOREACH(np, chain, entries)
521 {
522 t = np->data;
523 if (t && (t[0] == '0') && (t[1] == '\0'))
524 t = "<random>";
525
526 if ((c + mutt_str_len(t) + 2) >= win->state.cols)
527 break;
528
529 mutt_window_addstr(win, NONULL(t));
530 if (STAILQ_NEXT(np, entries))
531 mutt_window_addstr(win, ", ");
532
533 c += mutt_str_len(t) + 2;
534 }
535}
536#endif
537
547static int draw_envelope_addr(int field, struct AddressList *al,
548 struct MuttWindow *win, int row, size_t max_lines)
549{
550 draw_header(win, row, field);
551
552 struct ListHead list = STAILQ_HEAD_INITIALIZER(list);
553 int count = mutt_addrlist_count_recips(al);
554
555 int lines_used = 1;
556 int width_left = win->state.cols - MaxHeaderWidth;
557 char more[32] = { 0 };
558 int more_len = 0;
559
560 struct Buffer *buf = buf_pool_get();
561 bool in_group = false;
562 char *sep = NULL;
563 struct Address *addr = NULL;
564 TAILQ_FOREACH(addr, al, entries)
565 {
566 struct Address *next = TAILQ_NEXT(addr, entries);
567
568 if (addr->group)
569 {
570 in_group = true;
571 }
572
573 buf_reset(buf);
574 mutt_addr_write(buf, addr, true);
575 size_t addr_len = buf_len(buf);
576
577 sep = "";
578 if (!addr->group)
579 {
580 // group terminator
581 if (in_group && next && !next->mailbox && !next->personal)
582 {
583 sep = ";";
584 addr_len += 1;
585 in_group = false;
586 }
587 else if (next)
588 {
589 sep = ", ";
590 addr_len += 2;
591 }
592 }
593
594 count--;
595 try_again:
596 more_len = snprintf(more, sizeof(more),
597 ngettext("(+%d more)", "(+%d more)", count), count);
598 mutt_debug(LL_DEBUG3, "text: '%s' len: %d\n", more, more_len);
599
600 int reserve = ((count > 0) && (lines_used == max_lines)) ? more_len : 0;
601 mutt_debug(LL_DEBUG3, "processing: %s (al:%zu, wl:%d, r:%d, lu:%d)\n",
602 buf_string(buf), addr_len, width_left, reserve, lines_used);
603 if (addr_len >= (width_left - reserve))
604 {
605 mutt_debug(LL_DEBUG3, "not enough space\n");
606 if (lines_used == max_lines)
607 {
608 mutt_debug(LL_DEBUG3, "no more lines\n");
609 mutt_debug(LL_DEBUG3, "truncating: %s\n", buf_string(buf));
610 mutt_paddstr(win, width_left, buf_string(buf));
611 break;
612 }
613
614 if (width_left == (win->state.cols - MaxHeaderWidth))
615 {
616 mutt_debug(LL_DEBUG3, "couldn't print: %s\n", buf_string(buf));
617 mutt_paddstr(win, width_left, buf_string(buf));
618 break;
619 }
620
621 mutt_debug(LL_DEBUG3, "start a new line\n");
623 row++;
624 lines_used++;
625 width_left = win->state.cols - MaxHeaderWidth;
627 goto try_again;
628 }
629
630 if (addr_len < width_left)
631 {
632 mutt_debug(LL_DEBUG3, "space for: %s\n", buf_string(buf));
634 mutt_window_addstr(win, sep);
635 width_left -= addr_len;
636 }
637 mutt_debug(LL_DEBUG3, "%d addresses remaining\n", count);
638 mutt_debug(LL_DEBUG3, "%zd lines remaining\n", max_lines - lines_used);
639 }
640 mutt_list_free(&list);
641 buf_pool_release(&buf);
642
643 if (count > 0)
644 {
645 mutt_window_move(win, win->state.cols - more_len, row);
647 mutt_window_addstr(win, more);
649 mutt_debug(LL_DEBUG3, "%d more (len %d)\n", count, more_len);
650 }
651 else
652 {
654 }
655
656 for (int i = lines_used; i < max_lines; i++)
657 {
658 mutt_window_move(win, 0, row + i);
660 }
661
662 mutt_debug(LL_DEBUG3, "used %d lines\n", lines_used);
663 return lines_used;
664}
665
673static int draw_envelope_user_hdrs(struct MuttWindow *win,
674 struct EnvelopeWindowData *wdata, int row)
675{
676 const char *overflow_text = "...";
677 int rows_used = 0;
678
679 struct ListNode *first = STAILQ_FIRST(&wdata->email->env->userhdrs);
680 if (!first)
681 return rows_used;
682
683 /* Draw first entry on same line as prompt */
685 mutt_paddstr(win,
688 first->data);
689 rows_used++;
690
691 /* Draw any following entries on their own line */
692 struct ListNode *np = STAILQ_NEXT(first, entries);
693 if (!np)
694 return rows_used;
695
696 STAILQ_FOREACH_FROM(np, &wdata->email->env->userhdrs, entries)
697 {
698 if ((rows_used == (MAX_USER_HDR_ROWS - 1)) && STAILQ_NEXT(np, entries))
699 {
700 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, overflow_text);
701 rows_used++;
702 break;
703 }
704 draw_header_content(win, row + rows_used, HDR_CUSTOM_HEADERS, np->data);
705 rows_used++;
706 }
707 return rows_used;
708}
709
715static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
716{
717 struct Email *e = wdata->email;
718 const char *fcc = buf_string(wdata->fcc);
719 const int cols = win->state.cols - MaxHeaderWidth;
720
722 int row = draw_envelope_addr(HDR_FROM, &e->env->from, win, 0, 1);
723
724 if (wdata->is_news)
725 {
726 draw_header(win, row++, HDR_NEWSGROUPS);
727 mutt_paddstr(win, cols, NONULL(e->env->newsgroups));
728
729 draw_header(win, row++, HDR_FOLLOWUPTO);
730 mutt_paddstr(win, cols, NONULL(e->env->followup_to));
731
732 const bool c_x_comment_to = cs_subset_bool(wdata->sub, "x_comment_to");
733 if (c_x_comment_to)
734 {
735 draw_header(win, row++, HDR_XCOMMENTTO);
736 mutt_paddstr(win, cols, NONULL(e->env->x_comment_to));
737 }
738 }
739 else
740 {
741 row += draw_envelope_addr(HDR_TO, &e->env->to, win, row, wdata->to_rows);
742 row += draw_envelope_addr(HDR_CC, &e->env->cc, win, row, wdata->cc_rows);
743 row += draw_envelope_addr(HDR_BCC, &e->env->bcc, win, row, wdata->bcc_rows);
744 }
745
746 draw_header(win, row++, HDR_SUBJECT);
747 mutt_paddstr(win, cols, NONULL(e->env->subject));
748
749 row += draw_envelope_addr(HDR_REPLYTO, &e->env->reply_to, win, row, 1);
750
751 draw_header(win, row++, HDR_FCC);
752 mutt_paddstr(win, cols, fcc);
753
754 if (WithCrypto)
755 row += draw_crypt_lines(win, wdata, row);
756
757#ifdef MIXMASTER
758 draw_mix_line(&e->chain, win, row++);
759#endif
760 const bool c_compose_show_user_headers = cs_subset_bool(wdata->sub, "compose_show_user_headers");
761 if (c_compose_show_user_headers)
762 row += draw_envelope_user_hdrs(win, wdata, row);
763
765}
766
770static int env_recalc(struct MuttWindow *win)
771{
772 struct EnvelopeWindowData *wdata = win->wdata;
773
774 const int cur_rows = win->state.rows;
775 const int new_rows = calc_envelope(win, wdata);
776
777 if (new_rows != cur_rows)
778 {
779 win->req_rows = new_rows;
781 }
782
783 win->actions |= WA_REPAINT;
784 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
785 return 0;
786}
787
791static int env_repaint(struct MuttWindow *win)
792{
793 struct EnvelopeWindowData *wdata = win->wdata;
794
795 draw_envelope(win, wdata);
796 mutt_debug(LL_DEBUG5, "repaint done\n");
797 return 0;
798}
799
803static int env_color_observer(struct NotifyCallback *nc)
804{
805 if (nc->event_type != NT_COLOR)
806 return 0;
807 if (!nc->global_data || !nc->event_data)
808 return -1;
809
810 struct EventColor *ev_c = nc->event_data;
811 struct MuttWindow *win_env = nc->global_data;
812
813 enum ColorId cid = ev_c->cid;
814
815 switch (cid)
816 {
817 case MT_COLOR_BOLD:
823 case MT_COLOR_NORMAL:
824 case MT_COLOR_STATUS:
825 case MT_COLOR_MAX: // Sent on `uncolor *`
826 mutt_debug(LL_DEBUG5, "color done, request WA_REPAINT\n");
827 win_env->actions |= WA_REPAINT;
828 break;
829
830 default:
831 break;
832 }
833 return 0;
834}
835
840{
841 if (nc->event_type != NT_CONFIG)
842 return 0;
843 if (!nc->global_data || !nc->event_data)
844 return -1;
845
846 struct EventConfig *ev_c = nc->event_data;
847 if (!ev_c->name)
848 return 0;
849
850 struct MuttWindow *win_env = nc->global_data;
851
852 switch (ev_c->name[0])
853 {
854 case 'a':
855 if (mutt_str_equal(ev_c->name, "autocrypt"))
856 break;
857 return 0;
858 case 'c':
859 if (mutt_str_equal(ev_c->name, "compose_show_user_headers") ||
860 mutt_str_equal(ev_c->name, "crypt_opportunistic_encrypt"))
861 {
862 break;
863 }
864 return 0;
865 case 'p':
866 if (mutt_str_equal(ev_c->name, "pgp_sign_as"))
867 break;
868 return 0;
869 case 's':
870 if (mutt_str_equal(ev_c->name, "smime_encrypt_with") ||
871 mutt_str_equal(ev_c->name, "smime_sign_as"))
872 {
873 break;
874 }
875 return 0;
876 case 'x':
877 if (mutt_str_equal(ev_c->name, "x_comment_to"))
878 break;
879 return 0;
880 default:
881 return 0;
882 }
883
884 win_env->actions |= WA_RECALC;
885 mutt_debug(LL_DEBUG5, "config done, request WA_RECALC\n");
886 return 0;
887}
888
892static int env_email_observer(struct NotifyCallback *nc)
893{
894 if ((nc->event_type != NT_EMAIL) && (nc->event_type != NT_ENVELOPE))
895 return 0;
896 if (!nc->global_data)
897 return -1;
898
899 struct MuttWindow *win_env = nc->global_data;
900
901 // pgp/smime/autocrypt menu, or external change
902 if (nc->event_type == NT_EMAIL)
903 {
904 struct EnvelopeWindowData *wdata = win_env->wdata;
905 update_crypt_info(wdata);
906 }
907
908 win_env->actions |= WA_RECALC;
909 mutt_debug(LL_DEBUG5, "email done, request WA_RECALC\n");
910 return 0;
911}
912
917{
918 if (nc->event_type != NT_HEADER)
919 return 0;
920 if (!nc->global_data || !nc->event_data)
921 return -1;
922
923 const struct EventHeader *ev_h = nc->event_data;
924 struct MuttWindow *win_env = nc->global_data;
925 struct EnvelopeWindowData *wdata = win_env->wdata;
926
927 struct Envelope *env = wdata->email->env;
928
930 {
931 header_set(&env->userhdrs, ev_h->header);
932 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
933 win_env->actions |= WA_RECALC;
934 return 0;
935 }
936
938 {
939 struct ListNode *removed = header_find(&env->userhdrs, ev_h->header);
940 if (removed)
941 {
942 header_free(&env->userhdrs, removed);
943 mutt_debug(LL_DEBUG5, "header done, request reflow\n");
944 win_env->actions |= WA_RECALC;
945 }
946 return 0;
947 }
948
949 return 0;
950}
951
956{
957 if (nc->event_type != NT_WINDOW)
958 return 0;
959 if (!nc->global_data || !nc->event_data)
960 return -1;
961
962 struct MuttWindow *win_env = nc->global_data;
963 struct EventWindow *ev_w = nc->event_data;
964 if (ev_w->win != win_env)
965 return 0;
966
968 {
969 win_env->actions |= WA_RECALC;
970 mutt_debug(LL_DEBUG5, "window state done, request WA_RECALC\n");
971 }
972 else if (nc->event_subtype == NT_WINDOW_DELETE)
973 {
974 struct EnvelopeWindowData *wdata = win_env->wdata;
975
981 mutt_debug(LL_DEBUG5, "window delete done\n");
982 }
983
984 return 0;
985}
986
994struct MuttWindow *env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
995{
997
1000 HDR_ATTACH_TITLE - 1);
1001
1007
1008 struct EnvelopeWindowData *wdata = env_wdata_new();
1009 wdata->fcc = fcc;
1010 wdata->email = e;
1011 wdata->sub = sub;
1012 wdata->is_news = OptNewsSend;
1013
1014 win_env->wdata = wdata;
1015 win_env->wdata_free = env_wdata_free;
1016 win_env->recalc = env_recalc;
1017 win_env->repaint = env_repaint;
1018
1019 return win_env;
1020}
size_t mutt_addrlist_write_list(const struct AddressList *al, struct ListHead *list)
Write Addresses to a List.
Definition: address.c:1221
size_t mutt_addr_write(struct Buffer *buf, struct Address *addr, bool display)
Write a single Address to a buffer.
Definition: address.c:1050
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition: address.c:872
Email Address Handling.
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:508
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
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:40
@ MT_COLOR_COMPOSE_SECURITY_ENCRYPT
Mail will be encrypted.
Definition: color.h:48
@ 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:49
@ MT_COLOR_BOLD
Bold text.
Definition: color.h:45
@ MT_COLOR_COMPOSE_SECURITY_BOTH
Mail will be encrypted and signed.
Definition: color.h:47
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:59
@ MT_COLOR_COMPOSE_SECURITY_SIGN
Mail will be signed.
Definition: color.h:50
@ MT_COLOR_COMPOSE_HEADER
Header labels, e.g. From:
Definition: color.h:46
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:343
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:445
void header_free(struct ListHead *hdrlist, struct ListNode *target)
Free and remove a header from a header list.
Definition: email.c:208
struct ListNode * header_set(struct ListHead *hdrlist, const char *header)
Set a header value in a list.
Definition: email.c:196
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:143
Structs that make up an email.
@ NT_HEADER_CHANGE
An existing header has been changed.
Definition: email.h:213
@ NT_HEADER_ADD
Header has been added.
Definition: email.h:211
@ NT_HEADER_DELETE
Header has been removed.
Definition: email.h:212
void update_crypt_info(struct EnvelopeWindowData *wdata)
Update the crypto info.
Definition: functions.c:148
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:54
@ 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:53
@ HDR_FOLLOWUPTO
"Followup-To:" field
Definition: private.h:51
@ HDR_XCOMMENTTO
"X-Comment-To:" field
Definition: private.h:52
@ HDR_NEWSGROUPS
"Newsgroups:" field
Definition: private.h:50
@ 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:547
static const char *const AutocryptRecUiFlags[]
Autocrypt "recommendation" strings.
Definition: window.c:135
static void draw_header(struct MuttWindow *win, int row, enum HeaderField field)
Draw an aligned label.
Definition: window.c:360
static int HeaderPadding[HDR_ATTACH_TITLE]
Number of padding spaces needed after each of the strings in Prompts after translation.
Definition: window.c:88
static void draw_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Write the email headers to the compose window.
Definition: window.c:715
static void draw_floating(struct MuttWindow *win, int col, int row, const char *text)
Draw a floating label.
Definition: window.c:347
static void draw_mix_line(struct ListHead *chain, struct MuttWindow *win, int row)
Redraw the Mixmaster chain.
Definition: window.c:505
const char *const Prompts[]
Names of header fields used in the envelope, e.g. From:, To:
Definition: window.c:93
#define MAX_USER_HDR_ROWS
Maximum number of rows to use for the Headers: field.
Definition: window.c:85
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:673
static int calc_address(struct AddressList *al, short cols, short *srows)
Calculate how many rows an AddressList will need.
Definition: window.c:221
struct MuttWindow * env_window_new(struct Email *e, struct Buffer *fcc, struct ConfigSubset *sub)
Create the Envelope Window.
Definition: window.c:994
static int MaxHeaderWidth
Widest of the Prompts strings after translation.
Definition: window.c:90
static int calc_envelope(struct MuttWindow *win, struct EnvelopeWindowData *wdata)
Calculate how many rows the envelope will need.
Definition: window.c:308
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:376
static int calc_user_hdrs(const struct ListHead *hdrs)
Calculate how many rows are needed for user-defined headers.
Definition: window.c:289
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:266
#define MAX_ADDR_ROWS
Maximum number of rows to use for the To:, Cc:, Bcc: fields.
Definition: window.c:82
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:165
static int draw_crypt_lines(struct MuttWindow *win, struct EnvelopeWindowData *wdata, int row)
Update the encryption info in the compose window.
Definition: window.c:390
static void init_header_padding(void)
Calculate how much padding the compose table will need.
Definition: window.c:184
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:71
#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:892
static int env_color_observer(struct NotifyCallback *nc)
Notification that a Color has changed - Implements observer_t -.
Definition: window.c:803
static int env_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: window.c:955
static int env_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t -.
Definition: window.c:839
static int env_header_observer(struct NotifyCallback *nc)
Notification that a User Header has changed - Implements observer_t -.
Definition: window.c:916
static int env_recalc(struct MuttWindow *win)
Recalculate the Window data - Implements MuttWindow::recalc() -.
Definition: window.c:770
static int env_repaint(struct MuttWindow *win)
Repaint the Window - Implements MuttWindow::repaint() -.
Definition: window.c:791
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:709
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
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:63
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:79
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: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: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:36
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:39
struct Envelope * env
Envelope information.
Definition: email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct ListHead chain
Mixmaster chain.
Definition: email.h:93
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:73
Data to fill the Envelope Window.
Definition: wdata.h:38
bool is_news
Email is a news article.
Definition: wdata.h:48
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:50
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:85
char *const subject
Email's subject.
Definition: envelope.h:70
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:80
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:81
char * newsgroups
List of newsgroups.
Definition: envelope.h:78
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
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:220
char * header
The contents of the header.
Definition: email.h:221
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