home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 February / maximum-cd-2011-02.iso / DiscContents / digsby_setup85.exe / lib / util / net.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-11-24  |  48.7 KB  |  1,612 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. from __future__ import with_statement
  5. import sys
  6. import traceback
  7. import re
  8. import struct
  9. import logging
  10. import random
  11. import StringIO
  12. import calendar
  13. import time
  14. import rfc822
  15. import socks
  16. import socket
  17. import asynchat
  18. import urllib
  19. import urllib2
  20. import urlparse
  21. import httplib
  22. import httplib2
  23. import cookielib
  24. import simplejson
  25. import itertools
  26. from httplib import HTTPConnection
  27. from httplib import NotConnected
  28. import primitives.funcs as primitives
  29. import proxy_settings
  30. from Events import EventMixin
  31. from callbacks import callsback
  32.  
  33. try:
  34.     sentinel
  35. except NameError:
  36.     
  37.     class Sentinel(object):
  38.         
  39.         def __repr__(self):
  40.             return '<Sentinel (%r backup) %#x>' % (__file__, id(self))
  41.  
  42.  
  43.     sentinel = Sentinel()
  44.  
  45. log = logging.getLogger('util.net')
  46. default_chunksize = 4096
  47.  
  48. def get_ips_s(hostname = ''):
  49.     if not hostname:
  50.         pass
  51.     return socket.gethostbyname_ex(socket.gethostname())[2]
  52.  
  53.  
  54. def get_ips(hostname = ''):
  55.     return [ socket.inet_aton(ip) for ip in get_ips_s(hostname) ]
  56.  
  57. myips = get_ips
  58.  
  59. def myip():
  60.     return myips()[0]
  61.  
  62.  
  63. def ip_from_bytes(bytes):
  64.     return socket.inet_ntoa(bytes)
  65.  
  66.  
  67. class FileChunker(object):
  68.     
  69.     def __init__(self, fileobj, chunksize = default_chunksize, close_when_done = False, progress_cb = (lambda bytes: pass), bytecounter = None):
  70.         self.fileobj = fileobj
  71.         self.chunksize = chunksize
  72.         self.close_when_done = close_when_done
  73.         if bytecounter is None:
  74.             bytecounter = fileobj.tell
  75.         
  76.         self.total = bytecounter()
  77.         self.progress_cb = progress_cb
  78.         self.cancelled = False
  79.  
  80.     
  81.     def more(self):
  82.         
  83.         try:
  84.             data_read = self.fileobj.read(self.chunksize)
  85.         except ValueError:
  86.             
  87.             try:
  88.                 self.fileobj.close()
  89.             except:
  90.                 pass
  91.  
  92.             return ''
  93.  
  94.         sz = len(data_read)
  95.         if sz == 0 and self.close_when_done:
  96.             self.fileobj.close()
  97.         
  98.         self.total += sz
  99.         self.progress_cb(self.total)
  100.         return data_read
  101.  
  102.     
  103.     def tofile(cls, sourcefile, outfile, progress_callback = (lambda : pass), bytecounter = None):
  104.         gen = cls.tofile_gen(sourcefile, outfile, progress_callback, bytecounter)
  105.         gen.next()
  106.         
  107.         try:
  108.             gen.next()
  109.         except StopIteration:
  110.             pass
  111.  
  112.  
  113.     tofile = classmethod(tofile)
  114.     
  115.     def tofile_gen(cls, sourcefile, outfile, progress_callback = (lambda : pass), bytecounter = None):
  116.         fc = cls(sourcefile, close_when_done = True, bytecounter = bytecounter)
  117.         yield fc
  118.         chunk = fc.more()
  119.         bytes_written = 0
  120.         write = outfile.write
  121.         tell = outfile.tell
  122.         more = fc.more
  123.         while chunk and not (fc.cancelled):
  124.             write(chunk)
  125.             bytes_written += len(chunk)
  126.             progress_callback(tell())
  127.             chunk = more()
  128.         outfile.close()
  129.  
  130.     tofile_gen = classmethod(tofile_gen)
  131.  
  132.  
  133. class NoneFileChunker(FileChunker):
  134.     
  135.     def more(self):
  136.         if not super(NoneFileChunker, self).more():
  137.             pass
  138.  
  139.  
  140.  
  141. def httpjoin(base, path, keepquery = False):
  142.     if path.startswith('http'):
  143.         return path
  144.     joined = urlparse.urljoin(base, path)
  145.     if not keepquery:
  146.         parsed = list(urlparse.urlparse(joined))
  147.         parsed[4] = ''
  148.         return urlparse.urlunparse(parsed)
  149.     return joined
  150.  
  151.  
  152. class UrlQuery(str):
  153.     
  154.     def parse(cls, url, parse_query = True, utf8 = False):
  155.         (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
  156.         if parse_query:
  157.             query = WebFormData.parse(query, utf8 = utf8)
  158.         
  159.         return dict(scheme = scheme, netloc = netloc, path = path, params = params, query = query, fragment = fragment)
  160.  
  161.     parse = classmethod(parse)
  162.     
  163.     def unparse(cls, scheme = '', netloc = '', path = '', params = '', query = None, fragment = ''):
  164.         if query is None:
  165.             query = { }
  166.         
  167.         if isinstance(query, dict):
  168.             query = WebFormData(query)
  169.         
  170.         return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
  171.  
  172.     unparse = classmethod(unparse)
  173.     
  174.     def __new__(cls, link, d = { }, **kwargs):
  175.         if not d or kwargs:
  176.             return str.__new__(cls, link)
  177.         if link.endswith('?'):
  178.             link = link[:-1]
  179.         
  180.         if '?' in link:
  181.             joiner = None if d or kwargs else ''
  182.         else:
  183.             joiner = '?'
  184.         return str.__new__(cls, ''.join([
  185.             link,
  186.             joiner,
  187.             WebFormData(d = d, **kwargs)]))
  188.  
  189.  
  190.  
  191. class WebFormData(str):
  192.     
  193.     def __new__(cls, d = { }, **kwargs):
  194.         if d and kwargs:
  195.             kwargs.update(d)
  196.         elif not kwargs:
  197.             pass
  198.         kwargs = d
  199.         base = urllib.urlencode(kwargs)
  200.         return str.__new__(cls, base)
  201.  
  202.     
  203.     def parse(cls, s, utf8 = False):
  204.         querymap = { }
  205.         if not s:
  206.             return querymap
  207.         encoding = s if utf8 else 'url'
  208.         for elem in s.split('&'):
  209.             if '=' in elem:
  210.                 (key, value) = elem.split('=', 1)
  211.                 querymap[key] = value.decode(encoding)
  212.                 continue
  213.             querymap[elem] = True
  214.         
  215.         return querymap
  216.  
  217.     parse = classmethod(parse)
  218.  
  219.  
  220. def int_to_ip(s, byteorder = '<'):
  221.     return '.'.join((lambda .0: for c in .0:
  222. str(ord(c)))(struct.pack(byteorder + 'I', int(s))))
  223.  
  224. spacify_pattern = re.compile('( {2,})')
  225.  
  226. def spacify_repl(m):
  227.     l = len(m.group())
  228.     if l == 2:
  229.         return '  '
  230.     return ' ' + ''.join([
  231.         ' '] * (l - 2)) + ' '
  232.  
  233.  
  234. def spacify(s):
  235.     return spacify_pattern.sub(spacify_repl, s)
  236.  
  237. urlregex = re.compile("([A-Za-z][A-Za-z0-9+.-]{1,120}:[A-Za-z0-9/](([A-Za-z0-9$_.+!*,;/?:@&~=-])|%[A-Fa-f0-9]{2}){1,333}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*,;/?:@&~=%-']{0,1000}))?)[^\\. <]")
  238. TLDs = [
  239.     'arpa',
  240.     'root',
  241.     'aero',
  242.     'asia',
  243.     'biz',
  244.     'com',
  245.     'coop',
  246.     'edu',
  247.     'gov',
  248.     'info',
  249.     'int',
  250.     'museum',
  251.     'name',
  252.     'net',
  253.     'org',
  254.     'pro',
  255.     'ac',
  256.     'ad',
  257.     'ae',
  258.     'af',
  259.     'ag',
  260.     'ai',
  261.     'al',
  262.     'am',
  263.     'an',
  264.     'ao',
  265.     'aq',
  266.     'ar',
  267.     'as',
  268.     'at',
  269.     'au',
  270.     'aw',
  271.     'ax',
  272.     'az',
  273.     'ba',
  274.     'bb',
  275.     'bd',
  276.     'be',
  277.     'bf',
  278.     'bg',
  279.     'bh',
  280.     'bi',
  281.     'bj',
  282.     'bm',
  283.     'bn',
  284.     'bo',
  285.     'br',
  286.     'bs',
  287.     'bt',
  288.     'bv',
  289.     'bw',
  290.     'by',
  291.     'bz',
  292.     'ca',
  293.     'cc',
  294.     'cd',
  295.     'cf',
  296.     'cg',
  297.     'ch',
  298.     'ci',
  299.     'ck',
  300.     'cl',
  301.     'cm',
  302.     'cn',
  303.     'co',
  304.     'cr',
  305.     'cu',
  306.     'cv',
  307.     'cx',
  308.     'cy',
  309.     'cz',
  310.     'de',
  311.     'dj',
  312.     'dk',
  313.     'dm',
  314.     'do',
  315.     'dz',
  316.     'ec',
  317.     'ee',
  318.     'eg',
  319.     'er',
  320.     'es',
  321.     'et',
  322.     'eu',
  323.     'fi',
  324.     'fj',
  325.     'fk',
  326.     'fm',
  327.     'fo',
  328.     'fr',
  329.     'ga',
  330.     'gb',
  331.     'gd',
  332.     'ge',
  333.     'gf',
  334.     'gg',
  335.     'gh',
  336.     'gi',
  337.     'gl',
  338.     'gm',
  339.     'gn',
  340.     'gp',
  341.     'gq',
  342.     'gr',
  343.     'gs',
  344.     'gt',
  345.     'gu',
  346.     'gw',
  347.     'gy',
  348.     'hk',
  349.     'hm',
  350.     'hn',
  351.     'hr',
  352.     'ht',
  353.     'hu',
  354.     'id',
  355.     'ie',
  356.     'il',
  357.     'im',
  358.     'in',
  359.     'io',
  360.     'iq',
  361.     'ir',
  362.     'is',
  363.     'it',
  364.     'je',
  365.     'jm',
  366.     'jo',
  367.     'jp',
  368.     'ke',
  369.     'kg',
  370.     'kh',
  371.     'ki',
  372.     'km',
  373.     'kn',
  374.     'kp',
  375.     'kr',
  376.     'kw',
  377.     'ky',
  378.     'kz',
  379.     'la',
  380.     'lb',
  381.     'lc',
  382.     'li',
  383.     'lk',
  384.     'lr',
  385.     'ls',
  386.     'lt',
  387.     'lu',
  388.     'lv',
  389.     'ly',
  390.     'ma',
  391.     'mc',
  392.     'md',
  393.     'me',
  394.     'mg',
  395.     'mh',
  396.     'mk',
  397.     'ml',
  398.     'mm',
  399.     'mn',
  400.     'mo',
  401.     'mp',
  402.     'mq',
  403.     'mr',
  404.     'ms',
  405.     'mt',
  406.     'mu',
  407.     'mv',
  408.     'mw',
  409.     'mx',
  410.     'my',
  411.     'mz',
  412.     'na',
  413.     'nc',
  414.     'ne',
  415.     'nf',
  416.     'ng',
  417.     'ni',
  418.     'nl',
  419.     'no',
  420.     'np',
  421.     'nr',
  422.     'nu',
  423.     'nz',
  424.     'om',
  425.     'pa',
  426.     'pe',
  427.     'pf',
  428.     'pg',
  429.     'ph',
  430.     'pk',
  431.     'pl',
  432.     'pm',
  433.     'pn',
  434.     'pr',
  435.     'ps',
  436.     'pt',
  437.     'pw',
  438.     'py',
  439.     'qa',
  440.     're',
  441.     'ro',
  442.     'rs',
  443.     'ru',
  444.     'rw',
  445.     'sa',
  446.     'sb',
  447.     'sc',
  448.     'sd',
  449.     'se',
  450.     'sg',
  451.     'sh',
  452.     'si',
  453.     'sj',
  454.     'sk',
  455.     'sl',
  456.     'sm',
  457.     'sn',
  458.     'so',
  459.     'sr',
  460.     'st',
  461.     'su',
  462.     'sv',
  463.     'sy',
  464.     'sz',
  465.     'tc',
  466.     'td',
  467.     'tf',
  468.     'tg',
  469.     'th',
  470.     'tj',
  471.     'tk',
  472.     'tl',
  473.     'tm',
  474.     'tn',
  475.     'to',
  476.     'tp',
  477.     'tr',
  478.     'tt',
  479.     'tv',
  480.     'tw',
  481.     'tz',
  482.     'ua',
  483.     'ug',
  484.     'uk',
  485.     'um',
  486.     'us',
  487.     'uy',
  488.     'uz',
  489.     'va',
  490.     'vc',
  491.     've',
  492.     'vg',
  493.     'vi',
  494.     'vn',
  495.     'vu',
  496.     'wf',
  497.     'ws',
  498.     'ye',
  499.     'yt',
  500.     'yu',
  501.     'za',
  502.     'zm',
  503.     'zw']
  504. domains = '(?:%s)' % '|'.join(TLDs)
  505. email_regex_string = '(?:([a-zA-Z0-9_][a-zA-Z0-9_\\-\\.]*)(\\+[a-zA-Z0-9_\\-\\.]+)?@((?:[a-zA-Z0-9\\-_]+\\.?)*[a-zA-Z]{1,4}))'
  506. email_regex = re.compile(email_regex_string)
  507. email_wholestring_regex = re.compile('^' + email_regex_string + '$')
  508. is_email = primitives.funcs.ischeck((lambda s: bool(email_wholestring_regex.match(s))))
  509.  
  510. class EmailAddress(tuple):
  511.     
  512.     def __new__(cls, addr, default_domain = sentinel):
  513.         
  514.         try:
  515.             (name, label, domain) = parse_email(addr)
  516.         except:
  517.             if default_domain is sentinel:
  518.                 raise 
  519.             default_domain is sentinel
  520.             (name, label, domain) = parse_email(addr + '@' + default_domain)
  521.  
  522.         return tuple.__new__(cls, (name, label, domain))
  523.  
  524.     
  525.     def name(self):
  526.         return self[0]
  527.  
  528.     name = property(name)
  529.     
  530.     def label(self):
  531.         return self[1]
  532.  
  533.     label = property(label)
  534.     
  535.     def domain(self):
  536.         return self[2]
  537.  
  538.     domain = property(domain)
  539.     
  540.     def __str__(self):
  541.         if self.label:
  542.             return '%s+%s@%s' % self
  543.         return '%s@%s' % (self.name, self.domain)
  544.  
  545.     
  546.     def __repr__(self):
  547.         return '<EmailAddress %s>' % (self,)
  548.  
  549.  
  550.  
  551. def parse_email(s):
  552.     match = email_wholestring_regex.match(s)
  553.     if match is None:
  554.         raise ValueError('Not a valid email address: %r', s)
  555.     match is None
  556.     (user, lbl, dom) = match.groups()
  557.     if lbl:
  558.         lbl = lbl.strip('+')
  559.     else:
  560.         lbl = ''
  561.     return (user, lbl, dom)
  562.  
  563. protocols = 'ftp|https?|gopher|msnim|icq|telnet|nntp|aim|file|svn|svn+(?:\\w)+'
  564. single_letter_rule_tlds = frozenset(('net', 'com', 'org'))
  565. allowed_single_letter_domains = frozenset(('i.net', 'q.com', 'q.net', 'x.com', 'x.org', 'z.com'))
  566. linkify_url_pattern = re.compile('(?=[a-zA-Z0-9])                             # Must start correctly\n      ((?:                                        # Match the leading part (proto://hostname, or just hostname)\n          (?:(?P<protocol>%s)                     #     protocol\n          ://                                     #     ://\n          (?:                                     #     Optional \'username:password@\'\n              (?P<username>\\w+)                   #         username\n              (?::(?P<password>\\w+))?             #         optional :password\n              @                                   #         @\n          )?)?                                    #\n          (?P<hostname>                           # hostname (sub.example.com). single-letter\n          (?:[iqxz]|(?:[-\\w\\x7F-\\xFF]+))          # domains are not allowed, except those listed:\n          (?:\\.[\\w\\x7F-\\xFF][-\\w\\x7F-\\xFF]*)*)    # http://en.wikipedia.org/wiki/Single-letter_second-level_domains\n      )?                                          #\n      (?::(?P<port>\\d+))?                         # Optional port number\n      (?P<selector>\n        (?:                                       # Rest of the URL, optional\n          /?                                      #     Start with \'/\'\n          [^.!,?;:"<>\\[\\]{}\\s\\x7F-\\xFF]+          #     Can\'t start with these\n          (?:                                     #\n              [.!,?;:]+                           #     One or more of these\n              [^.!,?;:"<>{}\\s\\x7F-\\xFF]+          #     Can\'t finish with these\n              #\'"                                 #     # or \' or "\n          )*)                                     #\n      )?)                                         #\n   ' % protocols, re.VERBOSE)
  567.  
  568. def isurl(text):
  569.     m = linkify_url_pattern.match(text)
  570.     if not m:
  571.         return False
  572.     protocol = m.group('protocol')
  573.     host = m.group('hostname')
  574.     if host is not None:
  575.         if protocol is None:
  576.             myTLDs = m if '.' in host else [
  577.                 host]
  578.             if len(myTLDs) < 2 or myTLDs[-1] not in TLDs:
  579.                 return False
  580.         
  581.     
  582.     return True
  583.  
  584.  
  585. class LinkAccumulator(object):
  586.     
  587.     def __init__(self, s = None):
  588.         self.links = []
  589.         self.spans = []
  590.         if s is not None:
  591.             linkify_url_pattern.sub(self.repl, s)
  592.         
  593.  
  594.     
  595.     def repl(self, m):
  596.         (url, protocol, after) = _url_from_match(m)
  597.         if url is None:
  598.             return ''
  599.         href = url is None if protocol is None else url
  600.         self.links.append(href)
  601.         self.spans.append(m.span())
  602.         return ''
  603.  
  604.     
  605.     def __iter__(self):
  606.         return itertools.izip(self.links, self.spans)
  607.  
  608.  
  609.  
  610. def find_links(text):
  611.     return LinkAccumulator(text).links
  612.  
  613.  
  614. def _url_from_match(m):
  615.     protocol = m.group('protocol')
  616.     host = m.group('hostname')
  617.     url = m.group()
  618.     after = ''
  619.     if url.endswith(')') and '(' not in url:
  620.         url = url[:-1]
  621.         after = ')'
  622.     
  623.     if host is not None:
  624.         myTLDs = None if '.' in host else [
  625.             host]
  626.         if protocol is None:
  627.             if len(myTLDs) < 2 or myTLDs[-1] not in TLDs:
  628.                 return (None, None, None)
  629.         
  630.         if len(myTLDs) >= 2:
  631.             second_level_domain = myTLDs[-2]
  632.             top_level_domain = myTLDs[-1]
  633.             if len(second_level_domain) == 1 and '.'.join((second_level_domain, top_level_domain)) not in allowed_single_letter_domains and top_level_domain in single_letter_rule_tlds:
  634.                 return (None, None, None)
  635.         
  636.         return (url, protocol, after)
  637.     return (None, None, None)
  638.  
  639.  
  640. def _dolinkify(text):
  641.     
  642.     def repl(m):
  643.         (url, protocol, after) = _url_from_match(m)
  644.         if url is None:
  645.             (i, j) = m.span()
  646.             return text[i:j]
  647.         href = url is None if protocol is None else url
  648.         return '<a href="%s">%s</a>' % (href, url) + after
  649.  
  650.     text = linkify_url_pattern.sub(repl, text)
  651.     return text
  652.  
  653.  
  654. def linkify(text):
  655.     if isinstance(text, unicode):
  656.         return _linkify(text.encode('utf-8')).decode('utf-8')
  657.     return _linkify(text)
  658.  
  659.  
  660. def _linkify(text):
  661.     if not re.search('<.*>', text):
  662.         return _dolinkify(text)
  663.     lines = []
  664.     prev_line = ''
  665.     for line in re.split('(<.*?>)', text):
  666.         if not re.match('<.*?>', line) and not prev_line.startswith('<a'):
  667.             line = _dolinkify(line)
  668.         
  669.         prev_line = line
  670.         lines.append(line)
  671.     
  672.     return ''.join(lines)
  673.  
  674.  
  675. class QueueableMixin(object):
  676.     
  677.     def __init__(self):
  678.         object.__init__(self)
  679.         self._on_queue = False
  680.  
  681.     
  682.     def queue(self):
  683.         if not self._on_queue:
  684.             self._queue()
  685.             self._on_queue = True
  686.         
  687.  
  688.     
  689.     def unqueue(self):
  690.         if self._on_queue:
  691.             self._unqueue()
  692.             self._on_queue = False
  693.         
  694.  
  695.  
  696.  
  697. class ProducerQueuable(QueueableMixin):
  698.     
  699.     def __init__(self, sck):
  700.         QueueableMixin.__init__(self)
  701.         self.sck = sck
  702.  
  703.     
  704.     def _queue(self):
  705.         self.sck.push_with_producer(self)
  706.  
  707.     
  708.     def _unqueue(self):
  709.         
  710.         try:
  711.             self.sck.producer_fifo.remove(self)
  712.         except ValueError:
  713.             pass
  714.  
  715.  
  716.  
  717.  
  718. class RoundRobinProducer(ProducerQueuable):
  719.     
  720.     def __init__(self, sck):
  721.         ProducerQueuable.__init__(self, sck)
  722.         self.list = []
  723.  
  724.     
  725.     def add(self, prod):
  726.         
  727.         try:
  728.             if not callable(prod.more):
  729.                 raise AssertionError('Producers must have a "more" method')
  730.             callable(prod.more)
  731.         except:
  732.             traceback.print_exc()
  733.             raise 
  734.  
  735.         self.unqueue()
  736.         self.list.append(prod)
  737.         self.queue()
  738.  
  739.     
  740.     def more(self):
  741.         self._on_queue = True
  742.         d = None
  743.         l = self.list
  744.         prod = None
  745.         while not d and l:
  746.             prod = l.pop(0)
  747.             d = prod.more()
  748.         if d:
  749.             l.append(prod)
  750.         else:
  751.             self.unqueue()
  752.             if self.list:
  753.                 self.queue()
  754.             
  755.         return d
  756.  
  757.  
  758.  
  759. class PriorityProducer(ProducerQueuable):
  760.     
  761.     def __init__(self, sck):
  762.         ProducerQueuable.__init__(self, sck)
  763.         self.high = []
  764.         self.mid = []
  765.         self.low = []
  766.  
  767.     
  768.     def add(self, prod, pri = 'mid'):
  769.         self.unqueue()
  770.         getattr(self, pri).append(prod)
  771.         self.queue()
  772.  
  773.     
  774.     def more(self):
  775.         self._on_queue = True
  776.         d = None
  777.         for l in (self.high, self.mid, self.low):
  778.             if not l:
  779.                 continue
  780.             
  781.             while not d and l:
  782.                 prod = l.pop(0)
  783.                 d = prod.more()
  784.             if d:
  785.                 l.insert(0, prod)
  786.                 break
  787.                 continue
  788.         
  789.         return d
  790.  
  791.  
  792.  
  793. class HTTPConnProgress(HTTPConnection):
  794.     
  795.     def send_file_cb(self, fileobj, progress_cb, blocksize = default_chunksize, progressDelta = 0):
  796.         if self.sock is None:
  797.             if self.auto_open:
  798.                 self.connect()
  799.             else:
  800.                 raise NotConnected()
  801.         self.auto_open
  802.         if self.debuglevel > 0:
  803.             print 'sending contents of', fileobj
  804.         
  805.         
  806.         try:
  807.             read = fileobj.read
  808.             sendall = self.sock.sendall
  809.             chunk = read(blocksize)
  810.             total = 0
  811.             while chunk:
  812.                 total += len(chunk)
  813.                 sendall(chunk)
  814.                 progress_cb(total - progressDelta)
  815.                 chunk = read(blocksize)
  816.         except socket.error:
  817.             v = None
  818.             if v[0] == 32:
  819.                 self.close()
  820.             
  821.             raise 
  822.  
  823.  
  824.  
  825.  
  826. class SocketEventMixin(EventMixin):
  827.     events = EventMixin.events | set(('connected', 'connection_failed', 'socket_error', 'socket_closed'))
  828.     
  829.     def post_connect_error(self, e = None):
  830.         self.event('socket_error')
  831.         self.post_connect_disconnect()
  832.  
  833.     
  834.     def post_connect_expt(self):
  835.         self.event('socket_error')
  836.         self.post_connect_disconnect()
  837.  
  838.     
  839.     def post_connect_disconnect(self):
  840.         self.close()
  841.         self.event('socket_closed')
  842.  
  843.     
  844.     def post_connect_close(self):
  845.         self.close()
  846.         self.event('socket_closed')
  847.  
  848.     
  849.     def reassign(self):
  850.         self.handle_expt = self.post_connect_expt
  851.         self.handle_error = self.post_connect_error
  852.         self.handle_close = self.post_connect_close
  853.         self.do_disconnect = self.post_connect_disconnect
  854.  
  855.  
  856.  
  857. def build_cookie(name, value, version = 0, domain = sentinel, port = sentinel, path = sentinel, secure = False, expires = None, discard = False, comment = None, comment_url = None, rest = {
  858.     'httponly': None }, rfc2109 = False):
  859.     if domain is sentinel:
  860.         domain = None
  861.         domain_specified = False
  862.         domain_initial_dot = False
  863.     else:
  864.         domain_specified = True
  865.         domain_initial_dot = domain.startswith('.')
  866.     if port is sentinel:
  867.         port = None
  868.         port_specified = False
  869.     else:
  870.         port_specified = True
  871.     if path is sentinel:
  872.         path = None
  873.         path_specified = False
  874.     else:
  875.         path_specified = True
  876.     return cookielib.Cookie(**locals())
  877.  
  878.  
  879. def GetSocketType():
  880.     d = GetProxyInfo()
  881.     if d:
  882.         return socks.socksocket
  883.     return socket.socket
  884.  
  885. NONE = 'NONPROX'
  886. SYSDEFAULT = 'SYSPROX'
  887. CUSTOM = 'SETPROX'
  888.  
  889. def GetProxyInfo():
  890.     ps = proxy_settings
  891.     
  892.     try:
  893.         pd = ps.get_proxy_dict()
  894.     except Exception:
  895.         e = None
  896.         print >>sys.stderr, 'No proxies because: %r' % e
  897.         pd = { }
  898.  
  899.     get = pd.get
  900.     proxytype = get('proxytype')
  901.     port = get('port')
  902.     
  903.     try:
  904.         port = int(port)
  905.     except:
  906.         port = None
  907.  
  908.     addr = get('addr')
  909.     username = get('username')
  910.     password = get('password')
  911.     override = get('override')
  912.     rdns = get('rdns', False)
  913.     
  914.     try:
  915.         override = int(override)
  916.     except:
  917.         if override not in (SYSDEFAULT, CUSTOM, NONE):
  918.             override = SYSDEFAULT
  919.         
  920.  
  921.     if override:
  922.         override = CUSTOM
  923.     else:
  924.         override = SYSDEFAULT
  925.     if override == NONE:
  926.         return { }
  927.     if all((type, port, addr)):
  928.         proxytype = getattr(socks, ('proxy_type_%s' % proxytype).upper(), None)
  929.         return dict(addr = addr, port = port, username = username, password = password, proxytype = proxytype, rdns = rdns)
  930.     return { }
  931.  
  932.  
  933. def GetProxyInfoHttp2():
  934.     i = GetProxyInfo()
  935.     if not i:
  936.         return None
  937.     return httplib2.ProxyInfo(proxy_type = i['proxytype'], proxy_host = i['addr'], proxy_port = i['port'], proxy_user = i['username'], proxy_pass = i['password'], proxy_rdns = i.get('rdns', False))
  938.  
  939.  
  940. def getproxies_digsby():
  941.     pinfo = GetProxyInfo()
  942.     proxies = { }
  943.     if pinfo.get('username', None) and pinfo.get('password', None):
  944.         unpw = '%s:%s@' % (pinfo['username'], pinfo['password'])
  945.     else:
  946.         unpw = ''
  947.     if pinfo.get('port', None):
  948.         port = ':' + str(pinfo['port'])
  949.     else:
  950.         port = ''
  951.     host = pinfo.get('addr', None)
  952.     if not host:
  953.         return proxies
  954.     all = unpw + host + port
  955.     proxies = urllib.OneProxy()
  956.     proxies._proxyServer = all
  957.     if pinfo['proxytype'] != socks.PROXY_TYPE_HTTP:
  958.         proxy_url = host % 'socks%d://' if pinfo['proxytype'] == socks.PROXY_TYPE_SOCKS4 else 5 + all
  959.         return dict(socks = proxy_url, http = proxy_url, https = proxy_url)
  960.     proxies['https'] = 'http://' + all
  961.     proxies['http'] = 'http://' + all
  962.     proxies['ftp'] = 'http://' + all
  963.     return proxies
  964.  
  965.  
  966. class SocksProxyHandler(urllib2.ProxyHandler):
  967.     handler_order = 100
  968.     
  969.     def proxy_open(self, req, type):
  970.         
  971.         try:
  972.             req._proxied
  973.         except AttributeError:
  974.             proxyinfo = self.proxies.get(type, '')
  975.             proxytype = urllib2._parse_proxy(proxyinfo)[0]
  976.             if proxytype is None:
  977.                 req._proxied = False
  978.                 return urllib2.ProxyHandler.proxy_open(self, req, type)
  979.             req._proxytype = proxytype
  980.             req._proxied = True
  981.             if proxytype == 'http' and type != 'https':
  982.                 return urllib2.ProxyHandler.proxy_open(self, req, type)
  983.             return None
  984.         except:
  985.             type != 'https'
  986.  
  987.         return None
  988.  
  989.     
  990.     def socks4_open(self, req):
  991.         return self.socks_open(req, 4)
  992.  
  993.     
  994.     def socks5_open(self, req):
  995.         return self.socks_open(req, 5)
  996.  
  997.     
  998.     def socks_open(self, req, sockstype):
  999.         (orig_url_type, __, __, orighostport) = urllib2._parse_proxy(req.get_full_url())
  1000.         req.set_proxy(orighostport, orig_url_type)
  1001.         endpoint = req.get_host()
  1002.         if ':' in endpoint:
  1003.             (host, port) = endpoint.rsplit(':', 1)
  1004.             port = int(port)
  1005.         else:
  1006.             host = endpoint
  1007.             port = 80
  1008.         req._proxied = True
  1009.         return self.parent.open(req)
  1010.  
  1011.  
  1012.  
  1013. try:
  1014.     import ssl
  1015. except ImportError:
  1016.     pass
  1017.  
  1018.  
  1019. class SocksHttpsOpener(urllib2.HTTPSHandler):
  1020.     handler_order = 101
  1021.     
  1022.     def https_open(self, req):
  1023.         if getattr(req, '_proxied', False) and getattr(req, '_proxytype', None) is not None:
  1024.             return urllib2.HTTPSHandler.do_open(self, SocksHttpsConnection, req)
  1025.         return urllib2.HTTPSHandler.https_open(self, req)
  1026.  
  1027.  
  1028.  
  1029. class SocksHttpsConnection(httplib.HTTPSConnection):
  1030.     _sockettype = socks.socksocket
  1031.     
  1032.     def connect(self):
  1033.         pd = urllib.getproxies().get('https', None)
  1034.         if pd is None:
  1035.             sockstype = ''
  1036.         else:
  1037.             (sockstype, user, password, hostport) = urllib2._parse_proxy(pd)
  1038.         (host, port) = hostport.rsplit(':', 1)
  1039.         port = int(port)
  1040.         sock = self._sockettype(socket.AF_INET, socket.SOCK_STREAM)
  1041.         sock.setproxy(proxytype = getattr(socks, 'PROXY_TYPE_%s' % sockstype.upper()), addr = host, port = port, rdns = True, username = user, password = password)
  1042.         sock.connect((self.host, self.port))
  1043.         self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
  1044.  
  1045.  
  1046.  
  1047. class SocksHttpOpener(urllib2.HTTPHandler):
  1048.     handler_order = 101
  1049.     
  1050.     def http_open(self, req):
  1051.         proxytype = getattr(req, '_proxytype', None)
  1052.         if getattr(req, '_proxied', False) and proxytype not in ('http', None):
  1053.             return urllib2.HTTPHandler.do_open(self, SocksConnection, req)
  1054.         return urllib2.HTTPHandler.http_open(self, req)
  1055.  
  1056.  
  1057.  
  1058. class SocksConnection(httplib.HTTPConnection):
  1059.     _sockettype = socks.socksocket
  1060.     
  1061.     def connect(self):
  1062.         pd = urllib.getproxies().get('http', None)
  1063.         if pd is None:
  1064.             sockstype = ''
  1065.         else:
  1066.             (sockstype, user, password, hostport) = urllib2._parse_proxy(pd)
  1067.         if 'socks' not in sockstype:
  1068.             return httplib.HTTPConnection.connect(self)
  1069.         (host, port) = hostport.rsplit(':', 1)
  1070.         port = int(port)
  1071.         for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
  1072.             (af, socktype, proto, canonname, sa) = res
  1073.             
  1074.             try:
  1075.                 self.sock = self._sockettype(af, socktype, proto)
  1076.                 self.sock.setproxy(proxytype = getattr(socks, 'PROXY_TYPE_%s' % sockstype.upper()), addr = host, port = port, rdns = False, username = user, password = password)
  1077.                 self.sock.connect(sa)
  1078.             except socket.error:
  1079.                 'socks' not in sockstype
  1080.                 msg = 'socks' not in sockstype
  1081.                 if self.debuglevel > 0:
  1082.                     print 'connect fail:', (self.host, self.port)
  1083.                 
  1084.                 if self.sock:
  1085.                     self.sock.close()
  1086.                 
  1087.                 self.sock = None
  1088.                 continue
  1089.             except:
  1090.                 'socks' not in sockstype
  1091.  
  1092.         
  1093.         if not self.sock:
  1094.             raise socket.error, msg
  1095.         self.sock
  1096.  
  1097.  
  1098.  
  1099. class DigsbyHttpProxyPasswordManager(urllib2.HTTPPasswordMgr):
  1100.     
  1101.     def find_user_password(self, realm, uri):
  1102.         pi = GetProxyInfo()
  1103.         if not pi['username']:
  1104.             pass
  1105.         if not pi['password']:
  1106.             pass
  1107.         return (None, None)
  1108.  
  1109.  
  1110. if not hasattr(urllib, '_getproxies'):
  1111.     urllib._getproxies = urllib.getproxies
  1112.     urllib.getproxies = getproxies_digsby
  1113.     urllib2.UnknownHandler.handler_order = sys.maxint
  1114.     urllib2.ProxyDigestAuthHandler.__bases__ = urllib2.ProxyDigestAuthHandler.__bases__[::-1]
  1115.     urllib2.ProxyBasicAuthHandler.handler_order = 499
  1116.     httplib2.ProxyInfo.get_default_proxy = staticmethod(GetProxyInfoHttp2)
  1117.  
  1118.  
  1119. def GetDefaultHandlers():
  1120.     handlers = [
  1121.         SocksProxyHandler,
  1122.         SocksHttpOpener]
  1123.     httpsopener = globals().get('SocksHttpsOpener', None)
  1124.     if httpsopener is not None:
  1125.         handlers.append(httpsopener)
  1126.     
  1127.     pwdmgr = DigsbyHttpProxyPasswordManager()
  1128.     for auth_handler_type in (urllib2.ProxyBasicAuthHandler, urllib2.ProxyDigestAuthHandler):
  1129.         handlers.append(auth_handler_type(pwdmgr))
  1130.     
  1131.     return handlers
  1132.  
  1133.  
  1134. def build_opener(*a, **k):
  1135.     if 'default_classes' not in k:
  1136.         k['default_classes'] = GetDefaultHandlers() + urllib2.default_opener_classes
  1137.     
  1138.     return urllib2.build_opener(*a, **k)
  1139.  
  1140. opener = urllib2.build_opener(*GetDefaultHandlers())
  1141. urllib2.install_opener(opener)
  1142. _hostprog = re.compile('^//([^/?]*)(.*)$')
  1143.  
  1144. def splithost(url):
  1145.     match = _hostprog.match(url)
  1146.     if match:
  1147.         groups = match.group(1, 2)
  1148.         if groups[0] == '':
  1149.             return (groups[0], '/' + groups[1])
  1150.         return groups
  1151.     match
  1152.     return (None, url)
  1153.  
  1154. urllib.splithost = urllib2.splithost = splithost
  1155.  
  1156. def _HTTPError__repr(self):
  1157.     if not hasattr(self, 'content'):
  1158.         
  1159.         try:
  1160.             self.content = self.read()
  1161.             self.close()
  1162.         except Exception:
  1163.             e = None
  1164.             self._error = e
  1165.             self.content = 'error reading body: %r' % e
  1166.             
  1167.             self.read = lambda : ''
  1168.  
  1169.         self._stringio = StringIO.StringIO(self.content)
  1170.         self.read = self._stringio.read
  1171.     
  1172.     etxt = self.content
  1173.     return '<HTTPError headers = %r, body = %r>' % (str(getattr(self, 'hdrs', { })), etxt)
  1174.  
  1175. urllib2.HTTPError.__repr__ = _HTTPError__repr
  1176.  
  1177. def httpok(_code):
  1178.     return getattr(_code, 'status', _code) // 100 == 2
  1179.  
  1180.  
  1181. class SimpleProducer(asynchat.simple_producer):
  1182.     
  1183.     def more(self):
  1184.         data = asynchat.simple_producer.more(self)
  1185.         if data == '':
  1186.             data = None
  1187.         
  1188.         return data
  1189.  
  1190.  
  1191.  
  1192. class CallbackProducerMixin(object):
  1193.     
  1194.     def __init__(self):
  1195.         bases = self.__class__.__bases__
  1196.         found_self = False
  1197.         self._siblingClass = None
  1198.         for base in bases:
  1199.             if base is CallbackProducerMixin:
  1200.                 found_self = True
  1201.                 continue
  1202.             if hasattr(base, 'more') and found_self:
  1203.                 self._siblingClass = base
  1204.                 break
  1205.                 continue
  1206.         
  1207.         if self._siblingClass is None:
  1208.             raise AssertionError("This mix-in requires there is a sibling class with a 'more' method. Additionally, CallbackProducerMixin must be *before* that class in the inheritance list (for method resolution reasons).")
  1209.         self._siblingClass is None
  1210.  
  1211.     
  1212.     def set_callback(self, callback = None):
  1213.         self._callback = callback
  1214.  
  1215.     set_callback = callsback(set_callback)
  1216.     
  1217.     def more(self):
  1218.         if not hasattr(self, '_siblingClass'):
  1219.             result = None
  1220.         else:
  1221.             result = self._siblingClass.more(self)
  1222.         if result is None:
  1223.             if getattr(self, '_callback', None) is not None:
  1224.                 self._callback.success()
  1225.             
  1226.             if getattr(self, '_callback', None) is not None:
  1227.                 del self._callback
  1228.             
  1229.         
  1230.         return result
  1231.  
  1232.  
  1233.  
  1234. class SimpleCallbackProducer(CallbackProducerMixin, SimpleProducer):
  1235.     
  1236.     def __init__(self, data):
  1237.         SimpleProducer.__init__(self, data)
  1238.         CallbackProducerMixin.__init__(self)
  1239.  
  1240.  
  1241.  
  1242. def _fifo_remove(self, val):
  1243.     
  1244.     try:
  1245.         self.list.remove(val)
  1246.     except Exception:
  1247.         return False
  1248.  
  1249.     return True
  1250.  
  1251. asynchat.fifo.remove = _fifo_remove
  1252.  
  1253. def producer_cb(data, callback = None):
  1254.     prod = SimpleCallbackProducer(data)
  1255.     prod.set_callback(callback = callback)
  1256.     return prod
  1257.  
  1258. producer_cb = callsback(producer_cb)
  1259.  
  1260. class GeneratorProducer(object):
  1261.     
  1262.     def __init__(self, gen):
  1263.         self.gen = gen
  1264.  
  1265.     
  1266.     def more(self):
  1267.         if self.gen is None:
  1268.             return None
  1269.         
  1270.         try:
  1271.             return self.gen.next()
  1272.         except StopIteration:
  1273.             self.gen is None
  1274.             self.gen is None
  1275.             self.gen = None
  1276.             return None
  1277.  
  1278.  
  1279.  
  1280. _short_domains = frozenset(('2big.at', '2me.tw', '3.ly', 'a.gd', 'a2n.eu', 'abbrr.com', 'adjix.com', 'arunaurl.com', 'beam.to', 'bit.ly', 'bitly.com', 'bkite.com', 'blip.fm', 'bloat.me', 'budurl.com', 'burnurl.com', 'canurl.com', 'chilp.it', 'cli.gs', 'decenturl.com', 'digg.com', 'digs.by', 'dn.vc', 'doiop.com', 'durl.us', 'dwarfurl.com', 'easyuri.com', 'easyurl.net', 'ff.im', 'fon.gs', 'fyiurl.com', 'ginx.com', 'goo.gl', 'go2.me', 'hex.io', 'hopurl.com', 'hurl.ws', 'icanhaz.com', 'idek.net', 'is.gd', 'ix.it', 'jijr.com', 'jmp2.net', 'knol.me', 'krz.ch', 'kurl.us', 'last.fm', 'lin.cr', 'lnk.in', 'makeitbrief.com', 'memurl.com', 'micurl.com', 'minu.ws', 'moourl.com', 'myturl.com', 'notlong.com', 'ow.ly', 'pic.im', 'pikchur.com', 'ping.fm', 'piurl.com', 'poprl.com', 'qurlyq.com', 'r.im', 'refurl.com', 'rubyurl.com', 'rurl.org', 'rurl.us', 's7y.us', 'sai.ly', 'sbt.sh', 'shorl.comshort.ie', 'short.to', 'shortna.me', 'shrinkify.com', 'shw.com', 'si9.org', 'skocz.pl', 'smalur.com', 'sn.im', 'snipr.com', 'snipurl.com', 'snurl.com', 'spedr.com', 'starturl.com', 'three.ly', 'timesurl.at', 'tiny.cc', 'tiny.pl', 'tinyarro.ws', 'tinylink.co.za', 'tinyuri.ca', 'tinyurl.com', 'tnij.org', 'tr.im', 'turo.us', 'twitclicks.com', 'twitpic.com', 'twt.fm', 'twurl.cc', 'twurl.nl', 'u.nu', 'ub0.cc', 'uris.jp', 'urlb.at', 'urlcut.com', 'urlenco.de', 'urlhawk.com', 'urltea.com', 'vieurl.com', 'w3t.org', 'x.se', 'xaddr.com', 'xr.com', 'xrl.us', 'yep.it', 'zi.ma', 'zombieurl.com', 'zz.gd'))
  1281.  
  1282. def is_short_url(url, domains = _short_domains):
  1283.     parsed = urlparse.urlparse(url)
  1284.     if parsed.netloc in domains:
  1285.         return True
  1286.     return False
  1287.  
  1288.  
  1289. def get_snurl(url):
  1290.     return get_short_url(url, 'snurl')
  1291.  
  1292.  
  1293. def get_isgd(url):
  1294.     return get_short_url(url, 'isgd')
  1295.  
  1296.  
  1297. def get_tinyurl(url):
  1298.     return get_short_url(url, 'tinyurl')
  1299.  
  1300.  
  1301. class UrlShortenerException(Exception):
  1302.     pass
  1303.  
  1304. from lrucache import LRU
  1305. _short_url_cache = LRU(10)
  1306.  
  1307. def cache_shortened_url(url, short_url):
  1308.     if short_url:
  1309.         _short_url_cache[short_url] = url
  1310.     
  1311.  
  1312.  
  1313. class UrlShortener(object):
  1314.     endpoint = None
  1315.     
  1316.     def build_request_url(self, url):
  1317.         return UrlQuery(self.endpoint, d = self.get_args(url.encode('utf-8')))
  1318.  
  1319.     
  1320.     def shorten(self, url):
  1321.         
  1322.         try:
  1323.             resp = urllib2.urlopen(self.build_request_url(url))
  1324.         except urllib2.HTTPError:
  1325.             e = None
  1326.             resp = e
  1327.  
  1328.         short_url = self.process_response(resp)
  1329.         cache_shortened_url(url, short_url)
  1330.         return short_url
  1331.  
  1332.     
  1333.     def shorten_async(self, url, success, error = None):
  1334.         
  1335.         def async_success(req, resp):
  1336.             
  1337.             try:
  1338.                 ret = self.process_response(resp)
  1339.             except Exception:
  1340.                 e = None
  1341.                 if error is not None:
  1342.                     error(e)
  1343.                 
  1344.             except:
  1345.                 error is not None
  1346.  
  1347.             cache_shortened_url(url, ret)
  1348.             success(ret)
  1349.  
  1350.         
  1351.         def async_error(req = None, resp = (None,)):
  1352.             print req
  1353.             print resp
  1354.             if error is not None:
  1355.                 error(None)
  1356.             
  1357.  
  1358.         import common.asynchttp as asynchttp
  1359.         asynchttp.httpopen(self.build_request_url(url), success = async_success, error = async_error)
  1360.  
  1361.     
  1362.     def get_args(self, url):
  1363.         raise NotImplementedError
  1364.  
  1365.     
  1366.     def process_response(self, resp):
  1367.         if resp.code != 200:
  1368.             body = resp.read()
  1369.             raise UrlShortenerException(body)
  1370.         resp.code != 200
  1371.         ret = resp.read()
  1372.         return ret
  1373.  
  1374.  
  1375.  
  1376. class isgd_shortener(UrlShortener):
  1377.     endpoint = 'http://is.gd/api.php'
  1378.     
  1379.     def get_args(self, url):
  1380.         return dict(longurl = url)
  1381.  
  1382.  
  1383.  
  1384. class tinyurl_shortener(UrlShortener):
  1385.     endpoint = 'http://tinyurl.com/api-create.php'
  1386.     
  1387.     def get_args(self, url):
  1388.         return dict(url = url)
  1389.  
  1390.  
  1391.  
  1392. class threely_shortener(UrlShortener):
  1393.     endpoint = 'http://3.ly/'
  1394.     
  1395.     def get_args(self, url):
  1396.         return dict(api = 'em5893833', u = url)
  1397.  
  1398.     
  1399.     def process_response(self, resp):
  1400.         ret = UrlShortener.process_response(self, resp)
  1401.         if not ret.startswith(self.endpoint):
  1402.             raise UrlShortenerException(ret)
  1403.         ret.startswith(self.endpoint)
  1404.         return ret
  1405.  
  1406.  
  1407.  
  1408. class snipr_shortener(UrlShortener):
  1409.     endpoint = 'http://snipr.com/site/snip'
  1410.     
  1411.     def get_args(self, url):
  1412.         return dict(r = 'simple', link = url.encode('url'))
  1413.  
  1414.     
  1415.     def process_response(self, resp):
  1416.         ret = UrlShortener.process_response(self, resp)
  1417.         if not ret.startswith('http'):
  1418.             raise UrlShortenerException('bad url: %r' % ret, ret)
  1419.         ret.startswith('http')
  1420.         return ret
  1421.  
  1422.  
  1423.  
  1424. class shortname_shortener(UrlShortener):
  1425.     endpoint = 'http://shortna.me/hash/'
  1426.     
  1427.     def get_args(self, url):
  1428.         return dict(snURL = url, api = 0)
  1429.  
  1430.     
  1431.     def process_response(self, resp):
  1432.         ret = UrlShortener.process_response(self, resp)
  1433.         import lxml.html as HTML
  1434.         doc = HTML.fromstring(ret)
  1435.         links = doc.findall('a')
  1436.         for link in links:
  1437.             href = link.attrib.get('href')
  1438.             if href is not None and href.startswith('http://shortna.me/') and href != 'http://shortna.me':
  1439.                 return href
  1440.         
  1441.         raise UrlShortenerException('short link not found in %r' % ret, ret)
  1442.  
  1443.  
  1444.  
  1445. class digsby_shortener(UrlShortener):
  1446.     endpoint = 'https://accounts.digsby.com/api/shorturl'
  1447.     
  1448.     def get_args(self, url):
  1449.         import common
  1450.         import hashlib
  1451.         username = common.profile.username.encode('utf8')
  1452.         password = hashlib.sha256(common.profile.password.encode('utf8')).digest()
  1453.         return {
  1454.             'user': username,
  1455.             'pass': password,
  1456.             'link': url }
  1457.  
  1458.     
  1459.     def process_response(self, httpresp):
  1460.         ret = UrlShortener.process_response(self, httpresp)
  1461.         resp = simplejson.loads(ret)
  1462.         if resp['shorter']['status'] == 'error':
  1463.             raise UrlShortenerException(resp['shorter']['errormsg'])
  1464.         resp['shorter']['status'] == 'error'
  1465.         if resp['shorter']['status'] == 'ok':
  1466.             import common
  1467.             url = resp['shorter']['shortURL']
  1468.             to_add = common.pref('urlshorteners.digsby.append_text', type = unicode, default = u'')
  1469.             return url + to_add
  1470.  
  1471.  
  1472.  
  1473. class bitly_shortener(UrlShortener):
  1474.     login = 'digsby'
  1475.     api_key = 'R_1fdb0bb8ce9af01f9939c2ffdf391dc8'
  1476.     endpoint = 'http://api.bit.ly/shorten'
  1477.     
  1478.     def __init__(self, login = None, api_key = None):
  1479.         if login is not None:
  1480.             self.login = login
  1481.         
  1482.         if api_key is not None:
  1483.             self.api_key = api_key
  1484.         
  1485.  
  1486.     
  1487.     def get_args(self, url):
  1488.         return dict(longUrl = url, version = '2.0.1', login = self.login, apiKey = self.api_key)
  1489.  
  1490.     
  1491.     def process_response(self, resp):
  1492.         ret = UrlShortener.process_response(self, resp)
  1493.         
  1494.         try:
  1495.             info = simplejson.loads(ret)
  1496.         except Exception:
  1497.             raise UrlShortenerException('expected JSON')
  1498.  
  1499.         if info['errorCode'] == 0:
  1500.             return self.extract_shorturl(info)
  1501.         raise UrlShortenerException(info['errorMessage'])
  1502.  
  1503.     
  1504.     def extract_shorturl(self, info):
  1505.         return info['results'].values()[0]['shortUrl']
  1506.  
  1507.  
  1508.  
  1509. class digsby_bitly_shortener(bitly_shortener):
  1510.     
  1511.     def extract_shorturl(self, info):
  1512.         return 'http://digs.by/' + info['results'].values()[0]['userHash']
  1513.  
  1514.  
  1515. _shorteners = {
  1516.     'isgd': isgd_shortener,
  1517.     'tinyurl': tinyurl_shortener,
  1518.     'tiny': tinyurl_shortener,
  1519.     'threely': threely_shortener,
  1520.     '3ly': threely_shortener,
  1521.     'shortname': shortname_shortener,
  1522.     'digsby': digsby_bitly_shortener }
  1523.  
  1524. def get_short_url(url, provider = 'digsby', choices = None):
  1525.     if choices is None:
  1526.         choices = list(_shorteners.keys())
  1527.     
  1528.     choices = choices[:]
  1529.     random.shuffle(choices)
  1530.     if provider is not None:
  1531.         choices.append(provider)
  1532.     
  1533.     e = None
  1534.     while choices:
  1535.         
  1536.         try:
  1537.             provider = choices.pop()
  1538.             shortener = _shorteners.get(provider)
  1539.             if shortener is None:
  1540.                 raise Exception('UrlShortener provider %r not found', provider)
  1541.             shortener is None
  1542.             return shortener().shorten(url)
  1543.         continue
  1544.         except Exception:
  1545.             e = None
  1546.             log.error('error getting short URL from %r: %r', provider, e)
  1547.             shortener = None
  1548.             provider = None
  1549.             continue
  1550.         
  1551.  
  1552.         None<EXCEPTION MATCH>Exception
  1553.     if e is None:
  1554.         e = Exception('No shorteners found!')
  1555.     
  1556.     raise e
  1557.  
  1558.  
  1559. def wget(url, data = None):
  1560.     closing = closing
  1561.     import contextlib
  1562.     import urllib2
  1563.     
  1564.     try:
  1565.         web = _[1]
  1566.         return web.read()
  1567.     finally:
  1568.         pass
  1569.  
  1570.  
  1571.  
  1572. def long_url_from_cache(shorturl):
  1573.     
  1574.     try:
  1575.         return _short_url_cache[shorturl]
  1576.     except KeyError:
  1577.         return None
  1578.  
  1579.  
  1580.  
  1581. def unshorten_url(url, cb):
  1582.     longurl = long_url_from_cache(url)
  1583.     if url is not None:
  1584.         return cb(longurl)
  1585.     requrl = UrlQuery('http://untiny.me/api/1.0/extract', url = url, format = 'json')
  1586.     
  1587.     def success(req, resp):
  1588.         json = resp.read()
  1589.         unshortened_url = simplejson.loads(json)['org_url']
  1590.         cb(unshortened_url)
  1591.  
  1592.     
  1593.     def error(req, resp):
  1594.         pass
  1595.  
  1596.     import common.asynchttp as asynchttp
  1597.     return asynchttp.httpopen(requrl, success = success, error = error)
  1598.  
  1599.  
  1600. def timestamp_to_http_date(ts):
  1601.     return rfc822.formatdate(timeval = ts)
  1602.  
  1603.  
  1604. def http_date_to_timestamp(date_str):
  1605.     if date_str is None:
  1606.         return None
  1607.     return calendar.timegm(rfc822.parsedate(date_str))
  1608.  
  1609. if __name__ == '__main__':
  1610.     print get_snurl('http://www.google.com')
  1611.  
  1612.