
    Jj~                   z   U d Z ddlm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 ddlmZmZ ddlmZ ddlmZ ddlmZ dd	lmZmZmZmZ 	 dd
lmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z' n`# e($ rX e)xZxZxZ$xZ%Z' G d d          Z*e*Z  G d d          Z+e+Z! G d d          Z,e,Z" G d d          Z-e-Z# G d d          Z.e.Z&Y nw xY wddl/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z: ddl;m<Z<  ej=        e>          Z? ej@        dejA                  ZBdgdZCdhdZD G d  d!e          ZE ed"#           G d$ d%                      ZFe G d& d'                      ZGe G d( d)                      ZHd*ZIdd+lJmKZL  eLd,d-          ZMeMd.z  ZNd/ZO ej@        d0          ZPd1ZQ eRh d2          ZSd3ZTd4d4d4d4d4d4d4d4d4d4d4d5d4d6ZUd7eVd8<   did9ZWdjd;ZXdkd?ZYdldAZZdmdBZ[dndDZ\dodpdGZ]dndHZ^dqdKZ_drdMZ`dsdPZadtdRZbdudTZcdhdUZddmdVZe G dW dX          Zf G dY dZe3          Zgddd[d\d]Zhdvd^ZidwdcZjdmddZkde ZldvdfZmdS )xu  Matrix gateway adapter.

Connects to any Matrix homeserver (self-hosted or matrix.org) via the
mautrix Python SDK.  Supports optional end-to-end encryption (E2EE)
when installed with ``pip install "mautrix[encryption]"``.

Environment variables:
    MATRIX_HOMESERVER           Homeserver URL (e.g. https://matrix.example.org)
    MATRIX_ACCESS_TOKEN         Access token (preferred auth method)
    MATRIX_USER_ID              Full user ID (@bot:server) — required for password login
    MATRIX_PASSWORD             Password (alternative to access token)
    MATRIX_ENCRYPTION           Set "true" to enable E2EE
    MATRIX_E2EE_MODE            off | optional | required. Overrides MATRIX_ENCRYPTION
                                when set. Legacy MATRIX_ENCRYPTION=true maps to required.
    MATRIX_DEVICE_ID            Stable device ID for E2EE persistence across restarts
    MATRIX_PROXY                HTTP(S) or SOCKS proxy URL for Matrix traffic
    MATRIX_ALLOWED_USERS    Comma-separated Matrix user IDs (@user:server)
    MATRIX_ALLOWED_ROOMS    Comma-separated Matrix room IDs allowed to trigger turns
    MATRIX_HOME_ROOM        Room ID for cron/notification delivery
    MATRIX_REACTIONS        Set "false" to disable processing lifecycle reactions
                            (eyes/checkmark/cross). Default: true
    MATRIX_REQUIRE_MENTION      Require @mention in rooms (default: true)
    MATRIX_FREE_RESPONSE_ROOMS  Comma-separated room IDs exempt from mention requirement
                                (alias of matrix.free_response_rooms)
    MATRIX_ALLOWED_ROOMS    Comma-separated room IDs; if set, bot ONLY responds
                            in these rooms (whitelist, DMs exempt; alias of
                            matrix.allowed_rooms)
    MATRIX_IGNORE_USER_PATTERNS Comma-separated regular expressions for appservice /
                                bridge ghost user IDs to ignore
    MATRIX_PROCESS_NOTICES      Set "true" to process inbound m.notice events
                                (default: false)
    MATRIX_ALLOW_ROOM_MENTIONS  Allow outbound @room mentions to notify whole rooms
                                (default: false)
    MATRIX_TOOLS_ALLOW_REDACTION
                              Allow Matrix redaction tool execution (default: false)
    MATRIX_TOOLS_ALLOW_INVITES Allow Matrix invite tool execution (default: false)
    MATRIX_TOOLS_ALLOW_ROOM_CREATE
                              Allow Matrix room creation tool execution (default: false)
    MATRIX_AUTO_THREAD          Auto-create threads for room messages (default: true)
    MATRIX_DM_AUTO_THREAD       Auto-create threads for DM messages (default: false)
    MATRIX_RECOVERY_KEY         Recovery key for cross-signing verification after device key rotation
    MATRIX_DM_MENTION_THREADS   Create a thread when bot is @mentioned in a DM (default: false)
    MATRIX_ALLOW_PUBLIC_ROOMS   Allow Matrix tools to create public rooms (default: false)
    MATRIX_APPROVAL_REQUIRE_SENDER
                              Require reaction controls to come from the original requester
                              when requester metadata is available (default: true)
    MATRIX_APPROVAL_TIMEOUT_SECONDS
                              Reaction approval/model-picker timeout (default: 300)
    )annotationsN)urljoinurlsplit
urlunsplit)	dataclassfield)escape)
HTMLParser)Path)AnyDictOptionalSet

ContentURIEventID	EventTypePaginationDirectionPresenceStateRoomCreatePresetRoomID	SyncToken
TrustStateUserIDc                      e Zd ZdZdZdZdZdS )_EventTypeStubzm.room.messagez
m.reactionzm.room.encryptedm.room.nameN)__name__
__module____qualname__ROOM_MESSAGEREACTIONROOM_ENCRYPTED	ROOM_NAME     F/home/rurouni/.hermes/hermes-agent/plugins/platforms/matrix/adapter.pyr   r   X   s"        '+!			r&   r   c                      e Zd ZdZdZdS )_PaginationDirectionStubbfN)r   r   r    BACKWARDFORWARDr%   r&   r'   r)   r)   `   s        r&   r)   c                      e Zd ZdZdZdZdS )_PresenceStateStubonlineofflineunavailableN)r   r   r    ONLINEOFFLINEUNAVAILABLEr%   r&   r'   r/   r/   f   s        #r&   r/   c                      e Zd ZdZdZdZdS )_RoomCreatePresetStubprivate_chatpublic_chattrusted_private_chatN)r   r   r    PRIVATEPUBLICTRUSTED_PRIVATEr%   r&   r'   r7   r7   m   s         0r&   r7   c                      e Zd ZdZdZdS )_TrustStateStubr      N)r   r   r    
UNVERIFIEDVERIFIEDr%   r&   r'   r?   r?   t   s        
r&   r?   )PlatformPlatformConfig)BasePlatformAdapterMessageEventMessageTypeProcessingOutcome
SendResultresolve_proxy_urlproxy_kwargs_for_aiohttp_ssrf_redirect_guard)ThreadParticipationTrackerz'^!([A-Za-z][A-Za-z0-9_-]*)(?=$|\s)(.*)$namestrreturn
str | Nonec                   | sdS |                                  g}|                                                      dd          }||d         k    r|                    |           	 ddlm} |D ]} ||          r|c S n-# t
          $ r  t                              d| d           Y nw xY w	 dd	lm	}  |            pi }|D ]}d
| |v r|c S n-# t
          $ r  t                              d| d           Y nw xY wdS )u  Resolve a ``!command`` token to a dispatchable Hermes command token.

    Matrix clients often reserve leading ``/`` for local client commands.
    Hermes accepts ``!command`` as a Matrix-friendly alias, but only for
    commands that the gateway can actually dispatch so ordinary exclamations
    remain normal chat text.

    Returns the token form that actually resolves (which may differ from
    *name* only by underscore→hyphen normalization, e.g. ``reload_skills`` →
    ``reload-skills``) so the emitted ``/command`` always resolves downstream,
    or ``None`` when *name* is not a known command. Aliases are intentionally
    left as-is — the gateway dispatcher resolves them to their canonical name.
    N_-r   )is_gateway_known_commandz.Matrix: is_gateway_known_command failed for %rTexc_info)get_skill_commands/z(Matrix: get_skill_commands failed for %r)
lowerreplaceappendhermes_cli.commandsrU   	Exceptionloggerdebugagent.skill_commandsrX   )rN   
candidates
hyphenatedrU   	candidaterX   skill_commandss          r'   _resolve_matrix_bang_commandrf      s     t
 **,,J%%c3//JZ]""*%%%	
@@@@@@# 	! 	!I''	22 !    !	!  
 
 
<dT 	 	
 	
 	
 	
 	



V;;;;;;++--3 $ 	! 	!I9.00     1	!  V V V?PTUUUUUV 4s0   $A? =A? ?'B)(B)- C C 'C:9C:textc                    | r|                      d          s| S t                              |           }|s| S t          |                    d                    }|| S d| |                    d          pd S )zGConvert Matrix ``!command`` aliases to normal Hermes ``/command`` text.!r@   NrY       )
startswith_MATRIX_BANG_COMMAND_REmatchrf   group)rg   rn   resolveds      r'   _normalize_matrix_bang_commandrq      s     ts++ #))$//E +EKKNN;;H/x/Q-2///r&   c                       e Zd ZdZh dZddhZd fdZedd
            ZddZ	ddZ
ddZddZddZddZddZ xZS )_MatrixHtmlSanitizerz9Allowlist sanitizer for Matrix-compatible formatted HTML.>   ar*   ipsbremh1h2h3h4h5h6hrlioltdthtruldelprecodetabletbodytheadstrikestrong
blockquoterx   r   rP   Nonec                h    t                                          d           g | _        d| _        d S )NF)convert_charrefsr   )super__init___parts_skip_depth)self	__class__s    r'   r   z_MatrixHtmlSanitizer.__init__   s3    %000!#r&   valuerO   c                    t          j        dd| pd                                          }t          j        d|          }|r'|                    d                                          nd}|r|dvrdS |S )Nz[\x00-\x1f\x7f]+rk   z^([A-Za-z][A-Za-z0-9+.-]*):r@   >   httphttpsmailtomatrix)resubstriprn   ro   rZ   )r   strippedrn   schemes       r'   	_safe_urlz_MatrixHtmlSanitizer._safe_url   sz    6-r5;B??EEGG7BB+08Q%%'''b 	f$III2r&   tagattrslist[tuple[str, str | None]]c                   g }|D ]\  }}t          |pd                                          }|dnt          |          }|                    d          rQ|dk    rF|dk    r@|                     |          }|r(|                    dt          |d           d           |d	k    rC|d
k    r=t          j        d|          r(|                    dt          |d           d           d                    |          S )Nrk   onrt   hrefz href="Tquote"r   classzlanguage-[A-Za-z0-9_+.-]{1,64}z class=")	rO   rZ   rl   r   r\   _html_escaper   	fullmatchjoin)	r   r   r   safekeyr   attr	raw_valuer   s	            r'   _safe_attrsz _MatrixHtmlSanitizer._safe_attrs   s    	S 	SJCsyb>>''))D#mUIt$$ czzdfnn~~i00 MKK K,t4*H*H*H K K KLLL47??< A9MM SKK Q<	+N+N+N Q Q QRRRwwt}}r&   c                <   |                                 }|dv r| xj        dz  c_        d S | j        rd S || j        vrd S || j        v r | j                            d| d           d S | j                            d| |                     ||           d           d S )N>   stylescriptr@   <>)rZ   r   _ALLOWED_TAGS
_VOID_TAGSr   r\   r   )r   r   r   s      r'   handle_starttagz$_MatrixHtmlSanitizer.handle_starttag   s    iikk%%%!F 	Fd(((F$/!!Kz3zzz***FCsCD$4$4S%$@$@CCCDDDDDr&   c                    |                                 }|dv r| j        r| xj        dz  c_        d S | j        s|| j        vs	|| j        v rd S | j                            d| d           d S )N>   r   r   r@   z</r   )rZ   r   r   r   r   r\   )r   r   s     r'   handle_endtagz"_MatrixHtmlSanitizer.handle_endtag  s    iikk%%%$*:%!F 	s$*<<<t@V@VF;;;;'''''r&   datac                f    | j         s)| j                            t          |                     d S d S N)r   r   r\   r   )r   r   s     r'   handle_dataz _MatrixHtmlSanitizer.handle_data  s;     	3K|D1122222	3 	3r&   rN   c                T    | j         s | j                            d| d           d S d S )N&;r   r   r\   r   rN   s     r'   handle_entityrefz%_MatrixHtmlSanitizer.handle_entityref  s;     	,K{4{{{+++++	, 	,r&   c                T    | j         s | j                            d| d           d S d S )Nz&#r   r   r   s     r'   handle_charrefz#_MatrixHtmlSanitizer.handle_charref  s;     	-K|D|||,,,,,	- 	-r&   c                6    d                     | j                  S Nrk   )r   r   )r   s    r'   get_htmlz_MatrixHtmlSanitizer.get_html  s    wwt{###r&   rP   r   )r   rO   rP   rO   )r   rO   r   r   rP   rO   )r   rO   r   r   rP   r   )r   rO   rP   r   )r   rO   rP   r   )rN   rO   rP   r   )rP   rO   )r   r   r    __doc__r   r   r   staticmethodr   r   r   r   r   r   r   r   __classcell__r   s   @r'   rs   rs      s       CC  M
 J     
    \    E E E E( ( ( (3 3 3 3, , , ,- - - -$ $ $ $ $ $ $ $r&   rs   T)frozenc                      e Zd ZU dZded<   ded<   ded<   ded<   ded<   d	ed
<   ded<   ded<   ded<   ded<   dZded<   dS )MatrixRoomIdentityz=Resolved Matrix room identity for routing and prompt context.rO   room_idrQ   	room_name
room_topiccanonical_aliasserver_namez
int | Nonejoined_member_countboolis_direct_account_datadisplay_namehas_explicit_name	chat_typeFconflictN)r   r   r    r   __annotations__r   r%   r&   r'   r   r     s         GGLLL####    NNNHr&   r   c                  "    e Zd ZdZ	 	 	 dddZdS )_MatrixApprovalPromptz<Tracks a pending Matrix reaction-based exec approval prompt.FNsession_keyrO   chat_id
message_idrp   r   requester_user_idrQ   
expires_atfloat | Nonec                h    || _         || _        || _        || _        || _        || _        i | _        d S r   )r   r   r   rp   r   r   bot_reaction_events)r   r   r   r   rp   r   r   s          r'   r   z_MatrixApprovalPrompt.__init__3  s>     '$ !2$35   r&   )FNN)r   rO   r   rO   r   rO   rp   r   r   rQ   r   r   )r   r   r    r   r   r%   r&   r'   r   r   /  s>        FF (,#'6 6 6 6 6 6 6r&   r   c                      e Zd ZU dZded<   ded<   ded<   ded<   ded	<   d
Zded<   d
Zded<   dZded<    ee	          Z
ded<   d
S )_MatrixModelPickerPromptz;Tracks a pending Matrix reaction-based model picker prompt.rO   r   r   r   zdict[str, tuple[str, str]]choicesr   on_model_selectedNrQ   r   r   r   Fr   rp   )default_factoryzdict[str, str]r   )r   r   r    r   r   r   r   rp   r   dictr   r%   r&   r'   r   r   E  s         EELLLOOO''''$(((((#J####H*/%*E*E*EEEEEEEr&   r     )get_hermes_dirzplatforms/matrix/storezmatrix/storez	crypto.db   z6(?<![\w/])(@[0-9A-Za-z._=/-]+:[0-9A-Za-z.-]+(?::\d+)?)z^Install with: pip install 'mautrix[encryption]' asyncpg aiosqlite  (requires libolm C library)>
   .bmp.svg.avif.heic.heif.jpeg.gif.jpg.png.webp)
u   1️⃣u   2️⃣u   3️⃣u   4️⃣u   5️⃣u   6️⃣u   7️⃣u   8️⃣u   9️⃣u   🔟yeszoff / optional / required)rg   threads	reactions	approvalsmodel pickerzthinking panesimageszmultiple imagesfileszvoice/audiovideoE2EEdiagnosticsDict[str, str]_MATRIX_CAPABILITIESc                 *    t          t                    S )z?Return Matrix gateway capabilities for docs and release checks.)r   r  r%   r&   r'   get_matrix_capabilitiesr    s    $%%%r&   r   c                   t          | pd                                          }|rd|v s|                    d          rdS t          |          j        }|r||k    rdS t          |          j                                        }|sdS t          j        |          \  }}|r|	                    d          rdS |t          v S )a5  Return True when Matrix image body text is probably just a transport filename.

    Matrix ``m.image`` events commonly populate ``content.body`` with the uploaded
    filename when the user did not add a caption. Treating that raw filename as
    user-authored text confuses downstream vision enrichment.
    rk   
rY   Fimage/T)rO   r   endswithr   rN   suffixrZ   	mimetypes
guess_typerl   _MATRIX_IMAGE_FILENAME_EXTS)rg   rd   rN   r  guessed_typerS   s         r'   !_looks_like_matrix_image_filenamer    s     DJB%%''I 	))Y-?-?-D-D)u	??D 49$$u$ZZ$$&&F u*400OL! //99 t000r&   eventr   floatc                    t          | dd          pt          | dd          pd}|sdS 	 t          |          }n# t          t          f$ r Y dS w xY w|dk    r|dz  S |S )zGReturn a Matrix event timestamp in seconds, accepting ms or sec values.	timestampNserver_timestampr           l    d(	 g     @@)getattrr  	TypeError
ValueError)r  raw_tstss      r'   _matrix_event_timestamp_secondsr%    s     	{D)) 	5,d33	 
  s6]]z"   ss 
NF{Is   : AA	proxy_urlc                   ddl }| s|                    d          S |                     d          d                                                             d          rs	 ddlm} |                    |                    | d          	          S # t          $ r4 t          
                    d
|            |                    d          cY S w xY w|                    |           S )a  Create an ``aiohttp.ClientSession`` whose proxy applies to *all* requests.

    mautrix's ``HTTPAPI._send()`` calls ``session.request()`` without forwarding
    per-request ``proxy=`` kwargs.  For HTTP(S) proxies we use aiohttp's native
    ``proxy=`` session parameter which sets a default for every request.  For SOCKS
    we use ``aiohttp_socks.ProxyConnector`` (connector-level).
    When no proxy is configured we enable ``trust_env`` so standard env vars
    (``HTTP_PROXY`` / ``HTTPS_PROXY``) are honoured automatically.
    r   NT)	trust_envz://socks)ProxyConnector)rdns)	connectoruV   aiohttp_socks not installed — SOCKS proxy %s ignored. Run: pip install aiohttp-socks)proxy)aiohttpClientSessionsplitrZ   rl   aiohttp_socksr*  from_urlImportErrorr_   warning)r&  r.  r*  s      r'   _create_matrix_sessionr5    s    NNN 5$$t$444ua &&((33G<< 9	9444444(((11)$1GG )     	9 	9 	9NN1  
 ((4(88888	9   y 111s   0B ;CCc                 `    	 ddl m}  ddlm} ddl}ddl}dS # t          t          f$ r Y dS w xY w)u[  Return True if mautrix E2EE dependencies are available.

    Verifies python-olm (via mautrix.crypto.OlmMachine), the SQLite crypto
    store backend (mautrix.crypto.store.asyncpg.PgCryptoStore — yes, the
    PgCryptoStore class also drives the sqlite backend in mautrix 0.21),
    and the database drivers actually used at connect time (``asyncpg`` for
    the underlying upgrade_table machinery, ``aiosqlite`` for the
    ``sqlite:///`` URL we pass to ``Database.create``).  Without all four,
    encrypted rooms fail at connect time with a confusing
    ``No module named 'asyncpg'`` (#31116).
    r   
OlmMachinePgCryptoStoreNTF)mautrix.cryptor8  mautrix.crypto.store.asyncpgr:  asyncpg	aiosqliter3  AttributeError)r8  r:  r=  r>  s       r'   _check_e2ee_depsr@    sl    ------>>>>>>t(   uus    --r   c                    t          | pd                                                                          }|dv rdS |dv rdS dS )z4Normalize Matrix E2EE mode to off/optional/required.rk   )requiredrequiretrue1r  r   rB  )optionalprefer	preferredrF  off)rO   r   rZ   )r   raws     r'   _normalize_e2ee_moderK     sR    
ekr


 
 
"
"
(
(
*
*C
???z
111z5r&   extraOptional[Dict[str, Any]]c                   | pi } |                      d          pt          j        dd          }|rt          |          S |                      dt          j        dd                                          dv           }|rdndS )	zAResolve E2EE mode with MATRIX_ENCRYPTION backwards compatibility.	e2ee_modeMATRIX_E2EE_MODErk   
encryptionMATRIX_ENCRYPTIONrD  rE  r  rB  rI  )getosgetenvrK  rZ   )rL  explicitlegacy_enableds      r'   _resolve_e2ee_moderY  
  s    KREyy%%J3Er)J)JH .#H---YY
	%r**00226JJ N (2::U2r&   c                T    t          | pd                                          }|sdS dS )z=Return a safe, non-reversible preview for Matrix diagnostics.rk   ***rO   r   )r   rg   s     r'   _redact_matrix_valuer]    s1    u{!!##D r5r&   recovery_keyOptional[Path]c                n   t          j        dd                                          }|sdS t          |                                          }|j                            dd           t           j        t           j        z  t           j	        z  }t          j
        ||d          }	 t          j        |dd	          5 }|                    |            |                    d
           ddd           n# 1 swxY w Y   n5# t          $ r( 	 t          j        |           n# t          $ r Y nw xY w w xY w|S )zWrite a generated Matrix recovery key to an operator-chosen file.

    The file is created with mode 0600 and never overwritten. Returns the path
    when written, otherwise None.
    MATRIX_RECOVERY_KEY_OUTPUT_FILErk   NTparentsexist_oki  wzutf-8)encodingr  )rU  rV  r   r   
expanduserparentmkdirO_WRONLYO_CREATO_EXCLopenfdopenwriter^   closeOSError)r^  output_filepathflagsfdfhs         r'   &_write_matrix_recovery_key_output_filerw    sv    )=rBBHHJJK t''))DKdT222K"*$ry0E	ue	$	$B	Yr3111 	RHH\"""HHTNNN	 	 	 	 	 	 	 	 	 	 	 	 	 	 	    	HRLLLL 	 	 	D	 KsT   &D  =+C4(D  4C88D  ;C8<D   
D2D D2 
D-*D2,D--D2tuple[Optional[Path], str]c                 F   t          j        dd                                          } | sdS t          |                                           }|                                rdS 	 |j                            dd           n# t          $ r}dd| fcY d}~S d}~ww xY w|dfS )	zHReturn a usable one-time recovery-key output path, or a redacted reason.ra  rk   )Nnot_configured)NexistsTrb  Nz
unusable: )	rU  rV  r   r   rg  r{  rh  ri  r^   )rr  rs  excs      r'   &_get_matrix_recovery_key_output_targetr}  9  s    )=rBBHHJJK &%%''))D{{}} ~($6666 ( ( ('#'''''''''(8Os   $B 
BBBBmxidr   c                T   	 t          |          }n[# t          $ r t                              d|            Y dS t          $ r'}t                              d| |           Y d}~dS d}~ww xY w|rt                              d| |           dS t                              d|            dS )zBHandle a freshly generated Matrix recovery key without logging it.zMatrix: bootstrapped cross-signing for %s. Recovery key output file already exists; refusing to overwrite. Store the generated key securely and set MATRIX_RECOVERY_KEY for future restarts.NzMatrix: bootstrapped cross-signing for %s, but failed to write MATRIX_RECOVERY_KEY_OUTPUT_FILE: %s. Store the generated key securely and set MATRIX_RECOVERY_KEY for future restarts.zMatrix: bootstrapped cross-signing for %s. A new recovery key was written to %s with mode 0600. Move it to your secret store and set MATRIX_RECOVERY_KEY for future restarts.zMatrix: bootstrapped cross-signing for %s. A new recovery key was generated but will not be logged. Set MATRIX_RECOVERY_KEY_OUTPUT_FILE to write it once with mode 0600, or configure MATRIX_RECOVERY_KEY from your Matrix client before future restarts.)rw  FileExistsErrorr_   r4  r^   )r~  r^  output_pathr|  s       r'   %_handle_generated_matrix_recovery_keyr  H  s   <\JJ   H 		
 	
 	
 	   H 	
 	
 	
 	  
7 	
 	
 	
 	
 	
 	> 	
 	
 	
 	
 	
s    %A*	A*A%%A*htmlc                    t                      }	 |                    | pd           |                                 |                                S # t          $ r t          | pd          cY S w xY wr   )rs   feedrp  r   r^   r   )r  	sanitizers     r'   _sanitize_matrix_htmlr  p  s}    $&&I(tzr"""!!### ( ( (DJB'''''(s   >A A-,A-urlc                F   	 t          t          |                     }|j        sJ|j        sCt          |                               dd          d                             dd          d         S t          |j        |j        |j        ddf          S # t          $ r Y dS w xY w)zAStrip query/fragment from URLs before logging signed media links.?r@   r   #rk   z<url>)r   rO   r   netlocr0  r   rs  r^   )r  partss     r'   _redact_url_for_logr  z  s    S""| 	>EL 	>s88>>#q))!,223::1==5<uz2rJKKK   wws   A,B /"B 
B B c                    t          j        dd| pd          }t          j        dd|          }t          j        dd|          }|S )z@Remove unsafe raw HTML before Markdown conversion can escape it.z0(?is)<\s*(script|style)\b[^>]*>.*?<\s*/\s*\1\s*>rk   z5(?is)\s+on[a-z0-9_-]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)z(?is)\s+(href|src)\s*=\s*("[^"]*(?:javascript|data|vbscript):[^"]*"|'[^']*(?:javascript|data|vbscript):[^']*'|[^\s>]*(?:javascript|data|vbscript):[^\s>]*)r   r   )rg   results     r'   _pre_sanitize_matrix_markdownr    sb    V;

 F
 VD
 F
 V 	j
 F
 Mr&   c                 :   t          j        dd          } t          j        dd          }t          j        dd          }| s|st                              d           dS |st                              d           dS 	 dd	lm}m}  |d
          }n6# t          $ r)}t                              d|           d}d}Y d}~nd}~ww xY w|s|Vd }|dS  |d
