home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 October / maximum-cd-2011-10.iso / DiscContents / digsby_setup.exe / lib / common / emailaccount.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-06-22  |  22.3 KB  |  638 lines

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