NeoMutt  2025-12-11-911-gd8d604
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 "module_data.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 (struct AutocryptModuleData *mod_data)
 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 62 of file autocrypt.c.

63{
64 int rc = 0;
65 struct stat st = { 0 };
66
67 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
68 if (stat(c_autocrypt_dir, &st) == 0)
69 return 0;
70
71 if (!can_create)
72 return -1;
73
74 struct Buffer *prompt = buf_pool_get();
75 /* L10N: s is a directory. NeoMutt is looking for a directory it needs
76 for some reason (e.g. autocrypt, header cache, bcache), but it
77 doesn't exist. The prompt is asking whether to create the directory */
78 buf_printf(prompt, _("%s does not exist. Create it?"), c_autocrypt_dir);
80 {
81 if (mutt_file_mkdir(c_autocrypt_dir, S_IRWXU) < 0)
82 {
83 /* L10N: mkdir() on the directory %s failed. The second %s is the
84 error message returned by libc */
85 mutt_error(_("Can't create %s: %s"), c_autocrypt_dir, strerror(errno));
86 rc = -1;
87 }
88 }
89 else
90 {
91 rc = -1;
92 }
93
94 buf_pool_release(&prompt);
95 return rc;
96}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
int mutt_file_mkdir(const char *path, mode_t mode)
Recursively create directories.
Definition file.c:844
#define mutt_error(...)
Definition logging2.h:94
#define _(a)
Definition message.h:28
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno_ignore_macro(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question ignoring the macro buffer.
Definition question.c:342
String manipulation buffer.
Definition buffer.h:36
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
+ 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 104 of file autocrypt.c.

105{
107 if (mod_data->autocrypt_db)
108 return 0;
109
110 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
111 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
112 if (!c_autocrypt || !c_autocrypt_dir)
113 return -1;
114
115 if (autocrypt_dir_init(can_create))
116 goto bail;
117
119 goto bail;
120
121 if (mutt_autocrypt_db_init(can_create))
122 goto bail;
123
124 return 0;
125
126bail:
127 cs_subset_str_native_set(NeoMutt->sub, "autocrypt", false, NULL);
128 mutt_autocrypt_db_close(mod_data);
129 return -1;
130}
void mutt_autocrypt_db_close(struct AutocryptModuleData *mod_data)
Close the Autocrypt SQLite database connection.
Definition db.c:127
int mutt_autocrypt_db_init(bool can_create)
Initialise the Autocrypt SQLite database.
Definition db.c:73
static int autocrypt_dir_init(bool can_create)
Initialise an Autocrypt directory.
Definition autocrypt.c:62
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
int mutt_autocrypt_gpgme_init(void)
Initialise GPGME.
Definition gpgme.c:70
@ MODULE_ID_AUTOCRYPT
ModuleAutocrypt, Autocrypt
Definition module_api.h:50
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
Autocrypt private Module data.
Definition module_data.h:32
sqlite3 * autocrypt_db
Autocrypt database.
Definition module_data.h:38
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:303
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_autocrypt_cleanup()

void mutt_autocrypt_cleanup ( struct AutocryptModuleData * mod_data)

Shutdown Autocrypt.

Parameters
mod_dataAutocrypt module data

Definition at line 136 of file autocrypt.c.

137{
138 mutt_autocrypt_db_close(mod_data);
139}
+ 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 150 of file autocrypt.c.

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

264{
265 struct AutocryptHeader *valid_ac_hdr = NULL;
266 struct AutocryptPeer *peer = NULL;
267 struct AutocryptPeerHistory *peerhist = NULL;
268 struct Buffer *keyid = NULL;
269 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
270 int rc = -1;
271
272 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
273 if (!c_autocrypt)
274 return 0;
275
276 if (mutt_autocrypt_init(false) != 0)
277 return -1;
278
279 if (!e || !e->body || !env)
280 return 0;
281
282 /* 1.1 spec says to skip emails with more than one From header */
283 struct Address *from = TAILQ_FIRST(&env->from);
284 if (!from || TAILQ_NEXT(from, entries))
285 return 0;
286
287 /* 1.1 spec also says to skip multipart/report emails */
288 if ((e->body->type == TYPE_MULTIPART) && mutt_istr_equal(e->body->subtype, "report"))
289 {
290 return 0;
291 }
292
293 /* Ignore emails that appear to be more than a week in the future,
294 * since they can block all future updates during that time. */
295 if (e->date_sent > (mutt_date_now() + (7 * 24 * 60 * 60)))
296 return 0;
297
298 for (struct AutocryptHeader *ac_hdr = env->autocrypt; ac_hdr; ac_hdr = ac_hdr->next)
299 {
300 if (ac_hdr->invalid)
301 continue;
302
303 /* NOTE: this assumes the processing is occurring right after
304 * mutt_parse_rfc822_line() and the from ADDR is still in the same
305 * form (intl) as the autocrypt header addr field */
306 if (!mutt_istr_equal(buf_string(from->mailbox), ac_hdr->addr))
307 continue;
308
309 /* 1.1 spec says ignore all, if more than one valid header is found. */
310 if (valid_ac_hdr)
311 {
312 valid_ac_hdr = NULL;
313 break;
314 }
315 valid_ac_hdr = ac_hdr;
316 }
317
318 if (mutt_autocrypt_db_peer_get(from, &peer) < 0)
319 goto cleanup;
320
321 if (peer)
322 {
323 if (e->date_sent <= peer->autocrypt_timestamp)
324 {
325 rc = 0;
326 goto cleanup;
327 }
328
329 if (e->date_sent > peer->last_seen)
330 {
331 update_db = true;
332 peer->last_seen = e->date_sent;
333 }
334
335 if (valid_ac_hdr)
336 {
337 update_db = true;
339 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
340 if (!mutt_str_equal(peer->keydata, valid_ac_hdr->keydata))
341 {
342 import_gpg = true;
343 insert_db_history = true;
344 mutt_str_replace(&peer->keydata, valid_ac_hdr->keydata);
345 }
346 }
347 }
348 else if (valid_ac_hdr)
349 {
350 import_gpg = true;
351 insert_db = true;
352 insert_db_history = true;
353 }
354
355 if (!(import_gpg || insert_db || update_db))
356 {
357 rc = 0;
358 goto cleanup;
359 }
360
361 if (!peer)
362 {
364 peer->last_seen = e->date_sent;
366 peer->keydata = mutt_str_dup(valid_ac_hdr->keydata);
367 peer->prefer_encrypt = valid_ac_hdr->prefer_encrypt;
368 }
369
370 if (import_gpg)
371 {
372 keyid = buf_pool_get();
374 goto cleanup;
375 mutt_str_replace(&peer->keyid, buf_string(keyid));
376 }
377
378 if (insert_db && mutt_autocrypt_db_peer_insert(from, peer))
379 goto cleanup;
380
381 if (update_db && mutt_autocrypt_db_peer_update(peer))
382 goto cleanup;
383
384 if (insert_db_history)
385 {
387 peerhist->email_msgid = mutt_str_dup(env->message_id);
388 peerhist->timestamp = e->date_sent;
389 peerhist->keydata = mutt_str_dup(peer->keydata);
390 if (mutt_autocrypt_db_peer_history_insert(from, peerhist))
391 goto cleanup;
392 }
393
394 rc = 0;
395
396cleanup:
399 buf_pool_release(&keyid);
400
401 return rc;
402}
struct AutocryptPeer * mutt_autocrypt_db_peer_new(void)
Create a new AutocryptPeer.
Definition db.c:537
int mutt_autocrypt_db_peer_insert(struct Address *addr, struct AutocryptPeer *peer)
Insert a peer into the Autocrypt database.
Definition db.c:640
int mutt_autocrypt_db_peer_get(struct Address *addr, struct AutocryptPeer **peer)
Get peer info from the Autocrypt database.
Definition db.c:568
int mutt_autocrypt_db_peer_update(struct AutocryptPeer *peer)
Update the peer info in an Autocrypt database.
Definition db.c:710
void mutt_autocrypt_db_peer_history_free(struct AutocryptPeerHistory **ptr)
Free an AutocryptPeerHistory.
Definition db.c:780
void mutt_autocrypt_db_peer_free(struct AutocryptPeer **ptr)
Free an AutocryptPeer.
Definition db.c:546
struct AutocryptPeerHistory * mutt_autocrypt_db_peer_history_new(void)
Create a new AutocryptPeerHistory.
Definition db.c:771
int mutt_autocrypt_db_peer_history_insert(struct Address *addr, struct AutocryptPeerHistory *peerhist)
Insert peer history into the Autocrypt database.
Definition db.c:799
int mutt_autocrypt_init(bool can_create)
Initialise Autocrypt.
Definition autocrypt.c:104
int mutt_autocrypt_gpgme_import_key(const char *keydata, struct Buffer *keyid)
Read a key from GPGME.
Definition gpgme.c:320
@ 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:457
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
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:143
char * email_msgid
Message id of the email.
Definition lib.h:145
char * keydata
PGP Key data.
Definition lib.h:147
sqlite3_int64 timestamp
Timestamp of email.
Definition lib.h:146
Autocrypt peer.
Definition lib.h:127
sqlite3_int64 autocrypt_timestamp
When the email was sent.
Definition lib.h:130
char * keyid
PGP Key id.
Definition lib.h:131
char * keydata
PGP Key data.
Definition lib.h:132
sqlite3_int64 last_seen
When was the peer last seen.
Definition lib.h:129
bool prefer_encrypt
false = nopref, true = mutual
Definition lib.h:133
char * subtype
content-type subtype
Definition body.h:61
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 411 of file autocrypt.c.

412{
413 struct AutocryptPeer *peer = NULL;
414 struct AutocryptGossipHistory *gossip_hist = NULL;
415 struct Buffer *keyid = NULL;
416 struct Address *peer_addr = NULL;
417 struct Address ac_hdr_addr = { 0 };
418 ac_hdr_addr.mailbox = buf_new(NULL);
419 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
420 bool update_db = false, insert_db = false, insert_db_history = false, import_gpg = false;
421 int rc = -1;
422
423 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
424 if (!c_autocrypt)
425 {
426 rc = 0;
427 goto cleanup;
428 }
429
430 if (mutt_autocrypt_init(false) != 0)
431 goto cleanup;
432
433 if (!e || !e->env || !prot_headers)
434 {
435 rc = 0;
436 goto cleanup;
437 }
438
439 struct Envelope *env = e->env;
440
441 struct Address *from = TAILQ_FIRST(&env->from);
442 if (!from)
443 {
444 rc = 0;
445 goto cleanup;
446 }
447
448 /* Ignore emails that appear to be more than a week in the future,
449 * since they can block all future updates during that time. */
450 if (e->date_sent > (mutt_date_now() + (7 * 24 * 60 * 60)))
451 {
452 rc = 0;
453 goto cleanup;
454 }
455
456 keyid = buf_pool_get();
457
458 /* Normalize the recipient list for comparison */
459 mutt_addrlist_copy(&recips, &env->to, false);
460 mutt_addrlist_copy(&recips, &env->cc, false);
461 mutt_addrlist_copy(&recips, &env->reply_to, false);
463
464 for (struct AutocryptHeader *ac_hdr = prot_headers->autocrypt_gossip; ac_hdr;
465 ac_hdr = ac_hdr->next)
466 {
467 if (ac_hdr->invalid)
468 continue;
469
470 /* normalize for comparison against recipient list */
471 buf_strcpy(ac_hdr_addr.mailbox, ac_hdr->addr);
472 ac_hdr_addr.is_intl = true;
473 ac_hdr_addr.intl_checked = true;
475
476 /* Check to make sure the address is in the recipient list. */
477 TAILQ_FOREACH(peer_addr, &recips, entries)
478 {
479 if (buf_str_equal(peer_addr->mailbox, ac_hdr_addr.mailbox))
480 break;
481 }
482
483 if (!peer_addr)
484 continue;
485
486 if (mutt_autocrypt_db_peer_get(peer_addr, &peer) < 0)
487 goto cleanup;
488
489 if (peer)
490 {
491 if (e->date_sent <= peer->gossip_timestamp)
492 {
494 continue;
495 }
496
497 update_db = true;
498 peer->gossip_timestamp = e->date_sent;
499 /* This is slightly different from the autocrypt 1.1 spec.
500 * Avoid setting an empty peer.gossip_keydata with a value that matches
501 * the current peer.keydata. */
502 if ((peer->gossip_keydata && !mutt_str_equal(peer->gossip_keydata, ac_hdr->keydata)) ||
503 (!peer->gossip_keydata && !mutt_str_equal(peer->keydata, ac_hdr->keydata)))
504 {
505 import_gpg = true;
506 insert_db_history = true;
507 mutt_str_replace(&peer->gossip_keydata, ac_hdr->keydata);
508 }
509 }
510 else
511 {
512 import_gpg = true;
513 insert_db = true;
514 insert_db_history = true;
515 }
516
517 if (!peer)
518 {
520 peer->gossip_timestamp = e->date_sent;
521 peer->gossip_keydata = mutt_str_dup(ac_hdr->keydata);
522 }
523
524 if (import_gpg)
525 {
527 goto cleanup;
529 }
530
531 if (insert_db && mutt_autocrypt_db_peer_insert(peer_addr, peer))
532 goto cleanup;
533
534 if (update_db && mutt_autocrypt_db_peer_update(peer))
535 goto cleanup;
536
537 if (insert_db_history)
538 {
540 gossip_hist->sender_email_addr = buf_strdup(from->mailbox);
541 gossip_hist->email_msgid = mutt_str_dup(env->message_id);
542 gossip_hist->timestamp = e->date_sent;
543 gossip_hist->gossip_keydata = mutt_str_dup(peer->gossip_keydata);
544 if (mutt_autocrypt_db_gossip_history_insert(peer_addr, gossip_hist))
545 goto cleanup;
546 }
547
550 buf_reset(keyid);
551 update_db = false;
552 insert_db = false;
553 insert_db_history = false;
554 import_gpg = false;
555 }
556
557 rc = 0;
558
559cleanup:
560 buf_free(&ac_hdr_addr.mailbox);
561 mutt_addrlist_clear(&recips);
564 buf_pool_release(&keyid);
565
566 return rc;
567}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:774
void mutt_autocrypt_db_normalize_addrlist(struct AddressList *al)
Normalise a list of Email Addresses.
Definition db.c:173
struct AutocryptGossipHistory * mutt_autocrypt_db_gossip_history_new(void)
Create a new AutocryptGossipHistory.
Definition db.c:854
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:883
void mutt_autocrypt_db_normalize_addr(struct Address *a)
Normalise an Email Address.
Definition db.c:162
void mutt_autocrypt_db_gossip_history_free(struct AutocryptGossipHistory **ptr)
Free an AutocryptGossipHistory.
Definition db.c:863
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition buffer.c:319
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition buffer.c:683
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
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
bool intl_checked
Checked for IDN?
Definition address.h:40
bool is_intl
International Domain Name.
Definition address.h:39
Autocrypt gossip history.
Definition lib.h:154
char * email_msgid
Sender's email's message id.
Definition lib.h:157
char * sender_email_addr
Sender's email address.
Definition lib.h:156
char * gossip_keydata
Gossip Key data.
Definition lib.h:159
sqlite3_int64 timestamp
Timestamp of sender's email.
Definition lib.h:158
char * gossip_keydata
Gossip Key data.
Definition lib.h:136
char * gossip_keyid
Gossip Key id.
Definition lib.h:135
sqlite3_int64 gossip_timestamp
Timestamp of Gossip header.
Definition lib.h:134
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 578 of file autocrypt.c.

579{
581 struct AutocryptAccount *account = NULL;
582 struct AutocryptPeer *peer = NULL;
583 struct Address *recip = NULL;
584 bool all_encrypt = true, has_discourage = false;
585 const char *matching_key = NULL;
586 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
587 struct Buffer *keylist_buf = NULL;
588
589 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
590 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
591 {
592 if (keylist)
593 {
594 /* L10N: Error displayed if the user tries to force sending an Autocrypt
595 email when the engine is not available. */
596 mutt_message(_("Autocrypt is not available"));
597 }
598 return AUTOCRYPT_REC_OFF;
599 }
600
601 struct Address *from = TAILQ_FIRST(&e->env->from);
602 if (!from || TAILQ_NEXT(from, entries))
603 {
604 if (keylist)
605 mutt_message(_("Autocrypt is not available"));
606 return AUTOCRYPT_REC_OFF;
607 }
608
610 {
611 if (keylist)
612 mutt_message(_("Autocrypt is not available"));
613 return AUTOCRYPT_REC_OFF;
614 }
615
616 if ((mutt_autocrypt_db_account_get(from, &account) <= 0) || !account->enabled)
617 {
618 if (keylist)
619 {
620 /* L10N: Error displayed if the user tries to force sending an Autocrypt
621 email when the account does not exist or is not enabled.
622 %s is the From email address used to look up the Autocrypt account.
623 */
624 mutt_message(_("Autocrypt is not enabled for %s"), buf_string(from->mailbox));
625 }
626 goto cleanup;
627 }
628
629 keylist_buf = buf_pool_get();
630 buf_addstr(keylist_buf, account->keyid);
631
632 mutt_addrlist_copy(&recips, &e->env->to, false);
633 mutt_addrlist_copy(&recips, &e->env->cc, false);
634 mutt_addrlist_copy(&recips, &e->env->bcc, false);
635
636 rc = AUTOCRYPT_REC_NO;
637 if (TAILQ_EMPTY(&recips))
638 goto cleanup;
639
640 TAILQ_FOREACH(recip, &recips, entries)
641 {
642 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
643 {
644 if (keylist)
645 {
646 /* L10N: s is an email address. Autocrypt is scanning for the keyids
647 to use to encrypt, but it can't find a valid keyid for this address.
648 The message is printed and they are returned to the compose menu. */
649 mutt_message(_("No (valid) autocrypt key found for %s"),
650 buf_string(recip->mailbox));
651 }
652 goto cleanup;
653 }
654
656 {
657 matching_key = peer->keyid;
658
659 if (!(peer->last_seen && peer->autocrypt_timestamp) ||
660 (peer->last_seen - peer->autocrypt_timestamp > (35 * 24 * 60 * 60)))
661 {
662 has_discourage = true;
663 all_encrypt = false;
664 }
665
666 if (!account->prefer_encrypt || !peer->prefer_encrypt)
667 all_encrypt = false;
668 }
670 {
671 matching_key = peer->gossip_keyid;
672
673 has_discourage = true;
674 all_encrypt = false;
675 }
676 else
677 {
678 if (keylist)
679 {
680 mutt_message(_("No (valid) autocrypt key found for %s"),
681 buf_string(recip->mailbox));
682 }
683 goto cleanup;
684 }
685
686 if (!buf_is_empty(keylist_buf))
687 buf_addch(keylist_buf, ' ');
688 buf_addstr(keylist_buf, matching_key);
689
691 }
692
693 if (all_encrypt)
695 else if (has_discourage)
697 else
699
700 if (keylist)
701 mutt_str_replace(keylist, buf_string(keylist_buf));
702
703cleanup:
705 mutt_addrlist_clear(&recips);
707 buf_pool_release(&keylist_buf);
708 return rc;
709}
AutocryptRec
Recommendation.
Definition lib.h:166
@ AUTOCRYPT_REC_DISCOURAGE
Prefer not to use Autocrypt.
Definition lib.h:169
@ AUTOCRYPT_REC_NO
Do no use Autocrypt.
Definition lib.h:168
@ AUTOCRYPT_REC_OFF
No recommendations.
Definition lib.h:167
@ AUTOCRYPT_REC_AVAILABLE
Autocrypt is available.
Definition lib.h:170
@ AUTOCRYPT_REC_YES
Autocrypt should be used.
Definition lib.h:171
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
bool mutt_autocrypt_gpgme_is_valid_key(const char *keyid)
Is a key id valid?
Definition gpgme.c:361
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define TAILQ_EMPTY(head)
Definition queue.h:778
char * keyid
PGP Key id.
Definition lib.h:116
bool enabled
Is this account enabled.
Definition lib.h:119
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 717 of file autocrypt.c.

718{
719 int rc = -1;
720 struct AutocryptAccount *account = NULL;
722
723 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
724 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
725 return -1;
726
727 struct Address *from = TAILQ_FIRST(&e->env->from);
728 if (!from || TAILQ_NEXT(from, entries))
729 return -1;
730
731 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
732 goto cleanup;
733 if (!account->keyid)
734 goto cleanup;
735 if (!account->enabled)
736 goto cleanup;
737
738 mutt_str_replace(&mod_data->autocrypt_sign_as, account->keyid);
739 mutt_str_replace(&mod_data->autocrypt_default_key, account->keyid);
740
741 rc = 0;
742
743cleanup:
745 return rc;
746}
char * autocrypt_sign_as
Autocrypt Key id to sign as.
Definition module_data.h:36
char * autocrypt_default_key
Autocrypt default key id (used for postponing messages)
Definition module_data.h:35
+ 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 755 of file autocrypt.c.

757{
758 fprintf(fp, "addr=%s; ", addr);
759 if (prefer_encrypt)
760 fputs("prefer-encrypt=mutual; ", fp);
761 fputs("keydata=\n", fp);
762
763 while (*keydata)
764 {
765 int count = 0;
766 fputs("\t", fp);
767 while (*keydata && count < 75)
768 {
769 fputc(*keydata, fp);
770 count++;
771 keydata++;
772 }
773 fputs("\n", fp);
774 }
775}
+ 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 784 of file autocrypt.c.

785{
786 int rc = -1;
787 struct AutocryptAccount *account = NULL;
788
789 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
790 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
791 return -1;
792
793 struct Address *from = TAILQ_FIRST(&env->from);
794 if (!from || TAILQ_NEXT(from, entries))
795 return -1;
796
797 if (mutt_autocrypt_db_account_get(from, &account) <= 0)
798 goto cleanup;
799 if (!account->keydata)
800 goto cleanup;
801 if (!account->enabled)
802 goto cleanup;
803
804 fputs("Autocrypt: ", fp);
806 account->keydata);
807
808 rc = 0;
809
810cleanup:
812 return rc;
813}
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:755
char * email_addr
Email address.
Definition lib.h:115
char * keydata
PGP Key data.
Definition lib.h:117
+ 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 822 of file autocrypt.c.

