NeoMutt  2025-12-11-911-gd8d604
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 "module_data.h"
51#include "mutt_logging.h"
52#ifdef ENABLE_NLS
53#include <libintl.h>
54#endif
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{
389 int idx;
390 const char *s = NULL, *s2 = NULL;
391 time_t tt = 0;
392 char shortbuf[128] = { 0 };
393 unsigned long aval = 0;
394 const char *delim = NULL;
395 gpgme_user_id_t uid = NULL;
396 static int max_header_width = 0;
397
398 if (max_header_width == 0)
399 {
400 for (int i = 0; i < KIP_MAX; i++)
401 {
402 mod_data->key_info_padding[i] = mutt_str_len(_(KeyInfoPrompts[i]));
403 const int width = mutt_strwidth(_(KeyInfoPrompts[i]));
404 if (max_header_width < width)
405 max_header_width = width;
406 mod_data->key_info_padding[i] -= width;
407 }
408 for (int i = 0; i < KIP_MAX; i++)
409 mod_data->key_info_padding[i] += max_header_width;
410 }
411
412 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
413
414 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
415 {
416 if (uid->revoked)
417 continue;
418
419 s = uid->uid;
420 /* L10N: DOTFILL */
421
422 if (idx == 0)
423 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_NAME], _(KeyInfoPrompts[KIP_NAME]));
424 else
425 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_AKA], _(KeyInfoPrompts[KIP_AKA]));
426 if (uid->invalid)
427 {
428 /* L10N: comes after the Name or aka if the key is invalid */
429 fputs(_("[Invalid]"), fp);
430 putc(' ', fp);
431 }
432 if (is_pgp)
433 print_utf8(fp, s, strlen(s));
434 else
436 putc('\n', fp);
437 }
438
439 if (key->subkeys && (key->subkeys->timestamp > 0))
440 {
441 tt = key->subkeys->timestamp;
442
443 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
444 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_FROM],
445 _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
446 }
447
448 if (key->subkeys && (key->subkeys->expires > 0))
449 {
450 tt = key->subkeys->expires;
451
452 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
453 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_TO],
454 _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
455 }
456
457 if (key->subkeys)
458 s = gpgme_pubkey_algo_name(key->subkeys->pubkey_algo);
459 else
460 s = "?";
461
462 s2 = is_pgp ? "PGP" : "X.509";
463
464 if (key->subkeys)
465 aval = key->subkeys->length;
466
467 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_TYPE],
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
472 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_USAGE],
474 delim = "";
475
477 {
478 /* L10N: value in Key Usage: field */
479 fprintf(fp, "%s%s", delim, _("encryption"));
480 delim = _(", ");
481 }
483 {
484 /* L10N: value in Key Usage: field */
485 fprintf(fp, "%s%s", delim, _("signing"));
486 delim = _(", ");
487 }
489 {
490 /* L10N: value in Key Usage: field */
491 fprintf(fp, "%s%s", delim, _("certification"));
492 }
493 putc('\n', fp);
494
495 if (key->subkeys)
496 {
497 s = key->subkeys->fpr;
498 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_FINGERPRINT],
500 if (is_pgp && (strlen(s) == 40))
501 {
502 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0') &&
503 (s[3] != '\0') && (s[4] != '\0');
504 s += 4, i++)
505 {
506 putc(*s, fp);
507 putc(s[1], fp);
508 putc(s[2], fp);
509 putc(s[3], fp);
510 putc(' ', fp);
511 if (i == 4)
512 putc(' ', fp);
513 }
514 }
515 else
516 {
517 for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0'); s += 2, i++)
518 {
519 putc(*s, fp);
520 putc(s[1], fp);
521 putc(is_pgp ? ' ' : ':', fp);
522 if (is_pgp && (i == 7))
523 putc(' ', fp);
524 }
525 }
526 fprintf(fp, "%s\n", s);
527 }
528
529 if (key->issuer_serial)
530 {
531 s = key->issuer_serial;
532 fprintf(fp, "%*s0x%s\n", mod_data->key_info_padding[KIP_SERIAL_NO],
534 }
535
536 if (key->issuer_name)
537 {
538 s = key->issuer_name;
539 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_ISSUED_BY],
542 putc('\n', fp);
543 }
544
545 /* For PGP we list all subkeys. */
546 if (is_pgp)
547 {
548 gpgme_subkey_t subkey = NULL;
549
550 for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next)
551 {
552 s = subkey->keyid;
553
554 putc('\n', fp);
555 if (strlen(s) == 16)
556 s += 8; /* display only the short keyID */
557 fprintf(fp, "%*s0x%s", mod_data->key_info_padding[KIP_SUBKEY],
559 if (subkey->revoked)
560 {
561 putc(' ', fp);
562 /* L10N: describes a subkey */
563 fputs(_("[Revoked]"), fp);
564 }
565 if (subkey->invalid)
566 {
567 putc(' ', fp);
568 /* L10N: describes a subkey */
569 fputs(_("[Invalid]"), fp);
570 }
571 if (subkey->expired)
572 {
573 putc(' ', fp);
574 /* L10N: describes a subkey */
575 fputs(_("[Expired]"), fp);
576 }
577 if (subkey->disabled)
578 {
579 putc(' ', fp);
580 /* L10N: describes a subkey */
581 fputs(_("[Disabled]"), fp);
582 }
583 putc('\n', fp);
584
585 if (subkey->timestamp > 0)
586 {
587 tt = subkey->timestamp;
588
589 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
590 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_FROM],
591 _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
592 }
593
594 if (subkey->expires > 0)
595 {
596 tt = subkey->expires;
597
598 mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
599 fprintf(fp, "%*s%s\n", mod_data->key_info_padding[KIP_VALID_TO],
600 _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
601 }
602
603 s = gpgme_pubkey_algo_name(subkey->pubkey_algo);
604
605 aval = subkey->length;
606
607 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_TYPE],
609 /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
610 fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), "PGP", aval, s);
611
612 fprintf(fp, "%*s", mod_data->key_info_padding[KIP_KEY_USAGE],
614 delim = "";
615
616 if (subkey->can_encrypt)
617 {
618 fprintf(fp, "%s%s", delim, _("encryption"));
619 delim = _(", ");
620 }
621 if (subkey->can_sign)
622 {
623 fprintf(fp, "%s%s", delim, _("signing"));
624 delim = _(", ");
625 }
626 if (subkey->can_certify)
627 {
628 fprintf(fp, "%s%s", delim, _("certification"));
629 }
630 putc('\n', fp);
631 }
632 }
633}
634
639static void verify_key(struct CryptKeyInfo *key)
640{
641 const char *s = NULL;
642 gpgme_ctx_t listctx = NULL;
643 gpgme_error_t err = GPG_ERR_NO_ERROR;
644 gpgme_key_t k = NULL;
645 int maxdepth = 100;
646
647 struct Buffer *tempfile = buf_pool_get();
648 buf_mktemp(tempfile);
649 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w");
650 if (!fp)
651 {
652 mutt_perror(_("Can't create temporary file"));
653 goto cleanup;
654 }
655 mutt_message(_("Collecting data..."));
656
657 print_key_info(key->kobj, fp);
658
659 listctx = create_gpgme_context(key->flags & KEYFLAG_ISX509);
660
661 k = key->kobj;
662 gpgme_key_ref(k);
663 while ((s = k->chain_id) && k->subkeys && !mutt_str_equal(s, k->subkeys->fpr))
664 {
665 putc('\n', fp);
666 err = gpgme_op_keylist_start(listctx, s, 0);
667 gpgme_key_unref(k);
668 k = NULL;
669 if (err == GPG_ERR_NO_ERROR)
670 err = gpgme_op_keylist_next(listctx, &k);
671 if (err != GPG_ERR_NO_ERROR)
672 {
673 fprintf(fp, _("Error finding issuer key: %s\n"), gpgme_strerror(err));
674 goto leave;
675 }
676 gpgme_op_keylist_end(listctx);
677
678 print_key_info(k, fp);
679 if (!--maxdepth)
680 {
681 putc('\n', fp);
682 fputs(_("Error: certification chain too long - stopping here\n"), fp);
683 break;
684 }
685 }
686
687leave:
688 gpgme_key_unref(k);
689 gpgme_release(listctx);
690 mutt_file_fclose(&fp);
692 char title[1024] = { 0 };
693 snprintf(title, sizeof(title), _("Key ID: 0x%s"), crypt_keyid(key));
694
695 struct PagerData pdata = { 0 };
696 struct PagerView pview = { &pdata };
697
698 pdata.fname = buf_string(tempfile);
699
700 pview.banner = title;
701 pview.flags = MUTT_PAGER_NONE;
702 pview.mode = PAGER_MODE_OTHER;
703
704 mutt_do_pager(&pview, NULL);
705
706cleanup:
707 buf_pool_release(&tempfile);
708}
709
715static bool crypt_key_is_valid(struct CryptKeyInfo *k)
716{
717 if (k->flags & KEYFLAG_CANTUSE)
718 return false;
719 return true;
720}
721
728{
729 for (struct CryptKeyInfo *k = keys; k != NULL; k = k->next)
730 {
731 if (!crypt_key_is_valid(k))
732 return false;
733 }
734
735 return true;
736}
737
738// -----------------------------------------------------------------------------
739
743static int op_exit(struct GpgmeData *gd, const struct KeyEvent *event)
744{
745 gd->done = true;
746 return FR_SUCCESS;
747}
748
752static int op_generic_select_entry(struct GpgmeData *gd, const struct KeyEvent *event)
753{
754 const int index = menu_get_index(gd->menu);
755 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
756 if (!pkey)
757 return FR_ERROR;
758
759 struct CryptKeyInfo *cur_key = *pkey;
760
761 /* FIXME make error reporting more verbose - this should be
762 * easy because GPGME provides more information */
764 {
765 if (!crypt_key_is_valid(cur_key))
766 {
767 mutt_error(_("This key can't be used: expired/disabled/revoked"));
768 return FR_ERROR;
769 }
770 }
771
772 if (OptPgpCheckTrust && (!crypt_id_is_valid(cur_key) || !crypt_id_is_strong(cur_key)))
773 {
774 const char *warn_s = NULL;
775 char buf2[1024] = { 0 };
776
777 if (cur_key->flags & KEYFLAG_CANTUSE)
778 {
779 warn_s = _("ID is expired/disabled/revoked. Do you really want to use the key?");
780 }
781 else
782 {
783 warn_s = "??";
784 switch (cur_key->validity)
785 {
786 case GPGME_VALIDITY_NEVER:
787 warn_s = _("ID is not valid. Do you really want to use the key?");
788 break;
789 case GPGME_VALIDITY_MARGINAL:
790 warn_s = _("ID is only marginally valid. Do you really want to use the key?");
791 break;
792 case GPGME_VALIDITY_FULL:
793 case GPGME_VALIDITY_ULTIMATE:
794 break;
795 case GPGME_VALIDITY_UNKNOWN:
796 case GPGME_VALIDITY_UNDEFINED:
797 warn_s = _("ID has undefined validity. Do you really want to use the key?");
798 break;
799 }
800 }
801
802 snprintf(buf2, sizeof(buf2), "%s", warn_s);
803
804 if (query_yesorno(buf2, MUTT_NO) != MUTT_YES)
805 {
807 return FR_NO_ACTION;
808 }
809 }
810
811 gd->key = crypt_copy_key(cur_key);
812 gd->done = true;
813 return FR_SUCCESS;
814}
815
819static int op_verify_key(struct GpgmeData *gd, const struct KeyEvent *event)
820{
821 const int index = menu_get_index(gd->menu);
822 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
823 if (!pkey)
824 return FR_ERROR;
825
826 verify_key(*pkey);
828 return FR_SUCCESS;
829}
830
834static int op_view_id(struct GpgmeData *gd, const struct KeyEvent *event)
835{
836 const int index = menu_get_index(gd->menu);
837 struct CryptKeyInfo **pkey = ARRAY_GET(gd->key_table, index);
838 if (!pkey)
839 return FR_ERROR;
840
841 mutt_message("%s", (*pkey)->uid);
842 return FR_SUCCESS;
843}
844
845// -----------------------------------------------------------------------------
846
850static const struct GpgmeFunction GpgmeFunctions[] = {
851 // clang-format off
852 { OP_EXIT, op_exit },
853 { OP_GENERIC_SELECT_ENTRY, op_generic_select_entry },
854 { OP_VERIFY_KEY, op_verify_key },
855 { OP_VIEW_ID, op_view_id },
856 { 0, NULL },
857 // clang-format on
858};
859
863int gpgme_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
864{
865 // The Dispatcher may be called on any Window in the Dialog
866 struct MuttWindow *dlg = dialog_find(win);
867 if (!event || !dlg || !dlg->wdata)
868 {
870 return FR_ERROR;
871 }
872
873 const int op = event->op;
874 struct Menu *menu = dlg->wdata;
875 struct GpgmeData *gd = menu->mdata;
876 if (!gd)
877 {
879 return FR_ERROR;
880 }
881
882 int rc = FR_UNKNOWN;
883 for (size_t i = 0; GpgmeFunctions[i].op != OP_NULL; i++)
884 {
885 const struct GpgmeFunction *fn = &GpgmeFunctions[i];
886 if (fn->op == op)
887 {
888 rc = fn->function(gd, event);
889 break;
890 }
891 }
892
893 if (rc == FR_UNKNOWN) // Not our function
894 return rc;
895
896 const char *result = dispatcher_get_retval_name(rc);
897 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
898
900 return rc;
901}
#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: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:446
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
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:
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_exit(struct AliasFunctionData *fdata, const struct KeyEvent *event)
exit this menu - Implements alias_function_t -
Definition functions.c:312
static int op_generic_select_entry(struct AliasFunctionData *fdata, const struct KeyEvent *event)
select the current entry - Implements alias_function_t -
Definition functions.c:392
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.
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition menu.c:179
int menu_get_index(struct Menu *menu)
Get the current selection in the Menu.
Definition menu.c:155
@ MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:64
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:80
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:663
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: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: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:38
int key_info_padding[KIP_MAX]
Padding for key info prompts.
Definition module_data.h:45
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