NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
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 "options.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. More...
 
int mutt_autocrypt_init (bool can_create)
 Initialise Autocrypt. More...
 
void mutt_autocrypt_cleanup (void)
 Shutdown Autocrypt. More...
 
int mutt_autocrypt_account_init (bool prompt)
 Create a new Autocrypt account. More...
 
int mutt_autocrypt_process_autocrypt_header (struct Email *e, struct Envelope *env)
 Parse an Autocrypt email header. More...
 
int mutt_autocrypt_process_gossip_header (struct Email *e, struct Envelope *prot_headers)
 Parse an Autocrypt email gossip header. More...
 
enum AutocryptRec mutt_autocrypt_ui_recommendation (const struct Email *e, char **keylist)
 Get the recommended action for an Email. More...
 
int mutt_autocrypt_set_sign_as_default_key (struct Email *e)
 Set the Autocrypt default key for signing. More...
 
static void write_autocrypt_header_line (FILE *fp, const char *addr, bool prefer_encrypt, const char *keydata)
 Write an Autocrypt header to a file. More...
 
int mutt_autocrypt_write_autocrypt_header (struct Envelope *env, FILE *fp)
 Write the Autocrypt header to a file. More...
 
int mutt_autocrypt_write_gossip_headers (struct Envelope *env, FILE *fp)
 Write the Autocrypt gossip headers to a file. More...
 
int mutt_autocrypt_generate_gossip_list (struct Email *e)
 Create the gossip list headers. More...
 
void mutt_autocrypt_scan_mailboxes (void)
 Scan mailboxes for Autocrypt headers. More...
 

Detailed Description

Autocrypt end-to-end encryption.

Authors
  • Kevin J. McCarthy

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 59 of file autocrypt.c.

60{
61 int rc = 0;
62 struct stat st = { 0 };
63
64 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
65 if (stat(c_autocrypt_dir, &st) == 0)
66 return 0;
67
68 if (!can_create)
69 return -1;
70
71 struct Buffer *prompt = mutt_buffer_pool_get();
72 /* L10N: s is a directory. NeoMutt is looking for a directory it needs
73 for some reason (e.g. autocrypt, header cache, bcache), but it
74 doesn't exist. The prompt is asking whether to create the directory */
75 mutt_buffer_printf(prompt, _("%s does not exist. Create it?"), c_autocrypt_dir);
77 {
78 if (mutt_file_mkdir(c_autocrypt_dir, S_IRWXU) < 0)
79 {
80 /* L10N: mkdir() on the directory %s failed. The second %s is the
81 error message returned by libc */
82 mutt_error(_("Can't create %s: %s"), c_autocrypt_dir, strerror(errno));
83 rc = -1;
84 }
85 }
86
88 return rc;
89}
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition: file.c:930
#define mutt_error(...)
Definition: logging.h:87
#define _(a)
Definition: message.h:28
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
String manipulation buffer.
Definition: buffer.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ 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 97 of file autocrypt.c.

98{
99 if (AutocryptDB)
100 return 0;
101
102 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
103 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
104 if (!c_autocrypt || !c_autocrypt_dir)
105 return -1;
106
108 /* The init process can display menus at various points
109 *(e.g. browser, pgp key selection). This allows the screen to be
110 * autocleared after each menu, so the subsequent prompts can be
111 * read. */
113
114 if (autocrypt_dir_init(can_create))
115 goto bail;
116
118 goto bail;
119
120 if (mutt_autocrypt_db_init(can_create))
121 goto bail;
122
123 OptIgnoreMacroEvents = false;
124 OptMenuPopClearScreen = false;
125
126 return 0;
127
128bail:
129 OptIgnoreMacroEvents = false;
130 OptMenuPopClearScreen = false;
131 cs_subset_str_native_set(NeoMutt->sub, "autocrypt", false, NULL);
133 return -1;
134}
void mutt_autocrypt_db_close(void)
Close the Autocrypt SQLite database connection.
Definition: db.c:130
sqlite3 * AutocryptDB
Definition: db.c:52
int mutt_autocrypt_db_init(bool can_create)
Initialise the Autocrypt SQLite database.
Definition: db.c:79
static int autocrypt_dir_init(bool can_create)
Initialise an Autocrypt directory.
Definition: autocrypt.c:59
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
int mutt_autocrypt_gpgme_init(void)
Initialise GPGME.
Definition: gpgme.c:67
bool OptMenuPopClearScreen
(pseudo) clear the screen when popping the last menu
Definition: options.h:45
bool OptIgnoreMacroEvents
(pseudo) don't process macro/push/exec events while set
Definition: options.h:43
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:305
+ 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 139 of file autocrypt.c.

