
    e`                         d dl Z d dlZ 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
 d dlZd dlmZ ddddd	adad
 Zd Z G d d      Zy)    N)Queue)deque)OfflineImapErrorz'Other offlineimap related sync messageszIMAP protocol debuggingzMaildir repository debuggingzThreading debugging) imapmaildirthreadc                     | a y)z0Set the global ui object to be used for logging.Nglobalui)newuis    0/usr/share/offlineimap3/offlineimap/ui/UIBase.pysetglobaluir   '   s	     H    c                      t         S )zReturn the current ui object.r    r   r   getglobaluir   .   s	     Or   c                   ~   e Zd Zej                  fdZd Zd Zd Zd Z	d Z
d:dZd;d	Zd
 Zd Zd<dZd Zd Zd Zd Zd Zd Zd Zd<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$ Z'd% Z(d& Z)d' Z*d( Z+d) Z,d* Z-d+ Z.d, Z/d- Z0d. Z1d/ Z2d0 Z3d1 Z4d2 Z5d3 Z6d4 Z7d=d5Z8d6 Z9d7 Z:d8 Z;d9 Z<y)>UIBasec                 V   || _         |j                  ddd      | _        g | _        i | _        d| _        i | _        i | _        d | _        t               | _
        d| _        t        j                  d      | _        | j                  j                  |       | j!                         | _        y )Ngeneralzdry-runF   OfflineImap)configgetdefaultbooleandryrun	debuglistdebugmessagesdebugmsglenthreadaccountsacct_startimeslogfiler   	exc_queueuidval_problemlogging	getLoggerloggersetLevelsetup_consolehandler_log_con_handler)selfr   loglevels      r   __init__zUIBase.__init__6   s    ..y)UK  # ''6X& $ 9 9 ;Ir   c                 >   t        j                  t        j                        }t        j                  d      | _        |j                  | j
                         | j                  j                  |       | j                  j                  t        j                         |S )zBackend specific console handler.

        Sets up things and adds them to self.logger.
        :returns: The logging.Handler() for console outputz%(message)s)r%   StreamHandlersysstdout	Formatter	formattersetFormatterr'   
addHandlerinfoofflineimapbannerr+   chs     r   r)   zUIBase.setup_consolehandlerO   sk     ""3::. !**=9
'r"++,	r   c                     t         j                  j                  d      }t        j                  d      | _        |j                  | j                         | j                  j                  |       y)z Backend specific syslog handler.z/dev/logz%offlineimap[%(process)d]: %(message)sN)r%   handlersSysLogHandlerr2   r3   r4   r'   r5   r9   s     r   setup_sysloghandlerzUIBase.setup_sysloghandler`   sO     ++J7 **+RS
'r"r   c           
      :   t        j                  |d      }t        j                  dd      }|j                  |       | j                  j                  |       dj                  t        j                  dd D cg c]  }t        |       c}      }dt        j                  d|d	t        j                  d
dj                  t        j                        }t        j                  dt         j                  t         d|dd      }|j#                  |       yc c}w )z'Create file handler which logs to file.atz&%(asctime)s %(levelname)s: %(message)sz%Y-%m-%d %H:%M:%S.r      zOfflineImap z starting...
  Python: z Platform: z	
  Args:  r   N)r%   FileHandlerr2   r4   r'   r5   joinr0   version_infostrr7   __version__platformargv	LogRecordINFO__file__emit)r+   r"   fhfile_formatterxp_vermsgrecords           r   
