Decompiled source of FomoTelegram v1.2.8

AndrewLin.FomoTelegram.dll

Decompiled 4 hours ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Alpha;
using Alpha.Core.Command;
using Alpha.Core.Util;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Fomo;
using Fomo.Core;
using FomoTelegram.Commands;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AndrewLin")]
[assembly: AssemblyConfiguration("Publish")]
[assembly: AssemblyDescription("FomoTelegram: A Fomo submod that relays On-Together chat messages to a Telegram chat via a Telegram Bot.  Use /fomohelp and look for /fomotelegram commands")]
[assembly: AssemblyFileVersion("1.2.8.0")]
[assembly: AssemblyInformationalVersion("1.2.8+6b728ac84723d4f7964ec0bde26047dc2f58fe8d")]
[assembly: AssemblyProduct("AndrewLin.FomoTelegram")]
[assembly: AssemblyTitle("AndrewLin.FomoTelegram")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/andrewlimforfun/ot-mods")]
[assembly: AssemblyVersion("1.2.8.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace FomoTelegram
{
	public static class BuildInfo
	{
		public const string Version = "1.2.8";
	}
	public sealed class FomoTelegramManager : IDisposable
	{
		public const string PlaceholderApiKey = "YOUR_BOT_TOKEN_HERE";

		public const string PlaceholderChatId = "YOUR_CHAT_ID_HERE";

		private static readonly TimeSpan MinSendInterval = TimeSpan.FromMilliseconds(50.0);

		private readonly ManualLogSource _log = Logger.CreateLogSource("FomoTelegram.Manager");

		private readonly HttpClient _http = new HttpClient
		{
			Timeout = TimeSpan.FromSeconds(40.0)
		};

		private readonly string _apiBase;

		private readonly string _chatId;

		private readonly long _chatIdLong;

		private readonly ConcurrentQueue<string> _sendQueue = new ConcurrentQueue<string>();

		private readonly CancellationTokenSource _cts = new CancellationTokenSource();

		private readonly Task _workerTask;

		public bool IsReady { get; private set; }

		public FomoTelegramManager(string apiKey, string chatId)
		{
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
			_apiBase = "https://api.telegram.org/bot" + apiKey;
			_chatId = chatId;
			long.TryParse(chatId, out _chatIdLong);
			_workerTask = Task.Run(() => WorkerLoopAsync(_cts.Token));
			ValidateAndStartReceiverAsync();
		}

		public void Enqueue(string text)
		{
			if (IsReady)
			{
				_sendQueue.Enqueue(text);
			}
		}

		public async Task SendDirectAsync(string text)
		{
			try
			{
				string json = JsonConvert.SerializeObject((object)new
				{
					chat_id = _chatId,
					text = text
				});
				using StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
				HttpResponseMessage resp = await _http.PostAsync(_apiBase + "/sendMessage", content);
				if (!resp.IsSuccessStatusCode)
				{
					string respBody = await resp.Content.ReadAsStringAsync();
					_log.LogWarning((object)$"Telegram send failed ({resp.StatusCode}): {respBody}");
				}
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				_log.LogWarning((object)("Telegram send failed: " + ex.Message));
			}
		}

		private async Task ValidateAndStartReceiverAsync()
		{
			try
			{
				_log.LogInfo((object)("Validating Telegram credentials against " + _apiBase + "/getMe ..."));
				HttpResponseMessage resp = await _http.GetAsync(_apiBase + "/getMe");
				string raw = await resp.Content.ReadAsStringAsync();
				_log.LogDebug((object)$"getMe HTTP {(int)resp.StatusCode}: {raw}");
				JObject json = JObject.Parse(raw);
				JToken obj = json["ok"];
				if (obj == null || !Extensions.Value<bool>((IEnumerable<JToken>)obj))
				{
					JToken obj2 = json["description"];
					string description = ((obj2 != null) ? Extensions.Value<string>((IEnumerable<JToken>)obj2) : null) ?? raw;
					JToken obj3 = json["error_code"];
					int errorCode = ((obj3 != null) ? Extensions.Value<int>((IEnumerable<JToken>)obj3) : 0);
					_log.LogError((object)$"Telegram validation failed (HTTP {(int)resp.StatusCode}, error_code={errorCode}): {description}. Check your API key in the config.");
					return;
				}
				JToken obj4 = json["result"];
				object obj5;
				if (obj4 == null)
				{
					obj5 = null;
				}
				else
				{
					JToken obj6 = obj4[(object)"username"];
					obj5 = ((obj6 != null) ? Extensions.Value<string>((IEnumerable<JToken>)obj6) : null);
				}
				if (obj5 == null)
				{
					obj5 = "unknown";
				}
				string username = (string)obj5;
				JToken obj7 = json["result"];
				long? obj8;
				if (obj7 == null)
				{
					obj8 = null;
				}
				else
				{
					JToken obj9 = obj7[(object)"id"];
					obj8 = ((obj9 != null) ? new long?(Extensions.Value<long>((IEnumerable<JToken>)obj9)) : null);
				}
				long? num = obj8;
				long id = num.GetValueOrDefault();
				_log.LogInfo((object)$"Connected to Telegram as @{username} (id={id}).");
				IsReady = true;
			}
			catch (HttpRequestException ex3)
			{
				HttpRequestException ex2 = ex3;
				_log.LogError((object)"Telegram validation failed - network error reaching api.telegram.org. This is NOT an API key issue.");
				_log.LogError((object)("  HttpRequestException: " + ex2.Message));
				if (ex2.InnerException != null)
				{
					_log.LogError((object)("  Caused by (" + ex2.InnerException.GetType().Name + "): " + ex2.InnerException.Message));
				}
				if (ex2.InnerException?.InnerException != null)
				{
					_log.LogError((object)("  Root cause (" + ex2.InnerException.InnerException.GetType().Name + "): " + ex2.InnerException.InnerException.Message));
				}
				_log.LogError((object)"  Possible causes: no internet, firewall blocking api.telegram.org, TLS negotiation failure on Mono, or missing root certificates.");
				return;
			}
			catch (Exception ex4)
			{
				Exception ex = ex4;
				_log.LogError((object)("Telegram validation failed - unexpected " + ex.GetType().Name + ": " + ex.Message));
				if (ex.InnerException != null)
				{
					_log.LogError((object)("  Caused by (" + ex.InnerException.GetType().Name + "): " + ex.InnerException.Message));
				}
				return;
			}
			Task.Run(() => ReceiveLoopAsync(_cts.Token));
			_log.LogInfo((object)"Telegram inbound receiver started.");
		}

		private async Task ReceiveLoopAsync(CancellationToken ct)
		{
			long offset = await DropPendingUpdatesAsync(ct);
			while (!ct.IsCancellationRequested)
			{
				try
				{
					string url = $"{_apiBase}/getUpdates?offset={offset}&timeout=30&allowed_updates=%5B%22message%22%5D";
					JObject json = JObject.Parse(await (await _http.GetAsync(url, ct)).Content.ReadAsStringAsync());
					JToken obj = json["ok"];
					if (obj == null || !Extensions.Value<bool>((IEnumerable<JToken>)obj))
					{
						continue;
					}
					JToken obj2 = json["result"];
					JArray updates = (JArray)(object)((obj2 is JArray) ? obj2 : null);
					if (updates == null)
					{
						continue;
					}
					foreach (JToken update in updates)
					{
						JToken obj3 = update[(object)"update_id"];
						long updateId = ((obj3 != null) ? Extensions.Value<long>((IEnumerable<JToken>)obj3) : 0);
						offset = updateId + 1;
						JToken msg = update[(object)"message"];
						if (msg == null)
						{
							continue;
						}
						JToken obj4 = msg[(object)"text"];
						string text = ((obj4 != null) ? Extensions.Value<string>((IEnumerable<JToken>)obj4) : null);
						if (string.IsNullOrEmpty(text))
						{
							continue;
						}
						JToken obj5 = msg[(object)"chat"];
						long? obj6;
						if (obj5 == null)
						{
							obj6 = null;
						}
						else
						{
							JToken obj7 = obj5[(object)"id"];
							obj6 = ((obj7 != null) ? new long?(Extensions.Value<long>((IEnumerable<JToken>)obj7)) : null);
						}
						long? num = obj6;
						long chatId = num.GetValueOrDefault();
						if (_chatIdLong == 0L || chatId == _chatIdLong)
						{
							JToken obj8 = msg[(object)"from"];
							bool? obj9;
							if (obj8 == null)
							{
								obj9 = null;
							}
							else
							{
								JToken obj10 = obj8[(object)"is_bot"];
								obj9 = ((obj10 != null) ? new bool?(Extensions.Value<bool>((IEnumerable<JToken>)obj10)) : null);
							}
							bool? flag = obj9;
							if (!flag.GetValueOrDefault())
							{
								FomoPlugin.DispatchIncomingText(text);
							}
						}
					}
				}
				catch (OperationCanceledException)
				{
					break;
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("Telegram polling error: " + ex.Message));
					try
					{
						await Task.Delay(5000, ct);
					}
					catch (OperationCanceledException)
					{
						break;
					}
				}
			}
		}

		private async Task<long> DropPendingUpdatesAsync(CancellationToken ct)
		{
			try
			{
				string url = _apiBase + "/getUpdates?timeout=0";
				JObject json = JObject.Parse(await (await _http.GetAsync(url, ct)).Content.ReadAsStringAsync());
				JToken val = json["result"];
				JArray updates = (JArray)(object)((val is JArray) ? val : null);
				if (updates != null && ((JContainer)updates).Count > 0)
				{
					JToken obj = updates[((JContainer)updates).Count - 1][(object)"update_id"];
					long lastId = ((obj != null) ? Extensions.Value<long>((IEnumerable<JToken>)obj) : 0);
					return lastId + 1;
				}
			}
			catch
			{
			}
			return 0L;
		}

		private async Task WorkerLoopAsync(CancellationToken ct)
		{
			_log.LogInfo((object)"Telegram send-worker started.");
			while (!ct.IsCancellationRequested)
			{
				try
				{
					if (_sendQueue.TryDequeue(out string text))
					{
						await SendDirectAsync(text);
						try
						{
							await Task.Delay(MinSendInterval, ct);
						}
						catch (OperationCanceledException)
						{
							goto end_IL_005f;
						}
					}
					else
					{
						try
						{
							await Task.Delay(100, ct);
						}
						catch (OperationCanceledException)
						{
							goto end_IL_005f;
						}
					}
					text = null;
					continue;
					end_IL_005f:;
				}
				catch (OperationCanceledException)
				{
				}
				catch (Exception ex)
				{
					_log.LogError((object)$"Unexpected error in Telegram send-worker: {ex}");
					try
					{
						await Task.Delay(1000, ct);
					}
					catch (OperationCanceledException)
					{
						goto end_IL_0226;
					}
					continue;
					end_IL_0226:;
				}
				break;
			}
			_log.LogInfo((object)"Telegram send-worker stopped.");
		}

		public void Dispose()
		{
			_cts.Cancel();
			try
			{
				_workerTask.Wait(TimeSpan.FromSeconds(2.0));
			}
			catch
			{
			}
			_cts.Dispose();
			_http.Dispose();
		}
	}
	[BepInPlugin("com.andrewlin.ontogether.fomotelegram", "FomoTelegram", "1.2.8")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class FomoTelegramPlugin : BaseUnityPlugin
	{
		public const string ModGUID = "com.andrewlin.ontogether.fomotelegram";

		public const string ModName = "FomoTelegram";

		public const string ModVersion = "1.2.8";

		private static TelegramChatSink? _sink;

		internal static ManualLogSource Log = null;

		public static ConfigEntry<bool>? EnableFeature { get; private set; }

		public static ConfigEntry<string>? TelegramBotApiKey { get; private set; }

		public static ConfigEntry<string>? TelegramChatId { get; private set; }

		public static ConfigEntry<bool>? RelayGlobalChat { get; private set; }

		public static ConfigEntry<bool>? RelayLocalChat { get; private set; }

		public static ConfigEntry<bool>? RelayNotifications { get; private set; }

		public static ConfigEntry<string>? MessageFormat { get; private set; }

		public static ConfigEntry<string>? NotificationFormat { get; private set; }

		public static FomoTelegramManager? TelegramManager { get; private set; }

		public static string ConfigPath { get; private set; } = "BepInEx/config/com.andrewlin.ontogether.fomotelegram.cfg";


		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"FomoTelegram v1.2.8 loading…");
			InitConfig();
			ConfigPath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
			Log.LogInfo((object)("Config file path: " + ConfigPath));
			ChatCommandManager commandManager = AlphaPlugin.CommandManager;
			if (commandManager != null)
			{
				commandManager.Register((IChatCommand)(object)new FomoTelegramToggleCommand());
			}
			ChatCommandManager commandManager2 = AlphaPlugin.CommandManager;
			if (commandManager2 != null)
			{
				commandManager2.Register((IChatCommand)(object)new FomoTelegramMessageFormatCommand());
			}
			ChatCommandManager commandManager3 = AlphaPlugin.CommandManager;
			if (commandManager3 != null)
			{
				commandManager3.Register((IChatCommand)(object)new FomoTelegramNotificationFormatCommand());
			}
			ChatCommandManager commandManager4 = AlphaPlugin.CommandManager;
			if (commandManager4 != null)
			{
				commandManager4.Register((IChatCommand)(object)new FomoTelegramSetupInfoCommand());
			}
			ChatCommandManager commandManager5 = AlphaPlugin.CommandManager;
			if (commandManager5 != null)
			{
				commandManager5.Register((IChatCommand)(object)new FomoTelegramReloadConfigCommand());
			}
			ChatCommandManager commandManager6 = AlphaPlugin.CommandManager;
			if (commandManager6 != null)
			{
				commandManager6.Register((IChatCommand)(object)new FomoTelegramRestartCommand());
			}
			string text = TelegramBotApiKey?.Value ?? string.Empty;
			string text2 = TelegramChatId?.Value ?? string.Empty;
			if (string.IsNullOrWhiteSpace(text) || text == "YOUR_BOT_TOKEN_HERE")
			{
				Log.LogWarning((object)("TelegramBotApiKey is not set. Edit config and restart: " + ConfigPath));
			}
			else if (string.IsNullOrWhiteSpace(text2) || text2 == "YOUR_CHAT_ID_HERE")
			{
				Log.LogWarning((object)("TelegramChatId is not set. Edit config and restart: " + ConfigPath));
			}
			else
			{
				TelegramManager = new FomoTelegramManager(text, text2);
				_sink = new TelegramChatSink(TelegramManager);
				ChatSinkManager sinkManager = FomoPlugin.SinkManager;
				if (sinkManager != null)
				{
					sinkManager.Register((IChatSink)(object)_sink);
				}
				Log.LogInfo((object)"TelegramChatSink registered with Fomo SinkManager.");
			}
			Log.LogInfo((object)"FomoTelegram loaded.");
		}

		private void OnDestroy()
		{
			TelegramManager?.Dispose();
		}

		internal static string ReloadConfig()
		{
			ConfigEntry<string>? telegramBotApiKey = TelegramBotApiKey;
			if (telegramBotApiKey != null)
			{
				ConfigFile configFile = ((ConfigEntryBase)telegramBotApiKey).ConfigFile;
				if (configFile != null)
				{
					configFile.Reload();
				}
			}
			string apiKey = TelegramBotApiKey?.Value ?? string.Empty;
			string text = TelegramChatId?.Value ?? string.Empty;
			string text2 = MaskApiKey(apiKey);
			return "ApiKey = " + text2 + "\nChatId = " + text;
		}

		internal static string RestartTelegram()
		{
			ConfigEntry<string>? telegramBotApiKey = TelegramBotApiKey;
			if (telegramBotApiKey != null)
			{
				ConfigFile configFile = ((ConfigEntryBase)telegramBotApiKey).ConfigFile;
				if (configFile != null)
				{
					configFile.Reload();
				}
			}
			string text = TelegramBotApiKey?.Value ?? string.Empty;
			string text2 = TelegramChatId?.Value ?? string.Empty;
			if (string.IsNullOrWhiteSpace(text) || text == "YOUR_BOT_TOKEN_HERE")
			{
				return "Cannot restart: TelegramBotApiKey is not set.";
			}
			if (string.IsNullOrWhiteSpace(text2) || text2 == "YOUR_CHAT_ID_HERE")
			{
				return "Cannot restart: TelegramChatId is not set.";
			}
			TelegramManager?.Dispose();
			TelegramManager = new FomoTelegramManager(text, text2);
			if (_sink != null)
			{
				_sink.SwapManager(TelegramManager);
			}
			else
			{
				_sink = new TelegramChatSink(TelegramManager);
				ChatSinkManager sinkManager = FomoPlugin.SinkManager;
				if (sinkManager != null)
				{
					sinkManager.Register((IChatSink)(object)_sink);
				}
			}
			string text3 = MaskApiKey(text);
			return "Telegram restarted.\nApiKey = " + text3 + "\nChatId = " + text2;
		}

		internal static string MaskApiKey(string apiKey)
		{
			if (string.IsNullOrWhiteSpace(apiKey) || apiKey == "YOUR_BOT_TOKEN_HERE")
			{
				return apiKey;
			}
			return (apiKey.Length > 8) ? (apiKey.Substring(0, 4) + "..." + apiKey.Substring(apiKey.Length - 4)) : "****";
		}

		private void InitConfig()
		{
			EnableFeature = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFeature", true, "Master switch - disable to stop all Telegram forwarding without removing the plugin.");
			TelegramBotApiKey = ((BaseUnityPlugin)this).Config.Bind<string>("Telegram", "TelegramBotApiKey", "YOUR_BOT_TOKEN_HERE", "Your Telegram Bot API token from @BotFather (e.g. 123456:ABC-DEF…).");
			TelegramChatId = ((BaseUnityPlugin)this).Config.Bind<string>("Telegram", "TelegramChatId", "YOUR_CHAT_ID_HERE", "Telegram chat / group / channel ID to forward messages to. Use @userinfobot or the Telegram API to find your chat ID. e.g. 1234567890");
			RelayGlobalChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "RelayGlobalChat", true, "Forward global chat messages to Telegram.");
			RelayLocalChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "RelayLocalChat", true, "Forward local chat messages to Telegram.");
			RelayNotifications = ((BaseUnityPlugin)this).Config.Bind<bool>("Filters", "RelayNotifications", true, "Forward system notifications (joins, leaves, etc.) to Telegram.");
			MessageFormat = ((BaseUnityPlugin)this).Config.Bind<string>("Formatting", "MessageFormat", "[{channel:short}{distance}] {username}: {message}", "Format string for chat messages sent to Telegram.\nPlaceholders: {timestamp[:fmt]}, {channel[:short]}, {username}, {message}, {distance}, {source}, {playerid}");
			NotificationFormat = ((BaseUnityPlugin)this).Config.Bind<string>("Formatting", "NotificationFormat", "{message}", "Format string for system notifications sent to Telegram.\nPlaceholders: {timestamp[:fmt]}, {channel[:short]}, {username}, {message}, {distance}, {source}, {playerid}");
		}
	}
	public class TelegramChatSink : IChatSink
	{
		private static readonly ManualLogSource _log = Logger.CreateLogSource("FomoTelegram.TCS");

		private FomoTelegramManager _manager;

		public TelegramChatSink(FomoTelegramManager manager)
		{
			_manager = manager;
		}

		internal void SwapManager(FomoTelegramManager manager)
		{
			_manager = manager;
		}

		public Task SendAsync(ChatEntry entry)
		{
			ConfigEntry<bool>? enableFeature = FomoTelegramPlugin.EnableFeature;
			if (enableFeature == null || !enableFeature.Value)
			{
				return Task.CompletedTask;
			}
			if (!_manager.IsReady)
			{
				return Task.CompletedTask;
			}
			if (entry.Channel == null || entry.UserName == null)
			{
				ConfigEntry<bool>? relayNotifications = FomoTelegramPlugin.RelayNotifications;
				if (relayNotifications == null || !relayNotifications.Value)
				{
					return Task.CompletedTask;
				}
			}
			else if (entry.Channel != null && entry.Channel.StartsWith("Local"))
			{
				ConfigEntry<bool>? relayLocalChat = FomoTelegramPlugin.RelayLocalChat;
				if (relayLocalChat == null || !relayLocalChat.Value)
				{
					return Task.CompletedTask;
				}
			}
			else
			{
				ConfigEntry<bool>? relayGlobalChat = FomoTelegramPlugin.RelayGlobalChat;
				if (relayGlobalChat == null || !relayGlobalChat.Value)
				{
					return Task.CompletedTask;
				}
			}
			if (entry.IsNotification)
			{
				string text = ChatEntryFormatter.Format(entry, FomoTelegramPlugin.NotificationFormat?.Value);
				_manager.Enqueue(text);
			}
			else
			{
				string text2 = ChatEntryFormatter.Format(entry, FomoTelegramPlugin.MessageFormat?.Value);
				_manager.Enqueue(text2);
			}
			return Task.CompletedTask;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "AndrewLin.FomoTelegram";

		public const string PLUGIN_NAME = "AndrewLin.FomoTelegram";

		public const string PLUGIN_VERSION = "1.2.8";
	}
}
namespace FomoTelegram.Commands
{
	public class FomoTelegramMessageFormatCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomotelegrammessageformat";

