o
    ñu]e/  ã                   @   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ddl	Zddl
ZddlZddlmZmZmZmZmZ ddlmZ zddlmZ W n eyY   ddlmZ Y nw dZdd„ Zejd	d
„ ƒZG dd„ dejƒZdS )z7
Handles making requests and formatting the responses.
é    N)ÚSTANDARD_OUTPUTÚBOLD_OUTPUTÚERROR_OUTPUTÚuses_settingsÚmsg)Úformat)ÚStringIOéd   c           	      C   s  | sz|  d¡W S    tdƒ‚tjj | ¡r| S tjj | ¡r1z| | ¡jW S    td|  ƒ‚d| v s<tjj	 
| ¡rÂd| v ri|  dd¡\}}tjj	 
|¡sUtd| ƒ‚|rdtjj	 |¡sdtd| ƒ‚t|ƒ}n| d}}i }| ¡ D ]}|j|krˆ|r‚|j|krˆ|j||j< qtt|ƒd	kr•td
|  ƒ‚t|ƒdkr£t| ¡ ƒd	 S d|  }t|ƒD ]\}}|d|d |||| f 7 }q«t|ƒ‚td|  ƒ‚)aÞ  
  Resolves user input into a relay fingerprint. This accepts...

    * Fingerprints
    * Nicknames
    * IPv4 addresses, either with or without an ORPort
    * Empty input, which is resolved to ourselves if we're a relay

  :param str arg: input to be resolved to a relay fingerprint
  :param stem.control.Controller controller: tor control connection

  :returns: **str** for the relay fingerprint

  :raises: **ValueError** if we're unable to resolve the input to a relay
  Úfingerprintz,We aren't a relay, no information to providez0Unable to find a relay with the nickname of '%s'ú:é   z'%s' isn't a valid IPv4 addressz'%s' isn't a valid portNr   zNo relays found at %szAThere's multiple relays at %s, include a port to specify which.

z  %i. %s:%s, fingerprint: %s
z1'%s' isn't a fingerprint, nickname, or IP address)Úget_infoÚ
ValueErrorÚstemÚutilZ	tor_toolsZis_valid_fingerprintZis_valid_nicknameÚget_network_statusr
   Z
connectionZis_valid_ipv4_addressÚrsplitZis_valid_portÚintZget_network_statusesÚaddressÚor_portÚlenÚlistÚvaluesÚ	enumerate)	ÚargÚ
controllerr   ZportÚmatchesÚdescÚresponseÚir   © r    ú;/usr/lib/python3/dist-packages/stem/interpreter/commands.pyÚ_get_fingerprint    sH   


€r"   c              	   c   sD    t jt jf}| |t _t _zd V  W |\t _t _d S |\t _t _w )N)ÚsysÚstdoutÚstderr)r$   r%   Zoriginalr    r    r!   Úredirect`   s   €r&   c                   @   sN   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
d„ Zdd„ Z	e
ddd„ƒZdS )ÚControlInterpreterzw
  Handles issuing requests and providing nicely formed responses, with support
  for special irc style subcommands.
  c                    sV   g ˆ_ tj ˆttj|ˆjdœ¡ |ˆ_dˆ_dˆ_	ˆjj
‰ ‡ ‡fdd„}|ˆj_
d S )N)r   zstem.controlr   ÚeventsTFc                    s6   ˆ | ƒ ˆj  d| ¡ tˆj ƒtkrˆj  ¡  d S d S )Nr   )Ú_received_eventsÚinsertr   Ú
MAX_EVENTSÚpop)Zevent_message©Zhandle_event_realÚselfr    r!   Úhandle_event_wrapperˆ   s
   ÿz9ControlInterpreter.__init__.<locals>.handle_event_wrapper)r)   ÚcodeÚInteractiveConsoleÚ__init__r   ZcontrolÚ