setlogfilezUIBase.setlogfilek   s       $/ ** ,9:MO
'r"#*:*:1Q*?@Q#a&@A'33UCLLHHSXX.0 ""=',,#'dD:
 As   9Dc                 &    | j                  |       yzDisplay a message.N)r6   r+   rS   s     r   _msgzUIBase._msg}   s     			#r   c                 :    | j                   j                  |       yrW   r'   r6   rX   s     r   r6   zUIBase.info   s     	r   c                 :    | j                   j                  |       y N)r'   warning)r+   rS   minors      r   warnzUIBase.warn   s    C r   Nc                 F   |r"| j                   j                  d|d|       n| j                   j                  d|z         |}| j                  sd}| j                  j	                  |||f       |r/| j                   j                  t        j                  |             yy)a  Log a message at severity level ERROR.

        Log Exception 'exc' to error log, possibly prepended by a preceding
        error "msg", detailing at what point the error occurred.

        In debug mode, we also output the full traceback that occurred
        if one has been passed in via sys.info()[2].

        Also save the Exception to a stack that can be output at the end
        of the sync run when offlineiamp exits. It is recommended to
        always pass in exceptions if possible, so we can give the user
        the best debugging info.

        We are always pushing tracebacks to the exception queue to
        make them to be output at the end of the run to allow users
        pass sensible diagnostics to the developers or to solve
        problems by themselves.

        One example of such a call might be:

           ui.error(exc, sys.exc_info()[2], msg="While syncing Folder %s in "
               "repo %s")
        ERROR: 
  	ERROR: %sN)r'   errorr   r#   put	traceback	format_tb)r+   excexc_tracebackrS   instant_tracebacks        r   re   zUIBase.error   s    0 KK3<=KKkC/0)~~ $Cm45KKi112CDE r   c           
      (   t        j                         }|| j                  v r:| j                  dd|j	                         d| j                  |      d|d       n'| j                  dd|j	                         d|d       || j                  |<   y)	zARegister current thread as being associated with an account name.r	   zRegister thread 'z' (previously 'z', now 'z')zRegister new thread 'z' (account 'N)	threadingcurrentThreadr    debuggetNamegetthreadaccount)r+   account
cur_threads      r   registerthreadzUIBase.registerthread   s     ,,.
,,,JJx,6,>,>,@,0,A,A*,Mw"X Y JJx"**,g"7 8*1J'r   c                     || j                   v r| j                   |= | j                  dd|j                         z         y)z=Unregister a thread as being associated with an account name.r	   zUnregister thread '%s'N)r    ro   rp   r+   thrs     r   unregisterthreadzUIBase.unregisterthread   s:     $%%%##C(

85EFr   c                 j    |t        j                         }|| j                  v r| j                  |   S y)zxGet Account() for a thread (current if None)

        If no account has been registered with this thread, return 'None'.N)rm   rn   r    rv   s     r   rq   zUIBase.getthreadaccount   s9    
 ;))+C$%%%&&s++r   c                    t        j                         }|| j                  vrt               | j                  |<   | j                  |   j	                  |d|       t        | j                  |         | j                  kD  r| j                  |   j                          || j                  v r"| j                  j                  d|d|       y y )N: [z]: )rm   rn   r   r   appendlenr   popleftr   r'   ro   )r+   	debugtyperS   rs   s       r   ro   zUIBase.debug   s    ,,.
T/// .3WDz*:&--)S.IJ t!!*-.1A1AAz*224&KKIs;< 'r   c                     |t         v r<|| j                  vr-| j                  j                  |       | j                  |       y y | j	                  |       y r]   )
debugtypesr   r}   	debugginginvaliddebugr+   r   s     r   	add_debugzUIBase.add_debug   sI    
".%%i0y) / i(r   c                     || j                   v S r]   )r   r   s     r   is_debuggingzUIBase.is_debugging   s    T^^+,r   c                 T    | j                   j                  d|dt        |          y )NzNow debugging for r{   )r'   ro   r   r   s     r   r   zUIBase.debugging   s%    	8B98MO 	Pr   c                 ,    | j                  d|z         y )NzInvalid debug type: %s)r`   r   s     r   r   zUIBase.invaliddebug   s    		*Y67r   c                     |j                   j                  j                  d      d   }t        j                  dd|      S )z\Return the type of a repository or Folder as string.

        (IMAP, Gmail, Maildir, etc...)rA   z(Folder|Repository)r   )	__class____name__splitresub)r+   mobject
prelimnames      r   getnicenamezUIBase.getnicename   s9    
 &&//55c:2>
