§
    øžyj+Ò  ã                  ól  — 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m	Z	 ddl
mZmZmZmZmZ ddlmZmZ ddlmZ ddlmZmZmZmZ dd	lmZ dd
lmZ d6d„Z ej         e!¦  «        Z"dZ#dddddœZ$ddiZ%dZ&dZ'dZ(d7d„Z)d8d„Z*d9d„Z+ G d„ d e¦  «        Z,ddd!d"œd:d+„Z-d;d-„Z.d<d2„Z/d8d3„Z0d4„ Z1d;d5„Z2dS )=u  Mattermost gateway adapter.

Connects to a self-hosted (or cloud) Mattermost instance via its REST API
(v4) and WebSocket for real-time events.  No external Mattermost library
required â€” uses aiohttp which is already a Hermes dependency.

Environment variables:
    MATTERMOST_URL              Server URL (e.g. https://mm.example.com)
    MATTERMOST_TOKEN            Bot token or personal-access token
    MATTERMOST_ALLOWED_USERS    Comma-separated user IDs
    MATTERMOST_HOME_CHANNEL     Channel ID for cron/notification delivery
é    )ÚannotationsN)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)ÚPlatformÚPlatformConfig)ÚMessageDeduplicator)ÚBasePlatformAdapterÚMessageEventÚMessageTypeÚ
SendResult)ÚUnscopedSecretError)Ú
get_secretc                óz   — 	 t          | |¦  «        }n$# t          $ r t          j        | ¦  «        }Y nw xY w|�|n|S )a¹  Scope-aware credential read with the default-profile startup fallback.

    Secondary profiles construct their adapters under a profile secret
    scope -- the scope is authoritative and a scoped miss returns ``default``
    (no cross-profile borrow from ``os.environ``, which may hold another
    profile's value). The DEFAULT profile's adapter constructs and sends
    *unscoped* under multiplexing, where a bare ``get_secret`` would raise
    ``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
    profile's own value, so fall back to it. Same pattern as the Slack
    ``SLACK_APP_TOKEN`` read (#59739) and
    ``gateway/platforms/whatsapp_common.py::_get_wsecret``.
    )Ú_scoped_get_secretÚ_UnscopedSecretErrorÚosÚgetenv)ÚnameÚdefaultÚvals      úJ/home/ragecks/.hermes/hermes-agent/plugins/platforms/mattermost/adapter.pyÚ_get_scoped_secretr   %   sR   € ðÝ   wÑ/Ô/ˆˆøÝð ð ð ÝŒi˜‰oŒoˆˆˆðøøøà�/ˆ3ˆ3 wÐ.s   ‚ “4³4i   ÚdmÚgroupÚchannel)ÚDÚGÚPÚOÚdisable_mentionsTg       @g      N@gš™™™™™É?ÚpayloadúDict[str, Any]Úreturnc                ó¦   — |                       d¦  «        }t          |t          ¦  «        ri |¥t          ¥| d<   nt          t          ¦  «        | d<   | S )zDReturn a post payload that prevents Mattermost from firing mentions.Úprops)ÚgetÚ
isinstanceÚdictÚ"_MATTERMOST_DISABLE_MENTIONS_PROPS)r%   r)   s     r   Ú_with_mentions_disabledr.   O   sV   € à�KŠK˜Ñ Ô €EÝ�%�ÑÔð DØJ˜eÐJÕ'IÐJˆ�ÑÐåÕ BÑCÔCˆ�ÑØ€Nó    Úboolc                 óf   — 	 ddl } dS # t          $ r t                               d¦  «         Y dS w xY w)zFReturn True if the Mattermost adapter runtime dependency is available.r   NTz!Mattermost: aiohttp not installedF)ÚaiohttpÚImportErrorÚloggerÚwarning)r2   s    r   Úcheck_mattermost_requirementsr6   Y   sJ   € ðØˆˆˆØˆtøÝð ð ð Ý�ŠÐ:Ñ;Ô;Ð;Øˆuˆuðøøøs   ‚ ˆ$0¯0Úconfigr   c                ó„  — t          | di ¦  «        pi }t          | dd¦  «        pt          dd¦  «                             ¦   «         }|                     dd¦  «        pt	          j        dd¦  «                             ¦   «         }|st                               d¦  «         d	S |st                               d
¦  «         d	S dS )z9Return True when Mattermost has enough config to connect.ÚextraÚtokenNÚMATTERMOST_TOKENÚ ÚurlÚMATTERMOST_URLz$Mattermost: MATTERMOST_TOKEN not setFz"Mattermost: MATTERMOST_URL not setT)	Úgetattrr   Ústripr*   r   r   r4   Údebugr5   )r7   r9   r:   r=   s       r   Úvalidate_mattermost_configrB   c   s½   € å�F˜G RÑ(Ô(Ð.¨B€EÝ�V˜W dÑ+Ô+ÐYÕ/AÐBTÐVXÑ/YÔ/Y×`Ò`ÑbÔb€EØ�9Š9�U˜BÑÔÐB¥2¤9Ð-=¸rÑ#BÔ#B×
IÒ
IÑ
KÔ
K€CØð Ý�ŠÐ;Ñ<Ô<Ð<ØˆuØð Ý�ŠÐ;Ñ<Ô<Ð<ØˆuØˆ4r/   c                  óZ  ‡ — e Zd ZdZdZdNˆ fd„ZdOd„ZdPd„ZdQd„ZdRd„Z	dSd„Z
dTd„ZdQd„Z	 dUdVd„Zd d!œdWd#„ZdXd%„ZdYd'„Z	 	 dZd[d+„Zd\d,„Z	 d]d^d-„Zd d.œd_d1„Z	 	 	 d`dad4„Z	 	 	 d`dbd6„Z	 	 	 	 dcddd9„Z	 	 	 d`ded;„Z	 	 	 d`dfd=„Zdgd>„Z	 	 dhdidB„Z	 	 dZdjdC„Z	 	 dkdlˆ fdI„ZdXdJ„ZdXdK„ZdmdM„Z ˆ xZ!S )nÚMattermostAdapterz6Gateway adapter for Mattermost (self-hosted or cloud).Tr7   r   c                óZ  •— t          ¦   «                              |t          j        ¦  «         |j                             dd¦  «        pt          j        dd¦  «                             d¦  «        | _	        |j
        pt          dd¦  «        | _        d| _        d| _        d | _        d | _        d | _        d | _        d| _        |j                             dd¦  «        pt          j        dd	¦  «                             ¦   «         | _        d | _        d| _        t1          ¦   «         | _        d S )
Nr=   r<   r>   ú/r;   FÚ
reply_modeÚMATTERMOST_REPLY_MODEÚoff)ÚsuperÚ__init__r
   Ú
MATTERMOSTr9   r*   r   r   ÚrstripÚ	_base_urlr:   r   Ú_tokenÚ_bot_user_idÚ_bot_usernameÚ_sessionÚ_wsÚ_ws_taskÚ_reconnect_taskÚ_closingÚlowerÚ_reply_modeÚ_last_post_statusÚ_last_post_errorr   Ú_dedup)Úselfr7   Ú	__class__s     €r   rK   zMattermostAdapter.__init__v   s  ø€ Ý‰Œ×Ò˜¥Ô!4Ñ5Ô5Ð5ð ŒL×Ò˜U BÑ'Ô'ð /ÝŒyÐ)¨2Ñ.Ô.ß
Š&�‰+Œ+ð 	Œð "œ<ÐUÕ+=Ð>PÐRTÑ+UÔ+UˆŒà!#ˆÔØ"$ˆÔð "ˆŒØˆŒØ04ˆŒØ7;ˆÔØˆŒð ŒL×Ò˜\¨2Ñ.Ô.ð 9ÝŒyÐ0°%Ñ8Ô8ß
Š%‰'Œ'ð 	Ôð
 15ˆÔØ%'ˆÔõ *Ñ+Ô+ˆŒˆˆr/   r'   úDict[str, str]c                ó   — d| j         › �ddœS )NúBearer úapplication/json©ÚAuthorizationzContent-Type)rO   ©r\   s    r   Ú_headerszMattermostAdapter._headers™   s!   € à4 t¤{Ð4Ð4Ø.ð
ð 
ð 	
r/   ÚpathÚstrr&   c           	   ƒ  óÒ  K  — ddl }d|v rt                               d|¦  «         i S | j        › d|                     d¦  «        › �}	 | j                             ||                      ¦   «         |                     d¬¦  «        ¬	¦  «        4 ƒd{V —†}|j	        d
k    rX| 
                    ¦   «         ƒ d{V —†}t                               d||j	        |dd…         ¦  «         i cddd¦  «        ƒd{V —† S |                     ¦   «         ƒ d{V —†cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS # |j        $ r(}t                               d||¦  «         i cY d}~S d}~ww xY w)zGET /api/v4/{path}.r   Nú..ú!MM API path traversal blocked: %sú/api/v4/rF   é   ©Útotal©ÚheadersÚtimeouté�  u   MM API GET %s â†’ %s: %séÈ   zMM API GET %s network error: %s)r2   r4   ÚerrorrN   ÚlstriprR   r*   re   ÚClientTimeoutÚstatusÚtextÚjsonÚClientError)r\   rf   r2   r=   ÚrespÚbodyÚexcs          r   Ú_api_getzMattermostAdapter._api_getŸ   sQ  è è € àˆˆˆØ�4ˆ<ˆ<Ý�LŠLÐ<¸dÑCÔCÐCØˆIØ”Ð;Ð;¨¯ª°SÑ)9Ô)9Ð;Ð;ˆð		Ø”}×(Ò(¨°d·m²m±o´oÈw×OdÒOdÐkmÐOdÑOnÔOnÐ(ÑoÔoð )ð )ð )ð )ð )ð )ð )ÐswØ”; #Ò%Ð%Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DÝ—L’LÐ!;¸TÀ4Ä;ÐPTÐUYÐVYÐUYÔPZÑ[Ô[Ð[Øð	)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð )ð
 "ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(ð)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ð )ð )øð Ô"ð 	ð 	ð 	Ý�LŠLÐ:¸DÀ#ÑFÔFÐFØˆIˆIˆIˆIˆIˆIøøøøð	øøøsP   ÁA	D4 ÂAD!Ã"D4 Ã5D!ÄD4 Ä!
D+Ä+D4 Ä.D+Ä/D4 Ä4
E&Ä>E!ÅE&Å!E&r%   c           	   ƒ  óD  K  — ddl }d|v rt                               d|¦  «         i S | j        › d|                     d¦  «        › �}d| _        d| _        	 | j                             ||  	                    ¦   «         || 
                    d¬	¦  «        ¬
