mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2025-12-06 06:52:01 +01:00
Compare commits
17 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfc8e0e1b5 | ||
|
|
e923d65d53 | ||
|
|
4ad2f0a212 | ||
|
|
30bc536ebc | ||
|
|
d6fdcab440 | ||
|
|
9ec2f31f72 | ||
|
|
4ccfddd22e | ||
|
|
9693037ef2 | ||
|
|
40bcf69bfb | ||
|
|
4875f75774 | ||
|
|
2e95576be5 | ||
|
|
48d005b605 | ||
|
|
a5323eaa86 | ||
|
|
610d059b4c | ||
|
|
3f1036a559 | ||
|
|
4578dea3a3 | ||
|
|
253249e06a |
31
.github/workflows/dev.yml
vendored
31
.github/workflows/dev.yml
vendored
|
|
@ -12,14 +12,16 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
permissions:
|
||||||
|
id-token: write # enable GitHub OIDC token issuance for this job
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 100
|
fetch-depth: 30
|
||||||
- name: Determine version
|
- name: Determine version
|
||||||
run: |
|
run: |
|
||||||
git fetch --depth=100 --tags
|
git fetch --depth=30 --tags
|
||||||
DESCR_TAG=$(git describe --tags)
|
DESCR_TAG=$(git describe --tags)
|
||||||
COMMITS=${DESCR_TAG#*-}
|
COMMITS=${DESCR_TAG#*-}
|
||||||
COMMITS=${COMMITS%-*}
|
COMMITS=${COMMITS%-*}
|
||||||
|
|
@ -29,19 +31,32 @@ jobs:
|
||||||
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi
|
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi
|
||||||
echo Last tag: $LAST_TAG · Next version: $NEXT_VERSION · Release version: $RELEASE_VERSION · Build version: $VERSION
|
echo Last tag: $LAST_TAG · Next version: $NEXT_VERSION · Release version: $RELEASE_VERSION · Build version: $VERSION
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v4
|
# - name: Setup .NET
|
||||||
with:
|
# uses: actions/setup-dotnet@v4
|
||||||
dotnet-version: 8.0.x
|
# with:
|
||||||
|
# dotnet-version: 8.0.x
|
||||||
- name: Pack
|
- name: Pack
|
||||||
run: dotnet pack $PROJECT_PATH --configuration $CONFIGURATION -p:Version=$VERSION "-p:ReleaseNotes=\"$RELEASE_NOTES\"" --output packages
|
run: |
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//$'\n'/%0A}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//\"/%22}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//,/%2C}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//;/%3B}
|
||||||
|
dotnet pack $PROJECT_PATH --configuration $CONFIGURATION -p:Version=$VERSION -p:ReleaseNotes="$RELEASE_NOTES" --output packages
|
||||||
# - name: Upload artifact
|
# - name: Upload artifact
|
||||||
# uses: actions/upload-artifact@v4
|
# uses: actions/upload-artifact@v4
|
||||||
# with:
|
# with:
|
||||||
# name: packages
|
# name: packages
|
||||||
# path: packages/*.nupkg
|
# path: packages/*.nupkg
|
||||||
|
|
||||||
|
- name: NuGet login (OIDC → temp API key)
|
||||||
|
uses: NuGet/login@v1
|
||||||
|
id: login
|
||||||
|
with:
|
||||||
|
user: ${{ secrets.NUGET_USER }}
|
||||||
- name: Nuget push
|
- name: Nuget push
|
||||||
run: dotnet nuget push packages/*.nupkg --api-key ${{secrets.NUGETAPIKEY}} --skip-duplicate --source https://api.nuget.org/v3/index.json
|
run: dotnet nuget push packages/*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --skip-duplicate --source https://api.nuget.org/v3/index.json
|
||||||
|
|
||||||
- name: Deployment Notification
|
- name: Deployment Notification
|
||||||
env:
|
env:
|
||||||
JSON: |
|
JSON: |
|
||||||
|
|
|
||||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
|
|
@ -22,6 +22,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # For git tag
|
contents: write # For git tag
|
||||||
|
id-token: write # enable GitHub OIDC token issuance for this job
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
|
@ -37,19 +38,35 @@ jobs:
|
||||||
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi
|
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi
|
||||||
echo Last tag: $LAST_TAG · Next version: $NEXT_VERSION · Release version: $RELEASE_VERSION · Build version: $VERSION
|
echo Last tag: $LAST_TAG · Next version: $NEXT_VERSION · Release version: $RELEASE_VERSION · Build version: $VERSION
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: 8.0.x
|
dotnet-version: 8.0.x
|
||||||
- name: Pack
|
- name: Pack
|
||||||
run: dotnet pack $PROJECT_PATH --configuration $CONFIGURATION -p:Version=$VERSION "-p:ReleaseNotes=\"$RELEASE_NOTES\"" --output packages
|
run: |
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//|/%0A}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES// - /%0A- }
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES// /%0A%0A}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//$'\n'/%0A}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//\"/%22}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//,/%2C}
|
||||||
|
RELEASE_NOTES=${RELEASE_NOTES//;/%3B}
|
||||||
|
dotnet pack $PROJECT_PATH --configuration $CONFIGURATION -p:Version=$VERSION -p:ReleaseNotes="$RELEASE_NOTES" --output packages
|
||||||
# - name: Upload artifact
|
# - name: Upload artifact
|
||||||
# uses: actions/upload-artifact@v4
|
# uses: actions/upload-artifact@v4
|
||||||
# with:
|
# with:
|
||||||
# name: packages
|
# name: packages
|
||||||
# path: packages/*.nupkg
|
# path: packages/*.nupkg
|
||||||
|
|
||||||
|
- name: NuGet login (OIDC → temp API key)
|
||||||
|
uses: NuGet/login@v1
|
||||||
|
id: login
|
||||||
|
with:
|
||||||
|
user: ${{ secrets.NUGET_USER }}
|
||||||
- name: Nuget push
|
- name: Nuget push
|
||||||
run: dotnet nuget push packages/*.nupkg --api-key ${{secrets.NUGETAPIKEY}} --skip-duplicate --source https://api.nuget.org/v3/index.json
|
run: dotnet nuget push packages/*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --skip-duplicate --source https://api.nuget.org/v3/index.json
|
||||||
|
|
||||||
- name: Git tag
|
- name: Git tag
|
||||||
run: |
|
run: |
|
||||||
git tag $VERSION
|
git tag $VERSION
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[](https://corefork.telegram.org/methods)
|
[](https://corefork.telegram.org/methods)
|
||||||
[](https://www.nuget.org/packages/WTelegramClient/)
|
[](https://www.nuget.org/packages/WTelegramClient/)
|
||||||
[](https://www.nuget.org/packages/WTelegramClient/absoluteLatest)
|
[](https://www.nuget.org/packages/WTelegramClient/absoluteLatest)
|
||||||
[](https://buymeacoffee.com/wizou)
|
[](https://buymeacoffee.com/wizou)
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
This library allows you to connect to Telegram and control a user programmatically (or a bot, but [WTelegramBot](https://www.nuget.org/packages/WTelegramBot) is much easier for that).
|
This library allows you to connect to Telegram and control a user programmatically (or a bot, but [WTelegramBot](https://www.nuget.org/packages/WTelegramBot) is much easier for that).
|
||||||
All the Telegram Client APIs (MTProto) are supported so you can do everything the user could do with a full Telegram GUI client.
|
All the Telegram Client APIs (MTProto) are supported so you can do everything the user could do with a full Telegram GUI client.
|
||||||
|
|
||||||
Library was developed solely by one unemployed guy. [Donations are welcome](https://buymeacoffee.com/wizou).
|
Library was developed solely by one unemployed guy. [Donations](https://buymeacoffee.com/wizou) or [Patreon memberships are welcome](https://patreon.com/wizou).
|
||||||
|
|
||||||
This ReadMe is a **quick but important tutorial** to learn the fundamentals about this library. Please read it all.
|
This ReadMe is a **quick but important tutorial** to learn the fundamentals about this library. Please read it all.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ public class MTProtoGenerator : IIncrementalGenerator
|
||||||
var nullables = LoadNullables(layer);
|
var nullables = LoadNullables(layer);
|
||||||
var namespaces = new Dictionary<string, Dictionary<string, string>>(); // namespace,class,methods
|
var namespaces = new Dictionary<string, Dictionary<string, string>>(); // namespace,class,methods
|
||||||
var tableTL = new StringBuilder();
|
var tableTL = new StringBuilder();
|
||||||
|
var methodsTL = new StringBuilder();
|
||||||
var source = new StringBuilder();
|
var source = new StringBuilder();
|
||||||
source
|
source
|
||||||
.AppendLine("using System;")
|
.AppendLine("using System;")
|
||||||
|
|
@ -46,6 +47,9 @@ public class MTProtoGenerator : IIncrementalGenerator
|
||||||
tableTL
|
tableTL
|
||||||
.AppendLine("\t\tpublic static readonly Dictionary<uint, Func<BinaryReader, IObject>> Table = new()")
|
.AppendLine("\t\tpublic static readonly Dictionary<uint, Func<BinaryReader, IObject>> Table = new()")
|
||||||
.AppendLine("\t\t{");
|
.AppendLine("\t\t{");
|
||||||
|
methodsTL
|
||||||
|
.AppendLine("\t\tpublic static readonly Dictionary<uint, Func<BinaryReader, IObject>> Methods = new()")
|
||||||
|
.AppendLine("\t\t{");
|
||||||
|
|
||||||
foreach (var classDecl in unit.classes)
|
foreach (var classDecl in unit.classes)
|
||||||
{
|
{
|
||||||
|
|
@ -79,15 +83,20 @@ public class MTProtoGenerator : IIncrementalGenerator
|
||||||
ns = symbol.ContainingNamespace.ToString();
|
ns = symbol.ContainingNamespace.ToString();
|
||||||
name = symbol.Name;
|
name = symbol.Name;
|
||||||
if (!namespaces.TryGetValue(ns, out var classes)) namespaces[ns] = classes = [];
|
if (!namespaces.TryGetValue(ns, out var classes)) namespaces[ns] = classes = [];
|
||||||
if (name is "_Message" or "RpcResult" or "MsgCopy")
|
if (name is "_Message" or "MsgCopy")
|
||||||
{
|
{
|
||||||
classes[name] = "\t\tpublic void WriteTL(BinaryWriter writer) => throw new NotSupportedException();";
|
classes[name] = "\t\tpublic void WriteTL(BinaryWriter writer) => throw new NotSupportedException();";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (id == 0x3072CFA1) // GzipPacked
|
if (id == 0x3072CFA1) // GzipPacked
|
||||||
tableTL.AppendLine($"\t\t\t[0x{id:X8}] = reader => (IObject)reader.ReadTLGzipped(typeof(IObject)),");
|
tableTL.AppendLine($"\t\t\t[0x{id:X8}] = reader => (IObject)reader.ReadTLGzipped(typeof(IObject)),");
|
||||||
else if (name != "Null" && (ns != "TL.Methods" || name == "Ping"))
|
else if (name != "Null")
|
||||||
|
{
|
||||||
|
if (ns == "TL.Methods")
|
||||||
|
methodsTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}{(symbol.IsGenericType ? "<object>" : "")}.ReadTL,");
|
||||||
|
if (ns != "TL.Methods" || name == "Ping")
|
||||||
tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,");
|
tableTL.AppendLine($"\t\t\t[0x{id:X8}] = {(ns == "TL" ? "" : ns + '.')}{name}.ReadTL,");
|
||||||
|
}
|
||||||
var override_ = symbol.BaseType == object_ ? "" : "override ";
|
var override_ = symbol.BaseType == object_ ? "" : "override ";
|
||||||
if (name == "Messages_AffectedMessages") override_ = "virtual ";
|
if (name == "Messages_AffectedMessages") override_ = "virtual ";
|
||||||
//if (symbol.Constructors[0].IsImplicitlyDeclared)
|
//if (symbol.Constructors[0].IsImplicitlyDeclared)
|
||||||
|
|
@ -167,26 +176,35 @@ public class MTProtoGenerator : IIncrementalGenerator
|
||||||
writeTl.AppendLine($"writer.WriteTLMessages({member.Name});");
|
writeTl.AppendLine($"writer.WriteTLMessages({member.Name});");
|
||||||
break;
|
break;
|
||||||
case "TL.IObject": case "TL.IMethod<X>":
|
case "TL.IObject": case "TL.IMethod<X>":
|
||||||
readTL.AppendLine($"r.{member.Name} = {(memberType == "TL.IObject" ? "" : $"({memberType})")}reader.ReadTLObject();");
|
readTL.AppendLine($"r.{member.Name} = {(memberType == "TL.IObject" ? "reader.ReadTLObject()" : "reader.ReadTLMethod<X>()")};");
|
||||||
writeTl.AppendLine($"{member.Name}.WriteTL(writer);");
|
writeTl.AppendLine($"{member.Name}.WriteTL(writer);");
|
||||||
break;
|
break;
|
||||||
case "System.Collections.Generic.Dictionary<long, TL.User>":
|
case "System.Collections.Generic.Dictionary<long, TL.User>":
|
||||||
readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<User>();");
|
readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<User>();");
|
||||||
writeTl.AppendLine($"writer.WriteTLVector({member.Name}.Values.ToArray());");
|
writeTl.AppendLine($"writer.WriteTLVector({member.Name}?.Values.ToArray());");
|
||||||
break;
|
break;
|
||||||
case "System.Collections.Generic.Dictionary<long, TL.ChatBase>":
|
case "System.Collections.Generic.Dictionary<long, TL.ChatBase>":
|
||||||
readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<ChatBase>();");
|
readTL.AppendLine($"r.{member.Name} = reader.ReadTLDictionary<ChatBase>();");
|
||||||
writeTl.AppendLine($"writer.WriteTLVector({member.Name}.Values.ToArray());");
|
writeTl.AppendLine($"writer.WriteTLVector({member.Name}?.Values.ToArray());");
|
||||||
|
break;
|
||||||
|
case "object":
|
||||||
|
readTL.AppendLine($"r.{member.Name} = reader.ReadTLObject();");
|
||||||
|
writeTl.AppendLine($"writer.WriteTLValue({member.Name}, {member.Name}.GetType());");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (member.Type is IArrayTypeSymbol arrayType)
|
if (member.Type is IArrayTypeSymbol arrayType)
|
||||||
{
|
{
|
||||||
if (name is "FutureSalts")
|
if (name is "FutureSalts")
|
||||||
|
{
|
||||||
readTL.AppendLine($"r.{member.Name} = reader.ReadTLRawVector<{memberType.Substring(0, memberType.Length - 2)}>(0x0949D9DC).ToArray();");
|
readTL.AppendLine($"r.{member.Name} = reader.ReadTLRawVector<{memberType.Substring(0, memberType.Length - 2)}>(0x0949D9DC).ToArray();");
|
||||||
|
writeTl.AppendLine($"writer.WriteTLRawVector({member.Name}, 16);");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
readTL.AppendLine($"r.{member.Name} = reader.ReadTLVector<{memberType.Substring(0, memberType.Length - 2)}>();");
|
readTL.AppendLine($"r.{member.Name} = reader.ReadTLVector<{memberType.Substring(0, memberType.Length - 2)}>();");
|
||||||
writeTl.AppendLine($"writer.WriteTLVector({member.Name});");
|
writeTl.AppendLine($"writer.WriteTLVector({member.Name});");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (member.Type.BaseType.SpecialType == SpecialType.System_Enum)
|
else if (member.Type.BaseType.SpecialType == SpecialType.System_Enum)
|
||||||
{
|
{
|
||||||
readTL.AppendLine($"r.{member.Name} = ({memberType})reader.ReadUInt32();");
|
readTL.AppendLine($"r.{member.Name} = ({memberType})reader.ReadUInt32();");
|
||||||
|
|
@ -213,7 +231,8 @@ public class MTProtoGenerator : IIncrementalGenerator
|
||||||
foreach (var nullable in nullables)
|
foreach (var nullable in nullables)
|
||||||
tableTL.AppendLine($"\t\t\t[0x{nullable.Value:X8}] = null,");
|
tableTL.AppendLine($"\t\t\t[0x{nullable.Value:X8}] = null,");
|
||||||
tableTL.AppendLine("\t\t};");
|
tableTL.AppendLine("\t\t};");
|
||||||
namespaces["TL"]["Layer"] = tableTL.ToString();
|
methodsTL.AppendLine("\t\t};");
|
||||||
|
namespaces["TL"]["Layer"] = tableTL.ToString() + methodsTL.ToString();
|
||||||
foreach (var namesp in namespaces)
|
foreach (var namesp in namespaces)
|
||||||
{
|
{
|
||||||
source.Append("namespace ").AppendLine(namesp.Key).Append('{');
|
source.Append("namespace ").AppendLine(namesp.Key).Append('{');
|
||||||
|
|
|
||||||
|
|
@ -94,19 +94,19 @@ namespace WTelegram
|
||||||
/// <summary>Search messages in chat with <see href="https://corefork.telegram.org/type/MessagesFilter">filter</see> and text <para>See <a href="https://corefork.telegram.org/method/messages.search"/></para></summary>
|
/// <summary>Search messages in chat with <see href="https://corefork.telegram.org/type/MessagesFilter">filter</see> and text <para>See <a href="https://corefork.telegram.org/method/messages.search"/></para></summary>
|
||||||
/// <typeparam name="T">See <see cref="MessagesFilter"/> for a list of possible filter types</typeparam>
|
/// <typeparam name="T">See <see cref="MessagesFilter"/> for a list of possible filter types</typeparam>
|
||||||
/// <param name="peer">User or chat, histories with which are searched, or <see langword="null"/> constructor for global search</param>
|
/// <param name="peer">User or chat, histories with which are searched, or <see langword="null"/> constructor for global search</param>
|
||||||
/// <param name="text">Text search request</param>
|
/// <param name="q">Text search request</param>
|
||||||
/// <param name="offset_id">Only return messages starting from the specified message ID</param>
|
/// <param name="offset_id">Only return messages starting from the specified message ID</param>
|
||||||
/// <param name="limit"><a href="https://corefork.telegram.org/api/offsets">Number of results to return</a></param>
|
/// <param name="limit"><a href="https://corefork.telegram.org/api/offsets">Number of results to return</a></param>
|
||||||
public Task<Messages_MessagesBase> Messages_Search<T>(InputPeer peer, string text = null, int offset_id = 0, int limit = int.MaxValue) where T : MessagesFilter, new()
|
public Task<Messages_MessagesBase> Messages_Search<T>(InputPeer peer, string q = null, int offset_id = 0, int limit = int.MaxValue) where T : MessagesFilter, new()
|
||||||
=> this.Messages_Search(peer, text, new T(), offset_id: offset_id, limit: limit);
|
=> this.Messages_Search(peer, q, new T(), offset_id: offset_id, limit: limit);
|
||||||
|
|
||||||
/// <summary>Search messages globally with <see href="https://corefork.telegram.org/type/MessagesFilter">filter</see> and text <para>See <a href="https://corefork.telegram.org/method/messages.searchGlobal"/></para></summary>
|
/// <summary>Search messages globally with <see href="https://corefork.telegram.org/type/MessagesFilter">filter</see> and text <para>See <a href="https://corefork.telegram.org/method/messages.searchGlobal"/></para></summary>
|
||||||
/// <typeparam name="T">See <see cref="MessagesFilter"/> for a list of possible filter types</typeparam>
|
/// <typeparam name="T">See <see cref="MessagesFilter"/> for a list of possible filter types</typeparam>
|
||||||
/// <param name="text">Text search request</param>
|
/// <param name="q">Query</param>
|
||||||
/// <param name="offset_id">Only return messages starting from the specified message ID</param>
|
/// <param name="offset_id">Only return messages starting from the specified message ID</param>
|
||||||
/// <param name="limit"><a href="https://corefork.telegram.org/api/offsets">Number of results to return</a></param>
|
/// <param name="limit"><a href="https://corefork.telegram.org/api/offsets">Number of results to return</a></param>
|
||||||
public Task<Messages_MessagesBase> Messages_SearchGlobal<T>(string text = null, int offset_id = 0, int limit = int.MaxValue) where T : MessagesFilter, new()
|
public Task<Messages_MessagesBase> Messages_SearchGlobal<T>(string q = null, int offset_id = 0, int limit = int.MaxValue) where T : MessagesFilter, new()
|
||||||
=> this.Messages_SearchGlobal(text, new T(), offset_id: offset_id, limit: limit);
|
=> this.Messages_SearchGlobal(q, new T(), offset_id: offset_id, limit: limit);
|
||||||
|
|
||||||
/// <summary>Helper method to send a media message more easily</summary>
|
/// <summary>Helper method to send a media message more easily</summary>
|
||||||
/// <param name="peer">Destination of message (chat group, channel, user chat, etc..) </param>
|
/// <param name="peer">Destination of message (chat group, channel, user chat, etc..) </param>
|
||||||
|
|
@ -361,6 +361,18 @@ namespace WTelegram
|
||||||
return thumbSize == null ? document.mime_type : "image/" + fileType;
|
return thumbSize == null ? document.mime_type : "image/" + fileType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Download a document from Telegram into the outputStream</summary>
|
||||||
|
/// <param name="document">The document to download</param>
|
||||||
|
/// <param name="outputStream">Stream to write the file content to. This method does not close/dispose the stream</param>
|
||||||
|
/// <param name="videoSize">A specific size/version of the animated photo. Use <c>photo.LargestVideoSize</c> to download the largest version of the animated photo</param>
|
||||||
|
/// <param name="progress">(optional) Callback for tracking the progression of the transfer</param>
|
||||||
|
/// <returns>MIME type of the document/thumbnail</returns>
|
||||||
|
public async Task<Storage_FileType> DownloadFileAsync(Document document, Stream outputStream, VideoSize videoSize, ProgressCallback progress = null)
|
||||||
|
{
|
||||||
|
var fileLocation = document.ToFileLocation(videoSize);
|
||||||
|
return await DownloadFileAsync(fileLocation, outputStream, document.dc_id, videoSize.size, progress);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Download a file from Telegram into the outputStream</summary>
|
/// <summary>Download a file from Telegram into the outputStream</summary>
|
||||||
/// <param name="fileLocation">Telegram file identifier, typically obtained with a .ToFileLocation() call</param>
|
/// <param name="fileLocation">Telegram file identifier, typically obtained with a .ToFileLocation() call</param>
|
||||||
/// <param name="outputStream">Stream to write file content to. This method does not close/dispose the stream</param>
|
/// <param name="outputStream">Stream to write file content to. This method does not close/dispose the stream</param>
|
||||||
|
|
@ -535,18 +547,20 @@ namespace WTelegram
|
||||||
case Messages_DialogsSlice mds:
|
case Messages_DialogsSlice mds:
|
||||||
var dialogList = new List<DialogBase>();
|
var dialogList = new List<DialogBase>();
|
||||||
var messageList = new List<MessageBase>();
|
var messageList = new List<MessageBase>();
|
||||||
while (dialogs.Dialogs.Length != 0)
|
int skip = 0;
|
||||||
|
while (dialogs.Dialogs.Length > skip)
|
||||||
{
|
{
|
||||||
dialogList.AddRange(dialogs.Dialogs);
|
dialogList.AddRange(skip == 0 ? dialogs.Dialogs : dialogs.Dialogs[skip..]);
|
||||||
messageList.AddRange(dialogs.Messages);
|
messageList.AddRange(dialogs.Messages);
|
||||||
|
skip = 0;
|
||||||
int last = dialogs.Dialogs.Length - 1;
|
int last = dialogs.Dialogs.Length - 1;
|
||||||
var lastDialog = dialogs.Dialogs[last];
|
var lastDialog = dialogs.Dialogs[last];
|
||||||
|
retryDate:
|
||||||
var lastPeer = dialogs.UserOrChat(lastDialog).ToInputPeer();
|
var lastPeer = dialogs.UserOrChat(lastDialog).ToInputPeer();
|
||||||
var lastMsgId = lastDialog.TopMessage;
|
var lastMsgId = lastDialog.TopMessage;
|
||||||
retryDate:
|
|
||||||
var lastDate = dialogs.Messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage)?.Date ?? default;
|
var lastDate = dialogs.Messages.LastOrDefault(m => m.Peer.ID == lastDialog.Peer.ID && m.ID == lastDialog.TopMessage)?.Date ?? default;
|
||||||
if (lastDate == default)
|
if (lastDate == default)
|
||||||
if (--last < 0) break; else { lastDialog = dialogs.Dialogs[last]; goto retryDate; }
|
if (--last < 0) break; else { ++skip; lastDialog = dialogs.Dialogs[last]; goto retryDate; }
|
||||||
dialogs = await this.Messages_GetDialogs(lastDate, lastMsgId, lastPeer, folder_id: folder_id);
|
dialogs = await this.Messages_GetDialogs(lastDate, lastMsgId, lastPeer, folder_id: folder_id);
|
||||||
if (dialogs is not Messages_Dialogs md) break;
|
if (dialogs is not Messages_Dialogs md) break;
|
||||||
foreach (var (key, value) in md.chats) mds.chats[key] = value;
|
foreach (var (key, value) in md.chats) mds.chats[key] = value;
|
||||||
|
|
@ -638,18 +652,18 @@ namespace WTelegram
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Helper simplified method: Get all <a href="https://corefork.telegram.org/api/forum">topics of a forum</a> <para>See <a href="https://corefork.telegram.org/method/channels.getForumTopics"/></para> <para>Possible <see cref="RpcException"/> codes: 400 (<a href="https://corefork.telegram.org/method/channels.getForumTopics#possible-errors">details</a>)</para></summary>
|
/// <summary>Helper simplified method: Get all <a href="https://corefork.telegram.org/api/forum">topics of a forum</a> <para>See <a href="https://corefork.telegram.org/method/channels.getForumTopics"/></para> <para>Possible <see cref="RpcException"/> codes: 400 (<a href="https://corefork.telegram.org/method/channels.getForumTopics#possible-errors">details</a>)</para></summary>
|
||||||
/// <param name="channel">Supergroup</param>
|
/// <param name="peer">Supergroup or Bot peer</param>
|
||||||
/// <param name="q">Search query</param>
|
/// <param name="q">Search query</param>
|
||||||
public async Task<Messages_ForumTopics> Channels_GetAllForumTopics(InputChannelBase channel, string q = null)
|
public async Task<Messages_ForumTopics> Channels_GetAllForumTopics(InputPeer peer, string q = null)
|
||||||
{
|
{
|
||||||
var result = await this.Channels_GetForumTopics(channel, offset_date: DateTime.MaxValue, q: q);
|
var result = await this.Messages_GetForumTopics(peer, offset_date: DateTime.MaxValue, q: q);
|
||||||
if (result.topics.Length < result.count)
|
if (result.topics.Length < result.count)
|
||||||
{
|
{
|
||||||
var topics = result.topics.ToList();
|
var topics = result.topics.ToList();
|
||||||
var messages = result.messages.ToList();
|
var messages = result.messages.ToList();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var more_topics = await this.Channels_GetForumTopics(channel, messages[^1].Date, messages[^1].ID, topics[^1].ID);
|
var more_topics = await this.Messages_GetForumTopics(peer, messages[^1].Date, messages[^1].ID, topics[^1].ID);
|
||||||
if (more_topics.topics.Length == 0) break;
|
if (more_topics.topics.Length == 0) break;
|
||||||
topics.AddRange(more_topics.topics);
|
topics.AddRange(more_topics.topics);
|
||||||
messages.AddRange(more_topics.messages);
|
messages.AddRange(more_topics.messages);
|
||||||
|
|
|
||||||
|
|
@ -185,10 +185,6 @@ namespace WTelegram
|
||||||
return Console.ReadLine();
|
return Console.ReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Load a specific Telegram server public key</summary>
|
|
||||||
/// <param name="pem">A string starting with <c>-----BEGIN RSA PUBLIC KEY-----</c></param>
|
|
||||||
public static void LoadPublicKey(string pem) => Encryption.LoadPublicKey(pem);
|
|
||||||
|
|
||||||
/// <summary>Builds a structure that is used to validate a 2FA password</summary>
|
/// <summary>Builds a structure that is used to validate a 2FA password</summary>
|
||||||
/// <param name="accountPassword">Password validation configuration. You can obtain this via <c>Account_GetPassword</c> or through OnOther as part of the login process</param>
|
/// <param name="accountPassword">Password validation configuration. You can obtain this via <c>Account_GetPassword</c> or through OnOther as part of the login process</param>
|
||||||
/// <param name="password">The password to validate</param>
|
/// <param name="password">The password to validate</param>
|
||||||
|
|
@ -358,7 +354,7 @@ namespace WTelegram
|
||||||
if (await stream.FullReadAsync(data, 4, ct) != 4)
|
if (await stream.FullReadAsync(data, 4, ct) != 4)
|
||||||
throw new WTException(ConnectionShutDown);
|
throw new WTException(ConnectionShutDown);
|
||||||
#if OBFUSCATION
|
#if OBFUSCATION
|
||||||
_recvCtr.EncryptDecrypt(data, 4);
|
_recvCtr.EncryptDecrypt(data.AsSpan(0, 4));
|
||||||
#endif
|
#endif
|
||||||
int payloadLen = BinaryPrimitives.ReadInt32LittleEndian(data);
|
int payloadLen = BinaryPrimitives.ReadInt32LittleEndian(data);
|
||||||
if (payloadLen <= 0)
|
if (payloadLen <= 0)
|
||||||
|
|
@ -370,7 +366,7 @@ namespace WTelegram
|
||||||
if (await stream.FullReadAsync(data, payloadLen, ct) != payloadLen)
|
if (await stream.FullReadAsync(data, payloadLen, ct) != payloadLen)
|
||||||
throw new WTException("Could not read frame data : Connection shut down");
|
throw new WTException("Could not read frame data : Connection shut down");
|
||||||
#if OBFUSCATION
|
#if OBFUSCATION
|
||||||
_recvCtr.EncryptDecrypt(data, payloadLen);
|
_recvCtr.EncryptDecrypt(data.AsSpan(0, payloadLen));
|
||||||
#endif
|
#endif
|
||||||
obj = ReadFrame(data, payloadLen);
|
obj = ReadFrame(data, payloadLen);
|
||||||
}
|
}
|
||||||
|
|
@ -593,7 +589,7 @@ namespace WTelegram
|
||||||
{
|
{
|
||||||
var msg = new _Message(reader.ReadInt64(), reader.ReadInt32(), null) { bytes = reader.ReadInt32() };
|
var msg = new _Message(reader.ReadInt64(), reader.ReadInt32(), null) { bytes = reader.ReadInt32() };
|
||||||
messages.Add(msg);
|
messages.Add(msg);
|
||||||
if ((msg.seq_no & 1) != 0) lock (_msgsToAck) _msgsToAck.Add(msg.msg_id);
|
if ((msg.seqno & 1) != 0) lock (_msgsToAck) _msgsToAck.Add(msg.msg_id);
|
||||||
var pos = reader.BaseStream.Position;
|
var pos = reader.BaseStream.Position;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -606,7 +602,7 @@ namespace WTelegram
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var obj = msg.body = reader.ReadTLObject(ctorNb);
|
var obj = msg.body = reader.ReadTLObject(ctorNb);
|
||||||
Helpers.Log(1, $" → {obj.GetType().Name,-38} {MsgIdToStamp(msg.msg_id):u} {((msg.seq_no & 1) != 0 ? "" : "(svc)")} {((msg.msg_id & 2) == 0 ? "" : "NAR")}");
|
Helpers.Log(1, $" → {obj.GetType().Name,-38} {MsgIdToStamp(msg.msg_id):u} {((msg.seqno & 1) != 0 ? "" : "(svc)")} {((msg.msg_id & 2) == 0 ? "" : "NAR")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -1129,7 +1125,7 @@ namespace WTelegram
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var users = await this.Users_GetUsers(InputUser.Self); // this calls also reenable incoming Updates
|
var users = await this.Users_GetUsers(InputUser.Self); // this call also reenable incoming Updates
|
||||||
var self = users[0] as User;
|
var self = users[0] as User;
|
||||||
if (self.id == long.Parse(botToken.Split(':')[0]))
|
if (self.id == long.Parse(botToken.Split(':')[0]))
|
||||||
{
|
{
|
||||||
|
|
@ -1481,7 +1477,7 @@ namespace WTelegram
|
||||||
writer.Write(0L); // int64 auth_key_id = 0 (Unencrypted)
|
writer.Write(0L); // int64 auth_key_id = 0 (Unencrypted)
|
||||||
writer.Write(msgId); // int64 message_id
|
writer.Write(msgId); // int64 message_id
|
||||||
writer.Write(0); // int32 message_data_length (to be patched)
|
writer.Write(0); // int32 message_data_length (to be patched)
|
||||||
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_')}...");
|
Helpers.Log(1, $"{_dcSession.DcID}>Sending {msg.GetType().Name.TrimEnd('_')}");
|
||||||
writer.WriteTLObject(msg); // bytes message_data
|
writer.WriteTLObject(msg); // bytes message_data
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(memStream.GetBuffer().AsSpan(20), (int)memStream.Length - 24); // patch message_data_length
|
BinaryPrimitives.WriteInt32LittleEndian(memStream.GetBuffer().AsSpan(20), (int)memStream.Length - 24); // patch message_data_length
|
||||||
}
|
}
|
||||||
|
|
@ -1526,7 +1522,7 @@ namespace WTelegram
|
||||||
int frameLength = (int)memStream.Length;
|
int frameLength = (int)memStream.Length;
|
||||||
BinaryPrimitives.WriteInt32LittleEndian(buffer, frameLength - 4); // patch payload_len with correct value
|
BinaryPrimitives.WriteInt32LittleEndian(buffer, frameLength - 4); // patch payload_len with correct value
|
||||||
#if OBFUSCATION
|
#if OBFUSCATION
|
||||||
_sendCtr?.EncryptDecrypt(buffer, frameLength);
|
_sendCtr?.EncryptDecrypt(buffer.AsSpan(0, frameLength));
|
||||||
#endif
|
#endif
|
||||||
if (_networkStream != null)
|
if (_networkStream != null)
|
||||||
await _networkStream.WriteAsync(buffer, 0, frameLength);
|
await _networkStream.WriteAsync(buffer, 0, frameLength);
|
||||||
|
|
@ -1633,7 +1629,7 @@ namespace WTelegram
|
||||||
got503 = true;
|
got503 = true;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
else if (code == 401 && message == "SESSION_REVOKED" && !IsMainDC) // need to renegociate alt-DC auth
|
else if (code == 401 && !IsMainDC && message is "SESSION_REVOKED" or "AUTH_KEY_UNREGISTERED") // need to renegociate alt-DC auth
|
||||||
{
|
{
|
||||||
lock (_session)
|
lock (_session)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using static WTelegram.Compat;
|
||||||
|
|
||||||
namespace WTelegram
|
namespace WTelegram
|
||||||
{
|
{
|
||||||
internal static class Encryption
|
public static class Encryption
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<long, RSAPublicKey> PublicKeys = [];
|
private static readonly Dictionary<long, RSAPublicKey> PublicKeys = [];
|
||||||
internal static readonly RandomNumberGenerator RNG = RandomNumberGenerator.Create();
|
internal static readonly RandomNumberGenerator RNG = RandomNumberGenerator.Create();
|
||||||
|
|
@ -94,7 +94,7 @@ namespace WTelegram
|
||||||
if (serverDHparams is not ServerDHParamsOk serverDHparamsOk) throw new WTException("not server_DH_params_ok");
|
if (serverDHparams is not ServerDHParamsOk serverDHparamsOk) throw new WTException("not server_DH_params_ok");
|
||||||
if (serverDHparamsOk.nonce != nonce) throw new WTException("Nonce mismatch");
|
if (serverDHparamsOk.nonce != nonce) throw new WTException("Nonce mismatch");
|
||||||
if (serverDHparamsOk.server_nonce != resPQ.server_nonce) throw new WTException("Server Nonce mismatch");
|
if (serverDHparamsOk.server_nonce != resPQ.server_nonce) throw new WTException("Server Nonce mismatch");
|
||||||
var (tmp_aes_key, tmp_aes_iv) = ConstructTmpAESKeyIV(resPQ.server_nonce, pqInnerData.new_nonce);
|
var (tmp_aes_key, tmp_aes_iv) = ConstructTmpAESKeyIV(sha1, resPQ.server_nonce, pqInnerData.new_nonce);
|
||||||
var answer = AES_IGE_EncryptDecrypt(serverDHparamsOk.encrypted_answer, tmp_aes_key, tmp_aes_iv, false);
|
var answer = AES_IGE_EncryptDecrypt(serverDHparamsOk.encrypted_answer, tmp_aes_key, tmp_aes_iv, false);
|
||||||
|
|
||||||
using var answerReader = new BinaryReader(new MemoryStream(answer));
|
using var answerReader = new BinaryReader(new MemoryStream(answer));
|
||||||
|
|
@ -163,8 +163,9 @@ namespace WTelegram
|
||||||
session.AuthKey = authKey;
|
session.AuthKey = authKey;
|
||||||
session.Salt = BinaryPrimitives.ReadInt64LittleEndian(pqInnerData.new_nonce.raw) ^ BinaryPrimitives.ReadInt64LittleEndian(resPQ.server_nonce.raw);
|
session.Salt = BinaryPrimitives.ReadInt64LittleEndian(pqInnerData.new_nonce.raw) ^ BinaryPrimitives.ReadInt64LittleEndian(resPQ.server_nonce.raw);
|
||||||
session.OldSalt = session.Salt;
|
session.OldSalt = session.Salt;
|
||||||
|
}
|
||||||
|
|
||||||
(byte[] key, byte[] iv) ConstructTmpAESKeyIV(TL.Int128 server_nonce, Int256 new_nonce)
|
public static (byte[] key, byte[] iv) ConstructTmpAESKeyIV(SHA1 sha1, TL.Int128 server_nonce, Int256 new_nonce)
|
||||||
{
|
{
|
||||||
byte[] tmp_aes_key = new byte[32], tmp_aes_iv = new byte[32];
|
byte[] tmp_aes_key = new byte[32], tmp_aes_iv = new byte[32];
|
||||||
sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
sha1.TransformBlock(new_nonce, 0, 32, null, 0);
|
||||||
|
|
@ -183,7 +184,6 @@ namespace WTelegram
|
||||||
sha1.Initialize();
|
sha1.Initialize();
|
||||||
return (tmp_aes_key, tmp_aes_iv);
|
return (tmp_aes_key, tmp_aes_iv);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal static void CheckGoodPrime(BigInteger p, int g)
|
internal static void CheckGoodPrime(BigInteger p, int g)
|
||||||
{
|
{
|
||||||
|
|
@ -237,6 +237,8 @@ namespace WTelegram
|
||||||
throw new WTException("g^a or g^b is not between 2^{2048-64} and dh_prime - 2^{2048-64}");
|
throw new WTException("g^a or g^b is not between 2^{2048-64} and dh_prime - 2^{2048-64}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Load a specific Telegram server public key</summary>
|
||||||
|
/// <param name="pem">A string starting with <c>-----BEGIN RSA PUBLIC KEY-----</c></param>
|
||||||
public static void LoadPublicKey(string pem)
|
public static void LoadPublicKey(string pem)
|
||||||
{
|
{
|
||||||
using var rsa = RSA.Create();
|
using var rsa = RSA.Create();
|
||||||
|
|
@ -245,10 +247,7 @@ namespace WTelegram
|
||||||
var rsaParam = rsa.ExportParameters(false);
|
var rsaParam = rsa.ExportParameters(false);
|
||||||
if (rsaParam.Modulus[0] == 0) rsaParam.Modulus = rsaParam.Modulus[1..];
|
if (rsaParam.Modulus[0] == 0) rsaParam.Modulus = rsaParam.Modulus[1..];
|
||||||
var publicKey = new RSAPublicKey { n = rsaParam.Modulus, e = rsaParam.Exponent };
|
var publicKey = new RSAPublicKey { n = rsaParam.Modulus, e = rsaParam.Exponent };
|
||||||
using var memStream = new MemoryStream(280);
|
var bareData = publicKey.ToBytes();
|
||||||
using (var writer = new BinaryWriter(memStream))
|
|
||||||
writer.WriteTLObject(publicKey);
|
|
||||||
var bareData = memStream.ToArray();
|
|
||||||
var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(bareData, 4, bareData.Length - 4).AsSpan(12)); // 64 lower-order bits of SHA1
|
var fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(bareData, 4, bareData.Length - 4).AsSpan(12)); // 64 lower-order bits of SHA1
|
||||||
PublicKeys[fingerprint] = publicKey;
|
PublicKeys[fingerprint] = publicKey;
|
||||||
Helpers.Log(1, $"Loaded a public key with fingerprint {fingerprint:X}");
|
Helpers.Log(1, $"Loaded a public key with fingerprint {fingerprint:X}");
|
||||||
|
|
@ -276,7 +275,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
-----END RSA PUBLIC KEY-----");
|
-----END RSA PUBLIC KEY-----");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, int x, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
|
public static byte[] EncryptDecryptMessage(Span<byte> input, bool encrypt, int x, byte[] authKey, byte[] msgKey, int msgKeyOffset, SHA256 sha256)
|
||||||
{
|
{
|
||||||
// first, construct AES key & IV
|
// first, construct AES key & IV
|
||||||
byte[] aes_key = new byte[32], aes_iv = new byte[32];
|
byte[] aes_key = new byte[32], aes_iv = new byte[32];
|
||||||
|
|
@ -297,7 +296,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt);
|
return AES_IGE_EncryptDecrypt(input, aes_key, aes_iv, encrypt);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt)
|
public static byte[] AES_IGE_EncryptDecrypt(Span<byte> input, byte[] aes_key, byte[] aes_iv, bool encrypt)
|
||||||
{
|
{
|
||||||
if (input.Length % 16 != 0) throw new WTException("AES_IGE input size not divisible by 16");
|
if (input.Length % 16 != 0) throw new WTException("AES_IGE input size not divisible by 16");
|
||||||
|
|
||||||
|
|
@ -305,8 +304,8 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
var output = new byte[input.Length];
|
var output = new byte[input.Length];
|
||||||
var prevBytes = (byte[])aes_iv.Clone();
|
var prevBytes = (byte[])aes_iv.Clone();
|
||||||
var span = MemoryMarshal.Cast<byte, long>(input);
|
var span = MemoryMarshal.Cast<byte, long>(input);
|
||||||
var sout = MemoryMarshal.Cast<byte, long>(output);
|
var sout = MemoryMarshal.Cast<byte, long>(output.AsSpan());
|
||||||
var prev = MemoryMarshal.Cast<byte, long>(prevBytes);
|
var prev = MemoryMarshal.Cast<byte, long>(prevBytes.AsSpan());
|
||||||
if (!encrypt) { (prev[2], prev[0]) = (prev[0], prev[2]); (prev[3], prev[1]) = (prev[1], prev[3]); }
|
if (!encrypt) { (prev[2], prev[0]) = (prev[0], prev[2]); (prev[3], prev[1]) = (prev[1], prev[3]); }
|
||||||
for (int i = 0, count = input.Length / 8; i < count;)
|
for (int i = 0, count = input.Length / 8; i < count;)
|
||||||
{
|
{
|
||||||
|
|
@ -319,7 +318,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OBFUSCATION
|
#if OBFUSCATION
|
||||||
internal sealed class AesCtr(byte[] key, byte[] ivec) : IDisposable
|
public sealed class AesCtr(byte[] key, byte[] ivec) : IDisposable
|
||||||
{
|
{
|
||||||
readonly ICryptoTransform _encryptor = AesECB.CreateEncryptor(key, null);
|
readonly ICryptoTransform _encryptor = AesECB.CreateEncryptor(key, null);
|
||||||
readonly byte[] _ecount = new byte[16];
|
readonly byte[] _ecount = new byte[16];
|
||||||
|
|
@ -327,9 +326,9 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
|
|
||||||
public void Dispose() => _encryptor.Dispose();
|
public void Dispose() => _encryptor.Dispose();
|
||||||
|
|
||||||
public void EncryptDecrypt(byte[] buffer, int length)
|
public void EncryptDecrypt(Span<byte> buffer)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < buffer.Length; i++)
|
||||||
{
|
{
|
||||||
if (_num == 0)
|
if (_num == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -373,7 +372,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
var sendCtr = new AesCtr(sendKey, sendIV);
|
var sendCtr = new AesCtr(sendKey, sendIV);
|
||||||
var recvCtr = new AesCtr(recvKey, recvIV);
|
var recvCtr = new AesCtr(recvKey, recvIV);
|
||||||
var encrypted = (byte[])preamble.Clone();
|
var encrypted = (byte[])preamble.Clone();
|
||||||
sendCtr.EncryptDecrypt(encrypted, 64);
|
sendCtr.EncryptDecrypt(encrypted);
|
||||||
for (int i = 56; i < 64; i++)
|
for (int i = 56; i < 64; i++)
|
||||||
preamble[i] = encrypted[i];
|
preamble[i] = encrypted[i];
|
||||||
return (sendCtr, recvCtr, preamble);
|
return (sendCtr, recvCtr, preamble);
|
||||||
|
|
@ -557,7 +556,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB
|
||||||
{
|
{
|
||||||
count = count + 15 & ~15;
|
count = count + 15 & ~15;
|
||||||
var span = MemoryMarshal.Cast<byte, long>(buffer.AsSpan(offset, count));
|
var span = MemoryMarshal.Cast<byte, long>(buffer.AsSpan(offset, count));
|
||||||
var prev = MemoryMarshal.Cast<byte, long>(_prevBytes);
|
var prev = MemoryMarshal.Cast<byte, long>(_prevBytes.AsSpan());
|
||||||
for (offset = 0, count /= 8; offset < count;)
|
for (offset = 0, count /= 8; offset < count;)
|
||||||
{
|
{
|
||||||
prev[0] ^= span[offset]; prev[1] ^= span[offset + 1];
|
prev[0] ^= span[offset]; prev[1] ^= span[offset + 1];
|
||||||
|
|
|
||||||
|
|
@ -70,8 +70,13 @@ namespace TL
|
||||||
foreach (var chat in chats)
|
foreach (var chat in chats)
|
||||||
if (chat is not Channel channel)
|
if (chat is not Channel channel)
|
||||||
_chats[chat.ID] = chat;
|
_chats[chat.ID] = chat;
|
||||||
else if (!channel.flags.HasFlag(Channel.Flags.min) || !_chats.TryGetValue(channel.id, out var prevChat) || prevChat is not Channel prevChannel || prevChannel.flags.HasFlag(Channel.Flags.min))
|
else if (!_chats.TryGetValue(channel.id, out var prevChat) || prevChat is not Channel prevChannel)
|
||||||
_chats[channel.id] = channel;
|
_chats[channel.id] = channel;
|
||||||
|
else if (!channel.flags.HasFlag(Channel.Flags.min) || prevChannel.flags.HasFlag(Channel.Flags.min))
|
||||||
|
{
|
||||||
|
if (channel.participants_count == 0) channel.participants_count = prevChannel.participants_count; // non-min channel can lack this info
|
||||||
|
_chats[channel.id] = channel;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{ // update previously full channel from min channel:
|
{ // update previously full channel from min channel:
|
||||||
const Channel.Flags updated_flags = (Channel.Flags)0x7FDC0BE0;
|
const Channel.Flags updated_flags = (Channel.Flags)0x7FDC0BE0;
|
||||||
|
|
@ -378,15 +383,15 @@ namespace TL
|
||||||
end = offset + 1;
|
end = offset + 1;
|
||||||
if (end < sb.Length && sb[end] == '#') end++;
|
if (end < sb.Length && sb[end] == '#') end++;
|
||||||
while (end < sb.Length && sb[end] is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '0' and <= '9') end++;
|
while (end < sb.Length && sb[end] is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '0' and <= '9') end++;
|
||||||
if (end >= sb.Length || sb[end] != ';') break;
|
var html = HttpUtility.HtmlDecode(end >= sb.Length || sb[end] != ';'
|
||||||
var html = HttpUtility.HtmlDecode(sb.ToString(offset, end - offset + 1));
|
? sb.ToString(offset, end - offset) + ";" : sb.ToString(offset, ++end - offset));
|
||||||
if (html.Length == 1)
|
if (html.Length == 1)
|
||||||
{
|
{
|
||||||
sb[offset] = html[0];
|
sb[offset] = html[0];
|
||||||
sb.Remove(++offset, end - offset + 1);
|
sb.Remove(++offset, end - offset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
offset = end + 1;
|
offset = end;
|
||||||
}
|
}
|
||||||
else if (c == '<')
|
else if (c == '<')
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -109,15 +109,13 @@ namespace TL
|
||||||
public Int128 new_nonce_hash3;
|
public Int128 new_nonce_hash3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DestroyAuthKeyRes : uint
|
public abstract partial class DestroyAuthKeyRes : IObject { }
|
||||||
{
|
[TLDef(0xF660E1D4)] //destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes
|
||||||
///<summary>See <a href="https://corefork.telegram.org/constructor/destroy_auth_key_ok"/></summary>
|
public sealed partial class DestroyAuthKeyOk : DestroyAuthKeyRes { }
|
||||||
Ok = 0xF660E1D4,
|
[TLDef(0x0A9F2259)] //destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes
|
||||||
///<summary>See <a href="https://corefork.telegram.org/constructor/destroy_auth_key_none"/></summary>
|
public sealed partial class DestroyAuthKeyNone : DestroyAuthKeyRes { }
|
||||||
None = 0x0A9F2259,
|
[TLDef(0xEA109B13)] //destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes
|
||||||
///<summary>See <a href="https://corefork.telegram.org/constructor/destroy_auth_key_fail"/></summary>
|
public sealed partial class DestroyAuthKeyFail : DestroyAuthKeyRes { }
|
||||||
Fail = 0xEA109B13,
|
|
||||||
}
|
|
||||||
|
|
||||||
[TLDef(0x62D6B459)] //msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck
|
[TLDef(0x62D6B459)] //msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck
|
||||||
public sealed partial class MsgsAck : IObject
|
public sealed partial class MsgsAck : IObject
|
||||||
|
|
@ -327,12 +325,12 @@ namespace TL
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Task<DestroyAuthKeyRes> DestroyAuthKey(this Client client)
|
public static Task<DestroyAuthKeyRes> DestroyAuthKey(this Client client)
|
||||||
=> client.InvokeBare(new DestroyAuthKey
|
=> client.Invoke(new DestroyAuthKey
|
||||||
{
|
{
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Task<RpcDropAnswer> RpcDropAnswer(this Client client, long req_msg_id)
|
public static Task<RpcDropAnswer> RpcDropAnswer(this Client client, long req_msg_id)
|
||||||
=> client.InvokeBare(new Methods.RpcDropAnswer
|
=> client.Invoke(new Methods.RpcDropAnswer
|
||||||
{
|
{
|
||||||
req_msg_id = req_msg_id,
|
req_msg_id = req_msg_id,
|
||||||
});
|
});
|
||||||
|
|
@ -357,7 +355,7 @@ namespace TL
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Task<DestroySessionRes> DestroySession(this Client client, long session_id)
|
public static Task<DestroySessionRes> DestroySession(this Client client, long session_id)
|
||||||
=> client.InvokeBare(new DestroySession
|
=> client.Invoke(new DestroySession
|
||||||
{
|
{
|
||||||
session_id = session_id,
|
session_id = session_id,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
1159
src/TL.Schema.cs
1159
src/TL.Schema.cs
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -3,7 +3,7 @@
|
||||||
namespace TL
|
namespace TL
|
||||||
{
|
{
|
||||||
#pragma warning disable IDE1006, CS1574
|
#pragma warning disable IDE1006, CS1574
|
||||||
/// <summary>Object describes the contents of an encrypted message. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessage"/></para></summary>
|
/// <summary>Object describes the contents of an encrypted message. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessage"/></para> <para>Derived classes: <see cref="DecryptedMessage"/>, <see cref="DecryptedMessageService"/></para></summary>
|
||||||
public abstract partial class DecryptedMessageBase : IObject
|
public abstract partial class DecryptedMessageBase : IObject
|
||||||
{
|
{
|
||||||
/// <summary>Flags, see <a href="https://corefork.telegram.org/mtproto/TL-combinators#conditional-fields">TL conditional fields</a> (added in layer 45)</summary>
|
/// <summary>Flags, see <a href="https://corefork.telegram.org/mtproto/TL-combinators#conditional-fields">TL conditional fields</a> (added in layer 45)</summary>
|
||||||
|
|
@ -24,11 +24,12 @@ namespace TL
|
||||||
public virtual long ReplyToRandom => default;
|
public virtual long ReplyToRandom => default;
|
||||||
/// <summary>Random group ID, assigned by the author of message.<br/>Multiple encrypted messages with a photo attached and with the same group ID indicate an <a href="https://corefork.telegram.org/api/files#albums-grouped-media">album or grouped media</a> (parameter added in layer 45)</summary>
|
/// <summary>Random group ID, assigned by the author of message.<br/>Multiple encrypted messages with a photo attached and with the same group ID indicate an <a href="https://corefork.telegram.org/api/files#albums-grouped-media">album or grouped media</a> (parameter added in layer 45)</summary>
|
||||||
public virtual long Grouped => default;
|
public virtual long Grouped => default;
|
||||||
|
/// <summary>Random bytes, removed in layer 17.</summary>
|
||||||
public virtual byte[] RandomBytes => default;
|
public virtual byte[] RandomBytes => default;
|
||||||
public virtual DecryptedMessageAction Action => default;
|
public virtual DecryptedMessageAction Action => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Object describes media contents of an encrypted message. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessageMedia"/></para></summary>
|
/// <summary>Object describes media contents of an encrypted message. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessageMedia"/></para> <para>Derived classes: <see cref="DecryptedMessageMediaPhoto"/>, <see cref="DecryptedMessageMediaVideo"/>, <see cref="DecryptedMessageMediaGeoPoint"/>, <see cref="DecryptedMessageMediaContact"/>, <see cref="DecryptedMessageMediaDocument"/>, <see cref="DecryptedMessageMediaAudio"/>, <see cref="DecryptedMessageMediaExternalDocument"/>, <see cref="DecryptedMessageMediaVenue"/>, <see cref="DecryptedMessageMediaWebPage"/></para></summary>
|
||||||
/// <remarks>a <see langword="null"/> value means <a href="https://corefork.telegram.org/constructor/decryptedMessageMediaEmpty">decryptedMessageMediaEmpty</a></remarks>
|
/// <remarks>a <see langword="null"/> value means <a href="https://corefork.telegram.org/constructor/decryptedMessageMediaEmpty">decryptedMessageMediaEmpty</a></remarks>
|
||||||
public abstract partial class DecryptedMessageMedia : IObject
|
public abstract partial class DecryptedMessageMedia : IObject
|
||||||
{
|
{
|
||||||
|
|
@ -36,14 +37,17 @@ namespace TL
|
||||||
internal virtual (long size, byte[] key, byte[] iv) SizeKeyIV { get => default; set => throw new WTelegram.WTException("Incompatible DecryptedMessageMedia"); }
|
internal virtual (long size, byte[] key, byte[] iv) SizeKeyIV { get => default; set => throw new WTelegram.WTException("Incompatible DecryptedMessageMedia"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Object describes the action to which a service message is linked. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessageAction"/></para></summary>
|
/// <summary>Object describes the action to which a service message is linked. <para>See <a href="https://corefork.telegram.org/type/DecryptedMessageAction"/></para> <para>Derived classes: <see cref="DecryptedMessageActionSetMessageTTL"/>, <see cref="DecryptedMessageActionReadMessages"/>, <see cref="DecryptedMessageActionDeleteMessages"/>, <see cref="DecryptedMessageActionScreenshotMessages"/>, <see cref="DecryptedMessageActionFlushHistory"/>, <see cref="DecryptedMessageActionResend"/>, <see cref="DecryptedMessageActionNotifyLayer"/>, <see cref="DecryptedMessageActionTyping"/>, <see cref="DecryptedMessageActionRequestKey"/>, <see cref="DecryptedMessageActionAcceptKey"/>, <see cref="DecryptedMessageActionAbortKey"/>, <see cref="DecryptedMessageActionCommitKey"/>, <see cref="DecryptedMessageActionNoop"/></para></summary>
|
||||||
public abstract partial class DecryptedMessageAction : IObject { }
|
public abstract partial class DecryptedMessageAction : IObject { }
|
||||||
|
|
||||||
/// <summary>Indicates the location of a photo, will be deprecated soon <para>See <a href="https://corefork.telegram.org/type/FileLocation"/></para></summary>
|
/// <summary>Indicates the location of a photo, will be deprecated soon <para>See <a href="https://corefork.telegram.org/type/FileLocation"/></para> <para>Derived classes: <see cref="FileLocationUnavailable"/>, <see cref="FileLocation"/></para></summary>
|
||||||
public abstract partial class FileLocationBase : IObject
|
public abstract partial class FileLocationBase : IObject
|
||||||
{
|
{
|
||||||
|
/// <summary>Volume ID</summary>
|
||||||
public virtual long VolumeId => default;
|
public virtual long VolumeId => default;
|
||||||
|
/// <summary>Local ID</summary>
|
||||||
public virtual int LocalId => default;
|
public virtual int LocalId => default;
|
||||||
|
/// <summary>Secret</summary>
|
||||||
public virtual long Secret => default;
|
public virtual long Secret => default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +59,7 @@ namespace TL
|
||||||
{
|
{
|
||||||
/// <summary>Random message ID, assigned by the author of message.<br/>Must be equal to the ID passed to sending method.</summary>
|
/// <summary>Random message ID, assigned by the author of message.<br/>Must be equal to the ID passed to sending method.</summary>
|
||||||
public long random_id;
|
public long random_id;
|
||||||
|
/// <summary>Random bytes, removed in layer 17.</summary>
|
||||||
public byte[] random_bytes;
|
public byte[] random_bytes;
|
||||||
/// <summary>Message text</summary>
|
/// <summary>Message text</summary>
|
||||||
public string message;
|
public string message;
|
||||||
|
|
@ -67,6 +72,7 @@ namespace TL
|
||||||
public override string Message => message;
|
public override string Message => message;
|
||||||
/// <summary>Media content</summary>
|
/// <summary>Media content</summary>
|
||||||
public override DecryptedMessageMedia Media => media;
|
public override DecryptedMessageMedia Media => media;
|
||||||
|
/// <summary>Random bytes, removed in layer 17.</summary>
|
||||||
public override byte[] RandomBytes => random_bytes;
|
public override byte[] RandomBytes => random_bytes;
|
||||||
}
|
}
|
||||||
/// <summary>Contents of an encrypted service message. <para>See <a href="https://corefork.telegram.org/constructor/decryptedMessageService"/></para></summary>
|
/// <summary>Contents of an encrypted service message. <para>See <a href="https://corefork.telegram.org/constructor/decryptedMessageService"/></para></summary>
|
||||||
|
|
@ -75,12 +81,14 @@ namespace TL
|
||||||
{
|
{
|
||||||
/// <summary>Random message ID, assigned by the message author.<br/>Must be equal to the ID passed to the sending method.</summary>
|
/// <summary>Random message ID, assigned by the message author.<br/>Must be equal to the ID passed to the sending method.</summary>
|
||||||
public long random_id;
|
public long random_id;
|
||||||
|
/// <summary>Random bytes, removed in Layer 17.</summary>
|
||||||
public byte[] random_bytes;
|
public byte[] random_bytes;
|
||||||
/// <summary>Action relevant to the service message</summary>
|
/// <summary>Action relevant to the service message</summary>
|
||||||
public DecryptedMessageAction action;
|
public DecryptedMessageAction action;
|
||||||
|
|
||||||
/// <summary>Random message ID, assigned by the message author.<br/>Must be equal to the ID passed to the sending method.</summary>
|
/// <summary>Random message ID, assigned by the message author.<br/>Must be equal to the ID passed to the sending method.</summary>
|
||||||
public override long RandomId => random_id;
|
public override long RandomId => random_id;
|
||||||
|
/// <summary>Random bytes, removed in Layer 17.</summary>
|
||||||
public override byte[] RandomBytes => random_bytes;
|
public override byte[] RandomBytes => random_bytes;
|
||||||
/// <summary>Action relevant to the service message</summary>
|
/// <summary>Action relevant to the service message</summary>
|
||||||
public override DecryptedMessageAction Action => action;
|
public override DecryptedMessageAction Action => action;
|
||||||
|
|
@ -167,6 +175,7 @@ namespace TL
|
||||||
public int thumb_w;
|
public int thumb_w;
|
||||||
/// <summary>Thumbnail height</summary>
|
/// <summary>Thumbnail height</summary>
|
||||||
public int thumb_h;
|
public int thumb_h;
|
||||||
|
/// <summary>File name, moved to <c>attributes</c> in Layer 45.</summary>
|
||||||
public string file_name;
|
public string file_name;
|
||||||
/// <summary>File MIME-type</summary>
|
/// <summary>File MIME-type</summary>
|
||||||
public string mime_type;
|
public string mime_type;
|
||||||
|
|
@ -498,25 +507,38 @@ namespace TL
|
||||||
[TLDef(0x7C596B46)]
|
[TLDef(0x7C596B46)]
|
||||||
public sealed partial class FileLocationUnavailable : FileLocationBase
|
public sealed partial class FileLocationUnavailable : FileLocationBase
|
||||||
{
|
{
|
||||||
|
/// <summary>Volume ID</summary>
|
||||||
public long volume_id;
|
public long volume_id;
|
||||||
|
/// <summary>Local ID</summary>
|
||||||
public int local_id;
|
public int local_id;
|
||||||
|
/// <summary>Secret</summary>
|
||||||
public long secret;
|
public long secret;
|
||||||
|
|
||||||
|
/// <summary>Volume ID</summary>
|
||||||
public override long VolumeId => volume_id;
|
public override long VolumeId => volume_id;
|
||||||
|
/// <summary>Local ID</summary>
|
||||||
public override int LocalId => local_id;
|
public override int LocalId => local_id;
|
||||||
|
/// <summary>Secret</summary>
|
||||||
public override long Secret => secret;
|
public override long Secret => secret;
|
||||||
}
|
}
|
||||||
/// <summary>File location. <para>See <a href="https://corefork.telegram.org/constructor/fileLocation"/></para></summary>
|
/// <summary>File location. <para>See <a href="https://corefork.telegram.org/constructor/fileLocation"/></para></summary>
|
||||||
[TLDef(0x53D69076)]
|
[TLDef(0x53D69076)]
|
||||||
public sealed partial class FileLocation : FileLocationBase
|
public sealed partial class FileLocation : FileLocationBase
|
||||||
{
|
{
|
||||||
|
/// <summary>DC ID</summary>
|
||||||
public int dc_id;
|
public int dc_id;
|
||||||
|
/// <summary>Volume ID</summary>
|
||||||
public long volume_id;
|
public long volume_id;
|
||||||
|
/// <summary>Local ID</summary>
|
||||||
public int local_id;
|
public int local_id;
|
||||||
|
/// <summary>Secret</summary>
|
||||||
public long secret;
|
public long secret;
|
||||||
|
|
||||||
|
/// <summary>Volume ID</summary>
|
||||||
public override long VolumeId => volume_id;
|
public override long VolumeId => volume_id;
|
||||||
|
/// <summary>Local ID</summary>
|
||||||
public override int LocalId => local_id;
|
public override int LocalId => local_id;
|
||||||
|
/// <summary>Secret</summary>
|
||||||
public override long Secret => secret;
|
public override long Secret => secret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -775,7 +797,6 @@ namespace TL
|
||||||
{
|
{
|
||||||
/// <summary>Field <see cref="reply_to_random_id"/> has a value</summary>
|
/// <summary>Field <see cref="reply_to_random_id"/> has a value</summary>
|
||||||
has_reply_to_random_id = 0x8,
|
has_reply_to_random_id = 0x8,
|
||||||
/// <summary>Whether this is a silent message (no notification triggered)</summary>
|
|
||||||
silent = 0x20,
|
silent = 0x20,
|
||||||
/// <summary>Field <see cref="entities"/> has a value</summary>
|
/// <summary>Field <see cref="entities"/> has a value</summary>
|
||||||
has_entities = 0x80,
|
has_entities = 0x80,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace TL
|
||||||
{
|
{
|
||||||
public static partial class Layer
|
public static partial class Layer
|
||||||
{
|
{
|
||||||
public const int Version = 211; // fetched 16/08/2025 00:21:53
|
public const int Version = 216; // fetched 10/10/2025 20:01:17
|
||||||
internal const int SecretChats = 144;
|
internal const int SecretChats = 144;
|
||||||
internal const int MTProto2 = 73;
|
internal const int MTProto2 = 73;
|
||||||
internal const uint VectorCtor = 0x1CB5C415;
|
internal const uint VectorCtor = 0x1CB5C415;
|
||||||
|
|
@ -41,7 +41,9 @@ namespace TL
|
||||||
[0x3BCBF734] = typeof(DhGenOk),
|
[0x3BCBF734] = typeof(DhGenOk),
|
||||||
[0x46DC1FB9] = typeof(DhGenRetry),
|
[0x46DC1FB9] = typeof(DhGenRetry),
|
||||||
[0xA69DAE02] = typeof(DhGenFail),
|
[0xA69DAE02] = typeof(DhGenFail),
|
||||||
[0x7ABE77EC] = typeof(Methods.Ping),
|
[0xF660E1D4] = typeof(DestroyAuthKeyOk),
|
||||||
|
[0x0A9F2259] = typeof(DestroyAuthKeyNone),
|
||||||
|
[0xEA109B13] = typeof(DestroyAuthKeyFail),
|
||||||
[0x62D6B459] = typeof(MsgsAck),
|
[0x62D6B459] = typeof(MsgsAck),
|
||||||
[0xA7EFF811] = typeof(BadMsgNotification),
|
[0xA7EFF811] = typeof(BadMsgNotification),
|
||||||
[0xEDAB447B] = typeof(BadServerSalt),
|
[0xEDAB447B] = typeof(BadServerSalt),
|
||||||
|
|
@ -66,6 +68,7 @@ namespace TL
|
||||||
[0x37982646] = typeof(IpPortSecret),
|
[0x37982646] = typeof(IpPortSecret),
|
||||||
[0x4679B65F] = typeof(AccessPointRule),
|
[0x4679B65F] = typeof(AccessPointRule),
|
||||||
[0x5A592A6C] = typeof(Help_ConfigSimple),
|
[0x5A592A6C] = typeof(Help_ConfigSimple),
|
||||||
|
[0x7ABE77EC] = typeof(Methods.Ping),
|
||||||
// from TL.SchemaExtensions:
|
// from TL.SchemaExtensions:
|
||||||
[0x3FEDD339] = typeof(True),
|
[0x3FEDD339] = typeof(True),
|
||||||
[0xC4B9F9BB] = typeof(Error),
|
[0xC4B9F9BB] = typeof(Error),
|
||||||
|
|
@ -140,7 +143,7 @@ namespace TL
|
||||||
[0xFE685355] = typeof(Channel),
|
[0xFE685355] = typeof(Channel),
|
||||||
[0x17D493D5] = typeof(ChannelForbidden),
|
[0x17D493D5] = typeof(ChannelForbidden),
|
||||||
[0x2633421B] = typeof(ChatFull),
|
[0x2633421B] = typeof(ChatFull),
|
||||||
[0xE07429DE] = typeof(ChannelFull),
|
[0xE4E0B29D] = typeof(ChannelFull),
|
||||||
[0xC02D4007] = typeof(ChatParticipant),
|
[0xC02D4007] = typeof(ChatParticipant),
|
||||||
[0xE46BCEE4] = typeof(ChatParticipantCreator),
|
[0xE46BCEE4] = typeof(ChatParticipantCreator),
|
||||||
[0xA0933F5B] = typeof(ChatParticipantAdmin),
|
[0xA0933F5B] = typeof(ChatParticipantAdmin),
|
||||||
|
|
@ -197,7 +200,7 @@ namespace TL
|
||||||
[0x502F92F7] = typeof(MessageActionInviteToGroupCall),
|
[0x502F92F7] = typeof(MessageActionInviteToGroupCall),
|
||||||
[0x3C134D7B] = typeof(MessageActionSetMessagesTTL),
|
[0x3C134D7B] = typeof(MessageActionSetMessagesTTL),
|
||||||
[0xB3A07661] = typeof(MessageActionGroupCallScheduled),
|
[0xB3A07661] = typeof(MessageActionGroupCallScheduled),
|
||||||
[0xAA786345] = typeof(MessageActionSetChatTheme),
|
[0xB91BBD3A] = typeof(MessageActionSetChatTheme),
|
||||||
[0xEBBCA3CB] = typeof(MessageActionChatJoinedByRequest),
|
[0xEBBCA3CB] = typeof(MessageActionChatJoinedByRequest),
|
||||||
[0x47DD8079] = typeof(MessageActionWebViewDataSentMe),
|
[0x47DD8079] = typeof(MessageActionWebViewDataSentMe),
|
||||||
[0xB4C38CB5] = typeof(MessageActionWebViewDataSent),
|
[0xB4C38CB5] = typeof(MessageActionWebViewDataSent),
|
||||||
|
|
@ -215,8 +218,8 @@ namespace TL
|
||||||
[0x41B3E202] = typeof(MessageActionPaymentRefunded),
|
[0x41B3E202] = typeof(MessageActionPaymentRefunded),
|
||||||
[0x45D5B021] = typeof(MessageActionGiftStars),
|
[0x45D5B021] = typeof(MessageActionGiftStars),
|
||||||
[0xB00C47A2] = typeof(MessageActionPrizeStars),
|
[0xB00C47A2] = typeof(MessageActionPrizeStars),
|
||||||
[0x4717E8A4] = typeof(MessageActionStarGift),
|
[0xF24DE7FA] = typeof(MessageActionStarGift),
|
||||||
[0x34F762F3] = typeof(MessageActionStarGiftUnique),
|
[0x95728543] = typeof(MessageActionStarGiftUnique),
|
||||||
[0xAC1F1FCD] = typeof(MessageActionPaidMessagesRefunded),
|
[0xAC1F1FCD] = typeof(MessageActionPaidMessagesRefunded),
|
||||||
[0x84B88578] = typeof(MessageActionPaidMessagesPrice),
|
[0x84B88578] = typeof(MessageActionPaidMessagesPrice),
|
||||||
[0x2FFE2F7A] = typeof(MessageActionConferenceCall),
|
[0x2FFE2F7A] = typeof(MessageActionConferenceCall),
|
||||||
|
|
@ -226,6 +229,7 @@ namespace TL
|
||||||
[0x95DDCF69] = typeof(MessageActionSuggestedPostSuccess),
|
[0x95DDCF69] = typeof(MessageActionSuggestedPostSuccess),
|
||||||
[0x69F916F8] = typeof(MessageActionSuggestedPostRefund),
|
[0x69F916F8] = typeof(MessageActionSuggestedPostRefund),
|
||||||
[0xA8A3C699] = typeof(MessageActionGiftTon),
|
[0xA8A3C699] = typeof(MessageActionGiftTon),
|
||||||
|
[0x2C8F2A25] = typeof(MessageActionSuggestBirthday),
|
||||||
[0xD58A08C6] = typeof(Dialog),
|
[0xD58A08C6] = typeof(Dialog),
|
||||||
[0x71BD134C] = typeof(DialogFolder),
|
[0x71BD134C] = typeof(DialogFolder),
|
||||||
[0x2331B22D] = typeof(PhotoEmpty),
|
[0x2331B22D] = typeof(PhotoEmpty),
|
||||||
|
|
@ -240,7 +244,7 @@ namespace TL
|
||||||
[0xB2A2F663] = typeof(GeoPoint),
|
[0xB2A2F663] = typeof(GeoPoint),
|
||||||
[0x5E002502] = typeof(Auth_SentCode),
|
[0x5E002502] = typeof(Auth_SentCode),
|
||||||
[0x2390FE44] = typeof(Auth_SentCodeSuccess),
|
[0x2390FE44] = typeof(Auth_SentCodeSuccess),
|
||||||
[0xD7CEF980] = typeof(Auth_SentCodePaymentRequired),
|
[0xE0955A3C] = typeof(Auth_SentCodePaymentRequired),
|
||||||
[0x2EA2C0D4] = typeof(Auth_Authorization),
|
[0x2EA2C0D4] = typeof(Auth_Authorization),
|
||||||
[0x44747E9A] = typeof(Auth_AuthorizationSignUpRequired),
|
[0x44747E9A] = typeof(Auth_AuthorizationSignUpRequired),
|
||||||
[0xB434E2B8] = typeof(Auth_ExportedAuthorization),
|
[0xB434E2B8] = typeof(Auth_ExportedAuthorization),
|
||||||
|
|
@ -254,7 +258,7 @@ namespace TL
|
||||||
[0xF47741F7] = typeof(PeerSettings),
|
[0xF47741F7] = typeof(PeerSettings),
|
||||||
[0xA437C3ED] = typeof(WallPaper),
|
[0xA437C3ED] = typeof(WallPaper),
|
||||||
[0xE0804116] = typeof(WallPaperNoFile),
|
[0xE0804116] = typeof(WallPaperNoFile),
|
||||||
[0x7E63CE1F] = typeof(UserFull),
|
[0xA02BC13E] = typeof(UserFull),
|
||||||
[0x145ADE0B] = typeof(Contact),
|
[0x145ADE0B] = typeof(Contact),
|
||||||
[0xC13E3C50] = typeof(ImportedContact),
|
[0xC13E3C50] = typeof(ImportedContact),
|
||||||
[0x16D9703B] = typeof(ContactStatus),
|
[0x16D9703B] = typeof(ContactStatus),
|
||||||
|
|
@ -266,8 +270,8 @@ namespace TL
|
||||||
[0x15BA6C40] = typeof(Messages_Dialogs),
|
[0x15BA6C40] = typeof(Messages_Dialogs),
|
||||||
[0x71E094F3] = typeof(Messages_DialogsSlice),
|
[0x71E094F3] = typeof(Messages_DialogsSlice),
|
||||||
[0xF0E3E596] = typeof(Messages_DialogsNotModified),
|
[0xF0E3E596] = typeof(Messages_DialogsNotModified),
|
||||||
[0x8C718E87] = typeof(Messages_Messages),
|
[0x1D73E7EA] = typeof(Messages_Messages),
|
||||||
[0x762B263D] = typeof(Messages_MessagesSlice),
|
[0x5F206716] = typeof(Messages_MessagesSlice),
|
||||||
[0xC776BA4E] = typeof(Messages_ChannelMessages),
|
[0xC776BA4E] = typeof(Messages_ChannelMessages),
|
||||||
[0x74535F21] = typeof(Messages_MessagesNotModified),
|
[0x74535F21] = typeof(Messages_MessagesNotModified),
|
||||||
[0x64FF9FD5] = typeof(Messages_Chats),
|
[0x64FF9FD5] = typeof(Messages_Chats),
|
||||||
|
|
@ -294,7 +298,7 @@ namespace TL
|
||||||
[0x1F2B0AFD] = typeof(UpdateNewMessage),
|
[0x1F2B0AFD] = typeof(UpdateNewMessage),
|
||||||
[0x4E90BFD6] = typeof(UpdateMessageID),
|
[0x4E90BFD6] = typeof(UpdateMessageID),
|
||||||
[0xA20DB0E5] = typeof(UpdateDeleteMessages),
|
[0xA20DB0E5] = typeof(UpdateDeleteMessages),
|
||||||
[0xC01E857F] = typeof(UpdateUserTyping),
|
[0x2A17BF5C] = typeof(UpdateUserTyping),
|
||||||
[0x83487AF0] = typeof(UpdateChatUserTyping),
|
[0x83487AF0] = typeof(UpdateChatUserTyping),
|
||||||
[0x07761198] = typeof(UpdateChatParticipants),
|
[0x07761198] = typeof(UpdateChatParticipants),
|
||||||
[0xE5BDF8DE] = typeof(UpdateUserStatus),
|
[0xE5BDF8DE] = typeof(UpdateUserStatus),
|
||||||
|
|
@ -311,7 +315,7 @@ namespace TL
|
||||||
[0xEBE46819] = typeof(UpdateServiceNotification),
|
[0xEBE46819] = typeof(UpdateServiceNotification),
|
||||||
[0xEE3B272A] = typeof(UpdatePrivacy),
|
[0xEE3B272A] = typeof(UpdatePrivacy),
|
||||||
[0x05492A13] = typeof(UpdateUserPhone),
|
[0x05492A13] = typeof(UpdateUserPhone),
|
||||||
[0x9C974FDF] = typeof(UpdateReadHistoryInbox),
|
[0x9E84BC99] = typeof(UpdateReadHistoryInbox),
|
||||||
[0x2F2F21BF] = typeof(UpdateReadHistoryOutbox),
|
[0x2F2F21BF] = typeof(UpdateReadHistoryOutbox),
|
||||||
[0x7F891213] = typeof(UpdateWebPage),
|
[0x7F891213] = typeof(UpdateWebPage),
|
||||||
[0xF8227181] = typeof(UpdateReadMessagesContents),
|
[0xF8227181] = typeof(UpdateReadMessagesContents),
|
||||||
|
|
@ -398,8 +402,6 @@ namespace TL
|
||||||
[0x6F7863F4] = typeof(UpdateRecentReactions),
|
[0x6F7863F4] = typeof(UpdateRecentReactions),
|
||||||
[0x86FCCF85] = typeof(UpdateMoveStickerSetToTop),
|
[0x86FCCF85] = typeof(UpdateMoveStickerSetToTop),
|
||||||
[0xD5A41724] = typeof(UpdateMessageExtendedMedia),
|
[0xD5A41724] = typeof(UpdateMessageExtendedMedia),
|
||||||
[0x192EFBE3] = typeof(UpdateChannelPinnedTopic),
|
|
||||||
[0xFE198602] = typeof(UpdateChannelPinnedTopics),
|
|
||||||
[0x20529438] = typeof(UpdateUser),
|
[0x20529438] = typeof(UpdateUser),
|
||||||
[0xEC05B097] = typeof(UpdateAutoSaveSettings),
|
[0xEC05B097] = typeof(UpdateAutoSaveSettings),
|
||||||
[0x75B3B798] = typeof(UpdateStory),
|
[0x75B3B798] = typeof(UpdateStory),
|
||||||
|
|
@ -436,6 +438,10 @@ namespace TL
|
||||||
[0x77B0E372] = typeof(UpdateReadMonoForumInbox),
|
[0x77B0E372] = typeof(UpdateReadMonoForumInbox),
|
||||||
[0xA4A79376] = typeof(UpdateReadMonoForumOutbox),
|
[0xA4A79376] = typeof(UpdateReadMonoForumOutbox),
|
||||||
[0x9F812B08] = typeof(UpdateMonoForumNoPaidException),
|
[0x9F812B08] = typeof(UpdateMonoForumNoPaidException),
|
||||||
|
[0x78C314E0] = typeof(UpdateGroupCallMessage),
|
||||||
|
[0xC957A766] = typeof(UpdateGroupCallEncryptedMessage),
|
||||||
|
[0x683B2C52] = typeof(UpdatePinnedForumTopic),
|
||||||
|
[0xDEF143D0] = typeof(UpdatePinnedForumTopics),
|
||||||
[0xA56C2A3E] = typeof(Updates_State),
|
[0xA56C2A3E] = typeof(Updates_State),
|
||||||
[0x5D75A138] = typeof(Updates_DifferenceEmpty),
|
[0x5D75A138] = typeof(Updates_DifferenceEmpty),
|
||||||
[0x00F49CA0] = typeof(Updates_Difference),
|
[0x00F49CA0] = typeof(Updates_Difference),
|
||||||
|
|
@ -505,6 +511,7 @@ namespace TL
|
||||||
[0xB05AC6B1] = typeof(SendMessageChooseStickerAction),
|
[0xB05AC6B1] = typeof(SendMessageChooseStickerAction),
|
||||||
[0x25972BCB] = typeof(SendMessageEmojiInteraction),
|
[0x25972BCB] = typeof(SendMessageEmojiInteraction),
|
||||||
[0xB665902E] = typeof(SendMessageEmojiInteractionSeen),
|
[0xB665902E] = typeof(SendMessageEmojiInteractionSeen),
|
||||||
|
[0x376D975C] = typeof(SendMessageTextDraftAction),
|
||||||
[0xB3134D9D] = typeof(Contacts_Found),
|
[0xB3134D9D] = typeof(Contacts_Found),
|
||||||
[0x0D09E07B] = typeof(InputPrivacyValueAllowContacts),
|
[0x0D09E07B] = typeof(InputPrivacyValueAllowContacts),
|
||||||
[0x184B35CE] = typeof(InputPrivacyValueAllowAll),
|
[0x184B35CE] = typeof(InputPrivacyValueAllowAll),
|
||||||
|
|
@ -1079,6 +1086,10 @@ namespace TL
|
||||||
[0xE3779861] = typeof(Account_ResetPasswordFailedWait),
|
[0xE3779861] = typeof(Account_ResetPasswordFailedWait),
|
||||||
[0xE9EFFC7D] = typeof(Account_ResetPasswordRequestedWait),
|
[0xE9EFFC7D] = typeof(Account_ResetPasswordRequestedWait),
|
||||||
[0xE926D63E] = typeof(Account_ResetPasswordOk),
|
[0xE926D63E] = typeof(Account_ResetPasswordOk),
|
||||||
|
[0xC3DFFC04] = typeof(ChatTheme),
|
||||||
|
[0x3458F9C8] = typeof(ChatThemeUniqueGift),
|
||||||
|
[0xE011E1C4] = null,//Account_ChatThemesNotModified
|
||||||
|
[0xBE098173] = typeof(Account_ChatThemes),
|
||||||
[0x7DBF8673] = typeof(SponsoredMessage),
|
[0x7DBF8673] = typeof(SponsoredMessage),
|
||||||
[0xFFDA656D] = typeof(Messages_SponsoredMessages),
|
[0xFFDA656D] = typeof(Messages_SponsoredMessages),
|
||||||
[0x1839490F] = null,//Messages_SponsoredMessagesEmpty
|
[0x1839490F] = null,//Messages_SponsoredMessagesEmpty
|
||||||
|
|
@ -1130,6 +1141,9 @@ namespace TL
|
||||||
[0xDABAB2EF] = typeof(InputInvoicePremiumGiftStars),
|
[0xDABAB2EF] = typeof(InputInvoicePremiumGiftStars),
|
||||||
[0xF4997E42] = typeof(InputInvoiceBusinessBotTransferStars),
|
[0xF4997E42] = typeof(InputInvoiceBusinessBotTransferStars),
|
||||||
[0xC39F5324] = typeof(InputInvoiceStarGiftResale),
|
[0xC39F5324] = typeof(InputInvoiceStarGiftResale),
|
||||||
|
[0x9A0B48B8] = typeof(InputInvoiceStarGiftPrepaidUpgrade),
|
||||||
|
[0x3E77F614] = typeof(InputInvoicePremiumAuthCode),
|
||||||
|
[0x0923D8D1] = typeof(InputInvoiceStarGiftDropOriginalDetails),
|
||||||
[0xAED0CBD9] = typeof(Payments_ExportedInvoice),
|
[0xAED0CBD9] = typeof(Payments_ExportedInvoice),
|
||||||
[0xCFB9D957] = typeof(Messages_TranscribedAudio),
|
[0xCFB9D957] = typeof(Messages_TranscribedAudio),
|
||||||
[0x5334759C] = typeof(Help_PremiumPromo),
|
[0x5334759C] = typeof(Help_PremiumPromo),
|
||||||
|
|
@ -1137,7 +1151,7 @@ namespace TL
|
||||||
[0x616F7FE8] = typeof(InputStorePaymentGiftPremium),
|
[0x616F7FE8] = typeof(InputStorePaymentGiftPremium),
|
||||||
[0xFB790393] = typeof(InputStorePaymentPremiumGiftCode),
|
[0xFB790393] = typeof(InputStorePaymentPremiumGiftCode),
|
||||||
[0x160544CA] = typeof(InputStorePaymentPremiumGiveaway),
|
[0x160544CA] = typeof(InputStorePaymentPremiumGiveaway),
|
||||||
[0xDDDD0F56] = typeof(InputStorePaymentStarsTopup),
|
[0xF9A2A6CB] = typeof(InputStorePaymentStarsTopup),
|
||||||
[0x1D741EF7] = typeof(InputStorePaymentStarsGift),
|
[0x1D741EF7] = typeof(InputStorePaymentStarsGift),
|
||||||
[0x751F08FA] = typeof(InputStorePaymentStarsGiveaway),
|
[0x751F08FA] = typeof(InputStorePaymentStarsGiveaway),
|
||||||
[0x9BB2636D] = typeof(InputStorePaymentAuthCode),
|
[0x9BB2636D] = typeof(InputStorePaymentAuthCode),
|
||||||
|
|
@ -1172,7 +1186,7 @@ namespace TL
|
||||||
[0xFCFEB29C] = typeof(StickerKeyword),
|
[0xFCFEB29C] = typeof(StickerKeyword),
|
||||||
[0xB4073647] = typeof(Username),
|
[0xB4073647] = typeof(Username),
|
||||||
[0x023F109B] = typeof(ForumTopicDeleted),
|
[0x023F109B] = typeof(ForumTopicDeleted),
|
||||||
[0x71701DA9] = typeof(ForumTopic),
|
[0xCDFF0ECA] = typeof(ForumTopic),
|
||||||
[0x367617D3] = typeof(Messages_ForumTopics),
|
[0x367617D3] = typeof(Messages_ForumTopics),
|
||||||
[0x43B46B20] = typeof(DefaultHistoryTTL),
|
[0x43B46B20] = typeof(DefaultHistoryTTL),
|
||||||
[0x41BF109B] = typeof(ExportedContactToken),
|
[0x41BF109B] = typeof(ExportedContactToken),
|
||||||
|
|
@ -1260,6 +1274,8 @@ namespace TL
|
||||||
[0xEDF3ADD0] = typeof(PublicForwardStory),
|
[0xEDF3ADD0] = typeof(PublicForwardStory),
|
||||||
[0x93037E20] = typeof(Stats_PublicForwards),
|
[0x93037E20] = typeof(Stats_PublicForwards),
|
||||||
[0xB54B5ACF] = typeof(PeerColor),
|
[0xB54B5ACF] = typeof(PeerColor),
|
||||||
|
[0xB9C0639A] = typeof(PeerColorCollectible),
|
||||||
|
[0xB8EA86A9] = typeof(InputPeerColorCollectible),
|
||||||
[0x26219A58] = typeof(Help_PeerColorSet),
|
[0x26219A58] = typeof(Help_PeerColorSet),
|
||||||
[0x767D61EB] = typeof(Help_PeerColorProfileSet),
|
[0x767D61EB] = typeof(Help_PeerColorProfileSet),
|
||||||
[0xADEC6EBE] = typeof(Help_PeerColorOption),
|
[0xADEC6EBE] = typeof(Help_PeerColorOption),
|
||||||
|
|
@ -1362,8 +1378,8 @@ namespace TL
|
||||||
[0x4BA3A95A] = typeof(MessageReactor),
|
[0x4BA3A95A] = typeof(MessageReactor),
|
||||||
[0x94CE852A] = typeof(StarsGiveawayOption),
|
[0x94CE852A] = typeof(StarsGiveawayOption),
|
||||||
[0x54236209] = typeof(StarsGiveawayWinnersOption),
|
[0x54236209] = typeof(StarsGiveawayWinnersOption),
|
||||||
[0x00BCFF5B] = typeof(StarGift),
|
[0x80AC53C3] = typeof(StarGift),
|
||||||
[0x3A274D50] = typeof(StarGiftUnique),
|
[0xB0BF741B] = typeof(StarGiftUnique),
|
||||||
[0xA388A368] = null,//Payments_StarGiftsNotModified
|
[0xA388A368] = null,//Payments_StarGiftsNotModified
|
||||||
[0x2ED82995] = typeof(Payments_StarGifts),
|
[0x2ED82995] = typeof(Payments_StarGifts),
|
||||||
[0x7903E3D9] = typeof(MessageReportOption),
|
[0x7903E3D9] = typeof(MessageReportOption),
|
||||||
|
|
@ -1387,12 +1403,12 @@ namespace TL
|
||||||
[0x13ACFF19] = typeof(StarGiftAttributePattern),
|
[0x13ACFF19] = typeof(StarGiftAttributePattern),
|
||||||
[0xD93D859C] = typeof(StarGiftAttributeBackdrop),
|
[0xD93D859C] = typeof(StarGiftAttributeBackdrop),
|
||||||
[0xE0BFF26C] = typeof(StarGiftAttributeOriginalDetails),
|
[0xE0BFF26C] = typeof(StarGiftAttributeOriginalDetails),
|
||||||
[0x167BD90B] = typeof(Payments_StarGiftUpgradePreview),
|
[0x3DE1DFED] = typeof(Payments_StarGiftUpgradePreview),
|
||||||
[0x62D706B8] = typeof(Users_Users),
|
[0x62D706B8] = typeof(Users_Users),
|
||||||
[0x315A4974] = typeof(Users_UsersSlice),
|
[0x315A4974] = typeof(Users_UsersSlice),
|
||||||
[0xCAA2F60B] = typeof(Payments_UniqueStarGift),
|
[0x416C56E8] = typeof(Payments_UniqueStarGift),
|
||||||
[0xB53E8B21] = typeof(Messages_WebPagePreview),
|
[0x8C9A88AC] = typeof(Messages_WebPagePreview),
|
||||||
[0x1EA646DF] = typeof(SavedStarGift),
|
[0x8983A452] = typeof(SavedStarGift),
|
||||||
[0x95F389B1] = typeof(Payments_SavedStarGifts),
|
[0x95F389B1] = typeof(Payments_SavedStarGifts),
|
||||||
[0x69279795] = typeof(InputSavedStarGiftUser),
|
[0x69279795] = typeof(InputSavedStarGiftUser),
|
||||||
[0xF101AA7F] = typeof(InputSavedStarGiftChat),
|
[0xF101AA7F] = typeof(InputSavedStarGiftChat),
|
||||||
|
|
@ -1429,6 +1445,17 @@ namespace TL
|
||||||
[0x564EDAEB] = null,//Stories_AlbumsNotModified
|
[0x564EDAEB] = null,//Stories_AlbumsNotModified
|
||||||
[0xC3987A3A] = typeof(Stories_Albums),
|
[0xC3987A3A] = typeof(Stories_Albums),
|
||||||
[0x3E0B5B6A] = typeof(SearchPostsFlood),
|
[0x3E0B5B6A] = typeof(SearchPostsFlood),
|
||||||
|
[0x512FE446] = typeof(Payments_UniqueStarGiftValueInfo),
|
||||||
|
[0xE3878AA4] = typeof(Users_SavedMusicNotModified),
|
||||||
|
[0x34A2F297] = typeof(Users_SavedMusic),
|
||||||
|
[0x4FC81D6E] = null,//Account_SavedMusicIdsNotModified
|
||||||
|
[0x998D6636] = typeof(Account_SavedMusicIds),
|
||||||
|
[0x374FA7AD] = typeof(Payments_CheckCanSendGiftResultOk),
|
||||||
|
[0xD5E58274] = typeof(Payments_CheckCanSendGiftResultFail),
|
||||||
|
[0x83268483] = null,//InputChatThemeEmpty
|
||||||
|
[0xC93DE95C] = typeof(InputChatTheme),
|
||||||
|
[0x87E5DFE4] = typeof(InputChatThemeUniqueGift),
|
||||||
|
[0x99EA331D] = typeof(StarGiftUpgradePrice),
|
||||||
// from TL.Secret:
|
// from TL.Secret:
|
||||||
[0x6ABD9782] = typeof(Layer143.DecryptedMessageMediaDocument),
|
[0x6ABD9782] = typeof(Layer143.DecryptedMessageMediaDocument),
|
||||||
[0x020DF5D0] = typeof(Layer101.MessageEntityBlockquote),
|
[0x020DF5D0] = typeof(Layer101.MessageEntityBlockquote),
|
||||||
|
|
@ -1548,6 +1575,7 @@ namespace TL
|
||||||
[typeof(ChatReactions)] = 0xEAFC32BC, //chatReactionsNone
|
[typeof(ChatReactions)] = 0xEAFC32BC, //chatReactionsNone
|
||||||
[typeof(Messages_Reactions)] = 0xB06FDBDF, //messages.reactionsNotModified
|
[typeof(Messages_Reactions)] = 0xB06FDBDF, //messages.reactionsNotModified
|
||||||
// from TL.Secret:
|
// from TL.Secret:
|
||||||
|
[typeof(Account_ChatThemes)] = 0xE011E1C4, //account.chatThemesNotModified
|
||||||
[typeof(EmojiStatusBase)] = 0x2DE11AAE, //emojiStatusEmpty
|
[typeof(EmojiStatusBase)] = 0x2DE11AAE, //emojiStatusEmpty
|
||||||
[typeof(EmojiList)] = 0x481EADFA, //emojiListNotModified
|
[typeof(EmojiList)] = 0x481EADFA, //emojiListNotModified
|
||||||
[typeof(Messages_EmojiGroups)] = 0x6FB4AD87, //messages.emojiGroupsNotModified
|
[typeof(Messages_EmojiGroups)] = 0x6FB4AD87, //messages.emojiGroupsNotModified
|
||||||
|
|
@ -1564,6 +1592,8 @@ namespace TL
|
||||||
[typeof(Contacts_SponsoredPeers)] = 0xEA32B4B1, //contacts.sponsoredPeersEmpty
|
[typeof(Contacts_SponsoredPeers)] = 0xEA32B4B1, //contacts.sponsoredPeersEmpty
|
||||||
[typeof(Payments_StarGiftCollections)] = 0xA0BA4F17, //payments.starGiftCollectionsNotModified
|
[typeof(Payments_StarGiftCollections)] = 0xA0BA4F17, //payments.starGiftCollectionsNotModified
|
||||||
[typeof(Stories_Albums)] = 0x564EDAEB, //stories.albumsNotModified
|
[typeof(Stories_Albums)] = 0x564EDAEB, //stories.albumsNotModified
|
||||||
|
[typeof(Account_SavedMusicIds)] = 0x4FC81D6E, //account.savedMusicIdsNotModified
|
||||||
|
[typeof(InputChatThemeBase)] = 0x83268483, //inputChatThemeEmpty
|
||||||
[typeof(DecryptedMessageMedia)] = 0x089F5C4A, //decryptedMessageMediaEmpty
|
[typeof(DecryptedMessageMedia)] = 0x089F5C4A, //decryptedMessageMediaEmpty
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,6 @@ namespace TL
|
||||||
{
|
{
|
||||||
public abstract long ID { get; }
|
public abstract long ID { get; }
|
||||||
protected internal abstract IPeerInfo UserOrChat(Dictionary<long, User> users, Dictionary<long, ChatBase> chats);
|
protected internal abstract IPeerInfo UserOrChat(Dictionary<long, User> users, Dictionary<long, ChatBase> chats);
|
||||||
public static implicit operator long(Peer peer) => peer.ID;
|
|
||||||
}
|
}
|
||||||
partial class PeerUser
|
partial class PeerUser
|
||||||
{
|
{
|
||||||
|
|
@ -216,7 +215,7 @@ namespace TL
|
||||||
/// <remarks>a <c>null</c> value means <a href="https://corefork.telegram.org/constructor/userStatusEmpty">userStatusEmpty</a> = last seen a long time ago, more than a month (or blocked/deleted users)</remarks>
|
/// <remarks>a <c>null</c> value means <a href="https://corefork.telegram.org/constructor/userStatusEmpty">userStatusEmpty</a> = last seen a long time ago, more than a month (or blocked/deleted users)</remarks>
|
||||||
partial class UserStatus { internal abstract TimeSpan LastSeenAgo { get; } }
|
partial class UserStatus { internal abstract TimeSpan LastSeenAgo { get; } }
|
||||||
partial class UserStatusOnline { internal override TimeSpan LastSeenAgo => TimeSpan.Zero; }
|
partial class UserStatusOnline { internal override TimeSpan LastSeenAgo => TimeSpan.Zero; }
|
||||||
partial class UserStatusOffline { internal override TimeSpan LastSeenAgo => DateTime.UtcNow - new DateTime((was_online + 62135596800L) * 10000000, DateTimeKind.Utc); }
|
partial class UserStatusOffline { internal override TimeSpan LastSeenAgo => DateTime.UtcNow - was_online; }
|
||||||
/// <remarks>covers anything between 1 second and 2-3 days</remarks>
|
/// <remarks>covers anything between 1 second and 2-3 days</remarks>
|
||||||
partial class UserStatusRecently { internal override TimeSpan LastSeenAgo => TimeSpan.FromDays(1); }
|
partial class UserStatusRecently { internal override TimeSpan LastSeenAgo => TimeSpan.FromDays(1); }
|
||||||
/// <remarks>between 2-3 and seven days</remarks>
|
/// <remarks>between 2-3 and seven days</remarks>
|
||||||
|
|
@ -690,8 +689,8 @@ namespace TL
|
||||||
{
|
{
|
||||||
System.Text.Json.JsonValueKind.True or
|
System.Text.Json.JsonValueKind.True or
|
||||||
System.Text.Json.JsonValueKind.False => new JsonBool { value = elem.GetBoolean() },
|
System.Text.Json.JsonValueKind.False => new JsonBool { value = elem.GetBoolean() },
|
||||||
System.Text.Json.JsonValueKind.Object => new JsonObject { value = elem.EnumerateObject().Select(FromJsonProperty).ToArray() },
|
System.Text.Json.JsonValueKind.Object => new JsonObject { value = [.. elem.EnumerateObject().Select(FromJsonProperty)] },
|
||||||
System.Text.Json.JsonValueKind.Array => new JsonArray { value = elem.EnumerateArray().Select(FromJsonElement).ToArray() },
|
System.Text.Json.JsonValueKind.Array => new JsonArray { value = [.. elem.EnumerateArray().Select(FromJsonElement)] },
|
||||||
System.Text.Json.JsonValueKind.String => new JsonString { value = elem.GetString() },
|
System.Text.Json.JsonValueKind.String => new JsonString { value = elem.GetString() },
|
||||||
System.Text.Json.JsonValueKind.Number => new JsonNumber { value = elem.GetDouble() },
|
System.Text.Json.JsonValueKind.Number => new JsonNumber { value = elem.GetDouble() },
|
||||||
_ => new JsonNull(),
|
_ => new JsonNull(),
|
||||||
|
|
@ -710,7 +709,7 @@ namespace TL
|
||||||
sb.Append(i == 0 ? "" : ",").Append(value[i]);
|
sb.Append(i == 0 ? "" : ",").Append(value[i]);
|
||||||
return sb.Append(']').ToString();
|
return sb.Append(']').ToString();
|
||||||
}
|
}
|
||||||
public object[] ToNativeArray() => value.Select(v => v.ToNative()).ToArray();
|
public object[] ToNativeArray() => [.. value.Select(v => v.ToNative())];
|
||||||
public override object ToNative()
|
public override object ToNative()
|
||||||
{
|
{
|
||||||
if (value.Length == 0) return Array.Empty<object>();
|
if (value.Length == 0) return Array.Empty<object>();
|
||||||
|
|
|
||||||
69
src/TL.cs
69
src/TL.cs
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -16,7 +17,7 @@ namespace TL
|
||||||
#else
|
#else
|
||||||
public interface IObject { }
|
public interface IObject { }
|
||||||
#endif
|
#endif
|
||||||
public interface IMethod<ReturnType> : IObject { }
|
public interface IMethod<out ReturnType> : IObject { }
|
||||||
public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); }
|
public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); }
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
|
@ -48,6 +49,15 @@ namespace TL
|
||||||
|
|
||||||
public static class Serialization
|
public static class Serialization
|
||||||
{
|
{
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public static byte[] ToBytes<T>(this T obj) where T : IObject
|
||||||
|
{
|
||||||
|
using var ms = new MemoryStream(384);
|
||||||
|
using var writer = new BinaryWriter(ms);
|
||||||
|
writer.WriteTLObject(obj);
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public static void WriteTLObject<T>(this BinaryWriter writer, T obj) where T : IObject
|
public static void WriteTLObject<T>(this BinaryWriter writer, T obj) where T : IObject
|
||||||
{
|
{
|
||||||
if (obj == null) { writer.WriteTLNull(typeof(T)); return; }
|
if (obj == null) { writer.WriteTLNull(typeof(T)); return; }
|
||||||
|
|
@ -105,6 +115,17 @@ namespace TL
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IMethod<X> ReadTLMethod<X>(this BinaryReader reader)
|
||||||
|
{
|
||||||
|
uint ctorNb = reader.ReadUInt32();
|
||||||
|
if (!Layer.Methods.TryGetValue(ctorNb, out var ctor))
|
||||||
|
throw new WTelegram.WTException($"Cannot find method for ctor #{ctorNb:x}");
|
||||||
|
var method = ctor?.Invoke(reader);
|
||||||
|
if (method is IMethod<bool> && typeof(X) == typeof(object))
|
||||||
|
method = new BoolMethod { query = method };
|
||||||
|
return (IMethod<X>)method;
|
||||||
|
}
|
||||||
|
|
||||||
internal static void WriteTLValue(this BinaryWriter writer, object value, Type valueType)
|
internal static void WriteTLValue(this BinaryWriter writer, object value, Type valueType)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
|
|
@ -197,10 +218,10 @@ namespace TL
|
||||||
foreach (var msg in messages)
|
foreach (var msg in messages)
|
||||||
{
|
{
|
||||||
writer.Write(msg.msg_id);
|
writer.Write(msg.msg_id);
|
||||||
writer.Write(msg.seq_no);
|
writer.Write(msg.seqno);
|
||||||
var patchPos = writer.BaseStream.Position;
|
var patchPos = writer.BaseStream.Position;
|
||||||
writer.Write(0); // patched below
|
writer.Write(0); // patched below
|
||||||
if ((msg.seq_no & 1) != 0)
|
if ((msg.seqno & 1) != 0)
|
||||||
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}");
|
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}");
|
||||||
else
|
else
|
||||||
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}");
|
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}");
|
||||||
|
|
@ -222,6 +243,21 @@ namespace TL
|
||||||
writer.WriteTLValue(array.GetValue(i), elementType);
|
writer.WriteTLValue(array.GetValue(i), elementType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void WriteTLRawVector(this BinaryWriter writer, Array array, int elementSize)
|
||||||
|
{
|
||||||
|
var startPos = writer.BaseStream.Position;
|
||||||
|
int count = array.Length;
|
||||||
|
var elementType = array.GetType().GetElementType();
|
||||||
|
for (int i = count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
writer.BaseStream.Position = startPos + i * elementSize;
|
||||||
|
writer.WriteTLValue(array.GetValue(i), elementType);
|
||||||
|
}
|
||||||
|
writer.BaseStream.Position = startPos;
|
||||||
|
writer.Write(count);
|
||||||
|
writer.BaseStream.Position = startPos + count * elementSize + 4;
|
||||||
|
}
|
||||||
|
|
||||||
internal static List<T> ReadTLRawVector<T>(this BinaryReader reader, uint ctorNb)
|
internal static List<T> ReadTLRawVector<T>(this BinaryReader reader, uint ctorNb)
|
||||||
{
|
{
|
||||||
int count = reader.ReadInt32();
|
int count = reader.ReadInt32();
|
||||||
|
|
@ -289,13 +325,14 @@ namespace TL
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void WriteTLStamp(this BinaryWriter writer, DateTime datetime)
|
internal static void WriteTLStamp(this BinaryWriter writer, DateTime datetime)
|
||||||
=> writer.Write(datetime == DateTime.MaxValue ? int.MaxValue : (int)(datetime.ToUniversalTime().Ticks / 10000000 - 62135596800L));
|
=> writer.Write((int)Math.Min(Math.Max(datetime.ToUniversalTime().Ticks / 10000000 - 62135596800L, 0), int.MaxValue));
|
||||||
|
|
||||||
internal static DateTime ReadTLStamp(this BinaryReader reader)
|
internal static DateTime ReadTLStamp(this BinaryReader reader) => reader.ReadInt32() switch
|
||||||
{
|
{
|
||||||
int unixstamp = reader.ReadInt32();
|
<= 0 => default,
|
||||||
return unixstamp == int.MaxValue ? DateTime.MaxValue : new((unixstamp + 62135596800L) * 10000000, DateTimeKind.Utc);
|
int.MaxValue => DateTime.MaxValue,
|
||||||
}
|
int unixstamp => new((unixstamp + 62135596800L) * 10000000, DateTimeKind.Utc)
|
||||||
|
};
|
||||||
|
|
||||||
internal static void WriteTLString(this BinaryWriter writer, string str)
|
internal static void WriteTLString(this BinaryWriter writer, string str)
|
||||||
{
|
{
|
||||||
|
|
@ -428,10 +465,10 @@ namespace TL
|
||||||
}
|
}
|
||||||
|
|
||||||
[TLDef(0x5BB8E511)] //message#5bb8e511 msg_id:long seqno:int bytes:int body:Object = Message
|
[TLDef(0x5BB8E511)] //message#5bb8e511 msg_id:long seqno:int bytes:int body:Object = Message
|
||||||
public sealed partial class _Message(long msgId, int seqNo, IObject obj) : IObject
|
public sealed partial class _Message(long msgId, int seqno, IObject obj) : IObject
|
||||||
{
|
{
|
||||||
public long msg_id = msgId;
|
public long msg_id = msgId;
|
||||||
public int seq_no = seqNo;
|
public int seqno = seqno;
|
||||||
public int bytes;
|
public int bytes;
|
||||||
public IObject body = obj;
|
public IObject body = obj;
|
||||||
}
|
}
|
||||||
|
|
@ -443,4 +480,16 @@ namespace TL
|
||||||
|
|
||||||
[TLDef(0x3072CFA1)] //gzip_packed#3072cfa1 packed_data:bytes = Object
|
[TLDef(0x3072CFA1)] //gzip_packed#3072cfa1 packed_data:bytes = Object
|
||||||
public sealed partial class GzipPacked : IObject { public byte[] packed_data; }
|
public sealed partial class GzipPacked : IObject { public byte[] packed_data; }
|
||||||
|
|
||||||
|
public sealed class Null<X> : IObject
|
||||||
|
{
|
||||||
|
public readonly static Null<X> Instance = new();
|
||||||
|
public void WriteTL(BinaryWriter writer) => writer.WriteTLNull(typeof(X));
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class BoolMethod : IMethod<object>
|
||||||
|
{
|
||||||
|
public IObject query;
|
||||||
|
public void WriteTL(BinaryWriter writer) => query.WriteTL(writer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -566,7 +566,7 @@ namespace WTelegram
|
||||||
|
|
||||||
/// <summary>Save the current state of the manager to JSON file</summary>
|
/// <summary>Save the current state of the manager to JSON file</summary>
|
||||||
/// <param name="statePath">File path to write</param>
|
/// <param name="statePath">File path to write</param>
|
||||||
/// <remarks>Note: This does not save the the content of collected Users/Chats dictionaries</remarks>
|
/// <remarks>Note: This does not save the content of collected Users/Chats dictionaries</remarks>
|
||||||
public void SaveState(string statePath)
|
public void SaveState(string statePath)
|
||||||
=> System.IO.File.WriteAllText(statePath, System.Text.Json.JsonSerializer.Serialize(State, Helpers.JsonOptions));
|
=> System.IO.File.WriteAllText(statePath, System.Text.Json.JsonSerializer.Serialize(State, Helpers.JsonOptions));
|
||||||
public static Dictionary<long, MBoxState> LoadState(string statePath) => !System.IO.File.Exists(statePath) ? null
|
public static Dictionary<long, MBoxState> LoadState(string statePath) => !System.IO.File.Exists(statePath) ? null
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@
|
||||||
<PackageId>WTelegramClient</PackageId>
|
<PackageId>WTelegramClient</PackageId>
|
||||||
<Authors>Wizou</Authors>
|
<Authors>Wizou</Authors>
|
||||||
<VersionPrefix>0.0.0</VersionPrefix>
|
<VersionPrefix>0.0.0</VersionPrefix>
|
||||||
<VersionSuffix>layer.211</VersionSuffix>
|
<VersionSuffix>layer.216</VersionSuffix>
|
||||||
<Description>Telegram Client API (MTProto) library written 100% in C# and .NET Standard | Latest API layer: 211
|
<Description>Telegram Client API (MTProto) library written 100% in C# and .NET Standard | Latest API layer: 216
|
||||||
|
|
||||||
Release Notes:
|
Release Notes:
|
||||||
$(ReleaseNotes.Replace("|", "%0D%0A").Replace(" - ","%0D%0A- ").Replace(" ", "%0D%0A%0D%0A"))</Description>
|
$(ReleaseNotes)</Description>
|
||||||
<Copyright>Copyright © Olivier Marcoux 2021-2025</Copyright>
|
<Copyright>Copyright © Olivier Marcoux 2021-2025</Copyright>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageProjectUrl>https://wiz0u.github.io/WTelegramClient</PackageProjectUrl>
|
<PackageProjectUrl>https://wiz0u.github.io/WTelegramClient</PackageProjectUrl>
|
||||||
|
|
@ -27,7 +27,7 @@ $(ReleaseNotes.Replace("|", "%0D%0A").Replace(" - ","%0D%0A- ").Replace(" ", "%
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<PackageTags>Telegram;MTProto;Client;Api;UserBot</PackageTags>
|
<PackageTags>Telegram;MTProto;Client;Api;UserBot</PackageTags>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<PackageReleaseNotes>$(ReleaseNotes.Replace("|", "%0D%0A").Replace(" - ","%0D%0A- ").Replace(" ", "%0D%0A%0D%0A"))</PackageReleaseNotes>
|
<PackageReleaseNotes>$(ReleaseNotes)</PackageReleaseNotes>
|
||||||
<NoWarn>NETSDK1138;CS0419;CS1573;CS1591</NoWarn>
|
<NoWarn>NETSDK1138;CS0419;CS1573;CS1591</NoWarn>
|
||||||
<DefineConstants>TRACE;OBFUSCATION;MTPG</DefineConstants>
|
<DefineConstants>TRACE;OBFUSCATION;MTPG</DefineConstants>
|
||||||
<!--<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>-->
|
<!--<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>-->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue