
    e/4                        d dl Z d dlZd dlZd dlm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g 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dee e!f   fdZ"d Z#de deee!f   fd Z$ G d! d"ejJ                        Z% G d# d$ejL                        Z&d% Z' ejP                  e'       d& Z)y)'    N)Tuple)getglobalui)zX-LabelKeywordsz
&[^-]*-|\+c                      g }| D ]  }|j                  t        |              t               j                  ddj	                  |             y )Nimap )appendstrr   debugjoin)argsmsgargs      //usr/share/offlineimap3/offlineimap/imaputil.py__debugr   !   s@    
C 

3s8M.    c                     | rK| j                  d      r:| j                  d      r)| dd } | j                  dd      } | j                  dd      } | S )zTakes 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."   \"\\\)
startswithendswithreplacess    r   dequoter   (   sL     	Q\\#1::c?aGIIeS!IIfd#Hr   c                 T    | j                  dd      } | j                  dd      } d| z  S )zTakes an unquoted string and quotes it.

    It only adds double quotes. This function does NOT consider
    parenthised lists to be quoted.r   r   r   r   z"%s")r   r   s    r   quoter!   5   s.     	
		#uA			$AA:r   c                 Z    | d   dk7  s| d   dk7  rt        d| z        t        | dd       S )zConverts 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']
    r   (r   )z Passed s '%s' is not a flag listr   )
ValueError	imapsplitr   s    r   	flagsplitr'   @   s;     	ts{aesl;a?@@QqWr   c                     i }d}|t        |       k  r"| |dz      || |   <   |dz  }|t        |       k  r"t        d|       |S )z/convert l_list [1,2,3,4,5,6] to {1:2, 3:4, 5:6}r   r      z__options2hash returning:)lenr   )l_listretvalcounters      r   __options2hashr.   M   sZ     FG
CK
"(1"5vg1 CK
 '0Mr   c                 *    t        t        |             S )zConverts 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'   )flagss    r   
flags2hashr1   \   s     )E*++r   c                 n   t        | t              s| j                  d      } | j                         }g }t	        |      r|d   dk(  rSd}d}|r#||   dk(  r|dz  }n||   dk(  r|dz  }|dz  }|r#|d| }||d j                         }|j                  |       n|d   dk(  r"t        |      \  }}|j                  |       |}net        j                  |d      }t	        |      }	|	d	k(  r|j                  |d          |d   }|	dk(  r|j                  |d          	 |S |	dk(  r	 |S t	        |      r|S )
zTakes 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"']utf-8r   r#   r   r$   Nr   )maxsplitr)   )	
isinstancer
   decodestripr*   lstripr	   __split_quotedsplit)

imapstringworkstrr,   rparencrpareni	parenlistquotedrestsplits	splitslens
             r   r&   r&   e   sg    j#&&&w/
 GF
g,1:GG7#s*qLGW%,qLG1   '*Igh'..0GMM)$QZ3+G4NVTMM&!GYYwY3FFIA~fQi( )afQi( M aMI g,H Mr   ))z\SeenS)z	\AnsweredR)z\FlaggedF)z\DeletedT)z\DraftDc                     t               }| dd j                         }t        D ]  \  }}||v s|j                  |        |S )z8Convert string '(\Draft \Deleted)' into a flags set(DR).r   r   )setr:   flagmapadd)
flagstringr,   imapflaglistimapflagmaildirflags        r   flagsimap2maildirrQ      sO     UFa#))+L!( $+|#JJ{#$ Mr   c                     t        | dd j                               }t        t        D cg c]  \  }}|	 c}}      }||z
  S c c}}w )znConvert string '(\Draft \Deleted somekeyword otherkeyword)' into a
    keyword set (somekeyword otherkeyword).r   r   )rJ   r:   rK   )rM   imapflagsetflagcserverflagsets        r   flagsimap2keywordsrW      sG     j2&,,./Kw7)478M&& 8s   A