¦  «        4 ƒd{V —†	 }|j        | _        |j        dk    ra|                     ¦   «         ƒ d{V —†}|pd| _        t                               d||j        |dd…         ¦  «         i cddd¦  «        ƒd{V —† S |                     ¦   «         ƒ d{V —†cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS # |j        $ r<}t          |¦  «        | _        t                               d||¦  «         i cY d}~S d}~ww xY w)z#POST /api/v4/{path} with JSON body.r   Nri   rj   rk   rF   r<   rl   rm   )rp   ry   rq   rr   u   MM API POST %s â†’ %s: %srs   z MM API POST %s network error: %s)r2   r4   rt   rN   ru   rY   rZ   rR   Úpostre   rv   rw   rx   ry   rz   rg   ©r\   rf   r%   r2   r=   r{   r|   r}   s           r   Ú	_api_postzMattermostAdapter._api_post±   s—  è è € ð 	ˆˆˆØ�4ˆ<ˆ<Ý�LŠLÐ<¸dÑCÔCÐCØˆIØ”Ð;Ð;¨¯ª°SÑ)9Ô)9Ð;Ð;ˆØ!%ˆÔØ "ˆÔð	Ø”}×)Ò)Ø˜TŸ]š]™_œ_°7Ø×-Ò-°BÐ-Ñ7Ô7ð *ñ ô ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð Ø)-¬�Ô&Ø”; #Ò%Ð%Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DØ,0¨J°B�DÔ)Ý—L’LÐ!<¸dÀDÄKÐQUÐVZÐWZÐVZÔQ[Ñ\Ô\Ð\Øð
)ð 
)ð 
)ð 
)ñ 
)ô 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð "ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(ð
)ð 
)ð 
)ð 
)ñ 
)ô 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)ð 
)øøøð 
)ð 
)ð 
)ð 
)ð 
)ð 
)øð Ô"ð 	ð 	ð 	Ý$'¨¡H¤HˆDÔ!Ý�LŠLÐ;¸TÀ3ÑGÔGÐGØˆIˆIˆIˆIˆIˆIøøøøð	øøøsP   ÁA
E Â!A&EÄE ÄEÄ3E Å
EÅE ÅEÅE Å
FÅ#1FÆFÆFÚreply_toúOptional[str]ÚmetadataúOptional[Dict[str, Any]]c              ƒ  óþ   K  — | j         dk    rdS |}|s?t          |t          ¦  «        r*|                     d¦  «        p|                     d¦  «        }|sdS |                      t          |¦  «        ¦  «        ƒ d{V —†S )z9Resolve the Mattermost root_id from reply_to or metadata.ÚthreadNÚ	thread_idÚroot_id)rX   r+   r,   r*   Ú_resolve_root_idrg   )r\   rƒ   r…   Ú	candidates       r   Ú_thread_root_for_sendz'MattermostAdapter._thread_root_for_sendÍ   s–   è è € ð Ô˜xÒ'Ð'Ø�4Øˆ	Øð 	M�Z¨µ$Ñ7Ô7ð 	MØ Ÿš [Ñ1Ô1ÐL°X·\²\À)Ñ5LÔ5LˆIØð 	Ø�4Ø×*Ò*­3¨y©>¬>Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:r/   r0   c                óÌ   ‡— | j         dvrdS | j        pd                     ¦   «         Š‰sdS t          ˆfd„dD ¦   «         ¦  «        }t          ˆfd„dD ¦   «         ¦  «        }|o|S )zCReturn True only for clear invalid/missing Mattermost thread roots.>   é”  rr   Fr<   c              3  ó    •K  — | ]}|‰v V — Œ	d S ©N© ©Ú.0Úmarkerr|   s     €r   ú	<genexpr>zMMattermostAdapter._last_post_failure_is_broken_thread_root.<locals>.<genexpr>ã   s'   øè è € ÐfÐf¨�f �nÐfÐfÐfÐfÐfÐfr/   )rŠ   Úrootidzroot idrˆ   r€   c              3  ó    •K  — | ]}|‰v V — Œ	d S r‘   r’   r“   s     €r   r–   zMMattermostAdapter._last_post_failure_is_broken_thread_root.<locals>.<genexpr>ä   s'   øè è € ÐhÐh¨�V˜t�^ÐhÐhÐhÐhÐhÐhr/   )Úinvalidz	not foundzdoes not existÚmissing)rY   rZ   rW   Úany)r\   ÚrootishÚbrokenr|   s      @r   Ú(_last_post_failure_is_broken_thread_rootz:MattermostAdapter._last_post_failure_is_broken_thread_rootÜ   s�   ø€ àÔ!¨Ð3Ð3Ø�5ØÔ%Ð+¨×2Ò2Ñ4Ô4ˆØð 	Ø�5ÝÐfÐfÐfÐfÐ3eÐfÑfÔfÑfÔfˆÝÐhÐhÐhÐhÐ2gÐhÑhÔhÑhÔhˆØÐ!˜6Ð!r/   Úchat_idc              ƒ  ó  K  — |                       d|¦  «        ƒ d{V —†}|sd|vr|S t          |t          ¦  «        r|                     d¦  «        s|S |                      ¦   «         s|S t          |¦  «        }|                     dd¦  «         t          |                     d¦  «        pd¦  «        }d|z                        ¦   «         |d<   t           	                    d|¦  «         |                       d|¦  «        ƒ d{V —†S )	zAPost once, optionally falling back flat for final notify content.ÚpostsNrŠ   ÚnotifyÚmessager<   uK   âš ï¸� Mattermost thread delivery failed; posting final reply in channel.

