ó
Gh\c           @   s…  d  d l  Z  d  d l Z d  d l Z d  d l Z d  d l m Z d, Z e  j d ƒ Z d „  Z	 d „  Z
 d „  Z d	 „  Z d
 „  Z d „  Z d „  Z d- d. d/ d0 d1 g Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d  „  Z d! „  Z d" „  Z d# „  Z d$ „  Z d% „  Z d& „  Z  d' e j! f d( „  ƒ  YZ! d) e j" f d* „  ƒ  YZ" d+ „  Z# e j$ e# ƒ d S(2   iÿÿÿÿN(   t   getglobaluis   X-Labelt   Keywordss
   &[^-]*-|\+c          G   sJ   g  } x! |  D] } | j  t | ƒ ƒ q Wt ƒ  j d d j | ƒ ƒ d  S(   Nt   imapt    (   t   appendt   strR    t   debugt   join(   t   argst   msgt   arg(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   __debug"   s    c         C   s\   |  rX |  j  d ƒ rX |  j d ƒ rX |  d d !}  |  j d d ƒ }  |  j d d ƒ }  n  |  S(   s¦   Takes string which may or may not be quoted and unquotes it.

    It only considers double quotes. This function does NOT consider
    parenthised lists to be quoted.t   "i   iÿÿÿÿs   \"s   \\s   \(   t
   startswitht   endswitht   replace(   t   s(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   dequote(   s
    $c         C   s,   |  j  d d ƒ }  |  j  d d ƒ }  d |  S(   sŒ   Takes an unquoted string and quotes it.

    It only adds double quotes. This function does NOT consider
    parenthised lists to be quoted.R   s   \"s   \s   \\s   "%s"(   R   (   R   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   quote4   s    c         C   sD   |  d d k s  |  d d k r3 t  d |  ƒ ‚ n  t |  d d !ƒ S(   sÐ   Converts a string of IMAP flags to a list

    :returns: E.g. '(\Draft \Deleted)' returns  ['\Draft','\Deleted'].
        (FLAGS (\Seen Old) UID 4807) returns
        ['FLAGS,'(\Seen Old)','UID', '4807']
    i    t   (iÿÿÿÿt   )s    Passed s '%s' is not a flag listi   (   t
   ValueErrort	   imapsplit(   R   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt	   flagsplit>   s     c         C   sV   i  } d } x6 | t  |  ƒ k  rD |  | d | |  | <| d 7} q Wt d | ƒ | S(   s-   convert list [1,2,3,4,5,6] to {1:2, 3:4, 5:6}i    i   i   s   __options2hash returning:(   t   lenR   (   t   listt   retvalt   counter(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   __options2hashJ   s    c         C   s   t  t |  ƒ ƒ S(   sœ   Converts IMAP response string from eg IMAP4.fetch() to a hash.

    E.g. '(FLAGS (\Seen Old) UID 4807)' leads to
    {'FLAGS': '(\Seen Old)', 'UID': '4807'}(   R   R   (   t   flags(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt
   flags2hashX   s    c         C   s§  t  |  t ƒ s t d ƒ g  } xÆ t t |  ƒ ƒ D]² } | d rž |  | } | j d d ƒ } | j d d ƒ } d | } t d | | f ƒ | j | ƒ q2 |  | } t j d	 d
 | ƒ } t d | | f ƒ | j	 t
 | ƒ ƒ q2 Wt d t | ƒ ƒ | S|  j ƒ  } g  } xŽt | ƒ r¢| d d k r»d } d } xN | r| | d k rc| d 8} n | | d k r€| d 7} n  | d 7} q@W| d | !} | | j ƒ  } | j | ƒ q| d d k rót | ƒ \ } }	 | j | ƒ |	 } qd }
 t t d ƒ r t j | d d ƒ}
 n t j | d d ƒ}
 t |
 ƒ } | d k rn| j |
 d ƒ |
 d } qq| d k r| j |
 d ƒ Pq| d k rPqqW| S(   sõ   Takes a string from an IMAP conversation and returns a list containing
    its components.  One example string is:

    (\HasNoChildren) "." "INBOX.Sent"

    The result from parsing this will be:

    ['(\HasNoChildren)', '"."', '"INBOX.Sent"']s3   imapsplit() got a non-string input; working around.i   s   \s   \\R   s   \"s   "%s"s)   imapsplit() non-string [%d]: Appending %ss   \{\d+\}$t    s4   imapsplit() non-string [%d]: Feeding %s to recursions$   imapsplit() non-string: returning %si    R   i   R   t   splitt   maxsplitN(   t
   isinstanceR   R   t   rangeR   R   R   t   ret   subt   extendR   t   stript   lstript   __split_quotedt   Nonet   hasattrt   stringR    (   t
   imapstringR   t   iR
   t   workstrt   rparenct   rparenit	   parenlistt   quotedt   restt   splitst	   splitslen(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyR   `   sh    





		
s   \Seent   Ss	   \Answeredt   Rs   \Flaggedt   Fs   \Deletedt   Ts   \Draftt   Dc         C   sS   t  ƒ  } |  d d !j ƒ  } x0 t D]( \ } } | | k r# | j | ƒ q# q# W| S(   s8   Convert string '(\Draft \Deleted)' into a flags set(DR).i   iÿÿÿÿ(   t   setR    t   flagmapt   add(   t
   flagstringR   t   imapflaglistt   imapflagt   maildirflag(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   flagsimap2maildirÄ   s    	c         C   sF   t  |  d d !j ƒ  ƒ } t  g  t D] \ } } | ^ q# ƒ } | | S(   sn   Convert string '(\Draft \Deleted somekeyword otherkeyword)' into a
    keyword set (somekeyword otherkeyword).i   iÿÿÿÿ(   R<   R    R=   (   R?   t   imapflagsett   flagt   ct   serverflagset(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   flagsimap2keywordsÎ   s    %c         C   sT   g  } x0 t  D]( \ } } | |  k r | j | ƒ q q Wd d j t | ƒ ƒ d S(   s>   Convert set of flags ([DR]) into a string '(\Deleted \Draft)'.R   R   R   (   R=   R   R   t   sorted(   t   maildirflaglistR   RA   RB   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   flagsmaildir2imapÖ   s
    c         C   sÞ   d „  } t  |  ƒ s d Sd \ } } g  } t t t |  ƒ ƒ } xx t | ƒ D]j } t | ƒ } | d k r{ | | } } qM | | d k r” | } qM | j | | | ƒ ƒ | | } } qM W| j | | | ƒ ƒ d j | ƒ S(   sí   Collapse UID lists into shorter sequence sets

    [1,2,3,4,5,10,12,13] will return "1:5,10,12:13".  This function sorts
    the list, and only collapses if subsequent entries form a range.
    :returns: The collapsed UID list as string.c         S   s$   |  | k r t  |  ƒ Sd |  | f S(   Ns   %s:%s(   R   (   t   startt   end(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   getrangeæ   s    
R   i   t   ,N(   NN(   R   R*   RI   t   mapt   intt   iterR   R   (   t   uidlistRN   RL   RM   R   t   sorted_uidst   item(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   uid_sequenceß   s     	 	c         C   sð   t  |  ƒ d k r d S|  d } } |  d } x» t rë | j | ƒ } | d k rk t d | |  f ƒ ‚ n  t } | d } x1 | d k r® | | d k r® | d 8} | } q~ W| | d | d !7} | | d } | s1 | | j ƒ  f Sq1 Wd S(	   s{  Looks for the ending quote character in the string that starts
    with quote character, splitting out quoted component and the
    rest of the string (without possible space between these two
    parts.

    First character of the string is taken to be quote character.

    Examples:
     - "this is " a test" (\None) => ("this is " a test", (\None))
     - "\" => ("\", )
    i    R   i   iÿÿÿÿs$   can't find ending quote '%s' in '%s's   \N(   R   R   (   R   t   Truet   findR   t   FalseR(   (   R   t   qR3   R4   t   next_qt
   is_escapedR.   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyR)   ÿ   s"    
	

c         C   s(   |  t  k r d } n d } | j | ƒ S(   s:  Formats labels for embedding into a message,
    with format according to header name.

    Headers from SPACE_SEPARATED_LABEL_HEADERS keep space-separated list
    of labels, the rest uses comma (',') as the separator.

    Also see parse_labels_string() and modify it accordingly
    if logics here gets changed.R   RO   (   t   SPACE_SEPARATED_LABEL_HEADERSR   (   t   headert   labelst   sep(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   format_labels_string$  s    
	c         C   s_   |  t  k r d } n d } | j ƒ  j | ƒ } t g  | D] } | j ƒ  r: | j ƒ  ^ q: ƒ S(   s~  Parses a string into a set of labels, with a format according to
    the name of the header.

    See __format_labels_string() for explanation on header handling
    and keep these two functions synced with each other.

    TODO: add test to ensure that
    - format_labels_string * parse_labels_string is unity
    and
    - parse_labels_string * format_labels_string is unity
    R   RO   (   R]   R'   R    R<   (   R^   t
   labels_strR`   R_   t   l(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   parse_labels_string6  s
    	c         C   s%   | r t  |  | ƒ } n	 t ƒ  } | S(   s  Helper that builds label set from the corresponding header value.

    Arguments:
    - header_name: name of the header that keeps labels;
    - header_value: value of the said header, can be None

    Returns: set of labels parsed from the header (or empty set).
    (   Rd   R<   (   t   header_namet   header_valueR_   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   labels_from_headerM  s    
	c         C   sT   d „  } t  j | |  ƒ } y | j d ƒ j d ƒ SWn t t f k
 rO |  SXd S(   sø   Decodes a modified UTF-7 mailbox name.

    If the string cannot be decoded, it is returned unmodified.

    See RFC 3501, sec. 5.1.3.

    Arguments:
    - name: string, possibly encoded with modified UTF-7

    Returns: decoded UTF-8 string.
    c         S   s;   |  j  ƒ  } | d k r d Sd | d d !j d d ƒ d S(   Nt   +s   +-i   iÿÿÿÿRO   t   /t   -(   t   groupR   (   t   mR   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   demodifyk  s    s   utf-7s   utf-8N(   t   MUTF7_SHIFT_RER%   t   decodet   encodet   UnicodeDecodeErrort   UnicodeEncodeError(   t   nameRm   t   ret(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   decode_mailbox_name_  s    	c         C   s   |  j  d ƒ j d ƒ S(   s+   Convert IMAP4_utf_7 encoded string to utf-8s   imap4-utf-7s   utf-8(   Ro   Rp   (   t
   foldername(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt	   IMAP_utf8}  s    c         C   s   |  j  d ƒ j d ƒ S(   s+   Convert utf-8 encoded string to IMAP4_utf_7s   utf-8s   imap4-utf-7(   Ro   Rp   (   Rv   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt	   utf8_IMAP  s    c         C   s1   |  j  d ƒ }  t j |  ƒ j d ƒ j d d ƒ S(   Ns   utf-16bes   
=Ri   RO   (   Rp   t   binasciit
   b2a_base64t   rstripR   (   R   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   modified_base64‡  s    c         C   s1   |  r- | j  d t d j |  ƒ ƒ ƒ |  2n  d  S(   Ns   &%s-R   (   R   R|   R   (   t   _int   r(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   doB64‹  s     c         C   sà   g  } g  } x¥ |  D] } t  | ƒ } d | k o< d k n s] d | k oX d k n rz t | | ƒ | j | ƒ q | d k r£ t | | ƒ | j d ƒ q | j | ƒ q Wt | | ƒ t d j | ƒ ƒ t |  ƒ f S(   Ni    i%   i'   i~   t   &s   &-R   (   t   ordR   R   R   R   R   (   R   R~   R}   RF   t   ordC(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   encoder  s    8c         C   s,   t  j |  j d d ƒ d ƒ } t | d ƒ S(   NRO   Ri   s   ===s   utf-16be(   Ry   t
   a2b_base64R   t   unicode(   R   t   b(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   modified_unbase64¡  s    c         C   s  g  } g  } x± |  D]© } | d k r< | r< | j  d ƒ q | d k r™ | r™ t | ƒ d k rp | j  d ƒ n  | j  t d j | d ƒ ƒ ƒ g  } q | r¯ | j  | ƒ q | j  | ƒ q W| ré | j  t d j | d ƒ ƒ ƒ n  d j | ƒ } | t |  ƒ f S(   NR€   Rj   i   R   (   R   R   R‡   R   (   R   R~   Ro   RF   t   bin_str(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   decoder¥  s"     	#t   StreamReaderc           B   s   e  Z d  d „ Z RS(   t   strictc         C   s
   t  | ƒ S(   N(   R‰   (   t   selfR   t   errors(    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyRo   ¼  s    (   t   __name__t
   __module__Ro   (    (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyRŠ   »  s   t   StreamWriterc           B   s   e  Z d  d „ Z RS(   R‹   c         C   s
   t  | ƒ S(   N(   Rƒ   (   RŒ   R   R   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyRo   À  s    (   RŽ   R   Ro   (    (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyR   ¿  s   c         C   s    |  d k r t  t t t f Sd  S(   Ns   imap4-utf-7(   Rƒ   R‰   RŠ   R   (   Rs   (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   imap4_utf_7Ã  s    (   s   X-LabelR   (   s   \SeenR7   (   s	   \AnsweredR8   (   s   \FlaggedR9   (   s   \DeletedR:   (   s   \DraftR;   (%   R$   R,   Ry   t   codecst   offlineimap.uiR    R]   t   compileRn   R   R   R   R   R   R   R   R=   RC   RH   RK   RV   R)   Ra   Rd   Rg   Ru   Rw   Rx   R|   R   Rƒ   R‡   R‰   RŠ   R   R‘   t   register(    (    (    s.   /usr/share/offlineimap/offlineimap/imaputil.pyt   <module>   sL   			
				^		
				 	%												