NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
gpgme_functions.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <ctype.h>
32#include <gpg-error.h>
33#include <gpgme.h>
34#include <langinfo.h>
35#include <stdio.h>
36#include <string.h>
37#include <time.h>
38#include "mutt/lib.h"
39#include "config/lib.h"
40#include "core/lib.h"
41#include "gui/lib.h"
42#include "gpgme_functions.h"
43#include "lib.h"
44#include "menu/lib.h"
45#include "pager/lib.h"
46#include "question/lib.h"
47#include "crypt_gpgme.h"
48#include "globals.h"
49#include "mutt_logging.h"
50#ifdef ENABLE_NLS
51#include <libintl.h>
52#endif
53
56
58static const char *const KeyInfoPrompts[] = {
59 /* L10N: The following are the headers for the "verify key" output from the
60 GPGME key selection menu (bound to "c" in the key selection menu).
61 They will be automatically aligned. */
62 N_("Name: "), N_("aka: "), N_("Valid From: "), N_("Valid To: "),
63 N_("Key Type: "), N_("Key Usage: "), N_("Fingerprint: "), N_("Serial-No: "),
64 N_("Issued By: "), N_("Subkey: ")
65};
66
70struct DnArray
71{
72 char *key;
73 char *value;
74};
75
84static void print_utf8(FILE *fp, const char *buf, size_t len)
85{
86 char *tstr = MUTT_MEM_MALLOC(len + 1, char);
87 memcpy(tstr, buf, len);
88 tstr[len] = 0;
89
90 /* fromcode "utf-8" is sure, so we don't want
91 * charset-hook corrections: flags must be 0. */
93 fputs(tstr, fp);
94 FREE(&tstr);
95}
96
107static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
108{
109 bool any = false;
110
111 for (; dn->key; dn++)
112 {
113 if (mutt_str_equal(dn->key, key))
114 {
115 if (any)
116 fputs(" + ", fp);
117 print_utf8(fp, dn->value, strlen(dn->value));
118 any = true;
119 }
120 }
121 return any;
122}
123
129static void print_dn_parts(FILE *fp, struct DnArray *dn)
130{
131 static const char *const stdpart[] = {
132 "CN", "OU", "O", "STREET", "L", "ST", "C", NULL,
133 };
134 bool any = false;
135 bool any2 = false;
136
137 for (int i = 0; stdpart[i]; i++)
138 {
139 if (any)
140 fputs(", ", fp);
141 any = print_dn_part(fp, dn, stdpart[i]);
142 }
143 /* now print the rest without any specific ordering */
144 for (; dn->key; dn++)
145 {
146 int i;
147 for (i = 0; stdpart[i]; i++)
148 {
149 if (mutt_str_equal(dn->key, stdpart[i]))
150 break;
151 }
152 if (!stdpart[i])
153 {
154 if (any)
155 fputs(", ", fp);
156 if (!any2)
157 fputs("(", fp);
158 any = print_dn_part(fp, dn, dn->key);
159 any2 = true;
160 }
161 }
162 if (any2)
163 fputs(")", fp);
164}
165
174static const char *parse_dn_part(struct DnArray *array, const char *str)
175{
176 const char *s = NULL, *s1 = NULL;
177 size_t n;
178 char *p = NULL;
179
180 /* parse attribute type */
181 for (s = str + 1; (s[0] != '\0') && (s[0] != '='); s++)
182 ; // do nothing
183
184 if (s[0] == '\0')
185 return NULL; /* error */
186 n = s - str;
187 if (n == 0)
188 return NULL; /* empty key */
189 array->key = MUTT_MEM_MALLOC(n + 1, char);
190 p = array->key;
191 memcpy(p, str, n); /* fixme: trim trailing spaces */
192 p[n] = 0;
193 str = s + 1;
194
195 if (*str == '#')
196 { /* hexstring */
197 str++;
198 for (s = str; isxdigit(*s); s++)
199 s++;
200 n = s - str;
201 if ((n == 0) || (n & 1))
202 return NULL; /* empty or odd number of digits */
203 n /= 2;
204 p = MUTT_MEM_MALLOC(n + 1, char);
205 array->value = (char *) p;
206 for (s1 = str; n; s1 += 2, n--)
207 sscanf(s1, "%2hhx", (unsigned char *) p++);
208 *p = '\0';
209 }
210 else
211 { /* regular v3 quoted string */
212 for (n = 0, s = str; *s; s++)
213 {
214 if (*s == '\\')
215 { /* pair */
216 s++;
217 if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') || (*s == '>') ||
218 (*s == '#') || (*s == ';') || (*s == '\\') || (*s == '\"') || (*s == ' '))
219 {
220 n++;
221 }
222 else if (isxdigit(s[0]) && isxdigit(s[1]))
223 {
224 s++;
225 n++;
226 }
227 else
228 {
229 return NULL; /* invalid escape sequence */
230 }
231 }
232 else if (*s == '\"')
233 {
234 return NULL; /* invalid encoding */
235 }
236 else if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') ||
237 (*s == '>') || (*s == '#') || (*s == ';'))
238 {
239 break;
240 }
241 else
242 {
243 n++;
244 }
245 }
246
247 p = MUTT_MEM_MALLOC(n + 1, char);
248 array->value = (char *) p;
249 for (s = str; n; s++, n--)
250 {
251 if (*s == '\\')
252 {
253 s++;
254 if (isxdigit(*s))
255 {
256 sscanf(s, "%2hhx", (unsigned char *) p++);
257 s++;
258 }
259 else
260 {
261 *p++ = *s;
262 }
263 }
264 else
265 {
266 *p++ = *s;
267 }
268 }
269 *p = '\0';
270 }
271 return s;
272}
273
282static struct DnArray *parse_dn(const char *str)
283{
284 struct DnArray *array = NULL;
285 size_t arrayidx, arraysize;
286
287 arraysize = 7; /* C,ST,L,O,OU,CN,email */
288 array = MUTT_MEM_MALLOC(arraysize + 1, struct DnArray);
289 arrayidx = 0;
290 while (*str)
291 {
292 while (str[0] == ' ')
293 str++;
294 if (str[0] == '\0')
295 break; /* ready */
296 if (arrayidx >= arraysize)
297 {
298 /* neomutt lacks a real mutt_mem_realloc - so we need to copy */
299 arraysize += 5;
300 struct DnArray *a2 = MUTT_MEM_MALLOC(arraysize + 1, struct DnArray);
301 for (int i = 0; i < arrayidx; i++)
302 {
303 a2[i].key = array[i].key;
304 a2[i].value = array[i].value;
305 }
306 FREE(&array);
307 array = a2;
308 }
309 array[arrayidx].key = NULL;
310 array[arrayidx].value = NULL;
311 str = parse_dn_part(array + arrayidx, str);
312 arrayidx++;
313 if (!str)
314 goto failure;
315 while (str[0] == ' ')
316 str++;
317 if ((str[0] != '\0') && (str[0] != ',') && (str[0] != ';') && (str[0] != '+'))
318 goto failure; /* invalid delimiter */
319 if (str[0] != '\0')
320 str++;
321 }
322 array[arrayidx].key = NULL;
323 array[arrayidx].value = NULL;
324 return array;
325
326failure:
327 for (int i = 0; i < arrayidx; i++)
328 {
329 FREE(&array[i].key);
330 FREE(&array[i].value);
331 }
332 FREE(&array);
333 return NULL;
334}
335
344static void parse_and_print_user_id(FILE *fp, const char *userid)
345{
346 const char *s = NULL;
347
348 if (*userid == '<')
349 {
350 s = strchr(userid + 1, '>');
351 if (s)
352 print_utf8(fp, userid + 1, s - userid - 1);
353 }
354 else if (*userid == '(')
355 {
356 fputs(_("[Can't display this user ID (unknown encoding)]"), fp);
357 }
358 else if (!isalnum(userid[0]))
359 {
360 fputs(_("[Can't display this user ID (invalid encoding)]"), fp);
361 }
362 else
363 {
364 struct DnArray *dn = parse_dn(userid);
365 if (dn)
366 {
367 print_dn_parts(fp, dn);
368 for (int i = 0; dn[i].key; i++)
369 {
370 FREE(&dn[i].key);
371 FREE(&dn[i].value);
372 }
373 FREE(&dn);
374 }
375 else
376 {
377 fputs(_("[Can't display this user ID (invalid DN)]"), fp);
378 }
379 }
380}
381
387static void print_key_info(gpgme_key_t key, FILE *fp)
388{
389 int idx;
390 const char *s = NULL, *s2 = NULL;
391 time_t tt = 0;
392 char shortbuf[128] = { 0 };
393 unsigned long aval = 0;
394 const char *delim = NULL;
395 gpgme_user_id_t uid = NULL;
396 static int max_header_width = 0;
397
398 if (max_header_width == 0)
399 {
400 for (int i = 0; i < KIP_MAX; i++)
401 {
403 const int width = mutt_strwidth(_(KeyInfoPrompts[i]));
404 if (max_header_width < width)
405 max_header_width = width;
406 KeyInfoPadding[i] -= width;
407 }
408 for (int i = 0; i < KIP_MAX; i++)
409 KeyInfoPadding[i] += max_header_width;
410 }
411
412 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
413
414 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
415 {
416 if (uid->revoked)
417 continue;
418
419 s = uid->uid;
420 /* L10N: DOTFILL */
421
422 if (idx == 0)
423 fprintf(fp, "%*s", KeyInfoPadding[KIP_NAME], _(KeyInfoPrompts[KIP_NAME]));
424 else
425 fprintf(fp, "%*s", KeyInfoPadding[KIP_AKA], _(KeyInfoPrompts[KIP_AKA]));
426 if (uid->invalid)
427 {
428 /* L10N: comes after the Name or aka if the key is invalid */
429 fputs(_("[Invalid]"), fp);
430 putc(' ', fp);
431 }
432 if (is_pgp)
433 print_utf8(fp, s, strlen(s));
434 else
436 putc('\n', fp);
437 }
438
439 if (key->subkeys && (key->subkeys->timestamp > 0))
440 {
441 tt = key->subkeys->timestamp;
442
443 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
444 fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
445 _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
446 }
447
448 if (key->subkeys && (key->subkeys->expires > 0))
449 {
450 tt = key->subkeys->expires;
451
452 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
453 fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
454 _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
455 }
456
457 if (key->subkeys)
458 s = gpgme_pubkey_algo_name(key->subkeys->pubkey_algo);
459 else
460 s = "?";
461
462 s2 = is_pgp ? "PGP" : "X.509";
463
464 if (key->subkeys)
465 aval = key->subkeys->length;
466
468 /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
469 fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), s2, aval, s);
470
472 delim = "";
473
475 {
476 /* L10N: value in Key Usage: field */
477 fprintf(fp, "%s%s", delim, _("encryption"));
478 delim = _(", ");
479 }
481 {
482 /* L10N: value in Key Usage: field */
483 fprintf(fp, "%s%s", delim, _("signing"));
484 delim = _(", ");
485 }
487 {
488 /* L10N: value in Key Usage: field */
489 fprintf(fp, "%s%s", delim, _("certification"));
490 }
491 putc('\n', fp);
492
493 if (key->subkeys)
494 {
495 s = key->subkeys->fpr;
497 if (is_pgp && (strlen(s) == 40))
498 {
499 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0') &&
500 (s[3] != '\0') && (s[4] != '\0');
501 s += 4, i++)
502 {
503 putc(*s, fp);
504 putc(s[1], fp);
505 putc(s[2], fp);
506 putc(s[3], fp);
507 putc(' ', fp);
508 if (i == 4)
509 putc(' ', fp);
510 }
511 }
512 else
513 {
514 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0'); s += 2, i++)
515 {
516 putc(*s, fp);
517 putc(s[1], fp);
518 putc(is_pgp ? ' ' : ':', fp);
519 if (is_pgp && (i == 7))
520 putc(' ', fp);
521 }
522 }
523 fprintf(fp, "%s\n", s);
524 }
525
526 if (key->issuer_serial)
527 {
528 s = key->issuer_serial;
529 fprintf(fp, "%*s0x%s\n", KeyInfoPadding[KIP_SERIAL_NO],
531 }
532
533 if (key->issuer_name)
534 {
535 s = key->issuer_name;
538 putc('\n', fp);
539 }
540
541 /* For PGP we list all subkeys. */
542 if (is_pgp)
543 {
544 gpgme_subkey_t subkey = NULL;
545
546 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next)
547 {
548 s = subkey->keyid;
549
550 putc('\n', fp);
551 if (strlen(s) == 16)
552 s += 8; /* display only the short keyID */
553 fprintf(fp, "%*s0x%s", KeyInfoPadding[KIP_SUBKEY], _(KeyInfoPrompts[KIP_SUBKEY]), s);
554 if (subkey->revoked)
555 {
556 putc(' ', fp);
557 /* L10N: describes a subkey */
558 fputs(_("[Revoked]"), fp);
559 }
560 if (subkey->invalid)
561 {
562 putc(' ', fp);
563 /* L10N: describes a subkey */
564 fputs(_("[Invalid]"), fp);
565 }
566 if (subkey->expired)
567 {
568 putc(' ', fp);
569 /* L10N: describes a subkey */
570 fputs(_("[Expired]"), fp);
571 }
572 if (subkey->disabled)
573 {
574 putc(' ', fp);
575 /* L10N: describes a subkey */
576 fputs(_("[Disabled]"), fp);
577 }
578 putc('\n', fp);
579
580 if (subkey->timestamp > 0)
581 {
582 tt = subkey->timestamp;
583
584 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
585 fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
586 _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
587 }
588
589 if (subkey->expires > 0)
590 {
591 tt = subkey->expires;
592
593 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
594 fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
595 _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
596 }
597
598 s = gpgme_pubkey_algo_name(subkey->pubkey_algo);
599
600 aval = subkey->length;
601
603 /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
604 fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), "PGP", aval, s);
605
607 delim = "";
608
609 if (subkey->can_encrypt)
610 {
611 fprintf(fp, "%s%s", delim, _("encryption"));
612 delim = _(", ");
613 }
614 if (subkey->can_sign)
615 {
616 fprintf(fp, "%s%s", delim, _("signing"));
617 delim = _(", ");
618 }
619 if (subkey->can_certify)
620 {
621 fprintf(fp, "%s%s", delim, _("certification"));
622 }
623 putc('\n', fp);
624 }
625 }
626}
627
632static void verify_key(struct CryptKeyInfo *key)
633{
634 const char *s = NULL;
635 gpgme_ctx_t listctx = NULL;
636 gpgme_error_t err = GPG_ERR_NO_ERROR;
637 gpgme_key_t k = NULL;
638 int maxdepth = 100;
639
640 struct Buffer *tempfile = buf_pool_get();
641 buf_mktemp(tempfile);
642 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w");
643 if (!fp)
644 {
645 mutt_perror(_("Can't create temporary file"));
646 goto cleanup;
647 }
648 mutt_message(_("Collecting data..."));
649
650 print_key_info(key->kobj, fp);
651
652 listctx = create_gpgme_context(key->flags & KEYFLAG_ISX509);
653
654 k = key->kobj;
655 gpgme_key_ref(k);
656 while ((s = k->chain_id) && k->subkeys && !mutt_str_equal(s, k->subkeys->fpr))
657 {
658 putc('\n', fp);
659 err = gpgme_op_keylist_start(listctx, s, 0);
660 gpgme_key_unref(k);
661 k = NULL;
662 if (err == GPG_ERR_NO_ERROR)
663 err = gpgme_op_keylist_next(listctx, &k);
664 if (err != GPG_ERR_NO_ERROR)
665 {
666 fprintf(fp, _("Error finding issuer key: %s\n"), gpgme_strerror(err));
667 goto leave;
668 }
669 gpgme_op_keylist_end(listctx);
670
671 print_key_info(k, fp);
672 if (!--maxdepth)
673 {
674 putc('\n', fp);
675 fputs(_("Error: certification chain too long - stopping here\n"), fp);
676 break;
677 }
678 }
679
680leave:
681 gpgme_key_unref(k);
682 gpgme_release(listctx);
683 mutt_file_fclose(&fp);
685 char title[1024] = { 0 };
686 snprintf(title, sizeof(title), _("Key ID: 0x%s"), crypt_keyid(key));
687
688 struct PagerData pdata = { 0 };
689 struct PagerView pview = { &pdata };
690
691 pdata.fname = buf_string(tempfile);
692
693 pview.banner = title;
695 pview.mode = PAGER_MODE_OTHER;
696
697 mutt_do_pager(&pview, NULL);
698
699cleanup:
700 buf_pool_release(&tempfile);
701}
702
708static bool crypt_key_is_valid(struct CryptKeyInfo *k)
709{
710 if (k->flags & KEYFLAG_CANTUSE)
711 return false;
712 return true;
713}
714
721{
722 for (struct CryptKeyInfo *k = keys; k != NULL; k = k->next)
723 {
724 if (!crypt_key_is_valid(k))
725 return false;
726 }
727
728 return true;
729}
730
731// -----------------------------------------------------------------------------
732
736static int op_exit(struct GpgmeData *gd, int op)
737{
738 gd->done = true;
739 return FR_SUCCESS;
740}
741
745static int op_generic_select_entry(struct GpgmeData *gd, int op)
746{
747 const int index = menu_get_index(gd->menu);
748 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
749 if (!pkey)
750 return FR_ERROR;
751
752 struct CryptKeyInfo *cur_key = *pkey;
753
754 /* FIXME make error reporting more verbose - this should be
755 * easy because GPGME provides more information */
757 {
758 if (!crypt_key_is_valid(cur_key))
759 {
760 mutt_error(_("This key can't be used: expired/disabled/revoked"));
761 return FR_ERROR;
762 }
763 }
764
765 if (OptPgpCheckTrust && (!crypt_id_is_valid(cur_key) || !crypt_id_is_strong(cur_key)))
766 {
767 const char *warn_s = NULL;
768 char buf2[1024] = { 0 };
769
770 if (cur_key->flags & KEYFLAG_CANTUSE)
771 {
772 warn_s = _("ID is expired/disabled/revoked. Do you really want to use the key?");
773 }
774 else
775 {
776 warn_s = "??";
777 switch (cur_key->validity)
778 {
779 case GPGME_VALIDITY_NEVER:
780 warn_s = _("ID is not valid. Do you really want to use the key?");
781 break;
782 case GPGME_VALIDITY_MARGINAL:
783 warn_s = _("ID is only marginally valid. Do you really want to use the key?");
784 break;
785 case GPGME_VALIDITY_FULL:
786 case GPGME_VALIDITY_ULTIMATE:
787 break;
788 case GPGME_VALIDITY_UNKNOWN:
789 case GPGME_VALIDITY_UNDEFINED:
790 warn_s = _("ID has undefined validity. Do you really want to use the key?");
791 break;
792 }
793 }
794
795 snprintf(buf2, sizeof(buf2), "%s", warn_s);
796
797 if (query_yesorno(buf2, MUTT_NO) != MUTT_YES)
798 {
800 return FR_NO_ACTION;
801 }
802 }
803
804 gd->key = crypt_copy_key(cur_key);
805 gd->done = true;
806 return FR_SUCCESS;
807}
808
812static int op_verify_key(struct GpgmeData *gd, int op)
813{
814 const int index = menu_get_index(gd->menu);
815 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
816 if (!pkey)
817 return FR_ERROR;
818
819 verify_key(*pkey);
821 return FR_SUCCESS;
822}
823
827static int op_view_id(struct GpgmeData *gd, int op)
828{
829 const int index = menu_get_index(gd->menu);
830 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
831 if (!pkey)
832 return FR_ERROR;
833
834 mutt_message("%s", (*pkey)->uid);
835 return FR_SUCCESS;
836}
837
838// -----------------------------------------------------------------------------
839
843static const struct GpgmeFunction GpgmeFunctions[] = {
844 // clang-format off
845 { OP_EXIT, op_exit },
846 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
847 { OP_VERIFY_KEY, op_verify_key },
848 { OP_VIEW_ID, op_view_id },
849 { 0, NULL },
850 // clang-format on
851};
852
857{
858 // The Dispatcher may be called on any Window in the Dialog
859 struct MuttWindow *dlg = dialog_find(win);
860 if (!dlg || !dlg->wdata)
861 return FR_ERROR;
862
863 struct Menu *menu = dlg->wdata;
864 struct GpgmeData *gd = menu->mdata;
865
866 int rc = FR_UNKNOWN;
867 for (size_t i = 0; GpgmeFunctions[i].op != OP_NULL; i++)
868 {
869 const struct GpgmeFunction *fn = &GpgmeFunctions[i];
870 if (fn->op == op)
871 {
872 rc = fn->function(gd, op);
873 break;
874 }
875 }
876
877 if (rc == FR_UNKNOWN) // Not our function
878 return rc;
879
880 const char *result = dispatcher_get_retval_name(rc);
881 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
882
883 return rc;
884}
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
Convenience wrapper for the core headers.
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:234
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:310
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:275
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2948
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:138
Wrapper for PGP/SMIME calls to GPGME.
@ KIP_FINGERPRINT
PGP Key field: Fingerprint.
Definition: crypt_gpgme.h:66
@ KIP_SERIAL_NO
PGP Key field: Serial number.
Definition: crypt_gpgme.h:67
@ KIP_SUBKEY
PGP Key field: Subkey.
Definition: crypt_gpgme.h:69
@ KIP_AKA
PGP Key field: aka (Also Known As)
Definition: crypt_gpgme.h:61
@ KIP_VALID_FROM
PGP Key field: Valid From date.
Definition: crypt_gpgme.h:62
@ KIP_MAX
Definition: crypt_gpgme.h:70
@ KIP_KEY_TYPE
PGP Key field: Key Type.
Definition: crypt_gpgme.h:64
@ KIP_NAME
PGP Key field: Name.
Definition: crypt_gpgme.h:60
@ KIP_ISSUED_BY
PGP Key field: Issued By.
Definition: crypt_gpgme.h:68
@ KIP_KEY_USAGE
PGP Key field: Key Usage.
Definition: crypt_gpgme.h:65
@ KIP_VALID_TO
PGP Key field: Valid To date.
Definition: crypt_gpgme.h:63
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition: crypt_gpgme.h:80
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition: crypt_gpgme.h:78
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition: crypt_gpgme.h:79
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:443
struct MuttWindow * dialog_find(struct MuttWindow *win)
Find the parent Dialog of a Window.
Definition: dialog.c:89
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition: dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
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:122
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:70
static int create_gpgme_context(gpgme_ctx_t *ctx)
Create a GPGME context.
Definition: gpgme.c:51
static const struct GpgmeFunction GpgmeFunctions[]
All the NeoMutt functions that the Gpgme supports.
static const char *const KeyInfoPrompts[]
Names of header fields used in the pgp key display, e.g. Name:, Fingerprint:
int KeyInfoPadding[KIP_MAX]
Number of padding spaces needed after each of the strings in KeyInfoPrompts after translation.
static void parse_and_print_user_id(FILE *fp, const char *userid)
Print a nice representation of the userid.
static struct DnArray * parse_dn(const char *str)
Parse a DN and return an array-ized one.
static void print_key_info(gpgme_key_t key, FILE *fp)
Verbose information about a key or certificate to a file.
static void print_utf8(FILE *fp, const char *buf, size_t len)
Write a UTF-8 string to a file.
static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
Print the X.500 Distinguished Name.
static bool crypt_key_is_valid(struct CryptKeyInfo *k)
Is the key valid.
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
static void verify_key(struct CryptKeyInfo *key)
Show detailed information about the selected key.
static void print_dn_parts(FILE *fp, struct DnArray *dn)
Print all parts of a DN in a standard sequence.
static const char * parse_dn_part(struct DnArray *array, const char *str)
Parse an RDN.
Gpgme functions.
int gpgme_function_dispatcher(struct MuttWindow *win, int op)
Perform a Gpgme function - Implements function_dispatcher_t -.
static int op_exit(struct GpgmeData *gd, int op)
Exit this menu - Implements gpgme_function_t -.
static int op_generic_select_entry(struct GpgmeData *gd, int op)
Select the current entry - Implements gpgme_function_t -.
static int op_view_id(struct GpgmeData *gd, int op)
View the key's user id - Implements gpgme_function_t -.
static int op_verify_key(struct GpgmeData *gd, int op)
Verify a PGP public key - Implements gpgme_function_t -.
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
Convenience wrapper for the gui headers.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition: memory.h:41
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition: menu.c:160
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:831
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:64
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:951
Convenience wrapper for the library headers.
#define N_(a)
Definition: message.h:32
#define _(a)
Definition: message.h:28
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:129
#define KEYFLAG_CANTUSE
Definition: lib.h:139
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:48
GUI display a file/email/help in a viewport with paging.
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: lib.h:60
@ PAGER_MODE_OTHER
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition: lib.h:142
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
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
Key value store.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
A stored PGP key.
Definition: crypt_gpgme.h:45
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:51
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:50
struct CryptKeyInfo * next
Linked list.
Definition: crypt_gpgme.h:46
gpgme_key_t kobj
Definition: crypt_gpgme.h:47
An X500 Distinguished Name.
char * key
Key.
char * value
Value.
Data to pass to the Gpgme Functions.
struct CryptKeyInfoArray * key_table
Array of Keys.
struct CryptKeyInfo * key
Selected Key.
bool done
Should we close the Dialog?
struct Menu * menu
Gpgme Menu.
A NeoMutt function.
gpgme_function_t function
Function to call.
int op
Op code, e.g. OP_GENERIC_SELECT_ENTRY.
Definition: lib.h:79
void * mdata
Private data.
Definition: lib.h:147
void * wdata
Private data.
Definition: mutt_window.h:144
Data to be displayed by PagerView.
Definition: lib.h:161
const char * fname
Name of the file to read.
Definition: lib.h:165
Paged view into some data.
Definition: lib.h:172
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition: lib.h:173
enum PagerMode mode
Pager mode.
Definition: lib.h:174
PagerFlags flags
Additional settings to tweak pager's function.
Definition: lib.h:175
const char * banner
Title to display in status bar.
Definition: lib.h:176
#define buf_mktemp(buf)
Definition: tmp.h:33