diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index c09f394f..dd2c33c6 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -73,6 +73,7 @@ + diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 46e0ad42..f683279b 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -8,6 +8,7 @@ using TeleSharp.TL; using TeleSharp.TL.Account; using TeleSharp.TL.Auth; +using TeleSharp.TL.Channels; using TeleSharp.TL.Contacts; using TeleSharp.TL.Help; using TeleSharp.TL.Messages; @@ -17,13 +18,20 @@ using TLSharp.Core.MTProto.Crypto; using TLSharp.Core.Network; using TLSharp.Core.Network.Exceptions; +using TLSharp.Core.Types; using TLSharp.Core.Utils; using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; +using TLRequestUpdateUsername = TeleSharp.TL.Account.TLRequestUpdateUsername; namespace TLSharp.Core { public class TelegramClient : IDisposable { + /// + /// When pagination is needed, this is the default page size + /// + public const int DEFAULT_PAGE_SIZE = 200; + private MtProtoSender sender; private TcpTransport transport; private string apiHash = String.Empty; @@ -262,7 +270,7 @@ public bool IsUserAuthorized() public async Task CheckUsernameAsync(string username, CancellationToken token = default(CancellationToken)) { - var req = new TLRequestCheckUsername { Username = username }; + var req = new TeleSharp.TL.Account.TLRequestCheckUsername { Username = username }; return await SendAuthenticatedRequestAsync(req, token) .ConfigureAwait(false); @@ -406,6 +414,239 @@ await sender.SendPingAsync(token) .ConfigureAwait(false); } + /// + /// Authenticates a Bot + /// + /// The token of the bot to authenticate + /// + /// The TLUser descriptor + public async Task MakeAuthBotAsync(string botAuthToken, CancellationToken token = default(CancellationToken)) + { + if (String.IsNullOrWhiteSpace(botAuthToken)) + { + throw new ArgumentNullException(nameof(botAuthToken)); + } + + var request = new TLRequestImportBotAuthorization() { BotAuthToken = botAuthToken, ApiId = apiId, ApiHash = apiHash }; + + await RequestWithDcMigration(request, token).ConfigureAwait(false); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + /// + /// Gets the full information of a specified chat + /// + /// The ID of the chat we want the info of + /// + /// + public async Task GetFullChat(int chatId, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetFullChat() { ChatId = chatId }; + var fchat = await SendRequestAsync(req, token).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the list of chats and channels opened by the authenticated user. + /// Throws an exception if the authenticated user is a bot. + /// + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(CancellationToken token = default(CancellationToken)) + { + return await GetAllChats(null, token); + } + + /// + /// Gets the list of chats and channels opened by the authenticated user except the passed ones. + /// Throws an exception if the authenticated user is a bot. + /// + /// The IDs of the chats to be returned + /// + /// The list of chats opened by the authenticated user + public async Task GetAllChats(int[] exceptdIds, CancellationToken token = default(CancellationToken)) + { + var ichats = new TeleSharp.TL.TLVector(); // we can't pass a null argument to the TLRequestGetChats + if (exceptdIds != null) + Array.ForEach(exceptdIds, x => ichats.Add(x)); + var chats = await SendRequestAsync(new TLRequestGetAllChats() { ExceptIds = ichats }, token).ConfigureAwait(false); + return chats; + } + + /// + /// Gets the information about a channel + /// + /// The channel to get the info of + /// + /// + public async Task GetFullChannel(TLChannel channel, CancellationToken token = default(CancellationToken)) + { + if (channel == null) return null; + return await GetFullChannel(channel.Id, (long)channel.AccessHash, token).ConfigureAwait(false); + } + + /// + /// Gets the information about a channel + /// + /// The ID of the channel + /// + /// + public async Task GetFullChannel(int channelId, long accessHash, CancellationToken token = default(CancellationToken)) + { + var req = new TLRequestGetFullChannel() { Channel = new TLInputChannel() { ChannelId = channelId, AccessHash = accessHash } }; + var fchat = await SendRequestAsync(req, token).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the channels having the supplied IDs + /// + /// The IDs of the channels to be retrieved + /// + /// + public async Task GetChannels(int[] channelIds, CancellationToken token = default(CancellationToken)) + { + var channels = new TLVector(); // we can't pass a null argument to the TLRequestGetChats + if (channelIds != null) + Array.ForEach(channelIds, x => channels.Add(new TLInputChannel() { ChannelId = x })); + var req = new TLRequestGetChannels() { Id = channels }; + var fchat = await SendRequestAsync(req, token).ConfigureAwait(false); + + return fchat; + } + + /// + /// Gets the participants of the channel having the supplied type. + /// The method will auto-paginate results and return all the participants + /// + /// The TLChannel whose participants are requested + /// The index to start fetching from. -1 will automatically fetch all the results + /// How many results to be fetch on each iteration. + /// Values smaller than 0 are ignored. If stIdx is set, a number of results smaller than pageSize might be returned by Telegram. + /// The type of the participants to get. Choose Recents not to filter + /// + /// + public async Task GetParticipants(TLChannel channel, int stIdx = -1, int pageSize = -1, ParticipantFilterTypes partType = ParticipantFilterTypes.Recents, CancellationToken token = default(CancellationToken)) + { + if (channel == null) return null; + return await GetParticipants(channel.Id, (long)channel.AccessHash, stIdx, pageSize, partType, token).ConfigureAwait(false); + } + + /// + /// Gets the participants of the channel having the supplied type. + /// The method will auto-paginate results and return all the participants + /// + /// The id of the channel whose participants are requested + /// The access hash of the channel whose participants are requested + /// The index to start fetching from. -1 will automatically fetch all the results + /// How many results to be fetch on each iteration. + /// Values smaller than 0 are ignored. If stIdx is set, a number of results smaller than pageSize might be returned by Telegram. + /// The type of the participants to get. Choose Recents not to filter + /// + /// + public async Task GetParticipants(int channelId, long accessHash, int stIdx = -1, int pageSize = -1, ParticipantFilterTypes partType = ParticipantFilterTypes.Recents, CancellationToken token = default(CancellationToken)) + { + TLAbsChannelParticipantsFilter filter; + switch (partType) + { + case ParticipantFilterTypes.Admins: + filter = new TLChannelParticipantsAdmins(); + break; + + case ParticipantFilterTypes.Kicked: + filter = new TLChannelParticipantsKicked(); + break; + + case ParticipantFilterTypes.Bots: + filter = new TLChannelParticipantsBots(); + break; + + case ParticipantFilterTypes.Recents: + filter = new TLChannelParticipantsRecent(); + break; + + case ParticipantFilterTypes.Banned: + case ParticipantFilterTypes.Restricted: + case ParticipantFilterTypes.Contacts: + case ParticipantFilterTypes.Search: + default: + throw new NotImplementedException($"{partType} not implemented yet"); + } + + int total = 0; + int found = stIdx < 0 ? 0 : stIdx; + pageSize = pageSize < 0 ? DEFAULT_PAGE_SIZE : pageSize; + + TLChannelParticipants ret = new TLChannelParticipants(); + ret.Participants = new TLVector(); + ret.Users = new TLVector(); + + do + { + var req = new TLRequestGetParticipants() + { + Channel = new TLInputChannel() + { + ChannelId = channelId, + AccessHash = accessHash + }, + Filter = filter, + Offset = found, + Limit = pageSize + }; + var fchat = await SendRequestAsync(req, token).ConfigureAwait(false); + total = fchat.Count; + found += fchat.Participants.Count; + foreach (var p in fchat.Participants) + ret.Participants.Add(p); + foreach (var u in fchat.Users) + ret.Users.Add(u); + } while (found < total && stIdx == -1); + ret.Count = ret.Participants.Count; + return ret; + } + + /// + /// Invites the passed users to the specified channel + /// + /// The descriptor of the channel to invite the users to + /// + /// + public async Task InviteToChannel(TLChannel channel, int[] users, CancellationToken token = default(CancellationToken)) + { + return await InviteToChannel(channel.Id, (long)channel.AccessHash, users, token); + } + + /// + /// Invites the passed users to the specified channel + /// + /// The id of the channel to invite the users to + /// The access hash of the channel to invite the users to + /// + /// + public async Task InviteToChannel(int channelId, long accessHash, int[] users, CancellationToken token = default(CancellationToken)) + { + TLVector absUsers = new TLVector(); + Array.ForEach(users, u => absUsers.Add(new TLInputUser() { UserId = u })); + var req = new TLRequestInviteToChannel() + { + Channel = new TLInputChannel() + { + ChannelId = channelId, + AccessHash = accessHash + }, + Users = absUsers + }; + var updates = await SendRequestAsync(req, token).ConfigureAwait(false); + + return updates; + } + /// /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; /// diff --git a/TLSharp.Core/Types/ParticipantFilterTypes.cs b/TLSharp.Core/Types/ParticipantFilterTypes.cs new file mode 100644 index 00000000..99eef19f --- /dev/null +++ b/TLSharp.Core/Types/ParticipantFilterTypes.cs @@ -0,0 +1,16 @@ +namespace TLSharp.Core.Types +{ + public enum ParticipantFilterTypes + { + Recents, + Restricted, + Admins, + Bots, + Search, + Contacts, + Kicked, + Banned + } + + +}