
    e@                     Z    d Z ddlZddlmZ ddlmZmZmZ ddlZddl	m
Z
  G d de
      Zy)	zCFolder implementation to support features of the Gmail IMAP server.    N)exc_info)imaputilimaplibutilOfflineImapError   )
IMAPFolderc                   v     e Zd ZdZd fd	Zd Zd Zd Zd fd	Z fdZ	d Z
d	 Zd
 Zd Zd fd	Zd Z xZS )GmailFoldera  Folder implementation to support features of the Gmail IMAP server.

    Removing a message from a folder will only remove the "label" from
    the message and keep it in the "All mails" folder. To really delete
    a message it needs to be copied to the Trash folder. However, this
    is dangerous as our folder moves are implemented as a 1) delete in
    one folder and 2) append to the other. If 2 comes before 1, this
    will effectively delete the message from all folders. So we cannot
    do that until we have a smarter folder move mechanism.

    For more information on the Gmail IMAP server:
      http://mail.google.com/support/bin/answer.py?answer=77657&topic=12815
      https://developers.google.com/google-apps/gmail/imap_extensions
    c                 J   t         t        |   ||||       | j                  j                  j                  dd      | _        | j                  j                  j                  dd      | _        | j                  rA| j                  j                  dd       | j                  j                  | j                         | j                  j                  j                  dd      }t        t        j                   d	|      D cg c]  }t#        |      s| c}      | _        y c c}w )
Nlabelsheaderz
X-Keywords
synclabelsFr   X-GM-LABELSignorelabels z\s*,\s*)superr
   __init__
repositoryaccountgetconfr   getconfbooleanr   
imap_queryinsertsyncmessagesto_passesappendsyncmessagesto_labelssetresplitlenr   )self
imapservernamer   decoder   v	__class__s          3/usr/share/offlineimap3/offlineimap/folder/Gmail.pyr   zGmailFolder.__init__+   s    k4)*dJO !OO33;;NLY //11@@uU ??OO""1m4&&--d.H.HI ..66~rJBHHZ,N YqRUVWRX YZ Ys   >D D c                 8   | j                  t        |      | j                        }|d   }| j                  rt	        j
                  d|d         }|rOt        t        j                  |j                  d            D cg c]  }t        j                  |       c}      }n
t               }|| j                  z
  }t        j                  | j                  t        |            }| j                  || j                         | j!                  || j                  |       | j"                  j%                  d      r^|j'                  | j(                  d         }t+        |      dkD  r|dd	 d
|dd }	n|}	| j"                  j-                  dd||	fz         |S c c}w )a=  Retrieve message with UID from the IMAP server (incl body).  Also
           gets Gmail labels and embeds them into the message.

        :returns: the message body or throws and OfflineImapError
                  (probably severity MESSAGE) if e.g. no message with
                  this UID could be found.
        r   zX-GM-LABELS\s*[(](.*)[)]r   imapz8bit-RFC)policy   N   z...iz&Returned object from fetching %d: '%s')_fetch_from_imapstr
retrycountr   r   searchr   r   	imapsplitgroupdequoter   format_labels_stringr   sorteddeletemessageheadersaddmessageheaderuiis_debugging	as_stringr)   r   debug)
r    uiddatamsgmlblabels
labels_strmsg_s
dbg_outputs
             r&   
getmessagezGmailFolder.getmessage=   sg    $$SXt?
 1g ??		4d1g>AX=O=OPQPWPWXYPZ=[\rh..r2\]d///F!66t7H7H&QW.YJ %%c4+<+<=!!#t'8'8*E77'MMZ)@MAE5zC*/+uST{C
"
GGMM&"J
+#, - 
- ]s   =Fc                 \    d| j                   |   v r| j                   |   d   S t               S )Nr@   )messagelistr   r    r;   s     r&   getmessagelabelszGmailFolder.getmessagelabelsh   s2    t'',,##C(225L    c                 0    |t               t               ddS )Nr   r;   flagsr@   time)r   rG   s     r&   msglist_item_initializerz$GmailFolder.msglist_item_initializero   s    SUceQGGrI   c           	         | j                   st        t        |   ||      S | j	                          | j
                  j                  d |        | j                  j                         }	 | j                  |||      }|s	 | j                  j                  |       y |j                  d|z  d      \  }}|dk7  rOt        d| j                         d| dd|d	|d
z   t        j                  j                  t!               d         	 | j                  j                  |       |D ]  }|t#        |t$              r|j'                  d      }|j)                  dd      d   }t+        j,                  |      }d|vr*| j
                  j/                  dt1        |      z  d       t3        |d         }	| j5                  |	      | j6                  |	<   t+        j8                  |d         }
