
    `gj                     x   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mZm	Z	m
Z
mZ  ej                  e      ZddlmZmZmZmZ ddlmZ dedefdZd	edefd
Z G d de      ZdefdZdefdZddZdefdZdedz  fdZ dedefdZ!dedefdZ"dddddededee   dee
e      dede	eef   fdZ#d Z$y) u  
IRC Platform Adapter for Hermes Agent.

A plugin-based gateway adapter that connects to an IRC server and relays
messages to/from the Hermes agent.  Zero external dependencies — uses
Python's stdlib asyncio for the IRC protocol.

Configuration in config.yaml::

    gateway:
      platforms:
        irc:
          enabled: true
          extra:
            server: irc.libera.chat
            port: 6697
            nickname: hermes-bot
            channel: "#hermes"
            use_tls: true
            server_password: ""       # optional server password
            nickserv_password: ""     # optional NickServ identification
            allowed_users: []         # empty = allow all, or list of nicks
            max_message_length: 450   # IRC line limit (safe default)

Or via environment variables (overrides config.yaml):
    IRC_SERVER, IRC_PORT, IRC_NICKNAME, IRC_CHANNEL, IRC_USE_TLS,
    IRC_SERVER_PASSWORD, IRC_NICKSERV_PASSWORD
    N)AnyDictListOptional)BasePlatformAdapter
SendResultMessageEventMessageType)Platformrawreturnc                 J   d}d}| j                  d      r	 | dd j                  dd      \  }} d| v r| j                  dd      \  } }| j                         }|r|d   nd}t        |      dkD  r|dd ng }|r|j	                  |       |||dS # t        $ r
 | dd }d} Y rw xY w)	ziParse a raw IRC protocol line into components.

    Returns dict with keys: prefix, command, params.
     :   N  :r   )prefixcommandparams)
startswithsplit
ValueErrorlenappend)r   r   trailingpartsr   r   s         P/root/.hermes/venv/lib/python3.12/site-packages/plugins/platforms/irc/adapter.py_parse_irc_messager   ;   s    
 FH
~~c	ab'--Q/KFC
 s{		$*XIIKEeAhRGe*q.U12YbFhFCC  	WFC	s   B B"!B"r   c                 6    d| v r| j                  d      d   S | S )z2Extract nickname from IRC prefix (nick!user@host).!r   )r   )r   s    r   _extract_nickr"   V   s!    #&&=6<<Q<f<    c                   2    e Zd ZdZ fdZedefd       ZdddedefdZ	dd
Z
	 	 d dededee   deeeef      fdZd!dedd	fdZdedeeef   fdZdededee   fdZededefd       Zdedd	fdZddZdedd	fdZdedededededd	fdZ xZS )"
IRCAdapterzAsync IRC adapter implementing the BasePlatformAdapter interface.

    This class is instantiated by the adapter_factory passed to
    register_platform().
    c                    t        d      }t        	| 	  ||       t        |di       xs i }t	        j
                  d      xs |j                  dd      | _        	 t        t	        j
                  d      xs |j                  dd	            | _	        t	        j
                  d
      xs |j                  dd      | _        t	        j
                  d      xs |j                  dd      | _        t	        j
                  d      r&t	        j
                  dd      j                         dv n|j                  dd      | _        t	        j
                  d      xs |j                  dd      | _        t	        j
                  d      xs |j                  dd      | _        |j                  dg       | _        | j$                  D ch c]#  }t'        |t(              s|j                         % c}| _        |j                  d      }|2	 ddlm} |j                  d      }|r|j0                  r|j0                  }t        |xs d      | _        d | _        d | _        d | _        | j                  | _        d| _        t?        j@                         | _!        y # t        t        f$ r d	| _	        Y w xY wc c}w # t2        $ r Y w xY w)Nirc)configplatformextra
IRC_SERVERserverr   IRC_PORTport)  IRC_NICKNAMEnickname
hermes-botIRC_CHANNELchannelIRC_USE_TLS>   1yestrueuse_tlsTIRC_SERVER_PASSWORDserver_passwordIRC_NICKSERV_PASSWORDnickserv_passwordallowed_usersmax_message_lengthr   )platform_registry  F)"r   super__init__getattrosgetenvgetr,   intr.   r   	TypeErrorr1   r4   lowerr9   r;   r=   r>   
isinstancestr_allowed_users_lowergateway.platform_registryr@   r?   	Exception_reader_writer
_recv_task_current_nick_registeredasyncioEvent_registration_event)
selfr(   kwargsr)   r*   umax_msgr@   entry	__class__s
            r   rC   zIRCAdapter.__init__f   sR   E?:,2 ii-H8R1H	BIIj1LUYYvt5LMDI 		.1XUYYz<5Xyy/K599Y3K yy' IImR(..04HH9d+ 	
  "yy)>?c599M^`bCc!#+B!C!iuyyQdfhGi $)99_b#A=A=O=O)fS]^_adSe!''))f! ))01?G)--e4U55#66G #&gn"5 8<7;26!]] #*==? G I& 	DI	 *g  s0   7J J1J11J6 J.-J.6	KKr   c                      y)NIRC )rX   s    r   namezIRCAdapter.name   s    r#   F)is_reconnectrb   c                  K   | j                   r| j                  s*t        j                  d       | j	                  ddd       y	 ddlm}m} | j                    d| j                   } |d	|      s@t        j                  d