|t                      d          s4t                              d|rd
                    |          nd
           dS t                      }|dk    r0t                      s"t                              dt                     dS |dk    r.t                      s t                              dt                     dS )u  Return True if the Matrix adapter can be used.

    Lazy-installs the full ``platform.matrix`` feature group via
    ``tools.lazy_deps.ensure_and_bind`` whenever any of the declared
    packages (mautrix, Markdown, aiosqlite, asyncpg, aiohttp-socks) is
    missing — not just mautrix itself.  Previously this short-circuited on
    ``import mautrix``, which left the other four packages uninstalled
    forever and broke E2EE connect with ``No module named 'asyncpg'``
    (#31116).  Rebinds module-level type globals on success.
    MATRIX_ACCESS_TOKENrk   MATRIX_PASSWORDMATRIX_HOMESERVERz;Matrix: neither MATRIX_ACCESS_TOKEN nor MATRIX_PASSWORD setFz!Matrix: MATRIX_HOMESERVER not setr   )feature_missingensure_and_bindplatform.matrixz#Matrix: lazy_deps lookup failed: %sr%   Nc                 L    ddl m} m}m}m}m}m}m}m}m	}m
}	 | |||||||||	d
S )Nr   r   )mautrix.typesr   r   r   r   r   r   r   r   r   r   r   s
             r'   _importz*check_matrix_requirements.<locals>._import  s                            )"&':!.$4 &(   r&   promptz}Matrix: required packages not installed (%s). Run: pip install 'mautrix[encryption]' asyncpg aiosqlite Markdown aiohttp-socksz, rB  zMatrix: E2EE is required but dependencies are missing. %s. Without this, encrypted rooms will not work. Set MATRIX_E2EE_MODE=off to disable E2EE.rF  z6Matrix: E2EE optional but dependencies are missing. %sT)rU  rV  r_   r`   r4  tools.lazy_depsr  r  r^   globalsr   rY  r@  error_E2EE_INSTALL_HINT)	tokenpassword
homeserverr  r  missingr|  r  rO  s	            r'   check_matrix_requirementsr    s    I+R00Ey*B//H.33J  RSSSu :;;;uDDDDDDDD!/"344   :C@@@
  /)	 	 	& "50'799USSS 	NN) '.D		'"""3D	   5"$$IJ'7'9'98 		
 	
 	
 uJ'7'9'9D	
 	
 	

 4s   ?B 
CCCc                  2    e Zd ZdZddZddZddZddZdS )_CryptoStateStoreaa  Adapter that satisfies the mautrix crypto StateStore interface.

    OlmMachine requires a StateStore with ``is_encrypted``,
    ``get_encryption_info``, and ``find_shared_rooms``.  The basic
    ``MemoryStateStore`` from ``mautrix.client`` doesn't implement these,
    so we provide simple implementations that consult the client's room
    state.
    client_state_storer   joined_roomssetc                "    || _         || _        d S r   )_ss_joined_rooms)r   r  r  s      r'   r   z_CryptoStateStore.__init__  s    %)r&   r   rO   rP   r   c                @   K   |                      |           d {V d uS r   )get_encryption_infor   r   s     r'   is_encryptedz_CryptoStateStore.is_encrypted  s1      ..w77777777DDr&   c                t   K   t          | j        d          r | j                            |           d {V S d S )Nr  )hasattrr  r  r  s     r'   r  z%_CryptoStateStore.get_encryption_info  sH      48233 	?55g>>>>>>>>>tr&   user_idlistc                .   K   t          | j                  S r   )r  r  )r   r  s     r'   find_shared_roomsz#_CryptoStateStore.find_shared_rooms  s      D&'''r&   N)r  r   r  r  r   rO   rP   r   )r   rO   )r  rO   rP   r  )r   r   r    r   r   r  r  r  r%   r&   r'   r  r    sr         * * * *E E E E   
( ( ( ( ( (r&   r  c                      e Zd ZdZdZdZdZdZdш fdZdd
Z	e
dd            Ze
dd            Ze
dd            ZddZddZddddZddZ	 	 ddd$Zdd&Zdd'Z	 ddd(Zdd)Zdd*dd-Z	 	 	 dd fd0Zdd3Z	 	 	 ddd5Z	 	 ddd;Z	 	 	 	 ddd>Z	 	 	 ddd@Z	 	 	 dddBZ	 	 dddHZ	 dddMZ ddNZ!	 	 	 	 dddVZ"	 	 	 	 	 dddWZ#ddXZ$ddZZ%dd\Z&e
dd]            Z'dd^Z(dd_Z)dd`Z*ddbZ+ddiZ,ddkZ-ddlZ.ddmZ/ddnZ0ddodpddsZ1ddtZ2ddvZ3	 dddyZ4	 dddzZ5dd|Z6ddZ7ddZ8d dZ9ddZ:ddZ;ddZ<ddZ=ddZ>ddZ?ddZ@ddZAddZBd	dZCd
dZD	 dddZE	 	 	 	 	 dddZFddZG	 	 dddZHddZI eJd          ZKdddZLddZMe
dd            ZNddZOddZPddZQddZRe
dd            ZSddZTddddZUddZVddZWddZXdddZYdddddZZddZ[ddÄZ\d dĄZ]d!dƄZ^	 	 dؐd"dɄZ_d#dʄZ`d$d˄Zad%d̈́Zbd d΄Zce
d&dτ            Zde
d dЄ            Ze xZfS ('  MatrixAdapterz,Gateway adapter for Matrix (any homeserver).Tri   i<  configrD   c                   t                                          |t          j                   |j                            dd          pt          j        dd                              d          | _	        |j
        pt          j        dd          | _        |j                            dd          pt          j        dd          | _        |j                            dd          pt          j        d	d          | _        t          |j                  | _        | j        d
k    | _        |j                            dd          pt          j        dd          | _        d| _        d | _        d | _        d | _        i | _        d| _        d| _        d| _        d| _        d| _        d| _        i | _        i | _        i | _        	 tA          t          j        dd                    | _!        n# tD          $ r
 d| _!        Y nw xY wd| _#        tI                      | _%        ddl&m'}  |d          | _(        tI                      | _)        tU          d          | _+        | ,                    |          | _-        | .                    |          | _/        |j                            d          }|t          j        dd          }ta          |tb                    rd |D             | _2        n1d tg          |          4                    d          D             | _2        |j                            d          }|t          j        dd          }ta          |tb                    rd |D             | _5        n1d  tg          |          4                    d          D             | _5        t          j        d!d"          6                                d#v | _7        t          j        d$d%          6                                d#v | _8        t          j        d&d"          6                                d'v | _9        t          j        d(d"          6                                d#v | _:        t          j        d)d*          ;                                6                                }|d+v r|nd*| _<        t          j        d,d"          6                                d#v | _=        t          j        d-d%          6                                d.v| _>        i | _?        d/| _@        tI                      | _A        t          d01          | _C        | jC        r t          E                    d2| jC                   	 t          t          j        d3tg          d4                              | _G        n# tD          $ r
 d4| _G        Y nw xY wtA          t          j        d5d6                    | _H        tA          t          j        d7d8                    | _I        i | _J        i | _K        d9d:d:d:d:d;d;d<| _L        i | _M        i | _N        t          j        d=d%          6                                d#v | _O        	 t          t          j        d>d?                    | _P        n# tD          $ r
 d@| _P        Y nw xY wi | _Q        t          j        dAd          }dB |4                    d          D             | _R        tI          | j5                  | _S        t          j        dCd          }g | _T        dD |4                    d          D             D ]g}	 | jT        U                    t          jW        |                     0# t          jX        $ r&}	t          Y                    dE||	           Y d }	~	`d }	~	ww xY wd S )FNr  rk   r  rY   r  r  MATRIX_USER_IDr  r  rI  	device_idMATRIX_DEVICE_IDFr  r    MATRIX_ROOM_IDENTITY_TTL_SECONDS60g      N@   )deque  )maxlenr   free_response_roomsMATRIX_FREE_RESPONSE_ROOMSc                    h | ]D}t          |                                          #t          |                                          ES r%   r\  .0rs     r'   	<setcomp>z)MatrixAdapter.__init__.<locals>.<setcomp>^  sI     * * *#$#a&&,,..*A* * *r&   c                ^    h | ]*}|                                 |                                 +S r%   r   r  s     r'   r  z)MatrixAdapter.__init__.<locals>.<setcomp>b  s=     * * *QWWYY*		* * *r&   ,allowed_roomsMATRIX_ALLOWED_ROOMSc                    h | ]D}t          |                                          #t          |                                          ES r%   r\  r  s     r'   r  z)MatrixAdapter.__init__.<locals>.<setcomp>j  sI     - - -#$SVV\\^^-A- - -r&   c                ^    h | ]*}|                                 |                                 +S r%   r  r  s     r'   r  z)MatrixAdapter.__init__.<locals>.<setcomp>n  s=     - - -		-		- - -r&   MATRIX_ALLOW_ROOM_MENTIONSfalserS  MATRIX_AUTO_THREADrD  MATRIX_DM_AUTO_THREAD>   rE  r  rD  MATRIX_DM_MENTION_THREADSMATRIX_SESSION_SCOPEauto>   r  roomthreadMATRIX_PROCESS_NOTICESMATRIX_REACTIONS>   0nor  g      @MATRIX_PROXY)platform_env_varu   Matrix: proxy configured — %sMATRIX_MAX_MEDIA_BYTESi  @&HERMES_MATRIX_TEXT_BATCH_DELAY_SECONDSz0.6,HERMES_MATRIX_TEXT_BATCH_SPLIT_DELAY_SECONDSz2.0oncealwaysdeny)   ✅   ♾️   ♾r  r     ❌u   ❎MATRIX_APPROVAL_REQUIRE_SENDERMATRIX_APPROVAL_TIMEOUT_SECONDS300i,  MATRIX_ALLOWED_USERSc                ^    h | ]*}|                                 |                                 +S r%   r  r  us     r'   r  z)MatrixAdapter.__init__.<locals>.<setcomp>  s=     ,
 ,
 ,
qwwyy,
GGII,
 ,
 ,
r&   MATRIX_IGNORE_USER_PATTERNSc              3  f   K   | ],}|                                 |                                 V  -d S r   r  )r  rv   s     r'   	<genexpr>z)MatrixAdapter.__init__.<locals>.<genexpr>  s7      WWaQWWYYW		WWWWWWr&   zAMatrix: ignoring invalid MATRIX_IGNORE_USER_PATTERNS entry %r: %s)Zr   r   rC   MATRIXrL  rT  rU  rV  rstrip_homeserverr  _access_token_user_id	_passwordrY  
_e2ee_mode_encryption
_device_id_device_id_unverified_client
_crypto_db
_sync_task_invite_join_tasks_closing_startup_ts_late_grace_drops_late_grace_skew_clock_skew_warned_last_sync_ts	_dm_rooms_room_identities_room_identity_cached_atr  _room_identity_ttl_secondsr"  _room_identity_cache_maxr  r  collectionsr  _processed_events_processed_events_setrM   _threads_parse_require_mention_require_mention_parse_thread_require_mention_thread_require_mention
isinstancer  _free_roomsrO   r0  _allowed_roomsrZ   _allow_room_mentions_auto_thread_dm_auto_thread_dm_mention_threadsr   _matrix_session_scope_process_notices_reactions_enabled_pending_reactions!_reaction_redaction_delay_seconds_reaction_redaction_tasksrJ   
_proxy_urlr_   infoint_max_media_bytes_text_batch_delay_seconds_text_batch_split_delay_seconds_pending_text_batches_pending_text_batch_tasks_approval_reaction_map_approval_prompts_by_event_approval_prompt_by_session_approval_require_sender_approval_timeout_seconds_model_picker_prompts_by_event_allowed_user_ids_allowed_room_ids_ignored_user_patternsr\   r   compiler  r4  )r   r  r  free_rooms_rawallowed_rooms_rawraw_session_scopeallowed_users_rawignore_patterns_rawpatternr|  r   s             r'   r   zMatrixAdapter.__init__  s   111 L\2..T")<OQS2T2T
&++ 	 #),"V")<QSU2V2V#\--i<< 
	bA
 A
 %l..z2>> 
")rC
 C
  2&,??!%E!9%|//R@@  
BIE
 E
 ,1" #26;="% '('*(-$' +-?A:<%	3.3	<dCC/ /D++  	3 	3 	3.2D+++	3(+%'*uu%%%%%%(-T(:(:(:*-%%" 38<< '+&A&A&&I&I-1-O-OPV-W-W$))*?@@!Y'CRHHNnd++ 	* *(6* * *D* *#&~#6#6#<#<S#A#A* * *D #L,,_==$ "	*@" E E'.. 	- -(9- - -D- -#&'8#9#9#?#?#D#D- - -D +-)('+
 +

%'')+*! #%),@&"I"I"O"O"Q"Q V
 #

 &(Y#W&
 &

%'')&* *,'*
 *

%'')**  I&<fEEKKMMSSUU!26P!P!PV\ 	" ')i$g'
 '

%'')'*
 )+	)
 )

