Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
2183 lines (1945 sloc) 79.4 KB
/*
* Smuxi - Smart MUltipleXed Irc
*
* Copyright (c) 2005-2015 Mirco Bauer <meebey@meebey.net>
*
* Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
using System;
using System.IO;
using System.Net;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Threading;
using Smuxi.Common;
namespace Smuxi.Engine
{
public class Session : PermanentRemoteObject, IFrontendUI
{
#if LOG4NET
private static readonly log4net.ILog f_Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endif
private static readonly string _LibraryTextDomain = "smuxi-engine";
public static CertificateValidator CertificateValidator { get; private set; }
private int _Version = 0;
private IDictionary<string, FrontendManager> _FrontendManagers;
private IList<IProtocolManager> _ProtocolManagers;
private List<ChatModel> _Chats;
private SessionChatModel _SessionChat;
private Config _Config;
private string _Username;
private ProtocolManagerFactory _ProtocolManagerFactory;
private UserConfig _UserConfig;
private FilterListController _FilterListController;
private ICollection<FilterModel> _Filters;
Timer NewsFeedTimer { get; set; }
List<string> SeenNewsFeedIds { get; set; }
DateTime NewsFeedLastModified { get; set; }
TimeSpan NewsFeedUpdateInterval { get; set; }
TimeSpan NewsFeedRetryInterval { get; set; }
bool IsFirstNewsFeedEntry { get; set; }
internal MessageBuilderSettings MessageBuilderSettings { get; private set; }
public event EventHandler<GroupChatPersonAddedEventArgs> GroupChatPersonAdded;
public event EventHandler<GroupChatPersonRemovedEventArgs> GroupChatPersonRemoved;
public event EventHandler<GroupChatPersonUpdatedEventArgs> GroupChatPersonUpdated;
public event EventHandler<EventMessageEventArgs> EventMessage;
public IList<IProtocolManager> ProtocolManagers {
get {
return _ProtocolManagers;
}
}
public IProtocolManager FirstProtocolManager {
get {
lock (_ProtocolManagers) {
if (_ProtocolManagers.Count == 0) {
return null;
} else {
return _ProtocolManagers[0];
}
}
}
}
public IList<ChatModel> Chats {
get {
return _Chats;
}
}
public SessionChatModel SessionChat {
get {
return _SessionChat;
}
}
public int Version {
get {
return _Version;
}
}
public Config Config {
get {
return _Config;
}
}
public UserConfig UserConfig {
get {
return _UserConfig;
}
}
public string Username {
get {
return _Username;
}
}
public bool IsLocal {
get {
return _Username == "local";
}
}
internal ICollection<FilterModel> Filters {
get {
return _Filters;
}
set {
_Filters = value;
}
}
static Session()
{
CertificateValidator = new CertificateValidator();
}
public Session(Config config, ProtocolManagerFactory protocolManagerFactory,
string username)
{
Trace.Call(config, protocolManagerFactory, username);
if (config == null) {
throw new ArgumentNullException("config");
}
if (protocolManagerFactory == null) {
throw new ArgumentNullException("protocolManagerFactory");
}
if (username == null) {
throw new ArgumentNullException("username");
}
_Config = config;
_ProtocolManagerFactory = protocolManagerFactory;
_Username = username;
_FrontendManagers = new Dictionary<string, FrontendManager>();
_ProtocolManagers = new List<IProtocolManager>();
_UserConfig = new UserConfig(config, username);
_UserConfig.Changed += OnUserConfigChanged;
_FilterListController = new FilterListController(_UserConfig);
_Filters = _FilterListController.GetFilterList().Values;
MessageBuilderSettings = new MessageBuilderSettings();
MessageBuilderSettings.ApplyConfig(_UserConfig);
_Chats = new List<ChatModel>();
InitSessionChat();
SeenNewsFeedIds = new List<string>();
NewsFeedUpdateInterval = TimeSpan.FromHours(12);
NewsFeedRetryInterval = TimeSpan.FromMinutes(5);
IsFirstNewsFeedEntry = true;
NewsFeedTimer = new Timer(delegate { UpdateNewsFeed(); }, null,
TimeSpan.Zero, NewsFeedUpdateInterval);
}
public void ExecuteOnStartupCommands()
{
foreach (string command in (string[]) _UserConfig["OnStartupCommands"]) {
if (command.Length == 0) {
continue;
}
var cd = new CommandModel(null, _SessionChat,
(string)_UserConfig["Interface/Entry/CommandCharacter"],
command);
var handled = Command(cd);
if (!handled) {
#if LOG4NET
f_Logger.Error("ExecuteOnStartupCommands(): command unknown: " + command);
#endif
var builder = CreateMessageBuilder().
AppendEventPrefix().
AppendErrorText("unknown command: {0}", command);
AddMessageToChat(_SessionChat, builder.ToMessage(), true);
}
}
}
public void ProcessAutoConnect()
{
var serverCon = new ServerListController(_UserConfig);
IList<ServerModel> servers = serverCon.GetServerList();
foreach (ServerModel server in servers) {
if (!server.OnStartupConnect) {
continue;
}
var msg = String.Format(
_("Automatically connecting to {0}..."),
String.Format("{0}/{1} ({2}:{3})", server.Protocol,
server.Network, server.Hostname, server.Port)
);
#if LOG4NET
f_Logger.Info(msg);
#endif
var builder = CreateMessageBuilder().
AppendEventPrefix().
AppendText(msg);
AddMessageToChat(_SessionChat, builder.ToMessage(), true);
var srv = server;
// run connects in background threads as they block
ThreadPool.QueueUserWorkItem(delegate {
bool isError = false;
try {
IProtocolManager protocolManager = Connect(srv, null);
// if the connect command was correct, we should be
// able to get the chat model
if (protocolManager.Chat == null) {
isError = true;
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("ProcessAutoConnect(): Exception during "+
"automatic connect: ", ex);
#endif
isError = true;
}
if (isError) {
builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(
_("Automatic connect to {0} failed!"),
srv.Hostname + ":" + srv.Port
);
AddMessageToChat(_SessionChat, builder.ToMessage(), true);
}
});
}
}
public IProtocolManager NextProtocolManager(IProtocolManager currentProtocolManager)
{
lock (_ProtocolManagers) {
if (_ProtocolManagers.Count == 0) {
return null;
}
int pos = 0;
if (currentProtocolManager != null) {
pos = _ProtocolManagers.IndexOf(currentProtocolManager);
}
if (pos < _ProtocolManagers.Count - 1) {
pos++;
} else {
pos = 0;
}
return _ProtocolManagers[pos];
}
}
protected MessageBuilder CreateMessageBuilder()
{
var builder = new MessageBuilder();
// copy settings so the caller can override settings without
// changing the settings of the complete session
builder.Settings = new MessageBuilderSettings(MessageBuilderSettings);
return builder;
}
public void RegisterFrontendUI(IFrontendUI ui)
{
Trace.Call(ui);
if (ui == null) {
throw new ArgumentNullException("ui");
}
string uri = GetUri(ui);
#if LOG4NET
f_Logger.Debug("Registering UI with URI: " + uri);
#endif
// add the FrontendManager to the hashtable with an unique .NET remoting identifier
FrontendManager fm = new FrontendManager(this, ui);
lock (_FrontendManagers) {
_FrontendManagers[uri] = fm;
}
}
internal void DeregisterFrontendManager(FrontendManager fm)
{
Trace.Call(fm);
if (fm == null) {
throw new ArgumentNullException("fm");
}
string key = null;
lock (_FrontendManagers) {
foreach (KeyValuePair<string, FrontendManager> kv in _FrontendManagers) {
if (kv.Value == fm) {
key = kv.Key;
break;
}
}
}
if (key == null) {
#if LOG4NET
f_Logger.Debug("DeregisterFrontendManager(fm): could not find " +
"frontend manager (probably already cleanly " +
" deregistered), ignoring...");
#endif
return;
}
lock (_FrontendManagers) {
_FrontendManagers.Remove(key);
}
#if LOG4NET
f_Logger.Debug("DeregisterFrontendUI(fm): disposing FrontendManager");
#endif
fm.Dispose();
CheckPresenceStatus();
}
public void DeregisterFrontendUI(IFrontendUI ui)
{
Trace.Call(ui);
if (ui == null) {
throw new ArgumentNullException("ui");
}
string uri = GetUri(ui);
#if LOG4NET
f_Logger.Debug("DeregisterFrontendUI(ui): deregistering UI with URI: "+uri);
#endif
FrontendManager manager;
lock (_FrontendManagers) {
_FrontendManagers.TryGetValue(uri, out manager);
_FrontendManagers.Remove(uri);
}
if (manager == null) {
#if LOG4NET
f_Logger.Error("DeregisterFrontendUI(ui): can't dispose as FrontendManager not found with URI: " + uri);
#endif
} else {
#if LOG4NET
f_Logger.Debug("DeregisterFrontendUI(ui): disposing FrontendManager with URI: " + uri);
#endif
manager.Dispose();
}
CheckPresenceStatus();
}
public FrontendManager GetFrontendManager(IFrontendUI ui)
{
Trace.Call(ui);
if (ui == null) {
throw new ArgumentNullException("ui");
}
lock (_FrontendManagers) {
return _FrontendManagers[GetUri(ui)];
}
}
private string GetUri(IFrontendUI ui)
{
if (ui == null) {
throw new ArgumentNullException("ui");
}
if (IsLocal) {
return "local";
}
return RemotingServices.GetObjectUri((MarshalByRefObject)ui);
}
public static bool IsLocalFrontend(IFrontendUI ui)
{
if (ui == null) {
throw new ArgumentNullException("ui");
}
return RemotingServices.GetObjectUri((MarshalByRefObject)ui) == null;
}
public ChatModel GetChat(string id, ChatType chatType, IProtocolManager networkManager)
{
if (id == null) {
throw new ArgumentNullException("id");
}
lock (_Chats) {
foreach (ChatModel chat in _Chats) {
if ((chat.ID.ToLower() == id.ToLower()) &&
(chat.ChatType == chatType) &&
(chat.ProtocolManager == networkManager)) {
return chat;
}
}
}
return null;
}
public bool Command(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
bool handled = false;
if (cd.IsCommand) {
switch (cd.Command) {
case "help":
CommandHelp(cd);
if (cd.Chat.ChatType == ChatType.Session) {
handled = true;
}
break;
case "server":
case "connect":
CommandConnect(cd);
handled = true;
break;
case "disconnect":
CommandDisconnect(cd);
handled = true;
break;
case "reconnect":
CommandReconnect(cd);
handled = true;
break;
case "network":
CommandNetwork(cd);
handled = true;
break;
case "config":
CommandConfig(cd);
handled = true;
break;
case "shutdown":
CommandShutdown(cd);
handled = true;
break;
case "echo":
CommandEcho(cd);
handled = true;
break;
default:
var filteredCmd = IOSecurity.GetFilteredPath(cd.Command);
var hooks = new HookRunner("engine", "session",
"command-" + filteredCmd);
var pm = cd.Chat.ProtocolManager;
hooks.Environments.Add(new CommandHookEnvironment(cd));
hooks.Environments.Add(new ChatHookEnvironment(cd.Chat));
if (pm != null) {
hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
}
var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
hooks.Commands.Add(new SessionHookCommand(this, cd.Chat, cmdChar));
if (pm != null) {
hooks.Commands.Add(new ProtocolManagerHookCommand(pm, cd.Chat, cmdChar));
}
// show time
hooks.Init();
if (hooks.HasHooks) {
hooks.Run();
handled = true;
}
break;
}
} else {
// normal text
if (cd.Chat.ChatType == ChatType.Session &&
cd.FrontendManager != null &&
cd.FrontendManager.CurrentProtocolManager == null) {
_NotConnected(cd);
handled = true;
}
}
return handled;
}
public void CommandHelp(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
var builder = CreateMessageBuilder();
// TRANSLATOR: this line is used as a label / category for a
// list of commands below
builder.AppendHeader(_("Engine Commands"));
AddMessageToFrontend(cd, builder.ToMessage());
string[] help = {
"connect/server protocol [protocol-parameters]",
"connect/server network",
"disconnect [server]",
"network list",
"network close [network]",
"network switch [network]",
"config (save|load|list)",
"config get key",
"config set key=value",
"config remove key",
"shutdown"
};
foreach (string line in help) {
builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendText(line);
AddMessageToFrontend(cd, builder.ToMessage());
}
}
public void CommandConnect(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
FrontendManager fm = cd.FrontendManager;
MessageBuilder builder = null;
string protocol = null;
ServerModel server = null;
// first lookup by network name
if (cd.DataArray.Length == 2) {
var network = cd.Parameter;
var serverSettings = new ServerListController(UserConfig);
server = serverSettings.GetServerByNetwork(network);
if (server == null) {
// HACK: simply assume the user meant irc if not specified
// as Smuxi is still primarly an IRC client
protocol = "irc";
string cmd = String.Format("{0}connect irc {1}",
cd.CommandCharacter, cd.Parameter);
cd = new CommandModel(fm, cd.Chat, cd.CommandCharacter, cmd);
}
} else if (cd.DataArray.Length >= 3) {
protocol = cd.DataArray[1];
} else {
_NotEnoughParameters(cd);
return;
}
IProtocolManager protocolManager = null;
// TODO: detect matching protocol managers, how to parse host and port
// though in a protocol neutral ?
/*
foreach (IProtocolManager nm in _ProtocolManagers) {
if (nm.Host == server &&
nm.Port == port) {
// reuse network manager
if (nm.IsConnected) {
fm.AddTextToCurrentChat("-!- " + String.Format(
_("Already connected to: {0}:{1}"), server, port));
return;
}
networkManager = nm;
break;
}
}
*/
if (protocolManager == null && server == null) {
try {
protocolManager = CreateProtocolManager(protocol);
lock (_ProtocolManagers) {
_ProtocolManagers.Add(protocolManager);
}
} catch (ArgumentException ex) {
if (ex.ParamName != "protocol") {
throw;
}
// this is an unknown protocol error
builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(ex.Message);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
}
// HACK: this is hacky as the Command parser of the protocol manager
// will pass this command to it's connect method only if cd was
// constructed correctly beginning with /connect
// So make sure it's like it needs to be!
if (cd.Command != "connect") {
string cmd = String.Format("{0}connect {1}",
cd.CommandCharacter,
String.Join(" ", cd.DataArray, 1,
cd.DataArray.Length - 1));
cd = new CommandModel(fm, cd.Chat, cd.CommandCharacter, cmd);
}
// run in background so it can't block the command queue
ThreadPool.QueueUserWorkItem(delegate {
try {
if (protocolManager == null && server != null) {
protocolManager = Connect(server, fm);
} else {
protocolManager.Command(cd);
}
// set this as current protocol manager
// but only if there was none set (we might be on a chat for example)
// or if this is the neutral "smuxi" tab
if (fm.CurrentProtocolManager == null ||
(fm.CurrentChat != null && fm.CurrentChat.ChatType == ChatType.Session)) {
fm.CurrentProtocolManager = protocolManager;
fm.UpdateNetworkStatus();
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("CommandConnect(): ", ex);
#endif
builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(_("Connect failed!"));
fm.AddMessageToChat(cd.Chat, builder.ToMessage());
}
});
}
public void CommandDisconnect(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
FrontendManager fm = cd.FrontendManager;
IProtocolManager victim = null;
if (cd.DataArray.Length >= 2) {
string server = cd.DataArray[1];
victim = GetProtocolManagerByHost(server);
if (victim == null) {
var builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(
_("Disconnect failed - could not find server: {0}"),
server
);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
} else {
victim = cd.Chat.ProtocolManager;
}
if (victim == null) {
return;
}
victim.Disconnect(fm);
victim.Dispose();
lock (_ProtocolManagers) {
_ProtocolManagers.Remove(victim);
}
}
public void CommandReconnect(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
var pm = cd.Chat.ProtocolManager;
if (pm == null) {
return;
}
ThreadPool.QueueUserWorkItem(delegate {
try {
pm.Reconnect(cd.FrontendManager);
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("CommandReconnect(): ", ex);
#endif
var builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(_("Reconnect failed!"));
AddMessageToFrontend(cd, builder.ToMessage());
}
});
}
public void CommandConfig(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
if (cd.DataArray.Length < 2) {
_NotEnoughParameters(cd);
return;
}
var builder = CreateMessageBuilder();
builder.AppendEventPrefix();
var action = cd.DataArray[1].ToLower();
switch (action) {
case "load":
_Config.Load();
builder.AppendText(_("Configuration reloaded"));
break;
case "save":
_Config.Save();
builder.AppendText(_("Configuration saved"));
break;
case "get":
case "list":
string key = null;
if (action == "get" && cd.DataArray.Length >= 3) {
key = cd.DataArray[2];
}
foreach (var entry in _UserConfig.OrderBy(kvp => kvp.Key)) {
if (key != null &&
entry.Key.IndexOf(key, StringComparison.InvariantCultureIgnoreCase) == -1) {
continue;
}
builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendText("{0} = {1}", entry.Key, entry.Value);
AddMessageToFrontend(cd, builder.ToMessage());
}
return;
case "set":
if (cd.DataArray.Length < 3) {
_NotEnoughParameters(cd);
return;
}
var setParam = String.Join(" ", cd.DataArray.Skip(2).ToArray());
if (!setParam.Contains("=")) {
builder.AppendErrorText(
_("Invalid key/value format.")
);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
var setKey = setParam.Split('=')[0].Trim();
var setValue = String.Join(
"=", setParam.Split('=').Skip(1).ToArray()
).Trim();
object oldValue = _UserConfig[setKey];
if (oldValue == null && setKey.StartsWith("MessagePatterns/")) {
var id = setKey.Split('/')[1];
var parsedId = Int32.Parse(id);
var msgPatternSettings = new MessagePatternListController(_UserConfig);
var pattern = msgPatternSettings.Get(parsedId);
if (pattern == null) {
// pattern does not exist, create it with default values
pattern = new MessagePatternModel(parsedId);
msgPatternSettings.Add(pattern, parsedId);
oldValue = _UserConfig[setKey];
}
}
if (oldValue == null) {
builder.AppendErrorText(
_("Invalid config key: '{0}'"),
setKey
);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
try {
object newValue = Convert.ChangeType(setValue, oldValue.GetType());
_UserConfig[setKey] = newValue;
builder.AppendText("{0} = {1}", setKey, newValue.ToString());
if (setKey.StartsWith("MessagePatterns/")) {
MessageBuilderSettings.ApplyConfig(UserConfig);
}
} catch (InvalidCastException) {
builder.AppendErrorText(
_("Could not convert config value: '{0}' to type: {1}"),
setValue,
oldValue.GetType().Name
);
} catch (FormatException) {
builder.AppendErrorText(
_("Could not convert config value: '{0}' to type: {1}"),
setValue,
oldValue.GetType().Name
);
}
break;
case "remove": {
if (cd.DataArray.Length < 3) {
_NotEnoughParameters(cd);
return;
}
var removeParam = cd.DataArray[2];
if (!removeParam.StartsWith("MessagePatterns/")) {
builder.AppendErrorText(
_("Invalid config remove key: '{0}'. Valid remove " +
"keys: MessagePatterns/{{ID}}."),
removeParam
);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
var id = removeParam.Split('/')[1];
var parsedId = Int32.Parse(id);
var patternController = new MessagePatternListController(_UserConfig);
var pattern = patternController.Get(parsedId);
if (pattern == null) {
builder.AppendErrorText(
_("Message pattern with ID: '{0}' does not exist."),
id
);
} else {
patternController.Remove(parsedId);
MessageBuilderSettings.ApplyConfig(UserConfig);
builder.AppendText(
_("Message pattern with ID: '{0}' removed."),
id
);
}
break;
}
default:
builder.AppendErrorText(
_("Invalid parameter for config; use load, save, get or set.")
);
break;
}
AddMessageToFrontend(cd, builder.ToMessage());
}
public void CommandShutdown(CommandModel cmd)
{
Trace.Call(cmd);
#if LOG4NET
f_Logger.Info("Shutting down...");
#endif
var frontendMgr = cmd != null ? cmd.FrontendManager : null;
Shutdown(true, frontendMgr);
if (IsLocal) {
// allow the frontend to cleanly terminate
return;
}
#if LOG4NET
f_Logger.Debug("Terminating process...");
#endif
Environment.Exit(0);
}
public void CommandEcho(CommandModel cmd)
{
Trace.Call(cmd);
if (cmd == null) {
throw new ArgumentNullException("cmd");
}
var msg = CreateMessageBuilder().
AppendEventPrefix().
AppendText(cmd.Parameter).
ToMessage();
if (cmd.FrontendManager == null) {
AddMessageToChat(cmd.Chat, msg, true);
} else {
cmd.FrontendManager.AddMessageToChat(cmd.Chat, msg);
}
}
public void CommandNetwork(CommandModel cd)
{
Trace.Call(cd);
if (cd == null) {
throw new ArgumentNullException("cd");
}
if (cd.DataArray.Length == 1) {
// no parameter given, fallback to list
_CommandNetworkList(cd);
return;
}
if (cd.DataArray.Length >= 2) {
switch (cd.DataArray[1].ToLower()) {
case "list":
_CommandNetworkList(cd);
break;
case "switch":
_CommandNetworkSwitch(cd);
break;
case "close":
_CommandNetworkClose(cd);
break;
default:
var builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendText(
_("Invalid parameter for network; use list, " +
"switch, or close")
);
AddMessageToFrontend(cd, builder.ToMessage());
break;
}
} else {
_NotEnoughParameters(cd);
}
}
private void _CommandNetworkList(CommandModel cmd)
{
var servers = new ServerListController(UserConfig);
var availableNetworks = servers.GetNetworks();
var connectedNetworks = new List<IProtocolManager>();
lock (_ProtocolManagers) {
foreach (IProtocolManager pm in _ProtocolManagers) {
if (pm.IsConnected) {
connectedNetworks.Add(pm);
if (!String.IsNullOrEmpty(pm.NetworkID)) {
availableNetworks.Remove(pm.NetworkID);
}
}
}
}
var msg = CreateMessageBuilder();
// TRANSLATOR: this line is used as a label / category for a
// list of networks below
msg.AppendHeader(_("Connected Networks"));
AddMessageToFrontend(cmd, msg.ToMessage());
foreach (var network in connectedNetworks) {
msg = CreateMessageBuilder();
msg.AppendEventPrefix();
msg.AppendText("{0}: {1} ", _("Network"), network.NetworkID);
msg.AppendText("{0}: {1} ", _("Protocol"), network.Protocol);
msg.AppendText("{0}: {1} ", _("Host"), network.Host);
msg.AppendText("{0}: {1}", _("Port"), network.Port);
AddMessageToFrontend(cmd, msg.ToMessage());
}
if (connectedNetworks.Count == 0) {
msg = CreateMessageBuilder();
// TRANSLATOR: no connected networks
msg.AppendEventPrefix().AppendText("<{0}>", _("None"));
AddMessageToFrontend(cmd, msg.ToMessage());
}
msg = CreateMessageBuilder();
// TRANSLATOR: this line is used as a label / category for a
// list of networks below
msg.AppendHeader(_("Available Networks"));
AddMessageToFrontend(cmd, msg.ToMessage());
foreach (var network in availableNetworks) {
if (network == null || network.Trim().Length == 0) {
continue;
}
msg = CreateMessageBuilder();
msg.AppendEventPrefix();
msg.AppendText("{0}: {1}", _("Network"), network);
AddMessageToFrontend(cmd, msg.ToMessage());
}
if (availableNetworks.Count == 0) {
msg = CreateMessageBuilder();
// TRANSLATOR: no available networks
msg.AppendEventPrefix().AppendText("<{0}>", _("None"));
AddMessageToFrontend(cmd, msg.ToMessage());
}
}
private void _CommandNetworkClose(CommandModel cd)
{
IProtocolManager pm = null;
if (cd.DataArray.Length >= 3) {
// named protocol manager
string network = cd.DataArray[2];
pm = GetProtocolManagerByNetwork(network);
if (pm == null) {
var builder = CreateMessageBuilder();
builder.AppendText(_("Network close failed - could not " +
"find network: {0}"), network);
AddMessageToFrontend(cd, builder.ToMessage());
return;
}
} else if (cd.DataArray.Length >= 2) {
// network manager of chat
pm = cd.Chat.ProtocolManager;
}
if (pm == null) {
return;
}
// disconnect in background as could be blocking
ThreadPool.QueueUserWorkItem(delegate {
try {
pm.Disconnect(cd.FrontendManager);
pm.Dispose();
// Dispose() takes care of removing the chat from session (frontends)
lock (_ProtocolManagers) {
_ProtocolManagers.Remove(pm);
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("_CommandNetworkClose(): Exception", ex);
#endif
}
});
}
private void _CommandNetworkSwitch(CommandModel cd)
{
FrontendManager fm = cd.FrontendManager;
if (fm == null) {
_NotEnoughParameters(cd);
return;
}
if (cd.DataArray.Length >= 3) {
// named network manager
string network = cd.DataArray[2];
var pm = GetProtocolManagerByNetwork(network);
if (pm == null) {
var builder = CreateMessageBuilder();
builder.AppendText(_("Network switch failed - could not " +
"find network: {0}"), network);
fm.AddMessageToChat(cd.Chat, builder.ToMessage());
return;
}
fm.CurrentProtocolManager = pm;
fm.UpdateNetworkStatus();
} else if (cd.DataArray.Length >= 2) {
// next network manager
fm.NextProtocolManager();
} else {
_NotEnoughParameters(cd);
}
}
private void _NotConnected(CommandModel cd)
{
var builder = CreateMessageBuilder();
builder.AppendText(_("Not connected to any network"));
AddMessageToFrontend(cd, builder.ToMessage());
}
private void _NotEnoughParameters(CommandModel cd)
{
var builder = CreateMessageBuilder();
builder.AppendText(_("Not enough parameters for {0} command"),
cd.Command);
AddMessageToFrontend(cd, builder.ToMessage());
}
public void UpdateNetworkStatus()
{
Trace.Call();
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.UpdateNetworkStatus();
}
}
}
public T CreateChat<T>(string id,
string name,
IProtocolManager protocolManager)
where T : ChatModel
{
Trace.Call(id, name, protocolManager);
T chat;
Type chatType = typeof(T);
if (chatType == typeof(SessionChatModel)) {
chat = (T) Activator.CreateInstance(chatType, id, name);
} else if (chatType == typeof(PersonChatModel)) {
throw new NotSupportedException(
"PersonModel is not supported, use " +
"Session.CreatePersionChat() instead"
);
} else {
chat = (T) Activator.CreateInstance(chatType,
id, name, protocolManager);
}
chat.ApplyConfig(UserConfig);
return chat;
}
public PersonChatModel CreatePersonChat(PersonModel person,
IProtocolManager protocolManager)
{
Trace.Call(person, protocolManager);
if (person == null) {
throw new ArgumentNullException("person");
}
return CreatePersonChat(person, person.ID, person.IdentityName,
protocolManager);
}
public PersonChatModel CreatePersonChat(PersonModel person,
string id, string name,
IProtocolManager protocolManager)
{
Trace.Call(person, id, name, protocolManager);
var chat = new PersonChatModel(person, id, name, protocolManager);
chat.ApplyConfig(UserConfig);
return chat;
}
public void AddChat(ChatModel chat)
{
Trace.Call(chat);
if (chat == null) {
throw new ArgumentNullException("chat");
}
chat.Position = GetSortedChatPosition(chat);
lock (_Chats) {
_Chats.Add(chat);
if (chat.Position == -1) {
chat.Position = _Chats.IndexOf(chat);
} else {
MoveChat(chat, chat.Position);
}
}
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.AddChat(chat);
}
}
}
public void RemoveChat(ChatModel chat)
{
Trace.Call(chat);
if (chat == null) {
throw new ArgumentNullException("chat");
}
lock (_Chats) {
if (!_Chats.Remove(chat)) {
#if LOG4NET
f_Logger.Warn("RemoveChat(): _Chats.Remove(" + chat + ") failed, ignoring...");
#endif
chat.Close();
return;
}
chat.Close();
// refresh chat positions
foreach (var schat in _Chats) {
schat.Position = _Chats.IndexOf(schat);
}
}
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.RemoveChat(chat);
}
}
}
public void EnableChat(ChatModel chat)
{
Trace.Call(chat);
if (chat == null) {
throw new ArgumentNullException("chat");
}
chat.IsEnabled = true;
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.EnableChat(chat);
}
}
}
public void DisableChat(ChatModel chat)
{
Trace.Call(chat);
if (chat == null) {
throw new ArgumentNullException("chat");
}
chat.IsEnabled = false;
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.DisableChat(chat);
}
}
}
public void SyncChat(ChatModel chat)
{
Trace.Call(chat);
if (chat == null) {
throw new ArgumentNullException("chat");
}
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.SyncChat(chat);
}
}
}
public void MoveChat(ChatModel chat, int newPosition)
{
Trace.Call(chat, newPosition);
if (chat == null) {
throw new ArgumentNullException("chat");
}
lock (_Chats) {
_Chats.Remove(chat);
_Chats.Insert(newPosition, chat);
foreach (var schat in _Chats) {
schat.Position = _Chats.IndexOf(schat);
}
}
}
[Obsolete("This method is deprecated, use AddMessageToChat(ChatModel, MessageModel) instead!")]
public void AddTextToChat(ChatModel chat, string text)
{
AddTextToChat(chat, text, false);
}
[Obsolete("This method is deprecated, use AddMessageToChat(ChatModel, MessageModel, bool) instead!")]
public void AddTextToChat(ChatModel chat, string text, bool ignoreFilters)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (text == null) {
throw new ArgumentNullException("text");
}
AddMessageToChat(chat, new MessageModel(text), ignoreFilters);
}
public void AddMessageToChat(ChatModel chat, MessageModel msg)
{
AddMessageToChat(chat, msg, false);
}
public void AddMessageToChat(ChatModel chat, MessageModel msg,
bool ignoreFilters)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (msg == null) {
throw new ArgumentNullException("msg");
}
bool isFiltered = !ignoreFilters && IsFilteredMessage(chat, msg);
LogMessage(chat, msg, isFiltered);
if (isFiltered) {
return;
}
lock (chat.MessageBuffer) {
try {
chat.MessageBuffer.Add(msg);
} catch (Exception ex) {
#if LOG4NET
Trace.Call(chat, msg, ignoreFilters);
f_Logger.ErrorFormat(
"AddMessageToChat({0}, {1}, {2}): " +
"chat.MessageBuffer.Add() threw exception:",
chat, msg, ignoreFilters
);
f_Logger.Error("AddMessageToChat(): ", ex);
#endif
if (chat.MessageBuffer is Db4oMessageBuffer ||
chat.MessageBuffer is SqliteMessageBuffer) {
#if LOG4NET
f_Logger.Error(
"AddMessageToChat(): " +
"Falling back to volatile message buffer..."
);
#endif
chat.ResetMessageBuffer();
chat.InitMessageBuffer(MessageBufferPersistencyType.Volatile);
var builder = CreateMessageBuilder();
builder.AppendEventPrefix();
builder.AppendErrorText(
_("Failed to write to chat history. " +
"Your chat history will not be preserved. " +
"Reason: {0}"),
ex.Message
);
chat.MessageBuffer.Add(builder.ToMessage());
chat.MessageBuffer.Add(msg);
}
}
}
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.AddMessageToChat(chat, msg);
}
}
if (msg.MessageType == MessageType.Event) {
// on-event-message
OnEventMessage(
// at this point we no longer know who sent this nor to whom
new EventMessageEventArgs(chat, msg, String.Empty, String.Empty)
);
}
}
public void AddPersonToGroupChat(GroupChatModel groupChat, PersonModel person)
{
if (groupChat == null) {
throw new ArgumentNullException("groupChat");
}
if (person == null) {
throw new ArgumentNullException("person");
}
#if LOG4NET
f_Logger.Debug("AddPersonToGroupChat() groupChat.Name: "+groupChat.Name+" person.IdentityName: "+person.IdentityName);
#endif
groupChat.UnsafePersons.Add(person.ID, person);
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.AddPersonToGroupChat(groupChat, person);
}
}
OnGroupChatPersonAdded(
new GroupChatPersonAddedEventArgs(groupChat, person)
);
}
public void UpdatePersonInGroupChat(GroupChatModel groupChat, PersonModel oldPerson, PersonModel newPerson)
{
if (groupChat == null) {
throw new ArgumentNullException("groupChat");
}
if (oldPerson == null) {
throw new ArgumentNullException("oldPerson");
}
if (newPerson == null) {
throw new ArgumentNullException("newPerson");
}
#if LOG4NET
f_Logger.Debug("UpdatePersonInGroupChat()" +
" groupChat.Name: " + groupChat.Name +
" oldPerson.IdentityName: " + oldPerson.IdentityName +
" newPerson.IdentityName: " + newPerson.IdentityName);
#endif
// FIXME: do we have to lock groupChat.UnsafePersons here?
// probably not, as long as the ProtocolManager who owns this chat
// is only running one thread
groupChat.UnsafePersons.Remove(oldPerson.ID);
groupChat.UnsafePersons.Add(newPerson.ID, newPerson);
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.UpdatePersonInGroupChat(groupChat, oldPerson, newPerson);
}
}
OnGroupChatPersonUpdated(
new GroupChatPersonUpdatedEventArgs(groupChat, oldPerson, newPerson)
);
}
public void UpdateTopicInGroupChat(GroupChatModel groupChat, MessageModel topic)
{
if (groupChat == null) {
throw new ArgumentNullException("groupChat");
}
if (topic == null) {
throw new ArgumentNullException("topic");
}
#if LOG4NET
f_Logger.Debug("UpdateTopicInGroupChat() groupChat.Name: " + groupChat.Name + " topic: " + topic.ToString());
#endif
groupChat.Topic = topic;
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.UpdateTopicInGroupChat(groupChat, topic);
}
}
}
public void RemovePersonFromGroupChat(GroupChatModel groupChat, PersonModel person)
{
if (groupChat == null) {
throw new ArgumentNullException("groupChat");
}
if (person == null) {
throw new ArgumentNullException("person");
}
#if LOG4NET
f_Logger.Debug("RemovePersonFromGroupChat() groupChat.Name: " + groupChat.Name + " person.ID: "+person.ID);
#endif
groupChat.UnsafePersons.Remove(person.ID);
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.RemovePersonFromGroupChat(groupChat, person);
}
}
OnGroupChatPersonRemoved(
new GroupChatPersonRemovedEventArgs(groupChat, person)
);
}
public void SetNetworkStatus(string status)
{
if (status == null) {
throw new ArgumentNullException("status");
}
#if LOG4NET
f_Logger.Debug("SetNetworkStatus() status: "+status);
#endif
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.SetNetworkStatus(status);
}
}
}
public void SetStatus(string status)
{
if (status == null) {
throw new ArgumentNullException("status");
}
#if LOG4NET
f_Logger.Debug("SetStatus() status: "+status);
#endif
lock (_FrontendManagers) {
foreach (FrontendManager fm in _FrontendManagers.Values) {
fm.SetStatus(status);
}
}
}
public IList<string> GetSupportedProtocols()
{
return _ProtocolManagerFactory.GetProtocols();
}
public IProtocolManager Connect(ServerModel server, FrontendManager frontendManager)
{
Trace.Call(server, frontendManager);
if (server == null) {
throw new ArgumentNullException("server");
}
if (String.IsNullOrEmpty(server.Protocol)) {
throw new ArgumentNullException("server.Protocol");
}
IProtocolManager protocolManager = CreateProtocolManager(
server.Protocol
);
lock (_ProtocolManagers) {
_ProtocolManagers.Add(protocolManager);
}
string password = null;
// only pass non-empty passwords to Connect()
if (!String.IsNullOrEmpty(server.Password)) {
password = server.Password;
}
if (server.OnConnectCommands != null && server.OnConnectCommands.Count > 0) {
protocolManager.Connected += delegate {
ThreadPool.QueueUserWorkItem(delegate {
try {
foreach (string command in server.OnConnectCommands) {
if (command.Length == 0) {
continue;
}
try {
var cd = new CommandModel(
frontendManager,
protocolManager.Chat,
(string) _UserConfig["Interface/Entry/CommandCharacter"],
command
);
protocolManager.Command(cd);
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("Connect(): Command in Connected event: Exception", ex);
#endif
var msg = CreateMessageBuilder().
AppendErrorText("Command '{0}' failed. Reason: {1} ({2})",
command, ex.Message, ex.GetType()).
ToMessage();
AddMessageToFrontend (frontendManager, protocolManager.Chat, msg);
}
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("Connect(): Connected event: Exception", ex);
#endif
}
});
};
}
protocolManager.Connect(frontendManager, server);
if (protocolManager.Chat == null) {
// just in case the ProtocolManager is not setting the
// protocol chat
throw new ApplicationException(_("Connect failed."));
}
return protocolManager;
}
private IProtocolManager CreateProtocolManager(string protocol)
{
ProtocolManagerInfoModel info =
_ProtocolManagerFactory.GetProtocolManagerInfoByAlias(protocol);
if (info == null) {
if (_ProtocolManagerFactory.ProtocolManagerInfos.Count != 1) {
throw new ArgumentException(
String.Format(
_("No protocol manager found for the protocol: {0}"),
protocol
),
"protocol"
);
}
// ok, we forgive the user not passing a valid protocol by
// falling back to the only available protocol
info = _ProtocolManagerFactory.ProtocolManagerInfos[0];
}
return _ProtocolManagerFactory.CreateProtocolManager(info, this);
}
public void LogMessage(ChatModel chat, MessageModel msg, bool isFiltered)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (msg == null) {
throw new ArgumentNullException("msg");
}
if (!(bool) UserConfig["Logging/Enabled"]) {
return;
}
if (isFiltered && !(bool) UserConfig["Logging/LogFilteredMessages"]) {
return;
}
if (chat.ChatType == ChatType.Session ||
chat.ChatType == ChatType.Protocol) {
return;
}
try {
// HACK: twitter retrieves older messages and we don't want to
// re-log those when the twitter connection is re-opened
var protocol = chat.ProtocolManager.Protocol.ToLower();
if (protocol == "twitter") {
return;
}
// don't log chatstates
switch (msg.MessageType) {
case MessageType.ChatStateComposing:
case MessageType.ChatStatePaused:
case MessageType.ChatStateReset:
return;
}
using (var stream = File.AppendText(chat.LogFile)) {
stream.WriteLine(
String.Format(
"[{0:yyyy-MM-dd HH:mm:ss}] {1}",
msg.TimeStamp.ToLocalTime(),
msg.ToString()
)
);
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("LogMessage(): logging error", ex);
#endif
}
}
public bool IsFilteredMessage(ChatModel chat, MessageModel msg)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (msg == null) {
throw new ArgumentNullException("msg");
}
return IsFilteredMessage(chat, msg.ToString(), msg.MessageType);
}
public bool IsFilteredMessage(ChatModel chat, string msg,
MessageType msgType)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (msg == null) {
throw new ArgumentNullException("msg");
}
lock (_Filters) {
foreach (var filter in _Filters) {
if (!String.IsNullOrEmpty(filter.Protocol) &&
chat.ProtocolManager != null &&
filter.Protocol != chat.ProtocolManager.Protocol) {
continue;
}
if (!String.IsNullOrEmpty(filter.NetworkID) &&
chat.ProtocolManager != null &&
String.Compare(filter.NetworkID,
chat.ProtocolManager.NetworkID,
StringComparison.OrdinalIgnoreCase) != 0) {
continue;
}
if (filter.ChatType.HasValue &&
filter.ChatType != chat.ChatType) {
continue;
}
if (!String.IsNullOrEmpty(filter.ChatID) &&
!Pattern.IsMatch(chat.ID, filter.ChatID)) {
continue;
}
if (filter.MessageType.HasValue &&
filter.MessageType != msgType) {
continue;
}
if (!String.IsNullOrEmpty(filter.MessagePattern)) {
var pattern = filter.MessagePattern;
if (!Pattern.ContainsPatternCharacters(pattern)) {
// use globbing by default
pattern = String.Format("*{0}*", pattern);
}
if (!Pattern.IsMatch(msg, pattern)) {
continue;
}
}
return true;
}
}
return false;
}
public void AddMessageToFrontend(CommandModel cmd, MessageModel msg)
{
if (cmd == null) {
throw new ArgumentNullException("cmd");
}
AddMessageToFrontend(cmd.FrontendManager, cmd.Chat, msg);
}
public void AddMessageToFrontend(FrontendManager fm, ChatModel chat, MessageModel msg)
{
if (chat == null) {
throw new ArgumentNullException("chat");
}
if (msg == null) {
throw new ArgumentNullException("msg");
}
if (fm == null) {
// fallback to session
AddMessageToChat(chat, msg);
} else {
fm.AddMessageToChat(chat, msg);
}
}
void OnUserConfigChanged(object sender, ConfigChangedEventArgs e)
{
if (e.Key.StartsWith("Filters/")) {
#if LOG4NET
f_Logger.Debug("OnUserConfigChanged(): refreshing filters");
#endif
// referesh filters
// TODO: use a timeout here to only refresh once in 1 second
_Filters = _FilterListController.GetFilterList().Values;
}
if (e.Key == "Interface/Chat/HighlightWords") {
MessageBuilderSettings.ApplyConfig(UserConfig);
}
if (e.Key == "Interface/Notebook/EngineBufferLines") {
lock (_Chats) {
foreach (var chat in _Chats) {
chat.ApplyConfig(UserConfig);
}
}
}
}
public void CheckPresenceStatus()
{
Trace.Call();
var newStatus = PresenceStatus.Unknown;
var newMessage = String.Empty;
lock (_FrontendManagers) {
if (_FrontendManagers.Count == 0) {
newStatus = PresenceStatus.Away;
newMessage = "away from keyboard";
} else {
newStatus = PresenceStatus.Online;
}
}
if (newStatus == PresenceStatus.Unknown) {
return;
}
UpdatePresenceStatus(newStatus, newMessage);
}
public void Shutdown()
{
Shutdown(false, null);
}
public void Shutdown(bool clean, FrontendManager frontendManager)
{
Trace.Call(clean, frontendManager);
#if LOG4NET
f_Logger.Debug("Shutdown(): flushing all message buffers");
#endif
lock (_Chats) {
foreach (var chat in _Chats) {
try {
chat.MessageBuffer.Flush();
} catch (Exception ex) {
#if LOG4NET
f_Logger.ErrorFormat(
"Shutdown(): {0}.MessageBuffer.Flush() " +
"failed, continuing with shutdown...",
chat.ToString()
);
f_Logger.Error("Shutdown(): Exception", ex);
#endif
}
}
}
if (!clean) {
return;
}
#if LOG4NET
f_Logger.Debug("Shutdown(): disconnecting and disposing all protocol manangers");
#endif
lock (_ProtocolManagers) {
foreach (var protocolManager in _ProtocolManagers) {
try {
protocolManager.Disconnect(frontendManager);
protocolManager.Dispose();
} catch (Exception ex) {
#if LOG4NET
f_Logger.ErrorFormat(
"Shutdown(): {0}.Disconnect/Dispose() " +
"failed, continuing with shutdown...",
protocolManager.ToString()
);
f_Logger.Error("Shutdown(): Exception", ex);
#endif
}
}
}
}
void UpdatePresenceStatus(PresenceStatus status, string message)
{
lock (_ProtocolManagers) {
foreach (var manager in _ProtocolManagers) {
manager.SetPresenceStatus(status, message);
}
}
}
IProtocolManager GetProtocolManagerByHost(string network)
{
lock (_ProtocolManagers) {
foreach (var manager in _ProtocolManagers) {
if (String.Compare(manager.Host, network, true) == 0) {
return manager;
}
}
}
return null;
}
IProtocolManager GetProtocolManagerByNetwork(string network)
{
lock (_ProtocolManagers) {
foreach (var manager in _ProtocolManagers) {
if (String.Compare(manager.NetworkID, network, true) == 0) {
return manager;
}
}
}
return null;
}
int GetSortedChatPosition(ChatModel chatModel)
{
int position = chatModel.Position;
if (position != -1) {
return position;
}
ChatType type = chatModel.ChatType;
if (type != ChatType.Person &&
type != ChatType.Group) {
return position;
}
// new group person and group chats behind their protocol chat
IProtocolManager pm = chatModel.ProtocolManager;
lock (_Chats) {
foreach (var chat in _Chats) {
if (chat.ChatType == ChatType.Protocol &&
chat.ProtocolManager == pm) {
position = _Chats.IndexOf(chat) + 1;
break;
}
}
if (position == -1) {
return position;
}
// now find the first chat with a different protocol manager
foreach (var chat in _Chats.Skip(position)) {
if (chat.ProtocolManager != pm) {
return _Chats.IndexOf(chat);
}
}
}
// if there was no next protocol manager, simply append
// the chat way to the end
return -1;
}
void InitSessionChat()
{
_SessionChat = new SessionChatModel("smuxi", "Smuxi");
_Chats.Add(_SessionChat);
var builder = CreateMessageBuilder();
var text = builder.CreateText(_("Welcome to Smuxi"));
text.ForegroundColor = new TextColor(255, 0, 0);
text.Bold = true;
builder.AppendText(text);
builder.AppendText(Environment.NewLine);
text = builder.CreateText(
_("Type /help to get a list of available commands.")
);
text.Bold = true;
builder.AppendText(text);
builder.AppendText(Environment.NewLine);
text = builder.CreateText(_("After you have made a connection " +
"the list of available commands changes. Go to the newly " +
"opened connection tab and use the /help command again to " +
"see the extended command list."));
text.Bold = true;
builder.AppendText(text);
builder.AppendText(Environment.NewLine);
AddMessageToChat(_SessionChat,builder.ToMessage());
}
void UpdateNewsFeed()
{
Trace.Call();
try {
var proxySettings = new ProxySettings();
proxySettings.ApplyConfig(UserConfig);
var url = "http://news.smuxi.org/feed.php";
var req = WebRequest.Create(url);
req.Proxy = proxySettings.GetWebProxy(url);
if (req is HttpWebRequest) {
var httpReq = (HttpWebRequest) req;
httpReq.UserAgent = Engine.VersionString;
if (NewsFeedLastModified != DateTime.MinValue) {
httpReq.IfModifiedSince = NewsFeedLastModified;
}
}
var res = req.GetResponse();
if (res is HttpWebResponse) {
var httpRes = (HttpWebResponse) res;
if (httpRes.StatusCode == HttpStatusCode.NotModified) {
return;
}
NewsFeedLastModified = httpRes.LastModified;
}
var feed = AtomFeed.Load(res.GetResponseStream());
var sortedEntries = feed.Entry.OrderBy(x => x.Published);
foreach (var entry in sortedEntries) {
if (SeenNewsFeedIds.Contains(entry.Id)) {
continue;
}
SeenNewsFeedIds.Add(entry.Id);
var msg = new FeedMessageBuilder();
if (IsFirstNewsFeedEntry) {
IsFirstNewsFeedEntry = false;
msg.AppendText("\n");
msg.AppendHeader("Smuxi News");
msg.AppendText("\n");
}
msg.Append(entry);
if (!msg.IsEmpty) {
msg.AppendText("\n");
AddMessageToChat(SessionChat, msg.ToMessage());
}
}
} catch (WebException ex) {
switch (ex.Status) {
case WebExceptionStatus.ConnectFailure:
case WebExceptionStatus.ConnectionClosed:
case WebExceptionStatus.Timeout:
case WebExceptionStatus.ReceiveFailure:
case WebExceptionStatus.NameResolutionFailure:
case WebExceptionStatus.ProxyNameResolutionFailure:
#if LOG4NET
f_Logger.Warn(
String.Format(
"UpdateNewsFeed(): Temporarily issue " +
"detected, retrying in {0} min...",
NewsFeedRetryInterval.Minutes
),
ex
);
#endif
NewsFeedTimer.Change(NewsFeedRetryInterval, NewsFeedUpdateInterval);
break;
}
} catch (Exception ex) {
#if LOG4NET
f_Logger.Error("UpdateNewsFeed(): Exception, ignored...", ex);
#endif
}
}
protected virtual void OnGroupChatPersonAdded(GroupChatPersonAddedEventArgs e)
{
if (GroupChatPersonAdded != null) {
GroupChatPersonAdded(this, e);
}
var pm = e.GroupChat.ProtocolManager;
var hooks = new HookRunner("engine", "session", "on-group-chat-person-added");
hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
if (pm != null) {
hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
}
hooks.Environments.Add(new PersonHookEnvironment(e.AddedPerson));
var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
if (pm != null) {
hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
}
// show time
hooks.Init();
hooks.Run();
}
protected virtual void OnGroupChatPersonRemoved(GroupChatPersonRemovedEventArgs e)
{
if (GroupChatPersonRemoved != null) {
GroupChatPersonRemoved(this, e);
}
var pm = e.GroupChat.ProtocolManager;
var hooks = new HookRunner("engine", "session", "on-group-chat-person-removed");
hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
if (pm != null) {
hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
}
hooks.Environments.Add(new PersonHookEnvironment(e.RemovedPerson));
var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
if (pm != null) {
hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
}
// show time
hooks.Init();
hooks.Run();
}
protected virtual void OnGroupChatPersonUpdated(GroupChatPersonUpdatedEventArgs e)
{
if (GroupChatPersonUpdated != null) {
GroupChatPersonUpdated(this, e);
}
var pm = e.GroupChat.ProtocolManager;
var hooks = new HookRunner("engine", "session", "on-group-chat-person-updated");
hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
if (pm != null) {
hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
}
hooks.Environments.Add(new PersonHookEnvironment("OLD_", e.OldPerson));
hooks.Environments.Add(new PersonHookEnvironment("NEW_", e.NewPerson));
var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
if (pm != null) {
hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
}
// show time
hooks.Init();
hooks.Run();
}
protected virtual void OnEventMessage(EventMessageEventArgs e)
{
if (EventMessage != null) {
EventMessage(this, e);
}
var pm = e.Chat.ProtocolManager;
var hooks = new HookRunner("engine", "session", "on-event-message");
hooks.Environments.Add(new ChatHookEnvironment(e.Chat));
if (pm != null) {
hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
}
hooks.Environments.Add(new MessageHookEnvironment(e.Message,
e.Sender,
e.Receiver));
var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
hooks.Commands.Add(new SessionHookCommand(this, e.Chat, cmdChar));
if (pm != null) {
hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.Chat, cmdChar));
}
// show time
hooks.Init();
hooks.Run();
}
private static string _(string msg)
{
return LibraryCatalog.GetString(msg, _LibraryTextDomain);
}
}
public abstract class GroupChatEventArgs : EventArgs
{
public GroupChatModel GroupChat { get; protected set; }
}
public class GroupChatPersonAddedEventArgs : GroupChatEventArgs
{
public PersonModel AddedPerson { get; private set; }
public GroupChatPersonAddedEventArgs(GroupChatModel groupChat, PersonModel addedPerson)
{
GroupChat = groupChat;
AddedPerson = addedPerson;
}
}
public class GroupChatPersonRemovedEventArgs : GroupChatEventArgs
{
public PersonModel RemovedPerson { get; private set; }
public GroupChatPersonRemovedEventArgs(GroupChatModel groupChat, PersonModel removedPerson)
{
GroupChat = groupChat;
RemovedPerson = removedPerson;
}
}
public class GroupChatPersonUpdatedEventArgs : GroupChatEventArgs
{
public PersonModel OldPerson { get; private set; }
public PersonModel NewPerson { get; private set; }
public GroupChatPersonUpdatedEventArgs(GroupChatModel groupChat,
PersonModel oldPerson,
PersonModel newPerson)
{
GroupChat = groupChat;
OldPerson = oldPerson;
NewPerson = newPerson;
}
}
public class EventMessageEventArgs : EventArgs
{
public ChatModel Chat { get; protected set; }
public MessageModel Message { get; protected set; }
public string Sender { get; protected set; }
public string Receiver { get; protected set; }
public EventMessageEventArgs(ChatModel chat, MessageModel msg,
string sender, string receiver)
{
Chat = chat;
Message = msg;
Sender = sender;
Receiver = receiver;
}
}
}