140{
142}
+ 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 153 of file autocrypt.c.

154{
155 struct Address *addr = NULL;
156 struct AutocryptAccount *account = NULL;
157 bool done = false;
158 int rc = -1;
159 bool prefer_encrypt = false;
160
161 if (prompt)
162 {
163 /* L10N: The first time NeoMutt is started with $autocrypt set, it will
164 create $autocrypt_dir and then prompt to create an autocrypt account
165 with this message. */
166 if (mutt_yesorno(_("Create an initial autocrypt account?"), MUTT_YES) != MUTT_YES)
167 return 0;
168 }
169
170 struct Buffer *keyid = mutt_buffer_pool_get();
171 struct Buffer *keydata = mutt_buffer_pool_get();
172
173 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
174 if (c_from)
175 {
176 addr = mutt_addr_copy(c_from);
177 const char *const c_real_name = cs_subset_string(NeoMutt->sub, "real_name");
178 if (!addr->personal && c_real_name)
179 addr->personal = mutt_str_dup(c_real_name);
180 }
181
182 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
183 mutt_addrlist_append(&al, addr);
184
185 do
186 {
187 /* L10N: Autocrypt is asking for the email address to use for the
188 autocrypt account. This will generate a key and add a record
189 to the database for use in autocrypt operations. */
190 if (mutt_edit_address(&al, _("Autocrypt account address: "), false) != 0)
191 goto cleanup;
192
193 addr = TAILQ_FIRST(&al);
194 if (!addr || !addr->mailbox || TAILQ_NEXT(addr, entries))
195 {
196 /* L10N: Autocrypt prompts for an account email address, and requires
197 a single address. This is shown if they entered something invalid,
198 nothing, or more than one address for some reason. */
199 mutt_error(_("Please enter a single email address"));
200 done = false;
201 }
202 else
203 done = true;
204 } while (!done);
205
206 addr = TAILQ_FIRST(&al);
207 if (mutt_autocrypt_db_account_get(addr, &account) < 0)
208 goto cleanup;
209 if (account)
210 {
211 /* L10N: When creating an autocrypt account, this message will be displayed
212 if there is already an account in the database with the email address
213 they just entered. */
214 mutt_error(_("That email address already has an autocrypt account"));
215 goto cleanup;
216 }
217
218 if (mutt_autocrypt_gpgme_select_or_create_key(addr, keyid, keydata))
219 goto cleanup;
220
221 /* L10N: Autocrypt has a setting "prefer-encrypt".
222 When the recommendation algorithm returns "available" and BOTH sender and
223 recipient choose "prefer-encrypt", encryption will be automatically
224 enabled.
225 Otherwise the UI will show encryption is "available" but the user
226 will be required to enable encryption manually. */
227 if (mutt_yesorno(_("Prefer encryption?"), MUTT_NO) == MUTT_YES)
228 prefer_encrypt = true;
229
231 mutt_buffer_string(keydata), prefer_encrypt))
232 {
233 goto cleanup;
234 }
235
236 rc = 0;
237
238cleanup:
239 if (rc == 0)
240 {
241 /* L10N: Message displayed after an autocrypt account is successfully created. */
242 mutt_message(_("Autocrypt account creation succeeded"));
243 }
244 else
245 {
246 /* L10N: Error message displayed if creating an autocrypt account failed
247 or was aborted by the user. */
248 mutt_error(_("Autocrypt account creation aborted"));
249 }
250
254 mutt_buffer_pool_release(&keydata);
255 return rc;
256}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
int mutt_autocrypt_db_account_get(struct Address *addr, struct AutocryptAccount **account)
Get Autocrypt Account data from the database.
Definition: db.c:263
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:322
void mutt_autocrypt_db_account_free(struct AutocryptAccount **ptr)
Free an AutocryptAccount.
Definition: db.c:244
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
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:275
#define mutt_message(...)
Definition: logging.h:86
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
@ 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:178
An email address.
Definition: address.h:36
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
Autocrypt account.
Definition: lib.h:106
bool prefer_encrypt
false = nopref, true = mutual
Definition: lib.h:110
+ 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 265 of file autocrypt.c.

