Current File : //proc/self/root/usr/lib/python3.12/email/__pycache__/_header_value_parser.cpython-312.pyc
�

�(�g٣�	��
�dZddlZddlZddlZddlmZddlmZddlm	Z
ddlmZddlmZe
d�Zee
d	�zZe
d
�ZeezZee
d�z
Zee
d�z
Zee
d
�ze
d�z
ZeezZee
d�zZeezZee
d�z
ZddhZeezZd�Zej8dej:ej<z�ZGd�de �Z!Gd�de!�Z"Gd�de!�Z#Gd�de!�Z$Gd�de!�Z%Gd�de"�Z&Gd �d!e!�Z'Gd"�d#e!�Z(Gd$�d%e!�Z)Gd&�d'e!�Z*Gd(�d)e*�Z+Gd*�d+e"�Z,Gd,�d-e!�Z-Gd.�d/e!�Z.Gd0�d1e!�Z/Gd2�d3e!�Z0Gd4�d5e!�Z1Gd6�d7e!�Z2Gd8�d9e!�Z3Gd:�d;e!�Z4Gd<�d=e!�Z5Gd>�d?e!�Z6Gd@�dAe!�Z7GdB�dCe!�Z8GdD�dEe!�Z9GdF�dGe!�Z:GdH�dIe!�Z;GdJ�dKe!�Z<GdL�dMe$�Z=GdN�dOe!�Z>GdP�dQe!�Z?GdR�dSe!�Z@GdT�dUe!�ZAGdV�dWeA�ZBGdX�dYe!�ZCGdZ�d[e!�ZDGd\�d]e!�ZEGd^�d_e!�ZFGd`�dae!�ZGGdb�dceG�ZHGdd�deeG�ZIGdf�dge!�ZJGdh�die!�ZKGdj�dke!�ZLGdl�dmeL�ZMGdn�doeM�ZNGdp�dqe!�ZOGdr�dseP�ZQGdt�dueQ�ZRGdv�dweQ�ZSGdx�dyeR�ZTGdz�d{ej��ZVeSdd|�ZWeSd}d~�ZXdeX_YeSd�d��ZZej8d�j�d�j�e���j�Z^ej8d�j�ej�d�j�e����j�Zaej8d��j�Zcej8d�j�ej�d�j�e����j�Zdej8d�j�ej�d�j�e����j�Zeej8d�j�ej�d�j�e����j�Zfd��Zgd��Zhd��Zid��Zjd��Zkd��Zld��Zmd��Znd��Zod��Zpd��Zqd��Zrd��Zsd��Ztd��Zud��Zvd��Zwd��Zxd��Zyd��Zzd��Z{d��Z|d��Z}d��Z~d��Zd��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�d��Z�y)�alHeader value parser implementing various email-related RFC parsing rules.

The parsing methods defined in this module implement various email related
parsing rules.  Principal among them is RFC 5322, which is the followon
to RFC 2822 and primarily a clarification of the former.  It also implements
RFC 2047 encoded word decoding.

RFC 5322 goes to considerable trouble to maintain backward compatibility with
RFC 822 in the parse phase, while cleaning up the structure on the generation
phase.  This parser supports correct RFC 5322 generation by tagging white space
as folding white space only when folding is allowed in the non-obsolete rule
sets.  Actually, the parser is even more generous when accepting input than RFC
5322 mandates, following the spirit of Postel's Law, which RFC 5322 encourages.
Where possible deviations from the standard are annotated on the 'defects'
attribute of tokens that deviate.

The general structure of the parser follows RFC 5322, and uses its terminology
where there is a direct correspondence.  Where the implementation requires a
somewhat different structure than that used by the formal grammar, new terms
that mimic the closest existing terms are used.  Thus, it really helps to have
a copy of RFC 5322 handy when studying this code.

Input to the parser is a string that has already been unfolded according to
RFC 5322 rules.  According to the RFC this unfolding is the very first step, and
this parser leaves the unfolding step to a higher level message parser, which
will have already detected the line breaks that need unfolding while
determining the beginning and end of each header.

The output of the parser is a TokenList object, which is a list subclass.  A
TokenList is a recursive data structure.  The terminal nodes of the structure
are Terminal objects, which are subclasses of str.  These do not correspond
directly to terminal objects in the formal grammar, but are instead more
practical higher level combinations of true terminals.

All TokenList and Terminal objects have a 'value' attribute, which produces the
semantically meaningful value of that part of the parse subtree.  The value of
all whitespace tokens (no matter how many sub-tokens they may contain) is a
single space, as per the RFC rules.  This includes 'CFWS', which is herein
included in the general class of whitespace tokens.  There is one exception to
the rule that whitespace tokens are collapsed into single spaces in values: in
the value of a 'bare-quoted-string' (a quoted-string with no leading or
trailing whitespace), any whitespace that appeared between the quotation marks
is preserved in the returned value.  Note that in all Terminal strings quoted
pairs are turned into their unquoted values.

All TokenList and Terminal objects also have a string value, which attempts to
be a "canonical" representation of the RFC-compliant form of the substring that
produced the parsed subtree, including minimal use of quoted pair quoting.
Whitespace runs are not collapsed.

Comment tokens also have a 'content' attribute providing the string found
between the parens (including any nested comments) with whitespace preserved.

All TokenList and Terminal objects have a 'defects' attribute which is a
possibly empty list all of the defects found while creating the token.  Defects
may appear on any token in the tree, and a composite list of all defects in the
subtree is available through the 'all_defects' attribute of any node.  (For
Terminal notes x.defects == x.all_defects.)

Each object in a parse tree is called a 'token', and each has a 'token_type'
attribute that gives the name from the RFC 5322 grammar that it represents.
Not all RFC 5322 nodes are produced, and there is one non-RFC 5322 node that
may be produced: 'ptext'.  A 'ptext' is a string of printable ascii characters.
It is returned in place of lists of (ctext/quoted-pair) and
(qtext/quoted-pair).

XXX: provide complete list of token types.
�N)�	hexdigits)�
itemgetter)�_encoded_words)�errors)�utilsz 	�(z
()<>@,:;.\"[]�.z."(z/?=z*'%�%�
�
c�d�dt|�jdd�jdd�zdzS)N�"�\�\\z\")�str�replace��values �1/usr/lib/python3.12/email/_header_value_parser.py�quote_stringrbs0���s�5�z�!�!�$��/�7�7��U�C�C�C�G�G�z�
   =\?            # literal =?
   [^?]*          # charset
   \?             # literal ?
   [qQbB]         # literal 'q' or 'b', case insensitive
   \?             # literal ?
  .*?             # encoded word
  \?=             # literal ?=
c���eZdZdZdZdZ�fd�Zd�Z�fd�Ze	d��Z
e	d��Zd�Ze	d	��Z
e	d
��Zd�Zdd�Zdd
�Zdd�Z�xZS)�	TokenListNTc�2��t�|�|i|��g|_y�N)�super�__init__�defects)�self�args�kw�	__class__s   �rrzTokenList.__init__{s���
���$�%�"�%���rc�2�djd�|D��S)N�c3�2K�|]}t|����y�wr�r��.0�xs  r�	<genexpr>z$TokenList.__str__.<locals>.<genexpr>������,�!�s�1�v�,�����join�rs r�__str__zTokenList.__str__s���w�w�,�t�,�,�,rc�h��dj|jjt�|���S�Nz{}({})��formatr"�__name__r�__repr__�rr"s �rr6zTokenList.__repr__�s+������t�~�~�6�6�"�W�-�/�1�	1rc�2�djd�|D��S)Nr$c3�NK�|]}|js�|j���y�wrrr's  rr*z"TokenList.value.<locals>.<genexpr>�s����8�1����q�w�w�8�s�%�%r-r/s rrzTokenList.value�s���w�w�8��8�8�8rc�<�td�|D�|j�S)Nc3�4K�|]}|j���y�wr)�all_defectsr's  rr*z(TokenList.all_defects.<locals>.<genexpr>�s����0�a�A�M�M�0���)�sumrr/s rr<zTokenList.all_defects�s���0�4�0�$�,�,�?�?rc�(�|dj�S�Nr)�startswith_fwsr/s rrAzTokenList.startswith_fws�s���A�w�%�%�'�'rc�&�td�|D��S)zATrue if all top level tokens of this part may be RFC2047 encoded.c3�4K�|]}|j���y�wr)�
as_ew_allowed)r(�parts  rr*z*TokenList.as_ew_allowed.<locals>.<genexpr>�s����7�$�4�%�%�7�r=)�allr/s rrDzTokenList.as_ew_allowed�s���7�$�7�7�7rc�N�g}|D]}|j|j��|Sr)�extend�comments)rrI�tokens   rrIzTokenList.comments�s+�����	,�E��O�O�E�N�N�+�	,��rc��t||��S)N��policy)�_refold_parse_tree�rrMs  r�foldzTokenList.fold�s��!�$�v�6�6rc�:�t|j|���y)N��indent)�print�ppstr�rrSs  r�pprintzTokenList.pprint�s��
�d�j�j��j�'�(rc�D�dj|j|���S)NrrR)r.�_pprVs  rrUzTokenList.ppstr�s���y�y������0�1�1rc#�~K�dj||jj|j���|D]A}t	|d�s|dj|�z���&|j|dz�Ed{����C|jrdj|j�}nd}dj||���y7�E�w)Nz{}{}/{}(rYz*    !! invalid element in token list: {!r}z    z Defects: {}r$z{}){})r4r"r5�
token_type�hasattrrYr)rrSrJ�extras    rrYz
TokenList._pp�s����������N�N�#�#��O�O��	��	4�E��5�%�(��!5�5;�V�E�]�C�D�!�9�9�V�F�]�3�3�3�	4��<�<�"�)�)�$�,�,�7�E��E��n�n�V�U�+�+�4�s�A3B=�5B;�6AB=�r$)r5�
__module__�__qualname__r[�syntactic_break�ew_combine_allowedrr0r6�propertyrr<rArDrIrPrWrUrY�
__classcell__�r"s@rrrus�����J��O����-�1��9��9��@��@�(��8��8�����7�)�2�,rrc�,�eZdZed��Zed��Zy)�WhiteSpaceTokenListc��y�N� �r/s rrzWhiteSpaceTokenList.value����rc�`�|D�cgc]}|jdk(s�|j�� c}Scc}w)N�comment)r[�content�rr)s  rrIzWhiteSpaceTokenList.comments�s%��#'�C�a�1�<�<��+B��	�	�C�C��C��+�+N)r5r_r`rcrrIrkrrrgrg�s*��
�����D��Drrgc��eZdZdZy)�UnstructuredTokenList�unstructuredN�r5r_r`r[rkrrrsrs�s���Jrrsc��eZdZdZy)�Phrase�phraseNrurkrrrwrw�����Jrrwc��eZdZdZy)�Word�wordNrurkrrr{r{�����Jrr{c��eZdZdZy)�CFWSList�cfwsNrurkrrrr�r}rrc��eZdZdZy)�Atom�atomNrurkrrr�r��r}rr�c��eZdZdZdZy)�TokenrJFN)r5r_r`r[�encode_as_ewrkrrr�r��s���J��Lrr�c��eZdZdZdZdZdZy)�EncodedWord�encoded-wordN)r5r_r`r[�cte�charset�langrkrrr�r��s���J�
�C��G��Drr�c�@�eZdZdZed��Zed��Zed��Zy)�QuotedString�
quoted-stringc�L�|D]}|jdk(s�|jcSy�N�bare-quoted-string�r[rrps  rrozQuotedString.content�s'���	�A��|�|�3�3��w�w��	rc��g}|D]G}|jdk(r|jt|���-|j|j��Idj	|�S)Nr�r$)r[�appendrrr.)r�resr)s   r�quoted_valuezQuotedString.quoted_value�sS�����	$�A��|�|�3�3��
�
�3�q�6�"��
�
�1�7�7�#�		$�
�w�w�s�|�rc�L�|D]}|jdk(s�|jcSyr�r��rrJs  r�stripped_valuezQuotedString.stripped_value�s*���	#�E����#7�7��{�{�"�	#rN)r5r_r`r[rcror�r�rkrrr�r��sA�� �J�
����
�����#��#rr�c�&�eZdZdZd�Zed��Zy)�BareQuotedStringr�c�D�tdjd�|D���S)Nr$c3�2K�|]}t|����y�wrr&r's  rr*z+BareQuotedString.__str__.<locals>.<genexpr>s����#9�q�C��F�#9�r,)rr.r/s rr0zBareQuotedString.__str__s���B�G�G�#9�D�#9�9�:�:rc�2�djd�|D��S)Nr$c3�2K�|]}t|����y�wrr&r's  rr*z)BareQuotedString.value.<locals>.<genexpr>r+r,r-r/s rrzBareQuotedString.value����w�w�,�t�,�,�,rN)r5r_r`r[r0rcrrkrrr�r��s ��%�J�;��-��-rr�c�<�eZdZdZd�Zd�Zed��Zed��Zy)�Commentrnc��djtdg|D�cgc]}|j|���c}dggg��Scc}w)Nr$r�))r.r>�quoterps  rr0zComment.__str__
sG���w�w�s� �E�48�9�q�T�Z�Z��]�9� �E�� "�	#�$�	$��9s�>c��|jdk(rt|�St|�jdd�jdd�jdd�S)Nrnrrrz\(r�z\))r[rr)rrs  rr�z
Comment.quotesR�����y�(��u�:���5�z�!�!�$��/�7�7�"%�u�.�.5�g�"%�u�/.�	.rc�2�djd�|D��S)Nr$c3�2K�|]}t|����y�wrr&r's  rr*z"Comment.content.<locals>.<genexpr>r+r,r-r/s rrozComment.contentr�rc��|jgSr)ror/s rrIzComment.commentss�����~�rN)	r5r_r`r[r0r�rcrorIrkrrr�r�	s9���J�$�.��-��-����rr�c�@�eZdZdZed��Zed��Zed��Zy)�AddressListzaddress-listc�L�|D�cgc]}|jdk(s�|��c}Scc}w)N�address�r[rps  r�	addresseszAddressList.addresses'�!���;�a�1�<�<��#:��;�;��;��!�!c�(�td�|D�g�S)Nc3�RK�|]}|jdk(r|j���!y�w�r�N�r[�	mailboxesr's  rr*z(AddressList.mailboxes.<locals>.<genexpr>-s'����>��Q�\�\�9�%<��K�K�>���%'�r>r/s rr�zAddressList.mailboxes+�!���>�!�>�?A�C�	Crc�(�td�|D�g�S)Nc3�RK�|]}|jdk(r|j���!y�wr��r[�
all_mailboxesr's  rr*z,AddressList.all_mailboxes.<locals>.<genexpr>2s'����>��Q�\�\�9�%<��O�O�>�r�r�r/s rr�zAddressList.all_mailboxes0r�rN)r5r_r`r[rcr�r�r�rkrrr�r�#sE���J�
�<��<��C��C��C��Crr�c�@�eZdZdZed��Zed��Zed��Zy)�Addressr�c�F�|djdk(r|djSy)Nr�group�r[�display_namer/s rr�zAddress.display_name:s)����7����(���7�'�'�'�)rc�x�|djdk(r|dgS|djdk(rgS|djS�Nr�mailbox�invalid-mailboxr�r/s rr�zAddress.mailboxes?sH����7����*���G�9��
�!�W�
�
�#4�
4��I��A�w� � � rc��|djdk(r|dgS|djdk(r|dgS|djSr�r�r/s rr�zAddress.all_mailboxesGsO����7����*���G�9��
�!�W�
�
�#4�
4���G�9���A�w�$�$�$rN)r5r_r`r[rcr�r�r�rkrrr�r�6sA���J�
�(��(��!��!��%��%rr�c�0�eZdZdZed��Zed��Zy)�MailboxList�mailbox-listc�L�|D�cgc]}|jdk(s�|��c}Scc}w)Nr�r�rps  rr�zMailboxList.mailboxesSr�r�c�H�|D�cgc]}|jdvr|��c}Scc}w)N)r�r�r�rps  rr�zMailboxList.all_mailboxesWs.���?�a��|�|�=�=��?�	?��?s�N�r5r_r`r[rcr�r�rkrrr�r�Os-���J�
�<��<��?��?rr�c�0�eZdZdZed��Zed��Zy)�	GroupList�
group-listc�L�|r|djdk7rgS|djS�Nrr�r�r/s rr�zGroupList.mailboxesas+���t�A�w�)�)�^�;��I��A�w� � � rc�L�|r|djdk7rgS|djSr�r�r/s rr�zGroupList.all_mailboxesgs+���t�A�w�)�)�^�;��I��A�w�$�$�$rNr�rkrrr�r�]s-���J�
�!��!�
�%��%rr�c�@�eZdZdZed��Zed��Zed��Zy)�Groupr�c�H�|djdk7rgS|djS�N�r�r�r/s rr�zGroup.mailboxesrs)����7����-��I��A�w� � � rc�H�|djdk7rgS|djSr�r�r/s rr�zGroup.all_mailboxesxs)����7����-��I��A�w�$�$�$rc� �|djSr@)r�r/s rr�zGroup.display_name~s���A�w�#�#�#rN)r5r_r`r[rcr�r�r�rkrrr�r�nsA���J�
�!��!�
�%��%�
�$��$rr�c�`�eZdZdZed��Zed��Zed��Zed��Zed��Z	y)�NameAddr�	name-addrc�>�t|�dk(ry|djS�N�r)�lenr�r/s rr�zNameAddr.display_name�s ���t�9��>���A�w�#�#�#rc� �|djS�N�����
local_partr/s rr�zNameAddr.local_part�s���B�x�"�"�"rc� �|djSr���domainr/s rr�zNameAddr.domain�s���B�x���rc� �|djSr�)�router/s rr�zNameAddr.route�s���B�x�~�~�rc� �|djSr���	addr_specr/s rr�zNameAddr.addr_spec�s���B�x�!�!�!rN�
r5r_r`r[rcr�r�r�r�r�rkrrr�r��si���J�
�$��$�
�#��#����������"��"rr�c�P�eZdZdZed��Zed��Zed��Zed��Zy)�	AngleAddrz
angle-addrc�L�|D]}|jdk(s�|jcSy�N�	addr-spec)r[r�rps  rr�zAngleAddr.local_part�s'���	$�A��|�|�{�*��|�|�#�	$rc�L�|D]}|jdk(s�|jcSyr��r[r�rps  rr�zAngleAddr.domain�s&���	 �A��|�|�{�*��x�x��	 rc�L�|D]}|jdk(s�|jcSy)N�	obs-route)r[�domainsrps  rr�zAngleAddr.route�s'���	!�A��|�|�{�*��y�y� �	!rc��|D]O}|jdk(s�|jr|jcSt|j�|jzcSy)Nr�z<>)r[r�r�rrps  rr�zAngleAddr.addr_spec�sK���	�A��|�|�{�*��<�<��;�;�&�'����5����C�C�	�rN)	r5r_r`r[rcr�r�r�r�rkrrr�r��sU���J�
�$��$�
� �� �
�!��!�
���rr�c� �eZdZdZed��Zy)�ObsRouter�c�`�|D�cgc]}|jdk(s�|j�� c}Scc}w)Nr�r�rps  rr�zObsRoute.domains�s%��"&�C�Q�!�,�,�(�*B����C�C��CrqN)r5r_r`r[rcr�rkrrr�r��s���J�
�D��Drr�c�`�eZdZdZed��Zed��Zed��Zed��Zed��Z	y)�Mailboxr�c�F�|djdk(r|djSy�Nrr�r�r/s rr�zMailbox.display_name�s)����7����,���7�'�'�'�-rc� �|djSr@r�r/s rr�zMailbox.local_part�����A�w�!�!�!rc� �|djSr@r�r/s rr�zMailbox.domain�s���A�w�~�~�rc�F�|djdk(r|djSyr)r[r�r/s rr�z
Mailbox.route�s'����7����,���7�=�=� �-rc� �|djSr@r�r/s rr�zMailbox.addr_spec�s���A�w� � � rNr�rkrrrr�si���J�
�(��(��"��"������!��!��!��!rrc�0�eZdZdZed��ZexZxZxZZ	y)�InvalidMailboxr�c��yrrkr/s rr�zInvalidMailbox.display_name����rNr�rkrrr
r
�s/��"�J�
����/;�:�J�:��:�%�)rr
c�0��eZdZdZdZe�fd��Z�xZS)�Domainr�Fc�R��djt�|�j��S�Nr$�r.rr�splitr7s �rr�z
Domain.domain������w�w�u�w�}�*�*�,�-�-r)r5r_r`r[rDrcr�rdres@rrr�s����J��M�
�.��.rrc��eZdZdZy)�DotAtom�dot-atomNrurkrrrr�s���Jrrc��eZdZdZdZy)�DotAtomTextz
dot-atom-textTN�r5r_r`r[rDrkrrrr�s�� �J��Mrrc��eZdZdZdZy)�
NoFoldLiteralzno-fold-literalFNrrkrrrrs��"�J��Mrrc�T�eZdZdZdZed��Zed��Zed��Zed��Z	y)�AddrSpecr�Fc� �|djSr@r�r/s rr�zAddrSpec.local_partrrc�>�t|�dkry|djS)N�r�)r�r�r/s rr�zAddrSpec.domains���t�9�q�=���B�x���rc���t|�dkr|djS|djj�|djz|djj�zS)Nr rr�r�)r�r�rstrip�lstripr/s rrzAddrSpec.valuesU���t�9�q�=���7�=�=� ��A�w�}�}�#�#�%�d�1�g�m�m�3�D��G�M�M�4H�4H�4J�J�Jrc���t|j�}t|�t|tz
�kDrt	|j�}n|j}|j
�|dz|j
zS|S)N�@)�setr�r��
DOT_ATOM_ENDSrr�)r�nameset�lps   rr�zAddrSpec.addr_specs_���d�o�o�&���w�<�#�g�m�3�4�4��d�o�o�.�B����B��;�;�"���8�d�k�k�)�)��	rN)
r5r_r`r[rDrcr�r�rr�rkrrrrs\���J��M�
�"��"�����
�K��K�
���rrc��eZdZdZdZy)�ObsLocalPartzobs-local-partFNrrkrrr+r+(s��!�J��Mrr+c�@��eZdZdZdZed��Ze�fd��Z�xZS)�DisplayNamezdisplay-nameFc��t|�}t|�dk(r|jS|djdk(r|j	d�n)|ddjdk(rt|ddd�|d<|djdk(r|j	�|jS|ddjdk(rt|ddd�|d<|jS)Nrr�r�r�)rr�rr[�pop)rr�s  rr�zDisplayName.display_name3s�����o���s�8�q�=��9�9���q�6����&��G�G�A�J��1�v�a�y�#�#�v�-�"�3�q�6�!�"�:�.��A���r�7����'��G�G�I��y�y���2�w�r�{�%�%��/�#�C��G�C�R�L�1��B���y�y�rc�n��d}|jrd}n|D]}|jdk(s�d}�t|�dk7rs|rqdx}}|djdk(s|ddjdk(rd}|djdk(s|ddjdk(rd}|t|j�z|zSt
�|�S)	NFTr�rr$r�rjr�)rr[r�rr�rr)rr�r)�pre�postr"s     �rrzDisplayName.valueDs�������<�<��E��
!���<�<�?�2� �E�
!��t�9��>�e��O�C�$��A�w�!�!�6�)�T�!�W�Q�Z�-B�-B�F�-J����B�x�"�"�F�*�d�2�h�r�l�.E�.E�v�.M����|�D�$5�$5�6�6�t�;�;��7�=� r)	r5r_r`r[rbrcr�rrdres@rr-r-.s4����J���
���� �!��!rr-c�4�eZdZdZdZed��Zed��Zy)�	LocalPartz
local-partFc�b�|djdk(r|djS|djS)Nrr�)r[r�rr/s rrzLocalPart.value]s2����7����0���7�'�'�'���7�=�=� rc���tg}t}d}|dtgzD]�}|jdk(r�|r2|jdk(r#|djdk(rt|dd�|d<t|t�}|r?|jdk(r0|djdk(r|j	t|dd��n|j	|�|d}|}��t|dd�}|j
S)NFrr��dotr�r�)�DOTr[r�
isinstancer�r)rr��last�
last_is_tl�tok�is_tls      rr�zLocalPart.local_partds����e�����
���7�c�U�?�
	�C��~�~��'���s�~�~��6���H�'�'�6�1�#�D��"�I�.��B���s�I�.�E��$�/�/�U�2���F�%�%��/��
�
�9�S���W�-�.��
�
�3���r�7�D��J�
	���A�b�	�"���y�y�rN)r5r_r`r[rDrcrr�rkrrr4r4Xs2���J��M�
�!��!����rr4c�@��eZdZdZdZe�fd��Zed��Z�xZS)�
DomainLiteralzdomain-literalFc�R��djt�|�j��Srrr7s �rr�zDomainLiteral.domain�rrc�L�|D]}|jdk(s�|jcSy)N�ptextr�rps  r�ipzDomainLiteral.ip�s&���	�A��|�|�w�&��w�w��	r)	r5r_r`r[rDrcr�rCrdres@rr?r?|s3���!�J��M�
�.��.����rr?c��eZdZdZdZdZy)�MIMEVersionzmime-versionN)r5r_r`r[�major�minorrkrrrErE�s���J��E��ErrEc�<�eZdZdZdZdZdZed��Zed��Z	y)�	Parameter�	parameterF�us-asciic�<�|jr|djSdSr�)�	sectioned�numberr/s r�section_numberzParameter.section_number�s��"&���t�A�w�~�~�6�Q�6rc���|D]n}|jdk(r|jcS|jdk(s�0|D]:}|jdk(s�|D]#}|jdk(s�|jcccS�<�py)Nrr�r�r$)r[r�r�s  r�param_valuezParameter.param_value�s����	<�E����7�*��+�+�+����?�2�"�<�E��'�'�+?�?�%*�<�E�$�/�/�7�:�',�';�';� ;�<�<�		<�rN)
r5r_r`r[rM�extendedr�rcrOrQrkrrrIrI�s<���J��I��H��G�
�7��7�
���rrIc��eZdZdZy)�InvalidParameter�invalid-parameterNrurkrrrTrT�s��$�JrrTc� �eZdZdZed��Zy)�	Attribute�	attributec�d�|D]+}|jjd�s�|jcSy)N�attrtext)r[�endswithrr�s  rr�zAttribute.stripped_value�s/���	#�E����(�(��4��{�{�"�	#rN�r5r_r`r[rcr�rkrrrWrW�s���J�
�#��#rrWc��eZdZdZdZy)�Section�sectionN)r5r_r`r[rNrkrrr^r^�s���J�
�Frr^c� �eZdZdZed��Zy)�Valuerc��|d}|jdk(r|d}|jjd�r|jS|jS)Nrr�r�)r�rXzextended-attribute)r[r[r�rr�s  rr�zValue.stripped_value�sP���Q������v�%���G�E����$�$�D�F��'�'�'��z�z�rNr\rkrrrara�s���J�
���rrac�*�eZdZdZdZed��Zd�Zy)�MimeParameters�mime-parametersFc#�lK�i}|D]w}|jjd�s�|djdk7r�2|djj�}||vrg||<||j	|j
|f��y|j
�D�]�\}}t|td���}|dd}|j}|jsRt|�dkDrD|dddk(r9|ddjj	tjd��|dd}g}d}|D�]\}	}
|	|k7ri|
js/|
jj	tjd���G|
jj	tjd��|dz
}|
j}|
jrv	t j"j%|�}	|j'|d	�}t-j.|�r.|
jj	tj0��	|j	|���d
j5|�}||f�����y#t(t*f$r|j'd
d	�}Y��wxYw#t*$r$t j"j3|d��}Y��wxYw�w)NrJrrX)�keyr�z.duplicate parameter name; duplicate(s) ignoredz+duplicate parameter name; duplicate ignoredz(inconsistent RFC2231 parameter numbering�surrogateescaperKzlatin-1)�encodingr$)r[r[r�stripr�rO�items�sortedrr�rRr�rr�InvalidHeaderDefectrQ�urllib�parse�unquote_to_bytes�decode�LookupError�UnicodeEncodeErrorr�_has_surrogates�UndecodableBytesDefect�unquoter.)r�paramsrJ�name�parts�first_paramr��value_parts�irO�paramrs            rrwzMimeParameters.params�s��������	?�E��#�#�,�,�[�9���Q�x�"�"�k�1����8�>�>�'�'�)�D��6�!�!��t���4�L����!5�!5�u� =�>�	?�"�<�<�>�3	�K�D�%��5�j��m�4�E���(�1�+�K�!�)�)�G��'�'�C��J��N���8�A�;�!�#��!�H�Q�K�'�'�.�.�v�/I�/I�H�0J�K�!�"�1�I�E��K��A�).�!
*�%���!�Q�&�!�>�>��
�
�,�,�V�-G�-G�I�.K�L� ��
�
�,�,�V�-G�-G�F�.H�I��Q����)�)���>�>�R� &��� =� =�e� D��P�$)�L�L��:K�$L�E�!�0�0��7�!�M�M�0�0��1N�1N�1P�Q��"�"�5�)�C!
*�D�G�G�K�(�E���+��g3	��R!,�-?�@�P�
%*�L�L��=N�$O�E�P��.�P�!'��� 4� 4�U�Y� 4� O��	P�sI�F6J4�9J�I�+A2J4�!J�>J4�J�J4�*J1�.J4�0J1�1J4c	���g}|jD]C\}}|r+|jdj|t|����3|j|��Edj	|�}|rd|zSdS)N�{}={}z; rjr$)rwr�r4rr.)rrwrxrs    rr0zMimeParameters.__str__sj�����;�;�	$�K�D�%���
�
�g�n�n�T�<��3F�G�H��
�
�d�#�		$�
���6�"��%�s�V�|�-�2�-rN)r5r_r`r[rarcrwr0rkrrrdrd�s&��"�J��O�
�C��C�J.rrdc� �eZdZdZed��Zy)�ParameterizedHeaderValueFc�`�t|�D]}|jdk(s�|jcSiS)Nre)�reversedr[rwr�s  rrwzParameterizedHeaderValue.params/s5���d�^�	$�E����#4�4��|�|�#�	$��	rN)r5r_r`rarcrwrkrrr�r�)s���O�
���rr�c��eZdZdZdZdZdZy)�ContentTypezcontent-typeF�text�plainN)r5r_r`r[rD�maintype�subtyperkrrr�r�7s���J��M��H��Grr�c��eZdZdZdZdZy)�ContentDispositionzcontent-dispositionFN)r5r_r`r[rD�content_dispositionrkrrr�r�>s��&�J��M��rr�c��eZdZdZdZdZy)�ContentTransferEncodingzcontent-transfer-encodingF�7bitN)r5r_r`r[rDr�rkrrr�r�Ds��,�J��M�
�Crr�c��eZdZdZdZy)�HeaderLabelzheader-labelFNrrkrrr�r�Js���J��Mrr�c��eZdZdZdZd�Zy)�MsgIDzmsg-idFc�2�t|�|jzSr)r�lineseprOs  rrPz
MsgID.foldSs���4�y�6�>�>�)�)rN)r5r_r`r[rDrPrkrrr�r�Os���J��M�*rr�c��eZdZdZy)�	MessageIDz
message-idNrurkrrr�r�Xs���Jrr�c��eZdZdZy)�InvalidMessageIDzinvalid-message-idNrurkrrr�r�\s��%�Jrr�c��eZdZdZy)�Header�headerNrurkrrr�r�`ryrr�c�r��eZdZdZdZdZ�fd�Z�fd�Zd�Ze	d��Z
d
�fd�	Zd�Ze	d��Z
d	�Z�xZS)�TerminalTc�D��t�|�||�}||_g|_|Sr)r�__new__r[r)�clsrr[rr"s    �rr�zTerminal.__new__ns&����w��s�E�*��$�������rc�h��dj|jjt�|���Sr2r3r7s �rr6zTerminal.__repr__ts&������t�~�~�6�6���8H�8J�K�Krc�b�t|jjdz|jz�y)N�/)rTr"r5r[r/s rrWzTerminal.pprintws"��
�d�n�n�%�%��+�d�o�o�=�>rc�,�t|j�Sr)�listrr/s rr<zTerminal.all_defectszs���D�L�L�!�!rc	����dj||jj|jt�|��|jsd�gSdj|j��gS)Nz
{}{}/{}({}){}r$z {})r4r"r5r[rr6r)rrSr"s  �rrYzTerminal._pp~sg����&�&���N�N�#�#��O�O��G����l�l�B���	�
).���T�\�\�(B���	rc��yrrkr/s r�pop_trailing_wszTerminal.pop_trailing_ws�rrc��gSrrkr/s rrIzTerminal.comments�s���	rc�0�t|�|jfSr)rr[r/s r�__getnewargs__zTerminal.__getnewargs__�s���4�y�$�/�/�*�*rr^)r5r_r`rDrbrar�r6rWrcr<rYr�rIr�rdres@rr�r�hsZ����M����O��L�?��"��"�������+rr�c�"�eZdZed��Zd�Zy)�WhiteSpaceTerminalc��yrirkr/s rrzWhiteSpaceTerminal.value�rlrc��y)NTrkr/s rrAz!WhiteSpaceTerminal.startswith_fws�s��rN�r5r_r`rcrrArkrrr�r��s��
����rr�c�"�eZdZed��Zd�Zy)�
ValueTerminalc��|Srrkr/s rrzValueTerminal.value�s���rc��y)NFrkr/s rrAzValueTerminal.startswith_fws�s��rNr�rkrrr�r��s��
����rr�c�"�eZdZed��Zd�Zy)�EWWhiteSpaceTerminalc��yrrkr/s rrzEWWhiteSpaceTerminal.value�s��rc��yrrkr/s rr0zEWWhiteSpaceTerminal.__str__�s��rN)r5r_r`rcrr0rkrrr�r��s��
����rr�c��eZdZdZy)�_InvalidEwErrorz1Invalid encoded word found while parsing headers.N)r5r_r`�__doc__rkrrr�r��s��;rr�r7�,zlist-separatorFr%zroute-component-markerz([{}]+)r$z[^{}]+z[\x00-\x20\x7F]c��t|�}|r.|jjtj|��tj|�r/|jjtjd��yy)z@If input token contains ASCII non-printables, register a defect.z*Non-ASCII characters found in header tokenN)�_non_printable_finderrr�r�NonPrintableDefectrrtru)�xtext�non_printabless  r�_validate_xtextr��sc��+�5�1�N��
�
�
���V�6�6�~�F�G����U�#�
�
�
���V�:�:�8�:�	;�$rc�"�t|d�^}}g}d}d}tt|��D]6}||dk(r
|rd}d}nd}�|rd}n	|||vrn|j||��8dz}dj	|�dj	||dg|z�|fS)akScan printables/quoted-pairs until endchars and return unquoted ptext.

    This function turns a run of qcontent, ccontent-without-comments, or
    dtext-with-quoted-printables into a single string by unquoting any
    quoted printables.  It returns the string, the remaining value, and
    a flag that is True iff there were any quoted printables decoded.

    r�FrTr$N)�
_wsp_splitter�ranger�r�r.)r�endchars�fragment�	remainder�vchars�escape�had_qp�poss        r�_get_ptext_to_endcharsr��s���)���2��H�y�
�F�
�F�
�F��S��]�#����C�=�D� �����������F�
�c�]�h�
&���
�
�h�s�m�$���A�g��
�7�7�6�?�B�G�G�X�c�d�^�$4�y�$@�A�6�I�Irc�r�|j�}t|dt|�t|�z
d�}||fS)z�FWS = 1*WSP

    This isn't the RFC definition.  We're using fws to represent tokens where
    folding can be done, but when we are parsing the *un*folding has already
    been done so we don't need to watch out for CRLF.

    N�fws)r#r�r�)r�newvaluer�s   r�get_fwsr�s:���|�|�~�H�
�U�#<�C��J�s�8�}�$<�=�u�
E�C���=�rc��t�}|jd�s$tjdj	|���|ddjdd�^}}||ddk(r$tjdj	|���dj
|�}t|�dkDrF|dtvr;|dtvr0|jd	�dkr|jdd�^}}|dz|z}t|j��dkDr.|jjtjd
��||_
dj
|�}	tjd|zdz�\}}}}	||_||_|jj+|	�|ru|dt,vr t/|�\}
}|j|
��-t1|d�^}}t3|d�}t5|�|j|�dj
|�}|r�u|r9|dt,vr.|jjtjd
��||fS#t t"f$r%t%dj	|j���wxYw)zE encoded-word = "=?" charset "?" encoding "?" encoded-text "?="

    �=?z"expected encoded word but found {}r�Nz?=r�r$r�?zwhitespace inside encoded wordz!encoded word format invalid: '{}'�vtextz.missing trailing whitespace after encoded-word)r��
startswithr�HeaderParseErrorr4rr.r�r�countrr�rmr��_ewrq�
ValueError�KeyErrorr�r�r�rH�WSPr�r�r�r�)
r�ewr<r��remstr�restr�r�r�rrJ�charsr�s
             r�get_encoded_wordr�s`��
��B����D�!��%�%�0�7�7��>�@�	@��A�B�i�o�o�d�A�.�O�C�)�
�e�A�B�i���%�%�0�7�7��>�@�	@�
�W�W�Y�
�F��F��a���q�	�Y���q�	�Y���	�	�#����!�<�<��a�0���y��D�j�4���
�3�9�9�;��!��
�
�
���&�4�4�,�.�	/�
�B�F��G�G�I��E�@�'*�z�z�$��*�t�2C�'D�$��g�t�W��B�J��B�G��J�J���g��
���7�c�>�!�$�-�K�E�4��I�I�e���)�$��2���	��e�W�-�����
�	�	�%���w�w�y�!���
��q���$�
�
�
���&�4�4�<�>�	?�
�u�9���)
��!�@��/�6�6�r�v�v�>�@�	@�@�s� I
�
4I>c��t�}|�rZ|dtvr t|�\}}|j|��.d}|j	d�r�	t|�\}}d}t
|�dkDrB|djdk7r0|jjtjd��d}|r2t
|�dkDr$|d	jd
k(rt|dd�|d<|j|���t|d�^}}|r(tj!|�r|j#d�^}}t%|d�}t'|�|j|�dj)|�}|r��Z|S#t$rd}Y��tj$rY��wxYw)
aOunstructured = (*([FWS] vchar) *WSP) / obs-unstruct
       obs-unstruct = *((*LF *CR *(obs-utext) *LF *CR)) / FWS)
       obs-utext = %d0 / obs-NO-WS-CTL / LF / CR

       obs-NO-WS-CTL is control characters except WSP/CR/LF.

    So, basically, we have printable runs, plus control characters or nulls in
    the obsolete syntax, separated by whitespace.  Since RFC 2047 uses the
    obsolete syntax in its specification, but requires whitespace on either
    side of the encoded words, I can see no reason to need to separate the
    non-printable-non-whitespace from the printable runs if they occur, so we
    parse this into xtext tokens separated by WSP tokens.

    Because an 'unstructured' value must by definition constitute the entire
    value, this 'get' routine does not return a remaining value, only the
    parsed TokenList.

    rTr�r�r�z&missing whitespace before encoded wordFr����r�r�r$)rsr�r�r�r�r�r�r[rrrmr�r�r�r��rfc2047_matcher�search�	partitionr�r�r.)rrtrJ�valid_ew�have_wsr<r�r�s        r�get_unstructuredr�Bs���.)�*�L�
