NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
dlggpgme.c
Go to the documentation of this file.
1 
70 #include "config.h"
71 #include <ctype.h>
72 #include <gpgme.h>
73 #include <langinfo.h>
74 #include <limits.h>
75 #include <locale.h>
76 #include <stdbool.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <time.h>
81 #include <unistd.h>
82 #include "private.h"
83 #include "mutt/lib.h"
84 #include "address/lib.h"
85 #include "config/lib.h"
86 #include "core/lib.h"
87 #include "gui/lib.h"
88 #include "lib.h"
89 #include "menu/lib.h"
90 #include "pager/lib.h"
91 #include "question/lib.h"
92 #include "crypt_gpgme.h"
93 #include "format_flags.h"
94 #include "mutt_logging.h"
95 #include "muttlib.h"
96 #include "opcodes.h"
97 #include "options.h"
98 #ifdef ENABLE_NLS
99 #include <libintl.h>
100 #endif
101 
103 static const struct Mapping GpgmeHelp[] = {
104  // clang-format off
105  { N_("Exit"), OP_EXIT },
106  { N_("Select"), OP_GENERIC_SELECT_ENTRY },
107  { N_("Check key"), OP_VERIFY_KEY },
108  { N_("Help"), OP_HELP },
109  { NULL, 0 },
110  // clang-format on
111 };
112 
117 {
118  size_t num;
119  struct CryptKeyInfo *key;
120 };
121 
125 struct DnArray
126 {
127  char *key;
128  char *value;
129 };
130 
131 static const char *const KeyInfoPrompts[] = {
132  /* L10N: The following are the headers for the "verify key" output from the
133  GPGME key selection menu (bound to "c" in the key selection menu).
134  They will be automatically aligned. */
135  N_("Name: "), N_("aka: "), N_("Valid From: "), N_("Valid To: "),
136  N_("Key Type: "), N_("Key Usage: "), N_("Fingerprint: "), N_("Serial-No: "),
137  N_("Issued By: "), N_("Subkey: ")
138 };
139 
140 int KeyInfoPadding[KIP_MAX] = { 0 };
141 
150 static void print_utf8(FILE *fp, const char *buf, size_t len)
151 {
152  char *tstr = mutt_mem_malloc(len + 1);
153  memcpy(tstr, buf, len);
154  tstr[len] = 0;
155 
156  /* fromcode "utf-8" is sure, so we don't want
157  * charset-hook corrections: flags must be 0. */
158  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
159  mutt_ch_convert_string(&tstr, "utf-8", c_charset, MUTT_ICONV_NO_FLAGS);
160  fputs(tstr, fp);
161  FREE(&tstr);
162 }
163 
169 static bool crypt_key_is_valid(struct CryptKeyInfo *k)
170 {
171  if (k->flags & KEYFLAG_CANTUSE)
172  return false;
173  return true;
174 }
175 
184 static int crypt_compare_key_address(const void *a, const void *b)
185 {
186  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
187  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
188 
189  int r = mutt_istr_cmp((*s)->uid, (*t)->uid);
190  if (r != 0)
191  return r > 0;
193 }
194 
203 static int crypt_compare_address_qsort(const void *a, const void *b)
204 {
205  const short c_pgp_sort_keys = cs_subset_sort(NeoMutt->sub, "pgp_sort_keys");
206  return (c_pgp_sort_keys & SORT_REVERSE) ? !crypt_compare_key_address(a, b) :
208 }
209 
218 static int crypt_compare_keyid(const void *a, const void *b)
219 {
220  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
221  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
222 
224  if (r != 0)
225  return r > 0;
226  return mutt_istr_cmp((*s)->uid, (*t)->uid) > 0;
227 }
228 
237 static int crypt_crypt_compare_keyid_qsort(const void *a, const void *b)
238 {
239  const short c_pgp_sort_keys = cs_subset_sort(NeoMutt->sub, "pgp_sort_keys");
240  return (c_pgp_sort_keys & SORT_REVERSE) ? !crypt_compare_keyid(a, b) :
241  crypt_compare_keyid(a, b);
242 }
243 
252 static int crypt_compare_key_date(const void *a, const void *b)
253 {
254  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
255  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
256  unsigned long ts = 0, tt = 0;
257 
258  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
259  ts = (*s)->kobj->subkeys->timestamp;
260  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
261  tt = (*t)->kobj->subkeys->timestamp;
262 
263  if (ts > tt)
264  return 1;
265  if (ts < tt)
266  return 0;
267 
268  return mutt_istr_cmp((*s)->uid, (*t)->uid) > 0;
269 }
270 
279 static int crypt_compare_date_qsort(const void *a, const void *b)
280 {
281  const short c_pgp_sort_keys = cs_subset_sort(NeoMutt->sub, "pgp_sort_keys");
282  return (c_pgp_sort_keys & SORT_REVERSE) ? !crypt_compare_key_date(a, b) :
284 }
285 
297 static int crypt_compare_key_trust(const void *a, const void *b)
298 {
299  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
300  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
301  unsigned long ts = 0, tt = 0;
302 
303  int r = (((*s)->flags & KEYFLAG_RESTRICTIONS) - ((*t)->flags & KEYFLAG_RESTRICTIONS));
304  if (r != 0)
305  return r > 0;
306 
307  ts = (*s)->validity;
308  tt = (*t)->validity;
309  r = (tt - ts);
310  if (r != 0)
311  return r < 0;
312 
313  if ((*s)->kobj->subkeys)
314  ts = (*s)->kobj->subkeys->length;
315  if ((*t)->kobj->subkeys)
316  tt = (*t)->kobj->subkeys->length;
317  if (ts != tt)
318  return ts > tt;
319 
320  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
321  ts = (*s)->kobj->subkeys->timestamp;
322  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
323  tt = (*t)->kobj->subkeys->timestamp;
324  if (ts > tt)
325  return 1;
326  if (ts < tt)
327  return 0;
328 
329  r = mutt_istr_cmp((*s)->uid, (*t)->uid);
330  if (r != 0)
331  return r > 0;
332  return mutt_istr_cmp(crypt_fpr_or_lkeyid((*s)), crypt_fpr_or_lkeyid((*t))) > 0;
333 }
334 
343 static int crypt_compare_trust_qsort(const void *a, const void *b)
344 {
345  const short c_pgp_sort_keys = cs_subset_sort(NeoMutt->sub, "pgp_sort_keys");
346  return (c_pgp_sort_keys & SORT_REVERSE) ? !crypt_compare_key_trust(a, b) :
348 }
349 
360 static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
361 {
362  bool any = false;
363 
364  for (; dn->key; dn++)
365  {
366  if (strcmp(dn->key, key) == 0)
367  {
368  if (any)
369  fputs(" + ", fp);
370  print_utf8(fp, dn->value, strlen(dn->value));
371  any = true;
372  }
373  }
374  return any;
375 }
376 
382 static void print_dn_parts(FILE *fp, struct DnArray *dn)
383 {
384  static const char *const stdpart[] = {
385  "CN", "OU", "O", "STREET", "L", "ST", "C", NULL,
386  };
387  bool any = false;
388  bool any2 = false;
389 
390  for (int i = 0; stdpart[i]; i++)
391  {
392  if (any)
393  fputs(", ", fp);
394  any = print_dn_part(fp, dn, stdpart[i]);
395  }
396  /* now print the rest without any specific ordering */
397  for (; dn->key; dn++)
398  {
399  int i;
400  for (i = 0; stdpart[i]; i++)
401  {
402  if (strcmp(dn->key, stdpart[i]) == 0)
403  break;
404  }
405  if (!stdpart[i])
406  {
407  if (any)
408  fputs(", ", fp);
409  if (!any2)
410  fputs("(", fp);
411  any = print_dn_part(fp, dn, dn->key);
412  any2 = true;
413  }
414  }
415  if (any2)
416  fputs(")", fp);
417 }
418 
427 static const char *parse_dn_part(struct DnArray *array, const char *str)
428 {
429  const char *s = NULL, *s1 = NULL;
430  size_t n;
431  char *p = NULL;
432 
433  /* parse attribute type */
434  for (s = str + 1; (s[0] != '\0') && (s[0] != '='); s++)
435  ; // do nothing
436 
437  if (s[0] == '\0')
438  return NULL; /* error */
439  n = s - str;
440  if (n == 0)
441  return NULL; /* empty key */
442  array->key = mutt_mem_malloc(n + 1);
443  p = array->key;
444  memcpy(p, str, n); /* fixme: trim trailing spaces */
445  p[n] = 0;
446  str = s + 1;
447 
448  if (*str == '#')
449  { /* hexstring */
450  str++;
451  for (s = str; isxdigit(*s); s++)
452  s++;
453  n = s - str;
454  if ((n == 0) || (n & 1))
455  return NULL; /* empty or odd number of digits */
456  n /= 2;
457  p = mutt_mem_malloc(n + 1);
458  array->value = (char *) p;
459  for (s1 = str; n; s1 += 2, n--)
460  sscanf(s1, "%2hhx", (unsigned char *) p++);
461  *p = '\0';
462  }
463  else
464  { /* regular v3 quoted string */
465  for (n = 0, s = str; *s; s++)
466  {
467  if (*s == '\\')
468  { /* pair */
469  s++;
470  if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') || (*s == '>') ||
471  (*s == '#') || (*s == ';') || (*s == '\\') || (*s == '\"') || (*s == ' '))
472  {
473  n++;
474  }
475  else if (isxdigit(s[0]) && isxdigit(s[1]))
476  {
477  s++;
478  n++;
479  }
480  else
481  return NULL; /* invalid escape sequence */
482  }
483  else if (*s == '\"')
484  return NULL; /* invalid encoding */
485  else if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') ||
486  (*s == '>') || (*s == '#') || (*s == ';'))
487  {
488  break;
489  }
490  else
491  n++;
492  }
493 
494  p = mutt_mem_malloc(n + 1);
495  array->value = (char *) p;
496  for (s = str; n; s++, n--)
497  {
498  if (*s == '\\')
499  {
500  s++;
501  if (isxdigit(*s))
502  {
503  sscanf(s, "%2hhx", (unsigned char *) p++);
504  s++;
505  }
506  else
507  *p++ = *s;
508  }
509  else
510  *p++ = *s;
511  }
512  *p = '\0';
513  }
514  return s;
515 }
516 
525 static struct DnArray *parse_dn(const char *str)
526 {
527  struct DnArray *array = NULL;
528  size_t arrayidx, arraysize;
529 
530  arraysize = 7; /* C,ST,L,O,OU,CN,email */
531  array = mutt_mem_malloc((arraysize + 1) * sizeof(*array));
532  arrayidx = 0;
533  while (*str)
534  {
535  while (str[0] == ' ')
536  str++;
537  if (str[0] == '\0')
538  break; /* ready */
539  if (arrayidx >= arraysize)
540  {
541  /* neomutt lacks a real mutt_mem_realloc - so we need to copy */
542  arraysize += 5;
543  struct DnArray *a2 = mutt_mem_malloc((arraysize + 1) * sizeof(*array));
544  for (int i = 0; i < arrayidx; i++)
545  {
546  a2[i].key = array[i].key;
547  a2[i].value = array[i].value;
548  }
549  FREE(&array);
550  array = a2;
551  }
552  array[arrayidx].key = NULL;
553  array[arrayidx].value = NULL;
554  str = parse_dn_part(array + arrayidx, str);
555  arrayidx++;
556  if (!str)
557  goto failure;
558  while (str[0] == ' ')
559  str++;
560  if ((str[0] != '\0') && (str[0] != ',') && (str[0] != ';') && (str[0] != '+'))
561  goto failure; /* invalid delimiter */
562  if (str[0] != '\0')
563  str++;
564  }
565  array[arrayidx].key = NULL;
566  array[arrayidx].value = NULL;
567  return array;
568 
569 failure:
570  for (int i = 0; i < arrayidx; i++)
571  {
572  FREE(&array[i].key);
573  FREE(&array[i].value);
574  }
575  FREE(&array);
576  return NULL;
577 }
578 
587 static void parse_and_print_user_id(FILE *fp, const char *userid)
588 {
589  const char *s = NULL;
590 
591  if (*userid == '<')
592  {
593  s = strchr(userid + 1, '>');
594  if (s)
595  print_utf8(fp, userid + 1, s - userid - 1);
596  }
597  else if (*userid == '(')
598  fputs(_("[Can't display this user ID (unknown encoding)]"), fp);
599  else if (!isalnum(userid[0]))
600  fputs(_("[Can't display this user ID (invalid encoding)]"), fp);
601  else
602  {
603  struct DnArray *dn = parse_dn(userid);
604  if (!dn)
605  fputs(_("[Can't display this user ID (invalid DN)]"), fp);
606  else
607  {
608  print_dn_parts(fp, dn);
609  for (int i = 0; dn[i].key; i++)
610  {
611  FREE(&dn[i].key);
612  FREE(&dn[i].value);
613  }
614  FREE(&dn);
615  }
616  }
617 }
618 
624 static void print_key_info(gpgme_key_t key, FILE *fp)
625 {
626  int idx;
627  const char *s = NULL, *s2 = NULL;
628  time_t tt = 0;
629  char shortbuf[128];
630  unsigned long aval = 0;
631  const char *delim = NULL;
632  gpgme_user_id_t uid = NULL;
633  static int max_header_width = 0;
634 
635  if (max_header_width == 0)
636  {
637  for (int i = 0; i < KIP_MAX; i++)
638  {
640  const int width = mutt_strwidth(_(KeyInfoPrompts[i]));
641  if (max_header_width < width)
642  max_header_width = width;
643  KeyInfoPadding[i] -= width;
644  }
645  for (int i = 0; i < KIP_MAX; i++)
646  KeyInfoPadding[i] += max_header_width;
647  }
648 
649  bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
650 
651  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
652  {
653  if (uid->revoked)
654  continue;
655 
656  s = uid->uid;
657  /* L10N: DOTFILL */
658 
659  if (idx == 0)
660  fprintf(fp, "%*s", KeyInfoPadding[KIP_NAME], _(KeyInfoPrompts[KIP_NAME]));
661  else
662  fprintf(fp, "%*s", KeyInfoPadding[KIP_AKA], _(KeyInfoPrompts[KIP_AKA]));
663  if (uid->invalid)
664  {
665  /* L10N: comes after the Name or aka if the key is invalid */
666  fputs(_("[Invalid]"), fp);
667  putc(' ', fp);
668  }
669  if (is_pgp)
670  print_utf8(fp, s, strlen(s));
671  else
673  putc('\n', fp);
674  }
675 
676  if (key->subkeys && (key->subkeys->timestamp > 0))
677  {
678  tt = key->subkeys->timestamp;
679 
680  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
681  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
682  _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
683  }
684 
685  if (key->subkeys && (key->subkeys->expires > 0))
686  {
687  tt = key->subkeys->expires;
688 
689  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
690  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
691  _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
692  }
693 
694  if (key->subkeys)
695  s = gpgme_pubkey_algo_name(key->subkeys->pubkey_algo);
696  else
697  s = "?";
698 
699  s2 = is_pgp ? "PGP" : "X.509";
700 
701  if (key->subkeys)
702  aval = key->subkeys->length;
703 
704  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_TYPE], _(KeyInfoPrompts[KIP_KEY_TYPE]));
705  /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
706  fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), s2, aval, s);
707 
708  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_USAGE], _(KeyInfoPrompts[KIP_KEY_USAGE]));
709  delim = "";
710 
712  {
713  /* L10N: value in Key Usage: field */
714  fprintf(fp, "%s%s", delim, _("encryption"));
715  delim = _(", ");
716  }
718  {
719  /* L10N: value in Key Usage: field */
720  fprintf(fp, "%s%s", delim, _("signing"));
721  delim = _(", ");
722  }
724  {
725  /* L10N: value in Key Usage: field */
726  fprintf(fp, "%s%s", delim, _("certification"));
727  }
728  putc('\n', fp);
729 
730  if (key->subkeys)
731  {
732  s = key->subkeys->fpr;
733  fprintf(fp, "%*s", KeyInfoPadding[KIP_FINGERPRINT], _(KeyInfoPrompts[KIP_FINGERPRINT]));
734  if (is_pgp && (strlen(s) == 40))
735  {
736  for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0') &&
737  (s[3] != '\0') && (s[4] != '\0');
738  s += 4, i++)
739  {
740  putc(*s, fp);
741  putc(s[1], fp);
742  putc(s[2], fp);
743  putc(s[3], fp);
744  putc(' ', fp);
745  if (i == 4)
746  putc(' ', fp);
747  }
748  }
749  else
750  {
751  for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0'); s += 2, i++)
752  {
753  putc(*s, fp);
754  putc(s[1], fp);
755  putc(is_pgp ? ' ' : ':', fp);
756  if (is_pgp && (i == 7))
757  putc(' ', fp);
758  }
759  }
760  fprintf(fp, "%s\n", s);
761  }
762 
763  if (key->issuer_serial)
764  {
765  s = key->issuer_serial;
766  if (s)
767  {
768  fprintf(fp, "%*s0x%s\n", KeyInfoPadding[KIP_SERIAL_NO],
769  _(KeyInfoPrompts[KIP_SERIAL_NO]), s);
770  }
771  }
772 
773  if (key->issuer_name)
774  {
775  s = key->issuer_name;
776  if (s)
777  {
778  fprintf(fp, "%*s", KeyInfoPadding[KIP_ISSUED_BY], _(KeyInfoPrompts[KIP_ISSUED_BY]));
780  putc('\n', fp);
781  }
782  }
783 
784  /* For PGP we list all subkeys. */
785  if (is_pgp)
786  {
787  gpgme_subkey_t subkey = NULL;
788 
789  for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next)
790  {
791  s = subkey->keyid;
792 
793  putc('\n', fp);
794  if (strlen(s) == 16)
795  s += 8; /* display only the short keyID */
796  fprintf(fp, "%*s0x%s", KeyInfoPadding[KIP_SUBKEY], _(KeyInfoPrompts[KIP_SUBKEY]), s);
797  if (subkey->revoked)
798  {
799  putc(' ', fp);
800  /* L10N: describes a subkey */
801  fputs(_("[Revoked]"), fp);
802  }
803  if (subkey->invalid)
804  {
805  putc(' ', fp);
806  /* L10N: describes a subkey */
807  fputs(_("[Invalid]"), fp);
808  }
809  if (subkey->expired)
810  {
811  putc(' ', fp);
812  /* L10N: describes a subkey */
813  fputs(_("[Expired]"), fp);
814  }
815  if (subkey->disabled)
816  {
817  putc(' ', fp);
818  /* L10N: describes a subkey */
819  fputs(_("[Disabled]"), fp);
820  }
821  putc('\n', fp);
822 
823  if (subkey->timestamp > 0)
824  {
825  tt = subkey->timestamp;
826 
827  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
828  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
829  _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
830  }
831 
832  if (subkey->expires > 0)
833  {
834  tt = subkey->expires;
835 
836  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
837  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
838  _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
839  }
840 
841  s = gpgme_pubkey_algo_name(subkey->pubkey_algo);
842 
843  aval = subkey->length;
844 
845  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_TYPE], _(KeyInfoPrompts[KIP_KEY_TYPE]));
846  /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
847  fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), "PGP", aval, s);
848 
849  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_USAGE], _(KeyInfoPrompts[KIP_KEY_USAGE]));
850  delim = "";
851 
852  if (subkey->can_encrypt)
853  {
854  fprintf(fp, "%s%s", delim, _("encryption"));
855  delim = _(", ");
856  }
857  if (subkey->can_sign)
858  {
859  fprintf(fp, "%s%s", delim, _("signing"));
860  delim = _(", ");
861  }
862  if (subkey->can_certify)
863  {
864  fprintf(fp, "%s%s", delim, _("certification"));
865  }
866  putc('\n', fp);
867  }
868  }
869 }
870 
875 static void verify_key(struct CryptKeyInfo *key)
876 {
877  const char *s = NULL;
878  gpgme_ctx_t listctx = NULL;
879  gpgme_error_t err;
880  gpgme_key_t k = NULL;
881  int maxdepth = 100;
882 
883  struct Buffer tempfile = mutt_buffer_make(PATH_MAX);
884  mutt_buffer_mktemp(&tempfile);
885  FILE *fp = mutt_file_fopen(mutt_buffer_string(&tempfile), "w");
886  if (!fp)
887  {
888  mutt_perror(_("Can't create temporary file"));
889  goto cleanup;
890  }
891  mutt_message(_("Collecting data..."));
892 
893  print_key_info(key->kobj, fp);
894 
895  listctx = create_gpgme_context(key->flags & KEYFLAG_ISX509);
896 
897  k = key->kobj;
898  gpgme_key_ref(k);
899  while ((s = k->chain_id) && k->subkeys && (strcmp(s, k->subkeys->fpr) != 0))
900  {
901  putc('\n', fp);
902  err = gpgme_op_keylist_start(listctx, s, 0);
903  gpgme_key_unref(k);
904  k = NULL;
905  if (err == 0)
906  err = gpgme_op_keylist_next(listctx, &k);
907  if (err != 0)
908  {
909  fprintf(fp, _("Error finding issuer key: %s\n"), gpgme_strerror(err));
910  goto leave;
911  }
912  gpgme_op_keylist_end(listctx);
913 
914  print_key_info(k, fp);
915  if (!--maxdepth)
916  {
917  putc('\n', fp);
918  fputs(_("Error: certification chain too long - stopping here\n"), fp);
919  break;
920  }
921  }
922 
923 leave:
924  gpgme_key_unref(k);
925  gpgme_release(listctx);
926  mutt_file_fclose(&fp);
928  char title[1024];
929  snprintf(title, sizeof(title), _("Key ID: 0x%s"), crypt_keyid(key));
930 
931  struct PagerData pdata = { 0 };
932  struct PagerView pview = { &pdata };
933 
934  pdata.fname = mutt_buffer_string(&tempfile);
935 
936  pview.banner = title;
937  pview.flags = MUTT_PAGER_NO_FLAGS;
938  pview.mode = PAGER_MODE_OTHER;
939 
940  mutt_do_pager(&pview, NULL);
941 
942 cleanup:
943  mutt_buffer_dealloc(&tempfile);
944 }
945 
954 {
955  static char buf[3];
956 
957  if (!(flags & KEYFLAG_CANENCRYPT))
958  buf[0] = '-';
959  else if (flags & KEYFLAG_PREFER_SIGNING)
960  buf[0] = '.';
961  else
962  buf[0] = 'e';
963 
964  if (!(flags & KEYFLAG_CANSIGN))
965  buf[1] = '-';
966  else if (flags & KEYFLAG_PREFER_ENCRYPTION)
967  buf[1] = '.';
968  else
969  buf[1] = 's';
970 
971  buf[2] = '\0';
972 
973  return buf;
974 }
975 
984 {
985  if (flags & KEYFLAG_REVOKED)
986  return 'R';
987  if (flags & KEYFLAG_EXPIRED)
988  return 'X';
989  if (flags & KEYFLAG_DISABLED)
990  return 'd';
991  if (flags & KEYFLAG_CRITICAL)
992  return 'c';
993 
994  return ' ';
995 }
996 
1020 static const char *crypt_format_str(char *buf, size_t buflen, size_t col, int cols,
1021  char op, const char *src, const char *prec,
1022  const char *if_str, const char *else_str,
1023  intptr_t data, MuttFormatFlags flags)
1024 {
1025  char fmt[128];
1026  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
1027 
1028  struct CryptEntry *entry = (struct CryptEntry *) data;
1029  struct CryptKeyInfo *key = entry->key;
1030 
1031  /* if (isupper ((unsigned char) op)) */
1032  /* key = pkey; */
1033 
1034  KeyFlags kflags = (key->flags /* | (pkey->flags & KEYFLAG_RESTRICTIONS)
1035  | uid->flags */);
1036 
1037  switch (tolower(op))
1038  {
1039  case 'a':
1040  if (!optional)
1041  {
1042  const char *s = NULL;
1043  snprintf(fmt, sizeof(fmt), "%%%s.3s", prec);
1044  if (key->kobj->subkeys)
1045  s = gpgme_pubkey_algo_name(key->kobj->subkeys->pubkey_algo);
1046  else
1047  s = "?";
1048  snprintf(buf, buflen, fmt, s);
1049  }
1050  break;
1051 
1052  case 'c':
1053  if (!optional)
1054  {
1055  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1056  snprintf(buf, buflen, fmt, crypt_key_abilities(kflags));
1057  }
1058  else if (!(kflags & KEYFLAG_ABILITIES))
1059  optional = false;
1060  break;
1061 
1062  case 'f':
1063  if (!optional)
1064  {
1065  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
1066  snprintf(buf, buflen, fmt, crypt_flags(kflags));
1067  }
1068  else if (!(kflags & KEYFLAG_RESTRICTIONS))
1069  optional = false;
1070  break;
1071 
1072  case 'k':
1073  if (!optional)
1074  {
1075  /* fixme: we need a way to distinguish between main and subkeys.
1076  * Store the idx in entry? */
1077  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1078  snprintf(buf, buflen, fmt, crypt_keyid(key));
1079  }
1080  break;
1081 
1082  case 'l':
1083  if (!optional)
1084  {
1085  snprintf(fmt, sizeof(fmt), "%%%slu", prec);
1086  unsigned long val;
1087  if (key->kobj->subkeys)
1088  val = key->kobj->subkeys->length;
1089  else
1090  val = 0;
1091  snprintf(buf, buflen, fmt, val);
1092  }
1093  break;
1094 
1095  case 'n':
1096  if (!optional)
1097  {
1098  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1099  snprintf(buf, buflen, fmt, entry->num);
1100  }
1101  break;
1102 
1103  case 'p':
1104  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1105  snprintf(buf, buflen, fmt, gpgme_get_protocol_name(key->kobj->protocol));
1106  break;
1107 
1108  case 't':
1109  {
1110  char *s = NULL;
1111  if ((kflags & KEYFLAG_ISX509))
1112  s = "x";
1113  else
1114  {
1115  switch (key->validity)
1116  {
1117  case GPGME_VALIDITY_FULL:
1118  s = "f";
1119  break;
1120  case GPGME_VALIDITY_MARGINAL:
1121  s = "m";
1122  break;
1123  case GPGME_VALIDITY_NEVER:
1124  s = "n";
1125  break;
1126  case GPGME_VALIDITY_ULTIMATE:
1127  s = "u";
1128  break;
1129  case GPGME_VALIDITY_UNDEFINED:
1130  s = "q";
1131  break;
1132  case GPGME_VALIDITY_UNKNOWN:
1133  default:
1134  s = "?";
1135  break;
1136  }
1137  }
1138  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
1139  snprintf(buf, buflen, fmt, *s);
1140  break;
1141  }
1142 
1143  case 'u':
1144  if (!optional)
1145  {
1146  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1147  snprintf(buf, buflen, fmt, key->uid);
1148  }
1149  break;
1150 
1151  case '[':
1152  {
1153  char buf2[128];
1154  bool do_locales = true;
1155  struct tm tm = { 0 };
1156 
1157  char *p = buf;
1158 
1159  const char *cp = src;
1160  if (*cp == '!')
1161  {
1162  do_locales = false;
1163  cp++;
1164  }
1165 
1166  size_t len = buflen - 1;
1167  while ((len > 0) && (*cp != ']'))
1168  {
1169  if (*cp == '%')
1170  {
1171  cp++;
1172  if (len >= 2)
1173  {
1174  *p++ = '%';
1175  *p++ = *cp;
1176  len -= 2;
1177  }
1178  else
1179  break; /* not enough space */
1180  cp++;
1181  }
1182  else
1183  {
1184  *p++ = *cp++;
1185  len--;
1186  }
1187  }
1188  *p = '\0';
1189 
1190  if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
1191  tm = mutt_date_localtime(key->kobj->subkeys->timestamp);
1192  else
1193  tm = mutt_date_localtime(0); // Default to 1970-01-01
1194 
1195  if (!do_locales)
1196  setlocale(LC_TIME, "C");
1197  strftime(buf2, sizeof(buf2), buf, &tm);
1198  if (!do_locales)
1199  setlocale(LC_TIME, "");
1200 
1201  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1202  snprintf(buf, buflen, fmt, buf2);
1203  if (len > 0)
1204  src = cp + 1;
1205  break;
1206  }
1207 
1208  default:
1209  *buf = '\0';
1210  }
1211 
1212  if (optional)
1213  {
1214  mutt_expando_format(buf, buflen, col, cols, if_str, crypt_format_str, data,
1216  }
1217  else if (flags & MUTT_FORMAT_OPTIONAL)
1218  {
1219  mutt_expando_format(buf, buflen, col, cols, else_str, crypt_format_str,
1220  data, MUTT_FORMAT_NO_FLAGS);
1221  }
1222 
1223  /* We return the format string, unchanged */
1224  return src;
1225 }
1226 
1230 static void crypt_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
1231 {
1232  struct CryptKeyInfo **key_table = menu->mdata;
1233  struct CryptEntry entry;
1234 
1235  entry.key = key_table[line];
1236  entry.num = line + 1;
1237 
1238  const char *const c_pgp_entry_format =
1239  cs_subset_string(NeoMutt->sub, "pgp_entry_format");
1240  mutt_expando_format(buf, buflen, 0, menu->win->state.cols, NONULL(c_pgp_entry_format),
1241  crypt_format_str, (intptr_t) &entry, MUTT_FORMAT_ARROWCURSOR);
1242 }
1243 
1249 static void gpgme_key_table_free(struct Menu *menu, void **ptr)
1250 {
1251  FREE(ptr);
1252 }
1253 
1258 {
1259  if ((nc->event_type != NT_CONFIG) || !nc->global_data || !nc->event_data)
1260  return -1;
1261 
1262  struct EventConfig *ev_c = nc->event_data;
1263 
1264  if (!mutt_str_equal(ev_c->name, "pgp_entry_format") &&
1265  !mutt_str_equal(ev_c->name, "pgp_sort_keys"))
1266  {
1267  return 0;
1268  }
1269 
1270  struct Menu *menu = nc->global_data;
1272  mutt_debug(LL_DEBUG5, "config done, request WA_RECALC, MENU_REDRAW_FULL\n");
1273 
1274  return 0;
1275 }
1276 
1285 {
1286  if ((nc->event_type != NT_WINDOW) || !nc->global_data || !nc->event_data)
1287  return -1;
1288 
1289  if (nc->event_subtype != NT_WINDOW_DELETE)
1290  return 0;
1291 
1292  struct MuttWindow *win_menu = nc->global_data;
1293  struct EventWindow *ev_w = nc->event_data;
1294  if (ev_w->win != win_menu)
1295  return 0;
1296 
1297  struct Menu *menu = win_menu->wdata;
1298 
1301 
1302  mutt_debug(LL_DEBUG5, "window delete done\n");
1303  return 0;
1304 }
1305 
1318  struct Address *p, const char *s,
1319  unsigned int app, int *forced_valid)
1320 {
1321  int keymax;
1322  int i;
1323  bool done = false;
1324  struct CryptKeyInfo *k = NULL;
1325  int (*f)(const void *, const void *);
1326  enum MenuType menu_to_use = MENU_GENERIC;
1327  bool unusable = false;
1328 
1329  *forced_valid = 0;
1330 
1331  /* build the key table */
1332  keymax = 0;
1333  i = 0;
1334  struct CryptKeyInfo **key_table = NULL;
1335  for (k = keys; k; k = k->next)
1336  {
1337  const bool c_pgp_show_unusable =
1338  cs_subset_bool(NeoMutt->sub, "pgp_show_unusable");
1339  if (!c_pgp_show_unusable && (k->flags & KEYFLAG_CANTUSE))
1340  {
1341  unusable = true;
1342  continue;
1343  }
1344 
1345  if (i == keymax)
1346  {
1347  keymax += 20;
1348  mutt_mem_realloc(&key_table, sizeof(struct CryptKeyInfo *) * keymax);
1349  }
1350 
1351  key_table[i++] = k;
1352  }
1353 
1354  if (!i && unusable)
1355  {
1356  mutt_error(_("All matching keys are marked expired/revoked"));
1357  return NULL;
1358  }
1359 
1360  const short c_pgp_sort_keys = cs_subset_sort(NeoMutt->sub, "pgp_sort_keys");
1361  switch (c_pgp_sort_keys & SORT_MASK)
1362  {
1363  case SORT_ADDRESS:
1365  break;
1366  case SORT_DATE:
1368  break;
1369  case SORT_KEYID:
1371  break;
1372  case SORT_TRUST:
1373  default:
1375  break;
1376  }
1377  qsort(key_table, i, sizeof(struct CryptKeyInfo *), f);
1378 
1379  if (app & APPLICATION_PGP)
1380  menu_to_use = MENU_KEY_SELECT_PGP;
1381  else if (app & APPLICATION_SMIME)
1382  menu_to_use = MENU_KEY_SELECT_SMIME;
1383 
1384  struct MuttWindow *dlg = simple_dialog_new(menu_to_use, WT_DLG_CRYPT_GPGME, GpgmeHelp);
1385 
1386  struct Menu *menu = dlg->wdata;
1387  menu->max = i;
1388  menu->make_entry = crypt_make_entry;
1389  menu->mdata = key_table;
1391 
1392  struct MuttWindow *win_menu = menu->win;
1393 
1394  // NT_COLOR is handled by the SimpleDialog
1397 
1398  {
1399  const char *ts = NULL;
1400 
1401  if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
1402  ts = _("PGP and S/MIME keys matching");
1403  else if ((app & APPLICATION_PGP))
1404  ts = _("PGP keys matching");
1405  else if ((app & APPLICATION_SMIME))
1406  ts = _("S/MIME keys matching");
1407  else
1408  ts = _("keys matching");
1409 
1410  char buf[1024] = { 0 };
1411  if (p)
1412  {
1413  /* L10N: 1$s is one of the previous four entries.
1414  %2$s is an address.
1415  e.g. "S/MIME keys matching <me@mutt.org>" */
1416  snprintf(buf, sizeof(buf), _("%s <%s>"), ts, p->mailbox);
1417  }
1418  else
1419  {
1420  /* L10N: e.g. 'S/MIME keys matching "Michael Elkins".' */
1421  snprintf(buf, sizeof(buf), _("%s \"%s\""), ts, s);
1422  }
1423 
1424  struct MuttWindow *sbar = window_find_child(dlg, WT_STATUS_BAR);
1425  sbar_set_title(sbar, buf);
1426  }
1427 
1428  mutt_clear_error();
1429  k = NULL;
1430  while (!done)
1431  {
1432  *forced_valid = 0;
1433  switch (menu_loop(menu))
1434  {
1435  case OP_VERIFY_KEY:
1436  {
1437  const int index = menu_get_index(menu);
1438  struct CryptKeyInfo *cur_key = key_table[index];
1439  verify_key(cur_key);
1441  break;
1442  }
1443 
1444  case OP_VIEW_ID:
1445  {
1446  const int index = menu_get_index(menu);
1447  struct CryptKeyInfo *cur_key = key_table[index];
1448  mutt_message("%s", cur_key->uid);
1449  break;
1450  }
1451 
1452  case OP_GENERIC_SELECT_ENTRY:
1453  {
1454  const int index = menu_get_index(menu);
1455  struct CryptKeyInfo *cur_key = key_table[index];
1456  /* FIXME make error reporting more verbose - this should be
1457  * easy because GPGME provides more information */
1458  if (OptPgpCheckTrust)
1459  {
1460  if (!crypt_key_is_valid(cur_key))
1461  {
1462  mutt_error(_("This key can't be used: "
1463  "expired/disabled/revoked"));
1464  break;
1465  }
1466  }
1467 
1468  if (OptPgpCheckTrust && (!crypt_id_is_valid(cur_key) || !crypt_id_is_strong(cur_key)))
1469  {
1470  const char *warn_s = NULL;
1471  char buf2[1024];
1472 
1473  if (cur_key->flags & KEYFLAG_CANTUSE)
1474  {
1475  warn_s = _("ID is expired/disabled/revoked. Do you really want to "
1476  "use the key?");
1477  }
1478  else
1479  {
1480  warn_s = "??";
1481  switch (cur_key->validity)
1482  {
1483  case GPGME_VALIDITY_NEVER:
1484  warn_s =
1485  _("ID is not valid. Do you really want to use the key?");
1486  break;
1487  case GPGME_VALIDITY_MARGINAL:
1488  warn_s = _("ID is only marginally valid. Do you really want to "
1489  "use the key?");
1490  break;
1491  case GPGME_VALIDITY_FULL:
1492  case GPGME_VALIDITY_ULTIMATE:
1493  break;
1494  case GPGME_VALIDITY_UNKNOWN:
1495  case GPGME_VALIDITY_UNDEFINED:
1496  warn_s = _("ID has undefined validity. Do you really want to "
1497  "use the key?");
1498  break;
1499  }
1500  }
1501 
1502  snprintf(buf2, sizeof(buf2), "%s", warn_s);
1503 
1504  if (mutt_yesorno(buf2, MUTT_NO) != MUTT_YES)
1505  {
1506  mutt_clear_error();
1507  break;
1508  }
1509 
1510  /* A '!' is appended to a key in find_keys() when forced_valid is
1511  * set. Prior to GPGME 1.11.0, encrypt_gpgme_object() called
1512  * create_recipient_set() which interpreted the '!' to mean set
1513  * GPGME_VALIDITY_FULL for the key.
1514  *
1515  * Starting in GPGME 1.11.0, we now use a '\n' delimited recipient
1516  * string, which is passed directly to the gpgme_op_encrypt_ext()
1517  * function. This allows to use the original meaning of '!' to
1518  * force a subkey use. */
1519 #if (GPGME_VERSION_NUMBER < 0x010b00) /* GPGME < 1.11.0 */
1520  *forced_valid = 1;
1521 #endif
1522  }
1523 
1524  k = crypt_copy_key(cur_key);
1525  done = true;
1526  break;
1527  }
1528 
1529  case OP_EXIT:
1530  k = NULL;
1531  done = true;
1532  break;
1533  }
1534  }
1535 
1536  simple_dialog_free(&dlg);
1537  return k;
1538 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
Convenience wrapper for the gui headers.
#define KEYFLAG_PREFER_ENCRYPTION
Key&#39;s owner prefers encryption.
Definition: lib.h:133
int mutt_istr_cmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:580
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:550
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:780
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
MenuType
Types of GUI selections.
Definition: type.h:35
static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
Print the X.500 Distinguished Name.
Definition: dlggpgme.c:360
PGP Key field: Valid To date.
Definition: crypt_gpgme.h:62
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:691
void simple_dialog_free(struct MuttWindow **ptr)
Destroy a simple index Dialog.
Definition: simple.c:165
Definition: lib.h:67
Data passed to a notification function.
Definition: observer.h:39
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:217
Wrapper for PGP/SMIME calls to GPGME.
An Event that happened to a Window.
Definition: mutt_window.h:215
#define mutt_error(...)
Definition: logging.h:88
static void crypt_make_entry(struct Menu *menu, char *buf, size_t buflen, int line)
Format a menu item for the key selection list - Implements Menu::make_entry() -.
Definition: dlggpgme.c:1230
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:654
Generic selection list.
Definition: type.h:45
Crypt-GPGME Dialog, dlg_select_gpgme_key()
Definition: mutt_window.h:83
struct CryptKeyInfo * dlg_select_gpgme_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, int *forced_valid)
Get the user to select a key.
Definition: dlggpgme.c:1317
PGP Key field: Serial number.
Definition: crypt_gpgme.h:66
size_t idx
Definition: mailbox.c:257
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:347
NeoMutt Logging.
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
A config-change event.
Definition: subset.h:69
String manipulation buffer.
Definition: buffer.h:33
Paged view into some data.
Definition: lib.h:154
#define _(a)
Definition: message.h:28
Sort by email address.
Definition: sort2.h:54
Key can be used for encryption.
Definition: crypt_gpgme.h:77
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:126
Window is about to be deleted.
Definition: mutt_window.h:206
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:758
An email address.
Definition: address.h:35
Key can be used for signing.
Definition: crypt_gpgme.h:78
char * mailbox
Mailbox and host address.
Definition: address.h:38
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
PGP Key field: Key Usage.
Definition: crypt_gpgme.h:64
char * key
Definition: dlggpgme.c:127
size_t num
Definition: dlggpgme.c:118
static char crypt_flags(KeyFlags flags)
Parse the key flags into a single character.
Definition: dlggpgme.c:983
static int crypt_crypt_compare_keyid_qsort(const void *a, const void *b)
Compare the IDs of two keys.
Definition: dlggpgme.c:237
#define KEYFLAG_ABILITIES
Definition: lib.h:139
struct CryptKeyInfo * next
Definition: crypt_gpgme.h:46
Shared constants/structs that are private to libconn.
Flags to control mutt_expando_format()
All user-callable functions.
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:125
static int crypt_compare_keyid(const void *a, const void *b)
Compare Key IDs and addresses for sorting.
Definition: dlggpgme.c:218
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
static void gpgme_key_table_free(struct Menu *menu, void **ptr)
Free the key table - Implements Menu::mdata_free() -.
Definition: dlggpgme.c:1249
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
static const char * crypt_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the key selection menu - Implements format_t -Expando Description %n Number %p P...
Definition: dlggpgme.c:1020
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
#define KEYFLAG_PREFER_SIGNING
Key&#39;s owner prefers signing.
Definition: lib.h:134
static struct DnArray * parse_dn(const char *str)
Parse a DN and return an array-ized one.
Definition: dlggpgme.c:525
Convenience wrapper for the config headers.
void(* make_entry)(struct Menu *menu, char *buf, size_t buflen, int line)
Definition: lib.h:105
Email Address Handling.
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:43
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
Some miscellaneous functions.
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:519
A stored PGP key.
Definition: crypt_gpgme.h:44
static const char * parse_dn_part(struct DnArray *array, const char *str)
Parse an RDN.
Definition: dlggpgme.c:427
static int crypt_compare_address_qsort(const void *a, const void *b)
Compare the addresses of two keys.
Definition: dlggpgme.c:203
Data to be displayed by PagerView.
Definition: lib.h:143
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
PGP Key field: Key Type.
Definition: crypt_gpgme.h:63
PGP Key field: Valid From date.
Definition: crypt_gpgme.h:61
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
Convenience wrapper for the core headers.
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Select a PGP key.
Definition: type.h:47
static char * crypt_key_abilities(KeyFlags flags)
Parse key flags into a string.
Definition: dlggpgme.c:953
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:48
static int crypt_compare_key_address(const void *a, const void *b)
Compare Key addresses and IDs for sorting.
Definition: dlggpgme.c:184
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:484
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
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
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:128
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:443
static const char *const KeyInfoPrompts[]
Definition: dlggpgme.c:131
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
#define KEYFLAG_CANTUSE
Definition: lib.h:136
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
static int crypt_compare_trust_qsort(const void *a, const void *b)
Compare the trust levels of two keys.
Definition: dlggpgme.c:343
PGP Key field: Name.
Definition: crypt_gpgme.h:59
enum PagerMode mode
Pager mode.
Definition: lib.h:157
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
static void parse_and_print_user_id(FILE *fp, const char *userid)
Print a nice representation of the userid.
Definition: dlggpgme.c:587
static int gpgme_key_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: dlggpgme.c:1257
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
Sort by encryption key&#39;s trust level.
Definition: sort2.h:56
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:49
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
void * mdata
Private data.
Definition: lib.h:155
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:423
#define PATH_MAX
Definition: mutt.h:40
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:122
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
int mutt_do_pager(struct PagerView *pview, struct Email *e)
Display some page-able text to the user (help or attachment)
Definition: do_pager.c:120
Key can be used to certify.
Definition: crypt_gpgme.h:79
static int crypt_compare_date_qsort(const void *a, const void *b)
Compare the dates of two keys.
Definition: dlggpgme.c:279
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:3256
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
Ask the user a question.
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:130
PGP Key field: Fingerprint.
Definition: crypt_gpgme.h:65
WHERE bool OptPgpCheckTrust
(pseudo) used by dlg_select_pgp_key()
Definition: options.h:48
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:221
PagerFlags flags
Additional settings to tweak pager&#39;s function.
Definition: lib.h:158
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:124
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static int crypt_compare_key_trust(const void *a, const void *b)
Compare the trust of keys for sorting.
Definition: dlggpgme.c:297
static int crypt_compare_key_date(const void *a, const void *b)
Compare Key creation dates and addresses for sorting.
Definition: dlggpgme.c:252
#define KEYFLAG_RESTRICTIONS
Definition: lib.h:137
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
static void print_key_info(gpgme_key_t key, FILE *fp)
Verbose information about a key or certificate to a file.
Definition: dlggpgme.c:624
int max
Number of entries in the menu.
Definition: lib.h:71
void * event_data
Data from notify_send()
Definition: observer.h:44
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
static int gpgme_key_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: dlggpgme.c:1284
An entry in the Select-Key menu.
Definition: dlggpgme.c:116
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
struct CryptKeyInfo * key
Definition: dlggpgme.c:119
void(* mdata_free)(struct Menu *menu, void **ptr)
Definition: lib.h:170
Select a SMIME key.
Definition: type.h:48
#define KEYFLAG_CRITICAL
Key is marked critical.
Definition: lib.h:132
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
static void print_utf8(FILE *fp, const char *buf, size_t len)
Write a UTF-8 string to a file.
Definition: dlggpgme.c:150
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
static void verify_key(struct CryptKeyInfo *key)
Show detailed information about the selected key.
Definition: dlggpgme.c:875
Mapping between user-readable string and a constant.
Definition: mapping.h:31
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:51
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
Sort by the encryption key&#39;s ID.
Definition: sort2.h:55
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:228
struct MuttWindow * simple_dialog_new(enum MenuType mtype, enum WindowType wtype, const struct Mapping *help_data)
Create a simple index Dialog.
Definition: simple.c:128
PGP Key field: aka (Also Known As)
Definition: crypt_gpgme.h:60
Handling of global boolean variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
char * value
Definition: dlggpgme.c:128
const char * fname
Name of the file to read.
Definition: lib.h:148
Sort by the date the email was sent.
Definition: sort2.h:43
Log at debug level 5.
Definition: logging.h:44
Convenience wrapper for the library headers.
PGP Key field: Issued By.
Definition: crypt_gpgme.h:67
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:79
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:54
const char * banner
Title to display in status bar.
Definition: lib.h:159
GUI display a file/email/help in a viewport with paging.
void * wdata
Private data.
Definition: mutt_window.h:145
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:135
static void print_dn_parts(FILE *fp, struct DnArray *dn)
Print all parts of a DN in a standard sequence.
Definition: dlggpgme.c:382
#define N_(a)
Definition: message.h:32
int KeyInfoPadding[KIP_MAX]
Definition: dlggpgme.c:140
const char * name
Name of config item that changed.
Definition: subset.h:72
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:129
PGP Key field: Subkey.
Definition: crypt_gpgme.h:68
An X500 Distinguished Name.
Definition: dlggpgme.c:125
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:78
static bool crypt_key_is_valid(struct CryptKeyInfo *k)
Is the key valid.
Definition: dlggpgme.c:169
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39