266{
267 struct AutocryptHeader *valid_ac_hdr = NULL;
268 struct AutocryptPeer *peer = NULL;
269 struct AutocryptPeerHistory *peerhist = NULL;
270 struct Buffer *keyid = NULL;
271 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
272 int rc = -1;
273
274 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
275 if (!c_autocrypt)
276 return 0;
277
278 if (mutt_autocrypt_init(false))
279 return -1;
280
281 if (!e || !e->body || !env)
282 return 0;
283
284 /* 1.1 spec says to skip emails with more than one From header */
285 struct Address *from = TAILQ_FIRST(&env->from);
286 if (!from || TAILQ_NEXT(from, entries))
287 return 0;
288
289 /* 1.1 spec also says to skip multipart/report emails */
290 if ((e->body->type == TYPE_MULTIPART) && mutt_istr_equal(e->body->subtype, "report"))
291 {
292 return 0;
293 }
294
295 /* Ignore emails that appear to be more than a week in the future,
296 * since they can block all future updates during that time. */
297 if (e->date_sent > (mutt_date_epoch() + (7 * 24 * 60 * 60)))
298 return 0;
299
300 for (struct AutocryptHeader *ac_hdr = env->autocrypt; ac_hdr; ac_hdr = ac_hdr->next)
301 {
302 if (ac_hdr->invalid)
303 continue;
304
305 /* NOTE: this assumes the processing is occurring right after
306 * mutt_parse_rfc822_line() and the from ADDR is still in the same
307 * form (intl) as the autocrypt header addr field */
308 if (!mutt_istr_equal(from->mailbox, ac_hdr->addr))
309 continue;
310
311 /* 1.1 spec says ignore all, if more than one valid header is found. */
312 if (valid_ac_hdr)
313 {
314 valid_ac_hdr = NULL;
315 break;
316 }
317 valid_ac_hdr = ac_hdr;
318 }
319
320 if (mutt_autocrypt_db_peer_get(from, &peer) < 0)
321 goto cleanup;
322
323 if (peer)
324 {
325 if (e->date_sent <= peer->autocrypt_timestamp)
326 {
327 rc = 0;
328 goto cleanup;
329 }
330
331 if (e->date_sent > peer->last_seen)
332 {
333 update_db = true;
334 peer->last_seen = e->date_sent;
335 }
336
337 if (valid_ac_hdr)
338 {
339 update_db = true;
341 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
342 if (!mutt_str_equal(peer->keydata, valid_ac_hdr->keydata))
343 {
344 import_gpg = true;
345 insert_db_history = true;
346 mutt_str_replace(&peer->keydata, valid_ac_hdr->keydata);
347 }
348 }
349 }
350 else if (valid_ac_hdr)
351 {
352 import_gpg = true;
353 insert_db = true;
354 insert_db_history = true;
355 }
356
357 if (!(import_gpg || insert_db || update_db))
358 {
359 rc = 0;
360 goto cleanup;
361 }
362
363 if (!peer)
364 {
366 peer->last_seen = e->date_sent;
368 peer->keydata = mutt_str_dup(valid_ac_hdr->keydata);
369 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
370 }
371
372 if (import_gpg)
373 {
374 keyid = mutt_buffer_pool_get();
376 goto cleanup;
378 }
379
380 if (insert_db && mutt_autocrypt_db_peer_insert(from, peer))
381 goto cleanup;
382
383 if (update_db && mutt_autocrypt_db_peer_update(peer))
384 goto cleanup;
385
386 if (insert_db_history)
387 {
389 peerhist->email_msgid = mutt_str_dup(env->message_id);
390 peerhist->timestamp = e->date_sent;
391 peerhist->keydata = mutt_str_dup(peer->keydata);
392 if (mutt_autocrypt_db_peer_history_insert(from, peerhist))
393 goto cleanup;
394 }
395
396 rc = 0;
397
398cleanup:
402
403 return rc;
404}
struct AutocryptPeer * mutt_autocrypt_db_peer_new(void)
Create a new AutocryptPeer.
Definition: db.c:519
int mutt_autocrypt_db_peer_insert(struct Address *addr, struct AutocryptPeer *peer)
Insert a peer into the Autocrypt database.
Definition: db.c:615
int mutt_autocrypt_db_peer_get(struct Address *addr, struct AutocryptPeer **peer)
Get peer info from the Autocrypt database.
Definition: db.c:550
int mutt_autocrypt_db_peer_update(struct AutocryptPeer *peer)
Update the peer info in an Autocrypt database.
Definition: db.c:678
void mutt_autocrypt_db_peer_history_free(struct AutocryptPeerHistory **ptr)
Free an AutocryptPeerHistory.
Definition: db.c:743
void mutt_autocrypt_db_peer_free(struct AutocryptPeer **ptr)
Free an AutocryptPeer.
Definition: db.c:528
struct AutocryptPeerHistory * mutt_autocrypt_db_peer_history_new(void)
Create a new AutocryptPeerHistory.
Definition: db.c:734
int mutt_autocrypt_db_peer_history_insert(struct Address *addr, struct AutocryptPeerHistory *peerhist)
Insert peer history into the Autocrypt database.
Definition: db.c:762
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition: autocrypt.c:97
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:428
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
Read a key from GPGME.
Definition: gpgme.c:316
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
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:134
char * email_msgid
Message id of the email.
Definition: lib.h:136
char * keydata
PGP Key data.
Definition: lib.h:138
sqlite3_int64 timestamp
Timestamp of email.
Definition: lib.h:137
Autocrypt peer.
Definition: lib.h:118
sqlite3_int64 autocrypt_timestamp
When the email was sent.
Definition: lib.h:121
char * keyid
PGP Key id.
Definition: lib.h:122
char * keydata
PGP Key data.
Definition: lib.h:123
sqlite3_int64 last_seen
When was the peer last seen.
Definition: lib.h:120
bool prefer_encrypt
false = nopref, true = mutual
Definition: lib.h:124
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:67
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:58
char * message_id
Message ID.
Definition: envelope.h:73
struct AutocryptHeader * autocrypt
Autocrypt header.
Definition: envelope.h:89
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 413 of file autocrypt.c.

