o ¯bW:ã@s dZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZddlmZddlmZddlmZmZmZddlmZddlmZdd lmZmZdd lmZm Z m!Z!dd l"m#Z#dd l$m%Z%m&Z&m'Z'm(Z(m)Z)dd l*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:ddl;mZ>m?Z@mAZBmCZDmEZFmGZHmIZJmKZLmMZNmOZOmPZQddlRmSZSmTZTddlUmVZVmWZWddlXmYZYmZZZm[Z[m\Z\m]Z]e^e_e`ddƒd a¡ƒƒZbdd„Zcdd„ZdGdd„dƒZeGdd„dƒZfGdd„dƒZgGdd „d ƒZhGd!d"„d"ƒZid#Zjekee`d$ƒe`d%d&ƒƒƒZld'ejelZmem nd(¡Zoe pd)eod*¡Zqekd+d,„e`d&ƒDƒƒZreeFƒGd-d.„d.eSjseTjtƒƒZue  v¡ZweeFƒGd/d0„d0eSjseTjtƒƒZxdd1d2„Zyd3Zzd4Z{e|Z}džd5d6„Z~d7d8„Zd9d:„Z€dd;d<„Zd=d>„Z‚d?d@„ZƒdAdB„Z„dŸdCdD„Z…dEdF„Z†dGekdHekfdIdJ„Z‡GdKdL„dLƒZˆdMZ‰dNdO„ZŠdPdQ„Z‹dRdS„ZŒdTdU„ZdVdW„ZŽee=ƒGdXdY„dYƒƒZeeOƒGdZd[„d[eƒƒZd\d]d^d_d`daœZ‘dbdc„Z’ddde„Z“dfdg„Z”dhdi„Z•djdk„Z–dldm„Z—dndo„Z˜Gdpdq„dqƒZ™Gdrds„dse™ƒZšGdtdu„duešƒZ›Gdvdw„dwešƒZœGdxdy„dye™ƒZd d{d|„Zžd}d~„ZŸdd€„Z dd‚„Z¡Gdƒd„„d„ƒZ¢Gd…d†„d†ƒZ£Gd‡dˆ„dˆƒZ¤d‰dŠ„Z¥e¦e§d‹dŒd„ƒZ¨dŽd„Z©dd‘„Zªdd’d“„Z«dd”d•„Z¬Gd–d—„d—ej­ƒZ­Gd˜d™„d™ej®ƒZ®e ¯e«e¬e­e®¡Z°dšd›„Z±e ²e±¡gdœ¢Z³dS)¡aƒ An IMAP4 protocol implementation @author: Jp Calderone To do:: Suspend idle timeout while server is processing Use an async message parser instead of buffering in memory Figure out a way to not queue multi-message client requests (Flow? A simple callback?) Clarify some API docs (Query, etc) Make APPEND recognize (again) non-existent mailboxes before accepting the literal éN)Ú decodebytesÚ encodebytes)ÚBytesIO)Úchain)ÚAnyÚListÚcast)Ú implementer)Ú credentials)ÚUnauthorizedLoginÚUnhandledCredentials)ÚdeferÚerrorÚ interfaces)Ú maybeDeferred)ÚCramMD5ClientAuthenticatorÚLOGINAuthenticatorÚLOGINCredentialsÚPLAINAuthenticatorÚPLAINCredentials)ÚIllegalClientResponseÚIllegalIdentifierErrorÚIllegalMailboxEncodingÚIllegalOperationÚIllegalQueryErrorÚIllegalServerResponseÚIMAP4ExceptionÚMailboxCollisionÚMailboxExceptionÚMismatchedNestingÚMismatchedQuotingÚNegativeResponseÚ NoSuchMailboxÚNoSupportedAuthenticationÚReadOnlyMailboxÚUnhandledResponse) Ú IAccountIMAPÚIClientAuthenticationÚICloseableMailboxIMAPÚ IMailboxIMAPÚIMailboxIMAPInfoÚIMailboxIMAPListenerÚ IMessageIMAPÚIMessageIMAPCopierÚIMessageIMAPFileÚIMessageIMAPPartÚINamespacePresenterÚISearchableIMAPMailbox)ÚbasicÚpolicies)ÚlogÚtext)Ú_get_async_paramÚ_matchingStringÚ iterbytesÚ nativeStringÚ networkStringéé z/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov DeccCs||ur|S|S)zô Swap C{this} with C{that} if C{this} is C{ifIs}. @param this: The object that may be replaced. @param that: The object that may replace C{this}. @param ifIs: An object whose identity will be compared to C{this}. ©)ÚthisÚthatÚifIsr=r=ú4/usr/lib/python3/dist-packages/twisted/mail/imap4.pyÚ_swap`s rBcs‡‡fdd„|DƒS)a– Swap each element in each pair in C{of} with C{that} it is C{ifIs}. @param of: A list of 2-L{tuple}s, whose members may be the object C{that} @type of: L{list} of 2-L{tuple}s @param ifIs: An object whose identity will be compared to members of each pair in C{of} @return: A L{list} of 2-L{tuple}s with all occurences of C{ifIs} replaced with C{that} cs(g|]\}}t|ˆˆƒt|ˆˆƒf‘qSr=)rB)Ú.0ÚfirstÚsecond©r@r?r=rAÚ }sÿz!_swapAllPairs..r=)Úofr?r@r=rFrAÚ _swapAllPairsns ÿrIc@sÌeZdZUdZgZeeed<edƒZ eefdd„Z e dd„ƒZ e j dd„ƒZ efd d „Zd d „Zd d„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdefdd„Zdefdd„Zd edefd!d"„Zd#S)$Ú MessageSeta A set of message identifiers usable by both L{IMAP4Client} and L{IMAP4Server} via L{IMailboxIMAP.store} and L{IMailboxIMAP.fetch}. These identifiers can be either message sequence numbers or unique identifiers. See Section 2.3.1, "Message Numbers", RFC 3501. This represents the C{sequence-set} described in Section 9, "Formal Syntax" of RFC 3501: - A L{MessageSet} can describe a single identifier, e.g. C{MessageSet(1)} - A L{MessageSet} can describe C{*} via L{None}, e.g. C{MessageSet(None)} - A L{MessageSet} can describe a range of identifiers, e.g. C{MessageSet(1, 2)}. The range is inclusive and unordered (see C{seq-range} in RFC 3501, Section 9), so that C{Message(2, 1)} is equivalent to C{MessageSet(1, 2)}, and both describe messages 1 and 2. Ranges can include C{*} by specifying L{None}, e.g. C{MessageSet(None, 1)}. In all cases ranges are normalized so that the smallest identifier comes first, and L{None} always comes last; C{Message(2, 1)} becomes C{MessageSet(1, 2)} and C{MessageSet(None, 1)} becomes C{MessageSet(1, None)} - A L{MessageSet} can describe a sequence of single identifiers and ranges, constructed by addition. C{MessageSet(1) + MessageSet(5, 10)} refers the message identified by C{1} and the messages identified by C{5} through C{10}. B{NB: The meaning of * varies, but it always represents the largest number in use}. B{For servers}: Your L{IMailboxIMAP} provider must set L{MessageSet.last} to the highest-valued identifier (unique or message sequence) before iterating over it. B{For clients}: C{*} consumes ranges smaller than it, e.g. C{MessageSet(1, 100) + MessageSet(50, None)} is equivalent to C{1:*}. @type getnext: Function taking L{int} returning L{int} @ivar getnext: A function that returns the next message number, used when iterating through the L{MessageSet}. By default, a function returning the next integer is supplied, but as this can be rather inefficient for sparse UID iterations, it is recommended to supply one when messages are requested by UID. The argument is provided as a hint to the implementation and may be ignored if it makes sense to do so (eg, if an iterator is being used that maintains its own state, it is guaranteed that it will not be called out-of-order). Ú_emptyÚinfcCsZ|j|_g|_dd„|_||jurdSt|tƒr%|dd…|_| ¡dS| ||¡dS)zÔ Create a new MessageSet() @type start: Optional L{int} @param start: Start of range, or only message number @type end: Optional L{int} @param end: End of range. cSs|dS©Nr;r=©Úxr=r=rAÚËóz%MessageSet.__init__..N)rKÚ_lastÚrangesÚgetnextÚ isinstanceÚlistÚcleanÚadd©ÚselfÚstartÚendr=r=rAÚ__init__¿s     zMessageSet.__init__cCs|jS)z{ The largest number in use. This is undefined until it has been set by assigning to this property. )rR©rZr=r=rAÚlast×szMessageSet.lastcCsv|j|jur tdƒ‚||_t|jƒD]"\}\}}|dur|}|dur$|}||kr-||}}||f|j|<q| ¡dS)zø Replaces all occurrences of "*". This should be the largest number in use. Must be set before attempting to use the MessageSet as a container. @raises ValueError: if a largest value has already been set. zlast already setN)rRrKÚ ValueErrorÚ enumeraterSrW)rZÚvalueÚiÚlowÚhighr=r=rAr_ßs   cCst||jur|}|j|jur|dur|j}|dur|j}t||gtjt|jddd\}}|j  ||f¡|  ¡dS)zà Add another range @type start: L{int} @param start: Start of range, or only message number @type end: Optional L{int} @param end: End of range. N©r?r@)Úkey) rKrRr_ÚsortedÚ functoolsÚpartialrBÚ _infinityrSÚappendrWrYr=r=rArXös   ÿ zMessageSet.addcCslt|tƒr|j|j}t|ƒSt|jƒ}|j|jur|j|_z|j|ŽW|Sty5| |¡Y|Sw©N)rUrJrSr_rKrXÚ TypeError)rZÚotherrSÚresr=r=rAÚ__add__s      þ þzMessageSet.__add__cCsTt|tƒr|j |j¡| ¡|Sz|j|ŽW|Sty)| |¡Y|Sw)zÚ Extend our messages with another message or set of messages. @param other: The messages to include. @type other: L{MessageSet}, L{tuple} of two L{int}s, or a single L{int} )rUrJrSÚextendrWrXrn©rZror=r=rArrs û  ý ýzMessageSet.extendcCs”tt|j|jddƒ}tdƒtdƒfg}|D]$\}}|d\}}||dkr.| ||f¡qt||ƒt||ƒf|d<qt|dd…d|jd|_dS)z> Clean ranges list, combining adjacent ranges Nrfz-inféÿÿÿÿr;)rhrIrSrkÚfloatrlÚminÚmax)rZrSÚ mergedRangesrdreÚ previousLowÚ previousHighr=r=rArW0s   zMessageSet.cleancCs|jddduS)a¼ Is there a L{None} in our ranges? L{MessageSet.clean} merges overlapping or consecutive ranges. None is represents a value larger than any number. There are thus two cases: 1. C{(x, *) + (y, z)} such that C{x} is smaller than C{y} 2. C{(z, *) + (x, y)} such that C{z} is larger than C{y} (Other cases, such as C{y < x < z}, can be split into these two cases; for example C{(y - 1, y)} + C{(x, x) + (z, z + 1)}) In case 1, C{* > y} and C{* > z}, so C{(x, *) + (y, z) = (x, *)} In case 2, C{z > x and z > y}, so the intervals do not merge, and the ranges are sorted as C{[(x, y), (z, *)]}. C{*} is represented as C{(*, *)}, so this is the same as 2. but with a C{z} that is greater than everything. The result is that there is a maximum of two L{None}s, and one of them has to be the high element in the last tuple in C{self.ranges}. That means checking if C{self.ranges[-1][-1]} is L{None} suffices to check if I{any} element is L{None}. @return: L{True} if L{None} is in some range in ranges and L{False} if otherwise. rtN)rSr^r=r=rAÚ _noneInRangesDszMessageSet._noneInRangescCs@| ¡rtdƒ‚|jD]\}}||kr|krdSq q dS)z“ May raise TypeError if we encounter an open-ended range @param value: Is this in our ranges? @type value: L{int} z.Can't determine membership; last value not setTF)r{rnrS)rZrbrdrer=r=rAÚ __contains__esÿzMessageSet.__contains__ccsD|jD]\}}| |d¡}||kr|V| |¡}||ksqdSrM)rSrT)rZÚlÚhr=r=rAÚ _iteratorvs€ þ€þzMessageSet._iteratorcCs| ¡rtdƒ‚| ¡S)Nz!Can't iterate; last value not set)r{rnrr^r=r=rAÚ__iter__}szMessageSet.__iter__cCsJd}|jD]\}}|dur|d7}q|durtdƒ‚|||d7}q|S)Nrr;z%Can't size object; last value not set)rSrn)rZrpr}r~r=r=rAÚ__len__ƒs zMessageSet.__len__ÚreturncCsvg}|jD]0\}}||kr|dur| d¡q| t|ƒ¡q|dur,| d|f¡q| d||f¡qd |¡S)NÚ*z%d:*z%d:%dú,)rSrlÚstrÚjoin)rZÚprdrer=r=rAÚ__str__s  zMessageSet.__str__cCsdt|ƒ›dS)Nz ©r…r^r=r=rAÚ__repr__ózMessageSet.__repr__rocCs t|tƒrtt|j|jkƒStSrm)rUrJrÚboolrSÚNotImplementedrsr=r=rAÚ__eq__ s zMessageSet.__eq__N)Ú__name__Ú __module__Ú __qualname__Ú__doc__rKrrÚ__annotations__rurkr]Úpropertyr_ÚsetterrXrqrrrWr{r|rr€rr…rˆr‹Úobjectrrr=r=r=rArJ‚s* 9   ! rJc@s$eZdZdd„Zdd„Zdd„ZdS)Ú LiteralStringcCs||_g|_||_dSrm)ÚsizeÚdatar ©rZr™Údeferedr=r=rAr]§ó zLiteralString.__init__cCón|jt|ƒ8_d}|jdkr|j |¡|S|jr+|d|j…||jd…}}nd}|r5|j |¡|S©Nró)r™Úlenršrl©rZršÚpassonr=r=rAÚwrite¬s   ù  zLiteralString.writecCs|j d |j¡|f¡dS)ú: Call deferred with data and rest of line r N)r Úcallbackr†rš©rZÚliner=r=rAr¦»szLiteralString.callbackN)rr‘r’r]r¤r¦r=r=r=rAr˜¦s r˜c@ó(eZdZdZdd„Zdd„Zdd„ZdS) Ú LiteralFileé cCs0||_||_||jkrt ¡|_dStƒ|_dSrm)r™r Ú_memoryFileLimitÚtempfileÚ TemporaryFileršrr›r=r=rAr]Ås   zLiteralFile.__init__cCržrŸ)r™r¡ršr¤r¢r=r=rAr¤Ís  ú  zLiteralFile.writecCs$|j dd¡|j |j|f¡dS)r¥rN)ršÚseekr r¦r§r=r=rAr¦ÛszLiteralFile.callbackN)rr‘r’r¬r]r¤r¦r=r=r=rArªÂs  rªc@s*eZdZdZd dd„Zdd„Zdd„Zd S) Ú WriteBufferzU Buffer up a bunch of writes before sending them all to a transport at once. é cCs||_||_d|_g|_dS©Nr)Ú bufferSizeÚ transportÚ_lengthÚ_writes)rZr´r™r=r=rAr]ès zWriteBuffer.__init__cCs:|jt|ƒ7_|j |¡|j|jkr| ¡dSdSrm)rµr¡r¶rlr³Úflush©rZÚsr=r=rAr¤îs    ÿzWriteBuffer.writecCs(|jr|j |j¡g|_d|_dSdSr²)r¶r´Ú writeSequencerµr^r=r=rAr·ôs  ýzWriteBuffer.flushN)r±)rr‘r’r“r]r¤r·r=r=r=rAr°ãs   r°c@sJeZdZdZdZdZdZ   ddd„Zdefd d „Z d d „Z d d„Z dS)ÚCommand)ó CAPABILITYóFLAGSóLISTóLSUBóSTATUSóSEARCHó NAMESPACE)óEXISTSóEXPUNGEóFETCHóRECENT)ó UIDVALIDITYóUNSEENó READ-WRITEó READ-ONLYóUIDNEXTóPERMANENTFLAGSNr=cs.||_||_||_‡‡‡fdd„|_g|_dS)Ncsˆ|gˆ¢Riˆ¤ŽSrmr=rN©ÚcontArgsÚcontKwÚ continuationr=rArPóz"Command.__init__..)ÚcommandÚargsÚ wantResponserÐÚlines)rZrÒrÓrÔrÐrÎrÏr=rÍrAr]s   zCommand.__init__r‚cCsd |j|j|j|j|j¡S)Nz()ÚformatrÒrÓrÔrÐrÕr^r=r=rAr‹sÿzCommand.__repr__cCs.|jdur d ||jf¡Sd ||j|jf¡S©Nó )rÓr†rÒ©rZÚtagr=r=rArÖ$s zCommand.formatc CsÊg}g}|jD]E}t|ƒ}t|ƒ}|dkr|d|jvsA|dkr'|d|jvsA|dkrG|ddkrGt|dtƒrG|dd|jvrG| |¡q| |¡q|j d}|_ |  ||f¡|rc||ƒdSdS)Nr;réóOK) rÕÚparseNestedParensr¡Ú _1_RESPONSESÚ _2_RESPONSESrUrVÚ _OK_RESPONSESrlr r¦) rZÚlastLineÚunusedCallbackÚsendÚunuseÚLÚnamesÚNÚdr=r=rAÚfinish)s*   ÿ   ÿzCommand.finish)Nr=N) rr‘r’rÞrßràr r]r…r‹rÖrér=r=r=rAr»ûs  û r»rØé!é€és ]\\(){%*"Úcharmapú[ú]ccs|] }|tvr|VqdSrm)Ú _nonAtomChars)rCÚchr=r=rAÚ Rs€ròc@seZdZdZdZdZdZdZdZdZ dZ dZ dZ dZ dZdZdZhd£Zd Zd ZdMd d „Zd d„Zdd„Zdd„Zdd„Zdd„ZdZdd„Zdd„Zdd„Zdd„ZdNdd „Zd!d"„Z d#d$„Z!d%d&„Z"d'd(„Z#d)d*„Z$d+d,„Z%d-d.„Z&dOd/d0„Z'e( )d1e( *e+¡d2¡Z,d3d4„Z-d5d6„Z.d7d8„Z/d9d:„Z0d;d<„Z1d=d>„Z2d?d@„Z3dAdB„Z4dCdD„Z5dEdF„Z6dGdH„Z7dIdJ„Z8dPdLdM„Z9dPdNdO„Z:dPdPdQ„Z;dNdRdS„Z<dQdUdV„Z=dWdX„Z>dYdZ„Z?d[d\„Z@e@fZAeAZBeAZCeAZDd]d^„ZEeEfZFeFZGeFZHeFZId_d`„ZJeJfZKeKZLeKZMeKZNdadb„ZOeOe-fZPdcdd„ZQdedf„ZRdgdh„ZSdidj„ZTdkdl„ZUdmdn„ZVdodp„ZWeWfZXdqdr„ZYeYe'e&fZZdsdt„Z[dudv„Z\dwdx„Z]dydz„Z^e^fZ_e_Z`d{d|„Zad}d~„Zbdd€„Zceae'dd‚fZdedZeeae'dƒd„fZfefZgd…d†„Zhd‡dˆ„ZiehfZjejZkd‰dŠ„Zlele&fZmemZnd‹dŒ„Zoeoe&fZpepZqddŽ„Zrere'e&fZsesZtdd„Zueue&fZvevZwd‘d’„Zxexe&fZyeyZzd“d”„Z{d•d–„Z|d—d˜„Z}e{e'e'dƒd™fZ~e~Ze{e'e'ddšfZ€e€Zd›dœ„Z‚ddž„ZƒdŸd „Z„e‚e'e.fZ…e…Z†d¡d¢„Z‡d£d¤„Zˆd¥d¦„Z‰d§d¨„ZŠd©dª„Z‹e‰e'e5e6e/fZŒeŒZd«d¬„ZŽd­d®„Zd¯d°„ZefZ‘d±d²„Z’d³d´„Z“dµd¶„Z”d·d¸„Z•e•fZ–d¹dº„Z—d»d¼„Z˜d½d¾„Z™e™fZšd¿dÀ„Z›dÁd„ZœdRdÃdÄ„Zee7e0fZždÅdÆ„ZŸdNdÇdÈ„Z dÉdÊ„Z¡dËdÌ„Z¢dÍd΄Z£dÏdЄZ¤dÑdÒ„Z¥dÓdÔ„Z¦dÕdÖ„Z§d×dØ„Z¨dÙdÚ„Z©dÛdÜ„ZªdÝdÞ„Z«dßdà„Z¬dádâ„Z­dãdä„Z®dådæ„Z¯dçdè„Z°dédê„Z±dëdì„Z²dídî„Z³dïdð„Z´dñdò„Zµdódô„Z¶dõdö„Z·d÷dø„Z¸dùdú„Z¹dûdü„Zºdýdþ„Z»dÿd„Z¼dd„Z½dd„Z¾dd„Z¿dd„ZÀd d „ZÁd d „ZÂd d„ZÃdd„ZÄdd„ZÅdd„ZÆdRdd„ZÇeÇe1e2fZÈdd„ZÉdd„ZÊdSdd„ZËdSdd„ZÌdSdd „ZÍdSd!d"„ZÎdSd#d$„ZÏdSd%d&„ZÐdSd'd(„ZÑdSd)d*„ZÒdSd+d,„ZÓdSd-d.„ZÔd/d0„ZÕd1d2„ZÖdRd3d4„Z×e×e1e-e3fZØd5d6„ZÙd7d8„ZÚdRd9d:„ZÛeÛe1e&fZÜd;d<„ZÝd=d>„ZÞd?d@„ZßdAdB„ZàdCdD„ZádEdF„Zâeâe-e4fZãdGdH„ZädIdJ„ZådKdL„ZædS(TÚ IMAP4ServerzÀ Protocol implementation for an IMAP4rev1 server. The server can be in any of four states: - Non-authenticated - Authenticated - Selected - Logout sTwisted IMAP4rev1 Readyé<iFNi>óORóNOTóUIDÚunauthrÒcCs4|duri}||_||_|durt}||_g|_dSrm)Ú challengersÚctxÚiterateInReactorÚ _schedulerÚ _queuedAsync)rZÚchalÚcontextFactoryÚ schedulerr=r=rAr]s zIMAP4Server.__init__cCsZdt|j ¡ƒi}|jr#|jr#|js#t |jd¡dur#d|d<d|d<d|d<d|d<|S)NóAUTHó LOGINDISABLEDóSTARTTLSrÂsIDLE) rVrùÚkeysrúÚ canStartTLSÚ startedTLSrÚ ISSLTransportr´)rZÚcapr=r=rAÚ capabilitiesšs ÿzIMAP4Server.capabilitiescCs2i|_t |jd¡du|_| |j¡| ¡dSrm)ÚtagsrÚ ITLSTransportr´rÚ setTimeoutÚtimeOutÚsendServerGreetingr^r=r=rAÚconnectionMade§s  zIMAP4Server.connectionMadecCs&| d¡|jr| ¡d|_dSdSrm)r Ú _onLogout)rZÚreasonr=r=rAÚconnectionLost­s  þzIMAP4Server.connectionLostcCs\| d¡|j ¡|jr)|j |¡t|jdƒ}|dur&t|jƒ t j ¡d|_d|_ dS)Ns** BYE Autologout; connection idle too longÚtimeout) ÚsendLiner´ÚloseConnectionÚmboxÚremoveListenerÚICloseableMailboxrÚcloseÚ addErrbackr4ÚerrÚstate)rZÚcmbxr=r=rAÚtimeoutConnection³s     zIMAP4Server.timeoutConnectioncCs.| ¡|j |¡}|dur| |¡dSdSrm)Ú resetTimeoutÚ_pendingLiteralr¤Ú setLineModer¢r=r=rAÚrawDataReceived¾s  ÿzIMAP4Server.rawDataReceivedcCsV|j}d|_|r|jdur| | d¡¡|r|jdus |jdur)|j |¡dSdSr²)ÚblockedÚ lineReceivedÚpoprr)rZÚcommandsr=r=rAÚ_unblockÈsÿ ÿzIMAP4Server._unblockc Cs†|jdur |j |¡dS| ¡t|d|jƒ}z||ƒWdStyB}z| dtt|ƒƒ¡t   ¡WYd}~dSd}~ww)NÚparse_sBAD Server error: ) r#rlrÚgetattrÚ parseStateÚ ExceptionÚsendUntaggedResponser:r…r4r)rZr¨ÚfÚer=r=rAr$Ðs  €þzIMAP4Server.lineReceivedc CsB| dd¡}d}t|ƒdkr|\}}}n%t|ƒdkr|\}}nt|ƒdkr1|d}| |d¡dS| dd¡dS| ¡}z| |||¡WStyd}z| |dtt|ƒƒ¡WYd}~dSd}~wty‚}z|  |dtt|ƒƒ¡WYd}~dSd}~wt y }z|  |d tt|ƒƒ¡WYd}~dSd}~ww) NrÛér;rsMissing commands Null commandóIllegal syntax: óIllegal operation: óIllegal mailbox name: ) Úsplitr¡ÚsendBadResponseÚupperÚdispatchCommandrr:r…rÚsendNegativeResponser)rZr¨rÓÚrestrÚÚcmdr.r=r=rAÚ parse_commandÝs:        &€ÿ€ÿ€ÿzIMAP4Server.parse_commandcCs |j}d|_d|_| |¡dS)NrÒ)r r*r¦)rZr¨rèr=r=rAÚ parse_pendingúszIMAP4Server.parse_pendingcCsN| |¡}|r|d}|dd…}| ||||g|||¡dS| |d¡dS)Nrr;sUnsupported command)Ú lookupCommandÚ_IMAP4Server__doCommandr4)rZrÚr9r8Úuidr-ÚfnÚ parseargsr=r=rAr6s  zIMAP4Server.dispatchCommandcCs t|d |jt| ¡ƒf¡dƒS)NÚ_)r)r†rr9r5)rZr9r=r=rAr< s zIMAP4Server.lookupCommandc Csœt|ƒD],\}}t|ƒr+||dd…}t|||ƒ |j|||||¡ |j|¡dS| |¡q|r;tdt |ƒƒ‚|durH||d|iŽdS||ŽdS)Nr;z Too many arguments for command: r>) raÚcallablerÚ addCallbackÚ_IMAP4Server__cbDispatchrÚ_IMAP4Server__ebDispatchrlrÚrepr) rZrÚÚhandlerrÓr@r¨r>rcÚargr=r=rAÚ __doCommand s ÿ   zIMAP4Server.__doCommandc Cs*|\}}| |¡| ||||||¡dSrm)rlr=) rZÚresultrÚr?rÓr@r>rHr8r=r=rAÚ __cbDispatch s zIMAP4Server.__cbDispatchcCs | t¡r| |dtt|jƒƒ¡dS| t¡r(| |dtt|jƒƒ¡dS| t¡r<| |dtt|jƒƒ¡dS| |dtt|jƒƒ¡t   |¡dS)Nr0r1r2óServer error: ) Úcheckrr4r:r…rbrr7rr4r©rZÚfailurerÚr=r=rAÚ __ebDispatch%s ÿ ÿ ÿÿzIMAP4Server.__ebDispatchcCsR||jkr td|jfƒ‚t ¡}d|_t||ƒ|_| td|ƒ¡|  ¡|S)Nz,Literal too long! I accept at most %d octetsÚpendingzReady for %d octets of text) Ú_literalStringLimitrr ÚDeferredr*r˜r ÚsendContinuationRequestr:Ú setRawMode©rZr™rèr=r=rAÚ_stringLiteral8s ÿÿ  ÿzIMAP4Server._stringLiteralcCs8t ¡}d|_t||ƒ|_| td|ƒ¡| ¡|S)NrQzReady for %d octets of data)r rSr*rªr rTr:rUrVr=r=rAÚ _fileLiteralGs  ÿzIMAP4Server._fileLiteralcCs|j|ddS)a Parse an astring from line that represents a command's final argument. This special case exists to enable parsing empty string literals. @param line: A line that contains a string literal. @type line: L{bytes} @return: A 2-tuple containing the parsed argument and any trailing data, or a L{Deferred} that fires with that 2-tuple @rtype: L{tuple} of (L{bytes}, L{bytes}) or a L{Deferred} @see: https://twistedmatrix.com/trac/ticket/9207 T)Úfinal)Ú arg_astringr§r=r=rAÚarg_finalastringQszIMAP4Server.arg_finalastringc Cs| ¡}|s tdƒ‚d}d\}}|dd…dkr5z| dd¡\}}}|dd…}Wn^ty4tdƒ‚w|dd…d krs|d d…d krItd ƒ‚z t|dd …ƒ}Wntyftd t|dd …ƒƒ‚w|rm|smdS| |¡}n| dd¡}t|ƒdkr„| d¡|\}}|p||fS)aþ Parse an astring from the line, return (arg, rest), possibly via a deferred (to handle literals) @param line: A line that contains a string literal. @type line: L{bytes} @param final: Is this the final argument? @type final L{bool} @return: A 2-tuple containing the parsed argument and any trailing data, or a L{Deferred} that fires with that 2-tuple @rtype: L{tuple} of (L{bytes}, L{bytes}) or a L{Deferred} úMissing argumentN©NNrr;ó"rÛzUnmatched quotesó{rtó}úMalformed literalúBad literal size: )r r rØr ) Ústriprr3r`ÚintrFrWr¡rl)rZr¨rYrèrHr8Úspamr™r=r=rArZcs8 ÿ ÿ     zIMAP4Server.arg_astrings (?P[s]+)( (?P.*$)|$)cCs8|stdƒ‚|j |¡}|r| d¡| d¡fStdƒ‚)z- Parse an atom from the line r\Úatomr8zMalformed ATOM)rÚatomreÚmatchÚgroup)rZr¨Úmr=r=rAÚarg_atom–s  zIMAP4Server.arg_atomcCs`|stdƒ‚|dd…dkrtdƒ‚| d¡}|dkrtdƒ‚t|d|…d ƒ||d d…fS) zG Parse a (non-nested) parenthesised list from the line r\Nr;ó(zMissing parenthesisó)rtúMismatched parenthesisrrÛ)rÚfindrÝ)rZr¨rcr=r=rAÚ arg_plist¢s "zIMAP4Server.arg_plistcCs€|stdƒ‚|dd…dkrtdƒ‚|dd…dkrtdƒ‚z t|dd…ƒ}Wnty:td |dd…›ƒ‚w| |¡S) z/ Parse a literal from the line r\Nr;r_zMissing literalrtr`rarb)rrdr`rX)rZr¨r™r=r=rAÚ arg_literal³s ÿ zIMAP4Server.arg_literalcCst|ƒ}|dfS)z searchkeys r )rÝ)rZr¨Úqueryr=r=rAÚarg_searchkeysÇszIMAP4Server.arg_searchkeysc Csdd}| dd¡}t|ƒdkr|d}|d}zt|ƒ|fWSty1}ztdt|ƒƒ‚d}~ww)z sequence-set r rØr;rÛrzBad message number N)r3r¡Ú parseIdListrrr…)rZr¨r8rHr.r=r=rAÚ arg_seqsetÐs  €ÿzIMAP4Server.arg_seqsetcCstƒ}| |¡|jdfS)z fetch-att r )Ú _FetchParserÚ parseStringrJ)rZr¨r‡r=r=rAÚ arg_fetchattßs  zIMAP4Server.arg_fetchattcCsÂg}|dd…dkr|dd…dkrtdƒ‚|dd…}|r]|j |¡}|s*tdƒ‚|dd…d krC| ¡dkrC| d | d ¡¡n| ¡dkrR| | d ¡¡ntdƒ‚| d ¡}|s|d fS) z- Flag part of store-att-flag rr;rlrtNrmrnzMalformed flagó\rfr8r )rrgÚsearchr[rlri)rZr¨Úflagsrjr=r=rAÚ arg_flaglistçs"    ö zIMAP4Server.arg_flaglistcCs|dfS)z- Command line of UID command r r=r§r=r=rAÚarg_lineÿszIMAP4Server.arg_linecCs| d¡r | |¡Sd|fS)z- Optional parenthesised list rlN)Ú startswithrpr§r=r=rAÚ opt_plists  zIMAP4Server.opt_plistcCsP| d¡r$z | dd¡\}}}Wn tytdƒ‚w||dd…fSd|fS)z+ Optional date-time string r^rÛzMalformed date-timer;N)r~r3r`r)rZr¨reÚdater8r=r=rAÚ opt_datetimes  ÿzIMAP4Server.opt_datetimecCsd|dd… ¡dkr.| dd¡}t|ƒdkrtdƒ‚t|ƒdkr%| d¡|\}}}||fSd|fS) z4 Optional charset of SEARCH command NésCHARSETrØrÛr;zMissing charset identifierr )r5r3r¡rrl)rZr¨rHrer8r=r=rAÚ opt_charsets     zIMAP4Server.opt_charsetcCs,dd | ¡¡d|j}|j|ddS)Ns [CAPABILITY rØó] )Úmessage)r†ÚlistCapabilitiesÚIDENTÚsendPositiveResponse©rZÚmsgr=r=rAr*szIMAP4Server.sendServerGreetingr cCó| d||¡dS)NóBAD©Ú_respond©rZrÚr…r=r=rAr4.ózIMAP4Server.sendBadResponsecCr‹)NrÜrrr=r=rArˆ1rz IMAP4Server.sendPositiveResponsecCr‹)NóNOrrr=r=rAr74rz IMAP4Server.sendNegativeResponsecKs@t|fi|¤Ž}|r|jdur| |dd¡dS|j |¡dSrm)r6r#rŽrýrl)rZr…ÚisAsyncÚkwargsr=r=rAr,7sz IMAP4Server.sendUntaggedResponseó!Ready for additional command textcCs$|r | d|¡dS| d¡dS)Ns+ ó+©rr‰r=r=rArT>sz#IMAP4Server.sendContinuationRequestcCsp|dvr|jr|j}g|_|D] }| |dd¡q|sd}|r,| d |||f¡¡dS| d ||f¡¡dS)N)rÜr‘rŒó*rØ)rýrŽrr†)rZrrÚr…rÕrŠr=r=rArŽDszIMAP4Server._respondcsTdg}| ¡ ¡D]\‰}|dur| ˆ¡q t|ƒr'| ‡fdd„|Dƒ¡q |S)Ns IMAP4rev1csg|]}ˆd|‘qS)ó=r=)rCr©Úcr=rArGWóz0IMAP4Server.listCapabilities..)r Úitemsrlr¡rr)rZÚcapsÚvr=r™rAr†Qs €zIMAP4Server.listCapabilitiescCs(| dd | ¡¡¡| |d¡dS)Ns CAPABILITY rØsCAPABILITY completed)r,r†r†rˆrÙr=r=rAÚ do_CAPABILITYZszIMAP4Server.do_CAPABILITYcCs$| d¡| |d¡|j ¡dS)NsBYE Nice talking to yousLOGOUT successful)r,rˆr´rrÙr=r=rAÚ do_LOGOUTcs  zIMAP4Server.do_LOGOUTcCs| |d¡dS)NsNOOP No operation performed©rˆrÙr=r=rAÚdo_NOOPmrŒzIMAP4Server.do_NOOPcCs>| ¡ ¡}||jvr| |d¡dS| |j|ƒ|¡dS)NsAUTHENTICATE method unsupported)r5rcrùr7Ú authenticate)rZrÚrÓr=r=rAÚdo_AUTHENTICATEus  zIMAP4Server.do_AUTHENTICATEcCs*|jdur | |d¡dS| ||¡dS)Ns Temporary authentication failure)Úportalr7Ú_setupChallenge)rZrþrÚr=r=rAr£~s  zIMAP4Server.authenticatec Csœz| ¡}Wnty%}z| |dtt|ƒƒ¡WYd}~dSd}~wwt|ƒdd…}d|_t ¡|_ |  |¡|j   |j ||¡|j   |j|¡dS)NrLrtrQ)Ú getChallenger+r4r:r…rr*r rSr rTrCÚ_IMAP4Server__cbAuthChunkrÚ_IMAP4Server__ebAuthChunk)rZrþrÚÚ challenger.Úcodedr=r=rAr¦…s &€ÿ  zIMAP4Server._setupChallengecCstzt|ƒ}Wn tjytdƒ‚w| |¡| ¡r$| ||¡dS|j |dt ¡  |j |j |fd|fd¡dS)NzMalformed Response - not base64) rÚbinasciiÚErrorrÚ setResponseÚmoreChallengesr¦r¥ÚloginÚIAccountÚ addCallbacksÚ_IMAP4Server__cbAuthRespÚ_IMAP4Server__ebAuthResp)rZrJrþrÚÚuncodedr=r=rAÚ __cbAuthChunk’s ÿ ÿzIMAP4Server.__cbAuthChunkcCsH|\}}}|tus Jdƒ‚||_d|_||_| |d¡| |j¡dS)Nz(IAccount is the only supported interfaceÚauthsAuthentication successful)r±Úaccountrrrˆr ÚPOSTAUTH_TIMEOUT©rZrJrÚÚifaceÚavatarÚlogoutr=r=rAÚ __cbAuthResp s  zIMAP4Server.__cbAuthRespcCsN| t¡r | |d¡dS| t¡r| |d¡dS| |d¡t |¡dS)Ns#Authentication failed: unauthorizeds+Authentication failed: server misconfigureds'Server error: login failed unexpectedly)rMr r7r r4r4rrNr=r=rAÚ __ebAuthResp©s  ÿ zIMAP4Server.__ebAuthRespcCó| |dtt|jƒƒ¡dS)NsAuthentication failed: )r7r:r…rbrNr=r=rAÚ __ebAuthChunk´óÿzIMAP4Server.__ebAuthChunkcCsŽ|jr | |d¡dS|jr?|jr?| |d¡|j |j¡d|_|j ¡|_d|jvr1t |jd<d|jvr=t |jd<dSdS| |d¡dS)NsTLS already negotiatedsBegin TLS negotiation nowTóLOGINsPLAINsTLS not available) rr7rúrrˆr´ÚstartTLSrùÚcopyrrrÙr=r=rAÚ do_STARTTLS¹s      ÿzIMAP4Server.do_STARTTLScCsBd| ¡vr| |d¡dSt|j||ƒ |j|¡ |j|¡dS)Nrs!LOGIN is disabled before STARTTLS)r r4rÚauthenticateLoginrCÚ_IMAP4Server__cbLoginrÚ_IMAP4Server__ebLogin)rZrÚÚuserÚpasswdr=r=rAÚdo_LOGINÊs  ÿzIMAP4Server.do_LOGINcCs$|jr|j t ||¡dt¡Stƒ‚)a´ Lookup the account associated with the given parameters Override this method to define the desired authentication behavior. The default behavior is to defer authentication to C{self.portal} if it is not None, or to deny the login otherwise. @type user: L{str} @param user: The username to lookup @type passwd: L{str} @param passwd: The password to login with N)r¥r°r ÚUsernamePasswordr±r )rZrÊrËr=r=rArÇÕs ÿzIMAP4Server.authenticateLogincCsb|\}}}|tur| |d¡t d|›d¡dS||_||_| |d¡d|_| |j ¡dS)Ns-Server error: login returned unexpected valuez__cbLogin called with z, IAccount expectedsLOGIN succeededr·) r±r4r4rr¸rrˆrr r¹rºr=r=rAÚ __cbLoginês   zIMAP4Server.__cbLogincCsB| t¡r | |d¡dS| |dtt|jƒƒ¡t |¡dS)Ns LOGIN failedrL) rMr r7r4r:r…rbr4rrNr=r=rAÚ __ebLoginös ÿzIMAP4Server.__ebLogincCs`d}}}t|jdƒ}|dur| ¡}| ¡}| ¡}| dt|||gƒ¡| |d¡dS)Ns NAMESPACE sNAMESPACE command completed)r0r¸ÚgetPersonalNamespacesÚgetSharedNamespacesr,ÚcollapseNestedListsrˆ)rZrÚÚpersonalÚpublicÚsharedÚnpr=r=rAÚ do_NAMESPACEÿs  ÿzIMAP4Server.do_NAMESPACEcCs||jr"|j |¡t|jdƒ}|durt|jƒ tj¡d|_d|_t |ƒ}t|j j t |ƒ|ƒ  |j ||¡ |j||¡dS)Nr·)rrrrrrr4rrÚ _parseMboxr¸ÚselectrCÚ _cbSelectWorkÚ _ebSelectWork)rZrÚÚnameÚrwÚcmdNamerr=r=rAÚ _selectWorks  ÿzIMAP4Server._selectWorkcCs| ||d¡t |¡dS)Ns failed: Server error©r4r4r)rZrOrÞrÚr=r=rArÛszIMAP4Server._ebSelectWorkcCsì|dur | |d¡dSddd„| ¡Dƒvr| |d¡dSdd„| ¡Dƒ}| d| ¡f¡| d| ¡f¡| d d  |¡d ¡| dd | ¡f¡| ¡rYd pZd}|  |¡| |d|d|d¡d|_ ||_ dS)NsNo such mailboxz \noselectcSóg|]}| ¡‘qSr=)Úlower©rCr¹r=r=rArG$óz-IMAP4Server._cbSelectWork..zMailbox cannot be selectedcSóg|]}t|ƒ‘qSr=©r:©rCÚflagr=r=rArG(räó %d EXISTSó %d RECENTóFLAGS (rØrms[UIDVALIDITY %d]rÉrÊó[r„s successfulrÙ) r7ÚgetFlagsr,ÚgetMessageCountÚgetRecentCountr†rˆÚgetUIDValidityÚ isWriteableÚ addListenerrr)rZrrÞrÚr{r¹r=r=rArÚ s     zIMAP4Server._cbSelectWorkr;óSELECTróEXAMINEcCs"| d¡||_|j|_d|_dS)NÚidle)rTÚparseTagr*Ú lastStaterÙr=r=rAÚdo_IDLE:s  zIMAP4Server.do_IDLEcGs"|j|_|`| |jd¡|`dS)NsIDLE terminated)r÷r*rˆrö)rZrÓr=r=rAÚ parse_idle@szIMAP4Server.parse_idlec Csžt|ƒ}z|j |¡}Wn0ty)}z| |tt|ƒƒ¡WYd}~dSd}~wty<| |d¡t   ¡YdSw|rG|  |d¡dS| |d¡dS)Ns/Server error encountered while creating mailboxsMailbox createdsMailbox not created) rØr¸Úcreaterr7r:r…Ú BaseExceptionr4r4rrˆ)rZrÚrÜrJršr=r=rAÚ do_CREATEIs"€ ÿüzIMAP4Server.do_CREATEc Cs¨t|ƒ}| ¡dkr| |d¡dSz|j |¡Wn1ty8}z| |t|ƒ d¡¡WYd}~dSd}~wtyK|  |d¡t   ¡YdSw|  |d¡dS)NÚinboxsYou cannot delete the inboxú imap4-utf-7s/Server error encountered while deleting mailboxsMailbox deleted) rØrâr7r¸Údeleterr…Úencoderûr4r4rrˆ©rZrÚrÜrjr=r=rAÚ do_DELETE]s   $€ ÿüzIMAP4Server.do_DELETEc Csàdd„||fDƒ\}}| ¡dks| ¡dkr| |d¡dSz |j ||¡Wn?ty8| |d¡YdStyT}z| |tt|ƒƒ¡WYd}~dSd}~wt yg| |d¡t   ¡YdSw|  |d¡dS)Ncsó|]}t|ƒVqdSrm)rØ)rCÚnr=r=rAròró€z(IMAP4Server.do_RENAME..rýs@You cannot rename the inbox, or rename another mailbox to inbox.sInvalid command syntaxs/Server error encountered while renaming mailboxsMailbox renamed) râr7r¸Úrenamernr4rr:r…rûr4rrˆ)rZrÚÚoldnameÚnewnamerjr=r=rAÚ do_RENAMEqs(ÿ "€ ÿüzIMAP4Server.do_RENAMEc CóŠt|ƒ}z|j |¡Wn0ty)}z| |tt|ƒƒ¡WYd}~dSd}~wty<| |d¡t   ¡YdSw|  |d¡dS)Ns5Server error encountered while subscribing to mailboxs Subscribed) rØr¸Ú subscriberr7r:r…rûr4r4rrˆrr=r=rAÚ do_SUBSCRIBE‰ó"€ ÿüzIMAP4Server.do_SUBSCRIBEc Cr )Ns9Server error encountered while unsubscribing from mailboxs Unsubscribed) rØr¸Ú unsubscriberr7r:r…rûr4r4rrˆrr=r=rAÚdo_UNSUBSCRIBEšr zIMAP4Server.do_UNSUBSCRIBEcCs<t|ƒ}t|ƒ}t|jj||ƒ |j|||¡ |j|¡dSrm)rØrr¸Ú listMailboxesrCÚ _cbListWorkrÚ _ebListWork)rZrÚÚrefrÚsubrÞr=r=rAÚ _listWork«s  ÿzIMAP4Server._listWorkc Cs||D]1\}}|r|j |¡r3dd„| ¡Dƒ}| ¡ d¡}t|ƒtt|ƒ|| d¡f} | t| ƒ¡q|  ||d¡dS)NcSrår=rærçr=r=rArGµräz+IMAP4Server._cbListWork..rþs completed) r¸Ú isSubscribedríÚgetHierarchicalDelimiterrÚ DontQuoteMeÚmapr,rÒrˆ) rZÚ mailboxesrÚrrÞrÜÚboxr{ÚdelimÚrespr=r=rAr²s ü€zIMAP4Server._cbListWorkcCó| |d¡t |¡dS)Ns1Server error encountered while listing mailboxes.ràrNr=r=rArÀó zIMAP4Server._ebListWorkr¾r¿cCsPg}|D] }| t|ƒ¡qt|ƒ}t|jj|dƒ |j|||¡ |j |¡dSr²) rlr9rØrr¸rÙrCÚ_cbStatusGotMailboxrÚ_ebStatusGotMailbox)rZrÚÚmailboxræÚ nativeNamesrÜr=r=rAÚ do_STATUSÊs ÿzIMAP4Server.do_STATUScCs@|rt|j|ƒ |j|j||fd||fd¡dS| |d¡dS)NsCould not open mailbox)rÚ requestStatusr²Ú_IMAP4Server__cbStatusÚ_IMAP4Server__ebStatusr7)rZrrÚr"rær=r=rAr Õs ú zIMAP4Server._cbStatusGotMailboxcCr©Ns/Server error encountered while opening mailbox.ràrNr=r=rAr!ârzIMAP4Server._ebStatusGotMailboxcCsLtd dd„| ¡Dƒ¡ƒ}| d| d¡d|d¡| |d¡dS) Nú cSsg|]}d|‘qS)z%s %sr=©rCrOr=r=rArGëräz*IMAP4Server.__cbStatus..óSTATUS rþó (rmsSTATUS complete)r:r†rœr,rrˆ)rZÚstatusrÚrr¨r=r=rAÚ __cbStatusés ÿzIMAP4Server.__cbStatuscCs&| |d|dtt|jƒƒ¡dS)Nr+s failed: ©r4r:r…rb)rZrOrÚrr=r=rAÚ __ebStatusñsÿzIMAP4Server.__ebStatuscCs4t|ƒ}t|jj|ƒ |j||||¡ |j|¡dSrm)rØrr¸rÙrCÚ_cbAppendGotMailboxrÚ_ebAppendGotMailbox)rZrÚr"r{r€r…r=r=rAÚ do_APPENDöó  ÿzIMAP4Server.do_APPENDcCsR|s | |d¡dSdd„|Dƒ}| |||¡}| |j||¡| |j|¡dS)NzRYCREATE] No such mailboxcSrår=©r9rçr=r=rArGräz3IMAP4Server._cbAppendGotMailbox..)r7Ú addMessagerCÚ_IMAP4Server__cbAppendrÚ_IMAP4Server__ebAppend)rZrrÚr{r€r…Ú decodedFlagsrèr=r=rAr1üs zIMAP4Server._cbAppendGotMailboxcCrr(ràrNr=r=rAr2rzIMAP4Server._ebAppendGotMailboxcCs$| d| ¡f¡| |d¡dS)NrésAPPEND complete)r,rîrˆ)rZrJrÚrr=r=rAÚ __cbAppend szIMAP4Server.__cbAppendcCrÀ)NsAPPEND failed: r/rNr=r=rAÚ __ebAppendrÂzIMAP4Server.__ebAppendcCs>| ¡}|dur| d|¡dS|j|j|j|f|fddS)N)Ú callbackArgsÚ errbackArgs)Ú checkpointÚ_IMAP4Server__cbCheckr²Ú_IMAP4Server__ebCheck©rZrÚrèr=r=rAÚdo_CHECKs  ÿzIMAP4Server.do_CHECKcCs| |d¡dS)NsCHECK completedr¡©rZrJrÚr=r=rAÚ __cbCheck!rŒzIMAP4Server.__cbCheckcCrÀ)NsCHECK failed: r/rNr=r=rAÚ __ebCheck$ózIMAP4Server.__ebCheckcCódS)ah Called when the client issues a CHECK command. This should perform any checkpoint operations required by the server. It may be a long running operation, but may not block. If it returns a deferred, the client will only be informed of success (or failure) when the deferred's callback (or errback) is invoked. Nr=r^r=r=rAr>'s zIMAP4Server.checkpointcsŒd}|j ¡r t|jjƒ}t|jdƒ‰ˆdur*|dur%| ‡fdd„¡ntˆjƒ}|dur>| |j|j |fd|fd¡dS| d|¡dS)Ncóˆ ¡Srm)r)rJ©rr=rArP9rQz&IMAP4Server.do_CLOSE..) rrñrÚexpungerrCrr²Ú_IMAP4Server__cbCloseÚ_IMAP4Server__ebCloserAr=rIrAÚdo_CLOSE2s     zIMAP4Server.do_CLOSEcCs(| |d¡|j |¡d|_d|_dS)NsCLOSE completedr·)rˆrrrrCr=r=rAÚ __cbCloseCs   zIMAP4Server.__cbClosecCrÀ)NsCLOSE failed: r/rNr=r=rAÚ __ebCloseIrFzIMAP4Server.__ebClosecCsB|j ¡rt|jjƒ |j|j|fd|fd¡dS| |d¡dS)Ns$EXPUNGE ignored on read-only mailbox)rrñrrJr²Ú_IMAP4Server__cbExpungeÚ_IMAP4Server__ebExpunger7rÙr=r=rAÚ do_EXPUNGELs  ÿzIMAP4Server.do_EXPUNGEcCs*|D] }| d|f¡q| |d¡dS)Ns %d EXPUNGEsEXPUNGE completed)r,rˆ)rZrJrÚr.r=r=rAÚ __cbExpungeVszIMAP4Server.__cbExpungecCó(| |dtt|jƒƒ¡t |¡dS)NsEXPUNGE failed: ©r4r:r…rbr4rrNr=r=rAÚ __ebExpunge[óÿzIMAP4Server.__ebExpungecCs|t|jdƒ}|dur!t|j||d |j||j|¡ |j|¡dStdƒ}t|jj ||d |j ||j||¡ |j|¡dS)N©r>s1:*) ÚISearchableMailboxrrrzrCÚ_IMAP4Server__cbSearchrÚ_IMAP4Server__ebSearchrtÚfetchÚ_IMAP4Server__cbManualSearch)rZrÚÚcharsetrrr>Úsmr¹r=r=rAÚ do_SEARCHas  ÿÿzIMAP4Server.do_SEARCHcCsF|rt|j|ƒ}td dd„|Dƒ¡ƒ}| d|¡| |d¡dS)Nr)cSrår=rŠ©rCrcr=r=rArGträz*IMAP4Server.__cbSearch..óSEARCH óSEARCH completed)rÚgetUIDr:r†r,rˆ)rZrJrÚrr>Úidsr=r=rAÚ __cbSearchqs  zIMAP4Server.__cbSearchc Csî|durg}d}|o|dd}|o|dd ¡} tttdƒ|ƒƒD] \}\} } | t |¡| | || ¡rC| d|r>|  ¡n| f¡q#|dkrcddlm } |   d|j t|dd…ƒ|||||¡dS|ro|  d d   |¡¡| |d ¡dS) aL Apply the search filter to a set of messages. Send the response to the client. @type result: L{list} of L{tuple} of (L{int}, provider of L{imap4.IMessage}) @param result: A list two tuples of messages with their sequence ids, sorted by the ids in descending order. @type tag: L{str} @param tag: A command tag. @type mbox: Provider of L{imap4.IMailbox} @param mbox: The searched mailbox. @type query: L{list} @param query: A list representing the parsed form of the search query. @param uid: A flag indicating whether the search is over message sequence numbers or UIDs. @type searchResults: L{list} @param searchResults: The search results so far or L{None} if no results yet. Nrrtr;és%dé©ÚreactorrbrØrc)rdrVÚzipÚrangeÚ _searchFilterrÅÚdeepcopyrlÚtwisted.internetrjÚ callLaterr]r,r†rˆ) rZrJrÚrrrr>Ú searchResultsrcÚlastSequenceIdÚ lastMessageIdÚmsgIdrŠrjr=r=rAÚ__cbManualSearchxs4ÿ€ ø zIMAP4Server.__cbManualSearchcCs"|r| |||||¡s dS|sdS)aÙ Pop search terms from the beginning of C{query} until there are none left and apply them to the given message. @param query: A list representing the parsed form of the search query. @param id: The sequence number of the message being checked. @param msg: The message being checked. @type lastSequenceId: L{int} @param lastSequenceId: The highest sequence number of any message in the mailbox being searched. @type lastMessageId: L{int} @param lastMessageId: The highest UID of any message in the mailbox being searched. @return: Boolean indicating whether all of the query terms match the message. FT©Ú_singleSearchStep)rZrrÚidrŠrrrsr=r=rArm´s ÿüzIMAP4Server._searchFilterc Csº| d¡}t|tƒr| |||||¡sdSdS| ¡}|dd… ¡s,t||ƒ}||vSt|dt|ƒdƒ} | durBt dt|ƒƒ‚||j vrQ| |||||fƒ} n| |||ƒ} | s[dSdS)a— Pop one search term from the beginning of C{query} (possibly more than one element) and return whether it matches the given message. @param query: A list representing the parsed form of the search query. @param msgId: The sequence number of the message being checked. @param msg: The message being checked. @param lastSequenceId: The highest sequence number of any message in the mailbox being searched. @param lastMessageId: The highest UID of any message in the mailbox being searched. @return: Boolean indicating whether the query term matched the message. rFNr;Úsearch_zInvalid search command %sT) r%rUrVrmr5Úisalphartr)r9rÚ_requiresLastMessageInfo) rZrrrtrŠrrrsÚqršÚ messageSetr-rJr=r=rArwÑs(  ë  ÿ  zIMAP4Server._singleSearchStepcCrG)aS Returns C{True} if the message matches the ALL search key (always). @type query: A L{list} of L{str} @param query: A list representing the parsed query string. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} Tr=©rZrrrxrŠr=r=rAÚ search_ALLs zIMAP4Server.search_ALLcCó d| ¡vS)aA Returns C{True} if the message has been answered. @type query: A L{list} of L{str} @param query: A list representing the parsed query string. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} ú \Answered©rír~r=r=rAÚsearch_ANSWEREDs zIMAP4Server.search_ANSWEREDcCó0| dd¡ dd¡}| ¡ | d¡ ¡¡dkS)aR Returns C{True} if the message has a BCC address matching the query. @type query: A L{list} of L{str} @param query: A list whose first element is a BCC L{str} @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} FÚbccÚrrt©Ú getHeadersÚgetrâror%)rZrrrxrŠr…r=r=rAÚ search_BCCs zIMAP4Server.search_BCCcCs&t| d¡ƒ}tj t| ¡ƒ¡|kSr²)Ú parseTimer%ÚemailÚutilsÚ parsedater9ÚgetInternalDate©rZrrrxrŠr€r=r=rAÚ search_BEFORE,szIMAP4Server.search_BEFOREcCó | d¡ ¡}t || ¡d¡S©NrF©r%râr5ÚstrFileÚ getBodyFile©rZrrrxrŠÚbodyr=r=rAÚ search_BODY0szIMAP4Server.search_BODYcCr„)NFÚccr†rrtr‡)rZrrrxrŠršr=r=rAÚ search_CC4ózIMAP4Server.search_CCcCr€©Nz\Deletedr‚r~r=r=rAÚsearch_DELETED8ó zIMAP4Server.search_DELETEDcCr€©Nz\Draftr‚r~r=r=rAÚ search_DRAFT;rŸzIMAP4Server.search_DRAFTcCr€©Nz\Flaggedr‚r~r=r=rAÚsearch_FLAGGED>rŸzIMAP4Server.search_FLAGGEDcCr„)NFÚfromr†rrtr‡)rZrrrxrŠÚfmr=r=rAÚ search_FROMArœzIMAP4Server.search_FROMcCs>| d¡ ¡}| d|¡ |d¡}| ¡ | d¡ ¡¡dkS)NrFr†rt)r%rârˆr‰ro)rZrrrxrŠÚhdrr=r=rAÚ search_HEADEREszIMAP4Server.search_HEADERcCó| d¡dSr“©r%r~r=r=rAÚsearch_KEYWORDJó zIMAP4Server.search_KEYWORDcCst| d¡ƒ| ¡kSr²©rdr%ÚgetSizer~r=r=rAÚ search_LARGERNózIMAP4Server.search_LARGERcCsd| ¡vo d| ¡vS)Nú\Recentú\Seenr‚r~r=r=rAÚ search_NEWQszIMAP4Server.search_NEWcCs|\}}| |||||¡ S)aÊ Returns C{True} if the message does not match the query. @type query: A L{list} of L{str} @param query: A list representing the parsed form of the search query. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} @param msg: The message being checked. @type lastIDs: L{tuple} @param lastIDs: A tuple of (last sequence id, last message id). The I{last sequence id} is an L{int} containing the highest sequence number of a message in the mailbox. The I{last message id} is an L{int} containing the highest UID of a message in the mailbox. rv)rZrrrxrŠÚlastIDsrrrsr=r=rAÚ search_NOTTszIMAP4Server.search_NOTcCó d| ¡vS©Nr±r‚r~r=r=rAÚ search_OLDjrŸzIMAP4Server.search_OLDcCs"t| d¡ƒ}tj | ¡¡|kSr²©r‹r%rŒrrŽrrr=r=rAÚ search_ONmózIMAP4Server.search_ONc Cs4|\}}| |||||¡}| |||||¡}|p|S)aâ Returns C{True} if the message matches any of the first two query items. @type query: A L{list} of L{str} @param query: A list representing the parsed form of the search query. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} @param msg: The message being checked. @type lastIDs: L{tuple} @param lastIDs: A tuple of (last sequence id, last message id). The I{last sequence id} is an L{int} containing the highest sequence number of a message in the mailbox. The I{last message id} is an L{int} containing the highest UID of a message in the mailbox. rv) rZrrrxrŠr´rrrsÚaÚbr=r=rAÚ search_ORqszIMAP4Server.search_ORcCr€r·r‚r~r=r=rAÚ search_RECENTŠrŸzIMAP4Server.search_RECENTcCr€©Nr²r‚r~r=r=rAÚ search_SEENrŸzIMAP4Server.search_SEENcCs2| dd¡ dd¡}tj |¡}|t| d¡ƒkS)aÿ Returns C{True} if the message date is earlier than the query date. @type query: A L{list} of L{str} @param query: A list whose first element starts with a stringified date that is a fragment of an L{imap4.Query()}. The date must be in the format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} Fr€r†r©rˆr‰rŒrrŽr‹r%rr=r=rAÚsearch_SENTBEFOREs zIMAP4Server.search_SENTBEFOREcCsB| dd¡ dd¡}tj |¡}|dd…t| d¡ƒdd…kS)aŸ Returns C{True} if the message date is the same as the query date. @type query: A L{list} of L{str} @param query: A list whose first element starts with a stringified date that is a fragment of an L{imap4.Query()}. The date must be in the format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. @type msg: Provider of L{imap4.IMessage} Fr€r†Nr/rrÂrr=r=rAÚ search_SENTON¢s "zIMAP4Server.search_SENTONcCs2| dd¡ dd¡}tj |¡}|t| d¡ƒkS)až Returns C{True} if the message date is later than the query date. @type query: A L{list} of L{str} @param query: A list whose first element starts with a stringified date that is a fragment of an L{imap4.Query()}. The date must be in the format 'DD-Mon-YYYY', for example '03-March-2003' or '03-Mar-2003'. @type msg: Provider of L{imap4.IMessage} Fr€r†rrÂrr=r=rAÚsearch_SENTSINCE±s zIMAP4Server.search_SENTSINCEcCs"t| d¡ƒ}tj | ¡¡|kSr²r¹rr=r=rAÚ search_SINCEÀr»zIMAP4Server.search_SINCEcCst| d¡ƒ| ¡kSr²r­r~r=r=rAÚsearch_SMALLERÄr°zIMAP4Server.search_SMALLERcCr„)NFÚsubjectr†rrtr‡)rZrrrxrŠÚsubjr=r=rAÚsearch_SUBJECTÇrœzIMAP4Server.search_SUBJECTcCr’r“r”r—r=r=rAÚ search_TEXTËszIMAP4Server.search_TEXTcCr„)NFÚtor†rrtr‡)rZrrrxrŠrÌr=r=rAÚ search_TOÐrœzIMAP4Server.search_TOc Cs(|\}}| d¡}t||ƒ}| ¡|vS)al Returns C{True} if the message UID is in the range defined by the search query. @type query: A L{list} of L{bytes} @param query: A list representing the parsed form of the search query. Its first element should be a L{str} that can be interpreted as a sequence range, for example '2:4,5:*'. @type id: L{int} @param id: The sequence number of the message being checked. @type msg: Provider of L{imap4.IMessage} @param msg: The message being checked. @type lastIDs: L{tuple} @param lastIDs: A tuple of (last sequence id, last message id). The I{last sequence id} is an L{int} containing the highest sequence number of a message in the mailbox. The I{last message id} is an L{int} containing the highest UID of a message in the mailbox. r)r%rtrd) rZrrrxrŠr´rrrsršrjr=r=rAÚ search_UIDÔs   zIMAP4Server.search_UIDcCr¶)Nrr‚r~r=r=rAÚsearch_UNANSWEREDïrŸzIMAP4Server.search_UNANSWEREDcCr¶rr‚r~r=r=rAÚsearch_UNDELETEDòrŸzIMAP4Server.search_UNDELETEDcCr¶r r‚r~r=r=rAÚsearch_UNDRAFTõrŸzIMAP4Server.search_UNDRAFTcCr¶r¢r‚r~r=r=rAÚsearch_UNFLAGGEDørŸzIMAP4Server.search_UNFLAGGEDcCr©r“rªr~r=r=rAÚsearch_UNKEYWORDûr¬zIMAP4Server.search_UNKEYWORDcCr¶rÀr‚r~r=r=rAÚ search_UNSEENÿrŸzIMAP4Server.search_UNSEENcCrT)NsSEARCH failed: rUrNr=r=rAÚ __ebSearchrWzIMAP4Server.__ebSearchcCsT|r"| d¡|_t|jj||d t¡ |j|||¡ |j |¡dS|  |d¡dS)NrXsFETCH complete) r Ú _oldTimeoutrrr\rCÚiterÚ_IMAP4Server__cbFetchrÚ_IMAP4Server__ebFetchrˆ)rZrÚÚmessagesrrr>r=r=rAÚdo_FETCHs ÿÿzIMAP4Server.do_FETCHcsŒˆjdurgˆ_ztˆƒ\}}Wnty,ˆ ˆj¡ˆ`ˆ ˆd¡ˆ ¡YdSwˆ ||ˆˆ¡ ‡‡‡‡‡fdd„¡  ˆj ¡dS)NsFETCH completedcsˆ ˆˆˆˆ¡Srm)rØ©rA©rrÚresultsrZrÚr>r=rArP4sz'IMAP4Server.__cbFetch..) r#ÚnextÚ StopIterationr rÖrˆr'Ú spewMessagerCrÚ_IMAP4Server__ebSpewMessage)rZrÞrÚrrr>rxrŠr=rÝrAÚ __cbFetchs    éÿzIMAP4Server.__cbFetchcCst |¡|j ¡dSrm)r4rr´r©rZrOr=r=rAÚ__ebSpewMessage7s zIMAP4Server.__ebSpewMessagecCs*|dur|jj}|dtt|ƒgƒƒdS)Ns ENVELOPE )r´r¤rÒÚ getEnvelope©rZrxrŠÚ_wÚ_fr=r=rAÚ spew_envelope?szIMAP4Server.spew_envelopecCs<|dur|jj}dd„| ¡Dƒ}|dd |¡dƒdS)NcSrår=rærçr=r=rArGGräz*IMAP4Server.spew_flags..rërØrm)r´Úwritenrír†)rZrxrŠrèréÚ encodedFlagsr=r=rAÚ spew_flagsDszIMAP4Server.spew_flagsc Csì|dur|jj}| ¡}tj t|ƒ¡}|dur&t d|||f¡t dƒ‚t   d|dd…¡}t |t |dfƒ}|ddurF|d}n&|ddkrOd} nd } || d t|dƒd d t|dƒd d f}|dt|ƒƒdS)Nz$%d:%r: unpareseable internaldate: %rz(Internal failure generating INTERNALDATEz%d-%%s-%Y %H:%M:%S é r;s+0000rr•ó-s%04diédrôs INTERNALDATE )r´r¤rrŒrÚ parsedate_tzr9r4rŠrÚtimeÚstrftimer:Ú _MONTH_NAMESÚabsÚ_quote) rZrxrŠrèréÚidateÚttupÚstrdateÚodateÚsignr=r=rAÚspew_internaldateJs.   ÿ(ÿþÿzIMAP4Server.spew_internaldatecCs2|dur|jj}t| d¡ƒ}|dt|ƒƒdS)NTsRFC822.HEADER )r´r¤Ú_formatHeadersrˆÚ_literal)rZrxrŠrèréÚhdrsr=r=rAÚspew_rfc822headereszIMAP4Server.spew_rfc822headercCs2|dur|jj}|dƒ|ƒt| ¡ƒ |j¡S)Ns RFC822.TEXT )r´r¤Ú FileProducerr–ÚbeginProducingrçr=r=rAÚspew_rfc822textks zIMAP4Server.spew_rfc822textcCó&|dur|jj}|d| ¡fƒdS)NsRFC822.SIZE %d)r´r¤r®rçr=r=rAÚspew_rfc822sizerózIMAP4Server.spew_rfc822sizecCsZ|dur|jj}|dƒ|ƒt|dƒ}|dur"t| ¡ƒ |j¡St|d|jƒ |j¡S)NsRFC822 )r´r¤Ú IMessageFilerÚopenrÚMessageProducerrü)rZrxrŠrèréÚmfr=r=rAÚ spew_rfc822ws ÿzIMAP4Server.spew_rfc822cCr)NsUID %d)r´r¤rdrçr=r=rAÚspew_uidƒrzIMAP4Server.spew_uidcCs|dtt|dƒgƒƒdS)NsBODYSTRUCTURE T)rÒÚgetBodyStructurerçr=r=rAÚspew_bodystructureˆszIMAP4Server.spew_bodystructurec Csp|dur|jj}|jD]}| ¡r| |¡}q |dkrtdƒ‚q |jrB|j|jjg|jj ¢RŽ}t |ƒ}||  ¡dt |ƒƒdS|j rZ||  ¡dƒ|ƒt| ¡ƒ |j¡S|jrrt | d¡ƒ}||  ¡dt |ƒƒdS|jr«||  ¡dƒ|ƒ|jrt| ¡ƒ |j¡St|dƒ}|dur t| ¡ƒ |j¡St|d|jƒ |j¡S|dtt|ƒgƒƒdS)Nrz*Requested subpart of non-multipart messagerØTsBODY )r´r¤ÚpartÚ isMultipartÚ getSubPartrnÚheaderrˆÚnegateÚfieldsrýÚ __bytes__rþr5rr–rÚmimeÚemptyrrr rürÒr ) rZrrxrŠrèrér‡rÿr r=r=rAÚ spew_body‹s>  ý ÿzIMAP4Server.spew_bodyc sftˆjƒ}|j‰ |j‰‡‡ fdd„‰‡ fdd„‰‡ fdd„‰‡‡‡‡‡‡‡‡‡‡ f dd„}ˆ |ƒ¡S) NcsˆdˆfƒdS)Ns * %d FETCH (r=r=)rxr¤r=rAr[¶rz&IMAP4Server.spewMessage..startcó ˆdƒdS)Ns) r=r=©r¤r=rAré¹rŸz'IMAP4Server.spewMessage..finishcrr×r=r=rr=rAÚspace¼rŸz&IMAP4Server.spewMessage..spacec3s¦d}ˆƒˆD]2}|jdkrd}|jdkr!ˆ |ˆˆˆ ˆ¡Vntˆd|jƒ}|ˆˆˆ ˆƒV|ˆdur:ˆƒqˆrK|sKˆƒˆ ˆˆˆ ˆ¡VˆƒˆƒdS)NFr>Tr˜Úspew_rt)Útyperr)r )ÚseenUIDrr-© rér·rxrŠrrrZrr[r>r¤r=rAÚspew¿s$€   € z%IMAP4Server.spewMessage..spew)r°r´r¤r·rü)rZrxrŠrrr>Úwbufr r=rrArá±s    zIMAP4Server.spewMessagecCs8| |j¡|`t |¡| |dtt|jƒƒ¡dS)NsFETCH failed: )r rÖr4rr4r:r…rbrNr=r=rAÚ __ebFetchÔs  zIMAP4Server.__ebFetchcCs~| ¡}| d¡}| d¡rd}n | d¡rd}nd}dd„|Dƒ}t|jj||||d  |j|j||j||fd|fd¡dS) NsSILENTr•r;rïrtrcSrår=r5rçr=r=rArGäräz(IMAP4Server.do_STORE..rX) r5Úendswithr~rrÚstorer²Ú_IMAP4Server__cbStoreÚ_IMAP4Server__ebStore)rZrÚrÚÚmoder{r>Úsilentr=r=rAÚdo_STOREÚs     úzIMAP4Server.do_STOREc Csl|r.|s.| ¡D]%\}}|rd| |¡f}nd}dd„|Dƒ} | d|d | ¡|f¡q| |d¡dS)Ns UID %dr cSrår=rærçr=r=rArGøräz)IMAP4Server.__cbStore..s%d FETCH (FLAGS (%b)%b)rØsSTORE completed)rœrdr,r†rˆ) rZrJrÚrr>r(ÚkržÚuidstrr{r=r=rAÚ __cbStoreðsÿzIMAP4Server.__cbStorecCrÀ©NrLr/rNr=r=rAÚ __ebStoreþrFzIMAP4Server.__ebStorecCs4t|ƒ}t|jj|ƒ |j||||¡ |j|¡dSrm)rØrr¸rÙrCÚ_cbCopySelectedMailboxrÚ_ebCopySelectedMailbox)rZrÚrÚr"r>r=r=rAÚdo_COPY r4zIMAP4Server.do_COPYcCsN|s | |d|¡dSt|jj||ƒ |j||¡ |j||¡ |j|¡dS)NzNo such mailbox: ) r7rrr\rCÚ_IMAP4Server__cbCopyÚ_IMAP4Server__cbCopiedrÚ_IMAP4Server__ebCopy)rZrrÚrÚr"r>r=r=rAr/ s ÿz"IMAP4Server._cbCopySelectedMailboxcCrÀr-r/rNr=r=rAr0 rFz"IMAP4Server._ebCopySelectedMailboxcsÈg}tˆdƒ}|D]U\}}|durt|j|ƒ}| |¡q | ¡} | ¡} t|dƒ} | dur;|  ¡} tˆj| | | ƒ}ndd„‰t   ¡} t || |j ƒ  d¡ | | | f‡‡fdd„ ¡}| |¡q t |¡S)NcSs| d¡|Sr²)r¯©r-r=r=rAÚrewind+ r¬z$IMAP4Server.__cbCopy..rewindcsˆ ˆ|ƒ||¡Srm)r6)rAr½r-rè©rr6r=rArP4 s ÿz&IMAP4Server.__cbCopy..)ÚIMessageCopierrrÅrlrírrrr6r­r®r rürrCr Ú DeferredList)rZrÚrÚrÚaddedDeferredsÚ fastCopyMboxrxrŠrèr{r€r˜ÚbodyFileÚbufferr=r7rAÚ__cbCopy s.      ÿý zIMAP4Server.__cbCopycCsVg}g}|D]\}}|r| |¡q| |j¡q|r#| |d¡dS| |d¡dS)Nz%[ALERT] Some messages were not copiedsCOPY completed)rlrbr7rˆ)rZÚ deferredIdsrÚrreÚfailuresr-rJr=r=rAÚ __cbCopied< s  zIMAP4Server.__cbCopiedcCrT)Ns COPY failed:rUrNr=r=rAÚ__ebCopyI szIMAP4Server.__ebCopycCs.| ¡}|dvr t|ƒ‚|j|||dddS)N)óCOPYrÅóSTORErÁr;rX)r5rr6)rZrÚrÒr¨r=r=rAÚdo_UIDM szIMAP4Server.do_UIDcCs(|r |jddddS|jddddS)Ns [READ-WRITE]T)r…r’s [READ-ONLY]©r,©rZÚ writeabler=r=rAÚ modeChangedZ szIMAP4Server.modeChangedcCsD| ¡D]\}}dd„|Dƒ}d|d |¡f}|j|ddqdS)NcSrår=rærçr=r=rArGb räz,IMAP4Server.flagsChanged..s%d FETCH (FLAGS (%b))rØT©r’)rœr†r,)rZÚnewFlagsÚmIdr{rìrŠr=r=rAÚ flagsChanged` s ýzIMAP4Server.flagsChangedcCs@|dur|jd|fdd|dur|jd|fdddSdS)NréTrJrêrF©rZÚexistsÚrecentr=r=rAÚ newMessagesf s ÿzIMAP4Server.newMessages©NNNrm©F©Nr )r”©rr])çrr‘r’r“r‡r r¹rrr r¥r¸rrr rRrùr{rr*r]r rrrr"r#r'r$r:r;r6r<r=rDrErWrXr[rZÚreÚcompileÚescapeÚ _atomCharsrgrkrprqrsrurxr|r}rrrƒrr4rˆr7r,rTrŽr†rŸÚunauth_CAPABILITYÚauth_CAPABILITYÚselect_CAPABILITYÚlogout_CAPABILITYr Ú unauth_LOGOUTÚ auth_LOGOUTÚ select_LOGOUTÚ logout_LOGOUTr¢Ú unauth_NOOPÚ auth_NOOPÚ select_NOOPÚ logout_NOOPr¤Úunauth_AUTHENTICATEr£r¦r¨r³r´r©rÆÚunauth_STARTTLSrÌÚ unauth_LOGINrÇrÈrÉr×Úauth_NAMESPACEÚselect_NAMESPACErßrÛrÚÚ auth_SELECTÚ select_SELECTÚ auth_EXAMINEÚselect_EXAMINErørùÚ select_IDLEÚ auth_IDLErüÚ auth_CREATEÚ select_CREATErÚ auth_DELETEÚ select_DELETEr Ú auth_RENAMEÚ select_RENAMEr Úauth_SUBSCRIBEÚselect_SUBSCRIBErÚauth_UNSUBSCRIBEÚselect_UNSUBSCRIBErrrÚ auth_LISTÚ select_LISTÚ auth_LSUBÚ select_LSUBr$r r!Ú auth_STATUSÚ select_STATUSr&r'r3r1r2Ú auth_APPENDÚ select_APPENDr7r8rBÚ select_CHECKr?r@r>rMÚ select_CLOSErKrLrRÚselect_EXPUNGErPrQr`Ú select_SEARCHrZr]rmrwrrƒ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Ôr[rÛÚ select_FETCHrØrârêrírürrrr r rrrárÙr)Ú select_STOREr%r&r1Ú select_COPYr/r0r2r3r4rEÚ select_UIDrIrMrQr=r=r=rAróUsÆ         /ÿ                             <0             "  & #        (    róc@sJeZdZdZdZdZdZdZdZdZ dZ dZ dZ dZ dZeeedœZdZdºd d „Zd d „Zd d„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd „Zd!d"„Zd#d$„Zd%d&„Z d'd(„Z!d)d*„Z"d+d,„Z#d»d-d.„Z$d/d0„Z%d1d2„Z&d3d4„Z'd5d6„Z(d7d8„Z)dºd9d:„Z*d;d<„Z+d=d>„Z,d?d@„Z-dAdB„Z.dCdD„Z/dEdF„Z0dGdH„Z1dIdJ„Z2dKdL„Z3dMdN„Z4dOdP„Z5dQdR„Z6dSdT„Z7dUdV„Z8dWdX„Z9dYdZ„Z:d[d\„Z;d]d^„Zdcdd„Z?dedf„Z@dgdh„ZAdidj„ZBdkdl„ZCdmdn„doDƒZDdpdq„ZEdrds„ZFd¼dudv„ZGdwdx„ZHdydz„ZId{d|„ZJd}d~„ZKdd€„ZLdd‚„ZMddƒœd„d…„ZNd†d‡„ZOd½dˆd‰„ZPd½dŠd‹„ZQd½dŒd„ZRd½dŽd„ZSd½dd‘„ZTd½d’d“„ZUd½d”d•„ZVd½d–d—„ZWd½d˜d™„ZXd½dšd›„ZYd½dœd„ZZd½dždŸ„Z[d½d d¡„Z\d¢d£„Z]d¤d¥„Z^       d¾d¦d§„Z_d½d¨d©„Z`d¿dªd«„Zad¿d¬d­„Zbd¿d®d¯„Zcd°d±„Zdd²d³„Zed´dµ„Zfd¶d·„Zgd¸d¹„ZhdS)ÀÚ IMAP4ClientzIMAP4 client protocol implementation @ivar state: A string representing the state the connection is currently in. Nr;Frr«)ÚOKÚNOÚBADÚPREAUTHÚBYE)ÚMESSAGESÚRECENTÚUNSEENcCs.i|_g|_i|_||_d|_d|_d|_dSrm)r ÚqueuedÚauthenticatorsÚcontextÚ_tagÚ_partsÚ_lastCmd)rZrÿr=r=rAr]• s zIMAP4Client.__init__cCs||j| ¡ ¡<dS)a» Register a new form of authentication When invoking the authenticate() method of IMAP4Client, the first matching authentication scheme found will be used. The ordering is that in which the server lists support authentication schemes. @type auth: Implementor of C{IClientAuthentication} @param auth: The object to use to perform the client side of this authentication scheme. N)r•ÚgetNamer5)rZr·r=r=rAÚregisterAuthenticatorŸ s z!IMAP4Client.registerAuthenticatorcCs¸|jdkr | ¡|jt|ƒ8_|jdkr|j |¡dSd}|jdkr5|d|j…||jd…}}|j |¡|j}d|_d|_| dd¡|j |  ¡¡|  |  d¡¡dS)Nrr ó ) rrÚ _pendingSizer¡Ú_pendingBufferr¤r¯r˜rlÚreadr!Úlstrip)rZršr£r8r=r=rAr"­ s     zIMAP4Client.rawDataReceivedcCsD| |¡|_||_|jdur|dg|_n|j |dg¡| ¡dS)Nrœ)Ú messageFileržrr˜rrrU)rZr8Úoctetsr=r=rAÚ_setupForLiteralÄ s    zIMAP4Client._setupForLiteralcCs|jdkr | |j¡dSdSr²)rr r^r=r=rArÍ s ÿzIMAP4Client.connectionMadecCsŠ|jdkr | d¡|jdur |j}d|_|D]}|j |¡q|jdurA|j}d|_| ¡D]}|dur@|jdur@|j |¡q/dSdS)z, We are no longer connected rN)rr r”r Úerrbackr Úvalues)rZrr”r9r r=r=rArÑ s      €ûzIMAP4Client.connectionLostcCsð|jdkr | ¡| d¡}|dkrN||dd…}| d¡rNz t|dd…ƒ}Wn ty4t|ƒ‚w|jdurD| dd¡\|_ }n|}|  ||¡dS|jdurZ|  |¡dS|j  |¡|j d  |j¡}}d|_ |_| ||¡dS)aF Attempt to parse a single line from the server. @type line: L{bytes} @param line: The line from the server, without the line delimiter. @raise IllegalServerResponse: If the line or some part of the line does not represent an allowed message from the server at this time. rr_rtr;Nr`r )rrÚrfindr#rdr`rr˜r3r—r£Ú_regularDispatchrlr†r6)rZr¨ÚlastPartr¢ÚpartsrÚr8r=r=rAr$ã s,    ÿ     zIMAP4Client.lineReceivedcCsp|jr|jjdur|jjd}|j_| t¡|jr1|jD]}|jdur0|j|}|_| t¡q|j ¡dSrm)r™r r¤Ú TIMEOUT_ERRORr”r´r)rZrèr9r=r=rAr s    €zIMAP4Client.timeoutConnectioncCs:| dd¡}t|ƒdkr| d¡|\}}| ||¡dS)Nr;rÛr )r3r¡rlr6)rZr¨r©rÚr8r=r=rAr§ s   zIMAP4Client._regularDispatchcCs||jkr t ¡StƒS)a8 Create a file to which an incoming message may be written. @type octets: L{int} @param octets: The number of octets which will be written to the file @rtype: Any object which implements C{write(string)} and C{seek(int, int)} @return: A file-like object )r¬r­r®r)rZr¢r=r=rAr¡! s zIMAP4Client.messageFilecCs"d|j d¡}|jd7_|S)Nz%0.4XÚasciir;)ÚtagIDrrÙr=r=rAÚmakeTag1 szIMAP4Client.makeTagcCs|jdur |j}n t|d|j ¡dƒ}|r2z|||ƒWdSty1t ¡|j ¡YdSwt d|j›d|›d|›¡|j ¡dS)NÚ response_zCannot dispatch: z, ) rÚresponse_UNAUTHr)r5rûr4rr´r)rZrÚr8r-r=r=rAr66 s  þzIMAP4Client.dispatchCommandcCsÊ|jdur]| dd¡\}}| ¡dkrd|_n| ¡dkr!d|_n |j ¡t|d|ƒ‚| d¡| d¡}}|d krV|d krV| | t ||d|…ƒgdf¡¡dS| d¡dS|  ||¡dS) Nr;rÜrøsPREAUTHr·rØrìó]rt) rr3r5r´rrroÚserverGreetingÚ_IMAP4Client__cbCapabilitiesrÝÚ_defaultHandler)rZrÚr8r-r½r.r=r=rAr¯E s    ÿzIMAP4Client.response_UNAUTHcCs| ||¡dSrm)r³)rZrÚr8r=r=rAÚ response_AUTH\ rŒzIMAP4Client.response_AUTHcCsæ|dks|dkr.|js| t|ƒg¡dS|j|j}|dkr&| |¡dS|j |¡dSz|j|}WntyI|j  ¡t |d|ƒ‚w|  dd¡\}}|dkr^|  ||j¡n|j  t|ƒ¡|j|=d|_| ¡dS)Nr—r•rØr;rÜ)ÚwaitingÚ _extraInforÝr rÐrÕrlÚKeyErrorr´rrr3rér r¤rÚ _flushQueue)rZrÚr8r9r-r¨r=r=rAr³_ s(   ý zIMAP4Client._defaultHandlercCsB|jr|j d¡}| ¡}||j|<| | |¡¡||_dSdSr²)r”r%r­r rrÖrµ©rZr9Útr=r=rAr¸{ s   ûzIMAP4Client._flushQueuec Cs6i}d}}|D]y}t|ƒ}|dkr|ddgkr| d¡q|dkr0|ddgkr0| d¡q|dkrA|ddkrAt|dƒ}q|dkrR|dd krRt|dƒ}q|d kry|dd kryt|dƒ}| |d¡\}} | |g¡ | d d ¡¡qt d|›¡q|r‰|  |¡|dus‘|dur™|  ||¡dSdS)Nr;rrÊFrÉTrÛrÃrÆr/rÅÚFLAGSr=z Unhandled unsolicited response: ) r¡rIrdÚ_parseFetchPairsÚ setdefaultrrr‰r4rŠrMrQ) rZrÕr{rPrOÚresponseÚelementsrLr¥rAr=r=rAr¶ƒ s,    ÿzIMAP4Client._extraInfocCsVt ¡|_|jr|j |¡|jS| ¡}||j|<| | |¡¡||_||_ |jSrm) r rSrµr”rlr­r rrÖr™r¹r=r=rAÚ sendCommandŸ s   zIMAP4Client.sendCommandcCsD|r |jdur t |j¡Sd}d}| t||d¡}| |j¡|S)av Request the capabilities available on this server. This command is allowed in any state of connection. @type useCache: C{bool} @param useCache: Specify whether to use the capability-cache or to re-retrieve the capabilities from the server. Server capabilities should never change, so for normal use, this flag should never be false. @rtype: L{Deferred} @return: A deferred whose callback will be invoked with a dictionary mapping capability types to lists of supported mechanisms, or to None if a support list is not applicable. Nr¼)r¼©rÔ)Ú _capCacher ÚsucceedrÀr»rCr²)rZÚuseCacher9rrèr=r=rAÚgetCapabilities« s  zIMAP4Client.getCapabilitiesc Cs”|\}}i}|D],}|dd…D]#}| dd¡}t|ƒdkr&|dd}} n|\}} | |g¡ | ¡qq|D] }||dgkrDd||<q7||_|S)Nr;r˜r)r3r¡r½rlrÂ) rZrJrÕÚtaglinerr8rr©Úcategoryrbr=r=rAÚ__cbCapabilitiesÄ s   ú €zIMAP4Client.__cbCapabilitiescCs"| tddd¡}| |j¡|S)a* Inform the server that we are done with the connection. This command is allowed in any state of connection. @rtype: L{Deferred} @return: A deferred whose callback will be invoked with None when the proper server acknowledgement has been received. sLOGOUT)sBYErÁ)rÀr»rCÚ_IMAP4Client__cbLogout©rZrèr=r=rAr½Ù s zIMAP4Client.logoutcCs|\}}|j ¡dSrm)r´r©rZrJrÕrÆr=r=rAÚ __cbLogoutç s zIMAP4Client.__cbLogoutcCs| tdƒ¡}| |j¡|S)a Perform no operation. This command is allowed in any state of connection. @rtype: L{Deferred} @return: A deferred whose callback will be invoked with a list of untagged status updates the server responds with. sNOOP)rÀr»rCÚ_IMAP4Client__cbNooprÊr=r=rAÚnoopí s zIMAP4Client.noopcCs |\}}|Srmr=rËr=r=rAÚ__cbNoopû szIMAP4Client.__cbNoopcs¢ˆjrJdƒ‚|durˆ ¡}|durt tdƒ¡Sdˆjvr&t tdƒ¡St ˆjd¡}|dur8t tdƒ¡Sˆ  t dƒ¡}|  ˆj |¡|  ‡fdd„¡|S) a: Initiates a 'STARTTLS' request and negotiates the TLS / SSL Handshake. @param contextFactory: The TLS / SSL Context Factory to leverage. If the contextFactory is None the IMAP4Client will either use the current TLS / SSL Context Factory or attempt to create a new one. @type contextFactory: C{ssl.ClientContextFactory} @return: A Deferred which fires when the transport has been secured according to the given contextFactory, or which fails if the transport cannot be secured. z5Client and Server are currently communicating via TLSNzEIMAP4Client requires a TLS context to initiate the STARTTLS handshakerz:Server does not support secure communication via TLS / SSLzAIMAP4Client transport does not implement interfaces.ITLSTransportcrHrm©rÅrÜr^r=rArP1 rQz&IMAP4Client.startTLS..) rÚ_getContextFactoryr ÚfailrrÂrr r´rÀr»rCÚ _startedTLS)rZrÿÚtlsrèr=r^rArÄ s:ÿþÿÿ ÿÿÿÿzIMAP4Client.startTLScCs2|jdur | ¡}nt |j¡}| |j|¡|S)a2 Attempt to enter the authenticated state with the server This command is allowed in the Non-Authenticated state. @rtype: L{Deferred} @return: A deferred whose callback is invoked if the authentication succeeds and whose errback will be invoked otherwise. N)rÂrÅr rÃrCÚ_IMAP4Client__cbAuthenticate)rZÚsecretrèr=r=rAr£4 s  zIMAP4Client.authenticatecs¦| dd¡‰ˆD]}| ¡ˆjvr"td|dˆj||ƒ}ˆ |¡Sqˆjr1t t ˆˆj  ¡ƒ¡S‡‡fdd„}ˆ  ¡}|  |¡|  ‡fdd„¡|  ˆj|¡|S)Nrr=ó AUTHENTICATEcs | t¡t tˆˆj ¡ƒ¡Srm)Útraprr rÒr#r•r)r©ÚauthsrZr=rAÚ ebStartTLST s ÿz0IMAP4Client.__cbAuthenticate..ebStartTLScrHrmrÐrÜr^r=rArP] rQz.IMAP4Client.__cbAuthenticate..)r‰r5r•r»Ú_IMAP4Client__cbContinueAuthrÀrr rÒr#rrÄrrCÚ_IMAP4Client__cbAuthTLS)rZrrÖÚschemer9rÛrèr=rÙrAÚ__cbAuthenticateE s$ ÿüÿ zIMAP4Client.__cbAuthenticatecCs`zt|dƒ}Wntjy| d¡t|ƒ‚w|j|}| ||¡}| t|ƒ ¡¡dS)Nó r—) rr¬r­rrr•ÚchallengeResponserrc)rZr8rÞrÖrþr·r=r=rAÚ__cbContinueAutha s þ  zIMAP4Client.__cbContinueAuthcCsV| dd¡}|D]}| ¡|jvr"td|d|j||ƒ}| |¡Sqt||j ¡ƒ‚)Nrr=r×)r‰r5r•r»rÜrÀr#r)rZrrÖrÚrÞr9r=r=rAÚ __cbAuthTLSl s ÿüzIMAP4Client.__cbAuthTLScCst|jƒ}| |j||¡|S)aÆ Authenticate with the server using a username and password This command is allowed in the Non-Authenticated state. If the server supports the STARTTLS capability and our transport supports TLS, TLS is negotiated before the login command is issued. A more secure way to log in is to use C{startTLS} or C{authenticate} or both. @type username: L{str} @param username: The username to log in with @type password: L{str} @param password: The password to log in with @rtype: L{Deferred} @return: A deferred whose callback is invoked if login is successful and whose errback is invoked otherwise. )rrÅrCÚ_IMAP4Client__cbLoginCaps)rZÚusernameÚpasswordrèr=r=rAr°v s zIMAP4Client.logincCrG)z¦ Called when the server has sent us a greeting. @type caps: C{dict} @param caps: Capabilities the server advertised in its greeting. Nr=)rZrr=r=rAr± ózIMAP4Client.serverGreetingcCsL|jdur|jSzddlm}Wn tyYdSw| ¡}|jj|_|S)Nr)Ússl)r–rorèÚ ImportErrorÚClientContextFactoryÚSSLÚ TLSv1_METHODÚmethod)rZrèr–r=r=rArÑ— s  ÿ zIMAP4Client._getContextFactoryc Cs–d|v}t |jd¡du}t |jd¡du}|js1|r1|r1|r1| ¡}|j|j|j||fd|S|r8t   d¡d  t |ƒt |ƒf¡}|  td|ƒ¡S)Nr)r<z5Server has no TLS support. logging in over cleartext!rØrÃ)rr r´rrrÄr²Ú_IMAP4Client__cbLoginTLSÚ_IMAP4Client__ebLoginTLSr4rŠr†rörÀr») rZr råræÚtryTLSÚtlsableTransportÚnontlsTransportrèrÓr=r=rAÚ __cbLoginCaps£ sý zIMAP4Client.__cbLoginCapscCs|j |¡d|_d|_|S)NT)r´rÄrÂr)rZrJr–r=r=rArÓ¼ s zIMAP4Client._startedTLScCs&d t|ƒt|ƒf¡}| td|ƒ¡S)NrØrÃ)r†rörÀr»)rZrJrårærÓr=r=rAÚ __cbLoginTLS szIMAP4Client.__cbLoginTLScCst |¡|Srm)r4rrär=r=rAÚ __ebLoginTLSÆ r¬zIMAP4Client.__ebLoginTLScCó*d}d}| t||d¡}| |j¡|S)að Retrieve information about the namespaces available to this account This command is allowed in the Authenticated and Selected states. @rtype: L{Deferred} @return: A deferred whose callback is invoked with namespace information. An example of this information is:: [[['', '/']], [], []] which indicates a single personal namespace called '' with '/' as its hierarchical delimiter, and no shared or user namespaces. rÂ)rÂrÁ)rÀr»rCÚ_IMAP4Client__cbNamespace©rZr9rrèr=r=rAÚ namespaceÊ ó  zIMAP4Client.namespacecsd|\}}dd„‰|D]}t|ƒdkr'|ddkr'‡fdd„|dd…DƒSq t d ¡ggggS) NcSsdd„|DƒS)NcSóg|]}| d¡‘qS)rþ)Údecode)rCÚelementr=r=rArGí rÑzSIMAP4Client.__cbNamespace.._prepareNamespaceOrDelimiter..r=)Ú namespaceListr=r=rAÚ_prepareNamespaceOrDelimiterì óz?IMAP4Client.__cbNamespace.._prepareNamespaceOrDelimiterrhrrÂcs*g|]}|dur gn‡fdd„|Dƒ‘qS)Ncóg|]}ˆ|ƒ‘qSr=r=)rCrb©rÿr=rArGô räz8IMAP4Client.__cbNamespace...r=)rCÚ pairOrNonerr=rArGñ s þÿýz-IMAP4Client.__cbNamespace..r;z*No NAMESPACE response to NAMESPACE command)r¡r4r)rZrJrÕr_r©r=rrAÚ __cbNamespaceß s    ü€  zIMAP4Client.__cbNamespacecCó6d}t|ƒ}d}| t|||d¡}| |jd¡|S)a· Select a mailbox This command is allowed in the Authenticated and Selected states. @type mailbox: L{str} @param mailbox: The name of the mailbox to select @rtype: L{Deferred} @return: A deferred whose callback is invoked with mailbox information if the select is successful and whose errback is invoked otherwise. Mailbox information consists of a dictionary with the following L{str} keys and values:: FLAGS: A list of strings containing the flags settable on messages in this mailbox. EXISTS: An integer indicating the number of messages in this mailbox. RECENT: An integer indicating the number of "recent" messages in this mailbox. UNSEEN: The message sequence number (an integer) of the first unseen message in the mailbox. PERMANENTFLAGS: A list of strings containing the flags that can be permanently set on messages in this mailbox. UIDVALIDITY: An integer uniquely identifying this mailbox. ró)r»ÚEXISTSr’r“ÚPERMANENTFLAGSÚ UIDVALIDITYrÁr;©Ú_prepareMailboxNamerÀr»rCÚ_IMAP4Client__cbSelect©rZr"r9rÓrrèr=r=rArÙú s  zIMAP4Client.selectcCr)a³ Select a mailbox in read-only mode This command is allowed in the Authenticated and Selected states. @type mailbox: L{str} @param mailbox: The name of the mailbox to examine @rtype: L{Deferred} @return: A deferred whose callback is invoked with mailbox information if the examine is successful and whose errback is invoked otherwise. Mailbox information consists of a dictionary with the following keys and values:: 'FLAGS': A list of strings containing the flags settable on messages in this mailbox. 'EXISTS': An integer indicating the number of messages in this mailbox. 'RECENT': An integer indicating the number of "recent" messages in this mailbox. 'UNSEEN': An integer indicating the number of messages not flagged \Seen in this mailbox. 'PERMANENTFLAGS': A list of strings containing the flags that can be permanently set on messages in this mailbox. 'UIDVALIDITY': An integer uniquely identifying this mailbox. rô)r½rÃrÆrÈrÌrÇrÁrr r r=r=rAÚexamine# s  zIMAP4Client.examinecCs"zt|ƒWStyt|ƒ‚w)zÀ Parse C{value} as an integer and return the result or raise L{IllegalServerResponse} with C{phrase} as an argument if C{value} cannot be parsed as an integer. )rdr`r)rZrbÚphraser=r=rAÚ _intOrRaiseQ s   ÿzIMAP4Client._intOrRaisec Csê|\}}d|i}| t|ƒ¡|D]á}t|ƒdkr|d ¡dkr|d}t|tƒr/|d}n|}| ¡}|dkr>d|d<q|dkrGd|d<q|d krV| |d|¡|d <q|d kre| |d|¡|d <q|d krt| |d|¡|d<q|dkr†tdd„|dDƒƒ|d<qt  d|›¡qt|ƒdkrê|d ¡dkr«tdd„|dDƒƒ|d<qt|dt ƒrá|d ¡dkrÅ| |d|¡|d<q|d ¡dkrØ| |d|¡|d<qt  d|›¡qt  d|›¡qt  d|›¡q|S)zy Handle lines received in response to a SELECT or EXAMINE command. See RFC 3501, section 6.3.1. z READ-WRITErrÜr;rÊFrÉTrÇrrÈr“rËÚUIDNEXTrÌcsrrmr5rçr=r=rArò| s€ ÿz)IMAP4Client.__cbSelect..rzUnhandled SELECT response (2): rÛr½csrrmr5rçr=r=rArò„ rr»rÃrrÆr’zUnhandled SELECT response (0): zUnhandled SELECT response (1): zUnhandled SELECT response (4): ) rlrÝr¡r5rUrVrÚtupler4rÚbytes) rZrJrÝrÕrÆÚdatumr3Úcontentrgr=r=rAÚ __cbSelect\ sJ    ÿ zIMAP4Client.__cbSelectcCó| tdt|ƒƒ¡S)a| Create a new mailbox on the server This command is allowed in the Authenticated and Selected states. @type name: L{str} @param name: The name of the mailbox to create. @rtype: L{Deferred} @return: A deferred whose callback is invoked if the mailbox creation is successful and whose errback is invoked otherwise. sCREATE©rÀr»r ©rZrÜr=r=rArú• ó zIMAP4Client.createcCr)ak Delete a mailbox This command is allowed in the Authenticated and Selected states. @type name: L{str} @param name: The name of the mailbox to delete. @rtype: L{Deferred} @return: A deferred whose calblack is invoked if the mailbox is deleted successfully and whose errback is invoked otherwise. sDELETErrr=r=rArÿ¤ rzIMAP4Client.deletecCs*t|ƒ}t|ƒ}| tdd ||f¡ƒ¡S)aÇ Rename a mailbox This command is allowed in the Authenticated and Selected states. @type oldname: L{str} @param oldname: The current name of the mailbox to rename. @type newname: L{str} @param newname: The new name to give the mailbox. @rtype: L{Deferred} @return: A deferred whose callback is invoked if the rename is successful and whose errback is invoked otherwise. sRENAMErØ)r rÀr»r†)rZrrr=r=rAr³ szIMAP4Client.renamecCr)a‰ Add a mailbox to the subscription list This command is allowed in the Authenticated and Selected states. @type name: L{str} @param name: The mailbox to mark as 'active' or 'subscribed' @rtype: L{Deferred} @return: A deferred whose callback is invoked if the subscription is successful and whose errback is invoked otherwise. s SUBSCRIBErrr=r=rAr Ç rzIMAP4Client.subscribecCr)a{ Remove a mailbox from the subscription list This command is allowed in the Authenticated and Selected states. @type name: L{str} @param name: The mailbox to unsubscribe @rtype: L{Deferred} @return: A deferred whose callback is invoked if the unsubscription is successful and whose errback is invoked otherwise. s UNSUBSCRIBErrr=r=rArÖ rzIMAP4Client.unsubscribecCsFd}d|›d|›d d¡}d}| t|||d¡}| |jd¡|S)ap List a subset of the available mailboxes This command is allowed in the Authenticated and Selected states. @type reference: L{str} @param reference: The context in which to interpret C{wildcard} @type wildcard: L{str} @param wildcard: The pattern of mailbox names to match, optionally including either or both of the '*' and '%' wildcards. '*' will match zero or more characters and cross hierarchical boundaries. '%' will also match zero or more characters, but is limited to a single hierarchical level. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a list of L{tuple}s, the first element of which is a L{tuple} of mailbox flags, the second element of which is the hierarchy delimiter for this mailbox, and the third of which is the mailbox name; if the command is unsuccessful, the deferred's errback is invoked instead. B{NB}: the delimiter and the mailbox name are L{str}s. r¾ú"z" "rþ)r¾rÁ)rrÀr»rCÚ_IMAP4Client__cbList)rZÚ referenceÚwildcardr9rÓrrèr=r=rArVå s zIMAP4Client.listc CsVd}| d¡}| d¡}d d|d|dg¡}d}| t|||d¡}| |jd¡|S) aa List a subset of the subscribed available mailboxes This command is allowed in the Authenticated and Selected states. The parameters and returned object are the same as for the L{list} method, with one slight difference: Only mailboxes which have been subscribed can be included in the resulting list. r¿r«rþr r^s" ")r¿rÁ)rr†rÀr»rCr) rZrrr9ÚencodedReferenceÚencodedWildcardrÓrrèr=r=rAÚlsub s  ûÿ zIMAP4Client.lsubcCs†|\}}g}|D]8}t|ƒdkr@|d|kr@tdd„|dDƒƒ|d<|d d¡|d<|d d¡|d<| t|dd…ƒ¡q|S) Nrhrcsrrmr5rçr=r=rArò+ rz'IMAP4Client.__cbList..r;rÛrþr/)r¡rrürl)rZrJrÒrÕr_rÞr©r=r=rAÚ__cbList$ s €zIMAP4Client.__cbListcCsi|]}|| d¡“qS)r«©r©rCrÜr=r=rAÚ ? s ÿÿzIMAP4Client.©r‘r’rrr“csŽd}t|ƒ}zd ‡fdd„|Dƒ¡}Wnty)tdt|ƒtˆjƒ›ƒ‚wd |d|dg¡}d }ˆ t|||d ¡}| ˆj ¡|S) a7 Retrieve the status of the given mailbox This command is allowed in the Authenticated and Selected states. @type mailbox: L{str} @param mailbox: The name of the mailbox to query @type names: L{bytes} @param names: The status names to query. These may be any number of: C{'MESSAGES'}, C{'RECENT'}, C{'UIDNEXT'}, C{'UIDVALIDITY'}, and C{'UNSEEN'}. @rtype: L{Deferred} @return: A deferred which fires with the status information if the command is successful and whose errback is invoked otherwise. The status information is in the form of a C{dict}. Each element of C{names} is a key in the dictionary. The value for each key is the corresponding response from the server. rÀrØc3s|]}ˆj|VqdSrm)Ú _statusNamesr#r^r=rAròc s€z%IMAP4Client.status..zUnknown names: r r,rm)rÀrÁ) r r†r·r`Úsetr&rÀr»rCÚ_IMAP4Client__cbStatus)rZr"rær9ÚpreparedMailboxrÓrrèr=r^rAr-J s ÿ zIMAP4Client.statusc sô|\}}i}|D]7}|ddkr?|d‰‡fdd„tdtˆƒdƒDƒ‰ˆD]\}}z||t|ƒ<Wq%ty>ttˆƒƒ‚wq| ¡D]3}|j |¡}|rwz |||ƒ||<WqDt yv} ztd|d||dt | ƒƒ‚d} ~ wwqD|S) NrrÀrÛcsg|] }ˆ||d…‘qS)rÛr=ra©rœr=rArGs óz*IMAP4Client.__cbStatus..ú(r)z): ) rlr¡r9ÚUnicodeDecodeErrorrrFrÚSTATUS_TRANSFORMATIONSr‰r+r…) rZrJrÕr_r-r©r*ržrºr.r=r*rAr.m s4    ÿ€  ÿ€ÿýzIMAP4Client.__cbStatusr=c Cs~| dd¡| ¡}| dd¡|rtdt|ƒƒ}nd}dd„|Dƒ}dt|ƒd |¡||f}| td |d |j|ƒ¡}|S) aÆ Add the given message to the given mailbox. This command is allowed in the Authenticated and Selected states. @type mailbox: L{str} @param mailbox: The mailbox to which to add this message. @type message: Any file-like object opened in B{binary mode}. @param message: The message to add, in RFC822 format. Newlines in this file should be \r\n-style. @type flags: Any iterable of L{str} @param flags: The flags to associated with this message. @type date: L{str} @param date: The date to associate with this message. This should be of the format DD-MM-YYYY HH:MM:SS +/-HHMM. For example, in Eastern Standard Time, on July 1st 2004 at half past 1 PM, "01-07-2004 13:30:00 -0500". @rtype: L{Deferred} @return: A deferred whose callback is invoked when this command succeeds or whose errback is invoked if it fails. rrÛz "%s"r cSrår=rærçr=r=rArG¦ räz&IMAP4Client.append..s%b (%b)%b {%d}rØsAPPENDr=) r¯Útellr:r9r r†rÀr»Ú_IMAP4Client__cbContinueAppend) rZr"r…r{r€rårìr9rèr=r=rArl„ s"  üÿzIMAP4Client.appendcCs t ¡}| ||jd¡ |j¡Srm)r2Ú FileSenderÚbeginFileTransferr´rCÚ_IMAP4Client__cbFinishAppend)rZrÕr…r¹r=r=rAÚ__cbContinueAppend´ sÿzIMAP4Client.__cbContinueAppendcCs| d¡dSrTr–)rZÚfoor=r=rAÚ__cbFinishAppendº rzIMAP4Client.__cbFinishAppendcCó| tdƒ¡S)a Tell the server to perform a checkpoint This command is allowed in the Selected state. @rtype: L{Deferred} @return: A deferred whose callback is invoked when this command succeeds or whose errback is invoked if it fails. sCHECK©rÀr»r^r=r=rArM½ s zIMAP4Client.checkcCr7)aý Return the connection to the Authenticated state. This command is allowed in the Selected state. Issuing this command will also remove all messages flagged \Deleted from the selected mailbox if it is opened in read-write mode, otherwise it indicates success by no messages are removed. @rtype: L{Deferred} @return: A deferred whose callback is invoked when the command completes successfully or whose errback is invoked if it fails. sCLOSEr8r^r=r=rArÉ szIMAP4Client.closecCrö)aý Return the connection to the Authenticate state. This command is allowed in the Selected state. Issuing this command will perform the same actions as issuing the close command, but will also generate an 'expunge' response for every message deleted. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a list of the 'expunge' responses when this command is successful or whose errback is invoked otherwise. rÄ)rÄrÁ)rÀr»rCÚ_IMAP4Client__cbExpungerør=r=rArJÙ rúzIMAP4Client.expungecCsH|\}}g}|D]}t|ƒdkr!|ddkr!| | |d|¡¡q|S)NrÛr;rÄr)r¡rlr)rZrJrÕr_rer©r=r=rArSî s€zIMAP4Client.__cbExpungerXcGsJdd„|Dƒ}|r dnd}d |¡}| t|||fd¡}| |j¡|S)a„ Search messages in the currently selected mailbox This command is allowed in the Selected state. Any non-zero number of queries are accepted by this method, as returned by the C{Query}, C{Or}, and C{Not} functions. @param uid: if true, the server is asked to return message UIDs instead of message sequence numbers. @type uid: L{bool} @rtype: L{Deferred} @return: A deferred whose callback will be invoked with a list of all the message sequence numbers return by the search, or whose errback will be invoked if there is an error. cSrû)rír")rCrrr=r=rArG rÑz&IMAP4Client.search..s UID SEARCHrÁrØrÁ)r†rÀr»rCÚ_IMAP4Client__cbSearch)rZr>Úqueriesr9rÓrèr=r=rArzö s    zIMAP4Client.searchcsT|\}}g}|D]‰tˆƒdkr'ˆddkr'| ‡‡fdd„ˆdd…Dƒ¡q|S)NrrÁcsg|]}ˆ |ˆ¡‘qSr=)r©rCr‡©r©rZr=rArGr›z*IMAP4Client.__cbSearch..r;)r¡rr)rZrJrÕr\rer=r=rArfs"€zIMAP4Client.__cbSearchcCó|j||ddS)aV Retrieve the unique identifier for one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message sequence numbers to unique message identifiers, or whose errback is invoked if there is an error. r;)ÚuseUIDr>©Ú_fetch©rZrÚr>r=r=rAÚfetchUIDózIMAP4Client.fetchUIDcCr>)aH Retrieve the flags for one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: The messages for which to retrieve flags. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to lists of flags, or whose errback is invoked if there is an error. r;)r?r{r@rBr=r=rAÚ fetchFlags.rDzIMAP4Client.fetchFlagscCr>)a¯ Retrieve the internal date associated with one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: The messages for which to retrieve the internal date. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to date strings, or whose errback is invoked if there is an error. Date strings take the format of "day-month-year time timezone". r;)r?Ú internaldater@rBr=r=rAÚfetchInternalDateBszIMAP4Client.fetchInternalDatecCr>)a– Retrieve the envelope data for one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: The messages for which to retrieve envelope data. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to envelope data, or whose errback is invoked if there is an error. Envelope data consists of a sequence of the date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, and message-id header fields. The date, subject, in-reply-to, and message-id fields are L{str}, while the from, sender, reply-to, to, cc, and bcc fields contain address data as L{str}s. Address data consists of a sequence of name, source route, mailbox name, and hostname. Fields which are not present for a particular address may be L{None}. r;)r?Úenveloper@rBr=r=rAÚ fetchEnvelopeWózIMAP4Client.fetchEnvelopecCr>)aÐ Retrieve the structure of the body of one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: The messages for which to retrieve body structure data. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to body structure data, or whose errback is invoked if there is an error. Body structure data describes the MIME-IMB format of a message and consists of a sequence of mime type, mime subtype, parameters, content id, description, encoding, and size. The fields following the size field are variable: if the mime type/subtype is message/rfc822, the contained message's envelope information, body structure data, and number of lines of text; if the mime type is text, the number of lines of text. Extension fields may also be included; if present, they are: the MD5 hash of the body, body disposition, body language. r;)r?Ú bodystructurer@rBr=r=rAÚfetchBodyStructuretrJzIMAP4Client.fetchBodyStructurecCr>)aÉ Retrieve the simplified body structure of one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: C{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to body data, or whose errback is invoked if there is an error. The simplified body structure is the same as the body structure, except that extension fields will never be present. r;)r?r˜r@rBr=r=rAÚfetchSimplifiedBody‘szIMAP4Client.fetchSimplifiedBodycCr>)a) Retrieve one or more entire messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: C{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A L{Deferred} which will fire with a C{dict} mapping message sequence numbers to C{dict}s giving message data for the corresponding message. If C{uid} is true, the inner dictionaries have a C{'UID'} key mapped to a L{str} giving the UID for the message. The text of the message is a L{str} associated with the C{'RFC822'} key in each dictionary. r;)r?Úrfc822r@rBr=r=rAÚ fetchMessage§szIMAP4Client.fetchMessagecCr>)a< Retrieve headers of one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to dicts of message headers, or whose errback is invoked if there is an error. r;)r?Ú rfc822headerr@rBr=r=rAÚ fetchHeaders¿rDzIMAP4Client.fetchHeaderscCr>)aL Retrieve body text of one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to file-like objects containing body text, or whose errback is invoked if there is an error. r;)r?Ú rfc822textr@rBr=r=rAÚ fetchBodyÓrDzIMAP4Client.fetchBodycCr>)a6 Retrieve the size, in octets, of one or more messages This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to sizes, or whose errback is invoked if there is an error. r;)r?Ú rfc822sizer@rBr=r=rAÚ fetchSizeçrDzIMAP4Client.fetchSizec Cs|j||ddddddS)aV Retrieve several different fields of one or more messages This command is allowed in the Selected state. This is equivalent to issuing all of the C{fetchFlags}, C{fetchInternalDate}, C{fetchSize}, C{fetchEnvelope}, and C{fetchSimplifiedBody} functions. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to dict of the retrieved data values, or whose errback is invoked if there is an error. They dictionary keys are "flags", "date", "size", "envelope", and "body". r;)r?r{rFrTrHr˜r@rBr=r=rAÚ fetchFullûsùzIMAP4Client.fetchFullcCs|j||dddddS)a. Retrieve several different fields of one or more messages This command is allowed in the Selected state. This is equivalent to issuing all of the C{fetchFlags}, C{fetchInternalDate}, C{fetchSize}, and C{fetchEnvelope} functions. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to dict of the retrieved data values, or whose errback is invoked if there is an error. They dictionary keys are "flags", "date", "size", and "envelope". r;)r?r{rFrTrHr@rBr=r=rAÚfetchAlls ÿzIMAP4Client.fetchAllcCs|j||ddddS)a Retrieve several different fields of one or more messages This command is allowed in the Selected state. This is equivalent to issuing all of the C{fetchFlags}, C{fetchInternalDate}, and C{fetchSize} functions. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a dict mapping message numbers to dict of the retrieved data values, or whose errback is invoked if there is an error. They dictionary keys are "flags", "date", and "size". r;)r?r{rFrTr@rBr=r=rAÚ fetchFast4szIMAP4Client.fetchFastc sú‡fdd„‰i}g}t|ƒ} zt|ƒ}Wn ty!Y||fSwzt|ƒ}Wn ty4td|ƒ‚w|dvr.nativeStringResponse..)rUrrürV)ÚthingrZr=rAr[qs   ÿz:IMAP4Client._parseFetchPairs..nativeStringResponseTsNot enough arguments)óBODYs BODY.PEEKFrÛrcSrår=r5©rCržr=r=rArG¸räz0IMAP4Client._parseFetchPairs..cSrår=r5r^r=r=rArG¾rär;ó<ó>rt)r×rßràrrUrVr¡r9rlrr~r#rdr`) rZÚfetchResponseListr¥Ú unstructuredÚ responsePartsrgrbÚ hasSectionÚ valueHeadÚ valueTailr=rZrAr¼Ks~ &  `Ÿ   ÿ        ÿÿ þ    ÿÿ žzIMAP4Client._parseFetchPairscCs„|\}}i}|D]-}t|ƒdkr5|ddkr5| |d|¡}||vr*|dg||<q||d |d¡qi} i} | ¡D]"\} } | | d¡\} }|  | gg¡d |¡|  | i¡ | ¡q>| }i}t|  ¡ƒD]I} | | } t|  ¡ƒD]<}||vr³|dkr³| d|| <t t|| dƒƒD]}|| d|dkrª|| d||d…=nq‘| d=| s³| | =qwqk|r¼|  |¡|rÀ| S|S)Nr/r;rÅrrÛr») r¡rrrrœr¼r½ÚupdaterVrrlrM)rZrJÚrequestedPartsÚ structuredrÕr_Úinfor©rxrÞÚ decodedInfoÚ messageIdr¥Ú structuredMapÚunstructuredListÚ flagChangesrrcr=r=rAÚ_cbFetchásJ€ þ€ö zIMAP4Client._cbFetchc Csød} |dur d} nt|tƒrt|ƒ} nd tt|ƒ¡} |dur"d} n | r)d|} n|} | r@|dvr@|dur=dd |¡} nd} nd} |durId} nd ||f} |rSd pTd }| ||r[d p\d| | | | f}| d ¡}| t||dd¡}| |j dd¡|S)a^ Retrieve a specific section of one or more messages @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @type headerType: L{str} @param headerType: If specified, must be one of HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, or TEXT, and will determine which part of the message is retrieved. For HEADER.FIELDS and HEADER.FIELDS.NOT, C{headerArgs} must be a sequence of header names. For MIME, C{headerNumber} must be specified. @type headerNumber: L{int} or L{int} sequence @param headerNumber: The nested rfc822 index specifying the entity to retrieve. For example, C{1} retrieves the first entity of the message, and C{(2, 1, 3}) retrieves the 3rd entity inside the first entity inside the second entity of the message. @type headerArgs: A sequence of L{str} @param headerArgs: If C{headerType} is HEADER.FIELDS, these are the headers to retrieve. If it is HEADER.FIELDS.NOT, these are the headers to exclude from retrieval. @type peek: C{bool} @param peek: If true, cause the server to not set the \Seen flag on this message as a result of this command. @type offset: L{int} @param offset: The number of octets at the beginning of the result to skip. @type length: L{int} @param length: The number of octets to retrieve. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a mapping of message numbers to retrieved data, or whose errback is invoked if there is an error. z%s BODY%s[%s%s%s]%sNr†Ú.)z HEADER.FIELDSzHEADER.FIELDS.NOTz (%s)r)z ()z<%d.%d>ó UID FETCHrÅz.PEEKrí©rÅrÁr=F) rUrdr…r†rrrÀr»rCrp)rZrÚr>Ú headerTypeÚ headerNumberÚ headerArgsÚpeekÚoffsetÚlengthÚfmtÚnumberrÚpayloadÚextrar\r9rèr=r=rAÚ fetchSpecific s27       zIMAP4Client.fetchSpecificcKsÀt|ƒ d¡}|r dp d}d|vr|d=d|d<d|vr#|d=d|d<d |vr.|d =d|d <d d „|Dƒ}|d d dd „|Dƒ¡d}| t||dd¡}| |jdd „| ¡Dƒd¡|S)Nr«rrrÅrRTú rfc822.textrTú rfc822.sizerPú rfc822.headercSrår=rærãr=r=rArGvräz&IMAP4Client._fetch..r,rØcSrár=©r5rãr=r=rArGwrärmrsrÁcSrár=r‚)rCrºr=r=rArGzrä)r…rr†rÀr»rCrpr)rZrÚr?Útermsr\Ú encodedTermsr9rèr=r=rArAes   zIMAP4Client._fetchcCó| |d|||¡S)a  Set the flags for one or more messages. This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type flags: Any iterable of L{str} @param flags: The flags to set @type silent: L{bool} @param silent: If true, cause the server to suppress its verbose response. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a list of the server's responses (C{[]} if C{silent} is true) or whose errback is invoked if there is an error. r½©Ú_store©rZrÚr{r(r>r=r=rAÚsetFlags}ózIMAP4Client.setFlagscCr…)a Add to the set flags for one or more messages. This command is allowed in the Selected state. @type messages: C{MessageSet} or L{str} @param messages: A message sequence set @type flags: Any iterable of L{str} @param flags: The flags to set @type silent: C{bool} @param silent: If true, cause the server to suppress its verbose response. @type uid: C{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a list of the server's responses (C{[]} if C{silent} is true) or whose errback is invoked if there is an error. s+FLAGSr†rˆr=r=rAÚaddFlags˜rŠzIMAP4Client.addFlagscCr…)a Remove from the set flags for one or more messages. This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type flags: Any iterable of L{str} @param flags: The flags to set @type silent: L{bool} @param silent: If true, cause the server to suppress its verbose response. @type uid: L{bool} @param uid: Indicates whether the message sequence set is of message numbers or of unique message IDs. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a list of the server's responses (C{[]} if C{silent} is true) or whose errback is invoked if there is an error. s-FLAGSr†rˆr=r=rAÚ removeFlags³rŠzIMAP4Client.removeFlagsc Cs†t|ƒ d¡}dd„|Dƒ}|r|d}|rdpd}d ||dd |¡d f¡}| t||d d ¡} d } |s9d } |  |j| d¡| S)Nr«cSrår=rærçr=r=rArGÐräz&IMAP4Client._store..s.SILENTs UID STORErDrØrlrmrsrÁr=)r»T)r…rr†rÀr»rCrp) rZrÚr9r(r{r>rìr$rÓrèÚexpectedr=r=rAr‡Îs zIMAP4Client._storecCs>t|ƒ d¡}|r d}nd}d |t|ƒg¡}| t||ƒ¡S)a” Copy the specified messages to the specified mailbox. This command is allowed in the Selected state. @type messages: L{MessageSet} or L{str} @param messages: A message sequence set @type mailbox: L{str} @param mailbox: The mailbox to which to copy the messages @type uid: C{bool} @param uid: If true, the C{messages} refers to message UIDs, rather than message sequence numbers. @rtype: L{Deferred} @return: A deferred whose callback is invoked with a true value when the copy is successful, or whose errback is invoked if there is an error. r«sUID COPYrCrØ)r…rr†r rÀr»)rZrÚr"r>r9rÓr=r=rArÅÜs zIMAP4Client.copycCrG©z Override meNr=rGr=r=rArIürçzIMAP4Client.modeChangedcCrGrŽr=)rZrKr=r=rArMÿrçzIMAP4Client.flagsChangedcCrGrŽr=rNr=r=rArQrçzIMAP4Client.newMessagesrm©r;)r=NrU)rNNNNNN)r;r)irr‘r’r“r rµr”r¬rrrrÂr¬r•Ú STATUS_CODESrdr.r–r]r›r"r£rrr$rr§r¡r­r6r¯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 rr rúrÿrr rrVr rr&r-r(rlr0r3rMrrJr9rzr:rCrErGrIrLrMrOrQrSrUrVrWrXr¼rpr~rAr‰r‹rŒr‡rÅrIrMrQr=r=r=rAr‹p sà    *   3   ). 9#þ # 0             - ÷ Z     r‹c Cs6tƒ}| d¡}|D]Ž}d|vrl| dd¡\}}zH|dkr d}nt|ƒ}|dkr+d}nt|ƒ}||ur.cSstd |¡ƒSrT)r½r†rÄr=r=rArPcscSsd dd„|Dƒ¡gS)Nr cSsg|]}|d‘qSrUr=rar=r=rArGdräz5collapseStrings....)r†rÄr=r=rArPdrÑ)rr;)rarUrVrrrÃrlÚcollapseStrings)rÞrÅÚbegunÚpredÚtranrcršr=r=rArÅQs$ þ €rÅc CsÊ| ¡}d}gg}zÀd}t|ƒ}||krÈ|||d…}|rG|dkr4|d |||d…¡|d7}q|dkr;| }|d |¡|d7}n}|dkrZ|d |¡| }|d7}nj|r‘|dkr‘| d|¡}|dkrntd ƒ‚t||d|…ƒ}|d ||d |d |…f¡|d |}n3|d ks™|d kr£| g¡|d7}n!|d ks«|dkr¹|d | ¡¡|d7}n |d |¡|d7}||ksWn tyÔt|ƒ‚wt|ƒdkrßt|ƒ‚t |dƒS)ak Parse an s-exp-like string into a more useful data structure. @type s: L{bytes} @param s: The s-exp-like string to parse @rtype: L{list} of L{bytes} and L{list} @return: A list containing the tokens present in the input. @raise MismatchedNesting: Raised if the number or placement of opening or closing parenthesis is invalid. rr;ryrtrÛr^r_r`rar/rlrìrmr°éþÿÿÿ) rcr¡rlror`rdr%Ú IndexErrorrrÅ) r¹Ú handleLiteralr·Ú contentStackrcråršr\Ú literalSizer=r=rArÝssX     $   ဠÿ  rÝcCs8td|ƒ}td|ƒ}|| |||¡ |||¡|S)Nrr²)r7r¯)r¹r¹rºr=r=rArö­s  $rör¹r‚cCsdt|ƒ|fS)Ns{%d} %b)r¡©r¹r=r=rArþ³rŒrþc@s"eZdZdd„Zdefdd„ZdS)rcCó ||_dSrm)rb)rZrbr=r=rAr]¸ó zDontQuoteMe.__init__r‚cCs t|jƒSrm)r…rbr^r=r=rArˆ»rÐzDontQuoteMe.__str__N)rr‘r’r]r…rˆr=r=r=rAr·srs(){ %*"cCsB|dkrdSt|ƒD]}|dks|dkrdS|tvrdSq dS)Nr r;rØór)r8Ú_ATOM_SPECIALS)r¹ršr=r=rAÚ _needsQuoteÂs ÿrÓcCs:t|tƒr|Sz| d¡WStyt ¡t|ƒ‚w)Nrþ)rUr…rürûr4rr©rÜr=r=rArØÍs   þrØcCs2t|tƒs | d¡}| d¡}t|ƒrt|ƒS|S)Nrírþ)rUr…rürrÓrörÔr=r=rAr ×s   r cCs0td|ƒ}td|ƒ}||vp||vpt|ƒdkS)NÚ ú iè)r7r¡)r¹ÚcrÚlfr=r=rAÚ _needsLiteralàs  rÙcCsg}|D]€}t|tƒr| d¡}|dur| ddg¡qt|tƒr-| dtt|ƒƒg¡qt|tƒr;| d|jg¡qt|tƒr^t |ƒrT| ddt |ƒft j |g¡q| dt |ƒg¡qt|dƒrw| ¡}| ddt |ƒft j |g¡q| ddt|ƒdg¡qd  |d d…¡S) a° Turn a nested list structure into an s-exp-like string. Strings in C{items} will be sent as literals if they contain CR or LF, otherwise they will be quoted. References to None in C{items} will be translated to the atom NIL. Objects with a 'read' attribute will have it called on them with no arguments and the returned string will be inserted into the output as a literal. Integers will be converted to strings and inserted into the output unquoted. Instances of C{DontQuoteMe} will be converted to strings and inserted into the output unquoted. This function used to be much nicer, and only quote things that really needed to be quoted (and C{DontQuoteMe} did not exist), however, many broken IMAP4 clients were unable to deal with this level of sophistication, forcing the current behavior to be adopted for practical reasons. @type items: Any iterable @rtype: L{str} r«NrØsNILs{%d}rŸrlrmr r;)rUr…rrrrdr:rrbrrÙr¡róÚ delimiterröÚhasattrrŸrÒr†)rœÚpiecesrcrèr=r=rArÒçs&        rÒc@s„eZdZdZdZdZdd„Zdd„Zddd„Zd d „Z d d „Z ddd„Z dd„Z dd„Z dd„Zdd„Zdd„Zdd„Zdd„ZdS) ÚMemoryAccountWithoutNamespacesNrcCs||_i|_g|_dSrm)rÜrÚ subscriptionsrr=r=rAr]rz'MemoryAccountWithoutNamespaces.__init__cCs|j}|jd7_|SrM)Útop_id)rZrxr=r=rAÚ allocateID#sz)MemoryAccountWithoutNamespaces.allocateIDcCsDt| ¡ƒ}||jvrt|ƒ‚|dur| || ¡¡}||j|<dSrM)rØr5rrÚ _emptyMailboxrà)rZrÜrr=r=rAÚ addMailbox+s   z)MemoryAccountWithoutNamespaces.addMailboxc Cs’dd„| d¡Dƒ}tdt|ƒƒD]}z| d |d|…¡¡Wqty*Yqwz | d |¡¡WdStyH| d¡sEYdSYdSw)NcSsg|]}|r|‘qSr=r=)rCÚpathr=r=rArG5räz9MemoryAccountWithoutNamespaces.create..ú/r;FT)r3rlr¡râr†rr#)rZÚpathspecÚpathsÚaccumr=r=rArú4s  ÿ ý ÿýz%MemoryAccountWithoutNamespaces.createcCst‚rm)ÚNotImplementedError)rZrÜrxr=r=rAráBóz,MemoryAccountWithoutNamespaces._emptyMailboxr;cCs|j t| ¡ƒ¡Srm)rr‰rØr5)rZrÜÚ readwriter=r=rArÙEsz%MemoryAccountWithoutNamespaces.selectcCst| ¡ƒ}|j |¡}|stdƒ‚d| ¡vr-|j ¡D]}||kr,| |¡r,tdƒ‚q| ¡t |  |¡ƒdkrBtd|›dƒ‚|j|=dS)NzNo such mailboxz \Noselectz.)rØr5rr"rìr)rZrrÚ inferiorsÚoldÚnewr=rïrAr_s      ÿ  þz%MemoryAccountWithoutNamespaces.renamecCs,g}|j ¡D] }| |¡r| |¡q|Srm)rrr~rl)rZrÜrñÚinfnamer=r=rArìps   €z-MemoryAccountWithoutNamespaces._inferiorNamescCst| ¡ƒ|jvSrm)rØr5rÞrr=r=rArwrz+MemoryAccountWithoutNamespaces.isSubscribedcCs*t| ¡ƒ}||jvr|j |¡dSdSrm)rØr5rÞrlrr=r=rAr zs  ÿz(MemoryAccountWithoutNamespaces.subscribecCs4t| ¡ƒ}||jvrtd|›ƒ‚|j |¡dS)NzNot currently subscribed to )rØr5rÞrÚremoverr=r=rArs  z*MemoryAccountWithoutNamespaces.unsubscribecs0ˆ t| ¡ƒ¡}tˆdƒ‰‡‡fdd„|DƒS)Nräcs$g|]}ˆ |¡r|ˆj|f‘qSr=)rhrra©rZrr=rArGˆs$z@MemoryAccountWithoutNamespaces.listMailboxes..)rìrØr5r±)rZrrr=rörAr…s z,MemoryAccountWithoutNamespaces.listMailboxesrmr)rr‘r’rrÞrßr]ràrârúrárÙrÿrrìrr rrr=r=r=rArÝs"    rÝc@s,eZdZdd„Zdd„Zdd„Zdd„Zd S) Ú MemoryAccountcCs ddggS)Nr ó/r=r^r=r=rArÐrÐz#MemoryAccount.getPersonalNamespacescCódSrmr=r^r=r=rArÑ“réz!MemoryAccount.getSharedNamespacescCrùrmr=r^r=r=rAÚgetOtherNamespaces–réz MemoryAccount.getOtherNamespacescCrùrmr=r^r=r=rAÚgetUserNamespaces™szMemoryAccount.getUserNamespacesN)rr‘r’rÐrÑrúrûr=r=r=rAr÷‹s  r÷rîrïÚ getUIDNextrðÚgetUnseenCountr%cCs*i}|D]}t|t| ¡ƒƒ||<q|Srm)r)Ú_statusRequestDictr5)rræÚrrr=r=rAÚstatusRequestHelper§srcCs*|durdgStj |g¡}dd„|DƒS)NrRcSs&g|]\}}|p ddg| d¡‘qS)Nú@©r3)rCr?Úaddressr=r=rArG´s&zparseAddr..)rŒrÚ getaddresses)Úaddrr=r=rAÚ parseAddr®s ÿrc Cs²| d¡}| d¡}| d¡}| d¡}| d|¡}| d|¡}| d¡}| d¡}| d ¡} | d ¡} | d ¡} ||t|ƒt|ƒ|oFt|ƒ|oKt|ƒ|oPt|ƒ| oUt| ƒ| | f S) NTr€rÈr¤Úsenderzreply-torÌršr…z in-reply-toz message-id)rˆr‰r) rŠÚheadersr€rÈÚfrom_rÚreply_torÌršr…Ú in_reply_toÚmidr=r=rAræ·s,               öræcCsd}| ¡D]}|d7}q|Sr¾)r–)rŠrÕrAr=r=rAÚ getLineCountÑs  r cCs2|d|dkrdkrn|S|dd…S|S)Nrrtrr;r=rÎr=r=rAÚunquoteÚs ÿrcCs”d}| dd¡ dd¡}d | ¡¡}|rA| d¡}|d dd¡}t|ƒdkr/|d}d}n|\}}td d „|dd…Dƒƒ}nd}}|||fS) zJ Return a two-tuple of the main and subtype of the given message. NFú content-typer†ú;rrär;css$|] }| ¡ ¡ dd¡VqdS)ú=r;N)rcrâr3r*r=r=rAròðs€"z"_getContentType..)rˆr‰r†Ú splitlinesr3r¡Údict)rŠÚattrsÚmmÚmimetyperÚmajorÚminorr=r=rAÚ_getContentTypeàs   rcCs€t|ƒ\}}}|dur| ¡}|dur| ¡}|dkr!t|||ƒS||fdkr.t||||ƒS|dkr9t||||ƒSt||||ƒS)aE Construct an appropriate type of message structure object for the given message object. @param message: A L{IMessagePart} provider @return: A L{_MessageStructure} instance of the most specific type available for the given message, determined by inspecting the MIME type of the message. NÚ multipart)r…rNr5)rrâÚ_MultipartMessageStructureÚ_RFC822MessageStructureÚ_TextMessageStructureÚ_SinglepartMessageStructure)r…ÚmainÚsubtyperr=r=rAÚ_getMessageStructureös   r!c@r©) Ú_MessageStructurez¶ L{_MessageStructure} is a helper base class for message structure classes representing the structure of particular kinds of messages, as defined by their MIME type. cCs||_||_dS)zâ @param message: An L{IMessagePart} provider which this structure object reports on. @param attrs: A C{dict} giving the parameters of the I{Content-Type} header of the message. N)r…r)rZr…rr=r=rAr]s z_MessageStructure.__init__cCsh|r2| d¡}t|ƒdkr|d ¡df}|St|ƒdkr0dd„|dd…Dƒ}|d ¡|g}|SdS)a Parse a I{Content-Disposition} header into a two-sequence of the disposition and a flattened list of its parameters. @return: L{None} if there is no disposition header value, a L{list} with two elements otherwise. z; r;rNcSs"g|] }| dd¡D]}|‘q qS©rr;r)rCÚparamrOr=r=rArG0s"z2_MessageStructure._disposition..)r3r¡râ)rZÚdispÚparamsr=r=rAÚ _disposition"s   üz_MessageStructure._dispositioncCs0|jrdd„|j ¡Dƒ}dd„t|ƒDƒSdS)zÕ @return: The I{Content-Type} parameters, unquoted, as a flat list with each Nth element giving a parameter name and N+1th element giving the corresponding parameter value. cSsg|] \}}|t|ƒf‘qSr=)r©rCr*ržr=r=rArG=r+z4_MessageStructure._unquotedAttrs..cSsg|] }|D]}|‘qqSr=r=)rCrOÚyr=r=rArG>óN)rrœrh)rZÚunquotedr=r=rAÚ_unquotedAttrs6sz _MessageStructure._unquotedAttrsN)rr‘r’r“r]r'r,r=r=r=rAr"s  r"c@s8eZdZdZgd¢Zdd„Zdd„Zdd„Zd d „Zd S) rzn L{_SinglepartMessageStructure} represents the message structure of a non-I{multipart/*} message. )ú content-idúcontent-descriptionúcontent-transfer-encodingcCs$t |||¡||_||_||_dS)aÀ @param message: An L{IMessagePart} provider which this structure object reports on. @param main: A L{str} giving the main MIME type of the message (for example, C{"text"}). @param subtype: A L{str} giving the MIME subtype of the message (for example, C{"plain"}). @param attrs: A C{dict} giving the parameters of the I{Content-Type} header of the message. N)r"r]rr r)rZr…rr rr=r=rAr]Js z$_SinglepartMessageStructure.__init__cCsZ|jjdg|j¢RŽ}|j ¡}|j|j}}| ¡}|||| d¡| d¡| d¡|gS)zN Return a list of the basic fields for a single-part message. Fr-r.r/)r…rˆÚ_HEADERSr®rr r,r‰)rZrr™rrÚ unquotedAttrsr=r=rAÚ _basicFields]s ùz(_SinglepartMessageStructure._basicFieldscCs| ¡}|r | | ¡¡|S)zÁ Construct and return a list of the basic and extended fields for a single-part message. The list suitable to be encoded into a BODY or BODYSTRUCTURE response. )r2rrÚ _extended©rZÚextendedrJr=r=rArusz"_SinglepartMessageStructure.encodecCsbg}|j ddddd¡}| | d¡¡| | | d¡¡¡| | d¡¡| | d¡¡|S)aw The extension data of a non-multipart body part are in the following order: 1. body MD5 A string giving the body MD5 value as defined in [MD5]. 2. body disposition A parenthesized list with the same content and function as the body disposition for a multipart body part. 3. body language A string or parenthesized list giving the body language value as defined in [LANGUAGE-TAGS]. 4. body location A string list giving the body content URI as defined in [LOCATION]. Fz content-md5úcontent-dispositionúcontent-languageúcontent-location)r…rˆrlr‰r'©rZrJrr=r=rAr3€sûz%_SinglepartMessageStructure._extendedN) rr‘r’r“r0r]r2rr3r=r=r=rArBs rc@óeZdZdZdd„ZdS)rz_ L{_TextMessageStructure} represents the message structure of a I{text/*} message. cCs0t |¡}| t|jƒ¡|r| | ¡¡|S)a A body type of type TEXT contains, immediately after the basic fields, the size of the body in text lines. Note that this size is the size in its content transfer encoding and not the resulting size after any decoding. )rr2rlr r…rrr3r4r=r=rAr°s z_TextMessageStructure.encodeN©rr‘r’r“rr=r=r=rArªó rc@r:)rzi L{_RFC822MessageStructure} represents the message structure of a I{message/rfc822} message. cCsHt ||¡}|j d¡}| t|ƒ¡| t|dƒ¡| t|ƒ¡|S)zâ A body type of type MESSAGE and subtype RFC822 contains, immediately after the basic fields, the envelope structure, body structure, and size in text lines of the encapsulated message. rF)rrr…rrlrær r )rZr5rJÚ containedr=r=rArÄs  z_RFC822MessageStructure.encodeNr;r=r=r=rAr¾r<rc@s0eZdZdZdd„Zdd„Zdd„Zdd „Zd S) rzi L{_MultipartMessageStructure} represents the message structure of a I{multipart/*} message. cCst |||¡||_dS)aR @param message: An L{IMessagePart} provider which this structure object reports on. @param subtype: A L{str} giving the MIME subtype of the message (for example, C{"plain"}). @param attrs: A C{dict} giving the parameters of the I{Content-Type} header of the message. N)r"r]r )rZr…r rr=r=rAr]Ùs z#_MultipartMessageStructure.__init__ccs>d} z|j |¡}Wn tyYdSw|V|d7}q)zR Return an iterator over all of the sub-messages of this message. rTr;N)r…rrÊ)rZrcrr=r=rAÚ _getPartsçs€ ÿùz$_MultipartMessageStructure._getPartscs8‡fdd„| ¡Dƒ}| |j¡ˆr| | ¡¡|S)zW Encode each sub-message and added the additional I{multipart} fields. csg|] }t|ƒ ˆ¡‘qSr=©r!rr<©r5r=rArGùr*z5_MultipartMessageStructure.encode..)r>rlr rrr3r4r=r@rArõs  z!_MultipartMessageStructure.encodecCsbg}|j dddd¡}| | ¡¡| | | d¡¡¡| | dd¡¡| | dd¡¡|S)af The extension data of a multipart body part are in the following order: 1. body parameter parenthesized list A parenthesized list of attribute/value pairs [e.g., ("foo" "bar" "baz" "rag") where "bar" is the value of "foo", and "rag" is the value of "baz"] as defined in [MIME-IMB]. 2. body disposition A parenthesized list, consisting of a disposition type string, followed by a parenthesized list of disposition attribute/value pairs as defined in [DISPOSITION]. 3. body language A string or parenthesized list giving the body language value as defined in [LANGUAGE-TAGS]. 4. body location A string list giving the body content URI as defined in [LOCATION]. Fr7r8r6N)r…rˆrlr,r'r‰r9r=r=rAr3ÿsÿz$_MultipartMessageStructure._extendedN)rr‘r’r“r]r>rr3r=r=r=rArÓs  rFcCst|ƒ |¡S)ar RFC 3501, 7.4.2, BODYSTRUCTURE:: A parenthesized list that describes the [MIME-IMB] body structure of a message. This is computed by the server by parsing the [MIME-IMB] header fields, defaulting various fields as necessary. For example, a simple text message of 48 lines and 2279 octets can have a body structure of: ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2279 48) This is represented as:: ["TEXT", "PLAIN", ["CHARSET", "US-ASCII"], None, None, "7BIT", 2279, 48] These basic fields are documented in the RFC as: 1. body type A string giving the content media type name as defined in [MIME-IMB]. 2. body subtype A string giving the content subtype name as defined in [MIME-IMB]. 3. body parameter parenthesized list A parenthesized list of attribute/value pairs [e.g., ("foo" "bar" "baz" "rag") where "bar" is the value of "foo" and "rag" is the value of "baz"] as defined in [MIME-IMB]. 4. body id A string giving the content id as defined in [MIME-IMB]. 5. body description A string giving the content description as defined in [MIME-IMB]. 6. body encoding A string giving the content transfer encoding as defined in [MIME-IMB]. 7. body size A number giving the size of the body in octets. Note that this size is the size in its transfer encoding and not the resulting size after any decoding. Put another way, the body structure is a list of seven elements. The semantics of the elements of this list are: 1. Byte string giving the major MIME type 2. Byte string giving the minor MIME type 3. A list giving the Content-Type parameters of the message 4. A byte string giving the content identifier for the message part, or None if it has no content identifier. 5. A byte string giving the content description for the message part, or None if it has no content description. 6. A byte string giving the Content-Encoding of the message body 7. An integer giving the number of octets in the message body The RFC goes on:: Multiple parts are indicated by parenthesis nesting. Instead of a body type as the first element of the parenthesized list, there is a sequence of one or more nested body structures. The second element of the parenthesized list is the multipart subtype (mixed, digest, parallel, alternative, etc.). For example, a two part message consisting of a text and a BASE64-encoded text attachment can have a body structure of: (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff") "<960723163407.20117h@cac.washington.edu>" "Compiler diff" "BASE64" 4554 73) "MIXED") This is represented as:: [["TEXT", "PLAIN", ["CHARSET", "US-ASCII"], None, None, "7BIT", 1152, 23], ["TEXT", "PLAIN", ["CHARSET", "US-ASCII", "NAME", "cc.diff"], "<960723163407.20117h@cac.washington.edu>", "Compiler diff", "BASE64", 4554, 73], "MIXED"] In other words, a list of N + 1 elements, where N is the number of parts in the message. The first N elements are structures as defined by the previous section. The last element is the minor MIME subtype of the multipart message. Additionally, the RFC describes extension data:: Extension data follows the multipart subtype. Extension data is never returned with the BODY fetch, but can be returned with a BODYSTRUCTURE fetch. Extension data, if present, MUST be in the defined order. The C{extended} flag controls whether extension data might be returned with the normal data. r?)rŠr5r=r=rAr "sir cCs(dd„| ¡Dƒ}d |¡d}t|ƒS)Nc Ss,g|]\}}d | ¡d | ¡¡f¡‘qS)z: ú )r†Útitlerr(r=r=rArGsÿÿz"_formatHeaders..rA)rœr†r:)rrÿr=r=rArýŽs þrýccs4d}z | |¡V|d7}qtyYdSw)NrTr;)rrÊ)rjrcr=r=rAÚsubparts˜s€ þ ÿrCcs2ddlm‰t ¡‰‡‡‡‡fdd„‰ˆdƒˆS)a© Consume an interator at most a single iteration per reactor iteration. If the iterator produces a Deferred, the next iteration will not occur until the Deferred fires, otherwise the next iteration will be taken in the next reactor iteration. @rtype: C{Deferred} @return: A deferred which fires (with None) when the iterator is exhausted or whose errback is called if there is an exception. rricsrztˆƒ}Wntyˆ |¡YdSty"ˆ ¡YdSwt|tjƒr0| ˆ¡dSˆ  dˆ|¡dSr²) rßràr¦rûr¤rUr rSrCrp)r_rÿ©rèÚgorcrjr=rArE²s   ÿ ziterateInReactor..goN)rorjr rS)rcr=rDrArû¢s  rûc@s4eZdZdZeejƒZd dd„Zdd„Z dd„Z dS) r éNcCs<||_|dur t ¡}||_|durt}||_|jj|_dS)a Produce this message. @param msg: The message I am to produce. @type msg: L{IMessage} @param buffer: A buffer to hold the message in. If None, I will use a L{tempfile.TemporaryFile}. @type buffer: file-like N)rŠr­r®r=rûrr¤)rZrŠr=rr=r=rAr]Çs zMessageProducer.__init__cCs||_| | ¡¡Srm)ÚconsumerrÚ_produce)rZrGr=r=rArÛszMessageProducer.beginProducingc#s–ˆj d¡}d}ˆj ¡rZ| d¡}dd„| d¡dd…Dƒ}dd„|Dƒ}| d ¡}|durFd ˆ ¡j›}|dd |›d 7<n| d ¡rV| d ¡rV|dd …}t |ƒ}ˆ  t |ƒ¡ˆ  d¡ˆj ¡r’t ˆjƒD]}ˆ  d|d¡t |ˆjˆjƒ d¡Vqpˆ  d|d¡nˆj ¡} | ˆj¡}|rªˆj  |¡dVnnq˜ˆjrɈj dd¡tˆjƒ ˆj¡ ‡fdd„¡VdSdS)NTrcSsg|]}| dd¡‘qSr#rr*r=r=rArGär›z,MessageProducer._produce..rr;cSsi|] \}}| ¡ ¡|“qSr=)rârcr(r=r=rAr$årðz,MessageProducer._produce..Úboundaryz----=z ; boundary="rrtrœs --s-- rcsˆSrmr=rÜr^r=rArPrçz*MessageProducer._produce..)rŠrˆrr‰r3Ú_uuid4Úhexr~r#r:r¤rýrCr r=rrr–rŸÚ CHUNK_SIZErGr¯rrC)rZrrIrr©r‡r-r½r=r^rArHßsJ€       ÿ   ú  ÿþzMessageProducer._producer]) rr‘r’rLÚ staticmethodÚuuidÚuuid4rJr]rrHr=r=r=rAr Ãs    r c @szeZdZGdd„dƒZGdd„dƒZGdd„dƒZGdd„dƒZGd d „d ƒZGd d „d ƒZGd d„dƒZ Gdd„dƒZ Gdd„dƒZ Gdd„dƒZ Gdd„dƒZ Gdd„dƒZGdd„dƒZdZdefdefdefdefd efd!efd"e fd#e fd$e fg Zd%d&„Zd'd(„Zd)d*„Zd+d,„Zd-d.„Zd/d0„Zd1d2„Zd3d4„Zd5d6„Ze d7¡Zd8d9„Zd:d;„Zdd?„Z!d@dA„Z"dS)Brvc@r:)z_FetchParser.EnveloperHcCrG)NrHr=r^r=r=rArPrçz_FetchParser.Envelope.N©rr‘r’rrˆr=r=r=rAÚEnvelope s rQc@r:)z_FetchParser.Flagsr{cCrG)Nr{r=r^r=r=rArPrçz_FetchParser.Flags.NrPr=r=r=rAÚFlagsó rRc@r:)z_FetchParser.InternalDaterFcCrG)NrFr=r^r=r=rArPrçz"_FetchParser.InternalDate.NrPr=r=r=rAÚ InternalDaterSrTc@r:)z_FetchParser.RFC822HeaderrPcCrG)Nrr=r^r=r=rArP"rçz"_FetchParser.RFC822Header.NrPr=r=r=rAÚ RFC822Header rSrUc@r:)z_FetchParser.RFC822TextrRcCrG)Nrr=r^r=r=rArP&rçz _FetchParser.RFC822Text.NrPr=r=r=rAÚ RFC822Text$rSrVc@r:)z_FetchParser.RFC822SizerTcCrG)Nr€r=r^r=r=rArP*rçz _FetchParser.RFC822Size.NrPr=r=r=rAÚ RFC822Size(rSrWc@r:)z_FetchParser.RFC822rNcCrG)NrNr=r^r=r=rArP.rçz_FetchParser.RFC822.NrPr=r=r=rAÚRFC822,rSrXc@r:)z_FetchParser.UIDr>cCrG)Nr>r=r^r=r=rArP2rçz_FetchParser.UID.NrPr=r=r=rAr¡0rSr¡c@sLeZdZdZdZdZdZdZdZdZ dZ dZ de fdd„Z defdd „ZdS) z_FetchParser.Bodyr˜FNr=r‚cCó| ¡ d¡S©Nr«©rrür^r=r=rArˆ?rz_FetchParser.Body.__str__cCsÈd}d}d}|jrd dd„|jDƒ¡}d}|jr,|d||t|jƒ d¡d7}n'|jr:|d||d 7}n|jrH|d||d 7}n |jrS|d|d7}|jdurb|d |j|j f7}|S) Nr]r ó.cSsg|] }t|dƒ d¡‘qS)r;r«)r…rr*r=r=rArGGrðz/_FetchParser.Body.__bytes__..rìr«r°sTEXT]sMIME]s<%d.%d>) rr†rr…rr5rrÚ partialBeginÚ partialLength)rZÚbaserÚ separatorr=r=rArBs&ÿ z_FetchParser.Body.__bytes__)rr‘r’rrwrrr5rrr]r^r…rˆrrr=r=r=rAÚBody4srac@r:)z_FetchParser.BodyStructurerKcCrG)NrKr=r^r=r=rArP[rçz#_FetchParser.BodyStructure.NrPr=r=r=rAÚ BodyStructureYrSrbc@s4eZdZdZdZdZdefdd„Zdefdd„Z dS)z_FetchParser.HeaderFNr‚cCrYrZr[r^r=r=rArˆcrz_FetchParser.Header.__str__cCsd}|jr4|d7}|jr|d7}g}|jD]}| ¡}t|ƒr#t|ƒ}| |¡q|dd |¡d7}|jrFd dd „|jDƒ¡d|}|S) NsHEADERs.FIELDSs.NOTr,rØrmr\cSsg|]}|d ¡‘qSr)rr*r=r=rArGvr›z1_FetchParser.Header.__bytes__..)rrrBrÓrörlr†r)rZr_rr-r=r=rArfs  z_FetchParser.Header.__bytes__) rr‘r’rrrr…rˆrrr=r=r=rAÚHeader^s rcc@ó eZdZdS)z_FetchParser.TextN©rr‘r’r=r=r=rAÚTextyórfc@rd)z_FetchParser.MIMENrer=r=r=rAÚMIME|rgrhNsenvelopesflagss internaldates rfc822.headers rfc822.texts rfc822.sizesrfc822suids bodystructurecCsdg|_g|_d|_dS)NÚinitialr )rrJÚ remainingr^r=r=rAr]s z_FetchParser.__init__cCs˜|j|}zB|s |jrB|jstdƒ‚|j ¡}z t|d|ƒ|ƒ}Wnty0|j |¡‚w||d…}|s |js W||_dSW||_dS||_w)NzInvalid ArgumentÚstate_)rjrrr%r)rûrl)rZr¹rÚusedr=r=rArw’s"     þ  ô òz_FetchParser.parseStringcCsÔ|dkrdS| ¡}| d¡r#|j | ¡| ¡| ¡| ¡f¡dS| d¡r?|j | ¡| ¡| ¡| ¡| ¡f¡dS| d¡rU|j | ¡| ¡| ¡f¡dS| d¡rb|j  d ¡d S|j   d ¡dS) Nr rsallr/sfullrhsfastrl)Ú close_parenÚmaybe_fetch_attÚ fetch_attr;ro) râr~rJrrrRrTrWrQrarrl)rZr¹r}r=r=rAÚ state_initial¥s> ÿ ûÿ ýÿ   z_FetchParser.state_initialcCs| d¡rdStdƒ‚)Nrmr;z Missing )©r~r+r¸r=r=rAÚstate_close_parenÎs z_FetchParser.state_close_parencCsP|r |dd… ¡stdƒ‚d}tt|ƒƒD]}|||d… ¡s%|Sq|S)Nrr;zWhitespace expected, none found)Úisspacer+rlr¡)rZr¹rcr=r=rAÚstate_whitespaceÕsþz_FetchParser.state_whitespacecCs| d¡s |j d¡dS)Nrm)rnrorµr©r~rrrr¸r=r=rAÚstate_maybe_fetch_attßs  z"_FetchParser.state_maybe_fetch_attcCsŽ| ¡}|jD]\}}| |¡r|j |ƒ¡t|ƒSq| ¡}| d¡r-d|_d}n| d¡r5d}ntd|›ƒ‚||_ |j   d¡|S)Ns body.peekTrîsbodyrhz!Nothing recognized in fetch_att: )Úgot_bodyÚ maybe_partialÚ maybe_section) râÚ_simple_fetch_attr~rJrlr¡rarwr+Ú pending_bodyrrr)rZr¹r}rÜÚclsr½rlr=r=rAÚstate_fetch_attäs   þ   z_FetchParser.state_fetch_attcCs|j |j¡|`dSr²)rJrlr{r¸r=r=rAÚstate_got_bodyýsz_FetchParser.state_got_bodycCs| d¡sdS|j d¡dS)Nrìr)ÚsectionÚ part_numberr;rur¸r=r=rAÚstate_maybe_sections  z _FetchParser.state_maybe_sections(\d+(?:\.\d+)*)\.?cCsD|j |¡}|durdd„| ¡d d¡Dƒ|_| ¡Sg|_dS)NcSsg|]}t|ƒd‘qSr)rdr<r=r=rArGr›z2_FetchParser.state_part_number..rr\)Ú _partExprrhÚgroupsr3r©r\)rZr¹rjr=r=rAÚstate_part_number s z_FetchParser.state_part_numbercCs| ¡}d}| d¡rd|j_|d7}nd| d¡r,| ¡}|j_d|_d|_|d7}nL| d¡r<| ¡|j_ |d 7}n<| d ¡rL|  ¡|j_ |d 7}n,| ¡}| d ¡r]d|_|d 7}n| d ¡rg|d7}nt d|›ƒ‚||j_|j  d¡t|jƒ|j_d|_|S)Nrr°Tr;sheader]r=r‚stext]rgsmime]sheader.fields.notés header.fieldsr<zUnhandled section contents: )Úfinish_sectionÚ header_listrµ)râr~r{rrcrrrrfr5rhrr+rrrrr©r)rZr¹r}rlr~r=r=rAÚ state_sections8               z_FetchParser.state_sectioncCs| d¡s tdƒ‚dS)Nr°zsection must end with ]r;rqr¸r=r=rAÚstate_finish_section9s z!_FetchParser.state_finish_sectioncCsX| d¡s tdƒ‚| d¡}|dkrtdƒ‚|d|… ¡}dd„|Dƒ|jj_|dS) NrlzHeader list must begin with (rmrtzHeader list must end with )r;cSrár=r‚)rCr~r=r=rArGFräz2_FetchParser.state_header_list..)r~r+ror3r{rr)rZr¹r\rr=r=rAÚstate_header_list>s  z_FetchParser.state_header_listcCsz| d¡sdS| d¡}|dkrtdƒ‚|d|…}| dd¡}t|ƒdkr*td ƒ‚tt|ƒ\}}||j_||j_ |dS) Nr_rr`rtzFound < but not >r;r\rÛz>Partial specification did not include two .-delimited integers) r~ror+r3r¡rrdr{r]r^)rZr¹r\rjr©Úbeginryr=r=rAÚstate_maybe_partialIs     ÿz _FetchParser.state_maybe_partial)#rr‘r’rQrRrTrUrVrWrXr¡rarbrcrfrhr©rzr]rwrprrrtrvr}r~rrVrWr‚r„rˆr‰rŠrŒr=r=r=rArv sP%÷ )   % rvc@sDeZdZdZdZdd„Zdd„Zdd„Zd d „Zd d „Z d d„Z dS)rrFTcCrÏrmr5)rZr-r=r=rAr]crÐzFileProducer.__init__cCs.||_|j|_t ¡}|_|j |d¡|S)NF)rGr¤Úproducer rSÚ_onDoneÚregisterProducer)rZrGrèr=r=rArfs zFileProducer.beginProducingcCsxd}|jrd| ¡f}d|_|jsdS||j |j¡}|s5|j ¡|j |¡d|_|_|_dS|  |¡dS)Nr s{%d} F) Ú firstWriteÚ_sizer-rŸrLrGÚunregisterProducerrŽr¦r)rZr½r=r=rAÚresumeProducingms  zFileProducer.resumeProducingcCrG)z9 Pause the producer. This does nothing. Nr=r^r=r=rAÚpauseProducing|rçzFileProducer.pauseProducingcCrG)z8 Stop the producer. This does nothing. Nr=r^r=r=rAÚ stopProducingrçzFileProducer.stopProducingcCs8|j ¡}|j dd¡|j ¡}|j |d¡||S)NrrÛ)r-r/r¯)rZr½r.r=r=rAr‘†s  zFileProducer._sizeN) rr‘r’rLrr]rr“r”r•r‘r=r=r=rAr^s rc CsÆgd¢}ddddœ}t d||¡}|std|›ƒ‚| ¡}z!d| |d  ¡¡d |d <t|d ƒ|d <t|d ƒ|d <WntyNtd|›ƒ‚wt |d |d |d d d d dddf ¡S)N)ÚjanÚfebÚmarÚaprÚmayÚjunÚjulÚaugÚsepÚoctÚnovÚdecÚjanuaryÚfebruaryÚmarchÚaprilršÚjuneÚjulyÚaugustÚ septemberÚoctoberÚnovemberÚdecemberz+(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])z (?P\w+)z(?P\d\d\d\d))ÚdayÚmonÚyearz%(day)s-%(mon)s-%(year)szCannot parse time string r;r®é r¯r­rrt) rVrhr`Ú groupdictÚindexrârdròÚ struct_time)r¹ÚmonthsÚexprrjrèr=r=rAr‹Žs"ý ÿ(r‹rcGs|dSr²r=rNr=r=rArPÀrQrPcCs| d¡}|dd… dd¡S)Núutf-7r;rtrør‘)rr¯©r¹Ús_utf7r=r=rAÚmodified_base64Ãs r¹cCsd| dd¡d}| d¡S)Nr•r‘rørïr¶)r¯rür·r=r=rAÚmodified_unbase64Ès rºcCsâtƒ}g}ttttddƒƒƒdh}|D]D}||vr6|r.|dtd |¡ƒd7}|dd…=| t|ƒ¡q|dkrS|rN|dtd |¡ƒd7}|dd…=|d7}q| |¡q|ri|  dtd |¡ƒd¡t |ƒt |ƒfS) ap Encode the given C{unicode} string using the IMAP4 specific variation of UTF-7. @type s: C{unicode} @param s: The text to encode. @param errors: Policy for handling encoding errors. Currently ignored. @return: L{tuple} of a L{str} giving the encoded bytes and an L{int} giving the number of code units consumed from the input. é éú&ó&r†rïNs&-) Ú bytearrayr'rÚchrrlr¹r†rlÚordrrrr¡)r¹ÚerrorsrÿÚ_inÚ valid_charsršr=r=rAÚencoderÍs$     rÅc CsÎg}g}tt|ƒdƒ}|D]@}|dkr|s| d¡q |dkr>|r>t|ƒdkr-| d¡n| td |dd…¡ƒ¡g}q |rF| |¡q | | ¡¡q |r^| td |dd…¡ƒ¡d |¡t|ƒfS) aw Decode the given L{str} using the IMAP4 specific variation of UTF-7. @type s: L{str} @param s: The bytes to decode. @param errors: Policy for handling decoding errors. Currently ignored. @return: a L{tuple} of a C{unicode} string giving the text which was decoded and an L{int} giving the number of bytes consumed from the input. ršr¾rïr;r½r Nr†)Ú memory_castÚ memoryviewrlr¡rºr†rü)r¹rÂrÿrüršr=r=rAÚdecoderïs"       rÈc@óeZdZddd„ZdS)Ú StreamReaderÚstrictcCót|ƒSrm)rÈ©rZr¹rÂr=r=rArüózStreamReader.decodeN©rË)rr‘r’rür=r=r=rArÊórÊc@rÉ)Ú StreamWriterrËcCrÌrm)rÅrÍr=r=rArrÎzStreamWriter.encodeNrÏ)rr‘r’rr=r=r=rArÑrÐrÑcCs| dd¡dkr tSdS)Nú-rAÚ imap4_utf_7)r¯Ú _codecInforÔr=r=rArÓsÿrÓ)(rór‹ÚIMailboxListenerr'r±ÚIMailboxr0rÚ IMailboxInfoÚIMessager8rrYÚ IMessagePartrrrrr%r!r#rrrrr rrr"r$rrrrrr«r­r¬r÷rrmrUrrS)´r“r¬ÚcodecsrÅÚ email.utilsrŒrirVr´r­ròrNÚbase64rrÚiorÚ itertoolsrÚtypingrrrÚzope.interfacer Ú twisted.credr Útwisted.cred.errorr r ror rrÚtwisted.internet.deferrÚtwisted.mail._credrrrrrÚtwisted.mail._exceptrrrrrrrrrrr r!r"r#r$r%Útwisted.mail.interfacesr&r±r'r(rr)rÖr*r×r+rÕr,rØr-r8r.rr/rÙr0r1rYÚtwisted.protocolsr2r3Útwisted.pythonr4r5Útwisted.python.compatr6r7r8r9r:rrkrlr3rôrBrIrJr˜rªr°r»Ú_SPrÚ_CTLrðrüÚ_nativeNonAtomCharsrWr¨rYÚ LineReceiverÚ TimeoutMixinróÚ TimeoutErrorrªr‹rtr§r©rhr¦r«r¬r­r±r½rÃrÅrÝrörþrrÒrÓrØr rÙrÒrÝr÷rþrrrær rrr!r"rrrrr rýrCrûr rvrr‹r)rÇrÆr¹rºrÅrÈrÊrÑÚ CodecInforÔrÓÚregisterÚ__all__r=r=r=rAÚs      H8 ÿ&!K  % $9   A ":   1rû   2h Ol  !FW02  ""