%''-). ?A
 25.<?EE& '8&X&X&X? 	LKK94?KKK	6$'	2JCPaLbLb(c(c$d$dD!! 	6 	6 	6$5D!!!	6
 */I>FF*
 *
& 05IDeLL0
 0
, ?A"BD& $'
 '
# MO';=(.0i,f/
 /

%'')/*%	1-0	;UCC. .D**  	1 	1 	1-0D***	1SU+I&<bAA,
 ,
066s;;,
 ,
 ,
 ,/t/B+C+C i(ErJJ=?#WW+>+D+DS+I+IWWW 	 	G+222:g3F3FGGGG8   W       	 	sN   'G* *G>=G>4V V V 'Y3 3ZZ!,]^]>>^rP   r   c                   |sdS || j         v rdS t          | j                  | j        j        k    r'| j        d         }| j                             |           | j                            |           | j                             |           dS )zIReturn True if this event was already processed. Tracks the ID otherwise.FTr   )r  lenr  r  discardr\   add)r   event_idevicteds      r'   _is_duplicate_eventz!MatrixAdapter._is_duplicate_event  s     	5t1114t%&&$*@*GGG,Q/G&..w777%%h///"&&x000ur&   c                .   | j                             d          }|Qt          |t                    r|S t          |t                    r|                                dvS t          |          S t          j        dd                                          dvS )a  Parse require_mention from config.extra or env var.

        Handles both YAML booleans and string values (``"true"``, ``"false"``,
        ``"yes"``, ``"no"``, ``"on"``, ``"off"``, ``"1"``, ``"0"``).
        Falls back to ``MATRIX_REQUIRE_MENTION`` env var, default ``true``.
        require_mentionN>   r  r  rI  r  MATRIX_REQUIRE_MENTIONrD  rL  rT  r  r   rO   rZ   rU  rV  r  
configureds     r'   r  z$MatrixAdapter._parse_require_mention  s     \%%&788
!*d++ "!!*c** M!''))1LLL
###y$f
 

%''45 	5r&   c                .   | j                             d          }|Qt          |t                    r|S t          |t                    r|                                dvS t          |          S t          j        dd                                          dv S )a_  Parse thread_require_mention from config.extra or env var.

        Handles both YAML booleans and string values (``"true"``, ``"false"``,
        ``"yes"``, ``"no"``, ``"on"``, ``"off"``, ``"1"``, ``"0"``).
        Falls back to ``MATRIX_THREAD_REQUIRE_MENTION`` env var, default ``false``.
        Mirrors Discord adapter's parsing pattern.
        thread_require_mentionN>   r  r  rI  r  MATRIX_THREAD_REQUIRE_MENTIONr  >   rE  r   r  rD  rI  rJ  s     r'   r  z+MatrixAdapter._parse_thread_require_mention  s     \%%&>??
!*d++ "!!*c** M!''))1LLL
###y+W
 

%''/0 	0r&   device_keys_objr   Optional[str]c                    t          | di           pi                                 D ]8\  }}t          |                              d          rt          |          c S 9dS )z:Extract the ed25519 identity key from a DeviceKeys object.keyszed25519:N)r   itemsrO   rl   )rO  kidkvals      r'   _extract_server_ed25519z%MatrixAdapter._extract_server_ed25519  sl     "/62>>D"KKMM 	! 	!IC3xx"":.. !4yy   !tr&   clientlocal_ed25519rO   c                `  K   |j         r| j        rt                              d           dS 	 |                    |j        |j         gi           d{V }t          |di           pi }|                    t          |j                            pi }|                    t          |j                             }|r=| 	                    |          }||k    r"t          
                    d|j                    dS n5# t          $ r(}t          
                    d|d           Y d}~dS d}~ww xY wdS )	zJRe-query the server after share_keys() and verify our ed25519 key matches.uO   Matrix: skipping post-upload key verification — device_id not yet establishedTNdevice_keyszMatrix: device %s has immutable identity keys that don't match this installation. Generate a new access token with a fresh device.Fz/Matrix: post-upload key verification failed: %srV   )r  r  r_   r4  
query_keysr~  r   rT  rO   rV  r  r^   )	r   rW  rX  respdkuddev	server_edr|  s	            r'   _reverify_keys_after_uploadz)MatrixAdapter._reverify_keys_after_upload  sf       	4#= 	NN0   4	**FK&:J9K+LMMMMMMMMD}b117RBFK(())/RB&&V-..//C 	! 88==	--LL5 (	   !5 	 	 	LLJCZ^L___55555	 ts   CC9 9
D+D&&D+olmc                  K   |j         r| j        rt                              d           dS 	 |                    |j        |j         gi           d{V }n5# t          $ r(}t                              d|d           Y d}~dS d}~ww xY wt          |di           pi }|	                    t          |j                            pi }|	                    t          |j                             }|j        j        	                    d          }|st                              d	           d|j        _        	 |                                 d{V  n5# t          $ r(}t                              d
|d           Y d}~dS d}~ww xY w|                     ||           d{V S |                     |          }	|	|k    rH|j        j        r(t                              d|j         t"                     dS t                              d|j                    	 |j                            t)          |j        d          r|j        j        j        ndd|j                     d{V  t                              d|j                    n# t          $ r Y nw xY w	 |                                 d{V  n;# t          $ r.}t                              d|j         |d           Y d}~dS d}~ww xY w|                     ||           d{V S dS )zVerify our device keys are on the homeserver after loading crypto state.

        Returns True if keys are valid or were successfully re-uploaded.
        Returns False if verification fails (caller should refuse E2EE).
        uJ   Matrix: skipping device key verification — device_id not yet establishedTNuA   Matrix: cannot verify device keys on server: %s — refusing E2EErV   FrZ  ed25519u8   Matrix: device keys missing from server — re-uploadingz+Matrix: failed to re-upload device keys: %sup   Matrix: server has different identity keys for device %s — local crypto state is stale. Delete %s and restart.uD   Matrix: server has stale keys for device %s — attempting re-uploadMethodDELETEz/_matrix/client/v3/devices/z+Matrix: deleted stale device %s from serverzfMatrix: cannot upload device keys for %s: %s. Try generating a new access token to get a fresh device.)r  r  r_   r4  r[  r~  r^   r  r   rT  rO   accountidentity_keysshared
share_keysra  rV  _CRYPTO_DB_PATHapirequestr  re  rf  r(  )
r   rW  rb  r\  r|  device_keys_mapour_user_devicesour_keysrX  server_ed25519s
             r'   _verify_device_keys_on_serverz+MatrixAdapter._verify_device_keys_on_server-  s       	4#= 	NN0   4	**FK&:J9K+LMMMMMMMMDD 	 	 	LLS    
 55555	 "$r::@b*..s6;/?/?@@FB#''F,<(=(=>>155i@@ 	QNNUVVV!&CKnn&&&&&&&&&&   JCZ^___uuuuu 99&-PPPPPPPPP55h??]**{! J$#	   uNNV   j((vz844"FJ%,,!D&2BDD	         A6CS       
nn&&&&&&&&&&   O$!     uuuuu 99&-PPPPPPPPPtsZ   (A 
B	!BB	7E 
FE??FA/J 
JJJ0 0
K(:#K##K(F)is_reconnectrs  c               (  K   d| _         | j        N	 |                                  d{V  n2# t          $ r%}t                              d|           Y d}~nd}~ww xY wddlm} ddlm	} ddl
m}m} | j        st                              d           dS t                              d	d	
           t#          | j                  } || j        | j        pd|          } |            }	 |            }
 || j        rt+          | j                  nt+          d          | j        pd||	|
          }|| _        | j        r?| j        |_        	 |                                 d{V }t3          |dd          p| j        }t3          |dd          }|r-t5          |          | _        t+          | j                  |_        | j        p|}|r||_        |j        s	 |                    |j        g i           d{V }t3          |di           pi                     t5          |j                            pi }t?          |          dk    r"tA          tC          |                    |_        n3t?          |          dk    r t                              d|j                   n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w|j        s't                              d|j                   d	| _         t          "                    d| j        pd|rd| dnd           n_# t          $ rG}t                              d|d	           |j#        $                                 d{V  Y d}~dS d}~ww xY w| j%        r| j        r	 |&                    | j        | j%        d| j        pd           d{V }|rtO          |d          r|j        |_        t          "                    d| j                   n# t          $ rE}t                              d|           |j#        $                                 d{V  Y d}~dS d}~ww xY wt                              d           |j#        $                                 d{V  dS | j(        r_tS                      st| j*        d k    r(t                              d!tV                     d| _(        nAt                              d"tV                     |j#        $                                 d{V  dS | j(        sn	 dd#l,m-} dd$l.m/} dd%l0m1} t                              d	d	
           n# t          $ r}| j*        d k    r)t                              d&|tV                     d| _(        nFt                              d'|tV                     |j#        $                                 d{V  Y d}~dS Y d}~nd}~ww xY w| j(        r	 t          d(z  }|2                                r.t          "                    d)           |3                                 |4                    d*tj           |j6        +          }|7                                 d{V  || _8        | j        pd,}| d-| j        pd. } ||||/          }|9                                 d{V  |j        r |:                    |j                   d{V  tw          |	| j<                  } ||||          }tz          j>        |_?        tz          j>        |_@        |A                                 d{V  | B                    ||           d{V s;|C                                 d{V  |j#        $                                 d{V  dS 	 |D                                 d{V  n# t          $ r}t5          |          }d0|v r_t                              d1|j                   |C                                 d{V  |j#        $                                 d{V  Y d}~dS t                              d2|           Y d}~nd}~ww xY wt          jF        d3d          G                                }|rk	 |H                    |           d{V  t          "                    d4           nf# t          $ r&}t                              d5|           Y d}~n;d}~ww xY w	 |I                                 d{V }n4# t          $ r'}d}t                              d6|           Y d}~nd}~ww xY w|t                      \  }} | d7k    rt                              d8           n| d9k    rt                              d:           n| rt                              d;|            np	 |K                                 d{V }!t          t5          |j                  |!           n2# t          $ r%}t                              d<|           Y d}~nd}~ww xY w||_M        t          "                    d=t5          tj                    |j        r
d>|j         nd           n# t          $ r}| j*        d k    r)t                              d?|tV                     d| _(        nFt                              d@|tV                     |j#        $                                 d{V  Y d}~dS Y d}~nd}~ww xY wddAlmN}" ddBlOmP}# |Q                    |#           |R                    t          jT        | jU        d	C           |R                    t          jV        | jW        d	C           |R                    |"jX        | jY        d	C           t          jZ                    | _[        d| _\        dD| _]        d| _^        d| __        	 |`                    dEd	F           d{V }$t          |$t                    rt          jZ                    | _c        |$                    dGi                               dHi           }%| j<        d                                 | j<        e                    |%f                                           | jg        d                                 | jh        d                                 |$                    dI          }&|&r |ji        j                    |&           d{V  t          "                    dJt?          | j<                             | k                                 d{V  	 | l                    |$           d{V  n2# t          $ r%}t                              dK|           Y d}~nd}~ww xY w| m                    |$           n-t                              dLt          |$          jo                   n2# t          $ r%}t                              dM|           Y d}~nd}~ww xY w| j(        rdt3          |dNd          rS	 |jM        D                                 d{V  n2# t          $ r%}t                              dO|           Y d}~nd}~ww xY wt          jq        | r                                          | _s        | t                                 d	S )Pz3Connect to the Matrix homeserver and start syncing.FNz0Matrix: error disconnecting before reconnect: %sr   )HTTPAPI)Client)MemoryStateStoreMemorySyncStorez%Matrix: homeserver URL not configuredTrb  rk   )base_urlr  client_session)r~  r  rl  state_store
sync_storer  r  rZ  r@   uD   Matrix: no devices found for %s — key verification will be skippedz$Matrix: device list query failed: %szMatrix: device_id could not be resolved for %s. Set MATRIX_DEVICE_ID for full key verification. E2EE will proceed without server-side device key confirmation.z#Matrix: using access token for %s%sz(unknown user)z	 (device )uM   Matrix: whoami failed — check MATRIX_ACCESS_TOKEN and MATRIX_HOMESERVER: %srV   zHermes Agent)
identifierr  device_namer  zMatrix: logged in as %su   Matrix: login failed — %szDMatrix: need MATRIX_ACCESS_TOKEN or MATRIX_USER_ID + MATRIX_PASSWORDrF  zaMatrix: E2EE optional but dependencies are missing. Continuing without encrypted-room support. %suw   Matrix: E2EE is required but dependencies are missing. %s. Refusing to connect — encrypted rooms would silently fail.r7  r9  )Databasez`Matrix: failed to import optional E2EE client; continuing without encrypted-room support: %s. %sz,Matrix: failed to import E2EE client: %s. %szcrypto_store.picklez@Matrix: removing legacy crypto_store.pickle (migrated to SQLite)z
sqlite:///)upgrade_tablehermes:default)
account_id
pickle_keydbzalready existszMatrix: device %s has stale one-time keys on the server signed with a previous identity key. Delete the device from the homeserver and restart, or generate a new access token to get a fresh device ID.z/Matrix: share_keys() warning during startup: %sMATRIX_RECOVERY_KEYz/Matrix: cross-signing verified via recovery keyz,Matrix: recovery key verification failed: %sz+Matrix: cross-signing key lookup failed: %srz  a  Matrix: cross-signing keys are missing, but automatic bootstrap is skipped because MATRIX_RECOVERY_KEY_OUTPUT_FILE is not configured. Configure MATRIX_RECOVERY_KEY from your Matrix client or set MATRIX_RECOVERY_KEY_OUTPUT_FILE to write a new recovery key once with mode 0600.r{  zMatrix: cross-signing keys are missing, but automatic bootstrap is skipped because MATRIX_RECOVERY_KEY_OUTPUT_FILE already exists and will not be overwritten.zMatrix: cross-signing keys are missing, but automatic bootstrap is skipped because MATRIX_RECOVERY_KEY_OUTPUT_FILE is not usable: %suh   Matrix: cross-signing bootstrap failed (non-fatal — Element will show 'not verified by its owner'): %sz"Matrix: E2EE enabled (store: %s%s)z, device_id=z`Matrix: failed to create optional E2EE client; continuing without encrypted-room support: %s. %sz,Matrix: failed to create E2EE client: %s. %s)InternalEventType)MembershipEventDispatcher)	wait_syncr  i'  )timeout
full_stateroomsr   
next_batchz.Matrix: initial sync complete, joined %d roomsz-Matrix: initial sync event dispatch error: %sz0Matrix: initial sync returned unexpected type %szMatrix: initial sync error: %scryptoz$Matrix: initial key share failed: %s)ur  r  
disconnectr^   r_   r4  mautrix.apiru  mautrix.clientrv  mautrix.client.state_storerw  rx  r  r  
_STORE_DIRri  r5  r'  r  r  r   r  r  whoamir   rO   r~  r  r[  rT  r@  nextiterr(  sessionrp  r  loginr  r   r@  r  r  r;  r8  r<  r:  mautrix.util.async_dbr  r{  unlinkcreaterk  r  startr  rm  put_device_idr  r  r   rA   share_keys_min_trustsend_keys_min_trustloadrr  stoprj  rU  rV  r   verify_with_recovery_key!get_own_cross_signing_public_keysr}  generate_recovery_keyr  r  r  mautrix.client.dispatcherr  add_dispatcheradd_event_handlerr   r!   _on_room_messager"   _on_reactionINVITE
_on_invitetimer  r	  r
  r  r  syncr  r   r  clearupdaterR  r  r  r|  put_next_batch_refresh_dm_cache_dispatch_sync_schedule_pending_invite_joinstyper   asynciocreate_task
_sync_loopr  _mark_connected)'r   rs  r|  ru  rv  rw  rx  rz  rl  r{  r|  rW  r\  resolved_user_idresolved_device_ideffective_device_iddev_respall_devicesr8  r:  r  legacy_pickle	crypto_db_acct_id_pickle_keycrypto_storecrypto_staterb  exc_strr^  	own_xsignrS   output_errornew_recovery_keyIntEvtr  	sync_data
rooms_joinnbs'                                          r'   connectzMatrixAdapter.connect  sl     %*"<#Xoo'''''''''' X X XQSVWWWWWWWWX 	('''''))))))PPPPPPPP 	LL@AAA5 	555 0@@g%$*)
 
 
 '&(($_&&
*.-G&&&VBZZo-#!
 
 
   P	*CI7#]]__,,,,,,#*4B#?#?#P4= %,T;%C%C"# 8$'(8$9$9DM"("7"7FK '+o&K9K#& ;':F$' )/):):FK;L)M)M#M#M#M#M#M#M$X}bAAGR SV[!1!122968 $ {++q00/3D4E4E/F/FF,, --22"NN!C &  
 %   BC       
 ' 6NN,    26D.9M5%5:MU6 36666SU   
    c!    
 k'')))))))))uuuuu ^ 	 	#\\#}!^ ."o5	 *          6GD+66 6'+~F$5t}EEEE   :C@@@k'')))))))))uuuuu
 LLV   +##%%%%%%%%%5  o	%#%% !?j00NNH*  
 (-D$$LLW*  
 +++--------- 5# %%999999JJJJJJ>>>>>>$$TD$AAAA  % % %*44P.	   ,1((J.  
 "k//111111111$uuuuu )((((%"  D%C%$.1F$FM$++-- /^   &,,... (6_66&3&A !0 ! !I $//+++++++++&/DO#}8H%-"N"N0L9"N"NK#0=#+#.$$ $ $L
 '++---------' K*889IJJJJJJJJJ#4[$BT#U#UL$*V\<HHC/9/DC,.8.CC+((**$$$$$$$!%!C!CFC!P!PPPPPPP %'nn.........!k//111111111$u_!nn..........$ _ _ _"%c((+w66"LL![ !' 0   #,.."2"22222222"%+"3"3"5"55555555#(55555'XZ]^^^^^^^^_ $&9-BB#G#G#M#M#O#OL# 1&`"%">">|"L"LLLLLLLL"KK(YZZZZ( ` ` `"NN+Y[^________`_.1.S.S.U.U(U(U(U(U(U(UII( _ _ _(,I"NN+XZ]^^^^^^^^_ %,.T.V.VOA|+/??? &%H!" !" !" !" ".!9!9 &%?!" !" !" !" ". & &%X %1	!" !" !" !"!&=@=V=V=X=X7X7X7X7X7X7X$4$I(+FK(8(8(8%& %& %& %& (1 !& !& !&$*NN)l(+%& %& %& %& %& %& %& %&!& %(FMKK<O,,=C=MU9v'7999SU   
 ! % % %*44P.	   ,1((J.  
 "k//111111111$uuuuu )((((%& 	?>>>>>GGGGGG 	7888  "! 	! 	
 	
 	

 	   	! 	
 	
 	

 	  MO 	! 	
 	
 	
  9;; "# #"'"	B$kk%DkIIIIIIIII)T** %)Y[["&]]7B77;;FBGG
"((***"))*//*;*;<<<%++----33555 ]]<00 ? +::2>>>>>>>>>D*++  
 ,,.........Y--i8888888888  Y Y YNN#RTWXXXXXXXXY33I>>>>FOO,    	B 	B 	BNN;SAAAAAAAA	B  	L$ ? ? 	LLm..0000000000 L L LEsKKKKKKKKL "-doo.?.?@@ts  - 
AAABL- CJ  L-  
K*K
L- 
KAL- -
M>7<M99M>A.O? ?
Q	:Q		Q.U 
WA4WW(F*i" ^0 /i" 0
a:A,a&i" ,ai" a,i" >5b5 3i" 5
c%?c i"  c%%i" )d i" 
d5d0+i" 0d55A6i" ,<g) (i" )
h3hi" hA	i" "
k0,A4k++k09E*v6 $u  ?v6  
u/
u*%v6 *u//Av6 6
w% w  w%x! !
y+yyr   c                j  K   d| _         | j        r]| j                                        sD| j                                         	 | j         d{V  n# t          j        t          f$ r Y nw xY wt          | j        	                                          }|D ]*}|                                s|                                 +|rt	          j
        |ddi d{V  | j                                         t          | j                  }|D ]*}|                                s|                                 +|rt	          j
        |ddi d{V  | j                                         t          | d          rZ| j        rS	 | j                                         d{V  n2# t          $ r%}t                               d|           Y d}~nd}~ww xY w| j        rB	 | j        j        j                                         d{V  n# t          $ r Y nw xY wd| _        t                               d           dS )zDisconnect from Matrix.TNreturn_exceptionsr  z3Matrix: could not close crypto DB on disconnect: %szMatrix: disconnected)r  r  donecancelr  CancelledErrorr^   r  r  valuesgatherr  r&  r  r  r  r_   r`   r  rl  r  rp  r(  )r   invite_join_taskstaskredaction_tasksr|  s        r'   r  zMatrixAdapter.disconnect  s     ? 	4?#7#7#9#9 	O""$$$o%%%%%%%%*I6    !!8!?!?!A!ABB% 	 	D99;;  	M."3LtLLLLLLLLL%%'''t=>># 	 	D99;;  	K./JTJJJJJJJJJ&,,... 4&& 	Y4? 	YYo**,,,,,,,,,, Y Y YRTWXXXXXXXXY < 	 l&.446666666666   DL*+++++s<   A A+*A+>F 
G(GG)H 
HHNr   contentreply_tometadatarM  rI   c           	       K   |st          d          S |                     |          }|                     |t                    }d}t	          |          D ]\  }}	|                     |	          }
|                     |
||           	 t          j        | j	        
                    t          |          t          j        |
          d           d{V }t          |          }t                              d||           # t"          $ r_}| j        rt'          | j	        dd          r	 | j	        j                                         d{V  t          j        | j	        
                    t          |          t          j        |
          d           d{V }t          |          }t                              d	||           Y d}~y# t"          $ rK}t                              d
||           t          dt          |                    cY d}~cY d}~c S d}~ww xY wt                              d||           t          dt          |                    cY d}~c S d}~ww xY wt          d|          S )z Send a message to a Matrix room.T)successNr  r  -   r  zMatrix: sent event %s to %sr  z-Matrix: sent event %s to %s (after key share)z,Matrix: failed to send to %s after retry: %sFr  r  z Matrix: failed to send to %s: %sr  r   )rI   format_messagetruncate_messageMAX_MESSAGE_LENGTH	enumerate_build_text_message_content_apply_relation_metadatar  wait_forr  send_message_eventr   r   r!   rO   r_   r(  r^   r   r   r  rj  r  )r   r   r  r  r  	formattedchunkslast_event_idru   chunkmsg_contentrC  r|  	retry_excs                 r'   sendzMatrixAdapter.send*  s       	,d++++''00	&&y2DEE!&)) ,	A ,	AHAu::5AAK))+S[)\\\'A!(!1L33w!.# 
 " " "       !$H9='RRRR A A A# Oh(M(M OO"l1<<>>>>>>>>>)0)9 L;; &w ) 6 + 
 %'* * * $ $ $ $ $ $ ),HK)#  
 !$ O O OJ#%  
  *%s9~~NNNNNNNNNNNNNNNNO ?#NNN!%s3xx@@@@@@@@@@@9A< $=AAAAsP   
A8DI-I(-BG
H$9HH$I(I-H$$<I( I-(I-Dict[str, Any]c                n   K   |                      |           d{V }|j        dk    rdnd}|j        |dS )z%Return room name and type (dm/group).Ndmro   )rN   r  )_resolve_room_identityr   r   )r   r   identityr   s       r'   get_chat_infozMatrixAdapter.get_chat_infoj  sR      44W========$.$66DDG	 -yAAAr&   c                   t          j                     }t          | j                  }| j        pt	          | j        dd          pd}| j        pt	          | j        dd          pd}d| j        |t          | j                  |rdnd|t          |          t          |          d| j        dut          | j                  | j        rt          d|| j        z
            ndd	| j        t          | j                  t!                      t#          t$                    t          t'          j        d
d                                                    dt          | j                  t          | j                  t          | j                  | j        t          | j                  | j        | j        t'          j        dd                                          dv dd| j        idS )z4Return redacted Matrix readiness/status diagnostics.r~  rk   r  r   r[  )access_token_presentpassword_presenttoken_previewr  device_id_presentdevice_id_previewNr  )	connectedjoined_room_countlast_sync_age_secondsr  )modeenableddeps_availablecrypto_store_pathrecovery_key_configuredMATRIX_ALLOW_PUBLIC_ROOMSrS  )allowed_user_countallowed_room_countignored_user_pattern_countrG  free_response_room_countallow_room_mentionsprocess_noticesallow_public_roomsmax_media_bytes)platformr  authr  e2eepolicymedia)r  r   r  r  r   r  r  r  r  r]  r@  r  r  maxr  r   r@  rO   rk  rU  rV  r   r5  r6  r7  r  r  r  r"  rZ   r*  )r   nowtoken_presentr  r  s        r'   get_diagnosticszMatrixAdapter.get_diagnosticsp  s   ikkT/00-J74<#D#DJOSwt|["'M'MSQS	 *(5$($8$8*7!?R"%))__%9)%D%D  "\5%();%<%<:>:LVCS4#55666RV	   011"2"4"4%(%9%9+/	:OQS0T0T0Z0Z0\0\+]+]  '*$*@&A&A&)$*@&A&A.1$2M.N.N#'#8,/0@,A,A'+'@#'#8&(i0KR&P&P&V&V&X&X''(
 
 "4#8I'
 '
 '	
r&   c                   K   | j         rC	 | j                             t          |          d           d{V  dS # t          $ r Y dS w xY wdS )zSend a typing indicator.0u  r  Nr  
set_typingr   r^   )r   r   r  s      r'   send_typingzMatrixAdapter.send_typing  s|       < 	l--fWoou-MMMMMMMMMMM   	 	   /< 
A
	A
c                   K   | j         rC	 | j                             t          |          d           d{V  dS # t          $ r Y dS w xY wdS )zClear the typing indicator.r   r  Nr  )r   r   s     r'   stop_typingzMatrixAdapter.stop_typing  sz      < 	l--fWooq-IIIIIIIIIII   	 	r  )finalizer   r   c                 K   |                      |          }|                     |          }dd| |d}d|v r|d         |d<   d|v rd|d<   d|d          |d<   d|d	|d
<   	 | j                            t	          |          t
          j        |           d{V }t          dt          |                    S # t          $ r(}	t          dt          |	                    cY d}	~	S d}	~	ww xY w)z)Edit an existing message (via m.replace).m.textz* )msgtypebodyzm.new_content
m.mentionsformatted_bodyorg.matrix.custom.htmlformat	m.replace)rel_typerC  m.relates_toNTr  Fr  )
r  r  r  r  r   r   r!   rI   rO   r^   )
r   r   r   r  r   r  new_contentr  rC  r|  s
             r'   edit_messagezMatrixAdapter.edit_message  sZ     
 ''00	66yAA$$$('
 '

 ;&&(3L(AK%{**$<K!,P=M1N,P,PK()#"'
 '
N#
	=!\<<w&       H
 ds8}}EEEE 	= 	= 	=e3s88<<<<<<<<<	=s   %AB< <
C.C)#C.)C.	image_urlcaptionc           
       K   ddl m}  ||          sFt                              d           t	                                          |||||           d{V S 	 |                     |           d{V \  }}}	nh# t          $ r[}
t                              dt          |          |
           d}|r| d| }| 	                    |||           d{V cY d}
~
S d}
~
ww xY w| 
                    |||	|d	|||           d{V S )
z.Download an image URL and upload it to Matrix.r   is_safe_urlz2Matrix: blocked unsafe image URL (SSRF protection)r  Nz'Matrix: failed to download image %s: %szwI couldn't download and upload the image to Matrix. The source URL was not shown because it may contain private tokens.r  m.image)tools.url_safetyr2  r_   r4  r   
send_image!_download_external_media_with_capr^   r  r  _upload_and_send)r   r   r.  r/  r  r  r2  r   ctfnamer|  fallbackr   s               r'   r6  zMatrixAdapter.send_image  s      	100000{9%% 	NNOPPP++GX ,         	$($J$J9$U$UUUUUUUOD"ee 	 	 	NN9#I..  V   4%3333             	$ **T5"i(H
 
 
 
 
 
 
 
 	
s   A< <
C!ACC!C!r  tuple[bytes, str, str]c                L   K   ddl m  |          st          d          d/ fd}d0d}d1 fd}|                    dd          d                             d          d         pd}d2fd}	 ddl}t           j                  \  }}	 |j        d3i |4 d{V }
|}t          d          D ]l} |
j
        |f|                    d          dd |	4 d{V 	 }|j        d!v rJ|j        
                    d"          }|st          d#           |||          }	 ddd          d{V  |                                  ||j                   g }d}|j                            d$          2 3 d{V } |||t#          |                    }"6  |t%          |d	d          p|j        
                    d%d&                    }d'                    |          ||fcddd          d{V  c cddd          d{V  S # 1 d{V swxY w Y   nt          d(          # 1 d{V swxY w Y   dS # t(          $ rU ddl}i } j        r
 j        |d)<   d*t,          gi|d+<    |j        d3i |4 d{V }
|
                    d,|d-d.          4 d{V 	 }|                                  ||j                   g }d}|                                2 3 d{V } |||t#          |                    }"6  ||j        
                    d%d&                    }d'                    |          ||fcddd          d{V  cddd          d{V  cY S # 1 d{V swxY w Y   	 ddd          d{V  Y dS # 1 d{V swxY w Y   Y dS w xY w)4zFDownload external media while enforcing redirect safety and size caps.r   r1  zblocked unsafe media URLheadersr   rP   r   c                .   d }	 |                      d          p|                      d          }n# t          $ r d }Y nw xY w|d S 	 t          |          }n# t          t          f$ r Y d S w xY w|j        k    rt	          d| dj         d          d S )NzContent-Lengthzcontent-lengthzmedia exceeds Matrix limit ( >  bytes))rT  r^   r)  r!  r"  r*  )r>  rJ  sizer   s      r'   _check_content_lengthzNMatrixAdapter._download_external_media_with_cap.<locals>._check_content_length  s    Ckk"233Tw{{CS7T7T   {3xxz*   d+++ Z4ZZD<QZZZ   ,+s   *0 ??A A,+A,content_typerO   c                    t          | pd                              dd          d                                                                         } |                     d          st          d          | S )Nrk   r   r@   r   r  zexternal media is not an image)rO   r0  r   rZ   rl   r"  )rD  s    r'   _check_image_content_typezRMatrixAdapter._download_external_media_with_cap.<locals>._check_image_content_type  sm    |1r2288a@@CIIKKQQSSL**844 C !ABBBr&   r  list[bytes]totalr)  r  bytesc                    |t          |          z  }|j        k    rt          dj         d          |                     |           |S )Nzmedia exceeds Matrix limit (> rA  )r@  r*  r"  r\   )r  rH  r  r   s      r'   _append_chunkzFMatrixAdapter._download_external_media_with_cap.<locals>._append_chunk  s]    SZZEt,,, ST5JSSS   LLLr&   rY   r@   r  z	image.pngcurrent_urllocationc                \    t          | |          } |          st          d          |S )a  Resolve a redirect Location and re-validate it against SSRF policy.

            A public-looking URL can 302-redirect the gateway toward loopback,
            private-network, or cloud-metadata endpoints. Validating only the
            final URL is insufficient because the connection to the unsafe hop
            has already been made. Re-check every hop before following it.
            zblocked unsafe redirect URL)r   r"  )rM  rN  next_urlr2  s      r'   _safe_redirect_targetzNMatrixAdapter._download_external_media_with_cap.<locals>._safe_redirect_target(  s;     {H55H;x(( @ !>???Or&   N      rH  F)r  allow_redirects>   -  .  /  3  4  Locationzredirect missing Locationi   zcontent-typeapplication/octet-streamr&   ztoo many redirectsr-  responseevent_hooksGETT)follow_redirectsr  )r>  r   rP   r   )rD  rO   rP   rO   )r  rG  rH  r)  r  rI  rP   r)  )rM  rO   rN  rO   rP   rO   r%   )r5  r2  r"  rsplitr0  r.  rK   r'  r/  rangerT  ClientTimeoutstatusr>  raise_for_statusr  iter_chunkedrI  r   r   r3  httpxrL   AsyncClientstreamaiter_bytes)r   r  rC  rF  rK  r:  rQ  _aiohttp_sess_kw_req_kwr   	fetch_urlrS   r\  rN  r  rH  r  r9  rg  	_httpx_kwr2  s   `                    @r'   r7  z/MatrixAdapter._download_external_media_with_cap  s     000000{3 	97888	 	 	 	 	 	"	  	  	  	 	 	 	 	 	 	 

3""2&,,S11!4C	 	 	 	 	 	6	6&&&& 8 I IHg-x-9999 7 7 7 7 7 7 7T	r : :A'tx!  ( 6 6R 6 @ @(-    "	    : : : : : : : :
 ;*CCC'+|'7'7
'C'CH#+ N&01L&M&M M(=(=i(R(RI$: : : : : : : : : : : : : --///--dl;;;-/ !+/<+D+DU+K+K N N N N N N N%$1M%e$M$MEE ,L66#D.$?? \#|//@Z[[   #xxE9-: : : : : : : : : : : : : : :7 7 7 7 7 7 7 7 7 7 7 7 7 7: : : : : : : : : : : : : : :. !!566657 7 7 7 7 7 7 7 7 7 7 7 7 7 7 76  	6 	6 	6LLL I 5%)_	'"(25I4J'KIm$(u(55955 6 6 6 6 6 6 6;;%)	 '   6 6 6 6 6 6 6 6
 ))+++))$,777)+EE'+'7'7'9'9 J J J J J J Je -eUE%LL I I (:22((9STT B 88E??B56 6 6 6 6 6 6 6 6 6 6 6 66 6 6 6 6 6 6 6 6 6 6 6 6 6 6 66 6 6 6 6 6 6 6 6 6 6 6 6 6 66 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6	6s   3.I !A H0"AH$H06AH8F>A)H'H0;I 
HH0HH00
H::I =H:>I AN# N&=M(#L)AM(NN#(
M22N5M26N:N#
N	N#N	N#"N#
image_pathc                H   K   |                      ||d|||           d{V S )z$Upload a local image file to Matrix.r4  r3  N_send_local_file)r   r   rp  r/  r  r  s         r'   send_image_filezMatrixAdapter.send_image_filem  P       **ZGX + 
 
 
 
 
 
 
 
 	
r&   r  r  list[tuple[str, str]]human_delayr  c           	       K   |sdS ddl m} t          |          }t          |d          D ]\  }\  }}	|dk    r |dk    rt	          j        |           d{V  |	pd}
|dk    r|
r|
 d| d| d}
|                    d	          r1|                     | ||d
d                   |
|           d{V }n|                     |||
|           d{V }|j	        s"t                              d|||j                   dS )z9Send multiple Matrix images as one ordered logical batch.Nr   )unquoter@   )r  z (rY   r}  zfile://   )r   rp  r/  r  )r   r.  r/  r  z&Matrix: failed to send image %d/%d: %s)urllib.parsery  r@  r  r  sleeprl   rt  r6  r  r_   r4  r  )r   r   r  r  rw  _unquoterH  idxr.  alt_textr/  r  s               r'   send_multiple_imagesz"MatrixAdapter.send_multiple_imagesz  s       	F444444F*3F!*D*D*D 	c 	c&C&)XQ377mK000000000&$GqyyWy$6666e666##I.. #33#'x	!""66#%	  4            $#'#%	  /           > cGeU[Uabbb+	c 	cr&   	file_path	file_namec           	     H   K   |                      ||d||||           d{V S )z"Upload a local file as a document.m.fileNrr  )r   r   r  r/  r  r  r  s          r'   send_documentzMatrixAdapter.send_document  sM       **Y'8Y
 
 
 
 
 
 
 
 	
r&   
audio_pathc           	     J   K   |                      ||d|||d           d{V S )z?Upload an audio file as a voice message (MSC3245 native voice).m.audioT)r  is_voiceNrr  )r   r   r  r/  r  r  s         r'   
send_voicezMatrixAdapter.send_voice  sX       ** + 
 
 
 
 
 
 
 
 	
r&   
video_pathc                H   K   |                      ||d|||           d{V S )zUpload a video file.m.videor3  Nrr  )r   r   r  r/  r  r  s         r'   
send_videozMatrixAdapter.send_video  ru  r&   dangerous commandcommandr   descriptionOptional[dict]c                N  K   | j         st          dd          S t          |pi                     d          pd          pd}t	          |          dk    r|dd         dz   n|}d	| d
| d}|                     |||           d{V }	|	j        r|	j        s|	S t          |||	j        |t          j
                    t          | j        d          z             }
| j                            |          }|r| j                            |d           |
| j        |	j        <   |	j        | j        |<   dD ]q}	 |                     ||	j        |           d{V }|rt          |          |
j        |<   ?# t$          $ r&}t&                              d||           Y d}~jd}~ww xY w|	S )z6Send a reaction-based exec approval prompt for Matrix.FNot connectedr  r   rk   Ni  ...u3   ⚠️ **Dangerous command requires approval**
```
z
```
Reason: u   

Reply `!approve` to execute, `!approve session` to approve this pattern for the session, `!approve always` to approve permanently, or `!deny` to cancel.

You can also click the reaction to approve:
✅ = approve
❎ = denyr3  r   )r   r   r   r   r   )r  r  r  z.Matrix: failed to add approval reaction %s: %s)r  rI   rO   rT  r@  r  r  r   r   r  	monotonicr  r3  r1  r0  pop_send_reactionr   r^   r_   r`   )r   r   r  r   r  r  r   cmd_previewrg   r  r  	old_eventemojireaction_resultr|  s                  r'   send_exec_approvalz MatrixAdapter.send_exec_approval  s4      | 	De?CCCCR 4 45H I I ORPPXTX03Gt0C0Cgetenu,, "   	 yy$yBBBBBBBB~ 	V%6 	M&#(/~''#d.La*P*PP
 
 
 488EE	 	A+//	4@@@=C'(9:8>8I(5- 	[ 	[E[(,(;(;GVEVX](^(^"^"^"^"^"^"^" M8;O8L8LF.u5 [ [ [MuVYZZZZZZZZ[ s   6;E22
F"<FF"	providersr  current_modelcurrent_providerc                  K   | j         st          dd          S g }|pg D ]}	t          |	                    d          pd          }
t          |	                    d          p|
          }|	                    d          pg }|D ]g}t	          |          t	          t
                    k    r n?|                    t
          t	          |                   t          |          |
|f           ht	          |          t	          t
                    k    r n|s|                     |d|	           d
{V S 	 ddlm	}  ||          }n# t          $ r |}Y nw xY wdd|pd dd|pd ddg}i }|D ]+\  }}}
}||
f||<   |                    | d| d|            ,|                     |d                    |          |	           d
{V }|j        r|j        s|S t          ||j        |||t          |pi                     d          pd          pd
t          j                    t#          | j        d          z             }|| j        |j        <   |D ]q}	 |                     ||j        |           d
{V }|rt          |          |j        |<   ?# t          $ r&}t,                              d||           Y d
}~jd
}~ww xY w|S )z*Send a Matrix reaction-based model picker.Fr  r  slugrk   rN   modelsz7No authenticated models are available for this session.r3  Nr   )	get_labelu   ⚙ **Model Configuration**zCurrent model: `unknown`z
Provider: zReact to choose a model:z `u   ` — r  r   )r   r   r   r   r   r   r   z2Matrix: failed to add model picker reaction %s: %s)r  rI   rO   rT  r@  _MATRIX_MODEL_PICKER_REACTIONSr\   r  hermes_cli.providersr  r^   r   r  r   r   r  r  r  r3  r4  r  r   r_   r`   )r   r   r  r  r  r   r   r  flat_choicesproviderprovider_slugprovider_namer  model_idr  provider_labellinesr   r  r  r  reaction_event_idr|  s                          r'   send_model_pickerzMatrixAdapter.send_model_picker  s      | 	De?CCCC8:!R 	 	HV 4 4 :;;MV 4 4 EFFM\\(++1rF"  |$$,J(K(KKKE##23|3D3DEMM!!	%     <  C(F$G$GGG H  	I! #         	.666666&Y'788NN 	. 	. 	.-NNN	. *<}9	<<<64966&
 /1=I 	F 	F9E8]M&6GENLLEDDXDD]DDEEEEyy$))E*:*:XyNNNNNNNN~ 	V%6 	M)(#/!8>r"6"67J"K"K"QrRRZVZ~''#d.La*P*PP
 
 
 BH+F,=> 	_ 	_E_*.*=*=gvGXZ_*`*`$`$`$`$`$`$`!$ O8;<M8N8NF.u5 _ _ _QSXZ]^^^^^^^^_ s*   5E EE;J
KJ??Kc                2    t          j        dd|          }|S )u<   Pass-through — Matrix supports standard Markdown natively.z!\[([^\]]*)\]\(([^)]+)\)z\2r  )r   r  s     r'   r  zMatrixAdapter.format_messageR  s     &4eWEEr&   r   r   rI  filenamerD  r#  r  c
                l  K   t          |          | j        k    r*t          ddt          |           d| j         d          S |}
d}| j        rt	          | j        dd          rt	          | j        dd          }|r	 t          |                    t          |                     d{V           }n# t          $ r d}Y nw xY w|rf	 d	d
l
m}  ||          \  }
}nP# t          $ rC}t                              d|           t          dt          |                    cY d}~S d}~ww xY w	 | j                            |
||t          |
                     d{V }nP# t          $ rC}t                              d|           t          dt          |                    cY d}~S d}~ww xY w||p||t          |          dd}|,|                                }t          |          |d<   ||d<   nt          |          |d<   |	ri |d<   |                     |||           	 | j                            t          |          t&          j        |           d{V }t          dt          |                    S # t          $ r(}t          dt          |                    cY d}~S d}~ww xY w)z3Upload bytes to Matrix and send as a media message.F!Media file exceeds Matrix limit (r@  rA  r  Nr  r{  r   )encrypt_attachmentz(Matrix: attachment encryption failed: %s)	mime_typer  rB  zMatrix: upload failed: %s)mimetyperB  )r#  r$  r(  r  fileorg.matrix.msc3245.voicer  Tr  )r@  r*  rI   r   r   r  r   r  r   r^   mautrix.crypto.attachmentsr  r_   r  rO   upload_media	serializer  r  r   r!   )r   r   r   r  rD  r#  r/  r  r  r  upload_dataencrypted_filer{  room_encryptedr  r|  mxc_urlr  file_payloadrC  s                       r'   r8  zMatrixAdapter._upload_and_send\  s      t99t,,,f#d))ffH]fff   
  	Ih E E 	I!$,tDDK I+%)0H0HPW0Y0Y*Y*Y*Y*Y*Y*Y%Z%ZNN  + + +%*NNN+! IIQQQQQQ6H6H6N6N3^^$ I I I%OQTUUU)%s3xxHHHHHHHHHI
		= L55&!%%	 6        GG  	= 	= 	=LL4c:::e3s88<<<<<<<<<	= 'x(D		 '
 '
 %)3355L"%g,,L".K!$WK  	968K23%%kHx%XXX	=!\<<w&       H
 ds8}}EEEE 	= 	= 	=e3s88<<<<<<<<<	=sm   ?5B5 5CC
C 
D,)8D'!D,'D,01E" "
F/,8F*$F/*F/*AJ 
J3J.(J3.J3c	                `  K   t          |                                          }	|	                                sGt                              d| j        |           |r| dnd}
|                     ||
|           d{V S 	 |	                                j        }n# t          $ r d}Y nw xY w|| j
        k    rt          dd| d| j
         d	
          S |p|	j        }t          j        |          d         pd}|	                                }|                     |||||||||	  	         d{V S )z Read a local file and upload it.z1[%s] upload fallback: media file not found for %su(   
⚠️ Couldn't deliver the attachment.u'   ⚠️ Couldn't deliver the attachment.Nr   Fr  r@  rA  r  r\  )r   rg  r{  r_   r4  rN   r  statst_sizerq  r*  rI   r  r  
read_bytesr8  )r   r   r  r#  r/  r  r  r  r  rv   rg   	file_sizer:  r9  r   s                  r'   rs  zMatrixAdapter._send_local_file  s      OO&&((xxzz 	<NNC	9   MT ?gHHHH> 7D(;;;;;;;;;	(II 	 	 	III	t,,,f)ffH]fff   
 #QV!%((+I/I||~~**T5"gw(H
 
 
 
 
 
 
 
 	
s    B B)(B)c                  K   | j         }|j                                         d{V }| j        s	 t	          j        |                    |d          d           d{V }t          |dd          }|rNt          |t                    r9|
                                }d|v sd|v rt                              d	|           dS t          |t                    rYt          j                    | _        |                    d
i                               di           }|r^| j                            |                                           | j                                         | j                                         |                    d          }|r"|}|j                            |           d{V  	 |                     |           d{V  n2# t2          $ r%}t                              d|           Y d}~nd}~ww xY w|                     |           t	          j        d           d{V  n# t          j        $ r Y dS t2          $ r}| j        rY d}~dS t          |          
                                }	d|	v sd|	v sd|	v sd|	v r!t                              d|           Y d}~dS t                              d|           t	          j        d           d{V  Y d}~nd}~ww xY w| j        dS dS )z&Continuously sync with the homeserver.Nr  )sincer       F@r  messagem_unknown_tokenunknown_tokenu7   Matrix: permanent auth error from sync: %s — stoppingr  r   r  z%Matrix: sync event dispatch error: %sr   401403unauthorized	forbiddenu2   Matrix: permanent auth error: %s — stopping syncu)   Matrix: sync error: %s — retrying in 5sr   )r  r|  get_next_batchr  r  r  r  r   r  rO   rZ   r_   r  r   r  r  rT  r  r  rR  r  r  r  r  r  r^   r4  r  r|  r  )
r   rW  r  r  	_sync_msg_lowerr  r  r|  err_strs
             r'   r  zMatrixAdapter._sync_loop  s     !,;;========
- F	'E' #*"2KK( %     !# # #      	 $Iy$??	 Is!;!; &__..F(F22o6O6OU%   i.. +)-D&!*w!;!;!?!?!K!KJ! >*11*//2C2CDDD-335555;;=== #|44B C%'
$/>>rBBBBBBBBBU"11)<<<<<<<<<<$ U U U'NPSTTTTTTTTU77	BBB "-*********)    ' ' '= FFFFFc((..**W$$''%00"g--LLLc   FFFFFJCPPPmA&&&&&&&&&&&&&&!'m - F	' F	' F	' F	' F	's\   BH4 C1H4 6G H4 
HG<7H4 <H2H4 4K-	K-K(AK(.5K((K-r  c                B  K   | j         }|rt          |d          sdS |                    |          }t          j        |          r| d{V }|rLt          j        |ddi d{V }|D ]4}t          |t                    rt          
                    d|           3dS dS )z=Dispatch a sync response through the mautrix event machinery.handle_syncNr  Tz5Matrix: event handler failed during sync dispatch: %s)r  r  r  inspectisawaitabler  r  r  r^   r_   r4  )r   r  rW  tasksresultsr  s         r'   r  zMatrixAdapter._dispatch_sync)	  s       	WV];; 	F""9--u%% 	 KKKKKKE 	 $NEJTJJJJJJJJG!  fi00 NNO  	 	 r&   senderc                    | j         pd                                                                }|sdS |                                                                |k    S )u  Return True if the sender refers to the bot's own account.

        Matrix user IDs are byte-compared after trimming whitespace and
        lowercasing — some homeservers normalize the localpart case
        differently at different API surfaces, and the reply-loop tail
        of the "hall of mirrors" bug (#15763) has been observed with the
        bot's own account bypassing a case-sensitive equality check.

        When ``self._user_id`` is empty (whoami hasn't resolved yet, or
        login failed), we cannot prove a sender is NOT us, so we return
        True defensively — an unidentified bot dropping its own events
        is always preferable to falling into an echo loop.
        rk   T)r  r   rZ   )r   r  owns      r'   _is_self_senderzMatrixAdapter._is_self_sender?	  sT     }"))++1133 	4||~~##%%,,r&   c                    | pd                                 }|sdS |                    d          r