414{
415 struct AutocryptPeer *peer = NULL;
416 struct AutocryptGossipHistory *gossip_hist = NULL;
417 struct Address *peer_addr = NULL;
418 struct Address ac_hdr_addr = { 0 };
419 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
420 int rc = -1;
421
422 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
423 if (!c_autocrypt)
424 return 0;
425
426 if (mutt_autocrypt_init(false))
427 return -1;
428
429 if (!e || !e->env || !prot_headers)
430 return 0;
431
432 struct Envelope *env = e->env;
433
434 struct Address *from = TAILQ_FIRST(&env->from);
435 if (!from)
436 return 0;
437
438 /* Ignore emails that appear to be more than a week in the future,
439 * since they can block all future updates during that time. */
440 if (e->date_sent > (mutt_date_epoch() + (7 * 24 * 60 * 60)))
441 return 0;
442
443 struct Buffer *keyid = mutt_buffer_pool_get();
444
445 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
446
447 /* Normalize the recipient list for comparison */
448 mutt_addrlist_copy(&recips, &env->to, false);
449 mutt_addrlist_copy(&recips, &env->cc, false);
450 mutt_addrlist_copy(&recips, &env->reply_to, false);
452
453 for (struct AutocryptHeader *ac_hdr = prot_headers->autocrypt_gossip; ac_hdr;
454 ac_hdr = ac_hdr->next)
455 {
456 if (ac_hdr->invalid)
457 continue;
458
459 /* normalize for comparison against recipient list */
460 mutt_str_replace(&ac_hdr_addr.mailbox, ac_hdr->addr);
461 ac_hdr_addr.is_intl = true;
462 ac_hdr_addr.intl_checked = true;
464
465 /* Check to make sure the address is in the recipient list. */
466 TAILQ_FOREACH(peer_addr, &recips, entries)
467 {
468 if (mutt_str_equal(peer_addr->mailbox, ac_hdr_addr.mailbox))
469 break;
470 }
471
472 if (!peer_addr)
473 continue;
474
475 if (mutt_autocrypt_db_peer_get(peer_addr, &peer) < 0)
476 goto cleanup;
477
478 if (peer)
479 {
480 if (e->date_sent <= peer->gossip_timestamp)
481 {
483 continue;
484 }
485
486 update_db = true;
487 peer->gossip_timestamp = e->date_sent;
488 /* This is slightly different from the autocrypt 1.1 spec.
489 * Avoid setting an empty peer.gossip_keydata with a value that matches
490 * the current peer.keydata. */
491 if ((peer->gossip_keydata && !mutt_str_equal(peer->gossip_keydata, ac_hdr->keydata)) ||
492 (!peer->gossip_keydata && !mutt_str_equal(peer->keydata, ac_hdr->keydata)))
493 {
494 import_gpg = true;
495 insert_db_history = true;
496 mutt_str_replace(&peer->gossip_keydata, ac_hdr->keydata);
497 }
498 }
499 else
500 {
501 import_gpg = true;
502 insert_db = true;
503 insert_db_history = true;
504 }
505
506 if (!peer)
507 {
509 peer->gossip_timestamp = e->date_sent;
510 peer->gossip_keydata = mutt_str_dup(ac_hdr->keydata);
511 }
512
513 if (import_gpg)
514 {
516 goto cleanup;
518 }
519
520 if (insert_db && mutt_autocrypt_db_peer_insert(peer_addr, peer))
521 goto cleanup;
522
523 if (update_db && mutt_autocrypt_db_peer_update(peer))
524 goto cleanup;
525
526 if (insert_db_history)
527 {
529 gossip_hist->sender_email_addr = mutt_str_dup(from->mailbox);
530 gossip_hist->email_msgid = mutt_str_dup(env->message_id);
531 gossip_hist->timestamp = e->date_sent;
532 gossip_hist->gossip_keydata = mutt_str_dup(peer->gossip_keydata);
533 if (mutt_autocrypt_db_gossip_history_insert(peer_addr, gossip_hist))
534 goto cleanup;
535 }
536
539 mutt_buffer_reset(keyid);
540 update_db = false;
541 insert_db = false;
542 insert_db_history = false;
543 import_gpg = false;
544 }
545
546 rc = 0;
547
548cleanup:
549 FREE(&ac_hdr_addr.mailbox);
550 mutt_addrlist_clear(&recips);
554
555 return rc;
556}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
void mutt_autocrypt_db_normalize_addrlist(struct AddressList *al)
Normalise a list of Email Addresses.
Definition: db.c:176
struct AutocryptGossipHistory * mutt_autocrypt_db_gossip_history_new(void)
Create a new AutocryptGossipHistory.
Definition: db.c:812
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:841
void mutt_autocrypt_db_normalize_addr(struct Address *a)
Normalise an Email Address.
Definition: db.c:165
void mutt_autocrypt_db_gossip_history_free(struct AutocryptGossipHistory **ptr)
Free an AutocryptGossipHistory.
Definition: db.c:821
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
#define FREE(x)
Definition: memory.h:43
#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:145
char * email_msgid
Sender's email's message id.
Definition: lib.h:148
char * sender_email_addr
Sender's email address.
Definition: lib.h:147
char * gossip_keydata
Gossip Key data.
Definition: lib.h:150
sqlite3_int64 timestamp
Timestamp of sender's email.
Definition: lib.h:149
char * gossip_keydata
Gossip Key data.
Definition: lib.h:127
char * gossip_keyid
Gossip Key id.
Definition: lib.h:126
sqlite3_int64 gossip_timestamp
Timestamp of Gossip header.
Definition: lib.h:125
struct Envelope * env
Envelope information.
Definition: email.h:66
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:90
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
numRecommendation, 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 567 of file autocrypt.c.

