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