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