vv+R<<r   c                      y)zReturns true if this UI object is usable in the current
        environment.  For instance, an X GUI would return true if it's
        being run in X with a valid DISPLAY setting, and false otherwise.Tr   r+   s    r   isusablezUIBase.isusable   s    
 r   c                     t        d      )Nz=Prompting for a password is not supported in this UI backend.)NotImplementedError)r+   usernamer   errmsgs       r   getpasszUIBase.getpass  s    ! #9 : 	:r   c           	          dj                  |D cg c]'  }| j                  |      d|j                         d) c}      S c c}w )N, r|   ])rE   r   getname)r+   folder_listrQ   s      r   
folderlistzUIBase.folderlist  sH    yyFQSAB4++A.		= S T 	T Ss   ,Ac                     | j                   j                  dd      r| j                   j                  dd      ry | j                  d|| j	                  |      |fz         y )Nr   ignore-readonlyzAttempted to synchronize message %d to folder %s[%s], but that folder is read-only.  The message will not be copied to that folder.)r   
has_option
getbooleanr`   r   )r+   
destfolderuids      r   msgtoreadonlyzUIBase.msgtoreadonly  sa    ;;!!)->?&&y2CD		 + 4++J7.EE 	Fr   c           	          | j                   j                  dd      r| j                   j                  dd      ry | j                  dt	        |      d| j                  |      d|d       y )Nr   r   z'Attempted to modify flags for messages  in folder r|   zO], but that folder is read-only.  No flags have been modified for that message.r   r   r   r`   rG   r   )r+   r   uidlistflagss       r   flagstoreadonlyzUIBase.flagstoreadonly  Z    ;;!!)->?&&y2CD		 'lD$4$4Z$@*N 	Or   c           	          | j                   j                  dd      r| j                   j                  dd      ry | j                  dt	        |      d| j                  |      d|d       y )Nr   r   z(Attempted to modify labels for messages r   r|   zP], but that folder is read-only.  No labels have been modified for that message.r   )r+   r   r   labelss       r   labelstoreadonlyzUIBase.labelstoreadonly"  r   r   c           	          | j                   j                  dd      r| j                   j                  dd      ry | j                  dt	        |      d| j                  |      d|d       y )Nr   r   zAttempted to delete messages r   r|   zO], but that folder is read-only.  No messages have been deleted in that folder.r   )r+   r   r   s      r   deletereadonlyzUIBase.deletereadonly+  sW    ;;!!)->?&&y2CD		"7|T-=-=j-I)+ 	,r   c                      y)zCalled when the UI starts.  Must be called before any other UI
        call except isusable().  Displays the copyright banner.  This is
        where the UI should do its setup -- TK, for instance, would
        create the application window here.Nr   r   s    r   init_bannerzUIBase.init_banner6  s    
 	r   c                     | j                   j                  t        j                        syd}|r|nd}|rd|z  nd}|rd|d|}| j                   j	                  d|d|d       y)	z!Log 'Establishing connection to'.Nr   z%s to :zEstablishing connectionz ())r'   isEnabledForr%   rL   r6   )r+   	reposnamehostnameport
displaystrs        r   
connectingzUIBase.connecting=  sa     {{''5
'8R"td{(0$7J$i1 	2r   c                     t        j                          | j                  |<   | j                  j                  d|z         y)z=Output that we start syncing an account (and start counting).z*** Processing account %sNtimer!   r'   r6   )r+   rr   s     r   acctzUIBase.acctK  s2     (,yy{G$4w>?r   c                     t        j                          | j                  |   z
  }| j                  |= | j                  j                  d||dz  |dz  fz         y)z;Output that we finished syncing an account (in which time).z$*** Finished account '%s' in %d:%02d<   Nr   )r+   rr   secs      r   acctdonezUIBase.acctdoneQ  sY     iikD//88(?!3"9cBh78 	9r   c                     | j                   j                  t        j                        r| j	                  dd|d|       yy)z"Log 'Copying folder structure...'.r   zCopying folder structure from r   N)r'   r   r%   DEBUGro   )r+   src_repodst_repos      r   syncfolderszUIBase.syncfoldersY  s7     ;;##GMM2JJr (, - 3r   c                 h    | j                   rdnd}| j                  dj                  |||             y)z Called when a folder is created.	[DRYRUN] r   z{0}Creating folder {1}[{2}]Nr   r6   format)r+   repo
