Package screenlets :: Package plugins :: Module Mail
[hide private]
[frames] | no frames]

Source Code for Module screenlets.plugins.Mail

  1  # This application is released under the GNU General Public License  
  2  # v3 (or, at your option, any later version). You can find the full  
  3  # text of the license under http://www.gnu.org/licenses/gpl.txt.  
  4  # By using, editing and/or distributing this software you agree to  
  5  # the terms and conditions of this license.  
  6  # Thank you for using free software! 
  7   
  8  #  mail module (c) Whise (Helder Fraga) 2008 <helder.fraga@hotmail.com> 
  9   
 10  import screenlets 
 11  import dbus 
 12  import os 
 13  import sys 
 14  import stat 
 15  import gettext 
 16  import re 
 17  import urllib 
 18  gettext.textdomain('screenlets') 
 19  gettext.bindtextdomain('screenlets', screenlets.INSTALL_PREFIX +  '/share/locale') 
 20  import gobject 
 21  import socket 
 22  import threading 
 23  try: 
 24          import poplib 
 25  except ImportError, err: 
 26          print " !!!Please install python poplib :", err 
 27  try: 
 28          import imaplib 
 29  except ImportError, err: 
 30          print " !!!Please install python imaplib :", err 
 31   
 32  try: 
 33          import gnomevfs 
 34  except ImportError, err: 
 35          print " !!!Please install python gnomevfs :", err 
 36   
 37   
