
    eo                         d dl mZmZ d dlmZmZ d dlZd dlZd dlm	Z	 d dl
Z
d dlmZmZmZ d dlmZ d dlmZ d dlmZ d d	lmZ d
Zi Z e       Z	 d dlZd Z G d dej8                        Z G d de      Zd Zy#  	 d dlZn#  Y nxY wY 8xY w)    )PopenPIPE)EventLockN)exc_info)mbnamesCustomConfigOfflineImapError)globals)
Repository)getglobalui)InstanceLimitedThreadLIMITED_FOLDER_c                 f    | j                  d      D cg c]  }|j                          c}S c c}w )NAccount)getsectionlistlstrip)customconfignames     //usr/share/offlineimap3/offlineimap/accounts.pygetaccountlistr   -   s'    &2&A&A)&LMdDKKMMMMs   .c                   ~    e Zd ZdZ e       Z e       Zd Zd Zd Z	d Z
d Zd Zd Zed	        Zd
 Zd Zd Zd Zy)r   zRepresents an account (ie. 2 repositories) to sync.

    Most of the time you will actually want to use the derived
    :class:`accounts.SyncableAccount` which contains all functions used
    for syncing an account.c                    || _         || _        |j                         | _        |j	                         | _        | j                  dd      | _        t               | _	        | j                  dd      | _        | j                   j                  dd      | _        d| _        | j                  dk  r%| j                  j                  d|z         d| _        | j                  dk(  rd	| _        d	| _        d	| _        d	| _        y	)
a  
        :param config: Representing the offlineimap configuration file.
        :type config: :class:`offlineimap.CustomConfig.CustomConfigParser`

        :param name: A (str) string denoting the name of the Account
                     as configured.
        utf8foldernamesFautorefreshg        generalzdry-runr   z/autorefresh for %s is negative, fixing it to 0.N)configr   getmetadatadirmetadatadirgetlocaleval	localevalgetconfbooleanutf_8_supportr   uigetconffloatrefreshperiod