���8�s�?�"�5�>�L�E�5�����&�������D�!�
�/��6���u����|�$�q�(�#�B�'�2�2�e�;�$�,�,�3�3�F�4N�4N�D�5F�G�"'���s�<�0�1�4�#�B�'�2�2�n�D�+?�(��,�e�,5��R�(��#�#�E�*��'��q�1���i���.�.�s�3�#�o�o�d�3�O�C�)��c�7�+��������E�"����	�"��Q�R���A#�
!� ���*�*�
��
�s�
E*�*F�7F�Fc�X�t|d�\}}}t|d�}t|�||fS)actext = <printable ascii except \ ( )>

    This is not the RFC ctext, since we are handling nested comments in comment
    and unquoting quoted-pairs here.  We allow anything except the '()'
    characters, but if we find any ASCII other than the RFC defined printable
    ASCII, a NonPrintableDefect is added to the token's defects list.  Since
    quoted pairs are converted to their unquoted values, what is returned is
    a 'ptext' token.  In this case it is a WhiteSpaceTerminal, so it's value
    is ' '.

    z()rB)r�r�r��rrB�_s   r�get_qp_ctextr��s4��-�U�D�9�O�E�5�!��u�g�.�E��E���%�<�rc�X�t|d�\}}}t|d�}t|�||fS)aoqcontent = qtext / quoted-pair

    We allow anything except the DQUOTE character, but if we find any ASCII
    other than the RFC defined printable ASCII, a NonPrintableDefect is
    added to the token's defects list.  Any quoted pairs are converted to their
    unquoted values, so what is returned is a 'ptext' token.  In this case it
    is a ValueTerminal.

    rrB)r�r�r�r�s   r�get_qcontentr��s4��-�U�C�8�O�E�5�!��%��)�E��E���%�<�rc���t|�}|s$tjdj|���|j	�}|t|�d}t