568{
570 struct AutocryptAccount *account = NULL;
571 struct AutocryptPeer *peer = NULL;
572 struct Address *recip = NULL;
573 bool all_encrypt = true, has_discourage = false;
574 const char *matching_key = NULL;
575 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
576 struct Buffer *keylist_buf = NULL;
577
578 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
579 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
580 {
581 if (keylist)
582 {
583 /* L10N: Error displayed if the user tries to force sending an Autocrypt
584 email when the engine is not available. */
585 mutt_message(_("Autocrypt is not available"));
586 }
587 return AUTOCRYPT_REC_OFF;
588 }
589
590 struct Address *from = TAILQ_FIRST(&e->env->from);
591 if (!from || TAILQ_NEXT(from, entries))
592 {
593 if (keylist)
594 mutt_message(_("Autocrypt is not available"));
595 return AUTOCRYPT_REC_OFF;
596 }
597
599 {
600 if (keylist)
601 mutt_message(_("Autocrypt is not available"));
602 return AUTOCRYPT_REC_OFF;
603 }
604
605 if ((mutt_autocrypt_db_account_get(from, &account) <= 0) || !account->enabled)
606 {
607 if (keylist)
608 {
609 /* L10N: Error displayed if the user tries to force sending an Autocrypt
610 email when the account does not exist or is not enabled.
611 %s is the From email address used to look up the Autocrypt account.
612 */
613 mutt_message(_("Autocrypt is not enabled for %s"), NONULL(from->mailbox));
614 }
615 goto cleanup;
616 }
617
618 keylist_buf = mutt_buffer_pool_get();
619 mutt_buffer_addstr(keylist_buf, account->keyid);
620
621 mutt_addrlist_copy(&recips, &e->env->to, false);
622 mutt_addrlist_copy(&recips, &e->env->cc, false);
623 mutt_addrlist_copy(&recips, &e->env->bcc, false);
624
625 rc = AUTOCRYPT_REC_NO;
626 if (TAILQ_EMPTY(&recips))
627 goto cleanup;
628
629 TAILQ_FOREACH(recip, &recips, entries)
630 {
631 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
632 {
633 if (keylist)
634 {
635 /* L10N: s is an email address. Autocrypt is scanning for the keyids
636 to use to encrypt, but it can't find a valid keyid for this address.
637 The message is printed and they are returned to the compose menu. */
638 mutt_message(_("No (valid) autocrypt key found for %s"), recip->mailbox);
639 }
640 goto cleanup;
641 }
642
644 {
645 matching_key = peer->keyid;
646
647 if (!(peer->last_seen && peer->autocrypt_timestamp) ||
648 (peer->last_seen - peer->autocrypt_timestamp > (35 * 24 * 60 * 60)))
649 {
650 has_discourage = true;
651 all_encrypt = false;
652 }
653
654 if (!account->prefer_encrypt || !peer->prefer_encrypt)
655 all_encrypt = false;
656 }
658 {
659 matching_key = peer->gossip_keyid;
660
661 has_discourage = true;
662 all_encrypt = false;
663 }
664 else
665 {
666 if (keylist)
667 mutt_message(_("No (valid) autocrypt key found for %s"), recip->mailbox);
668 goto cleanup;
669 }
670
671 if (!mutt_buffer_is_empty(keylist_buf))
672 mutt_buffer_addch(keylist_buf, ' ');
673 mutt_buffer_addstr(keylist_buf, matching_key);
674
676 }
677
678 if (all_encrypt)
680 else if (has_discourage)
682 else
684
685 if (keylist)
686 mutt_str_replace(keylist, mutt_buffer_string(keylist_buf));
687
688cleanup:
690 mutt_addrlist_clear(&recips);
692 mutt_buffer_pool_release(&keylist_buf);
693 return rc;
694}
AutocryptRec
Recommendation.
Definition: lib.h:157
@ AUTOCRYPT_REC_DISCOURAGE
Prefer not to use Autocrypt.
Definition: lib.h:160
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition: lib.h:159
@ AUTOCRYPT_REC_OFF
No recommendations.
Definition: lib.h:158
@ AUTOCRYPT_REC_AVAILABLE
Autocrypt is available.
Definition: lib.h:161
@ AUTOCRYPT_REC_YES
Autocrypt should be used.
Definition: lib.h:162
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
Is a key id valid?
Definition: gpgme.c:357
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define NONULL(x)
Definition: string2.h:37
char * keyid
PGP Key id.
Definition: lib.h:108
bool enabled
Is this account enabled.
Definition: lib.h:111
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
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 702 of file autocrypt.c.

