home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / common / emailaccount.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  19.3 KB  |  540 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. from common import AccountBase, profile, netcall, pref, UpdateMixin, FromNetMixin
  6. from util.observe import ObservableList
  7. from common.actions import action
  8. from common.notifications import fire
  9. from urllib import quote
  10. from util.net import UrlQuery
  11. from traceback import print_exc
  12. import os
  13. import shlex
  14. import locale
  15. from subprocess import Popen
  16. from os.path import expandvars
  17. from logging import getLogger
  18. log = getLogger('emailaccount')
  19. info = log.info
  20. from util import urlprotocol, try_this, get_func_name, call_later, callsback
  21. from path import path
  22. from prefs import localprefprop
  23. import util
  24.  
  25. class EmailAccount(AccountBase, UpdateMixin, FromNetMixin):
  26.     retry_time = 3
  27.     error_max = 3
  28.     
  29.     def __init__(self, enabled = True, updateNow = True, **options):
  30.         AccountBase.__init__(self, **options)
  31.         UpdateMixin.__init__(self, **options)
  32.         FromNetMixin.__init__(self, **options)
  33.         self.emails = ObservableList()
  34.         self.count = 0
  35.         self.seen = set()
  36.         self._dirty_error = True
  37.         log.info('Created EmailAccount: %r. Setting enabled to %r', self, enabled)
  38.         self.enabled = enabled
  39.  
  40.     
  41.     def timestamp_is_time(self, tstamp):
  42.         return True
  43.  
  44.     
  45.     def mailclient_localprefs_key(acct):
  46.         return '/'.join([
  47.             acct.protocol,
  48.             acct.username,
  49.             'mailclient'])
  50.  
  51.     mailclient = localprefprop(mailclient_localprefs_key, None)
  52.     email_address = util.iproperty('get_email_address', 'set_email_address')
  53.     
  54.     def get_email_address(self):
  55.         EmailAddress = EmailAddress
  56.         import util
  57.         
  58.         try:
  59.             return str(EmailAddress(self.name, self.default_domain)).decode('ascii')
  60.         except AttributeError:
  61.             
  62.             try:
  63.                 ret = None if '@' in self.name else self.name + '@' + self.default_domain
  64.                 return str(ret).decode('ascii')
  65.             except Exception:
  66.                 return self.name.decode('ascii', 'replace')
  67.             except:
  68.                 None<EXCEPTION MATCH>Exception
  69.             
  70.  
  71.             None<EXCEPTION MATCH>Exception
  72.  
  73.  
  74.     
  75.     def set_email_address(self, val):
  76.         pass
  77.  
  78.     
  79.     def display_name(self):
  80.         return (try_this,)((lambda : getattr(self, pref('email.display_attr'))), self.email_address)
  81.  
  82.     display_name = property(display_name)
  83.     
  84.     def on_error(self, task = None):
  85.         self.error_count += 1
  86.         log.error("%r's error count is now: %d", self, self.error_count)
  87.         log.error('on_error called from %s', get_func_name(2))
  88.         del self.emails[:]
  89.  
  90.     
  91.     def bad_pw(self):
  92.         log.info('%r: changing state to BAD_PASSWORD', self)
  93.         self.set_offline(self.Reasons.BAD_PASSWORD)
  94.         self.timer.stop()
  95.  
  96.     
  97.     def no_mailbox(self):
  98.         log.info('%r: changing state to NO_MAILBOX', self)
  99.         self.set_offline(self.Reasons.NO_MAILBOX)
  100.         self.timer.stop()
  101.  
  102.     
  103.     def __repr__(self):
  104.         r = AccountBase.__repr__(self)[:-1]
  105.         r += ', '
  106.         None += r if self.enabled else 'disabled'
  107.         return r + '>'
  108.  
  109.     
  110.     def web_login(self):
  111.         if pref('privacy.www_auto_signin'):
  112.             pass
  113.         return self.state in (self.Statuses.ONLINE, self.Statuses.CHECKING)
  114.  
  115.     web_login = property(web_login)
  116.     
  117.     def error_link(self):
  118.         reason = self.Reasons
  119.         linkref = {
  120.             reason.BAD_PASSWORD: (('Edit Account',), (lambda : profile.account_manager.edit(self, True))),
  121.             reason.CONN_FAIL: (('Retry',), (lambda : self.update_now())) }
  122.         if self.offline_reason in linkref:
  123.             (name, callback) = linkref[self.offline_reason]
  124.             return (name, callback)
  125.         else:
  126.             return None
  127.  
  128.     
  129.     def sort_emails(self, new = None):
  130.         self.emails.sort()
  131.         if new is not None:
  132.             new.sort()
  133.         
  134.  
  135.     
  136.     def _received_emails(self, emails, inboxCount = None):
  137.         self.emails[:] = list(emails)
  138.         new = []
  139.         for email in self.emails:
  140.             if email.id not in self.seen:
  141.                 new.append(email)
  142.                 self.seen.add(email.id)
  143.                 import plugin_manager.plugin_hub as plugin_hub
  144.                 plugin_hub.act('digsby.mail.newmessage.async', self, email)
  145.                 continue
  146.         
  147.         self.sort_emails(new)
  148.         info('%s - %s: %d new emails', self.__class__.__name__, self.name, len(new))
  149.         if inboxCount is not None:
  150.             self._setInboxCount(inboxCount)
  151.         
  152.         self.new = new
  153.         if new:
  154.             profile.when_active(self.fire_notification)
  155.         
  156.         self.error_count = 0
  157.         self.change_state(self.Statuses.ONLINE)
  158.         self._dirty_error = True
  159.  
  160.     
  161.     def fire_notification(self):
  162.         if self.new:
  163.             self._notify_emails(self.new)
  164.         
  165.  
  166.     
  167.     def _notify_emails(self, emails, always_show = None, allow_click = True):
  168.         if self.enabled:
  169.             None(fire, email.new = 'emails', emails = 'onclick' if allow_click else None, always_show = always_show, icon = self.icon)
  170.         
  171.  
  172.     
  173.     def _setInboxCount(self, inboxCount):
  174.         self.setnotifyif('count', inboxCount)
  175.  
  176.     
  177.     def OnComposeEmail(self, to = '', subject = '', body = '', cc = '', bcc = '', callback = None):
  178.         for name in ('to', 'subject', 'body', 'cc', 'bcc'):
  179.             pass
  180.         
  181.         if self.mailclient and (try_this,)((lambda : self.mailclient.startswith('file:')), False):
  182.             os.startfile(self.mailclient[5:])
  183.         elif self.mailclient == 'sysdefault':
  184.             kw = { }
  185.             for name in ('subject', 'body', 'cc', 'bcc'):
  186.                 if vars()[name]:
  187.                     kw[name] = vars()[name]
  188.                     continue
  189.             
  190.             query = UrlQuery('mailto:' + quote(to), **kw)
  191.             log.info('OnComposeEmail is launching query: %s' % query)
  192.             os.startfile(query)
  193.         else:
  194.             url = self.compose(to, subject, body, cc, bcc)
  195.             if url:
  196.                 import wx
  197.                 wx.LaunchDefaultBrowser(url)
  198.             
  199.         callback.success()
  200.  
  201.     OnComposeEmail = action()(callsback(OnComposeEmail))
  202.     
  203.     def client_name(self):
  204.         mc = self.mailclient
  205.         if mc in (None, True, False):
  206.             return self.protocol_info().name
  207.         elif mc.startswith('file:'):
  208.             return path(mc).basename().title()
  209.         elif mc == 'sysdefault':
  210.             return ''
  211.         else:
  212.             log.warning('unknown mailclient attribute in %r: %s', self, mc)
  213.             return _('Email Client')
  214.  
  215.     client_name = property(client_name)
  216.     
  217.     def OnClickInboxURL(self, e = None):
  218.         if self.mailclient:
  219.             url = self.start_client_email()
  220.             if url is None:
  221.                 return None
  222.             
  223.         else:
  224.             url = self.inbox_url
  225.         import wx
  226.         wx.LaunchDefaultBrowser(self.inbox_url)
  227.  
  228.     OnClickInboxURL = action()(OnClickInboxURL)
  229.     OnClickHomeURL = OnClickInboxURL
  230.     
  231.     def OnClickEmail(self, email):
  232.         if self.mailclient:
  233.             self.start_client_email(email)
  234.         else:
  235.             import wx
  236.             wx.LaunchDefaultBrowser(self.urlForEmail(email))
  237.         cname = self.__class__.__name__
  238.         if self.web_login and cname not in ('IMAPMail', 'PopMail'):
  239.             self._remove_email(email)
  240.         
  241.  
  242.     
  243.     def OnClickSend(self, to = '', subject = '', body = '', cc = '', bcc = '', callback = None):
  244.         getattr(self, 'send_email', self.OnComposeEmail)(to = to, subject = subject, body = body, cc = cc, bcc = bcc, callback = callback)
  245.  
  246.     OnClickSend = callsback(OnClickSend)
  247.     
  248.     def start_client_email(self, email = None):
  249.         log.info('mailclient: %s', self.mailclient)
  250.         import os.path as os
  251.         if self.mailclient == 'sysdefault':
  252.             launch_sysdefault_email(email)
  253.         elif (try_this,)((lambda : self.mailclient.startswith('file:')), False):
  254.             filename = self.mailclient[5:]
  255.             if os.path.exists(filename):
  256.                 os.startfile(filename)
  257.             else:
  258.                 log.warning('cannot find %s', filename)
  259.         
  260.  
  261.     
  262.     def __len__(self):
  263.         return self.count
  264.  
  265.     
  266.     def __iter__(self):
  267.         return iter(self.emails)
  268.  
  269.     can_has_preview = False
  270.     
  271.     def icon(self):
  272.         skin = skin
  273.         import gui
  274.         try_this = try_this
  275.         import util
  276.         return (None, try_this)((lambda : skin.get('serviceicons.%s' % self.protocol)), None)
  277.  
  278.     icon = property(icon)
  279.     
  280.     def inbox_url(self):
  281.         raise NotImplementedError
  282.  
  283.     inbox_url = property(inbox_url)
  284.     
  285.     def observe_count(self, callback):
  286.         self.add_gui_observer(callback, 'count')
  287.         self.emails.add_gui_observer(callback)
  288.  
  289.     
  290.     def unobserve_count(self, callback):
  291.         self.remove_gui_observer(callback, 'count')
  292.         self.emails.remove_gui_observer(callback)
  293.  
  294.     
  295.     def observe_state(self, callback):
  296.         self.add_gui_observer(callback, 'enabled')
  297.         self.add_gui_observer(callback, 'state')
  298.  
  299.     
  300.     def unobserve_state(self, callback):
  301.         self.remove_gui_observer(callback, 'enabled')
  302.         self.remove_gui_observer(callback, 'state')
  303.  
  304.     
  305.     def header_funcs(self):
  306.         return [
  307.             ('Inbox', self.OnClickInboxURL),
  308.             ('Compose', self.OnComposeEmail)]
  309.  
  310.     header_funcs = property(header_funcs)
  311.     
  312.     def _get_options(self):
  313.         opts = UpdateMixin.get_options(self)
  314.         return opts
  315.  
  316.     
  317.     def update_info(self, **info):
  318.         flush_state = False
  319.         self.frozen().__enter__()
  320.         
  321.         try:
  322.             for k, v in info.iteritems():
  323.                 if k in ('password', 'username', 'server') and getattr(self, k, None) != v:
  324.                     flush_state = True
  325.                 
  326.                 self.setnotifyif(k, v)
  327.         finally:
  328.             pass
  329.  
  330.         profile.update_account(self)
  331.         if flush_state:
  332.             log.info('Resetting state for %r', self)
  333.             self._reset_state()
  334.         
  335.         self._dirty_error = True
  336.  
  337.     
  338.     def _reset_state(self):
  339.         return NotImplemented
  340.  
  341.     
  342.     def update(self):
  343.         if self.update == EmailAccount.update:
  344.             log.warning('not implemented: %s.update', self.__class__.__name__)
  345.             raise NotImplementedError
  346.         
  347.         if not self.enabled:
  348.             return None
  349.         
  350.         log.info('%s (%s) -- preparing for update. update called from: %s', self, self.state, get_func_name(2))
  351.         if self.state == self.Statuses.OFFLINE:
  352.             self.change_state(self.Statuses.CONNECTING)
  353.         elif self.state == self.Statuses.ONLINE:
  354.             self.change_state(self.Statuses.CHECKING)
  355.         elif self.state == self.Statuses.CONNECTING:
  356.             if not self.error_count:
  357.                 log.error('%s -- called update while connecting, and no errors! disconnecting...', self)
  358.                 self.set_offline(self.Reasons.CONN_FAIL)
  359.             
  360.         else:
  361.             log.error('Unexpected state for update: %r', self.state)
  362.  
  363.     
  364.     def update_now(self):
  365.         netcall(self.update)
  366.         self.timer.reset(self.updatefreq)
  367.  
  368.     update_now = action((lambda self: self.state != self.Statuses.CHECKING))(update_now)
  369.     
  370.     def tell_me_again(self):
  371.         if self.emails:
  372.             emails = self.emails
  373.             allow_click = True
  374.         else:
  375.             Email = Email
  376.             import mail.emailobj
  377.             emails = [
  378.                 Email(id = -1, fromname = _('No unread mail'))]
  379.             allow_click = False
  380.         self._notify_emails(emails, always_show = [
  381.             'Popup'], allow_click = allow_click)
  382.  
  383.     tell_me_again = action()(tell_me_again)
  384.     
  385.     def auth(self):
  386.         netcall(self.authenticate)
  387.  
  388.     auth = action()(auth)
  389.     
  390.     def Connect(self):
  391.         self.change_reason(self.Reasons.NONE)
  392.         call_later(1.5, self.update)
  393.  
  394.     
  395.     def compose(self, to, subject, body, cc, bcc):
  396.         raise NotImplementedError
  397.  
  398.     compose = action()(compose)
  399.     
  400.     def urlForEmail(self, email):
  401.         raise NotImplementedError
  402.  
  403.     
  404.     def open(self, email_message):
  405.         if type(self) is EmailAccount:
  406.             raise NotImplementedError
  407.         
  408.  
  409.     open = action()(open)
  410.     
  411.     def _remove_email(self, email_message):
  412.         
  413.         try:
  414.             self.emails.remove(email_message)
  415.         except ValueError:
  416.             pass
  417.  
  418.         self.setnotifyif('count', self.count - 1)
  419.  
  420.     
  421.     def markAsRead(self, email_message):
  422.         self._remove_email(email_message)
  423.  
  424.     markAsRead = action()(markAsRead)
  425.     
  426.     def delete(self, email_message):
  427.         self._remove_email(email_message)
  428.  
  429.     delete = action()(delete)
  430.     
  431.     def archive(self, email_message):
  432.         self._remove_email(email_message)
  433.  
  434.     archive = action()(archive)
  435.     
  436.     def reportSpam(self, email_message):
  437.         self._remove_email(email_message)
  438.  
  439.     reportSpam = action()(reportSpam)
  440.  
  441. import re
  442. env_re = re.compile('(%.*?%)')
  443.  
  444. def mailclient_error():
  445.     fire('error', title = _('No System Email Client'), msg = _('No system email client is configured.'), details = '')
  446.  
  447.  
  448. def mailclient_launch_error(msg):
  449.     fire('error', title = _('Error launching system mail client'), msg = msg, details = '')
  450.  
  451.  
  452. def envexpand(s):
  453.     parts = env_re.split(s)
  454.     out = []
  455.     for part in parts:
  456.         if part.startswith('%') and part.endswith('%'):
  457.             part = '${' + part[1:-1] + '}'
  458.         
  459.         out.append(part)
  460.     
  461.     return expandvars(''.join(out))
  462.  
  463.  
  464. def launch_sysdefault_email(email = None):
  465.     import wx
  466.     if 'wxMSW' in wx.PlatformInfo:
  467.         is_vista = is_vista
  468.         import gui.native.win.winutil
  469.         if is_vista():
  470.             return launch_sysdefault_email_vista(email)
  471.         
  472.     
  473.     mailclient = urlprotocol.get('mailto')
  474.     log.info('mail client is %r', mailclient)
  475.     if not mailclient.strip():
  476.         mailclient_error()
  477.         return False
  478.     
  479.     mailclient = envexpand(mailclient)
  480.     
  481.     try:
  482.         args = shlex.split(mailclient.encode(locale.getpreferredencoding()))
  483.         args = args[:1]
  484.         log.info('launching %r', args)
  485.         if Popen(args):
  486.             return True
  487.     except Exception:
  488.         e = None
  489.         print_exc()
  490.         msg = e.message
  491.  
  492.     
  493.     try:
  494.         msg = _('Could not start system mail client %r.') % mailclient
  495.     except Exception:
  496.         msg = _('Could not start system mail client.')
  497.         print_exc()
  498.  
  499.     mailclient_launch_error(msg)
  500.  
  501.  
  502. def launch_sysdefault_email_vista(email = None):
  503.     import _winreg as reg
  504.     
  505.     try:
  506.         key = reg.OpenKey(reg.HKEY_CURRENT_USER, 'Software\\Clients\\mail', 0, reg.KEY_READ)
  507.         (client_name, t) = reg.QueryValueEx(key, None)
  508.         log.info('canonical name for mail client: %r', client_name)
  509.         mc_key_name = 'SOFTWARE\\Clients\\Mail\\%s\\shell\\open\\command'
  510.         mc_key = reg.OpenKey(reg.HKEY_LOCAL_MACHINE, mc_key_name % client_name, 0, reg.KEY_READ)
  511.         (program, t) = reg.QueryValueEx(mc_key, None)
  512.         log.info('mail client shell launch string: %r', program)
  513.     except Exception:
  514.         e = None
  515.         print_exc()
  516.         return mailclient_error()
  517.  
  518.     if isinstance(program, unicode):
  519.         import sys
  520.         program = program.encode(sys.getfilesystemencoding())
  521.     
  522.     
  523.     try:
  524.         program = envexpand(program)
  525.         import subprocess
  526.         import shlex
  527.         args = shlex.split(program)
  528.         log.info('launching vista mail client: %r', args)
  529.         subprocess.Popen(args)
  530.         return True
  531.     except Exception:
  532.         e = None
  533.         print_exc()
  534.         mailclient_launch_error(_('Could not start system mail client.'))
  535.  
  536.  
  537. if __name__ == '__main__':
  538.     launch_sysdefault_email_vista()
  539.  
  540.