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

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. __version__ = '2.58'
  5. import binascii
  6. import os
  7. import random
  8. import re
  9. import socket
  10. import sys
  11. import time
  12. __all__ = [
  13.     'IMAP4',
  14.     'IMAP4_stream',
  15.     'Internaldate2tuple',
  16.     'Int2AP',
  17.     'ParseFlags',
  18.     'Time2Internaldate']
  19. CRLF = '\r\n'
  20. Debug = 0
  21. IMAP4_PORT = 143
  22. IMAP4_SSL_PORT = 993
  23. AllowedVersions = ('IMAP4REV1', 'IMAP4')
  24. Commands = {
  25.     'APPEND': ('AUTH', 'SELECTED'),
  26.     'AUTHENTICATE': ('NONAUTH',),
  27.     'CAPABILITY': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
  28.     'CHECK': ('SELECTED',),
  29.     'CLOSE': ('SELECTED',),
  30.     'COPY': ('SELECTED',),
  31.     'CREATE': ('AUTH', 'SELECTED'),
  32.     'DELETE': ('AUTH', 'SELECTED'),
  33.     'DELETEACL': ('AUTH', 'SELECTED'),
  34.     'EXAMINE': ('AUTH', 'SELECTED'),
  35.     'EXPUNGE': ('SELECTED',),
  36.     'FETCH': ('SELECTED',),
  37.     'GETACL': ('AUTH', 'SELECTED'),
  38.     'GETANNOTATION': ('AUTH', 'SELECTED'),
  39.     'GETQUOTA': ('AUTH', 'SELECTED'),
  40.     'GETQUOTAROOT': ('AUTH', 'SELECTED'),
  41.     'MYRIGHTS': ('AUTH', 'SELECTED'),
  42.     'LIST': ('AUTH', 'SELECTED'),
  43.     'LOGIN': ('NONAUTH',),
  44.     'LOGOUT': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
  45.     'LSUB': ('AUTH', 'SELECTED'),
  46.     'NAMESPACE': ('AUTH', 'SELECTED'),
  47.     'NOOP': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
  48.     'PARTIAL': ('SELECTED',),
  49.     'PROXYAUTH': ('AUTH',),
  50.     'RENAME': ('AUTH', 'SELECTED'),
  51.     'SEARCH': ('SELECTED',),
  52.     'SELECT': ('AUTH', 'SELECTED'),
  53.     'SETACL': ('AUTH', 'SELECTED'),
  54.     'SETANNOTATION': ('AUTH', 'SELECTED'),
  55.     'SETQUOTA': ('AUTH', 'SELECTED'),
  56.     'SORT': ('SELECTED',),
  57.     'STATUS': ('AUTH', 'SELECTED'),
  58.     'STORE': ('SELECTED',),
  59.     'SUBSCRIBE': ('AUTH', 'SELECTED'),
  60.     'THREAD': ('SELECTED',),
  61.     'UID': ('SELECTED',),
  62.     'UNSUBSCRIBE': ('AUTH', 'SELECTED') }
  63. Continuation = re.compile('\\+( (?P<data>.*))?')
  64. Flags = re.compile('.*FLAGS \\((?P<flags>[^\\)]*)\\)')
  65. InternalDate = re.compile('.*INTERNALDATE "(?P<day>[ 0123][0-9])-(?P<mon>[A-Z][a-z][a-z])-(?P<year>[0-9][0-9][0-9][0-9]) (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9]) (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])"')
  66. Literal = re.compile('.*{(?P<size>\\d+)}$')
  67. MapCRLF = re.compile('\\r\\n|\\r|\\n')
  68. Response_code = re.compile('\\[(?P<type>[A-Z-]+)( (?P<data>[^\\]]*))?\\]')
  69. Untagged_response = re.compile('\\* (?P<type>[A-Z-]+)( (?P<data>.*))?')
  70. Untagged_status = re.compile('\\* (?P<data>\\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?')
  71.  
  72. class IMAP4:
  73.     
  74.     class error(Exception):
  75.         pass
  76.  
  77.     
  78.     class abort(error):
  79.         pass
  80.  
  81.     
  82.     class readonly(abort):
  83.         pass
  84.  
  85.     mustquote = re.compile("[^\\w!#$%&'*+,.:;<=>?^`|~-]")
  86.     
  87.     def __init__(self, host = '', port = IMAP4_PORT):
  88.         self.debug = Debug
  89.         self.state = 'LOGOUT'
  90.         self.literal = None
  91.         self.tagged_commands = { }
  92.         self.untagged_responses = { }
  93.         self.continuation_response = ''
  94.         self.is_readonly = False
  95.         self.tagnum = 0
  96.         self.open(host, port)
  97.         self.tagpre = Int2AP(random.randint(4096, 65535))
  98.         self.tagre = re.compile('(?P<tag>' + self.tagpre + '\\d+) (?P<type>[A-Z]+) (?P<data>.*)')
  99.         self.welcome = self._get_response()
  100.         if 'PREAUTH' in self.untagged_responses:
  101.             self.state = 'AUTH'
  102.         elif 'OK' in self.untagged_responses:
  103.             self.state = 'NONAUTH'
  104.         else:
  105.             raise self.error(self.welcome)
  106.         (typ, dat) = ('PREAUTH' in self.untagged_responses).capability()
  107.         if dat == [
  108.             None]:
  109.             raise self.error('no CAPABILITY response from server')
  110.         dat == [
  111.             None]
  112.         self.capabilities = tuple(dat[-1].upper().split())
  113.         for version in AllowedVersions:
  114.             if version not in self.capabilities:
  115.                 continue
  116.             
  117.             self.PROTOCOL_VERSION = version
  118.             return None
  119.         
  120.         raise self.error('server not IMAP4 compliant')
  121.  
  122.     
  123.     def __getattr__(self, attr):
  124.         if attr in Commands:
  125.             return getattr(self, attr.lower())
  126.         raise AttributeError("Unknown IMAP4 command: '%s'" % attr)
  127.  
  128.     
  129.     def open(self, host = '', port = IMAP4_PORT):
  130.         self.host = host
  131.         self.port = port
  132.         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  133.         self.sock.connect((host, port))
  134.         self.file = self.sock.makefile('rb')
  135.  
  136.     
  137.     def read(self, size):
  138.         return self.file.read(size)
  139.  
  140.     
  141.     def readline(self):
  142.         return self.file.readline()
  143.  
  144.     
  145.     def send(self, data):
  146.         self.sock.sendall(data)
  147.  
  148.     
  149.     def shutdown(self):
  150.         self.file.close()
  151.         self.sock.close()
  152.  
  153.     
  154.     def socket(self):
  155.         return self.sock
  156.  
  157.     
  158.     def recent(self):
  159.         name = 'RECENT'
  160.         (typ, dat) = self._untagged_response('OK', [
  161.             None], name)
  162.         if dat[-1]:
  163.             return (typ, dat)
  164.         (typ, dat) = self.noop()
  165.         return self._untagged_response(typ, dat, name)
  166.  
  167.     
  168.     def response(self, code):
  169.         return self._untagged_response(code, [
  170.             None], code.upper())
  171.  
  172.     
  173.     def append(self, mailbox, flags, date_time, message):
  174.         name = 'APPEND'
  175.         if not mailbox:
  176.             mailbox = 'INBOX'
  177.         
  178.         if flags:
  179.             if (flags[0], flags[-1]) != ('(', ')'):
  180.                 flags = '(%s)' % flags
  181.             
  182.         else:
  183.             flags = None
  184.         if date_time:
  185.             date_time = Time2Internaldate(date_time)
  186.         else:
  187.             date_time = None
  188.         self.literal = MapCRLF.sub(CRLF, message)
  189.         return self._simple_command(name, mailbox, flags, date_time)
  190.  
  191.     
  192.     def authenticate(self, mechanism, authobject):
  193.         mech = mechanism.upper()
  194.         self.literal = _Authenticator(authobject).process
  195.         (typ, dat) = self._simple_command('AUTHENTICATE', mech)
  196.         if typ != 'OK':
  197.             raise self.error(dat[-1])
  198.         typ != 'OK'
  199.         self.state = 'AUTH'
  200.         return (typ, dat)
  201.  
  202.     
  203.     def capability(self):
  204.         name = 'CAPABILITY'
  205.         (typ, dat) = self._simple_command(name)
  206.         return self._untagged_response(typ, dat, name)
  207.  
  208.     
  209.     def check(self):
  210.         return self._simple_command('CHECK')
  211.  
  212.     
  213.     def close(self):
  214.         
  215.         try:
  216.             (typ, dat) = self._simple_command('CLOSE')
  217.         finally:
  218.             self.state = 'AUTH'
  219.  
  220.         return (typ, dat)
  221.  
  222.     
  223.     def copy(self, message_set, new_mailbox):
  224.         return self._simple_command('COPY', message_set, new_mailbox)
  225.  
  226.     
  227.     def create(self, mailbox):
  228.         return self._simple_command('CREATE', mailbox)
  229.  
  230.     
  231.     def delete(self, mailbox):
  232.         return self._simple_command('DELETE', mailbox)
  233.  
  234.     
  235.     def deleteacl(self, mailbox, who):
  236.         return self._simple_command('DELETEACL', mailbox, who)
  237.  
  238.     
  239.     def expunge(self):
  240.         name = 'EXPUNGE'
  241.         (typ, dat) = self._simple_command(name)
  242.         return self._untagged_response(typ, dat, name)
  243.  
  244.     
  245.     def fetch(self, message_set, message_parts):
  246.         name = 'FETCH'
  247.         (typ, dat) = self._simple_command(name, message_set, message_parts)
  248.         return self._untagged_response(typ, dat, name)
  249.  
  250.     
  251.     def getacl(self, mailbox):
  252.         (typ, dat) = self._simple_command('GETACL', mailbox)
  253.         return self._untagged_response(typ, dat, 'ACL')
  254.  
  255.     
  256.     def getannotation(self, mailbox, entry, attribute):
  257.         (typ, dat) = self._simple_command('GETANNOTATION', mailbox, entry, attribute)
  258.         return self._untagged_response(typ, dat, 'ANNOTATION')
  259.  
  260.     
  261.     def getquota(self, root):
  262.         (typ, dat) = self._simple_command('GETQUOTA', root)
  263.         return self._untagged_response(typ, dat, 'QUOTA')
  264.  
  265.     
  266.     def getquotaroot(self, mailbox):
  267.         (typ, dat) = self._simple_command('GETQUOTAROOT', mailbox)
  268.         (typ, quota) = self._untagged_response(typ, dat, 'QUOTA')
  269.         (typ, quotaroot) = self._untagged_response(typ, dat, 'QUOTAROOT')
  270.         return (typ, [
  271.             quotaroot,
  272.             quota])
  273.  
  274.     
  275.     def list(self, directory = '""', pattern = '*'):
  276.         name = 'LIST'
  277.         (typ, dat) = self._simple_command(name, directory, pattern)
  278.         return self._untagged_response(typ, dat, name)
  279.  
  280.     
  281.     def login(self, user, password):
  282.         (typ, dat) = self._simple_command('LOGIN', user, self._quote(password))
  283.         if typ != 'OK':
  284.             raise self.error(dat[-1])
  285.         typ != 'OK'
  286.         self.state = 'AUTH'
  287.         return (typ, dat)
  288.  
  289.     
  290.     def login_cram_md5(self, user, password):
  291.         self.user = user
  292.         self.password = password
  293.         return self.authenticate('CRAM-MD5', self._CRAM_MD5_AUTH)
  294.  
  295.     
  296.     def _CRAM_MD5_AUTH(self, challenge):
  297.         import hmac
  298.         return self.user + ' ' + hmac.HMAC(self.password, challenge).hexdigest()
  299.  
  300.     
  301.     def logout(self):
  302.         self.state = 'LOGOUT'
  303.         
  304.         try:
  305.             (typ, dat) = self._simple_command('LOGOUT')
  306.         except:
  307.             typ = 'NO'
  308.             dat = [
  309.                 '%s: %s' % sys.exc_info()[:2]]
  310.  
  311.         self.shutdown()
  312.         if 'BYE' in self.untagged_responses:
  313.             return ('BYE', self.untagged_responses['BYE'])
  314.         return (typ, dat)
  315.  
  316.     
  317.     def lsub(self, directory = '""', pattern = '*'):
  318.         name = 'LSUB'
  319.         (typ, dat) = self._simple_command(name, directory, pattern)
  320.         return self._untagged_response(typ, dat, name)
  321.  
  322.     
  323.     def myrights(self, mailbox):
  324.         (typ, dat) = self._simple_command('MYRIGHTS', mailbox)
  325.         return self._untagged_response(typ, dat, 'MYRIGHTS')
  326.  
  327.     
  328.     def namespace(self):
  329.         name = 'NAMESPACE'
  330.         (typ, dat) = self._simple_command(name)
  331.         return self._untagged_response(typ, dat, name)
  332.  
  333.     
  334.     def noop(self):
  335.         return self._simple_command('NOOP')
  336.  
  337.     
  338.     def partial(self, message_num, message_part, start, length):
  339.         name = 'PARTIAL'
  340.         (typ, dat) = self._simple_command(name, message_num, message_part, start, length)
  341.         return self._untagged_response(typ, dat, 'FETCH')
  342.  
  343.     
  344.     def proxyauth(self, user):
  345.         name = 'PROXYAUTH'
  346.         return self._simple_command('PROXYAUTH', user)
  347.  
  348.     
  349.     def rename(self, oldmailbox, newmailbox):
  350.         return self._simple_command('RENAME', oldmailbox, newmailbox)
  351.  
  352.     
  353.     def search(self, charset, *criteria):
  354.         name = 'SEARCH'
  355.         if charset:
  356.             (typ, dat) = self._simple_command(name, 'CHARSET', charset, *criteria)
  357.         else:
  358.             (typ, dat) = self._simple_command(name, *criteria)
  359.         return self._untagged_response(typ, dat, name)
  360.  
  361.     
  362.     def select(self, mailbox = 'INBOX', readonly = False):
  363.         self.untagged_responses = { }
  364.         self.is_readonly = readonly
  365.         if readonly:
  366.             name = 'EXAMINE'
  367.         else:
  368.             name = 'SELECT'
  369.         (typ, dat) = self._simple_command(name, mailbox)
  370.         if typ != 'OK':
  371.             self.state = 'AUTH'
  372.             return (typ, dat)
  373.         self.state = 'SELECTED'
  374.         if 'READ-ONLY' in self.untagged_responses and not readonly:
  375.             raise self.readonly('%s is not writable' % mailbox)
  376.         not readonly
  377.         return (typ, self.untagged_responses.get('EXISTS', [
  378.             None]))
  379.  
  380.     
  381.     def setacl(self, mailbox, who, what):
  382.         return self._simple_command('SETACL', mailbox, who, what)
  383.  
  384.     
  385.     def setannotation(self, *args):
  386.         (typ, dat) = self._simple_command('SETANNOTATION', *args)
  387.         return self._untagged_response(typ, dat, 'ANNOTATION')
  388.  
  389.     
  390.     def setquota(self, root, limits):
  391.         (typ, dat) = self._simple_command('SETQUOTA', root, limits)
  392.         return self._untagged_response(typ, dat, 'QUOTA')
  393.  
  394.     
  395.     def sort(self, sort_criteria, charset, *search_criteria):
  396.         name = 'SORT'
  397.         if (sort_criteria[0], sort_criteria[-1]) != ('(', ')'):
  398.             sort_criteria = '(%s)' % sort_criteria
  399.         
  400.         (typ, dat) = self._simple_command(name, sort_criteria, charset, *search_criteria)
  401.         return self._untagged_response(typ, dat, name)
  402.  
  403.     
  404.     def status(self, mailbox, names):
  405.         name = 'STATUS'
  406.         (typ, dat) = self._simple_command(name, mailbox, names)
  407.         return self._untagged_response(typ, dat, name)
  408.  
  409.     
  410.     def store(self, message_set, command, flags):
  411.         if (flags[0], flags[-1]) != ('(', ')'):
  412.             flags = '(%s)' % flags
  413.         
  414.         (typ, dat) = self._simple_command('STORE', message_set, command, flags)
  415.         return self._untagged_response(typ, dat, 'FETCH')
  416.  
  417.     
  418.     def subscribe(self, mailbox):
  419.         return self._simple_command('SUBSCRIBE', mailbox)
  420.  
  421.     
  422.     def thread(self, threading_algorithm, charset, *search_criteria):
  423.         name = 'THREAD'
  424.         (typ, dat) = self._simple_command(name, threading_algorithm, charset, *search_criteria)
  425.         return self._untagged_response(typ, dat, name)
  426.  
  427.     
  428.     def uid(self, command, *args):
  429.         command = command.upper()
  430.         if command not in Commands:
  431.             raise self.error('Unknown IMAP4 UID command: %s' % command)
  432.         command not in Commands
  433.         if self.state not in Commands[command]:
  434.             raise self.error('command %s illegal in state %s, only allowed in states %s' % (command, self.state, ', '.join(Commands[command])))
  435.         self.state not in Commands[command]
  436.         name = 'UID'
  437.         (typ, dat) = self._simple_command(name, command, *args)
  438.         if command in ('SEARCH', 'SORT'):
  439.             name = command
  440.         else:
  441.             name = 'FETCH'
  442.         return self._untagged_response(typ, dat, name)
  443.  
  444.     
  445.     def unsubscribe(self, mailbox):
  446.         return self._simple_command('UNSUBSCRIBE', mailbox)
  447.  
  448.     
  449.     def xatom(self, name, *args):
  450.         name = name.upper()
  451.         if name not in Commands:
  452.             Commands[name] = (self.state,)
  453.         
  454.         return self._simple_command(name, *args)
  455.  
  456.     
  457.     def _append_untagged(self, typ, dat):
  458.         if dat is None:
  459.             dat = ''
  460.         
  461.         ur = self.untagged_responses
  462.         if typ in ur:
  463.             ur[typ].append(dat)
  464.         else:
  465.             ur[typ] = [
  466.                 dat]
  467.  
  468.     
  469.     def _check_bye(self):
  470.         bye = self.untagged_responses.get('BYE')
  471.         if bye:
  472.             raise self.abort(bye[-1])
  473.         bye
  474.  
  475.     
  476.     def _command(self, name, *args):
  477.         if self.state not in Commands[name]:
  478.             self.literal = None
  479.             raise self.error('command %s illegal in state %s, only allowed in states %s' % (name, self.state, ', '.join(Commands[name])))
  480.         self.state not in Commands[name]
  481.         for typ in ('OK', 'NO', 'BAD'):
  482.             if typ in self.untagged_responses:
  483.                 del self.untagged_responses[typ]
  484.                 continue
  485.         
  486.         if 'READ-ONLY' in self.untagged_responses and not (self.is_readonly):
  487.             raise self.readonly('mailbox status changed to READ-ONLY')
  488.         not (self.is_readonly)
  489.         tag = self._new_tag()
  490.         data = '%s %s' % (tag, name)
  491.         for arg in args:
  492.             if arg is None:
  493.                 continue
  494.             
  495.             data = '%s %s' % (data, self._checkquote(arg))
  496.         
  497.         literal = self.literal
  498.         if literal is not None:
  499.             self.literal = None
  500.             if type(literal) is type(self._command):
  501.                 literator = literal
  502.             else:
  503.                 literator = None
  504.                 data = '%s {%s}' % (data, len(literal))
  505.         
  506.         
  507.         try:
  508.             self.send('%s%s' % (data, CRLF))
  509.         except (socket.error, OSError):
  510.             val = None
  511.             raise self.abort('socket error: %s' % val)
  512.  
  513.         if literal is None:
  514.             return tag
  515.         while None:
  516.             while self._get_response():
  517.                 if self.tagged_commands[tag]:
  518.                     return tag
  519.                 continue
  520.                 self.tagged_commands[tag]
  521.             if literator:
  522.                 literal = literator(self.continuation_response)
  523.             
  524.             
  525.             try:
  526.                 self.send(literal)
  527.                 self.send(CRLF)
  528.             except (socket.error, OSError):
  529.                 val = None
  530.                 raise self.abort('socket error: %s' % val)
  531.  
  532.             if not literator:
  533.                 break
  534.                 continue
  535.             continue
  536.             return tag
  537.  
  538.     
  539.     def _command_complete(self, name, tag):
  540.         self._check_bye()
  541.         
  542.         try:
  543.             (typ, data) = self._get_tagged_response(tag)
  544.         except self.abort:
  545.             val = None
  546.             raise self.abort('command: %s => %s' % (name, val))
  547.         except self.error:
  548.             val = None
  549.             raise self.error('command: %s => %s' % (name, val))
  550.  
  551.         self._check_bye()
  552.         if typ == 'BAD':
  553.             raise self.error('%s command error: %s %s' % (name, typ, data))
  554.         typ == 'BAD'
  555.         return (typ, data)
  556.  
  557.     
  558.     def _get_response(self):
  559.         resp = self._get_line()
  560.         if self._match(self.tagre, resp):
  561.             tag = self.mo.group('tag')
  562.             if tag not in self.tagged_commands:
  563.                 raise self.abort('unexpected tagged response: %s' % resp)
  564.             tag not in self.tagged_commands
  565.             typ = self.mo.group('type')
  566.             dat = self.mo.group('data')
  567.             self.tagged_commands[tag] = (typ, [
  568.                 dat])
  569.         else:
  570.             dat2 = None
  571.             if not self._match(Untagged_response, resp):
  572.                 if self._match(Untagged_status, resp):
  573.                     dat2 = self.mo.group('data2')
  574.                 
  575.             
  576.             if self.mo is None:
  577.                 if self._match(Continuation, resp):
  578.                     self.continuation_response = self.mo.group('data')
  579.                     return None
  580.                 raise self.abort("unexpected response: '%s'" % resp)
  581.             self.mo is None
  582.             typ = self.mo.group('type')
  583.             dat = self.mo.group('data')
  584.             if dat is None:
  585.                 dat = ''
  586.             
  587.             if dat2:
  588.                 dat = dat + ' ' + dat2
  589.             
  590.             while self._match(Literal, dat):
  591.                 size = int(self.mo.group('size'))
  592.                 data = self.read(size)
  593.                 self._append_untagged(typ, (dat, data))
  594.                 dat = self._get_line()
  595.             self._append_untagged(typ, dat)
  596.         if typ in ('OK', 'NO', 'BAD') and self._match(Response_code, dat):
  597.             self._append_untagged(self.mo.group('type'), self.mo.group('data'))
  598.         
  599.         return resp
  600.  
  601.     
  602.     def _get_tagged_response(self, tag):
  603.         while None:
  604.             result = self.tagged_commands[tag]
  605.             if result is not None:
  606.                 del self.tagged_commands[tag]
  607.                 return result
  608.             
  609.             try:
  610.                 self._get_response()
  611.             continue
  612.             except self.abort:
  613.                 result is not None
  614.                 val = result is not None
  615.                 raise 
  616.                 continue
  617.             
  618.  
  619.             return None
  620.  
  621.     
  622.     def _get_line(self):
  623.         line = self.readline()
  624.         if not line:
  625.             raise self.abort('socket error: EOF')
  626.         line
  627.         line = line[:-2]
  628.         return line
  629.  
  630.     
  631.     def _match(self, cre, s):
  632.         self.mo = cre.match(s)
  633.         return self.mo is not None
  634.  
  635.     
  636.     def _new_tag(self):
  637.         tag = '%s%s' % (self.tagpre, self.tagnum)
  638.         self.tagnum = self.tagnum + 1
  639.         self.tagged_commands[tag] = None
  640.         return tag
  641.  
  642.     
  643.     def _checkquote(self, arg):
  644.         if type(arg) is not type(''):
  645.             return arg
  646.         if len(arg) >= 2 and (arg[0], arg[-1]) in (('(', ')'), ('"', '"')):
  647.             return arg
  648.         if arg and self.mustquote.search(arg) is None:
  649.             return arg
  650.         return self._quote(arg)
  651.  
  652.     
  653.     def _quote(self, arg):
  654.         arg = arg.replace('\\', '\\\\')
  655.         arg = arg.replace('"', '\\"')
  656.         return '"%s"' % arg
  657.  
  658.     
  659.     def _simple_command(self, name, *args):
  660.         return self._command_complete(name, self._command(name, *args))
  661.  
  662.     
  663.     def _untagged_response(self, typ, dat, name):
  664.         if typ == 'NO':
  665.             return (typ, dat)
  666.         if name not in self.untagged_responses:
  667.             return (typ, [
  668.                 None])
  669.         data = self.untagged_responses.pop(name)
  670.         return (typ, data)
  671.  
  672.  
  673.  
  674. try:
  675.     import ssl
  676. except ImportError:
  677.     pass
  678.  
  679.  
  680. class IMAP4_SSL(IMAP4):
  681.     
  682.     def __init__(self, host = '', port = IMAP4_SSL_PORT, keyfile = None, certfile = None):
  683.         self.keyfile = keyfile
  684.         self.certfile = certfile
  685.         IMAP4.__init__(self, host, port)
  686.  
  687.     
  688.     def open(self, host = '', port = IMAP4_SSL_PORT):
  689.         self.host = host
  690.         self.port = port
  691.         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  692.         self.sock.connect((host, port))
  693.         self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
  694.  
  695.     
  696.     def read(self, size):
  697.         chunks = []
  698.         read = 0
  699.         while read < size:
  700.             data = self.sslobj.read(min(size - read, 16384))
  701.             read += len(data)
  702.             chunks.append(data)
  703.         return ''.join(chunks)
  704.  
  705.     
  706.     def readline(self):
  707.         line = []
  708.         while None:
  709.             char = self.sslobj.read(1)
  710.             if char == '\n':
  711.                 return ''.join(line)
  712.             continue
  713.             return None
  714.  
  715.     
  716.     def send(self, data):
  717.         bytes = len(data)
  718.         while bytes > 0:
  719.             sent = self.sslobj.write(data)
  720.             if sent == bytes:
  721.                 break
  722.             
  723.             data = data[sent:]
  724.             bytes = bytes - sent
  725.  
  726.     
  727.     def shutdown(self):
  728.         self.sock.close()
  729.  
  730.     
  731.     def socket(self):
  732.         return self.sock
  733.  
  734.     
  735.     def ssl(self):
  736.         return self.sslobj
  737.  
  738.  
  739. __all__.append('IMAP4_SSL')
  740.  
  741. class IMAP4_stream(IMAP4):
  742.     
  743.     def __init__(self, command):
  744.         self.command = command
  745.         IMAP4.__init__(self)
  746.  
  747.     
  748.     def open(self, host = None, port = None):
  749.         self.host = None
  750.         self.port = None
  751.         self.sock = None
  752.         self.file = None
  753.         (self.writefile, self.readfile) = os.popen2(self.command)
  754.  
  755.     
  756.     def read(self, size):
  757.         return self.readfile.read(size)
  758.  
  759.     
  760.     def readline(self):
  761.         return self.readfile.readline()
  762.  
  763.     
  764.     def send(self, data):
  765.         self.writefile.write(data)
  766.         self.writefile.flush()
  767.  
  768.     
  769.     def shutdown(self):
  770.         self.readfile.close()
  771.         self.writefile.close()
  772.  
  773.  
  774.  
  775. class _Authenticator:
  776.     
  777.     def __init__(self, mechinst):
  778.         self.mech = mechinst
  779.  
  780.     
  781.     def process(self, data):
  782.         ret = self.mech(self.decode(data))
  783.         if ret is None:
  784.             return '*'
  785.         return self.encode(ret)
  786.  
  787.     
  788.     def encode(self, inp):
  789.         oup = ''
  790.         while inp:
  791.             if len(inp) > 48:
  792.                 t = inp[:48]
  793.                 inp = inp[48:]
  794.             else:
  795.                 t = inp
  796.                 inp = ''
  797.             e = binascii.b2a_base64(t)
  798.             if e:
  799.                 oup = oup + e[:-1]
  800.                 continue
  801.         return oup
  802.  
  803.     
  804.     def decode(self, inp):
  805.         if not inp:
  806.             return ''
  807.         return binascii.a2b_base64(inp)
  808.  
  809.  
  810. Mon2num = {
  811.     'Jan': 1,
  812.     'Feb': 2,
  813.     'Mar': 3,
  814.     'Apr': 4,
  815.     'May': 5,
  816.     'Jun': 6,
  817.     'Jul': 7,
  818.     'Aug': 8,
  819.     'Sep': 9,
  820.     'Oct': 10,
  821.     'Nov': 11,
  822.     'Dec': 12 }
  823.  
  824. def Internaldate2tuple(resp):
  825.     mo = InternalDate.match(resp)
  826.     if not mo:
  827.         return None
  828.     mon = Mon2num[mo.group('mon')]
  829.     zonen = mo.group('zonen')
  830.     day = int(mo.group('day'))
  831.     year = int(mo.group('year'))
  832.     hour = int(mo.group('hour'))
  833.     min = int(mo.group('min'))
  834.     sec = int(mo.group('sec'))
  835.     zoneh = int(mo.group('zoneh'))
  836.     zonem = int(mo.group('zonem'))
  837.     zone = (zoneh * 60 + zonem) * 60
  838.     if zonen == '-':
  839.         zone = -zone
  840.     
  841.     tt = (year, mon, day, hour, min, sec, -1, -1, -1)
  842.     utc = time.mktime(tt)
  843.     lt = time.localtime(utc)
  844.     if time.daylight and lt[-1]:
  845.         zone = zone + time.altzone
  846.     else:
  847.         zone = zone + time.timezone
  848.     return time.localtime(utc - zone)
  849.  
  850.  
  851. def Int2AP(num):
  852.     val = ''
  853.     AP = 'ABCDEFGHIJKLMNOP'
  854.     num = int(abs(num))
  855.     while num:
  856.         (num, mod) = divmod(num, 16)
  857.         val = AP[mod] + val
  858.     return val
  859.  
  860.  
  861. def ParseFlags(resp):
  862.     mo = Flags.match(resp)
  863.     if not mo:
  864.         return ()
  865.     return tuple(mo.group('flags').split())
  866.  
  867.  
  868. def Time2Internaldate(date_time):
  869.     if isinstance(date_time, (int, float)):
  870.         tt = time.localtime(date_time)
  871.     elif isinstance(date_time, (tuple, time.struct_time)):
  872.         tt = date_time
  873.     elif isinstance(date_time, str) and (date_time[0], date_time[-1]) == ('"', '"'):
  874.         return date_time
  875.     raise ValueError('date_time not of a known type')
  876.     dt = time.strftime('%d-%b-%Y %H:%M:%S', tt)
  877.     if dt[0] == '0':
  878.         dt = ' ' + dt[1:]
  879.     
  880.     if time.daylight and tt[-1]:
  881.         zone = -(time.altzone)
  882.     else:
  883.         zone = -(time.timezone)
  884.     return '"' + dt + ' %+03d%02d' % divmod(zone // 60, 60) + '"'
  885.  
  886. if __name__ == '__main__':
  887.     import getopt
  888.     import getpass
  889.     
  890.     try:
  891.         (optlist, args) = getopt.getopt(sys.argv[1:], 'd:s:')
  892.     except getopt.error:
  893.         val = None
  894.         (optlist, args) = ((), ())
  895.  
  896.     stream_command = None
  897.     for opt, val in optlist:
  898.         if opt == '-d':
  899.             Debug = int(val)
  900.         elif opt == '-s':
  901.             stream_command = val
  902.             if not args:
  903.                 args = (stream_command,)
  904.             
  905.         
  906.     
  907.     if not args:
  908.         args = ('',)
  909.     
  910.     host = args[0]
  911.     USER = getpass.getuser()
  912.     if not host:
  913.         pass
  914.     PASSWD = getpass.getpass('IMAP password for %s on %s: ' % (USER, 'localhost'))
  915.     test_mesg = 'From: %(user)s@localhost%(lf)sSubject: IMAP4 test%(lf)s%(lf)sdata...%(lf)s' % {
  916.         'user': USER,
  917.         'lf': '\n' }
  918.     test_seq1 = (('login', (USER, PASSWD)), ('create', ('/tmp/xxx 1',)), ('rename', ('/tmp/xxx 1', '/tmp/yyy')), ('CREATE', ('/tmp/yyz 2',)), ('append', ('/tmp/yyz 2', None, None, test_mesg)), ('list', ('/tmp', 'yy*')), ('select', ('/tmp/yyz 2',)), ('search', (None, 'SUBJECT', 'test')), ('fetch', ('1', '(FLAGS INTERNALDATE RFC822)')), ('store', ('1', 'FLAGS', '(\\Deleted)')), ('namespace', ()), ('expunge', ()), ('recent', ()), ('close', ()))
  919.     test_seq2 = (('select', ()), ('response', ('UIDVALIDITY',)), ('uid', ('SEARCH', 'ALL')), ('response', ('EXISTS',)), ('append', (None, None, None, test_mesg)), ('recent', ()), ('logout', ()))
  920.     
  921.     def run(cmd, args):
  922.         M._mesg('%s %s' % (cmd, args))
  923.         (typ, dat) = getattr(M, cmd)(*args)
  924.         M._mesg('%s => %s %s' % (cmd, typ, dat))
  925.         if typ == 'NO':
  926.             raise dat[0]
  927.         typ == 'NO'
  928.         return dat
  929.  
  930.     
  931.     try:
  932.         if stream_command:
  933.             M = IMAP4_stream(stream_command)
  934.         else:
  935.             M = IMAP4(host)
  936.         if M.state == 'AUTH':
  937.             test_seq1 = test_seq1[1:]
  938.         
  939.         M._mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
  940.         M._mesg('CAPABILITIES = %r' % (M.capabilities,))
  941.         for cmd, args in test_seq1:
  942.             run(cmd, args)
  943.         
  944.         for ml in run('list', ('/tmp/', 'yy%')):
  945.             mo = re.match('.*"([^"]+)"$', ml)
  946.             if mo:
  947.                 path = mo.group(1)
  948.             else:
  949.                 path = ml.split()[-1]
  950.             run('delete', (path,))
  951.         
  952.         for cmd, args in test_seq2:
  953.             dat = run(cmd, args)
  954.             if (cmd, args) != ('uid', ('SEARCH', 'ALL')):
  955.                 continue
  956.             
  957.             uid = dat[-1].split()
  958.             if not uid:
  959.                 continue
  960.             
  961.             run('uid', ('FETCH', '%s' % uid[-1], '(FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822.TEXT)'))
  962.         
  963.         print '\nAll tests OK.'
  964.     except:
  965.         print '\nTests failed.'
  966.         if not Debug:
  967.             print '\nIf you would like to see debugging output,\ntry: %s -d5\n' % sys.argv[0]
  968.         
  969.         raise 
  970.  
  971.  
  972.