getbooleandryrunquicknumwarnremoterepos
localreposstatusrepos)selfr   r   s      r   __init__zAccount.__init__>   s     	!002,,.!001BEJ-!..}cBkk,,Y	B!GGLLJ !$D$!%D    c                     | j                   S N)r!   r.   s    r   r    zAccount.getlocaleval\   s    ~~r0   c                     | j                   S r2   )r   r3   s    r   	getconfigzAccount.getconfig`   s    {{r0   c                     | j                   S r2   r   r3   s    r   getnamezAccount.getnamec       yyr0   c                     | j                   S r2   r7   r3   s    r   __str__zAccount.__str__f   r9   r0   c                 p    t         j                  j                  | j                  d| j                  z         S )NzAccount-)ospathjoinr   r   r3   s    r   getaccountmetazAccount.getaccountmetai   s&    ww||D,,j499.DEEr0   c                 (    d| j                         z   S )NAccount )r8   r3   s    r   
getsectionzAccount.getsectionm   s    DLLN**r0   c                     |dk(  r't        |      D ]  }|j                  d|z   dd        y|dk(  r| j                  j                          y|dk(  r| j                  j                          yy)aY  Set skip sleep/abort event for all accounts.

        If we want to skip a current (or the next) sleep, or if we want
        to abort an autorefresh loop, the main thread can use
        set_abort_event() to send the corresponding signal. Signum = 1
        implies that we want all accounts to abort or skip the current
        or next sleep phase. Signum = 2 will end the autorefresh loop,
        ie all accounts will return after they finished a sync. signum=3
        means, abort NOW, e.g. on SIGINT or SIGTERM.

        This is a class method, it will send the signal to all accounts.
           rB   	skipsleep1      N)r   setabort_soon_signalabort_NOW_signal)clsr   signumacctsections       r   set_abort_eventzAccount.set_abort_eventp   sm     Q;-f5 G

:3[#FGq[!!%%'q[  $$& r0   c                    | j                  dd      }|r+| j                  j                  | j                         dd       |xs> t        j
                  j                         xs t        j                  j                         S )av  Checks if an abort signal had been sent.

        If the 'skipsleep' config option for this account had been set,
        with `set_abort_event(config, 1)` it will get cleared in this
        function. Ie, we will only skip one sleep and not all.

        :returns: True, if the main thread had called
            :meth:`set_abort_event` earlier, otherwise 'False'.
        rF   r   0)r"   r   rJ   rC   r   rK   is_setrL   )r.   rF   s     r   get_abort_eventzAccount.get_abort_event   si     ''Q7	KKOODOO-{C@ 1G55<<> 1''..0	1r0   c                    | j                   syg }t        | d      r|j                  | j                         t        | d      r|j                  | j                         |D ]  }|j                           t        | j                   dz        }| j                  j                  ||       }|D ]  }|j                           |rEt        j                  j                         st        j                  j                         ryd| _        yy)zSleep if the account is set to autorefresh.

        :returns: 0:timeout expired, 1: canceled the timer,
                  2:request to abort the program,
                  100: if configured to not sleep at all.
        d   r,   r+   <   rH   r   rE   )r&   hasattrappendr,   r+   startkeepaliveintr$   sleepstopkeepaliver   rK   rS   rL   r)   )r.   kaobjsitemr&   sleepresults        r   _sleeperzAccount._sleeper   s     !!4&MM$//*4'MM$**+ 	"D!	" D..34ggmmM48  	!D 	! ((//1,,335DMr0   c                     t        | d      }t        | d      }| j                  j                  |d       | j                  j                  |d       y)z1Output diagnostics for all involved repositories.remotelocalRemoteLocalN)r   r$   serverdiagnostics)r.   remote_repo
local_repos      r   rg   zAccount.serverdiagnostics   sD     !x0g.
!!+x8!!*g6r0   c                 <   t        | d      }	 | j                  r#| j                  j                  d|d| d       y|j	                  |       | j                  j                  d|z         y# t
        $ r%}| j                  j                  |       Y d }~yd }~ww xY w)Nrc   zwould try to remove 'z' on remote of 'z	' accountzFolder '%s' deleted.r   rE   )r   r(   r$   infodeletefolder	Exceptionerror)r.   
foldernamerh   es       r   rl   zAccount.deletefolder   s     x0
	{{*4d< =
  ((43j@A 	GGMM!	s   .A- /A- -	B6BBN)__name__
__module____qualname____doc__r   rK   rL   r/   r    r5   r8   r;   r@   rC   classmethodrP   rT   ra   rg   rl    r0   r   r   r   2   sf     w <F+ ' '21""H7r0   r   c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
SyncableAccounta0  A syncable email account connecting 2 repositories.

    Derives from :class:`accounts.Account` but contains the additional
    functions :meth:`syncrunner`, :meth:`sync`, :meth:`syncfolders`,
    used for syncing.

    In multi-threaded mode, one instance of this object is run per "account"
    thread.c                     t        j                  | g|i | d | _        t        j                  j                  | j                  j                         d| z        | _        y )Nz%s.lock)	r   r/   _lockfdr=   r>   r?   r   r   _lockfilepath)r.   argskwargss      r   r/   zSyncableAccount.__init__   sM    ///WW\\KK&&()d*:<r0   c                 v   t        | j                  d      | _        	 t        j                  | j                  t        j
                         y# t        $ r 	 t        j                  | j                  t        j
                  t        j                  z         Y y# t        $ r Y Y yt        $ r4 t        d| z  t        j                  j                  t               d         w xY wt        $ rN | j                  j                          t        d| z  t        j                  j                  t               d         w xY w)z@Lock the account, throwing an exception if it is locked already.wzBCould not lock account %s. Is another instance using this account?rH   N)openr{   rz   portalockerlockLOCK_EX	NameErrorfcntllockfLOCK_NBIOErrorr
   ERRORREPOr   closer3   s    r   __lockzSyncableAccount.__lock   s    D..4	T\\;+>+>? 	#	#DLL%--%--*GH  #&359:$**//JqM	# ##  	LL "/156 &&++
1	 	s*   .A 	D8?B	C D8#<CAD8c                 <   | j                   rr| j                   j                  s[	 t        j                  | j                          | j                   j                          	 t        j                  | j                         yyy# t        $ r Y Hw xY w# t        $ r Y yw xY w)z*Unlock the account, deleting the lock fileN)
rz   closedr   unlockr   r   r=   unlinkr{   OSErrorr3   s    r   _unlockzSyncableAccount._unlock  s     << 3 3""4<<0 LL 		$,,- !4<  
  s#   B  B  	BB	BBc                 v   | j                   j                  |        	 | j                         }t        j                  j                  |      st        j                  |d       t        | d      | _        t        | d      | _	        t        | d      | _
        d}|r| j                   j#                  |        	 | j%                          | j'                          | j(                  rd}	 | j                   j3                  |        | j5                          |r| j7                         dk\  rd}	 |ryy# t        $ rY}| j                   j                  |t               d          |j                  t        j                  j                   k\  r Y d}~yd}~ww xY w# t*        t,        f$ r  t        $ r}|j                  t        j                  j.                  k\  r/|r|dz  }|j                  t        j                  j                   k\  r | j                   j                  |t               d          Y d}~Hd}~wt0        $ r7}| j                   j                  |t               d   d	| z  
       Y d}~d}~ww xY w# | j                   j3                  |        | j5                          |r| j7                         dk\  rd}w w w xY w)z4The target for both single and multi-threaded modes.i  rc   rd   statusrH   NrI   rE   z%While attempting to sync account '%s'msgr   )r$   registerthreadr@   r=   r>   existsmkdirr   r+   r,   r-   r
   rn   r   severityr   CRITICALacct_SyncableAccount__lock_SyncableAccount__syncr&   KeyboardInterrupt
SystemExitr   rm   acctdoner   ra   )r.   accountmetadatarp   loopings       r   
syncrunnerzSyncableAccount.syncrunner  s!    	t$	"113O77>>/2%0)$9D(w7DO)$9D GGLL " %%G  &t}}!3G7    	GGMM!XZ]+zz-33<<<		 &z2 # 0::!1!7!7!<!<<1zz%5%;%;%D%DDaA// (aA"I"&#'  ( ((   &t}}!3G  47s]   A8D, 5 F I2 ,	F5AF		FI/)A=H,&I2 ,I/8,I*$I2 *I//I2 2AJ8c                     | j                   j                  |j                         j                  | j                  j                         | j                   j                                     S )z?Return the corresponding local folder for a given remotefolder.)r,   	getfoldergetvisiblenamereplacer+   getsep)r.   remotefolders     r   get_local_folderz SyncableAccount.get_local_folderC  sQ     (('')((//14??3I3I3KLN 	Nr0   c           
         g }| j                  dd      }|dk  rd}nF|dkD  r?| j                  dk(  s| j                  |kD  r
d| _        d}n| j                  dz   | _        d}nd}| j                  dd      }| j                  ||rdnd       | j                  r^| j
                  j                         rDt        d	d
| j                         z  z   dz   dz   dz   dz   t        j                  j                        	 d}| j
                  }| j                  }| j                  }|j                          |j                          |j                  ||       |j                  dd      s| j                   j#                  ||       |j                         D ]  }	t$        j&                  j)                         r n|	j*                  s2| j                   j-                  dd|	j                         d|d       c|j/                         }
|
t0        j2                  j4                  k7  re|
|j/                         k7  rR|
|	j                         v r@| j                   j7                  dd|	j                         d|j/                         d       | j9                  |	      }|j*                  s=| j                   j-                  dd|j                         d|j:                  d       Ot<        j>                  j@                  smtC        tD        | j
                  j                         tF        d|	jI                         d| d| |	|f      }|jK                          |jM                  |       ntG        | |	|       d} |D ]  }|jO                           |du r tQ        jR                  | jT                         n5djW                  |       }t        |t        j                  j                        |jY                          |jY                          |j[                          |j[                          | j                  dd      }| j                  ||rd       yd       y#  j]                          j]                           xY w)zSynchronize the account once, then return.

        Assumes that `self.remoterepos`, `self.localrepos`, and
        `self.statusrepos` has already been populated, so it should only
        be called from the :meth:`syncrunner` function.quickr   TrE   Fpresynchook fullz"Configuration mismatch in account z'%s'. z2
Account setting 'utf8foldernames' and repository z3setting 'decodefoldernames'
may not be used at the z3same time. This account has not been synchronized.
z1Please check the configuration and documentation.readonlyzNot syncing filtered folder 'z'[]zIgnoring folder 'z' due to unsupported 'z'' character serving as local separator.zFolder z [acc: )limitNamespacetargetr   r|   z3Account {}: no folder to sync (folderfilter issue?)postsynchookN)/
getconfintr)   getconfcallhookr#   r+   getdecodefoldernamesr
   r8   r   r   r,   r-   
getfolderssync_folder_structurer"   r$   syncfoldersr   rL   rS   	sync_thisdebugr   r=   r>   sepr*   r   
repositoryr   optionssinglethreadingr   FOLDER_NAMESPACE
syncfoldergetexplainednamestartrY   r?   r   writeIntermediateFiler   formatforgetfoldersholdordropconnectionsdropconnections)r.   folderthreadsquickconfigr   hookstartedThreadr+   r,   r-   r   r   localfolderthreadthrr   s                  r   __synczSyncableAccount.__syncL  s    oogq1?E1_}}!T]][%@ ! $ 1E ||M2.duG&9$"2"2"G"G"I"#G#+dlln#<$=#X$Y $Z$Z $Z	$Z
 $W$W $4#9#9#>#>@ @N	0!M**KJ**K ""$!!#--j+F,,Z?##K< !, 6 6 8 )%++224#--GGMM"0<0D0D0F'U V
 !'')277;;&{1133|3355GGLL"."6"6"8*:K:K:M&O P "33LA",,GGMM"0;0C0C0E{G]G]'_ `662,d.>.>.F.F.H(J)(99;TC"L%8F LLN!((0t\59 $S)%V % 
$--dii8KRRSWX&s,<,B,B,G,GHH$$&%%' ,,.--/||NB/duG9&9	 &&('')s   6LQ #Q5c           	         t         j                  j                         ry |sy 	 | j                  j	                  d|z          | j
                  ry t        j                  j                         }||d<   t        |dt        t        t        d|      }|j                         \  }}| j                  j	                  d|j                  d      d|j                  d      d       | j                  j	                  d	|j                  z         y # t        t        f$ r  t         $ r3}| j                  j#                  |t%               d
   d       Y d }~y d }~ww xY w)NzCalling hook: OFFLINEIMAPSYNCMODET)shellstdinstdoutstderr	close_fdsenvzHook stdout: zutf-8z