823{
824 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
825 if (!c_autocrypt || mutt_autocrypt_init(false) || !env)
826 return -1;
827
828 for (struct AutocryptHeader *gossip = env->autocrypt_gossip; gossip;
829 gossip = gossip->next)
830 {
831 fputs("Autocrypt-Gossip: ", fp);
832 write_autocrypt_header_line(fp, gossip->addr, 0, gossip->keydata);
833 }
834
835 return 0;
836}
+ 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 844 of file autocrypt.c.

845{
846 int rc = -1;
847 struct AutocryptPeer *peer = NULL;
848 struct AutocryptAccount *account = NULL;
849 struct Address *recip = NULL;
850
851 const bool c_autocrypt = cs_subset_bool(NeoMutt->sub, "autocrypt");
852 if (!c_autocrypt || mutt_autocrypt_init(false) || !e)
853 return -1;
854
855 struct Envelope *mime_headers = e->body->mime_headers;
856 if (!mime_headers)
857 mime_headers = e->body->mime_headers = mutt_env_new();
859
860 struct AddressList recips = TAILQ_HEAD_INITIALIZER(recips);
861
862 mutt_addrlist_copy(&recips, &e->env->to, false);
863 mutt_addrlist_copy(&recips, &e->env->cc, false);
864
865 TAILQ_FOREACH(recip, &recips, entries)
866 {
867 /* At this point, we just accept missing keys and include what we can. */
868 if (mutt_autocrypt_db_peer_get(recip, &peer) <= 0)
869 continue;
870
871 const char *keydata = NULL;
873 keydata = peer->keydata;
875 keydata = peer->gossip_keydata;
876
877 if (keydata)
878 {
879 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
880 gossip->addr = mutt_str_dup(peer->email_addr);
881 gossip->keydata = mutt_str_dup(keydata);
882 gossip->next = mime_headers->autocrypt_gossip;
883 mime_headers->autocrypt_gossip = gossip;
884 }
885
887 }
888
889 TAILQ_FOREACH(recip, &e->env->reply_to, entries)
890 {
891 const char *addr = NULL;
892 const char *keydata = NULL;
893 if (mutt_autocrypt_db_account_get(recip, &account) > 0)
894 {
895 addr = account->email_addr;
896 keydata = account->keydata;
897 }
898 else if (mutt_autocrypt_db_peer_get(recip, &peer) > 0)
899 {
900 addr = peer->email_addr;
902 keydata = peer->keydata;
904 keydata = peer->gossip_keydata;
905 }
906
907 if (keydata)
908 {
909 struct AutocryptHeader *gossip = mutt_autocrypthdr_new();
910 gossip->addr = mutt_str_dup(addr);
911 gossip->keydata = mutt_str_dup(keydata);
912 gossip->next = mime_headers->autocrypt_gossip;
913 mime_headers->autocrypt_gossip = gossip;
914 }
917 }
918
919 rc = 0;
920
921 mutt_addrlist_clear(&recips);
924 return rc;
925}
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
struct AutocryptHeader * mutt_autocrypthdr_new(void)
Create a new AutocryptHeader.
Definition envelope.c:94
void mutt_autocrypthdr_free(struct AutocryptHeader **ptr)
Free an AutocryptHeader.
Definition envelope.c:103
char * addr
Email address.
Definition envelope.h:45
char * email_addr
Email address.
Definition lib.h:128
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
+ 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 937 of file autocrypt.c.

938{
939#ifdef USE_HCACHE
940 const char *c_header_cache = cs_subset_path(NeoMutt->sub, "header_cache");
941 char *old_hdrcache = mutt_str_dup(c_header_cache);
942 cs_subset_str_native_set(NeoMutt->sub, "header_cache", 0, NULL);
943#endif
944
945 struct Buffer *folderbuf = buf_pool_get();
946
947 /* L10N: The first time autocrypt is enabled, NeoMutt will ask to scan
948 through one or more mailboxes for Autocrypt: headers. Those headers are
949 then captured in the database as peer records and used for encryption.
950 If this is answered yes, they will be prompted for a mailbox. */
951 enum QuadOption scan = query_yesorno_ignore_macro(_("Scan a mailbox for autocrypt headers?"),
952 MUTT_YES);
953 while (scan == MUTT_YES)
954 {
955 struct Mailbox *m_cur = get_current_mailbox();
956 // L10N: The prompt for a mailbox to scan for Autocrypt: headers
957 if ((!mw_enter_fname(_("Scan mailbox"), folderbuf, true, m_cur, false, NULL,
958 NULL, MUTT_SEL_NONE)) &&
959 (!buf_is_empty(folderbuf)))
960 {
961 expand_path(folderbuf, false);
962 struct Mailbox *m_ac = mx_path_resolve(buf_string(folderbuf));
963 /* NOTE: I am purposely *not* executing folder hooks here,
964 * as they can do all sorts of things like push into the getch() buffer.
965 * Authentication should be in account-hooks. */
966 if (mx_mbox_open(m_ac, MUTT_READONLY))
967 {
968 mx_mbox_close(m_ac);
969 }
970 buf_reset(folderbuf);
971 }
972
973 /* L10N: This is the second prompt to see if the user would like
974 to scan more than one mailbox for Autocrypt headers.
975 I'm purposely being extra verbose; asking first then prompting
976 for a mailbox. This is because this is a one-time operation
977 and I don't want them to accidentally ctrl-g and abort it. */
978 scan = query_yesorno_ignore_macro(_("Scan another mailbox for autocrypt headers?"), MUTT_YES);
979 }
980
981#ifdef USE_HCACHE
982 cs_subset_str_native_set(NeoMutt->sub, "header_cache", (intptr_t) old_hdrcache, NULL);
983 old_hdrcache = NULL;
984#endif
985 buf_pool_release(&folderbuf);
986}
@ MUTT_SEL_NONE
No flags are set.
Definition lib.h:59
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:726
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1647
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
@ MUTT_READONLY
Open in read-only mode.
Definition mxapi.h:45
QuadOption
Possible values for a quad-option.
Definition quad.h:36
A mailbox.
Definition mailbox.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function: