o
    
]J                     @   s   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dZdd ZG dd deZG d	d
 d
eZdd Zdd ZG dd deZdS )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              	   K   s   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jtd}z||  }W n t	yX   t	d|  w ||_|jdi | dS )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)Z	ADD_ONIONZAUTHCHALLENGEZEVENTZGETCONFZGETINFOZ
MAPADDRESSZPROTOCOLINFOZ
SINGLELINEzUnsupported response type: %s )Zstem.response.add_onionZstem.response.authchallengeZstem.response.eventsZstem.response.getinfoZstem.response.getconfZstem.response.mapaddressZstem.response.protocolinfo
isinstancer	   	TypeErrorZresponser   ZAddOnionResponser   ZAuthChallengeResponser   ZEventr   ZGetConfResponser   ZGetInfoResponseZ
mapaddressZMapAddressResponser   ZProtocolInfoResponser   	__class___parse_message)Zresponse_typemessagekwargsstemZresponse_typesZresponse_classr   r   8/usr/lib/python3/dist-packages/stem/response/__init__.pyr   9   s2   '
r   c                   @   s|   e Zd ZdZedddZdddZdd	 Zdd
dZdddZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd ZdS )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.
  NFc                 K   sj   |r|  ds| d7 } tdd| } tjjttjj	
| |ddd}|dur3t||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)r   )endswithresubr   ZsocketZrecv_messageioBytesIOutil	str_tools	_to_bytespopr   )contentZmsg_type	normalizer   msgr   r   r   from_str   s   
(zControlMessage.from_strc                 C   sH   |st d|r
|ntt | _|| _|| _d | _tj	| d| _
d S )NzControlMessages can't be empty_raw_content)
ValueErrorinttimer   _parsed_contentr$   _strr   r   Z
_hash_attr_hash)selfZparsed_contentraw_contentr   r   r   r   __init__   s   zControlMessage.__init__c                 C   s$   | j D ]\}}}|dkr dS qdS )z
    Checks if any of our lines have a 250 response.

    :returns: **True** if any lines have a 250 response code, **False** otherwise
    250TF)r(   )r+   code_r   r   r   is_ok   s
   zControlMessage.is_okc                 C   s(   t j r|sdd | jD S t| jS )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
    c                 S   s&   g | ]\}}}||t jj|fqS r   )r   r   r   _to_unicode).0r/   Zdivr    r   r   r   
<listcomp>   s   & z*ControlMessage.content.<locals>.<listcomp>)r   prereqis_python_3r(   listr+   	get_bytesr   r   r   r       s   "
zControlMessage.contentc                 C   s$   t j r|st 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   r5   r6   r   r   r2   r$   r8   r   r   r   r,      s   zControlMessage.raw_contentc                 C   s    | j du rdt| | _ | j S )z^
    Content of the message, stripped of status code and divider protocol
    formatting.
    Nr   )r)   joinr7   r+   r   r   r   __str__   s   
zControlMessage.__str__c                 c   s:    | j D ]\}}}tj rtjj|}t|V  qdS )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r(   r   r5   r6   r   r   r2   r
   )r+   r0   r    r   r   r   __iter__	  s   
zControlMessage.__iter__c                 C   s
   t | jS )z*
    :returns: number of ControlLines
    )lenr(   r;   r   r   r   __len__&  s   
zControlMessage.__len__c                 C   s.   | j | d }tj rtjj|}t|S )zD
    :returns: :class:`~stem.response.ControlLine` at the index
       r=   )r+   indexr    r   r   r   __getitem__-  s   
zControlMessage.__getitem__c                 C      | j S N)r*   r;   r   r   r   __hash__9  s   zControlMessage.__hash__c                 C   s   t |trt| t|kS dS NF)r   r	   hashr+   otherr   r   r   __eq__<  s   zControlMessage.__eq__c                 C   s
   | |k S rE   r   rI   r   r   r   __ne__?  s   
zControlMessage.__ne__rG   rE   F)__name__
__module____qualname____doc__staticmethodr#   r-   r1   r    r,   r<   r>   r@   rC   rF   rK   rL   r   r   r   r   r	      s    


'r	   c                   @   s`   e Zd ZdZdd Zdd Zdd Zdd	 ZdddZdddZ	dd Z
dddZdddZdS )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                 C   s   t | |S rE   )str__new__r+   valuer   r   r   rT   M  s   zControlLine.__new__c                 C   s   || _ t | _d S rE   )
_remainder	threadingRLock_remainder_lockrU   r   r   r   r-   P  s   zControlLine.__init__c                 C   rD   )z
    Provides our unparsed content. This is an empty string after we've popped
    all entries.

    :returns: **str** of the unparsed content
    rW   r;   r   r   r   	remainderT  s   zControlLine.remainderc                 C   s
   | 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[   r;   r   r   r   is_empty^  s   
zControlLine.is_emptyFc                 C   s    t | j|\}}|dko|dk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_indicesrW   )r+   escapedstart_quote	end_quoter   r   r   is_next_quotedg  s   	zControlLine.is_next_quotedNc                 C   sZ   | j }t|}|r+|r|| d krdS |r)t||\}}|| ko(|dkS dS dS )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)rW   KEY_ARGmatchgroupsr`   end)r+   keyquotedra   r\   	key_matchrb   rc   r   r   r   is_next_mappings  s   
zControlLine.is_next_mappingc                 C   s$   | j }t|}|r| d S dS )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)rW   re   rf   rg   )r+   r\   rk   r   r   r   peek_key  s
   
zControlLine.peek_keyc                 C   sH   | j  t| j||d\}}|| _|W  d   S 1 sw   Y  dS )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)rZ   _parse_entryrW   )r+   rj   ra   
next_entryr\   r   r   r   r     s
   $zControlLine.popc                 C   s   | j > |  rtdt| j}|std| j | d }| j| d }t	||||\}}|| _||fW  d   S 1 sDw   Y  dS )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)
rZ   r^   
IndexErrorre   rf   rW   r%   rg   rh   rn   )r+   rj   ra   r9   rk   ri   r\   ro   r   r   r   pop_mapping  s   $zControlLine.pop_mappingrM   )NFF)FF)FFF)rN   rO   rP   rQ   rT   r-   r\   r^   rd   rl   rm   r   rr   r   r   r   r   r
   C  s    	

	

"r
   c                 C   s   | dkrt dd| }}|r4t||\}}|dks|dkr$td|  |d| ||d d }}nd|v rA|dd\}}n|d}}|r]t|d }tj r]|s]tj	j
|}|rft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]   rp   r   r_   z%the next entry isn't a quoted value:    N )rq   r`   r%   splitcodecsescape_decoder   r5   r6   r   r   r2   r   lstrip)linerj   ra   r9   ro   r\   rb   rc   r   r   r   rn     s$   
 
rn   c                 C   s~   g d}}t dD ]1}| d|d }|r5|dkr5| |d  dkr5| d|d }|dkr5| |d  dks!|| q	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_   rA   "rs   \)rangefindappendtuple)ry   ra   indicesZquote_indexr0   r   r   r   r`   "  s   

r`   c                   @   s"   e Zd ZdZdddZdd ZdS )	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
  Fc                 C   s(   |r
|   d dkS |   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   )r.   rt   ZOKr.   )r    )r+   strictr   r   r   r1   F  s   zSingleLineResponse.is_okc                 C   sJ   |   }t|dkrtdt|dkrtd|d \| _}| _d S )Nrs   zReceived multi-line responser   zReceived empty response)r    r?   r   ZProtocolErrorr/   r   )r+   r    r0   r   r   r   r   W  s   

z!SingleLineResponse._parse_messageNrM   )rN   rO   rP   rQ   r1   r   r   r   r   r   r   <  s    
	r   )rQ   rv   r   r   r'   rX   Zstem.socketr   Z	stem.utilZstem.util.str_tools__all__compilere   r   objectr	   rS   r
   rn   r`   r   r   r   r   r   <module>   s&   
F E $<