+
    kHàjrÖ  ã                   ó(  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIt^ RIt^ RIHt ^ RIHt ^ RIHtHtHt ^ RIHt ^ RIHtHtHtHtHt ^ RIHtHt ^ RIt^ RI H!t!H"t" ^ R	I#H$t$ ^ R
I%H&t&H't'H(t(H)t)H*t*H+t+H,t, ^ RI-H.t.H/t/H0t0 ^ RI1H2t2 ^ RI1H3t3 ^ RI4H5t5 ^ RI6H7t7H8t8 ^ RI9H:t: ^ RI;H<t<H=t=H>t>H?t?H@t@HAtAHBtBHCtCHDtD ^ RIEHFtG ^ RIHHItI ]P”                  ! ]K4      tLR<tMRtNRtORtPRtQRtRR=tSR]/P¨                  3R]/Pª                  3R]/P¬                  33tW]0P°                  R]0P²                  R/tZRR R R! R"R# /t[R>t\R$ R% lt]R& R' lt^R( R) lt_R* R+ lt`R, R- ltaR. R/ ltbR0 R1 ltcR2 R3 ltdR4 R5 lteR6 R7 ltfR8 R9 ltg ! R: R;]&4      thR# )?zÎSignal messenger platform adapter for a signal-cli daemon in HTTP mode (``signal-cli daemon
--http 127.0.0.1:8080``): inbound via SSE, outbound via JSON-RPC 2.0. Requires SIGNAL_HTTP_URL
and SIGNAL_ACCOUNT.N)ÚOrderedDict)Úsuppress)ÚdatetimeÚtimezoneÚUTC)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)ÚquoteÚunquote)ÚPlatformÚPlatformConfig)Út)ÚBasePlatformAdapterÚ
SendResultÚcache_image_from_bytes_asyncÚcache_audio_from_bytes_asyncÚcache_document_from_bytes_asyncÚcache_image_from_urlÚ	utf16_len)ÚMessageEventÚMessageTypeÚProcessingOutcome)Úredact_phone)Úcancel_task©Úmime_for_ext)ÚCONTAINER_TO_EXTÚsniff_container)Úmarkdown_to_signal)	Ú$SIGNAL_BATCH_PACING_NOTICE_THRESHOLDÚSIGNAL_MAX_ATTACHMENTS_PER_MSGÚSIGNAL_RATE_LIMIT_MAX_ATTEMPTSÚSignalRateLimitErrorÚ_extract_retry_after_secondsÚ_format_waitÚ_is_signal_rate_limit_errorÚ_signal_send_timeoutÚget_scheduler)Úget_scoped_secret)ÚTRUTHY_STRINGSi@  ç       @ç      N@ç      >@g      ^@zaudio/zimage/zvideo/u   âœ…u   â�ŒÚdownloadc                 ó
   € R W3# )z'Signal: failed to download image %s: %s© ©ÚurlÚdetails   &&ÚE/home/ubuntu/.hermes/hermes-agent/plugins/platforms/signal/adapter.pyÚ<lambda>r8   =   s   € Ð%NÐPSÑ$\ó    Úmissingc                 ó
   € R V 3# )z#Signal: image file not found for %sr3   r4   s   &&r7   r8   r8   >   s
   € Ð$IÈ3Ñ#Or9   Úoversizec                 ó
   € R W3# )z/Signal: image too large (%d bytes), skipping %sr3   r4   s   &&r7   r8   r8   ?   s   € Ð%VÐX^Ñ$dr9   c                óF   € V ^8„  d   QhR\         R\        \         ,          /# ©é   ÚvalueÚreturn©ÚstrÚlist)Úformats   "r7   Ú__annotate__rG   D   s   € ÷ >ñ >œSð >¤T¬#¥Yñ >r9   c                ó˜   € V P                  R4       Uu. uF*  qP                  4       '       g   K  VP                  4       NK,  	  up# u upi )zASplit a comma-separated string into a list, stripping whitespace.Ú,)ÚsplitÚstrip)rA   Úvs   & r7   Ú_parse_comma_listrM   D   s3   € à$Ÿ{™{¨3Ô/Ó=Ñ/˜!·7±7·9ŒIˆA�G‰GŽIÑ/Ñ=Ð=ùÒ=s
   ”A°Ac                ó0   € V ^8„  d   QhR\         R\        /# )r@   ÚdatarB   )ÚbytesrD   )rF   s   "r7   rG   rG   I   s   € ÷ 
