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