703{
704 int rc = -1;
705 struct AutocryptAccount *account = NULL;
706
707 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
708 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
709 return -1;
710
711 struct Address *from = TAILQ_FIRST(&e->env->from);
712 if (!from || TAILQ_NEXT(from, entries))
713 return -1;
714
715 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
716 goto cleanup;
717 if (!account->keyid)
718 goto cleanup;
719 if (!account->enabled)
720 goto cleanup;
721
724
725 rc = 0;
726
727cleanup:
729 return rc;
730}
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:35
char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: config.c:36
+ 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 739 of file autocrypt.c.

741{
742 fprintf(fp, "addr=%s; ", addr);
743 if (prefer_encrypt)
744 fputs("prefer-encrypt=mutual; ", fp);
745 fputs("keydata=\n", fp);
746
747 while (*keydata)
748 {
749 int count = 0;
750 fputs("\t", fp);
751 while (*keydata && count < 75)
752 {
753 fputc(*keydata, fp);
754 count++;
755 keydata++;
756 }
757 fputs("\n", fp);
758 }
759}
+ 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 768 of file autocrypt.c.

769{
770 int rc = -1;
771 struct AutocryptAccount *account = NULL;
772
773 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
774 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
775 return -1;
776
777 struct Address *from = TAILQ_FIRST(&env->from);
778 if (!from || TAILQ_NEXT(from, entries))
779 return -1;
780
781 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
782 goto cleanup;
783 if (!account->keydata)
784 goto cleanup;
785 if (!account->enabled)
786 goto cleanup;
787
788 fputs("Autocrypt: ", fp);
790 account->keydata);
791
792 rc = 0;
793
794cleanup:
796 return rc;
797}
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:739
char * email_addr
Email address.
Definition: lib.h:107
char * keydata
PGP Key data.
Definition: lib.h:109
+ 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 806 of file autocrypt.c.