foldernameprefixs       r   
makefolderzUIBase.makefoldera  s2     !%		077J& 	(r   c           
          | j                   j                  d|d| j                  |      d| j                  |             y)/Called when a folder sync operation is started.zSyncing r{    -> N)r'   r6   r   )r+   srcrepos	srcfolder	destreposr   s        r   syncingfolderzUIBase.syncingfolderh  s;     	9373C3CH3M373C3CI3NP 	Qr   c                 @    | j                   j                  d|z         y)r   zSkipping %s (not changed)Nr[   r+   folders     r   skippingfolderzUIBase.skippingfoldero  s    4v=>r   c                     d| _         | j                  j                  d||j                         |j	                         |j                         fz         y )NTz~UID validity problem for folder %s (repo %s) (saved %d; got %d); skipping it. Please see FAQ and manual on how to handle this.)r$   r'   r^   getrepositoryget_saveduidvalidityget_uidvalidityr   s     r   validityproblemzUIBase.validityproblems  sV    " @ $V%9%9%;#88:F<R<R<TVV 	Wr   c                 f    | j                   j                  d| j                  |      d|d       y )NzLoading message list for r|   r   r'   ro   r   )r+   reposr   s      r   loadmessagelistzUIBase.loadmessagelist{  s*    U# 	r   c                 d    | j                   j                  d| j                  |      ||fz         y )Nz+Message list for %s[%s] loaded: %d messagesr   )r+   r   r   counts       r   messagelistloadedzUIBase.messagelistloaded  s4    GU#VUK4 4 	5r   c                     | j                   j                  d| j                  |      d|d| j                  |      d|d	       y )NzSyncing messages r|   z] -> r   r   )r+   srr   dr	dstfolders        r   syncingmessageszUIBase.syncingmessages  s9    R )R )- 	.r   c           
      z    | j                   j                  d|d|j                  d|d|j                         y)z3Output a log line stating which message is ignored.zIGNORED: Copy message UID rC   r   r   Nr'   r6   
repository)r+   r   srcr   s       r   ignorecopyingmessagezUIBase.ignorecopyingmessage  s.     	j&;&;= 	>r   c           
      v    | j                   j                  d||||j                  ||j                  |fz         y)z0Output a log line stating which message we copy.z*Copy message UID %s (%d/%d) %s:%s -> %s:%sNr   )r+   r   numnum_to_copyr   r   s         r   copyingmessagezUIBase.copyingmessage  s>     	Ek3>>3!!:I/ / 	0r   c           	          | j                  |      }| j                  rdnd}| j                  dj                  |t	        |      t
        j                  j                  |      |             y )Nr   r   z%{0}Deleting {1} messages ({2}) in {3})r   r   r6   r   r~   r7   imaputiluid_sequence)r+   r   destlistdsr   s        r   deletingmessageszUIBase.deletingmessages  sV    __X& $		9@@CL  --g6< 	=r   c                 v    | j                   j                  ddj                  |      t        |      |fz         y )Nz#Adding flag %s to %d messages on %sr   r'   r6   rE   r~   r+   r   r   dests       r   addingflagszUIBase.addingflags  s6    >IIec'lDB2 2 	3r   c                 v    | j                   j                  ddj                  |      t        |      |fz         y )Nz'Deleting flag %s from %d messages on %sr   r  r  s       r   deletingflagszUIBase.deletingflags  s6    BIIec'lDF2 2 	3r   c                 X    | j                   j                  d|t        |      |fz         y )Nz$Adding label %s to %d messages on %sr'   r6   r~   r+   r   labelr  s       r   addinglabelszUIBase.addinglabels  s-    ?3w<C' ' 	(r   c                 X    | j                   j                  d|t        |      |fz         y )Nz(Deleting label %s from %d messages on %sr
  r  s       r   deletinglabelszUIBase.deletinglabels  s-    C3w<G' ' 	(r   c           
      h    | j                   j                  d||||dj                  |      fz         y )Nz1Setting labels to message %d on %s (%d of %d): %sr   )r'   r6   rE   )r+   r   r   
