aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--climl/imap.py82
1 files changed, 61 insertions, 21 deletions
diff --git a/climl/imap.py b/climl/imap.py
index bd5b3ff..783b228 100644
--- a/climl/imap.py
+++ b/climl/imap.py
@@ -62,6 +62,50 @@ def connect_to_imap(conf, password):
finally:
connection.shutdown()
+
+def imap_waiter(connection):
+ '''
+ from dovecot wiki:
+ > If IDLE command is started, Dovecot never
+ > disconnects. Only if the connection is lost there will be
+ > a disconnection. A dead connection is detected by Dovecot
+ > periodically sending "I'm still here" notifications to
+ > client (imap_idle_notify_interval setting - default every
+ > 2 minutes).
+ >
+ > IMAP clients are supposed to send something before 30
+ > minutes are up, but several clients don't do this. Some
+ > Outlook versions even stop receiving new mails entirely
+ > until manual intervention if IMAP server disconnects the
+ > client.
+
+ We are a compliant client. To be compatible with a lot of servers
+ (general assumption is a 29minutes timeout), we try to redo idle-mode
+ every 24 minutes. Each call to imap_waiter is a single idle iteration.
+ Thus this function may return empty list.
+ '''
+ print('entering idle mode...')
+ connection.idle()
+ print('waiting for an event')
+ try:
+ while True:
+ events = connection.idle_check(timeout=24*60)
+ if len(events) == 1 and \
+ str(bytes(events[0][0]), encoding='ascii') == 'OK':
+ # in case of dovecot 'Ok still here' keepalives, timeout did
+ # not expired (and never will appart from a disconnection)
+ continue
+ else:
+ break
+ except KeyboardInterrupt:
+ print('quitting idle mode on interrupt.')
+ connection.idle_done()
+ raise
+ print('quitting idle mode...')
+ connection.idle_done()
+ return [i for i in events if str(bytes(i[0]), encoding='ascii') != 'OK']
+
+
def main(callback=None):
assert callback
confpath = os.path.expanduser('~/.config/climl/climl.cfg')
@@ -72,24 +116,20 @@ def main(callback=None):
password = subprocess.check_output(password_command, shell=True)
password = password.rstrip().decode('utf8')
print('got pasword:', password)
-
- #connection = connect_to_imap(conf, password)
- with connect_to_imap(conf, password) as connection:
- print('selecting folder')
- connection.select_folder(conf.get('imap.mailbox'))
- print('entering idle mode')
- connection.idle()
- print('waiting for an event')
- while True:
- try:
- result = connection.idle_check(timeout=10)
- except KeyboardInterrupt:
- break
- print('result:', result)
- print('calling callback')
- if result:
- callback('mail')
- print('end of connection')
-
-
-#main() # dev mode for now
+ while True:
+ print('connection...')
+ try:
+ with connect_to_imap(conf, password) as connection:
+ print('selecting folder', conf.get('imap.mailbox'))
+ connection.select_folder(conf.get('imap.mailbox'))
+ while True:
+ events = imap_waiter(connection)
+ if events:
+ print('events:', events)
+ print('calling callback')
+ callback('mail')
+ except (socket.error, socket.timeout):
+ pass
+ except KeyboardInterrupt:
+ break
+ print('end of connection')