|d�}t|�||fS)z�atext = <matches _atext_matcher>

    We allow any non-ATOM_ENDS in atext, but add an InvalidATextDefect to
    the token's defects list if we find non-atext characters.
    zexpected atext but found '{}'N�atext)�_non_atom_end_matcherrr�r4r�r�r�r�)r�mr�s   r�	get_atextr��sk��	�e�$�A���%�%�+�2�2�5�9�;�	;�
�G�G�I�E��#�e�*�+��E��%��)�E��E���%�<�rc�J�|ddk7r$tjdj|���t�}|dd}|r'|ddk(rt	|�\}}|j|�|r�|ddk7r�|dtvrt|�\}}n�|dddk(r�d}	t|�\}}|jjtjd	��d
}|rSt|�dkDrE|djdk(r3|d
jdk(r!t|dd�|d<nt	|�\}}|j|�|r	|ddk7r��|s2|jjtjd��||fS||ddfS#tj$rt	|�\}}Y��wxYw)z�bare-quoted-string = DQUOTE *([FWS] qcontent) [FWS] DQUOTE

    A quoted-string without the leading or trailing white space.  Its
    value is the text between the quote marks, with whitespace
    preserved and quoted pairs decoded.
    rrzexpected '"' but found '{}'r�Nr�r�Fz!encoded word inside quoted stringTr�r�r�r�z"end of header inside quoted string)rr�r4r�r�r�r�r�r�rrmr�r[r�)r�bare_quoted_stringrJr�s    r�get_bare_quoted_stringr��s���
�Q�x�3���%�%�*�1�1�%�8�:�	:�)�+���!�"�I�E���q��S��#�E�*���u��!�!�%�(�
�E�!�H��O���8�s�?�"�5�>�L�E�5�
�2�A�Y�$�
��H�
3�/��6���u�"�*�*�1�1�&�2L�2L�7�39�:���
�C� 2�3�a�7�&�r�*�5�5��>�*�2�.�9�9�^�K�-A�*�2�.��.7�&�r�*�(��.�L�E�5��!�!�%�(�+�E�!�H��O�,��"�"�)�)�&�*D�*D�0�+2�	3�!�5�(�(��u�Q�R�y�(�(��!�*�*�
3�+�E�2���u�
3�s�>E>�>!F"�!F"c��|r,|ddk7r$tjdj|���t�}|dd}|rc|ddk7r[|dtvrt|�\}}n%|ddk(rt
|�\}}nt|�\}}|j|�|r	|ddk7r�[|s2|jjtjd��||fS||ddfS)z�comment = "(" *([FWS] ccontent) [FWS] ")"
       ccontent = ctext / quoted-pair / comment

    We handle nested comments here, and quoted-pair in our qp-ctext routine.
    rrzexpected '(' but found '{}'r�Nr�zend of header inside comment)rr�r4r�r�r��get_commentr�r�rrm)rrnrJs   rr�r��s���
��q��S���%�%�)�0�0��7�9�	9��i�G��!�"�I�E�
�E�!�H��O���8�s�?�"�5�>�L�E�5�
�1�X��_�&�u�-�L�E�5�'��.�L�E�5����u���E�!�H��O�������v�9�9�*� ,�	-���~���E�!�"�I��rc���t�}|rR|dtvrG|dtvrt|�\}}nt	|�\}}|j|�|r|dtvr�G||fS)z,CFWS = (1*([FWS] comment) [FWS]) / FWS

    r)r�CFWS_LEADERr�r�r�r�)rr�rJs   r�get_cfwsr��sg���:�D�
�E�!�H��+���8�s�?�"�5�>�L�E�5�&�u�-�L�E�5����E���E�!�H��+���;�rc��t�}|r*|dtvrt|�\}}|j|�t	|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS)z�quoted-string = [CFWS] <bare-quoted-string> [CFWS]

    'bare-quoted-string' is an intermediate class defined by this
    parser and not by the RFC grammar.  It is the quoted string
    without any attached CFWS.
    r)r�r�r�r�r�)r�
quoted_stringrJs   r�get_quoted_stringrs���!�N�M���q��[�(������u����U�#�)�%�0�L�E�5��������q��[�(������u����U�#��%��rc��t�}|r*|dtvrt|�\}}|j|�|r/|dtvr$tjdj|���|jd�r	t|�\}}nt|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS#t
j$rt|�\}}Y�dwxYw)zPatom = [CFWS] 1*atext [CFWS]

    An atom could be an rfc2047 encoded word.
    rzexpected atom but found '{}'r�)r�r�r�r��	ATOM_ENDSrr�r4r�r�r�)rr�rJs   r�get_atomrs���
�6�D���q��[�(������u����E����q��Y�&��%�%�*�1�1�%�8�:�	:������	,�+�E�2�L�E�5�!��'���u��K�K�����q��[�(������u����E����;����&�&�	,�%�U�+�L�E�5�	,�s�:C�!C<�;C<c��t�}|r|dtvr$tjdj	|���|r\|dtvrQt|�\}}|j
|�|r"|ddk(r|j
t�|dd}|r|dtvr�Q|dtur'tjdj	d|z���||fS)z( dot-text = 1*atext *("." 1*atext)

    rz8expected atom at a start of dot-atom-text but found '{}'r	r�Nr�z4expected atom at end of dot-atom-text but found '{}')rrrr�r4r�r�r8)r�
dot_atom_textrJs   r�get_dot_atom_textr3s��� �M�M��E�!�H�	�)��%�%�'+�+1�6�%�=�:�	:�
�E�!�H�I�-� ��'���u����U�#��U�1�X��_�� � ��%��!�"�I�E��E�!�H�I�-��R��C���%�%�'�#�V�C��I�.�0�	0��%��rc��t�}|dtvrt|�\}}|j|�|j	d�r	t|�\}}nt|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS#tj$rt|�\}}Y�dwxYw)z� dot-atom = [CFWS] dot-atom-text [CFWS]

    Any place we can have a dot atom, we could instead have an rfc2047 encoded
    word.
    rr�)	rr�r�r�r�r�rr�r)r�dot_atomrJs   r�get_dot_atomr	Fs����y�H��Q�x�;�������u�����������	4�+�E�2�L�E�5�)��/���u��O�O�E����q��[�(������u�������U�?����&�&�	4�-�U�3�L�E�5�	4�s�B%�%!C	�C	c�(�|dtvrt|�\}}nd}|stjd��|ddk(rt	|�\}}n=|dt
vr$tjdj
|���t|�\}}|�|g|dd||fS)a�word = atom / quoted-string

    Either atom or quoted-string may start with CFWS.  We have to peel off this
    CFWS first to determine which type of word to parse.  Afterward we splice
    the leading CFWS, if any, into the parsed sub-token.

    If neither an atom or a quoted-string is found before the next special, a
    HeaderParseError is raised.

    The token returned is either an Atom or a QuotedString, as appropriate.
    This means the 'word' level of the formal grammar is not represented in the
    parse tree; this is because having that extra layer when manipulating the
    parse tree is more confusing than it is helpful.

    rNz5Expected 'atom' or 'quoted-string' but found nothing.rz1Expected 'atom' or 'quoted-string' but found '{}')r�r�rr�r�SPECIALSr4r)r�leaderrJs   r�get_wordr
_s��� 
�Q�x�;�� ���
�������%�%�C�E�	E��Q�x��}�(��/���u�	�q��X�	��%�%�'7�7=�v�e�}�F�	F� �����u�
���H��b�q�	��%�<�rc���t�}	t|�\}}|j|�|r�|dtvr|ddk(rI|jt�|j
jtjd��|dd}n 	t|�\}}|j|�|r|dtvr�||fS#tj$r1|j
jtjd��Y��wxYw#tj$rL|dtvr=t|�\}}|j
jtjd��n�Y��wxYw)a� phrase = 1*word / obs-phrase
        obs-phrase = word *(word / "." / CFWS)

    This means a phrase can be a sequence of words, periods, and CFWS in any
    order as long as it starts with at least one word.  If anything other than
    words is detected, an ObsoleteHeaderDefect is added to the token's defect
    list.  We also accept a phrase that starts with CFWS followed by a dot;
    this is registered as an InvalidHeaderDefect, since it is not supported by
    even the obsolete grammar.

    zphrase does not start with wordrr	zperiod in 'phrase'r�Nzcomment found without atom)rwr
