NeoMutt  2024-03-23-23-gec7045
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
autocrypt.c File Reference

Autocrypt end-to-end encryption. More...

#include "config.h"
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "lib.h"
#include "browser/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "muttlib.h"
#include "mx.h"
+ Include dependency graph for autocrypt.c:

Go to the source code of this file.

Functions

static int autocrypt_dir_init (bool can_create)
 Initialise an Autocrypt directory.
 
int mutt_autocrypt_init (bool can_create)
 Initialise Autocrypt.
 
void mutt_autocrypt_cleanup (void)
 Shutdown Autocrypt.
 
int mutt_autocrypt_account_init (bool prompt)
 Create a new Autocrypt account.
 
int mutt_autocrypt_process_autocrypt_header (struct Email *e, struct Envelope *env)
 Parse an Autocrypt email header.
 
int mutt_autocrypt_process_gossip_header (struct Email *e, struct Envelope *prot_headers)
 Parse an Autocrypt email gossip header.
 
enum AutocryptRec mutt_autocrypt_ui_recommendation (const struct Email *e, char **keylist)
 Get the recommended action for an Email.
 
int mutt_autocrypt_set_sign_as_default_key (struct Email *e)
 Set the Autocrypt default key for signing.
 
static void write_autocrypt_header_line (FILE *fp, const char *addr, bool prefer_encrypt, const char *keydata)
 Write an Autocrypt header to a file.
 
int mutt_autocrypt_write_autocrypt_header (struct Envelope *env, FILE *fp)
 Write the Autocrypt header to a file.
 
int mutt_autocrypt_write_gossip_headers (struct Envelope *env, FILE *fp)
 Write the Autocrypt gossip headers to a file.
 
int mutt_autocrypt_generate_gossip_list (struct Email *e)
 Create the gossip list headers.
 
void mutt_autocrypt_scan_mailboxes (void)
 Scan mailboxes for Autocrypt headers.
 

Detailed Description

Autocrypt end-to-end encryption.

Authors
  • Kevin J. McCarthy
  • Richard Russon
  • Pietro Cerutti
  • Anna Figueiredo Gomes

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file autocrypt.c.

Function Documentation

◆ autocrypt_dir_init()

static int autocrypt_dir_init ( bool  can_create)
static

Initialise an Autocrypt directory.

Parameters
can_createIf true, the directory may be created
Return values
0Success
-1Error

Definition at line 61 of file autocrypt.c.

62{
63 int rc = 0;
64 struct stat st = { 0 };
65
66 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
67 if (stat(c_autocrypt_dir, &st) == 0)
68 return 0;
69
70 if (!can_create)
71 return -1;
72
73 struct Buffer *prompt = buf_pool_get();
74 /* L10N: s is a directory. NeoMutt is looking for a directory it needs
75 for some reason (e.g. autocrypt, header cache, bcache), but it
76 doesn't exist. The prompt is asking whether to create the directory */
77 buf_printf(prompt, _("%s does not exist. Create it?"), c_autocrypt_dir);
79 {
80 if (mutt_file_mkdir(c_autocrypt_dir, S_IRWXU) < 0)
81 {
82 /* L10N: mkdir() on the directory %s failed. The second %s is the
83 error message returned by libc */
84 mutt_error(_("Can't create %s: %s"), c_autocrypt_dir, strerror(errno));
85 rc = -1;
86 }
87 }
88
89 buf_pool_release(&prompt);
90 return rc;
91}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:178
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:1015
#define mutt_error(...)
Definition: logging2.h:92
#define _(a)
Definition: message.h:28
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
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:327
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_init()

int mutt_autocrypt_init ( bool  can_create)

Initialise Autocrypt.

Parameters
can_createIf true, directories may be created
Return values
0Success
-1Error

Definition at line 99 of file autocrypt.c.

100{
101 if (AutocryptDB)
102 return 0;
103
104 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
105 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
106 if (!c_autocrypt || !c_autocrypt_dir)
107 return -1;
108
110
111 if (autocrypt_dir_init(can_create))
112 goto bail;
113
115 goto bail;
116
117 if (mutt_autocrypt_db_init(can_create))
118 goto bail;
119
120 return 0;
121
122bail:
123 cs_subset_str_native_set(NeoMutt->sub, "autocrypt", false, NULL);
125 return -1;
126}
void mutt_autocrypt_db_close(void)
Close the Autocrypt SQLite database connection.
Definition: db.c:133
sqlite3 * AutocryptDB
Handle to the open Autocrypt database.
Definition: db.c:56
int mutt_autocrypt_db_init(bool can_create)
Initialise the Autocrypt SQLite database.
Definition: db.c:83
static int autocrypt_dir_init(bool can_create)
Initialise an Autocrypt directory.
Definition: autocrypt.c:61
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
int mutt_autocrypt_gpgme_init(void)
Initialise GPGME.
Definition: gpgme.c:69
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:297
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_cleanup()

