
    <iJ                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	r/ SQr
\R                  " S5      rS r " S S\5      r " S S	\5      rS
 rS r " S S\5      rg)a  
Parses replies from the control socket.

**Module Overview:**

::

  convert - translates a ControlMessage into a particular response subclass

  ControlMessage - Message that's read from the control socket.
    |- SingleLineResponse - Simple tor response only including a single line of information.
    |
    |- from_str - provides a ControlMessage for the given string
    |- is_ok - response had a 250 status
    |- content - provides the parsed message content
    +- raw_content - unparsed socket data

  ControlLine - String subclass with methods for parsing controller responses.
    |- remainder - provides the unparsed content
    |- is_empty - checks if the remaining content is empty
    |- is_next_quoted - checks if the next entry is a quoted value
    |- is_next_mapping - checks if the next entry is a KEY=VALUE mapping
    |- peek_key - provides the key of the next entry
    |- pop - removes and returns the next entry
    +- pop_mapping - removes and returns the next entry as a KEY=VALUE mapping
    N)
	add_onioneventsgetinfogetconfprotocolinfoauthchallengeconvertControlMessageControlLineSingleLineResponsez^(\S+)=c           	         SSK nSSKnSSKnSSKnSSKnSSKnSSKn[        U[        5      (       d  [        S5      eUR                  R                  R                  UR                  R                  R                  UR                  R                  R                   UR                  R"                  R$                  UR                  R&                  R(                  UR                  R*                  R,                  UR                  R.                  R0                  [2        S.n X@   nXQl        UR6                  " S0 UD6  g! [         a    [        SU -  5      ef = f)a  
Converts a :class:`~stem.response.ControlMessage` into a particular kind of
tor response. This does an in-place conversion of the message from being a
:class:`~stem.response.ControlMessage` to a subclass for its response type.
Recognized types include...

=================== =====
response_type       Class
=================== =====
**ADD_ONION**       :class:`stem.response.add_onion.AddOnionResponse`
**AUTHCHALLENGE**   :class:`stem.response.authchallenge.AuthChallengeResponse`
**EVENT**           :class:`stem.response.events.Event` subclass
**GETCONF**         :class:`stem.response.getconf.GetConfResponse`
**GETINFO**         :class:`stem.response.getinfo.GetInfoResponse`
**MAPADDRESS**      :class:`stem.response.mapaddress.MapAddressResponse`
**PROTOCOLINFO**    :class:`stem.response.protocolinfo.ProtocolInfoResponse`
**SINGLELINE**      :class:`stem.response.SingleLineResponse`
=================== =====

:param str response_type: type of tor response to convert to
:param stem.response.ControlMessage message: message to be converted
:param kwargs: optional keyword arguments to be passed to the parser method

:raises:
  * :class:`stem.ProtocolError` the message isn't a proper response of
    that type
  * :class:`stem.InvalidArguments` the arguments given as input are
    invalid, this is can only be raised if the response_type is: **GETINFO**,
    **GETCONF**
  * :class:`stem.InvalidRequest` the arguments given as input are
    invalid, this is can only be raised if the response_type is:
    **MAPADDRESS**
  * :class:`stem.OperationFailed` if the action the event represents failed,
    this is can only be raised if the response_type is: **MAPADDRESS**
  * **TypeError** if argument isn't a :class:`~stem.response.ControlMessage`
    or response_type isn't supported
r   Nz;Only able to convert stem.response.ControlMessage instances)	ADD_ONIONAUTHCHALLENGEEVENTGETCONFGETINFO
MAPADDRESSPROTOCOLINFO
SINGLELINEzUnsupported response type: %s )stem.response.add_onionstem.response.authchallengestem.response.eventsstem.response.getinfostem.response.getconfstem.response.mapaddressstem.response.protocolinfo
isinstancer
   	TypeErrorresponser   AddOnionResponser   AuthChallengeResponser   Eventr   GetConfResponser   GetInfoResponse
mapaddressMapAddressResponser   ProtocolInfoResponser   	__class___parse_message)response_typemessagekwargsstemresponse_typesresponse_classs         P/home/james-whalen/.local/lib/python3.13/site-packages/stem/response/__init__.pyr	   r	   9   s   N !$!#	G^	,	,
Q
RR ((99]]00FF]]!!''}}$$44}}$$44--**==MM..CC$	.E#2N %	"6"	 
 E