zNMattermost: falling back to flat channel delivery for notify-worthy post in %s)
r‚   r+   r,   r*   rž   Úpoprg   r@   r4   r5   )r\   rŸ   r%   r…   ÚdataÚflat_payloadÚoriginals          r   Ú_post_preserving_threadz)MattermostAdapter._post_preserving_threadç   s,  è è € ð —^’^ G¨WÑ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5ˆØð 	�9 GÐ+Ð+ØˆKÝ˜8¥TÑ*Ô*ð 	¨x¯|ª|¸HÑ/EÔ/Eð 	ØˆKØ×<Ò<Ñ>Ô>ð 	ØˆKå˜G‘}”}ˆØ×Ò˜ DÑ)Ô)Ð)Ý�|×'Ò'¨	Ñ2Ô2Ð8°bÑ9Ô9ˆà[Øñç
Š%‰'Œ'ð 	�YÑõ 	�ŠØ\Øñ	
ô 	
ð 	
ð —^’^ G¨\Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:r/   c           	   ƒ  ó¬  K  — ddl }d|v rt                               d|¦  «         i S | j        › d|                     d¦  «        › �}	 | j                             ||                      ¦   «         |¬¦  «        4 ƒd{V —†	 }|j        dk    rX| 	                    ¦   «         ƒ d{V —†}t                               d	||j        |dd
…         ¦  «         i cddd¦  «        ƒd{V —† S | 
                    ¦   «         ƒ d{V —†cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS # |j        $ r(}t                               d||¦  «         i cY d}~S d}~ww xY w)z"PUT /api/v4/{path} with JSON body.r   Nri   rj   rk   rF   ©rp   ry   rr   u   MM API PUT %s â†’ %s: %srs   zMM API PUT %s network error: %s)r2   r4   rt   rN   ru   rR   Úputre   rw   rx   ry   rz   r�   s           r   Ú_api_putzMattermostAdapter._api_put  sM  è è € ð 	ˆˆˆØ�4ˆ<ˆ<Ý�LŠLÐ<¸dÑCÔCÐCØˆIØ”Ð;Ð;¨¯ª°SÑ)9Ô)9Ð;Ð;ˆð	Ø”}×(Ò(Ø˜TŸ]š]™_œ_°7ð )ñ ô ð )ð )ð )ð )ð )ð )ð )ð )àØ”; #Ò%Ð%Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�DÝ—L’LÐ!;¸TÀ4Ä;ÐPTÐUYÐVYÐUYÔPZÑ[Ô[Ð[Øð)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð )ð "ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(ð)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ð )ð )øð Ô"ð 	ð 	ð 	Ý�LŠLÐ:¸DÀ#ÑFÔFÐFØˆIˆIˆIˆIˆIˆIøøøøð	øøøsO   Á5D! Á>ADÃD! Ã"DÃ;D! Ä
DÄD! ÄDÄD! Ä!
EÄ+EÅEÅEúapplication/octet-streamÚ
channel_idÚ	file_dataÚbytesÚfilenameÚcontent_typec              ƒ  óÄ  K  — ddl }| j        › d�}|                     ¦   «         }|                     d|¦  «         |                     d|||¬¦  «         dd| j        › �i}| j                             ||||                     d	¬
¦  «        ¬¦  «        4 ƒd{V —†}	|	j        dk    rW|	 	                    ¦   «         ƒ d{V —†}
t                               d|	j        |
dd…         ¦  «         	 ddd¦  «        ƒd{V —† dS |	                     ¦   «         ƒ d{V —†}|                     dg ¦  «        }|r|d         d         ndcddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS )z9Upload a file and return its file ID, or None on failure.r   Nú/api/v4/filesr®   Úfiles)r±   r²   rc   r`   é<   rm   )rp   r¥   rq   rr   u   MM file upload â†’ %s: %srs   Ú
file_infosÚid)r2   rN   ÚFormDataÚ	add_fieldrO   rR   r€   rv   rw   rx   r4   rt   ry   r*   )r\   r®   r¯   r±   r²   r2   r=   Úformrp   r{   r|   r¥   Úinfoss                r   Ú_upload_filezMattermostAdapter._upload_file  sO  è è € ð 	ˆˆˆà”Ð.Ð.Ð.ˆØ×ÒÑ!Ô!ˆØ�Š�| ZÑ0Ô0Ð0Ø�ŠØØØØ%ð	 	ñ 	
ô 	
ð 	
ð #Ð$;¨d¬kÐ$;Ð$;Ð<ˆØ”=×%Ò% c°7ÀÈw×OdÒOdÐkmÐOdÑOnÔOnÐ%ÑoÔoð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ÐswØŒ{˜cÒ!Ð!Ø!ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(�Ý—’Ð8¸$¼+ÀtÈDÈSÈDÄzÑRÔRÐRØð		5ð 	5ð 	5ñ 	5ô 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð
 Ÿš™œÐ$Ð$Ð$Ð$Ð$Ð$ˆDØ—H’H˜\¨2Ñ.Ô.ˆEØ%*Ð4�5˜”8˜D”>�>°ð	5ð 	5ð 	5ð 	5ñ 	5ô 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5ð 	5øøøð 	5ð 	5ð 	5ð 	5ð 	5ð 	5s   ÂAEÃ;AEÅ
EÅEF)Úis_reconnectr¾   c             ƒ  ó°  K  — ddl }| j        r| j        st                               d¦  «         dS |                     |                     d¬¦  «        ¬¦  «        | _        d| _        |  	                    d¦  «        ƒ d{V —†}|rd	|vr;t                               d
¦  «         | j         
                    ¦   «         ƒ d{V —† dS |d	         | _        |                     dd¦  «        | _        t                               d| j        | j        | j        ¦  «         t          j        |                      ¦   «         ¦  «        | _        |                      ¦   «          dS )z7Connect to Mattermost and start the WebSocket listener.r   Nz'Mattermost: URL or token not configuredFrl   rm   ©rq   zusers/mer¸   uP   Mattermost: failed to authenticate â€” check MATTERMOST_TOKEN and MATTERMOST_URLÚusernamer<   z+Mattermost: authenticated as @%s (%s) on %sT)r2   rN   rO   r4   rt   ÚClientSessionrv   rR   rV   r~   ÚcloserP   r*   rQ   ÚinfoÚasyncioÚcreate_taskÚ_ws_looprT   Ú_mark_connected)r\   r¾   r2   Úmes       r   ÚconnectzMattermostAdapter.connect6  se  è è € àˆˆˆàŒ~ð 	 T¤[ð 	Ý�LŠLÐBÑCÔCÐCØ�5à×-Ò-Ø×)Ò)°Ð)Ñ3Ô3ð .ñ 
ô 
ˆŒð ˆŒð —=’= Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,ˆØð 	�T �^�^Ý�LŠLÐkÑlÔlÐlØ”-×%Ò%Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'Ø�5à˜tœHˆÔØŸVšV J°Ñ3Ô3ˆÔÝ�ŠØ9ØÔØÔØŒNñ		
ô 	
ð 	
õ  Ô+¨D¯MªM©O¬OÑ<Ô<ˆŒØ×ÒÑÔÐØˆtr/   ÚNonec              ƒ  óD  K  — d| _         | j        r]| j                             ¦   «         sD| j                             ¦   «          	 | j        ƒ d{V —† n# t          j        t          f$ r Y nw xY w| j        r2| j                             ¦   «         s| j                             ¦   «          | j        r&| j         	                    ¦   «         ƒ d{V —† d| _        | j
        r+| j
        j        s| j
         	                    ¦   «         ƒ d{V —† t                               d¦  «         dS )zDisconnect from Mattermost.TNzMattermost: disconnected)rV   rT   ÚdoneÚcancelrÅ   ÚCancelledErrorÚ	ExceptionrU   rS   rÃ   rR   Úclosedr4   rÄ   rd   s    r   Ú
disconnectzMattermostAdapter.disconnectX  sL  è è € àˆŒàŒ=ð 	 ¤×!3Ò!3Ñ!5Ô!5ð 	ØŒM× Ò Ñ"Ô"Ð"ðØ”mÐ#Ð#Ð#Ð#Ð#Ð#Ð#Ð#øÝÔ*­IÐ6ð ð ð Ø�ðøøøð Ôð 	*¨Ô(<×(AÒ(AÑ(CÔ(Cð 	*ØÔ ×'Ò'Ñ)Ô)Ð)àŒ8ð 	Ø”(—.’.Ñ"Ô"Ð"Ð"Ð"Ð"Ð"Ð"Ð"ØˆDŒHàŒ=ð 	( ¤Ô!5ð 	(Ø”-×%Ò%Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'å�ŠÐ.Ñ/Ô/Ð/Ð/Ð/s   ÁA ÁA+Á*A+Úpost_idc              ƒ  óŒ   K  — |s|S |                       d|› �¦  «        ƒ d{V —†}|r|                     d¦  «        r|d         S |S )a=  Resolve a post_id to the thread root_id for Mattermost.

        Mattermost requires root_id to be the *root* post of a thread.
        If the post is a reply (has its own root_id), we must use that
        root_id instead.  Using a reply's own ID as root_id causes
        "Invalid RootId parameter" errors.
        úposts/NrŠ   )r~   r*   )r\   rÓ   r¥   s      r   r‹   z"MattermostAdapter._resolve_root_idp  sk   è è € ð ð 	ØˆNà—]’]Ð#5¨GÐ#5Ð#5Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6ˆØð 	#�D—H’H˜YÑ'Ô'ð 	#Ø˜	”?Ð"Øˆr/   NÚcontentr   c              ƒ  ó   K  — |st          d¬¦  «        S |                      |¦  «        }|                      |t          ¦  «        }d}|D ]u}t	          ||dœ¦  «        }	|                      ||¦  «        ƒ d{V —†}
|
r|
|	d<   |                      ||	|¦  «        ƒ d{V —†}|rd|vrt          dd¬	¦  «        c S |d         }Œvt          d|¬
¦  «        S )z1Send a message (or multiple chunks) to a channel.T)ÚsuccessN©r®   r£   rŠ   r¸   FzFailed to create post©rØ   rt   ©rØ   Ú
message_id)r   Úformat_messageÚtruncate_messageÚMAX_POST_LENGTHr.   r�   r¨   )r\   rŸ   rÖ   rƒ   r…   Ú	formattedÚchunksÚlast_idÚchunkr%   Úresolved_rootr¥   s               r   ÚsendzMattermostAdapter.send€  s+  è è € ð ð 	,Ý dÐ+Ñ+Ô+Ð+à×'Ò'¨Ñ0Ô0ˆ	Ø×&Ò& yµ/ÑBÔBˆàˆØð 	!ð 	!ˆEÝ&=Ø%Ø ð?ð ?ñ 'ô 'ˆGð
 #'×"<Ò"<¸XÀxÑ"PÔ"PÐPÐPÐPÐPÐPÐPˆMØð 3Ø%2�˜	Ñ"à×5Ò5°g¸wÈÑQÔQÐQÐQÐQÐQÐQÐQˆDØð P˜4 tÐ+Ð+Ý!¨%Ð7NÐOÑOÔOÐOÐOÐOØ˜4”jˆGˆGå $°7Ð;Ñ;Ô;Ð;r/   c              ƒ  ó  K  — |                       d|› �¦  «        ƒ d{V —†}|s|ddœS t                               |                     dd¦  «        d¦  «        }|                     d¦  «        p|                     d¦  «        p|}||dœS )	zReturn channel name and type.z	channels/Nr   )r   Útyperç   r#   Údisplay_namer   )r~   Ú_CHANNEL_TYPE_MAPr*   )r\   rŸ   r¥   Úch_typerè   s        r   Úget_chat_infozMattermostAdapter.get_chat_info   s    è è € à—]’]Ð#8¨wÐ#8Ð#8Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9ˆØð 	8Ø#¨YÐ7Ð7Ð7å#×'Ò'¨¯ª°¸Ñ(=Ô(=¸yÑIÔIˆØ—x’x Ñ/Ô/ÐN°4·8²8¸FÑ3CÔ3CÐNÀwˆØ$¨gÐ6Ð6Ð6r/   c              ƒ  óX   K  — |                       d| j        › d�d|i¦  «        ƒ d{V —† dS )zSend a typing indicator.zusers/z/typingr®   N)r‚   rP   )r\   rŸ   r…   s      r   Úsend_typingzMattermostAdapter.send_typing®  s_   è è € ð �nŠnØ/�TÔ&Ð/Ð/Ð/Ø˜7Ð#ñ
ô 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
r/   )ÚfinalizerÜ   rî   c             ƒ  óê   K  — |                       |¦  «        }|                      d|› d�t          d|i¦  «        ¦  «        ƒ d{V —†}|rd|vrt          dd¬¦  «        S t          d	|d         ¬
¦  «        S )zEdit an existing post.rÕ   z/patchr£   Nr¸   FzFailed to edit postrÚ   TrÛ   )rÝ   r¬   r.   r   )r\   rŸ   rÜ   rÖ   rî   rà   r¥   s          r   Úedit_messagezMattermostAdapter.edit_message·  sª   è è € ð ×'Ò'¨Ñ0Ô0ˆ	Ø—]’]Ø'�ZÐ'Ð'Ð'Ý# Y°	Ð$:Ñ;Ô;ñ
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ˆð ð 	J�t 4Ð'Ð'Ý eÐ3HÐIÑIÔIÐIÝ $°4¸´:Ð>Ñ>Ô>Ð>r/   Ú	image_urlÚcaptionc              ƒ  óF   K  — |                       ||||d|¦  «        ƒ d{V —†S )z5Download an image and upload it as a file attachment.ÚimageN)Ú_send_url_as_file)r\   rŸ   rñ   rò   rƒ   r…   s         r   Ú
send_imagezMattermostAdapter.send_imageÄ  sK   è è € ð ×+Ò+Ø�Y ¨°7¸Hñ
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 	
r/   Ú
image_pathc              ƒ  óF   K  — |                       |||||¬¦  «        ƒ d{V —†S )zUpload a local image file.©r…   N©Ú_send_local_file)r\   rŸ   r÷   rò   rƒ   r…   s         r   Úsend_image_filez!MattermostAdapter.send_image_fileÑ  óN   è è € ð ×*Ò*Ø�Z ¨(¸Xð +ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 	
r/   Ú	file_pathÚ	file_namec              ƒ  óF   K  — |                       ||||||¦  «        ƒ d{V —†S )z"Upload a local file as a document.Nrú   )r\   rŸ   rþ   rò   rÿ   rƒ   r…   s          r   Úsend_documentzMattermostAdapter.send_documentÞ  sK   è è € ð ×*Ò*Ø�Y ¨°9¸hñ
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 	
r/   Ú
audio_pathc              ƒ  óF   K  — |                       |||||¬¦  «        ƒ d{V —†S )zUpload an audio file.rù   Nrú   )r\   rŸ   r  rò   rƒ   r…   s         r   Ú
send_voicezMattermostAdapter.send_voiceì  rý   r/   Ú
video_pathc              ƒ  óF   K  — |                       |||||¬¦  «        ƒ d{V —†S )zUpload a video file.rù   Nrú   )r\   rŸ   r  rò   rƒ   r…   s         r   Ú
send_videozMattermostAdapter.send_videoù  rý   r/   c                ó2   — t          j        dd|¦  «        }|S )u“   Mattermost uses standard Markdown â€” mostly pass through.

        Strip image markdown into plain links (files are uploaded separately).
        z!\[([^\]]*)\]\(([^)]+)\)z\2)ÚreÚsub)r\   rÖ   s     r   rÝ   z MattermostAdapter.format_message  s   € õ ”&Ð4°e¸WÑEÔEˆØˆr/   Úfiler=   Úkindc           	   ƒ  óÒ  K  — ddl m}  ||¦  «        sRt                               d¦  «         |                      ||pd› d|› �                     ¦   «         ||¬¦  «        ƒ d{V —†S ddl}d}	d}
|                     d	d
¦  «        d                              d¦  «        d         p|› d�}t          d¦  «        D �]ÿ}	 | j
                             ||                     d¬¦  «        ¬¦  «        4 ƒd{V —†}|j        dk    s|j        dk    rf|dk     r`t                               d|d
