
    hJ                         d Z ddlZddlZddlZddlZddlZddlZddlZddl	Zg dZ
 ej                  d      Zd Z G d de      Z G d d	e      Zd
 Zd Z G d de      Zy)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           	         ddl }ddl}ddl}ddl}ddl}ddl}ddl}t        |t              st        d      |j                  j                  j                  |j                  j                  j                  |j                  j                  j                   |j                  j"                  j$                  |j                  j&                  j(                  |j                  j*                  j,                  |j                  j.                  j0                  t2        d}	 ||    }||_         |j6                  di | y# t        $ r t        d| z        w xY w)aG  
  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         `/var/www/betterdocs.net/sherlock_api/venv/lib/python3.12/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#M2N %''"6"	 
 E
3mC
DDEs   D9 9Ec                   j    e Zd ZdZedd       ZddZd ZddZddZ	d Z
d	 Zd
 Zd Zd Zd Zd Zy)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                 X   |r-| j                  d      s| dz  } t        j                  dd|       } t        j                  j                  t        j                  t        j                  j                  j                  |             |j                  dd            }|t        ||fi | |S )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)r5   )endswithresubr.   socketrecv_messageioBytesIOutil	str_tools	_to_bytespopr	   )contentmsg_type	normalizer-   msgs        r1   from_strz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                     |st        d      |r|nt        t        j                               | _        || _        || _        d | _        t        j                  j                  | d      | _
        y )NzControlMessages can't be empty_raw_content)
ValueErrorinttimer5   _parsed_contentrH   _strr.   r=   
_hash_attr_hash)selfparsed_contentraw_contentr5   s       r1   __init__zControlMessage.__init__   sV    788$.jC		4DDO)D#DDI%%dN;DJrF   c                 <    | j                   D ]  \  }}}|dk(  s y y)z
    Checks if any of our lines have a 250 response.

    :returns: **True** if any lines have a 250 response code, **False** otherwise
    250TF)rL   )rP   code_s      r1   is_okzControlMessage.is_ok   s.     ** 
a	 rF   c           
         t         j                  j                         rN|sL| j                  D cg c]2  \  }}}||t         j                  j
                  j                  |      f4 c}}}S t        | j                        S c c}}}w )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_3rL   r=   r>   _to_unicodelist)rP   	get_bytesrV   divrA   s        r1   rA   zControlMessage.content   sl    D {{ `d`t`tuuH\sT[tS$))--99'BCuu$&&'' vs   7Bc                     t         j                  j                         r5|s3t         j                  j                  j                  | j                        S | j                  S )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.   rZ   r[   r=   r>   r\   rH   )rP   r^   s     r1   rR   zControlMessage.raw_content   sC     {{ YY  ,,T->->??rF   c                 p    | j                   dj                  t        |             | _         | j                   S )z^
    Content of the message, stripped of status code and divider protocol
    formatting.
    r4   )rM   joinr]   rP   s    r1   __str__zControlMessage.__str__   s,     yy))DJ'di99rF   c              #      K   | j                   D ]Z  \  }}}t        j                  j                         r)t        j                  j
                  j                  |      }t        |       \ yw)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rL   r.   rZ   r[   r=   r>   r\   r   )rP   rW   rA   s      r1   __iter__zControlMessage.__iter__	  sX     . -- !1g		 	 	"))%%11':  	!s   A+A-c                 ,    t        | j                        S )z*
    :returns: number of ControlLines
    )lenrL   rc   s    r1   __len__zControlMessage.__len__&  s    
 t##$$rF   c                     | j                   |   d   }t        j                  j                         r)t        j                  j
                  j                  |      }t        |      S )zD
    :returns: :class:`~stem.response.ControlLine` at the index
       rf   )rP   indexrA   s      r1   __getitem__zControlMessage.__getitem__-  sN    
 ""5)!,G{{ 		##//8gwrF   c                     | j                   S N)rO   rc   s    r1   __hash__zControlMessage.__hash__9  s    ::rF   c                 T    t        |t              rt        |       t        |      k(  S dS NF)r   r
   hashrP   others     r1   __eq__zControlMessage.__eq__<  s#    (25.(I4:e$TuTrF   c                     | |k(   S rp   r   ru   s     r1   __ne__zControlMessage.__ne__?  s    u}rF   rs   rp   F)__name__
__module____qualname____doc__staticmethodrE   rS   rX   rA   rR   rd   rg   rj   rn   rq   rw   ry   r   rF   r1   r
   r
      sT      >	<%(N"	!:%
 UrF   r
   c                   N    e Zd ZdZd Zd Zd Zd ZddZddZ	d	 Z
dd
ZddZy)r   aR  
  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                 .    t         j                  | |      S rp   )str__new__rP   values     r1   r   zControlLine.__new__M  s    ;;tU##rF   c                 D    || _         t        j                         | _        y rp   )
_remainder	threadingRLock_remainder_lockr   s     r1   rS   zControlLine.__init__P  s    DO$??,DrF   c                     | j                   S )z
    Provides our unparsed content. This is an empty string after we've popped
    all entries.

    :returns: **str** of the unparsed content
    r   rc   s    r1   	remainderzControlLine.remainderT  s     ??rF   c                      | j                   dk(  S )z
    Checks if we have further content to pop or not.

    :returns: **True** if we have additional content, **False** otherwise
     r   rc   s    r1   is_emptyzControlLine.is_empty^  s     ??b  rF   c                 L    t        | j                  |      \  }}|dk(  xr |dk7  S )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   )rP   escapedstart_quote	end_quotes       r1   is_next_quotedzControlLine.is_next_quotedg  s-     0IK!/	R/rF   Nc                     | j                   }t        j                  |      }|rE|r||j                         d   k7  ry|r)t	        ||      \  }}||j                         k(  xr |dk7  S yy)az  
    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)rP   keyquotedr   r   	key_matchr   r   s           r1   is_next_mappingzControlLine.is_next_mappings  sm     Ii(I		((*1--	!3Iw!GYimmo-A)r/ArF   c                 p    | j                   }t        j                  |      }|r|j                         d   S y)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   )rP   r   r   s      r1   peek_keyzControlLine.peek_key  s5     Ii(I""rF   c                     | j                   5  t        | j                  ||d      \  }}|| _        |cddd       S # 1 sw Y   yxY w)aq  
    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   )rP   r   r   
next_entryr   s        r1   r@   zControlLine.pop  sE    : 
		 *4??FGUSj)!do  s	   $;Ac                    | j                   5  | j                         rt        d      t        j	                  | j
                        }|st        d| j
                  z         |j                         d   }| j
                  |j                         d }t        ||||      \  }}|| _        ||fcddd       S # 1 sw Y   yxY w)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   rI   r   r   r   )rP   r   r   r^   r   r   r   r   s           r1   pop_mappingzControlLine.pop_mapping  s    & 
		 	899--0iEWXX q!c//)--/"23i*9fgyQj)!do:  s   B B77C rz   )NFF)FF)FFF)r{   r|   r}   r~   r   rS   r   r   r   r   r   r@   r   r   rF   r1   r   r   C  s5    $-!
08  D"rF   r   c                    | dk(  rt        d      d| }}|r5t        ||      \  }}|dk7  s|dk(  rt        d| z         |d| ||dz   d }}nd|v r|j                  dd      \  }}n|d}}|rat	        j
                  |      d   }t        j                  j                         r+|s)t        j                  j                  j                  |      }|r)t        j                  j                  j                  |      }||j                         fS )	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   rI   splitcodecsescape_decoder.   rZ   r[   r=   r>   r\   r?   lstrip)liner   r   r^   r   r   r   r   s           r1   r   r     s    
RZ
4
55di*/	7CKa9?>EFF%a	2Ii!mn4M	J i'ooc15j)')j %%j1!4J{{ 99&&22:>j$$..z:J
i&&(	))rF   c                     g d}}t        d      D ]`  }| j                  d|dz         }|r6|dk\  r1| |dz
     dk(  r&| j                  d|dz         }|dk\  r| |dz
     dk(  r&|j                  |       b t        |      S )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   rl   "r   \)rangefindappendtuple)r   r   indicesquote_indexrW   s        r1   r   r   "  s     R;'8 	 a))Cq1K 1kAo!6$!>ii[1_5 1kAo!6$!> NN;	  
wrF   c                       e Zd ZdZddZd Zy)r   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                 d    |r| j                         d   dk(  S | j                         d   d   dk(  S )a}  
    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   )rU   r   OKrU   )rA   )rP   stricts     r1   rX   zSingleLineResponse.is_okF  s9     \\^A"444<<>!Q5((rF   c                     | j                         }t        |      dkD  rt        j                  d      t        |      dk(  rt        j                  d      |d   \  | _        }| _        y )Nr   zReceived multi-line responser   zReceived empty response)rA   ri   r.   ProtocolErrorrV   r,   )rP   rA   rW   s      r1   r*   z!SingleLineResponse._parse_messageW  s]    llnG
7|a=>>	W	899#*1: diDLrF   Nrz   )r{   r|   r}   r~   rX   r*   r   rF   r1   r   r   <  s    )".rF   r   )r~   r   r;   r7   rK   r   stem.socketr.   	stem.utilstem.util.str_tools__all__compiler   r	   objectr
   r   r   r   r   r   r   rF   r1   <module>r      sy   6  	 	      "**Z
 C#LAV AH`# `F9*x4#. #.rF   