void mutt_autocrypt_cleanup ( void  )

Shutdown Autocrypt.

Definition at line 131 of file autocrypt.c.

132{
134}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_account_init()

int mutt_autocrypt_account_init ( bool  prompt)

Create a new Autocrypt account.

Parameters
promptPrompt the user
Return values
0Success
-1Error

This is used the first time autocrypt is initialized, and in the account menu.

Definition at line 145 of file autocrypt.c.

146{
147 struct Address *addr = NULL;
148 struct AutocryptAccount *account = NULL;
149 bool done = false;
150 int rc = -1;
151 bool prefer_encrypt = false;
152
153 if (prompt)
154 {
155 /* L10N: The first time NeoMutt is started with $autocrypt set, it will
156 create $autocrypt_dir and then prompt to create an autocrypt account
157 with this message. */
158 if (query_yesorno(_("Create an initial autocrypt account?"), MUTT_YES) != MUTT_YES)
159 return 0;
160 }
161
162 struct Buffer *keyid = buf_pool_get();
163 struct Buffer *keydata = buf_pool_get();
164
165 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
166 if (c_from)
167 {
168 addr = mutt_addr_copy(c_from);
169 const char *const c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
170 if (!addr->personal && c_real_name)
171 addr->personal = buf_new(c_real_name);
172 }
173
174 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
175 mutt_addrlist_append(&al, addr);
176
177 do
178 {
179 /* L10N: Autocrypt is asking for the email address to use for the
180 autocrypt account. This will generate a key and add a record
181 to the database for use in autocrypt operations. */
182 if (mutt_edit_address(&al, _("Autocrypt account address: "), false) != 0)
183 goto cleanup;
184
185 addr = TAILQ_FIRST(&al);
186 if (!addr || !addr->mailbox || TAILQ_NEXT(addr, entries))
187 {
188 /* L10N: Autocrypt prompts for an account email address, and requires
189 a single address. This is shown if they entered something invalid,
190 nothing, or more than one address for some reason. */
191 mutt_error(_("Please enter a single email address"));
192 done = false;
193 }
194 else
195 {
196 done = true;
197 }
198 } while (!done);
199
200 addr = TAILQ_FIRST(&al);
201 if (mutt_autocrypt_db_account_get(addr, &account) < 0)
202 goto cleanup;
203 if (account)
204 {
205 /* L10N: When creating an autocrypt account, this message will be displayed
206 if there is already an account in the database with the email address
207 they just entered. */
208 mutt_error(_("That email address already has an autocrypt account"));
209 goto cleanup;
210 }
211
212 if (mutt_autocrypt_gpgme_select_or_create_key(addr, keyid, keydata))
213 goto cleanup;
214
215 /* L10N: Autocrypt has a setting "prefer-encrypt".
216 When the recommendation algorithm returns "available" and BOTH sender and
217 recipient choose "prefer-encrypt", encryption will be automatically
218 enabled.
219 Otherwise the UI will show encryption is "available" but the user
220 will be required to enable encryption manually. */
221 if (query_yesorno(_("Prefer encryption?"), MUTT_NO) == MUTT_YES)
222 prefer_encrypt = true;
223
224 if (mutt_autocrypt_db_account_insert(addr, buf_string(keyid), buf_string(keydata), prefer_encrypt))
225 {
226 goto cleanup;
227 }
228
229 rc = 0;
230
231cleanup:
232 if (rc == 0)
233 {
234 /* L10N: Message displayed after an autocrypt account is successfully created. */
235 mutt_message(_("Autocrypt account creation succeeded"));
236 }
237 else
238 {
239 /* L10N: Error message displayed if creating an autocrypt account failed
240 or was aborted by the user. */
241 mutt_error(_("Autocrypt account creation aborted"));
242 }
243
246 buf_pool_release(&keyid);
247 buf_pool_release(&keydata);
248 return rc;
249}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1464
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1484
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:745
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:273
int mutt_autocrypt_db_account_get(struct Address *addr, struct AutocryptAccount **account)
Get Autocrypt Account data from the database.
Definition: db.c:266
int mutt_autocrypt_db_account_insert(struct Address *addr, const char *keyid, const char *keydata, bool prefer_encrypt)
Insert an Account into the Autocrypt database.
Definition: db.c:328
void mutt_autocrypt_db_account_free(struct AutocryptAccount **ptr)
Free an AutocryptAccount.
Definition: db.c:247
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:321
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
int mutt_autocrypt_gpgme_select_or_create_key(struct Address *addr, struct Buffer *keyid, struct Buffer *keydata)
Ask the user to select or create an Autocrypt key.
Definition: gpgme.c:278
#define mutt_message(...)
Definition: logging2.h:91
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition: send.c:193
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
Autocrypt account.
Definition: lib.h:107
bool prefer_encrypt
false = nopref, true = mutual
Definition: lib.h:111
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_process_autocrypt_header()

