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>
When moving/copying/deleting/archiving a message in imap, the RUE counts
displayed in the dirlist would not update properly. Maildir has (had) an
implementation that recounts the entire directory and updates the
DirectoryInfo after one of these actions.
This patch implements a more efficient method of updating, and also
enables it to apply to IMAP without any additional requests. Upon
completion of the action, the counts are manually updated with the count
of messages in the action and recent and/or unseen states of those
messages. This is more efficient for maildir, because we aren't counting
everything in the store. For IMAP, we get the updates for free because
we are only performing the update after confirmation from the server
that the action has happened.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Check for new mail (recent, unseen, exists counts) with an external
command, or for imap with the STATUS command, at start or on
reconnection and every X time duration
IMAP:
The selected folder is skipped, per specification. Additional config
options are included for including/excluding folders explicitly.
Maildir/Notmuch:
An external command will be run in the background to check for new mail.
An optional timeout can be used with maildir/notmuch. Default is 10s
New account options:
check-mail
check-mail-cmd (maildir/notmuch only)
check-mail-timeout (maildir/notmuch only), default 10s
check-mail-include (IMAP only)
check-mail-exclude (IMAP only)
If unset, or set less than or equal to 0, check-mail will be ignored
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Tested-by: Moritz Poldrack <moritz@poldrack.dev>
Acked-by: Robin Jarry <robin@jarry.cc>
Apply the user-defined sort criteria to the message with the highest
uid in a threaded discussion. Restore the default sort order when
leaving threading mode.
Commit 7811620eb8 ("threading: implement on-the-fly message
threading") introduced message threading with the threaded messages
being only sorted by their message uids irrespective of the defined sorting
criteria. It did not restore the default sort order either.
Reported-by: Sebastien Binet <s@sbinet.org>
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
implement message threading on the message store level using the
jwz algorithm. Build threads on-the-fly when new message headers arrive.
Use the references header to create the threads and the in-reply-to
header as a fall-back option in case no references header is present.
Does not run when the worker provides its own threading (e.g. imap
server threads).
Include only those message headers that have been fetched and are
stored in the message store.
References: https://www.jwz.org/doc/threading.html
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Inwit <inwit@sindominio.net>
Tested-by: akspecs <akspecs@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
if the worker emits a connection error, the ui will automatically send back a
reconnect command. The worker then establishes a new connection. Auto-reconnect
is disabled when the user sends the disconnect command.
Fixes: https://todo.sr.ht/~rjarry/aerc/1
Signed-off-by: Koni Marti <koni.marti@gmail.com>
implements a new connection error message. This allows the worker to emit a
connection-related error message to the ui when the imap client closes the
loggedOut channel.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Display threads in the message list. For now, only supported by the
notmuch backend and on IMAP when the server supports the THREAD
extension.
Setting threading-enable=true is global and will cause the message list
to be empty with maildir:// accounts.
Co-authored-by: Kevin Kuehler <keur@xcf.berkeley.edu>
Co-authored-by: Reto Brunner <reto@labrat.space>
Signed-off-by: Robin Jarry <robin@jarry.cc>
The `:rmdir` command removes the current directory (`-f` is required if
the directory is not empty).
This is not supported on the notmuch backend.
An issue with the maildir backend is that some sync programs (e.g.
offlineimap) may recover the directory after it is deleted. They need
to specifically be configured to accept deletions, or special commands
need to be executed (e.g. `offlineimap --delete-folder`) to properly
delete folders.
A danger of using this on the IMAP backend is that it is possible for a
new message to be added to the directory and for aerc to not show it
immediately (due to a slow connection) - using `:rmdir` at this moment
(with `-f` if the directory already contains messages) would delete the
directory and the new message that just arrived (and all other
contents). This is documented in aerc(1) so that users are aware of
possible risks.
More mail flags can now be set, unset, and toggled, not just the
read/seen flag.
This functionality is implemented with a new `:flag` and `:unflag`
command, which are extensions to the matching `:read` and `:unread`
commands, adding support for different flags. In fact, the
`read`/`unread` commands are now recognized aliases to `flag`/`unflag`.
The new commands are also well documented in aerc(1).
The change mostly extends the previous read/unread setting functionality
by adding a selection for the flag to change.
- Add maildir flags to complement a messages imap flags
- Set the "seen" flag on sent messages when using the maildir backend
- Cleanup AppendMessage interface to use models.Flag for both IMAP and
maildir
Actions such as read / unread or the addition of new messages do change
the read/unread/recent count. Hence we request an update from the workers.
Workers going over the network should probably cache the information and invalidate
it only if necessary
Previously the workers returned a mixture of decoded / encoded parts.
This lead to a whole bunch of issues.
This commit changes the msgviewer and the commands to assume parts to already
be decoded
There is a command and config option. The criteria are a list of the
sort criterion and each can be individually reversed.
This only includes support for sorting in the maildir backend currently.
The other backends are not supported in this patch.
A sequence-set is an IMAP-specific implementation detail. Throughout the
UI, aerc simply operates using lists of opaque identifiers. In order to
loosen the coupling between the UI and IMAP in particular, replace most
usages of imap.SeqSet with []uint32, leaving the translation to a SeqSet
to the IMAP backend as needed.
Before, the information needed to display different parts of the UI was
tightly coupled to the specific messages being sent back and forth to
the backend worker. Separating out a models package allows us to be more
specific about exactly what a backend is able to and required to
provide for the UI.
Adds an archive command that moves the current message into the folder
specified in the account config entry.
Supports three layouts at this point:
- flat: puts all messages next to each other
- year: creates a folder per year
- month: same as above, plus folders per month
This also adds a "-p" argument to "cp" and "mv" that works like
"--parents" on mkdir(1). We use this to auto-create the directories
for the archive layout.
Worker.callbacks contains two types of callbacks: some are action callbacks,
some are message callbacks. Each of those is access from one side of the
communication channel (UI goroutine vs. worker goroutine).
Instead of using a channel, we can use two different maps for each kind. This
simplifies the code and also ensures we don't call an action callback instead
of a message callback (or the other way around).
Message IDs are allocated for both messages from UI to workers and the other
way around. Hence, the global nextId variable is accessed from multiple
goroutines.
Instead, use atomic to access the global counter.
Worker.Process* functions were called in different goroutines than
Worker.Post*. Protect the map with a mutex. Also make the map unexported to
prevent external unprotected accesses.
Worker.Process* functions used to delete items from the map. However they
didn't delete the element they retrieved: callbacks[msg.InResponseTo()] was
read while callbacks[msg] was deleted. I'm not sure I understand why. I tried
to delete the element that was accessed - but this broke everything (UI froze
at "Connecting..."). I don't believe any elements were actually removed from
the map, so the new code just doesn't remove anything.