From fb432c8fc3bf03b0ffc7bff1a7f9dd4ca37db67f Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Wed, 28 Jun 2017 14:18:59 -0400 Subject: [PATCH] Chat Refactor (#79) [TGSDeploy] * Chat refactor: Service changes * Settings migration * First pass at implementing the commandline * WIP irc modes * Wip * Fix it * Working * Fix dickscord * Some readme updates * Fixes * PMs are admin etc * Compiling * Final touches * Version bump to 3.0.86.0 --- README.md | 26 +- TGCommandLine/ChatCommands.cs | 602 ++++++++++++------ TGCommandLine/Properties/AssemblyInfo.cs | 4 +- TGCommandLine/RootCommands.cs | 2 +- TGControlPanel/App.config | 3 + TGControlPanel/ChatPage.cs | 132 ++-- TGControlPanel/Main.Designer.cs | 229 +++++-- TGControlPanel/Properties/AssemblyInfo.cs | 4 +- .../Properties/Settings.Designer.cs | 12 + TGControlPanel/Properties/Settings.settings | 3 + TGInstallerWrapper/Properties/AssemblyInfo.cs | 4 +- TGServerService/App.config | 30 +- TGServerService/Byond.cs | 10 +- TGServerService/Chat.cs | 383 +++++------ TGServerService/Compiler.cs | 18 +- TGServerService/Discord.cs | 122 ++-- TGServerService/DreamDaemon.cs | 16 +- TGServerService/IRC.cs | 150 +++-- TGServerService/Interop.cs | 4 +- TGServerService/Program.cs | 20 + TGServerService/Properties/AssemblyInfo.cs | 4 +- .../Properties/Settings.Designer.cs | 78 +-- TGServerService/Properties/Settings.settings | 26 +- TGServerService/Repository.cs | 26 +- TGServerService/ServerService.cs | 17 +- TGServiceInstaller/Product.wxs | 2 +- TGServiceInterface/Chat.cs | 340 +++++++--- TGServiceInterface/Properties/AssemblyInfo.cs | 4 +- TGServiceInterface/TGServiceInterface.csproj | 1 + 29 files changed, 1385 insertions(+), 887 deletions(-) diff --git a/README.md b/README.md index d075ec9ff6..7728810a4b 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Requires python 2.7/3.6 to be installed for changelog generation 1. Go to the `Repository` Tab and set the remote address and branch of the git you with to track 1. Hit the clone button 1. While waiting go to the BYOND tab and install the BYOND version you wish -1. You may also configure an IRC or discord bot for the server on the chat tab +1. You may also configure an IRC and/or discord bot for the server on the chat tab 1. Once the clone is complete you may set up a committer identity, user name, and password on the `Repository` tab for pushing changelog updates 1. Go to the `Server` tab and click the `Initialize Game Folders` button 1. Optionally change the `Project Path` Setting from tgstation to wherever the dme/dmb pair are in your repository @@ -31,20 +31,34 @@ This process is identical to the above steps in command line mode. You can alway 1. Launch TGCommandLine.exe (running with no parameters puts you in interactive mode) 1. `config move-server D:\tgstation` 1. `repo setup https://github.com/tgstation/tgstation master` -1. `byond update 511.1382` -1. `chat set-provider irc` +1. `byond update 511.1385` 1. `irc nick TGS3Test` +1. `irc set-auth-mode channel-mode` +1. `irc set-auth-level %` 1. `irc setup-auth NickServ "id hunter2"` Yes this is the real password, please use it only for testing -1. `chat enable` +1. `irc join coderbus dev` +1. `irc join devbus dev` +1. `irc join adminbus admin` +1. `irc join adminbus wd` +1. `irc join tgstation13 game` +1. `irc enable` +1. `discord set-token Rjfa93jlksjfj934jlkjasf8a08wfl.asdjfj08e44` See https://discordapp.com/developers/docs/topics/oauth2#bots +1. `discord set-auth-mode role-id` +1. `discord addmin 192837419273409` See how to get a role id: https://www.reddit.com/r/discordapp/comments/5bezg2/role_id/. Note that if you `discord set-auth-mode user-id` you'll need to use user ids (Enable developer mode, right click user, `Copy ID`) +1. `discord join 12341234453235 dev` This is a channel id (Enable developer mode, right click channel, `Copy ID`) +1. `discord join 34563456344245 dev` +1. `discord join 23452362574456 admin` +1. `discord join 23452362574456 wd` +1. `discord join 53457345736788 game` +1. `discord enable` 1. `repo set-name tgstation-server` These two lines specify the changelog's committer identity. They are not mirrored in the GUI 1. `repo set-email tgstation-server@tgstation13.org` 1. `repo set-credentials` And follow the prompts 1. `dm project-name tgstation` 1. `repo python-path C:\Python27` 1. `dd autostart on` -1. Use `repo status` To check the clone job status +1. `repo status` To check the clone job status 1. `dm initialize --wait` -1. `dm compile --wait` 1. `dd start` ## Updating diff --git a/TGCommandLine/ChatCommands.cs b/TGCommandLine/ChatCommands.cs index 689a76c004..ed130ef4c4 100644 --- a/TGCommandLine/ChatCommands.cs +++ b/TGCommandLine/ChatCommands.cs @@ -4,78 +4,30 @@ using TGServiceInterface; namespace TGCommandLine { - class ChatCommand : RootCommand - { - public ChatCommand() - { - Keyword = "chat"; - Children = new Command[] { new ChatAnnounceCommand(), new ChatStatusCommand(), new ChatSetAdminChannelCommand(), new ChatEnableCommand(), new ChatDisableCommand(), new ChatReconnectCommand(), new ChatListAdminsCommand(), new ChatAddminCommand(), new ChatDeadminCommand(), new ChatSetProviderCommand(), new ChatJoinCommand(), new ChatPartCommand() }; - } - protected override string GetHelpText() - { - return "Manages general chat settings"; - } - } - class ChatSetProviderCommand : Command { - public ChatSetProviderCommand() - { - Keyword = "set-provider"; - RequiredParameters = 1; - } - protected override string GetHelpText() - { - return "Set the chat provider"; - } - protected override string GetArgumentString() - { - return " [if discord, add the bot token]"; - } - public override ExitCode Run(IList parameters) - { - var Chat = Server.GetComponent(); - string res; - switch (parameters[0].ToLower()) - { - case "irc": - res = Chat.SetProviderInfo(new TGIRCSetupInfo()); - break; - case "discord": - if(parameters.Count < 2) - { - Console.WriteLine("Missing discord bot token!"); - return ExitCode.BadCommand; - } - res = Chat.SetProviderInfo(new TGDiscordSetupInfo() { BotToken = parameters[1] }); - break; - default: - Console.WriteLine("Invalid provider!"); - return ExitCode.BadCommand; - } - Console.WriteLine(res ?? "Success!"); - return res == null ? ExitCode.Normal : ExitCode.ServerError; - } - } class IRCCommand : RootCommand { public IRCCommand() { Keyword = "irc"; - Children = new Command[] { new IRCNickCommand(), new IRCAuthCommand(), new IRCDisableAuthCommand(), new IRCServerCommand() }; - } - public override ExitCode Run(IList parameters) - { - if (Server.GetComponent().ProviderInfo().Provider != TGChatProvider.IRC) - { - Console.WriteLine("The current provider is not IRC. Please switch providers first!"); - return ExitCode.ServerError; - } - return base.Run(parameters); + Children = new Command[] { new IRCNickCommand(), new IRCAuthCommand(), new IRCDisableAuthCommand(), new IRCServerCommand(), new ChatJoinCommand(TGChatProvider.IRC), new ChatPartCommand(TGChatProvider.IRC), new ChatListAdminsCommand(TGChatProvider.IRC), new ChatReconnectCommand(TGChatProvider.IRC), new ChatAddminCommand(TGChatProvider.IRC), new ChatDeadminCommand(TGChatProvider.IRC), new ChatEnableCommand(TGChatProvider.IRC), new ChatDisableCommand(TGChatProvider.IRC), new ChatStatusCommand(TGChatProvider.IRC), new IRCAuthModeCommand(), new IRCAuthLevelCommand() }; } protected override string GetHelpText() { return "Manages the IRC bot"; } } + class DiscordCommand : RootCommand + { + public DiscordCommand() + { + Keyword = "discord"; + Children = new Command[] { new DiscordSetTokenCommand(), new ChatJoinCommand(TGChatProvider.Discord), new ChatPartCommand(TGChatProvider.Discord), new ChatListAdminsCommand(TGChatProvider.Discord), new ChatReconnectCommand(TGChatProvider.Discord), new ChatAddminCommand(TGChatProvider.Discord), new ChatDeadminCommand(TGChatProvider.Discord), new ChatEnableCommand(TGChatProvider.Discord), new ChatDisableCommand(TGChatProvider.Discord), new ChatStatusCommand(TGChatProvider.Discord) , new DiscordAuthModeCommand() }; + } + protected override string GetHelpText() + { + return "Manages the Discord bot"; + } + } class IRCNickCommand : Command { public IRCNickCommand() @@ -96,7 +48,7 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { var Chat = Server.GetComponent(); - Chat.SetProviderInfo(new TGIRCSetupInfo(Chat.ProviderInfo()) + Chat.SetProviderInfo(new TGIRCSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.IRC]) { Nickname = parameters[0], }); @@ -106,25 +58,48 @@ namespace TGCommandLine class ChatJoinCommand : Command { - public ChatJoinCommand() + readonly int providerIndex; + public ChatJoinCommand(TGChatProvider pI) { Keyword = "join"; - RequiredParameters = 1; + RequiredParameters = 2; + providerIndex = (int)pI; } protected override string GetArgumentString() { - return ""; + return " "; } protected override string GetHelpText() { - return "Joins a channel for listening and broadcasting"; + return "Joins a channel for listening and broadcasting of the specified message type (Developer, Watchdog, Game, Admin)"; } public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - var channels = IRC.Channels(); + var info = IRC.ProviderInfos()[providerIndex]; + IList channels; + + switch (parameters[1].ToLower()) + { + case "dev": + channels = info.DevChannels; + break; + case "wd": + channels = info.WatchdogChannels; + break; + case "game": + channels = info.GameChannels; + break; + case "admin": + channels = info.AdminChannels; + break; + default: + Console.WriteLine("Invalid parameter: " + parameters[1]); + return ExitCode.BadCommand; + } + var lowerParam = parameters[0].ToLower(); foreach (var I in channels) { @@ -134,74 +109,97 @@ namespace TGCommandLine return ExitCode.BadCommand; } } - Array.Resize(ref channels, channels.Length + 1); - channels[channels.Length - 1] = parameters[0]; - IRC.SetChannels(channels, null); + channels.Add(parameters[0]); + switch (parameters[1].ToLower()) + { + case "dev": + info.DevChannels = channels; + break; + case "wd": + info.WatchdogChannels = channels; + break; + case "game": + info.GameChannels = channels; + break; + case "admin": + info.AdminChannels = channels; + break; + } + var res = IRC.SetProviderInfo(info); + if(res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } return ExitCode.Normal; } } class ChatPartCommand : Command { - public ChatPartCommand() + readonly int providerIndex; + public ChatPartCommand(TGChatProvider pI) { Keyword = "part"; - RequiredParameters = 1; + RequiredParameters = 2; + providerIndex = (int)pI; } protected override string GetArgumentString() { - return ""; + return " "; } protected override string GetHelpText() { - return "Stops listening and broadcasting on a channel"; + return "Stops listening and broadcasting on a channel for the specified message type (Developer, Watchdog, Game, Admin)"; } public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - var channels = IRC.Channels(); - var lowerParam = parameters[0].ToLower(); - if (lowerParam[0] != '#') - lowerParam = "#" + lowerParam; - var new_channels = new List(); - foreach (var I in channels) - { - if (I.ToLower() == lowerParam) - continue; - new_channels.Add(I); - } - if (new_channels.Count == 0) - { - Console.WriteLine("Error: Cannot part from the last channel!"); - return ExitCode.BadCommand; - } - IRC.SetChannels(new_channels.ToArray(), null); - return ExitCode.Normal; - } - } - class ChatAnnounceCommand : Command - { - public ChatAnnounceCommand() - { - Keyword = "announce"; - RequiredParameters = 1; - } - protected override string GetArgumentString() - { - return ""; - } - protected override string GetHelpText() - { - return "Sends a message to all connected channels"; - } + var info = IRC.ProviderInfos()[providerIndex]; + IList channels; - public override ExitCode Run(IList parameters) - { - var res = Server.GetComponent().SendMessage("SCP: " + parameters[0]); + switch (parameters[1].ToLower()) + { + case "dev": + channels = info.DevChannels; + break; + case "wd": + channels = info.WatchdogChannels; + break; + case "game": + channels = info.GameChannels; + break; + case "admin": + channels = info.AdminChannels; + break; + default: + Console.WriteLine("Invalid parameter: " + parameters[1]); + return ExitCode.BadCommand; + } + var lowerParam = parameters[0].ToLower(); + if ((TGChatProvider)providerIndex == TGChatProvider.IRC && lowerParam[0] != '#') + lowerParam = "#" + lowerParam; + channels.Remove(lowerParam); + switch (parameters[1].ToLower()) + { + case "dev": + info.DevChannels = channels; + break; + case "wd": + info.WatchdogChannels = channels; + break; + case "game": + info.GameChannels = channels; + break; + case "admin": + info.AdminChannels = channels; + break; + } + var res = IRC.SetProviderInfo(info); if (res != null) { - Console.WriteLine("Error: " + res); + Console.WriteLine(res); return ExitCode.ServerError; } return ExitCode.Normal; @@ -209,9 +207,11 @@ namespace TGCommandLine } class ChatListAdminsCommand : Command { - public ChatListAdminsCommand() + readonly int providerIndex; + public ChatListAdminsCommand(TGChatProvider pI) { Keyword = "list-admins"; + providerIndex = (int)pI; } protected override string GetHelpText() @@ -221,17 +221,56 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { - var res = Server.GetComponent().ListAdmins(); - foreach (var I in res) - Console.WriteLine(I); + var info = Server.GetComponent().ProviderInfos()[providerIndex]; + string authType; + switch ((TGChatProvider)providerIndex) + { + case TGChatProvider.IRC: + if (info.AdminsAreSpecial) + authType = "Mode:"; + else + authType = "Nicknames:"; + break; + case TGChatProvider.Discord: + if (info.AdminsAreSpecial) + authType = "Role IDs:"; + else + authType = "User IDs:"; + break; + default: + Console.WriteLine(String.Format("Invalid provider: {0}!", providerIndex)); + return ExitCode.ServerError; + } + Console.WriteLine("Authorized " + authType); + if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC) + switch(new TGIRCSetupInfo(info).AuthLevel) + { + case IRCMode.Voice: + Console.WriteLine("+"); + break; + case IRCMode.Halfop: + Console.WriteLine("%"); + break; + case IRCMode.Op: + Console.WriteLine("@"); + break; + case IRCMode.Owner: + Console.WriteLine("~"); + break; + } + else + foreach (var I in info.AdminList) + Console.WriteLine(I); return ExitCode.Normal; } } class ChatReconnectCommand : Command { - public ChatReconnectCommand() + readonly TGChatProvider providerIndex; + public ChatReconnectCommand(TGChatProvider pI) { Keyword = "reconnect"; + providerIndex = pI; } protected override string GetHelpText() @@ -241,7 +280,7 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { - var res = Server.GetComponent().Reconnect(); + var res = Server.GetComponent().Reconnect(providerIndex); if (res != null) { Console.WriteLine("Error: " + res); @@ -252,68 +291,221 @@ namespace TGCommandLine } class ChatAddminCommand : Command { - public ChatAddminCommand() + readonly int providerIndex; + public ChatAddminCommand(TGChatProvider pI) { Keyword = "addmin"; RequiredParameters = 1; + providerIndex = (int)pI; } - + protected override string GetArgumentString() { return "[nick]"; } protected override string GetHelpText() { - return "Add a user which can use restricted commands in the admin channel"; + return "Add a user which can use restricted commands in the admin channels"; } public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - var mins = new List(IRC.ListAdmins()); - var newmin = parameters[0]; + var info = IRC.ProviderInfos()[providerIndex]; + var newmin = parameters[0].ToLower(); - foreach (var I in mins) - if (I.ToLower() == newmin.ToLower()) - { - Console.WriteLine(newmin + " is already an admin!"); - return ExitCode.Normal; - } + if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC) + { + Console.WriteLine("Invalid auth mode for this command!"); + return ExitCode.BadCommand; + } - mins.Add(newmin); - IRC.SetAdmins(mins.ToArray()); + if (info.AdminList.Contains(newmin)) + { + Console.WriteLine(parameters[0] + " is already an admin!"); + return ExitCode.BadCommand; + } + var al = info.AdminList; + al.Add(newmin); + info.AdminList = al; + var res = IRC.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } + return ExitCode.Normal; + } + } + class IRCAuthModeCommand : Command + { + public IRCAuthModeCommand() + { + Keyword = "set-auth-mode"; + RequiredParameters = 1; + } + + protected override string GetArgumentString() + { + return ""; + } + protected override string GetHelpText() + { + return "Switch between admin command authorization via user channel mode or nicknames"; + } + public override ExitCode Run(IList parameters) + { + var IRC = Server.GetComponent(); + var info = IRC.ProviderInfos()[(int)TGChatProvider.IRC]; + var lowerparam = parameters[0].ToLower(); + if (lowerparam == "channel-mode") + info.AdminsAreSpecial = true; + else if (lowerparam == "nickname") + info.AdminsAreSpecial = false; + else + { + Console.WriteLine("Invalid parameter: " + parameters[0]); + return ExitCode.BadCommand; + } + var res = IRC.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } + return ExitCode.Normal; + } + } + class DiscordAuthModeCommand : Command + { + public DiscordAuthModeCommand() + { + Keyword = "set-auth-mode"; + RequiredParameters = 1; + } + + protected override string GetArgumentString() + { + return ""; + } + protected override string GetHelpText() + { + return "Switch between admin command authorization via user roles or individual users"; + } + public override ExitCode Run(IList parameters) + { + var IRC = Server.GetComponent(); + var info = IRC.ProviderInfos()[(int)TGChatProvider.Discord]; + var lowerparam = parameters[0].ToLower(); + if (lowerparam == "role-id") + info.AdminsAreSpecial = true; + else if (lowerparam == "user-id") + info.AdminsAreSpecial = false; + else + { + Console.WriteLine("Invalid parameter: " + parameters[0]); + return ExitCode.BadCommand; + } + var res = IRC.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } + return ExitCode.Normal; + } + } + class IRCAuthLevelCommand : Command + { + public IRCAuthLevelCommand() + { + Keyword = "set-auth-level"; + RequiredParameters = 1; + } + + protected override string GetArgumentString() + { + return "<+|%|@|~>"; + } + protected override string GetHelpText() + { + return "Set the required channel mode for users to use admin commands"; + } + public override ExitCode Run(IList parameters) + { + var IRC = Server.GetComponent(); + var info = new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC]); + switch (parameters[0]) + { + case "+": + info.AuthLevel = IRCMode.Voice; + break; + case "%": + info.AuthLevel = IRCMode.Halfop; + break; + case "@": + info.AuthLevel = IRCMode.Op; + break; + case "~": + info.AuthLevel = IRCMode.Owner; + break; + default: + Console.WriteLine("Invalid parameter: " + parameters[0]); + return ExitCode.BadCommand; + } + + var res = IRC.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } return ExitCode.Normal; } } class ChatDeadminCommand : Command { - public ChatDeadminCommand() + readonly int providerIndex; + public ChatDeadminCommand(TGChatProvider pI) { Keyword = "deadmin"; RequiredParameters = 1; + providerIndex = (int)pI; } protected override string GetArgumentString() { - return "[nick]"; + return ""; } protected override string GetHelpText() { - return "Remove a user which can use restricted commands in the admin channel"; + return "Remove a user which can use restricted commands in the admin channels"; } public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - var mins = new List(IRC.ListAdmins()); - var deadmin = parameters[0]; + var info = IRC.ProviderInfos()[providerIndex]; + var newmin = parameters[0].ToLower(); + + if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC) + { + Console.WriteLine("Invalid auth mode for this command!"); + return ExitCode.BadCommand; + } + + if (!info.AdminList.Contains(newmin)) + { + Console.WriteLine(parameters[0] + " is not an admin!"); + return ExitCode.BadCommand; + } - foreach (var I in mins) - if (I.ToLower() == deadmin.ToLower()) - { - mins.Remove(I); - IRC.SetAdmins(mins.ToArray()); - return ExitCode.Normal; - } - - Console.WriteLine(deadmin + " is not an admin!"); + var al = info.AdminList; + al.Remove(newmin); + info.AdminList = al; + var res = IRC.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } return ExitCode.Normal; } } @@ -337,7 +529,7 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfo()) + IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC]) { AuthTarget = parameters[0], AuthMessage = parameters[1] @@ -359,7 +551,7 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfo()) + IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC]) { AuthTarget = null, AuthMessage = null, @@ -370,9 +562,11 @@ namespace TGCommandLine class ChatStatusCommand : Command { - public ChatStatusCommand() + readonly int providerIndex; + public ChatStatusCommand(TGChatProvider pI) { Keyword = "status"; + providerIndex = (int)pI; } protected override string GetHelpText() { @@ -381,56 +575,33 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { var IRC = Server.GetComponent(); - Console.WriteLine("Currently configured broadcast channels:"); - Console.WriteLine("\tAdmin Channel: " + IRC.AdminChannel()); - foreach (var I in IRC.Channels()) + var info = IRC.ProviderInfos()[providerIndex]; + Console.WriteLine("Currently configured channels:"); + Console.WriteLine("Admin:"); + foreach (var I in info.AdminChannels) Console.WriteLine("\t" + I); - string provider; - switch (IRC.ProviderInfo().Provider) - { - case TGChatProvider.Discord: - provider = "Discord"; - break; - case TGChatProvider.IRC: - provider = "IRC"; - break; - default: - provider = "Unknown"; - break; - } - Console.WriteLine("Provider: " + provider); - Console.WriteLine("Chat bot is: " + (!IRC.Enabled() ? "Disabled" : IRC.Connected() ? "Connected" : "Disconnected")); - return ExitCode.Normal; - } - } - class ChatSetAdminChannelCommand : Command - { - public ChatSetAdminChannelCommand() - { - Keyword = "set-admin-channel"; - RequiredParameters = 1; - } - protected override string GetArgumentString() - { - return ""; - } - protected override string GetHelpText() - { - return "Sets the admin chat channel"; - } - public override ExitCode Run(IList parameters) - { - Server.GetComponent().SetChannels(null, parameters[0]); + Console.WriteLine("Watchdog:"); + foreach (var I in info.WatchdogChannels) + Console.WriteLine("\t" + I); + Console.WriteLine("Game:"); + foreach (var I in info.GameChannels) + Console.WriteLine("\t" + I); + Console.WriteLine("Developer:"); + foreach (var I in info.DevChannels) + Console.WriteLine("\t" + I); + Console.WriteLine("Chat bot is: " + (!info.Enabled ? "Disabled" : IRC.Connected(info.Provider) ? "Connected" : "Disconnected")); return ExitCode.Normal; } } class ChatEnableCommand : Command { - public ChatEnableCommand() + readonly int providerIndex; + public ChatEnableCommand(TGChatProvider pI) { Keyword = "enable"; + providerIndex = (int)pI; } - + protected override string GetHelpText() { return "Enables the chat bot"; @@ -438,17 +609,27 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { - Server.GetComponent().SetEnabled(true); + var Chat = Server.GetComponent(); + var info = Chat.ProviderInfos()[providerIndex]; + info.Enabled = true; + var res = Chat.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } return ExitCode.Normal; } } class ChatDisableCommand : Command { - public ChatDisableCommand() + readonly int providerIndex; + public ChatDisableCommand(TGChatProvider pI) { Keyword = "disable"; + providerIndex = (int)pI; } - + protected override string GetHelpText() { return "Disables the chat bot"; @@ -456,7 +637,15 @@ namespace TGCommandLine public override ExitCode Run(IList parameters) { - Server.GetComponent().SetEnabled(true); + var Chat = Server.GetComponent(); + var info = Chat.ProviderInfos()[providerIndex]; + info.Enabled = false; + var res = Chat.SetProviderInfo(info); + if (res != null) + { + Console.WriteLine(res); + return ExitCode.ServerError; + } return ExitCode.Normal; } } @@ -486,7 +675,7 @@ namespace TGCommandLine return ExitCode.BadCommand; } var Chat = Server.GetComponent(); - var PI = new TGIRCSetupInfo(Chat.ProviderInfo()) + var PI = new TGIRCSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.IRC]) { URL = splits[0] }; @@ -504,6 +693,29 @@ namespace TGCommandLine Console.WriteLine(res ?? "Success"); return res == null ? ExitCode.Normal : ExitCode.ServerError; } + } + class DiscordSetTokenCommand : Command + { + public DiscordSetTokenCommand() + { + Keyword = "set-token"; + RequiredParameters = 1; + } + protected override string GetArgumentString() + { + return ""; + } + protected override string GetHelpText() + { + return "Sets the discord API bot token"; + } + public override ExitCode Run(IList parameters) + { + var Chat = Server.GetComponent(); + var res = Chat.SetProviderInfo(new TGDiscordSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.Discord]) { BotToken = parameters[0] }); + Console.WriteLine(res ?? "Success"); + return res == null ? ExitCode.Normal : ExitCode.ServerError; + } } } \ No newline at end of file diff --git a/TGCommandLine/Properties/AssemblyInfo.cs b/TGCommandLine/Properties/AssemblyInfo.cs index 7a1bc0a1c5..1cf6533653 100644 --- a/TGCommandLine/Properties/AssemblyInfo.cs +++ b/TGCommandLine/Properties/AssemblyInfo.cs @@ -22,5 +22,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("3.0.85.4")] -[assembly: AssemblyFileVersion("3.0.85.4")] +[assembly: AssemblyVersion("3.0.86.0")] +[assembly: AssemblyFileVersion("3.0.86.0")] diff --git a/TGCommandLine/RootCommands.cs b/TGCommandLine/RootCommands.cs index c8030622c5..38271c96c9 100644 --- a/TGCommandLine/RootCommands.cs +++ b/TGCommandLine/RootCommands.cs @@ -15,7 +15,7 @@ namespace TGCommandLine public RootCommand() { if (IsRealRoot()) //stack overflows - Children = new Command[] { new UpdateCommand(), new TestmergeCommand(), new IRCCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new ChatCommand() }; + Children = new Command[] { new UpdateCommand(), new TestmergeCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new IRCCommand(), new DiscordCommand() }; } public override ExitCode Run(IList parameters) { diff --git a/TGControlPanel/App.config b/TGControlPanel/App.config index ddc58262f2..f5c9789d43 100644 --- a/TGControlPanel/App.config +++ b/TGControlPanel/App.config @@ -23,6 +23,9 @@ True + + 0 + diff --git a/TGControlPanel/ChatPage.cs b/TGControlPanel/ChatPage.cs index a4fdaddfc4..6b09ce2f58 100644 --- a/TGControlPanel/ChatPage.cs +++ b/TGControlPanel/ChatPage.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using TGServiceInterface; @@ -10,16 +7,22 @@ namespace TGControlPanel { partial class Main { - TGChatProvider modifyingProvider; bool updatingChat = false; + TGChatProvider ModifyingProvider + { + get { return (TGChatProvider)Properties.Settings.Default.LastChatProvider; } + set { Properties.Settings.Default.LastChatProvider = (int)value; } + } + void LoadChatPage() { updatingChat = true; var Chat = Server.GetComponent(); - var PI = Chat.ProviderInfo(); - modifyingProvider = PI.Provider; - switch (modifyingProvider) + var PI = Chat.ProviderInfos()[(int)ModifyingProvider]; + ChatAdminsTextBox.Visible = true; + IRCModesComboBox.Visible = false; + switch (ModifyingProvider) { case TGChatProvider.Discord: var DPI = new TGDiscordSetupInfo(PI); @@ -34,6 +37,11 @@ namespace TGControlPanel ChatPortTitle.Visible = false; ChatNicknameText.Visible = false; ChatNicknameTitle.Visible = false; + + ChatAdminsTitle.Text = String.Format("Admin {0} IDs:", DPI.AdminsAreSpecial ? "Role" : "User"); + ChannelsTitle.Text = "Broadcast/Listening Channel IDs:"; + AdminModeNormal.Text = "User IDs"; + AdminModeSpecial.Text = "Role IDs"; break; case TGChatProvider.IRC: var IRC = new TGIRCSetupInfo(PI); @@ -53,36 +61,49 @@ namespace TGControlPanel ChatNicknameText.Visible = true; ChatNicknameTitle.Visible = true; ChatNicknameText.Text = IRC.Nickname; + ChatAdminsTitle.Text = String.Format("Admin {0}:", IRC.AdminsAreSpecial ? "Req Mode" : "Nicknames"); + ChannelsTitle.Text = "Broadcast/Listening Channels:"; + AdminModeNormal.Text = "Nicknames"; + AdminModeSpecial.Text = "Channel Mode"; + if (IRC.AdminsAreSpecial) + { + ChatAdminsTextBox.Visible = false; + IRCModesComboBox.Visible = true; + IRCModesComboBox.SelectedIndex = (int)IRC.AuthLevel; + } break; default: - MessageBox.Show("This is a bug, I'll try and recover. Provider was " + modifyingProvider.ToString()); - MessageBox.Show(Chat.SetProviderInfo(new TGIRCSetupInfo()) ?? "Success!"); + Properties.Settings.Default.LastChatProvider = (int)TGChatProvider.IRC; LoadChatPage(); return; } - var Enabled = Chat.Enabled(); - ChatEnabledCheckbox.Checked = Enabled; - if (!Enabled) + AdminModeNormal.Checked = !PI.AdminsAreSpecial; + AdminModeSpecial.Checked = PI.AdminsAreSpecial; + ChatEnabledCheckbox.Checked = PI.Enabled; + if (!PI.Enabled) ChatStatusLabel.Text = "Disabled"; - else if (Chat.Connected()) + else if (Chat.Connected(ModifyingProvider)) ChatStatusLabel.Text = "Connected"; else ChatStatusLabel.Text = "Disconnected"; - ChatReconnectButton.Enabled = Enabled; + ChatReconnectButton.Enabled = PI.Enabled; - AdminChannelText.Text = Chat.AdminChannel(); - - ChatAdminsTextBox.Text = ""; - foreach (var I in Chat.ListAdmins()) - ChatAdminsTextBox.Text += I + "\r\n"; - - ChatChannelsTextBox.Text = ""; - foreach (var I in Chat.Channels()) - ChatChannelsTextBox.Text += I + "\r\n"; + AssignListToTextbox(PI.AdminList, ChatAdminsTextBox); + AssignListToTextbox(PI.WatchdogChannels, WDChannelsTextbox); + AssignListToTextbox(PI.AdminChannels, AdminChannelsTextbox); + AssignListToTextbox(PI.DevChannels, DevChannelsTextbox); + AssignListToTextbox(PI.GameChannels, GameChannelsTextbox); updatingChat = false; } + static void AssignListToTextbox(IList a, TextBox b) + { + b.Text = ""; + foreach (var I in a) + b.Text += I + Environment.NewLine; + } + private void ChatRefreshButton_Click(object sender, EventArgs e) { LoadChatPage(); @@ -90,7 +111,7 @@ namespace TGControlPanel private void ChatReconnectButton_Click(object sender, EventArgs e) { - Server.GetComponent().Reconnect(); + Server.GetComponent().Reconnect(ModifyingProvider); LoadChatPage(); } @@ -112,9 +133,7 @@ namespace TGControlPanel { if (!updatingChat && DiscordProviderSwitch.Checked) { - var res = Server.GetComponent().SetProviderInfo(new TGDiscordSetupInfo()); - if (res != null) - MessageBox.Show(res); + ModifyingProvider = TGChatProvider.Discord; LoadChatPage(); } } @@ -123,44 +142,73 @@ namespace TGControlPanel { if (!updatingChat && IRCProviderSwitch.Checked) { - var res = Server.GetComponent().SetProviderInfo(new TGIRCSetupInfo()); - if (res != null) - MessageBox.Show(res); + ModifyingProvider = TGChatProvider.IRC; LoadChatPage(); } } + void SetAdminsAreSpecial(bool value) + { + var Chat = Server.GetComponent(); + var PI = Chat.ProviderInfos()[(int)ModifyingProvider]; + PI.AdminsAreSpecial = value; + var res = Chat.SetProviderInfo(PI); + if (res != null) + MessageBox.Show(res); + LoadChatPage(); + } + + private void AdminModeNormal_CheckedChanged(object sender, EventArgs e) + { + if (!updatingChat && AdminModeNormal.Checked) + SetAdminsAreSpecial(false); + } + + private void AdminModeSpecial_CheckedChanged(object sender, EventArgs e) + { + if (!updatingChat && AdminModeSpecial.Checked) + SetAdminsAreSpecial(true); + } private void ChatApplyButton_Click(object sender, EventArgs e) { - var Chat = Server.GetComponent(); - - string res; - switch (modifyingProvider) + string res = null; + TGChatSetupInfo wip = null; + switch (ModifyingProvider) { case TGChatProvider.Discord: - res = Chat.SetProviderInfo(new TGDiscordSetupInfo() { BotToken = AuthField1.Text }); + wip = new TGDiscordSetupInfo() + { + BotToken = AuthField1.Text + }; break; case TGChatProvider.IRC: - res = Chat.SetProviderInfo(new TGIRCSetupInfo() { + wip = new TGIRCSetupInfo() + { AuthMessage = AuthField2.Text, AuthTarget = AuthField1.Text, Nickname = ChatNicknameText.Text, URL = ChatServerText.Text, Port = (ushort)ChatPortSelector.Value, - }); + AuthLevel = (IRCMode)IRCModesComboBox.SelectedIndex, + }; break; default: res = "You really shouldn't be able to read this."; break; } + if (res == null) + { + wip.AdminChannels = new List(AdminChannelsTextbox.Text.Split('\n')); + wip.WatchdogChannels = new List(WDChannelsTextbox.Text.Split('\n')); + wip.DevChannels = new List(DevChannelsTextbox.Text.Split('\n')); + wip.GameChannels = new List(GameChannelsTextbox.Text.Split('\n')); + wip.Enabled = ChatEnabledCheckbox.Checked; + + res = Server.GetComponent().SetProviderInfo(wip); + } if (res != null) MessageBox.Show(res); - - Chat.SetChannels(SplitByLine(ChatChannelsTextBox), AdminChannelText.Text); - Chat.SetAdmins(SplitByLine(ChatAdminsTextBox)); - Chat.SetEnabled(ChatEnabledCheckbox.Checked); - LoadChatPage(); } } diff --git a/TGControlPanel/Main.Designer.cs b/TGControlPanel/Main.Designer.cs index fc339c266a..20c4e75974 100644 --- a/TGControlPanel/Main.Designer.cs +++ b/TGControlPanel/Main.Designer.cs @@ -105,6 +105,16 @@ this.ServerStatusLabel = new System.Windows.Forms.Label(); this.ServerStatusTitle = new System.Windows.Forms.Label(); this.ChatPanel = new System.Windows.Forms.TabPage(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.IRCModesComboBox = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.AdminChannelsTextbox = new System.Windows.Forms.TextBox(); + this.WDChannelsTextbox = new System.Windows.Forms.TextBox(); + this.GameChannelsTextbox = new System.Windows.Forms.TextBox(); + this.DevChannelsTextbox = new System.Windows.Forms.TextBox(); this.ChatRefreshButton = new System.Windows.Forms.Button(); this.ChatNicknameText = new System.Windows.Forms.TextBox(); this.ChatNicknameTitle = new System.Windows.Forms.Label(); @@ -117,8 +127,6 @@ this.AuthField1Title = new System.Windows.Forms.Label(); this.AuthField2 = new System.Windows.Forms.TextBox(); this.AuthField1 = new System.Windows.Forms.TextBox(); - this.AdminChannelTitle = new System.Windows.Forms.Label(); - this.AdminChannelText = new System.Windows.Forms.TextBox(); this.ChatReconnectButton = new System.Windows.Forms.Button(); this.ChatStatusLabel = new System.Windows.Forms.Label(); this.ChatStatusTitle = new System.Windows.Forms.Label(); @@ -130,7 +138,9 @@ this.ChannelsTitle = new System.Windows.Forms.Label(); this.ChatAdminsTextBox = new System.Windows.Forms.TextBox(); this.ChatAdminsTitle = new System.Windows.Forms.Label(); - this.ChatChannelsTextBox = new System.Windows.Forms.TextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.AdminModeSpecial = new System.Windows.Forms.RadioButton(); + this.AdminModeNormal = new System.Windows.Forms.RadioButton(); this.ConfigPanel = new System.Windows.Forms.TabPage(); this.ConfigApply = new System.Windows.Forms.Button(); this.ConfigDownloadRepo = new System.Windows.Forms.Button(); @@ -180,6 +190,7 @@ this.ChatPanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.ChatPortSelector)).BeginInit(); this.ChatProviderSelectorPanel.SuspendLayout(); + this.panel1.SuspendLayout(); this.ConfigPanel.SuspendLayout(); this.ConfigPanels.SuspendLayout(); this.AdminsPanel.SuspendLayout(); @@ -1170,6 +1181,16 @@ // ChatPanel // this.ChatPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34))))); + this.ChatPanel.Controls.Add(this.label5); + this.ChatPanel.Controls.Add(this.label4); + this.ChatPanel.Controls.Add(this.label3); + this.ChatPanel.Controls.Add(this.label2); + this.ChatPanel.Controls.Add(this.IRCModesComboBox); + this.ChatPanel.Controls.Add(this.label1); + this.ChatPanel.Controls.Add(this.AdminChannelsTextbox); + this.ChatPanel.Controls.Add(this.WDChannelsTextbox); + this.ChatPanel.Controls.Add(this.GameChannelsTextbox); + this.ChatPanel.Controls.Add(this.DevChannelsTextbox); this.ChatPanel.Controls.Add(this.ChatRefreshButton); this.ChatPanel.Controls.Add(this.ChatNicknameText); this.ChatPanel.Controls.Add(this.ChatNicknameTitle); @@ -1182,8 +1203,6 @@ this.ChatPanel.Controls.Add(this.AuthField1Title); this.ChatPanel.Controls.Add(this.AuthField2); this.ChatPanel.Controls.Add(this.AuthField1); - this.ChatPanel.Controls.Add(this.AdminChannelTitle); - this.ChatPanel.Controls.Add(this.AdminChannelText); this.ChatPanel.Controls.Add(this.ChatReconnectButton); this.ChatPanel.Controls.Add(this.ChatStatusLabel); this.ChatPanel.Controls.Add(this.ChatStatusTitle); @@ -1193,7 +1212,7 @@ this.ChatPanel.Controls.Add(this.ChannelsTitle); this.ChatPanel.Controls.Add(this.ChatAdminsTextBox); this.ChatPanel.Controls.Add(this.ChatAdminsTitle); - this.ChatPanel.Controls.Add(this.ChatChannelsTextBox); + this.ChatPanel.Controls.Add(this.panel1); this.ChatPanel.Location = new System.Drawing.Point(4, 22); this.ChatPanel.Name = "ChatPanel"; this.ChatPanel.Padding = new System.Windows.Forms.Padding(3); @@ -1201,6 +1220,117 @@ this.ChatPanel.TabIndex = 4; this.ChatPanel.Text = "Chat"; // + // label5 + // + this.label5.AutoSize = true; + this.label5.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.label5.Location = new System.Drawing.Point(686, 219); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(148, 18); + this.label5.TabIndex = 43; + this.label5.Text = "Game Messages:"; + this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.label4.Location = new System.Drawing.Point(516, 219); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(136, 18); + this.label4.TabIndex = 42; + this.label4.Text = "Developer Info:"; + this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.label3.Location = new System.Drawing.Point(686, 61); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(135, 18); + this.label3.TabIndex = 41; + this.label3.Text = "Administration:"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.label2.Location = new System.Drawing.Point(516, 61); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(153, 18); + this.label2.TabIndex = 40; + this.label2.Text = "Server Watchdog:"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // IRCModesComboBox + // + this.IRCModesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.IRCModesComboBox.FormattingEnabled = true; + this.IRCModesComboBox.Items.AddRange(new object[] { + "Voice - +", + "Halfop - %", + "Op - @", + "Owner - ~"}); + this.IRCModesComboBox.Location = new System.Drawing.Point(369, 170); + this.IRCModesComboBox.Name = "IRCModesComboBox"; + this.IRCModesComboBox.Size = new System.Drawing.Size(141, 21); + this.IRCModesComboBox.TabIndex = 38; + this.IRCModesComboBox.Visible = false; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.label1.Location = new System.Drawing.Point(30, 174); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(110, 18); + this.label1.TabIndex = 39; + this.label1.Text = "Admin Auth:"; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // AdminChannelsTextbox + // + this.AdminChannelsTextbox.Location = new System.Drawing.Point(689, 82); + this.AdminChannelsTextbox.Multiline = true; + this.AdminChannelsTextbox.Name = "AdminChannelsTextbox"; + this.AdminChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.AdminChannelsTextbox.Size = new System.Drawing.Size(167, 120); + this.AdminChannelsTextbox.TabIndex = 37; + // + // WDChannelsTextbox + // + this.WDChannelsTextbox.Location = new System.Drawing.Point(516, 82); + this.WDChannelsTextbox.Multiline = true; + this.WDChannelsTextbox.Name = "WDChannelsTextbox"; + this.WDChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.WDChannelsTextbox.Size = new System.Drawing.Size(167, 120); + this.WDChannelsTextbox.TabIndex = 36; + // + // GameChannelsTextbox + // + this.GameChannelsTextbox.Location = new System.Drawing.Point(689, 240); + this.GameChannelsTextbox.Multiline = true; + this.GameChannelsTextbox.Name = "GameChannelsTextbox"; + this.GameChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.GameChannelsTextbox.Size = new System.Drawing.Size(167, 120); + this.GameChannelsTextbox.TabIndex = 35; + // + // DevChannelsTextbox + // + this.DevChannelsTextbox.Location = new System.Drawing.Point(516, 240); + this.DevChannelsTextbox.Multiline = true; + this.DevChannelsTextbox.Name = "DevChannelsTextbox"; + this.DevChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.DevChannelsTextbox.Size = new System.Drawing.Size(167, 120); + this.DevChannelsTextbox.TabIndex = 34; + // // ChatRefreshButton // this.ChatRefreshButton.Location = new System.Drawing.Point(174, 335); @@ -1323,7 +1453,6 @@ this.AuthField2.Name = "AuthField2"; this.AuthField2.Size = new System.Drawing.Size(151, 20); this.AuthField2.TabIndex = 22; - this.AuthField2.UseSystemPasswordChar = true; // // AuthField1 // @@ -1331,26 +1460,6 @@ this.AuthField1.Name = "AuthField1"; this.AuthField1.Size = new System.Drawing.Size(151, 20); this.AuthField1.TabIndex = 21; - this.AuthField1.UseSystemPasswordChar = true; - // - // AdminChannelTitle - // - this.AdminChannelTitle.AutoSize = true; - this.AdminChannelTitle.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.AdminChannelTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); - this.AdminChannelTitle.Location = new System.Drawing.Point(30, 174); - this.AdminChannelTitle.Name = "AdminChannelTitle"; - this.AdminChannelTitle.Size = new System.Drawing.Size(138, 18); - this.AdminChannelTitle.TabIndex = 20; - this.AdminChannelTitle.Text = "Admin Channel:"; - this.AdminChannelTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - // - // AdminChannelText - // - this.AdminChannelText.Location = new System.Drawing.Point(174, 172); - this.AdminChannelText.Name = "AdminChannelText"; - this.AdminChannelText.Size = new System.Drawing.Size(149, 20); - this.AdminChannelText.TabIndex = 19; // // ChatReconnectButton // @@ -1441,9 +1550,9 @@ this.ChatProviderTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); this.ChatProviderTitle.Location = new System.Drawing.Point(20, 15); this.ChatProviderTitle.Name = "ChatProviderTitle"; - this.ChatProviderTitle.Size = new System.Drawing.Size(125, 18); + this.ChatProviderTitle.Size = new System.Drawing.Size(144, 18); this.ChatProviderTitle.TabIndex = 13; - this.ChatProviderTitle.Text = "Chat Provider:"; + this.ChatProviderTitle.Text = "Editing Provider:"; this.ChatProviderTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // ChannelsTitle @@ -1451,7 +1560,7 @@ this.ChannelsTitle.AutoSize = true; this.ChannelsTitle.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.ChannelsTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); - this.ChannelsTitle.Location = new System.Drawing.Point(628, 15); + this.ChannelsTitle.Location = new System.Drawing.Point(565, 15); this.ChannelsTitle.Name = "ChannelsTitle"; this.ChannelsTitle.Size = new System.Drawing.Size(234, 18); this.ChannelsTitle.TabIndex = 11; @@ -1464,7 +1573,7 @@ this.ChatAdminsTextBox.Multiline = true; this.ChatAdminsTextBox.Name = "ChatAdminsTextBox"; this.ChatAdminsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ChatAdminsTextBox.Size = new System.Drawing.Size(231, 311); + this.ChatAdminsTextBox.Size = new System.Drawing.Size(141, 311); this.ChatAdminsTextBox.TabIndex = 10; // // ChatAdminsTitle @@ -1479,14 +1588,40 @@ this.ChatAdminsTitle.Text = "Admins:"; this.ChatAdminsTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // - // ChatChannelsTextBox + // panel1 // - this.ChatChannelsTextBox.Location = new System.Drawing.Point(631, 49); - this.ChatChannelsTextBox.Multiline = true; - this.ChatChannelsTextBox.Name = "ChatChannelsTextBox"; - this.ChatChannelsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.ChatChannelsTextBox.Size = new System.Drawing.Size(231, 311); - this.ChatChannelsTextBox.TabIndex = 0; + this.panel1.Controls.Add(this.AdminModeSpecial); + this.panel1.Controls.Add(this.AdminModeNormal); + this.panel1.Location = new System.Drawing.Point(174, 168); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(202, 25); + this.panel1.TabIndex = 15; + // + // AdminModeSpecial + // + this.AdminModeSpecial.AutoSize = true; + this.AdminModeSpecial.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.AdminModeSpecial.Location = new System.Drawing.Point(87, 8); + this.AdminModeSpecial.Name = "AdminModeSpecial"; + this.AdminModeSpecial.Size = new System.Drawing.Size(94, 17); + this.AdminModeSpecial.TabIndex = 13; + this.AdminModeSpecial.TabStop = true; + this.AdminModeSpecial.Text = "Channel Mode"; + this.AdminModeSpecial.UseVisualStyleBackColor = true; + this.AdminModeNormal.CheckedChanged += new System.EventHandler(this.AdminModeSpecial_CheckedChanged); + // + // AdminModeNormal + // + this.AdminModeNormal.AutoSize = true; + this.AdminModeNormal.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242))))); + this.AdminModeNormal.Location = new System.Drawing.Point(3, 8); + this.AdminModeNormal.Name = "AdminModeNormal"; + this.AdminModeNormal.Size = new System.Drawing.Size(78, 17); + this.AdminModeNormal.TabIndex = 12; + this.AdminModeNormal.TabStop = true; + this.AdminModeNormal.Text = "Nicknames"; + this.AdminModeNormal.UseVisualStyleBackColor = true; + this.AdminModeNormal.CheckedChanged += new System.EventHandler(this.AdminModeNormal_CheckedChanged); // // ConfigPanel // @@ -1881,6 +2016,8 @@ ((System.ComponentModel.ISupportInitialize)(this.ChatPortSelector)).EndInit(); this.ChatProviderSelectorPanel.ResumeLayout(false); this.ChatProviderSelectorPanel.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); this.ConfigPanel.ResumeLayout(false); this.ConfigPanel.PerformLayout(); this.ConfigPanels.ResumeLayout(false); @@ -1950,7 +2087,6 @@ private System.Windows.Forms.TextBox ServerPathTextbox; private System.Windows.Forms.Label LatestVersionLabel; private System.Windows.Forms.Label LatestVersionTitle; - private System.Windows.Forms.TextBox ChatChannelsTextBox; private System.Windows.Forms.Label ChannelsTitle; private System.Windows.Forms.TextBox ChatAdminsTextBox; private System.Windows.Forms.Label ChatAdminsTitle; @@ -1962,8 +2098,6 @@ private System.Windows.Forms.RadioButton IRCProviderSwitch; private System.Windows.Forms.Label ChatProviderTitle; private System.Windows.Forms.Button ChatReconnectButton; - private System.Windows.Forms.Label AdminChannelTitle; - private System.Windows.Forms.TextBox AdminChannelText; private System.Windows.Forms.Label AuthField2Title; private System.Windows.Forms.Label AuthField1Title; private System.Windows.Forms.TextBox AuthField2; @@ -2028,5 +2162,18 @@ private System.Windows.Forms.ComboBox VisibilitySelector; private System.ComponentModel.BackgroundWorker ServerStartBGW; private System.Windows.Forms.Button RepoRefreshButton; + private System.Windows.Forms.ComboBox IRCModesComboBox; + private System.Windows.Forms.TextBox AdminChannelsTextbox; + private System.Windows.Forms.TextBox WDChannelsTextbox; + private System.Windows.Forms.TextBox GameChannelsTextbox; + private System.Windows.Forms.TextBox DevChannelsTextbox; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.RadioButton AdminModeSpecial; + private System.Windows.Forms.RadioButton AdminModeNormal; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; } } diff --git a/TGControlPanel/Properties/AssemblyInfo.cs b/TGControlPanel/Properties/AssemblyInfo.cs index f7497709e3..c9881c23aa 100644 --- a/TGControlPanel/Properties/AssemblyInfo.cs +++ b/TGControlPanel/Properties/AssemblyInfo.cs @@ -25,5 +25,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.85.4")] -[assembly: AssemblyFileVersion("3.0.85.4")] +[assembly: AssemblyVersion("3.0.86.0")] +[assembly: AssemblyFileVersion("3.0.86.0")] diff --git a/TGControlPanel/Properties/Settings.Designer.cs b/TGControlPanel/Properties/Settings.Designer.cs index c3ad294d5e..1d6c91d336 100644 --- a/TGControlPanel/Properties/Settings.Designer.cs +++ b/TGControlPanel/Properties/Settings.Designer.cs @@ -58,5 +58,17 @@ namespace TGControlPanel.Properties { this["UpgradeRequired"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int LastChatProvider { + get { + return ((int)(this["LastChatProvider"])); + } + set { + this["LastChatProvider"] = value; + } + } } } diff --git a/TGControlPanel/Properties/Settings.settings b/TGControlPanel/Properties/Settings.settings index ab8a13022f..7f247f5af3 100644 --- a/TGControlPanel/Properties/Settings.settings +++ b/TGControlPanel/Properties/Settings.settings @@ -11,5 +11,8 @@ True + + 0 + \ No newline at end of file diff --git a/TGInstallerWrapper/Properties/AssemblyInfo.cs b/TGInstallerWrapper/Properties/AssemblyInfo.cs index fab74056d9..2029a97308 100644 --- a/TGInstallerWrapper/Properties/AssemblyInfo.cs +++ b/TGInstallerWrapper/Properties/AssemblyInfo.cs @@ -25,5 +25,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.85.4")] -[assembly: AssemblyFileVersion("3.0.85.4")] +[assembly: AssemblyVersion("3.0.86.0")] +[assembly: AssemblyFileVersion("3.0.86.0")] diff --git a/TGServerService/App.config b/TGServerService/App.config index 13f2cdb1b8..4fb3840dc5 100644 --- a/TGServerService/App.config +++ b/TGServerService/App.config @@ -34,42 +34,17 @@ 2 - - False - False C:\Python27 - - 0 - NEEDS INITIALIZING - - - - theghostofwhibyl1 - - - - - - - #botbus - - - - - #botbus - - John Madden + True @@ -83,6 +58,9 @@ 0 + + 0 + diff --git a/TGServerService/Byond.cs b/TGServerService/Byond.cs index 8da6773b1f..e8c4646fab 100644 --- a/TGServerService/Byond.cs +++ b/TGServerService/Byond.cs @@ -163,7 +163,7 @@ namespace TGServerService var vi = (VersionInfo)param; using (var client = new WebClient()) { - SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", vi.major, vi.minor)); + SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", vi.major, vi.minor), ChatMessageType.DeveloperInfo); //DOWNLOADING @@ -173,7 +173,7 @@ namespace TGServerService } catch { - SendMessage("BYOND: Update download failed. Does the specified version exist?"); + SendMessage("BYOND: Update download failed. Does the specified version exist?", ChatMessageType.DeveloperInfo); lastError = String.Format("Download of BYOND version {0}.{1} failed! Does it exist?", vi.major, vi.minor); TGServerService.WriteWarning(String.Format("Failed to update BYOND to version {0}.{1}!", vi.major, vi.minor), TGServerService.EventID.BYONDUpdateFail); lock (ByondLock) @@ -216,7 +216,7 @@ namespace TGServerService default: RequestRestart(); lastError = "Update staged. Awaiting server restart..."; - SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", vi.major, vi.minor)); + SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", vi.major, vi.minor), ChatMessageType.DeveloperInfo); TGServerService.WriteInfo(String.Format("BYOND update {0}.{1} staged", vi.major, vi.minor), TGServerService.EventID.BYONDUpdateStaged); break; } @@ -273,14 +273,14 @@ namespace TGServerService Directory.Move(StagingDirectoryInner, ByondDirectory); Program.DeleteDirectory(StagingDirectory); lastError = null; - SendMessage("BYOND: Update completed!"); + SendMessage("BYOND: Update completed!", ChatMessageType.DeveloperInfo); TGServerService.WriteInfo(String.Format("BYOND update {0} completed!", GetVersion(TGByondVersion.Installed)), TGServerService.EventID.BYONDUpdateComplete); return true; } catch (Exception e) { lastError = e.ToString(); - SendMessage("BYOND: Update failed!"); + SendMessage("BYOND: Update failed!", ChatMessageType.DeveloperInfo); TGServerService.WriteError("BYOND update failed!", TGServerService.EventID.BYONDUpdateFail); return false; } diff --git a/TGServerService/Chat.cs b/TGServerService/Chat.cs index ebab10ca2c..f858a468d5 100644 --- a/TGServerService/Chat.cs +++ b/TGServerService/Chat.cs @@ -1,26 +1,58 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Security.Cryptography; using System.Text; using System.Web.Script.Serialization; using TGServiceInterface; namespace TGServerService { - interface ITGChatProvider : ITGChatBase, IDisposable + /// + /// Type of chat message, these may be OR'd together + /// + [Flags] + enum ChatMessageType { + AdminInfo = 1, + GameInfo = 2, + WatchdogInfo = 4, + DeveloperInfo = 8, + } + interface ITGChatProvider : IDisposable + { + /// + /// Sets info for the provider + /// + /// The info to set + /// null on success, error message on failure + string SetProviderInfo(TGChatSetupInfo info); + + /// + /// Gets the info of the provider + /// + /// The info for the chat provider + TGChatSetupInfo ProviderInfo(); + /// /// Called with chat message info /// event OnChatMessage OnChatMessage; /// - /// Connects the chat provider + /// Connects the chat provider if it's enabled /// /// null on success, error message on failure string Connect(); + /// + /// Forces a reconnection of the chat provider if it's enabled + /// + /// null on success, error message on failure + string Reconnect(); + + /// + /// Checks if the chat provider is connected + /// + /// true if the provider is connected, false otherwise + bool Connected(); /// /// Disconnects the chat provider @@ -34,72 +66,70 @@ namespace TGServerService /// The channel to send to /// null on success, error message on failure string SendMessageDirect(string message, string channel); + + /// + /// Broadcast a message to appropriate channels based on the message type + /// + /// The message to send + /// The message type + void SendMessage(string msg, ChatMessageType mt); } /// /// Callback for the chat provider recieving a message /// + /// The chat provider the message came from /// The username of the speaker /// The name of the channel /// The message text /// true if the bot was mentioned in the first word, false otherwise - public delegate void OnChatMessage(string speaker, string channel, string message, bool tagged); + delegate void OnChatMessage(ITGChatProvider ChatProvider, string speaker, string channel, string message, bool isAdmin, bool isAdminChannel); partial class TGStationServer : ITGChat { - ITGChatProvider ChatProvider; - TGChatProvider currentProvider; + + IList ChatProviders; object ChatLock = new object(); - public void InitChat(TGChatSetupInfo info = null) + public void InitChat() { - if (info == null) - info = ProviderInfo(); - currentProvider = info.Provider; - try + var infos = InitProviderInfos(); + ChatProviders = new List(infos.Count); + foreach (var info in infos) { - switch (info.Provider) + ITGChatProvider ChatProvider; + try { - case TGChatProvider.Discord: - ChatProvider = new TGDiscordChatProvider(info); - break; - case TGChatProvider.IRC: - ChatProvider = new TGIRCChatProvider(info); - break; - default: - TGServerService.WriteError(String.Format("Invalid chat provider: {0}", info.Provider), TGServerService.EventID.InvalidChatProvider); - break; + switch (info.Provider) + { + case TGChatProvider.Discord: + ChatProvider = new TGDiscordChatProvider(info); + break; + case TGChatProvider.IRC: + ChatProvider = new TGIRCChatProvider(info); + break; + default: + TGServerService.WriteError(String.Format("Invalid chat provider: {0}", info.Provider), TGServerService.EventID.InvalidChatProvider); + continue; + } } - } - catch (Exception e) - { - TGServerService.WriteError(String.Format("Failed to start chat provider {0}! Error: {1}", info.Provider, e.ToString()), TGServerService.EventID.ChatProviderStartFail); - return; - } - ChatProvider.OnChatMessage += ChatProvider_OnChatMessage; - if (Properties.Settings.Default.ChatEnabled) - { + catch (Exception e) + { + TGServerService.WriteError(String.Format("Failed to start chat provider {0}! Error: {1}", info.Provider, e.ToString()), TGServerService.EventID.ChatProviderStartFail); + continue; + } + ChatProvider.OnChatMessage += ChatProvider_OnChatMessage; var res = ChatProvider.Connect(); if (res != null) TGServerService.WriteWarning(String.Format("Unable to connect to chat! Provider {0}, Error: {1}", ChatProvider.GetType().ToString(), res), TGServerService.EventID.ChatConnectFail); + ChatProviders.Add(ChatProvider); } } - private void ChatProvider_OnChatMessage(string speaker, string channel, string message, bool tagged) + private void ChatProvider_OnChatMessage(ITGChatProvider ChatProvider, string speaker, string channel, string message, bool isAdmin, bool isAdminChannel) { var splits = message.Trim().Split(' '); - - var s0l = splits[0].ToLower(); - - if (s0l == "!check") - { - ChatProvider.SendMessageDirect(StatusString(HasChatAdmin(speaker, channel) == null), channel); - return; - } - - if (!tagged) - return; - + if (splits.Length == 1 && splits[0] == "") { ChatProvider.SendMessageDirect("Hi!", channel); @@ -110,37 +140,48 @@ namespace TGServerService var command = asList[0].ToLower(); asList.RemoveAt(0); - ChatProvider.SendMessageDirect(ChatCommand(command, speaker, channel, asList), channel); + ChatProvider.SendMessageDirect(ChatCommand(command, speaker, channel, asList, isAdmin, isAdminChannel), channel); } - string HasChatAdmin(string speaker, string channel) + string HasChatAdmin(bool isAdmin, bool isAdminChannel) { - var Config = Properties.Settings.Default; - if (!Config.ChatAdmins.Contains(speaker.ToLower())) + if (!isAdmin) return "You are not authorized to use that command!"; - if (channel.ToLower() != Config.ChatAdminChannel.ToLower()) - return "Use this command in the admin channel!"; + if (!isAdminChannel) + return "Use this command in an admin channel!"; return null; } - //cleanup + //cleanup and save void DisposeChat() { - if (ChatProvider != null) + var infosList = new List>(); + + foreach (var ChatProvider in ChatProviders) { + infosList.Add(ChatProvider.ProviderInfo().DataFields); ChatProvider.Dispose(); - ChatProvider = null; } + ChatProviders = null; + + var rawdata = new JavaScriptSerializer().Serialize(infosList); + var Config = Properties.Settings.Default; + + byte[] plaintext = Encoding.UTF8.GetBytes(rawdata); + + Config.ChatProviderData = Program.EncryptData(plaintext, out string entrp); + Config.ChatProviderEntropy = entrp; } //Do stuff with words that were spoken to us - string ChatCommand(string command, string speaker, string channel, IList parameters) + string ChatCommand(string command, string speaker, string channel, IList parameters, bool isAdmin, bool isAdminChannel) { TGServerService.WriteInfo(String.Format("Chat Command from {0}: {1} {2}", speaker, command, String.Join(" ", parameters)), TGServerService.EventID.ChatCommand); + var adminmessage = HasChatAdmin(isAdmin, isAdminChannel); switch (command) { case "check": - return StatusString(HasChatAdmin(speaker, channel) == null); + return StatusString(adminmessage == null); case "byond": if (parameters.Count > 0) if (parameters[0].ToLower() == "--staged") @@ -149,27 +190,25 @@ namespace TGServerService return GetVersion(TGByondVersion.Latest) ?? "Unknown"; return GetVersion(TGByondVersion.Staged) ?? "Uninstalled"; case "status": - return HasChatAdmin(speaker, channel) ?? SendCommand(SCIRCStatus); + return adminmessage ?? SendCommand(SCIRCStatus); case "adminwho": - return HasChatAdmin(speaker, channel) ?? SendCommand(SCAdminWho); + return adminmessage ?? SendCommand(SCAdminWho); case "ahelp": - var res = HasChatAdmin(speaker, channel); - if (res != null) - return res; + if (adminmessage != null) + return adminmessage; if (parameters.Count < 2) return "Usage: ahelp "; var ckey = parameters[0]; parameters.RemoveAt(0); return SendPM(ckey, speaker, String.Join(" ", parameters)); case "namecheck": - res = HasChatAdmin(speaker, channel); - if (res != null) - return res; + if (adminmessage != null) + return adminmessage; if (parameters.Count < 1) return "Usage: namecheck "; return NameCheck(parameters[0], speaker); case "prs": - var PRs = MergedPullRequests(out res); + var PRs = MergedPullRequests(out string res); if (PRs == null) return res; if (PRs.Count == 0) @@ -186,100 +225,34 @@ namespace TGServerService return "Unknown command: " + command; } - //public api - public string SetEnabled(bool enable) + public IList ProviderInfos() { - lock (ChatLock) - { - Properties.Settings.Default.ChatEnabled = enable; - if (!enable && Connected()) - ChatProvider.Disconnect(); - else if (enable && !Connected()) - return ChatProvider != null ? ChatProvider.Connect() : "Null chat provider!"; - return null; - } + var infosList = new List(); + foreach (var ChatProvider in ChatProviders) + infosList.Add(ChatProvider.ProviderInfo()); + return infosList; } //public api - public string[] Channels() - { - lock (ChatLock) - { - return CollectionToArray(Properties.Settings.Default.ChatChannels); - } - } - - //what it says on the tin - string[] CollectionToArray(StringCollection sc) - { - string[] strArray = new string[sc.Count]; - sc.CopyTo(strArray, 0); - return strArray; - } - //public api - public string AdminChannel() - { - lock (ChatLock) - { - return Properties.Settings.Default.ChatAdminChannel; - } - } - //public api - public bool Enabled() - { - lock (ChatLock) - { - return Properties.Settings.Default.ChatEnabled; - } - } - - //public api - public string[] ListAdmins() - { - lock (ChatLock) - { - return CollectionToArray(Properties.Settings.Default.ChatAdmins); - } - } - - //public api - public void SetAdmins(string[] admins) - { - var si = new StringCollection(); - foreach (var I in admins) - si.Add(I.Trim().ToLower()); - lock (ChatLock) - { - Properties.Settings.Default.ChatAdmins = si; - } - } - - //public api - public TGChatSetupInfo ProviderInfo() + IList InitProviderInfos() { lock (ChatLock) { var Config = Properties.Settings.Default; var rawdata = Config.ChatProviderData; if (rawdata == "NEEDS INITIALIZING") - switch ((TGChatProvider)Config.ChatProvider) - { - case TGChatProvider.Discord: - return new TGDiscordSetupInfo(); - case TGChatProvider.IRC: - return new TGIRCSetupInfo(); - default: - TGServerService.WriteError("Invalid chat provider: " + Config.ChatProvider.ToString(), TGServerService.EventID.InvalidChatProvider); - return null; - } + return new List() { new TGIRCSetupInfo(), new TGDiscordSetupInfo() }; byte[] plaintext; try { - plaintext = ProtectedData.Unprotect(Convert.FromBase64String(Config.ChatProviderData), Convert.FromBase64String(Config.ChatProviderEntropy), DataProtectionScope.CurrentUser); - - var Deserializer = new JavaScriptSerializer(); - return new TGChatSetupInfo(Deserializer.Deserialize>(Encoding.UTF8.GetString(plaintext)), (TGChatProvider)Config.ChatProvider); + plaintext = Program.DecryptData(rawdata, Config.ChatProviderEntropy); + + var lists = new JavaScriptSerializer().Deserialize>>(Encoding.UTF8.GetString(plaintext)); + var output = new List(lists.Count); + foreach (var l in lists) + output.Add(new TGChatSetupInfo(l)); + return output; } catch { @@ -287,7 +260,7 @@ namespace TGServerService } } //if we get here we want to retry - return ProviderInfo(); + return InitProviderInfos(); } //public api @@ -297,34 +270,10 @@ namespace TGServerService { lock (ChatLock) { - var Serializer = new JavaScriptSerializer(); - var rawdata = Serializer.Serialize(info.DataFields); - var Config = Properties.Settings.Default; - Config.ChatProvider = (int)info.Provider; - Config.ChatProviderData = rawdata; - - byte[] plaintext = Encoding.UTF8.GetBytes(rawdata); - - // Generate additional entropy (will be used as the Initialization vector) - byte[] entropy = new byte[20]; - using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) - { - rng.GetBytes(entropy); - } - - byte[] ciphertext = ProtectedData.Protect(plaintext, entropy, DataProtectionScope.CurrentUser); - - Config.ChatProviderEntropy = Convert.ToBase64String(entropy, 0, entropy.Length); - Config.ChatProviderData = Convert.ToBase64String(ciphertext, 0, ciphertext.Length); - - if (ChatProvider != null && info.Provider == currentProvider) - return ChatProvider.SetProviderInfo(info); - else - { - DisposeChat(); - InitChat(info); - return null; - } + foreach (var ChatProvider in ChatProviders) + if (info.Provider == ChatProvider.ProviderInfo().Provider) + return ChatProvider.SetProviderInfo(info); + return "Error: Invalid provider: " + info.Provider.ToString(); } } catch (Exception e) @@ -333,75 +282,41 @@ namespace TGServerService } } - //trims and adds the leading # - string SanitizeChannelName(string working) + //public api + public bool Connected(TGChatProvider providerType) { - if (String.IsNullOrWhiteSpace(working)) - return null; - working = working.Trim(); - if (working[0] != '#') - return "#" + working; - return working; + foreach (var I in ChatProviders) + if (I.ProviderInfo().Provider == providerType) + return I.Connected(); + return false; } //public api - public void SetChannels(string[] channels = null, string adminchannel = null) + public string Reconnect(TGChatProvider providerType) + { + foreach (var I in ChatProviders) + if (I.ProviderInfo().Provider == providerType) + return I.Reconnect(); + return "Could not find specified provider!"; + } + + /// + /// Broadcast a message to appropriate channels based on the message type + /// + /// The message to send + /// The message type + public void SendMessage(string msg, ChatMessageType mt) { - var Config = Properties.Settings.Default; lock (ChatLock) { - if (channels != null) - { - var oldchannels = Config.ChatChannels; - var si = new StringCollection(); - foreach (var c in channels) + foreach (var ChatProvider in ChatProviders) + try { - var Res = SanitizeChannelName(c); - if (Res != null) - si.Add(Res); + ChatProvider.SendMessage(msg, mt); + }catch(Exception e) + { + TGServerService.WriteWarning(String.Format("Chat broadcast failed (Provider: {3}) (Flags: {0}) (Message: {1}): {2}", mt, msg, e.ToString(), ChatProvider.ProviderInfo().Provider), TGServerService.EventID.ChatBroadcastFail); } - if (!si.Contains(Config.ChatAdminChannel)) - si.Add(Config.ChatAdminChannel); - Config.ChatChannels = si; - } - adminchannel = SanitizeChannelName(adminchannel); - if (adminchannel != null) - { - Config.ChatAdminChannel = adminchannel; - if (!Config.ChatChannels.Contains(adminchannel)) - Config.ChatChannels.Add(adminchannel); - } - if (channels != null && Connected()) - ChatProvider.SetChannels(CollectionToArray(Config.ChatChannels), Config.ChatAdminChannel); - } - } - - //public api - public bool Connected() - { - lock (ChatLock) - { - return ChatProvider != null ? ChatProvider.Connected() : false; - } - } - - //public api - public string Reconnect() - { - lock (ChatLock) - { - if (!Properties.Settings.Default.ChatEnabled) - return "Chat is disabled!"; - return ChatProvider != null ? ChatProvider.Reconnect() : "Null chat provider!"; - } - } - - //public api - public string SendMessage(string msg, bool adminOnly = false) - { - lock (ChatLock) - { - return ChatProvider != null ? ChatProvider.SendMessage(msg, adminOnly) : "Null chat provider!"; } } } diff --git a/TGServerService/Compiler.cs b/TGServerService/Compiler.cs index 9260d9453a..57760fd066 100644 --- a/TGServerService/Compiler.cs +++ b/TGServerService/Compiler.cs @@ -179,7 +179,7 @@ namespace TGServerService } try { - SendMessage("DM: Setting up symlinks..."); + SendMessage("DM: Setting up symlinks...", ChatMessageType.DeveloperInfo); CleanGameFolder(); Program.DeleteDirectory(GameDir); @@ -211,7 +211,7 @@ namespace TGServerService { lock (CompilerLock) { - SendMessage("DM: Setup failed!"); + SendMessage("DM: Setup failed!", ChatMessageType.DeveloperInfo); lastCompilerError = e.ToString(); compilerCurrentStatus = TGCompilerStatus.Uninitialized; return; @@ -301,7 +301,7 @@ namespace TGServerService } if(!silent) - SendMessage("DM: Compiling..."); + SendMessage("DM: Compiling...", ChatMessageType.DeveloperInfo); var resurrectee = GetStagingDir(); @@ -331,7 +331,7 @@ namespace TGServerService if (repobusy_check) { - SendMessage("DM: Copy aborted, repo locked!"); + SendMessage("DM: Copy aborted, repo locked!", ChatMessageType.DeveloperInfo); lock (CompilerLock) { lastCompilerError = "The repo could not be locked for copying"; @@ -368,7 +368,7 @@ namespace TGServerService if (!File.Exists(dmePath)) { var errorMsg = String.Format("Could not find {0}!", dmeName); - SendMessage("DM: " + errorMsg); + SendMessage("DM: " + errorMsg, ChatMessageType.DeveloperInfo); TGServerService.WriteError(errorMsg, TGServerService.EventID.DMCompileCrash); lock (CompilerLock) { @@ -464,7 +464,7 @@ namespace TGServerService } var staged = DaemonStatus() != TGDreamDaemonStatus.Offline; var msg = String.Format("Compile complete!{0}", !staged ? "" : " Server will update next round."); - SendMessage("DM: " + msg); + SendMessage("DM: " + msg, ChatMessageType.DeveloperInfo); TGServerService.WriteInfo(msg, TGServerService.EventID.DMCompileSuccess); lock (CompilerLock) { @@ -476,7 +476,7 @@ namespace TGServerService } else { - SendMessage("DM: Compile failed!"); //Also happens for warnings + SendMessage("DM: Compile failed!", ChatMessageType.DeveloperInfo); //Also happens for warnings TGServerService.WriteWarning("Compile error: " + OutputList.ToString(), TGServerService.EventID.DMCompileError); lock (CompilerLock) { @@ -493,7 +493,7 @@ namespace TGServerService } catch (Exception e) { - SendMessage("DM: Compiler thread crashed!"); + SendMessage("DM: Compiler thread crashed!", ChatMessageType.DeveloperInfo); TGServerService.WriteError("Compile manager errror: " + e.ToString(), TGServerService.EventID.DMCompileCrash); lock (CompilerLock) { @@ -510,7 +510,7 @@ namespace TGServerService { compilerCurrentStatus = TGCompilerStatus.Initialized; compilationCancellationRequestation = false; - SendMessage("DM: Compile cancelled!"); + SendMessage("DM: Compile cancelled!", ChatMessageType.DeveloperInfo); TGServerService.WriteInfo("Compilation cancelled", TGServerService.EventID.DMCompileCancel); } } diff --git a/TGServerService/Discord.cs b/TGServerService/Discord.cs index 95460ec379..a1e5f1ee4d 100644 --- a/TGServerService/Discord.cs +++ b/TGServerService/Discord.cs @@ -1,6 +1,7 @@ using Discord; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using TGServiceInterface; @@ -20,6 +21,11 @@ namespace TGServerService Init(info); } + public TGChatSetupInfo ProviderInfo() + { + return DiscordConfig; + } + void Init(TGChatSetupInfo info) { DiscordConfig = new TGDiscordSetupInfo(info); @@ -27,29 +33,50 @@ namespace TGServerService client.MessageReceived += Client_MessageReceived; } + private bool CheckAdmin(User u) + { + if (!DiscordConfig.AdminsAreSpecial) + return DiscordConfig.AdminList.Contains(u.Id.ToString()); + foreach (var I in u.Roles) + if (DiscordConfig.AdminList.Contains(I.Id.ToString())) + return true; + return false; + } + private void Client_MessageReceived(object sender, MessageEventArgs e) { - var isValidChannel = Properties.Settings.Default.ChatChannels.Contains("#" + e.Channel.Name) || e.Channel.IsPrivate; - if (!isValidChannel) - return; - - var tagged = e.Channel.IsPrivate && e.User.Id != client.CurrentUser.Id; - if (tagged && !SeenPrivateChannels.ContainsKey(e.Channel.Id)) + var pm = e.Channel.IsPrivate && e.User.Id != client.CurrentUser.Id; + + if (pm && !SeenPrivateChannels.ContainsKey(e.Channel.Id)) SeenPrivateChannels.Add(e.Channel.Id, e.Channel); - var splits = new List(e.Message.Text.Trim().Split(' ')); - if (splits[0] == "@" + client.CurrentUser.Name) - { - splits.RemoveAt(0); - tagged = true; - } - OnChatMessage(e.User.Id.ToString(), e.Channel.Id.ToString(), String.Join(" ", splits), tagged); + bool found = false; + + var formattedMessage = e.Message.RawText; + foreach (var u in e.Message.MentionedUsers) + if(u.Id == client.CurrentUser.Id) + { + found = true; + formattedMessage = formattedMessage.Replace(u.Mention, ""); + break; + } + + if (!found && !pm) + return; + + formattedMessage = formattedMessage.Trim(); + + var cid = e.Channel.Id.ToString(); + + OnChatMessage(this, e.User.Id.ToString(), cid, formattedMessage, CheckAdmin(e.User), pm || DiscordConfig.AdminChannels.Contains(cid)); } public string Connect() { try { + if (Connected() || !DiscordConfig.Enabled) + return null; lock (DiscordLock) { SeenPrivateChannels.Clear(); @@ -105,35 +132,36 @@ namespace TGServerService } } - public string SendMessage(string msg, bool adminOnly = false) + public void SendMessage(string msg, ChatMessageType mt) { - try + if (!Connected()) + return; + lock (DiscordLock) { - lock (DiscordLock) - { - var tasks = new List(); - var Config = Properties.Settings.Default; - foreach (var I in client.Servers) - foreach (var J in I.TextChannels) - { - var SendToThisChannel = adminOnly ? ("#" + J.Name) == Config.ChatAdminChannel : Config.ChatChannels.Contains("#" + J.Name); - if (SendToThisChannel) - tasks.Add(J.SendMessage(msg)); - } - foreach (var I in tasks) - I.Wait(); - TGServerService.WriteInfo(String.Format("Discord Send{0}: {1}", adminOnly ? " (ADMIN)" : "", msg), adminOnly ? TGServerService.EventID.ChatAdminBroadcast : TGServerService.EventID.ChatBroadcast); - return null; - } - } - catch (Exception e) - { - return e.ToString(); + var tasks = new List(); + var Config = Properties.Settings.Default; + foreach (var I in client.Servers) + foreach (var J in I.TextChannels) + { + var cid = J.Id.ToString(); + var wdc = DiscordConfig.WatchdogChannels; + bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && DiscordConfig.AdminChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.DeveloperInfo) && DiscordConfig.DevChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.GameInfo) && DiscordConfig.GameChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.WatchdogInfo) && DiscordConfig.WatchdogChannels.Contains(cid)); + + if (SendToThisChannel) + tasks.Add(J.SendMessage(msg)); + } + foreach (var I in tasks) + I.Wait(); } } public string SendMessageDirect(string message, string channelname) { + if (!Connected()) + return "Disconnected."; try { lock (DiscordLock) @@ -157,12 +185,6 @@ namespace TGServerService return e.ToString(); } } - - public void SetChannels(string[] channels = null, string adminchannel = null) - { - //noop - } - void DisconnectAndDispose() { try @@ -181,10 +203,20 @@ namespace TGServerService { lock (DiscordLock) { - DisconnectAndDispose(); - Init(info); - if (Properties.Settings.Default.ChatEnabled) - Connect(); + var odc = DiscordConfig; + DiscordConfig = new TGDiscordSetupInfo(info); + if (DiscordConfig.BotToken != odc.BotToken) + { + DisconnectAndDispose(); + Init(info); + } + if (DiscordConfig.Enabled) + { + if (!Connected()) + return Reconnect(); + } + else + Disconnect(); } return null; } diff --git a/TGServerService/DreamDaemon.cs b/TGServerService/DreamDaemon.cs index dd59f39f14..47bbd4a645 100644 --- a/TGServerService/DreamDaemon.cs +++ b/TGServerService/DreamDaemon.cs @@ -46,7 +46,7 @@ namespace TGServerService if (Proc == null) throw new Exception("GetProcessById returned null!"); TGServerService.WriteInfo("Reattached to running DD process!", TGServerService.EventID.DDReattachSuccess); - SendMessage("DD: Update complete. Watch dog reactivated..."); + SendMessage("DD: Update complete. Watch dog reactivated...", ChatMessageType.WatchdogInfo); //start wd InitInterop(); @@ -93,7 +93,7 @@ namespace TGServerService Thread.Sleep(1000); } else - SendMessage("DD: Detaching watch dog for update!"); + SendMessage("DD: Detaching watch dog for update!", ChatMessageType.WatchdogInfo); } else if (Detach) { @@ -184,7 +184,7 @@ namespace TGServerService return "Restart already in progress"; try { - SendMessage("DD: Hard restart triggered"); + SendMessage("DD: Hard restart triggered", ChatMessageType.WatchdogInfo); RestartInProgress = true; Stop(); var res = Start(); @@ -206,7 +206,7 @@ namespace TGServerService { if (!RestartInProgress) { - SendMessage("DD: Server started, watchdog active..."); + SendMessage("DD: Server started, watchdog active...", ChatMessageType.WatchdogInfo); TGServerService.WriteInfo("Watchdog started", TGServerService.EventID.DDWatchdogStarted); } else @@ -242,14 +242,14 @@ namespace TGServerService { ++retries; var sleep_time = (int)Math.Min(Math.Pow(2, retries), 3600); //max of one hour - SendMessage(String.Format("DD: Watchdog server startup failed! Retrying in {0} seconds...", sleep_time)); + SendMessage(String.Format("DD: Watchdog server startup failed! Retrying in {0} seconds...", sleep_time), ChatMessageType.WatchdogInfo); Thread.Sleep(sleep_time * 1000); } else { retries = 0; var msg = "DD: DreamDaemon crashed! Watchdog rebooting DD..."; - SendMessage(msg); + SendMessage(msg, ChatMessageType.WatchdogInfo); TGServerService.WriteWarning(msg, TGServerService.EventID.DDWatchdogRebootingServer); } } @@ -280,7 +280,7 @@ namespace TGServerService } catch (Exception e) { - SendMessage("DD: Watchdog thread crashed!"); + SendMessage("DD: Watchdog thread crashed!", ChatMessageType.WatchdogInfo); TGServerService.WriteError("Watch dog thread crashed: " + e.ToString(), TGServerService.EventID.DDWatchdogCrash); } finally @@ -292,7 +292,7 @@ namespace TGServerService AwaitingShutdown = ShutdownRequestPhase.None; if (!RestartInProgress) { - SendMessage("DD: Server stopped, watchdog exiting..."); + SendMessage("DD: Server stopped, watchdog exiting...", ChatMessageType.WatchdogInfo); TGServerService.WriteInfo("Watch dog exited", TGServerService.EventID.DDWatchdogExit); } else diff --git a/TGServerService/IRC.cs b/TGServerService/IRC.cs index d6016aef35..3c651e79f3 100644 --- a/TGServerService/IRC.cs +++ b/TGServerService/IRC.cs @@ -11,7 +11,6 @@ namespace TGServerService { const string PrivateMessageMarker = "---PRIVATE-MSG---"; IrcFeatures irc; - int reconnectAttempt = 0; object IRCLock = new object(); @@ -19,15 +18,30 @@ namespace TGServerService public event OnChatMessage OnChatMessage; + public TGChatSetupInfo ProviderInfo() + { + return IRCConfig; + } + public TGIRCChatProvider(TGChatSetupInfo info) { IRCConfig = new TGIRCSetupInfo(info); - irc = new IrcFeatures() { SupportNonRfc = true }; + irc = new IrcFeatures() + { + SupportNonRfc = true, + CtcpUserInfo = TGServerService.Version, + AutoRejoin = true, + AutoRejoinOnKick = true, + AutoRelogin = true, + AutoRetry = true, + AutoRetryLimit = 5, + AutoRetryDelay = 5, + ActiveChannelSyncing = true, + }; irc.OnChannelMessage += Irc_OnChannelMessage; irc.OnQueryMessage += Irc_OnQueryMessage; - irc.CtcpUserInfo = TGServerService.Version; } - + //public api public string SendMessageDirect(string message, string channel) { @@ -55,32 +69,62 @@ namespace TGServerService var convertedInfo = (TGIRCSetupInfo)info; var serverChange = convertedInfo.URL != IRCConfig.URL || convertedInfo.Port != IRCConfig.Port; IRCConfig = convertedInfo; - if (serverChange) + if (!IRCConfig.Enabled) + { + Disconnect(); + return null; + } + else if (serverChange || !Connected()) return Reconnect(); - else if (convertedInfo.Nickname != irc.Nickname) + + if (IRCConfig.Nickname != irc.Nickname) irc.RfcNick(convertedInfo.Nickname); Login(); + JoinChannels(); return null; } - public void SetChannels(string[] channels = null, string adminchannel = null) + private bool CheckAdmin(IrcMessageData e) { - lock (IRCLock) { - var channelsList = new List(channels); - var Config = Properties.Settings.Default; - foreach (var I in irc.JoinedChannels) - if (!channelsList.Contains(I)) - irc.RfcPart(I); - foreach (var I in channelsList) - if (!irc.JoinedChannels.Contains(I)) - irc.RfcJoin(I); + if (IRCConfig.AdminsAreSpecial) + { + var Chan = irc.GetChannel(e.Channel); + var user = (NonRfcChannelUser)irc.GetChannelUser(e.Channel, e.Nick); + if (user != null) + switch (IRCConfig.AuthLevel) + { + case IRCMode.Voice: + if (user.IsVoice) + return true; + goto case IRCMode.Halfop; + case IRCMode.Halfop: + if (user.IsHalfop) + return true; + goto case IRCMode.Op; + case IRCMode.Op: + if (user.IsOp) + return true; + goto case IRCMode.Owner; + case IRCMode.Owner: + if (user.IsOwner) + return true; + break; + } } + else + { + var lowerNick = e.Nick.ToLower(); + foreach (var I in IRCConfig.AdminList) + if (lowerNick == I.ToLower()) + return true; + } + return false; } //private message private void Irc_OnQueryMessage(object sender, IrcEventArgs e) { - OnChatMessage(e.Data.Nick, e.Data.Nick + PrivateMessageMarker, e.Data.Message, true); + OnChatMessage(this, e.Data.Nick, e.Data.Nick + PrivateMessageMarker, e.Data.Message, CheckAdmin(e.Data), true); } private void Irc_OnChannelMessage(object sender, IrcEventArgs e) @@ -91,20 +135,33 @@ namespace TGServerService var test = splits[0]; if (test.Length > 1 && test[test.Length - 1] == ':') test = test.Substring(0, test.Length - 1); - var tagged = test.ToLower() == irc.Nickname.ToLower(); + if (test.ToLower() != irc.Nickname.ToLower()) + return; - if (tagged) - { - splits.RemoveAt(0); - formattedMessage = String.Join(" ", splits); - } + splits.RemoveAt(0); + formattedMessage = String.Join(" ", splits); - OnChatMessage(e.Data.Nick, e.Data.Channel, formattedMessage, tagged); + OnChatMessage(this, e.Data.Nick, e.Data.Channel, formattedMessage, CheckAdmin(e.Data), IRCConfig.AdminChannels.Contains(e.Data.Channel.ToLower())); } //Joins configured channels void JoinChannels() { - foreach (var I in Properties.Settings.Default.ChatChannels) + var hs = new HashSet(); //for unique inserts + foreach (var I in IRCConfig.AdminChannels) + hs.Add(I); + foreach (var I in IRCConfig.DevChannels) + hs.Add(I); + foreach (var I in IRCConfig.GameChannels) + hs.Add(I); + foreach (var I in IRCConfig.WatchdogChannels) + hs.Add(I); + var ToPart = new List(); + foreach (var I in irc.JoinedChannels) + if (!hs.Remove(I)) + ToPart.Add(I); + foreach (var I in ToPart) + irc.RfcPart(I); + foreach (var I in hs) irc.RfcJoin(I); } //runs the login command @@ -119,7 +176,7 @@ namespace TGServerService //public api public string Connect() { - if (Connected()) + if (Connected() || !IRCConfig.Enabled) return null; lock (IRCLock) { @@ -128,20 +185,10 @@ namespace TGServerService try { irc.Connect(IRCConfig.URL, IRCConfig.Port); - reconnectAttempt = 0; } catch (Exception e) { - reconnectAttempt++; - if (reconnectAttempt <= 5) - { - Thread.Sleep(5000); //Reconnecting after 5 seconds. - return Connect(); - } - else - { - return "IRC server unreachable: " + e.ToString(); - } + return "IRC server unreachable: " + e.ToString(); } try @@ -154,6 +201,7 @@ namespace TGServerService } Login(); JoinChannels(); + new Thread(new ThreadStart(IRCListen)) { IsBackground = true }.Start(); return null; } @@ -210,27 +258,21 @@ namespace TGServerService } } //public api - public string SendMessage(string message, bool adminOnly) + public void SendMessage(string message, ChatMessageType mt) { - try + if (!Connected()) + return; + lock (IRCLock) { - if (!Connected()) - return "Disconnected."; - lock (IRCLock) + foreach (var cid in irc.JoinedChannels) { - var Config = Properties.Settings.Default; - if (adminOnly) - irc.SendMessage(SendType.Message, Config.ChatAdminChannel, message); - else - foreach (var I in Config.ChatChannels) - irc.SendMessage(SendType.Message, I, message); + bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && IRCConfig.AdminChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.DeveloperInfo) && IRCConfig.DevChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.GameInfo) && IRCConfig.GameChannels.Contains(cid)) + || (mt.HasFlag(ChatMessageType.WatchdogInfo) && IRCConfig.WatchdogChannels.Contains(cid)); + if (SendToThisChannel) + irc.SendMessage(SendType.Message, cid, message); } - TGServerService.WriteInfo(String.Format("IRC Send{0}: {1}", adminOnly ? " (ADMIN)" : "", message), adminOnly ? TGServerService.EventID.ChatAdminBroadcast : TGServerService.EventID.ChatBroadcast); - return null; - } - catch (Exception e) - { - return e.ToString(); } } diff --git a/TGServerService/Interop.cs b/TGServerService/Interop.cs index c1d503875f..fcfe195526 100644 --- a/TGServerService/Interop.cs +++ b/TGServerService/Interop.cs @@ -45,13 +45,13 @@ namespace TGServerService switch (cmd) { case SRIRCBroadcast: - SendMessage("GAME: " + String.Join(" ", splits)); + SendMessage("GAME: " + String.Join(" ", splits), ChatMessageType.GameInfo); break; case SRKillProcess: KillMe(); break; case SRIRCAdminChannelMessage: - SendMessage("RELAY: " + String.Join(" ", splits), true); + SendMessage("RELAY: " + String.Join(" ", splits), ChatMessageType.AdminInfo); break; case SRWorldReboot: TGServerService.WriteInfo("World Rebooted", TGServerService.EventID.WorldReboot); diff --git a/TGServerService/Program.cs b/TGServerService/Program.cs index 1bf86f3d78..922ab55e7d 100644 --- a/TGServerService/Program.cs +++ b/TGServerService/Program.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.IO; +using System.Security.Cryptography; +using System.Text; namespace TGServerService { @@ -45,6 +47,24 @@ namespace TGServerService } } + public static string EncryptData(byte[] data, out string sentropy) + { + // Generate additional entropy (will be used as the Initialization vector) + byte[] entropy = new byte[20]; + using (var rng = new RNGCryptoServiceProvider()) + rng.GetBytes(entropy); + + byte[] ciphertext = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser); + + sentropy = Convert.ToBase64String(entropy, 0, entropy.Length); + return Convert.ToBase64String(ciphertext, 0, ciphertext.Length); + } + + public static byte[] DecryptData(string data, string entropy) + { + return ProtectedData.Unprotect(Convert.FromBase64String(data), Convert.FromBase64String(entropy), DataProtectionScope.CurrentUser); + } + public static void CopyDirectory(string sourceDirName, string destDirName, IList ignore = null, bool ignoreIfNotExists = false) { // If the destination directory doesn't exist, create it. diff --git a/TGServerService/Properties/AssemblyInfo.cs b/TGServerService/Properties/AssemblyInfo.cs index 9e4dbb74f6..78203898f9 100644 --- a/TGServerService/Properties/AssemblyInfo.cs +++ b/TGServerService/Properties/AssemblyInfo.cs @@ -25,5 +25,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.85.4")] -[assembly: AssemblyFileVersion("3.0.85.4")] +[assembly: AssemblyVersion("3.0.86.0")] +[assembly: AssemblyFileVersion("3.0.86.0")] diff --git a/TGServerService/Properties/Settings.Designer.cs b/TGServerService/Properties/Settings.Designer.cs index 1514726ce1..cd14ea9f18 100644 --- a/TGServerService/Properties/Settings.Designer.cs +++ b/TGServerService/Properties/Settings.Designer.cs @@ -119,18 +119,6 @@ namespace TGServerService.Properties { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("False")] - public bool ChatEnabled { - get { - return ((bool)(this["ChatEnabled"])); - } - set { - this["ChatEnabled"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("False")] @@ -155,18 +143,6 @@ namespace TGServerService.Properties { } } - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("0")] - public int ChatProvider { - get { - return ((int)(this["ChatProvider"])); - } - set { - this["ChatProvider"] = value; - } - } - [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("NEEDS INITIALIZING")] @@ -181,47 +157,7 @@ namespace TGServerService.Properties { [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n theghostofwhibyl1\r\n")] - public global::System.Collections.Specialized.StringCollection ChatAdmins { - get { - return ((global::System.Collections.Specialized.StringCollection)(this["ChatAdmins"])); - } - set { - this["ChatAdmins"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n #botbus\r\n")] - public global::System.Collections.Specialized.StringCollection ChatChannels { - get { - return ((global::System.Collections.Specialized.StringCollection)(this["ChatChannels"])); - } - set { - this["ChatChannels"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("#botbus")] - public string ChatAdminChannel { - get { - return ((string)(this["ChatAdminChannel"])); - } - set { - this["ChatAdminChannel"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("John Madden")] + [global::System.Configuration.DefaultSettingValueAttribute("")] public string ChatProviderEntropy { get { return ((string)(this["ChatProviderEntropy"])); @@ -278,5 +214,17 @@ namespace TGServerService.Properties { this["ReattachPort"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int SettingsVersion { + get { + return ((int)(this["SettingsVersion"])); + } + set { + this["SettingsVersion"] = value; + } + } } } diff --git a/TGServerService/Properties/Settings.settings b/TGServerService/Properties/Settings.settings index 670bc0fd77..2500ddda3c 100644 --- a/TGServerService/Properties/Settings.settings +++ b/TGServerService/Properties/Settings.settings @@ -26,38 +26,17 @@ 2 - - False - False C:\Python27 - - 0 - NEEDS INITIALIZING - - <?xml version="1.0" encoding="utf-16"?> -<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - <string>theghostofwhibyl1</string> -</ArrayOfString> - - - <?xml version="1.0" encoding="utf-16"?> -<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - <string>#botbus</string> -</ArrayOfString> - - - #botbus - - John Madden + True @@ -71,5 +50,8 @@ 0 + + 0 + \ No newline at end of file diff --git a/TGServerService/Repository.cs b/TGServerService/Repository.cs index 23c2fa33ca..f7ac4f842a 100644 --- a/TGServerService/Repository.cs +++ b/TGServerService/Repository.cs @@ -113,7 +113,7 @@ namespace TGServerService var BranchName = ts.b; try { - SendMessage(String.Format("REPO: {2} started: Cloning {0} branch of {1} ...", BranchName, RepoURL, Repository.IsValid(RepoPath) ? "Full reset" : "Setup")); + SendMessage(String.Format("REPO: {2} started: Cloning {0} branch of {1} ...", BranchName, RepoURL, Repository.IsValid(RepoPath) ? "Full reset" : "Setup"), ChatMessageType.DeveloperInfo); try { DisposeRepo(); @@ -161,7 +161,7 @@ namespace TGServerService } Program.CopyDirectory(RepoData, StaticDataDir, null, true); File.Copy(RepoPath + LibMySQLFile, StaticDirs + LibMySQLFile, true); - SendMessage("REPO: Clone complete!"); + SendMessage("REPO: Clone complete!", ChatMessageType.DeveloperInfo); TGServerService.WriteInfo("Repository {0}:{1} successfully cloned", TGServerService.EventID.RepoClone); } finally @@ -172,7 +172,7 @@ namespace TGServerService catch(Exception e) { - SendMessage("REPO: Setup failed!"); + SendMessage("REPO: Setup failed!", ChatMessageType.DeveloperInfo); TGServerService.WriteWarning(String.Format("Failed to clone {2}:{0}: {1}", BranchName, e.ToString(), RepoURL), TGServerService.EventID.RepoCloneFail); } finally @@ -297,7 +297,7 @@ namespace TGServerService var result = LoadRepo(); if (result != null) return result; - SendMessage("REPO: Checking out object: " + sha); + SendMessage("REPO: Checking out object: " + sha, ChatMessageType.DeveloperInfo); try { var Opts = new CheckoutOptions() @@ -307,13 +307,13 @@ namespace TGServerService }; Commands.Checkout(Repo, sha, Opts); var res = ResetNoLock(null); - SendMessage("REPO: Checkout complete!"); + SendMessage("REPO: Checkout complete!", ChatMessageType.DeveloperInfo); TGServerService.WriteInfo("Repo checked out " + sha, TGServerService.EventID.RepoCheckout); return res; } catch (Exception e) { - SendMessage("REPO: Checkout failed!"); + SendMessage("REPO: Checkout failed!", ChatMessageType.DeveloperInfo); TGServerService.WriteWarning(String.Format("Repo checkout of {0} failed: {1}", sha, e.ToString()), TGServerService.EventID.RepoCheckoutFail); return e.ToString(); } @@ -333,7 +333,7 @@ namespace TGServerService { case MergeStatus.Conflicts: ResetNoLock(null); - SendMessage("REPO: Merge conflicted, aborted."); + SendMessage("REPO: Merge conflicted, aborted.", ChatMessageType.DeveloperInfo); return "Merge conflict occurred."; case MergeStatus.UpToDate: return RepoErrorUpToDate; @@ -349,7 +349,7 @@ namespace TGServerService var result = LoadRepo(); if (result != null) return result; - SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge")); + SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge"), ChatMessageType.DeveloperInfo); try { if (Repo.Head == null || !Repo.Head.IsTracking) @@ -383,7 +383,7 @@ namespace TGServerService } catch (Exception E) { - SendMessage("REPO: Update failed!"); + SendMessage("REPO: Update failed!", ChatMessageType.DeveloperInfo); TGServerService.WriteWarning(String.Format("Repo{0} update failed", reset ? " hard" : ""), reset ? TGServerService.EventID.RepoHardUpdateFail : TGServerService.EventID.RepoMergeUpdateFail); return E.ToString(); } @@ -456,7 +456,7 @@ namespace TGServerService var res = LoadRepo() ?? ResetNoLock(trackedBranch ? (Repo.Head.TrackedBranch ?? Repo.Head) : Repo.Head); if (res == null) { - SendMessage(String.Format("REPO: Hard reset to {0}branch", trackedBranch ? "tracked " : "")); + SendMessage(String.Format("REPO: Hard reset to {0}branch", trackedBranch ? "tracked " : ""), ChatMessageType.DeveloperInfo); if (trackedBranch) DeletePRList(); TGServerService.WriteInfo(String.Format("Repo branch reset{0}", trackedBranch ? " to tracked branch" : ""), trackedBranch ? TGServerService.EventID.RepoResetTracked : TGServerService.EventID.RepoReset); @@ -518,7 +518,7 @@ namespace TGServerService var result = LoadRepo(); if (result != null) return result; - SendMessage(String.Format("REPO: {2}erging PR #{0}...", PRNumber, impliedUpdate ? "Test m" : "M")); + SendMessage(String.Format("REPO: {2}erging PR #{0}...", PRNumber, impliedUpdate ? "Test m" : "M"), ChatMessageType.DeveloperInfo); try { //only supported with github @@ -550,7 +550,7 @@ namespace TGServerService branch = Repo.Branches[LocalBranchName]; if (branch == null) { - SendMessage("REPO: PR could not be fetched. Does it exist?"); + SendMessage("REPO: PR could not be fetched. Does it exist?", ChatMessageType.DeveloperInfo); return String.Format("PR #{0} could not be fetched. Does it exist?", PRNumber); } @@ -600,7 +600,7 @@ namespace TGServerService } catch (Exception E) { - SendMessage("REPO: PR merge failed!"); + SendMessage("REPO: PR merge failed!", ChatMessageType.DeveloperInfo); TGServerService.WriteWarning(String.Format("Failed to merge pull request #{0}: {1}", PRNumber, E.ToString()), TGServerService.EventID.RepoPRMergeFail); return E.ToString(); } diff --git a/TGServerService/ServerService.cs b/TGServerService/ServerService.cs index 9c15118ef7..dd031462ce 100644 --- a/TGServerService/ServerService.cs +++ b/TGServerService/ServerService.cs @@ -40,7 +40,7 @@ namespace TGServerService DDWatchdogStarted = 2500, ChatSend = 2600, ChatBroadcast = 2700, - ChatAdminBroadcast = 2800, + //ChatAdminBroadcast = 2800, ChatDisconnectFail = 2900, TopicSent = 3000, TopicFailed = 3100, @@ -73,6 +73,8 @@ namespace TGServerService ServiceShutdownFail = 6100, WorldReboot = 6200, ServerUpdateApplied = 6300, + ChatBroadcastFail = 6400, + IRCLogModes = 6500, } static TGServerService ActiveService; //So everyone else can write to our eventlog @@ -92,7 +94,13 @@ namespace TGServerService ActiveService.EventLog.WriteEntry(message, EventLogEntryType.Warning, (int)id); } - ServiceHost host; //the WCF host + ServiceHost host; //the WCF host + + void MigrateSettings(int oldVersion, int newVersion) + { + if (oldVersion == newVersion && newVersion == 0) //chat refactor + Properties.Settings.Default.ChatProviderData = "NEEDS INITIALIZING"; //reset chat settings to be safe + } //you should seriously not add anything here //Use OnStart instead @@ -102,7 +110,12 @@ namespace TGServerService { if (Properties.Settings.Default.UpgradeRequired) { + var newVersion = Properties.Settings.Default.SettingsVersion; Properties.Settings.Default.Upgrade(); + var oldVersion = Properties.Settings.Default.SettingsVersion; + + MigrateSettings(oldVersion, newVersion); + Properties.Settings.Default.UpgradeRequired = false; Properties.Settings.Default.Save(); } diff --git a/TGServiceInstaller/Product.wxs b/TGServiceInstaller/Product.wxs index 7100010fa3..e1a8c494ab 100644 --- a/TGServiceInstaller/Product.wxs +++ b/TGServiceInstaller/Product.wxs @@ -1,6 +1,6 @@ - + diff --git a/TGServiceInterface/Chat.cs b/TGServiceInterface/Chat.cs index a6e2d35020..cd9b83e0a7 100644 --- a/TGServiceInterface/Chat.cs +++ b/TGServiceInterface/Chat.cs @@ -2,13 +2,14 @@ using System.Collections.Generic; using System.Runtime.Serialization; using System.ServiceModel; +using System.Web.Script.Serialization; namespace TGServiceInterface { /// /// The type of chat provider /// - public enum TGChatProvider + public enum TGChatProvider : int { /// /// IRC chat provider @@ -17,7 +18,30 @@ namespace TGServiceInterface /// /// Discord chat provider /// - Discord, + Discord = 1, + } + + /// + /// Supported irc permission modes + /// + public enum IRCMode : int + { + /// + /// + + /// + Voice, + /// + /// % + /// + Halfop, + /// + /// @ + /// + Op, + /// + /// ~ + /// + Owner, } /// @@ -28,6 +52,16 @@ namespace TGServiceInterface [KnownType(typeof(TGDiscordSetupInfo))] public class TGChatSetupInfo { + const int AdminListIndex = 0; + const int AdminModeIndex = 1; + const int AdminChannelIndex = 2; + const int DevChannelIndex = 3; + const int WDChannelIndex = 4; + const int GameChannelIndex = 5; + const int ProviderIndex = 6; + const int EnabledIndex = 7; + protected const int BaseIndex = 8; + protected readonly bool InitializeFields; /// /// Constructs a TGChatSetupInfo from optional past data /// @@ -35,10 +69,56 @@ namespace TGServiceInterface /// The number of fields in this chat provider protected TGChatSetupInfo(TGChatSetupInfo baseInfo, int numFields) { - DataFields = baseInfo != null ? baseInfo.DataFields : new List(numFields); - if (baseInfo == null) + numFields += BaseIndex; + InitializeFields = baseInfo == null || baseInfo.DataFields.Count != numFields; + + if (InitializeFields) + { + DataFields = new List(numFields); for (var I = 0; I < numFields; ++I) DataFields.Add(null); + + AdminList = new List(); + AdminChannels = new List(); + DevChannels = new List(); + GameChannels = new List(); + WatchdogChannels = new List(); + AdminsAreSpecial = false; + Enabled = false; + } + else + DataFields = baseInfo.DataFields; + } + + TGChatSetupInfo Specialize() + { + switch (Provider) + { + case TGChatProvider.IRC: + return new TGIRCSetupInfo(this); + case TGChatProvider.Discord: + return new TGDiscordSetupInfo(this); + default: + throw new Exception("Invalid provider!"); + } + } + + //trims and adds the leading # + protected virtual string SanitizeChannelName(string working) + { + return Specialize().SanitizeChannelName(working); + } + void SanitizeChannelNames(IList working) + { + for (var I = 0; I < working.Count; ++I) + + if (String.IsNullOrWhiteSpace(working[I])) + { + working.RemoveAt(I); + --I; + } + else + working[I] = SanitizeChannelName(working[I].Trim()); } /// @@ -46,17 +126,91 @@ namespace TGServiceInterface /// /// The data /// The chat provider - public TGChatSetupInfo(IList DeserializedData, TGChatProvider provider) + public TGChatSetupInfo(IList DeserializedData) { DataFields = DeserializedData; - Provider = provider; + } + /// + /// The list of admin entries + /// + public IList AdminList + { + get { return new JavaScriptSerializer().Deserialize>(DataFields[AdminListIndex]); } + set { DataFields[AdminListIndex] = new JavaScriptSerializer().Serialize(value); } + } + /// + /// If AdminList corresponds to a Provider specific recognization method + /// + public bool AdminsAreSpecial + { + get { return Convert.ToBoolean(DataFields[AdminModeIndex]); } + set { DataFields[AdminModeIndex] = Convert.ToString(value); } + } + /// + /// The channels from which admin commands/messages can be sent/received + /// + public IList AdminChannels + { + get { return new JavaScriptSerializer().Deserialize>(DataFields[AdminChannelIndex]); } + set + { + SanitizeChannelNames(value); + DataFields[AdminChannelIndex] = new JavaScriptSerializer().Serialize(value); + } + } + /// + /// The channels to which repo and compile messages are sent + /// + public IList DevChannels + { + get { return new JavaScriptSerializer().Deserialize>(DataFields[DevChannelIndex]); } + set + { + SanitizeChannelNames(value); + DataFields[DevChannelIndex] = new JavaScriptSerializer().Serialize(value); + } + } + /// + /// The channels to which watchdog messages are sent + /// + public IList WatchdogChannels + { + get { return new JavaScriptSerializer().Deserialize>(DataFields[WDChannelIndex]); } + set + { + SanitizeChannelNames(value); + DataFields[WDChannelIndex] = new JavaScriptSerializer().Serialize(value); + } + } + /// + /// The channels to which game messages are sent + /// + public IList GameChannels + { + get { return new JavaScriptSerializer().Deserialize>(DataFields[GameChannelIndex]); } + set + { + SanitizeChannelNames(value); + DataFields[GameChannelIndex] = new JavaScriptSerializer().Serialize(value); + } + } + /// + /// If this chat provider is enabled + /// + public bool Enabled + { + get { return Convert.ToBoolean(DataFields[EnabledIndex]); } + set { DataFields[EnabledIndex] = Convert.ToString(value); } } /// /// The type of provider /// - [DataMember] - public TGChatProvider Provider { get; protected set; } + public TGChatProvider Provider + { + get { return (TGChatProvider)Convert.ToInt32(DataFields[ProviderIndex]); } + set { DataFields[ProviderIndex] = Convert.ToString((int)value); } + } /// /// Raw access to the underlying data @@ -67,6 +221,7 @@ namespace TGServiceInterface /// /// Chat provider for IRC + /// Admin entries should be user nicknames in normal mode or required flags in special mode /// [DataContract] public class TGIRCSetupInfo : TGChatSetupInfo @@ -76,7 +231,8 @@ namespace TGServiceInterface const int NickIndex = 2; const int AuthTargetIndex = 3; const int AuthMessageIndex = 4; - const int FieldsLen = 5; + const int AuthLevelIndex = 5; + const int FieldsLen = 6; /// /// Construct IRC setup info from optional generic info. Defaults to TGS3 on rizons IRC server @@ -85,54 +241,78 @@ namespace TGServiceInterface public TGIRCSetupInfo(TGChatSetupInfo baseInfo = null) : base(baseInfo, FieldsLen) { Provider = TGChatProvider.IRC; - if (baseInfo == null) + if (InitializeFields) { Nickname = "TGS3"; URL = "irc.rizon.net"; Port = 6667; + AuthTarget = ""; + AuthMessage = ""; + AdminsAreSpecial = true; + AuthLevel = IRCMode.Op; } } + + protected override string SanitizeChannelName(string working) + { + if (working[0] != '#') + return "#" + working; + return working; + } + /// /// The port of the IRC server /// public ushort Port { - get { return Convert.ToUInt16(DataFields[PortIndex]); } - set { DataFields[PortIndex] = value.ToString(); } + get { return Convert.ToUInt16(DataFields[BaseIndex + PortIndex]); } + set { DataFields[BaseIndex + PortIndex] = value.ToString(); } } /// /// The URL of the IRC server /// public string URL { - get { return DataFields[URLIndex]; } - set { DataFields[URLIndex] = value; } + get { return DataFields[BaseIndex + URLIndex]; } + set { DataFields[BaseIndex + URLIndex] = value; } } /// /// The nickname of the IRC bot /// public string Nickname { - get { return DataFields[NickIndex]; } - set { DataFields[NickIndex] = value; } + get { return DataFields[BaseIndex + NickIndex]; } + set { DataFields[BaseIndex + NickIndex] = value; } } /// /// The target for sending authentication messages /// public string AuthTarget { - get { return DataFields[AuthTargetIndex]; } - set { DataFields[AuthTargetIndex] = value; } + get { return DataFields[BaseIndex + AuthTargetIndex]; } + set { DataFields[BaseIndex + AuthTargetIndex] = value; } } /// /// The authentication message /// public string AuthMessage { - get { return DataFields[AuthMessageIndex]; } - set { DataFields[AuthMessageIndex] = value; } + get { return DataFields[BaseIndex + AuthMessageIndex]; } + set { DataFields[BaseIndex + AuthMessageIndex] = value; } + } + /// + /// The minimum mode required to use admin bot commands when in special auth mode + /// + public IRCMode AuthLevel + { + get { return (IRCMode)Convert.ToInt32(DataFields[BaseIndex + AuthLevelIndex]); } + set { DataFields[BaseIndex + AuthLevelIndex] = Convert.ToString((int)value); } } } + /// + /// Chat provider for Discord + /// Admin entires should be user ids in normal mode or group ids in special mode + /// [DataContract] public class TGDiscordSetupInfo : TGChatSetupInfo { @@ -145,8 +325,20 @@ namespace TGServiceInterface public TGDiscordSetupInfo(TGChatSetupInfo baseInfo = null) : base(baseInfo, FieldsLen) { Provider = TGChatProvider.Discord; - if (baseInfo == null) - BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + if (InitializeFields) + BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; //needless to say, this is fake + } + protected override string SanitizeChannelName(string working) + { + try + { + Convert.ToUInt64(working); + } + catch + { + throw new Exception("Invalid Discord channel ID!"); + } + return working; } /// @@ -154,109 +346,45 @@ namespace TGServiceInterface /// public string BotToken { - get { return DataFields[BotTokenIndex]; } - set { DataFields[BotTokenIndex] = value; } + get { return DataFields[BaseIndex + BotTokenIndex]; } + set { DataFields[BaseIndex + BotTokenIndex] = value; } } } - /// - /// Used internally - /// - [ServiceContract] - public interface ITGChatBase - { - /// - /// Set the chat provider info - /// - /// - [OperationContract] - string SetProviderInfo(TGChatSetupInfo info); - - /// - /// Set the channels to join - /// - /// The names of the channels to join and broadcast to - /// The name of the channel which accepts admin commands. Need not be in the channels parameter - [OperationContract] - void SetChannels(string[] channels = null, string adminchannel = null); - - /// - /// Checks connection status - /// - /// true if connected, false otherwise - [OperationContract] - bool Connected(); - - /// - /// Reconnect to the chat service - /// - /// null on success, error message on failure - [OperationContract] - string Reconnect(); - - /// - /// Send a message to the chat service - /// - /// The message to send - /// true if the message should only be sent to the admin channel, false otherwise - /// - [OperationContract] - string SendMessage(string msg, bool adminOnly = false); - } - /// /// Interface for handling chat bot /// [ServiceContract] - public interface ITGChat : ITGChatBase + public interface ITGChat { + /// + /// Set the chat provider info + /// + /// The info to set + [OperationContract] + string SetProviderInfo(TGChatSetupInfo info); /// /// Returns the chat provider info /// - /// + /// The type of provider to get info for + /// The chat provider info for the selected provider [OperationContract] - TGChatSetupInfo ProviderInfo(); - /// - /// Get channels we are set to connect to, includes the admin channel - /// - /// An array of channels - [OperationContract] - string[] Channels(); + IList ProviderInfos(); /// - /// Get the channel from which secure commands can be sent + /// Checks connection status /// - /// The name of the channel + /// The type of provider to check if connected + /// true if connected, false otherwise [OperationContract] - string AdminChannel(); + bool Connected(TGChatProvider providerType); /// - /// Check if the configuration allows the IRC bot + /// Reconnect to the chat service /// - /// true if the bot is enabled, false otherwise + /// The type of provider to reconnect + /// null on success, error message on failure [OperationContract] - bool Enabled(); - - /// - /// Enable or disable the chat provider - /// - /// true to enable, false to disable - /// null on success, connection error message on failure - [OperationContract] - string SetEnabled(bool enable); - - /// - /// Print out the users who can use admin restricted commands over IRC from the admin channel - /// - /// A list of irc nicknames - [OperationContract] - string[] ListAdmins(); - - /// - /// Set the users who can use admin restricted commands over IRC from the admin channel - /// - /// The list of irc admin nicknames - [OperationContract] - void SetAdmins(string[] nicknames); + string Reconnect(TGChatProvider providerType); } } diff --git a/TGServiceInterface/Properties/AssemblyInfo.cs b/TGServiceInterface/Properties/AssemblyInfo.cs index fcec1fd3fd..1a9b91d32c 100644 --- a/TGServiceInterface/Properties/AssemblyInfo.cs +++ b/TGServiceInterface/Properties/AssemblyInfo.cs @@ -25,5 +25,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.85.4")] -[assembly: AssemblyFileVersion("3.0.85.4")] +[assembly: AssemblyVersion("3.0.86.0")] +[assembly: AssemblyFileVersion("3.0.86.0")] diff --git a/TGServiceInterface/TGServiceInterface.csproj b/TGServiceInterface/TGServiceInterface.csproj index a85f942bd6..3f501150f9 100644 --- a/TGServiceInterface/TGServiceInterface.csproj +++ b/TGServiceInterface/TGServiceInterface.csproj @@ -36,6 +36,7 @@ +