|dd         }d|v r|                    d          \  }}}n|}|sdS |                    d          S )u$  Return True if the sender looks like a system / bridge / appservice
        identity rather than a real user.

        Appservice namespaces on Matrix conventionally prefix bot / puppet
        user IDs with an underscore (e.g. ``@_telegram_12345:server``,
        ``@_discord_999:server``, ``@_slack_...:server``).  Server-notices
        bots and bridge-controller bots on many homeservers use the same
        pattern.

        We treat these as system identities for pairing purposes: they
        should never be offered a pairing code, because an operator
        approving the code would hand the bridge itself permanent
        authorization — and every outbound message relayed by the bridge
        would then loop back into the agent as an "authorized user
        message", which is the root of issue #15763.

        Matches:
            ``@_something:server``   — appservice namespace convention
            ``@:server``             — malformed / empty localpart
            ``:server``              — malformed, no leading ``@``
        rk   T@r@   Nr  rS   )r   rl   	partition)r  rw   	localpartrS   s       r'   _is_system_or_bridge_senderz)MatrixAdapter._is_system_or_bridge_senderR	  s    . \r  "" 	4<< 	!""A!88kk#..OIq!!I 	4##C(((r&   c                D    t          fd| j        D                       S )zBReturn True when sender matches configured Matrix ignore patterns.c              3  F   K   | ]}|                     pd           V  dS )rk   N)search)r  r>  r  s     r'   r  z>MatrixAdapter._matches_ignored_user_pattern.<locals>.<genexpr>y	  s3      [[G7>>&,B//[[[[[[r&   )anyr7  )r   r  s    `r'   _matches_ignored_user_patternz+MatrixAdapter._matches_ignored_user_patternw	  s)    [[[[t?Z[[[[[[r&   c                $    | j          p|| j         v S )z7Return True when MATRIX_ALLOWED_ROOMS permits the room.)r6  r  s     r'   _is_allowed_matrix_roomz%MatrixAdapter._is_allowed_matrix_room{	  s    ))NW8N-NNr&   c                   K   |                      |          rdS 	 |                     |           d{V S # t          $ r'}t                              d||           Y d}~dS d}~ww xY w)zReturn True when a room event may proceed past intake filters.

        MATRIX_ALLOWED_ROOMS constrains shared rooms. Matrix DMs are exempt so
        personal chats still work when operators use a room allowlist for
        project rooms.
        TNzEMatrix: could not resolve room identity for allowlist check in %s: %sF)r  _is_dm_roomr^   r_   r`   )r   r   r|  s      r'   _is_allowed_matrix_room_eventz+MatrixAdapter._is_allowed_matrix_room_event	  s       ''00 	4	))'222222222 	 	 	LLW  
 55555	s   6 
A' A""A'r  c           	       K   t          t          |dd                    }t          t          |dd                    }t                              dt          |dd          ||           |                     |          rdS |                     |          rt                              d||           dS |                     |          rt                              d	||           dS |                     |           d{V st                              d
|           dS t          t          |dd                    }| 	                    |          rdS t          |          }|r|| j        t          z
  k     r| j        st          j                    | j        z
  dk    r| j        |z
  }d|cxk     rdk     rn n| j        dk    r|| _        d| _        n:t#          || j        z
            dk     r| xj        dz  c_        n|| _        d| _        | j        dk    r(t                              d| j        |           d| _        dS t          |dd          }|dS t'          |d          rt          |j                  }n.t+          |t,                    r|                    dd          }nd}t+          |t,                    r|}	n't'          |d          r|                                }	ni }	|	                    di           }
|
                    d          dk    rdS |dk    r	| j        sdS d}||v r#|                     |||||	|
|           d{V  dS |dv r"|                     |||||	|
           d{V  dS dS )z2Handle incoming room message events (text, media).r   rk   r  u1   Matrix: callback fired — event %s from %s in %srC  r  Nz.Matrix: ignoring system/bridge sender %s in %szAMatrix: ignoring sender %s in %s due to configured ignore patternz2Matrix: ignoring message from unauthorized room %srS  r   iQ r   r@   <      u1  Matrix: dropped %d consecutive live events as 'too old' more than 30s after startup (skew ≈ %.0fs). The host system clock is likely set ahead of real time, which causes the startup grace filter to silently discard every incoming message. Run `timedatectl set-ntp true` (or sync NTP) and restart the bot.Tr  r#  r  r+  r*  r)  m.notice)r4  r  r  r  )r"  r  )rO   r   r_   r`   r  r  r  r  r(  rE  r%  r  _STARTUP_GRACE_SECONDSr  r  r	  r
  absr4  r  r#  r  r   rT  r  r"  _handle_media_message_handle_text_message)r   r  r   r  rC  event_tsskewr  r#  source_content
relates_tomedia_msgtypess               r'   r  zMatrixAdapter._on_room_message	  so     geY3344WUHb1122 	?E:s++		
 	
 	
 '' 	F ++F33 	LL@  
 F--f55 	LLS  
 F77@@@@@@@@ 	KKD   F wuj"5566##H-- 	F 3599 ,	4#36L#LLL * 7	d..33'(2 t####e#####-2204-12..TD$99::R??..!3... 15-12.-22= !2 
 
 
 37/F %D11?F 7I&& 	'/**GG&& 	kk)R00GGG gt$$ 	 $NNWk** 	 $..00NNN#'';;
 >>*%%44F j  )> F En$$,,8^ZQX           ...++8^Z           /.r&   rC  r$  r  r   r  Optional[tuple]c                  K   |                      |           d{V }|                     |           d{V }|rdnd}	d}