| j                  | j                          | j	                  ddd       y|| _	        	 d}| j                  rt        j                         }t        j                  t        j                   | j                   | j"                  |      d       d{   \  | _        | _        | j,                  r&| j/                  d| j,                          d{    | j/                  d| j                          d{    | j/                  d| j                   d       d{    t        j0                  | j3                               | _        	 t        j                  | j6                  j9                         d       d{    | j>                  rC| j/                  d| j>                          d{    t        j@                  d       d{    | j/                  d| j                          d{    | jC                          t        jE                  d| j                   | j"                  | jF                  | j                         y# t        $ r d| _	        Y 2w xY w7 # t(        $ rS}t        j                  d| j                   | j"                  |       | j	                  dt+        |      d       Y d}~yd}~ww xY w7 7 7 7 N# t        j:                  $ rE t        j                  d       | j=                          d{  7   | j	                  ddd       Y yw xY w7 z7 `7 =w)z:Connect to the IRC server, register, and join the channel.z*IRC: server and channel must be configuredconfig_missingz&IRC_SERVER and IRC_CHANNEL must be setF	retryabler   )acquire_scoped_lockrelease_scoped_lockr   r'   z,IRC: %s@%s already in use by another profilelock_conflictz&IRC identity in use by another profileNsslg      >@timeoutu&   IRC: failed to connect to %s:%s — %sconnect_failedTPASS NICK USER z 0 * :Hermes AgentzIRC: registration timed outregistration_timeoutz#IRC server did not send RPL_WELCOMEPRIVMSG NickServ :IDENTIFY    JOIN z(IRC: connected to %s:%s as %s, joined %s)$r,   r4   loggererror_set_fatal_errorgateway.statusrg   rh   r1   	_lock_keyImportErrorr9   rk   create_default_contextrU   wait_foropen_connectionr.   rP   rQ   rO   rL   r;   	_send_rawcreate_task_receive_looprR   rW   waitTimeoutError
disconnectr=   sleep_mark_connectedinforS   )rX   rb   rg   rh   lock_keyssl_ctxes          r   connectzIRCAdapter.connect   s&    {{$,,LLEF!! 8 " 
 		"O++a7H&uh7KT]]\`\g\gh%%o7_kp%q%DN	G||446/6/?/?''TYYGL0 *&DL$, ..5)=)=(>!?@@@nnuT]]O4555nnuT]]O3EFGGG "--d.@.@.BC	""4#;#;#@#@#BDQQQ !!..#>t?U?U>V!WXXX--""" nnuT\\N3444>TYYX\XjXjlplxlxy[  	"!DN	"*  	LLA4;;PTPYPY[\]!!"2CFd!K	 A5G R## 	LL67//###!!"8:_ko!p		 Y" 	5s  AOA+K 1O2K :A&K2  K/!K2 2-OM %OM&O,M-,O2M MM -O>N8?ON;%ON>AOK,(O+K,,O/K2 2	M;A	M	O	MOOOM ;N5NN52O4N55O;O>ONc                 T  K   t        | dd      r	 ddlm}  |d| j                         | j                          | j                  r| j                  j                         st	 | j                  d       d{    t        j                  d       d{    	 | j                  j                          | j                  j                          d{    | j                  rI| j                  j                         s/| j                  j                          	 | j                   d{    d| _        d| _        d| _        | j&                  j)                          y# t        $ r Y ;w xY w7 7 # t        $ r Y w xY w7 # t        $ r Y w xY w7 h# t        j                   $ r Y {w xY ww)	zQuit and close the connection.rz   Nr   )rh   r'   z QUIT :Hermes Agent shutting downg      ?F)rD   ry   rh   rz   rO   _mark_disconnectedrQ   
is_closingr   rU   r   closewait_closedrR   donecancelCancelledErrorrP   rT   rW   clear)rX   rh   s     r   r   zIRCAdapter.disconnect   sj     4d+>#E4>>: 	!<< 7 7 9nn%GHHHmmC(((""$ll..000 ??4??#7#7#9OO""$oo%%    &&(3  
 I(  1  &)) s   F(E 6F(!E- 5E)6E- E+E- 7E> E<E> A F(F $F%F )0F(	E&"F(%E&&F()E- +E- -	E96F(8E99F(<E> >	F
F(	F

F(F F%"F($F%%F(chat_idcontentreply_tometadatac           	        K   | j                   r| j                   j                         rt        dd      S |}| j                  ||      }|D ]?  }	 | j	                  d| d|        d {    t        j                  d       d {    A t        dt        t        t        j                         dz              	      S 7 W7 <# t        $ r"}t        dt        |            cY d }~c S d }~ww xY ww)
NFzNot connected)successrw   PRIVMSG r   333333?T  r   
message_id)rQ   r   r   _split_messager   rU   r   rO   rL   rH   time)	rX   r   r   r   r   targetlinesliner   s	            r   sendzIRCAdapter.send  s      ||t||668e?CC##GV4 	?D?nnxxr$%@AAAmmC(((		? $3s499;;M7N3OPP B( ?!%s1v>>?sZ   AC4C*C+CCC6C4CC	C1C,$C1%C4,C11C4c                    K   yw)u&   IRC has no typing indicator — no-op.Nr`   )rX   r   r   s      r   send_typingzIRCAdapter.send_typing  s	     s   c                 h   K   |j                  d      xs |j                  d      }||rddS ddS w)N#&groupdm)ra   type)r   )rX   r   
is_channels      r   get_chat_infozIRCAdapter.get_chat_info  sE     '',G0B0B30G
)G
 	
/3
 	
s   02r   c                    | j                  |      }t        d| dj                  d            dz   }d|z
  }| j                  }g }|j	                  d      D ]  }|j                         s	 |j                  d      }t        ||      }	t        |      |	k  r"|j                         r|j                  |       cdt        |      }}
d}|
|k  r;|
|z   dz  }t        |d	| j                  d            |	k  r|}|dz   }
n|dz
  }|
|k  r;|}|j                  d
d|      }||dz  kD  r|}|j                  |d	| j                                ||d	 j                         } |r|S dgS )zSplit a long message into IRC-safe chunks.

        IRC has a ~512 byte line limit.  After accounting for protocol
        overhead (``PRIVMSG <target> :``), we split content into chunks.
        r   r   utf-8rt     
r   r   Nr      r   )_strip_markdownr   encoder?   r   stripminr   rfindrstriplstrip)rX   r   r   overhead	max_bytes
user_limitr   	paragraph
para_byteslimitlowhighbestmidsplit_atspaces                   r   r   zIRCAdapter._split_message&  s    &&w/&,33G<=A(N	,,
 t, 	:I??$&--g6
J	2z?e+ (Y/s9~TTk:!+C9Tc?11':;uD"!Ag"Qw Tk  !Q98q=($HYy188:;%hi0779	/ 	:8 u'B4'r#   textc                 v   t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  dd|       } t        j                  d	d
|       } t        j                  dd|       } | S )z-Convert basic markdown to plain text for IRC.z\*\*(.+?)\*\*z\1z	__(.+?)__z	\*(.+?)\*z(?<!\w)_(.+?)_(?!\w)z`(.+?)`z	```\w*\n?r   z!\[([^\]]*)\]\(([^)]+)\)z\2z\[([^\]]+)\]\(([^)]+)\)z\1 (\2))resubr   s    r   r   zIRCAdapter._strip_markdownR  s     vv&t4vvlE40vvlE40vv-ud;vvj%.vvlB-vv15$?vv0*dCr#   r   c                    K   | j                   r| j                   j                         ry|dz   j                  d      }| j                   j                  |       | j                   j	                          d{    y7 w)zSend a raw IRC protocol line.N
r   )rQ   r   r   writedrain)rX   r   encodeds      r   r   zIRCAdapter._send_rawg  s[     ||t||668&=((17#ll  """s   A4A>6A<7A>c                   K   d}	 | j                   r| j                   j                         s| j                   j                  d       d{   }|snw||z  }d|v rG|j                  dd      \  }}	 |j	                  dd      }| j                  |       d{    d|v rG| j                   r| j                   j                         s| j                  rBt        j                  d       | j                  ddd       | j                          d{    yy7 7 # t        $ r }t        j                  d	|       Y d}~d}~ww xY w# t        j                  $ r  t        $ r }t        j                  d
|       Y d}~d}~ww xY w7 u# | j                  rCt        j                  d       | j                  ddd       | j                          d{  7   w w xY ww)u6   Main receive loop — reads lines and dispatches them.r#   i   N   
r   r   replaceerrorszIRC: error handling line: %szIRC: receive loop error: %sz*IRC: connection lost, marking disconnectedconnection_lostz"IRC connection closed unexpectedlyTre   )rP   at_eofreadr   decode_handle_linerO   rv   warningrU   r   rw   is_connectedrx   _notify_fatal_error)rX   bufferdatar   decodedr   s         r   r   zIRCAdapter._receive_loopo  s    	1,,t||':':'<!\\..t44$'#)<<#;LD&J"&++gi+"H"//888	 ' ,,t||':':'<"   KL%%&79]im%n..000 !! 5 9$ J'EqIIJ%% 	 	;LL6::	; 1   KL%%&79]im%n..000 !s   GAE 
D%E 1'D DD E "&E 	AGFGE D 	E%E ;E  EE F$E?:F	 ?FF	 G	A	GGGGr   c                   K   t        |      }|d   }|d   }|dk(  r&|r|d   nd}| j                  d|        d{    y|dk(  r.d	| _        | j                  j	                          |r
|d   | _        y|d
k(  r| j                  j                  d      }t        j                  d| j
                        }|r*t        |j                  d            dz   }| d| | _        nB| j
                  | j                  k(  r| j                  dz   | _        n| j                  dz   | _        | j                  d| j
                          d{    y|dk(  rt        |      dk\  rt        |d         }	|d   }
|d   }|	j                         | j
                  j                         k(  ry|j                  d      r|j!                  d      rd|	 d|dd  }|j                  d      ry|
j                  d      xs |
j                  d      }|r|
n|	}|rdnd}|rd}| j
                   d| j
                   d | j
                   dfD ]O  }|j                         j                  |j                               s1|t        |      d j#                         }d	} n |sy| j$                  r3|	j                         | j$                  vrt&        j)                  d!|	       y| j+                  ||||	|	"       d{    |d#k(  rFt        |d         j                         | j
                  j                         k(  r|r|d   | _        yyyy7 7 7 Vw)$z$Dispatch a single IRC protocol line.r   r   PINGr   r   PONG :N001T433_0123456789z_(\d+)$r   __1rp   PRIVMSGrt   r   zACTION z* r      r   r   r   r   Fr   ,z/IRC: ignoring message from unauthorized user %s)r   r   	chat_typeuser_id	user_nameNICK)r   r   rT   rW   setrS   r1   r   r   searchrH   r   r   r"   rJ   r   endswithr   rM   rv   debug_dispatch_message)rX   r   msgr   r   payloadbasesuffix_matchnext_numsender_nickr   r   r   r   r   	addressedr   s                    r   r   zIRCAdapter._handle_line  sh     %i.X f#)fQirG..6'!3444 e#D$$((*%+AY" e==''6D99Z1C1CDL|11!459(,vQxj%9"##t}}4%)]]S%8"%)]]T%9"..5););(<!=>>> iCK1$4'H6KAYF!9D   "d&8&8&>&>&@@ }-$--2GK=$q*6 v&  **3/I63D3DS3IJ *fG#-4I !	"&"4"4!5Q7D<N<N;Oq9Q"&"4"4!5Q79 Fzz|..v||~>#CKL1779$(	 ! (([->->-@HaHa-aNP[\((##% )    fs8}!=!C!C!EI[I[IaIaIc!c%+AY"  "dY 50 ?Vs=   ;M	MDM	MD-M	4A<M	0M1AM	M	M	r   r   r   c                 T  K   | j                   sy| j                  |||||      }t        |t        j                  |t        t        t        j                         dz              t        d      j                  j                               }| j                  |       d{    y7 w)z;Build a MessageEvent and hand it to the base class handler.N)r   	chat_namer   r   r   r   datetime)r   message_typesourcer   	timestamp)_message_handlerbuild_sourcer	   r
   TEXTrL   rH   r   
__import__r  nowhandle_message)rX   r   r   r   r   r   r  events           r   r   zIRCAdapter._dispatch_message  s      $$"" # 
 $))3tyy{T123 ,5599;
 !!%(((s   BB( B&!B(r   N)NNN)__name__
__module____qualname____doc__rC   propertyrL   ra   boolr   r   r   r   r   r   r   r   r   r   staticmethodr   r   r   r   r   __classcell__)r]   s   @r   r%   r%   _   sq   -3^ c  
 5: AT Ad AF )P #'-1QQ Q 3-	Q
 4S>*Q.  
3 
4S> 
*(c *(3 *(49 *(X c c  (#C #D #14W/c W/d W/r)) ) 	)
 ) ) 
)r#   r%   c                  x    t        j                  dd      } t        j                  dd      }t        | xr |      S )uo   Check if IRC is configured.

    Only requires the server and channel — no external pip packages needed.
    r+   r   r3   )rE   rF   r  r,   r4   s     r   check_requirementsr    s6    
 YY|R(Fiir*G "7##r#   c                     t        | di       xs i }t        j                  d      xs |j                  dd      }t        j                  d      xs |j                  dd      }t	        |xr |      S )z=Validate that the platform config has enough info to connect.r*   r+   r,   r   r3   r4   rD   rE   rF   rG   r  r(   r*   r,   r4   s       r   validate_configr    a    FGR(.BEYY|$?		(B(?Fii&B%))Ir*BG"7##r#   c                  
   ddl m} m}m}m}m}m}m}m}  |d        |d      }|r |d| d        |dd      sy	 |d
        |d       t                 | d|xs d      }	|	s	 |d       y	 |d|	j                                 |dd      }
 |d|
rdnd       |
rdnd} | d| d |d      xs d      }|r	  |dt        t        |                   n |d      r	 |dd        | d |d      xs d      }|s	 |d       y	 |d|j                                 | d |d      xs d      }|s	 |d       y	 |d|j                                t                 |d         |d!        |d"d      r | d#d$      }|r	 |d%|        |d&d      r | d'd$      }|r	 |d(|       t                 |d)        |d*        |d+        |d,        |d-d      }|r |d.d        |d/d        |d0       nR |d.d        | d1 |d/      xs d      }|r" |d/|j                  d2d              |d3       n |d/d        |d4       t                 |d5        |d6       y	# t        $ r  |d|        Y w xY w)7zInteractive `hermes gateway setup` flow for the IRC platform.

    Lazy-imports ``hermes_cli.setup`` helpers so the plugin stays importable
    in non-CLI contexts (gateway runtime, tests).
    r   )promptprompt_yes_nosave_env_valueget_env_valueprint_header
print_infoprint_warningprint_successr_   r+   z!IRC: already configured (server: )zReconfigure IRC?FNuR   Connect Hermes to an IRC network. Uses Python stdlib — no extra packages needed.z<   Works with Libera.Chat, OFTC, your own ZNC/InspIRCd, etc.z*IRC server hostname (e.g. irc.libera.chat)r   )defaultu)   Server is required — skipping IRC setupzUse TLS (recommended)?Tr5   r8   false66976667zPort (default r-   u   Invalid port — using default zBot nickname (e.g. hermes-bot)r0   u+   Nickname is required — skipping IRC setupu>   Channel to join (e.g. #hermes — comma-separate for multiple)r3   u*   Channel is required — skipping IRC setupu   🔑 Optional authenticationz   Leave blank to skip.z+Configure a server password (PASS command)?zServer password)passwordr:   z"Identify with NickServ on connect?zNickServ passwordr<   u5   🔒 Access control: restrict who can message the botuA      IRC nicks are not authenticated — anyone can claim any nick.zD   For public channels, pair with NickServ-only mode on your networkz,   if you want stronger identity guarantees.z2Allow all users in the channel to talk to the bot?IRC_ALLOW_ALL_USERSIRC_ALLOWED_USERSuD   ⚠️  Open access — any nick in the channel can command the bot.z=Allowed nicks (comma-separated, leave empty to deny everyone)r   zAllowlist configureduJ   No nicks allowed — the bot will ignore all messages until you add nicks.z)IRC configuration saved to ~/.hermes/.envzFRestart the gateway for changes to take effect: hermes gateway restart)hermes_cli.setupr  r   r!  r"  r#  r$  r%  r&  printr   rL   rH   r   r   )r  r   r!  r"  r#  r$  r%  r&  existing_serverr,   r9   default_portr.   r1   r4   r;   nickserv	allow_allalloweds                      r   interactive_setupr6    s   	 	 	 #L1O66GqIJ/7cdMN	G@/J_]_`FAB<04d;G=G&A$6&LN<.2M*<U<[Y[\D	L:s3t9~6 
z	"z2&(n-3H CD>8>>#34Hm,2G BC='--/2	G-.()BEJ !2TB0/B95A-=2H=	GFGRSUV=>RTYZI,f5*B/\],g6K!"56<"
 .R0HI01.3cd	G=>WX}  	L;L>JK	Ls   >I* *JJc                     t        | di       xs i }t        j                  d      xs |j                  dd      }t        j                  d      xs |j                  dd      }t	        |xr |      S )z5Check whether IRC is configured (env or config.yaml).r*   r+   r,   r   r3   r4   r  r  s       r   r   r     r  r#   c                  "   t        j                  dd      j                         } t        j                  dd      j                         }| r|sy| |d}t        j                  dd      j                         }|r	 t        |      |d<   t        j                  dd      j                         }|r||d	<   t        j                  d
d      j                         j                         }|r|dv |d<   t        j                  d      rt        j                  d      |d<   t        j                  d      rt        j                  d      |d<   t        j                  d      xs |}|r|t        j                  d|      d|d<   |S # t        $ r Y w xY w)u  Seed ``PlatformConfig.extra`` from env vars during gateway config load.

    Called by the platform registry's env-enablement hook (landed in the
    generic-plugin-interface migration) BEFORE adapter construction, so
    ``gateway status`` and ``get_connected_platforms()`` reflect env-only
    configuration without instantiating the IRC client.  Returns ``None``
    when IRC isn't minimally configured; the caller skips auto-enabling.

    The special ``home_channel`` key in the returned dict is handled by
    the core hook — it becomes a proper ``HomeChannel`` dataclass on the
    ``PlatformConfig`` rather than being merged into ``extra``.
    r+   r   r3   Nr  r-   r.   r0   r1   r5   >   r6   r7   r8   r9   r:   r;   r<   r=   IRC_HOME_CHANNELIRC_HOME_CHANNEL_NAME)r   ra   home_channel)rE   rF   r   rH   r   rJ   )r,   r4   seedr.   r1   r9   homes          r   _env_enablementr>    so    YY|R(..0Fiir*002GwD 99Z$**,D	t9DL yy,224H#Ziir*00288:G!%99Y 
yy&'"$)),A"B	yy()$&II.E$F ! 99'(3GDII5t< 
^ K/  		s   :F 	FFr   c                 f    | j                  dd      j                  dd      j                  dd      S )a1  Strip IRC line terminators and the NUL byte from ``text``.

    IRC commands are CRLF-delimited; a bare ``\r`` or ``\n`` in user
    content lets an attacker inject arbitrary IRC commands (CTCP, JOIN,
    KICK).  ``\x00`` is a protocol-illegal byte.  Everything else is
    valid in PRIVMSG payloads.
    r   r    r   )r   r   s    r   _strip_irc_control_charsrB    s/     <<c"**45==fbIIr#   r   c                 *    t        |       xr | d   dv S )Nr   z#&+!)r  )r   s    r   _is_irc_channelrD    s    </F1I//r#   F)	thread_idmedia_filesforce_documentr   messagerE  rF  rG  c          	      2  23K   t        | di       xs i }t        j                  d      xs |j                  dd      }t        j                  d      xs |j                  dd      }|r|sddiS t        j                  d	      xs |j                  d
d      }		 t	        |	      }
t        j                  d      xs |j                  dd      }t        j                  d      }||j                         dv }nt        |j                  dd            }t        j                  d      xs |j                  dd      }t        j                  d      xs |j                  dd      }|xs |2t        2fddD              rddiS 2}|j                  d      dd xs d}| ddd }t        j                  |      }|rt        j                         nd}	 t        j                   t        j"                  ||
|       d!"       d{   \  }3d$t(        d%df3fd&}d'}d(}	 |r |d)t+        |              d{     |d*|        d{     |d+| d,       d{    t        j,                         }|j/                         d!z   }d-}|s||j/                         z
  }|d'k  rBdd.i	 3j1                          t        j                   3j3                         d/"       d{    S 	 t        j                   |j7                  d0      |"       d{   }|j;                  d2d34      j                  d5      }t=        |      } | d6   }!|!d7k(  r#| d8   r| d8   d'   nd}" |d9|"        d{    n|!d:k(  rd}n|!d;v rj|d<z  }||kD  rBdd=i	 3j1                          t        j                   3j3                         d/"       d{    S | d>| dd } |d*|        d{    nJ|!d?v rFdd@|! dAi	 3j1                          t        j                   3j3                         d/"       d{    S |s|r9 |dBt+        |              d{    t        j>                  dC       d{    tA        |      r# |dD|        d{    |j/                         d/z   }#d-}$|$s|#|j/                         z
  }|d'k  rn	 t        j                   |j7                  d0      |"       d{   }|j;                  d2d34      j                  d5      }t=        |      }%|%d6   }&|&d7k(  r#|%d8   r|%d8   d'   nd}" |d9|"        d{    nT|&dEv rd}$nM|&dFv rIddG| dH|& dAi	 3j1                          t        j                   3j3                         d/"       d{    S |$stC        dI| dJjE                  d2            dCz   }'dK|'z
  }(d-})|jG                  dL      D ]B  }*t+        |*      j                         }*|*s |*s#|*jE                  d2      }+tC        |+      |(k  r6 |dI| dJ|*        d{    t        j>                  dM       d{    d})xd<tC        |*      d'}.}-},|,|-k  r;|,|-z   dCz  }/tC        |*d|/ jE                  d2            |(k  r|/}.|/d<z   },n|/d<z
  }-|,|-k  r;|.}0|*jI                  dNd'|0      }1|1|0dOz  kD  r|1}0 |dI| dJ|*d|0 j                                 d{    t        j>                  dM       d{    d})|*|0d jK                         }*|*r E |)sBddPi	 3j1                          t        j                   3j3                         d/"       d{    S  |dQ       d{    	 t        j                   |jM                  dR      dS"       d{    dt)        t	        t/        j.                         dTz              dU	 3j1                          t        j                   3j3                         d/"       d{    S # t
        t        f$ r
 dd|	icY S w xY w7 %# t        j$                  $ r  t&        $ r}dd#| icY d}~S d}~ww xY w7 $7 7 7 # t        j4                  t&        f$ r Y S w xY w7 s# t        j4                  $ re dd.icY 	 3j1                          t        j                   3j3                         d/"       d{  7   S # t        j4                  t&        f$ r Y S w xY wt        j8                  $ re dd1icY 	 3j1                          t        j                   3j3                         d/"       d{  7   S # t        j4                  t&        f$ r Y S w xY ww xY w7 7 # t        j4                  t&        f$ r Y S w xY w7 7 v# t        j4                  t&        f$ r Y S w xY w7 u7 [7 ?7 # t        j4                  t        j8                  f$ r Y Vw xY w7 7 f# t        j4                  t&        f$ r Y S w xY w7 7 7 D7 *7 # t        j4                  t&        f$ r Y S w xY w7 7 # t        j4                  $ r Y w xY w7 g# t        j4                  t&        f$ r Y S w xY w# t        j$                  $ r  t&        $ r}tN        jQ                  dVdW       ddX| icY d}~	 3j1                          t        j                   3j3                         d/"       d{  7   S # t        j4                  t&        f$ r Y S w xY wd}~ww xY w# 	 3j1                          t        j                   3j3                         d/"       d{  7   w # t        j4                  t&        f$ r Y w w xY wxY ww)Ya  Open an ephemeral IRC connection, send a PRIVMSG, and quit.

    Used by ``tools/send_message_tool._send_via_adapter`` when the gateway
    runner is not in this process (e.g. ``hermes cron`` running as a
    separate process from ``hermes gateway``).  Without this hook,
    ``deliver=irc`` cron jobs fail with ``No live adapter for platform``.

    The standalone client uses a distinct nick suffix (``-cron``) so it
    does not collide with the long-running gateway adapter that may already
    be holding the configured nickname on the same network.  When the
    target is a channel, the client JOINs it before sending PRIVMSG so
    networks with the default ``+n`` (no external messages) channel mode
    accept the delivery.

    ``thread_id`` and ``media_files`` are accepted for signature parity but
    are not meaningful on IRC: IRC has no native thread or attachment
    primitive.
    r*   r+   r,   r   r3   r4   rw   zBIRC standalone send: IRC_SERVER and IRC_CHANNEL must be configuredr-   r.   r/   z"IRC standalone send: invalid port r0   r1   r2   r5   N>   r6   r7   r8   r9   Tr:   r;   r<   r=   c              3   &   K   | ]  }|v  
 y wr  r`   ).0ch
raw_targets     r   	<genexpr>z#_standalone_send.<locals>.<genexpr>  s     
@2
@s   )r@  r   rA  r   z<IRC standalone send: chat_id contains illegal IRC charactersz_0123456789-   z-cron   rj   g      .@rl   zIRC standalone connect failed: r   r   c                    K   j                  | dz   j                  d             j                          d {    y 7 w)Nr   r   )r   r   r   )r   writers    r   _rawz_standalone_send.<locals>._raw  s1     dVm++G45llns   7AA Ar      ro   rp   rq   z 0 * :Hermes Agent (cron)Fz:IRC standalone send: registration timeout (no RPL_WELCOME)g      @r   zAIRC standalone send: server closed connection during registrationr   r   r   r   r   r   r   r   r   >   432r   r   z-IRC standalone send: too many nick collisionsz-cron->   464465z-IRC standalone send: server rejected client (r'  rs   rt   ru   >   366JOIN>   403405471473474475zIRC standalone send: JOIN z rejected (r   r   r   r   r   r   r   z2IRC standalone send: empty message after strippingzQUIT :deliveredi   g       @r   r   zIRC standalone send raised)exc_infozIRC standalone send failed: ))rD   rE   rF   rG   rH   rI   r   rJ   r  anyr   r%   r   rk   r|   rU   r}   r~   r   rO   rL   rB  get_running_loopr   r   r   r   	readuntilIncompleteReadErrorr   r   r   rD  r   r   r   r   r   r   rv   r   )4pconfigr   rH  rE  rF  rG  r*   r,   r4   
port_valuer.   r1   use_tls_envr9   r;   r=   r   	nick_basestandalone_nickplainr   readerr   rS  nick_attemptsmax_nick_attemptsloopdeadline
registered	remainingraw_liner   r   cmdr   join_deadlinejoinedjmsgjcmdr   r   sent_anyr   r   r   r   r   r   r   r   rM  rR  s4                                                     @@r   _standalone_sendry    s    6 GWb)/REYY|$?		(B(?Fii&B%))Ir*BG]^^:&A%))FD*AJN: yy(OEIIj,,OH))M*K##%)==uyyD12ii 56Z%))DUWY:ZO		"9:`eiiH[]_>` #GJ

@&?
@@WXXF /4DI"5)#2.O&&w/E.5c((*4G@&//##FDg> 
 
   M7HIJKKKU?+,---U?++DEFFF'')99;%
 499;.IA~!]^^	LLN""6#5#5#7EEEaf!(!1!1&2B2B72KU^!__
 oogio@GGOG$W-Ci.Cf}.1(m#h-*VG9-...!
&" #44#%TUz	LLN""6#5#5#7EEEy &/Kvm_"Ecr"JU?"34555&#PQTPUUV!WXn	LLN""6#5#5#7EEEi : 45MN_5`4abccc--""" 6"vh'((( IIK#-MF)DIIK7	> %,%5%5f6F6Fw6OYb%ccH #//')/DKKFS)'2I6>37>d8nQ/rGy1222_,!FGG#'A&UYTZZ[%\]l	LLN""6#5#5#7EEEW 2 &,33G<=A(N	T* 	:I0;BBDI#**73w<9,&I;?@@@!--,,,#H"#S^Q4TTk:!+C9Tc?11':;yH"!Ag"Qw Tk  !Q98q=($HXfXR	)80D0K0K0M/NOPPPmmC(((%hi0779	/ 		:: QR	LLN""6#5#5#7EEE $%%%	""6;;t#4cBBB  s3tyy{T7I3J/KL	LLN""6#5#5#7EEES z" N=j^LMMN:
 !!  @:1#>??@ L-Fr F$$i0 		a `'' _!]^^V	LLN""6#5#5#7EEE$$i0 		[ .. f!deeR	LLN""6#5#5#7EEE$$i0 		[f /J F$$i0 		y 6v F$$i0 		o d" )  d,,g.I.IJ  3x F$$i0 		S A,  Q(, F$$i0 		! 	&B## 		 F$$i0 		 !!  =1DA7s;<<	LLN""6#5#5#7EEE$$i0 		=	LLN""6#5#5#7EEE$$i0 		s  Bn` %D-n0`+ `(`+ nj 7a8j 
aj a!Aj +8a'#a$$a'(n*)b	 bb	 Aj ,e:-j 8f e=f 	n
j "f#j 48f%,f"-f%1n2j 6j gj ,g-j g
4j )g *g+g /Aj g:j 8h g=h nj  Aj <0j ,h-j 	h"
Aj  Aj !h%"j >h(?j j %8h.h+h."n#j .i/j 4)i ii "+j 8i0i-i0n`%"n$`%%n(`+ +aaananj j !j $a''b nbnb	 	e7 j "8c!cc! n!c=:n<c==n e7j 8eeene30n2e33n6e77j =f  fnfnj "f%%g>n gnj j 
j g #g73j 6g77j =h  hnhnj "j %j (j +h..i
n	i

nj i i*&j )i**j -i00j	njnl1+l,l1	l4 8ll	lnl)&n(l))n,l11l4 4n68m5.m1/m54n5nnnnnc                     | j                  ddd t        t        t        g ddt        t
        dt        ddd	d
ddd       y)z7Plugin entry point: called by the Hermes plugin system.r'   r_   c                     t        |       S r  )r%   )cfgs    r   <lambda>zregister.<locals>.<lambda>  s
    JsO r#   )r+   r3   r0   z&No extra packages needed (stdlib only)r9  r.  r-  rA   u   💬FTu  You are chatting via IRC. IRC does not support markdown formatting — use plain text only. Messages are limited to ~450 characters per line (long messages are automatically split). In channels, users address you by prefixing your nick. Keep responses concise and conversational.)ra   labeladapter_factorycheck_fnr  r   required_envinstall_hintsetup_fnenv_enablement_fncron_deliver_env_varstandalone_sender_fnallowed_users_envallow_all_envr?   emojipii_safeallow_update_commandplatform_hintN)register_platformr  r  r   r6  r>  ry  )ctxs    r   registerr    sW    3#'!B=" * 0 .-+!E  (r#   r  )%r  rU   loggingrE   r   rk   r   typingr   r   r   r   	getLoggerr  rv   gateway.platforms.baser   r   r	   r
   gateway.configr   rL   dictr   r"   r%   r  r  r  r6  r   r>  rB  rD  ry  r  r`   r#   r   <module>r     sP  :   	 	 
  , ,			8	$  $DC DD D6=# =# =_)$ _)L
$D 
$$t $hYV$D $0 0fJ3 J3 J0C 0D 0  $'+ OO O
 }O $s)$O O 
#s(^Od*r#   