int mutt_autocrypt_process_autocrypt_header ( struct Email e,
struct Envelope env 
)

Parse an Autocrypt email header.

Parameters
eEmail
envEnvelope
Return values
0Success
-1Error

Definition at line 258 of file autocrypt.c.

259{
260 struct AutocryptHeader *valid_ac_hdr = NULL;
261 struct AutocryptPeer *peer = NULL;
262 struct AutocryptPeerHistory *peerhist = NULL;
263 struct Buffer *keyid = NULL;
264 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
265 int rc = -1;
266
267 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
268 if (!c_autocrypt)
269 return 0;
270
271 if (mutt_autocrypt_init(false))
272 return -1;
273
274 if (!e || !e->body || !env)
275 return 0;
276
277 /* 1.1 spec says to skip emails with more than one From header */
278 struct Address *from = TAILQ_FIRST(&env->from);
279 if (!from || TAILQ_NEXT(from, entries))
280 return 0;
281
282 /* 1.1 spec also says to skip multipart/report emails */
283 if ((e->body->type == TYPE_MULTIPART) && mutt_istr_equal(e->body->subtype, "report"))
284 {
285 return 0;
286 }
287
288 /* Ignore emails that appear to be more than a week in the future,
289 * since they can block all future updates during that time. */
290 if (e->date_sent > (mutt_date_now() + (7 * 24 * 60 * 60)))
291 return 0;
292
293 for (struct AutocryptHeader *ac_hdr = env->autocrypt; ac_hdr; ac_hdr = ac_hdr->next)
294 {
295 if (ac_hdr->invalid)
296 continue;
297
298 /* NOTE: this assumes the processing is occurring right after
299 * mutt_parse_rfc822_line() and the from ADDR is still in the same
300 * form (intl) as the autocrypt header addr field */
301 if (!mutt_istr_equal(buf_string(from->mailbox), ac_hdr->addr))
302 continue;
303
304 /* 1.1 spec says ignore all, if more than one valid header is found. */
305 if (valid_ac_hdr)
306 {
307 valid_ac_hdr = NULL;
308 break;
309 }
310 valid_ac_hdr = ac_hdr;
311 }
312
313 if (mutt_autocrypt_db_peer_get(from, &peer) < 0)
314 goto cleanup;
315
316 if (peer)
317 {
318 if (e->date_sent <= peer->autocrypt_timestamp)
319 {
320 rc = 0;
321 goto cleanup;
322 }
323
324 if (e->date_sent > peer->last_seen)
325 {
326 update_db = true;
327 peer->last_seen = e->date_sent;
328 }
329
330 if (valid_ac_hdr)
331 {
332 update_db = true;
334 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
335 if (!mutt_str_equal(peer->keydata, valid_ac_hdr->keydata))
336 {
337 import_gpg = true;
338 insert_db_history = true;
339 mutt_str_replace(&peer->keydata, valid_ac_hdr->keydata);
340 }
341 }
342 }
343 else if (valid_ac_hdr)
344 {
345 import_gpg = true;
346 insert_db = true;
347 insert_db_history = true;
348 }
349
350 if (!(import_gpg || insert_db || update_db))
351 {
352 rc = 0;
353 goto cleanup;
354 }
355
356 if (!peer)
357 {
359 peer->last_seen = e->date_sent;
361 peer->keydata = mutt_str_dup(valid_ac_hdr->keydata);
362 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
363 }
364
365 if (import_gpg)
366 {
367 keyid = buf_pool_get();
369 goto cleanup;
370 mutt_str_replace(&peer->keyid, buf_string(keyid));
371 }
372
373 if (insert_db && mutt_autocrypt_db_peer_insert(from, peer))
374 goto cleanup;
375
376 if (update_db && mutt_autocrypt_db_peer_update(peer))
377 goto cleanup;
378
379 if (insert_db_history)
380 {
382 peerhist->email_msgid = mutt_str_dup(env->message_id);
383 peerhist->timestamp = e->date_sent;
384 peerhist->keydata = mutt_str_dup(peer->keydata);
385 if (mutt_autocrypt_db_peer_history_insert(from, peerhist))
386 goto cleanup;
387 }
388
389 rc = 0;
390
391cleanup:
394 buf_pool_release(&keyid);
395
396 return rc;
397}
struct AutocryptPeer * mutt_autocrypt_db_peer_new(void)
Create a new AutocryptPeer.
Definition: db.c:528
int mutt_autocrypt_db_peer_insert(struct Address *addr, struct AutocryptPeer *peer)
Insert a peer into the Autocrypt database.
Definition: db.c:627
int mutt_autocrypt_db_peer_get(struct Address *addr, struct AutocryptPeer **peer)
Get peer info from the Autocrypt database.
Definition: db.c:559
int mutt_autocrypt_db_peer_update(struct AutocryptPeer *peer)
Update the peer info in an Autocrypt database.
Definition: db.c:693
void mutt_autocrypt_db_peer_history_free(struct AutocryptPeerHistory **ptr)
Free an AutocryptPeerHistory.
Definition: db.c:758
void mutt_autocrypt_db_peer_free(struct AutocryptPeer **ptr)
Free an AutocryptPeer.
Definition: db.c:537
struct AutocryptPeerHistory * mutt_autocrypt_db_peer_history_new(void)
Create a new AutocryptPeerHistory.
Definition: db.c:749
int mutt_autocrypt_db_peer_history_insert(struct Address *addr, struct AutocryptPeerHistory *peerhist)
Insert peer history into the Autocrypt database.
Definition: db.c:777
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:99
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
Read a key from GPGME.
Definition: gpgme.c:319
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
Parse Autocrypt header info.
Definition: envelope.h:44
struct AutocryptHeader * next
Linked list.
Definition: envelope.h:49
char * keydata
PGP Key data.
Definition: envelope.h:46
bool prefer_encrypt
User prefers encryption.
Definition: envelope.h:47
Autocrypt peer history.
Definition: lib.h:135
char * email_msgid
Message id of the email.
Definition: lib.h:137
char * keydata
PGP Key data.
Definition: lib.h:139
sqlite3_int64 timestamp
Timestamp of email.
Definition: lib.h:138
Autocrypt peer.
Definition: lib.h:119
sqlite3_int64 autocrypt_timestamp
When the email was sent.
Definition: lib.h:122
char * keyid
PGP Key id.
Definition: lib.h:123
char * keydata
PGP Key data.
Definition: lib.h:124
sqlite3_int64 last_seen
When was the peer last seen.
Definition: lib.h:121
bool prefer_encrypt
false = nopref, true = mutual
Definition: lib.h:125
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
struct Body * body
List of MIME parts.
Definition: email.h:69
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:60
char * message_id
Message ID.
Definition: envelope.h:73
struct AutocryptHeader * autocrypt
Autocrypt header.
Definition: envelope.h:87
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_process_gossip_header()