|                    d          dk    r|                    d          }
|                    d          }|                    d          pi }t          |t                    r|                    d	          nd}|                     |||          }|s| j        r'|| j        vrt                              d
||           dS || j	        v }t          |
o|
| j        v           }|                    d          }| j        r'|s%|s#|s |st                              d||           dS n+| j        r$|r"|s |st                              d||
           dS |r'|
s%| j        r|r|}
| j                            |
           |r| j        r|                     |          }|
s|r$| j        r|}
| j                            |
           nY| j        dk    rd}
nK| j        dk    r|}
| j                            |
           n#| j        r|}
| j                            |
           |                     ||           d{V }|                     ||j        |	|||
|j        |j        |
r|nd|
  
        }|
r| j                            |
           |                     ||           |||	|
||fS )zShared mention/thread/DM gating for text and media handlers.

        Returns (body, is_dm, chat_type, thread_id, display_name, source)
        or None if the message should be dropped (mention gating).
        Nr  ro   r*  m.threadrC  r&  r%  user_idsuP   Matrix: ignoring message %s in %s — room not in MATRIX_ALLOWED_ROOMS whitelistrY   u_   Matrix: ignoring message %s in %s — no @mention (set MATRIX_REQUIRE_MENTION=false to disable)uV   Matrix: ignoring message %s in thread %s — no @mention (thread_require_mention=true)r  r  )
r   	chat_namer   r  	user_name	thread_id
chat_topicguild_idparent_chat_idr   )r  r  rT  r  r   _is_bot_mentionedr  r_   r`   r  r   r  rl   r  r  r   mark_strip_mentionr  r!  r  _get_display_namebuild_sourcer   r   r   _background_read_receipt)r   r   r  rC  r$  r  r  r  is_dmr   r  r&  mentions_blockmention_user_idsis_mentionedis_free_roomin_bot_thread
is_commandr   sources                       r'   _resolve_message_contextz&MatrixAdapter._resolve_message_context
  s      44W========&&w////////!.DDw		>>*%%33"z22I'++,<=='++L99?R.8.N.NXNz***TX 	 --dNDTUU  '	  " wd6I'I'I5	   t"d&66L !IyDM/IJJM--J$  \  -  #  J  LLH 	    4 . 	 = 	 &	 #  LLD !	    4  	* 	*t'? 	*L 	* IMy)))  	-D1 	-&&t,,D  	. .' 2 (IM&&y111+v55 		+x77$	""9----" .$	""9---!33GVDDDDDDDD""+"*)&/977T # 
 
  	*My)))%%gx888UIy,FFr&   r  c                l  K   |                     dd          pd}|sdS t          |          }|                     ||||||           d{V }|dS |\  }}	}
}}}d}|                     di           }|r|                     d          }|r|                    d          ru|                    d          }g }d}|D ]@}|s'|                    d          s|d	k    r |dk    rd
})d
}|                    |           A|rd                    |          n|}t          |          }t          j        }|                    d          rt          j	        }t          ||||||          }|t          j        k    r"| j        dk    r|                     |           dS |                     |           d{V  dS )zProcess a text message event.r$  rk   Nm.in_reply_torC  > r  Fr   TrY   )rg   message_typer  raw_messager   reply_to_message_idr   )rT  rq   r  rl   r0  r\   r   rG   TEXTCOMMANDrF   r+  _enqueue_text_eventhandle_message)r   r   r  rC  r  r  r  r$  ctxr  r   r  r   r  r  in_reply_tor  r   past_fallbacklinemsg_type	msg_events                         r'   r  z"MatrixAdapter._handle_text_message
  sB      !!&"--3 	F-d3311
 
 
 
 
 
 
 
 ;FBE?eY	<  nn_b99 	3"z22H  	=-- 	=JJt$$EH!M & &$ )t,, ! rzz(, $(M%%%%*2<499X&&&D
 .d33#??3 	+"*H !& (
 
 
	 {'''D,JQ,N,N$$Y/////%%i00000000000r&   c           	       K   |                     dd          pd}|                     dd          }	|	r?t          |	                              d          st                              d|           dS d}
|	r*|	                    d          r|                     |	          }
|                     di           }t          |t                    si }|                     dd          }|                     d	          }	 |t          |          nd
}n# t          t          f$ r d
}Y nw xY w|r/|| j        k    r$t                              d||| j                   dS |                     di           }|	st          |t                    r|                     dd          pd}	|	r?t          |	                              d          st                              d|           dS |	r*|	                    d          r|                     |	          }
t          |o)t          |t                    o|                     d                    }d}t          j        }d}|dk    rt          j        }|pd}nV|dk    r5|                     d          d}t          j        }nt          j        }|pd}n|dk    rt          j        }|pd}n|r|}d}|t          j        t          j        t          j        t          j        hv p|p|}|rD|	rA	 | j                            t+          |	                     d{V }||rd
dlm} t          |t                    r|                     d          nd}t          |t                    r|                     d          nd}t          |t                    r|                     d          nd}t          |t                    r|                     d          }t          |t                    r|                     d          nd}|r|r|r |||||          }nt                              d|           d}|d
dlm}m}m} |t          j        k    rFd d!d"d#d$}|                     |d           }  ||| %          }t                              d&|           nf|t          j        t          j        hv r*t;          |p|rd'nd(          j        pd)}  ||| %          }n"|p|t          j        k    rd*nd+}! |||!          }n2# t>          $ r%}"t                              d,|"           Y d}"~"nd}"~"ww xY w|                      ||||||           d{V }#|#dS |#\  }}$}%}&}'}(|dk    rtC          |          rd}t          |
          o| })|r|gn|)r|
gnd}*|*r|gnd}+tE          |||(|||*|+-          },| #                    |,           d{V  dS ).z:Process a media message event (image, audio, video, file).r$  rk   r  mxc://z4[Matrix] Rejecting inbound media %s with non-MXC URLNr(  r  rB  r   z=[Matrix] Rejecting oversized inbound media %s (%d > %d bytes)r  z>[Matrix] Rejecting inbound encrypted media %s with non-MXC URLr\  Fr4  	image/pngr  r  Tz	audio/oggr  z	video/mp4)decrypt_attachmenthashessha256r   kivzA[Matrix] Encrypted media event missing decryption metadata for %s)cache_audio_from_bytescache_document_from_bytescache_image_from_bytesr   r   r   r  )z
image/jpegr'  z	image/gifz
image/webp)extz [Matrix] Cached user image at %sz	voice.oggz	audio.oggz.oggz	video.mp4documentz"[Matrix] Failed to cache media: %s)rg   r  r  r  r   
media_urlsmedia_types)$rT  rO   rl   r_   r4  _mxc_to_httpr  r   r)  r!  r"  r*  r   rG   DOCUMENTPHOTOVOICEAUDIOVIDEOr  download_mediar   r  r(  gateway.platforms.baser-  r.  r/  r(  r   r  r^   r  r  rF   r  )-r   r   r  rC  r  r  r  r#  r$  r  http_urlcontent_infoevent_mimetype
event_sizeevent_size_intfile_contentis_encrypted_media
media_typer#  is_voice_messagecached_pathshould_cache_locally
file_bytesr(  hashes_value
hash_value	key_valueiv_valuer-  r.  r/  ext_mapr0  r  er  r  r   r  r   r  allow_http_fallbackr2  r3  r$  s-                                                r'   r  z#MatrixAdapter._handle_media_message
  s      !!&"--3  ++ 	s3xx**844 	NNF   F  	.3>>(++ 	.((--H &))&"55,-- 	L%))*b99!%%f--
	0:0FS___ANN:& 	 	 	NNN	 	nt/DDDNNO%	   F &))&"55 		2z,55 		2""5"--3C 3s88..x88 T    2s~~h// 2,,S11!WZd;;W@P@PQV@W@W
 
 0
' i"(H'6;JJ	!!!!"<==I#' &,&,'6;JJ	!!"(H'6;JJ 	('J '{0+2C[EY,
  
  4 4!3 	   Q	HC Q	HPH#'<#>#>z##O#OOOOOOO
)) %.QQQQQQ  *,==&L,,X666!% %  *,==&L,,X666!% #  *,==&L,,U333!% "
 &i66 ;(1c(:(:I  *,==&L,,T222!% ! % 	. 	. 	.);); *Iz8* *JJ #NN c (   *.J!-          ${'888.4-3-3.5	' 'G #*++j&"A"AC*@*@QT*U*U*UK"KK(JKXXXX%+*;[=N)OOO $$( %&7G(X[!" !"
 #)!* $*   +A*@QT*U*U*UKK'+ (#+{/@#@#@ !,%/ %
 +D*C *H+ +K  H H HCQGGGGGGGGH 11
 
 
 
 
 
 
 
 ;FBE?eY	<i$Ed$K$KD"8nnG5G1G ?[MM 3=8** 	
 '1:zlld !&!#
 
 
	 !!),,,,,,,,,,,s+   9D D#"D#<HT
 

T9T44T9c                  K   t          t          |dd                    }t          |dd          }t          t          |dd                    }t          t          |dd                    }t          j        dd                                          d	v }|s.| j        r	|| j        v st                              d
||           dS t          	                    d||           | 
                    ||ot          |          |           dS )z=Auto-join rooms when invited, recording DM rooms in m.direct.r   rk   r  N	is_directFr  GATEWAY_ALLOW_ALL_USERS>   rE  r  rD  z8Matrix: rejecting invite to %s from unauthorized user %su0   Matrix: invited to %s — joining (is_direct=%s)rP  inviter)rO   r   r   rU  rV  rZ   r5  r_   r4  r(  _schedule_invite_join)r   r  r   r  rP  rS  	allow_alls          r'   r  zMatrixAdapter._on_invite  s4      geY3344%D11+u==>>	geXr2233 I7<<BBDD I
 
	
  	"	'.$2H'H'HNNJ  
 F>	
 	
 	
 	""1DMM 	# 	
 	
 	
 	
 	
r&   c                  K   |sdS || j         v rdS 	 | j                            t          |                     d{V  | j                             |           | j                            |d           | j                            |d           t          	                    d|           | 
                                 d{V  dS # t          $ r}t                              d||           t          |                                          }d|v sd|v rZ	 | j                            t          |                     d{V  t          	                    d|           n# t          $ r Y nw xY wY d}~dS d}~ww xY w)	z6Join a room by ID and refresh local caches on success.FTNzMatrix: joined %szMatrix: error joining %s: %sz
no serverszroom not foundz"Matrix: declined dead invite to %s)r  r  	join_roomr   rB  r  r  r  r_   r(  r  r^   r4  rO   rZ   
leave_room)r   r   r|  msgs       r'   _join_room_by_idzMatrixAdapter._join_room_by_id  s      	5d(((4	,((999999999""7+++!%%gt444)--gt<<<KK+W555((*********4 	 	 	NN97CHHH c((..""C##)9S)@)@,11&//BBBBBBBBBKK DgNNNN    D55555	s>   B2C 
E;AE6AE E6 
E-*E6,E--E66E;rk   rR  rP  rS  c                    r	 j         v rdS  j                                      }|r|                                sdS d fd}t	          j         |                       j        <   dS )zCSchedule an invite join without blocking sync or gateway readiness.NrP   r   c                   K   	 t          j                                      d           d {V } | r rr                               d {V  n0# t           j        $ r t
                              d           Y nw xY wj                            d            d S # j                            d            w xY w)Nr  r  z#Matrix: timed out joining invite %s)	r  r  rZ  _record_dm_roomTimeoutErrorr_   r4  r  r  )joinedrS  rP  r   r   s    r'   _join_invitez9MatrixAdapter._schedule_invite_join.<locals>._join_invite   s     ;&/))'22D           
  Ai AG A..w@@@@@@@@@' O O ODgNNNNNO '++GT:::::'++GT::::s*   AA B$ *BB$ BB$ $Cr   )r  r  rT  r  r  r  )r   r   rP  rS  existingr`  s   ````  r'   rT  z#MatrixAdapter._schedule_invite_join  s      	'T%777F*..w77 	HMMOO 	F	; 	; 	; 	; 	; 	; 	; 	; 	; ,3+>||~~+N+N(((r&   c                R   t          |t                    r|                    di           ni }|                    di           }t          |t                    sdS |D ]I}|| j        v rt                              d|           |                     t          |                     JdS )z?Join rooms still present in rooms.invite after sync processing.r  inviteNz)Matrix: reconciling pending invite for %s)r  r   rT  r  r_   r(  rT  rO   )r   r  r  invitesr   s        r'   r  z,MatrixAdapter._schedule_pending_invite_joins  s    .8D.I.IQ	gr***r))Hb))'4(( 	F 	5 	5G$,,,KKCWMMM&&s7||4444		5 	5r&   r  c                X  K   | j         sdS dd||di}	 | j                             t          |          t          j        |           d{V }t
                              d||           t          |          S # t          $ r&}t
                              d|           Y d}~dS d}~ww xY w)zzSend an emoji reaction to a message in a room.
        Returns the reaction event_id on success, None on failure.
        Nr+  zm.annotation)r*  rC  r   zMatrix: sent reaction %s to %szMatrix: reaction send error: %s)	r  r  r   r   r"   r_   r`   rO   r^   )r   r   rC  r  r  resp_event_idr|  s          r'   r  zMatrixAdapter._send_reaction   s       | 	4*$ 

	"&,"A"Aw"# #      M
 LL95(KKK}%%% 	 	 	LL:C@@@44444	s   A#A9 9
B)B$$B)r  reasonc                @   K   |                      |||           d{V S )z)Remove a reaction by redacting its event.N)redact_message)r   r   r  rg  s       r'   _redact_reactionzMatrixAdapter._redact_reaction?  s3       ((2CVLLLLLLLLLr&   c                     d fd}t          j         |                      } j                            |           |                     j        j                   dS )zBRedact a reaction after a short delay so message delivery settles.rP   r   c                 T  K   	 j         rt          j        j                    d {V                                 d {V st                              d           d S d S # t          j        $ r  t          $ r'} t                              d|            Y d } ~ d S d } ~ ww xY w)Nz$Matrix: failed to redact reaction %sz4Matrix: delayed reaction redaction failed for %s: %s)r%  r  r|  rj  r_   r`   r  r^   )r|  r  rg  r   r   s    r'   _redact_laterzAMatrixAdapter._schedule_reaction_redaction.<locals>._redact_laterP  s     9 P!-(NOOOOOOOOO!227<MvVVVVVVVV LL>@Q      )      J%        s   AA' 'B' B""B'Nr   )r  r  r&  rB  add_done_callbackrA  )r   r   r  rg  rm  r  s   ````  r'   _schedule_reaction_redactionz*MatrixAdapter._schedule_reaction_redactionH  s    	 	 	 	 	 	 	 	 	" "==??33&**4000t=EFFFFFr&   rF   c                   K   | j         sdS |j        }|j        j        }|r/|r/|                     ||d           d{V }|r|| j        ||f<   dS dS dS dS )z=Add eyes reaction when the agent starts processing a message.Nu   👀)r#  r   r  r   r  r$  )r   r  msg_idr   r  s        r'   on_processing_startz!MatrixAdapter.on_processing_starte  s      & 	F!,& 	Og 	O&*&9&9'6<&X&X X X X X X X  O=N'&(9:::	O 	O 	O 	OO Or&   outcomerH   c                L  K   | j         sdS |j        }|j        j        }|r|sdS |t          j        k    rdS ||f}|| j        v r1| j                            |          }|                     ||d           | 	                    |||t          j
        k    rdnd           d{V  dS )z9Replace eyes with checkmark (success) or cross (failure).Nzprocessing completer  r  )r#  r   r  r   rH   	CANCELLEDr$  r  ro  r  SUCCESS)r   r  rs  rq  r   reaction_keyeyes_event_ids          r'   on_processing_completez$MatrixAdapter.on_processing_completep  s       & 	F!,& 	W 	F'111F(4222 377EEM--%  
 !!#4#<<<HH(
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
r&   c                x	  K   t          t          |dd                    }|                     |          rdS t          t          |dd                    }|                     |          rdS t          t          |dd                    }t          |dd          }|rt	          |t
                    r|                    di           nt          |di           }d}d}t	          |t
                    r-|                    dd          }|                    d	d          }nLt          |d          r<t          t          |dd                    }t          t          |d	d                    }t          	                    d
||||           | j
                            |          }	|	ru|	j        sm||	j        k    rdS |                     |	          r|                     |||	           d{V  dS |                     ||||	d           d{V sdS | j                            |          }
|
s|                     ||d           d{V  dS 	 ddlm}  ||	j        |
          }|rd|	_        | j
                            |d           | j                            |	j        d           t          	                    d||	j        |
|           |                     ||	           d{V  n2# t0          $ r%}t                              d|           Y d}~nd}~ww xY wdS | j                            |          }|r~|j        sx||j        k    rdS |                     |          r|                     |||           d{V  dS |                     ||||d           d{V sdS |j                            |          }|s|                     ||d           d{V  dS d|_        | j                            |d           |\  }}	 |                    |||           d{V }|                     ||           d{V  |r|                     |||           d{V  nS# t0          $ rF}t                              d|           |                     |d| |           d{V  Y d}~nd}~ww xY wdS dS dS dS )z Handle incoming reaction events.r  rk   NrC  r   r  r+  r  r   z'Matrix: reaction %s from %s on %s in %sapprovalz4That reaction is not valid for this approval prompt.r   )resolve_gateway_approvalTzKMatrix reaction resolved %d approval(s) for session %s (choice=%s, user=%s)z;Failed to resolve gateway approval from Matrix reaction: %sr  z8That reaction is not one of the available model choices.r  z/Failed to switch model from Matrix reaction: %szFailed to switch model: ) rO   r   r  rE  r  r   rT  r  r_   r(  r0  rp   r   _matrix_prompt_expired_expire_matrix_approval_prompt_validate_matrix_prompt_reactorr/  _send_invalid_reaction_feedbacktools.approvalr|  r   r  r1  _redact_bot_approval_reactionsr^   r  r4  "_expire_matrix_model_picker_promptr   r   "_redact_bot_model_picker_reactionsr  )r   r  r  rC  r   r  r  	reacts_tor   r  choicer|  countr|  model_prompt	selectionr  r  confirmations                      r'   r  zMatrixAdapter._on_reaction  s     WUHb1122'' 	Fwuj"5566##H-- 	FgeY3344%D11 a	 gt,,8NB///WlB77 
 IC*d++ :&NN:r::	 nnUB//Z00 :
J C CDD	'*eR8899KK9   488CCF #fo #fn,,F..v66 ==gyRXYYYYYYYYYF!AAY
         F488== >>!N        
 FeGGGGGG44V5GPPE 
S*.7;;ItLLL8<<V=OQUVVV3!6#5vv   #AA'6RRRRRRRRR  e e eLL!^`cdddddddde>BB9MML #L$9 #l222F..|<< AA'9VbcccccccccF!AAYn         F(044S99	  >>!R        
 F(,%377	4HHH*3'-)5)G)G=* * $ $ $ $ $ $L AA'<XXXXXXXXX# S"ii	iRRRRRRRRR    LL!RTWXXX))8388!* $               Ca	 a	|# # # #s2   BK) )
L3LLAQ! !
R1+<R,,R1r  c                t    t          |dd           }|d uo#t          j                    t          |          k    S )Nr   )r   r  r  r  )r   r  r   s      r'   r~  z$MatrixAdapter._matrix_prompt_expired  s8    V\488
%N$.*:*:U:=N=N*NNr&   target_event_idprompt_labelc                  K   t          j        dd                                          dv }|sL| j        r	|| j        v s<t                              d|||           |                     ||d           d {V  dS t          |dd           }t          | dd	          }|rD|rB||k    r<t                              d
|||           |                     ||d           d {V  dS d	S )NrQ  rk   >   rE  r  rD  z<Matrix: ignoring %s reaction from unauthorized user %s on %sz6Only an authorized Matrix user can use these controls.Fr   r2  Tz5Matrix: ignoring %s reaction from %s; requester is %sz?Only the user who requested this action can use these controls.)rU  rV  rZ   r5  r_   r(  r  r   )	r   r   r  r  r  r  rU  	requesterapproval_require_senders	            r'   r  z-MatrixAdapter._validate_matrix_prompt_reactor  sg      I7<<BBDD I
 
	
  	"	'-1G'G'GKKNfo   66H        
 5F$7>>	")$0JD"Q"Q" 
	y 
	Vy5H5HKKGfi   66Q        
 5tr&   rg   c                   K   	 |                      |||           d {V  d S # t          $ r&}t                              d|           Y d }~d S d }~ww xY w)Nr}  z4Matrix: failed to send invalid reaction feedback: %s)r  r^   r_   r`   )r   r   r  rg   r|  s        r'   r  z-MatrixAdapter._send_invalid_reaction_feedback(  s      	V))GTO)DDDDDDDDDDD 	V 	V 	VLLOQTUUUUUUUUU	Vs   $ 
AAA'_MatrixApprovalPrompt'c                   K   d|_         | j                            |d            | j                            |j        d            |                     ||           d {V  |                     ||d           d {V  d S )NTzXThis approval prompt has expired. Run the command again if you still want to approve it.)rp   r0  r  r1  r   r  r  r   r   r  r  s       r'   r  z,MatrixAdapter._expire_matrix_approval_prompt3  s       '++OTBBB(,,V-?FFF11'6BBBBBBBBB22f
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
r&   '_MatrixModelPickerPrompt'c                   K   d|_         | j                            |d            |                     ||           d {V  |                     ||d           d {V  d S )NTzDThis model picker has expired. Run `/model` again to choose a model.)rp   r4  r  r  r  r  s       r'   r  z0MatrixAdapter._expire_matrix_model_picker_promptC  s       +//FFF55gvFFFFFFFFF22R
 
 	
 	
 	
 	
 	
 	
 	
 	
 	
r&   c                   K   |j                                         D ]8\  }}|                     ||d           t                              d||           9dS )zMRedact the bot's seeded approval reactions, leaving only the user's reaction.zapproval resolvedz0Matrix: scheduled bot reaction redaction %s (%s)N)r   rS  ro  r_   r`   )r   r   r  r  evt_ids        r'   r  z,MatrixAdapter._redact_bot_approval_reactionsR  sl       $7==?? 	\ 	\ME6--gv?RSSSLLKUTZ[[[[	\ 	\r&   c                "  K   |j                                         D ]r\  }}	 |                     ||d           d{V  t                              d||           @# t
          $ r&}t                              d||           Y d}~kd}~ww xY wdS )z/Redact the bot's seeded model picker reactions.zmodel picker resolvedNz.Matrix: redacted model picker reaction %s (%s)z5Matrix: failed to redact model picker reaction %s: %s)r   rS  ri  r_   r`   r^   )r   r   r  r  r  r|  s         r'   r  z0MatrixAdapter._redact_bot_model_picker_reactions\  s       $7==?? 	b 	bME6b))'6;RSSSSSSSSSMuV\]]]] b b bTV[]`aaaaaaaab		b 	bs   9A
B&BBc                    ddl m}  ||j        | j        j                            dd          | j        j                            dd                    S )z-Session-scoped key for text message batching.r   )build_session_keygroup_sessions_per_userTthread_sessions_per_userF)r  r  )gateway.sessionr  r  r  rL  rT  )r   r  r  s      r'   _text_batch_keyzMatrixAdapter._text_batch_keym  so    555555  L$(K$5$9$9)4% % &*[%6%:%:*E& &
 
 
 	
r&   c                   |                      |          }| j                            |          }t          |j        pd          }|||_        || j        |<   nw|j        r$|j        r|j         d|j         n|j        |_        ||_        |j        r>|j                            |j                   |j                            |j                   | j	                            |          }|r(|
                                s|                                 t          j        |                     |                    | j	        |<   dS )z.Buffer a text event and reset the flush timer.rk   Nr  )r  r-  rT  r@  rg   _last_chunk_lenr2  extendr3  r.  r  r  r  r  _flush_text_batch)r   r  r   ra  	chunk_len
prior_tasks         r'   r  z!MatrixAdapter._enqueue_text_event{  sL   ""5))-11#66
(b))	$-E!.3D&s++z 8@Ux}44
4445:  (1H$ ?#**5+;<<<$++E,=>>>377<<
 	 joo// 	 .5.A""3''/
 /
&s+++r&   r   c                ,  K   t          j                    }	 | j                            |          }|rt	          |dd          nd}|| j        k    r| j        }n| j        }t          j        |           d{V  | j        	                    |d          }|s<	 | j
                            |          |u r| j
        	                    |d           dS dS t                              d|t          |j        pd                     |                     |           d{V  | j
                            |          |u r| j
        	                    |d           dS dS # | j
                            |          |u r| j
        	                    |d           w w xY w)z<Wait for the quiet period then dispatch the aggregated text.r  r   Nz*[Matrix] Flushing text batch %s (%d chars)rk   )r  current_taskr-  rT  r   _SPLIT_THRESHOLDr,  r+  r|  r  r.  r_   r(  r@  rg   r  )r   r   r  pendinglast_lendelayr  s          r'   r  zMatrixAdapter._flush_text_batch  s     +--	>044S99GAHOww(91===aH4000<6-&&&&&&&&&.223==E  -11#66,FF.223===== GF KK<EJ$"%%  
 %%e,,,,,,,,,-11#66,FF.223===== GFt-11#66,FF.223==== Gs   B E AE :Fc                T     d fd}t          j         |                       dS )z0Fire-and-forget read receipt with error logging.rP   r   c                    K   	                                 d {V  d S # t          $ r&} t                              d|            Y d } ~ d S d } ~ ww xY w)Nz*Matrix: background read receipt failed: %s)send_read_receiptr^   r_   r`   )r|  rC  r   r   s    r'   _sendz5MatrixAdapter._background_read_receipt.<locals>._send  s      P,,Wh??????????? P P PI3OOOOOOOOOPs   # 
AAANr   )r  ensure_future)r   r   rC  r  s   ``` r'   r  z&MatrixAdapter._background_read_receipt  sT    	P 	P 	P 	P 	P 	P 	P 	P 	eegg&&&&&r&   c                  K   | j         sdS 	 t          |          }t          |          }t          | j         d          r#| j                             |||           d{V  nt          | j         d          r"| j                             ||           d{V  nUt          | j         d          r$| j                             |||           d{V  nt                              d           dS t                              d||           d	S # t          $ r&}t                              d
|           Y d}~dS d}~ww xY w)z*Send a read receipt (m.read) for an event.Fset_fully_read_markerNsend_receiptset_read_markers)fully_read_eventread_receiptz)Matrix: client has no read receipt methodz&Matrix: sent read receipt for %s in %sTzMatrix: read receipt failed: %s)
r  r   r   r  r  r  r  r_   r`   r^   )r   r   rC  r  r  r|  s         r'   r  zMatrixAdapter.send_read_receipt  s     | 	5	'??DH%%Et|%<== l88ueLLLLLLLLLL~66 
l//e<<<<<<<<<<'9:: l33%*!& 4           HIIIuLLA8WUUU4 	 	 	LL:C@@@55555	s   C D /D 
D=D88D=c                :  K   | j         sdS 	 | j                             t          |          t          |          |pd           d{V  t                              d||           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)z/Redact (delete) a message or event from a room.FN)rg  zMatrix: redacted %s in %sTzMatrix: redact error: %s)r  redactr   r   r_   r(  r^   r4  )r   r   rC  rg  r|  s        r'   ri  zMatrixAdapter.redact_message  s       | 	5
	,%%w!!~ &         
 KK3XwGGG4 	 	 	NN5s;;;55555	s   AA* *
B4BBr8   rN   topicrc  Optional[list]presetc                  K   | j         sdS |dk    rEt          j        dd                                          dvrt                              d           dS 	 t          j        t          j        t          j	        d
                    |t          j                  }d |pg D             }| j                             |pd|pd|||	           d{V }t          |          }	| j                            |	           t                              d
|	|pd           |	S # t           $ r&}
t                              d|
           Y d}
~
dS d}
~
ww xY w)zCreate a new Matrix room.Nr9   r  rk   rS  zMMatrix: refusing to create public room without MATRIX_ALLOW_PUBLIC_ROOMS=true)r8   r9   r:   c                ,    g | ]}t          |          S r%   )r   r  s     r'   
<listcomp>z-MatrixAdapter.create_room.<locals>.<listcomp>
  s    :::aq		:::r&   )rN   r  inviteesrP  r  zMatrix: created room %s (%s)unnamedzMatrix: create_room error: %s)r  rU  rV  rZ   r_   r4  r   r;   r<   r=   rT  create_roomrO   r  rB  r(  r^   )r   rN   r  rc  rP  r  preset_enumr  r   room_id_strr|  s              r'   r  zMatrixAdapter.create_room  s      | 	4]""ry1Lb'Q'Q'W'W'Y'Y b
 (
 (

 NNjkkk4	 0 8/6(8(H  c&*233	 
 ;:FLb:::H L44\Tmt!#" 5        G g,,K"";///KK6TEVYWWW 	 	 	NN:C@@@44444	s   CD 
E
$EE
r  c                2  K   | j         sdS 	 | j                             t          |          t          |                     d{V  t                              d||           dS # t          $ r&}t                              d|           Y d}~dS d}~ww xY w)zInvite a user to a room.FNzMatrix: invited %s to %sTzMatrix: invite error: %s)r  invite_userr   r   r_   r(  r^   r4  )r   r   r  r|  s       r'   r  zMatrixAdapter.invite_user  s      | 	5	,**6'??F7OOLLLLLLLLLKK2GWEEE4 	 	 	NN5s;;;55555	s   AA& &
B0BBrR  limitr)  
from_tokenlist[dict[str, Any]]c                <   K    j         sg S t          dt          t          |pd          d                    }	 t	          t
          dd          }t           j         d          rC j                             t          |          |rt          |          nd||           d{V }ntt           j         d	          rC j         
                    t          |          |rt          |          nd||
           d{V }nt                              d           g S t	          |dd          }|*t          |t                    r|                    d          } fd|pg D             S # t           $ r'}t                              d|           g cY d}~S d}~ww xY w)z7Fetch recent Matrix room history using the live client.r@   rR  d   r,   r*   messagesN)r  	directionr  get_messages)r  r  r  z2Matrix: client has no messages/get_messages methodr  c                :    g | ]}                     |          S r%   )_serialize_history_event)r  evtr   s     r'   r  z/MatrixAdapter.fetch_history.<locals>.<listcomp>F  s'    PPP3D11#66PPPr&   zMatrix: fetch history error: %s)r  r  minr)  r   r   r  r  r   r   r  r_   r`   r  r   rT  r^   r4  )r   r   r  r  r  r]  r  r|  s   `       r'   fetch_historyzMatrixAdapter.fetch_history&  s      | 	IAs3u{++S1122	 3ZEEIt|Z00 !%!6!67OO8BLy444'	 "7 " "       ~66 	!%!:!:7OO3=G)J///4'	 "; " "       QRRR	Hgt44E}Hd!;!;} W--PPPP5;BPPPP 	 	 	NN<cBBBIIIIII	s%   C!E* AE* *
F4FFFdict[str, Any]c           
        t          |dd           }|+t          |t                    r|                    di           }t          |t                    s!t	          |d          rt          |          ni }t          t          |dd          p,t          |t                    r|                    dd          nd          t          t          |dd          p,t          |t                    r|                    dd          nd          t          |          t          |                    dd                    t          |                    dd                    dS )	Nr  rS  rC  rk   r  r#  r$  )rC  r  r  r#  r$  )r   r  r   rT  r  rO   r%  )r   r  r  s      r'   r  z&MatrixAdapter._serialize_history_eventK  sH   %D11?z%66?ii	2..G'4(( 	I'.w'@'@Hd7mmmbGz2.. R1;E41H1HPEIIj"---b  x,, P/9%/F/FNEIIh+++B  9??7;;y"5566FB//00
 
 	
r&   r0   r1   r2   r0   state
status_msgc                  K   | j         sdS || j        vrt                              d|           dS 	 t          j        t          j        t          j        d}| j                             ||         |pd           d{V  t          	                    d|           dS # t          $ r&}t          	                    d|           Y d}~dS d}~ww xY w)	zSet the bot's presence status.Fz!Matrix: invalid presence state %rr  N)presencerd  zMatrix: presence set to %sTzMatrix: set_presence failed: %s)r  _VALID_PRESENCE_STATESr_   r4  r   r3   r4   r5   set_presencer`   r^   )r   r  r  presence_mapr|  s        r'   r  zMatrixAdapter.set_presencee  s     | 	5333NN>FFF5	'.(0,8 L
 ,++%e,!)T ,          LL5u===4 	 	 	LL:C@@@55555	s   A)B 
C(C		Cc                  K   | j         r|st          dd          S |                     ||          }	 | j                             t	          |          t
          j        |           d{V }t          dt          |                    S # t          $ r(}t          dt          |                    cY d}~S d}~ww xY w)zDSend a simple message (emote, notice) with optional HTML formatting.FzNo client or empty textr  )r#  NTr  )	r  rI   r  r  r   r   r!   rO   r^   )r   r   rg   r#  r  rC  r|  s          r'   _send_simple_messagez"MatrixAdapter._send_simple_message  s       | 	N4 	Ne3LMMMM66tW6MM	=!\<<w&       H
 ds8}}EEEE 	= 	= 	=e3s88<<<<<<<<<	=s   AB 
B>B93B>9B>c                x   | dS t          | |d          }|rt          |          S t          | t                    r~|                     |          rt          | |                   S |                     d          }t          |t                    r*|                    |          rt          ||                   S t          | dd          }t          |t                    r*|                    |          rt          ||                   S |.t          ||d          rt          t          ||                    S dS )z@Extract a simple value from a Matrix state event object or dict.Nr  )r   rO   r  r   rT  )r  r   r   r  s       r'   _state_event_valuez MatrixAdapter._state_event_value  s+    =4sD)) 	u::eT"" 	)yy~~ '5:&ii	**G'4(( )W[[-=-= )73<(((%D11gt$$ 	%S)9)9 	%ws|$$$77C#>#>ww,,---tr&   Optional[int]c                  K   | j         rt          | j         dd           nd }|r>	 |                    |           d {V }|t          |          S n# t          $ r Y nw xY wt          | dd           }|bt          |d          rR	 |                    |           d {V }t          |dd           t          |j                  S n# t          $ r Y nw xY wd S )Nr{  r  joined_membersmembers)r  r   get_membersr@  r^   r  r  r  )r   r   r{  r  rW  r\  s         r'   _get_room_member_countz$MatrixAdapter._get_room_member_count  s6      ;?,PGDL-666D 	  	 + 7 7 @ @@@@@@@&w<<' '    y$//'&2B"C"C#227;;;;;;;;4D11=t|,,, >    ts#   +A 
AA?C 
CCc                H  K   | j         rt          | j         d          sd S 	 | j                             t          |          d           d {V }n# t          $ r Y d S w xY w|                     |d          }|r(|                                r|                                nd S )Nget_state_eventr   rN   r  r  r  r   r^   r  r   r   r   r  r   s       r'   _get_room_namezMatrixAdapter._get_room_name  s      | 	74<9J#K#K 	4	,66w       EE  	 	 	44	''v66 %A%++--Au{{}}}TA   .A 
AAc                H  K   | j         rt          | j         d          sd S 	 | j                             t          |          d           d {V }n# t          $ r Y d S w xY w|                     |d          }|r(|                                r|                                nd S )Nr  zm.room.canonical_aliasaliasr  r  s       r'   _get_room_canonical_aliasz'MatrixAdapter._get_room_canonical_alias  s      | 	74<9J#K#K 	4	,66w(       EE  	 	 	44	''w77 %A%++--Au{{}}}TAr  c                H  K   | j         rt          | j         d          sd S 	 | j                             t          |          d           d {V }n# t          $ r Y d S w xY w|                     |d          }|r(|                                r|                                nd S )Nr  zm.room.topicr  r  r  s       r'   _get_room_topiczMatrixAdapter._get_room_topic  s      | 	74<9J#K#K 	4	,66w       EE  	 	 	44	''w77 %A%++--Au{{}}}TAr  c                r    d| vrd S |                      dd          d                                         }|pd S )Nr  r@   rL  )ra  r   )r   servers     r'   _room_server_namezMatrixAdapter._room_server_name  s@    g4Q''+1133~r&   r  r   c                <   t          | j                  | j        k    rYt          | j        | j        j        d           }|r6| j                            |d            | j                            |d            || j        |<   t          j                    | j        |<   d S )N)r   r  )	r@  r  r  r  r  rT  r  r  r  )r   r   r  oldests       r'   _cache_room_identityz"MatrixAdapter._cache_room_identity  s    t$%%)FFF-15  F
  @%))&$777-11&$???)1g&151A1A%g...r&   )force_refreshr  c                 K   | j                             |          }| j                            |d          }| j        dk    pt	          j                    |z
  | j        k    }||r|s|S |                     |           d{V }|                     |           d{V }|                     |           d{V }| 	                    |           d{V }	t          |          }
t          | j                            |d                    }|	dur|	dk    p|o|
 }t          |o|
o	|	du p|	dk              }|rdnd}|p|p|}t          |||||                     |          |	|||
||          }|                     ||           |S )	zResolve Matrix room identity without member-count DM heuristics.

        Matrix ``m.direct`` account data is the authoritative DM signal, but
        explicitly named rooms win over stale/conflicting DM account data.
        r  r   NFrj   r  r  )r   r   r   r   r   r   r   r   r   r   r   )r  rT  r  r  r  r  r  r  r  r  r   r  r   r  r  )r   r   r  cached	cached_atcache_freshr   r   r   member_countr   rP  is_likely_dmr   r   r   r  s                    r'   r  z$MatrixAdapter._resolve_room_identity  s      &**733155gsCC	+q0 O~)+t/NN 	 +mM--g66666666	//88888888
 $ > >w G GGGGGGG!88AAAAAAAA OO++GU;;<<	 %D0F\Q5F 
/// 	  ;!;%9)9
 

 )4DDf	 >O>w%!+..w77 ,#,%/
 
 
 	!!'8444r&   c                N   K   |                      |           d{V j        dk    S )zCheck if a room is a DM.Nr  )r  r   r  s     r'   r  zMatrixAdapter._is_dm_room@  s4      11'::::::::EMMr&   c                |  K   | j         sdS d}	 | j                             d           d{V }t          |d          r|j        }nt	          |t
                    r|}n2# t          $ r%}t                              d|           Y d}~nd}~ww xY w|dS t                      |
                                D ]9\  }}t	          |t                    r                    d |D                        :fd| j        D             | _        | j                                         | j                                         dS )z5Refresh the DM room cache from m.direct account data.Nm.directr  z/Matrix: get_account_data('m.direct') failed: %sc              3  ^   K   | ](}t          |t                    t          |          V  )d S r   )r  rO   r  s     r'   r  z2MatrixAdapter._refresh_dm_cache.<locals>.<genexpr>Z  s7      "O"OaJq#<N<N"O3q66"O"O"O"O"O"Or&   c                    i | ]}||v S r%   r%   )r  riddm_room_idss     r'   
<dictcomp>z3MatrixAdapter._refresh_dm_cache.<locals>.<dictcomp>\  s     RRR#{ 2RRRr&   )r  get_account_datar  r  r  r   r^   r_   r`   r  rS  r  r  r  r  r  r  r  )r   dm_datar\  r|  r  r  r  s         @r'   r  zMatrixAdapter._refresh_dm_cacheD  sy     | 	F"&	Q66zBBBBBBBBDtY'' ,D$''  	Q 	Q 	QLLJCPPPPPPPP	Q ?F #%mmoo 	P 	PNGU%&& P"""O"O5"O"O"OOOORRRRt?QRRR##%%%%++-----s   AA   
B*B

Bc                  K   | j         sdS i }	 | j                             d           d{V }t          |d          r"t          |j        t
                    r|j        }nt          |t
                    r|}n# t          $ r Y nw xY w|                    |g           }t          |t                    sg }||vr|	                    |           |||<   	 | j         
                    d|           d{V  t                              d||           n2# t          $ r%}t                              d|           Y d}~nd}~ww xY wd| j        |<   | j                            |d           | j                            |d           dS )a  Persist a room as DM in m.direct account data after an invite.

        When the bot account has never been used for DMs, ``m.direct`` is
        absent (404).  This method fetches the current mapping (if any),
        appends *room_id* under the *inviter*'s entry, and writes it back
        so that subsequent ``_refresh_dm_cache`` calls treat the room as a
        DM without requiring manual ``m.direct`` setup.
        Nr  r  z+Matrix: recorded %s as DM room (inviter=%s)z%Matrix: failed to update m.direct: %sT)r  r  r  r  r  r   r^   rT  r  r\   set_account_datar_   r(  r4  r  r  r  r  )r   r   rS  r	  r\  rooms_for_userr|  s          r'   r]  zMatrixAdapter._record_dm_room`  s      | 	F#%	66zBBBBBBBBDtY'' Jt|T,J,J ,D$''  	 	 	D	 !Wb11.$// 	 N.((!!'***-GGMl33JHHHHHHHHHA7G     M M MFLLLLLLLLM #'w!!'4000%))'488888s*   A)A9 9
BB=D 
ED==Er"  c                2   ||d}|                      |          }| j        o|                     |          }|rd|i|d<   |rd|                    di           d<   |                     |          }|                     |          }|r||k    r
d|d<   ||d<   |S )	zBBuild Matrix text content with HTML and outbound mention metadata.r#  r$  r  r%  Tr  r'  r(  r&  )_extract_outbound_mentionsr  _has_outbound_room_mention
setdefault_inject_outbound_mention_links_markdown_to_html)r   rg   r#  r  r  room_mentionedhtml_sourcer  s           r'   r  z)MatrixAdapter._build_text_message_content  s    294&H&H::4@@2\t7V7VW[7\7\ 	G)35E(FK% 	D?CK""<44V<99$??%%k22 	1DDLL$<K!,0K()r&   r  r  c                   t          |pi                     d          pd          }|r	dd|ii|d<   |rF|                    di           }d|d<   ||d<   d|d	<   |                    dd|p|i           ||d<   d
S d
S )zCApply Matrix reply/thread relation metadata to an outbound payload.r  rk   r  rC  r+  r  r*  Tis_falling_backN)rO   rT  r  )r   r  r  r  r  r  s         r'   r  z&MatrixAdapter._apply_relation_metadata  s     R,,[99?R@@	 	T+:Z<R*SK' 	5$<<J%/Jz"%.Jz",0J() !!X23   +5K'''	5 	5r&   	list[str]c                   |                      |          \  }}t                      }g }t                              |          D ]E}|                    d          }||vr*|                    |           |                    |           F|S )z9Return unique Matrix user IDs mentioned in outbound text.r@   )!_protect_outbound_mention_regionsr  _OUTBOUND_MENTION_REfinditerro   rB  r\   )r   rg   	protectedrS   seenmentionsrn   r  s           r'   r  z(MatrixAdapter._extract_outbound_mentions  s    ==dCC	1 )229== 	) 	)Ekk!nnGd""!!!(((r&   c                v    |                      |          \  }}t          t          j        d|                    S )zFReturn True when outbound text contains @room outside protected spans.z(?<![\w/])@room(?![\w:.-]))r  r   r   r  )r   rg   r  rS   s       r'   r  z(MatrixAdapter._has_outbound_room_mention  s4    ==dCC	1BI;YGGHHHr&   c                    |s|S |                      |          \  }}t                              d |          }t          |          D ]\  }}|                    d| d|          } |S )zCWrap outbound Matrix mentions in markdown links outside code spans.c                `    d|                      d           d|                      d           dS )N[r@   z](https://matrix.to/#/r}  ro   )rn   s    r'   <lambda>z>MatrixAdapter._inject_outbound_mention_links.<locals>.<lambda>  s/    Uekk!nnUUEKKPQNNUUU r&    MENTION_PROTECTED )r  r  r   r  r[   )r   rg   r  placeholderslinkedr~  originals          r'   r  z,MatrixAdapter._inject_outbound_mention_links  s     	K"&"H"H"N"N	<%))UU
 

 '|44 	Q 	QMC^^$EC$E$E$ExPPFFr&   tuple[str, list[str]]c                    g dfdt          j        dfd|pd          }t          j        dfd	|          }t          j        d
fd|          }|fS )zEProtect markdown regions where outbound mentions should stay literal.fragmentrO   rP   c                X    t                    }                    |            d| dS )Nr&  r'  r@  r\   )r-  r~  r(  s     r'   _protectzAMatrixAdapter._protect_outbound_mention_regions.<locals>._protect  s5    l##C)))434444r&   z```[\s\S]*?```c                @     |                      d                    S Nr   r$  rn   r0  s    r'   r%  zAMatrixAdapter._protect_outbound_mention_regions.<locals>.<lambda>      ((5;;q>>22 r&   rk   z	`[^`\n]+`c                @     |                      d                    S r2  r$  r3  s    r'   r%  zAMatrixAdapter._protect_outbound_mention_regions.<locals>.<lambda>  r4  r&   z\[[^\]]+\]\([^)]+\)c                @     |                      d                    S r2  r$  r3  s    r'   r%  zAMatrixAdapter._protect_outbound_mention_regions.<locals>.<lambda>  r4  r&   )r-  rO   rP   rO   r  )r   rg   r  r0  r(  s      @@r'   r  z/MatrixAdapter._protect_outbound_mention_regions  s    "$	5 	5 	5 	5 	5 	5
 F2222JB
 
	
 F2222
 
	
 F"2222
 
	 ,&&r&   r&  r  c                   |r| j         r| j         |v rdS |s|sdS | j         r| j         |v rdS | j         rxd| j         v ro| j                             d          d                             d          }|r:t          j        dt          j        |          z   dz   |t          j                  rdS |r| j         rd| j          |v rdS dS )u  Return True if the bot is mentioned in the message.

        Per MSC3952, ``m.mentions.user_ids`` is the authoritative mention
        signal in the Matrix spec.  When the sender's client populates that
        field with the bot's user-id, we trust it — even when the visible
        body text does not contain an explicit ``@bot`` string (some clients
        only render mention "pills" in ``formatted_body`` or use display
        names).
        TFr  r   r  \bzmatrix.to/#/)r  r0  lstripr   r  r	   
IGNORECASE)r   r$  r&  r  r  s        r'   r  zMatrixAdapter._is_bot_mentioned  s      	 	$-CS2S2S4 	N 	5= 	T]d224= 	SDM11++C003::3??I RY	),,,u4dBM   t 	dm 	-dm--??tur&   c                   |sdS | j         r|                    | j         d          }| j         rxd| j         v ro| j                             d          d                             d          }|r:t	          j        dt	          j        |          z   dz   d|t          j                  }t	          j        dd	|          }t	          j        d
d|          }|                                S )a  Remove explicit bot mentions from message body.

        Important: only strip explicit mention tokens (``@user:server`` or
        ``@localpart``). Do NOT strip bare words matching the bot localpart,
        otherwise normal phrases like "Hermes Agent" become "Agent".
        rk   r  r   r  z
(?<![\w])@r8  rt  z	[ \t]{2,} z\s+([,.;:!?])\1)	r  r[   r0  r9  r   r   r	   r:  r   )r   r$  r  s      r'   r  zMatrixAdapter._strip_mention  s      	2 = 	3<<r22D = 	SDM11++C003::3??I v!BIi$8$885@-	   vlC..v&t44zz||r&   c                T  K   | j         rt          | j         dd          nd}|rH	 |                    ||           d{V }|rt          |dd          r|j        S n# t          $ r Y nw xY w|                    d          r'd|v r#|dd                             d          d         S |S )z=Get a user's display name in a room, falling back to user_id.r{  Ndisplaynamer  r  r@   r   )r  r   
get_memberr@  r^   rl   r0  )r   r   r  r{  members        r'   r	  zMatrixAdapter._get_display_name4  s       ;?,PGDL-666D 	  	*55gwGGGGGGGG .gfmTBB .!--    c"" 	-sg~~122;$$S))!,,s   5A 
A)(A)r  c                \    |                     d          s|S |dd         }| j         d| S )z6Convert mxc://server/media_id to an HTTP download URL.r&     Nz"/_matrix/client/v1/media/download/)rl   r  )r   r  r  s      r'   r4  zMatrixAdapter._mxc_to_httpE  sA    !!(++ 	N"MMeMMMr&   c                   t          |          }	 ddl}|                    g d          }d|j        v r|j                            d           |                    |          }|                                 |                    d          dk    r*|                    dd                              d	d          }t          |          S # t          $ r Y nw xY wt          |                     |                    S )
u  Convert Markdown to Matrix-compatible HTML (org.matrix.custom.html).

        Uses the ``markdown`` library (a core dependency) when available.
        Falls back to a comprehensive regex converter that handles fenced
        code blocks, inline code, headers, bold, italic, strikethrough,
        links, blockquotes, lists, and horizontal rules — everything the
        Matrix HTML spec allows.
        r   N)fenced_codetablesnl2br
sane_lists
extensions
html_blockz<p>r@   rk   z</p>)r  markdownMarkdownpreprocessors
deregisterconvertresetr  r[   r  r3  _markdown_to_html_fallback)r   rg   _mdmdr  s        r'   r  zMatrixAdapter._markdown_to_htmlL  s    -T22	""""KKK   B r/// ++L999::d##DHHJJJzz%  A%%||E2..66vrBB(... 	 	 	D	 %T%D%DT%J%JKKKs   B9C 
CCc                    |                                  }d|v r@|                    dd          d                                                                          nd}|dv rdS |                    dd          S )z,Sanitize a URL for use in an href attribute.r  r@   r   rk   >   r   vbscript
javascriptr   z&quot;)r   r0  rZ   r[   )r  r   r   s      r'   _sanitize_link_urlz MatrixAdapter._sanitize_link_urln  sv     99;;>AXooQ''*002288:::SU7772X...r&   c           	     X   g d8fdt          j        dfd| t           j                  }t          j        dfd	|          }t          j        d
fd|          }t          j        d|          }t	          |          D ],\  }}|                    d          st          |          ||<   -d                    |          }|                    d          }g }d}|t          |          k     r||         }t          j	        d|          r|
                    d           |dz  }Lt          j	        d|          }	|	rlt          |	                    d                    }
|
                    d|
 d|	                    d                                           d|
 d           |dz  }|                    d          s"|dk    s|                    d          s|dk    r{g }|t          |          k     r7||                             d          s3||         dk    s'||                             d          s||         dk    r||         }|                    d          r|
                    |dd                    nH|                    d          r|
                    |dd                    n|
                    d           |dz  }|t          |          k     rN||                             d          ||         dk    ||                             d          ||         dk    |
                    dd                    |           d            t          j	        d!|          }|rg }|t          |          k     rt          j	        d!||                   rt|
                    t          j	        d!||                                       d                     |dz  }|t          |          k     rt          j	        d!||                   td                    d" |D                       }|
                    d#| d$           vt          j	        d%|          }|rg }|t          |          k     rt          j	        d%||                   rt|
                    t          j	        d%||                                       d                     |dz  }|t          |          k     rt          j	        d%||                   td                    d& |D                       }|
                    d'| d(           k|
                    |           |dz  }|t          |          k     d                    |          }t          j        d)d*|t           j                  }t          j        d+d*|t           j                  }t          j        d,d-|t           j                  }t          j        d.d-|t           j                  }t          j        d/d0|t           j                  }t          j        d1d2|          }t          j        d3d4|          }t          j        d5d6|          }t	                    D ]\  }}|                    d| d7|          } |S )9z0Comprehensive regex Markdown-to-HTML for Matrix.html_fragmentrO   rP   c                X    t                    }                    |            d| dS )N
 PROTECTEDr'  r/  )r[  r~  r(  s     r'   _protect_htmlz?MatrixAdapter._markdown_to_html_fallback.<locals>._protect_html|  s5    l##C...,3,,,,r&   z```(\w*)\n(.*?)```c           
         |                      d          rIdt          |                      d                     dt          |                      d                     dn%dt          |                      d                     d          S )Nr@   z<pre><code class="language-z">rj   z</code></pre>z<pre><code>)ro   r   mr^  s    r'   r%  z:MatrixAdapter._markdown_to_html_fallback.<locals>.<lambda>  s    mm 771::K ;l1771::.F.F ; ;

++; ; ; ; K<

#;#;JJJ	  r&   r<  z`([^`\n]+)`c                b     dt          |                     d                     d          S )Nz<code>r@   z</code>)r   ro   r`  s    r'   r%  z:MatrixAdapter._markdown_to_html_fallback.<locals>.<lambda>  s/    mm$N\!''!**-E-E$N$N$NOO r&   z\[([^\]]+)\]\(([^)]+)\)c           
          d                     t                              |                     d                    t	          |                     d                                        S )Nz<a href="{}">{}</a>rj   r@   )r(  r  rY  ro   r   r`  s    r'   r%  z:MatrixAdapter._markdown_to_html_fallback.<locals>.<lambda>  sV    mm%,,!44QWWQZZ@@ ,,   r&   z(\x00PROTECTED\d+\x00)r]  rk   r  r   z!^[\s]*([-*_])\s*\1\s*\1[\s\-*_]*$z<hr>r@   z^(#{1,6})\s+(.+)$z<hr   rj   z</hz&gt; z&gt;r  r   Nz<blockquote>z<br>z</blockquote>z^[\s]*[-*+]\s+(.+)$c              3  "   K   | ]
}d | dV  dS z<li>z</li>Nr%   r  items     r'   r  z;MatrixAdapter._markdown_to_html_fallback.<locals>.<genexpr>  .      BBD/D///BBBBBBr&   z<ul>z</ul>z^[\s]*\d+[.)]\s+(.+)$c              3  "   K   | ]
}d | dV  dS re  r%   rf  s     r'   r  z;MatrixAdapter._markdown_to_html_fallback.<locals>.<genexpr>  rh  r&   z<ol>z</ol>z\*\*(.+?)\*\*<strong>\1</strong>z	__(.+?)__z	\*(.+?)\*z<em>\1</em>z(?<!\w)_(.+?)_(?!\w)z	~~(.+?)~~z<del>\1</del>z\nz<br>
z0<br>\n(</?(?:pre|blockquote|h[1-6]|ul|ol|li|hr))z\n\1z+(</(?:pre|blockquote|h[1-6]|ul|ol|li)>)<br>r>  r'  )r[  rO   rP   rO   )r   r   DOTALLr0  r  rl   r   r   r@  rn   r\   ro   r   r[   )rg   r  r  r~  partr  	out_linesru   r"  hdrlevelbq_lineslnul_matchrS  r   ol_matchr*  r^  r(  s                     @@r'   rS  z(MatrixAdapter._markdown_to_html_fallbackw  s     	- 	- 	- 	- 	- 	- !    )

 

 

 OOOO
 
 &    	
 	
 2F;;"5)) 	0 	0IC???33 0)$//c
 T""	#e**nn8D x<dCC   (((Q (/66C CIIaLL))  !Oe!O!Ociill.@.@.B.B!O!Ou!O!O!OPPPQ ((6>>??4(( "3;;#e**nn!H''00 %Qx6))Qx**400 *Qx3qB}}W-- , 122////t,, , 122//// +++FA #e**nn!H''00 %Qx6))Qx**400 *Qx3   !TH0E0E!T!T!TUUU x 6==H #e**nn2H%PQ()S)SnLL*@%(!K!K!Q!QRS!T!TUUUFA #e**nn2H%PQ()S)Sn WWBBEBBBBB  !1!1!1!1222 x 8$??H #e**nn2JERSH)U)UnLL*BE!H!M!M!S!STU!V!VWWWFA #e**nn2JERSH)U)Un WWBBEBBBBB  !1!1!1!1222T"""FAC #e**nnF 9%% 4fBI
 
 
 &<fBIVVVnfBINNN#^V29
 
 
 &6biPPPx00?&
 
 FvVV '|44 	I 	IMC^^$=C$=$=$=xHHFFr&   )r  rD   rP   r   )rO  r   rP   rP  )rW  r   rX  rO   rP   r   )rW  r   rb  r   rP   r   )rs  r   rP   r   r   )NN)
r   rO   r  rO   r  rP  r  rM  rP   rI   )r   rO   rP   r  )rP   r  r   )r   rO   r  rM  rP   r   )r   rO   rP   r   )
r   rO   r   rO   r  rO   r   r   rP   rI   )NNN)r   rO   r.  rO   r/  rP  r  rP  r  rM  rP   rI   )r  rO   rP   r<  )r   rO   rp  rO   r/  rP  r  rP  r  rM  rP   rI   )Nr  )
r   rO   r  rv  r  rM  rw  r  rP   r   )NNNN)r   rO   r  rO   r/  rP  r  rP  r  rP  r  rM  rP   rI   )r   rO   r  rO   r/  rP  r  rP  r  rM  rP   rI   )r   rO   r  rO   r/  rP  r  rP  r  rM  rP   rI   )r  N)r   rO   r  rO   r   rO   r  rO   r  r  rP   rI   )r   rO   r  r  r  rO   r  rO   r   rO   r  rM  rP   rI   )r  rO   rP   rO   )NNNF)r   rO   r   rI  r  rO   rD  rO   r#  rO   r/  rP  r  rP  r  rM  r  r   rP   rI   )NNNNF)r   rO   r  rO   r#  rO   r/  rP  r  rP  r  rP  r  rM  r  r   rP   rI   )r  r  rP   r   )r  rO   rP   r   r  )r  r   rP   r   )r   rO   r  rO   rC  rO   r$  rO   r  r   r  r   rP   r  )r   rO   r  rO   rC  rO   r  r  r  r   r  r   rP   r   )r   rO   r  rO   rC  rO   r  r  r  r   r  r   r#  rO   rP   r   )r   rO   rP  r   rS  rO   rP   r   )r   rO   rC  rO   r  rO   rP   rP  )rk   )r   rO   r  rO   rg  rO   rP   r   )r   rO   r  rO   rg  rO   rP   r   )r  rF   rP   r   )r  rF   rs  rH   rP   r   )r  r   rP   r   )r   rO   r  rO   r  rO   r  r   r  rO   rP   r   )r   rO   r  rO   rg   rO   rP   r   )r   rO   r  rO   r  r  rP   r   )r   rO   r  rO   r  r  rP   r   )r   rO   r  r  rP   r   )r   rO   r  r  rP   r   )r  rF   rP   rO   )r   rO   rP   r   )r   rO   rC  rO   rP   r   )r   rO   rC  rO   rP   r   )r   rO   rC  rO   rg  rO   rP   r   )rk   rk   NFr8   )rN   rO   r  rO   rc  r  rP  r   r  rO   rP   rP  )r   rO   r  rO   rP   r   )rR  rk   )r   rO   r  r)  r  rO   rP   r  )r  r   rP   r  )r0   rk   )r  rO   r  rO   rP   r   )r   rO   rg   rO   r#  rO   rP   rI   )r  r   r   rO   rP   rP  )r   rO   rP   r  )r   rO   rP   rP  )r   rO   r  r   rP   r   )r   rO   r  r   rP   r   )r   rO   rS  rO   rP   r   )r"  )rg   rO   r#  rO   rP   r  )r  r  r  rP  r  rM  rP   r   )rg   rO   rP   r  rg   rO   rP   r   rg   rO   rP   rO   )rg   rO   rP   r+  )r$  rO   r&  rP  r  r  rP   r   )r$  rO   rP   rO   )r   rO   r  rO   rP   rO   )r  rO   rP   rO   r  rO   rP   rO   )gr   r   r    r   supports_code_blockssplits_long_messagestyped_command_prefixr  r   rE  r   r  r  rV  ra  rr  r  r  r  r  r  r  r  r-  r6  r7  rt  r  r  r  r  r  r  r  r8  rs  r  r  r  r  r  r  r  r  r  r  r  r  rZ  rT  r  r  rj  ro  rr  ry  r  r~  r  r  r  r  r  r  r  r  r  r  r  ri  r  r  r  r  	frozensetr  r  r  r  r  r  r  r  r  r  r  r  r  r]  r  r  r  r  r  r  r  r  r	  r4  r  rY  rS  r   r   s   @r'   r  r    s
       66
 
 u u u u u un    5 5 5 \5$ 0 0 0 \00    \   <N N N Nh 5: | | | | | ||), ), ), ),^ #'-1>B >B >B >B >B@B B B B-
 -
 -
 -
h BF        PU= = = = = =H "&"&-1'
 '
 '
 '
 '
 '
 '
Rl6 l6 l6 l6d "&"&-1
 
 
 
 
" .2 "c "c "c "c "cP "&#'"&-1
 
 
 
 
$ "&"&-1
 
 
 
 
. "&"&-1
 
 
 
 
$ /#'3 3 3 3 3z .2O O O O Ob   " "&"&-1N= N= N= N= N=j "&"&#'-1&
 &
 &
 &
 &
XK' K' K' K'b   ,- - - -& ") ") ") \")H\ \ \ \O O O O   &K K K KZtG tG tG tGlF1 F1 F1 F1PJ- J- J- J-X(
 (
 (
 (
T   F  O O O O O O<
5 
5 
5 
5    F 	M M M M M 	G G G G G:	O 	O 	O 	O
 
 
 
8l l l l\O O O O( ( ( (T	V 	V 	V 	V
 
 
 
 
 
 
 
\ \ \ \b b b b"
 
 
 

 
 
 
2> > > >8	' 	' 	' 	'   D 	    6 !%$& & & & &P
 
 
 
 	# # # # #J
 
 
 
0 'Y'KLL    6= = = =4    \(   2B B B BB B B BB B B B    \B B B B" $	; ; ; ; ; ;zN N N N. . . .8'9 '9 '9 '9Z    , #'-15 5 5 5 5 52
 
 
 
I I I I
   "' ' ' '< )-+/	    B   <   "N N N NL L L LD / / / \/ M M M \M M M M Mr&   r  F)r  media_filesforce_documentc               D  K   t          | di           pi }t          | dd          }	 ddl}n# t          $ r ddicY S w xY w	 |                    d          pt	          j        dd	                              d
          }	|pt	          j        dd	          }|	r|sddiS dt          t          j                    dz             dt	          j	        d          
                                 }
ddlm}  ||d	          }|	 d| d|
 }d| dd}d|d}	 ddl}|                    |ddg          }t          j        dd|          }d|d <   ||d!<   n# t          $ r Y nw xY w|                    |                    d"#          $          4 d{V }|                    |||%          4 d{V }|j        d&vrM|                                 d{V }dd'|j         d(| icddd          d{V  cddd          d{V  S |                                 d{V }ddd          d{V  n# 1 d{V swxY w Y   ddd          d{V  n# 1 d{V swxY w Y   d)d*||                    d+          d,S # t,          $ r}dd-| icY d}~S d}~ww xY w).ac  Out-of-process Matrix delivery via the Client-Server API.

    Implements the standalone_sender_fn contract so deliver=matrix cron jobs
    succeed when cron runs separately from the gateway. Converts markdown to
    HTML for rich rendering, falling back to plain text when the markdown
    library is absent. Replaces the legacy _send_matrix helper.
    rL  r  Nr   r  z/aiohttp not installed. Run: pip install aiohttpr  r  rk   rY   r  zGMatrix not configured (MATRIX_HOMESERVER, MATRIX_ACCESS_TOKEN required)hermes_r  rS      r   )r   z/_matrix/client/v3/rooms/z/send/m.room.message/zBearer zapplication/json)AuthorizationzContent-Typer"  r  rF  rG  rJ  z<h[1-6]>(.*?)</h[1-6]>rj  r'  r(  r&  rS  rT  r  )r>  json>         zMatrix API error (z): Tr   rC  )r  r  r   r   zMatrix send failed: )r   r.  r3  rT  rU  rV  r  r)  r  urandomhexr{  r   rM  r   r   r/  rc  putrd  rg   r  r^   )pconfigr   r  r  r|  r}  rL  r  r.  r  txn_idr   encoded_roomr  r>  payloadrT  r  r  r\  r$  r   rM  s                          r'   _standalone_sendr    s       GWb))/REGWd++EL L L LJKKKKL5ii--S;NPR1S1S[[\_``
=#8"== 	h 	hfggJ3ty{{T122JJRZ]]5F5F5H5HJJ&&&&&&uW2...aalaaY_aa$5e$5$5GYZZ&88	""""<<]H4M<NND635KTRRD 8GH(,G$%% 	 	 	D	 ((1F1FR1F1P1P(QQ 	) 	) 	) 	) 	) 	) 	)U\{{3g{FF ) ) ) ) ) ) )$;j00!%,,,,,,D#%P$+%P%P$%P%PQ) ) ) ) ) ) ) ) ) ) ) ) )	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	)
 "YY[[((((((	) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	) 	)  X'Y]YaYablYmYmnnn 5 5 533344444445s   - >>AJ A7J =E J 
E!J  E!!3J I32H6%I7J 
H6$I6
I 	 II 	IJ 
I##J &I#'J 
JJJJc            
        ddl } ddl}ddlm}m} ddlm}m}m}m	}m
}m}	  |d            |d          p
 |d          }
|
r |d            |d	d
          sdS  |d            |d            |d            |d          }|r |d|                    d                      |d            |dd          }|r1 |d|            |d          }|r |d|            |d           n? |d          }|r |d|            |dd          }|r |d|            |d           |s |d          r |dd
          }|r |dd            |d           |rdnd }	 dd!lm}m}  |d"          }|rl |d#| d$t!          |           d%           	  |d"d
&            || d'           n0# t"          $ r#} |	d(            |d)|            Y d}~nd}~ww xY wn# t$          $ r 	 t'          d            n# t$          $ r  |d#| d*           ddl}|                     d+          }|r$|                    |d,d-d.|j        |gdd/          }n"|                    |j        d0d,d-|gdd/          }|j        dk    r || d'           n |	d1| d2           Y nw xY wY nw xY w |d3            |d4            |d5          }|r, |d6|                    d7d8                      |d9           n |d:            |d;            |d<            |d=            |d>          }|r |d?|           dS dS dS )@zConfigure Matrix credentials. Replaces hermes_cli/setup.py::_setup_matrix
    and the static _PLATFORMS["matrix"] dict. CLI helpers are lazy-imported.r   N)get_env_valuesave_env_value)r  prompt_yes_noprint_header
print_infoprint_successprint_warningMatrixr  r  zMatrix: already configuredzReconfigure Matrix?FzMWorks with any Matrix homeserver (Synapse, Conduit, Dendrite, or matrix.org).zC   1. Create a bot user on your homeserver, or use your own accountzE   2. Get an access token from Element, or provide user ID + passwordz0Homeserver URL (e.g. https://matrix.example.org)r  rY   zCAuth: provide an access token (recommended), or user ID + password.z-Access token (leave empty for password login)T)r  u9   User ID (@bot:server — optional, will be auto-detected)r  zMatrix access token savedzUser ID (@bot:server)PasswordzMatrix credentials savedz$Enable end-to-end encryption (E2EE)?rR  rD  zE2EE enabledzmautrix[encryption]mautrix)ensurer  r  zInstalling z (+ z runtime deps)...r  z
 installeduk   Install failed — run manually: pip install 'mautrix[encryption]' asyncpg aiosqlite Markdown aiohttp-socksz	  Error: r  uvpipinstallz--python)capture_outputrg   z-mu.   Install failed — run manually: pip install 'z*' asyncpg aiosqlite Markdown aiohttp-socksu,   🔒 Security: Restrict who can use your botz-   Matrix user IDs look like @username:serverz?Allowed user IDs (comma-separated, leave empty for open access)r  r=  rk   zMatrix allowlist configureduE   ⚠️  No allowlist set - anyone who can message the bot can use it!uI   📬 Home Room: where Hermes delivers cron job results and notifications.zE   Room IDs look like !abc123:server (shown in Element room settings)zD   You can also set this later by typing /set-home in a Matrix room.z6Home room ID (leave empty to set later with /set-home)MATRIX_HOME_ROOM)shutilsyshermes_cli.configr  r  hermes_cli.cli_outputr  r  r  r  r  r  r  r  r  r  r@  r^   r3  
__import__
subprocesswhichrun
executable
returncoder[   )r  _sysr  r  r  r  r  r  r  r  ra  r  r  r  r  	want_e2ee
matrix_pkg_lazy_ensurer  _missing_beforer|  r  uv_binr  allowed_users	home_rooms                             r'   interactive_setupr  L  s    MMM????????                L}233W}}EV7W7WH 
/000}2E:: 	FJ^___JTUUUJVWWWJKKJ D*J,=,=c,B,BCCCJTUUUFBTRRRE 6,e444&TUU 	6N+W55512222&011 	6N+W5556*t444 	6N,h777M4555 <:/00 <:!M"H%PP	 	*N.777M.))).7F**Y
%	OOOOOOOO-o.?@@O 
2
```_9M9M```aaa2 L!25AAAA!MZ";";";<<<<  2 2 2!MY   J0300111111112  	 	 	9%%%%   
8888999!!!!d++ 	'^^	:tPZ['+$ ,  FF
 (^^$y*M'+$ ,  F $))!MZ";";";<<<<!MS&S S S  #	2 	
ABBB
BCCC`aa 	`N1=3H3Hb3Q3QRRRM78888J^___
^___
Z[[[
YZZZFSTT	 	:N-y99999y<: <:v	: 	:sa   .4G0 #F? >G0 ?
G,	G'"G0 'G,,G0 0
J7;H
J7B#J1.J70J11J76J7yaml_cfgr   
matrix_cfgdict | Nonec                   d|v rHt          j        d          s4t          |d                                                   t           j        d<   |                    d          }|dt          j        d          sPt          |t                    rd                    d |D                       }t          |          t           j        d<   |                    d          }|dt          j        d	          sPt          |t                    rd                    d
 |D                       }t          |          t           j        d	<   |                    d          }|dt          j        d          sPt          |t                    rd                    d |D                       }t          |          t           j        d<   |                    d          }|dt          j        d          sPt          |t                    rd                    d |D                       }t          |          t           j        d<   d|v rHt          j        d          s4t          |d                                                   t           j        d<   d|v rHt          j        d          s4t          |d                                                   t           j        d<   d|v rHt          j        d          s4t          |d                                                   t           j        d<   d|v rHt          j        d          s4t          |d                                                   t           j        d<   dS )u)  Translate config.yaml matrix: keys into MATRIX_* env vars.

    Implements the apply_yaml_config_fn contract (#24849). Mirrors the legacy
    matrix_cfg block from gateway/config.py::load_gateway_config(). Env vars
    take precedence over YAML. Returns None — everything flows through env.
    rG  rH  r  Nr  r  c              3  4   K   | ]}t          |          V  d S r   rO   r  vs     r'   r  z%_apply_yaml_config.<locals>.<genexpr>  (      --Q#a&&------r&   r  r  c              3  4   K   | ]}t          |          V  d S r   r  r  s     r'   r  z%_apply_yaml_config.<locals>.<genexpr>  s(      //a3q66//////r&   r  r  c              3  4   K   | ]}t          |          V  d S r   r  r  s     r'   r  z%_apply_yaml_config.<locals>.<genexpr>  r  r&   ignore_user_patternsr  c              3  4   K   | ]}t          |          V  d S r   r  r  s     r'   r  z%_apply_yaml_config.<locals>.<genexpr>  s(      &G&G!s1vv&G&G&G&G&G&Gr&   r  r  session_scoper  auto_threadr  dm_mention_threadsr  )	rU  rV  rO   rZ   environrT  r  r  r   )r  r  aufrcarignore_patternss         r'   _apply_yaml_configr    s     J&&ry9Q/R/R&/2:>O3P/Q/Q/W/W/Y/Y
+,		(	(B	~bi(>??~b$ 	.--"-----B-0WW
)*
...
/
/C
ry)EFFc4   	0((//3/////C36s88
/0		(	(B	~bi(>??~b$ 	.--"-----B-0WW
)* nn%;<<O"295R+S+S"ot,, 	H!hh&G&G&G&G&GGGO474H4H
01J&&ry9Q/R/R&/2:>O3P/Q/Q/W/W/Y/Y
+,*$$RY7M-N-N$-0O1L-M-M-S-S-U-U
)*
""295I+J+J"+.z-/H+I+I+O+O+Q+Q
'(z))")<W2X2X)25jAU6V2W2W2]2]2_2_
./4r&   c                   t          | di           pi }ddlm} |                    d          p|                    d          pd}t          | dd          p+|                    d          p|                    d	          pd}t          t          |                                          o t          |                                                    S )
a  Matrix is connected when a homeserver + access token (or password) are
    configured. Read via hermes_cli.gateway.get_env_value so setup-status
    callers that patch get_env_value observe the same value, and PlatformConfig
    extras (homeserver) are honored too. As a built-in, Matrix used the generic
    token check; as a plugin it needs an explicit is_connected so
    _platform_status / get_connected_platforms reflect real configuration
    rather than mere SDK presence. #41112.
    rL  r   Nr  r  rk   r  r  r  )r   hermes_cli.gatewaygatewayrT  r  r   rO   r   )r  rL  gateway_modr  r  s        r'   _is_connectedr    s     FGR((.BE,,,,,,<((`K,E,EFY,Z,Z`^`J&& 	$$%:;;	$$%677	 	 
 J%%''>CJJ,<,<,>,>???r&   c                     t          |           S )zDFactory wrapper that constructs MatrixAdapter from a PlatformConfig.)r  )r  s    r'   _build_adapterr    s       r&   c                    |                      ddt          t          t          ddgdt          t
          dddt          d	d
d           dS )u:   Plugin entry point — called by the Hermes plugin system.r   r  r  r  z!pip install 'mautrix[encryption]'r  MATRIX_ALLOW_ALL_USERSr  r   u   🔐T)rN   labeladapter_factorycheck_fnis_connectedrequired_envinstall_hintsetup_fnapply_yaml_config_fnallowed_users_envallow_all_envcron_deliver_env_varstandalone_sender_fnmax_message_lengthr  allow_update_commandN)register_platformr  r  r  r  r  r  )r  s    r'   registerr    s_    &*")+@A8"/0./-!!      r&   )rN   rO   rP   rQ   rv  )rP   r  ru  )r  r   rP   r  )r&  rQ   rt  )r   r   rP   rO   r   )rL  rM  rP   rO   )r^  rO   rP   r_  )rP   rx  )r~  rO   r^  rO   rP   r   )r  rO   rP   rO   rw  r   )r  r   r  r   rP   r  )nr   
__future__r   r  r  loggingr  rU  r   r  r{  r   r   r   dataclassesr   r   r  r	   r   html.parserr
   pathlibr   typingr   r   r   r   r  r   r   r   r   r   r   r   r   r   r   r3  rO   r   r)   r/   r7   r?   gateway.configrC   rD   r;  rE   rF   rG   rH   rI   rJ   rK   rL   gateway.platforms.helpersrM   	getLoggerr   r_   r8  rk  rm   rf   rq   rs   r   r   r   r  hermes_constantsr   _get_hermes_dirr  rk  r  r  r  r{  r  r  r  r   r  r  r%  r5  r@  rK  rY  r]  rw  r}  r  r  r  r  r  r  r  r  r  r  r  r  r  r%   r&   r'   <module>r     sz  0 0 0d # " " " " "        				 				  6 6 6 6 6 6 6 6 6 6 ( ( ( ( ( ( ( ( ' ' ' ' ' ' " " " " " "       + + + + + + + + + + + +4!                          '! '! '!
 :=<J<<6<I" " " " " " " " I        3$ $ $ $ $ $ $ $
 'M1 1 1 1 1 1 1 1
 -        !JJJO'!R 4 3 3 3 3 3 3 3	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 A @ @ @ @ @		8	$	$$"*.I  0 0 0 0f
0 
0 
0 
0L$ L$ L$ L$ L$: L$ L$ L$^ $         6 6 6 6 6 6 6 6* F F F F F F F F    ? > > > > >_5~FF
{*  !rz=  
" 
 (i ) ) )   "  '( (     "& & & &
1 1 1 12   (2 2 2 2B   .   
3 
3 
3 
3 
3      4   %
 %
 %
 %
P( ( ( (      (P P P Pf( ( ( ( ( ( ( (6~7 ~7 ~7 ~7 ~7' ~7 ~7 ~7hp 35 35 35 35 35lj: j: j: j:Z% % % %P@ @ @ @*! ! !
     s   A0 0ACC