NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
gpgme_functions.c
Go to the documentation of this file.
1
23
29
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.
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: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.
static int op_generic_select_entry(struct AliasMenuData *mdata, int op)
select the current entry - Implements alias_function_t -
Definition functions.c:214
static int op_exit(struct AliasMenuData *mdata, int op)
exit this menu - Implements alias_function_t -
Definition functions.c:200
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:950
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:498
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: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:325
#define NONULL(x)
Definition string2.h:43
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.
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