t;        j<                  d|d         }|rOt?        t+        j@                  |jC                  d            D cg c]  }t+        jD                  |       c}      }n
t?               }|| jF                  z
  }t#        |t0              rt%        |d      }tI        jJ                  |      }|	|
||d| j6                  |	<    y # | j                  j                  |       w xY wc c}w )N)min_datemin_uidz%sz(FLAGS X-GM-LABELS UID)OKzFETCHING UIDs in folder []z	 failed. zServer responded '[z] '   zutf-8)encoding r   UIDz!No UID in message with options %s)minorFLAGSz^[(](.*)[)]r   rK   )&r   r   r
   cachemessagelistdropmessagelistcacher7   collectingdatar!   acquireconnection_msgs_to_fetchreleaseconnectionfetchr   getrepositoryERRORFOLDERr   
isinstancebytesr#   r   r   
flags2hashwarnr-   intrN   rF   flagsimap2maildirr   r/   r   r0   r1   r2   r   r   Internaldate2epoch)r    rP   rQ   imapobjmsgsToFetchres_typeresponse
messagestroptionsr;   rL   r>   r?   r@   rtimer%   s                  r&   r[   zGmailFolder.cachemessagelistt   s   d<!7 = 4 4 	!!#tT*//335	7--(G . =K  OO--g6 ")tk/A/H"JHh4&'')41 x)) %**11JqM# #   OO--g6" 	fJ !*e,'...@
#))#q1!4J))*5GG#@ \*12  4 '%.)(,(E(Ec(J  % 22773CDIImW]-CD ASASTUT[T[\]T^A_!`2("2"22"6!`aF UF$"3"33j#.!&z7!;J#66zB03ev_d(e  %9	f OO--g6. "as   *J8 A,J8 2K
8Kc                 P   | j                   st        t        |   ||||      S t	               }| j                  || j                        D ]1  }|j                  t        j                  | j                  |             3 t        t        |   ||||      }| j                  ||       |S )az  Save the message on the Server

        This backend always assigns a new uid, so the uid arg is ignored.

        This function will update the self.messagelist dict to contain
        the new message after sucessfully saving it, including labels.

        See folder/Base for details. Note that savemessage() does not
        check against dryrun settings, so you need to ensure that
        savemessage is never called in a dryrun mode.

        :param uid: Message UID
        :param msg: Message object
        :param flags: Message flags
        :param rtime: A timestamp to be used as the mail date
        :returns: the UID of the new message as assigned by the server. If the
                  message is saved, but it's UID can not be found, it will
                  return 0. If the message can't be written (folder is
                  read-only for example) it will return -1.)r   r   r
   savemessager   getmessageheaderlistr   updater   labels_from_headersavemessagelabels)	r    r;   r=   rL   rr   r@   hstrretr%   s	           r&   rt   zGmailFolder.savemessage   s    * d7S%OO--c43D3DE 	PDMM(55d6G6GNO	P K23UEJsF+
rI   c           	      t   || j                   z
  }|D cg c]
  }|dkD  s	| }}t        |      dkD  r	| j                  j                         }	 ddj	                  |D cg c]  }t        j                  |       c}      z   dz   }t        j                  |      }| j                  ||||      }		 | j                  j                  |       |	rot        j                  t        j                  |	      d         d   }
t        t        j                  |
      D cg c]  }t        j                   |       c}      }
|
S yc c}w c c}w # |j                  $ r; | j                  j                  | ||       Y | j                  j                  |       yw xY w# | j                  j                  |       w xY wc c}w )z5Common code to savemessagelabels and addmessagelabelsr   (rW   )Nr   r   )r   r   r!   r^   joinr   quoteuid_sequence_store_to_imapreadonlyr7   labelstoreadonlyr`   rg   r0   r   r2   )r    arguidlistr@   r;   rl   r?   rA   uid_strresult	retlabelss              r&   _messagelabels_auxzGmailFolder._messagelabels_aux   s{   $+++")53S1W355w<!oo779G; 388&,QBX^^B-?,Q#RRUXX
"//8,,WgsJO 11':$//0B0B60J10MN}]	@R@RS\@] ^"!1!1"!5 ^_	  ) 6 -R
 ## ((w? 11':
 11': !_sF   