int mutt_autocrypt_process_gossip_header ( struct Email e,
struct Envelope prot_headers 
)

Parse an Autocrypt email gossip header.

Parameters
eEmail
prot_headersEnvelope with protected headers
Return values
0Success
-1Error

Definition at line 406 of file autocrypt.c.

407{
408 struct AutocryptPeer *peer = NULL;
409 struct AutocryptGossipHistory *gossip_hist = NULL;
410 struct Address *peer_addr = NULL;
411 struct Address ac_hdr_addr = { 0 };
412 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
413 int rc = -1;
414
415 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
416 if (!c_autocrypt)
417 return 0;
418
419 if (mutt_autocrypt_init(false))
420 return -1;
421
422 if (!e || !e->env || !prot_headers)
423 return 0;
424
425 struct Envelope *env = e->env;
426
427 struct Address *from = TAILQ_FIRST(&env->from);
428 if (!from)
429 return 0;
430
431 /* Ignore emails that appear to be more than a week in the future,
432 * since they can block all future updates during that time. */
433 if (e->date_sent > (mutt_date_now() + (7 * 24 * 60 * 60)))
434 return 0;
435
436 struct Buffer *keyid = buf_pool_get();
437
438 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
439
440 /* Normalize the recipient list for comparison */
441 mutt_addrlist_copy(&recips, &env->to, false);
442 mutt_addrlist_copy(&recips, &env->cc, false);
443 mutt_addrlist_copy(&recips, &env->reply_to, false);
445
446 for (struct AutocryptHeader *ac_hdr = prot_headers->autocrypt_gossip; ac_hdr;
447 ac_hdr = ac_hdr->next)
448 {
449 if (ac_hdr->invalid)
450 continue;
451
452 /* normalize for comparison against recipient list */
453 buf_strcpy(ac_hdr_addr.mailbox, ac_hdr->addr);
454 ac_hdr_addr.is_intl = true;
455 ac_hdr_addr.intl_checked = true;
457
458 /* Check to make sure the address is in the recipient list. */
459 TAILQ_FOREACH(peer_addr, &recips, entries)
460 {
461 if (buf_str_equal(peer_addr->mailbox, ac_hdr_addr.mailbox))
462 break;
463 }
464
465 if (!peer_addr)
466 continue;
467
468 if (mutt_autocrypt_db_peer_get(peer_addr, &peer) < 0)
469 goto cleanup;
470
471 if (peer)
472 {
473 if (e->date_sent <= peer->gossip_timestamp)
474 {
476 continue;
477 }
478
479 update_db = true;
480 peer->gossip_timestamp = e->date_sent;
481 /* This is slightly different from the autocrypt 1.1 spec.
482 * Avoid setting an empty peer.gossip_keydata with a value that matches
483 * the current peer.keydata. */
484 if ((peer->gossip_keydata && !mutt_str_equal(peer->gossip_keydata, ac_hdr->keydata)) ||
485 (!peer->gossip_keydata && !mutt_str_equal(peer->keydata, ac_hdr->keydata)))
486 {
487 import_gpg = true;
488 insert_db_history = true;
489 mutt_str_replace(&peer->gossip_keydata, ac_hdr->keydata);
490 }
491 }
492 else
493 {
494 import_gpg = true;
495 insert_db = true;
496 insert_db_history = true;
497 }
498
499 if (!peer)
500 {
502 peer->gossip_timestamp = e->date_sent;
503 peer->gossip_keydata = mutt_str_dup(ac_hdr->keydata);
504 }
505
506 if (import_gpg)
507 {
509 goto cleanup;
511 }
512
513 if (insert_db && mutt_autocrypt_db_peer_insert(peer_addr, peer))
514 goto cleanup;
515
516 if (update_db && mutt_autocrypt_db_peer_update(peer))
517 goto cleanup;
518
519 if (insert_db_history)
520 {
522 gossip_hist->sender_email_addr = buf_strdup(from->mailbox);
523 gossip_hist->email_msgid = mutt_str_dup(env->message_id);
524 gossip_hist->timestamp = e->date_sent;
525 gossip_hist->gossip_keydata = mutt_str_dup(peer->gossip_keydata);
526 if (mutt_autocrypt_db_gossip_history_insert(peer_addr, gossip_hist))
527 goto cleanup;
528 }
529
532 buf_reset(keyid);
533 update_db = false;
534 insert_db = false;
535 insert_db_history = false;
536 import_gpg = false;
537 }
538
539 rc = 0;
540
541cleanup:
542 FREE(&ac_hdr_addr.mailbox);
543 mutt_addrlist_clear(&recips);
546 buf_pool_release(&keyid);
547
548 return rc;
549}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
void mutt_autocrypt_db_normalize_addrlist(struct AddressList *al)
Normalise a list of Email Addresses.
Definition: db.c:179
struct AutocryptGossipHistory * mutt_autocrypt_db_gossip_history_new(void)
Create a new AutocryptGossipHistory.
Definition: db.c:830
int mutt_autocrypt_db_gossip_history_insert(struct Address *addr, struct AutocryptGossipHistory *gossip_hist)
Insert a gossip history into the Autocrypt database.
Definition: db.c:859
void mutt_autocrypt_db_normalize_addr(struct Address *a)
Normalise an Email Address.
Definition: db.c:168
void mutt_autocrypt_db_gossip_history_free(struct AutocryptGossipHistory **ptr)
Free an AutocryptGossipHistory.
Definition: db.c:839
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:702
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
#define FREE(x)
Definition: memory.h:45
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool intl_checked
Checked for IDN?
Definition: address.h:41
bool is_intl
International Domain Name.
Definition: address.h:40
Autocrypt gossip history.
Definition: lib.h:146
char * email_msgid
Sender's email's message id.
Definition: lib.h:149
char * sender_email_addr
Sender's email address.
Definition: lib.h:148
char * gossip_keydata
Gossip Key data.
Definition: lib.h:151
sqlite3_int64 timestamp
Timestamp of sender's email.
Definition: lib.h:150
char * gossip_keydata
Gossip Key data.
Definition: lib.h:128
char * gossip_keyid
Gossip Key id.
Definition: lib.h:127
sqlite3_int64 gossip_timestamp
Timestamp of Gossip header.
Definition: lib.h:126
struct Envelope * env
Envelope information.
Definition: email.h:68
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
struct AutocryptHeader * autocrypt_gossip
Autocrypt Gossip header.
Definition: envelope.h:88
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_ui_recommendation()