807{
808 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
809 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
810 return -1;
811
812 for (struct AutocryptHeader *gossip = env->autocrypt_gossip; gossip;
813 gossip = gossip->next)
814 {
815 fputs("Autocrypt-Gossip: ", fp);
816 write_autocrypt_header_line(fp, gossip->addr, 0, gossip->keydata);
817 }
818
819 return 0;
820}
+ 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 828 of file autocrypt.c.

829{
830 int rc = -1;
831 struct AutocryptPeer *peer = NULL;
832 struct AutocryptAccount *account = NULL;
833 struct Address *recip = NULL;
834
835 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
836 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
837 return -1;
838
839 struct Envelope *mime_headers = e->body->mime_headers;
840 if (!mime_headers)
841 mime_headers = e->body->mime_headers = mutt_env_new();
843
844 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
845
846 mutt_addrlist_copy(&recips, &e->env->to, false);
847 mutt_addrlist_copy(&recips, &e->env->cc, false);
848
849 TAILQ_FOREACH(recip, &recips, entries)
850 {
851 /* At this point, we just accept missing keys and include what we can. */
852 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
853 continue;
854
855 const char *keydata = NULL;
857 keydata = peer->keydata;
859 keydata = peer->gossip_keydata;
860
861 if (keydata)
862 {
863 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
864 gossip->addr = mutt_str_dup(peer->email_addr);
865 gossip->keydata = mutt_str_dup(keydata);
866 gossip->next = mime_headers->autocrypt_gossip;
867 mime_headers->autocrypt_gossip = gossip;
868 }
869
871 }
872
873 TAILQ_FOREACH(recip, &e->env->reply_to, entries)
874 {
875 const char *addr = NULL;
876 const char *keydata = NULL;
877 if (mutt_autocrypt_db_account_get(recip, &account) > 0)
878 {
879 addr = account->email_addr;
880 keydata = account->keydata;
881 }
882 else if (mutt_autocrypt_db_peer_get(recip, &peer) > 0)
883 {
884 addr = peer->email_addr;
886 keydata = peer->keydata;
888 keydata = peer->gossip_keydata;
889 }
890
891 if (keydata)
892 {
893 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
894 gossip->addr = mutt_str_dup(addr);
895 gossip->keydata = mutt_str_dup(keydata);
896 gossip->next = mime_headers->autocrypt_gossip;
897 mime_headers->autocrypt_gossip = gossip;
898 }
901 }
902
903 mutt_addrlist_clear(&recips);
906 return rc;
907}
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
void mutt_autocrypthdr_free(struct AutocryptHeader **p)
Free an AutocryptHeader.
Definition: envelope.c:75
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition: envelope.c:66
char * addr
Email address.
Definition: envelope.h:45
char * email_addr
Email address.
Definition: lib.h:119
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 919 of file autocrypt.c.