3mC
DDEs   D< <Ec                   z    \ rS rSrSr\SS j5       rSS jrS rSS jr	SS jr
S	 rS
 rS rS rS rS rS rSrg)r
      a  
Message from the control socket. This is iterable and can be stringified for
individual message components stripped of protocol formatting. Messages are
never empty.

:var int arrived_at: unix timestamp for when the message arrived

.. versionchanged:: 1.7.0
   Implemented equality and hashing.

.. versionchanged:: 1.8.0
   Moved **arrived_at** from the Event class up to this base ControlMessage.
Nc                 j   U(       a3  U R                  S5      (       d  U S-  n [        R                  " SSU 5      n [        R                  R                  [        R                  " [        R                  R                  R                  U 5      5      UR                  SS5      S9nUb  [        X40 UD6  U$ )a  
Provides a ControlMessage for the given content.

.. versionadded:: 1.1.0

.. versionchanged:: 1.6.0
   Added the normalize argument.

:param str content: message to construct the message from
:param str msg_type: type of tor reply to parse the content as
:param bool normalize: ensures expected carriage return and ending newline
  are present
:param kwargs: optional keyword arguments to be passed to the parser method

:returns: stem.response.ControlMessage instance

z([]?)
z

arrived_atN)r6   )endswithresubr.   socketrecv_messageioBytesIOutil	str_tools	_to_bytespopr	   )contentmsg_type	normalizer-   msgs        r1   from_strControlMessage.from_str   s    & d##4{FG4g
++
"
"2::dii.A.A.K.KG.T#Udjdndno{  ~B  eC
"  DCh&v&J    c                     U(       d  [        S5      eU(       a  UO[        [        R                  " 5       5      U l        Xl        X l        S U l        [        R                  R                  U S5      U l
        g )NzControlMessages can't be empty_raw_content)
ValueErrorinttimer6   _parsed_contentrJ   _strr.   r>   
_hash_attr_hash)selfparsed_contentraw_contentr6   s       r1   __init__ControlMessage.__init__   sR    788$.jC		4DDO)#DI%%dN;DJrH   c                 B    U R                    H  u  n  nUS:X  d  M    g   g)z
Checks if any of our lines have a 250 response.