num_to_setr   r  s         r   settinglabelszUIBase.settinglabels  s6    LsJ		&(9P; ; 	<r   c                     |r*| j                   j                  dt        |      |fz         y | j                   j                  d|z         y )Nz&Collecting data from %d messages on %sz#Collecting data from messages on %sr
  )r+   r   sources      r   collectingdatazUIBase.collectingdata  sH    KKEGfI& & ' KKBVKLr   c           	         d}| j                  |d|j                  d| j                  |      d       	 t        |d      r| j                  d|j	                         d|j                         d|j                                	 |j                  j                         }d	|j                  v r| j                  d
       | j                  dt        |j                        z         | j                  dt        |j                        z         |j                  j                  |       |dk7  r%|j                  dd      }|r| j                  d|z         |j                  dd      }|r| j                  d|z         |j                  dd      }|r| j                  d|z         |j                         }|D 	cg c])  }	|	j                  |	j!                         |	j"                  f+ }
}	g }|
D ]?  \  }}}|rdnd}||k(  r|j%                  ||       (|j%                  |d||       A | j                  ddj'                  |      z         |r|j                  j)                          yy# t        $ r}| j                  d|z         Y d}~ld}~ww xY wc c}	w # |r|j                  j)                          w w xY w)zBConnect to repository and output useful information for debugging.Nz repository 'z	': type ''gethostzHost: z Port: z SSL: IDzServer supports ID extension.zServer welcome string: %szServer capabilities: %s
zFailed to connect. Reason %sStatusfolderfilterzfolderfilter= %s
folderincludeszfolderincludes= %s
	nametransznametrans= %s
r   z (disabled)r   zFolderlist:
 %s
z
 )rY   namer   hasattrr  getportgetssl
imapserveracquireconnectioncapabilitiesrG   welcomereleaseconnectionr   getconf
getfoldersgetvisiblename	sync_thisr}   rE   close)r+   r   rtypeconner  r  r  foldersffoldernamesr  visiblenamer*  syncstrs                  r   serverdiagnosticszUIBase.serverdiagnostics  s    		UJOO595E5Ej5QS 	T-	.z9-		9K9K9M9C9K9K9MzO`O`Obd eB%00BBDD t000		"AB II9C<MMNII9C@Q@Q<RRS));;DA )11.$GII2\AB!+!3!34Dd!K!II4~EF&..{DA	II/);<$//1(/1#$ !"(8(8(:AKKH 1 14? N0D+y$-b=G{*18(: ;  t7BG(M NN 		.G1DDE%%++- M ( BII<q@AAB21 %%++- sD   AJ# I3 "DJ# <.J*A+J# 3	J<JJ# JJ# #Kc           	      F    | j                  |d||t        |      fz         y)z-Output a log line stating that we save a msg.z Write mail '%s:%d' with flags %sN)ro   repr)r+   r   r   r   r   s        r   savemessagezUIBase.savemessage  s(     	

9@Ce-. 	/r   c                     || j                   v rNdt        | j                   |         |j                         fz  }|dj                  | j                   |         z  }|S d|j                         z  }|S )Nz:
Last %d debug messages logged for %s prior to exception:

z&
No debug messages were logged for %s.)r   r~   rp   rE   r+   r	   messages      r   getThreadDebugLogzUIBase.getThreadDebugLog  s{    T'''TT//78&..:JKLGtyy!3!3F!;<<G  @nn&'Gr   c                 <    || j                   v r| j                   |= y y r]   )r   r+   r	   s     r   delThreadDebugLogzUIBase.delThreadDebugLog  s#    T'''""6* (r   c                 t    d|j                         d|j                  }|d| j                  |      z   z  }|S )NzThread 'z' terminated with exception:
r9  )rp   exit_stacktracer<  r:  s      r   getThreadExceptionStringzUIBase.getThreadExceptionString  s:    >>#V%;%;=4$00888r   c                     | j                  | j                  |             | j                  |       | j                  d       y)z{Called when a thread has terminated with an exception.
        The argument is the ExitNotifyThread that has so terminated.d   N)r`   rB  r?  	terminater>  s     r   threadExceptionzUIBase.threadException  s5     			$//78v&sr   c                    | j                   j                         s| j                  d       |dk(  rd}| j                   j                         s| j                   j                         \  }}}dj	                  t        j                  t        |      |            }|r| j                  d|d|       n| j                  d|z         |r6| j                  ddj	                  t        j                  |            z         | j                   j                         s|r|r| j                  d|d	|d
       n|r| j                  d|z         | j                  r| j                  d       |dk(  rd}t        j                  |       y)z$Called to terminate the application.z*ERROR: Exceptions occurred during the run!r      r   rb   rc   rd   z
Traceback:
%sz

r9  z%s
z7At least one folder skipped due to UID validity problem   N)r#   emptyr`   getrE   rg   format_exception_onlytyperh   r$   r0   exit)r+   
exitstatus
errortitleerrormsgrS   ri   rj   exc_strs           r   rE  zUIBase.terminate  s6    ~~##%IIBCQ
..&&(&*nn&8&8&:#Cmggi==d3iMNG		sG<=		+/0		,rww''608 8 9 ..&&( 
IIZBCIIfx'(IIOPQ
r   c                 H    | j                  |       | j                  |       y)zRCalled when a thread has exited normally.

        Many UIs will just ignore this.N)r?  rx   r>  s     r   threadExitedzUIBase.threadExited0  s     
 	v&f%r   c                     | j                   r!| j                  dj                  |             y | j                  |       y )Nz[DRYRUN] {0}r   rX   s     r   callhookzUIBase.callhook:  s+    ;;IIn++C01IIcNr   c                     d}|dkD  r4|s2|j                         rd}n| j                  d|      }|dz  }|dkD  r|s2| j                  dd       |S )a@  This function does not actually output anything, but handles
        the overall sleep, dealing with updates as necessary.  It will,
        however, call sleeping() which DOES output something.

        :returns: 0/False if timeout expired, 1/2/True if there is a
                  request to cancel the timer.
        Fr   T
   )get_abort_eventsleeping)r+   	sleepsecsrr   