Hook stderr:
zHook return code: %drH   zCalling hookr   )r   rL   rS   r$   r   r(   r=   environcopyr   r   communicatedecode
returncoder   r   rm   rn   r   )r.   cmdsyncmoder   pr   r   rp   s           r   r   zSyncableAccount.callhook  s   ##**,	@GG-34{{jjoo'G-5G)*c d $'3A ]]_NFFGG}}W-v}}W/EG HGG3allBC!:. 	 	@GGMM!XZ]M??	@s   *D B<D E$)EEN)rq   rr   rs   rt   r/   r   r   r   r   r   r   rv   r0   r   rx   rx      s/    <4/ bNt:l@r0   rx   c                 	     fd} fd}fd}fd}d } j                   } j                   j                  }	t               j	                          	  j                         |        t        j                   j                  j                         j                                |	j                  j                         j                  |j                         |	j                                     j                          j!                          j#                  |       j%                         }
j'                         }j'                         }|
du|duz   |duz   dkD  r0t)        dt(        j*                  j,                  t/               d	         |
|s|r|rj1                  d
       |
 ||
        |        n| ||        |        n| ||        |        nj!                          |rj3                        szj3                        sij5                         j7                          	 dD ]*  }|t9               v st9               |   j;                          , j=                           |        y |        j!                          j?                  dd      s'jA                  |       jC                         n#jE                  ddj                         z         |j?                  dd      s'jA                  |       jC                         n#jE                  dd|j                         z         jG                          j7                          dD ]*  }|t9               v st9               |   j;                          , j=                           |        y# tH        tJ        f$ r  t(        $ rX}|jL                  t(        j*                  jN                  kD  r jQ                  |t/               d	   dd d       Y d}~d}~wtR        $ rF}jQ                  |d dj                         dtU        jV                                Y d}~d}~ww xY w# dD ]*  }|t9               v st9               |   j;                          , j=                           |        w xY w)zSynchronizes given remote folder for the specified account.

    Filtered folders on the remote side will not invoke this function.

    When called in concurrently for the same localfolder, syncs are
    serialized.c                  D   j                         } j                         }t        5  t        j	                  |       	i t        | <   t        |    j	                  |      t               t        |    |<   d d d        t        |    |   j                          y # 1 sw Y   $xY wr2   )r8   getfullnameSYNC_MUTEXES_LOCKSYNC_MUTEXESgetr   acquire)account_namelocalfolder_nameaccountr   s     r   acquire_mutexz!syncfolder.<locals>.acquire_mutex  s    (&224 	F-5-/\* L)--.>?G @Dv\*+;<	F 	\"#34<<>	F 	Fs   ABBc                  r    t          j                            j                            j                          y r2   )r   r8   r   release)r   r   s   r   release_mutexz!syncfolder.<locals>.release_mutex  s)    W__&'(?(?(ABJJLr0   c                  p    j                         dkD  sj                         dkD  ro j                         s,j                           j                  j	                          y j                         s"j                         j	                          y y  j                          j                          y )Nr   )getmessagecountcheck_uidvalidityvalidityproblemr   restore_atimesave_uidvalidity)r   r,   r   statusfolderr$   s   r   check_uid_validityz&syncfolder.<locals>.check_uid_validity  s     &&(1,0L0L0NQR0R002"";/&&446113""<0((* 4 ((*))+r0   c                 R   j                  t        j                  t        j                  |       dz                j	                         }j                          t        |      dkD  rGj                          j                  t        |             j                  t        |             yj                  |        j	                         }|D cg c]
  }|dkD  s	| }}t        |      dkD  r,j                          j                  t        |             yyc c}w )zBReturns messages with uid > min(uids of messages newer than date).iQ min_dater   min_uidN)cachemessagelisttimegmtimemktimegetmessageuidlistdropmessagelistcachelenmin)dateuidsuidr   r   s      r   cachemessagelists_upto_datez/syncfolder.<locals>.cachemessagelists_upto_date  s    	%%[[T!2\!AB 	& 	D--/((*t9q= --/))#d))<((T(;
 (($(7002D $(3C37C3D34y1}113--c$i-@  4s   
D$#D$c                 @   | j                          |j                         }|t        | j                               dkD  rSt	        d|j
                  j                  d| j
                  j                  dt        j                  j                        |j                  |       t        |j                  j                               D cg c]
  }|dkD  s	| }}t        |      dkD  rt        |      }nd}|j                  |       y|j                  |       yc c}w )	a  Retrieve messagelists when startdate has been set for
        the folder 'partial'.

        Idea: suppose you want to clone the messages after date in one
        account (partial) to a new one (new). If new is empty, then copy
        messages in partial newer than date to new, and keep track of the
        min uid. On subsequent syncs, sync all the messages in new against
        those after that min uid in partial. This is a partial replacement
        for maxage in the IMAP-IMAP sync case, where maxage doesn't work:
        the UIDs of the messages in localfolder might not be in the same
        order as those of corresponding messages in remotefolder, so if L in
        local corresponds to R in remote, the ranges [L, ...] and [R, ...]
        might not correspond. But, if we're cloning a folder into a new one,
        [min_uid, ...] does correspond to [1, ...].

        This is just for IMAP-IMAP. For Maildir-IMAP, use maxage instead.Nr   zTo use startdate on Repository z, Repository z must be emptyr   rE   r   )r   retrieve_min_uidr  r  r
   r   r   r   MESSAGElistmessagelistkeysr  save_min_uid)newpartialr  r   r
  positive_uidss         r   cachemessagelists_startdatez/syncfolder.<locals>.cachemessagelists_startdate)  s    $ 	**,?3((*+a/&(/(:(:(?(?ATAT(V (8'='='E'EG G
 (($(7 15W5H5H5M5M5O0P \TWZ[T[ \ \}%)!-0GG$$W-$$W$5 !]s   	
DDNrE   zuYou can set at most one of the following: maxage, startdate (for the local folder), startdate (for the remote folder)rH   zTQuick syncs (-q) not supported in conjunction with maxage or startdate; ignoring -q.)r   r   r   r   Fr   z(Not syncing to read-only repository '%s'zAborting sync, folder 'z	' [acc: 'z']r   zERROR in syncfolder for z folder z: ),r+   r,   r-   r   r   r   r   addr   getlocalrootr8   r   r   r   r   	openfilesr   syncingfolder	getmaxagegetstartdater
   r   r   r   r*   quickchangedskippingfolderr   localsr  
closefilesr"   syncingmessagessyncmessagestor   saver   r   r   FOLDERrn   rm   	traceback
format_exc)r   r   r   r   r   r   r  r  r+   r-   maxage
localstartremotestartfolderrp   r   r,   r   r$   s   ``             @@@@r   r   r     s   ?"M, ,(A8&6P %%K##J%%K	Bg_..|< 	 	GLL*"9"9";'')	+ #,,\-H-H-J-4W[5G5G5I;K]K]K_-`b %%' 	lJL &&( --/
"//1$:T#9:kQU>UVYZZ" $P $4#9#9#>#>#+:a=	2 2
 * GG = >'/ #'k(24 $'\(35 ((*#00>(55lC%%l3,,.F F 	8F! 557	8 	!O  ))+ ((U;{L*kR''\BHHRC'')* + ))*e<z;\R&&|\BHHRC ((*+ , 	  " F 	8F! 557	8 	!% z*  S::(..555HHQ
1<G,RH S S Z
 ,"="="?AUAUAWY 	Z 	ZZ F 	8F! 557	8 	!sK   %G-O C/O R(AP;6R ;R<RR RR S#5S) 
subprocessr   r   	threadingr   r   r=   r  sysr   r%  offlineimapr   r	   r
   r   offlineimap.repositoryr   offlineimap.uir   offlineimap.threadutilr   r   r   r   r   r   r   ConfigHelperMixinr   rx   r   rv   r0   r   <module>r3     s   " # ! 	    ? ?  - & 8$ F N
dl,, dN@g @HYqs$   A< <B?BBBB