r�rr�rrm�PHRASE_ENDSr8�ObsoleteHeaderDefectr�r�)rrxrJs   r�
get_phraser�sM���X�F�0������u��
�
�e���E�!�H�K�/���8�S�=��M�M�#���N�N�!�!�&�"=�"=�$�#&�
'��!�"�I�E�
�'�����u�
�M�M�%� �!�E�!�H�K�/�"�5�=���)�"�"�0������f�8�8�-�/�	0�0���*�*�
���8�{�*�#+�E�?�L�E�5��N�N�)�)�&�*E�*E�4�+6�7��7�
�s%�B;�
D�;AC?�>C?�AE!� E!c��t�}d}|dtvrt|�\}}|s$tjdj|���	t
|�\}}|�|g|dd|j|�|r�|ddk(s|dtvr�tt|�|z�\}}|jdk(r/|jjtjd��n.|jjtj d��||d<	|j"j%d�||fS#tj$rK	t|�\}}n7#tj$r!|ddk7r|dtvr�t�}YnwxYwY��6wxYw#t&$r4|jjtj(d	��Y||fSwxYw)
z= local-part = dot-atom / quoted-string / obs-local-part

    Nrz"expected local-part but found '{}'r�invalid-obs-local-partz<local-part is not dot-atom, quoted-string, or obs-local-partz,local-part is not a dot-atom (contains CFWS)�asciiz)local-part contains non-ASCII characters))r4r�r�rr�r4r	r
rrr��get_obs_local_partrr[rrmrr�encoders�NonASCIILocalPartDefect)rr�rrJ�obs_local_parts     r�get_local_partr�s�����J�
�F��Q�x�;�� ���
�����%�%�0�7�7��>�@�	@� �#�E�*���u����H��b�q�	����e���%��(�D�.�E�!�H�K�$?� 2�3�z�?�U�3J� K�����$�$�(@�@����%�%�f�&@�&@�N�'P�
Q�
���%�%�f�&A�&A�>�'@�
A�&�
�1�
�>�������(��u����1�"�"� �	 �#�E�?�L�E�5���&�&�	 ��Q�x�4��E�!�H��$;���K�E�	 �� ��*�>����!�!�&�"@�"@�;�#=�	>��u���>�sH�
D4�F�4F�E�F�1F�F�
F�F�F�7G�Gc���t�}d}|�rB|ddk(s|dtv�r.|ddk(rM|r.|jjt	j
d��|jt�d}|dd}�l|ddk(rT|jt|dd	��|dd}|jjt	j
d
��d}��|r@|djdk7r.|jjt	j
d
��	t|�\}}d}|j|�|r|ddk(r��!|dtvr��.|djdk(s$|djdk(r@|djdk(r.|jjt	j
d��|djdk(s$|djdk(r@|djdk(r.|jjt	j
d��|jrd|_||fS#tj$r|dtvr�t|�\}}Y��9wxYw)z' obs-local-part = word *("." word)
    Frrr	zinvalid repeated '.'Tr�N�misplaced-specialz/'\' character outside of quoted-string/ccontentr�r7zmissing '.' between wordsr�z!Invalid leading '.' in local partr�z"Invalid trailing '.' in local partr)
r+rrr�rrmr8r�r[r
r�r�r�)rr�last_non_ws_was_dotrJs    rrr�sh��"�^�N���
�U�1�X�t�^�u�Q�x�{�'B���8�s�?�"��&�&�-�-�f�.H�.H�*�/,�-��!�!�#�&�"&���!�"�I�E��
�1�X�t�^��!�!�-��a��0C�#E�
F��!�"�I�E��"�"�)�)�&�*D�*D�B�+D�
E�"'����n�R�0�;�;�u�D��"�"�)�)�&�*D�*D�+�+-�
.�	+�#�E�?�L�E�5�"'��
	���e�$�7�U�1�X�t�^�u�Q�x�{�'B�8	�q��$�$��-��1��(�(�&�0��1��(�(�%�/����%�%�f�&@�&@�/�'1�	2��r��%�%��.��2��)�)�6�1��2��)�)�5�0����%�%�f�&@�&@�0�'2�	3����$<��!��5� � ��#�&�&�	+��Q�x�{�*��#�E�?�L�E�5�	+�s�H1�1-I"�!I"c��t|d�\}}}t|d�}|r.|jjt	j
d��t
|�||fS)a dtext = <printable ascii except \ [ ]> / obs-dtext
        obs-dtext = obs-NO-WS-CTL / quoted-pair

    We allow anything except the excluded characters, but if we find any
    ASCII other than the RFC defined printable ASCII, a NonPrintableDefect is
    added to the token's defects list.  Quoted pairs are converted to their
    unquoted values, so what is returned is a ptext token, in this case a
    ValueTerminal.  If there were quoted-printables, an ObsoleteHeaderDefect is
    added to the returned token's defect list.

    z[]rBz(quoted printable found in domain-literal)r�r�rr�rrr�)rrBr�s   r�	get_dtextr�sZ��2�%��>��E�5�&��%��)�E�
�
�
�
���V�8�8�6�8�	9��E���%�<�rc��|ry|jtjd��|jtdd��y)NFz"end of input inside domain-literal�]�domain-literal-endT)r�rrmr�)r�domain_literals  r�_check_for_early_dl_endr#s?�������&�4�4�,�.�/����-��-A�B�C�rc�n�t�}|dtvrt|�\}}|j|�|st	j
d��|ddk7r$t	j
dj
|���|dd}t||�r||fS|jtdd��|dtvrt|�\}}|j|�t|�\}}|j|�t||�r||fS|dtvrt|�\}}|j|�t||�r||fS|ddk7r$t	j
d	j
|���|jtdd
��|dd}|r*|dtvrt|�\}}|j|�||fS)zB domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]

    rzexpected domain-literal�[z6expected '[' at start of domain-literal but found '{}'r�Nzdomain-literal-startr z4expected ']' at end of domain-literal but found '{}'r!)r?r�r�r�rr�r4r#r�r�r�r)rr"rJs   r�get_domain_literalr&s���#�_�N��Q�x�;�������u����e�$���%�%�&?�@�@��Q�x�3���%�%�'!�!'����0�	0��!�"�I�E��u�n�5��u�$�$����-��-C�D�E��Q�x�3���u�~���u����e�$��U�#�L�E�5����%� ��u�n�5��u�$�$��Q�x�3���u�~���u����e�$��u�n�5��u�$�$��Q�x�3���%�%�'!�!'����0�	0����-��-A�B�C��!�"�I�E���q��[�(������u����e�$��5� � rc��t�}d}|dtvrt|�\}}|s$tjdj|���|ddk(r+t
|�\}}|�|g|dd|j|�||fS	t|�\}}|r|ddk(rtjd��|�|g|dd|j|�|r�|ddk(r�|jjtjd��|djd	k(r|d|dd|rJ|ddk(rB|jt�t|d
d�\}}|j|�|r	|ddk(r�B||fS#tj$rt|�\}}Y��wxYw)z] domain = dot-atom / domain-literal / obs-domain
        obs-domain = atom *("." atom))

    Nrzexpected domain but found '{}'r%r%zInvalid Domainr	z(domain is not a dot-atom (contains CFWS)rr�)rr�r�rr�r4r&r�r	rrrr[r8)rr�rrJs    r�
get_domainr(@s���
�X�F�
�F��Q�x�;�� ���
�����%�%�,�3�3�E�:�<�	<��Q�x�3��)�%�0���u�����E�"�1�I��
�
�e���u�}��'�#�E�*���u�
��q��S���%�%�&6�7�7�
���H��b�q�	�
�M�M�%����q��S�������f�9�9�6�8�	9��!�9���:�-��q�	�F�1�I���a��C���M�M�#��#�E�!�"�I�.�L�E�5��M�M�%� ���a��C���5�=���!�"�"�'������u�'�s�E(�(!F�Fc�N�t�}t|�\}}|j|�|r|ddk7r2|jjt	j
d��||fS|jt
dd��t|dd�\}}|j|�||fS)z( addr-spec = local-part "@" domain

    rr%z#addr-spec local part with no domain�address-at-symbolr�N)rrr�rrrmr�r()rr�rJs   r�
get_addr_specr+fs����
�I�!�%�(�L�E�5�
���U���E�!�H��O���� � ��!;�!;�1�"3�	4��%���
���]�3�(;�<�=��e�A�B�i�(�L�E�5�
���U���e��rc���t�}|rw|ddk(s|dtvrd|dtvr t|�\}}|j|�n"|ddk(r|jt�|dd}|r|ddk(r�X|dtvr�d|r|ddk7r$tjdj|���|jt�t|dd�\}}|j|�|r�|ddk(r�|jt�|dd}|snt|dtvrt|�\}}|j|�|ddk(r7|jt�t|dd�\}}|j|�|r	|ddk(r��|stjd��|ddk7r$tjd	j|���|jtdd
��||ddfS)z� obs-route = obs-domain-list ":"
        obs-domain-list = *(CFWS / ",") "@" domain *("," [CFWS] ["@" domain])

        Returns an obs-route token with the appropriate sub-tokens (that is,
        there is no obs-domain-list in the parse tree).
    rr�r�Nr%z(expected obs-route domain but found '{}'z%end of header while parsing obs-route�:z4expected ':' marking end of obs-route but found '{}'zend-of-obs-route-marker)r�r�r�r��
ListSeparatorrr�r4�RouteComponentMarkerr(r�)r�	obs_routerJs   r�
get_obs_router1vs����
�I�
�U�1�X�s�]�e�A�h�+�&=���8�{�"�#�E�?�L�E�5����U�#�
�1�X��_����]�+��!�"�I�E�
�U�1�X�s�]�e�A�h�+�&=��E�!�H��O��%�%�6�=�=�e�D�F�	F�
���)�*��e�A�B�i�(�L�E�5�
���U��
�E�!�H�c�M�����'��a�b�	������8�{�"�#�E�?�L�E�5����U�#���8�s�?����1�2�%�e�A�B�i�0�L�E�5����U�#��E�!�H�c�M���%�%�&M�N�N��Q�x�3���%�%�('�'-�v�e�}�6�	6�
���]�3�(A�B�C��e�A�B�i��rc�p�t�}|dtvrt|�\}}|j|�|r|ddk7r$t	j
dj
|���|jtdd��|dd}|ddk(rR|jtdd��|jjt	jd	��|dd}||fS	t|�\}}|j|�|r|ddk(r|dd}n.|jjt	jd��|jtdd��|r*|dtvrt|�\}}|j|�||fS#tj
$r�	t|�\}}|jjt	jd
��n;#tj
$r%t	j
dj
|���wxYw|j|�t|�\}}Y��HwxYw)
z� angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
        obs-angle-addr = [CFWS] "<" obs-route addr-spec ">" [CFWS]

    r�<z"expected angle-addr but found '{}'zangle-addr-startr�N�>zangle-addr-endznull addr-spec in angle-addrz*obsolete route specification in angle-addrz.expected addr-spec or obs-route but found '{}'z"missing trailing '>' on angle-addr)
r�r�r�r�rr�r4r�rrmr+r1r)r�
angle_addrrJs   r�get_angle_addrr6�s0��
��J��Q�x�;�������u����%� ��E�!�H��O��%�%�0�7�7��>�@�	@����m�C�);�<�=��!�"�I�E�
�Q�x�3�����-��-=�>�?����!�!�&�"<�"<�*�#,�	-��a�b�	���5� � �,�$�U�+���u����e����q��S���a�b�	�����!�!�&�"<�"<�0�#2�	3����m�C�)9�:�;���q��[�(������u����%� ��u����)�"�"�	,�	P�(��/�L�E�5����%�%�f�&A�&A�<�'>�
?���&�&�	P��)�)�@�G�G��N�P�
P�	P��	���%� �$�U�+���u�	,�s*�F�H5�<G�H5�8H�"H5�4H5c��t�}t|�\}}|j|dd�|jdd|_||fS)z� display-name = phrase

    Because this is simply a name-rule, we don't return a display-name
    token containing a phrase, but rather a display-name token with
    the content of the phrase.

    N)r-rrHr)rr�rJs   r�get_display_namer8�sG���=�L��e�$�L�E�5�����a��!� �=�=��+�L�����rc��t�}d}|dtvr4t|�\}}|s$tjdj|���|ddk7r�|dtvr$tjdj|���t|�\}}|s$tjdj|���|�|g|dddd}|j|�t|�\}}|�|g|dd|j|�||fS)z, name-addr = [display-name] angle-addr

    Nrz!expected name-addr but found '{}'r3)
r�r�r�rr�r4rr8r�r6)r�	name_addrrrJs    r�
get_name_addrr;�s!���
�I�
�F��Q�x�;�� ���
�����)�)�3�:�:�6�B�D�
D��Q�x�3����8�{�"��)�)�3�:�:�5�A�C�
C�'��.���u���)�)�3�:�:�5�A�C�
C���"�8�E�!�H�R�a�L��F������!�%�(�L�E�5�
���H��b�q�	�
���U���e��rc�l�t�}	t|�\}}t
d�|jD��rd|_|j|�||fS#tj$rN	t	|�\}}n;#tj$r%tjdj|���wxYwY��wxYw)z& mailbox = name-addr / addr-spec

    zexpected mailbox but found '{}'c3�PK�|]}t|tj���� y�wr)r9rrmr's  rr*zget_mailbox.<locals>.<genexpr>	s%����3���a��3�3�4�3���$&r�)
rr;rr�r+r4�anyr<r[r�)rr�rJs   r�get_mailboxr@�s����i�G�A�$�U�+���u��3� %� 1� 1�3�3�.����N�N�5���E�>����"�"�A�	A�(��/�L�E�5���&�&�	A��)�)�1�8�8��?�A�
A�	A���A�s)�A�B3�&A5�4B3�58B-�-B3�2B3c���t�}|r_|d|vrX|dtvr$|jt|dd��|dd}nt	|�\}}|j|�|r|d|vr�X||fS)z� Read everything up to one of the chars in endchars.

    This is outside the formal grammar.  The InvalidMailbox TokenList that is
    returned acts like a Mailbox, but the data attributes are None.

    rrr�N)r
rr�r�r)rr��invalid_mailboxrJs    r�get_invalid_mailboxrCs���%�&�O�
�E�!�H�H�,���8�{�"��"�"�=��q��1D�$F�
G��!�"�I�E�%�e�,�L�E�5��"�"�5�)��E�!�H�H�,��E�!�!rc�\�t�}|r�|ddk7r�	t|�\}}|j|�|ra|ddvrZ|d}d	|_t|d�\}}|j|�|jjtjd��|r"|ddk(r|jt�|d
d}|r	|ddk7r��||fS#tj$�rLd}|dt
vr�t
|�\}}|r|ddvr@|j|�|jjtjd��n�t|d�\}}|�|g|dd|j|�|jjtjd��n�|ddk(r/|jjtjd��nVt|d�\}}|�|g|dd|j|�|jjtjd��Y���wxYw)aJ mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
        obs-mbox-list = *([CFWS] ",") mailbox *("," [mailbox / CFWS])

    For this routine we go outside the formal grammar in order to improve error
    handling.  We recognize the end of the mailbox list only at the end of the
    value or at a ';' (the group terminator).  This is so that we can turn
    invalid mailboxes into InvalidMailbox tokens and continue parsing any
    remaining valid mailboxes.  We also allow all mailbox entries to be null,
    and this condition is handled appropriately at a higher level.

    r�;Nz,;zempty element in mailbox-listzinvalid mailbox in mailbox-listr�r�r�r�)r�r@r�rr�r�r�rrrCrmr[rHr.)r�mailbox_listrJrr�s     r�get_mailbox_listrG!s5���=�L�
�E�!�H��O�	8�&�u�-�L�E�5�����&�4�U�1�X�T�)�#�2�&�G�!2�G��.�u�d�;�L�E�5��N�N�5�!�� � �'�'��(B�(B�1�)3�
4��U�1�X��_����
�.��!�"�I�E�Q�E�!�H��O�R�����K�&�&�	8��F��Q�x�;�&� (���
�����a��D� 0� �'�'��/� �(�(�/�/��0K�0K�7�19�:�$7�u�d�#C�L�E�5��)�%+�H��b�q�	� �'�'��.� �(�(�/�/��0J�0J�9�1;�<��q��S���$�$�+�+�F�,G�,G�3�-5�6� 3�5�$�?���u��%�!'��E�"�1�I��#�#�E�*��$�$�+�+�F�,F�,F�5�-7�8��/	8�s�C�EH+�*H+c��t�}|s2|jjtjd��||fSd}|r{|dt
vrpt
|�\}}|sC|jjtjd��|j|�||fS|ddk(r|j|�||fSt|�\}}t|j�dk(rV|�|j|�|j|�|jjtjd��||fS|�|g|dd|j|�||fS)zg group-list = mailbox-list / CFWS / obs-group-list
        obs-group-list = 1*([CFWS] ",") [CFWS]

    zend of header before group-listNrzend of header in group-listrEzgroup-list with empty entries)r�rr�rrmr�r�rGr�r�rHr)r�
group_listrrJs    r�get_group_listrJZsa��
��J�����!�!�&�"<�"<�-�#/�	0��5� � �
�F���q��[�(� ���
����
���%�%�f�&@�&@�-�'/�
0����f�%��u�$�$���8�s�?����f�%��u�$�$�#�E�*�L�E�5�
�5�����"������f�%����%� ����!�!�&�"=�"=�+�#-�	.��5� � �
���H��b�q�	����e���u��rc���t�}t|�\}}|r|ddk7r$tjdj	|���|j|�|jt
dd��|dd}|r*|ddk(r"|jt
dd��||ddfSt|�\}}|j|�|s/|jjtjd	��n,|ddk7r$tjd
j	|���|jt
dd��|dd}|r*|dtvrt|�\}}|j|�||fS)z7 group = display-name ":" [group-list] ";" [CFWS]

    rr-z8expected ':' at end of group display name but found '{}'zgroup-display-name-terminatorr�NrEzgroup-terminatorzend of header in groupz)expected ';' at end of group but found {})r�r8rr�r4r�r�rJrrmr�r�)rr�rJs   r�	get_grouprLsa��
�G�E�#�E�*�L�E�5��E�!�H��O��%�%�'*�*0�&��-�9�	9�	�L�L���	�L�L��s�$C�D�E��!�"�I�E���q��S��
���]�3�(:�;�<��e�A�B�i���!�%�(�L�E�5�	�L�L����
�
�
���V�7�7�$�&�	'�	�q��S���%�%�7�>�>�u�E�G�	G�	�L�L��s�$6�7�8��!�"�I�E���q��[�(������u�
���U���%�<�rc�&�t�}	t|�\}}|j
|�||fS#tj$rN	t	|�\}}n;#tj$r%tjdj|���wxYwY�uwxYw)a� address = mailbox / group

    Note that counter-intuitively, an address can be either a single address or
    a list of addresses (a group).  This is why the returned Address object has
    a 'mailboxes' attribute which treats a single address as a list of length
    one.  When you need to differentiate between to two cases, extract the single
    element, which is either a mailbox or a group token.

    zexpected address but found '{}')r�rLrr�r@r4r�)rr�rJs   r�get_addressrN�s���"�i�G�A� ��'���u��N�N�5���E�>����"�"�A�	A�&�u�-�L�E�5���&�&�	A��)�)�1�8�8��?�A�
A�	A���A�s'�/�B�A�B�8B
�
B�Bc�^�t�}|r�	t|�\}}|j|�|re|ddk7r]|dd}d|_t|d�\}}|j|�|jjtjd��|r|jt�|d	d}|r��||fS#tj$�rad}|dt
vr�t
|�\}}|r|ddk(r@|j|�|jjtjd��n�t|d�\}}|�|g|dd|jt|g��|jjtjd��n�|ddk(r/|jjtjd��n`t|d�\}}|�|g|dd|jt|g��|jjtjd��Y���wxYw)
a� address_list = (address *("," address)) / obs-addr-list
        obs-addr-list = *([CFWS] ",") address *("," [address / CFWS])

    We depart from the formal grammar here by continuing to parse until the end
    of the input, assuming the input to be entirely composed of an
    address-list.  This is always true in email parsing, and allows us
    to skip invalid addresses to parse additional valid ones.

    Nrr�z"address-list entry with no contentzinvalid address in address-listzempty element in address-listr�r�r�)r�rNr�rr�r�r�rrrCr�rmr[rHr.)r�address_listrJrr�s     r�get_address_listrQ�s(���=�L�
�	8�&�u�-�L�E�5�����&�4�U�1�X��_�#�2�&�q�)�G�!2�G��.�u�c�:�L�E�5��N�N�5�!�� � �'�'��(B�(B�1�)3�
4�����
�.��!�"�I�E�Q�R�����K�&�&�	8��F��Q�x�;�&� (���
�����a��C�� �'�'��/� �(�(�/�/��0K�0K�<�1>�?�$7�u�c�#B�L�E�5��)�%+�H��b�q�	� �'�'����(8�9� �(�(�/�/��0J�0J�9�1;�<��q��S���$�$�+�+�F�,G�,G�3�-5�6� 3�5�#�>���u��%�!'��E�"�1�I��#�#�G�U�G�$4�5��$�$�+�+�F�,F�,F�5�-7�8��/	8�s�B7�7E1H,�+H,c���t�}|s$tjdj|���|ddk7r$tjdj|���|j	tdd��|dd}t
|�\}}|j	|�|r|ddk7r$tjd	j|���|j	tdd
��||ddfS)z& no-fold-literal = "[" *dtext "]"
    z'expected no-fold-literal but found '{}'rr%z;expected '[' at the start of no-fold-literal but found '{}'zno-fold-literal-startr�Nr z9expected ']' at the end of no-fold-literal but found '{}'zno-fold-literal-end)rrr�r4r�r�r)r�no_fold_literalrJs   r�get_no_fold_literalrT�s���$�o�O���%�%�5�<�<�U�C�E�	E��Q�x�3���%�%�
�#�V�E�]�,�	,����=��.E�F�G��!�"�I�E��U�#�L�E�5����5�!��E�!�H��O��%�%�
�#�V�E�]�,�	,����=��.C�D�E��E�!�"�I�%�%rc�F�t�}|r*|dtvrt|�\}}|j|�|r|ddk7r$t	j
dj
|���|jtdd��|dd}	t|�\}}|j|�|r|dd	k7r\|jjt	jd
��|r(|ddk(r |jtdd��|dd}||fS|jtd	d
��|dd}	t|�\}}|j|�|r|ddk(r|dd}n.|jjt	jd��|jtdd��|r*|dtvrt|�\}}|j|�||fS#tj
$r}	t|�\}}|jjt	jd��n;#tj
$r%t	j
dj
|���wxYwY���wxYw#tj
$r�	t|�\}}n�#tj
$r|	t|�\}}|jjt	jd��n;#tj
$r%t	j
dj
|���wxYwYnwxYwY���wxYw)z�msg-id = [CFWS] "<" id-left '@' id-right  ">" [CFWS]
       id-left = dot-atom-text / obs-id-left
       id-right = dot-atom-text / no-fold-literal / obs-id-right
       no-fold-literal = "[" *dtext "]"
    rr3zexpected msg-id but found '{}'zmsg-id-startr�Nzobsolete id-left in msg-idz4expected dot-atom-text or obs-id-left but found '{}'r%zmsg-id with no id-rightr4z
msg-id-endr*zobsolete id-right in msg-idzFexpected dot-atom-text, no-fold-literal or obs-id-right but found '{}'zmissing trailing '>' on msg-id)r�r�r�r�rr�r4r�rrrrrmrTr()r�msg_idrJs   r�
get_msg_idrWs����W�F���q��[�(������u��
�
�e���E�!�H��O��%�%�,�3�3�E�:�<�	<�
�M�M�-��^�4�5��!�"�I�E�1�(��/���u��M�M�%���E�!�H��O������f�8�8�%�'�	(�
�U�1�X��_��M�M�-��\�:�;��!�"�I�E��u�}��
�M�M�-��%8�9�:��!�"�I�E�
5�(��/���u��M�M�%����q��S���a�b�	�������f�8�8�,�.�	/�
�M�M�-��\�2�3���q��[�(������u��
�
�e���5�=���a�"�"�	1�	1�-�e�4�L�E�5��N�N�!�!�&�"=�"=�,�#.�
/���&�&�	1��)�)�"�"(�&��-�1�
1�	1��
/�		1��4�"�"�5�
	5�.�u�5�L�E�5���&�&�	5�
5�)�%�0���u����%�%�f�&A�&A�1�'3�4���*�*�
5��-�-�&�&,�f�U�m�5�5�
5��4�	5��5�sx�G�,I'�I$�(<H%�$I$�%8I�I$�#I$�'L �;J
�	L �
L�<K�L�8L�L�L �L�L �L c��t�}	t|�\}}|j|�|r=|jjt	j
dj
|���|S#tj$r^}t|�}t|�}|jjt	j
dj
|���Yd}~|Sd}~wwxYw)z2message-id      =   "Message-ID:" msg-id CRLF
    zUnexpected {!r}zInvalid msg-id: {!r}N)
r�rWr�rrrmr4r�r�r�)r�
message_idrJ�exs    r�parse_message_idr[Ls�����J�2�!�%�(���u����%� �����%�%�f�&@�&@�!�(�(��/�'1�
2�����"�"�K� ��'��%�e�,�
����!�!��&�&�'=�'D�'D�R�'H�I�	K�	K����K�s�A,�,C�?AC�Cc�j�t�}|s0|jjtjd��|S|dt
vrOt
|�\}}|j|�|s.|jjtjd��d}|r6|ddk7r.|dt
vr#||dz
}|dd}|r|ddk7r|dt
vr�#|j�sY|jjtjdj|���|jt|d	��n+t|�|_|jt|d
��|r*|dt
vrt
|�\}}|j|�|r|ddk7rY|j�.|jjtjd��|r|jt|d	��|S|jtdd��|dd}|r*|dt
vrt
|�\}}|j|�|s<|j�.|jjtjd��|Sd}|r&|dt
vr||dz
}|dd}|r|dt
vr�|j�sY|jjtjd
j|���|jt|d	��n+t|�|_
|jt|d
��|r*|dt
vrt
|�\}}|j|�|rI|jjtjd��|jt|d	��|S)zE mime-version = [CFWS] 1*digit [CFWS] "." [CFWS] 1*digit [CFWS]

    z%Missing MIME version number (eg: 1.0)rz0Expected MIME version number but found only CFWSr$r	r�Nz1Expected MIME major version number but found {!r}r��digitsz0Incomplete MIME version; found only major numberzversion-separatorz1Expected MIME minor version number but found {!r}z'Excess non-CFWS text after MIME version)rErr�r�HeaderMissingRequiredValuer�r��isdigitrmr4r��intrFrG)r�mime_versionrJr]s    r�parse_mime_versionrbhsp���=�L�����#�#�F�$E�$E�3�%5�	6����Q�x�;�������u����E�"��� � �'�'��(I�(I�B�)D�
E�
�F�
�E�!�H��O��a���(C��%��(����a�b�	���E�!�H��O��a���(C��>�>�����#�#�F�$>�$>�?�F�F�v�N�%P�	Q����M�&�'�:�;� ��[������M�&�(�;�<���q��[�(������u����E�"��E�!�H��O����)�� � �'�'��(B�(B�B�)D�
E�����
�e�W� =�>������
�c�+>�?�@��!�"�I�E���q��[�(������u����E�"�����)�� � �'�'��(B�(B�B�)D�
E���
�F�
�E�!�H�K�/��%��(����a�b�	���E�!�H�K�/��>�>�����#�#�F�$>�$>�?�F�F�v�N�%P�	Q����M�&�'�:�;� ��[������M�&�(�;�<���q��[�(������u����E�"�����#�#�F�$>�$>�5�%7�	8����M�%��9�:��rc���t�}|ra|ddk7rY|dtvr$|jt|dd��|dd}nt	|�\}}|j|�|r	|ddk7r�Y||fS)z� Read everything up to the next ';'.

    This is outside the formal grammar.  The InvalidParameter TokenList that is
    returned acts like a Parameter, but the data attributes are None.

    rrErr�N)rTrr�r�r)r�invalid_parameterrJs   r�get_invalid_parameterre�s���)�*��
�E�!�H��O���8�{�"��$�$�]�5��8�3F�&H�
I��!�"�I�E�%�e�,�L�E�5��$�$�U�+��E�!�H��O��e�#�#rc���t|�}|s$tjdj|���|j	�}|t|�d}t
|d�}t|�||fS)a8ttext = <matches _ttext_matcher>

    We allow any non-TOKEN_ENDS in ttext, but add defects to the token's
    defects list if we find non-ttext characters.  We also register defects for
    *any* non-printables even though the RFC doesn't exclude all of them,
    because we follow the spirit of RFC 5322.

    zexpected ttext but found '{}'N�ttext)�_non_token_end_matcherrr�r4r�r�r�r�)rr�rgs   r�	get_ttextri�sk��	�u�%�A���%�%�+�2�2�5�9�;�	;�
�G�G�I�E��#�e�*�+��E��%��)�E��E���%�<�rc�n�t�}|r*|dtvrt|�\}}|j|�|r/|dtvr$tjdj|���t|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS)z�token = [CFWS] 1*ttext [CFWS]

    The RFC equivalent of ttext is any US-ASCII chars except space, ctls, or
    tspecials.  We also exclude tabs even though the RFC doesn't.

    The RFC implies the CFWS but is not explicit about it in the BNF.

    r�expected token but found '{}')	r�r�r�r��
TOKEN_ENDSrr�r4ri)r�mtokenrJs   r�	get_tokenrn�s����W�F���q��[�(������u��
�
�e����q��Z�'��%�%�+�2�2�5�9�;�	;��U�#�L�E�5�
�M�M�%����q��[�(������u��
�
�e���5�=�rc���t|�}|s$tjdj|���|j	�}|t|�d}t
|d�}t|�||fS)aQattrtext = 1*(any non-ATTRIBUTE_ENDS character)

    We allow any non-ATTRIBUTE_ENDS in attrtext, but add defects to the
    token's defects list if we find non-attrtext characters.  We also register
    defects for *any* non-printables even though the RFC doesn't exclude all of
    them, because we follow the spirit of RFC 5322.

    z expected attrtext but found {!r}NrZ)�_non_attribute_end_matcherrr�r4r�r�r�r��rr�rZs   r�get_attrtextrr�sk��	#�5�)�A���%�%�.�5�5�e�<�>�	>��w�w�y�H��#�h�-�.�!�E��X�z�2�H��H���U�?�rc�n�t�}|r*|dtvrt|�\}}|j|�|r/|dtvr$tjdj|���t|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS)aH [CFWS] 1*attrtext [CFWS]

    This version of the BNF makes the CFWS explicit, and as usual we use a
    value terminal for the actual run of characters.  The RFC equivalent of
    attrtext is the token characters, with the subtraction of '*', "'", and '%'.
    We include tab in the excluded set just as we do for token.

    rrk)	rWr�r�r��ATTRIBUTE_ENDSrr�r4rr�rrXrJs   r�
get_attributerv�s�����I���q��[�(������u��������q��^�+��%�%�+�2�2�5�9�;�	;���&�L�E�5�
���U����q��[�(������u�������e��rc���t|�}|s$tjdj|���|j	�}|t|�d}t
|d�}t|�||fS)z�attrtext = 1*(any non-ATTRIBUTE_ENDS character plus '%')

    This is a special parsing routine so that we get a value that
    includes % escapes as a single string (which we decode as a single
    string later).

    z)expected extended attrtext but found {!r}N�extended-attrtext)�#_non_extended_attribute_end_matcherrr�r4r�r�r�r�rqs   r�get_extended_attrtextrz	sn��	,�E�2�A���%�%�7�>�>�u�E�G�	G��w�w�y�H��#�h�-�.�!�E��X�':�;�H��H���U�?�rc�n�t�}|r*|dtvrt|�\}}|j|�|r/|dtvr$tjdj|���t|�\}}|j|�|r*|dtvrt|�\}}|j|�||fS)z� [CFWS] 1*extended_attrtext [CFWS]

    This is like the non-extended version except we allow % characters, so that
    we can pick up an encoded value as a single string.

    rrk)	rWr�r�r��EXTENDED_ATTRIBUTE_ENDSrr�r4rzrus   r�get_extended_attributer}$	s�����I���q��[�(������u��������q��4�4��%�%�+�2�2�5�9�;�	;�(��/�L�E�5�
���U����q��[�(������u�������e��rc�l�t�}|r|ddk7r$tjdj|���|j	tdd��|dd}|r|dj
�s$tjdj|���d}|r6|dj
�r#||dz
}|dd}|r|dj
�r�#|dd	k(r3|d	k7r.|jj	tjd
��t|�|_
|j	t|d��||fS)a6 '*' digits

    The formal BNF is more complicated because leading 0s are not allowed.  We
    check for that and add a defect.  We also assume no CFWS is allowed between
    the '*' and the digits, though the RFC is not crystal clear on that.
    The caller should already have dealt with leading CFWS.

    r�*zExpected section but found {}zsection-markerr�Nz$Expected section number but found {}r$�0z'section number has an invalid leading 0r])r^rr�r4r�r�r_rrmr`rN)rr_r]s   r�get_sectionr�:	s2���i�G��E�!�H��O��%�%�&E�&L�&L�(-�'/�0�	0��N�N�=��&6�7�8��!�"�I�E���a��(�(�*��%�%�'1�17����@�	@�
�F�
�E�!�H�$�$�&��%��(����a�b�	���E�!�H�$�$�&��a�y�C��F�c�M������v�9�9�9� ;�	<���[�G�N��N�N�=���2�3��E�>�rc�J�t�}|stjd��d}|dtvrt	|�\}}|s$tjdj|���|ddk(rt
|�\}}nt|�\}}|�|g|dd|j|�||fS)z  quoted-string / attribute

    z&Expected value but found end of stringNrz Expected value but found only {}r)	rarr�r�r�r4rr}r�)r�vrrJs    r�	get_valuer�X	s���	��A���%�%�&N�O�O�
�F��Q�x�;�� ���
�����%�%�'0�06��v��@�	@��Q�x�3��(��/���u�-�e�4���u�
���H��b�q�	��H�H�U�O��e�8�Orc�2
�t�}t|�\}}|j|�|r|ddk(rA|jjt	j
dj
|���||fS|ddk(rm	t|�\}}d|_|j|�|st	jd��|ddk(r'|jtdd��|dd	}d|_|dd
k7rt	jd��|jtd
d��|dd	}|r*|dtvrt|�\}}|j|�d	}|}|j�r|�r|dd
k(r�t|�\}}|j}d}|j dk(r(|r|ddk(rd}n/t#|�\}}|r|ddk(rd}n	t%|�\}}|sd}	|ra|jjt	j
d��|j|�|D]}	|	j&dk(s�g|	d	d	|	}n|}n0d	}|jjt	j
d��|r|ddk(rd	}nt)|�\}}|jr|j dkDrZ|r|ddk7r"|j|�|�|rJ|��|}||fS|jjt	j
d��|sF|jjt	j
d��|j|�|��#||fS|�I|D]}	|	j&dk(s�n	j&dk(|j|	�|	j*|_|ddk7r$t	jdj
|���|jtdd��|dd	}|rf|ddk7r^t#|�\}}|j|�|j*|_|r|ddk7r$t	jdj
|���|jtdd��|dd	}|�et1�}
|rV|dt2vrt5|�\}}n(|dd
k(rtd
d�}|dd	}nt7|�\}}|
j|�|r�V|
}nt)|�\}}|j|�|�|rJ|��|}||fS#tj$rY��iwxYw#Y��@xYw)aY attribute [section] ["*"] [CFWS] "=" value

    The CFWS is implied by the RFC but not made explicit in the BNF.  This
    simplified form of the BNF from the RFC is made to conform with the RFC BNF
    through some extra checks.  We do it this way because it makes both error
    recovery and working with the resulting parse tree easier.
    rrEz)Parameter contains name ({}) but no valuerTzIncomplete parameterzextended-parameter-markerr�N�=zParameter not followed by '='�parameter-separatorrF�'z5Quoted string value for extended parameter is invalidr�zZParameter marked as extended but appears to have a quoted string value that is non-encodedzcApparent initial-extended-value but attribute was not marked as extended or was not initial sectionz(Missing required charset/lang delimitersrxrZz=Expected RFC2231 char/lang encoding delimiter, but found {!r}zRFC2231-delimiterz;Expected RFC2231 char/lang encoding delimiter, but found {}�DQUOTE)rIrvr�rrrmr4r�rMr�r�rRr�r�rr�rOrrrzr[r�rr�r�rar�r�r�)rr}rJr��appendto�qstring�inner_value�
semi_validr��tr�s           r�
get_parameterr�n	s5��
�K�E� ��'�L�E�5�	�L�L����E�!�H��O�
�
�
���V�7�7�9%�%+�V�E�]�4�	5��e�|���Q�x�3��	�&�u�-�L�E�5�"�E�O��L�L�����)�)�*@�A�A���8�s�?��L�L��s�,G�H�I��!�"�I�E�!�E�N��Q�x�3���%�%�&E�F�F�	�L�L��s�$9�:�;��!�"�I�E���q��[�(������u�
���U���I��H��~�~�%�E�!�H��O�/�u�5�����,�,���
����1�$��{�1�~��4�!�
�*�;�7���t��D��G�s�N�!%�J�
&�3�K�@���t��!%�J���M�M� � ��!;�!;�G�"I�
J��L�L��!��
���<�<�#7�7��A�a�D� �H��	
�
 �E��I��M�M� � ��!;�!;�:�";�
<�
��q��S���� ��'���u��>�>�U�1�1�A�5���a��C���O�O�E�"��$� �'�%�'�y�!���%�<��
�
�
���V�7�7�
D�E�	F��
�
�
���V�7�7�6�8�	9���������%�<�����
���<�<�#6�6��
�
�L�L�J�&��O�O�A���G�G�E�M���8�s�?��)�)�+F�FL�f�U�m�U�
U����
�c�+>�?�@��a�b�	���U�1�X��_�'��.�L�E�5��O�O�E�"����E�J��E�!�H��O��-�-�/<�<B�F�5�M�K�K����
�c�+>�?�@��a�b�	�����G����Q�x�3��&�u�~���u��q��S��%�c�8�4���a�b�	��+�E�2���u�
�H�H�U�O���� ��'���u��O�O�E������%��y����%�<���i�&�&�	��	��D
��s�>&S7�T�7T�
T�Tc��t�}|r�	t|�\}}|j|�|rp|ddk7rh|d}d|_t|�\}}|j|�|jjtjdj|���|r |jtdd	��|d
d}|r��|S#tj$r�d}|dt
vrt
|�\}}|s|j|�|cYS|ddk(rB|�|j|�|jjtjd��ndt|�\}}|r|g|dd|j|�|jjtjdj|���Y���wxYw)a! parameter *( ";" parameter )

    That BNF is meant to indicate this routine should only be called after
    finding and handling the leading ';'.  There is no corresponding rule in
    the formal RFC grammar, but it is more convenient for us for the set of
    parameters to be treated as its own TokenList.

    This is 'parse' routine because it consumes the remaining value, but it
    would never be called to parse a full header.  Instead it is called to
    parse everything after the non-parameter value of a specific MIME header.

    NrrEzparameter entry with no contentzinvalid parameter {!r}r�rUz)parameter with invalid trailing text {!r}r�r�)rdr�r�rr�r�r�rrmrer4r[rHr�)r�mime_parametersrJrr}s     r�parse_mime_parametersr��	s���%�&�O�
�	=�(��/�L�E�5��"�"�5�)�(�U�1�X��_�$�B�'�E�2�E��0��7�L�E�5��L�L����#�#�*�*�6�+E�+E�;�B�B�5�I�,K�
L���"�"�=��6K�#L�M��!�"�I�E�G�H���A�&�&�	=��F��Q�x�;�&� (���
�����&�&�v�.�&�&��Q�x�3���%�#�*�*�6�2��'�'�.�.�v�/I�/I�5�07�8� 5�U�;���u��!'��E�"�1�I��&�&�u�-��'�'�.�.�v�/I�/I�,�3�3�E�:�0<�=��#	=�s�C�AF=�B.F=�<F=c�@�|ra|ddk7rY|dtvr$|jt|dd��|dd}nt|�\}}|j|�|r	|ddk7r�Y|sy|jtdd��|jt	|dd��y)zBDo our best to find the parameters in an invalid MIME header

    rrErr�Nr�)rr�r�rr�)�	tokenlistrrJs   r�_find_mime_parametersr�/
s����E�!�H��O���8�{�"����]�5��8�5H�I�J��!�"�I�E�%�e�,�L�E�5����U�#�
�E�!�H��O���
���]�3�(=�>�?�
���*�5���9�5�6rc�8�t�}|s0|jjtjd��|S	t|�\}}|j|�|r|ddk7r>|jjtjd��|rt||�|S|jj�j�|_
|jtdd��|dd}	t|�\}}|j|�|jj�j�|_|s|S|dd
k7rO|jjtjdj|���|`
|`t||�|S|jtd
d��|jt!|dd��|S#tj$rN|jjtjdj|���t||�|cYSwxYw#tj$rN|jjtjd	j|���t||�|cYSwxYw)
z� maintype "/" subtype *( ";" parameter )

    The maintype and substype are tokens.  Theoretically they could
    be checked against the official IANA list + x-token, but we
    don't do that.
    z"Missing content type specificationz(Expected content maintype but found {!r}rr�zInvalid content typezcontent-type-separatorr�Nz'Expected content subtype but found {!r}rEz<Only parameters are valid after content type, but found {!r}r�)r�rr�rr^rnr�rmr4r�rrj�lowerr�r�r�r�)r�ctyperJs   r�parse_content_type_headerr�?