z   |dd…         |j        ¦  «         t          j        d|d
z   z  ¦  «        ƒ d{V —† 	 ddd¦  «        ƒd{V —† Œ·|j        dk    rL|                      ||pd› d|› �                     ¦   «         ||¬¦  «        ƒ d{V —†cddd¦  «        ƒd{V —† c S |                     ¦   «         ƒ d{V —†}	|j        pd}
	 ddd¦  «        ƒd{V —†  n¼# 1 ƒd{V —†swxY w Y   �ŒX# |j        t          j        f$ r�}|dk     r&t          j        d|d
z   z  ¦  «        ƒ d{V —† Y d}~�Œšt                               d||d
z   |¦  «         |                      ||pd› d|› �                     ¦   «         ||¬¦  «        ƒ d{V —†cY d}~c S d}~ww xY w|	€St                               d|¦  «         |                      ||pd› d|› �                     ¦   «         ||¬¦  «        ƒ d{V —†S |                      ||	||
¦  «        ƒ d{V —†}|s8|                      ||pd› d|› �                     ¦   «         ||¬¦  «        ƒ d{V —†S t-          ||pd|gdœ¦  «        }|                      ||¦  «        ƒ d{V —†}|r||d<   |                      |||¦  «        ƒ d{V —†}|rd|vrt3          dd¬ ¦  «        S t3          d!|d         ¬"¦  «        S )#z2Download a URL and upload it as a file attachment.r   ©Úis_safe_urlz0Mattermost: blocked unsafe URL (SSRF protection)r<   Ú
rù   Nr­   rF   é   éÿÿÿÿú?ú.pngé   rl   rm   rÀ   iô  i­  é   z1Mattermost download retry %d/2 for %s (status %d)éP   g      ø?rr   z7Mattermost: failed to download %s after %d attempts: %sz,Mattermost: download returned no data for %s©r®   r£   Úfile_idsrŠ   r¸   FúFailed to post with filerÚ   TrÛ   )Útools.url_safetyr  r4   r5   rå   r@   r2   ÚrsplitÚsplitÚrangerR   r*   rv   rw   rA   rÅ   ÚsleepÚreadr²   rz   ÚTimeoutErrorr½   r.   r�   r¨   r   )r\   rŸ   r=   rò   rƒ   r  r…   r  r2   r¯   ÚctÚfnameÚattemptr{   r}   Úfile_idr%   rä   r¥   s                      r   rõ   z#MattermostAdapter._send_url_as_file  s  è è € ð 	1Ð0Ð0Ð0Ð0Ð0Øˆ{˜3ÑÔð 	lÝ�NŠNÐMÑNÔNÐNØŸš 7¨w¨}¸"Ð,EÐ,EÀÐ,EÐ,E×,KÒ,KÑ,MÔ,MÈxÐbj˜ÑkÔkÐkÐkÐkÐkÐkÐkÐkàˆˆˆàˆ	Ø'ˆØ—
’
˜3 Ñ"Ô" 2Ô&×,Ò,¨SÑ1Ô1°!Ô4ÐE¸4¸¸¸ˆå˜Q‘x”xð 	pñ 	pˆGðpØœ=×,Ò,¨S¸'×:OÒ:OÐVXÐ:OÑ:YÔ:YÐ,ÑZÔZð ð ð ð ð ð ð Ð^bØ”{ cÒ)Ð)¨T¬[¸CÒ-?Ð-?Ø" Qš;˜;Ý"ŸLšLÐ)\Ø)0°1©°c¸#¸2¸#´hÀÄñMô Mð Må")¤-°°wÀ±{Ñ0CÑ"DÔ"DÐDÐDÐDÐDÐDÐDÐDØ$ðð ð ñ ô ð ð ð ð ð ð ð ð ð ”{ cÒ)Ð)Ø%)§Y¢Y¨w¸7¸=ÀbÐ8QÐ8QÈCÐ8QÐ8Q×8WÒ8WÑ8YÔ8YÐ[cÐnv YÑ%wÔ%wÐwÐwÐwÐwÐwÐwðð ð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð '+§i¢i¡k¤kÐ 1Ð 1Ð 1Ð 1Ð 1Ð 1�IØÔ*ÐHÐ.H�BØðð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð øøøð ð ð ð ñ øð Ô'­Ô)=Ð>ð pð pð pØ˜Q’;�;Ý!œ-¨¨w¸©{Ñ(;Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<Ð<Ø�H�H�H‘HÝ—’ÐXÐZ]Ð_fÐijÑ_jÐloÑpÔpÐpØ!ŸYšY w°7°=¸bÐ0IÐ0IÀCÐ0IÐ0I×0OÒ0OÑ0QÔ0QÐS[Ðfn˜YÑoÔoÐoÐoÐoÐoÐoÐoÐoÐoÐoÐoÐoÐoÐoÐoøøøøðpøøøð ÐÝ�NŠNÐIÈ3ÑOÔOÐOØŸš 7¨w¨}¸"Ð,EÐ,EÀÐ,EÐ,E×,KÒ,KÑ,MÔ,MÈxÐbj˜ÑkÔkÐkÐkÐkÐkÐkÐkÐkà×)Ò)¨'°9¸eÀRÑHÔHÐHÐHÐHÐHÐHÐHˆØð 	lØŸš 7¨w¨}¸"Ð,EÐ,EÀÐ,EÐ,E×,KÒ,KÑ,MÔ,MÈxÐbj˜ÑkÔkÐkÐkÐkÐkÐkÐkÐkå"9Ø!Ø�} "Ø ˜	ð;
ð ;
ñ #ô #ˆð
 #×8Ò8¸À8ÑLÔLÐLÐLÐLÐLÐLÐLˆØð 	/Ø!.ˆG�IÑà×1Ò1°'¸7ÀHÑMÔMÐMÐMÐMÐMÐMÐMˆØð 	O�t 4Ð'Ð'Ý eÐ3MÐNÑNÔNÐNÝ $°4¸´:Ð>Ñ>Ô>Ð>sc   Â;6HÃ1A+G<ÅHÅ.AG<Æ0HÇ$G<Ç)HÇ<
H	ÈHÈ	H	È
HÈJ5È%&J0ÉAJ0Ê(J5Ê0J5c              ƒ  óŠ  K  — ddl }t          |¦  «        }|                     ¦   «         s,t                               d|¦  «         t          dd¬¦  «        S |p|j        }	|                     |	¦  «        d         pd}
|                     ¦   «         }|  	                    |||	|
¦  «        ƒ d{V —†}|st          dd¬	¦  «        S t          ||pd
|gdœ¦  «        }|                      ||¦  «        ƒ d{V —†}|r||d<   |                      |||¦  «        ƒ d{V —†}|rd|vrt          dd¬	¦  «        S t          d|d         ¬¦  «        S )z,Upload a local file and attach it to a post.r   Nz.Mattermost: local file not found, skipping: %sTrÛ   r­   FzFile upload failedrÚ   r<   r  rŠ   r¸   r  )Ú	mimetypesr   Úexistsr4   r5   r   r   Ú
guess_typeÚ
read_bytesr½   r.   r�   r¨   )r\   rŸ   rþ   rò   rƒ   rÿ   r…   r'  Úpr#  r"  r¯   r%  r%   rä   r¥   s                   r   rû   z"MattermostAdapter._send_local_fileT  s¨  è è € ð 	ÐÐÐå�‰OŒOˆØ�xŠx‰zŒzð 	=Ý�NŠNØ@À)ñô ð õ  d°tÐ<Ñ<Ô<Ð<àÐ#˜QœVˆØ×!Ò! %Ñ(Ô(¨Ô+ÐIÐ/IˆØ—L’L‘N”Nˆ	à×)Ò)¨'°9¸eÀRÑHÔHÐHÐHÐHÐHÐHÐHˆØð 	IÝ eÐ3GÐHÑHÔHÐHå"9Ø!Ø�} "Ø ˜	ð;
ð ;
ñ #ô #ˆð
 #×8Ò8¸À8ÑLÔLÐLÐLÐLÐLÐLÐLˆØð 	/Ø!.ˆG�IÑà×1Ò1°'¸7ÀHÑMÔMÐMÐMÐMÐMÐMÐMˆØð 	O�t 4Ð'Ð'Ý eÐ3MÐNÑNÔNÐNÝ $°4¸´:Ð>Ñ>Ô>Ð>r/   ç        ÚimagesúList[Tuple[str, str]]Úhuman_delayÚfloatc           
   ƒ  ó²  •‡‡K  — ‰sdS ddl }ddl}ddlm} dŠˆˆfd„t	          dt          ‰¦  «        ‰¦  «        D ¦   «         }t          |¦  «        D �]\  }	}
|dk    r |	dk    rt          j        |¦  «        ƒ d{V —† g }g }	 |
D �]k\  }}|r| 	                    |¦  «         | 
                    d¦  «        rŒ ||dd…         ¦  «        }t          |¦  «        }|                     ¦   «         st                               d|¦  «         Œ„|j        }|                     |¦  «        d         pd	}|                     ¦   «         }�nxdd
lm}  ||¦  «        st                               d¦  «         Œê	 | j                             ||                     d¬¦  «        ¬¦  «        4 ƒd{V —†	 }|j        dk    r=t                               d|j        |dd…         ¦  «         	 ddd¦  «        ƒd{V —† �Œk|                     ¦   «         ƒ d{V —†}|j        pd	}ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   n<# t4          $ r/}t                               d|dd…         |¦  «         Y d}~�Œæd}~ww xY w|                     dd¦  «        d                              d¦  «        d         pdt          |¦  «        › d�}|                      ||||¦  «        ƒ d{V —†}|r| 	                    |¦  «         �Œm|s�Œ¤t=          |d                     |¦  «        |dœ¦  «        }|                       d|¦  «        ƒ d{V —†}|r||d<   t           !                    dt          |¦  «        |	dz   t          |¦  «        ¦  «         |  "                    |||¦  «        ƒ d{V —†}|rd|vrEt                               d¦  «         tG          ¦   «          $                    ||
||¬¦  «        ƒ d{V —† �Œ‘# t4          $ re}t                               d |	dz   t          |¦  «        |d!¬"¦  «         tG          ¦   «          $                    ||
||¬¦  «        ƒ d{V —† Y d}~�Œûd}~ww xY wdS )#a¤  Send a batch of images as a single Mattermost post with multiple attachments.

        Mattermost supports up to 5 ``file_ids`` per post. Each image is
        uploaded individually (Mattermost's file API is one-at-a-time),
        then a single post is created referencing all uploaded file_ids
        at once. Batches larger than 5 are chunked. Falls back to the
        base per-image loop on total failure.
        Nr   )Úunquoteé   c                ó*   •— g | ]}‰||‰z   …         ‘ŒS r’   r’   )r”   ÚiÚCHUNKr-  s     €€r   ú
