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

Source Code for Module screenlets.plugins.Mail

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