get_eventsÚ_controllerÚ_run_python_commandsÚis_multiline_contextZ_handle_event)r.   r   r/   r    r-   r!   r2   q   s   üzControlInterpreter.__init__c                    s4   t | jƒ}t ttjˆ ƒƒ‰ ˆ r‡ fdd„|D ƒ}|S )Nc                    s   g | ]	}|j ˆ v r|‘qS r    )Útype©Ú.0Úe©Úevent_typesr    r!   Ú
<listcomp>–   s    z1ControlInterpreter.get_events.<locals>.<listcomp>)r   r)   ÚmapÚstrÚupper)r.   r<   r(   r    r;   r!   r3   ‘   s
   
zControlInterpreter.get_eventsc                 C   s   t jj | j|¡S )z‡
    Performs the '/help' operation, giving usage information for the given
    argument or a general summary if there wasn't one.
    )r   ZinterpreterÚhelpr   r4   )r.   r   r    r    r!   Údo_helpš   s   zControlInterpreter.do_helpc                 C   sJ   |  ¡  ¡ }d|v r| jdd…= tdgt¢R Ž S d dd„ | j|Ž D ƒ¡S )a  
    Performs the '/events' operation, dumping the events that we've received
    belonging to the given types. If no types are specified then this provides
    all buffered events.

    If the user runs '/events clear' then this clears the list of events we've
    received.
    ZCLEARNzcleared event backlogÚ
c                 S   s    g | ]}t t|ƒgt¢R Ž ‘qS r    )r   r?   r   r8   r    r    r!   r=   ²   s     z0ControlInterpreter.do_events.<locals>.<listcomp>)r@   Úsplitr)   r   r   Újoinr3   )r.   r   r<   r    r    r!   Ú	do_events¢   s
   
zControlInterpreter.do_eventsc              
   C   sÔ  zt || jƒ}W n ty$ } ztt|ƒgt¢R Ž W  Y d}~S d}~ww | j |d¡}| j |d¡}d}| j |d¡}|sHtd| gt¢R Ž S t	j
jjdd}| |¡}	| |¡}
|	D ]}|}q\|
D ]}|}qcg }z| t |j¡d ¡ W n   Y z| | j d|j ¡¡ W n   Y |r˜dd |¡ nd	}|r¢t|jƒ}n
|rªt|jƒ}nd
}d|j|f tdgt¢R Ž d|j|j|f  g}|rÖ| tdgt¢R Ž t|jƒ ¡ | tdgt¢R Ž d |j¡ ¡ | tdgt¢R Ž | ¡ |r(|jr(t	jj |j¡}dD ]	}| |d¡}qdD ]	}| |d¡}q| tdgt¢R Ž | ¡ d|fd|fd|fd|fg}tdgt ¢R Ž }|D ]$\}}|rc|d	|t|gt¢R Ž |d	g7 }|dd„ t|ƒ !¡ D ƒ7 }q@d |¡S )z³
    Performs the '/info' operation, looking up a relay by fingerprint, IP
    address, or nickname and printing its descriptor and consensus entries in a
    pretty fashion.
    Nz+Unable to find consensus information for %sé   )Ztimeoutr   zip-to-country/%sz (%s)z, Ú ZUnknownz%s (%s)z	address: z%s:%s%sztor version: zflags: zexit policy: )z at z AT ú@)z dot z DOT Ú.z	contact: zServer Descriptor:zExtrainfo Descriptor:zMicrodescriptor:zRouter Status Entry:zP--------------------------------------------------------------------------------c                 S   s   g | ]
}t |gt¢R Ž ‘qS r    )r   r   )r9   Úlr    r    r!   r=     s    z.ControlInterpreter.do_info.<locals>.<listcomp>rC   )"r"   r4   r   r   r?   r   r   Zget_server_descriptorZget_microdescriptorr   Z
descriptorZremoteZDescriptorDownloaderZget_server_descriptorsZget_extrainfo_descriptorsÚappendÚsocketZgethostbyaddrr   r   rE   Zexit_policyZnicknamer   r   Ztor_versionÚflagsÚcontactr   Z	str_toolsZ_to_unicodeÚreplacer   Ú
splitlines)r.   r   r
   ÚexcZns_descZserver_descZextrainfo_descZ
micro_descZ
downloaderZserver_desc_queryZextrainfo_desc_queryr   Zaddress_extrainfoZaddress_extrainfo_labelZexit_policy_labelÚlinesrO   ÚaliasZdescriptor_sectionZdivZlabelr    r    r!   Údo_info´   sx    €ÿ

 þ "ü€
zControlInterpreter.do_infoc                 C   s‚   |s| j rdnd}td| gt¢R Ž S | ¡ dkrd| _ n| ¡ dkr'd| _ n
td| gt¢R Ž S | j r7d	}nd
}t|gt¢R Ž S )z]
    Performs the '/python' operation, toggling if we accept python commands or
    not.
    ÚenabledZdisabledzPython support is currently %s.ZenableTZdisableFzP'%s' is not recognized. Please run either '/python enable' or '/python disable'.zIPython support enabled, we'll now run non-interpreter commands as python.zBPython support disabled, we'll now pass along all commands to tor.)r5   r   r   Úlowerr   )r.   r   Ústatusr   r    r    r!   Ú	do_python  s   zControlInterpreter.do_pythonFc           
   
   C   sú  |  ¡ d}}d|v r| dd¡\}}d}| d¡rY| ¡ }|dkr&t ¡ ‚|dkr0|  |¡}n¿|dkr:|  |¡}nµ|dkrD|  |¡}n«|d	krN|  	|¡}n¡t
d
| gt¢R Ž }n–| ¡ }| dd¡dv rpt
tdƒgt¢R Ž }n|dkr~| j |¡ t ¡ ‚|| di ¡v o‹| ¡ dk}| jr¸|s¸tƒ }t||ƒ tj | |¡| _W d  ƒ n1 s¬w   Y  | ¡   ¡ }n7zt
| j |¡ ¡   ¡ gt¢R Ž }W n$ tjyî }	 zt|	tjƒrÚ‚ t
t|	ƒgt¢R Ž }W Y d}	~	nd}	~	ww |rû|d7 }|rût|ƒ |S )a  
    Runs the given command. Requests starting with a '/' are special commands
    to the interpreter, and anything else is sent to the control port.

    :param stem.control.Controller controller: tor control connection
    :param str command: command to be processed
    :param bool print_response: prints the response to stdout if true

    :returns: **list** out output lines, each line being a list of
      (msg, format) tuples

    :raises: **stem.SocketClosed** if the control connection has been severed
    rH   ú r   ú/z/quitz/eventsz/infoz/pythonz/helpz'%s' isn't a recognized commandú+)ZLOADCONFZPOSTDESCRIPTORz"msg.multiline_unimplemented_noticeZQUITz
help.usager(   NrC   )ÚstriprD   Ú
startswithrW   r   ZSocketClosedrF   rU   rY   rB   r   r   r@   rP   r   r4   Úgetr5   r   r&   r0   r1   Úpushr6   ÚgetvalueZraw_contentr   ZControllerErrorÚ
isinstancer?   Úprint)
r.   ZcommandZconfigZprint_responseÚcmdr   ÚoutputZis_tor_commandZconsole_outputrR   r    r    r!   Úrun_command-  sV   

ÿ$ €üzControlInterpreter.run_commandN)F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r2   r3   rB   rF   rU   rY   r   rf   r    r    r    r!   r'   k   s     	br'   )rj   r0   Ú
contextlibrM   r#   r   Zstem.controlZstem.descriptor.remoteZstem.interpreter.helpZstem.util.connectionZstem.util.str_toolsZstem.util.tor_toolsZstem.interpreterr   r   r   r   r   Zstem.util.termr   Ú	cStringIOr   ÚImportErrorÚior+   r"   Úcontextmanagerr&   r1   r'   r    r    r    r!   Ú<module>   s0   ÿ@