<listcomp>z:MattermostAdapter.send_multiple_images.<locals>.<listcomp>”  s&   ø€ ÐLÐLÐL¨!�&˜˜1˜u™9˜Ô%ÐLÐLÐLr/   zfile://é   z%Mattermost: skipping missing image %sz	image/pngr  z-Mattermost: blocked unsafe image URL in batchrl   rm   rÀ   rr   z2Mattermost: failed to download image (HTTP %d): %sr  z&Mattermost: download failed for %s: %srF   r  r  r  Úimage_r  r  r  rŠ   z<Mattermost: sending %d image(s) as single post (chunk %d/%d)r¸   z1Mattermost: multi-image post failed, falling back)r/  zCMattermost: multi-image send failed (chunk %d/%d), falling back: %sT)Úexc_info)%r'  r2   Úurllib.parser2  r  ÚlenÚ	enumeraterÅ   r  ÚappendÚ
startswithr   r(  r4   r5   r   r)  r*  r  r  rR   r*   rv   rw   r   r²   rÐ   r  r  r½   r.   Újoinr�   rÄ   r¨   rJ   Úsend_multiple_images)r\   rŸ   r-  r…   r/  r'  r2   Ú_unquoterá   Ú	chunk_idxrã   r  Úcaption_partsrñ   Úalt_textÚ
local_pathr+  r#  r"  r¯   r  r{   Údl_errÚfidr%   rä   r¥   Úer6  r]   s     `                         @€r   rA  z&MattermostAdapter.send_multiple_images}  sP  øøøè è € ð ð 	ØˆFàÐÐÐØˆˆˆØ4Ð4Ð4Ð4Ð4Ð4àˆØLÐLÐLÐLÐL­u°Q½¸F¹¼ÀUÑ/KÔ/KÐLÑLÔLˆå )¨&Ñ 1Ô 1ð F	fñ F	fÑˆI�uØ˜QŠˆ 9¨q¢= =Ý”m KÑ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0à"$ˆHØ')ˆMð@fØ+0ð %-ñ %-Ñ'�I˜xØð 7Ø%×,Ò,¨XÑ6Ô6Ð6à ×+Ò+¨IÑ6Ô6ð kØ%- X¨i¸¸¸¬mÑ%<Ô%<˜
Ý  Ñ,Ô,˜Ø Ÿxšx™zœzð %Ý"ŸNšNÐ+RÐT^Ñ_Ô_Ð_Ø$Ø !¤˜Ø&×1Ò1°%Ñ8Ô8¸Ô;ÐJ¸{˜Ø$%§L¢L¡N¤N˜	™	à@Ð@Ð@Ð@Ð@Ð@Ø*˜{¨9Ñ5Ô5ð %Ý"ŸNšNÐ+ZÑ[Ô[Ð[Ø$ð%Ø'+¤}×'8Ò'8Ø )°7×3HÒ3HÈrÐ3HÑ3RÔ3Rð (9ñ (ô (ð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fà!%Ø#'¤;°#Ò#5Ð#5Ý$*§N¢NØ(\Ø(,¬°Y¸sÀ¸s´^ñ%&ô %&ð %&ð %-ð
Fð 
Fð 
Fñ 
Fô 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fñ 
Fð 37·)²)±+´+Ð,=Ð,=Ð,=Ð,=Ð,=Ð,= 	Ø%)Ô%6Ð%E¸+ ð
Fð 
Fð 
Fñ 
Fô 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Fð 
Føøøð 
Fð 
Fð 
Fð 
Føøõ  )ð %ð %ð %Ý"ŸNšNÐ+SÐU^Ð_bÐ`bÐ_bÔUcÐekÑlÔlÐlØ$˜H˜H˜H™Høøøøð%øøøð !*× 0Ò 0°°aÑ 8Ô 8¸Ô <× BÒ BÀ3Ñ GÔ GÈÔ JÐ jÐNjÕWZÐ[cÑWdÔWdÐNjÐNjÐNj˜à $× 1Ò 1°'¸9ÀeÈRÑ PÔ PÐPÐPÐPÐPÐPÐP�CØð -Ø Ÿš¨Ñ,Ô,Ð,ùàð Ùå*AØ")Ø#Ÿyšy¨Ñ7Ô7Ø (ðCð Cñ +ô +�ð
 '+×&@Ò&@ÀÀxÑ&PÔ&PÐ PÐ PÐ PÐ PÐ PÐ P�Ø ð 7Ø)6�G˜IÑ&Ý—’ØRÝ˜‘M”M 9¨q¡=µ#°f±+´+ñô ð ð "×9Ò9¸'À7ÈHÑUÔUÐUÐUÐUÐUÐUÐU�Øð j˜t¨4Ð/Ð/Ý—N’NÐ#VÑWÔWÐWÝ™'œ'×6Ò6°wÀÀxÐ]hÐ6ÑiÔiÐiÐiÐiÐiÐiÐiÐiùøÝð fð fð fÝ—’ØYØ ‘M¥3 v¡;¤;°¸Dð ñ ô ð õ ‘g”g×2Ò2°7¸EÀ8ÐYdÐ2ÑeÔeÐeÐeÐeÐeÐeÐeÐeÐeÐeÐeÐeÑeøøøøðføøøðCF	fð F	fs‚   ÂC,O%Å26H9Æ)6H'ÇH9Ç0O%Ç2#H'ÈH9È'
