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