3ñ 
3œ5ð 
3¤Sñ 
3r9   c                ó  € \          F   w  rV P                  V4      '       g   K  Vu # 	  \        V 4      ^8¼  d   V R,          R8X  d   V R,          R8X  d   R# \        V 4      ;pe   \        V,          # V R,          R8X  d   R# R	# )
z³Guess file extension from magic bytes. WEBP is claimed before the shared audio/AV sniffer
(it shares RIFF with WAVE); tools/audio_container.py owns MP3-vs-ADTS-AAC disambiguation.:Né   Ns   RIFF:é   é   Ns   WEBPú.webp:Nr@   Ns   PKz.zipz.bin)Ú_MAGIC_EXTENSIONSÚ
startswithÚlenr!   r    )rO   ÚmagicÚextÚ	containers   &   r7   Ú_guess_extensionr\   I   s{   € ÷ (‰
ˆØ�?‰?˜5×!Ô!ØŠJñ (ô ˆ4ƒy�B„˜4 �8 wÔ.°4¸µ:ÀÔ3HÙÜ$ TÓ*Ð*ˆ	Ò7Ü 	Õ*Ð*Ø˜"•X Ô&ˆ6Ð2¨FÐ2r9   c                ó0   € V ^8„  d   QhR\         R\        /# ©r@   rZ   rB   ©rD   Úbool)rF   s   "r7   rG   rG   V   s   € ÷ Eñ E”sð Eœtñ Er9   c                 ó(   € V P                  4       R9   # )ú.jpg>   ú.gifrb   ú.pngú.jpegrU   ©Úlower©rZ   s   &r7   Ú_is_image_extri   V   s   € Ø�9‰9‹;ÐDÑDÐDr9   c                ó0   € V ^8„  d   QhR\         R\        /# r^   r_   )rF   s   "r7   rG   rG   Z   s   € ÷ Cñ C”sð Cœtñ Cr9   c                 ó(   € V P                  4       R9   # )ú.mp3>   ú.aacú.m4arl   ú.oggú.wavrf   rh   s   &r7   Ú_is_audio_extrq   Z   s   € Ø�9‰9‹;ÐBÑBÐBr9   c                ó0   € V ^8„  d   QhR\         R\         /# r^   ©rD   )rF   s   "r7   rG   rG   ^   s   € ÷ Bñ B”cð Bœcñ Br9   c                ó   € \        V RR7      # )zOMap file extension to MIME type (shared table matches Signal's historical map).zapplication/octet-stream)Úfallbackr   rh   s   &r7   Ú_ext_to_mimerv   ^   s   € ä˜Ð&@ÔAÐAr9   c                óh   € V ^8„  d   QhR\         R\        \        \         \        3,          ,          /# )r@   Úaac_datarB   )rP   r   ÚtuplerD   )rF   s   "r7   rG   rG   c   s(   € ÷ !ñ !¤ð !¬(´5¼Ä¸Õ3DÕ*Eñ !r9   c                ód  € \         P                  ! R4      ;'       g    \        R R 4       R4      pV'       g   \        P	                  R4       R#  \
        P                  ! RRR7      ;_uu_ 4       pVP                  V 4       VP                  pRRR4       XRR R,           p \        P                  ! VR	R
RRVRRRRV.\        P                  R^
RR7      pVP                  ^ 8w  d†   \        P                  RVP                  VP                  P                  RR4      R,          4        W43 F9  p\!        \"        4      ;_uu_ 4        \$        P&                  ! V4       RRR4       K;  	  R# \)        VR4      ;_uu_ 4       pVP+                  4       R3uuRRR4       W43 F9  p\!        \"        4      ;_uu_ 4        \$        P&                  ! V4       RRR4       K;  	  #   + '       g   i     ELY; i  + '       g   i     KÕ  ; i  + '       g   i     Kw  ; i  + '       g   i     M; i Y43 FM  p\!        \"        4      ;_uu_ 4        \$        P&                  ! T4       RRR4       K;    + '       g   i     KL  ; i	  R#   Y43 FM  p\!        \"        4      ;_uu_ 4        \$        P&                  ! T4       RRR4       K;    + '       g   i     KL  ; i	  i ; i  \        P,                   d    \        P                  R4        R# \.         d    \        P1                  R4        R# i ; i)z»Losslessly remux raw ADTS AAC (Android voice notes, rejected by most STT APIs) to .m4a.
Returns ``(m4a_bytes, ".m4a")``, or ``None`` when ffmpeg is missing/fails (caller keeps the input).Úffmpegc              3   óÎ   "  € T F[  p\         P                  P                  V4      '       g   K*  \         P                  ! V\         P                  4      '       g   KW  Vx € K]  	  R # 5i©N)ÚosÚpathÚisfileÚaccessÚX_OK)Ú.0Úps   & r7   Ú	<genexpr>Ú$_remux_aac_to_m4a.<locals>.<genexpr>h   s@   é € ð 	9ÑIˆqÜ�G‰G�N‰N˜1×ô 
Ü"$§)¢)¨A¬r¯w©w×"7÷ 
ŠÓIùs   ‚'A%®(A%Á
A%Nu2   Signal: ffmpeg not found, skipping AACâ†’M4A remuxrm   F)ÚsuffixÚdeletern   z-yz	-loglevelÚerrorz-iz-c:aÚcopyz	-movflagsz
+faststartT)ÚstdinÚcapture_outputÚtimeoutÚchecku3   Signal: AACâ†’M4A remux failed (ffmpeg exit %d): %szutf-8Úreplace:Ni,  NÚrbu(   Signal: AACâ†’M4A remux timed out (>10s)u   Signal: AACâ†’M4A remux error)z/opt/homebrew/bin/ffmpegz/usr/local/bin/ffmpegéüÿÿÿ)ÚshutilÚwhichÚnextÚloggerÚdebugÚtempfileÚNamedTemporaryFileÚwriteÚnameÚ
subprocessÚrunÚDEVNULLÚ
returncodeÚwarningÚstderrÚdecoder   ÚOSErrorr~   ÚunlinkÚopenÚreadÚTimeoutExpiredÚ	ExceptionÚ	exception)rx   r{   ÚsrcÚsrc_pathÚdst_pathÚprocr„   Úfs   &       r7   Ú_remux_aac_to_m4ar®   c   sq  € ô �\Š\˜(Ó#÷ @ð @¤tñ	9ÑIó 	9Ø:>ó(@€F÷ Ü�‰ÐIÔJÙðÜ×(Ò(°¸u×EÕEÈØ�I‰I�hÔØ—x‘xˆH÷ Fð ˜C˜R�= 6Õ)ˆð	!Ü—>’> 6¨4°¸gÀtÈXÐW]Ð_eÐgrØ#/°ð#;ÜBL×BTÑBTÐeiÐsuð  ~CôDˆDà�‰ !Ô#Ü—‘ÐTØ#Ÿ™°·±×0BÑ0BÀ7ÈIÓ0VÐW[Õ0\ô^àð Ó)�Üœg×&Õ&Ü—I’I˜a”L÷ 'Ñ&ó *ô �h ×%Ô%¨Ø—v‘v“x Ð'÷ &Ñ%ð Ó)�Üœg×&Õ&Ü—I’I˜a”L÷ 'Ñ&ò *÷ F×EÐEú÷ '×&Ð&ú×&×&Ð&ú÷	 &×%úÐ%ð Ó)�Üœg×&Õ&Ü—I’I˜a”L÷ '×&×&Ò&úó *ø�hÓ)�Üœg×&Õ&Ü—I’I˜a”L÷ '×&×&Ò&úò *ûô ×$Ñ$ô Ü�‰ÐAÔBÚÜô Ü×ÑÐ8Ô9ÚðúsÙ   Á K Á2G ÂK Â%BJ Ä-K Å
G4Å!K Å/J ÆHÆ
J ÆK Æ<H	ÇK Ç G1	Ç+	K Ç4HÇ?	K ÈHÈ	K ÈH,	È'J È0K ÉI.É$
K É.I?É9K ÊKÊ$KÊ;
KËKËKËK Ë*L/ÌL/ÌL/Ì.L/c                ó<   € V ^8„  d   QhR\         R\        R\         /# )r@   ÚtextÚmentionsrB   rC   )rF   s   "r7   rG   rG   ‡   s!   € ÷ ñ œ3ð ¬$ð ´3ñ r9   c                ó@  € V'       d   RV 9  d   V # \        VR RR7       Fy  pVP                  R^ 4      VP                  R^4      rCVP                  R4      ;'       g    VP                  R4      ;'       g    R	pV R
V RV 2,           WV,           R
 ,           p K{  	  V # )z^Replace \uFFFC mention placeholders with readable @identifiers (from the end so indices hold).u   ï¿¼c                 ó&   € V P                  R ^ 4      # ©Ústart©Úget)Úms   &r7   r8   Ú"_render_mentions.<locals>.<lambda>‹   s   € °!·%±%¸ÀÔ2Cr9   T)ÚkeyÚreverserµ   ÚlengthÚnumberÚuuidÚuserNÚ@)Úsortedr·   )r°   r±   Úmentionrµ   r¼   Ú
identifiers   &&    r7   Ú_render_mentionsrÄ   ‡   s–   € ç�x tÔ+ØˆÜ˜(Ñ(CÈT×RˆØŸ™ G¨QÓ/°·±¸XÀqÓ1IˆvØ—[‘[ Ó*×KÐK¨g¯k©k¸&Ó.A×KÐKÀVˆ
Ø�F�Uˆ|  * Ð.Õ.°¸fµn°oÐ1FÕFŠñ Sð €Kr9   c                ó0   € V ^8„  d   QhR\         R\        /# r?   r_   )rF   s   "r7   rG   rG   ’   s   € ÷ 	ñ 	¤ð 	¬ñ 	r9   c                óö   € V '       g   R# V P                  R4      '       d   R# \        \        \        \        4      ;_uu_ 4        \
        P                  ! V 4        RRR4       R#   + '       g   i     R# ; i)z_Return True if *value* already looks like a Signal service identifier (PNI:/u: prefix or UUID).FTN)zPNI:zu:)rW   r   Ú
ValueErrorÚAttributeErrorÚ	TypeErrorr¾   ÚUUID©rA   s   &r7   Ú_is_signal_service_idrÌ   ’   sN   € çÙØ×Ñ˜×'Ò'ÙÜ	”*œn¬i×	8Õ	8Ü�	Š	�%ÔØ÷ 
9×	8×	8Ð	8ñ ús   ÁA'Á'A8	c                ó0   € V ^8„  d   QhR\         R\        /# r?   r_   )rF   s   "r7   rG   rG   ž   s   € ÷ gñ g¤3ð g¬4ñ gr9   c                óä   € \        V 4      ;'       d_    V P                  R4      ;'       dF    V R,          P                  4       ;'       d'    ^\        V 4      ^,
          u;8*  ;'       d    ^8*  # u # )z/Return True for a plausible E.164 phone number.Ú+:é   NN)r`   rW   ÚisdigitrX   rË   s   &r7   Ú_looks_like_e164_numberrÒ   ž   s]   € ä�‹;×fÐf˜5×+Ñ+¨CÓ0×fÐf°U¸2µY×5FÑ5FÓ5H×fÐfÈQÔRUÐV[ÓR\Ð_`ÕR`×MfÔMfÐdfÑMfÐfÑMfÐfr9   c                ó$   € V ^8„  d   QhR\         /# ©r@   rB   ©r`   )rF   s   "r7   rG   rG   £   s   € ÷ ñ ¤4ñ r9   c                 ó   € R# )z3Check if Signal runtime dependencies are available.Tr3   r3   r9   r7   Úcheck_signal_requirementsr×   £   s   € ár9   c                ó0   € V ^8„  d   QhR\         R\        /# )r@   ÚconfigrB   )r   r`   )rF   s   "r7   rG   rG   ¨   s   € ÷ &ñ &¤>ð &´dñ &r9   c                ó*  € \        V R/ 4      ;'       g    / pVP                  RR4      ;'       g    \        RR4      P                  4       pVP                  RR4      ;'       g    \        RR4      P                  4       p\	        T;'       d    T4      # )z-Check if Signal has enough config to connect.ÚextraÚhttp_urlÚ ÚSIGNAL_HTTP_URLÚaccountÚSIGNAL_ACCOUNT)Úgetattrr·   Ú_sig_secretrK   r`   )rÙ   rÛ   rÜ   rß   s   &   r7   Úvalidate_signal_configrã   ¨   s}   € ä�F˜G RÓ(×.Ð.¨B€EØ—	‘	˜* bÓ)×OÐO¬[Ð9JÈBÓ-O×VÑVÓX€HØ�y‰y˜ BÓ'×LÐL¬;Ð7GÈÓ+L×SÑSÓU€GÜ�×$Ð$˜WÓ%Ð%r9   c                   ó†  a a€ ] tR t^±t oRt]P                  t]tRt	Rt
RtV3R lV 3R lltRR/V3R lR lltV3R	 lR
 ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR ltV3R lR  lt]V3R! lR" l4       tV3R# lR$ ltV3R% lR& ltV3R' lR( ltV3R) lR* ltR+R/V3R, lR- llt V3R. lR/ lt!RuR0RR1RR2R3/V3R4 lR5 lllt"V3R6 lR7 lt#V3R8 lR9 lt$]V3R: lR; l4       t%]V3R< lR= l4       t&]'V3R> lR? l4       t(V3R@ lRA lt)RvV3RB lRC llt*V3RD lRE lt+V3RF lRG lt,RuV3RH lRI llt-V3RJ lRK lt.RwV3RL lRM llt/V3RN lRO lt0V3RP lRQ lt1RuV3RR lRS llt2V3RT lRU lt3RuV3RV lRW llt4RvV3RX lRY llt5RvV3RZ lR[ llt6RvV3R\ lR] llt7RvV3R^ lR_ llt8V3R` lRa lt9V3Rb lRc lt:V3Rd lRe lt;V3Rf lRg lt<V3Rh lRi lt=V3Rj lRk lt>RuV3Rl lRm llt?V3Rn lRo lt@V3Rp lRq ltAV3Rr lRs ltBRttCVtDV ;tE# )xÚSignalAdapterz6Signal messenger adapter using signal-cli HTTP daemon.TFc                ó    <€ V ^8„  d   QhRS[ /# )r@   rÙ   )r   )rF   Ú__classdict__s   "€r7   rG   ÚSignalAdapter.__annotate__»   s   ø€ ÷ 'dñ 'd™~ñ 'dr9   c                óT  <€ \         SV `  V\        P                  4       VP                  ;'       g    / pVP                  R R4      P                  R4      V n        VP                  RR4      V n        VP                  RR4      V n	        \        \        \        RR4      4      4      V n        VP                  R4      pVe   \        V4      M*\        R
R4      ;'       g    RP                  4       \         9   V n        \        \        \        RR4      4      4      V n        R	V n        R	V n        R	V n        / V n        / V n        / V n        RV n        RV n        R	V n        V P                  P9                  4       V n        \=        4       V n        RV n         RV n!        \=        4       V n"        RV n#        / V n$        / V n%        \L        PN                  ! 4       V n(        \R        PU                  RV P                  \W        V P                  4      V P                  '       d	   R4       R	# R4       R	# )rÜ   zhttp://127.0.0.1:8080Ú/rß   rÝ   Úignore_storiesTÚSIGNAL_GROUP_ALLOWED_USERSÚrequire_mentionNÚSIGNAL_REQUIRE_MENTIONÚfalseÚSIGNAL_ALLOWED_USERSÚ*Fç        i   g     Àr@iô  z7Signal adapter initialized: url=%s account=%s groups=%sÚenabledÚdisabled),ÚsuperÚ__init__r   ÚSIGNALrÛ   r·   ÚrstriprÜ   rß   rë   ÚsetrM   râ   Úgroup_allow_fromr`   rg   r-   rí   Údm_allow_fromÚclientÚ	_sse_taskÚ_health_monitor_taskÚ_typing_tasksÚ_typing_failuresÚ_typing_skip_untilÚ_runningÚ_last_sse_activityÚ_sse_responserK   Ú_account_normalizedr   Ú_recent_sent_timestampsÚ_max_recent_timestampsÚ_recent_sent_ttl_secondsÚ_sent_message_timestampsÚ_max_sent_message_timestampsÚ_recipient_uuid_by_numberÚ_recipient_number_by_uuidÚasyncioÚLockÚ_recipient_cache_lockr•   Úinfor   )ÚselfrÙ   rÛ   Ú_rm_cfgÚ	__class__s   &&  €r7   rö   ÚSignalAdapter.__init__»   sÏ  ø€ Ü‰Ñ˜¤§¡Ô1Ø—‘×"Ð" ˆØŸ	™	 *Ð.EÓF×MÑMÈcÓRˆŒØ—y‘y ¨BÓ/ˆŒØ#Ÿi™iÐ(8¸$Ó?ˆÔô !$Ô$5´kÐB^Ð`bÓ6cÓ$dÓ eˆÔØ—)‘)Ð-Ó.ˆØ18Ò1D¤ W¤Ü&1Ð2JÈGÓ&T×&_Ð&_ÐX_×%fÑ%fÓ%hÔlzÑ%zð 	Ôä Ô!2´;Ð?UÐWZÓ3[Ó!\Ó]ˆÔØ37ˆŒØ15ˆŒØ<@ˆÔ!Ø68ˆÔà02ˆÔØ46ˆÔØˆŒØ"%ˆÔØ7;ˆÔØ#'§<¡<×#5Ñ#5Ó#7ˆÔ ô ALÃˆÔ$Ø&)ˆÔ#Ø(-ˆÔ%ô ALÃˆÔ%Ø,/ˆÔ)à9;ˆÔ&Ø9;ˆÔ&Ü%,§\¢\£^ˆÔ"Ü�‰ÐMÈtÏ}É}Ü  §¡Ó.¸T×=R×=RÐ=R°	ö	dØXbö	dr9   Úis_reconnectc                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r@   r  rB   rÕ   )rF   rç   s   "€r7   rG   rè   ä   s   ø€ ÷ %2ñ %2©Tð %2¹dñ %2r9   c             ƒ  ó^  "  € V P                   '       d   V P                  '       g   \        P                  R4       R# Rp V P	                  RV P                  R4      '       g   R# Rp^ RIHp \        P                  ! R	V! 4       R
7      V n          V P                  P                  V P                    R2RR7      G Rj  x€L
 pTP                   ^È8w  dj   \        P                  RTP                   4        T P                  '       g5   T P                  4       G Rj  x€L
  T'       d   T P                  4        R# R# R# RT n        \"        P"                  ! 4       T n        \&        P(                  ! T P+                  4       4      T n        \&        P(                  ! T P/                  4       4      T n        \        P3                  RT P                   4       T P5                  R4        T P                  '       g5   T P                  4       G Rj  x€L
  T'       d   T P                  4        R# R# R#   \
         d"   p\        P                  RT4        Rp?ELêRp?ii ; i EL›  \
         dt   p\        P                  RT P                   T4        Rp?T P                  '       g6   T P                  4       G Rj  x€L 
  T'       d   T P                  4        R# R# R# Rp?ii ; i ELÃ LØ  T P                  '       g4   T P                  4       G Rj  x€L 
  T'       d   T P                  4        i i i ; i5i)z4Connect to signal-cli daemon and start SSE listener.z7Signal: SIGNAL_HTTP_URL and SIGNAL_ACCOUNT are requiredFzsignal-phonezSignal accountTz4Signal: Could not acquire phone lock (non-fatal): %sN)Úplatform_httpx_limitsr0   )r�   Úlimitsú/api/v1/checkç      $@©r�   z)Signal: cannot reach signal-cli at %s: %sz'Signal: health check failed (status %d)zSignal: connected to %s)rÜ   rß   r•   r‰   Ú_acquire_platform_lockr§   rŸ   Ú%gateway.platforms._http_client_limitsr  ÚhttpxÚAsyncClientrü   r·   r  Ú_close_clientÚ_release_platform_lockÚstatus_codeÚtimer  r  Úcreate_taskÚ_sse_listenerrý   Ú_health_monitorrþ   r  Ú_wire_plugin_handlers)r  r  Úlock_acquiredÚer  Úresps   &$    r7   ÚconnectÚSignalAdapter.connectä   sl  é € à�}�}ˆ} D§L§L LÜ�L‰LÐRÔSÙØˆð	VØ×.Ñ.¨~¸t¿|¹|ÐM]×^Ò^ÙØ ˆMõ
 	PÜ×'Ò'°Ñ=RÓ=TÔUˆŒð	2ðØ!Ÿ[™[Ÿ_™_°·±¨¸mÐ-LÐVZ˜_Ó[×[�ð ×Ñ 3Ô&Ü—‘ÐFÈ×HXÑHXÔYØð —=—=�=Ø×(Ñ(Ó*×*Ð*ß Ø×/Ñ/Ö1ñ !ñ !ð !ˆDŒMÜ&*§i¢i£kˆDÔ#Ü$×0Ò0°×1CÑ1CÓ1EÓFˆDŒNÜ(/×(;Ò(;¸D×<PÑ<PÓ<RÓ(SˆDÔ%Ü�K‰KÐ1°4·=±=ÔAà×&Ñ& tÔ,Øà—=—=�=Ø×(Ñ(Ó*×*Ð*ß Ø×/Ñ/Ö1ñ !ñ !øô1 ô 	VÜ�N‰NÐQÐST×UÒUûð	Vúò \øÜô Ü—‘ÐHÈ$Ï-É-ÐYZÔ[Ûð —=—=�=Ø×(Ñ(Ó*×*Ñ*ß Ø×/Ñ/Ö1ñ !ñ !ûðúô  +øð —=—=�=Ø×(Ñ(Ó*×*Ñ*ß Ø×/Ñ/Õ1ð !ð !üsõ   ‚$L-§L-Á"H+ Á$L-Á&H+ Á((L-Â-I Â?IÃ I Ã1K# Ã6%L-ÄKÄL-Ä(L-Ä>B$K# Ç#%L-ÈK!È	L-ÈL-È+IÈ6IÉL-ÉIÉL-ÉI ÉKÉ(!KÊ	K# Ê%L-Ê2J5Ê3L-Ë L-ËKËK# ËL-Ë!L-Ë#&L*Ì	LÌ
L*ÌL*Ì*L-c                ó   <€ V ^8„  d   QhRR/# ©r@   rB   Nr3   )rF   rç   s   "€r7   rG   rè     s   ø€ ÷ ñ  Tñ r9   c              ƒ  óŒ   "  € V P                   '       d,   V P                   P                  4       G R j  x€L
  R V n         R # R #  L5ir}   )rü   Úaclose)r  s   &r7   r!  ÚSignalAdapter._close_client  s3   é € Ø�;�;ˆ;Ø—+‘+×$Ñ$Ó&×&Ð&ØˆDŽKñ Ù&ùs   ‚0A²A³Ac                ó   <€ V ^8„  d   QhRR/# r/  r3   )rF   rç   s   "€r7   rG   rè     s   ø€ ÷ 
,ñ 
, $ñ 
,r9   c              ƒ  ó˜  "  € RV n         V P                  V P                  3 F  p\        V4      G Rj  x€L
  K  	  V P                  P                  4        F  pVP                  4        K  	  V P                  P                  4        V P                  4       G Rj  x€L
  V P                  4        \        P                  R4       R#  L’ L-5i)zStop SSE listener and clean up.FNzSignal: disconnected)r  rý   rþ   r   rÿ   ÚvaluesÚcancelÚclearr!  r"  r•   r  ©r  Útasks   & r7   Ú
disconnectÚSignalAdapter.disconnect  s�   é € àˆŒØ—^‘^ T×%>Ñ%>Ó?ˆDÜ˜dÓ#×#Ò#ñ @à×&Ñ&×-Ñ-Ö/ˆDØ�K‰KŽMñ 0à×Ñ× Ñ Ô"Ø× Ñ Ó"×"Ð"Ø×#Ñ#Ô%Ü�‰Ð*Ö+ñ $ñ 	#ùs"   ‚1C
³C´A&C
ÂCÂ,C
ÃC
c                ó$   <€ V ^8„  d   QhRS[ RR/# )r@   ÚlinerB   Nrs   )rF   rç   s   "€r7   rG   rè     s   ø€ ÷ Eñ E©3ð E°4ñ Er9   c              ƒ  ó2  "  € VP                  R4      '       d   \        P                  ! 4       V n        R# VP                  R4      '       dl   VR,          P                  4       ;p'       dK   \        P                  ! 4       V n         V P	                  \
        P                  ! V4      4      G Rj  x€L
  R# R# R#  L
  \
        P                   d"    \        P                  RTR,          4        R# \         d    \        P                  R4        R# i ; i5i)zdDispatch one SSE line; keepalive comments (":") count as activity so the health monitor stays quiet.Ú:zdata::é   NNNzSignal SSE: invalid JSON: %s:Néd   Nz Signal SSE: error handling event)rW   r$  r  rK   Ú_handle_envelopeÚjsonÚloadsÚJSONDecodeErrorr•   r–   r§   r¨   )r  r=  Údata_strs   && r7   Ú_handle_sse_lineÚSignalAdapter._handle_sse_line  sÇ   é € à�?‰?˜3×ÒÜ&*§i¢i£kˆDÖ#Ø�_‰_˜W×%Ò%°t¸Bµx·~±~Ó7GÐ+G¨8Ö+GÜ&*§i¢i£kˆDÔ#ðEØ×+Ñ+¬D¯JªJ°xÓ,@ÓA×AÒAñ ,HÑ%ñ BøÜ×'Ñ'ô MÜ—‘Ð;¸XÀd½^×LÜô EÜ× Ñ Ð!C×DðEüsZ   ‚A
DÁDÁ,DÂ(B< Â/B:Â0B< Â4DÂ:B< Â<2DÃ.DÃ1DÃ:DÄDÄDÄDc                ó   <€ V ^8„  d   QhRR/# r/  r3   )rF   rç   s   "€r7   rG   rè   )  s   ø€ ÷ !"ñ !" Tñ !"r9   c              ƒ  óN  "  € V P                    R\        V P                  RR7       2p\        pV P                  '       Ed“    \
        P                  RV4       V P                  P                  RVRR/RR	7      ;_uu_4       GRj  x€L
 pW0n	        \        p\        P                  ! 4       V n        \
        P                  R
4       RpVP                  4         Rj  x€L
  pV P                  '       g    MZWE,          pRV9   g   K/  VP                  R^4      w  rdVP                  4       ;p'       g   K7  V P!                  V4      G Rj  x€L
  KR  RRR4      GRj  x€L
  T P                  '       g   EKF  \"        P.                  ! Y"R,          \0        P0                  ! 4       ,          ,           4      G Rj  x€L
  \3        T^,          \4        4      pEK¥  RV n	        R#  ELW EL L™EDL˜ LŒ  + GRj  x€L 
 '       g   i     L£; i  \"        P$                   d     KJ  \&        P(                   d3   pT P                  '       d   \
        P+                  RYr4        Rp?LÿRp?i\,         d4   pT P                  '       d   \
        P+                  RYr4        Rp?EL;Rp?ii ; i Lí5i)zQListen for SSE events from signal-cli daemon, reconnecting with jittered backoff.z/api/v1/events?account=rÝ   )ÚsafezSignal SSE: connecting to %sÚGETÚAcceptztext/event-streamN)Úheadersr�   zSignal SSE: connectedÚ
z2Signal SSE: HTTP error: %s (reconnecting in %.0fs)z-Signal SSE: error: %s (reconnecting in %.0fs)gš™™™™™É?)rÜ   r   rß   ÚSSE_RETRY_DELAY_INITIALr  r•   r–   rü   Ústreamr  r$  r  r  Ú
aiter_textrJ   rK   rG  r  ÚCancelledErrorr  Ú	HTTPErrorrŸ   r§   ÚsleepÚrandomÚminÚSSE_RETRY_DELAY_MAX)r  r5   ÚbackoffÚresponseÚbufferÚchunkr=  r*  s   &       r7   r&  ÚSignalAdapter._sse_listener)  sÿ  é € à—‘�Ð6´u¸T¿\¹\ÐPRÔ7SÐ6TÐUˆÜ)ˆØ�m�m‰mð`Ü—‘Ð;¸SÔAØŸ;™;×-Ñ-¨e°SÀ8ÐM`ÐBaØ6:ð .÷ <÷ <ô <Ø?GØ)1Ô&Ü5�GÜ.2¯iªi«k�DÔ+Ü—K‘KÐ 7Ô8Ø�FØ'/×':Ñ':Ô'<÷ Bð B˜eØ#Ÿ}Ÿ}˜}Ù!Ø�˜Ø" fžnØ+1¯<©<¸¸aÓ+@™L˜DØ'+§z¡z£|Ð3˜t×3Ð3Ø&*×&;Ñ&;¸DÓ&A× AÒ A÷<÷ <ð. �}�}‹}Ü—m’m G¸­m¼f¿mºm»oÕ.MÕ$MÓN×NÐNÜ˜g¨�kÔ+>Ó?“Ø!ˆÖò5<òBñ !Bò (=÷<÷ <÷ <ò <ûô ×)Ñ)ô ÚÜ—?‘?ô eØ—=—=�=Ü—N‘NÐ#WÐYZÔdÿøÜô `Ø—=—=�=Ü—N‘NÐ#RÐTUÔ_ÿùð`úñ Oùs
  ‚?J%ÁAH ÂGÂH Â
AG*ÃG%ÃG 
ÃG%Ã "G*Ä)G*Ä5G*Å	G#
Å
G*ÅH ÅG(ÅH Å J%Å5A J%Æ5J#Æ6'J%ÇH Ç G%Ç#G*Ç%G*Ç(H Ç*H	Ç0G3Ç1
H	Ç<H	Ç>H ÈJ%ÈH ÈJ ÈJ%ÈJ È1J È2(IÉJ%ÉJ É,J É-(JÊJ%ÊJ Ê J%c                ó   <€ V ^8„  d   QhRR/# r/  r3   )rF   rç   s   "€r7   rG   rè   L  s   ø€ ÷ (ñ ( tñ (r9   c              ƒ  ó  "  € V P                   '       Ed)   \        P                  ! \        4      G Rj  x€L
  V P                   '       g   R# \        P                  ! 4       V P
                  ,
          ;p\        8:  d   K|  \        P                  RV4        V P                  P                  V P                   R2RR7      G Rj  x€L
 pTP                  ^È8X  d3   \        P                  ! 4       T n        \        P                  R4       EK  \        P                  RTP                  4       T P                  4        EK;  R#  EL L  \         d3   p\        P                  RT4       T P                  4         Rp?EKz  Rp?ii ; i5i)	z;Monitor SSE connection health and force reconnect if stale.Nz2Signal: SSE idle for %.0fs, checking daemon healthr  r  r  z1Signal: health check error: %s, forcing reconnectz Signal: daemon healthy, SSE idlez3Signal: health check failed (%d), forcing reconnect)r  r  rU  ÚHEALTH_CHECK_INTERVALr$  r  ÚHEALTH_CHECK_STALE_THRESHOLDr•   rŸ   rü   r·   rÜ   r§   Ú_force_reconnectr#  r–   )r  Úelapsedr+  r*  s   &   r7   r'  ÚSignalAdapter._health_monitorL  s  é € à�m�m‰mÜ—-’-Ô 5Ó6×6Ð6Ø—=—=�=ÙÜŸ9š9›;¨×)@Ñ)@Õ@Ð@�ÔEaÔaÙÜ�N‰NÐOÐQXÔYðØ!Ÿ[™[Ÿ_™_°·±¨¸mÐ-LÐVZ˜_Ó[×[�ð
 ×Ñ 3Ô&Ü*.¯)ª)«+�Ô'Ü—‘Ð?×@ä—‘ÐTÐVZ×VfÑVfÔgØ×%Ñ%×'ñ% Ú6ñ \øÜô Ü—‘ÐRÐTUÔVØ×%Ñ%Ô'ÞûðüsX   ‚F–F³E ´FÁ
AFÂ-E ÃEÃE ÃA9FÅE ÅFÅ&E=Å6FÅ=FÆFc                ó   <€ V ^8„  d   QhRR/# r/  r3   )rF   rç   s   "€r7   rG   rè   b  s   ø€ ÷ &ñ & $ñ &r9   c                óº  € V P                   '       d¶   V P                   P                  '       g˜   \        \        4      ;_uu_ 4        \        P
                  ! V P                   P                  4       4      pV P                  P                  V4       VP                  V P                  P                  4       RRR4       RV n         R# R# R#   + '       g   i     L; i)z7Force SSE reconnection by closing the current response.N)r  Úis_stream_consumedr   r§   r  r%  r1  Ú_background_tasksÚaddÚadd_done_callbackÚdiscardr8  s   & r7   rb  ÚSignalAdapter._force_reconnectb  s–   € à××Ð d×&8Ñ&8×&K×&KÐ&KÜœ)×$Õ$Ü×*Ò*¨4×+=Ñ+=×+DÑ+DÓ+FÓG�Ø×&Ñ&×*Ñ*¨4Ô0Ø×&Ñ& t×'=Ñ'=×'EÑ'EÔF÷ %ð "&ˆDÖñ 'LÑß$×$ús   ÁA/C
Ã
C	c                ó6   <€ V ^8„  d   QhRS[ RS[S[ ,          /# )r@   Úenvelope_datarB   )Údictr   )rF   rç   s   "€r7   rG   rè   k  s   ø€ ÷ :ñ :±$ð :¹8ÁD½>ñ :r9   c                óî  € VP                  R4      p\        V\        4      '       d   VP                  R4      MRpV'       d   \        V\        4      '       g   R# VP                  R4      ;'       g    VP                  R4      pW@P                  8w  d3   VP                  R4      ;'       g    / P                  R4      '       g   R# V P	                  VP                  R4      4      '       d   R# / VCR	V/C# )
z’Promote a "Note to Self" / group sync-sent to a dataMessage envelope; None for other
sync events (read receipts, typing, our own outbound echoes).ÚsyncMessageÚsentMessageNÚdestinationNumberÚdestinationÚ	groupInfoÚgroupIdÚ	timestampÚdataMessage)r·   Ú
isinstancero  r  Ú_consume_sent_timestamp)r  rn  Úsync_msgÚsent_msgÚdests   &&   r7   Ú_unwrap_sync_messageÚ"SignalAdapter._unwrap_sync_messagek  sÄ   € ð !×$Ñ$ ]Ó3ˆÜ2<¸XÄt×2LÒ2L�8—<‘< Ô.ÐRVˆßœz¨(´D×9Ò9ÙØ�|‰|Ð/Ó0×OÐO°H·L±LÀÓ4OˆØ×+Ñ+Ô+°X·\±\À+Ó5N×5TÐ5TÐRT×4YÑ4YÐZc×4dÒ4dÙØ×'Ñ'¨¯©°[Ó(A×BÒBÙØ9�-Ð9 °Ñ9Ð9r9   c                óB   <€ V ^8„  d   QhRS[ RS[RS[S[S[ 3,          /# )r@   r°   Údata_messagerB   )rD   ro  ry   r`   )rF   rç   s   "€r7   rG   rè   y  s.   ø€ ÷ ñ ©sð Á$ð É5ÑQUÑWZÐQZÕK[ñ r9   c                ó¤  a€ V P                   oV P                  '       d²   S;'       d    RS 2T;'       g    R9   p\        ;QJ d8    V3R lVP                  R4      ;'       g    .  4       F  '       g   K   RM-	  RM)! V3R lVP                  R4      ;'       g    .  4       4      pV'       g"   V'       g   \        P                  R4       RV3# V'       dv   S'       dn   VP                  RS 2R4      pV P                  P                  S4      ;p'       d   VP                  RV 2R4      pVP                  RR	4      P                  4       pRV3# )
z¼Gate on require_mention (False = drop) and strip the bot's own @mention from every group
message, so the agent doesn't read "@+155****4567 say hello" as a directive to contact that number.rÀ   rÝ   c              3   ón   <"  € T F*  pSVP                  R 4      VP                  R4      39   x € K,  	  R# 5i)r½   r¾   Nr¶   )rƒ   r¸   Úaccount_norms   & €r7   r…   Ú;SignalAdapter._apply_group_mention_rules.<locals>.<genexpr>  s4   øé € ð (WÙ2T¨Að )5¸¿¹¸x»È!Ï%É%ÐPVË-Ð8XÖ(XÛ2Tùs   ƒ25r±   TFzHSignal: ignoring group message (require_mention=true, bot not mentioned)z  Ú )	r  rí   Úanyr·   r•   r–   r�   r  rK   )r  r°   r�  Úmentioned_in_textÚmentioned_in_metadataÚbot_uuidr„  s   &&&   @r7   Ú_apply_group_mention_rulesÚ(SignalAdapter._apply_group_mention_rulesy  s+  ø€ ð ×/Ñ/ˆØ××ÐØ ,× UÐ U°A°l°^Ð2DÈÏÈÐQSÑ2TÐß$'£Cô (WØ2>×2BÑ2BÀ:Ó2N×2TÐ2TÐRTÐ2Tó(W§C§C¢Cô (WØ2>×2BÑ2BÀ:Ó2N×2TÐ2TÐRTÐ2Tó(Wó %WÐ!ç$×-BÜ—‘ÐgÔhØ˜d�{Ð"ß—LØ—<‘< ! L >Ð 2°BÓ7ˆDØ×9Ñ9×=Ñ=¸lÓKÐKˆxÖKØ—|‘| a¨ z N°BÓ7�Ø—<‘<  cÓ*×0Ñ0Ó2ˆDØ�TˆzÐr9   c                ó\   <€ V ^8„  d   QhRS[ RS[S[ S[,          S[ S[,          3,          /# )r@   Úattachments_datarB   )rE   ry   rD   )rF   rç   s   "€r7   rG   rè   ‹  s0   ø€ ÷ 'ñ '¹4ð 'ÁEÉ$ÉsÍ)ÑUYÑZ]ÕU^ÐJ^ÕD_ñ 'r9   c              ƒ  óð  "  € . p. pV F¼  pVP                  R4      VP                  R^ 4      reV'       g   K/  V\        8”  d   \        P                  RV4       KR   V P	                  V4      G Rj  x€L
 w  rxV'       dG   VP                  V4       TP                  VP                  R4      ;'       g    \        V4      4       K¼  K¾  	  W#3#  L[  \         d    \        P                  RT4        Ké  i ; i5i)zEFetch + cache inbound attachments; returns (media_urls, media_types).ÚidÚsizez1Signal: attachment too large (%d bytes), skippingNÚcontentTypez%Signal: failed to fetch attachment %s)	r·   ÚSIGNAL_MAX_ATTACHMENT_SIZEr•   rŸ   Ú_fetch_attachmentÚappendrv   r§   r¨   )	r  rŽ  Ú
media_urlsÚmedia_typesÚattÚatt_idÚatt_sizeÚcached_pathrZ   s	   &&       r7   Ú_collect_attachmentsÚ"SignalAdapter._collect_attachments‹  sß   é € à "ˆ
Ø!#ˆÛ#ˆCØ"Ÿw™w t›}¨c¯g©g°f¸aÓ.@�HßÙØÔ4Ô4Ü—‘ÐRÐT\Ô]ÙðRØ)-×)?Ñ)?ÀÓ)G×#GÑ �ßØ×%Ñ% kÔ2Ø×&Ñ& s§w¡w¨}Ó'=×'RÐ'RÄÈcÓARÖSñ ñ $ð Ð&Ð&ñ $Høô ô RÜ× Ñ Ð!HÈ&×QðRüsC   ‚AC6ÁCÁ0CÁ1ACÂ3CÃ	C6ÃCÃ!C3Ã/C6Ã2C3Ã3C6c                ó$   <€ V ^8„  d   QhRS[ RR/# )r@   ÚenveloperB   N)ro  )rF   rç   s   "€r7   rG   rè   Ÿ  s   ø€ ÷ P)ñ P)©tð P)¸ñ P)r9   c              ƒ  ó†
  a"  € VP                  RV4      pRV9   pV'       d   V P                  V4      pVf   R# VP                  R4      ;'       g+    VP                  R4      ;'       g    VP                  R4      pVP                  RR4      pVP                  RR4      pV P                  WF4       V'       g   \        P	                  R	4       R# V P
                  '       d   W@P
                  8X  d   V'       g   R# V P                  '       d   VP                  R
4      '       d   R# VP                  R4      ;'       g+    VP                  R4      ;'       g    / P                  R4      pV'       g   R# VP                  R4      pV'       d   VP                  R4      MRp	\        V	4      p
V
'       d   V P                  V	4      '       g   R# V
'       d   RV	 2MTpVP                  RR4      pV'       d&   VP                  R. 4      ;p'       d   \        WÍ4      pV
'       d   V P                  WÇ4      w  rìV'       g   R# VP                  R4      ;'       g    / pVP                  R4      '       d   \        VP                  R4      4      MRpV P                  V4      pVP                  R. 4      p. . upoV'       d0   \        V RR4      '       g   V P                  V4      G Rj  x€L
 w  poV'       d   VP                  4       '       g>   V'       g6   \        P	                  R\!        V4      V'       d   \#        V4      M^ 4       R# T P%                  Y¸'       d   VP                  R4      MTV
'       d   RMRTT;'       g    TV'       d   TMRV
'       d   T	MRR7      pS'       g   \&        P(                  M'\+        V3R l\,         4       \&        P.                  4      pVP                  R^ 4      p\0        P2                  ! \4        R7      pV'       dI   \7        \8        \:        4      ;_uu_ 4        \0        P<                  ! VR,          \4        R7      pRRR4       \?        TT;'       g    RTTSTR TR!TRV'       d   TMR/TVP                  R"4      TVP                  R#4      ;'       g    VP                  R$4      V PA                  VV4      R%7      p\        P	                  R&\!        V4      VR',          T;'       g    RR(,          4       V PC                  V4      G Rj  x€L
  R#  ELD  + '       g   i     Lß; i L5i))z(Process an incoming signal-cli envelope.rŸ  rq  NÚsourceNumberÚ
sourceUuidÚsourceÚ
sourceNamerÝ   z(Signal: ignoring envelope with no senderÚstoryMessagerx  ÚeditMessageru  rv  úgroup:Úmessager±   r   r�  ÚattachmentsÚignore_attachmentsFz>Signal: skipping contentless envelope from %s (%d attachments)Ú	groupNameÚgroupÚdm)Úchat_idÚ	chat_nameÚ	chat_typeÚuser_idÚ	user_nameÚuser_id_altÚchat_id_altc              3   ó´   <a"  € T FL  w  op\         ;QJ d    V3R  lS 4       F  '       g   K   RM	  RM! V3R  lS 4       4      '       g   KH  Vx € KN  	  R# 5i)c              3   óD   <"  € T F  qP                  S4      x € K  	  R # 5ir}   )rW   )rƒ   r¸   Úprefixs   & €r7   r…   Ú;SignalAdapter._handle_envelope.<locals>.<genexpr>.<genexpr>Ý  s   øé € ÐCnÑbmÐ]^ÇLÁLÐQW×DXÐDXÓbmùs   ƒ TFN)r‡  )rƒ   Úmtr·  r—  s   & @€r7   r…   Ú1SignalAdapter._handle_envelope.<locals>.<genexpr>Ý  s8   ùé € ÐoÑ"<‘J�F˜BÇÃÔCnÑbmÓCnÇÇÂÔCnÑbmÓCn×@n�RŠRÓ"<ùs   „A—A®AÁ
Arw  )Útzéè  ÚsenderÚtimestamp_msr°   Ú
authorNameÚauthorProfileName)r£  r°   Úmessage_typer–  r—  rw  Úraw_messageÚreply_to_message_idÚreply_to_textÚreply_to_author_idÚreply_to_author_nameÚreply_to_is_own_messagez!Signal: message from %s in %s: %sºNé   N:Né2   N)"r·   r~  Ú_remember_recipient_identifiersr•   r–   r  rë   r`   Ú_group_allowedrÄ   r‹  rD   Ú_extract_quote_authorrá   rœ  rK   r   rX   Úbuild_sourcer   ÚTEXTr”   Ú_MEDIA_TYPE_BY_MIME_PREFIXÚDOCUMENTr   Únowr   r   rÇ   r¢   Úfromtimestampr   Ú_quote_references_own_messageÚhandle_message)r  rŸ  rn  Úis_note_to_selfr½  Úsender_nameÚsender_uuidr�  Ú
group_infoÚgroup_idÚis_groupr®  r°   r±   Ú	mentionedÚ
quote_dataÚreply_to_idÚreply_to_authorrŽ  r–  r£  Úmsg_typeÚts_msrw  Úeventr—  s   &&                       @r7   rB  ÚSignalAdapter._handle_envelopeŸ  sD  øé € à Ÿ™ Z°Ó:ˆØ'¨=Ñ8ˆßØ ×5Ñ5°mÓDˆMØÒ$ÙØ×#Ñ# NÓ3÷ 1ð 1°}×7HÑ7HÈÓ7V÷ 1ð 1Ø"×&Ñ& xÓ0ð 	à#×'Ñ'¨°bÓ9ˆØ#×'Ñ'¨°bÓ9ˆØ×,Ñ,¨VÔAßÜ�L‰LÐCÔDÙà×#×#Ð#¨×2JÑ2JÔ(J×SbÙØ××Ð =×#4Ñ#4°^×#DÒ#DÙà%×)Ñ)¨-Ó8÷ Wð WØ)×-Ñ-¨mÓ<×BÐBÀ×GÑGÈÓVð 	çÙØ!×%Ñ% kÓ2ˆ
ß0:�:—>‘> )Ô,ÀˆÜ˜“>ˆß˜D×/Ñ/°×9Ò9Ùß)1�F˜8˜*Ñ%°vˆØ×Ñ 	¨2Ó.ˆß ×!1Ñ!1°*¸bÓ!AÐA�XÖAÜ# DÓ3ˆDßØ"×=Ñ=¸dÓQ‰OˆIßÙð "×%Ñ% gÓ.×4Ð4°"ˆ
Ø3=·>±>À$×3GÒ3G”c˜*Ÿ.™.¨Ó.Ô/ÈTˆØ×4Ñ4°ZÓ@ˆØ'×+Ñ+¨M¸2Ó>ÐØ"$ bÐˆ
�Kß¤G¨DÐ2FÈ×$NÒ$NØ,0×,EÑ,EÐFVÓ,W×&WÑ#ˆJ˜÷ ˜DŸJ™JŸLšL·*Ü�L‰LÐYÔ[gÐhnÓ[oß,6œ˜Zœ¸Aô?áØ×"Ñ"ØÆj z§~¡~°kÔ'BÐVaß!)‘g¨t¸VØ!×+Ð+ VÏ¹ÐY]ß$,™°$ð	 #ó 8ˆ÷ ,7”;×#Ò#¼DÜoÕ"<ÓoÜ× Ñ ó="ˆð ×!Ñ! +¨qÓ1ˆÜ—L’L¤CÔ(ˆ	ßÜœ*¤g×.Õ.Ü$×2Ò2°5¸4µ<ÄCÔH�	÷ /ô Ø §
 
¨¸ÈjØ#¨yØ! 6¨>¸5À'×YcÉ:ÐimÐnØ +¸:¿>¹>È&Ó;QØ.Ø!+§¡°Ó!=×!dÐ!dÀÇÁÐPcÓAdØ$(×$FÑ$FÀ{ÐTcÓ$dô
ˆô 	�‰Ð8¼,ÀvÓ:NÐPWÐX[ÕP\Ð_c×_iÐ_iÐgiÐknÕ^oÔpØ×!Ñ! %Ó(×(Ò(òC 'X÷( /×.úñ 	)ùsï   ƒAUÁUÁ+A7UÃ#UÃ;UÄUÄ&UÅ UÅUÅ3UÆ<UÇ	UÇ UÇ6UÈUÈ#4UÉUÉ2A3UË%T)Ë&UË5UÌUÌA!UÍ5UÎ	UÎ
UÎUÎ(A,UÐUÐ1$T,ÑUÑ,UÑ?-UÒ-AUÔ "UÔ"T?Ô#UÔ,T<	Ô7	Uc                ó&   <€ V ^8„  d   QhRS[ RS[/# )r@   rÚ  rB   r_   )rF   rç   s   "€r7   rG   rè   ñ  s   ø€ ÷ 	ñ 	¡sð 	©tñ 	r9   c                óì   € V P                   '       g   \        P                  R4       R# RV P                   9  d:   WP                   9  d*   \        P                  RV'       d
   VR,          MR4       R# R# )u›   Group policy from SIGNAL_GROUP_ALLOWED_USERS: unset â†’ groups disabled; IDs â†’ only those
groups; "*" â†’ all. DM auth is run.py's (_is_user_authorized).z>Signal: ignoring group message (no SIGNAL_GROUP_ALLOWED_USERS)Frñ   z!Signal: group %s not in allowlist:NrS   NÚ?T)rú   r•   r–   )r  rÚ  s   &&r7   rÌ  ÚSignalAdapter._group_allowedñ  sW   € ð ×$×$Ð$Ü�L‰LÐYÔZÙØ�d×+Ñ+Ô+°×@UÑ@UÔ0UÜ�L‰LÐ<Ïh¸hÀr¾lÐ\_Ô`ÙÙr9   c                óJ   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          RR/# )r@   r½   Ú
service_idrB   N)r   rD   )rF   rç   s   "€r7   rG   rè   ü  s3   ø€ ÷ @ñ @±h¹sµmð @ÑQYÑZ]ÕQ^ð @Ðcgñ @r9   c                óŒ   € V'       d<   V'       d2   \        V4      '       d   W P                  V&   WP                  V&   R# R# R# R# )u?   Cache any numberâ†”UUID mapping observed from Signal envelopes.N)rÌ   r  r  )r  r½   ré  s   &&&r7   rË  Ú-SignalAdapter._remember_recipient_identifiersü  s8   € ç—jÔ%:¸:×%FÒ%FØ5?×*Ñ*¨6Ñ2Ø9?×*Ñ*¨:Ó6ñ &G‘j‰6r9   c                ó6   <€ V ^8„  d   QhRS[ RS[S[,          /# )r@   rÝ  rB   )r   r   rD   )rF   rç   s   "€r7   rG   rè     s#   ø€ ÷ Sñ S©#ð S±(¹3µ-ñ Sr9   c                ól   a € \        S \        4      '       d   \        MRp\        V 3R lV 4       R4      # )zGReturn the best available Signal sender identifier from quote metadata.c              3   óz   <"  € T F0  pSP                  V4      '       g   K  \        SV,          4      x € K2  	  R # 5ir}   )r·   rD   )rƒ   ÚkrÝ  s   & €r7   r…   Ú6SignalAdapter._extract_quote_author.<locals>.<genexpr>  s+   øé € ÐK±¨A¸¿¹È×9JÔ'”S˜ A�×'Ð'³ùs   ƒ;¡;Nr3   )ry  ro  Ú_QUOTE_AUTHOR_KEYSr”   )rÝ  Úkeyss   f r7   rÍ  Ú#SignalAdapter._extract_quote_author  s,   ø€ ô &0°
¼D×%AÒ%AÕ!ÀrˆÜÔK±ÓKÈTÓRÐRr9   c                óL   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          RS[/# )r@   rÞ  rß  rB   )r   rD   r`   )rF   rç   s   "€r7   rG   rè     s3   ø€ ÷ 	Vñ 	V¹Á#½ð 	VÑYaÑbeÕYfð 	VÑkoñ 	Vr9   c                ój  € V'       d   \        V4      V P                  9   d   R# V'       g   R# \        V4      P                  4       V P                  rC\	        V4      ;'       dP    W48H  ;'       gD    W0P
                  P                  V4      8H  ;'       g    V P                  P                  V4      V8H  # )zCTrue when a Signal quote points at this adapter's outbound message.TF)rD   r	  rK   r  r`   r  r·   r  )r  rÞ  rß  ÚauthorÚaccts   &&&  r7   rÔ  Ú+SignalAdapter._quote_references_own_message  s¡   € çœ3˜{Ó+¨t×/LÑ/LÔLÙßÙÜ˜?Ó+×1Ñ1Ó3°T×5MÑ5M�ä�D‹z÷ Vð V˜v™~÷  Uð  U°×;YÑ;Y×;]Ñ;]Ð^bÓ;cÑ1c÷  Uð  UØ"&×"@Ñ"@×"DÑ"DÀVÓ"LÐPTÑ"Tð	Vr9   c                ó$   <€ V ^8„  d   QhRS[ RR/# )r@   rw  rB   N)r   )rF   rç   s   "€r7   rG   rè     s   ø€ ÷ >ñ >¹#ð >À$ñ >r9   c                ó  € Vf   R# \        V4      pV P                  P                  VR4       RV P                  V&   \        V P                  4      V P                  8”  d   V P                  P                  RR7       KB  R# )zFKeep a bounded cache of outbound Signal timestamps for quote matching.NF©Úlast)rD   r	  ÚpoprX   r
  Úpopitem)r  rw  rº   s   && r7   Ú _remember_sent_message_timestampÚ.SignalAdapter._remember_sent_message_timestamp  sp   € àÒÙÜ�)‹nˆØ×%Ñ%×)Ñ)¨#¨tÔ4Ø-1ˆ×%Ñ% cÑ*Ü�$×/Ñ/Ó0°4×3TÑ3TÔTØ×)Ñ)×1Ñ1°uÐ1Ö=ñ Ur9   c                ó<   <€ V ^8„  d   QhRS[ RS[RS[S[,          /# )r@   ÚcontactÚphone_numberrB   )r   rD   r   )rF   rç   s   "€r7   rG   rè     s'   ø€ ÷ ñ ©Sð Áð ÉÑQTÍñ r9   c                óÀ  € \        V\        4      '       g   R# VP                  R4      ;'       g    VP                  R4      pVP                  R4      pV'       gA   \        V\        4      '       d+   VP                  R4      ;'       g    VP                  R4      pV'       d;   \        V4      '       d*   VVP                  R4      VP                  R4      39   d   V# R# )zGBest-effort extraction of a Signal service ID from listContacts output.Nr¾   Ú	serviceIdÚprofiler½   Ú	recipient)ry  ro  r·   rÌ   )r  r  r  ré  r  s   &&&  r7   Ú_extract_contact_uuidÚ#SignalAdapter._extract_contact_uuid  s«   € ä˜'¤4×(Ò(ÙØ—[‘[ Ó(×DÐD¨G¯K©K¸Ó,Dˆ
Ø—+‘+˜iÓ(ˆßœj¨´$×7Ò7Ø Ÿ™ [Ó1×HÐH°W·[±[ÀÓ5HˆJßÔ/°
×;Ò;ÀØ—‘˜HÓ% w§{¡{°;Ó'?ðQAô AAàÐÙr9   c                ó&   <€ V ^8„  d   QhRS[ RS[ /# ©r@   r®  rB   rs   )rF   rç   s   "€r7   rG   rè   *  s   ø€ ÷ Hñ H±ð H¹ñ Hr9   c           	   ƒ  óV  "  € V'       d)   VP                  R4      '       g   \        V4      '       g   V# V P                  P                  V4      ;p'       d   V# V P                  ;_uu_4       GRj  x€L
  V P                  P                  V4      ;p'       d   TuuRRR4      GRj  x€L
  # V P                  RRV P                  RR/4      G Rj  x€L
 p\        V\        4      '       d   TMR Fb  p\        V\        4      '       d   VP                  R4      MRpV P                  WA4      pV'       g   KG  V'       g   KQ  V P                  WV4       Kd  	  V P                  P                  W4      uuRRR4      GRj  x€L
  #  EL LÝ L¶ L  + GRj  x€L 
 '       g   i     R# ; i5i)	zCReturn the preferred Signal recipient identifier for a direct chat.r§  NÚlistContactsrß   ÚallRecipientsTr½   r3   )rW   rÒ   r  r·   r  Ú_rpcrß   ry  rE   ro  r  rË  )r  r®  ÚcachedÚcontactsr  r½   ré  s   &&     r7   Ú_resolve_recipientÚ SignalAdapter._resolve_recipient*  s<  é € ç˜'×,Ñ,¨X×6Ò6Ô>UÐV]×>^Ò>^ØˆNØ×3Ñ3×7Ñ7¸Ó@Ð@ˆ6Ö@ØˆMØ×-×-×-Ó-Ø×7Ñ7×;Ñ;¸GÓDÐDˆvÖDØ÷ .×-Ò-ð "ŸY™Y ~¸	À4Ç<Á<ÐQ`ÐbfÐ7gÓh×hˆHÜ'1°(¼D×'AÒ'A™8ÀrÒI�Ü2<¸WÄd×2KÒ2K˜Ÿ™ XÔ.ÐQU�Ø!×7Ñ7¸ÓI�
ß‘6Ÿj™jØ×8Ñ8¸ÖLñ	 Jð
 ×1Ñ1×5Ñ5°gÓG÷ .×-×-ñ i÷ .×-×-Ó-üs•   ‚F)¢5F)ÁF)Á2FÁ3F)Á6%FÂF)Â(FÂ)F)Â.#FÃFÃA FÄ7FÅ/FÅ0F)Å=F
Å>F)ÆF)ÆFÆ
F)ÆF&	ÆFÆ
F&	ÆF&	Æ 	F)Úresolvec          
      ó^   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[RS[ S[S[3,          /# )r@   Úparamsr®  r  rB   )ro  rD   r   r`   )rF   rç   s   "€r7   rG   rè   ;  s?   ø€ ÷ ñ ©©c±3¨h­ð Á#ð ÑSWð ÑcgÑhkÑmpÐhpÕcqñ r9   c             ƒ  óª   "  € VP                  R4      '       d   VR,          VR&   V# V'       d   V P                  V4      G Rj  x€L
 MT.VR&   V#  L5i)zMAdd the groupId / recipient routing key for *chat_id* to *params* (in place).r§  :é   NNrv  Nr  )rW   r  )r  r  r®  r  s   &&&$r7   Ú_with_targetÚSignalAdapter._with_target;  s]   é € à×Ñ˜h×'Ò'Ø '¨¥ˆF�9Ñð ˆ÷ NU¨×)@Ñ)@ÀÓ)I×#IÐ#IÐZaÐ"bˆF�;ÑØˆñ $Jùs   ‚-A°AÁAÁAc                ó&   <€ V ^8„  d   QhRS[ RS[/# )r@   Úattachment_idrB   )rD   ry   )rF   rç   s   "€r7   rG   rè   C  s   ø€ ÷ /ñ /±Sð /¹Uñ /r9   c              ƒ  óB  "  € V P                  RRV P                  RV/4      G Rj  x€L
 pV'       g   R# \        V\        4      '       d1   VP	                  R4      pV'       g   \
        P                  R4       R# \        P                  ! V4      p\        V4      pVR8X  d1   \        P                  ! \        V4      G Rj  x€L
 ;'       g    W43w  r4\        V4      '       d   \        M\        V4      '       d   \         M\"        pV! W44      G Rj  x€L
 V3#  Lò LY L
5i)	zCFetch an attachment via JSON-RPC and cache it. Returns (path, ext).ÚgetAttachmentrß   r�  NrO   z.Signal: attachment response missing 'data' keyrm   )NrÝ   )r  rß   ry  ro  r·   r•   rŸ   Úbase64Ú	b64decoder\   r  Ú	to_threadr®   ri   r   rq   r   r   )r  r  ÚresultÚraw_datarZ   Úcaches   &&    r7   r”  ÚSignalAdapter._fetch_attachmentC  sí   é € à—y‘y °9¸d¿l¹lÈDÐR_Ð2`Óa×aˆßØˆOÜ�fœd×#Ò#Ø—Z‘Z Ó'ˆFßÜ—‘ÐOÔPØ�Ü×#Ò# FÓ+ˆÜ˜xÓ(ˆð �&Œ=Ü#*×#4Ò#4Ô5FÈÓ#Q×Q×eÐeÐW_ÐVe‰MˆHÜ1>¸s×1CÒ1CÕ-Ü6CÀC×6HÒ6HÕ2ÔNmð 	á˜8Ó)×)¨3Ð.Ð.ñ! bñ Rñ *ùsF   ‚$D¦D§D³0DÁ$ADÃDÃ
DÃADÄDÄDÄDÄDÚlog_failuresÚraise_on_rate_limitr�   r0   c                óR   <€ V ^8„  d   QhRS[ RS[RS[ R,          RS[RS[RS[RS[/# )	r@   Úmethodr  Úrpc_idNr&  r'  r�   rB   )rD   ro  r`   Úfloatr   )rF   rç   s   "€r7   rG   rè   W  sF   ø€ ÷ !ñ !¡ð !©dð !¹CÀ$½Jð !Ñ`dð !Ù(,ð!Ù?Dð!ÙPSñ!r9   c             ƒ  óÚ  "  € V P                   '       g   \        P                  R4       R# RRRTRTRVe   TM)V R\        \        P                  ! 4       R	,          4       2/pV'       d   \
        P                  M\
        P                  p V P                   P                  V P                   R
