djc / tokio-imap

Tokio-based IMAP implementation
Apache License 2.0
122 stars 42 forks source link

support IMAP IDLE/NOTIFY #18

Open dario23 opened 6 years ago

dario23 commented 6 years ago

supporting server-initiated notifications (standardized keeping one/multiple connections to the server open) using IMAP IDLE or IMAP NOTIFY extensions would be helpful, although it's not a very high priority for me currently.

StateStreams seem to be a good way to keep the client/connection info while iterating over/waiting for notifications. i'm not sure how well timeouts or actively cancelling a running command work with that, or if there's additional code needed

djc commented 6 years ago

I don't have a good use case for this today and don't have enough IMAP experience to understand what you want/need. Can you give me a sample client/server interaction of what you're looking for? I've implemented some support in imap-proto for IDLE/NOTIFY already.

dario23 commented 6 years ago

so a sample interaction would look roughly like this for IMAP NOTIFY:

0001 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE NOTIFY SPECIAL-USE] Logged in
0002 NOTIFY SET (subscribed (FlagChange SubscriptionChange MessageNew MessageExpunge))
0002 OK NOTIFY completed (0.000 + 0.000 secs).
* STATUS INBOX (MESSAGES 22413 UIDNEXT 41350 UNSEEN 1)
* STATUS INBOX (MESSAGES 22413 UIDNEXT 41350 UNSEEN 1)
* STATUS INBOX (MESSAGES 22413 UIDNEXT 41350 UNSEEN 1)
* STATUS debian.security.announce (MESSAGES 410 UIDNEXT 423 UNSEEN 1)

where between the various STATUS lines an arbitrary amount of time can pass, the server sends these updates without any trigger by the client.

for IMAP IDLE:

0001 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE NOTIFY SPECIAL-USE] Logged in
0002 EXAMINE INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft $Forwarded)
* OK [PERMANENTFLAGS ()] Read-only mailbox.
* 22413 EXISTS
* 0 RECENT
* OK [UNSEEN 22413] First unseen.
* OK [UIDVALIDITY 1408806677] UIDs valid
* OK [UIDNEXT 41350] Predicted next UID
* OK [HIGHESTMODSEQ 69038] Highest
0002 OK [READ-ONLY] Examine completed (0.000 + 0.000 secs).
0003 IDLE
+ idling
* 22414 EXISTS
* 1 RECENT

where IDLE works on only one selected folder and NOTIFY for an arbitrary set you specify (with special atoms like "subscribed").

i'd be happy to start hacking on a/some PR(s) as well if you're not against bigger features outside the base IMAP rfc 3501.

djc commented 6 years ago

That would be great! Not against extension support, but it might be good if you can lay out your plan in a bit more detail -- I'd like to get a sense of the amount of complexity that you want to add.

dignifiedquire commented 5 years ago

It is pretty easy to get the basics working by adding an idle command to the command builder and issue it. But there is a complication that arises after that. One does not want to consume all responses, but rather consume some, and then cancel the stream by issuing another command. But I am unclear on how I could do that with the current ResponseStream + StateStream, as they don't contain any solution for cancelation. Maybe sth like https://github.com/jonhoo/stream-cancel could be adapted to be used, or I might just be missing something. Any tips would be appreciated

djc commented 5 years ago

It sounds to me like you'd want to split the Stream and then at some point drop one of the parts of the split stream. Currently tokio-imap is only getting fairly passive maintenance, so if you want further movement on this I'm afraid you'll need to do the legwork to come up with a design proposal.