:returns: **True** if any lines have a 250 response code, **False** otherwise
250TF)rN   )rR   code_s      r1   is_okControlMessage.is_ok   s)     **
a	 + rH   c           
      (   [         R                  R                  5       (       aT  U(       dM  U R                   VVVs/ s H1  u  p#oBU[         R                  R
                  R                  U5      4PM3     snnn$ [        U R                  5      $ s  snnnf )a  
Provides the parsed message content. These are entries of the form...

::

  (status_code, divider, content)

**status_code**
  Three character code for the type of response (defined in section 4 of
  the control-spec).

**divider**
  Single character to indicate if this is mid-reply, data, or an end to the
  message (defined in section 2.3 of the control-spec).

**content**
  The following content is the actual payload of the line.

For data entries the content is the full multi-line payload with newline
linebreaks and leading periods unescaped.

The **status_code** and **divider** are both strings (**bytes** in python
2.x and **unicode** in python 3.x). The **content** however is **bytes** if
**get_bytes** is **True**.

.. versionchanged:: 1.1.0
   Added the get_bytes argument.

:param bool get_bytes: provides **bytes** for the **content** rather than a **str**

:returns: **list** of (str, str, str) tuples for the components of this message
)r.   prereqis_python_3rN   r>   r?   _to_unicodelist)rR   	get_bytesrY   divrB   s        r1   rB   ControlMessage.content   sn    D {{  `d`t`tu`tH\T[S$))--99'BC`tuu$&&'' vs   8Bc                     [         R                  R                  5       (       a:  U(       d3  [         R                  R                  R                  U R                  5      $ U R                  $ )a  
Provides the unparsed content read from the control socket.

.. versionchanged:: 1.1.0
   Added the get_bytes argument.

:param bool get_bytes: if **True** then this provides **bytes** rather than a **str**

:returns: **str** of the socket data used to generate this message
)r.   r^   r_   r>   r?   r`   rJ   )rR   rb   s     r1   rT   ControlMessage.raw_content   sF     {{  YY  ,,T->->??rH   c                 r    U R                   c  SR                  [        U 5      5      U l         U R                   $ )zR
Content of the message, stripped of status code and divider protocol
formatting.
r5   )rO   joinra   rR   s    r1   __str__ControlMessage.__str__   s,     yy))DJ'di99rH   c              #      #    U R                    H_  u    p[        R                  R                  5       (       a)  [        R                  R
                  R                  U5      n[        U5      v   Ma     g7f)a  
Provides :class:`~stem.response.ControlLine` instances for the content of
the message. This is stripped of status codes and dividers, for instance...

::

  250+info/names=
  desc/id/* -- Router descriptors by ID.
  desc/name/* -- Router descriptors by nickname.
  .
  250 OK

Would provide two entries...

::

  1st - "info/names=
         desc/id/* -- Router descriptors by ID.
         desc/name/* -- Router descriptors by nickname."
  2nd - "OK"
NrN   r.   r^   r_   r>   r?   r`   r   )rR   rZ   rB   s      r1   __iter__ControlMessage.__iter__	  sS     . --1		 	 	"	"))%%11':  	 .s   A1A3c                 ,    [        U R                  5      $ )z"
:returns: number of ControlLines
)lenrN   ri   s    r1   __len__ControlMessage.__len__&  s    
 t##$$rH   c                     U R                   U   S   n[        R                  R                  5       (       a)  [        R                  R
                  R                  U5      n[        U5      $ )z<