enum AutocryptRec mutt_autocrypt_ui_recommendation ( const struct Email e,
char **  keylist 
)

Get the recommended action for an Email.

Parameters
[in]eEmail
[out]keylistList of Autocrypt key ids
Return values
enumAutocryptRec Recommendation, e.g. AUTOCRYPT_REC_AVAILABLE

If the recommendataion is > NO and keylist is not NULL, keylist will be populated with the autocrypt keyids.

Definition at line 560 of file autocrypt.c.

561{
563 struct AutocryptAccount *account = NULL;
564 struct AutocryptPeer *peer = NULL;
565 struct Address *recip = NULL;
566 bool all_encrypt = true, has_discourage = false;
567 const char *matching_key = NULL;
568 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
569 struct Buffer *keylist_buf = NULL;
570
571 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
572 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
573 {
574 if (keylist)
575 {
576 /* L10N: Error displayed if the user tries to force sending an Autocrypt
577 email when the engine is not available. */
578 mutt_message(_("Autocrypt is not available"));
579 }
580 return AUTOCRYPT_REC_OFF;
581 }
582
583 struct Address *from = TAILQ_FIRST(&e->env->from);
584 if (!from || TAILQ_NEXT(from, entries))
585 {
586 if (keylist)
587 mutt_message(_("Autocrypt is not available"));
588 return AUTOCRYPT_REC_OFF;
589 }
590
592 {
593 if (keylist)
594 mutt_message(_("Autocrypt is not available"));
595 return AUTOCRYPT_REC_OFF;
596 }
597
598 if ((mutt_autocrypt_db_account_get(from, &account) <= 0) || !account->enabled)
599 {
600 if (keylist)
601 {
602 /* L10N: Error displayed if the user tries to force sending an Autocrypt
603 email when the account does not exist or is not enabled.
604 %s is the From email address used to look up the Autocrypt account.
605 */
606 mutt_message(_("Autocrypt is not enabled for %s"), buf_string(from->mailbox));
607 }
608 goto cleanup;
609 }
610
611 keylist_buf = buf_pool_get();
612 buf_addstr(keylist_buf, account->keyid);
613
614 mutt_addrlist_copy(&recips, &e->env->to, false);
615 mutt_addrlist_copy(&recips, &e->env->cc, false);
616 mutt_addrlist_copy(&recips, &e->env->bcc, false);
617
618 rc = AUTOCRYPT_REC_NO;
619 if (TAILQ_EMPTY(&recips))
620 goto cleanup;
621
622 TAILQ_FOREACH(recip, &recips, entries)
623 {
624 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
625 {
626 if (keylist)
627 {
628 /* L10N: s is an email address. Autocrypt is scanning for the keyids
629 to use to encrypt, but it can't find a valid keyid for this address.
630 The message is printed and they are returned to the compose menu. */
631 mutt_message(_("No (valid) autocrypt key found for %s"),
632 buf_string(recip->mailbox));
633 }
634 goto cleanup;
635 }
636
638 {
639 matching_key = peer->keyid;
640
641 if (!(peer->last_seen && peer->autocrypt_timestamp) ||
642 (peer->last_seen - peer->autocrypt_timestamp > (35 * 24 * 60 * 60)))
643 {
644 has_discourage = true;
645 all_encrypt = false;
646 }
647
648 if (!account->prefer_encrypt || !peer->prefer_encrypt)
649 all_encrypt = false;
650 }
652 {
653 matching_key = peer->gossip_keyid;
654
655 has_discourage = true;
656 all_encrypt = false;
657 }
658 else
659 {
660 if (keylist)
661 {
662 mutt_message(_("No (valid) autocrypt key found for %s"),
663 buf_string(recip->mailbox));
664 }
665 goto cleanup;
666 }
667
668 if (!buf_is_empty(keylist_buf))
669 buf_addch(keylist_buf, ' ');
670 buf_addstr(keylist_buf, matching_key);
671
673 }
674
675 if (all_encrypt)
677 else if (has_discourage)
679 else
681
682 if (keylist)
683 mutt_str_replace(keylist, buf_string(keylist_buf));
684
685cleanup:
687 mutt_addrlist_clear(&recips);
689 buf_pool_release(&keylist_buf);
690 return rc;
691}
AutocryptRec
Recommendation.
Definition: lib.h:158
@ AUTOCRYPT_REC_DISCOURAGE
Prefer not to use Autocrypt.
Definition: lib.h:161
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition: lib.h:160
@ AUTOCRYPT_REC_OFF
No recommendations.
Definition: lib.h:159
@ AUTOCRYPT_REC_AVAILABLE
Autocrypt is available.
Definition: lib.h:162
@ AUTOCRYPT_REC_YES
Autocrypt should be used.
Definition: lib.h:163
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
Is a key id valid?
Definition: gpgme.c:360
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define TAILQ_EMPTY(head)
Definition: queue.h:721
char * keyid
PGP Key id.
Definition: lib.h:109
bool enabled
Is this account enabled.
Definition: lib.h:112
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_set_sign_as_default_key()