		public string Name => "fomotelegrammessageformat";

		public string ShortName => "ftmf";

		public string Description => "Set or get the Telegram message format.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			ConfigEntry<bool>? enableFeature = FomoTelegramPlugin.EnableFeature;
			if (enableFeature == null || !enableFeature.Value)
			{
				ChatUtils.AddGlobalNotification("Telegram feature is disabled.");
			}
			else if (FomoTelegramPlugin.MessageFormat == null)
			{
				ChatUtils.AddGlobalNotification("Fomo Telegram Mod is not initialized yet.");
			}
			else if (args.Length == 0)
			{
				ChatUtils.AddGlobalNotification("Telegram message format: " + FomoTelegramPlugin.MessageFormat?.Value);
			}
			else if (args.Length != 0)
			{
				string text = string.Join(" ", args);
				if (string.IsNullOrWhiteSpace(text))
				{
					ChatUtils.AddGlobalNotification("Please enter a valid Telegram message format.");
					return;
				}
				FomoTelegramPlugin.MessageFormat.Value = text;
				ChatUtils.AddGlobalNotification("Telegram message format is now set to: " + text + ".");
			}
		}
	}
	public class FomoTelegramNotificationFormatCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomotelegramnotificationformat";

		public string Name => "fomotelegramnotificationformat";

		public string ShortName => "ftnf";

		public string Description => "Set or get the Telegram notification format.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			ConfigEntry<bool>? enableFeature = FomoTelegramPlugin.EnableFeature;
			if (enableFeature == null || !enableFeature.Value)
			{
				ChatUtils.AddGlobalNotification("Telegram feature is disabled.");
			}
			else if (FomoTelegramPlugin.NotificationFormat == null)
			{
				ChatUtils.AddGlobalNotification("Fomo Telegram Mod is not initialized yet.");
			}
			else if (args.Length == 0)
			{
				ChatUtils.AddGlobalNotification("Telegram notification format: " + FomoTelegramPlugin.NotificationFormat?.Value);
			}
			else if (args.Length != 0)
			{
				string text = string.Join(" ", args);
				if (string.IsNullOrWhiteSpace(text))
				{
					ChatUtils.AddGlobalNotification("Please enter a valid Telegram notification format.");
					return;
				}
				FomoTelegramPlugin.NotificationFormat.Value = text;
				ChatUtils.AddGlobalNotification("Telegram notification format is now set to: " + text + ".");
			}
		}
	}
	public class FomoTelegramReloadConfigCommand : IChatCommand, IComparable<IChatCommand>
	{
		public string Name => "fomotelegramreloadconfig";

		public string ShortName => "ftrc";

		public string Description => "Reload Telegram config from disk and show current API key and chat ID.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			string text = FomoTelegramPlugin.ReloadConfig();
			ChatUtils.AddGlobalNotification("Config reloaded.\n" + text);
		}
	}
	public class FomoTelegramRestartCommand : IChatCommand, IComparable<IChatCommand>
	{
		public string Name => "fomotelegramrestart";

		public string ShortName => "ftr";

		public string Description => "Reload config and restart the Telegram connection.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			string text = FomoTelegramPlugin.RestartTelegram();
			ChatUtils.AddGlobalNotification(text);
		}
	}
	public class FomoTelegramSetupInfoCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomotelegramsetupinfo";

		public string Name => "fomotelegramsetupinfo";

		public string ShortName => "ftsinfo";

		public string Description => "Instruction to set up the Telegram integration.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			ChatUtils.AddGlobalNotification("To set up Telegram integration you need:\n1. A Telegram Bot API key from @BotFather.\n2. Your Telegram chat ID from @userinfobot.\n3. Update the API key and chat ID in the mod configuration.\nConfig path: " + FomoTelegramPlugin.ConfigPath + "\n4. Reload config with /ftrc.\n5. Restart telegram manager with /ftr.");
		}
	}
	public class FomoTelegramToggleCommand : IChatCommand, IComparable<IChatCommand>
	{
		public const string CMD = "fomotelegramtoggle";

		public string Name => "fomotelegramtoggle";

		public string ShortName => "ftt";

		public string Description => "Toggle Telegram chat feature on/off.";

		public string Namespace => "fomo";

		public void Execute(string[] args)
		{
			if (FomoTelegramPlugin.EnableFeature != null)
			{
				FomoTelegramPlugin.EnableFeature.Value = !FomoTelegramPlugin.EnableFeature.Value;
				ChatUtils.AddGlobalNotification("Fomo Telegram is now " + (FomoTelegramPlugin.EnableFeature.Value ? "enabled" : "disabled") + ".");
			}
		}
	}
}