:returns: :class:`~stem.response.ControlLine` at the index
   rm   )rR   indexrB   s      r1   __getitem__ControlMessage.__getitem__-  sQ    
 ""5)!,G{{  		##//8gwrH   c                     U R                   $ N)rQ   ri   s    r1   __hash__ControlMessage.__hash__9  s    ::rH   c                 ^    [        U[        5      (       a  [        U 5      [        U5      :H  $ S$ NF)r   r
   hashrR   others     r1   __eq__ControlMessage.__eq__<  s&    (25.(I(I4:e$TuTrH   c                     X:X  + $ rz   r   r   s     r1   __ne__ControlMessage.__ne__?  s    rH   )rQ   rN   rJ   rO   r6   r~   rz   F)__name__
__module____qualname____firstlineno____doc__staticmethodrF   rU   r[   rB   rT   rj   rn   rr   rw   r{   r   r   __static_attributes__r   rH   r1   r
   r
      sT      >	<%(N"	!:%
 UrH   r
   c                   ^    \ rS rSrSrS rS rS rS rSS jr	SS	 jr
S
 rSS jrSS jrSrg)r   iC  aF  
String subclass that represents a line of controller output. This behaves as
a normal string with additional methods for parsing and popping entries from
a space delimited series of elements like a stack.

None of these additional methods effect ourselves as a string (which is still
immutable). All methods are thread safe.
c                 ,    [         R                  X5      $ rz   )str__new__rR   values     r1   r   ControlLine.__new__M  s    ;;t##rH   c                 D    Xl         [        R                  " 5       U l        g rz   )
_remainder	threadingRLock_remainder_lockr   s     r1   rU   ControlLine.__init__P  s    O$??,DrH   c                     U R                   $ )z
Provides our unparsed content. This is an empty string after we've popped
all entries.

:returns: **str** of the unparsed content
r   ri   s    r1   	remainderControlLine.remainderT  s     ??rH   c                      U R                   S:H  $ )zy
Checks if we have further content to pop or not.

:returns: **True** if we have additional content, **False** otherwise
 r   ri   s    r1   is_emptyControlLine.is_empty^  s     ??b  rH   c                 T    [        U R                  U5      u  p#US:H  =(       a    US:g  $ )z
Checks if our next entry is a quoted value or not.

:param bool escaped: unescapes the string

:returns: **True** if the next entry can be parsed as a quoted value, **False** otherwise
r   )_get_quote_indicesr   )rR   escapedstart_quote	end_quotes       r1   is_next_quotedControlLine.is_next_quotedg  s+     0IK!/	R/rH   Nc                     U R                   n[        R                  U5      nU(       aQ  U(       a  XR                  5       S   :w  a  gU(       a+  [	        XC5      u  pgXeR                  5       :H  =(       a    US:g  $ gg)a^  
Checks if our next entry is a KEY=VALUE mapping or not.

:param str key: checks that the key matches this value, skipping the check if **None**
:param bool quoted: checks that the mapping is to a quoted value
:param bool escaped: unescapes the string

:returns: **True** if the next entry can be parsed as a key=value mapping,
  **False** otherwise
r   Fr   T)r   KEY_ARGmatchgroupsr   end)rR   keyquotedr   r   	key_matchr   r   s           r1   is_next_mappingControlLine.is_next_mappings  se     Ii(I	((*1--	!3I!Gmmo-A)r/ArH   c                 z    U R                   n[        R                  U5      nU(       a  UR                  5       S   $ g)z
Provides the key of the next entry, providing **None** if it isn't a
key/value mapping.

:returns: **str** with the next entry's key
r   N)r   r   r   r   )rR   r   r   s      r1   peek_keyControlLine.peek_key  s5     Ii(I""rH   c                     U R                      [        U R                  XS5      u  p4X@l        UsSSS5        $ ! , (       d  f       g= f)a!  
Parses the next space separated entry, removing it and the space from our
remaining content. Examples...

::

  >>> line = ControlLine("\"We're all mad here.\" says the grinning cat.")
  >>> print line.pop(True)
    "We're all mad here."
  >>> print line.pop()
    "says"
  >>> print line.remainder()
    "the grinning cat."

  >>> line = ControlLine("\"this has a \\\" and \\\\ in it\" foo=bar more_data")
  >>> print line.pop(True, True)
    "this has a \" and \\ in it"

:param bool quoted: parses the next entry as a quoted value, removing the quotes
:param bool escaped: unescapes the string

:returns: **str** of the next space separated entry

:raises:
  * **ValueError** if quoted is True without the value being quoted
  * **IndexError** if we don't have any remaining content left to parse
FN)r   _parse_entryr   )rR   r   r   
next_entryr   s        r1   rA   ControlLine.pop  s6    : 
		*4??FUSj!o 
		s	   !8
Ac                    U R                      U R                  5       (       a  [        S5      e[        R	                  U R
                  5      nU(       d  [        SU R
                  -   5      eUR                  5       S   nU R
                  UR                  5       S n[        XaX#5      u  pvX`l        XW4sSSS5        $ ! , (       d  f       g= f)a]  
Parses the next space separated entry as a KEY=VALUE mapping, removing it
and the space from our remaining content.

.. versionchanged:: 1.6.0
   Added the get_bytes argument.

:param bool quoted: parses the value as being quoted, removing the quotes
:param bool escaped: unescapes the string
:param bool get_bytes: provides **bytes** for the **value** rather than a **str**

:returns: **tuple** of the form (key, value)

:raises: **ValueError** if this isn't a KEY=VALUE mapping or if quoted is
  **True** without the value being quoted
:raises: **IndexError** if there's nothing to parse from the line
no remaining content to parsez*the next entry isn't a KEY=VALUE mapping: r   N)
r   r   
IndexErrorr   r   r   rK   r   r   r   )rR   r   r   rb   r   r   r   r   s           r1   pop_mappingControlLine.pop_mapping  s    & 
			899--0iEWXX q!c//)--/"23i*9gQj!o 
		s   B%B<<
C
)r   r   r   )NFF)FF)FFF)r   r   r   r   r   r   rU   r   r   r   r   r   rA   r   r   r   rH   r1   r   r   C  s5    $-!
08  D"rH   r   c                 B   U S:X  a  [        S5      eSU pTU(       a3  [        XR5      u  pgUS:w  d  US:X  a  [        SU -   5      eUSU XWS-   S pTOSU;   a  UR                  SS5      u  pEOUSpTU(       al  [        R
                  " U5      S   n[        R                  R                  5       (       a0  U(       d)  [        R                  R                  R                  U5      nU(       a)  [        R                  R                  R                  U5      nXER                  5       4$ )	a  
Parses the next entry from the given space separated content.

:param str line: content to be parsed
:param bool quoted: parses the next entry as a quoted value, removing the quotes
:param bool escaped: unescapes the string

:returns: **tuple** of the form (entry, remainder)

:raises:
  * **ValueError** if quoted is True without the next value being quoted
  * **IndexError** if there's nothing to parse from the line
r   r   r   r   z%the next entry isn't a quoted value:    N )r   r   rK   splitcodecsescape_decoder.   r^   r_   r>   r?   r`   r@   lstrip)liner   r   rb   r   r   r   r   s           r1   r   r     s    
RZ
4
55di/	CKa9?>EFF%a	2I!mn4M	 i'ooc15j)') %%j1!4J{{  99&&22:>j$$..z:J
&&(	))rH   c                    / Sp2[        S5       Hi  nU R                  SUS-   5      nU(       a9  US:  a3  XS-
     S:X  a(  U R                  SUS-   5      nUS:  a  XS-
     S:X  a  M(  UR                  U5        Mk     [        U5      $ )z
Provides the indices of the next two quotes in the given content.

:param str line: content to be parsed
:param bool escaped: unescapes the string

:returns: **tuple** of two ints, indices being -1 if a quote doesn't exist
r   ru   "r   \)rangefindappendtuple)r   r   indicesquote_indexrZ   s        r1   r   r   "  s     R;8a))Cq1K 1Ao!6$!>ii[1_5 1Ao!6$!> NN;  
wrH   c                   (    \ rS rSrSrSS jrS rSrg)r   i<  a  
Reply to a request that performs an action rather than querying data. These
requests only contain a single line, which is 'OK' if successful, and a
description of the problem if not.

:var str code: status code for our line
:var str message: content of the line
c                 n    U(       a  U R                  5       S   S:H  $ U R                  5       S   S   S:H  $ )aa  
Checks if the response code is "250". If strict is **True** then this
checks if the response is "250 OK"

:param bool strict: checks for a "250 OK" message if **True**

:returns:
  * If strict is **False**: **True** if the response code is "250", **False** otherwise
  * If strict is **True**: **True** if the response is "250 OK", **False** otherwise
r   )rX   r   OKrX   )rB   )rR   stricts     r1   r[   SingleLineResponse.is_okF  s9     \\^A"444<<>!Q5((rH   c                     U R                  5       n[        U5      S:  a  [        R                  " S5      e[        U5      S:X  a  [        R                  " S5      eUS   u  U l        o l        g )Nr   zReceived multi-line responser   zReceived empty response)rB   rq   r.   ProtocolErrorrY   r,   )rR   rB   rZ   s      r1   r*   !SingleLineResponse._parse_messageW  s[    llnG
7|a=>>	W	899#*1: diLrH   )rY   r,   Nr   )r   r   r   r   r   r[   r*   r   r   rH   r1   r   r   <  s    )".rH   r   )r   r   r<   r8   rM   r   stem.socketr.   	stem.utilstem.util.str_tools__all__compiler   r	   objectr
   r   r   r   r   r   r   rH   r1   <module>r      sw   6  	 	      **Z
 C#LAV AH`# `F9*x4#. #.rH   