int mutt_autocrypt_set_sign_as_default_key ( struct Email e)

Set the Autocrypt default key for signing.

Parameters
eEmail
Return values
0Success
-1Error

Definition at line 699 of file autocrypt.c.

700{
701 int rc = -1;
702 struct AutocryptAccount *account = NULL;
703
704 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
705 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
706 return -1;
707
708 struct Address *from = TAILQ_FIRST(&e->env->from);
709 if (!from || TAILQ_NEXT(from, entries))
710 return -1;
711
712 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
713 goto cleanup;
714 if (!account->keyid)
715 goto cleanup;
716 if (!account->enabled)
717 goto cleanup;
718
721
722 rc = 0;
723
724cleanup:
726 return rc;
727}
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:37
char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: config.c:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ write_autocrypt_header_line()

static void write_autocrypt_header_line ( FILE *  fp,
const char *  addr,
bool  prefer_encrypt,
const char *  keydata 
)
static

Write an Autocrypt header to a file.

Parameters
fpFile to write to
addrEmail address
prefer_encryptWhether encryption is preferred
keydataRaw Autocrypt data

Definition at line 736 of file autocrypt.c.

738{
739 fprintf(fp, "addr=%s; ", addr);
740 if (prefer_encrypt)
741 fputs("prefer-encrypt=mutual; ", fp);
742 fputs("keydata=\n", fp);
743
744 while (*keydata)
745 {
746 int count = 0;
747 fputs("\t", fp);
748 while (*keydata && count < 75)
749 {
750 fputc(*keydata, fp);
751 count++;
752 keydata++;
753 }
754 fputs("\n", fp);
755 }
756}
+ Here is the caller graph for this function:

