NeoMutt  2024-11-14-34-g5aaf0d
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 <sys/types.h>
40#include <unistd.h>
41#include "private.h"
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "mutt.h"
48#include "pgpkey.h"
49#include "lib.h"
50#include "editor/lib.h"
51#include "history/lib.h"
52#include "send/lib.h"
53#include "crypt.h"
54#include "globals.h"
55#include "gnupgparse.h"
56#include "mutt_logging.h"
57#include "pgpinvoke.h"
58#ifdef CRYPT_BACKEND_CLASSIC_PGP
59#include "pgp.h"
60#include "pgplib.h"
61#endif
62
67{
68 char *what;
69 char *dflt;
70 struct PgpCache *next;
71};
72
74static struct PgpCache *IdDefaults = NULL;
75
76// clang-format off
77typedef uint8_t PgpKeyValidFlags;
78#define PGP_KV_NO_FLAGS 0
79#define PGP_KV_VALID (1 << 0)
80#define PGP_KV_ADDR (1 << 1)
81#define PGP_KV_STRING (1 << 2)
82#define PGP_KV_STRONGID (1 << 3)
83// clang-format on
84
85#define PGP_KV_MATCH (PGP_KV_ADDR | PGP_KV_STRING)
86
93{
94 if (key->flags & KEYFLAG_SUBKEY && key->parent)
95 return key->parent;
96 return key;
97}
98
105{
106 struct PgpKeyInfo *pk = pgp_principal_key(k);
107 if (k->flags & KEYFLAG_CANTUSE)
108 return false;
109 if (pk->flags & KEYFLAG_CANTUSE)
110 return false;
111
112 return true;
113}
114
121{
122 for (struct PgpKeyInfo *k = keys; k != NULL; k = k->next)
123 {
124 if (!pgp_key_is_valid(k))
125 return false;
126 }
127
128 return true;
129}
130
136bool pgp_id_is_strong(struct PgpUid *uid)
137{
138 if ((uid->trust & 3) < 3)
139 return false;
140 /* else */
141 return true;
142}
143
149bool pgp_id_is_valid(struct PgpUid *uid)
150{
151 if (!pgp_key_is_valid(uid->parent))
152 return false;
153 if (uid->flags & KEYFLAG_CANTUSE)
154 return false;
155 /* else */
156 return true;
157}
158
167 struct Address *u_addr, struct PgpUid *uid)
168{
170
171 if (pgp_id_is_valid(uid))
173
174 if (pgp_id_is_strong(uid))
176
177 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
178 {
180 }
181
182 if (addr->personal && u_addr->personal &&
183 buf_istr_equal(addr->personal, u_addr->personal))
184 {
186 }
187
188 return flags;
189}
190
199struct PgpKeyInfo *pgp_ask_for_key(char *tag, const char *whatfor,
200 KeyFlags abilities, enum PgpRing keyring)
201{
202 struct PgpKeyInfo *key = NULL;
203 struct PgpCache *l = NULL;
204 struct Buffer *resp = buf_pool_get();
205
207
208 if (whatfor)
209 {
210 for (l = IdDefaults; l; l = l->next)
211 {
212 if (mutt_istr_equal(whatfor, l->what))
213 {
214 buf_strcpy(resp, l->dflt);
215 break;
216 }
217 }
218 }
219
220 while (true)
221 {
222 buf_reset(resp);
223 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
224 {
225 goto done;
226 }
227
228 if (whatfor)
229 {
230 if (l)
231 {
232 mutt_str_replace(&l->dflt, buf_string(resp));
233 }
234 else
235 {
236 l = MUTT_MEM_MALLOC(1, struct PgpCache);
237 l->next = IdDefaults;
238 IdDefaults = l;
239 l->what = mutt_str_dup(whatfor);
240 l->dflt = buf_strdup(resp);
241 }
242 }
243
244 key = pgp_getkeybystr(buf_string(resp), abilities, keyring);
245 if (key)
246 goto done;
247
248 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
249 }
250
251done:
252 buf_pool_release(&resp);
253 return key;
254}
255
260{
261 struct Body *att = NULL;
262 char buf[1024] = { 0 };
263 char tmp[256] = { 0 };
264 struct stat st = { 0 };
265 pid_t pid;
266 OptPgpCheckTrust = false;
267 struct Buffer *tempf = NULL;
268
269 struct PgpKeyInfo *key = pgp_ask_for_key(_("Please enter the key ID: "), NULL,
271
272 if (!key)
273 return NULL;
274
275 snprintf(tmp, sizeof(tmp), "0x%s", pgp_fpr_or_lkeyid(pgp_principal_key(key)));
276 pgp_key_free(&key);
277
278 tempf = buf_pool_get();
279 buf_mktemp(tempf);
280 FILE *fp_tmp = mutt_file_fopen(buf_string(tempf), "w");
281 if (!fp_tmp)
282 {
283 mutt_perror(_("Can't create temporary file"));
284 goto cleanup;
285 }
286
287 FILE *fp_null = mutt_file_fopen("/dev/null", "w");
288 if (!fp_null)
289 {
290 mutt_perror(_("Can't open /dev/null"));
291 mutt_file_fclose(&fp_tmp);
292 unlink(buf_string(tempf));
293 goto cleanup;
294 }
295
296 mutt_message(_("Invoking PGP..."));
297
298 pid = pgp_invoke_export(NULL, NULL, NULL, -1, fileno(fp_tmp), fileno(fp_null), tmp);
299 if (pid == -1)
300 {
301 mutt_perror(_("Can't create filter"));
302 unlink(buf_string(tempf));
303 mutt_file_fclose(&fp_tmp);
304 mutt_file_fclose(&fp_null);
305 goto cleanup;
306 }
307
308 filter_wait(pid);
309
310 mutt_file_fclose(&fp_tmp);
311 mutt_file_fclose(&fp_null);
312
313 att = mutt_body_new();
314 att->filename = buf_strdup(tempf);
315 att->unlink = true;
316 att->use_disp = false;
317 att->type = TYPE_APPLICATION;
318 att->subtype = mutt_str_dup("pgp-keys");
319 snprintf(buf, sizeof(buf), _("PGP Key %s"), tmp);
320 att->description = mutt_str_dup(buf);
322
323 stat(buf_string(tempf), &st);
324 att->length = st.st_size;
325
326cleanup:
327 buf_pool_release(&tempf);
328 return att;
329}
330
339static void pgp_add_string_to_hints(const char *str, struct ListHead *hints)
340{
341 char *scratch = mutt_str_dup(str);
342 if (!scratch)
343 return;
344
345 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
346 {
347 if (strlen(t) > 3)
349 }
350
351 FREE(&scratch);
352}
353
359static struct PgpKeyInfo **pgp_get_lastp(struct PgpKeyInfo *p)
360{
361 for (; p; p = p->next)
362 if (!p->next)
363 return &p->next;
364
365 return NULL;
366}
367
376struct PgpKeyInfo *pgp_getkeybyaddr(struct Address *a, KeyFlags abilities,
377 enum PgpRing keyring, bool oppenc_mode)
378{
379 if (!a)
380 return NULL;
381
382 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
383
384 bool multi = false;
385
386 struct PgpKeyInfo *keys = NULL, *k = NULL, *kn = NULL;
387 struct PgpKeyInfo *the_strong_valid_key = NULL;
388 struct PgpKeyInfo *a_valid_addrmatch_key = NULL;
389 struct PgpKeyInfo *matches = NULL;
390 struct PgpKeyInfo **last = &matches;
391 struct PgpUid *q = NULL;
392
393 if (a->mailbox)
395 if (a->personal)
397
398 if (!oppenc_mode)
399 mutt_message(_("Looking for keys matching \"%s\"..."), buf_string(a->mailbox));
400 keys = pgp_get_candidates(keyring, &hints);
401
402 mutt_list_free(&hints);
403
404 if (!keys)
405 return NULL;
406
407 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", buf_string(a->personal),
408 buf_string(a->mailbox));
409
410 for (k = keys; k; k = kn)
411 {
412 kn = k->next;
413
414 mutt_debug(LL_DEBUG5, " looking at key: %s\n", pgp_keyid(k));
415
416 if (abilities && !(k->flags & abilities))
417 {
418 mutt_debug(LL_DEBUG3, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
419 continue;
420 }
421
422 bool match = false; /* any match */
423
424 for (q = k->address; q; q = q->next)
425 {
426 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
428 struct Address *qa = NULL;
429 TAILQ_FOREACH(qa, &al, entries)
430 {
431 PgpKeyValidFlags validity = pgp_id_matches_addr(a, qa, q);
432
433 if (validity & PGP_KV_MATCH) /* something matches */
434 match = true;
435
436 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_ADDR))
437 {
438 if (validity & PGP_KV_STRONGID)
439 {
440 if (the_strong_valid_key && (the_strong_valid_key != k))
441 multi = true;
442 the_strong_valid_key = k;
443 }
444 else
445 {
446 a_valid_addrmatch_key = k;
447 }
448 }
449 }
450
452 }
453
454 if (match)
455 {
456 *last = pgp_principal_key(k);
457 kn = pgp_remove_key(&keys, *last);
458 last = pgp_get_lastp(k);
459 }
460 }
461
462 pgp_key_free(&keys);
463
464 if (matches)
465 {
466 if (oppenc_mode || !isatty(STDIN_FILENO))
467 {
468 const bool c_crypt_opportunistic_encrypt_strong_keys =
469 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
470 if (the_strong_valid_key)
471 {
472 pgp_remove_key(&matches, the_strong_valid_key);
473 k = the_strong_valid_key;
474 }
475 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
476 {
477 pgp_remove_key(&matches, a_valid_addrmatch_key);
478 k = a_valid_addrmatch_key;
479 }
480 else
481 {
482 k = NULL;
483 }
484 }
485 else if (the_strong_valid_key && !multi)
486 {
487 /* There was precisely one strong match on a valid ID.
488 * Proceed without asking the user. */
489 pgp_remove_key(&matches, the_strong_valid_key);
490 k = the_strong_valid_key;
491 }
492 else
493 {
494 /* Else: Ask the user. */
495 k = dlg_pgp(matches, a, NULL);
496 if (k)
497 pgp_remove_key(&matches, k);
498 }
499
500 pgp_key_free(&matches);
501
502 return k;
503 }
504
505 return NULL;
506}
507
515struct PgpKeyInfo *pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
516{
517 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
518 struct PgpKeyInfo *keys = NULL;
519 struct PgpKeyInfo *matches = NULL;
520 struct PgpKeyInfo **last = &matches;
521 struct PgpKeyInfo *k = NULL, *kn = NULL;
522 struct PgpUid *a = NULL;
523 size_t l;
524 const char *ps = NULL, *pl = NULL, *pfcopy = NULL, *phint = NULL;
525
526 char *p = strdup(cp); // mutt_str_dup converts "" into NULL, see #1809
527 l = mutt_str_len(p);
528 if ((l > 0) && (p[l - 1] == '!'))
529 p[l - 1] = 0;
530
531 mutt_message(_("Looking for keys matching \"%s\"..."), p);
532
533 pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
534 pgp_add_string_to_hints(phint, &hints);
535 keys = pgp_get_candidates(keyring, &hints);
536 mutt_list_free(&hints);
537
538 for (k = keys; k; k = kn)
539 {
540 kn = k->next;
541 if (abilities && !(k->flags & abilities))
542 continue;
543
544 /* This shouldn't happen, but keys without any addresses aren't selectable
545 * in dlg_pgp(). */
546 if (!k->address)
547 continue;
548
549 bool match = false;
550
551 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s:\n", p, pgp_long_keyid(k));
552
553 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, k->fingerprint)) ||
554 (pl && mutt_istr_equal(pl, pgp_long_keyid(k))) ||
555 (ps && mutt_istr_equal(ps, pgp_short_keyid(k))))
556 {
557 mutt_debug(LL_DEBUG5, " match #1\n");
558 match = true;
559 }
560 else
561 {
562 for (a = k->address; a; a = a->next)
563 {
564 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\":\n", p,
565 pgp_long_keyid(k), NONULL(a->addr));
566 if (mutt_istr_find(a->addr, p))
567 {
568 mutt_debug(LL_DEBUG5, " match #2\n");
569 match = true;
570 break;
571 }
572 }
573 }
574
575 if (match)
576 {
577 *last = pgp_principal_key(k);
578 kn = pgp_remove_key(&keys, *last);
579 last = pgp_get_lastp(k);
580 }
581 }
582
583 pgp_key_free(&keys);
584
585 k = NULL;
586 if (matches)
587 {
588 if (isatty(STDIN_FILENO))
589 {
590 k = dlg_pgp(matches, NULL, p);
591 if (k)
592 pgp_remove_key(&matches, k);
593 pgp_key_free(&matches);
594 }
595 else if (pgp_keys_are_valid(matches))
596 {
597 k = matches;
598 }
599 else
600 {
601 mutt_error(_("A key can't be used: expired/disabled/revoked"));
602 }
603 }
604
605 FREE(&pfcopy);
606 FREE(&p);
607 return k;
608}
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:697
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
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:47
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:1385
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:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:70
struct PgpKeyInfo * pgp_get_candidates(enum PgpRing keyring, struct ListHead *hints)
Find PGP keys matching a list of hints.
Definition: gnupgparse.c:419
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:259
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:613
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:59
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_MALLOC(n, type)
Definition: memory.h:41
@ 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:672
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:521
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
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:149
#define PGP_KV_NO_FLAGS
No flags are set.
Definition: pgpkey.c:78
#define PGP_KV_STRONGID
PGP Key is strong.
Definition: pgpkey.c:82
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:339
#define PGP_KV_MATCH
Definition: pgpkey.c:85
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:166
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:199
#define PGP_KV_VALID
PGP Key ID is valid.
Definition: pgpkey.c:79
#define PGP_KV_STRING
PGP Key name string is valid.
Definition: pgpkey.c:81
#define PGP_KV_ADDR
PGP Key address is valid.
Definition: pgpkey.c:80
bool pgp_keys_are_valid(struct PgpKeyInfo *keys)
Are all these PGP keys valid?
Definition: pgpkey.c:120
static struct PgpKeyInfo ** pgp_get_lastp(struct PgpKeyInfo *p)
Get the last PGP key in a list.
Definition: pgpkey.c:359
static struct PgpCache * IdDefaults
Cache of GPGME keys.
Definition: pgpkey.c:74
bool pgp_id_is_strong(struct PgpUid *uid)
Is a PGP key strong?
Definition: pgpkey.c:136
struct PgpKeyInfo * pgp_getkeybyaddr(struct Address *a, KeyFlags abilities, enum PgpRing keyring, bool oppenc_mode)
Find a PGP key by address.
Definition: pgpkey.c:376
bool pgp_key_is_valid(struct PgpKeyInfo *k)
Is a PGP key valid?
Definition: pgpkey.c:104
struct PgpKeyInfo * pgp_getkeybystr(const char *cp, KeyFlags abilities, enum PgpRing keyring)
Find a PGP key by string.
Definition: pgpkey.c:515
uint8_t PgpKeyValidFlags
Flags for valid Pgp Key fields, e.g. PGP_KV_VALID.
Definition: pgpkey.c:77
struct PgpKeyInfo * pgp_principal_key(struct PgpKeyInfo *key)
Get the main (parent) PGP key.
Definition: pgpkey.c:92
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:422
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:68
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:61
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:59
String manipulation buffer.
Definition: buffer.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
List of cached PGP keys.
Definition: pgpkey.c:67
char * dflt
Definition: pgpkey.c:69
struct PgpCache * next
Linked list.
Definition: pgpkey.c:70
char * what
Definition: pgpkey.c:68
Information about a PGP key.
Definition: pgplib.h:48
KeyFlags flags
Definition: pgplib.h:52
struct PgpKeyInfo * next
Definition: pgplib.h:58
struct PgpUid * address
Definition: pgplib.h:51
char * fingerprint
Definition: pgplib.h:50
struct PgpKeyInfo * parent
Definition: pgplib.h:57
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