diff --git a/.github/ci.yml b/.github/ci.yml index 433e310..9f08f4f 100644 --- a/.github/ci.yml +++ b/.github/ci.yml @@ -2,7 +2,7 @@ pr: none trigger: - master -name: 1.4.1-ci.$(Rev:r) +name: 1.4.2-ci.$(Rev:r) pool: vmImage: ubuntu-latest diff --git a/EXAMPLES.md b/EXAMPLES.md index aa6b849..01af4f1 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -22,8 +22,8 @@ await client.SendMessageAsync(resolved.users[resolved.peer.ID], "Hello!"); ```csharp using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); await client.LoginUserIfNeeded(); -var imported = await client.Contacts_ImportContacts(new[] { new InputPhoneContact { phone = "+PHONENUMBER" } }); -await client.SendMessageAsync(imported.users[imported.imported[0].user_id], "Hello!"); +var contacts = await client.Contacts_ImportContacts(new[] { new InputPhoneContact { phone = "+PHONENUMBER" } }); +await client.SendMessageAsync(contacts.users[contacts.imported[0].user_id], "Hello!"); ``` *Note: To prevent spam, Telegram may restrict your ability to add new phone numbers.* @@ -33,7 +33,8 @@ using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); await client.LoginUserIfNeeded(); var chats = await client.Messages_GetAllChats(null); foreach (var (id, chat) in chats.chats) - Console.WriteLine($"{id} : {chat}"); + if (chat.IsActive) + Console.WriteLine($"{id} : {chat}"); Console.Write("Choose a chat ID to send a message to: "); long chatId = long.Parse(Console.ReadLine()); await client.SendMessageAsync(chats.chats[chatId], "Hello, World"); @@ -72,16 +73,15 @@ if (dialogsBase is Messages_Dialogs dialogs) while (dialogs.dialogs.Length != 0) { foreach (var dialog in dialogs.dialogs) - if (dialog is Dialog { peer: var peer } || (dialog is DialogFolder dialogFolder && (peer = dialogFolder.peer) != null)) - switch (peer) - { - case PeerUser: Console.WriteLine("User " + dialogs.users[peer.ID]); break; - case PeerChannel or PeerChat: Console.WriteLine(dialogs.chats[peer.ID]); break; - } - var lastDialog = (Dialog)dialogs.dialogs[^1]; - var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.peer.ID && m.ID == lastDialog.top_message); - InputPeer offsetPeer = lastDialog.peer is PeerUser pu ? dialogs.users[pu.ID] : dialogs.chats[lastDialog.peer.ID]; - dialogs = (Messages_Dialogs)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.top_message, offsetPeer, 500, 0); + switch (dialogs.GetUserOrChat(dialog)) + { + case UserBase user when user.IsActive: Console.WriteLine("User " + user); break; + case ChatBase chat when chat.IsActive: Console.WriteLine(chat); break; + } + var lastDialog = dialogs.dialogs[^1]; + var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage); + var offsetPeer = dialogs.GetUserOrChat(lastDialog).ToInputPeer(); + dialogs = (Messages_Dialogs)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.TopMessage, offsetPeer, 500, 0); } ``` diff --git a/Examples/Program_ListenUpdates.cs b/Examples/Program_ListenUpdates.cs index 3a32bd9..4e5de83 100644 --- a/Examples/Program_ListenUpdates.cs +++ b/Examples/Program_ListenUpdates.cs @@ -26,10 +26,10 @@ namespace WTelegramClientTest { foreach (var (id, user) in dialogs.users) users[id] = user; foreach (var (id, chat) in dialogs.chats) chats[id] = chat; - var lastDialog = (Dialog)dialogs.dialogs[^1]; - var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.peer.ID && m.ID == lastDialog.top_message); - InputPeer offsetPeer = lastDialog.peer is PeerUser pu ? dialogs.users[pu.ID] : dialogs.chats[lastDialog.peer.ID]; - dialogs = (Messages_Dialogs)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.top_message, offsetPeer, 500, 0); + var lastDialog = dialogs.dialogs[^1]; + var lastMsg = dialogs.messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage); + var offsetPeer = dialogs.GetUserOrChat(lastDialog).ToInputPeer(); + dialogs = (Messages_Dialogs)await client.Messages_GetDialogs(lastMsg?.Date ?? default, lastDialog.TopMessage, offsetPeer, 500, 0); } Console.ReadKey(); await client.Ping(42); // dummy API call diff --git a/src/Helpers.TL.cs b/src/Helpers.TL.cs index 77f8f6f..f743660 100644 --- a/src/Helpers.TL.cs +++ b/src/Helpers.TL.cs @@ -9,45 +9,56 @@ namespace TL partial class InputPeer { public static InputPeerSelf Self => new(); } partial class InputUser { public static InputUserSelf Self => new(); } - partial class ChatBase + public interface IPeerInfo { + long ID { get; } + bool IsActive { get; } + InputPeer ToInputPeer(); + } + + partial class ChatBase : IPeerInfo { public abstract long ID { get; } public abstract string Title { get; } + public abstract bool IsActive { get; } /// returns true if you're banned of any of these rights public abstract bool IsBanned(ChatBannedRights.Flags flags = 0); - protected abstract InputPeer ToInputPeer(); + public abstract InputPeer ToInputPeer(); public static implicit operator InputPeer(ChatBase chat) => chat.ToInputPeer(); } partial class ChatEmpty { public override long ID => id; public override string Title => null; + public override bool IsActive => false; public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true; - protected override InputPeer ToInputPeer() => null; + public override InputPeer ToInputPeer() => null; public override string ToString() => $"ChatEmpty {id}"; } partial class Chat { public override long ID => id; public override string Title => title; + public override bool IsActive => (flags & (Flags.kicked | Flags.left | Flags.deactivated)) == 0; public override bool IsBanned(ChatBannedRights.Flags flags = 0) => ((default_banned_rights?.flags ?? 0) & flags) != 0; - protected override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id }; + public override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id }; public override string ToString() => $"Chat \"{title}\""; } partial class ChatForbidden { public override long ID => id; public override string Title => title; + public override bool IsActive => false; public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true; - protected override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id }; + public override InputPeer ToInputPeer() => new InputPeerChat { chat_id = id }; public override string ToString() => $"ChatForbidden {id} \"{title}\""; } partial class Channel { public override long ID => id; public override string Title => title; + public override bool IsActive => (flags & Flags.left) == 0; public override bool IsBanned(ChatBannedRights.Flags flags = 0) => ((banned_rights?.flags ?? 0) & flags) != 0 || ((default_banned_rights?.flags ?? 0) & flags) != 0; - protected override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash }; + public override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash }; public static implicit operator InputChannel(Channel channel) => new() { channel_id = channel.id, access_hash = channel.access_hash }; public override string ToString() => (flags.HasFlag(Flags.broadcast) ? "Channel " : "Group ") + (username != null ? '@' + username : $"\"{title}\""); @@ -56,15 +67,17 @@ namespace TL { public override long ID => id; public override string Title => title; + public override bool IsActive => false; public override bool IsBanned(ChatBannedRights.Flags flags = 0) => true; - protected override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash }; + public override InputPeer ToInputPeer() => new InputPeerChannel { channel_id = id, access_hash = access_hash }; public override string ToString() => $"ChannelForbidden {id} \"{title}\""; } - partial class UserBase + partial class UserBase : IPeerInfo { public abstract long ID { get; } - protected abstract InputPeer ToInputPeer(); + public abstract bool IsActive { get; } + public abstract InputPeer ToInputPeer(); protected abstract InputUserBase ToInputUser(); public static implicit operator InputPeer(UserBase user) => user.ToInputPeer(); public static implicit operator InputUserBase(UserBase user) => user.ToInputUser(); @@ -72,15 +85,17 @@ namespace TL partial class UserEmpty { public override long ID => id; + public override bool IsActive => false; public override string ToString() => null; - protected override InputPeer ToInputPeer() => null; + public override InputPeer ToInputPeer() => null; protected override InputUserBase ToInputUser() => null; } partial class User { public override long ID => id; + public override bool IsActive => (flags & Flags.deleted) == 0; public override string ToString() => username != null ? '@' + username : last_name == null ? first_name : $"{first_name} {last_name}"; - protected override InputPeer ToInputPeer() => new InputPeerUser { user_id = id, access_hash = access_hash }; + public override InputPeer ToInputPeer() => new InputPeerUser { user_id = id, access_hash = access_hash }; protected override InputUserBase ToInputUser() => new InputUser { user_id = id, access_hash = access_hash }; } @@ -253,6 +268,36 @@ namespace TL partial class PeerChat { public override long ID => chat_id; public override string ToString() => "chat " + chat_id; } partial class PeerChannel { public override long ID => channel_id; public override string ToString() => "channel " + channel_id; } + partial class DialogBase + { + public abstract Peer Peer { get; } + public abstract int TopMessage { get; } + } + partial class Dialog + { + public override Peer Peer => peer; + public override int TopMessage => top_message; + } + partial class DialogFolder + { + public override Peer Peer => peer; + public override int TopMessage => top_message; + } + + partial class Messages_Dialogs + { + /// Find the matching User/Chat object for a dialog + /// The dialog which peer we want details on + /// a UserBase or ChatBase derived instance + public IPeerInfo GetUserOrChat(DialogBase dialog) => dialog.Peer switch + { + PeerUser pu => users[pu.user_id], + PeerChat pc => chats[pc.chat_id], + PeerChannel pch => chats[pch.channel_id], + _ => null, + }; + } + partial class JsonObjectValue { public override string ToString() => $"{HttpUtility.JavaScriptStringEncode(key, true)}:{value}"; } partial class JsonNull { public override string ToString() => "null"; } partial class JsonBool { public override string ToString() => value ? "true" : "false"; }