diff --git a/Examples/Program_SecretChats.cs b/Examples/Program_SecretChats.cs index 6bcee65..057ac3e 100644 --- a/Examples/Program_SecretChats.cs +++ b/Examples/Program_SecretChats.cs @@ -41,30 +41,38 @@ namespace WTelegramClientTest Type a command, or a message to send to the active secret chat:"); do { - var line = Console.ReadLine(); - if (line.StartsWith('/')) + try { - if (line == "/discard delete") { await Secrets.Discard(ActiveChat, true); SelectActiveChat(); } - else if (line == "/discard") { await Secrets.Discard(ActiveChat, false); SelectActiveChat(); } - else if (line == "/read") await Client.Messages_ReadEncryptedHistory(ActiveChat, DateTime.UtcNow); - else if (line == "/users") foreach (var user in Users.Values) Console.WriteLine($"{user.id,-10} {user}"); - else if (line.StartsWith("/select ")) SelectActiveChat(int.Parse(line[8..])); - else if (line.StartsWith("/request ")) - if (Users.TryGetValue(long.Parse(line[9..]), out var user)) - SelectActiveChat(await Secrets.Request(user)); - else - Console.WriteLine("User not found"); - else if (line.StartsWith("/photo ")) + var line = Console.ReadLine(); + if (line.StartsWith('/')) { - var media = new TL.Layer45.DecryptedMessageMediaPhoto { caption = line[7..] }; - var file = await Secrets.UploadFile(File.OpenRead(line[7..]), media); - var sent = await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { random_id = WTelegram.Helpers.RandomLong(), - media = media, flags = TL.Layer73.DecryptedMessage.Flags.has_media }, file: file); + if (line == "/discard delete") { await Secrets.Discard(ActiveChat, true); SelectActiveChat(); } + else if (line == "/discard") { await Secrets.Discard(ActiveChat, false); SelectActiveChat(); } + else if (line == "/read") await Client.Messages_ReadEncryptedHistory(ActiveChat, DateTime.UtcNow); + else if (line == "/users") foreach (var user in Users.Values) Console.WriteLine($"{user.id,-10} {user}"); + else if (line.StartsWith("/select ")) SelectActiveChat(int.Parse(line[8..])); + else if (line.StartsWith("/request ")) + if (Users.TryGetValue(long.Parse(line[9..]), out var user)) + SelectActiveChat(await Secrets.Request(user)); + else + Console.WriteLine("User not found"); + else if (line.StartsWith("/photo ")) + { + var media = new TL.Layer45.DecryptedMessageMediaPhoto { caption = line[7..] }; + var file = await Secrets.UploadFile(File.OpenRead(line[7..]), media); + var sent = await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { random_id = WTelegram.Helpers.RandomLong(), + media = media, flags = TL.Layer73.DecryptedMessage.Flags.has_media }, file: file); + } + else Console.WriteLine("Unrecognized command"); } - else Console.WriteLine("Unrecognized command"); + else if (ActiveChat == null) Console.WriteLine("No active secret chat"); + else await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { message = line, random_id = WTelegram.Helpers.RandomLong() }); + + } + catch (Exception ex) + { + Console.WriteLine(ex); } - else if (ActiveChat == null) Console.WriteLine("No active secret chat"); - else await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { message = line, random_id = WTelegram.Helpers.RandomLong() }); } while (true); } @@ -79,13 +87,13 @@ Type a command, or a message to send to the active secret chat:"); await Secrets.HandleUpdate(ue); break; case UpdateNewEncryptedMessage unem: // Encrypted message or service message: - if (unem.message.ChatId != ActiveChat) SelectActiveChat(unem.message.ChatId); + if (unem.message.ChatId != ActiveChat?.chat_id) SelectActiveChat(unem.message.ChatId); foreach (var msg in Secrets.DecryptMessage(unem.message)) { if (msg.Media != null && unem.message is EncryptedMessage { file: EncryptedFile ef }) { Console.WriteLine($"{unem.message.ChatId}> {msg.Message} [file being downloaded to media.jpg]"); - using var output = File.OpenWrite("media.jpg"); // not necessarily a JPG, check the msg.Media mime_type + using var output = File.Create("media.jpg"); // not necessarily a JPG, check the msg.Media mime_type using var decryptStream = new WTelegram.AES_IGE_Stream(output, msg.Media); await Client.DownloadFileAsync(ef, decryptStream, ef.dc_id, ef.size); } diff --git a/src/Client.Helpers.cs b/src/Client.Helpers.cs index aae1634..260cbdd 100644 --- a/src/Client.Helpers.cs +++ b/src/Client.Helpers.cs @@ -350,6 +350,7 @@ namespace WTelegram Storage_FileType fileType = Storage_FileType.unknown; var client = dc_id == 0 ? this : await GetClientForDC(dc_id, true); using var writeSem = new SemaphoreSlim(1); + bool canSeek = outputStream.CanSeek; long streamStartPos = outputStream.Position; long fileOffset = 0, maxOffsetSeen = 0; long transmitted = 0; @@ -362,6 +363,7 @@ namespace WTelegram var task = LoadPart(fileOffset); lock (tasks) tasks[fileOffset] = task; if (dc_id == 0) { await task; dc_id = client._dcSession.DcID; } + if (!canSeek) await task; fileOffset += FilePartSize; if (fileSize != 0 && fileOffset >= fileSize) { @@ -433,7 +435,7 @@ namespace WTelegram lock (tasks) remainingTasks = tasks.Values.ToArray(); await Task.WhenAll(remainingTasks); // wait completion and eventually propagate any task exception await outputStream.FlushAsync(); - outputStream.Seek(streamStartPos + maxOffsetSeen, SeekOrigin.Begin); + if (canSeek) outputStream.Seek(streamStartPos + maxOffsetSeen, SeekOrigin.Begin); return fileType; } diff --git a/src/Encryption.cs b/src/Encryption.cs index 2a8b7a2..3f490c0 100644 --- a/src/Encryption.cs +++ b/src/Encryption.cs @@ -540,6 +540,9 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB else { prevBytes = new byte[32]; Array.Copy(iv, 0, prevBytes, 16, 16); Array.Copy(iv, 16, prevBytes, 0, 16); } } + public override bool CanSeek => false; + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override int Read(byte[] buffer, int offset, int count) { count = _innerStream.Read(buffer, offset, count); diff --git a/src/TL.Secret.cs b/src/TL.Secret.cs index 3600095..0915f52 100644 --- a/src/TL.Secret.cs +++ b/src/TL.Secret.cs @@ -31,7 +31,7 @@ namespace TL /// a null value means decryptedMessageMediaEmpty public abstract class DecryptedMessageMedia : IObject { - public virtual (int, byte[], byte[]) SizeKeyIV { get => default; set => throw new ApplicationException("Incompatible DecryptedMessageMedia"); } + public virtual (int size, byte[] key, byte[] iv) SizeKeyIV { get => default; set => throw new ApplicationException("Incompatible DecryptedMessageMedia"); } } /// Object describes the action to which a service message is linked. See