1# vim:fileencoding=utf-8:noet
2from __future__ import (unicode_literals, division, absolute_import, print_function)
3
4import re
5
6from imaplib import IMAP4_SSL_PORT, IMAP4_SSL, IMAP4
7from collections import namedtuple
8
9from powerline.lib.threaded import KwThreadedSegment
10from powerline.segments import with_docstring
11
12
13_IMAPKey = namedtuple('Key', 'username password server port folder use_ssl')
14
15
16class EmailIMAPSegment(KwThreadedSegment):
17	interval = 60
18
19	@staticmethod
20	def key(username, password, server='imap.gmail.com', port=IMAP4_SSL_PORT, folder='INBOX', use_ssl=None, **kwargs):
21		if use_ssl is None:
22			use_ssl = (port == IMAP4_SSL_PORT)
23		return _IMAPKey(username, password, server, port, folder, use_ssl)
24
25	def compute_state(self, key):
26		if not key.username or not key.password:
27			self.warn('Username and password are not configured')
28			return None
29		if key.use_ssl:
30			mail = IMAP4_SSL(key.server, key.port)
31		else:
32			mail = IMAP4(key.server, key.port)
33		mail.login(key.username, key.password)
34		rc, message = mail.status(key.folder, '(UNSEEN)')
35		unread_str = message[0].decode('utf-8')
36		unread_count = int(re.search('UNSEEN (\d+)', unread_str).group(1))
37		return unread_count
38
39	@staticmethod
40	def render_one(unread_count, max_msgs=None, **kwargs):
41		if not unread_count:
42			return None
43		elif type(unread_count) != int or not max_msgs:
44			return [{
45				'contents': str(unread_count),
46				'highlight_groups': ['email_alert'],
47			}]
48		else:
49			return [{
50				'contents': str(unread_count),
51				'highlight_groups': ['email_alert_gradient', 'email_alert'],
52				'gradient_level': min(unread_count * 100.0 / max_msgs, 100),
53			}]
54
55
56email_imap_alert = with_docstring(EmailIMAPSegment(),
57('''Return unread e-mail count for IMAP servers.
58
59:param str username:
60	login username
61:param str password:
62	login password
63:param str server:
64	e-mail server
65:param int port:
66	e-mail server port
67:param str folder:
68	folder to check for e-mails
69:param int max_msgs:
70	Maximum number of messages. If there are more messages then max_msgs then it
71	will use gradient level equal to 100, otherwise gradient level is equal to
72	``100 * msgs_num / max_msgs``. If not present gradient is not computed.
73:param bool use_ssl:
74	If ``True`` then use SSL connection. If ``False`` then do not use it.
75	Default is ``True`` if port is equal to {ssl_port} and ``False`` otherwise.
76
77Highlight groups used: ``email_alert_gradient`` (gradient), ``email_alert``.
78''').format(ssl_port=IMAP4_SSL_PORT))
79