diff --git a/client/src/telethon/_impl/client/events/queries.py b/client/src/telethon/_impl/client/events/queries.py index c68a1d52..00c39284 100644 --- a/client/src/telethon/_impl/client/events/queries.py +++ b/client/src/telethon/_impl/client/events/queries.py @@ -1,9 +1,10 @@ from __future__ import annotations +import struct from typing import TYPE_CHECKING, Dict, Optional, Self, Union from ...tl import abcs, functions, types -from ..types import Chat, Message +from ..types import Chat, Message, Channel from .event import Event from ..types.chat import peer_id from ..client.messages import CherryPickedList @@ -34,7 +35,10 @@ class ButtonCallback(Event): cls, client: Client, update: abcs.Update, chat_map: Dict[int, Chat] ) -> Optional[Self]: if ( - isinstance(update, (types.UpdateBotCallbackQuery, types.UpdateInlineBotCallbackQuery)) + isinstance( + update, + (types.UpdateBotCallbackQuery, types.UpdateInlineBotCallbackQuery), + ) and update.data is not None ): return cls._create(client, update, chat_map) @@ -51,10 +55,41 @@ class ButtonCallback(Event): """ The :term:`chat` where the button was clicked. - This will be :data:`None` if the message with the button was sent from a user's inline query. + This will be :data:`None` if the message with the button was sent from a user's inline query, except in channel. """ if isinstance(self._raw, types.UpdateInlineBotCallbackQuery): - return None + owner_id = None + if isinstance(self._raw.msg_id, types.InputBotInlineMessageId): + _, owner_id = struct.unpack(" 0: + # We can't know if it's really a chat with user, or an ID of the user who issued the inline query. + # So it's better to return None, then to return wrong chat. + return None + + owner_id = -owner_id + + access_hash = 0 + packed = self.client._chat_hashes.get(owner_id) + if packed: + access_hash = packed.access_hash + + return Channel._from_raw( + types.ChannelForbidden( + broadcast=True, + megagroup=False, + id=owner_id, + access_hash=access_hash, + title="", + until_date=None, + ) + ) return self._chat_map.get(peer_id(self._raw.peer)) async def answer( @@ -91,20 +126,57 @@ class ButtonCallback(Event): If the message is inline, or too old and is no longer accessible, :data:`None` is returned instead. """ + chat = None + if isinstance(self._raw, types.UpdateInlineBotCallbackQuery): - return None + # for that type of update, the msg_id and owner_id are present, however bot is not guaranteed + # to have "access" to the owner_id. + if isinstance(self._raw.msg_id, types.InputBotInlineMessageId): + # telegram used to pack msg_id and peer_id into InputBotInlineMessageId.id + # I assume this is for the chats with IDs, fitting into 32-bit integer. + msg_id, owner_id = struct.unpack( + "