NeoMutt  2024-04-25-1-g3de005
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
pgpkey.c
Go to the documentation of this file.
1
33#include "config.h"
34#include <stdbool.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <string.h>
38#include <sys/stat.h>
39#include <unistd.h>
40#include "private.h"
41#include "mutt/lib.h"
42#include "address/lib.h"
43#include "config/lib.h"
44#include "email/lib.h"
45#include "core/lib.h"
46#include "mutt.h"
47#include "pgpkey.h"
48#include "lib.h"
49#include "editor/lib.h"
50#include "history/lib.h"
51#include "send/lib.h"
52#include "crypt.h"
53#include "globals.h"
54#include "gnupgparse.h"
55#include "mutt_logging.h"
56#include "pgpinvoke.h"
57#ifdef CRYPT_BACKEND_CLASSIC_PGP
58#include "pgp.h"
59#include "pgplib.h"
60#endif
61
66{
67 char *what;
68 char *dflt;
69 struct PgpCache *next;
70};
71
73static struct PgpCache *IdDefaults = NULL;
74
75// clang-format off
76typedef uint8_t PgpKeyValidFlags;
77#define PGP_KV_NO_FLAGS 0
78#define PGP_KV_VALID (1 << 0)
79#define PGP_KV_ADDR (1 << 1)
80#define PGP_KV_STRING (1 << 2)
81#define PGP_KV_STRONGID (1 << 3)
82// clang-format on
83
84#define PGP_KV_MATCH (PGP_KV_ADDR | PGP_KV_STRING)
85
92{
93 if (key->flags & KEYFLAG_SUBKEY && key->parent)
94 return key->parent;
95 return key;
96}
97
104{
105 struct PgpKeyInfo *pk = pgp_principal_key(k);
106 if (k->flags & KEYFLAG_CANTUSE)
107 return false;
108 if (pk->flags & KEYFLAG_CANTUSE)
109 return false;
110
111 return true;
112}
113
120{
121 for (struct PgpKeyInfo *k = keys; k != NULL; k = k->next)
122 {
123 if (!pgp_key_is_valid(k))
124 return false;
125 }
126
127 return true;
128}
129
135bool pgp_id_is_strong(struct PgpUid *uid)
136{
137 if ((uid->trust & 3) < 3)
138 return false;
139 /* else */
140 return true;
141}
142
148bool pgp_id_is_valid(struct PgpUid *uid)
149{
150 if (!pgp_key_is_valid(uid->parent))
151 return false;
152 if (uid->flags & KEYFLAG_CANTUSE)
153 return false;
154 /* else */
155 return true;
156}
157
166 struct Address *u_addr, struct PgpUid *uid)
167{
169
170 if (pgp_id_is_valid(uid))
172
173 if (pgp_id_is_strong(uid))
175
176 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
177 {
179 }
180
181 if (addr->personal && u_addr->personal &&
182 buf_istr_equal(addr->personal, u_addr->personal))
183 {
185 }
186
187 return flags;
188}
189
198struct PgpKeyInfo *pgp_ask_for_key(char *tag, const char *whatfor,
199 KeyFlags abilities, enum PgpRing keyring)
200{
201 struct PgpKeyInfo *key = NULL;
202 struct PgpCache *l = NULL;
203 struct Buffer *resp = buf_pool_get();
204
206
207 if (whatfor)
208 {
209 for (l = IdDefaults; l; l = l->next)
210 {
211 if (mutt_istr_equal(whatfor, l->what))
212 {
213 buf_strcpy(resp, l->dflt);
214 break;
215 }
216 }
217 }
218
219 while (true)
220 {
221 buf_reset(resp);
222 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
223 {
224 goto done;
225 }
226
227 if (whatfor)
228 {
229 if (l)
230 {
231 mutt_str_replace(&l->dflt, buf_string(resp));
232 }
233 else
234 {
235 l = mutt_mem_malloc(sizeof(struct PgpCache));
236 l->next = IdDefaults;
237 IdDefaults = l;
238 l->what = mutt_str_dup(whatfor);
239 l->dflt = buf_strdup(resp);
240 }
241 }
242
243 key = pgp_getkeybystr(buf_string(resp), abilities, keyring);
244 if (key)
245 goto done;
246
247 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
248 }
249
250done:
251 buf_pool_release(&resp);
252 return key;
253}
254
259{
260 struct Body *att = NULL;
261 char buf[1024] = { 0 };
262 char tmp[256] = { 0 };
263 struct stat st = { 0 };
264 pid_t pid;
265 OptPgpCheckTrust = false;
266 struct Buffer *tempf = NULL;
267
268 struct PgpKeyInfo *key = pgp_ask_for_key(_("Please enter the key ID: "), NULL,
270
271 if (!key)
272 return NULL;
273
274 snprintf(tmp, sizeof(tmp), "0x%s", pgp_fpr_or_lkeyid(pgp_principal_key(key)));
275 pgp_key_free(&key);
276
277 tempf = buf_pool_get();
278 buf_mktemp(tempf);
279 FILE *fp_tmp = mutt_file_fopen(buf_string(tempf), "w");
280 if (!fp_tmp)
281 {
282 mutt_perror(_("Can't create temporary file"));
283 goto cleanup;
284 }
285
286 FILE *fp_null = mutt_file_fopen("/dev/null", "w");
287 if (!fp_null)
288 {
289 mutt_perror(_("Can't open /dev/null"));
290 mutt_file_fclose(&fp_tmp);
291 unlink(buf_string(tempf));
292 goto cleanup;
293 }
294
295 mutt_message(_("Invoking PGP..."));
296
297 pid = pgp_invoke_export(NULL, NULL, NULL, -1, fileno(fp_tmp), fileno(fp_null), tmp);
298 if (pid == -1)
299 {
300 mutt_perror(_("Can't create filter"));
301 unlink(buf_string(tempf));
302 mutt_file_fclose(&fp_tmp);
303 mutt_file_fclose(&fp_null);
304 goto cleanup;
305 }
306
307 filter_wait(pid);
308
309 mutt_file_fclose(&fp_tmp);
310 mutt_file_fclose(&fp_null);
311
312 att = mutt_body_new();
313 att->filename = buf_strdup(tempf);
314 att->unlink = true;
315 att->use_disp = false;
316 att->type = TYPE_APPLICATION;
317 att->subtype = mutt_str_dup("pgp-keys");
318 snprintf(buf, sizeof(buf), _("PGP Key %s"), tmp);
319 att->description = mutt_str_dup(buf);
321
322 stat(buf_string(tempf), &st);
323 att->length = st.st_size;
324
325cleanup:
326 buf_pool_release(&tempf);
327 return att;
328}
329
338static void pgp_add_string_to_hints(const char *str, struct ListHead *hints)
339{
340 char *scratch = mutt_str_dup(str);
341 if (!scratch)
342 return;
343
344 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
345 {
346 if (strlen(t) > 3)
348 }
349
350 FREE(&scratch);
351}
352
358static struct PgpKeyInfo **pgp_get_lastp(struct PgpKeyInfo *p)
359{
360 for (; p; p = p->next)
361 if (!p->next)
362 return &p->next;
363
364 return NULL;
365}
366
375struct PgpKeyInfo *pgp_getkeybyaddr(struct Address *a, KeyFlags abilities,
376 enum PgpRing keyring, bool oppenc_mode)
377{
378 if (!a)
379 return NULL;
380
381 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
382
383 bool multi = false;
384
385 struct PgpKeyInfo *keys = NULL, *k = NULL, *kn = NULL;
386 struct PgpKeyInfo *the_strong_valid_key = NULL;
387 struct PgpKeyInfo *a_valid_addrmatch_key = NULL;
388 struct PgpKeyInfo *matches = NULL;
389 struct PgpKeyInfo **last = &matches;
390 struct PgpUid *q = NULL;
391
392 if (a->mailbox)
394 if (a->personal)
396
397 if (!oppenc_mode)
398 mutt_message(_("Looking for keys matching \"%s\"..."), buf_string(a->mailbox));
399 keys = pgp_get_candidates(keyring, &hints);
400
401 mutt_list_free(&hints);
402
403 if (!keys)
404 return NULL;
405
406 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", buf_string(a->personal),
407 buf_string(a->mailbox));
408
409 for (k = keys; k; k = kn)
410 {
411 kn = k->next;
412
413 mutt_debug(LL_DEBUG5, " looking at key: %s\n", pgp_keyid(k));
414
415 if (abilities && !(k->flags & abilities))
416 {
417 mutt_debug(LL_DEBUG3, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
418 continue;
419 }
420
421 bool match = false; /* any match */
422
423 for (q = k->address; q; q = q->next)
424 {
425 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
427 struct Address *qa = NULL;
428 TAILQ_FOREACH(qa, &al, entries)
429 {
430 PgpKeyValidFlags validity = pgp_id_matches_addr(a, qa, q);
431
432 if (validity & PGP_KV_MATCH) /* something matches */
433 match = true;
434
435 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_ADDR))
436 {
437 if (validity & PGP_KV_STRONGID)
438 {
439 if (the_strong_valid_key && (the_strong_valid_key != k))
440 multi = true;
441 the_strong_valid_key = k;
442 }
443 else
444 {
445 a_valid_addrmatch_key = k;
446 }
447 }
448 }
449
451 }
452
453 if (match)
454 {
455 *last = pgp_principal_key(k);
456 kn = pgp_remove_key(&keys, *last);
457 last = pgp_get_lastp(k);
458 }
459 }
460
461 pgp_key_free(&keys);
462
463 if (matches)
464 {
465 if (oppenc_mode || !isatty(STDIN_FILENO))
466 {
467 const bool c_crypt_opportunistic_encrypt_strong_keys =
468 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
469 if (the_strong_valid_key)
470 {
471 pgp_remove_key(&matches, the_strong_valid_key);
472 k = the_strong_valid_key;
473 }
474 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
475 {
476 pgp_remove_key(&matches, a_valid_addrmatch_key);
477 k = a_valid_addrmatch_key;
478 }
479 else
480 {
481 k = NULL;
482 }
483 }
484 else if (the_strong_valid_key && !multi)
485 {
486 /* There was precisely one strong match on a valid ID.
487 * Proceed without asking the user. */
488 pgp_remove_key(&matches, the_strong_valid_key);
489 k = the_strong_valid_key;
490 }
491 else
492 {
493 /* Else: Ask the user. */
494 k = dlg_pgp(matches, a, NULL);
495 if (k)
496 pgp_remove_key(&matches, k);
497 }
498
499 pgp_key_free(&matches);
500
501 return k;
502 }
503
504 return NULL;
505}
506
514struct PgpKeyInfo *pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
515{
516 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
517 struct PgpKeyInfo *keys = NULL;
518 struct PgpKeyInfo *matches = NULL;
519 struct PgpKeyInfo **last = &matches;
520 struct PgpKeyInfo *k = NULL, *kn = NULL;
521 struct PgpUid *a = NULL;
522 size_t l;
523 const char *ps = NULL, *pl = NULL, *pfcopy = NULL, *phint = NULL;
524
525 char *p = strdup(cp); // mutt_str_dup converts "" into NULL, see #1809
526 l = mutt_str_len(p);
527 if ((l > 0) && (p[l - 1] == '!'))
528 p[l - 1] = 0;
529
530 mutt_message(_("Looking for keys matching \"%s\"..."), p);
531
532 pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
533 pgp_add_string_to_hints(phint, &hints);
534 keys = pgp_get_candidates(keyring, &hints);
535 mutt_list_free(&hints);
536
537 for (k = keys; k; k = kn)
538 {
539 kn = k->next;
540 if (abilities && !(k->flags & abilities))
541 continue;
542
543 /* This shouldn't happen, but keys without any addresses aren't selectable
544 * in dlg_pgp(). */
545 if (!k->address)
546 continue;
547
548 bool match = false;
549
550 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s:\n", p, pgp_long_keyid(k));
551
552 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, k->fingerprint)) ||
553 (pl && mutt_istr_equal(pl, pgp_long_keyid(k))) ||
554 (ps && mutt_istr_equal(ps, pgp_short_keyid(k))))
555 {
556 mutt_debug(LL_DEBUG5, " match #1\n");
557 match = true;
558 }
559 else
560 {
561 for (a = k->address; a; a = a->next)
562 {
563 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\":\n", p,
564 pgp_long_keyid(k), NONULL(a->addr));
565 if (mutt_istr_find(a->addr, p))
566 {
567 mutt_debug(LL_DEBUG5, " match #2\n");
568 match = true;
569 break;
570 }
571 }
572 }
573
574 if (match)
575 {
576 *last = pgp_principal_key(k);
577 kn = pgp_remove_key(&keys, *last);
578 last = pgp_get_lastp(k);
579 }
580 }
581
582 pgp_key_free(&keys);
583
584 k = NULL;
585 if (matches)
586 {
587 if (isatty(STDIN_FILENO))
588 {
589 k = dlg_pgp(matches, NULL, p);
590 if (k)
591 pgp_remove_key(&matches, k);
592 pgp_key_free(&matches);
593 }
594 else if (pgp_keys_are_valid(matches))
595 {
596 k = matches;
597 }
598 else
599 {
600 mutt_error(_("A key can't be used: expired/disabled/revoked"));
601 }
602 }
603
604 FREE(&pfcopy);
605 FREE(&p);
606 return k;
607}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
Email Address Handling.
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:696
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1275
Signing/encryption multiplexor.
Edit a string.
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:44
Structs that make up an email.
#define mutt_file_fclose(FP)
Definition: file.h:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:73
struct PgpKeyInfo * pgp_get_candidates(enum PgpRing keyring, struct ListHead *hints)
Find PGP keys matching a list of hints.
Definition: gnupgparse.c:418
Parse the output of CLI PGP programinclude "pgpkey.h".
struct Body * pgp_class_make_key_attachment(void)
Generate a public key attachment - Implements CryptModuleSpecs::pgp_make_key_attachment() -.
Definition: pgpkey.c:258
struct PgpKeyInfo * dlg_pgp(struct PgpKeyInfo *keys, struct Address *p, const char *s)
Let the user select a key to use -.
Definition: dlg_pgp.c:629
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:45
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:666
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:515
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:490
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define KEYFLAG_SUBKEY
Key is a subkey.
Definition: lib.h:134
#define KEYFLAG_CANTUSE
Definition: lib.h:139
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:126
char * pgp_long_keyid(struct PgpKeyInfo *k)
Get a key's long id.
Definition: pgp.c:165
char * pgp_keyid(struct PgpKeyInfo *k)
Get the ID of the main (parent) key.
Definition: pgp.c:204
char * pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
Get the fingerprint or long keyid.
Definition: pgp.c:234
char * pgp_short_keyid(struct PgpKeyInfo *k)
Get a key's short id.
Definition: pgp.c:177
PGP sign, encrypt, check routines.
pid_t pgp_invoke_export(FILE **fp_pgp_in, FILE **fp_pgp_out, FILE **fp_pgp_err, int fd_pgp_in, int fd_pgp_out, int fd_pgp_err, const char *uids)
Use PGP to export a key from the user's keyring.
Definition: pgpinvoke.c:442
Wrapper around calls to external PGP program.
bool pgp_id_is_valid(struct PgpUid *uid)
Is a PGP key valid.
Definition: pgpkey.c:148
#define PGP_KV_NO_FLAGS
No flags are set.
Definition: pgpkey.c:77
#define PGP_KV_STRONGID
PGP Key is strong.
Definition: pgpkey.c:81
static void pgp_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: pgpkey.c:338
#define PGP_KV_MATCH
Definition: pgpkey.c:84
static PgpKeyValidFlags pgp_id_matches_addr(struct Address *addr, struct Address *u_addr, struct PgpUid *uid)
Does the key ID match the address.
Definition: pgpkey.c:165
struct PgpKeyInfo * pgp_ask_for_key(char *tag, const char *whatfor, KeyFlags abilities, enum PgpRing keyring)
Ask the user for a PGP key.
Definition: pgpkey.c:198
#define PGP_KV_VALID
PGP Key ID is valid.
Definition: pgpkey.c:78
#define PGP_KV_STRING
PGP Key name string is valid.
Definition: pgpkey.c:80
#define PGP_KV_ADDR
PGP Key address is valid.
Definition: pgpkey.c:79
bool pgp_keys_are_valid(struct PgpKeyInfo *keys)
Are all these PGP keys valid?
Definition: pgpkey.c:119
static struct PgpKeyInfo ** pgp_get_lastp(struct PgpKeyInfo *p)
Get the last PGP key in a list.
Definition: pgpkey.c:358
static struct PgpCache * IdDefaults
Cache of GPGME keys.
Definition: pgpkey.c:73
bool pgp_id_is_strong(struct PgpUid *uid)
Is a PGP key strong?
Definition: pgpkey.c:135
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition: pgpkey.c:375
bool pgp_key_is_valid(struct PgpKeyInfo *k)
Is a PGP key valid?
Definition: pgpkey.c:103
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition: pgpkey.c:514
uint8_t PgpKeyValidFlags
Flags for valid Pgp Key fields, e.g. PGP_KV_VALID.
Definition: pgpkey.c:76
struct PgpKeyInfo * pgp_principal_key(struct PgpKeyInfo *key)
Get the main (parent) PGP key.
Definition: pgpkey.c:91
PGP key management routines.
PgpRing
PGP ring type.
Definition: pgpkey.h:38
@ PGP_PUBRING
Public keys.
Definition: pgpkey.h:39
void pgp_key_free(struct PgpKeyInfo **kpp)
Free a PGP key info.
Definition: pgplib.c:201
struct PgpKeyInfo * pgp_remove_key(struct PgpKeyInfo **klist, struct PgpKeyInfo *key)
Remove a PGP key from a list.
Definition: pgplib.c:169
Misc PGP helper routines.
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:421
GUI display the mailboxes in a side panel.
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
The body of an email.
Definition: body.h:36
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
char * description
content-description
Definition: body.h:55
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
List of cached PGP keys.
Definition: pgpkey.c:66
char * dflt
Definition: pgpkey.c:68
struct PgpCache * next
Linked list.
Definition: pgpkey.c:69
char * what
Definition: pgpkey.c:67
Information about a PGP key.
Definition: pgplib.h:47
KeyFlags flags
Definition: pgplib.h:51
struct PgpKeyInfo * next
Definition: pgplib.h:57
struct PgpUid * address
Definition: pgplib.h:50
char * fingerprint
Definition: pgplib.h:49
struct PgpKeyInfo * parent
Definition: pgplib.h:56
PGP User ID.
Definition: pgplib.h:35
short trust
Definition: pgplib.h:37
struct PgpKeyInfo * parent
Parent key.
Definition: pgplib.h:39
int flags
Definition: pgplib.h:38
char * addr
Definition: pgplib.h:36
struct PgpUid * next
Linked list.
Definition: pgplib.h:40
#define buf_mktemp(buf)
Definition: tmp.h:33