◆ mutt_autocrypt_write_autocrypt_header()

int mutt_autocrypt_write_autocrypt_header ( struct Envelope env,
FILE *  fp 
)

Write the Autocrypt header to a file.

Parameters
envEnvelope
fpFile to write to
Return values
0Success
-1Error

Definition at line 765 of file autocrypt.c.

766{
767 int rc = -1;
768 struct AutocryptAccount *account = NULL;
769
770 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
771 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
772 return -1;
773
774 struct Address *from = TAILQ_FIRST(&env->from);
775 if (!from || TAILQ_NEXT(from, entries))
776 return -1;
777
778 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
779 goto cleanup;
780 if (!account->keydata)
781 goto cleanup;
782 if (!account->enabled)
783 goto cleanup;
784
785 fputs("Autocrypt: ", fp);
787 account->keydata);
788
789 rc = 0;
790
791cleanup:
793 return rc;
794}
static void write_autocrypt_header_line(FILE *fp, const char *addr, bool prefer_encrypt, const char *keydata)
Write an Autocrypt header to a file.
Definition: autocrypt.c:736
char * email_addr
Email address.
Definition: lib.h:108
char * keydata
PGP Key data.
Definition: lib.h:110
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_write_gossip_headers()

int mutt_autocrypt_write_gossip_headers ( struct Envelope env,
FILE *  fp 
)

Write the Autocrypt gossip headers to a file.

Parameters
envEnvelope
fpFile to write to
Return values
0Success
-1Error

Definition at line 803 of file autocrypt.c.

804{
805 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
806 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
807 return -1;
808
809 for (struct AutocryptHeader *gossip = env->autocrypt_gossip; gossip;
810 gossip = gossip->next)
811 {
812 fputs("Autocrypt-Gossip: ", fp);
813 write_autocrypt_header_line(fp, gossip->addr, 0, gossip->keydata);
814 }
815
816 return 0;
817}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_generate_gossip_list()

int mutt_autocrypt_generate_gossip_list ( struct Email e)

Create the gossip list headers.

Parameters
eEmail
Return values
0Success
-1Error

Definition at line 825 of file autocrypt.c.