2WvR7      G Rj  x€L
 p	V	P                  4        V	P                  4       p
RV
9   dŽ   V
R,          pV'       dd   \        V4      '       dS   \        V\        4      '       d   \        VP!                  RR4      4      M
\        V4      p\#        V\%        V4      R7      h\        P'                  VRW4       R# V
P!                  R4      p\        V\        4      '       d’   V'       dŠ   \        VP!                  R4      \(        4      '       d   VP!                  R4      MR FM  p\        V\        4      '       g   K  VP!                  R4      R8X  g   K3  \#        RVP!                  R4      R7      h	  V#  ELs  \"         d    h \*         d#   p\        P'                  TRY4        Rp?R# Rp?ii ; i5i)zúSend a JSON-RPC 2.0 request to signal-cli. ``log_failures=False`` logs failures at DEBUG (typing
path: silence NETWORK_FAILURE spam); ``raise_on_rate_limit=True`` raises ``SignalRateLimitError``
on a 429 / RateLimitException instead of swallowing it.z+Signal: RPC called but client not connectedNÚjsonrpcz2.0r)  r  r�  Ú_r¼  z/api/v1/rpc)rC  r�   r‰   r¨  rÝ   )Úretry_afterzSignal RPC error (%s): %sr"  ÚresultsÚtypeÚRATE_LIMIT_FAILUREz!Rate limit exceeded for recipientÚretryAfterSecondszSignal RPC %s failed: %sr3   )rü   r•   rŸ   Úintr$  ÚloggingÚWARNINGÚDEBUGÚpostrÜ   Úraise_for_statusrC  r)   ry  ro  rD   r·   r&   r'   ÚlogrE   r§   )r  r)  r  r*  r&  r'  r�   ÚpayloadÚ
fail_levelr+  rO   ÚerrÚerr_msgr"  Úrr*  s   &&&&$$$         r7   r  ÚSignalAdapter._rpcW  sé  é € ð
 �{�{ˆ{Ü�N‰NÐHÔIÙØ˜e X¨v°xÀØ 6Ò#5™¸f¸XÀQÄsÌ4Ï9Ê9Ë;ÐY]ÕK]ÓG^ÐF_Ð;`ðbˆç(4”W—_’_¼'¿-¹-ˆ
ð	ØŸ™×)Ñ)¨T¯]©]¨O¸;Ð*GÈgÐ)Óg×gˆDØ×!Ñ!Ô#Ø—9‘9“;ˆDØ˜$ŒØ˜7•m�ß&Ô+FÀs×+KÒ+KÜ=GÈÌT×=RÒ=Rœc #§'¡'¨)°RÓ"8Ô9ÔX[Ð\_ÓX`�GÜ.¨wÔD`ÐadÓDeÔfÐfÜ—
‘
˜:Ð'BÀFÔPÙØ—X‘X˜hÓ'ˆFÜ˜&¤$×'Ò'×,?Ü2<¸V¿Z¹ZÈ	Ó=RÔTX×2YÒ2Y˜Ÿ™ IÔ.Ð_aÒa�AÜ! !¤T×*Ô*¨q¯u©u°V«}Ð@TÖ/TÜ2Ð3VØ?@¿u¹uÐEXÓ?Yô[ð [ñ bð ˆMò! høô" $ô 	ØÜô 	Ü�J‰J�zÐ#=¸vÔIÝûð	üst   ‚A)I+Á, I+Â-H0 Â:H-Â;;H0 Ã7A:H0 Å1I+Å3.H0 Æ"AH0 Ç5H0 ÈH0 È,I+È-H0 È0I(ÉI(ÉI#ÉI+É#I(É(I+c                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r@   ÚcontentrB   rs   )rF   rç   s   "€r7   rG   rè   z  s   ø€ ÷ ñ ¡cð ©cñ r9   c                ó   € V# )zTPlain-text fallback for the base-class send path; send() applies rich styles itself.r3   )r  rB  s   &&r7   Úformat_messageÚSignalAdapter.format_messagez  s   € àˆr9   c                óL   <€ V ^8„  d   QhRS[ RS[S[S[S[,          3,          /# )r@   r"  rB   )r   ry   r`   r   rD   )rF   rç   s   "€r7   rG   rè   ~  s)   ø€ ÷ ñ ©Cð ±E¹$ÁÉÅÐ:MÕ4Nñ r9   c                ó¸  € \        V\        4      '       d   VP                  R4      MRp\        V\        4      '       d   TMR	 F’  p\        V\        4      '       g   K  VP                  R4      pV'       d   VR8w  d   R\	        V4      3u # RV9   g   KS  VP                  R4      '       d   Kl  R\	        VP                  R4      ;'       g    R4      3u # 	  R
# )zLValidate signal-cli send response results. Returns (success, error_message).r0  Nr1  ÚSUCCESSFÚsuccessÚfailurezRecipient delivery failedr3   )TN)ry  ro  r·   rE   rD   )r  r"  r0  r?  Úrtypes   &&   r7   Ú_validate_send_resultÚ#SignalAdapter._validate_send_result~  s®   € ä+5°f¼d×+CÒ+C�&—*‘*˜YÔ'ÈˆÜ& w´×5Ò5‘¸2Ò=ˆAÜ˜a¤×&Ò&ÙØ—E‘E˜&“MˆEß˜ )Ô+Øœc %›jÐ(Ò(Ø˜AŽ~ a§e¡e¨I×&6Ô&6Øœc !§%¡%¨	Ó"2×"QÐ"QÐ6QÓRÐRÒRñ >ð Ðr9   c                ó6   <€ V ^8„  d   QhRS[ RS[S[,          /# )r@   r°   rB   )rD   rE   r4  )rF   rç   s   "€r7   rG   rè   Œ  s#   ø€ ÷ Lñ L™Sð L¡T©#¥Yñ Lr9   c                óB   € ^ .\         P                  ! R V  4       4      O# )zEReturn cumulative UTF-16 offsets for every Python character boundary.c              3   ó8   "  € T F  p\        V4      x € K  	  R # 5ir}   )r   )rƒ   Úchars   & r7   r…   Ú/SignalAdapter._utf16_offsets.<locals>.<genexpr>Ž  s   é € Ð(JÁT¸T¬°4¯¨ÃTùs   ‚)Ú	itertoolsÚ
accumulate)r°   s   &r7   Ú_utf16_offsetsÚSignalAdapter._utf16_offsets‹  s#   € ð ÐK”I×(Ò(Ñ(JÁTÓ(JÓJÐKÐKr9   c          	      óR   <€ V ^8„  d   QhRS[ S[,          RS[RS[RS[ S[,          /# )r@   Útext_stylesÚchunk_startÚ	chunk_endrB   )rE   rD   r4  )rF   rç   s   "€r7   rG   rè   ‘  s4   ø€ ÷ ñ ¡t©C¥yð ¹sð Ésð ÑW[Ñ\_ÕW`ñ r9   c                ór  € . pV  F€  p VP                  R^4      w  rVp\        V4      \        V4      \        V4      ,           r˜\        Y�4      \        Y’4      rºY«8  g   K[  TP                  Y¡,
           RYº,
           RT 24       K‚  	  V#   \        \        3 d    \        P                  RT4        K°  i ; i)zCTranslate full-message Signal styles into a chunk-local range list.r?  z/[Signal] Ignoring malformed textStyle range: %r)	rJ   r4  rÉ   rÇ   r•   r–   ÚmaxrW  r•  )rX  rY  rZ  ÚadjustedÚstyle_stringÚstart_sÚlength_sÚ
style_typeÚstyle_startÚ	style_endÚoverlap_startÚoverlap_ends   &&&         r7   Ú_styles_for_chunkÚSignalAdapter._styles_for_chunk�  s¸   € ð !ˆÛ'ˆLðØ0<×0BÑ0BÀ3ÈÓ0JÑ-� :Ü),¨W«´s¸7³|ÄcÈ(ÃmÕ7S˜Yô *-¨[Ó)FÌÈIÓHa˜;ØÖ*Ø—‘ =Õ#>Ð"?¸qÀÕA\Ð@]Ð]^Ð_iÐ^jÐ kÖlñ (ð ˆøô œzÐ*ô Ü—‘ÐNÐP\Ô]Úðús   ‰:BÂ'B6Â5B6c                óx   <€ V ^8„  d   QhRS[ RS[S[ ,          RS[RS[S[S[ S[S[ ,          3,          ,          /# )r@   Ú
plain_textrX  Ú
max_lengthrB   )rD   rE   r4  ry   )rF   rç   s   "€r7   rG   rè   ¡  sO   ø€ ÷ gñ gÙ ðgÙ/3±C­yðgÙFIðgÙNRÑSXÑY\Ñ^bÑcfÕ^gÐYgÕShÕNiñgr9   c                ó‚  € \        V4      V8:  d   W3.# \        ^V^
,
          4      pV P                  V4      p. p^ VR,          r‡WW,          V8  d�   \        W…V,          V,           4      p	V^,           p
V
\	        V4      8  d   WZ,          V	8:  d   V
^,          p
K(  \        V
^,
          V^,           4      p
V P                  W%V,          WZ,          4      pVP                  WV
 V34       T
pK©  \	        V4      ^8X  d   V# \        V^R7       UUUu. uF  w  pw  rÞV RV R\	        V4       R2V3NK   	  uppp# u upppi )z»Split converted Signal text into chunks, translating body ranges per chunk. Splitting after
conversion keeps styles that cross a chunk boundary intact instead of leaking Markdown markers.r´   z (rê   Ú)éÿÿÿÿ)r   r\  rU  rW  rX   rf  r•  Ú	enumerate)Úclsri  rX  rj  Ú
body_limitÚoffsetsÚchunksÚ	start_idxÚ	total_u16Ú
end_budgetÚend_idxÚchunk_stylesÚidxÚtxtÚsts   &&&&           r7   Ú_split_signal_formatted_messageÚ-SignalAdapter._split_signal_formatted_message   s4  € ô
 �ZÓ  JÔ.ØÐ-Ð.Ð.Ü˜˜J¨�OÓ,ˆ
Ø×$Ñ$ ZÓ0ˆØ.0ˆØ  '¨"¥+�9ØÕ  9Ô,Ü˜Y°	Õ(:¸ZÕ(GÓHˆJØ !•mˆGØœC ›LÔ(¨WÕ-=ÀÔ-KØ˜1•’Ü˜' A�+ y°1¥}Ó5ˆGØ×0Ñ0°ÀiÕ>PÐRYÕRbÓcˆLØ�M‰M˜:°Ð8¸,ÐGÔHØŠIÜˆv‹;˜!ÔØˆMÜKTÐU[ÐcdÕKeÕfÑKe¹¸¹i¸s�C�5˜˜3˜%˜q¤ V£ ¨QÐ/°Ó4ÑKeÓfÐfùÔfs   Ä$D:c          	      óh   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[S[S[S[,          3,          /# )r@   r  Ú
fail_errorrB   )ro  rD   r   ry   r   r   )rF   rç   s   "€r7   rG   rè   ¸  s<   ø€ ÷ ñ ¡d©3±¨8¥nð Á#ð É%ÑPSÑU]Ñ^hÕUiÐPiÕJjñ r9   c              ƒ  óæ   "  € V P                  RV4      G Rj  x€L
 ;pf   R\        RVR7      3# V P                  V4      w  rEV'       g   R\        RWSR7      3# V P                  V4       VR3#  LV5i)z_Run a ``send`` RPC, validate and track it; ``(result, None)`` or ``(None, failed SendResult)``.ÚsendNF©rI  r‰   )rI  r‰   Úraw_response)r  r   rL  Ú_track_sent_timestamp)r  r  r~  r"  rI  r>  s   &&&   r7   Ú	_rpc_sendÚSignalAdapter._rpc_send¸  su   é € à ŸI™I f¨fÓ5×5Ð5ˆFÒ>Øœ¨E¸ÔDÐDÐDØ×5Ñ5°fÓ=ÑˆßØœ¨E¸ÔVÐVÐVØ×"Ñ" 6Ô*Ø�tˆ|Ðñ 6ùs   ‚A1˜A/™AA1c                ón   <€ V ^8„  d   QhRS[ RS[ RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r@   r®  rB  Úreply_toÚmetadatarB   )rD   r   ro  r   r   )rF   rç   s   "€r7   rG   rè   Â  sJ   ø€ ÷ Sñ S¡#ð S±ð S¹xÉ½}ð SÙ%¡d©3±¨8¥nÕ5ðSÙAKñSr9   c           	   ƒ  óž  "  € V P                  V4      G Rj  x€L
  V'       d   VP                  4       '       g   \        RRR7      # V P                  RV P                  /V4      G Rj  x€L
 pV P
                  ! . \        V4      OV P                  N5!  pRp\        V^R7       F�  w  pw  rš\        WYR7      p\        V
4      ^8X  d   V
^ ,          VR&   MV
'       d   W«R&   \        P                  R	V\        V4      \        V	4      V4       V P                  VR
4      G Rj  x€L
 w  r|V'       g   KŽ  Vu # 	  \        RRVR7      #  EL/ Là L)5i)z2Send a text message with native Signal formatting.NT)rI  Ú
message_idrß   r´   )r¨  Ú	textStyleÚ
textStylesz6[Signal] Sending response chunk %d/%d (%d chars) to %szRPC send failed)rI  rŠ  r‚  )Ú_stop_typing_indicatorrK   r   r  rß   r{  r"   ÚMAX_MESSAGE_LENGTHrn  ro  rX   r•   r  r„  )r  r®  rB  r‡  rˆ  Úbase_paramsrr  Úlast_resultrx  ri  rX  r  r=  s   &&&&&        r7   r€  ÚSignalAdapter.sendÂ  s1  é € ð ×)Ñ)¨'Ó2×2Ð2ß˜gŸm™mŸošoÜ d°tÔ<Ð<Ø ×-Ñ-¨y¸$¿,¹,Ð.GÈÓQ×QˆØ×5Ò5ÐlÔ7IÈ'Ó7RÐlÐTX×TkÑTkÓlˆØˆÜ.7¸Àa×.HÑ*ˆCÑ*�*Ü%)¨+Ô%JˆFÜ�;Ó 1Ô$Ø&1°!¥n��{Ò#ßØ'2�|Ñ$Ü�K‰KÐPÐRUÔWZÐ[aÓWbÔdgÐhrÓdsØô!à%)§^¡^°FÐ<MÓ%N×NÑˆKß‰sØ’
ñ /Iô  $°4ÀkÔRÐRò% 	3ñ Rñ  OùsK   ‚E—E˜E¤Eº.EÁ(E	Á)A3EÃAEÄ!EÄ"EÄ2EÅ	EÅEc                ó   <€ V ^8„  d   QhRR/# r/  r3   )rF   rç   s   "€r7   rG   rè   Ù  s   ø€ ÷ 'ñ '°4ñ 'r9   c                ó   € \        V\        4      '       d   VP                  R4      MRpV'       g   R# V P                  V4       \        P
                  ! 4       V P                  rCVP                  VR4       W4V&   W0P                  ,
          pV'       d<   \        \        VP                  4       4      4      V8  d   VP                  RR7       KC  \        V4      V P                  8”  d   VP                  RR7       K.  R# )z:Record outbound message timestamp for echo-back filtering.rw  NFrû  )ry  ro  r·   rÿ  r$  Ú	monotonicr  rý  r  r”   Úiterr5  rþ  rX   r  )r  Ú
rpc_resultÚtsrÒ  ÚrecentÚcutoffs   &&    r7   rƒ  Ú#SignalAdapter._track_sent_timestampÙ  s¶   € ä,6°zÄ4×,HÒ,HˆZ�^‰^˜KÔ(ÈdˆßÙØ×-Ñ-¨bÔ1Ü—n’nÓ&¨×(DÑ(DˆVØ�
‰
�2�tÔØˆr‰
à×4Ñ4Õ4ˆßœœd 6§=¡=£?Ó3Ó4°vÔ=Ø�N‰N ˆNÖ&Ü�&‹k˜D×7Ñ7Ô7Ø�N‰N ˆNÖ&ñ 8r9   c                ó    <€ V ^8„  d   QhRS[ /# rÔ   rÕ   )rF   rç   s   "€r7   rG   rè   é  s   ø€ ÷ Sñ S©Tñ Sr9   c                ód   € \        V4      ;'       d    V P                  P                  VR4      RJ# )z@Pop a timestamp if it matches one we sent. Returns True on echo.N)r`   r  rý  )r  r—  s   &&r7   rz  Ú%SignalAdapter._consume_sent_timestampé  s,   € ä�B‹x×RÐR˜D×8Ñ8×<Ñ<¸RÀÓFÈdÐRÐRr9   c                ó$   <€ V ^8„  d   QhRS[ RR/# ©r@   r®  rB   Nrs   )rF   rç   s   "€r7   rG   rè   í  s   ø€ ÷ Zñ Z©ð ZÀñ Zr9   c              ƒ  ój  "  € \         P                  ! 4       pW0P                  P                  VR4      8  d   R# V P	                  RV P
                  /V4      G Rj  x€L
 pV P                  P                  V^ 4      pV P                  RVRV^ 8H  R7      G Rj  x€L
 e;   V P                  P                  VR4       V P                  P                  VR4       R# V^,           ;qPP                  V&   V^8¼  d8   V\        RR^V^,
          ,          ,          4      ,           V P                  V&   R# R#  LÓ L™5i)	zÃTyping indicator (called every ~2s by base.py's ``_keep_typing``). Only the first consecutive
failure logs at WARNING; after three, the RPC is skipped for an exponential cooldown; success resets.rò   Nrß   Ú
sendTypingÚtyping©r*  r&  r/   g      0@)
r$  r”  r  r·   r  rß   r   r  rý  rW  )r  r®  rˆ  rÒ  r  Úfailss   &&&   r7   Úsend_typingÚSignalAdapter.send_typingí  s  é € ô �nŠnÓˆØ×(Ñ(×,Ñ,¨W°cÓ:Ô:ÙØ×(Ñ(¨)°T·\±\Ð)BÀGÓL×LˆØ×%Ñ%×)Ñ)¨'°1Ó5ˆØ—‘˜<¨¸ÐPUÐYZÑPZ�Ó\×\ÒhØ×!Ñ!×%Ñ% g¨tÔ4Ø×#Ñ#×'Ñ'¨°Ô6ÙØ16¸µÐ:ˆ×%Ñ% gÑ.Ø�AŒ:Ø/2´S¸¸tÀqÈUÐUVÍYÕGWÕ?XÓ5YÕ/YˆD×#Ñ# GÓ,ñ ñ Má\ùs%   ‚AD3ÁD/Á;D3ÂD1ÂBD3Ä1D3c                ó`   <€ V ^8„  d   QhRS[ RS[S[S[ ,          S[S[ ,          S[3,          /# )r@   Ú	image_urlrB   )rD   ry   r   r   )rF   rç   s   "€r7   rG   rè   ý  s3   ø€ ÷ %ñ %±3ð %¹5ÁÉ#ÅÑPXÑY\ÕP]Ñ_bÐAbÕ;cñ %r9   c              ƒ  ó†  "  € VP                  R4      '       d   \        VR,          4      pM \        V4      G Rj  x€L
 pV'       d    \	        V4      P                  4       '       g   R# \	        V4      P                  4       P                  ;p\        8”  d   RRV3# VRR3#  Le  \         d   pRRT3u Rp?# Rp?ii ; i5i)zh``(path, None, None)`` or ``(None, reason, detail)``: reason download (exc) / missing / oversize (size).zfile://:é   NNNr1   r<   )Nr:   N)	rW   r   r   r§   r   ÚexistsÚstatÚst_sizer“  )r  r¨  Ú	file_pathr*  Ú	file_sizes   &&   r7   Ú_resolve_image_pathÚ!SignalAdapter._resolve_image_pathý  s°   é € à×Ñ 	×*Ò*Ü 	¨"¥Ó.‰Ið+Ü"6°yÓ"A×A�	÷ ¤ Y£× 6Ñ 6× 8Ò 8Ø(Ð(Ü˜i›×-Ñ-Ó/×7Ñ7Ð7ˆIÔ;UÔUØ˜ YÐ.Ð.Ø˜$ Ð$Ð$ñ BøÜô +Ø˜Z¨Ð*Õ*ûð+üsK   ‚+C®B$ ¼B"½B$ ÁCÁ	ACÂ"B$ Â$B>Â/B9Â3B>Â4CÂ9B>Â>Cc          
      ó„   <€ V ^8„  d   QhRS[ RS[S[S[ S[ 3,          ,          RS[S[S[ S[3,          ,          RS[RS[/# )r@   r®  Úimagesrˆ  Úhuman_delayrB   )rD   rE   ry   r   ro  r   r+  r   )rF   rç   s   "€r7   rG   rè     sT   ø€ ÷ )Qñ )Q±#ð )Q¹tÁEÉ#ÉsÈ(ÅOÕ?Tð )QÙ-5±d¹3Á¸8µnÕ-Eð)QÙ[`ð)QÙkuñ)Qr9   c           	   ƒ  óX  "  € V'       g   \        RRR7      # \        4       p\        P                  R\	        V4      VR,          VP                  4       4       V P                  V4      G Rj  x€L
  . pR^ R^ R	^ /pV Fu  w  r‰V P                  V4      G Rj  x€L
 w  r«pV'       g   VP                  V
4       K<  W{;;,          ^,          uu&   \        P                  ! \        V,          ! WŒ4      !   Kw  	  V'       gE   \        P                  R
\	        V4      VR,          VR,          VR	,          4       \        RRR7      # \        P                  R\	        V4      \	        V4      4       V P                  RV P                  RR/V4      G Rj  x€L
 p\        p\        ^ \	        V4      V4       Uu. uF  qöWÿV,            NK  	  pp\	        V4      pRp\!        V^R7       F˜  w  pp\	        V4      pVP#                  V4      p\        P%                  RVVVV4       V\&        8¼  d   V P)                  VVVV4      G Rj  x€L
  V P+                  V\-        VVR7      VV RV 24      G Rj  x€L
 '       g   K–  RpKš  	  \        TV'       d   RR7      # RR7      #  EL, EL ELu upi  Lh L>5i)a  Send a batch of images via chunked Signal RPC calls. Alt texts are dropped (one shared body
per send); bad images are skipped with a warning; ``human_delay`` is ignored (scheduler paces).
Returns success when at least one batch was accepted, so media-only turns report SUCCESS.Fzno images to sendr�  uP   Signal send_multiple_images: received %d image(s) for %s â€” scheduler state: %s:Né   NNr1   r:   r<   zKSignal: no valid images in batch of %d (download=%d missing=%d oversize=%d)zno valid images in batchzBSignal send_multiple_images: %d/%d images valid, sending in chunksrß   r¨  rÝ   r´   z8Signal batch %d/%d: %d attachments, estimated wait=%.1fs)r©  rê   Tz$all Signal attachment batches failed)r   r+   r•   r  rX   Ústater�  r°  r•  rŸ   Ú_SKIP_IMAGE_LOGr‰   r  rß   r$   Úrangern  Úestimate_waitr–   r#   Ú_notify_batch_pacingÚ_send_attachment_batchro  )r  r®  r³  rˆ  r´  Ú	schedulerr©  Úskippedr¨  Ú	_alt_textr®  Úreasonr6   r�  ÚperÚiÚatt_batchesÚ	n_batchesÚ	deliveredrx  Ú	att_batchÚnÚ	estimateds   &&&&&                  r7   Úsend_multiple_imagesÚ"SignalAdapter.send_multiple_images  s‡  é € ÷
 Ü eÐ3FÔGÐGÜ!“Oˆ	Ü�‰ÐfÔhkÐlrÓhsØ˜C•L )§/¡/Ó"3ô	5à×)Ñ)¨'Ó2×2Ð2Ø!#ˆØ˜q )¨Q°
¸AÐ>ˆÛ$*Ñ ˆIØ.2×.FÑ.FÀyÓ.Q×(QÑ%ˆI˜vßØ×"Ñ" 9Ô-ÙØ�O˜qÕ ‹OÜ�NŠNœO¨FÖ3°IÓFÔGñ %+÷ Ü�L‰LÐfÔhkÐlrÓhsØ  Õ,¨g°iÕ.@À'È*ÕBUôWä eÐ3MÔNÐNÜ�‰ÐXÔZ]Ð^iÓZjÔloÐpvÓlwÔxØ ×-Ñ-¨y¸$¿,¹,È	ÐSUÐ.VÐX_Ó`×`ˆÜ,ˆÜ7<¸QÄÀKÓ@PÐRUÔ7VÓWÑ7V°! 1¨¥WÓ-Ñ7VˆÐWÜ˜Ó$ˆ	Øˆ	Ü'¨¸1×=‰NˆC�Ü�I“ˆAØ!×/Ñ/°Ó2ˆIÜ�L‰LÐSÐUXÐZcÐefÐhqÔrØÔ@Ô@Ø×/Ñ/°¸¸iÈÓS×SÐSØ×0Ñ0°¼DÀÐZcÔ<dÐfgØ47°5¸¸)¸Ð1EóG÷ G÷ Gð Gà ’	ñ >ô Øß#�$ôQð 	Qà)OôQð 	Qò; 	3ò )Rò aùâWñ TñGùsu   ‚A*J*Á,JÁ-)J*ÂJÂA&J*Ã>BJ*ÆJÆ"J*Æ1J!ÇA9J*È=J&È>+J*É)J(É*J*É6#J*ÊJ*ÊJ*Ê!J*Ê(J*c                óH   <€ V ^8„  d   QhRS[ S[S[3,          RS[RS[RS[/# )r@   r  rÇ  ÚlabelrB   )ro  rD   r   r4  r`   )rF   rç   s   "€r7   rG   rè   7  s4   ø€ ÷ "ñ "¹dÁ3ÉÀ8½nð "ÑQTð "Ñ]`ð "Ñeiñ "r9   c              ƒ  ó  "  € \        V4      \        re\        ^V^,           4       EF?  pVP                  V4      G Rj  x€L
  \        P
                  ! 4       p V P                  RVRVR7      G Rj  x€L
 p	\        P
                  ! 4       T,
          pT	e   T P                  T	4      MRw  rÞT'       dF   T P                  T	4       TP                  YÃ4      G Rj  x€L
  \        P!                  RYCTYv4        R# \        P                  RYCYvYÉe   RT 2MR4       Yv8¼  d    R	# \        P!                  RTRT,          4       \"        P$                  ! RT,          4      G Rj  x€L
  EKB  	  R	#  EL. Lý  \         dˆ   p
TP                  T
P                  T4       T
P                  '       d   T
P                  R R2MRpYv8¼  d   \        P                  RYCT4        Rp
?
 R	# \        P                  R
YGYk4        Rp
?
EKØ  Rp
?
ii ; i EL. L¨5i)zéSend one attachment batch with rate-limit pacing and a single transient retry. Tokens are
deducted only on validated success (None = server never accepted it); 429s feed the scheduler.
Returns True when the server accepted the batch.Nr€  T)r'  r�   z.0fÚsÚunknownz]Signal: rate-limit retries exhausted on batch %s (%d attachments lost, server retry_after=%s)FzfSignal: rate-limited on batch %s (attempt %d/%d, server retry_after=%s); scheduler will pace the retryz=Signal batch %s: %d attachments sent in %.1fs (attempt %d/%d)zZSignal: RPC send failed for batch %s (%d attachments, attempt %d/%d, rpc_duration=%.1fs)%sz: rÝ   z-Signal: retrying batch %s after %.1fs backoffr.   )FN)r*   r%   r¹  Úacquirer$  r”  r  r&   Úfeedbackr/  r•   r‰   rŸ   rL  rƒ  Úreport_rpc_durationr  r  rU  )r  r½  r  rÇ  rÌ  Úsend_timeoutÚmax_attemptsÚattemptÚt0r"  r*  r/  ÚdurationrI  r>  s   &&&&&          r7   r¼  Ú$SignalAdapter._send_attachment_batch7  sÊ  é € ô &:¸!Ó%<Ô>\�lÜ˜Q ¨qÕ 0×1ˆGØ×#Ñ# AÓ&×&Ð&Ü—’Ó!ˆBðØ#Ÿy™y¨°ÈTÐ[g˜yÓh×h�ô —~’~Ó'¨"Õ,ˆHØEKÒEW˜t×9Ñ9¸&ÔAÐ]jÑˆGßØ×*Ñ*¨6Ô2Ø×3Ñ3°HÓ@×@Ð@Ü—‘Ð[Ð]bÐgoØ#ô3âÜ�L‰LÐuØ 7¸(ÒVhÀbÈÈ	ÁNÐnpôràÔ&ÚÜ�K‰KÐGÈÐPSÐW^ÕP^Ô_Ü—-’-  w¥Ó/×/Ó/ñ9 2ñ: ò9 'ñ iøÜ'ô 	Ø×"Ñ" 1§=¡=°!Ô4Ø9:¿¿¸ §¡¨sÐ 3°1Ñ5ÈI�ØÔ*Ü—L‘Lð ":Ø;@À[ôRæ Ü—‘ð  ?Ø@EÐP\ôkæûð	úò Añ 0ùsx   ‚<H¾E,¿HÁE1Á1E/Á2E1Á6A"HÃHÃBHÅ H	Å!HÅ/E1Å1HÅ<AG>ÇHÇ G>Ç7HÇ>HÈHÈ	Hc          
      ó6   <€ V ^8„  d   QhRS[ RS[RS[RS[RR/# )r@   r®  Únext_batch_idxÚtotal_batchesÚwait_srB   N)rD   r4  r+  )rF   rç   s   "€r7   rG   rè   [  s:   ø€ ÷ Jñ J±#ð JÁsð JÑ[^ð JÑhmð JÐrvñ Jr9   c           
   ƒ  óÐ   "  €  V P                  V\        R\        V4      W#R7      4      G Rj  x€L
  R#  L  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i5i)zWTell the user about an inter-batch pacing wait over the notice threshold (best-effort).z#platform.signal.batch_pacing_notice)ÚwaitÚbatchÚtotalNz(Signal: failed to send pacing notice: %s)Úemit_warningr   r(   r§   r•   rŸ   )r  r®  rÚ  rÛ  rÜ  r*  s   &&&&& r7   r»  Ú"SignalAdapter._notify_batch_pacing[  sb   é € ð	JØ×#Ñ# G¬QØ5Ü! &Ó)°ô.Vó W÷ Wô Wøô ô 	JÜ�N‰NÐEÀq×IÒIûð	Jüs7   ‚A&„*7 ®5¯7 ³A&µ7 ·A#ÁAÁA&ÁA#Á#A&c                óB   <€ V ^8„  d   QhRS[ RS[ RS[S[ ,          RS[/# )r@   r®  r¨  ÚcaptionrB   ©rD   r   r   )rF   rç   s   "€r7   rG   rè   d  s4   ø€ ÷ 
eñ 
e©ð 
e¹ð 
eÁhÉsÅmð 
eÑisñ 
er9   c              ‹  óN  "  € V P                  V4      G Rj  x€L
  V P                  V4      G Rj  x€L
 w  rVpVR8X  d   \        P                  RV4       V'       d(   \	        RR\        V4      RRRRV R	2/V,          R
7      # V P                  WVR4      G Rj  x€L
 #  L‡ Lp L5i)z4Send an image. Supports http(s):// and file:// URLs.Nr1   z$Signal: failed to download image: %sFr:   zImage file not foundr<   zImage too large (ú bytes)r�  zRPC send with attachment failed)r�  r°  r•   rŸ   r   rD   Ú
_send_file)r  r®  r¨  rä  Úkwargsr®  rÀ  r6   s   &&&&,   r7   Ú
send_imageÚSignalAdapter.send_imaged  s¯   é € à×)Ñ)¨'Ó2×2Ð2Ø*.×*BÑ*BÀ9Ó*M×$MÑ!ˆ	˜6Ø�ZÔÜ�N‰NÐAÀ6ÔJßÜ eØœC ›K¨Ð4JØÐ/°¨x°wÐ?ð4AàAGõ4Iô Jð Jð —_‘_ W¸ÐBcÓd×dÐdñ 	3Ù$Mñ eùs7   ‚B%—B˜B%°B!±+B%Á=B%ÂB#ÂB%Â!B%Â#B%c          
      óH   <€ V ^8„  d   QhRS[ RS[ RS[S[ ,          RS[ RS[/# )r@   r®  r®  rä  r~  rB   rå  )rF   rç   s   "€r7   rG   rè   p  s6   ø€ ÷ /ñ /©ð /¹ð /ÁhÉsÅmð /Ñadð /Ñisñ /r9   c              ƒ  óÞ   "  € T P                  RV P                  RT;'       g    RRV./V4      G Rj  x€L
 pV P                  WT4      G Rj  x€L
 w  rgT;'       g    \        RR7      #  L5 L5i)z@Send one local file as a Signal attachment via the ``send`` RPC.rß   r¨  rÝ   r©  NT)rI  )r  rß   r„  r   )r  r®  r®  rä  r~  r  r.  r=  s   &&&&&   r7   rè  ÚSignalAdapter._send_filep  sk   é € à×(Ñ(Ø˜Ÿ™ i°·°¸BÀÐPYÈ{Ð[Ð]dóf÷ fˆà—~‘~ fÓ9×9‰ˆØ×.Ð.”j¨Ô.Ð.ñfá9ùs'   ‚1A-³A)´A-ÁA+ÁA-ÁA-Á+A-c          
      óH   <€ V ^8„  d   QhRS[ RS[ RS[ RS[S[ ,          RS[/# )r@   r®  r®  Úmedia_labelrä  rB   rå  )rF   rç   s   "€r7   rG   rè   w  s>   ø€ ÷ 
lñ 
l©cð 
l¹cð 
lÑPSð 
lÙ(0±­ð
lÙAKñ
lr9   c              ƒ  óh  "  € V P                  V4      G Rj  x€L
   \        V4      P                  4       P                  pT\        8”  d   \        RT RT R2R7      # T P                  YTRTP                  4        R24      G Rj  x€L
 #  Ls  \         d    \        RT RT 2R7      u # i ; i L)5i)	z\Send any local file as a Signal attachment (shared by send_document/image_file/voice/video).NFz file not found: r�  z too large (rç  z	RPC send z failed)	r�  r   r¬  r­  ÚFileNotFoundErrorr   r“  rè  rg   )r  r®  r®  rð  rä  r¯  s   &&&&& r7   Ú_send_attachmentÚSignalAdapter._send_attachmentw  sÂ   é € ð ×)Ñ)¨'Ó2×2Ð2ð	aÜ˜Y›×,Ñ,Ó.×6Ñ6ˆIð Ô1Ô1Ü e°k°]À,ÈyÈkÐY`Ð3aÔbÐbØ—_‘_ W¸ÀIÈk×N_ÑN_ÓNaÐMbÐbiÐBjÓk×kÐkñ 	3øô !ô 	aÜ e°k°]ÐBSÐT]ÐS^Ð3_Ô`Ò`ð	aúñ lùs?   ‚B2—B˜B2�#B Á AB2ÂB0ÂB2ÂB-Â*B2Â,B-Â-B2c                ó    <€ V ^8„  d   QhRS[ /# rÔ   ©r   )rF   rç   s   "€r7   rG   rè   ƒ  s   ø€ ÷ Pñ PÑ`jñ Pr9   c              ‹  óD   "  € V P                  WR V4      G Rj  x€L
 #  L5i)ÚFileN©ró  )r  r®  r®  rä  Úfilenameré  s   &&&&&,r7   Úsend_documentÚSignalAdapter.send_documentƒ  s    é € Ø×*Ñ*¨7¸vÀwÓO×OÐOÑOùó   ‚ ™š c                ó    <€ V ^8„  d   QhRS[ /# rÔ   rö  )rF   rç   s   "€r7   rG   rè   †  s   ø€ ÷ Rñ RÑcmñ Rr9   c              ‹  óD   "  € V P                  WRV4      G Rj  x€L
 #  L5i)z>Native Signal attachment for the gateway MEDIA: delivery path.ÚImageNrù  )r  r®  Ú
image_pathrä  r‡  ré  s   &&&&&,r7   Úsend_image_fileÚSignalAdapter.send_image_file†  ó    é € à×*Ñ*¨7ÀÈÓQ×QÐQÑQùrý  c                ó    <€ V ^8„  d   QhRS[ /# rÔ   rö  )rF   rç   s   "€r7   rG   rè   Š  s   ø€ ÷ Rñ RÑ^hñ Rr9   c              ‹  óD   "  € V P                  WRV4      G Rj  x€L
 #  L5i)u>   Audio attachment â€” Signal has no distinct voice-message API.ÚAudioNrù  )r  r®  Ú
audio_pathrä  r‡  ré  s   &&&&&,r7   Ú
send_voiceÚSignalAdapter.send_voiceŠ  r  rý  c                ó    <€ V ^8„  d   QhRS[ /# rÔ   rö  )rF   rç   s   "€r7   rG   rè   Ž  s   ø€ ÷ Rñ RÑ^hñ Rr9   c              ‹  óD   "  € V P                  WR V4      G Rj  x€L
 #  L5i)ÚVideoNrù  )r  r®  Ú
video_pathrä  r‡  ré  s   &&&&&,r7   Ú
send_videoÚSignalAdapter.send_videoŽ  s    é € Ø×*Ñ*¨7ÀÈÓQ×QÐQÑQùrý  c                ó$   <€ V ^8„  d   QhRS[ RR/# rŸ  rs   )rF   rç   s   "€r7   rG   rè   ‘  s   ø€ ÷ 
3ñ 
3±Cð 
3¸Dñ 
3r9   c           	   ƒ  óÚ  "  € \        V P                  P                  VR4      4      G Rj  x€L
  \        \        4      ;_uu_ 4        V P                  RV P                  /V4      G Rj  x€L
 pRVR&   V P                  RVRRR7      G Rj  x€L
  RRR4       V P                  P                  VR4       V P                  P                  VR4       R#  L¦ Lj LJ  + '       g   i     LP; i5i)	z(Stop a typing indicator loop for a chat.Nrß   TÚstopr¡  ztyping-stopFr£  )
r   rÿ   rý  r   r§   r  rß   r  r   r  ©r  r®  r  s   && r7   r�  Ú$SignalAdapter._stop_typing_indicator‘  s¿   é € ä˜$×,Ñ,×0Ñ0°¸$Ó?Ó@×@Ð@ô ”i× Õ Ø×,Ñ,¨i¸¿¹Ð-FÈÓP×PˆFØ!ˆF�6‰NØ—)‘)˜L¨&¸ÐUZ�)Ó[×[Ð[÷ !ð 	×Ñ×!Ñ! '¨4Ô0Ø×Ñ×#Ñ# G¨TÖ2ñ 	Añ Qá[÷ !× üsL   ‚)C+«C¬C+Á"CÁ)CÁ*!CÂCÂCÂAC+ÃCÃCÃC(	Ã#C+c                ó$   <€ V ^8„  d   QhRS[ RR/# rŸ  rs   )rF   rç   s   "€r7   rG   rè   �  s   ø€ ÷ 3ñ 3©ð 3°ñ 3r9   c              ƒ  óD   "  € V P                  V4      G Rj  x€L
  R#  L5i)zRPublic stop-typing hook called from the base adapter's _keep_typing finally block.N)r�  )r  r®  s   &&r7   Ústop_typingÚSignalAdapter.stop_typing�  s   é € à×)Ñ)¨'Ó2×2Ô2ùs   ‚ —˜ c                óB   <€ V ^8„  d   QhRS[ RS[S[ S[3,          RS[/# )r@   r®  r  rB   )rD   ro  r   r`   )rF   rç   s   "€r7   rG   rè   ¡  s0   ø€ ÷ Cñ C±ð C¹TÁ#ÁsÀ(½^ð CÑPTñ Cr9   c              ƒ  ó€   "  € V P                  W!RR7      G Rj  x€L
  V P                  RV4      G Rj  x€L
 RJ#  L  L5i)ub   Route a ``sendReaction`` RPC to *chat_id* (no UUID upgrade â€” author IDs come from the envelope).F)r  NÚsendReaction)r  r  r  s   &&&r7   Ú_send_reaction_rpcÚ SignalAdapter._send_reaction_rpc¡  s@   é € à×Ñ ¸ÐÓ?×?Ð?Ø—Y‘Y˜~¨vÓ6×6¸dÐBÐBñ 	@Ù6ùs   ‚>™:š>³<´>¼>c          
      ó8   <€ V ^8„  d   QhRS[ RS[ RS[ RS[RS[/# )r@   r®  ÚemojiÚtarget_authorÚtarget_timestamprB   ©rD   r4  r`   )rF   rç   s   "€r7   rG   rè   ¦  s2   ø€ ÷ ñ ©3ð ±sð É3ð Ñbeð Ñjnñ r9   c              ƒ  ó¶   "  € V P                  VRV P                  RVRVRV/4      G Rj  x€L
 pV'       g   \        P                  RVR,          V4       V#  L,5i)zRReact to the message (author number/UUID, Signal ms timestamp) via signal-cli RPC.rß   r   ÚtargetAuthorÚtargetTimestampNz/Signal: sendReaction failed (chat=%s, emoji=%s)rÈ  )r  rß   r•   r–   )r  r®  r   r!  r"  Úoks   &&&&& r7   Úsend_reactionÚSignalAdapter.send_reaction¦  s^   é € à×*Ñ*¨7Ø�t—|‘| W¨e°^À]ØÐ/ð51ó 2÷ 2ˆ÷ Ü�L‰LÐJÈGÐTWÍLÐZ_Ô`Øˆ	ñ2ùs   ‚(AªA«A·!Ac                ó2   <€ V ^8„  d   QhRS[ RS[ RS[RS[/# )r@   r®  r!  r"  rB   r#  )rF   rç   s   "€r7   rG   rè   ¯  s+   ø€ ÷ ñ ©Sð Áð ÑX[ð Ñ`dñ r9   c              ƒ  ój   "  € V P                  VRV P                  RRRVRVRR/4      G Rj  x€L
 #  L5i)	z3Remove a reaction by sending an empty-string emoji.rß   r   rÝ   r%  r&  ÚremoveTN)r  rß   )r  r®  r!  r"  s   &&&&r7   Úremove_reactionÚSignalAdapter.remove_reaction¯  sE   é € à×,Ñ,¨WØ�t—|‘| W¨b°.À-ÐQbÐdtØ�dð7ó ÷ ð 	ñ ùs   ‚*3¬1­3c                ó6   <€ V ^8„  d   QhRS[ RS[S[,          /# ©r@   râ  rB   )r   r   ry   )rF   rç   s   "€r7   rG   rè   µ  s#   ø€ ÷ Dñ D©lð D¹xÉ½ñ Dr9   c                óÖ   € VP                   p\        V\        4      ;'       d+    VP                  R4      ;'       d    VP                  R4      pV'       d   VR,          VR,          3# R# )zGExtract (target_author, target_timestamp) from a MessageEvent, or None.r½  r¾  N)rÂ  ry  ro  r·   )r  râ  Úrawr'  s   &&  r7   Ú_extract_reaction_targetÚ&SignalAdapter._extract_reaction_targetµ  sV   € à×ÑˆÜ˜œTÓ"×TÐT s§w¡w¨xÓ'8×TÐT¸S¿W¹WÀ^Ó=Tˆß79��H•˜s >Õ2Ð3ÐC¸tÐCr9   c                ó&   <€ V ^8„  d   QhRS[ RS[/# r0  )r   r`   )rF   rç   s   "€r7   rG   rè   »  s   ø€ ÷ cñ c©ð cÁñ cr9   c                óú   € \        \        RR4      4      P                  4       R9   d   R# Ve   \        \        VRR4      RR4      MRpT;'       d&    RV P                  9  ;'       d    W P                  9  '       * # )	u¥   SIGNAL_REACTIONS env gate, then the DM allowlist: reactions fire before run.py's auth gate,
so an unauthorized contact's ðŸ‘€ would otherwise reveal a listening bot.ÚSIGNAL_REACTIONSÚtrueFNr£  r±  rñ   >   Ú0Únorï   )rD   râ   rg   rá   rû   )r  râ  r½  s   && r7   Ú_reactions_enabledÚ SignalAdapter._reactions_enabled»  sr   € ô Œ{Ð-¨vÓ6Ó7×=Ñ=Ó?ÐCWÔWÙØMRÒM^”œ ¨°$Ó7¸ÀDÔIÐdhˆØ×aÐa˜s¨$×*<Ñ*<Ñ<×aÐaÀ×OaÑOaÑAaÔbÐbr9   c                ó$   <€ V ^8„  d   QhRS[ RR/# )r@   râ  rB   N)r   )rF   rç   s   "€r7   rG   rè   Ã  s   ø€ ÷ Lñ L©|ð LÀñ Lr9   c              ƒ  óÜ   "  € V P                  V4      '       dO   V P                  V4      ;p'       d4   V P                  ! VP                  P                  R.VO5!  G Rj  x€L
  R# R# R#  L
5i)u'   React with ðŸ‘€ when processing begins.u   ðŸ‘€N)r;  r3  r(  r£  r®  )r  râ  Útargets   && r7   Úon_processing_startÚ!SignalAdapter.on_processing_startÃ  s]   é € à×"Ñ" 5×)Ò)¸×9VÑ9VÐW\Ó9]Ð/]¨vÖ/]Ø×$Ò$ U§\¡\×%9Ñ%9¸6ÐKÀFÓK×KÒKñ 0^Ñ)ÙKùs   ‚0A,³,A,ÁA*Á A,c                ó*   <€ V ^8„  d   QhRS[ RS[RR/# )r@   râ  ÚoutcomerB   N)r   r   )rF   rç   s   "€r7   rG   rè   È  s)   ø€ ÷ Kñ K±,ð KÑIZð KÐ_cñ Kr9   c              ƒ  ó¨  "  € V\         P                  8X  g   V P                  V4      '       g   R# V P                  V4      ;p'       g   R# V P                  ! VP
                  P                  .VO5!  G Rj  x€L
  \        P                  V4      ;p'       d4   V P                  ! VP
                  P                  V.VO5!  G Rj  x€L
  R# R#  LV L
5i)ug   Swap ðŸ‘€ for âœ…/â�Œ; on CANCELLED the ðŸ‘€ stays to keep reflecting "in progress" (matches Telegram).N)
r   Ú	CANCELLEDr;  r3  r-  r£  r®  Ú_OUTCOME_REACTIONr·   r(  )r  râ  rC  r?  r   s   &&&  r7   Úon_processing_completeÚ$SignalAdapter.on_processing_completeÈ  s­   é € àÔ'×1Ñ1Ô1¸×9PÑ9PÐQV×9WÒ9WÙØ×7Ñ7¸Ó>Ð>�Ö>ÙØ×"Ò" 5§<¡<×#7Ñ#7ÐA¸&ÓA×AÐAÜ%×)Ñ)¨'Ó2Ð2ˆ5Ö2Ø×$Ò$ U§\¡\×%9Ñ%9¸5ÐJÀ6ÓJ×JÒJñ 3ñ 	BáJùs4   ‚,C¯CÁ
-CÁ7CÁ8 CÂ,CÃCÃ	CÃCc                ó<   <€ V ^8„  d   QhRS[ RS[S[ S[3,          /# r  )rD   ro  r   )rF   rç   s   "€r7   rG   rè   Ò  s'   ø€ ÷ Kñ K©3ð K±4¹¹S¸µ>ñ Kr9   c              ƒ  óD  "  € VP                  R4      '       d	   RVRRRV/# V P                  RRV P                  RV/4      G R	j  x€L
 p\        V\        4      '       d+   VP                  R4      ;'       g    VP                  R
4      MR	pRT;'       g    TRRRV/#  LX5i)z%Get information about a chat/contact.r§  rš   r1  r¬  r®  Ú
getContactrß   ÚcontactAddressNÚprofileNamer­  )rW   r  rß   ry  ro  r·   )r  r®  r"  rš   s   &&  r7   Úget_chat_infoÚSignalAdapter.get_chat_infoÒ  sš   é € à×Ñ˜h×'Ò'Ø˜G V¨W°iÀÐIÐIØ—y‘y °	¸4¿<¹<ÐIYÐ[bÐ/cÓd×dˆÜDNÈvÔW[×D\ÒD\�—
‘
˜6Ó"×?Ð? f§j¡j°Ó&?øÐbfˆØ˜Ÿ˜ ¨°°yÀ'ÐJÐJñ eùs   ‚AB ÁBÁ1B Á8B Â	B )r  rþ   r  r  r
  r  r  r  r  r  r  r	  r  rý   r   r  rÿ   rß   rü   rû   rú   rÜ   rë   rí   r}   )NN)Nrò   )FÚ__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r÷   ÚplatformrŽ  Úsplits_long_messagesÚserial_receive_loopÚSUPPORTS_MESSAGE_EDITINGrö   r,  r!  r:  rG  r&  r'  rb  r~  r‹  rœ  rB  rÌ  rË  ÚstaticmethodrÍ  rÔ  rÿ  r  r  r  r”  r  rD  rL  rU  rf  Úclassmethodr{  r„  r€  rƒ  rz  r¥  r°  rÉ  r¼  r»  rê  rè  ró  rû  r  r	  r  r�  r  r  r(  r-  r3  r;  r@  rG  rN  Ú__static_attributes__Ú__classdictcell__Ú__classcell__)r  rç   s   @@r7   rå   rå   ±   sË  ù‡ € Ù@à�‰€HØ+ÐØÐØÐà$Ð÷'dó 'dðR%2°E÷ %2ò %2÷Nð ÷

,ð 
,÷Eð E÷!"ð !"÷F(ð (÷,&ð &÷:ð :÷ð ÷$'ð '÷(P)ð P)÷d	ð 	÷@ð @ð ÷Só ðS÷
	Vð 	V÷>ð >÷ð ÷Hð Hð"ÐZ^÷ ò ÷/ð /ñ(!Ðgkð !Ø/4ð!ØGK÷!ó !÷Fð ÷ð ð ÷Ló ðLð ÷ó ðð ÷gó ðg÷.ð ÷Sò S÷.'ð '÷ Sð S÷Zò Z÷ %ð %÷)Qò )Q÷V"ð "÷HJð J÷
eò 
e÷/ð /÷
lò 
l÷Pò P÷Rò R÷Rò R÷Rò R÷
3ð 
3÷3ð 3÷Cð C÷
ð ÷ð ÷Dð D÷cò c÷Lð L÷
Kð K÷K÷ Kð Kr9   rå   i  @))s   ‰PNGrd   )s   ÿØrb   )s   GIF8rc   )s   %PDFz.pdf)rö  ÚauthorNumberÚ
authorUuidÚ	authorAciÚauthorServiceIdÚauthorServiceIdString)irT  r  r  rS  rC  r5  r~   rV  r’   r›   r—   r$  r¾   Úcollectionsr   Ú
contextlibr   r   r   r   Úpathlibr   r¢  r   r	   r
   r   r   Úurllib.parser   r   r  Úgateway.configr   r   Ú
agent.i18nr   Úgateway.platforms.baser   r   r   r   r   r   r   Úgateway.platforms.eventr   r   r   Úgateway.platforms.helpersr   r   Úgateway.platforms.media_cacher   Útools.audio_containerr    r!   Ú&plugins.platforms.signal.signal_formatr"   Ú*plugins.platforms.signal.signal_rate_limitr#   r$   r%   r&   r'   r(   r)   r*   r+   Úgateway.platforms._sharedr,   râ   Úutilsr-   Ú	getLoggerrP  r•   r“  rŽ  rP  rX  r`  ra  rV   ÚVOICEÚPHOTOÚVIDEOrÐ  rH  ÚFAILURErF  r¸  rñ  rM   r\   ri   rq   rv   r®   rÄ   rÌ   rÒ   r×   rã   rå   r3   r9   r7   Ú<module>rw     s�  ðñó Û Û Û Û Û 	Û Û Û Û Û Û Ý #Ý ß ,Ñ ,Ý ß 3Õ 3ß 'ã ç 3Ý ÷÷ ñ ÷ QÑ PÝ 2Ý 1Ý 6ß CÝ E÷)÷ )õ )õ GÝ  à	×	Ò	˜8Ó	$€à.Ð ØÐ ØÐ ØÐ ØÐ Ø$Ð ð hÐ àˆ{× Ñ Ð! H¨k×.?Ñ.?Ð#@À8È[×M^ÑM^ÐB_ðaÐ à&×.Ñ.°Ð7H×7PÑ7PÐRWÐXÐ ð Ñ\ØÑOØÑdðf€ðeÐ õ>õ

3õEõCõBõ
!õHõ	õgõ
õ
&ôgKÐ'ö gKr9   