c                     g }t         D ]  \  }}|| v s|j                  |        ddj                  t        |            z   dz   S )z>Convert set of flags ([DR]) into a string '(\Deleted \Draft)'.r#   r   r$   )rK   r	   r   sorted)maildirflaglistr,   rO   rP   s       r   flagsmaildir2imapr[      sP     F!( $+/)MM(#$ &.))C//r   c                 D   d }t        |       syd\  }}g }t        t        t        |             }t	        |      D ];  }t        |      }|||}}||dz   k(  r|} |j                   |||             ||}}= |j                   |||             dj                  |      S )zCollapse 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                 0    | |k(  rt        |       S | d|S )N:)r
   )startends     r   getrangezuid_sequence.<locals>.getrange   s    C<u:%%r    )NNr   ,)r*   rY   mapintiterr	   r   )uidlistra   r_   r`   r,   sorted_uidsitems          r   uid_sequencerj      s    &
 w<JE3FS'*+K[! $4y=t3ES1W_CMM(5#./t3E$ MM(5#&'88Fr   c                 .   t        |       dk(  ry| d   x}}| dd }	 |j                  |      }|dk(  rt        d|d| d      d	}|dz
  }|dk\  r||   d
k(  r|dz  }| }|dk\  r	||   d
k(  r||d|dz    z  }||dz   d }|s||j                         fS z)a{  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))
     - "\" => ("\", )
    r   )rb   rb   r   Nr   zcan't find ending quote 'z' in ''Fr   )r*   findr%   r8   )r   qr@   rA   next_q
is_escapedis          r   r9   r9      s     1v{1AQR5D
1R<q!LMM
 
QJ1faDFA'J 1faD 	$q!$$FQJK 4;;=((! r   c                 >    | t         v rd}nd}|j                  |      S )a:  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   rc   )SPACE_SEPARATED_LABEL_HEADERSr   )headerlabelsseps      r   format_labels_stringrw     s&     ..88Fr   c                     | t         v rd}nd}|j                         j                  |      }t        |D cg c]#  }|j                         s|j                         % c}      S c c}w )a~  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   rc   )rs   r7   r:   rJ   )rt   
labels_strrv   ru   ls        r   parse_labels_stringr{     sW     ..%%c*F67aQWWY	7887s   A%A%c                 :    |rt        | |      }|S t               }|S )a  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).
    )r{   rJ   )header_nameheader_valueru   s      r   labels_from_headerr   0  s(     $[,? M Mr   c                     d }t         j                  ||       }	 |j                  d      j                  d      S # t        t
        f$ r | cY S w xY w)zDecodes 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                 d    | j                         }|dk(  ryd|dd j                  dd      z   dz   S )N+z+-r   r   rc   /-)groupr   )mr   s     r   demodifyz%decode_mailbox_name.<locals>.demodifyO  s8    GGI8QqW__S#..44r   zutf-7r3   )MUTF7_SHIFT_REsubr6   encodeUnicodeDecodeErrorUnicodeEncodeError)namer   rets      r   decode_mailbox_namer   B  sT    5 

Xt
,Czz'"))'22 23 s   ; AAc                     t        j                  | j                         d      j                  d      j                         S )z+Convert IMAP4_utf_7 encoded string to utf-8imap4-utf-7r3   codecsr6   r   
foldernames    r   	IMAP_utf8r   b  s3    == fWoffhr   c                     t        j                  | j                         d      j                  d      j                         S )z+Convert utf-8 encoded string to IMAP4_utf_7r3   r   r   r   s    r   	utf8_IMAPr   j  s4    == f]FFH%r   c                     | j                  d      } t        j                  |       j                  d      j	                  dd      S )Nutf-16bes   
=   /   ,)r   binascii
b2a_base64rstripr   r   s    r   modified_base64r   s  s9    	Aq!((088tDDr   c                 l    | r2|j                  dt        dj                  |             z         | d d = y y )Ns   &%s-rb   )r	   r   r   )_inrs     r   doB64r   x  s/    
	?2773<889F r   textreturnc                    g }g }| D ]]  }dt        |      cxk  rdk  r6n n3t        ||       |j                  |dk(  rdn|j                                M|j                  |       _ t        ||       dj	                  |      t        |       fS )N    ~   &s   &-r   )ordr   r	   r   r   r*   )r   r   r   rU   s       r   utf7m_encoder   ~  s|    
A
C 3q6!T!#qMHHa3hUAHHJ7JJqM 
#qM88A;D	!!r   c                 j    t        j                  | j                  dd      dz         }t        |d      S )Nrc   r   z===r   )r   
a2b_base64r   r
   )r   bs     r   modified_unbase64r     s/    AIIc3/%78Aq*r   binaryc           
         g }g }| D ]  }|t        d      k(  r|s|j                  d       %|t        d      k(  rQ|rOt        |      dk(  r|j                  d       n,|j                  t        dj	                  |dd                     g }|r|j                  t        |             |j                  t        |              |r,|j                  t        dj	                  |dd                     dj	                  |      t        |       fS )Nr   r   r   rb   )r   r	   r*   r   r   chr)r   r   r6   rU   s       r   utf7m_decoder     s    
AF C=MM##c(]v6{a*2776!":+>?@FMM#a&!HHSV 	"2776!":#678771:s6{""r   c                       e Zd ZddZy)StreamReaderc                     t        |      S N)r   selfr   errorss      r   r6   zStreamReader.decode      Ar   Nstrict__name__
__module____qualname__r6    r   r   r   r         r   r   c                       e Zd ZddZy)StreamWriterc                     t        |      S r   )r   r   s      r   r6   zStreamWriter.decode  r   r   Nr   r   r   r   r   r   r     r   r   r   c                 V    t        j                  t        t        t        t
        d      S )Nr   r   )r   	CodecInfor   r   r   r   r   s    r   utf7m_search_functionr     s$     r   c                 H    g dt        fd| D              rd| z   dz   } | S )z
    This function returns the folder_name ready to send to the
    IMAP server. It tests if the folder_name has special characters
    Then, quote it.
    Args:
        folder_name: Folder's name

    Returns: The folder_name quoted if needed

    )r   r   r#   r$   {}c              3   &   K   | ]  }|v  
 y wr   r   ).0rU   atom_specialss     r   	<genexpr>z)foldername_to_imapname.<locals>.<genexpr>  s     
5AA
5s   r   )any)folder_namer   s    @r   foldername_to_imapnamer     s-     3M

5
55K'#-r   )*rer   r   typingr   offlineimap.uir   rs   compiler   r   r   r!   r'   r.   r1   r&   rK   rQ   rW   r[   rj   r9   rw   r{   r   r   r   r   r   r   r
   bytesre   r   r   r   r   r   r   registerr   r   r   r   <module>r      s  $ 
    &
 !8  M*/

,3l'0D")J$9.$@%E
"s "uUCZ0 " 
# #5c? #.6&& 
6&& 
 % &r   