sH��
�M�E��
�
�
���V�>�>�0�2�	3���� ��'���u�
�L�L����E�!�H��O�
�
�
���V�7�7�"�$�	%��!�%��/����[�[�&�&�(�.�.�0�E�N�	�L�L��s�$<�=�>��!�"�I�E�� ��'���u�
�L�L����K�K�%�%�'�-�-�/�E�M�����Q�x�3��
�
�
���V�7�7�
�����(�	)�
�N�E�M��e�U�+���	�L�L��s�$9�:�;�	�L�L�&�u�Q�R�y�1�2��L��Q�"�"��
�
�
���V�7�7�6�=�=�e�D�F�	G��e�U�+���	��&�"�"��
�
�
���V�7�7�5�<�<�U�C�E�	F��e�U�+���	�s%�G�3H8�AH5�4H5�8AJ�Jc��t�}|s0|jjtjd��|S	t|�\}}|j|�|jj�j�|_
|s|S|ddk7rK|jjtjdj|���t||�|S|jtdd��|jt|dd��|S#tj$rN|jjtjdj|���t||�|cYSwxYw)	z* disposition-type *( ";" parameter )

    zMissing content dispositionz+Expected content disposition but found {!r}rrEzCOnly parameters are valid after content disposition, but found {!r}r�r�N)r�rr�rr^rnr�rmr4r�rrjr�r�r�r�)r�disp_headerrJs   r� parse_content_disposition_headerr�w
s]��%�&�K�����"�"�6�#D�#D�)�$+�	,���� ��'���u����u��&+�k�k�&7�&7�&9�&?�&?�&A�K�#�����Q�x�3�����"�"�6�#=�#=�
�����$(�	)�	�k�5�1������}�S�*?�@�A����,�U�1�2�Y�7�8����#�"�"�����"�"�6�#=�#=�9�@�@��G�$I�	J��k�5�1���	�s�D�AE<�;E<c���t�}|s0|jjtjd��|S	t|�\}}|j|�|jj�j�|_	|s|S|r|jjtjd��|dtvr$|jt|dd��|dd}nt|�\}}|j|�|r�|S#tj$r@|jjtjdj|���Y��wxYw)z mechanism

    z!Missing content transfer encodingz1Expected content transfer encoding but found {!r}z*Extra text after content transfer encodingrrr�N)r�rr�rr^rnrrjr�r�r�rmr4rr�r)r�
cte_headerrJs   r�&parse_content_transfer_encoding_headerr��
sM��
)�*�J�����!�!�&�"C�"C�/�#1�	2���5� ��'���u�
	���%� ����*�*�,�2�2�4�
�����
����!�!�&�"<�"<�8�#:�	;���8�{�"����m�E�!�H�6I�J�K��!�"�I�E�%�e�,�L�E�5����e�$�����#�"�"�P����!�!�&�"<�"<�?�F�F�u�M�#O�	P�P�s�D�AE$�#E$c�Z�d}|r&|dr!|ddtvr|dd}|ddd|d<|S)Nr$r�)r�)�lines�wsps  r�_steal_trailing_WSP_if_existsr��
sD��
�C���r��u�R�y��}��3��B�i��m���"�I�c�r�N��b�	��Jrc��|jxstj}|jrdnd}dg}d}d}d}d}t	dd�}	t|�}
|
�r�|
j
d�}||	ur|dz}�t|�}|s<|jd	k(rtj|�}ntj|�}	|j|�|}
|jd
k(rt!||||���|r�|s�|j"s�d}d}|j$r|j'|��dt)|j*�}|j*|vrHt)|�|t)|d�z
kDrt-|�}|j/|�|dxx|z
cc<��8t1|d�st|�|
z}
n4|�|
|k7r|dk(s
|dk(r|
dk7rd}t3|||||j4|
�}|
}d}���t)|�|t)|d�z
kr|dxx|z
cc<���|j$rFt)|�dz|kr5t-|�}|s|j7�r|j/||z�d}��	t1|d�s4t|�}|j"s|dz
}|j/|	�||
z}
��I|j"r|s|
j9d|�d}��mt-|�}|s|j7�r|j/||z�n
|dxx|z
cc<|
r���|j*j;|�|j*zS#t$r'td
�|jD��rd}
nd}
d}Y���wxYw)zLReturn string of contents of parse_tree folded according to RFC rules.

    �utf-8rKr$NrF�wrap_as_ew_blockedr�rBc3�PK�|]}t|tj���� y�wr)r9rrur's  rr*z%_refold_parse_tree.<locals>.<genexpr>�
s%����.���a��!>�!>�?�.�r>�unknown-8bitTrerLr�r)�max_line_length�sys�maxsize�utf8r�r�r/rr[�
SPECIALSNL�
isdisjoint�NLSETrrsr?r<�_fold_mime_parametersrDrarPr�r�r�r�r\�_fold_as_ewrbrA�insertr.)�
parse_treerM�maxlenrir��last_ew�last_charsetr��
want_encoding�end_ew_not_allowedryrE�tstrr��encoded_part�newline�newpartss                 rrNrN�
sq��
�
#�
#�
2�s�{�{�F� �+�+�w�:�H�
�D�E��G��L����M�!�"�&:�;�����E�
��y�y��|���%�%��!�#����4�y������'�)�$.�$9�$9�$�$?� ?�
�%*�$4�$4�T�$:� :�
�	!��K�K��!��G��?�?�/�/�!�$��v�x�@���!3��%�%� %�
����'�'�#'�9�9�F�9�#;�<Q�c�&�.�.�>Q�=Q�#R�L��~�~�\�9��|�,�v��E�"�I��/F�F�&C�E�&J�G�!�L�L��1��b�	�\�1�	� �
�4��*��T�
�U�*���'��|�+�!�^�3�!�W�,��J�1F�"�G�%�d�E�6�7�&*�&=�&=�w�H��&��!�M���t�9���U�2�Y��/�/��"�I���I��
� � ��D�	�A�
��'�3�E�:�G��$�-�-�/����W�t�^�,�����t�X�&��D�z�H��%�%�"�a�'�"���� 2�3��u�$�E�����&8�
�L�L��D�!� �M��/��6���d�)�)�+��L�L��4��(�
�"�I���I�C�D�>�>���u�%����6�6��e"�	!��.� �,�,�.�.�(��"�� �M�	!�s�9L)�),M�Mc�n�|�*|r(tt|d|d|z��}|dd||d<|dtvrB|d}|dd}t|d�|k(r|j	t|��|dxx|z
cc<d}|dtvr
|d}|dd}|�t|d�n|}|dk(rdn|}	t|	�dz}
|
dz|k\rt
jd	��|r�|t|d�z
}||
z
}|dkr|j	d
��/|d|}
tj|
|	��}t|�|z
}|dkDr0|
dd}
tj|
|	��}t|�|z
}|dkDr�0|dxx|z
cc<|t|
�d}|r|j	d
�t|d�}|r��|dxx|z
cc<|r|SdS)a�Fold string to_encode into lines as encoded word, combining if allowed.
    Return the new value for last_ew, or None if ew_combine_allowed is False.

    If there is already an encoded word in the last line of lines (indicated by
    a non-None value for last_ew) and ew_combine_allowed is true, decode the
    existing ew, combine it with to_encode, and re-encode.  Otherwise, encode
    to_encode.  In either case, split to_encode as necessary so that the
    encoded segments fit within maxlen.

    Nr�rr�r$rKr��z3max_line_length is too small to fit an encoded wordrj)r�)
rr�r�r�r�r�rr�r�r)�	to_encoder�r�r�rbr��leading_wsp�trailing_wsp�new_last_ew�	encode_as�
chrome_len�remaining_space�
text_space�to_encode_word�encoded_word�excesss                rr�r�=s����1���U�2�Y�w�x�0�9�<�=�?�	��"�I�h�w�'��b�	���|�s�� ��l���a�b�M�	���b�	�N�f�$��L�L�6�u�=�>�
�b�	�[� �	��L���}��� ��}���c�r�N�	�$+�O�#�e�B�i�.��K�"�j�0��g�I��Y��!�#�J��Q��6�!��%�%�A�C�	C�� �3�u�R�y�>�1��$�z�1�
���?��L�L����"�;�J�/���z�z�.�)�D���\�"�_�4���q�j�,�C�R�0�N��:�:�n�i�H�L���&��8�F��q�j�	�b�	�\�!�	��c�.�1�2�3�	���L�L����e�B�i�.�K�+�,
�"�I���I�,�;�6�$�6rc	��|jD�]�\}}|dj�jd�s
|dxxdz
cc<|}d}	|j|�d}|r6tjj|d	|�
�}	dj|||	�}
ndj|t|��}
t|d�t|
�zd
z|kr|ddz|
z|d<��t|
�dz|kr|jd|
z���d}|dz}|s��t|�tt|��zdzt|�z}
||
dzkrd}||
z
dz
x}}	|d|}tjj|d	|�
�}	t|	�|krn|d
z}�<|jdj||||	��d	}|d
z
}||d}|r
|dxxdz
cc<|r�����y#t$r"d}tj|�rd}d}nd}Y���wxYw)a>Fold TokenList 'part' into the 'lines' list as mime parameters.

    Using the decoded list of parameters and values, format them according to
    the RFC rules, including using RFC2231 encoding if the value cannot be
    expressed in 'encoding' and/or the parameter+value is too long to fit
    within 'maxlen'.

    r�rE�strictFTr�rhr�r$)�saferz
{}*={}''{}rr�rjr�rz''r �NNz {}*{}*={}{})rwr"r[rrsrrtrnror�r4rr�r�r)rEr�r�rirxrr��
error_handler�encoding_required�
encoded_valuer�r_�extra_chromer��
splitpoint�maxchars�partials                 rr�r�~sF���{�{�:!���e��R�y���!�*�*�3�/��"�I���I��� �
�		"��L�L��"� %���"�L�L�.�.��B�}�/�6�M��&�&�t�W�m�D�D��>�>�$��U�(;�<�D��u�R�y�>�C��I�%��)�F�2��b�	�C��$�.�E�"�I��
��Y��]�f�
$��L�L��t��$������~����T��S��W��%6�6��:�S��=N�N�J���a��'�
��$*�Z�$7�!�$;�;�J������,�� &��� 2� 2��"�]�!3�!<�
��}�%��1���a��
�
�
�L�L��.�.��g�|�]�<�
=��L��q�L�G��*�+�&�E���b�	�S� �	�-�I:!��"�	"� $���$�$�U�+�(�� 1�
�!���
	"�s�G�'G>�=G>)�r��rer�rn�stringr�operatorr�emailrr�rrr&r�r�rrr'r�	TSPECIALSrl�	ASPECIALSrtr|r�r�r�compile�VERBOSE�	MULTILINEr�r�rrgrsrwr{rr�r�r�r�r�r�r�r�r�r�r�r�r�r�rr
rrrrrr+r-r4r?rErIrTrWr^rardr�r�r�r�r�r�r�r�r�rr�r�r�r�r�r�r8r.rDr/r4r.rr�r��matchr��findallr�rhrpryr�r�r�r�r�r�r�r�r�r�r�rrrr	r
rrrrr#r&r(r+r1r6r8r;r@rCrGrJrLrNrQrTrWr[rbrerirnrrrvrzr}r�r�r�r�r�r�r�r�r�rNr�r�rkrr�<module>r�s&��C�J
�
�
���'���
�%�j���C��H�n���� ���s�N�	��C��H�$�
���U��#��
��E�
�
"�c�#�h�.�	�
��_�
���E�
�"�	��S���(�3�s�8�3��	
�t���
��
�
�H��"�*�*���Z�Z�"�,�,�� ��@,��@,�FD�)�D� �I� ��Y���9���"���9���I��
�)��#�9�#�6	-�|�	-��!��4C�)�C�&%�i�%�2?�)�?�%�	�%�"$�I�$�*"�y�"�6�	��DD�y�D�!�i�!�6;�Y�;�.�Y�.��i���)��
�I��
�y��B�9��'!�&�'!�T!�	�!�H
�I�
� �)���	��8%�y�%�
#�	�#��i���I��S.�Y�S.�l�y���*���1���i���)��
*�I�*����&�y�&��Y��(+�s�(+�V����H���-��<�f�-�-�<��C�����c�#3�4�
�#�
��$�S�*B�C��.��
�
�:�,�,�R�W�W�S�\�:�;�A�A�
�"��
�
�9�#3�#3�
�B�I�I�b�g�g�i� �!�$#�$�$)�E��"��
�
�#5�6�>�>��#����I�$4�$4�
�B�I�I�b�g�g�j�!�"�%$�%�%*�U��'�R�Z�Z�	�(8�(8�
�B�I�I�b�g�g�n�%�&�)(�)�).���&0�b�j�j��1A�1A�
�B�I�I�b�g�g�-�.�/�21�'2�27�%�$�;�J�<
�/�bA�F�"
�� ))�V�2� �$�6 �&�2 �D$�L%�N-!�^�(�%!�N$�L� ' �R,�\��<�*"�$6�r#�J�<�:4�n&�,B�J�8B�H$�$�&�.�&�.�$�,�<�,K�Z2�h7� 6�p�<�^�p7�d?7�BI!r
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!