38 -def get_KMail_num():
39 """This gets the unread mail number of kmail""" 40 kmail = commands.getoutput("dcop kmail default checkMail; sleep 5; echo ' ' | tr -d '\n'; dcop kmail KMailIface getFolder /Krealia/Inbox > /dev/null; dcop 'DCOPRef(kmail,FolderIface)' unreadMessages | tr -d '\n'; echo ' '") 41 if kmail.find("ERROR: Couldn't attach to DCOP server!") != -1: 42 return None 43 else: 44 return kmail
45
46 -def get_GMail_Num(login, password):
47 """This output the number of messages of gmail box""" 48 f = os.popen("wget --no-check-certificate -qO - https://%s:%s@mail.google.com/mail/feed/atom" % (urllib.pathname2url(login), urllib.pathname2url(password))) 49 a = f.read() 50 f.close() 51 match = re.search("<fullcount>([0-9]+)</fullcount>", a) 52 if match == None: 53 return None 54 else: 55 return match.group(1)
56 57 58
59 -def get_Mail_Num(server, login, passwd):
60 """This output the number of messages of mail box""" 61 try: 62 m = poplib.POP3_SSL(server) 63 except: 64 try: 65 m = poplib.POP3(server) 66 except: 67 return None 68 69 m.user(login) 70 m.pass_(passwd) 71 out = m.stat() 72 m.quit() 73 num = out[0] 74 return num
75 76
77 -def send_mail(smtp_server,fromaddr,toaddrs, subject,msg):
78 """Send mail via SMTP""" 79 import smtplib 80 server = smtplib.SMTP(smtp_server) 81 server.sendmail(fromaddr, toaddrs, subject + msg) 82 server.quit()
83 84 #------CLASSES---------- 85 #----------------------- 86 87 # error messages 88 MSG_CONNECTION_FAILED = "Error while connecting to server." 89 MSG_FETCH_MAILS_FAILED = "Unable to retrieve mails from server." 90 MSG_AUTH_FAILED = """Error on login - invalid login data given? Some hosts 91 may block connections for a certain interval before allowing reconnects.""" 92 93 # the current operational status of the mailcheck
94 -class MailboxStatus(object):
95 UNKNOWN = 0 96 ALL_READ = 1 97 UNREAD_MAIL = 2 98 NEW_MAIL = 3
99 100 # the mailcheck status
101 -class MailCheckStatus(object):
102 REFRESH = 1 103 GOT_MAIL = 2 104 ERROR = 3 105 IDLE = 100
106
107 -class MailCheckBackend (gobject.GObject):
108 """The backend class which performs checking for mail and offers access 109 to the current mail-backend. By subclassing this class you can add multiple 110 mail-backends to the MailCheckScreenlet (e.g. pop3, maildir, imap, 111 gmail, ...).""" 112 113 114 __gsignals__ = { 115 'check_finished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_INT, gobject.TYPE_INT,)) 116 } 117
118 - def __init__ (self, name, screenlet):
119 gobject.GObject.__init__(self) 120 # properties 121 self.name = name # name of backend 122 self.screenlet = screenlet # assigned MailCheckScreenlet 123 self.refreshing = False # not refreshing yet 124 self.unseen_count = 0 # number of unread messages on the server 125 self.status = MailCheckStatus.IDLE # status of the mailcheck backend 126 self.mailbox_status = MailboxStatus.UNKNOWN # status of the mailbox 127 self.error = '' # human-readable error message 128 self.options = [] # ???additonal ptions for backend 129 self.thread = None 130 self.mailcount = 0 #
131
132 - def check_mail (self):
133 """This handler should be overridden by subclasses to add new types 134 of checking mails in a backend. This handler has to set self.mailcount 135 to the number of mails found in the backend. The return value is 136 ignored, set self.error and self.status to return results."""
137
138 - def stop (self):
139 """Stop receiving mails from the backend. This should be overridden 140 by subclasses.""" 141 self.thread = None
142
143 - def start (self):
144 """Start receiving mails from the backend. Runs self.__execute as 145 a separate thread.""" 146 self.thread = threading.Thread(target=self.__execute).start()
147
148 - def __execute (self):
149 """Execute the thread and call the check-mail function.""" 150 # set status to REFRESH and call check_mail-handler to fetch mails 151 self.refreshing = True 152 self.check_mail() 153 self.emit('check_finished', self.status, self.mailbox_status) 154 # not refreshing anymore 155 self.refreshing = False
156 157 158 # IMAPBackend was contributed by Robert Gartler - thanks :)
159 -class IMAPBackend(MailCheckBackend):
160 """A backend for retrieving the mailcount from an IMAP server.""" 161
162 - def __init__ (self, screenlet):
163 # call super 164 MailCheckBackend.__init__(self, 'IMAP', screenlet) 165 self.server = None
166
167 - def check_mail(self):
168 # set default timeout for all socket connections to 30 secs 169 socket.setdefaulttimeout(30000) 170 print "IMAPBackend: Connecting to IMAP-server ... please wait." 171 self.status = MailCheckStatus.REFRESH 172 try: 173 self.server = imaplib.IMAP4_SSL(self.screenlet.imap_host) 174 except: 175 try: 176 self.server = imaplib.IMAP4(self.screenlet.imap_host) 177 except: 178 self.error = MSG_CONNECTION_FAILED 179 self.status = MailCheckStatus.ERROR 180 return False 181 user, passwd = self.screenlet.imap_account 182 try: 183 self.server.login(user, passwd) 184 except: 185 self.error = MSG_AUTH_FAILED 186 self.status = MailCheckStatus.ERROR 187 self.server.logout() 188 return False 189 190 self.server.select() 191 typ, data = self.server.search(None, 'UNSEEN') 192 if typ == 'OK': 193 self.unseen_count = len(data[0].split()) 194 if self.unseen_count > 0: 195 typ, data = self.server.search(None, 'NEW') 196 if typ == 'OK': 197 if len(data[0].split()) > 0: 198 self.mailbox_status = MailboxStatus.NEW_MAIL 199 print "NEW_MAIL" 200 else: 201 self.mailbox_status = MailboxStatus.UNREAD_MAIL 202 print "UNREAD_MAIL" 203 else: 204 print "IMAP error (checking new count): " + typ 205 else: 206 self.mailbox_status = MailboxStatus.ALL_READ 207 self.status = MailCheckStatus.IDLE 208 else: 209 print "IMAP error (checking unseen count): " + typ 210 self.error = MSG_FETCH_MAILS_FAILED 211 self.status = MailCheckStatus.ERROR 212 self.mailbox_status = MailboxStatus.UNKNOWN 213 self.server.close() 214 self.server.logout() 215 return False
216
217 - def stop(self):
218 if self.server: 219 self.server.close() 220 self.server.logout() 221 self.thread.join() 222 self.thread = None
223
224 -class Mailer(object):
225 """ 226 Class that retrieve the information from an Imap, Pop or mbox account 227 228 All the email-related operation lies in this few lines 229 """ 230 import imaplib 231 import poplib 232 import mailbox 233 from sys import exc_info 234 from os import stat, utime, path, listdir 235 236
237 - def __init__(self, config):
238 self.config=config 239 self.last_size=-1 240 self.size=-1 241 self.mbox_size = 0 242 self.mbox_mtime = 0
243
244 - def __call__(self):
245 self.last_size=self.size 246 247 try: 248 # IMAP4 249 # 250 if self.config['method']=='imap4': 251 s = self.imaplib.__dict__['IMAP4'+['','_SSL'] 252 [self.config['ssl']]]\ 253 (self.config['host']) 254 s.login(self.config['user_name'],self.config['user_password']) 255 s.select() 256 size = len(s.search(None, 'UNSEEN')[1][0].split()) 257 s.logout() 258 259 # POP3 260 # 261 elif self.config['method']=='pop3': 262 s = self.poplib.__dict__['POP3'+['','_SSL'] 263 [self.config['ssl']]]\ 264 (self.config['host']) 265 s.user(self.config['user_name']) 266 s.pass_(self.config['user_password']) 267 size = len(s.list()[1]) 268 269 # Maildir 270 # 271 # This was reported to work with qmail, but it is untested with 272 # other mail servers -- for maximum portability, one could 273 # still rewrite next four lines using the mailbox Python module 274 # (in core libraries). 275 # 276 elif self.config['method'] == 'maildir': 277 mdir_path = getenv('MAILDIR', self.config['mailspool']) 278 mdir_new = self.path.join(self.path.expanduser(mdir_path), 'new') 279 280 size = len([f for f in self.listdir(mdir_new) if f[0] != '.']) 281 282 # Unix mbox 283 # 284 elif self.config['method'] == 'mbox': 285 mbox_path = getenv('MAIL',self.config['mailspool']) 286 # Get mbox inode properties 287 # 288 s = self.stat(mbox_path) 289 if (s.st_size == self.mbox_size and 290 s.st_mtime == self.mbox_mtime): 291 size = self.last_size # mbox has not changed on disk 292 else: 293 size = 0 # mbox has changed 294 for m in self.mailbox.PortableUnixMailbox(file(mbox_path)): 295 if m.get('status','N').find('N') != -1: 296 size += 1 297 298 # Trick the system into thinking the mbox inode was not 299 # accessed since last modification. From 'manual.txt' 300 # of mutt 1.5.8: 301 # 302 # [ ... new mail is detected by comparing the last 303 # modification time to the last access time. 304 # Utilities like biff or frm or any other program 305 # which accesses the mailbox might cause Mutt to 306 # never detect new mail for that mailbox if they 307 # do not properly reset the access time. 308 # Backup tools are another common reason for updated 309 # access times. ] 310 # 311 self.utime(mbox_path, (s.st_atime, s.st_mtime)) 312 313 # Remember size and time 314 # 315 self.mbox_size = s.st_size 316 self.mbox_mtime = s.st_mtime 317 318 # Uknown access method 319 # 320 else: 321 raise RuntimeError('unknown access method `%s\'' % 322 self.config['method']) 323 except: 324 # Exception handling: output a significant printout 325 # 326 size = -1 327 print '='*80 328 print traceback.print_exception(*self.exc_info()) 329 print '='*80 330 print self.config 331 print '='*80 332 333 self.size = size 334 return size
335 336
337 -class POP3Backend (MailCheckBackend):
338 """A backend for retrieving the mailcount from a POP3 server.""" 339
340 - def __init__ (self, screenlet):
341 # call super 342 MailCheckBackend.__init__(self, 'POP3', screenlet) 343 self.server = None
344 # init additional attributes for this backend-type 345 # TODO: add POP3-specific options to the backend instead of having them 346 # defined in the screenlet by default (ideally they should be only shown 347 # when the POP3-backend is active 348
349 - def check_mail (self):
350 # set default timeout for all socket connections to 30 secs 351 socket.setdefaulttimeout(30000) 352 print "POP3Backend: Connecting to POP3-server ... please wait." 353 #self.screenlet.redraw_canvas() 354 try: 355 self.server = poplib.POP3_SSL(self.screenlet.pop3_server) 356 except: 357 try: 358 self.server = poplib.POP3(self.screenlet.pop3_server) 359 except: 360 self.error = MSG_CONNECTION_FAILED 361 self.status = MailCheckStatus.ERROR 362 return False 363 # authenticate 364 user, pw = self.screenlet.pop3_account 365 #print "ACCOUNT IS %s/%s!!" % (o[0], o[1]) 366 try: 367 self.server.user(user) 368 self.server.pass_(pw) 369 except: 370 self.error = MSG_AUTH_FAILED 371 self.status = MailCheckStatus.ERROR 372 self.server.quit() 373 return False 374 # get list with mails (response, list-of-mails) 375 resp = self.server.list() 376 if resp[0].startswith('+OK'): 377 messages = resp[1] 378 #print messages 379 msgnum = len(messages) 380 if msgnum > self.mailcount: 381 diff = msgnum - self.mailcount 382 self.mailcount = msgnum 383 self.mailbox_status = MailboxStatus.NEW_MAIL 384 self.status = MailCheckStatus.GOT_MAIL 385 print "GOT_MAIL" 386 elif msgnum <= self.mailcount: 387 print "set status to IDLE (POP3Backend.check_mail)" 388 self.mailbox_status = MailboxStatus.ALL_READ 389 self.mailcount = msgnum 390 self.status = MailCheckStatus.IDLE 391 print "IDLE" 392 else: 393 self.error = MSG_FETCH_MAILS_FAILED 394 self.status = MailCheckStatus.ERROR 395 #server.quit() 396 #return False 397 # close connection 398 self.server.quit() 399 return False
400
401 - def stop(self):
402 if self.server: 403 self.server.quit() 404 self.thread.join() 405 self.thread = None
406