D>D>E E
;5E F5E ,F4F FF F2c                 @   || j                   v r$d| j                   |   v r| j                   |   d   }n
t               }|| j                  z
  }||| j                  z  z  }||k7  r<| j                  d|g|      }|r|| j                   |   d<   y|| j                   |   d<   yy)zChange a message's labels to `labels`.

        Note that this function does not check against dryrun settings,
        so you need to ensure that it is never called in a dryrun mode.r@   r   N)rF   r   r   r   )r    r;   r@   	oldlabels	newlabelsr   s         r&   rx   zGmailFolder.savemessagelabels   s    
 $"""x43C3CC3H'H((-h7II$+++i$*;*;;<		!,,]SE9MF2;  %h/2;  %h/ "rI   c                     || j                   z
  }| j                  d||      }|r-|D ]'  }| j                  |   d   |z  | j                  |   d<   ) yy)zAdd `labels` to all messages in uidlist.

        Note that this function does not check against dryrun settings,
        so you need to ensure that it is never called in a dryrun mode.z+X-GM-LABELSr@   Nr   r   rF   r    r   r@   r   r;   s        r&   addmessageslabelszGmailFolder.addmessageslabels   l     $+++((&I [262B2B32G2QTZ2Z  %h/[ rI   c                     || j                   z
  }| j                  d||      }|r-|D ]'  }| j                  |   d   |z
  | j                  |   d<   ) yy)zDelete `labels` from all messages in uidlist.

        Note that this function does not check against dryrun settings,
        so you need to ensure that it is never called in a dryrun mode.z-X-GM-LABELSr@   Nr   r   s        r&   deletemessageslabelsz GmailFolder.deletemessageslabels  r   rI   c                    |dkD  xr |j                  |       }t        t        |   ||||       |rE| j                  r8	 |j                  |      }|j                  |      }|j                  |||       yyy# t        $ r Y yw xY w)a  Copies a message from self to dst if needed, updating the status

        Note that this function does not check against dryrun settings,
        so you need to ensure that it is never called in a
        dryrun mode.

        :param uid: uid of the message to be copied.
        :param dstfolder: A BaseFolder-derived instance
        :param statusfolder: A LocalStatusFolder instance
        :param register: whether we should register a new thread."
        :returns: Nothing on success, or raises an Exception.r   )mtimeN)		uidexistsr   r
   copymessagetor   getmessagemtimerH   rx   NotImplementedError)	r    r;   	dstfolderstatusfolderregisterrealcopyr   r@   r%   s	           r&   r   zGmailFolder.copymessageto  s     7;9#6#6s#;; 	k4.sI|XV !11#6"33C8..sF%.H	 (8 ' s    6A9 9	BBc           	         g }	 | j                         D ]  }t        j                  j                  j                  j                         r n|dk  s|j                  |      sN| j                  |      | j                  z
  }|j                  |      r|j                  |      | j                  z
  }n
t               }||k7  s|j                  |        i }i }t        |      D ]&  \  }	}t        j                  j                  j                  j                         r n| j                  |      | j                  z
  }|j                  |      r|j                  |      | j                  z
  }n
t               }||k7  s| j                  j                  ||	dz   t        |      t        |      |       | j                   j"                  j$                  r|j'                  ||| j                         |j)                  |      }
|
||<   |||<   ) |j+                  |       |j-                  |       y# t.        $ r | j                  j1                  d       Y yw xY w)ah  Pass 4: Label Synchronization (Gmail only)

        Compare label mismatches in self with those in statusfolder. If
        msg has a valid UID and exists on dstfolder (has not e.g. been
        deleted there), sync the labels change to both dstfolder and
        statusfolder.

        This function checks and protects us from action in dryrun mode.
        r   r   )r   zPCan't sync labels. You need to configure a local repository of type GmailMaildirN)getmessageuidlistofflineimapaccountsAccountabort_NOW_signalis_setr   rH   r   r   r   	enumerater7   settinglabelsr   r4   r   r   dryrunrx   r   savemessageslabelsbulksavemessagesmtimebulkr   rh   )r    r   r   r   r;   
selflabelsstatuslabelsmtimesr@   ir   s              r&   r   z!GmailFolder.syncmessagesto_labels3  s    3	m--/ (''//@@GGI 7)"5"5c":!2237$:K:KK
))#.#/#@#@#EHYHY#YL#&5L-NN3'%(* FF#G, -3''//@@GGI!2237$:K:KK
))#.#/#@#@#EHYHY#YL#&5L-GG))#q1uc'lF:DVXab..55 //ZdN_N_/`%55c:E"'F3K",F3K'-. //7..v6" 	mGGLLkl	ms    B;H/  B:H/ ;B3H/ /$II)T)NN)r   )__name__
__module____qualname____doc__r   rD   rH   rN   r[   rt   r   rx   r   r   r   r   __classcell__)r%   s   @r&   r
   r
      sN    [$)VH
;fz@2<$
[
[>CmrI   r
   )r   r   sysr   r   r   r   r   offlineimap.accountsIMAPr   r
    rI   r&   <module>r      s-   $ J 	  ? ?  [m* [mrI   