613 lines
21 KiB
C#
613 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using NeoSmart.Unicode;
|
|
using TdLib;
|
|
using static telegram.tgcli;
|
|
using static telegram.Util;
|
|
|
|
namespace telegram
|
|
{
|
|
public abstract class Command
|
|
{
|
|
public string Trigger;
|
|
public string Shortcut;
|
|
public string Description;
|
|
public string Syntax;
|
|
public int ParamCount;
|
|
public abstract void Handler(List<string> inputParams);
|
|
|
|
protected Command(string trigger, string shortcut, string description, string syntax, int paramCount)
|
|
{
|
|
Trigger = trigger;
|
|
Shortcut = shortcut;
|
|
Description = description;
|
|
ParamCount = paramCount;
|
|
Syntax = syntax;
|
|
}
|
|
}
|
|
|
|
public static class CommandManager
|
|
{
|
|
public static List<Command> Commands = new List<Command>
|
|
{
|
|
new ClearCommand(),
|
|
new CloseCommand(),
|
|
new EditCommand(),
|
|
new ReplyCommand(),
|
|
new HistoryCommand(),
|
|
new OpenCommand(),
|
|
new UnreadsCommand(),
|
|
new CloseUnreadCommand(),
|
|
new ListSecretChatsCommand(),
|
|
new OpenSecretCommand(),
|
|
new OpenSecretDirectCommand(),
|
|
new NewSecretChatCommand(),
|
|
new CloseSecretChatCommand(),
|
|
new QuitCommand(),
|
|
new HelpCommand()
|
|
};
|
|
|
|
public static void HandleCommand(string input)
|
|
{
|
|
var split = input.Split(" ").ToList();
|
|
var trigger = split.First();
|
|
var command = Commands.Find(p => p.Trigger == trigger || p.Shortcut == trigger);
|
|
if (command == null)
|
|
{
|
|
//TODO Console.WriteLine("do something");
|
|
return;
|
|
}
|
|
|
|
split.RemoveAt(0);
|
|
if (command.ParamCount == -1)
|
|
{
|
|
command.Handler(split);
|
|
}
|
|
else if (split.Count == command.ParamCount)
|
|
{
|
|
command.Handler(split);
|
|
}
|
|
else
|
|
{
|
|
//TODO Console.WriteLine("do something");
|
|
}
|
|
}
|
|
}
|
|
|
|
public class OpenCommand : Command
|
|
{
|
|
public OpenCommand() : base("o", "^O", "opens a chat. queries chat list", "<query>", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var query = inputParams.Aggregate((current, param) => current + " " + param).Trim();
|
|
var chatId = SearchChatId(query);
|
|
if (chatId == 0) return;
|
|
|
|
currentChatId = 0;
|
|
currentChatUserId = 0;
|
|
currentUserRead = false;
|
|
|
|
var chat = GetChat(chatId);
|
|
if (chat.Type is TdApi.ChatType.ChatTypePrivate privChat)
|
|
{
|
|
currentChatUserId = privChat.UserId;
|
|
}
|
|
|
|
currentChatId = chat.Id;
|
|
|
|
chat.Title = TruncateString(chat.Title, 20);
|
|
|
|
prefix = $"[{chat.Title}";
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Opening chat: {chat.Title}");
|
|
messageQueue.Add($"{Ansi.Yellow}" + $"[tgcli] You have {chat.UnreadCount} unread message" +
|
|
$"{(chat.UnreadCount == 1 ? "." : "s.")}");
|
|
|
|
if (chat.UnreadCount >= 5)
|
|
{
|
|
var capped = chat.UnreadCount > 50;
|
|
GetHistory(chatId, capped ? 50 : chat.UnreadCount).ForEach(AddMessageToQueue);
|
|
if (capped)
|
|
messageQueue.Add(
|
|
$"{Ansi.Yellow}[tgcli] " + $"Showing 50 of {chat.UnreadCount} unread messages.");
|
|
}
|
|
else if (chat.UnreadCount > 0)
|
|
{
|
|
var unreads = GetHistory(chatId, chat.UnreadCount);
|
|
Console.WriteLine(unreads.Count);
|
|
var rest = GetHistory(chatId, 5 - unreads.Count, unreads.First().Id);
|
|
rest.ForEach(AddMessageToQueue);
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] ---UNREAD---");
|
|
unreads.ForEach(AddMessageToQueue);
|
|
}
|
|
else
|
|
{
|
|
GetHistory(chatId).ForEach(AddMessageToQueue);
|
|
}
|
|
}
|
|
|
|
var history = GetHistory(currentChatId, 50);
|
|
if (history.Count != 0)
|
|
MarkRead(chat.Id, history.First().Id);
|
|
var last = history.LastOrDefault(p => p.IsOutgoing);
|
|
if (last == null)
|
|
{
|
|
currentUserRead = true;
|
|
return;
|
|
}
|
|
|
|
lastMessage = last;
|
|
currentUserRead = IsMessageRead(last.ChatId, last.Id);
|
|
}
|
|
}
|
|
|
|
public class CloseSecretChatCommand : Command
|
|
{
|
|
public CloseSecretChatCommand() : base("cs", "", "closes a secret chat (permanently)", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> _)
|
|
{
|
|
if (currentChatId == 0)
|
|
return; //TODO do something
|
|
if (GetChat(currentChatId).Type is TdApi.ChatType.ChatTypeSecret type)
|
|
{
|
|
CloseSecretChat(type.SecretChatId);
|
|
DeleteChatHistory(currentChatId);
|
|
CommandManager.HandleCommand("c");
|
|
}
|
|
else
|
|
{
|
|
//TODO do something
|
|
}
|
|
}
|
|
}
|
|
|
|
public class NewSecretChatCommand : Command
|
|
{
|
|
public NewSecretChatCommand() : base("ns", "", "creates a new secret chat. queries contacts", "<query>", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var query = inputParams.Aggregate((current, param) => current + " " + param).Trim();
|
|
var userId = SearchContacts(query);
|
|
|
|
if (userId == 0)
|
|
return;
|
|
if (GetSecretChats().Count(p => ((TdApi.ChatType.ChatTypeSecret) p.Type).UserId == userId) > 0)
|
|
return; //TODO do something
|
|
|
|
var chat = CreateSecretChat(userId);
|
|
CommandManager.HandleCommand("osd " + chat.Id);
|
|
}
|
|
}
|
|
|
|
public class OpenSecretDirectCommand : Command
|
|
{
|
|
public OpenSecretDirectCommand() : base("osd", "", "opens a secret chat by chat id", "<chat_id>", 1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var id = inputParams[0];
|
|
if (!long.TryParse(id, out var chatId))
|
|
{
|
|
return; //todo do something
|
|
}
|
|
|
|
var chat = GetChat(chatId);
|
|
if (chat == null)
|
|
return; //TODO do something
|
|
|
|
TdApi.SecretChat secChat;
|
|
if (chat.Type is TdApi.ChatType.ChatTypeSecret secretChat)
|
|
{
|
|
currentChatUserId = secretChat.UserId;
|
|
currentChatId = chat.Id;
|
|
currentUserRead = false;
|
|
secChat = GetSecretChat(secretChat.SecretChatId);
|
|
}
|
|
else
|
|
{
|
|
return; //TODO do something
|
|
}
|
|
|
|
chat.Title = TruncateString(chat.Title, 20);
|
|
|
|
prefix = $"[{Ansi.Red}sec {Ansi.ResetAll}{chat.Title}]";
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Opening secret chat: {chat.Title}");
|
|
messageQueue.Add($"{Ansi.Yellow}" + $"[tgcli] You have {chat.UnreadCount} unread message" +
|
|
$"{(chat.UnreadCount == 1 ? "." : "s.")}");
|
|
if (secChat.State is TdApi.SecretChatState.SecretChatStateClosed)
|
|
{
|
|
messageQueue.Add($"{Ansi.Red}[tgcli] Secret chat has ended. No messages can be sent.");
|
|
}
|
|
else if (secChat.State is TdApi.SecretChatState.SecretChatStatePending)
|
|
{
|
|
messageQueue.Add($"{Ansi.Red}[tgcli] Secret chat is pending. No messages can be sent.");
|
|
}
|
|
|
|
if (chat.UnreadCount >= 5)
|
|
{
|
|
var capped = chat.UnreadCount > 50;
|
|
GetHistory(chatId, capped ? 50 : chat.UnreadCount, isSecret: true).ForEach(AddMessageToQueue);
|
|
if (capped)
|
|
messageQueue.Add(
|
|
$"{Ansi.Yellow}[tgcli] " + $"Showing 50 of {chat.UnreadCount} unread messages.");
|
|
}
|
|
else if (chat.UnreadCount > 0)
|
|
{
|
|
var unreads = GetHistory(chatId, chat.UnreadCount, isSecret: true);
|
|
var rest = GetHistory(chatId, 5 - unreads.Count, unreads.First().Id, isSecret: true);
|
|
rest.ForEach(AddMessageToQueue);
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] ---UNREAD---");
|
|
unreads.ForEach(AddMessageToQueue);
|
|
}
|
|
else
|
|
{
|
|
GetHistory(chatId, isSecret: true).ForEach(AddMessageToQueue);
|
|
}
|
|
}
|
|
|
|
var history = GetHistory(currentChatId, 50, isSecret: true);
|
|
if (history.Count != 0)
|
|
MarkRead(chat.Id, history.First().Id);
|
|
var last = history.LastOrDefault(p => p.IsOutgoing);
|
|
if (last == null)
|
|
{
|
|
currentUserRead = true;
|
|
return;
|
|
}
|
|
|
|
lastMessage = last;
|
|
currentUserRead = IsMessageRead(last.ChatId, last.Id);
|
|
}
|
|
}
|
|
|
|
public class OpenSecretCommand : Command
|
|
{
|
|
public OpenSecretCommand() : base("os", "", "opens a secret chat. queries contacts.", "<query>", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var query = inputParams.Aggregate((current, param) => current + " " + param).Trim();
|
|
var userId = SearchContacts(query);
|
|
if (userId == 0 || query.Length == 0)
|
|
return; //TODO do something;
|
|
var chat = GetSecretChats().Find(p => ((TdApi.ChatType.ChatTypeSecret) p.Type).UserId == userId);
|
|
if (chat == null)
|
|
{
|
|
return; //TODO do something
|
|
}
|
|
|
|
TdApi.SecretChat secChat;
|
|
if (chat.Type is TdApi.ChatType.ChatTypeSecret secretChat)
|
|
{
|
|
currentChatUserId = secretChat.UserId;
|
|
currentChatId = chat.Id;
|
|
currentUserRead = false;
|
|
secChat = GetSecretChat(secretChat.SecretChatId);
|
|
}
|
|
else
|
|
{
|
|
return; //TODO do something
|
|
}
|
|
|
|
chat.Title = TruncateString(chat.Title, 20);
|
|
|
|
prefix = $"[{Ansi.Red}sec {Ansi.ResetAll}{chat.Title}]";
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Opening secret chat: {chat.Title}");
|
|
messageQueue.Add($"{Ansi.Yellow}" + $"[tgcli] You have {chat.UnreadCount} unread message" +
|
|
$"{(chat.UnreadCount == 1 ? "." : "s.")}");
|
|
if (secChat.State is TdApi.SecretChatState.SecretChatStateClosed)
|
|
{
|
|
messageQueue.Add($"{Ansi.Red}[tgcli] Secret chat has ended. No messages can be sent.");
|
|
}
|
|
else if (secChat.State is TdApi.SecretChatState.SecretChatStatePending)
|
|
{
|
|
messageQueue.Add($"{Ansi.Red}[tgcli] Secret chat is pending. No messages can be sent.");
|
|
}
|
|
|
|
if (chat.UnreadCount >= 5)
|
|
{
|
|
var capped = chat.UnreadCount > 50;
|
|
GetHistory(chat.Id, capped ? 50 : chat.UnreadCount, isSecret: true).ForEach(AddMessageToQueue);
|
|
if (capped)
|
|
messageQueue.Add(
|
|
$"{Ansi.Yellow}[tgcli] " + $"Showing 50 of {chat.UnreadCount} unread messages.");
|
|
}
|
|
else if (chat.UnreadCount > 0)
|
|
{
|
|
var unreads = GetHistory(chat.Id, chat.UnreadCount, isSecret: true);
|
|
var rest = GetHistory(chat.Id, 5 - unreads.Count, unreads.First().Id, isSecret: true);
|
|
rest.ForEach(AddMessageToQueue);
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] ---UNREAD---");
|
|
unreads.ForEach(AddMessageToQueue);
|
|
}
|
|
else
|
|
{
|
|
GetHistory(chat.Id, isSecret: true).ForEach(AddMessageToQueue);
|
|
}
|
|
}
|
|
|
|
var history = GetHistory(currentChatId, 50, isSecret: true);
|
|
if (history.Count != 0)
|
|
MarkRead(chat.Id, history.First().Id);
|
|
var last = history.LastOrDefault(p => p.IsOutgoing);
|
|
if (last == null)
|
|
{
|
|
currentUserRead = true;
|
|
return;
|
|
}
|
|
|
|
lastMessage = last;
|
|
currentUserRead = IsMessageRead(last.ChatId, last.Id);
|
|
}
|
|
}
|
|
|
|
public class CloseUnreadCommand : Command
|
|
{
|
|
public CloseUnreadCommand() : base("cu", "", "closes a chat, marking it as unread", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
if (currentChatId == 0) return; //TODO: do something
|
|
MarkUnread(currentChatId);
|
|
CommandManager.HandleCommand("c");
|
|
}
|
|
}
|
|
|
|
public class CloseCommand : Command
|
|
{
|
|
public CloseCommand() : base("c", "^E", "closes a chat", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
if (currentChatId == 0) return; //TODO: do something
|
|
|
|
currentChatId = 0;
|
|
currentChatUserId = 0;
|
|
currentUserRead = false;
|
|
lastMessage = null;
|
|
prefix = "[tgcli";
|
|
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Closing chat.");
|
|
var count = missedMessages.Count;
|
|
if (count == 0) return;
|
|
messageQueue.Add($"{Ansi.Yellow}" + $"[tgcli] You have {count} missed message" +
|
|
$"{(count == 1 ? "." : "s.")}");
|
|
messageQueue.AddRange(missedMessages);
|
|
missedMessages.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class HistoryCommand : Command
|
|
{
|
|
public HistoryCommand() : base("h", "", "shows chat history. default limit is 5", "[1-50]", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
if (currentChatId == 0) return; //TODO: do something
|
|
|
|
var history = inputParams.Count == 1 && int.TryParse(inputParams[0], out var limit)
|
|
? GetHistory(currentChatId, limit)
|
|
: GetHistory(currentChatId);
|
|
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Last {history.Count} messages in " +
|
|
$"{GetChat(currentChatId).Title}");
|
|
}
|
|
|
|
foreach (var msg in history)
|
|
{
|
|
AddMessageToQueue(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ClearCommand : Command
|
|
{
|
|
public ClearCommand() : base("cl", "^L", "clears console", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
lock (@lock)
|
|
{
|
|
Console.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
public class UnreadsCommand : Command
|
|
{
|
|
public UnreadsCommand() : base("u", "^U", "displays unread chat", "[all]", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var unreads = GetUnreadChats(inputParams.Count == 1 && inputParams[0].Equals("all"));
|
|
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] You have {unreads.Count} unread chats.");
|
|
unreads.ForEach(chat =>
|
|
{
|
|
string line;
|
|
if (chat.UnreadCount == 0)
|
|
line = $"{Ansi.Bold}{Ansi.Yellow}[M] {chat.Title}";
|
|
else if (chat.Type is TdApi.ChatType.ChatTypeSecret)
|
|
line = $"{Ansi.Bold}{Ansi.Red}[{chat.UnreadCount}] [sec] {chat.Title}";
|
|
else
|
|
line = $"{Ansi.Bold}{Ansi.Green}[{chat.UnreadCount}] {chat.Title}";
|
|
messageQueue.Add(line);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ListSecretChatsCommand : Command
|
|
{
|
|
public ListSecretChatsCommand() : base("ls", "", "displays all open secret chats", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
var secretChats = GetSecretChats();
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Listing {secretChats.Count} secret chats:");
|
|
secretChats.ForEach(chat =>
|
|
{
|
|
messageQueue.Add($"{Ansi.Bold}{Ansi.Red}[sec] {chat.Title} -> {chat.Id}");
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public class HelpCommand : Command
|
|
{
|
|
public HelpCommand() : base("help", "", "lists all commands", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
lock (@lock)
|
|
{
|
|
messageQueue.Add($"{Ansi.Yellow}[tgcli] Listing {CommandManager.Commands.Count} commands:");
|
|
CommandManager.Commands.ForEach(command =>
|
|
{
|
|
var commandText = $"/{command.Trigger}";
|
|
if (!string.IsNullOrWhiteSpace(command.Syntax))
|
|
commandText += $" {command.Syntax}";
|
|
commandText += $": {command.Description}";
|
|
if (!string.IsNullOrWhiteSpace(command.Shortcut))
|
|
commandText += $" ({command.Shortcut})";
|
|
|
|
messageQueue.Add($"{Ansi.Yellow}{commandText}");
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
public class QuitCommand : Command
|
|
{
|
|
public QuitCommand() : base("q", "^D", "quits the program", "", 0)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
quitting = true;
|
|
}
|
|
}
|
|
|
|
public class EditCommand : Command
|
|
{
|
|
public EditCommand() : base("e", "", "edits last message. param empty adds last message to inputline",
|
|
"[message]", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
try
|
|
{
|
|
if (inputParams.Count == 0)
|
|
{
|
|
currentInputLine = "/e " + ((TdApi.MessageContent.MessageText) lastMessage?.Content)?.Text?.Text;
|
|
return;
|
|
}
|
|
|
|
var message = inputParams.Aggregate((current, param) => current + " " + param).Trim();
|
|
|
|
if (currentChatId == 0) return; //TODO do something
|
|
|
|
if (lastMessage == null)
|
|
{
|
|
//try to find last message
|
|
var history = GetHistory(currentChatId, 50);
|
|
var last = history.LastOrDefault(p => p.IsOutgoing);
|
|
if (last == null) return; //TODO do something
|
|
lastMessage = last;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(message))
|
|
return;
|
|
EditMessage(message, lastMessage);
|
|
}
|
|
catch
|
|
{
|
|
//TODO do something
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ReplyCommand : Command
|
|
{
|
|
public ReplyCommand() : base("r", "", "replies to message", "<offset> <message>", -1)
|
|
{
|
|
}
|
|
|
|
public override void Handler(List<string> inputParams)
|
|
{
|
|
try
|
|
{
|
|
if (inputParams.Count < 2)
|
|
{
|
|
return; //TODO do something
|
|
}
|
|
|
|
var history = GetHistory(currentChatId, 50);
|
|
var parsed = int.TryParse(inputParams[0], out var offset);
|
|
inputParams.RemoveAt(0);
|
|
history.Reverse();
|
|
var message = inputParams.Aggregate((current, param) => current + " " + param).Trim();
|
|
|
|
if (!parsed || string.IsNullOrWhiteSpace(message) || history.Count < offset)
|
|
{
|
|
return; //TODO do something
|
|
}
|
|
|
|
var replyMessage = history[offset - 1];
|
|
|
|
if (currentChatId == 0) return; //TODO do something
|
|
|
|
SendMessage(message, currentChatId, replyMessage.Id);
|
|
}
|
|
catch
|
|
{
|
|
//TODO do something
|
|
}
|
|
}
|
|
}
|
|
} |