H1È1H9È4H1È5H9È8O%È9
I2É$I-É'O%É-I2É2BO%Ë8C+O%Ï%
QÏ/AQÑQc              ƒ  ó  K  — t           }| j        �su	 |                      ¦   «         ƒ d{V —† t           }nç# t          j        $ r Y dS t
          $ rÉ}| j        rY d}~dS ddl}t          |¦  «                             ¦   «         }t          ||j
        ¦  «        r/|j        dv r&t                               d|j        ¦  «         Y d}~dS d|v sd|v sd|v r!t                               d|¦  «         Y d}~dS t                               d	||¦  «         Y d}~nd}~ww xY w| j        rdS ddl}|t           z  |                     ¦   «         z  }t          j        ||z   ¦  «        ƒ d{V —† t%          |d
z  t&          ¦  «        }| j        �¯sdS dS )zHConnect to the WebSocket and listen for events, reconnecting on failure.Nr   >   é‘  é“  u:   Mattermost WS auth failed (HTTP %d) â€” stopping reconnectÚ401Ú403Úunauthorizedu8   Mattermost WS permanent error: %s â€” stopping reconnectu1   Mattermost WS error: %s â€” reconnecting in %.0fsr  )Ú_RECONNECT_BASE_DELAYrV   Ú_ws_connect_and_listenrÅ   rÏ   rÐ   r2   rg   rW   r+   ÚWSServerHandshakeErrorrw   r4   rt   r5   ÚrandomÚ_RECONNECT_JITTERr  ÚminÚ_RECONNECT_MAX_DELAY)r\   Údelayr}   r2   Úerr_strrS  Újitters          r   rÇ   zMattermostAdapter._ws_loopâ  sü  è è € å%ˆØ”-ñ 	9ð`Ø×1Ò1Ñ3Ô3Ð3Ð3Ð3Ð3Ð3Ð3Ð3å-��øÝÔ)ð ð ð Ø��Ýð `ð `ð `Ø”=ð Ø�F�F�F�F�Fð ���Ý˜c™(œ(Ÿ.š.Ñ*Ô*�Ý˜c 7Ô#AÑBÔBð ÀsÄzÐU_ÐG_ÐG_Ý—L’LÐ!]Ð_bÔ_iÑjÔjÐjØ�F�F�F�F�FØ˜GÐ#Ð# u°Ð'7Ð'7¸>ÈWÐ;TÐ;TÝ—L’LÐ![Ð]`ÑaÔaÐaØ�F�F�F�F�FÝ—’ÐRÐTWÐY^Ñ_Ô_Ð_Ð_Ð_Ð_Ð_Ð_øøøøð`øøøð Œ}ð Ø�ð ˆMˆMˆMØÕ.Ñ.°·²±´Ñ@ˆFÝ”- ¨¡Ñ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Ý˜ ™	Õ#7Ñ8Ô8ˆEð; ”-ñ 	9ð 	9ð 	9ð 	9ð 	9s.   “!5 µDÁ	DÁDÁA#DÃ'DÃ3DÄDc              ƒ  ó   K  — t          j        dd| j        ¦  «        dz   }t                               d|¦  «         | j                             |d¬¦  «        ƒ d{V —†| _        dd	d
| j        idœ}| j         	                    |¦  «        ƒ d{V —† t                               d¦  «         | j        2 3 d{V —†}| j
        r dS |j        |j        j        |j        j        hv rS	 t          j        |j        ¦  «        }n# t          j        t$          f$ r Y Œcw xY w|                      |¦  «        ƒ d{V —† Œƒ|j        |j        j        |j        j        |j        j        |j        j        hv r#t                               d|j        ¦  «          dS ŒÜ6 dS )z@Single WebSocket session: connect, authenticate, process events.z^httpÚwsz/api/v4/websocketzMattermost: connecting to %sg      >@)Ú	heartbeatNr  Úauthentication_challenger:   )ÚseqÚactionr¥   z1Mattermost: WebSocket connected and authenticatedz!Mattermost: WebSocket closed (%s))r	  r
  rN   r4   rÄ   rR   Ú
ws_connectrS   rO   Ú	send_jsonrV   rç   ÚTEXTÚBINARYry   Úloadsr¥   ÚJSONDecodeErrorÚ	TypeErrorÚ_handle_ws_eventÚERRORÚCLOSEÚCLOSINGÚCLOSED)r\   Úws_urlÚauth_msgÚraw_msgÚevents        r   rQ  z(MattermostAdapter._ws_connect_and_listen  së  è è € õ ”˜ $¨¬Ñ7Ô7Ð:MÑMˆÝ�ŠÐ2°FÑ;Ô;Ð;àœ×1Ò1°&ÀDÐ1ÑIÔIÐIÐIÐIÐIÐIÐIˆŒð Ø0Ø˜dœkÐ*ð
ð 
ˆð
 Œh× Ò  Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ý�ŠÐGÑHÔHÐHà!œXð 	ð 	ð 	ð 	ð 	ð 	ð 	�'ØŒ}ð Ø��àŒ|Ø”Ô!Ø”Ô#ð ð ð ðÝ œJ w¤|Ñ4Ô4�E�EøÝÔ,­iÐ8ð ð ð Ø�Hðøøøà×+Ò+¨EÑ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ø”Ø”Ô"Ø”Ô"Ø”Ô$Ø”Ô#ð	"ð ð õ —’Ð?ÀÄÑNÔNÐNØ��ðð &˜X˜Xs   Â1FÃ"C<Ã<DÄDro  c           
   ƒ  ó`  ‡,K  — |                      d¦  «        }|dk    rdS |                      di ¦  «        }|                      d¦  «        }|sdS 	 t          j        |¦  «        }n# t          j        t          f$ r Y dS w xY w|                      d¦  «        | j        k    rdS |                      d¦  «        rdS |                      dd	¦  «        }| j                             |¦  «        rdS |                      d
d	¦  «        }|                      dd¦  «        }t                                |d¦  «        }	|                      dd	¦  «        Š,|dk    �rµ| j	        j
        r| j	        j
                              d¦  «        nd}
|
€t          j        dd	¦  «        }
t          |
t          ¦  «        rd„ |
D ¦   «         }n,d„ t          |
¦  «                             d¦  «        D ¦   «         }|r!||vrt"                               d|¦  «         dS t          j        dd¦  «                             ¦   «         dv}t          j        dd	¦  «        }d„ |                     d¦  «        D ¦   «         }||v }d| j        › �d| j        › �g}t+          ˆ,fd„|D ¦   «         ¦  «        }|r!|s|st"                               d|¦  «         dS |rK|D ]H}t-          j        t-          j        |¦  «        d	‰,t,          j        ¬¦  «                             ¦   «         Š,ŒI|                      dd	¦  «        }|                      dd	¦  «                             d¦  «        p|}|                      d ¦  «        pd}|s| j        d!k    r
|dk    r|r|}|                      d"¦  «        pg }t:          j        }‰,dd#…                              ¦   «         r;‰,                     ¦   «                               d$¦  «        r‰,                     ¦   «         Š,‰,                      d$¦  «        rt:          j!        }g }g }|D �]9}	 |  "                    d%|› d&�¦  «        ƒ d{V —†}|                      d'd(|› �¦  «        }tG          |¦  «        j$        pd	}|                      d)d*¦  «        }d+dl%}| j&        › d,|› �} | j'                              | d-d.| j(        › �i| )                    d/¬0¦  «        ¬1¦  «        4 ƒd{V —†	 }!|!j*        d2k     rû|! +                    ¦   «         ƒ d{V —†}"d+d3l,m-}#m.}$ |                      d4¦  «        r9 |#|"|pd5¦  «        }%| /                    |%¦  «         | /                    |¦  «         n¬|                      d6¦  «        r?d+d7l,m0}&  |&|"|pd8¦  «        }%| /                    |%¦  «         | /                    |¦  «         nX |$|"|¦  «        }%| /                    |%¦  «         | /                    |¦  «         n!t"           1                    d9||!j*        ¦  «         ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   �Œ# td          $ r'}'t"           1                    d:||'¦  «         Y d}'~'�Œ3d}'~'ww xY w|rj|t:          j        k    rZt+          d;„ |D ¦   «         ¦  «        rt:          j3        }n4t+          d<„ |D ¦   «         ¦  «        rt:          j4        }n|rt:          j5        }|  6                    ||	||||¬=¦  «        }(d+d>l,m7})  |)| j	        j
        |d¦  «        }*tq          ‰,||(|||r|nd|r|nd|*¬?¦  «        }+|  9                    |+¦  «        ƒ d{V —† dS )@z!Process a single WebSocket event.ro  ÚpostedNr¥   r€   Úuser_idrç   r¸   r<   r®   Úchannel_typer#   r   r£   r    Úallowed_channelsÚMATTERMOST_ALLOWED_CHANNELSc                ó’   — h | ]D}t          |¦  «                             ¦   «         ¯#t          |¦  «                             ¦   «         ’ŒES r’   )rg   r@   ©r”   Úcs     r   ú	<setcomp>z5MattermostAdapter._handle_ws_event.<locals>.<setcomp>^  s9   € Ð#ZÐ#ZÐ#Z°qÍ3ÈqÉ6Ì6Ï<Ê<É>Ì>Ð#Z¥C¨¡F¤F§L¢L¡N¤NÐ#ZÐ#ZÐ#Zr/   c                ó^   — h | ]*}|                      ¦   «         ¯|                      ¦   «         ’Œ+S r’   ©r@   rw  s     r   ry  z5MattermostAdapter._handle_ws_event.<locals>.<setcomp>`  s=   € ð $ð $ð $Ø"#ÀaÇgÂgÁiÄið$Ø—G’G‘I”Ið$ð $ð $r/   Ú,z7Mattermost: ignoring message in non-allowed channel: %sÚMATTERMOST_REQUIRE_MENTIONÚtrue>   Ú0ÚnoÚfalseÚ!MATTERMOST_FREE_RESPONSE_CHANNELSc                ó^   — h | ]*}|                      ¦   «         ¯|                      ¦   «         ’Œ+S r’   r{  )r”   Úchs     r   ry  z5MattermostAdapter._handle_ws_event.<locals>.<setcomp>o  s2   € Ð]Ð]Ð]¨BÐRT×RZÒRZÑR\ÔR\Ð]˜RŸXšX™ZœZÐ]Ð]Ð]r/   ú@c              3  óh   •K  — | ],}|                      ¦   «         ‰                      ¦   «         v V — Œ-d S r‘   )rW   )r”   ÚpatternÚmessage_texts     €r   r–   z5MattermostAdapter._handle_ws_event.<locals>.<genexpr>v  sP   øè è € ð ð àð —’‘” <×#5Ò#5Ñ#7Ô#7Ð7ðð ð ð ð ð r/   zAMattermost: skipping non-DM message without @mention (channel=%s))ÚflagsÚsender_namerŠ   rˆ   r  r  rF   zfiles/z/infor   Úfile_Ú	mime_typer­   r   z/api/v4/files/rc   r`   rl   rm   ro   rr   )Úcache_image_from_bytesÚcache_document_from_bytesúimage/r  úaudio/)Úcache_audio_from_bytesz.oggz/Mattermost: failed to download file %s: HTTP %sz)Mattermost: error downloading file %s: %sc              3  ó@   K  — | ]}|                      d ¦  «        V — ŒdS )r�  N©r?  ©r”   Úms     r   r–   z5MattermostAdapter._handle_ws_event.<locals>.<genexpr>É  s.   è è € Ð?Ð?¨a�1—<’< Ñ)Ô)Ð?Ð?Ð?Ð?Ð?Ð?r/   c              3  ó@   K  — | ]}|                      d ¦  «        V — ŒdS )r�  Nr“  r”  s     r   r–   z5MattermostAdapter._handle_ws_event.<locals>.<genexpr>Ë  s.   è è € ÐAÐA°�Q—\’\ (Ñ+Ô+ÐAÐAÐAÐAÐAÐAr/   )rŸ   Ú	chat_typerr  Ú	user_namer‰   rÜ   )Úresolve_channel_prompt)rx   Úmessage_typeÚsourceÚraw_messagerÜ   Ú
media_urlsÚmedia_typesÚchannel_prompt):r*   ry   rd  re  rf  rP   r[   Úis_duplicateré   r7   r9   r   r   r+   Úlistrg   r  r4   rA   rW   rQ   r›   r	  r
  ÚescapeÚ
IGNORECASEr@   ru   rX   r   rb  Úisspacer?  ÚCOMMANDr~   r   Úsuffixr2   rN   rR   rO   rv   rw   r   Úgateway.platforms.baser�  rŽ  r>  r‘  r5   rÐ   ÚPHOTOÚVOICEÚDOCUMENTÚbuild_sourcer™  r   Úhandle_message)-r\   ro  Ú
event_typer¥   Úraw_post_strr€   rÓ   r®   Úchannel_type_rawr—  Úallowed_rawrt  Úrequire_mentionÚfree_channels_rawÚfree_channelsÚis_free_channelÚmention_patternsÚhas_mentionr‡  Ú	sender_idrŠ  r‰   r  Úmsg_typer�  rž  rH  Ú	file_infor#  ÚextÚmimer2   Údl_urlr{   r¯   r�  rŽ  rF  r‘  r}   r›  r™  Ú_channel_promptÚ	msg_eventrˆ  s-                                               @r   rg  z"MattermostAdapter._handle_ws_event+  sa	  øè è € à—Y’Y˜wÑ'Ô'ˆ
Ø˜Ò!Ð!ØˆFà�yŠy˜ Ñ$Ô$ˆØ—x’x Ñ'Ô'ˆØð 	ØˆFð	Ý”:˜lÑ+Ô+ˆDˆDøÝÔ$¥iÐ0ð 	ð 	ð 	ØˆFˆFð	øøøð �8Š8�IÑÔ $Ô"3Ò3Ð3ØˆFð �8Š8�FÑÔð 	ØˆFà—(’(˜4 Ñ$Ô$ˆð Œ;×#Ò# GÑ,Ô,ð 	ØˆFð —X’X˜l¨BÑ/Ô/ˆ
ØŸ8š8 N°CÑ8Ô8ÐÝ%×)Ò)Ð*:¸IÑFÔFˆ	ð —x’x 	¨2Ñ.Ô.ˆð ˜sÒ"Ñ"ð HLÄ{ÔGXÐb˜$œ+Ô+×/Ò/Ð0BÑCÔCÐCÐ^bˆKØÐ"Ý œiÐ(EÀrÑJÔJ�Ý˜+¥tÑ,Ô,ð Ø#ZÐ#Z¸KÐ#ZÑ#ZÔ#ZÐ Ð ð$ð $Ý'*¨;Ñ'7Ô'7×'=Ò'=¸cÑ'BÔ'Bð$ñ $ô $Ð ð  ð  JÐ6FÐ$FÐ$FÝ—’ØMØñô ð ð �å œiØ,¨fñô çŠe‰gŒgÐ1ð2ˆOõ !#¤	Ð*MÈrÑ RÔ RÐØ]Ð]Ð2C×2IÒ2IÈ#Ñ2NÔ2NÐ]Ñ]Ô]ˆMØ(¨MÐ9ˆOð )�DÔ&Ð(Ð(Ø'�DÔ%Ð'Ð'ð Ðõ ð ð ð ð à/ðñ ô ñ ô ˆKð
 ð  ð ¸{ð Ý—’ØWØñô ð ð �ð ð Ø/ð ð �GÝ#%¤6Ýœ	 'Ñ*Ô*¨B°ÅBÄMð$ñ $ô $ç’e‘g”gð !�Lð
 —H’H˜Y¨Ñ+Ô+ˆ	Ø—h’h˜}¨bÑ1Ô1×8Ò8¸Ñ=Ô=ÐJÀˆð —H’H˜YÑ'Ô'Ð/¨4ˆ	àð	 àÔ  HÒ,Ð,Ø  CÒ'Ð'Øð (ð  ˆIð —8’8˜JÑ'Ô'Ð-¨2ˆÝÔ#ˆØ˜˜˜Ô×#Ò#Ñ%Ô%ð 	1¨,×*=Ò*=Ñ*?Ô*?×*JÒ*JÈ3Ñ*OÔ*Oð 	1Ø'×.Ò.Ñ0Ô0ˆLØ×"Ò" 3Ñ'Ô'ð 	+Ý"Ô*ˆHð !#ˆ
Ø!#ˆØð !	Vñ !	VˆCð VØ"&§-¢-Ð0C¸Ð0CÐ0CÐ0CÑ"DÔ"DÐDÐDÐDÐDÐDÐD�	Ø!Ÿš f¨m°c¨m¨mÑ<Ô<�Ý˜5‘k”kÔ(Ð.¨B�Ø —}’} [Ð2LÑMÔM�à���Ø œNÐ?Ð?¸#Ð?Ð?�Øœ=×,Ò,ØØ,Ð.E¸¼Ð.EÐ.EÐFØ#×1Ò1¸Ð1Ñ;Ô;ð -ñ ô ð lð lð lð lð lð lð lð lð Ø”{ SÒ(Ð(Ø*.¯)ª)©+¬+Ð$5Ð$5Ð$5Ð$5Ð$5Ð$5˜	ØlÐlÐlÐlÐlÐlÐlÐlØŸ?š?¨8Ñ4Ô4ð 5Ø)?Ð)?À	È3È=ÐRXÑ)YÔ)Y˜JØ&×-Ò-¨jÑ9Ô9Ð9Ø'×.Ò.¨tÑ4Ô4Ð4Ð4Ø!Ÿ_š_¨XÑ6Ô6ð 5ØUÐUÐUÐUÐUÐUØ)?Ð)?À	È3È=ÐRXÑ)YÔ)Y˜JØ&×-Ò-¨jÑ9Ô9Ð9Ø'×.Ò.¨tÑ4Ô4Ð4Ð4à)BÐ)BÀ9ÈeÑ)TÔ)T˜JØ&×-Ò-¨jÑ9Ô9Ð9Ø'×.Ò.¨tÑ4Ô4Ð4Ð4åŸšÐ'XÐZ]Ð_cÔ_jÑkÔkÐkð-lð lð lñ lô lð lð lð lð lð lð lð lð lð lð lð lð lð lð lð lð lð lð løøøð lð lð lð lùøõ. ð Vð Vð VÝ—’ÐJÈCÐQTÑUÔUÐUÐUÐUÐUÐUÑUøøøøðVøøøð ð 	0˜8¥{Ô'7Ò7Ð7ÝÐ?Ð?°;Ð?Ñ?Ô?Ñ?Ô?ð 0Ý&Ô,��ÝÐAÐA°[ÐAÑAÔAÑAÔAð 0Ý&Ô,��Øð 0Ý&Ô/�à×"Ò"ØØØØ!ØØð #ñ 
ô 
ˆð 	BÐAÐAÐAÐAÐAØ0Ð0ØŒKÔ˜z¨4ñ
ô 
ˆõ !ØØ!ØØØØ%/Ð9�z�z°TØ'2Ð<˜˜¸Ø*ð	
ñ 	
ô 	
ˆ	ð ×!Ò! )Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ð,sP   ÁA& Á&B Á?B ÐB5XÓD(X	×7XØ	
X	ØXØX	ØXØ
YØ&YÙY)r7   r   )r'   r^   )rf   rg   r'   r&   )rf   rg   r%   r&   r'   r&   )rƒ   r„   r…   r†   r'   r„   ©r'   r0   )rŸ   rg   r%   r&   r…   r†   r'   r&   )r­   )
r®   rg   r¯   r°   r±   rg   r²   rg   r'   r„   )r¾   r0   r'   r0   ©r'   rË   )rÓ   rg   r'   rg   )NN)
rŸ   rg   rÖ   rg   rƒ   r„   r…   r†   r'   r   )rŸ   rg   r'   r&   r‘   )rŸ   rg   r…   r†   r'   rË   )
rŸ   rg   rÜ   rg   rÖ   rg   rî   r0   r'   r   )NNN)rŸ   rg   rñ   rg   rò   r„   rƒ   r„   r…   r†   r'   r   )rŸ   rg   r÷   rg   rò   r„   rƒ   r„   r…   r†   r'   r   )NNNN)rŸ   rg   rþ   rg   rò   r„   rÿ   r„   rƒ   r„   r…   r†   r'   r   )rŸ   rg   r  rg   rò   r„   rƒ   r„   r…   r†   r'   r   )rŸ   rg   r  rg   rò   r„   rƒ   r„   r…   r†   r'   r   )rÖ   rg   r'   rg   )r  N)rŸ   rg   r=   rg   rò   r„   rƒ   r„   r  rg   r…   r†   r'   r   )rŸ   rg   rþ   rg   rò   r„   rƒ   r„   rÿ   r„   r…   r†   r'   r   )Nr,  )
rŸ   rg   r-  r.  r…   r†   r/  r0  r'   rË   )ro  r&   r'   rË   )"Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úsplits_long_messagesrK   re   r~   r‚   r�   rž   r¨   r¬   r½   rÊ   rÒ   r‹   rå   rë   rí   rð   rö   rü   r  r  r  rÝ   rõ   rû   rA  rÇ   rQ  rg  Ú__classcell__)r]   s   @r   rD   rD   q   sL  ø€ € € € € Ø@Ð@àÐð,ð ,ð ,ð ,ð ,ð ,ðF
ð 
ð 
ð 
ðð ð ð ð$ð ð ð ð8;ð ;ð ;ð ;ð	"ð 	"ð 	"ð 	"ð;ð ;ð ;ð ;ð8ð ð ð ð. Uoð5ð 5ð 5ð 5ð 5ð: 5:ð  ð  ð  ð  ð  ð  ðD0ð 0ð 0ð 0ð0ð ð ð ð( #'Ø-1ð<ð <ð <ð <ð <ð@7ð 7ð 7ð 7ð BFð
ð 
ð 
ð 
ð 
ð PUð?ð ?ð ?ð ?ð ?ð ?ð" "&Ø"&Ø-1ð
ð 
ð 
ð 
ð 
ð" "&Ø"&Ø-1ð
ð 
ð 
ð 
ð 
ð" "&Ø#'Ø"&Ø-1ð
ð 
ð 
ð 
ð 
ð$ "&Ø"&Ø-1ð
ð 
ð 
ð 
ð 
ð" "&Ø"&Ø-1ð
ð 
ð 
ð 
ð 
ðð ð ð ð( Ø-1ð>?ð >?ð >?ð >?ð >?ðL $(Ø-1ð'?ð '?ð '?ð '?ð '?ðZ .2Ø ð_fð _fð _fð _fð _fð _fð _fðJ 9ð  9ð  9ð  9ðD%ð %ð %ð %ðN-ð -ð -ð -ð -ð -ð -ð -r/   rD   F)r‰   Úmedia_filesÚforce_documentrŸ   rg   r£   r‰   r„   rÇ  úOptional[list]rÈ  c          
   ƒ  ót  K  — 	 ddl }n# t          $ r ddicY S w xY wt          | di ¦  «        pi                      d¦  «        pt	          j        dd¦  «                             d	¦  «        }t          | d
d¦  «        pt          dd¦  «                             ¦   «         }|r|sddiS d|› �ddœ}	dd|› �i}
|pg }	 ddl	m
}m}  |d¬¦  «        } ||¦  «        \  }} |j        d/d|                     d¬¦  «        i|¤Ž4 ƒd{V —†	 }g }|D �]í}t          |t          ¦  «        r|                     d¦  «        n|}|rt          j                             |¦  «        sŒQ|                     ¦   «         }|                     d|¦  «         t)          |d¦  «        5 }|                     d|                     ¦   «         t          j                             |¦  «        ¬¦  «         ddd¦  «         n# 1 swxY w Y    |j        |› d�f||
dœ|¤Ž4 ƒd{V —†	 }|j        dvrW|                     ¦   «         ƒ d{V —†}dd|j        › d |dd!…         › �icddd¦  «        ƒd{V —† c cddd¦  «        ƒd{V —† S |                     ¦   «         ƒ d{V —†}|                     d"g ¦  «        D ]2}|                     d#¦  «        r|                     |d#         ¦  «         Œ3	 ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   �Œï||d$œ}|r||d%<   |r||d&<    |j        |› d'�f|	|d(œ|¤Ž4 ƒd{V —†	 }|j        dvrU|                     ¦   «         ƒ d{V —†}dd)|j        › d |d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,œcddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS # |j        $ r}dd-|› �icY d}~S d}~wt:          $ r}dd.|› �icY d}~S d}~ww xY w)0uñ  Send via the Mattermost v4 REST API without a live gateway adapter.

    Used by ``tools/send_message_tool._send_via_adapter`` when the gateway
    runner is not in this process (typical for cron jobs running out-of-process).
    Reads ``MATTERMOST_TOKEN`` from ``pconfig.token`` (set by the gateway
    config loader from env) and falls back to the ``MATTERMOST_TOKEN`` env
    var.  Server URL comes from ``pconfig.extra["url"]`` (set by the YAML
    bridge / env loader) or the ``MATTERMOST_URL`` env var.

    Thread replies (Mattermost CRT) are supported via the ``root_id`` field
    on the ``POST /posts`` payload â€” pass ``thread_id`` when threading is
    desired.  ``media_files`` are uploaded via ``POST /files``
    (multipart/form-data), then their returned ``file_id`` values are
    attached to the post.

    ``force_document`` is accepted for signature parity with other
    standalone senders but unused â€” Mattermost stores every uploaded file
    as a generic attachment regardless.
    r   Nrt   z/aiohttp not installed. Run: pip install aiohttpr9   r=   r>   r<   rF   r:   r;   zPMattermost standalone send: MATTERMOST_URL and MATTERMOST_TOKEN must both be setr`   ra   rb   rc   )Úresolve_proxy_urlÚproxy_kwargs_for_aiohttpÚMATTERMOST_PROXY)Úplatform_env_varrq   r¶   rm   rf   r®   Úrbrµ   )r±   r´   )r¥   rp   >   rs   éÉ   zMattermost file upload failed (z): rr   r·   r¸   rÙ   rŠ   r  z/api/v4/postsrª   zMattermost API error (TÚ
mattermost)rØ   ÚplatformrŸ   rÜ   z"Mattermost send failed (network): zMattermost send failed: r’   )r2   r3   r?   r*   r   r   rM   r   r@   r§  rË  rÌ  rÂ   rv   r+   r,   rf   r(  r¹   rº   Úopenr   Úbasenamer€   rw   rx   ry   r>  rz   rÐ   )ÚpconfigrŸ   r£   r‰   rÇ  rÈ  r2   Úbase_urlr:   rp   Úupload_headersrË  rÌ  Ú_proxyÚ_sess_kwÚ_req_kwÚsessionr  Úmediarþ   r»   ÚfhÚupload_respr|   Úupload_datarÄ   r%   r{   r¥   r}   s                                 r   Ú_standalone_sendrà  ô  sö  è è € ð8LØˆˆˆˆøÝð Lð Lð LØÐJÐKÐKÐKÐKðLøøøõ 
�˜' 2Ñ	&Ô	&Ð	,¨"×1Ò1°%Ñ8Ô8ð 	+ÝŒ9Ð% rÑ*Ô*ß‚fˆS�k„kð õ �W˜g tÑ,Ô,ÐZÕ0BÐCUÐWYÑ0ZÔ0Z×aÒaÑcÔc€EØð 
˜5ð 
àð4ð
ð 	
ð + 5Ð*Ð*Ø*ðð €Gð &Ð'8°Ð'8Ð'8Ð9€NàÐ# €KðO;ð 	WÐVÐVÐVÐVÐVÐVÐVØ"Ð"Ð4FÐGÑGÔGˆØ4Ð4°VÑ<Ô<Ñˆ�'à(�7Ô(ð 
ð 
Ø×)Ò)°Ð)Ñ3Ô3ð
àð
ð 
ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð à"$ˆHØ$ð 8ñ 8�Ý1;¸EÅ4Ñ1HÔ1HÐS˜EŸIšI fÑ-Ô-Ð-Èe�	Ø ð ­¬¯ª°yÑ(AÔ(Að ØØ×'Ò'Ñ)Ô)�ð —’˜|¨WÑ5Ô5Ð5Ý˜) TÑ*Ô*ð ¨bØ—N’NØØŸš™	œ	Ý!#¤×!1Ò!1°)Ñ!<Ô!<ð #ñ ô ð ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð (˜7œ<ØÐ.Ð.Ð.ðàØ*ðð ð ð	ð ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð
 !Ø"Ô)°Ð;Ð;Ø%0×%5Ò%5Ñ%7Ô%7Ð7Ð7Ð7Ð7Ð7Ð7˜à#ð!HØ$/Ô$6ð!Hð !HØ;?ÀÀÀ¼:ð!Hð !Hð ð8ð 8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð)D	ð D	ð D	ð D	ñ D	ô D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ðD )4×(8Ò(8Ñ(:Ô(:Ð":Ð":Ð":Ð":Ð":Ð":�KØ +§¢°¸bÑ AÔ Að 8ð 8˜ØŸ8š8 D™>œ>ð 8Ø$ŸOšO¨D°¬JÑ7Ô7Ð7øð8ð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8øøøð 8ð 8ð 8ð 8ùð* &Ø"ð'ð 'ˆGð ð /Ø%.�˜	Ñ"Øð /Ø&.�˜
Ñ#Ø#�w”|ØÐ*Ð*Ð*ðàØðð ð ð	ð ð )ð )ð )ð )ð )ð )ð )ð )ð
 Ø”; jÐ0Ð0Ø!%§¢¡¤Ð,Ð,Ð,Ð,Ð,Ð,�Dàð,°T´[ð ,ð ,Ø# D S Dœzð,ð ,ðð)ð )ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ðaD	ð D	ð D	ð D	ñ D	ô D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð| "ŸYšY™[œ[Ð(Ð(Ð(Ð(Ð(Ð(�ð)ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ð   Ø(Ø"Ø"Ÿhšh t™nœnð	ð ðD	ð D	ð D	ð D	ñ D	ô D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	ð D	øøøð D	ð D	ð D	ð D	ð D	ð D	øðJ Ôð Eð Eð EØÐC¸cÐCÐCÐDÐDÐDÐDÐDÐDÐDøøøøÝð ;ð ;ð ;ØÐ9°CÐ9Ð9Ð:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð;øøøsô   „	 ‰™Â:AP ÄBO0ÆAG*ÇO0Ç*G.Ç.O0Ç1G.Ç2O0È:K'É
O0ÉP É1A#K'ËO0Ë'
K1Ë1O0Ë4K1Ë52O0Ì(:N3Í"O0Í4P ÎN3Î!O0Î3
N=	Î=O0Ï N=	ÏO0ÏP Ï0
O:Ï:P Ï=O:Ï>P Ð
P7ÐPÐP7ÐP7Ð&P2Ð,P7Ð2P7rË   c                 ó˜  — ddl m} m}m} ddlm}m}m}m}m	}  |d¦  «          | d¦  «        }|r |d¦  «          |dd¦  «        sd	S  |d
¦  «          |d¦  «          |d¦  «         t          ¦   «           |d¦  «        }	|	r |d|	                     d¦  «        ¦  «          |dd¬¦  «        }
|
sd	S  |d|
¦  «          |d¦  «         t          ¦   «           |d¦  «          |d¦  «          |d¦  «         t          ¦   «           |d¦  «        }|r, |d|                     dd¦  «        ¦  «          |d¦  «         n |d¦  «         t          ¦   «           |d¦  «          |d¦  «          |d¦  «          |d ¦  «                             ¦   «         }|r |d!|¦  «         n |d!¦  «        r |d"¦  «          |d#¦  «         d	S )$a†  Guide the user through Mattermost bot setup.

    Mirrors Discord/Teams' ``interactive_setup`` shape: lazy-imports CLI
    helpers so the plugin's import surface stays small, prompts for the
    server URL + bot token, captures an allowlist, and offers to set a
    home channel.  Replaces the central
    ``hermes_cli/setup.py::_setup_mattermost`` function this migration
    removes.
    r   )Úget_env_valueÚremove_env_valueÚsave_env_value)ÚpromptÚprompt_yes_noÚprint_headerÚ
print_infoÚprint_successÚ
Mattermostr;   zMattermost: already configuredzReconfigure Mattermost?FNz/Works with any self-hosted Mattermost instance.uF      1. In Mattermost: Integrations â†’ Bot Accounts â†’ Add Bot Accountz   2. Copy the bot tokenz3Mattermost server URL (e.g. https://mm.example.com)r>   rF   z	Bot tokenT)ÚpasswordzMattermost token savedu,   ðŸ”’ Security: Restrict who can use your botu6      To find your user ID: click your avatar â†’ Profilez'   or use the API: GET /api/v4/users/mez?Allowed user IDs (comma-separated, leave empty for open access)ÚMATTERMOST_ALLOWED_USERSÚ r<   zMattermost allowlist configureduE   âš ï¸�  No allowlist set - anyone who can message the bot can use it!uL   ðŸ“¬ Home Channel: where Hermes delivers cron job results and notifications.uH      To get a channel ID: click channel name â†’ View Info â†’ copy the IDzK   You can also set this later by typing /set-home in a Mattermost channel.z9Home channel ID (leave empty to set later with /set-home)ÚMATTERMOST_HOME_CHANNELzHome channel cleared.z2   Open config in your editor:  hermes config edit)Úhermes_cli.configrâ  rã  rä  Úhermes_cli.cli_outputrå  ræ  rç  rè  ré  ÚprintrM   Úreplacer@   )râ  rã  rä  rå  ræ  rç  rè  ré  ÚexistingÚmm_urlr:   Úallowed_usersÚhome_channels                r   Úinteractive_setupr÷  �  sÎ  € ð RÐQÐQÐQÐQÐQÐQÐQÐQÐQðð ð ð ð ð ð ð ð ð ð ð ð ð ð €L�ÑÔÐØˆ}Ð/Ñ0Ô0€HØð Øˆ
Ð3Ñ4Ô4Ð4Øˆ}Ð6¸Ñ>Ô>ð 	ØˆFà€JÐ@ÑAÔAÐAØ€JÐWÑXÔXÐXØ€JÐ)Ñ*Ô*Ð*Ý	�G„G€GØˆVÐIÑJÔJ€FØð =ØˆÐ'¨¯ª°sÑ);Ô);Ñ<Ô<Ð<ØˆF�;¨Ð.Ñ.Ô.€EØð ØˆØ€NÐ% uÑ-Ô-Ð-Ø€MÐ*Ñ+Ô+Ð+å	�G„G€GØ€JÐ=Ñ>Ô>Ð>Ø€JÐGÑHÔHÐHØ€JÐ8Ñ9Ô9Ð9Ý	�G„G€GØ�FÐ\Ñ]Ô]€MØð \ØˆÐ1°=×3HÒ3HÈÈbÑ3QÔ3QÑRÔRÐRØˆÐ7Ñ8Ô8Ð8Ð8àˆ
ÐZÑ[Ô[Ð[å	�G„G€GØ€JÐ]Ñ^Ô^Ð^Ø€JÐYÑZÔZÐZØ€JÐ\Ñ]Ô]Ð]Ø�6ÐUÑVÔV×\Ò\Ñ^Ô^€LØð 0ØˆÐ0°,Ñ?Ô?Ð?Ð?àÐÐ5Ñ6Ô6ð 	0ØˆJÐ.Ñ/Ô/Ð/Ø€JÐCÑDÔDÐDÐDÐDr/   Úyaml_cfgr,   Úmattermost_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S )uÒ  Translate ``config.yaml`` ``mattermost:`` keys into env vars.

    Implements the ``apply_yaml_config_fn`` contract (#24836 / #25443).
    Mirrors the legacy ``mattermost_cfg`` block that used to live in
    ``gateway/config.py::load_gateway_config()`` before this migration.

    The MattermostAdapter reads its runtime configuration via
    ``os.getenv()`` for ``MATTERMOST_REQUIRE_MENTION``,
    ``MATTERMOST_FREE_RESPONSE_CHANNELS``, and
    ``MATTERMOST_ALLOWED_CHANNELS``.  Rather than rewrite those call sites
    to read from ``PlatformConfig.extra``, this hook keeps the env-driven
    model and merely owns the YAMLâ†’env translation here, next to the
    adapter that consumes it.

    Env vars take precedence over YAML â€” every assignment is guarded
    by ``not os.getenv(...)`` so an explicit env var survives a config.yaml
    update.  Returns ``None`` because no extras are seeded into
    ``PlatformConfig.extra`` directly (everything flows through env).
    r±  r}  Úfree_response_channelsNr‚  r|  c              3  ó4   K  — | ]}t          |¦  «        V — Œd S r‘   ©rg   ©r”   Úvs     r   r–   z%_apply_yaml_config.<locals>.<genexpr>ß  s(   è è € Ð/Ð/ a�3˜q™6œ6Ð/Ð/Ð/Ð/Ð/Ð/r/   rt  ru  c              3  ó4   K  — | ]}t          |¦  «        V — Œd S r‘   rþ  rÿ  s     r   r–   z%_apply_yaml_config.<locals>.<genexpr>å  s(   è è € Ð-Ð- Q�#˜a™&œ&Ð-Ð-Ð-Ð-Ð-Ð-r/   )	r   r   rg   rW   Úenvironr*   r+   r¡  r@  )rø  rù  ÚfrcÚacs       r   Ú_apply_yaml_configr  Æ  s%  € ð( ˜NÐ*Ð*µ2´9Ð=YÑ3ZÔ3ZÐ*Ý36°~ÐFWÔ7XÑ3YÔ3Y×3_Ò3_Ñ3aÔ3a�Œ
Ð/Ñ0Ø
×
Ò
Ð5Ñ
6Ô
6€CØ
€�rœyÐ)LÑMÔM€Ý�c�4Ñ Ô ð 	0Ø—(’(Ð/Ð/¨3Ð/Ñ/Ô/Ñ/Ô/ˆCÝ:=¸c¹(¼(�Œ
Ð6Ñ7à	×	Ò	Ð.Ñ	/Ô	/€BØ	€~�bœiÐ(EÑFÔF€~Ý�b�$ÑÔð 	.Ø—’Ð-Ð-¨"Ð-Ñ-Ô-Ñ-Ô-ˆBÝ47¸±G´G�Œ
Ð0Ñ1Øˆ4r/   c                óÌ   — ddl m} t          |                     d¦  «        pd                     ¦   «         o(|                     d¦  «        pd                     ¦   «         ¦  «        S )ay  Mattermost is considered connected when BOTH MATTERMOST_TOKEN and
    MATTERMOST_URL are set.

    Looks up via ``hermes_cli.gateway.get_env_value`` at call time (not via
    the plugin's own bound import) so tests that patch
    ``gateway_mod.get_env_value`` can suppress ambient env vars.  Matches
    what the legacy connected-platforms check did before this migration.
    r   Nr;   r<   r>   )Úhermes_cli.gatewayÚgatewayr0   râ  r@   )r7   Úgateway_mods     r   Ú_is_connectedr
  ï  st   € ð -Ð,Ð,Ð,Ð,Ð,ÝØ	×	"Ò	"Ð#5Ñ	6Ô	6Ð	<¸"×CÒCÑEÔEð 	HØ×&Ò&Ð'7Ñ8Ô8Ð>¸B×EÒEÑGÔGñô ð r/   c                ó    — t          | ¦  «        S )zHFactory wrapper that constructs MattermostAdapter from a PlatformConfig.)rD   )r7   s    r   Ú_build_adapterr    s   € å˜VÑ$Ô$Ð$r/   c                ó¦   — |                       ddt          t          t          t          ddgdt
          t          dddt          t          d	d
¬¦  «         dS )u:   Plugin entry point â€” called by the Hermes plugin system.rÑ  rê  r>   r;   zpip install aiohttprì  ÚMATTERMOST_ALLOW_ALL_USERSrî  u   ðŸ’¬T)r   ÚlabelÚadapter_factoryÚcheck_fnÚvalidate_configÚ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_lengthÚemojiÚallow_update_commandN)	Úregister_platformr  r6   rB   r
  r÷  r  rà  rß   )Úctxs    r   Úregisterr!  	  sk   € à×ÒØØÝ&Ý.Ý2Ý"Ø&Ð(:Ð;Ø*õ #õ 0à4Ø2à6õ
 .õ +àØ!ðG ñ $ô $ð $ð $ð $r/   r‘   )r%   r&   r'   r&   r¿  )r7   r   r'   r0   )rŸ   rg   r£   rg   r‰   r„   rÇ  rÉ  rÈ  r0   r'   r&   rÀ  )rø  r,   rù  r,   r'   rú  )3rÄ  Ú
__future__r   rÅ   ry   Úloggingr   r	  Úpathlibr   Útypingr   r   r   r   r	   Úgateway.configr
   r   Úgateway.platforms.helpersr   r§  r   r   r   r   Úagent.secret_scoper   r   r   r   r   Ú	getLoggerrÁ  r4   rß   ré   r-   rP  rV  rT  r.   r6   rB   rD   rà  r÷  r  r
  r  r!  r’   r/   r   ú<module>r*     s“  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø Ð Ð Ð Ð Ð Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3à 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ø 9Ð 9Ð 9Ð 9Ð 9Ð 9ðð ð ð ð ð ð ð ð ð ð ð ð KÐ JÐ JÐ JÐ JÐ JØ ?Ð ?Ð ?Ð ?Ð ?Ð ?ð/ð /ð /ð /ð( 
ˆÔ	˜8Ñ	$Ô	$€ð €ð 
Ø	Ø	Ø	ð	ð Ð ð '9¸$Ð%?Ð "ð Ð ØÐ ØÐ ðð ð ð ðð ð ð ðð ð ð ðy-ð y-ð y-ð y-ð y-Ð+ñ y-ô y-ð y-ðP  $Ø"&Ø ðE;ð E;ð E;ð E;ð E;ð E;ðZ=Eð =Eð =Eð =EðJ!ð !ð !ð !ðRð ð ð ð*%ð %ð %ð
&ð &ð &ð &ð &ð &r/   