deltachat-core-rust icon indicating copy to clipboard operation
deltachat-core-rust copied to clipboard

Use NOTIFY (RFC 5465) instead of prefetch when available

Open link2xt opened this issue 1 year ago • 0 comments

Using RFC 5465 we can subscribe to notifications about new messages using command NOTIFY SET (selected (Messagenew {PREFETCH_FLAGS} messageexpunge)) like this:

? SELECT INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 38 EXISTS
* 0 RECENT
* OK [UIDVALIDITY 1697564012] UIDs valid
* OK [UIDNEXT 155] Predicted next UID
* OK [HIGHESTMODSEQ 294] Highest
? OK [READ-WRITE] Select completed (0.001 + 0.000 secs).
? NOTIFY SET (selected (Messagenew (UID INTERNALDATE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (MESSAGE-ID X-MICROSOFT-ORIGINAL-MESSAGE-ID FROM IN-REPLY-TO REFERENCES CHAT-VERSION AUTOCRYPT-SETUP-MESSAGE)]) messageexpunge))
? OK NOTIFY completed (0.001 + 0.000 secs).

Later when a message arrives we will get a prefetch instantly without making a request for it

* 39 EXISTS
* 1 RECENT
* 39 FETCH (UID 155 INTERNALDATE "12-Nov-2023 04:54:37 +0100" RFC822.SIZE 2766 BODY[HEADER.FIELDS (MESSAGE-ID X-MICROSOFT-ORIGINAL-MESSAGE-ID FROM IN-REPLY-TO REFERENCES CHAT-VERSION AUTOCRYPT-SETUP-MESSAGE)] {116}
From: <[email protected]>
Message-ID: <[email protected]>
Chat-Version: 1.0

)

There is even no need to be in IDLE for that, but IDLE is still needed to get * OK Still here keepalives, so no need to change anything around the IDLE code paths.

To implement NOTIFY support, we need to:

  1. Look for NOTIFY capability.
  2. If NOTIFY is supported, enable it once after logging in for the folder we watch (either INBOX or DeltaChat). In the example I used "selected", but we better watch for the explicit folder name to avoid missing messages if we switch folders or close the current folder. Ideally we don't need to switch folders when using NOTIFY, but I would suggest not getting rid of scan_folders() right away and make NOTIFY working with minimal changes first.
  3. Set up a data structure (a vector) inside the IMAP session to collect prefetches.
  4. After enabling notify, prefetch once manually to make sure we don't miss any message from the time before enabling NOTIFY.
  5. Process FETCH messages that we receive. Normally they will get into Session.unsolicited_responses() channel and we should process them when we read from it, but they may also accidentally be mistaken as a FETCH command response so we should also recognize such notify-prefetches whenever we read a FETCH command response.
  6. Add a flag Config::DisableNotify similar to Config::DisableIdle and run some tests with it enabled to ensure we don't break compatibility with the servers not supporting NOTIFY.

link2xt avatar Nov 12 '23 04:11 link2xt