diff --git a/README.md b/README.md index 8cdba23..54691f8 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,21 @@ #TLSharp + [![Join the chat at https://gitter.im/TLSharp/Lobby](https://badges.gitter.im/TLSharp/Lobby.svg)](https://gitter.im/TLSharp/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build status](https://ci.appveyor.com/api/projects/status/95rl618ch5c4h2fa?svg=true)](https://ci.appveyor.com/project/sochix/tlsharp) [![NuGet version](https://badge.fury.io/nu/TLSharp.svg)](https://badge.fury.io/nu/TLSharp) + _Unofficial_ Telegram (http://telegram.org) client library implemented in C#. Latest TL scheme supported, thanks to Afshin Arani -**Consider donation to speed up development process.** - -Bitcoin wallet: **3K1ocweFgaHnAibJ3n6hX7RNZWFTFcJjUe** - It's a perfect fit for any developer who would like to send data directly to Telegram users or write own custom Telegram client. :star2: If you :heart: library, please star it! :star2: +If you have difficulties with library usage, I can support you ( 75$/hour ). Contact me at @sochix. + +If you have difficulties with console or writing code, you can try [Telegram Tools](https://github.com/sochix/telegram-tools). It's a GUI for TLSharp. + # Table of contents? - [How do I add this to my project?](#how-do-i-add-this-to-my-project) @@ -161,6 +163,7 @@ For your convenience TLSharp have wrappers for several Telegram API methods. You 1. GetFile 1. UploadFile 1. SendPingAsync +1. GetHistoryAsync **What if you can't find needed method at the list?** @@ -186,7 +189,7 @@ Latest scheme in JSON format you can find [here](https://gist.github.com/aarani/ # Contributing -Contributing is highly appreciated! +Contributing is highly appreciated! Donations required ## What things can I Implement (Project Roadmap)? @@ -232,7 +235,7 @@ Without information listen above your issue will be closed. # Donations Thanks for donations! It's highly appreciated. -Bitcoin wallet: **3K1ocweFgaHnAibJ3n6hX7RNZWFTFcJjUe** + List of donators: * [mtbitcoin](https://github.com/mtbitcoin) diff --git a/TLSharp.Core/Network/TcpTransport.cs b/TLSharp.Core/Network/TcpTransport.cs index 9092828..254153e 100644 --- a/TLSharp.Core/Network/TcpTransport.cs +++ b/TLSharp.Core/Network/TcpTransport.cs @@ -1,22 +1,28 @@ using System; -using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; namespace TLSharp.Core.Network { + public delegate TcpClient TcpClientConnectionHandler(string address, int port); + public class TcpTransport : IDisposable { private readonly TcpClient _tcpClient; private int sendCounter = 0; - public TcpTransport(string address, int port) + public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null) { - _tcpClient = new TcpClient(); + if (handler == null) + { + _tcpClient = new TcpClient(); - var ipAddress = IPAddress.Parse(address); - _tcpClient.Connect(ipAddress, port); + var ipAddress = IPAddress.Parse(address); + _tcpClient.Connect(ipAddress, port); + } + else + _tcpClient = handler(address, port); } public async Task Send(byte[] packet) @@ -84,6 +90,6 @@ namespace TLSharp.Core.Network { if (_tcpClient.Connected) _tcpClient.Close(); - } + } } } diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 7cf7e5d..a4fa06a 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; -using System.Web; using TeleSharp.TL; using TeleSharp.TL.Account; using TeleSharp.TL.Auth; @@ -15,7 +14,6 @@ using TeleSharp.TL.Upload; using TLSharp.Core.Auth; using TLSharp.Core.MTProto.Crypto; using TLSharp.Core.Network; -using TLSharp.Core.Requests; using TLSharp.Core.Utils; using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; @@ -30,8 +28,10 @@ namespace TLSharp.Core private int _apiId = 0; private Session _session; private List dcOptions; + private TcpClientConnectionHandler _handler; - public TelegramClient(int apiId, string apiHash, ISessionStore store = null, string sessionUserId = "session") + public TelegramClient(int apiId, string apiHash, + ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null) { if (apiId == default(int)) throw new MissingApiConfigurationException("API_ID"); @@ -44,9 +44,10 @@ namespace TLSharp.Core TLContext.Init(); _apiHash = apiHash; _apiId = apiId; + _handler = handler; _session = Session.TryLoadOrCreateNew(store, sessionUserId); - _transport = new TcpTransport(_session.ServerAddress, _session.Port); + _transport = new TcpTransport(_session.ServerAddress, _session.Port, _handler); } public async Task ConnectAsync(bool reconnect = false) @@ -87,7 +88,7 @@ namespace TLSharp.Core var dc = dcOptions.First(d => d.id == dcId); - _transport = new TcpTransport(dc.ip_address, dc.port); + _transport = new TcpTransport(dc.ip_address, dc.port, _handler); _session.ServerAddress = dc.ip_address; _session.Port = dc.port; @@ -292,7 +293,7 @@ namespace TLSharp.Core }); } - public async Task GetFile(TLAbsInputFileLocation location, int filePartSize) + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) { TLFile result = null; try @@ -300,7 +301,8 @@ namespace TLSharp.Core result = await SendRequestAsync(new TLRequestGetFile() { location = location, - limit = filePartSize + limit = filePartSize, + offset = offset }); } catch (FileMigrationException ex) @@ -318,7 +320,7 @@ namespace TLSharp.Core bytes = exportedAuth.bytes, id = exportedAuth.id }); - result = await GetFile(location, filePartSize); + result = await GetFile(location, filePartSize, offset); _session.AuthKey = authKey; _session.TimeOffset = timeOffset; @@ -335,6 +337,38 @@ namespace TLSharp.Core public async Task SendPingAsync() { await _sender.SendPingAsync(); + } + + public async Task GetHistoryAsync(TLAbsInputPeer peer, int offset, int max_id, int limit) + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); + + var req = new TLRequestGetHistory() + { + peer = peer, + add_offset = offset, + max_id = max_id, + limit = limit + }; + return await SendRequestAsync(req); + } + + /// + /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; + /// + /// User or chat name + /// Max result count + /// + public async Task SearchUserAsync(string q, int limit = 10) + { + var r = new TeleSharp.TL.Contacts.TLRequestSearch + { + q = q, + limit = limit + }; + + return await SendRequestAsync(r); } private void OnUserAuthenticated(TLUser TLUser) diff --git a/TLSharp.Tests.NUnit/Test.cs b/TLSharp.Tests.NUnit/Test.cs index 7c390db..40e54ac 100644 --- a/TLSharp.Tests.NUnit/Test.cs +++ b/TLSharp.Tests.NUnit/Test.cs @@ -75,5 +75,11 @@ namespace TLSharp.Tests { await base.FloodExceptionShouldNotCauseCannotReadPackageLengthError(); } + + [Test] + public override async Task SendMessageByUserNameTest() + { + await base.SendMessageByUserNameTest(); + } } } diff --git a/TLSharp.Tests.VS/TLSharpTestsVs.cs b/TLSharp.Tests.VS/TLSharpTestsVs.cs index fff25b6..8f6c58d 100644 --- a/TLSharp.Tests.VS/TLSharpTestsVs.cs +++ b/TLSharp.Tests.VS/TLSharpTestsVs.cs @@ -73,5 +73,11 @@ namespace TLSharp.Tests { await base.FloodExceptionShouldNotCauseCannotReadPackageLengthError(); } + + [TestMethod] + public override async Task SendMessageByUserNameTest() + { + await base.SendMessageByUserNameTest(); + } } } diff --git a/TLSharp.Tests/TLSharpTests.cs b/TLSharp.Tests/TLSharpTests.cs index 6166067..487b535 100644 --- a/TLSharp.Tests/TLSharpTests.cs +++ b/TLSharp.Tests/TLSharpTests.cs @@ -323,6 +323,7 @@ namespace TLSharp.Tests var result = await client.IsPhoneRegisteredAsync(NumberToAuthenticate); Assert.IsTrue(result); } + public virtual async Task FloodExceptionShouldNotCauseCannotReadPackageLengthError() { for (int i = 0; i < 50; i++) @@ -338,5 +339,42 @@ namespace TLSharp.Tests } } } + + public virtual async Task SendMessageByUserNameTest() + { + UserNameToSendMessage = ConfigurationManager.AppSettings[nameof(UserNameToSendMessage)]; + if (string.IsNullOrWhiteSpace(UserNameToSendMessage)) + throw new Exception($"Please fill the '{nameof(UserNameToSendMessage)}' setting in app.config file first"); + + var client = NewClient(); + + await client.ConnectAsync(); + + var result = await client.SearchUserAsync(UserNameToSendMessage); + + var user = result.users.lists + .Where(x => x.GetType() == typeof(TLUser)) + .OfType() + .FirstOrDefault(x => x.username == UserNameToSendMessage.TrimStart('@')); + + if (user == null) + { + var contacts = await client.GetContactsAsync(); + + user = contacts.users.lists + .Where(x => x.GetType() == typeof(TLUser)) + .OfType() + .FirstOrDefault(x => x.username == UserNameToSendMessage.TrimStart('@')); + } + + if (user == null) + { + throw new System.Exception("Username was not found: " + UserNameToSendMessage); + } + + await client.SendTypingAsync(new TLInputPeerUser() { user_id = user.id }); + Thread.Sleep(3000); + await client.SendMessageAsync(new TLInputPeerUser() { user_id = user.id }, "TEST"); + } } }