920{
921#ifdef USE_HCACHE
922 const char *c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
923 char *old_hdrcache = mutt_str_dup(c_header_cache);
924 c_header_cache = NULL;
925#endif
926
927 struct Buffer *folderbuf = mutt_buffer_pool_get();
928
929 /* L10N: The first time autocrypt is enabled, NeoMutt will ask to scan
930 through one or more mailboxes for Autocrypt: headers. Those headers are
931 then captured in the database as peer records and used for encryption.
932 If this is answered yes, they will be prompted for a mailbox. */
933 enum QuadOption scan = mutt_yesorno(_("Scan a mailbox for autocrypt headers?"), MUTT_YES);
934 while (scan == MUTT_YES)
935 {
936 struct Mailbox *m_cur = get_current_mailbox();
937 // L10N: The prompt for a mailbox to scan for Autocrypt: headers
938 if ((!mutt_buffer_enter_fname(_("Scan mailbox"), folderbuf, true, m_cur,
939 false, NULL, NULL, MUTT_SEL_NO_FLAGS)) &&
940 (!mutt_buffer_is_empty(folderbuf)))
941 {
942 mutt_buffer_expand_path_regex(folderbuf, false);
943 struct Mailbox *m_ac = mx_path_resolve(mutt_buffer_string(folderbuf));
944 /* NOTE: I am purposely *not* executing folder hooks here,
945 * as they can do all sorts of things like push into the getch() buffer.
946 * Authentication should be in account-hooks. */
947 if (mx_mbox_open(m_ac, MUTT_READONLY))
948 {
949 mx_mbox_close(m_ac);
950 }
951 mutt_buffer_reset(folderbuf);
952 }
953
954 /* L10N: This is the second prompt to see if the user would like
955 to scan more than one mailbox for Autocrypt headers.
956 I'm purposely being extra verbose; asking first then prompting
957 for a mailbox. This is because this is a one-time operation
958 and I don't want them to accidentally ctrl-g and abort it. */
959 scan = mutt_yesorno(_("Scan another mailbox for autocrypt headers?"), MUTT_YES);
960 }
961
962#ifdef USE_HCACHE
963 cs_subset_str_native_set(NeoMutt->sub, "header_cache", (intptr_t) old_hdrcache, NULL);
964 old_hdrcache = NULL;
965#endif
966 mutt_buffer_pool_release(&folderbuf);
967}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:55
int mutt_buffer_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:445
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:624
void mutt_buffer_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:304
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1677
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:615
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:64
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: