5
from lib import feedparser
6
from lib.common import *
7
from lib.accountmanager import AccountManager
8
from notifier import Notifier
10
from lib.pop3 import *
11
from lib.imap import *
14
def __init__(self, account_id, set_status_cb):
15
self.account_id = account_id
16
self.set_status_cb = set_status_cb
19
self.notifier = Notifier()
23
After this method is invoked, the checer must consider
24
all mails as not notified
26
raise NotImplementedError()
28
def notify_error(self, error, text, f):
29
self.notifier.notify(error, text, msec = 10000,
30
buttons = False, error = True, force = f)
32
def notify_msg(self, mailbox, count, mails):
33
subject_i18n = _(u"<b>Subject:</b>")
34
author_i18n = _(u"<b>From:</b>")
37
mailboxname = _("<b>Box:</b> %s") % mailbox
39
for author, subject in mails:
41
author = unicode(author, "utf-8")
42
except UnicodeDecodeError:
43
author = unicode(author, "latin-1", "replace")
47
subject = unicode(subject, "utf-8")
48
except UnicodeDecodeError:
49
subject = unicode(subject, "latin-1", "replace")
53
message += u"%s %s\n%s %s\n%s\n\n" % \
54
(subject_i18n, subject,
55
author_i18n, author, mailboxname)
57
message += u"%s %s\n%s %s\n%s\n\n" % \
58
(subject_i18n, _("Unknown"),
59
author_i18n, _("Unknown"), mailboxname)
61
title = _("There are %s new mails") % total
63
title = _("There is a new mail")
65
self.set_status_cb(self.account_id, count, title, message)
69
Must return a list of 3 elements. First element must
70
be the mailbox name, second the message count into mailbox,
71
third element a list of tuple. Each
72
tuple must contain the from and subject field of the email
74
["test@gmail.com", 2, [ ["Test Mailer <test@domain.com>", "This is the subject"],
75
["Second <sec@test.com>", "Second Subject"] ]]
77
raise NotImplementedError()
79
def update_info(self, account):
81
This method receive an account dic and update checker info
84
raise NotImplementedError()
86
class GmailChecker(BaseChecker):
87
def __init__(self, account_id, status_cb, user, password):
89
self.password = password
91
BaseChecker.__init__(self, account_id, status_cb)
97
ah = urllib2.HTTPBasicAuthHandler()
98
ah.add_password('New mail feed', GMAIL_URL, \
99
self.username, self.password)
100
op = urllib2.build_opener(ah)
101
urllib2.install_opener(op)
102
res = urllib2.urlopen(GMAIL_ATOM_URL)
103
return ''.join(res.readlines())
105
def update_info(self, account):
106
self.username = account["username"]
107
self.password = account["password"]
114
if self.checking: return
117
print "checking gmail account %s ..." % self.username
120
feed = self.getfeed()
121
except urllib2.HTTPError, e:
122
if str(e) == "HTTP Error 401: Unauthorized":
123
msg = _("Invalid username or password! Please check your settings!")
127
error = _("Gmail Error on account %s") % self.username
128
self.notify_error(error, msg, True)
129
self.checking = False
133
self.notify_error(error, msg, False)
134
self.checking = False
140
atom = feedparser.parse(feed)
141
except Exception, detail:
142
print "Warning: Exception while parsing gmail feeds", detail
143
self.notify_error(_("Gmail Warning"), _("Exception while parsing gmail feeds", False))
144
self.checking = False
147
count = len(atom.entries)
149
mailbox = "%s@gmail.com" % self.username
153
self.checking = False
154
#return mailbox, 0, mails
157
if count < MAX_NOTIFIED_MAILS:
160
loop = MAX_NOTIFIED_MAILS
164
for i in xrange(loop):
165
link = atom.entries[i].link
166
tmp = link[link.find("message_id"):]
167
message_id = tmp[:tmp.find("&")].split("=")[1]
169
if message_id not in self.notified:
171
self.notified.append(message_id)
172
title = atom.entries[i].title
173
author = atom.entries[i].author
174
mails.append([author, title])
177
self.notify_msg(mailbox, count, [])
179
self.notify_msg(mailbox, count, mails)
181
self.checking = False
183
class POP3Checker(BaseChecker):
184
def __init__(self, account_id, status_cb, username, password, server, port, ssl):
185
self.username = username
191
self.popbox = PopBox(username, password, server, port, ssl)
193
BaseChecker.__init__(self, account_id, status_cb)
198
def update_info(self, account):
199
username = account["username"]
200
password = account["password"]
202
self.server = account["server"]
203
self.port = account["port"]
205
if account.has_key("ssl"):
206
if account["ssl"] == "1":
208
elif account["ssl"] == "0":
211
self.popbox = PopBox(username, password, self.server, self.port, ssl)
215
if self.checking: return
218
mailbox = "%s@%s" % (self.username, self.server)
220
print "checking pop3 account %s@%s ..." % (self.username, self.server)
222
# each mail in mail: [subject, from, msgid]
223
mails = self.popbox.get_mails()
224
except PopBoxConnectionError:
225
err = _("POP3 Error")
226
msg = _("Error while connecting to %s on port %s") % (self.server,
228
self.notify_error(error, msg, False)
229
self.checking = False
231
except PopBoxAuthError:
232
err = _("POP3 Auth Error")
233
msg = _("Invalid Username or password for account %s@%s") % (self.username,
235
self.notify_error(error, msg, True)
236
self.checking = False
243
self.checking = False
245
#return mailbox, 0, returnlist
247
if count < MAX_NOTIFIED_MAILS:
250
loop = MAX_NOTIFIED_MAILS
258
if msgid not in self.notified:
263
returnlist.append([author, subject])
265
print "Warning: pop3checker cannot display the message"
267
self.notified.append(msgid)
272
self.notify_msg(mailbox, count, [])
274
self.notify_msg(mailbox, count, mails)
276
self.checking = False
278
class IMAPChecker(BaseChecker):
279
def __init__(self, account_id, status_cb, username, password,
281
use_default_mbox, mbox_dir = None):
282
self.username = username
285
self.use_default_mbox = use_default_mbox
286
self.mbox_dir = mbox_dir
290
self.imapbox = ImapBox(username, password,
292
use_default_mbox, mbox_dir)
294
BaseChecker.__init__(self, account_id, status_cb)
299
def update_info(self, account):
300
self.username = account["username"]
301
password = account["password"]
303
self.server = account["server"]
304
self.port = account["port"]
306
if account.has_key("ssl"):
307
if account["ssl"] == "1":
309
elif account["ssl"] == "0":
312
if account["use_default_mbox"] == "1":
313
use_default_mbox = True
315
use_default_mbox = False
316
mbox_dir = account["mbox"]
319
self.imapbox = ImapBox(self.username, password,
320
self.server, self.port, ssl,
321
use_default_mbox, mbox_dir)
325
if self.checking: return
328
mailbox = "%s@%s" % (self.username, self.server)
330
print "checking imap account %s@%s ..." % (self.username, self.server)
332
# each mail in mail: [subject, from, msgid]
333
mails = self.imapbox.get_mails()
334
except ImapBoxConnectionError:
335
err = _("IMAP Error")
336
msg = _("Error while connecting to %s on port %s") % (self.server,
338
self.notify_error(error, msg, False)
339
self.checking = False
341
except ImapBoxAuthError:
342
err = _("IMAP Auth Error")
343
msg = _("Invalid Username or password for account %s@%s") % (self.username,
346
self.notify_error(error, msg, True)
347
self.checking = False
354
return mailbox, 0, returnlist
356
if count < MAX_NOTIFIED_MAILS:
359
loop = MAX_NOTIFIED_MAILS
367
if msgid not in self.notified:
372
returnlist.append([author, subject])
374
print "Warning: imapchecker cannot display the message"
376
self.notified.append(msgid)
381
self.notify_msg(mailbox, count, [])
383
self.notify_msg(mailbox, count, returnlist)
385
self.checking = False
390
self.notifier = Notifier()
391
self.checkers = {} # account_id: checker, messages_count
392
self.checking = False
395
def add_status_cb(self, cb):
396
self.status_cbs.append(cb)
398
def remove_status_cb(self,cb):
399
self.status_cbs.remove(cb)
401
def set_no_accounts_cb(self, cb):
402
self.no_accounts_cb = cb
404
def init_checkers(self, no_accounts_cb):
410
am = AccountManager().get_manager()
411
accounts = am.get_accounts_dicts()
412
if accounts is None or len(accounts) == 0:
414
if no_accounts_cb is not None:
421
for account in accounts:
422
id_list.append(account["id"])
424
needed_keys = ["type", "username", "password", "enabled"]
426
for k in needed_keys:
427
if not account.has_key(k):
428
print "Warnig: bad configration"
432
if not has_needed: continue
434
if account["enabled"] == "0":
435
# we no more want this checker
436
if self.checkers.has_key(account["id"]):
437
del self.checkers[account["id"]]
440
if account["id"] in self.checkers.keys():
441
# We already have a checker for this account
442
checker, msg_count = self.checkers[account["id"]]
443
checker.update_info(account)
446
if account["type"] == "gmail":
447
tmp = GmailChecker(account["id"], self.set_status,
450
self.checkers[account["id"]] = [tmp, 0]
451
elif account["type"] == "pop3" or account["type"] == "imap":
452
user = account["username"]
453
passw = account["password"]
454
if not account.has_key("server"):
455
print "Warnig: bad configration"
457
server = account["server"]
459
if account.has_key("ssl"):
460
if account["ssl"] == "1":
462
elif account["ssl"] == "0":
464
if account["type"] == "pop3":
465
port = 110 # default pop3 port
466
if account.has_key("port"):
467
port = account["port"]
469
tmp = POP3Checker(account["id"], self.set_status,
470
user, passw, server, port, ssl)
472
port = 143 # default imap port
473
if account.has_key("port"):
474
port = account["port"]
476
if account["use_default_mbox"] == "1":
478
tmp = IMAPChecker(account["id"], self.set_status,
480
server, port, ssl, True)
482
mbox = account["mbox"]
483
tmp = IMAPChecker(user, passw,
486
self.checkers[account["id"]] = [tmp, 0]
488
print "Error: unrecognized account type"
490
# remove checker if the account no more exist
491
for id in self.checkers.keys():
492
if id not in id_list:
493
del self.checkers[id]
497
for account_id, values in self.checkers.iteritems():
501
def set_status(self, account_id, messages_count, title, message):
503
This method is only called by BaseChecker
505
checker, msgs = self.checkers[account_id]
506
self.checkers[account_id] = [checker, messages_count]
509
for checker, count in self.checkers.values():
513
self.notifier.notify(title, message, msec = 10000)
515
for cb in self.status_cbs:
516
cb(total, title, message)
519
for cb in self.status_cbs:
520
cb(total, None, None)
525
self.init_checkers(None)
528
for account_id, values in self.checkers.iteritems():
530
thread.start_new_thread(checker.check, ())
533
if __name__ == "__main__":