diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcPasswordType.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcPasswordType.cs
new file mode 100644
index 0000000000..38181f9f99
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcPasswordType.cs
@@ -0,0 +1,9 @@
+namespace Tgstation.Server.Host.Components.Chat.Providers
+{
+ enum IrcPasswordType
+ {
+ Server,
+ Sasl,
+ NickServ
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
new file mode 100644
index 0000000000..49410fc57d
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
@@ -0,0 +1,175 @@
+using Meebey.SmartIrc4net;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+using Tgstation.Server.Api.Models;
+using Tgstation.Server.Host.Core;
+
+namespace Tgstation.Server.Host.Components.Chat.Providers
+{
+ ///
+ /// for internet relay chat
+ ///
+ sealed class IrcProvider : IProvider
+ {
+ ///
+ public bool Connected => throw new NotImplementedException();
+
+ ///
+ public string BotMention => throw new NotImplementedException();
+
+ ///
+ /// The for the
+ ///
+ readonly ILogger logger;
+
+ ///
+ /// The client
+ ///
+ readonly IrcFeatures client;
+
+ ///
+ /// Address of the server to connect to
+ ///
+ readonly string address;
+ ///
+ /// Port of the server to connect to
+ ///
+ readonly ushort port;
+ ///
+ /// IRC nickname
+ ///
+ readonly string nickname;
+ ///
+ /// Password which will used for authentication
+ ///
+ readonly string password;
+ ///
+ /// The of
+ ///
+ readonly IrcPasswordType? passwordType;
+
+ ///
+ /// Construct an
+ ///
+ /// The value of logger
+ /// The to get the from
+ /// The value of
+ /// The value of
+ /// The value of
+ /// The value of
+ /// The value of
+ /// If should be used
+ public IrcProvider(ILogger logger, IApplication application, string address, ushort port, string nickname, string password, IrcPasswordType? passwordType, bool useSsl)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ if (application == null)
+ throw new ArgumentNullException(nameof(application));
+
+ this.address = address ?? throw new ArgumentNullException(nameof(address));
+ this.port = port;
+ this.nickname = nickname ?? throw new ArgumentNullException(nameof(nickname));
+
+ if (passwordType.HasValue && password == null)
+ throw new ArgumentNullException(nameof(password));
+
+ if(password != null && !passwordType.HasValue)
+ throw new ArgumentNullException(nameof(passwordType));
+
+ this.password = password;
+ this.passwordType = passwordType;
+
+ client = new IrcFeatures
+ {
+ SupportNonRfc = true,
+ CtcpUserInfo = "You are going to play. And I am going to watch. And everything will be just fine...",
+ AutoRejoin = true,
+ AutoRejoinOnKick = true,
+ AutoRelogin = true,
+ AutoRetry = true,
+ AutoRetryLimit = 5,
+ AutoRetryDelay = 5,
+ ActiveChannelSyncing = true,
+ AutoNickHandling = true,
+ CtcpVersion = application.VersionString,
+ UseSsl = useSsl,
+ ValidateServerCertificate = useSsl,
+ };
+
+ client.OnChannelMessage += Client_OnChannelMessage;
+ client.OnQueryMessage += Client_OnQueryMessage;
+ }
+
+ void Client_OnQueryMessage(object sender, IrcEventArgs e)
+ {
+ throw new NotImplementedException();
+ }
+
+ void Client_OnChannelMessage(object sender, IrcEventArgs e)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public void Dispose() => Disconnect(default).Wait(); //not actually a task so whatever
+
+ ///
+ public Task Connect(CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
+ {
+ try
+ {
+ client.Connect(address, port);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ if (passwordType == IrcPasswordType.Sasl)
+ {
+ //TODO
+ }
+
+ if (passwordType == IrcPasswordType.Server)
+ client.Login(nickname, nickname, 0, nickname, password);
+ else
+ client.Login(nickname, nickname);
+
+ if (passwordType == IrcPasswordType.NickServ)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ client.SendMessage(SendType.Message, "NickServ", String.Format(CultureInfo.InvariantCulture, "IDENTIFY {0}", password));
+ }
+ }
+ catch(Exception e)
+ {
+ logger.LogWarning("Unable to connect to IRC: {0}", e);
+ }
+ return true;
+ }, cancellationToken,TaskCreationOptions.LongRunning, TaskScheduler.Current);
+
+ ///
+ public Task Disconnect(CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public Task> MapChannels(IEnumerable channels, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public Task NextMessage(CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs
index 963b22e98a..cd8c07c453 100644
--- a/src/Tgstation.Server.Host/Core/Application.cs
+++ b/src/Tgstation.Server.Host/Core/Application.cs
@@ -30,6 +30,9 @@ namespace Tgstation.Server.Host.Core
///
public Version Version { get; }
+ ///
+ public string VersionString { get; }
+
///
/// The for the
///
@@ -56,6 +59,7 @@ namespace Tgstation.Server.Host.Core
this.hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
Version = Assembly.GetExecutingAssembly().GetName().Version;
+ VersionString = String.Format(CultureInfo.InvariantCulture, "/tg/station server v{0}", Version);
}
///
diff --git a/src/Tgstation.Server.Host/Core/IApplication.cs b/src/Tgstation.Server.Host/Core/IApplication.cs
index eed6769ab3..b00ae8a3b9 100644
--- a/src/Tgstation.Server.Host/Core/IApplication.cs
+++ b/src/Tgstation.Server.Host/Core/IApplication.cs
@@ -7,6 +7,11 @@ namespace Tgstation.Server.Host.Core
///
public interface IApplication
{
+ ///
+ /// A more verbose version of
+ ///
+ string VersionString { get; }
+
///
/// The version of the
///