tgcli/telegram/Command.cs

629 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(),
new LogoutCommand(),
};
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)
{
if (inputParams.Count == 0)
return; //TODO do something
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;
Emojis.ForEach(em => currentInputLine = currentInputLine.Replace(em.Item2, em.Item1));
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
}
}
}
public class LogoutCommand : Command
{
public LogoutCommand() : base("logout", "", "log out this session (destroys all local data)", "", 0)
{
}
public override void Handler(List<string> inputParams)
{
LogOut();
}
}
}