826{
827 int rc = -1;
828 struct AutocryptPeer *peer = NULL;
829 struct AutocryptAccount *account = NULL;
830 struct Address *recip = NULL;
831
832 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
833 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
834 return -1;
835
836 struct Envelope *mime_headers = e->body->mime_headers;
837 if (!mime_headers)
838 mime_headers = e->body->mime_headers = mutt_env_new();
840
841 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
842
843 mutt_addrlist_copy(&recips, &e->env->to, false);
844 mutt_addrlist_copy(&recips, &e->env->cc, false);
845
846 TAILQ_FOREACH(recip, &recips, entries)
847 {
848 /* At this point, we just accept missing keys and include what we can. */
849 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
850 continue;
851
852 const char *keydata = NULL;
854 keydata = peer->keydata;
856 keydata = peer->gossip_keydata;
857
858 if (keydata)
859 {
860 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
861 gossip->addr = mutt_str_dup(peer->email_addr);
862 gossip->keydata = mutt_str_dup(keydata);
863 gossip->next = mime_headers->autocrypt_gossip;
864 mime_headers->autocrypt_gossip = gossip;
865 }
866
868 }
869
870 TAILQ_FOREACH(recip, &e->env->reply_to, entries)
871 {
872 const char *addr = NULL;
873 const char *keydata = NULL;
874 if (mutt_autocrypt_db_account_get(recip, &account) > 0)
875 {
876 addr = account->email_addr;
877 keydata = account->keydata;
878 }
879 else if (mutt_autocrypt_db_peer_get(recip, &peer) > 0)
880 {
881 addr = peer->email_addr;
883 keydata = peer->keydata;
885 keydata = peer->gossip_keydata;
886 }
887
888 if (keydata)
889 {
890 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
891 gossip->addr = mutt_str_dup(addr);
892 gossip->keydata = mutt_str_dup(keydata);
893 gossip->next = mime_headers->autocrypt_gossip;
894 mime_headers->autocrypt_gossip = gossip;
895 }
898 }
899
900 mutt_addrlist_clear(&recips);
903 return rc;
904}
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:95
void mutt_autocrypthdr_free(struct AutocryptHeader **ptr)
Free an AutocryptHeader.
Definition: envelope.c:104
char * addr
Email address.
Definition: envelope.h:45
char * email_addr
Email address.
Definition: lib.h:120
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_scan_mailboxes()

void mutt_autocrypt_scan_mailboxes ( void  )

Scan mailboxes for Autocrypt headers.

This is invoked during the first autocrypt initialization, to scan one or more mailboxes for autocrypt headers.

Due to the implementation, header-cached headers are not scanned, so this routine just opens up the mailboxes with $header_cache temporarily disabled.

Definition at line 916 of file autocrypt.c.

917{
918#ifdef USE_HCACHE
919 const char *c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
920 char *old_hdrcache = mutt_str_dup(c_header_cache);
921 cs_subset_str_native_set(NeoMutt->sub, "header_cache", 0, NULL);
922#endif
923
924 struct Buffer *folderbuf = buf_pool_get();
925
926 /* L10N: The first time autocrypt is enabled, NeoMutt will ask to scan
927 through one or more mailboxes for Autocrypt: headers. Those headers are
928 then captured in the database as peer records and used for encryption.
929 If this is answered yes, they will be prompted for a mailbox. */
930 enum QuadOption scan = query_yesorno(_("Scan a mailbox for autocrypt headers?"), MUTT_YES);
931 while (scan == MUTT_YES)
932 {
933 struct Mailbox *m_cur = get_current_mailbox();
934 // L10N: The prompt for a mailbox to scan for Autocrypt: headers
935 if ((!mw_enter_fname(_("Scan mailbox"), folderbuf, true, m_cur, false, NULL,
936 NULL, MUTT_SEL_NO_FLAGS)) &&
937 (!buf_is_empty(folderbuf)))
938 {
939 buf_expand_path_regex(folderbuf, false);
940 struct Mailbox *m_ac = mx_path_resolve(buf_string(folderbuf));
941 /* NOTE: I am purposely *not* executing folder hooks here,
942 * as they can do all sorts of things like push into the getch() buffer.
943 * Authentication should be in account-hooks. */
944 if (mx_mbox_open(m_ac, MUTT_READONLY))
945 {
946 mx_mbox_close(m_ac);
947 }
948 buf_reset(folderbuf);
949 }
950
951 /* L10N: This is the second prompt to see if the user would like
952 to scan more than one mailbox for Autocrypt headers.
953 I'm purposely being extra verbose; asking first then prompting
954 for a mailbox. This is because this is a one-time operation
955 and I don't want them to accidentally ctrl-g and abort it. */
956 scan = query_yesorno(_("Scan another mailbox for autocrypt headers?"), MUTT_YES);
957 }
958
959#ifdef USE_HCACHE
960 cs_subset_str_native_set(NeoMutt->sub, "header_cache", (intptr_t) old_hdrcache, NULL);
961 old_hdrcache = NULL;
962#endif
963 buf_pool_release(&folderbuf);
964}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
int mw_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file -.
Definition: curs_lib.c:238
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:715
void buf_expand_path_regex(struct Buffer *buf, bool regex)
Create the canonical path (with regex char escaping)
Definition: muttlib.c:135
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:286
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1634
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:596
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:43
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
A mailbox.
Definition: mailbox.h:79
+ Here is the call graph for this function:
+ Here is the caller graph for this function: