Commit Graph

255 Commits

Author SHA1 Message Date
Tim Culverhouse e7a51f5524 backends: send MessageInfoError on header fetching error
When an error is encountered fetching a header, the backends respond
with a type.Error worker message. On receipt of this message, the UI
deletes all pending headers. The headers are all requested again as they
remain on the screen, resulting in an infinite request loop - and an
infinite logging loop. The user only ever sees the spinner unless they
check the logs.

A previous commit intended to fix this, however it introduced a
regression where any message that was part of the fetch request would
also be marked as erroneous. This commit is reverted with commit
2aad2fea7d36 ("msgstore: revert 9fdc7acf5b48").

Send an erroneous message info message from the backend when an error is
encountered for a specific UID.

Fixes: 01f80721e2 ("msgstore: post MessageInfo on erroneous fetch")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:27 +02:00
Koni Marti e5b0725824 charset: handle unknown charsets more user-friendly
Do not throw an error when the charset is unknown; the message entity
can still be read, but log the error instead.

Reported-by: falsifian
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-25 11:54:23 +02:00
Tim Culverhouse 9fdc7acf5b cache: fetch flags from UI
When cached headers are fetched, an action is posted back to the Worker
to immediately fetch the flags for the message from the server (we can't
know the flags state, therefore it's not cached). When scrolling, a lag
occurs when loading cached headers because the n+1 message has to wait
for the flag request to return before the cached headers are retrieved.

Collect the message UIDs in the UI that need flags, and fetch them based
off a debounce timer in a single request. Post the action from the UI to
eliminate an (ugly) go routine in the worker.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 21:10:35 +02:00
Moritz Poldrack ddca71bcfd Revert "worker: prevent deadlock by flooding worker.Messages channel"
This reverts commit 7473571159.

The commit has introduced a regression that lead to the pager not being
filled with content, thereby making reading mails impossible.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:37:42 +02:00
Tim Culverhouse 7473571159 worker: prevent deadlock by flooding worker.Messages channel
Send to worker.Messages in goroutine to prevent deadlocks: the UI can
fill the worker.Actions channel. The worker can generate more than one
Message per action, and if it generates enough to fill the
worker.Messages channel from a single message while the worker.Actions
channel is full, a deadlock occurs.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:36 +02:00
Tim Culverhouse f4d6ade429 imap: prevent deadlock from posting actions to self
The IMAP worker has a few methods that post a new Action to itself. This
can create a deadlock when the worker.Actions channel is full: The
worker can't accept a new Action because it's trying to post an action.
This is most noticeable when cached headers are enabled and the message
list is scrolled fast.

Use a goroutine to post actions to the worker when posting from within
the worker.

Fixes: https://todo.sr.ht/~rjarry/aerc/45
Fixes: 7aa71d334b ("imap: add option to cache headers")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-20 00:03:36 +02:00
Jose Lombera 8ada3260ab notmuch: fix regression in error handling
Fix reggression introduced by 70bfcfef42 ("lint: work nicely with
wrapped errors (errorlint)").

Discovered this because it broke my arec-notmuch config where I have
`exclude-tags=deleted`.  Queries with `tag:deleted` would now fail with
error message saying "Argument was ignored".

Fixes: 70bfcfef42 ("lint: work nicely with wrapped errors (errorlint)")
Signed-off-by: Jose Lombera <jose@lombera.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-09-01 10:05:35 +02:00
Tim Culverhouse 921382a9bf maildir: do not send dircontents on fs event
The maildir worker watches the file system for events (new mail, moved
mail, copied mail, etc). On an event, the worker sends a
DirectoryContents message and a DirectoryInfo message.

Do not send DirectoryContents on FS Event in the maildir worker. The
DirectoryInfo message already triggers the UI to request the new
DirectoryContents, and does so in a more predictable way (IE any
currently applied filter is applied).

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-30 21:42:37 +02:00
Tim Culverhouse 1c9fc7b6b1 maildir: remove filename encoded UID when moving messages
The built-in maildir.Dir.Move method performs an OS level file rename,
which allows for preserving file creation time. Commit c98f704874
("move: enable MoveMessages from msgstore") enabled the use of the Move
method for maildir. One particular maildir synchronizer (isync/mbsync)
encodes the UID within the filename of the email and cannot recover if
the UID is preserved during a move. mbsync encodes filenames like so:

	/path/to/email/{maildir-key},U={uid}:2,S

OfflineIMAP encodes the UID within the filename, but also encodes a hash
of the originating folder so that it can recover from a move without a
rename of the underlying file. OfflineIMAP encodes like so:

	/path/to/email{maildir-key},U={uid},FMD5={folder-hash}:2,S

Remove encoded UIDs of the form `,U={uid}` from filenames to prevent
sync issues.

Fixes: https://todo.sr.ht/~rjarry/aerc/75
Fixes: c98f704874 ("move: enable MoveMessages from msgstore")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-24 17:00:44 +02:00
Thomas Faughnan 5ed849688a parse: remove trailing whitespace from rfc1123z regex
When there is no Date header in a message, aerc falls back to the
Received header and tries to extract an rfc1123z date from it
(introduced in commit d1600e46). The current regex for extracting the
date incorrectly allows for trailing whitespace, causing time.Parse() to
fail inside of parseReceivedHeader(). As a result, the message's date is
shown as "???????????????????" in the message list and as
"0000-12-31 07:03 PM" in the message view (the latter is likely related
to the zero value of time.Time).

Steps to reproduce:
1) Send yourself a message with no Date header, e.g. with msmtp:
printf 'Subject: foo bar\n\nbody text\n' | msmtp --set-date-header=off me@example.com
2) Note the message's displayed date in aerc's message list and message
   view.

Signed-off-by: Thomas Faughnan <tom@tjf.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:56 +02:00
Tim Culverhouse af72ca3607 maildir: implement MoveMessages handling
Implement MoveMessages in the maildir worker. go-maildir supports Move
operations by default, and is functionally equivalent to a OS-level
rename. Creation date of the file is preserved by using Move, which is
used by at least one maildir-to-IMAP synchronizer (isync/mbsync). The
previous move method of copy-and-delete would reset the creation date of
the message, and potentially cause sorting issues in other email
clients.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:54 +02:00
Tim Culverhouse 64e1a7ca93 imap: implement MoveMessages handling
Implement MoveMessages in the imap backend. go-imap includes the MOVE
Imap extension by default, and if a server does not support it the
command fallsback to a copy-and-delete operation. Servers with the MOVE
extension will see a slight performance increase when moving messages
due to fewer round trips. The IMAP implementation uses a MessagesMoved
worker message to avoid polling the destination mailbox.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:53 +02:00
Tim Culverhouse 57933f65ab mbox: implement MoveMessages handling
Implement MoveMessages handling in the mbox backend. The mbox backend
exists entirely in memory, so the handling is equivalent to a
copy-and-delete.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:52 +02:00
Tim Culverhouse e8c5bb641a worker: introduce MoveMessages type
Introduce a MoveMessages worker message to use for improved message
moving in subsequent patches.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:51 +02:00
Tim Culverhouse a0a5ba1538 imap: create copy of uids to retain sort order
Commit fdfec2c07a seqmap: refactor seqmap to use slice instead of map
introduced a regression to imap sorting (if supported). The slice passed
to seqmap was being sorted in place by UID, thus breaking any sort order
sent by the server.

Create a copy of the slice to retain the sort order reported to the UI
while also keeping a correct map for seqnum -> UID in the worker.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 15:46:49 +02:00
Koni Marti 132b5fed9e mbox: filtering for mbox accounts
Use FetchDirectoryContents for filtering instead of the SearchDirectory
message. This was an omission from rebasing the mbox worker and from not
realizing that c2f4404f ("threading: enable filtering of server-side
threads") changed the way we filter in the message store for the
server-side threading implementation. This patch enables filtering for
the mbox worker.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 09:30:37 +02:00
Koni Marti 117f99e187 mark: (un)mark message threads
Mark or unmark the shown message threads. Threads must be available in the
message store. Use the -T option for the mark or unmark commands. Can be
used in combination with the toggle flag (-t).

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 09:30:37 +02:00
Moritz Poldrack 9cffc45f03 go: removed io/ioutil
Since the minimum required version of Go has been bumped to 1.16, the
deprecation of io/ioutil can now be acted upon. This Commit removes the
remaining dependencies on ioutil and replaces them with their io or os
counterparts.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-22 09:30:19 +02:00
Robin Jarry 6b1afc3ae3 tests: fix errors after lint series
Fix the following test failures:

 FAIL: TestMessageInfoHandledError (0.00s)
 parse_test.go:53: could not parse envelope: date parsing failed:
 unrecognized date format:

 FAIL: TestReader (0.07s)
 gpg_test.go:27: using GNUPGHOME = /tmp/TestReader2384941142/001
 reader_test.go:108: Test case: Invalid Signature
 reader_test.go:112: gpg.Read() = gpgmail: failed to read PGP
 message: gpg: failed to run verification: exit status 1

Fixes: 5ca6022d00 ("lint: ensure errors are at least logged (errcheck)")
Fixes: 70bfcfef42 ("lint: work nicely with wrapped errors (errorlint)")
Signed-off-by: Robin Jarry <robin@jarry.cc>
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
2022-08-04 22:52:40 +02:00
Moritz Poldrack 70bfcfef42 lint: work nicely with wrapped errors (errorlint)
Error wrapping as introduced in Go 1.13 adds some additional logic to
use for comparing errors and adding information to it.

Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:58:04 +02:00
Moritz Poldrack 978d35d356 lint: homogenize operations and minor fixes (gocritic)
Apply GoDoc comment policy (comments for humans should have a space
after the //; machine-readable comments shouldn't)

Use strings.ReplaceAll instead of strings.Replace when appropriate

Remove if/else chains by replacing them with switches

Use short assignment/increment notation

Replace single case switches with if statements

Combine else and if when appropriate

Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:58:01 +02:00
Moritz Poldrack c882cf9960 lint: removed unused code (deadcode, structcheck, unused)
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:58:00 +02:00
Moritz Poldrack 5ca6022d00 lint: ensure errors are at least logged (errcheck)
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:57 +02:00
Moritz Poldrack ef599aa8fc lint: simplify code (gosimple)
Replaces infinite for loops containing a select on a channel with a
single case with a range over the channel.

Removes redundant assignments to blank identifiers.

Remove unnecessary guard clause around delete().

Remove `if condition { return true } return false` with return condition

Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:52 +02:00
Moritz Poldrack 03f9f4c3ab lint: remove ineffectual assignments (ineffassign)
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:50 +02:00
Moritz Poldrack 2534612c59 lint: remove unused structs and functions (unused)
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:48 +02:00
Moritz Poldrack 77a00de741 lint: remove redundant returns (S1023)
Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:45 +02:00
Moritz Poldrack f70eecc7cb lint: remove empty branches (SA9003)
Empty branches are effectively dead code and should therefore be
removed.

Signed-off-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-04 21:57:28 +02:00
Tim Culverhouse fdfec2c07a seqmap: refactor seqmap to use slice instead of map
The imap worker's seqmap is represented as a map of sequence number to
UID. This presents a problem when expunging group of messages from the
mailbox: each individual expunge decrements the sequence numbers by 1
(for every sequence number greater than the expunged). This requires a
looping around the map to update the keys. The use of a map also
requires that both the sequence number and the UID of a message be known
in order to insert it into the map. This is only discovered by fetching
individual message body parts (flags, headers, etc), leaving the seqmap
to be empty until we have fetched information about each message. In
certain instances (if a mailbox has recently been loaded), all
information is loaded in memory and no new information is fetched -
leaving the seqmap empty and the UI out of sync with the worker.

Refactor the seqmap as a slice, so that any expunge automatically
decrements the rest of the sequences.

Use the results of FetchDirectoryContents or FetchDirectoryThreaded to
initialize the seqmap with all discovered UIDs. Sort the UIDs in
ascending order: IMAP specification requires that sequence numbers start
at 1 increase in order of ascending UID.

Add individual messages to the map if they come via a MessageUpdate and
have a sequence number larger than our slice.

Update seqmap tests with new logic.

Reference: https://datatracker.ietf.org/doc/html/rfc3501#section-2.3.1.2
Fixes: https://todo.sr.ht/~rjarry/aerc/69
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-03 22:37:13 +02:00
Tim Culverhouse 9630d9d281 seqmap: compare ints instead of uints
When a test fails with a uint comparison, assert displays the hex code
instead of an int, making it harder to debug. Use ints in sequmap test
asserts instead of uints for better readability when tests fail

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-03 22:37:09 +02:00
Tim Culverhouse 23ee64b057 seqmap: re-order test asserts
Reorder seqmap asserts to properly show display expected and actual when
performing go test -v ./...

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-03 22:37:03 +02:00
Moritz Poldrack aaf0a0c656 lint: apply new formatting rules
Run `make fmt`.

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-01 10:44:52 +02:00
Tim Culverhouse 44651b43b3 checkmail: error if check-mail-cmd is not set
Send error message to UI if check-mail-cmd is required but not set.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-01 10:31:59 +02:00
Koni Marti 318f7d252c notmuch: fix cursor movement in threaded view
Set the SkipSort flag when sending directory infos for counting
purposes. Without this, the directory infos would trigger a directory
fetch which could bring the notmuch threads out of sync with the message
list. The notmuch backend sends these directory infos automatically
every minute.

To reproduce the weird cursor movement in notmuch's threaded view:
1. enter threaded view in notmuch
2. wait 1 min (until the auto directory infos are sent out)
3. move cursor around and notice how it jumps over threads

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Tim Culverhouse <tim@timculverhouse.com>
2022-07-31 20:02:46 +02:00
Tim Culverhouse ea718fe146 imap: remove unused expunge code
Remove unused code in the handleDeleteMessages routine. During
debugging, it was found that the channel for expunge updates was not
working and that all expunge details were coming through as
ExpungeUpdates. The reporting channel is unneeded.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-26 22:24:28 +02:00
Koni Marti 26b9c3d966 sort: show warning when sort is not supported
Use the capabilities returned by the backend to check whether sort is
implemented when the user tries to use the sort command. Print a warning
to the log when a sort request is silently dropped by the backend.

Suggested-by: |cos|
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-26 22:22:58 +02:00
Tim Culverhouse fb5558da81 seqmap: sync seqNum to uid after expunge
This patch updates the seqNums after an Expunge operation. When an
expunge operation occurs, the seqNum of the deleted message is reported.
The Imap spec [0] states that an immediate decrement of all seqnums greater
than the deleted occurs, even before the next reporting of an expunge
update.

[0]: https://datatracker.ietf.org/doc/html/rfc3501#section-7.4.1

Fixes: https://todo.sr.ht/~rjarry/aerc/61
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
2022-07-24 23:06:10 +02:00
Robin Jarry cd19995557 logging: use level-based logger functions
Do not pass logger objects around anymore. Shuffle some messages to make
them consistent with the new logging API. Avoid using %v when a more
specific verb exists for the argument types.

The loggers are completely disabled (i.e. Sprintf is not even called)
by default. They are only enabled when redirecting stdout to a file.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:52:15 +02:00
Robin Jarry b188f19131 imap: disable debug logger
This causes all raw email bodies to be dumped along with actual
debugging messages. I don't believe we neither need nor want such
a thing.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-07-23 22:37:08 +02:00
Robin Jarry 5dec1f09b1 imap: fix error when server returns a message without body section
When opening unread emails from certain people (I won't name any names,
sorry), an annoying error message is displayed on the status line:

 could not get section &imap.BodySectionName{BodyPartName:
 imap.BodyPartName{Specifier:"", Path:[]int(nil), Fields:[]string(nil),
 NotFields:false}, Peek:false, Partial:[]int(nil), value}

This does not occur for already read messages. This issue is similar to
the one that was fixed in commit 8ed95b0d2a ("imap: avoid crash when
replying to unread message").

This happens because the flags are updated in the callback that receives
the message itself. It causes the flag update to arrive in the same
channel/request. Ignore the messages that have an empty body (i.e. only
containing flag updates). This is inherently racy but there seems no way
to get rid of these extra messages.

Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-23 21:51:47 +02:00
Koni Marti e572087e58 account: import mbox file to a folder
Append all messages from an mbox file to the selected folder with the
import-mbox command.

User confirmation is required when the folder already contains messages.

A failed append will be retried a few times. If a backend timeout
occurs, the entire import is stopped to prevent a hang.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:56 +02:00
Koni Marti 845763cb1f account: export folder to mbox file
Export all message in the current folder to an mbox file. If an error
occurs during the export, aerc retries a few times before giving up to
prevent a hang.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:54 +02:00
Koni Marti a1a276e002 mbox: implement an mbox backend worker
Implement an mbox backend worker. Worker can be used for testing and
development by mocking a backend for the message store. Worker does not
modify the actual mbox file on disk; all operations are performed in
memory.

To use the mbox backend, create an mbox account in the accounts.conf
where the source uses the "mbox://" scheme, such as

source = mbox://~/mbox/

or

source = mbox://~/mbox/file.mbox

If the mbox source points to a directory, all files in this directory
with the .mbox suffix will be opened as folders.

If an outgoing smtp server is defined for the mbox account, replies can
be sent to emails that are stored in the mbox file.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-14 23:14:45 +02:00
Tim Culverhouse c2f4404fca threading: enable filtering of server-side threads
This patch enables the filtering of a threaded view which uses
server-built threads. Filtering is done server-side, in order to
preserve the use of server-built threads.

In adding this feature, the filtering of notmuch folders was brought up
to feature parity with the other workers. The filters function the same
(ie: they can be stacked). The notmuch filters, however, still use
notmuch syntax for the filtering.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Tim Culverhouse f0c76fad72 threading: add backend capabilities to workers
This patch provides a method to report backend capabilities to the UI.
The intial capabilities included in the report are Sort and Thread.
Having these available to the UI enables the client to better handle
server side threading.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-07-10 21:15:12 +02:00
Adnan Maolood c5daf43460 worker/maildir: implement Maildir++ support
See https://www.courier-mta.org/maildir.html#maildircontents

Signed-off-by: Adnan Maolood <me@adnano.co>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-10 20:34:47 +02:00
Tim Culverhouse e2be2dd4c0 notmuch: fix server-side threads
Notmuch server-side threading added messages within a thread that didn't
match the query into the uidstore. By doing so, several UI issues
presented:

* All "hidden" messages displayed at the bottom of the msglist
* Selected messages wouldn't open properly

This patch stops these messages from being put into the message store,
thereby resolving the UI issues

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Koni Marti <koni.marti@gmail.com>
2022-07-02 18:24:41 +02:00
Moritz Poldrack 5205951149 lint: fix composite literal using unkeyed fields
Fix the following go vet error:

 # git.sr.ht/~rjarry/aerc/worker/notmuch
 worker/notmuch/worker.go:86:19:
 git.sr.ht/~rjarry/aerc/worker/types.Done composite literal uses unkeyed
 fields

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
2022-06-26 11:23:21 +02:00
Robin Jarry 420f236d31 imap: fix data race on seqMap array
There are concurrent threads that are accessing and modifying
IMAPWorker.seqMap (the mapping of sequence numbers to message UIDs).
This can lead to crashes when trying to add and remove a message ID.

panic: runtime error: index out of range [391] with length 390

goroutine 1834 [running]:
git.sr.ht/~rjarry/aerc/logging.PanicHandler()
	logging/panic-logger.go:47 +0x6de
panic({0xa41760, 0xc0019b3290})
	/usr/lib/golang/src/runtime/panic.go:838 +0x207
git.sr.ht/~rjarry/aerc/worker/imap.(*IMAPWorker).handleFetchMessages.func1()
	worker/imap/fetch.go:214 +0x185
created by git.sr.ht/~rjarry/aerc/worker/imap.(*IMAPWorker).handleFetchMessages
	worker/imap/fetch.go:209 +0x12b

Use a map which makes more sense than a simple array for random access
operations. Also, it allows better typing for the key values. Protect
the map with a mutex. Add internal API to access the map. Add basic unit
tests to ensure that concurrent access works.

Fixes: https://todo.sr.ht/~rjarry/aerc/49
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Moritz Poldrack <moritz@poldrack.dev>
2022-06-24 21:08:12 +02:00
Tim Culverhouse 7aa71d334b imap: add option to cache headers
Add option to cache headers for imap accounts. Cache db is located at
$XDG_CACHE_DIR/aerc/{account name}. The cache is cleaned of stale
entries when aerc is first opened.

Two new account level configuration options are introduced:
* cache-headers (Default: false)
* cache-max-age (Default: 30 days (720 hours))

The change in worker/imap/open.go is to set the selected directory. This
is required to access the UIDVALIDITY field, which is used in
combination with the message ID to form the key for use in the cache db.
The key structure is: "header.{UIDVALIDITY}.{UID}"

Where reasonable, cache does not stop aerc from running. In general, if
there is an error in the cache, aerc should continue working as usual.
Errors are either displayed to the user or logged.

All messages are stored without flags, and when retrieved have the flags
set to SEEN. This is to prevent UI flashes. A new method to
FetchMessageFlags is introduced to update flags of cached headers. This
is done asynchronously, and the user will see their messages appear and
then any flags updated. The message will initially show as SEEN, but
will update to unread. I considered updating the cache with the
last-known flag state, however it seems prudent to spare the R/W cycle
and assume that - eventually - all messages will end up read, and if it
isn't the update will occur rather quickly.

Note that leveldb puts a lock on the database, preventing multiple
instances of aerc from accessing the cache at the same time.

Much of this work is based on previous efforts by Vladimír Magyar.

Implements: https://todo.sr.ht/~rjarry/aerc/2
Thanks: Vladimír Magyar <vladimir@mgyar.me>
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Tested-by: inwit <inwit@sindominio.net>
Reviewed-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-06-22 11:26:13 +02:00