void HandleMessage([NotNull] string message) {
if (message == null) throw new ArgumentNullException("message");
IRCMessage msg = MessageParser(message, ActualBotNick);
#if DEBUG_IRC
Logger.Log( LogType.IrcStatus,
"[{0}.{1}] {2}",
msg.Type, msg.ReplyCode, msg.RawMessage );
#endif
switch (msg.Type) {
case IRCMessageType.Login:
if (msg.ReplyCode == IRCReplyCode.Welcome) {
AuthWithNickServ();
foreach (string channel in channelNames) {
Send(IRCCommands.Join(channel));
}
IsReady = true;
Send(IRCCommands.Userhost(ActualBotNick));
AssignBotForInputParsing(); // bot should be ready to receive input after joining
} else if (msg.ReplyCode == IRCReplyCode.Bounce) {
Match nickLenMatch = MaxNickLengthRegex.Match(msg.Message);
int maxNickLengthTemp;
if (nickLenMatch.Success &&
Int32.TryParse(nickLenMatch.Groups[1].Value, out maxNickLengthTemp)) {
maxNickLength = maxNickLengthTemp;
}
}
return;
case IRCMessageType.Ping:
// ping-pong
Send(IRCCommands.Pong(msg.RawMessageArray[1].Substring(1)));
return;
case IRCMessageType.ChannelAction:
case IRCMessageType.ChannelMessage:
// channel chat
if (!ResponsibleForInputParsing) return;
if (!IsBotNick(msg.Nick)) {
string rawMessage = msg.Message;
if (msg.Type == IRCMessageType.ChannelAction) {
if (rawMessage.StartsWith("\u0001ACTION")) {
rawMessage = rawMessage.Substring(8);
} else {
return;
}
}
string processedMessage = ProcessMessageFromIRC(rawMessage);
if (processedMessage.Length > 0) {
if (ConfigKey.IRCBotForwardFromIRC.Enabled()) {
if (msg.Type == IRCMessageType.ChannelAction) {
Server.Message("&i(IRC) * {0} {1}",
msg.Nick,
processedMessage);
Logger.Log(LogType.IrcChat,
"{0}: * {1} {2}",
msg.Channel,
msg.Nick,
IRCColorsAndNonStandardCharsExceptEmotes.Replace(rawMessage, ""));
} else {
Server.Message("&i(IRC) {0}{1}: {2}",
msg.Nick,
ChatColor.White,
processedMessage);
Logger.Log(LogType.IrcChat,
"{0}: {1}: {2}",
msg.Channel,
msg.Nick,
IRCColorsAndNonStandardCharsExceptEmotes.Replace(rawMessage, ""));
}
} else if (msg.Message.StartsWith("#")) {
Server.Message("&i(IRC) {0}{1}: {2}",
msg.Nick,
ChatColor.White,
processedMessage.Substring(1));
Logger.Log(LogType.IrcChat,
"{0}: {1}: {2}",
msg.Channel,
msg.Nick,
IRCColorsAndNonStandardCharsExceptEmotes.Replace(rawMessage, ""));
}
}
}
return;
case IRCMessageType.Join:
if (!ResponsibleForInputParsing) return;
if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled()) {
Server.Message("&i(IRC) {0} joined {1}",
msg.Nick,
msg.Channel);
Logger.Log(LogType.IrcChat,
"{0} joined {1}",
msg.Nick,
msg.Channel);
}
return;
case IRCMessageType.Kick:
string kicked = msg.RawMessageArray[3];
if (kicked == ActualBotNick) {
// If we got kicked, attempt to rejoin
Logger.Log(LogType.IrcStatus,
"IRC Bot was kicked from {0} by {1} ({2}), rejoining.",
msg.Channel,
msg.Nick,
msg.Message);
Thread.Sleep(ReconnectDelay);
Send(IRCCommands.Join(msg.Channel));
} else {
if (!ResponsibleForInputParsing) return;
// Someone else got kicked -- announce it
string kickMessage = ProcessMessageFromIRC(msg.Message);
Server.Message("&i(IRC) {0} kicked {1} from {2} ({3})",
msg.Nick,
kicked,
msg.Channel,
kickMessage);
Logger.Log(LogType.IrcChat,
"{0} kicked {1} from {2} ({3})",
msg.Nick,
kicked,
msg.Channel,
IRCColorsAndNonStandardCharsExceptEmotes.Replace(kickMessage, ""));
}
return;
case IRCMessageType.Part:
case IRCMessageType.Quit:
// If someone using our desired nick just quit, retry for that nick
if (msg.Type == IRCMessageType.Quit &&
msg.Nick == desiredBotNick &&
ActualBotNick != desiredBotNick) {
RetryForDesiredNick();
return;
}
if (!ResponsibleForInputParsing) return;
// Announce parts/quits of IRC people (except the bots)
if (ConfigKey.IRCBotAnnounceIRCJoins.Enabled() && !IsBotNick(msg.Nick)) {
Server.Message("&i(IRC) {0} left {1}",
msg.Nick,
msg.Channel);
string quitMsg = (msg.Message == null)
? "Quit"
: IRCColorsAndNonStandardCharsExceptEmotes.Replace(msg.Message, "");
Logger.Log(LogType.IrcChat,
"{0} left {1} ({2})",
msg.Nick,
msg.Channel,
quitMsg);
}
return;
case IRCMessageType.NickChange:
if (msg.Nick == ActualBotNick) {
ActualBotNick = msg.Message;
nickTry = 0;
Logger.Log(LogType.IrcStatus,
"Bot was renamed from {0} to {1}",
msg.Nick,
msg.Message);
AuthWithNickServ();
} else {
if (!ResponsibleForInputParsing) return;
Server.Message("&i(IRC) {0} is now known as {1}",
msg.Nick,
msg.Message);
}
return;
case IRCMessageType.ErrorMessage:
case IRCMessageType.Error:
bool die = false;
switch (msg.ReplyCode) {
case IRCReplyCode.ErrorNicknameInUse:
case IRCReplyCode.ErrorNicknameCollision:
// Possibility 1: we tried to go for primary nick, but it's still taken
string currentName = msg.RawMessageArray[2];
string desiredName = msg.RawMessageArray[3];
if (currentName == ActualBotNick && desiredName == desiredBotNick) {
Logger.Log(LogType.IrcStatus,
"Error: Desired nick \"{0}\" is still in use. Will retry shortly.",
desiredBotNick);
break;
}
// Possibility 2: We don't have any nick yet, the one we wanted is in use
string oldActualBotNick = ActualBotNick;
if (ActualBotNick.Length < maxNickLength) {
// append '_' to the end of desired nick, if we can
ActualBotNick += "_";
} else {
// if resulting nick is too long, add a number to the end instead
nickTry++;
if (desiredBotNick.Length + nickTry/10 + 1 > maxNickLength) {
ActualBotNick = desiredBotNick.Substring(0, maxNickLength - nickTry/10 - 1) +
nickTry;
} else {
ActualBotNick = desiredBotNick + nickTry;
}
}
Logger.Log(LogType.IrcStatus,
"Error: Nickname \"{0}\" is already in use. Trying \"{1}\"",
oldActualBotNick,
ActualBotNick);
Send(IRCCommands.Nick(ActualBotNick));
Send(IRCCommands.Userhost(ActualBotNick));
break;
case IRCReplyCode.ErrorBannedFromChannel:
case IRCReplyCode.ErrorNoSuchChannel:
Logger.Log(LogType.IrcStatus,
"Error: {0} ({1})",
msg.ReplyCode,
msg.Channel);
die = true;
break;
case IRCReplyCode.ErrorBadChannelKey:
Logger.Log(LogType.IrcStatus,
"Error: Channel password required for {0}. " +
"fCraft does not currently support password-protected channels.",
msg.Channel);
die = true;
break;
default:
Logger.Log(LogType.IrcStatus,
"Error ({0}): {1}",
msg.ReplyCode,
msg.RawMessage);
break;
}
if (die) {
Logger.Log(LogType.IrcStatus, "Error: Disconnecting.");
reconnect = false;
DisconnectThread(null);
}
return;
case IRCMessageType.QueryAction:
// TODO: PMs
Logger.Log(LogType.IrcStatus,
"Query: {0}",
msg.RawMessage);
break;
case IRCMessageType.Kill:
Logger.Log(LogType.IrcStatus,
"Bot was killed from {0} by {1} ({2}), reconnecting.",
hostName,
msg.Nick,
msg.Message);
reconnect = true;
isConnected = false;
return;
case IRCMessageType.Unknown:
if (msg.ReplyCode == IRCReplyCode.UserHost) {
Match match = UserHostRegex.Match(msg.Message);
if (match.Success) {
userHostLength = match.Groups[1].Length;
}
}
return;
}
}