ó
Gh\c           @   s9  d  d l  Z  d  d l Z d  d l Z d  d l Z d  d l Z d  d l m Z d  d l m Z y d  d l	 m
 Z
 Wn! e k
 r“ d  d l
 m
 Z
 n Xy e Wn! e k
 r¿ d  d l m Z n Xd  d l m Z m Z d d l m Z e j d	 ƒ Z e j d
 ƒ Z i  a e ƒ  a d d „ Z d e f d „  ƒ  YZ d S(   iÿÿÿÿN(   t   exc_info(   t   Lock(   t   md5(   t   Set(   t   OfflineImapErrort	   emailutili   (   t
   BaseFolders   ,U=(\d+)s   (\d+)c         C   sx   t  j ƒ  z\ |  d  k r. t t j ƒ  ƒ }  n  |  t k rM t |  c d 7<n
 d t |  <|  t |  f SWd  t  j ƒ  Xd  S(   Ni   i    (   t   timelockt   acquiret   Nonet   intt   timet   timehasht   release(   t   date(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   _gettimeseq/   s    

t   MaildirFolderc           B   sË   e  Z d  „  Z d „  Z d „  Z d „  Z d „  Z d d d „ Z d „  Z	 d „  Z
 d d d „ Z d	 „  Z d
 „  Z e ƒ  d d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z e d „ Z RS(   c         C   s>  | |  _  t t |  ƒ j | | ƒ | |  _ |  j j d |  j d t ƒ |  _	 |  j	 r\ d n d |  _
 t j d |  j
 ƒ |  _ t j d |  j
 d ƒ |  _ t |  j ƒ  ƒ j ƒ  |  _ t j j |  j ƒ  |  j ƒ  ƒ |  _ |  j j d d	 t ƒ } |  j j |  j d	 | ƒ |  _ d
 |  _ t j j  |  j k r:d |  _ n  d  S(   Ns   Account s   maildir-windows-compatiblet   !t   :s	   %s2,(\w*)s   ([^s   ,]*)t   generalt   utime_from_headert   -t   _(   t   sept   superR   t   __init__t   roott   configt   getdefaultbooleant   accountnamet   Falset   wincompatiblet   infosept   ret   compilet   re_flagmatcht   re_prefixmatchR   t   getvisiblenamet	   hexdigestt
   _foldermd5t   ost   patht   joint   getroott   getnamet	   _fullnamet   repoconfnamet   _utime_from_headert	   sep_subst(   t   selfR   t   nameR   t
   repositoryt   utime_from_header_global(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyR   ?   s"    			$			c         C   s   |  j  S(   sB   Return the absolute file path to the Maildir folder (sans cur|new)(   R-   (   R1   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   getfullname[   s    c         C   s   d S(   sŒ   Retrieve the current connections UIDVALIDITY value

        Maildirs have no notion of uidvalidity, so we just return a magic
        token.i*   (    (   R1   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   get_uidvalidity`   s    c         C   sR   t  j | ƒ } | s t S| j ƒ  } t | ƒ } | t j | ƒ k  rJ t St Sd S(   s—   Check to see if the given message is newer than date (a
        time_struct) according to the maildir name which should begin
        with a timestamp.N(   t   re_timestampmatcht   searcht   Truet   groupR
   R   t   mktimeR   (   R1   t   messagenameR   t   timestampmatcht   timestampstrt   timestamplong(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   _iswithintimeg   s    c         C   sä   d d d t ƒ  f \ } } } } |  j j | ƒ } | rK | j d ƒ } n  d |  j } | | k } | rš t j | ƒ }	 |	 rš t |	 j d ƒ ƒ } qš n  |  j	 j | ƒ }
 |
 rÔ t d „  |
 j d ƒ Dƒ ƒ } n  | | | | f S(   s®  Returns a messages file name components

        Receives the file name (without path) of a msg.  Usual format is
        '<%d_%d.%d.%s>,U=<%d>,FMD5=<%s>:2,<FLAGS>' (pointy brackets
        denoting the various components).

        If FMD5 does not correspond with the current folder MD5, we will
        return None for the UID & FMD5 (as it is not valid in this
        folder).  If UID or FMD5 can not be detected, we return `None`
        for the respective element.  If flags are empty or cannot be
        detected, we return an empty flags list.

        :returns: (prefix, UID, FMD5, flags). UID is a numeric "long"
            type. flags is a set() of Maildir flags.
        i   s   ,FMD5=%sc         s   s   |  ] } | Vq d  S(   N(    (   t   .0t   c(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pys	   <genexpr>œ   s    N(
   R	   t   setR$   t   matchR:   R'   t   re_uidmatchR8   R
   R#   (   R1   t   filenamet   prefixt   uidt   fmd5t   flagst   prefixmatcht	   folderstrt   foldermatcht   uidmatcht	   flagmatch(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   _parse_filenamev   s    !
"c            sž  |  j  ƒ  } i  } g  } d } xU d d g D]G ‰  t j j |  j ƒ  ˆ  ƒ } | j ‡  f d †  t j | ƒ Dƒ ƒ q+ Wi  } xž| D]–\ ‰  }	 |	 j d ƒ r¤ qƒ n  t j j ˆ  |	 ƒ }
 | rò t j j t j j |  j ƒ  |
 ƒ ƒ | k rò qƒ n  |  j	 |	 ƒ \ } } } } | d
 k r,| } | d 8} nC t j |	 ƒ } d
 } | sZ| } | d 8} n t | j d ƒ ƒ } | d
 k r™| d k r™| | k  r™qƒ n  | d
 k rê|  j |	 | ƒ rê|  j | ƒ | | <| | | d <|
 | | d	 <qƒ |  j | ƒ | | <| | | d <|
 | | d	 <qƒ W| d
 k ršg  | D] } | d k r0| ^ q0} | ršt | ƒ } x4 | j ƒ  D]# } | | k rm| | | | <qmqmWqšn  | S(   s-  Cache the message list from a Maildir.

        If min_date is set, this finds the min UID of all messages newer than
        min_date and uses it as the real cutoff for considering messages.
        This handles the edge cases where the date is much earlier than messages
        with similar UID's (e.g. the UID was reassigned much later).

        Maildir flags are:
            D (draft) F (flagged) R (replied) S (seen) T (trashed),
        plus lower-case letters for custom flags.
        :returns: dict that can be used as self.messagelist.
        iÿÿÿÿt   newt   curc         3   s   |  ] } ˆ  | f Vq d  S(   N(    (   RA   RF   (   t   dirannex(    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pys	   <genexpr>´   s   t   .i   i    RJ   RF   N(   t
   getmaxsizeR(   R)   R*   R5   t   extendt   listdirt
   startswitht   getsizeRP   R	   RE   R8   R
   R:   R@   t   msglist_item_initializert   mint   keys(   R1   t   min_datet   min_uidt   maxsizet   retvalt   filest   nouidcountert   fulldirnamet   date_excludeesRF   t   filepathRG   RH   RI   RJ   RN   t   positive_uids(    (   RS   s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   _scanfolderŸ   sV    $$	%c         C   sl   t  |  j ƒ  ƒ t  | j ƒ  ƒ k r( t Sx= |  j ƒ  j ƒ  D]) \ } } | d | j | ƒ k r; t Sq; Wt S(   sd   Returns True if the Maildir has changed

        Assumes cachemessagelist() has already been called RJ   (   t   sortedt   getmessageuidlistR9   t   getmessagelistt   itemst   getmessageflagsR   (   R1   t   statusfolderRH   t   message(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   quickchangedï   s    c         C   s   i t  ƒ  d 6d d 6S(   NRJ   s   /no-dir/no-such-file/RF   (   RC   (   R1   RH   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyRZ   ÿ   s    c         C   sc   |  j  ƒ  r_ |  j j |  j |  ƒ |  j d | d | ƒ |  _ |  j j |  j |  |  j ƒ  ƒ n  d  S(   NR]   R^   (   t   ismessagelistemptyt   uit   loadmessagelistR3   Rg   t   messagelistt   messagelistloadedt   getmessagecount(   R1   R]   R^   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   cachemessagelist  s
    c         C   sa   |  j  | d } t j j |  j ƒ  | ƒ } t | d ƒ } | j ƒ  } | j ƒ  | j d d ƒ S(   s"   Return the content of the message.RF   t   rts   
s   
(	   Rs   R(   R)   R*   R5   t   opent   readt   closet   replace(   R1   RH   RF   Re   t   fileR`   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt
   getmessage  s    
c         C   s<   |  j  | d } t j j |  j ƒ  | ƒ } t j j | ƒ S(   NRF   (   Rs   R(   R)   R*   R5   t   getmtime(   R1   RH   RF   Re   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   getmessagetime  s    c         C   sn   t  | ƒ \ } } d | | t j ƒ  t j ƒ  | |  j |  j d j t | ƒ ƒ f } | j	 t j
 j |  j ƒ S(   sÌ   Creates a new unique Maildir filename

        :param uid: The UID`None`, or a set of maildir flags
        :param flags: A set of maildir flags
        :returns: String containing unique message filenames   %d_%d.%d.%s,U=%d,FMD5=%s%s2,%st    (   R   R(   t   getpidt   sockett   gethostnameR'   R    R*   Rh   R{   R)   R   R0   (   R1   RH   RJ   R   t   timevalt   timeseqt	   uniq_name(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   new_message_filename  s
    (c         C   sT  t  j j d | ƒ } d } xã | r | d } y@ t  j t  j j |  j ƒ  | ƒ t  j t  j Bt  j Bd ƒ } PWq t k
 rü } t	 | d ƒ s• ‚  n  | j
 | j k rö | rÀ t j d ƒ q n  t j j } t j t t d | | ƒ t ƒ  d ƒ qý ‚  q Xq Wt  j | d	 ƒ } | j | ƒ | j ƒ  |  j ƒ  rFt  j | ƒ n  | j ƒ  | S(
   s  Saves given content to the named temporary file in the
        'tmp' subdirectory of $CWD.

        Arguments:
        - filename: name of the temporary file;
        - content: data to be saved.

        Returns: relative path to the temporary file
        that was created.t   tmpi   i   i¶  t   EEXISTgq=
×£pÍ?s"   Unique filename %s already exists.i   t   wt(   R(   R)   R*   Rx   R5   t   O_EXCLt   O_CREATt   O_WRONLYt   OSErrort   hasattrt   errnoR‰   R   t   sleepR   t   ERRORt   MESSAGEt   sixt   reraiseR    t   fdopent   writet   flusht   dofsynct   fsyncRz   (   R1   RF   t   contentt   tmpnamet   triest   fdt   et   severity(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   save_to_tmp_file+  s:    	
	


c         C   s“  |  j  j d | | |  ƒ | d k  r) | S| |  j k rL |  j | | ƒ | St j j |  j ƒ  d ƒ } d } |  j	 t
 k	 r-y7 t j | d ƒ } | d k r² t j | d ƒ } n  Wq-t k
 r)} d d l m } d d l m }	 | ƒ  j | t ƒ j d ƒ }
 |	 ƒ  } | j d	 | |
 | f ƒ q-Xn  |  j | | d
 | ƒ} |  j | | ƒ } |  j t k r0yP t j | d ƒ } | d k	 rµt j t j j |  j ƒ  | ƒ | | f ƒ n  Wq0t k
 r,} d d l m } d d l m }	 | ƒ  j | t ƒ j d ƒ }
 |	 ƒ  } | j d | |
 | f ƒ q0Xn  |  j | ƒ |  j | <| |  j | d <| |  j | d <|  j | | ƒ |  j  j d d | ƒ | S(   së   Writes a new message, with the specified uid.

        See folder/Base for detail. Note that savemessage() does not
        check against dryrun settings, so you need to ensure that
        savemessage is never called in a dryrun mode.t   maildiri    Rˆ   t   Dates   Delivery-dateiÿÿÿÿ(   t   Parser(   t   getglobaluisI   UID %d has invalid date %s: %s
Not using message timestamp as file prefixR   sB   UID %d has invalid date %s: %s
Not changing file modification timeRJ   RF   s   savemessage: returning uid %dN(   Rq   t   savemessageRs   t   savemessageflagsR(   R)   R*   R5   R	   t   _filename_use_mail_timestampR   R   t   get_message_datet	   Exceptiont   email.ParserR¤   t   offlineimap.uiR¥   t   parsestrR9   t   gett   warnR‡   R¡   R/   t   utimeRZ   t   debug(   R1   RH   R›   RJ   t   rtimet   tmpdirt   message_timestampRŸ   R¤   R¥   t   datestrRq   R<   Rœ   R   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyR¦   \  sT    					c         C   s   |  j  | d S(   NRJ   (   Rs   (   R1   RH   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyRl   ¤  s    c   
      C   s¦  | |  j  k s t ‚ |  j  | d } t j j | ƒ \ } } d | k rP d n d } | |  j  | d k rÎ |  j j | ƒ } | rŸ | t | j ƒ  ƒ  } n  d |  j	 d j
 t | ƒ ƒ f } | | 7} n  t j j
 | | ƒ } | | k r¢y> t j t j j
 |  j ƒ  | ƒ t j j
 |  j ƒ  | ƒ ƒ WnM t k
 r|}	 t j t t d | | |	 d	 f t j j ƒ t ƒ  d
 ƒ n X| |  j  | d <| |  j  | d <n  d S(   s6  Sets the specified message's flags to the given set.

        This function moves the message to the cur or new subdir,
        depending on the 'S'een flag.

        Note that this function does not check against dryrun settings,
        so you need to ensure that it is never called in a
        dryrun mode.RF   t   SRR   RQ   RJ   s   %s2,%sR€   s"   Can't rename file '%s' to '%s': %si   i   N(   Rs   t   AssertionErrorR(   R)   t   splitR#   R8   t   lenR:   R    R*   Rh   t   renameR5   RŽ   R”   R•   R   R’   t   FOLDERR    (
   R1   RH   RJ   t   oldfilenamet
   dir_prefixRF   t	   infomatcht   infostrt   newfilenameRŸ   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyR§   ¨  s0    
" 	c         C   s  | |  j  k r+ t d | t j j ƒ ‚ n  | | k r; d S|  j  | d } t j j | ƒ \ } } |  j | ƒ } t j j | |  j	 | | ƒ ƒ } t j
 t j j |  j ƒ  | ƒ t j j |  j ƒ  | ƒ ƒ |  j  | |  j  | <| |  j  | d <|  j  | =d S(   sP  Change the message from existing uid to new_uid

        This will not update the statusfolder UID, you need to do that yourself.
        :param new_uid: (optional) If given, the old UID will be changed
                        to a new UID. The Maildir backend can implement this as
                        an efficient rename.
        s$   Cannot change unknown Maildir UID %sNRF   (   Rs   R   R’   R“   R(   R)   R¸   Rl   R*   R‡   Rº   R5   (   R1   RH   t   new_uidR¼   R½   RF   RJ   RÀ   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   change_message_uidÓ  s    	
 c         C   s°   |  j  | d } t j j |  j ƒ  | ƒ } y t j | ƒ Wnb t k
 r¡ |  j ƒ  } | | k r¢ | | d } t j j |  j ƒ  | ƒ } t j | ƒ q¢ n X|  j  | =d S(   sÙ   Unlinks a message file from the Maildir.

        :param uid: UID of a mail message
        :type uid: String
        :return: Nothing, or an Exception if UID but no corresponding file
                 found.
        RF   N(   Rs   R(   R)   R*   R5   t   unlinkRŽ   Rg   (   R1   RH   RF   Re   t
   newmsglist(    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   deletemessageï  s    c   
   	   C   sœ  t  |  j ƒ j ƒ  } |  j ƒ  } xt| j ƒ  D]f\ } } t j j |  j ƒ  | d ƒ } t	 j
 d | ƒ } | d k r‘ |  j j d d | ƒ q. | j d ƒ | k rY|  j j d | |  j f ƒ | s”| j d | j d ƒ d |  j ƒ } y t j | | ƒ WqVt k
 rR}	 t j t t d | | |	 d f t j j ƒ t ƒ  d	 ƒ qVXq”q. | j d ƒ |  j k r. |  j j d
 | | |  j f ƒ q. q. Wd S(   s–   Migrate FMD5 hashes from versions prior to 6.3.5

        :param dryrun: Run in dry run mode
        :type fix: Boolean
        :return: None
        RF   s   FMD5=([a-fA-F0-9]+)R¢   s'   File `%s' doesn't have an FMD5 assignedi   s    Migrating file `%s' to FMD5 `%s's   FMD5=s"   Can't rename file '%s' to '%s': %si   s<   Inconsistent FMD5 for file `%s': Neither `%s' nor `%s' foundN(   R   R2   R&   Rg   Rk   R(   R)   R*   R5   R!   R8   R	   Rq   R±   R:   t   infoR'   R{   Rº   RŽ   R”   R•   R   R’   R»   R    R¯   (
   R1   t   dryrunt   oldfmd5t   msglistt   mkeyt   mvalueRF   RD   RÀ   RŸ   (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   migratefmd5  s6     	N(   t   __name__t
   __module__R   R5   R6   R@   RP   R	   Rg   Ro   RZ   Rv   R}   R   RC   R‡   R¡   R¦   Rl   R§   RÂ   RÅ   R   RÌ   (    (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyR   >   s&   					)P					1	H		+		(   R‚   R   R!   R(   R”   t   sysR    t	   threadingR   t   hashlibR   t   ImportErrorRC   t	   NameErrort   setsR   t   offlineimapR   R   t   BaseR   R"   RE   R7   R   R   R	   R   R   (    (    (    s4   /usr/share/offlineimap/offlineimap/folder/Maildir.pyt   <module>   s,   	