abortsleeps       r   sleepzUIBase.sleepB  s]     
!mJ&&(!
!]]2y9
R	 !mJ 	ar   c                     |dkD  rD|dz  ||z
  dz  k7  r!| j                   j                  d|dz  z         t        j                  |       y)ab  Sleep for sleepsecs, display remainingsecs to go.

        Does nothing if sleepsecs <= 0.
        Display a message on the screen if we pass a full minute.

        This implementation in UIBase does not support this, but some
        implementations return 0 for successful sleep and 1 for an
        'abort', ie a request to sync immediately.
        r   r   zNext refresh in %.1f minutesg      N@)r'   ro   r   r]  )r+   r[  remainingsecss      r   rZ  zUIBase.sleepingU  sS     q="}y'@R&GG!!"@%,#. /JJy!r   )r   )NNr]   )r   NN)=r   
__module____qualname__r%   rL   r-   r)   r>   rU   rY   r6   r`   re   rt   rx   rq   ro   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r4  r7  r<  r?  rB  rF  rE  rT  rV  r]  rZ  r   r   r   r   r   5   s/   (/ J2"	#$
!$FL2G	= )-P
8=:T
FOO,2@9-(Q?W
5.
>0=33((<M3.j/+:&&r   r   )r%   logging.handlersr   r   r0   rg   rm   queuer   collectionsr   r7   offlineimap.errorr   r   r   r   r   r   r   r   r   <module>rf     sX   $   	  
      .;/7-/

 p pr   