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