home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 June / maximum-cd-2009-06.iso / DiscContents / digsby_setup.exe / lib / mail / ymail.pyo (.txt) < prev   
Encoding:
Python Compiled Bytecode  |  2009-02-26  |  18.5 KB  |  592 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. from __future__ import with_statement
  5. import traceback
  6. import cookielib
  7. import urllib2
  8. from threading import Lock
  9. from datetime import datetime
  10. from urlparse import urlparse
  11. from urllib import quote
  12. from logging import getLogger
  13. from mail import Email, MailException
  14. from util import UrlQuery, WebFormData, get_func_name, GetDefaultHandlers, threaded
  15. from util.primitives.error_handling import try_this
  16. from common.emailaccount import EmailAccount
  17. log = getLogger('YahooMail')
  18.  
  19. class YahooMailException(MailException):
  20.     pass
  21.  
  22.  
  23. class YahooMailAuthException(YahooMailException):
  24.     pass
  25.  
  26.  
  27. class YahooMailAuthRedirect(YahooMailException):
  28.     pass
  29.  
  30.  
  31. class YahooMailBadDataException(YahooMailException):
  32.     pass
  33.  
  34.  
  35. class YahooMailNoAccountException(YahooMailBadDataException):
  36.     pass
  37.  
  38. SessionIdReissue = 'Client.ClientRedirect.SessionIdReissue'
  39. ExpiredCredentials = 'Client.ExpiredCredentials'
  40. backup_server = 'us.mg1.mail.yahoo.com'
  41.  
  42. def ymail_action(func):
  43.     
  44.     def ymail_action_wrapper(self, *a, **k):
  45.         if self._current_action is None:
  46.             self._current_action = func.func_name
  47.         
  48.         
  49.         try:
  50.             return func(self, *a, **k)
  51.         except YahooMailAuthException:
  52.             e = None
  53.             self.bad_pw()
  54.         except YahooMailNoAccountException:
  55.             e = None
  56.             self.no_mailbox()
  57.         except Exception:
  58.             e = None
  59.             traceback.print_exc()
  60.         finally:
  61.             self._current_action = None
  62.  
  63.  
  64.     return threaded(ymail_action_wrapper)
  65.  
  66.  
  67. class YahooMail(EmailAccount):
  68.     protocol = 'ymail'
  69.     default_domain = 'yahoo.com'
  70.     
  71.     def __init__(self, *args, **kwargs):
  72.         EmailAccount.__init__(self, *args, **kwargs)
  73.         self.init_jar()
  74.         self.update_lock = Lock()
  75.         self.updated_emails = None
  76.         self.updated_count = None
  77.         self.isBeta = True
  78.         self._current_action = None
  79.  
  80.     
  81.     def timestamp_is_time(self, tstamp):
  82.         return False
  83.  
  84.     
  85.     def get_email_address(self):
  86.         val = getattr(self, '_default_send_address', None)
  87.         if not val:
  88.             pass
  89.         return EmailAccount.get_email_address(self)
  90.  
  91.     
  92.     def init_jar(self):
  93.         
  94.         try:
  95.             del self.u
  96.         except AttributeError:
  97.             pass
  98.  
  99.         
  100.         try:
  101.             del self._json_endpoint
  102.         except AttributeError:
  103.             pass
  104.  
  105.         self.jar = cookielib.CookieJar()
  106.         self.http_opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.jar), *GetDefaultHandlers())
  107.         self.http_opener.addheaders = [
  108.             ('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3')]
  109.  
  110.     
  111.     def get_json_endpoint(self):
  112.         
  113.         try:
  114.             return self._json_endpoint
  115.         except AttributeError:
  116.             self._json_endpoint = UrlQuery('http://' + self.hostname + '/ws/mail/v1.1/jsonrpc', appid = 'YahooMailRC')
  117.             return self._json_endpoint
  118.  
  119.  
  120.     
  121.     def set_json_endpoint(self, val):
  122.         self._json_endpoint = val
  123.  
  124.     json_endpoint = property(get_json_endpoint, set_json_endpoint)
  125.     
  126.     def _reset_state(self):
  127.         self.init_jar()
  128.         
  129.         try:
  130.             del self.u
  131.         except AttributeError:
  132.             pass
  133.  
  134.         
  135.         try:
  136.             del self._json_endpoint
  137.         except AttributeError:
  138.             pass
  139.  
  140.  
  141.     
  142.     def update(self):
  143.         log.error('ymail.update called from %s', get_func_name(2))
  144.         if self.offline_reason == self.Reasons.BAD_PASSWORD and hasattr(self, 'u'):
  145.             self.init_jar()
  146.         
  147.         EmailAccount.update(self)
  148.         self.real_update(success = self.finish_update, error = self.warning)
  149.  
  150.     
  151.     def warning(self, e = None):
  152.         log.warning('yahoo blew up: %s', e)
  153.         log.error('ymail.warning called from %s', get_func_name(2))
  154.         if isinstance(e, YahooMailAuthException):
  155.             self.bad_pw()
  156.         else:
  157.             self.on_error(self._current_action)
  158.         return True
  159.  
  160.     
  161.     def bad_pw(self):
  162.         self.init_jar()
  163.         EmailAccount.bad_pw(self)
  164.  
  165.     
  166.     def finish_update(self, update):
  167.         if self.state == self.Statuses.OFFLINE:
  168.             log.error('finish_update exiting early, state is %r, reason is %r', self.state, self.offline_reason)
  169.             return None
  170.         
  171.         if update is None:
  172.             log.warning('two updates were running at the same time')
  173.             return None
  174.         
  175.         
  176.         try:
  177.             (updated_emails, updated_count) = update
  178.             self.updated_emails = True
  179.             self._received_emails(updated_emails, updated_count)
  180.         except (TypeError, ValueError):
  181.             e = None
  182.             log.error('Invalid response from real_update: %r', update)
  183.  
  184.  
  185.     
  186.     def real_update(self):
  187.         if self.update_lock.acquire(False):
  188.             
  189.             try:
  190.                 result = self.get_yMsgs()
  191.                 if result:
  192.                     return self._process_update_result(result)
  193.                 else:
  194.                     log.info('Got bad result from get_yMsgs: %r', result)
  195.                     raise Exception('bad result')
  196.             finally:
  197.                 self.update_lock.release()
  198.  
  199.         
  200.  
  201.     real_update = threaded(real_update)
  202.     
  203.     def _process_update_result(self, result):
  204.         (msgs, incount) = result
  205.         updated_count = incount
  206.         emails = []
  207.         for from_ in msgs:
  208.             msg = None
  209.             if msg.get('flags', { }).get('isRead', False):
  210.                 continue
  211.             
  212.             if not from_:
  213.                 fromname = ''
  214.             else:
  215.                 fromname = from_.get('name', from_.get('email', ''))
  216.             e = Email(id = msg['mid'], fromname = fromname, sendtime = (try_this,)((lambda : datetime.fromtimestamp(msg['receivedDate'])), None), subject = msg.get('subject', u''), attachments = [
  217.                 True] * msg.get('flags', { }).get('hasAttachment', 0))
  218.             emails.append(e)
  219.         
  220.         updated_emails = emails
  221.         log.info('reporting %d emails', incount)
  222.         return (updated_emails, updated_count)
  223.  
  224.     
  225.     def get_auth_form(self):
  226.         import ClientForm
  227.         
  228.         try:
  229.             forms = ClientForm.ParseResponse(self.http_opener.open('https://mail.yahoo.com'), backwards_compat = False)
  230.             for f in forms:
  231.                 if f.action == 'https://login.yahoo.com/config/login':
  232.                     form = f
  233.                     break
  234.                     continue
  235.             else:
  236.                 raise AssertionError('there should be a login form here')
  237.         except Exception:
  238.             e = None
  239.             traceback.print_exc()
  240.             form = ClientForm.HTMLForm('https://login.yahoo.com/config/login?', method = 'POST')
  241.             form.new_control('hidden', '.done', {
  242.                 'value': 'http://mail.yahoo.com' })
  243.             form.new_control('text', 'login', {
  244.                 'value': self.name.encode('utf-8') })
  245.             form.new_control('text', 'passwd', {
  246.                 'value': self._decryptedpw().encode('utf-8') })
  247.             form.new_control('hidden', '.save', {
  248.                 'value': 'Sign+In' })
  249.             form.new_control('hidden', '.done', {
  250.                 'value': 'http://mail.yahoo.com' })
  251.  
  252.         form['login'] = self.name.encode('utf-8')
  253.         form['passwd'] = self._decryptedpw().encode('utf-8')
  254.         return form
  255.  
  256.     
  257.     def authenticate(self):
  258.         log.info('authenticating')
  259.         form = self.get_auth_form()
  260.         
  261.         try:
  262.             resp = self.http_opener.open(form.click())
  263.         except Exception:
  264.             e = None
  265.             raise YahooMailException('failed to load url: %r' % e)
  266.  
  267.         respdata = resp.read()
  268.         resp.close()
  269.         respurl = resp.geturl()
  270.         if '/login' in respurl:
  271.             self.jar._cookies_lock.__enter__()
  272.             
  273.             try:
  274.                 self.jar._cookies['.yahoo.com']['/']['Y']
  275.                 self.jar._cookies['.yahoo.com']['/']['T']
  276.             except KeyError:
  277.                 self.jar._cookies_lock
  278.                 self.jar._cookies_lock
  279.                 log.warning('html was: %r', respdata)
  280.                 raise YahooMailAuthException('failed to authenticate')
  281.             except:
  282.                 self.jar._cookies_lock
  283.             finally:
  284.                 pass
  285.  
  286.         elif 'replica_agree?' in respurl:
  287.             pass
  288.         elif 'verify?' in respurl:
  289.             pass
  290.         else:
  291.             raise YahooMailAuthException('failed to authenticate, response url not expected', respurl)
  292.         
  293.         try:
  294.             resp = self.http_opener.open('http://mail.yahoo.com/')
  295.         except Exception:
  296.             e = None
  297.             raise YahooMailException('failed to load url: %r' % e)
  298.  
  299.         self.u = urlparse(resp.geturl())
  300.         resp.read()
  301.         resp.close()
  302.         
  303.         try:
  304.             self.user_data = self.api('GetUserData')
  305.             self._default_send_address = self.user_data['result']['data']['userSendPref']['defaultFromAddress']
  306.             
  307.             try:
  308.                 self.isBeta = int(self.user_data['result']['data']['userFeaturePref'].get('optInState', '2')) == 2
  309.             except ValueError:
  310.                 pass
  311.  
  312.         except Exception:
  313.             traceback.print_exc()
  314.  
  315.         log.info('Authenticated successfully')
  316.  
  317.     
  318.     def hostname(self):
  319.         if not hasattr(self, 'u'):
  320.             self.authenticate()
  321.         
  322.         return self.u.hostname
  323.  
  324.     hostname = property(hostname)
  325.     
  326.     def get_yMsgs(self):
  327.         log.info('get_yMsgs')
  328.         
  329.         try:
  330.             nummessages = _[1][0]['unread']
  331.         except YahooMailAuthException:
  332.             raise 
  333.         except Exception:
  334.             nummessages = 25
  335.  
  336.         nummessages = min(nummessages, 25)
  337.         result = self.api('ListMessages', fid = 'Inbox', numMid = 0, groupBy = 'unRead', startMid = 0, numInfo = nummessages, sortKey = 'date', sortOrder = 'down')
  338.         incount = result['result']['folder']['unread']
  339.         incount = int(incount)
  340.         return (result['result']['messageInfo'], incount)
  341.  
  342.     
  343.     def sort_emails(self, new = None):
  344.         pass
  345.  
  346.     
  347.     def open_url(self, url, data = None):
  348.         log.debug('open_url called from %s', get_func_name(2))
  349.         return self._open_url(url, data)
  350.  
  351.     
  352.     def _open_url(self, url, data = None):
  353.         datastring = None if not data else ' with data: ' + data
  354.         log.info('opening url: ' + url + datastring)
  355.         
  356.         try:
  357.             response = self.http_opener.open(url, data)
  358.         except Exception:
  359.             e = None
  360.             ex = YahooMailException('failed to load url: %r' % e)
  361.             log.error('%r', ex)
  362.             raise ex
  363.         else:
  364.             log.info('httpopen succeeded')
  365.             respurl = urlparse(response.geturl())
  366.             if 'login.yahoo.com' in respurl.hostname:
  367.                 log.info('login.yahoo.com in URL -- calling authenticate')
  368.                 self.authenticate()
  369.                 return self.open_url(url, data)
  370.             
  371.             log.info('reading data from httpresponse')
  372.             strdata = response.read()
  373.             return (strdata, respurl)
  374.         finally:
  375.             if 'response' in locals():
  376.                 log.debug('closing response')
  377.                 response.close()
  378.             
  379.  
  380.  
  381.     
  382.     def delete(self, msg):
  383.         EmailAccount.delete(self, msg)
  384.         self.api('DeleteMessages', fid = 'Inbox', mid = [
  385.             msg.id])
  386.  
  387.     delete = ymail_action(delete)
  388.     
  389.     def markAsRead(self, msg):
  390.         EmailAccount.markAsRead(self, msg)
  391.         self.api('FlagMessages', fid = 'Inbox', mid = [
  392.             msg.id], setFlags = {
  393.             'read': 1 })
  394.  
  395.     markAsRead = ymail_action(markAsRead)
  396.     
  397.     def reportSpam(self, msg):
  398.         EmailAccount.reportSpam(self, msg)
  399.         mark = dict(FlagMessages = dict(fid = 'Inbox', mid = [
  400.             msg.id], setFlags = {
  401.             'spam': 1,
  402.             'read': 1 }))
  403.         move = dict(MoveMessages = dict(sourceFid = 'Inbox', destinationFid = '%40B%40Bulk', mid = [
  404.             msg.id]))
  405.         self.api('BatchExecute', call = [
  406.             mark,
  407.             move])
  408.  
  409.     reportSpam = ymail_action(reportSpam)
  410.     
  411.     def open(self, msg):
  412.         EmailAccount.open(self, msg)
  413.         mid = msg.id
  414.         return UrlQuery('http://mrd.mail.yahoo.com/msg?', mid = mid, fid = 'Inbox')
  415.  
  416.     
  417.     def urlForEmail(self, msg):
  418.         
  419.         try:
  420.             if self.web_login:
  421.                 return str(self.make_login_string() + '&.done=' + quote(self.open(msg), safe = ''))
  422.             else:
  423.                 return self.open(msg)
  424.         except Exception:
  425.             e = None
  426.             self.warning(e)
  427.             return self.open(msg)
  428.  
  429.  
  430.     
  431.     def compose_link(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  432.         extra = dict()
  433.         Body = body
  434.         subj = Subj = subject
  435.         To = to
  436.         Cc = cc
  437.         Bcc = bcc
  438.         for name in 'to To subj Subj subject body Body cc Cc bcc Bcc'.split():
  439.             if vars()[name]:
  440.                 val = vars()[name]
  441.                 if isinstance(val, unicode):
  442.                     val = val.encode('utf-8')
  443.                 
  444.                 extra[name.title()] = val
  445.                 continue
  446.         
  447.         return UrlQuery('http://compose.mail.yahoo.com/', **extra)
  448.  
  449.     
  450.     def compose(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  451.         link = self.compose_link(to = to, subject = subject, body = body, cc = cc, bcc = bcc)
  452.         
  453.         try:
  454.             if self.web_login:
  455.                 return str(self.make_login_string() + '&.done=' + quote(link, safe = ''))
  456.             else:
  457.                 return link
  458.         except Exception:
  459.             e = None
  460.             self.warning(e)
  461.             return link
  462.  
  463.  
  464.     
  465.     def send_email(self, to = '', subject = '', body = '', cc = '', bcc = ''):
  466.         result = self.api('SendMessage', message = {
  467.             'subject': subject,
  468.             'from': {
  469.                 'email': self.email_address },
  470.             'to': {
  471.                 'email': to },
  472.             'simplebody': {
  473.                 'text': body } })
  474.         if result['error'] is not None:
  475.             log.error('send_email(to=%r, subject=%r, body=%r) = %r', to, subject, body, result['error'])
  476.             raise YahooMailException(result['error']['message'])
  477.         
  478.         return True
  479.  
  480.     send_email = threaded(send_email)
  481.     
  482.     def make_login_string(self):
  483.         self.jar._cookies_lock.__enter__()
  484.         
  485.         try:
  486.             y = yBrowserCookie(self.jar._cookies['.yahoo.com']['/']['Y'])
  487.             t = yBrowserCookie(self.jar._cookies['.yahoo.com']['/']['T'])
  488.         finally:
  489.             pass
  490.  
  491.         return 'http://msg.edit.yahoo.com/config/reset_cookies?&' + y + '&' + t + '&.ver=2'
  492.  
  493.     
  494.     def inbox_url(self):
  495.         
  496.         try:
  497.             if self.web_login and hasattr(self, 'u'):
  498.                 link = UrlQuery('http://mrd.mail.yahoo.com/inbox')
  499.                 loginstr = self.make_login_string()
  500.                 log.debug('returning login URL for yahoo inbox')
  501.                 return str(loginstr + '&.done=' + quote(link, safe = ''))
  502.             else:
  503.                 return 'http://mrd.mail.yahoo.com/inbox'
  504.         except Exception:
  505.             e = None
  506.             self.warning(e)
  507.             return 'http://mrd.mail.yahoo.com/inbox'
  508.  
  509.  
  510.     inbox_url = property(inbox_url)
  511.     
  512.     def api(self, method, **params):
  513.         foo = None
  514.         loads = loads
  515.         dumps = dumps
  516.         import simplejson
  517.         recursed = params.pop('_recursed', 0)
  518.         recurse = False
  519.         
  520.         try:
  521.             foo = self.http_opener.open(self.json_endpoint, dumps(dict(method = method, params = [
  522.                 params]))).read()
  523.             log.debug_s('got data from yahoo: %r', foo)
  524.             if not foo.startswith('{'):
  525.                 import zlib
  526.                 
  527.                 try:
  528.                     foo = foo.decode('z')
  529.                 except zlib.error:
  530.                     raise YahooMailAuthRedirect
  531.                 except:
  532.                     None<EXCEPTION MATCH>zlib.error
  533.                 
  534.  
  535.             None<EXCEPTION MATCH>zlib.error
  536.             foo = loads(foo)
  537.         except YahooMailAuthException:
  538.             raise 
  539.         except Exception:
  540.             e = None
  541.             if hasattr(e, 'read') or isinstance(e, YahooMailAuthRedirect):
  542.                 if hasattr(e, 'read'):
  543.                     foo = e.read()
  544.                     log.debug('got error data from yahoo: %r', foo)
  545.                 
  546.             None if isinstance(e, YahooMailAuthRedirect) or getattr(e, 'code', None) == 404 else None<EXCEPTION MATCH>YahooMailException
  547.             raise 
  548.         finally:
  549.             if recurse and recursed < 5:
  550.                 params['_recursed'] = recursed + 1
  551.                 return self.api(method, **params)
  552.             
  553.  
  554.         return foo
  555.  
  556.  
  557.  
  558. class FakeYmail(YahooMail):
  559.     count = 1337
  560.     
  561.     def __init__(self, username, password):
  562.         self.name = username
  563.         self.password = password
  564.         self.init_jar()
  565.  
  566.     
  567.     def _decryptedpw(self):
  568.         return self.password
  569.  
  570.     
  571.     def __len__(self):
  572.         return 1337
  573.  
  574.  
  575. if __name__ == '__main__':
  576.     import main
  577.     main.setup_log_system()
  578.     f = FakeYmail('username', 'passwordShouldNotBeInSourceCode')
  579.     f.authenticate()
  580.     from pprint import pprint
  581.     msgs = [ m for m in f.get_yMsgs()[0] ]
  582.     print len(msgs)
  583.     pprint(msgs)
  584.  
  585.  
  586. class yBrowserCookie(str):
  587.     
  588.     def __new__(cls, cookie):
  589.         return str.__new__(cls, '.' + cookie.name.lower() + '=' + cookie.name + '=' + quote(cookie.value, safe = '/=') + ';+path=' + cookie.path + ';+domain=' + cookie.domain)
  590.  
  591.  
  592.