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