From e51ea2441e2a6114e4e59c5297e4fcbec8e0069e Mon Sep 17 00:00:00 2001
From: Wizou <11647984+wiz0u@users.noreply.github.com>
Date: Fri, 7 Oct 2022 11:24:08 +0200
Subject: [PATCH] DownloadFileAsync support for !CanSeek streams (like
AES_IGE_Stream)
---
Examples/Program_SecretChats.cs | 52 +++++++++++++++++++--------------
src/Client.Helpers.cs | 4 ++-
src/Encryption.cs | 3 ++
src/TL.Secret.cs | 2 +-
4 files changed, 37 insertions(+), 24 deletions(-)
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