NeoMutt  2025-12-11-949-g4870ee
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions_gpgme.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 <stdbool.h>
36#include <stdio.h>
37#include <string.h>
38#include <time.h>
39#include "mutt/lib.h"
40#include "config/lib.h"
41#include "core/lib.h"
42#include "gui/lib.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 "gpgme_functions.h"
51#include "module_data.h"
52#include "mutt_logging.h"
53#ifdef ENABLE_NLS
54#include <libintl.h>
55#endif
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 int 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; mutt_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 > 0; 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 (mutt_isxdigit(s[0]) && mutt_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 > 0; s++, n--)
250 {
251 if (*s == '\\')
252 {
253 s++;
254 if (mutt_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 (!mutt_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{
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 {
403 mod_data->key_info_padding[i] = mutt_str_len(_(KeyInfoPrompts[i]));
404 const int width = mutt_strwidth(_(KeyInfoPrompts[i]));
405 if (max_header_width < width)
406 max_header_width = width;
407 mod_data->key_info_padding[i] -= width;
408 }
409 for (int i = 0; i < KIP_MAX; i++)
410 mod_data->key_info_padding[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", mod_data->key_info_padding[KIP_NAME], _(KeyInfoPrompts[KIP_NAME]));
425 else
426 fprintf(fp, "%*s", mod_data->key_info_padding[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", mod_data->key_info_padding[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", mod_data->key_info_padding[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
468 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_TYPE],
470 /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
471 fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), s2, aval, s);
472
473 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_USAGE],
475 delim = "";
476
478 {
479 /* L10N: value in Key Usage: field */
480 fprintf(fp, "%s%s", delim, _("encryption"));
481 delim = _(", ");
482 }
484 {
485 /* L10N: value in Key Usage: field */
486 fprintf(fp, "%s%s", delim, _("signing"));
487 delim = _(", ");
488 }
490 {
491 /* L10N: value in Key Usage: field */
492 fprintf(fp, "%s%s", delim, _("certification"));
493 }
494 putc('\n', fp);
495
496 if (key->subkeys)
497 {
498 s = key->subkeys->fpr;
499 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_FINGERPRINT],
501 if (is_pgp && (strlen(s) == 40))
502 {
503 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0') &&
504 (s[3] != '\0') && (s[4] != '\0');
505 s += 4, i++)
506 {
507 putc(*s, fp);
508 putc(s[1], fp);
509 putc(s[2], fp);
510 putc(s[3], fp);
511 putc(' ', fp);
512 if (i == 4)
513 putc(' ', fp);
514 }
515 }
516 else
517 {
518 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0'); s += 2, i++)
519 {
520 putc(*s, fp);
521 putc(s[1], fp);
522 putc(is_pgp ? ' ' : ':', fp);
523 if (is_pgp && (i == 7))
524 putc(' ', fp);
525 }
526 }
527 fprintf(fp, "%s\n", s);
528 }
529
530 if (key->issuer_serial)
531 {
532 s = key->issuer_serial;
533 fprintf(fp, "%*s0x%s\n", mod_data->key_info_padding[KIP_SERIAL_NO],
535 }
536
537 if (key->issuer_name)
538 {
539 s = key->issuer_name;
540 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_ISSUED_BY],
543 putc('\n', fp);
544 }
545
546 /* For PGP we list all subkeys. */
547 if (is_pgp)
548 {
549 gpgme_subkey_t subkey = NULL;
550
551 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next)
552 {
553 s = subkey->keyid;
554
555 putc('\n', fp);
556 if (strlen(s) == 16)
557 s += 8; /* display only the short keyID */
558 fprintf(fp, "%*s0x%s", mod_data->key_info_padding[KIP_SUBKEY],
560 if (subkey->revoked)
561 {
562 putc(' ', fp);
563 /* L10N: describes a subkey */
564 fputs(_("[Revoked]"), fp);
565 }
566 if (subkey->invalid)
567 {
568 putc(' ', fp);
569 /* L10N: describes a subkey */
570 fputs(_("[Invalid]"), fp);
571 }
572 if (subkey->expired)
573 {
574 putc(' ', fp);
575 /* L10N: describes a subkey */
576 fputs(_("[Expired]"), fp);
577 }
578 if (subkey->disabled)
579 {
580 putc(' ', fp);
581 /* L10N: describes a subkey */
582 fputs(_("[Disabled]"), fp);
583 }
584 putc('\n', fp);
585
586 if (subkey->timestamp > 0)
587 {
588 tt = subkey->timestamp;
589
590 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
591 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_FROM],
592 _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
593 }
594
595 if (subkey->expires > 0)
596 {
597 tt = subkey->expires;
598
599 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
600 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_TO],
601 _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
602 }
603
604 s = gpgme_pubkey_algo_name(subkey->pubkey_algo);
605
606 aval = subkey->length;
607
608 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_TYPE],
610 /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
611 fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), "PGP", aval, s);
612
613 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_USAGE],
615 delim = "";
616
617 if (subkey->can_encrypt)
618 {
619 fprintf(fp, "%s%s", delim, _("encryption"));
620 delim = _(", ");
621 }
622 if (subkey->can_sign)
623 {
624 fprintf(fp, "%s%s", delim, _("signing"));
625 delim = _(", ");
626 }
627 if (subkey->can_certify)
628 {
629 fprintf(fp, "%s%s", delim, _("certification"));
630 }
631 putc('\n', fp);
632 }
633 }
634}
635
640static void verify_key(struct CryptKeyInfo *key)
641{
642 const char *s = NULL;
643 gpgme_ctx_t listctx = NULL;
644 gpgme_error_t err = GPG_ERR_NO_ERROR;
645 gpgme_key_t k = NULL;
646 int maxdepth = 100;
647
648 struct Buffer *tempfile = buf_pool_get();
649 buf_mktemp(tempfile);
650 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w");
651 if (!fp)
652 {
653 mutt_perror(_("Can't create temporary file"));
654 goto cleanup;
655 }
656 mutt_message(_("Collecting data..."));
657
658 print_key_info(key->kobj, fp);
659
660 listctx = create_gpgme_context(key->flags & KEYFLAG_ISX509);
661
662 k = key->kobj;
663 gpgme_key_ref(k);
664 while ((s = k->chain_id) && k->subkeys && !mutt_str_equal(s, k->subkeys->fpr))
665 {
666 putc('\n', fp);
667 err = gpgme_op_keylist_start(listctx, s, 0);
668 gpgme_key_unref(k);
669 k = NULL;
670 if (err == GPG_ERR_NO_ERROR)
671 err = gpgme_op_keylist_next(listctx, &k);
672 if (err != GPG_ERR_NO_ERROR)
673 {
674 fprintf(fp, _("Error finding issuer key: %s\n"), gpgme_strerror(err));
675 goto leave;
676 }
677 gpgme_op_keylist_end(listctx);
678
679 print_key_info(k, fp);
680 if (!--maxdepth)
681 {
682 putc('\n', fp);
683 fputs(_("Error: certification chain too long - stopping here\n"), fp);
684 break;
685 }
686 }
687
688leave:
689 gpgme_key_unref(k);
690 gpgme_release(listctx);
691 mutt_file_fclose(&fp);
693 char title[1024] = { 0 };
694 snprintf(title, sizeof(title), _("Key ID: 0x%s"), crypt_keyid(key));
695
696 struct PagerData pdata = { 0 };
697 struct PagerView pview = { &pdata };
698
699 pdata.fname = buf_string(tempfile);
700
701 pview.banner = title;
702 pview.flags = MUTT_PAGER_NONE;
703 pview.mode = PAGER_MODE_OTHER;
704
705 mutt_do_pager(&pview, NULL);
706
707cleanup:
708 buf_pool_release(&tempfile);
709}
710
716static bool crypt_key_is_valid(struct CryptKeyInfo *k)
717{
718 if (k->flags & KEYFLAG_CANTUSE)
719 return false;
720 return true;
721}
722
729{
730 for (struct CryptKeyInfo *k = keys; k != NULL; k = k->next)
731 {
732 if (!crypt_key_is_valid(k))
733 return false;
734 }
735
736 return true;
737}
738
739// -----------------------------------------------------------------------------
740
744static int op_quit(struct GpgmeData *gd, const struct KeyEvent *event)
745{
746 gd->done = true;
747 return FR_SUCCESS;
748}
749
753static int op_generic_select_entry(struct GpgmeData *gd, const struct KeyEvent *event)
754{
755 const int index = menu_get_index(gd->menu);
756 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
757 if (!pkey)
758 return FR_ERROR;
759
760 struct CryptKeyInfo *cur_key = *pkey;
761
762 /* FIXME make error reporting more verbose - this should be
763 * easy because GPGME provides more information */
765 {
766 if (!crypt_key_is_valid(cur_key))
767 {
768 mutt_error(_("This key can't be used: expired/disabled/revoked"));
769 return FR_ERROR;
770 }
771 }
772
773 if (OptPgpCheckTrust && (!crypt_id_is_valid(cur_key) || !crypt_id_is_strong(cur_key)))
774 {
775 const char *warn_s = NULL;
776 char buf2[1024] = { 0 };
777
778 if (cur_key->flags & KEYFLAG_CANTUSE)
779 {
780 warn_s = _("ID is expired/disabled/revoked. Do you really want to use the key?");
781 }
782 else
783 {
784 warn_s = "??";
785 switch (cur_key->validity)
786 {
787 case GPGME_VALIDITY_NEVER:
788 warn_s = _("ID is not valid. Do you really want to use the key?");
789 break;
790 case GPGME_VALIDITY_MARGINAL:
791 warn_s = _("ID is only marginally valid. Do you really want to use the key?");
792 break;
793 case GPGME_VALIDITY_FULL:
794 case GPGME_VALIDITY_ULTIMATE:
795 break;
796 case GPGME_VALIDITY_UNKNOWN:
797 case GPGME_VALIDITY_UNDEFINED:
798 warn_s = _("ID has undefined validity. Do you really want to use the key?");
799 break;
800 }
801 }
802
803 snprintf(buf2, sizeof(buf2), "%s", warn_s);
804
805 if (query_yesorno(buf2, MUTT_NO) != MUTT_YES)
806 {
808 return FR_NO_ACTION;
809 }
810 }
811
812 gd->key = crypt_copy_key(cur_key);
813 gd->done = true;
814 return FR_SUCCESS;
815}
816
820static int op_verify_key(struct GpgmeData *gd, const struct KeyEvent *event)
821{
822 const int index = menu_get_index(gd->menu);
823 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
824 if (!pkey)
825 return FR_ERROR;
826
827 verify_key(*pkey);
829 return FR_SUCCESS;
830}
831
835static int op_view_id(struct GpgmeData *gd, const struct KeyEvent *event)
836{
837 const int index = menu_get_index(gd->menu);
838 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
839 if (!pkey)
840 return FR_ERROR;
841
842 mutt_message("%s", (*pkey)->uid);
843 return FR_SUCCESS;
844}
845
846// -----------------------------------------------------------------------------
847
851static const struct GpgmeFunction GpgmeFunctions[] = {
852 // clang-format off
853 { OP_EXIT, op_quit },
854 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
855 { OP_QUIT, op_quit },
856 { OP_VERIFY_KEY, op_verify_key },
857 { OP_VIEW_ID, op_view_id },
858 { 0, NULL },
859 // clang-format on
860};
861
865int gpgme_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
866{
867 // The Dispatcher may be called on any Window in the Dialog
868 struct MuttWindow *dlg = dialog_find(win);
869 if (!event || !dlg || !dlg->wdata)
870 {
872 return FR_ERROR;
873 }
874
875 const int op = event->op;
876 struct Menu *menu = dlg->wdata;
877 struct GpgmeData *gd = menu->mdata;
878 if (!gd)
879 {
881 return FR_ERROR;
882 }
883
884 int rc = FR_UNKNOWN;
885 for (size_t i = 0; GpgmeFunctions[i].op != OP_NULL; i++)
886 {
887 const struct GpgmeFunction *fn = &GpgmeFunctions[i];
888 if (fn->op == op)
889 {
890 rc = fn->function(gd, event);
891 break;
892 }
893 }
894
895 if (rc == FR_UNKNOWN) // Not our function
896 return rc;
897
898 const char *result = dispatcher_get_retval_name(rc);
899 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
900
902 return rc;
903}
#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.
bool 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: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
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: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:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
@ 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:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
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:
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.
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
Gpgme functions.
static int op_quit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Save changes and exit this dialog - Implements alias_function_t -.
Definition functions.c:308
static int op_generic_select_entry(struct AliasFunctionData *fdata, const struct KeyEvent *event)
select the current entry - Implements alias_function_t -
Definition functions.c:388
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_verify_key(struct GpgmeData *gd, const struct KeyEvent *event)
Verify a PGP public key - Implements gpgme_function_t -.
static int op_quit(struct GpgmeData *gd, const struct KeyEvent *event)
Save changes and exit this dialog - 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.
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:177
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:153
@ MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:64
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
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_NONE
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:665
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
NeoMutt Logging.
API for encryption/signing of emails.
#define KEYFLAG_CANTUSE
Definition lib.h:161
@ KEYFLAG_ISX509
Key is an X.509 key.
Definition lib.h:149
Ncrypt private Module data.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
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_NONE
No flags are set.
Definition lib.h:63
@ PAGER_MODE_OTHER
Pager is invoked via 3rd path. Non-email content is likely to be shown.
Definition lib.h:143
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:329
#define NONULL(x)
Definition string2.h:44
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
GPGME key object.
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.
An event such as a keypress.
Definition get.h:75
Definition lib.h:86
void * mdata
Private data.
Definition lib.h:155
void * wdata
Private data.
Ncrypt private Module data.
Definition module_data.h:39
int key_info_padding[KIP_MAX]
Padding for key info prompts.
Definition module_data.h:46
Container for Accounts, Notifications.
Definition neomutt.h:41
Data to be displayed by PagerView.
Definition lib.h:162
const char * fname
Name of the file to read.
Definition lib.h:166
Paged view into some data.
Definition lib.h:173
struct PagerData * pdata
Data that pager displays. NOTNULL.
Definition lib.h:174
enum PagerMode mode
Pager mode.
Definition lib.h:175
PagerFlags flags
Additional settings to tweak pager's function.
Definition lib.h:176
const char * banner
Title to display in status bar.
Definition lib.h:177
#define buf_mktemp(buf)
Definition tmp.h:33