The easy to use and full featured Irc Bot everyone is talking about!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

416 rivejä
21 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Combot.IRCServices.Messaging
{
public class Messages
{
public event EventHandler<string> RawMessageEvent;
public event EventHandler<IReply> ServerReplyEvent;
public event EventHandler<ErrorMessage> ErrorMessageEvent;
public event EventHandler<ChannelMessage> ChannelMessageReceivedEvent;
public event EventHandler<PrivateMessage> PrivateMessageReceivedEvent;
public event EventHandler<ServerNotice> ServerNoticeReceivedEvent;
public event EventHandler<ChannelNotice> ChannelNoticeReceivedEvent;
public event EventHandler<PrivateNotice> PrivateNoticeReceivedEvent;
public event EventHandler<TopicChangeInfo> TopicChangeEvent;
public event EventHandler<ChannelModeChangeInfo> ChannelModeChangeEvent;
public event EventHandler<UserModeChangeInfo> UserModeChangeEvent;
public event EventHandler<NickChangeInfo> NickChangeEvent;
public event EventHandler<InviteChannelInfo> InviteChannelEvent;
public event EventHandler<JoinChannelInfo> JoinChannelEvent;
public event EventHandler<PartChannelInfo> PartChannelEvent;
public event EventHandler<KickInfo> KickEvent;
public event EventHandler<QuitInfo> QuitEvent;
public event EventHandler<PingInfo> PingEvent;
public event EventHandler<PongInfo> PongEvent;
private IRC _IRC;
internal Messages(IRC irc)
{
_IRC = irc;
}
/// <summary>
/// Parses the raw messages coming from the server and triggers an event based on the type of message.
/// </summary>
/// <param name="tcpMessage">The raw string read from the TCP stream.</param>
internal void ParseTCPMessage(string tcpMessage)
{
DateTime messageTime = DateTime.Now;
Regex messageRegex = new Regex(@"^:(?<Sender>[^\s]+)\s(?<Type>[^\s]+)\s(?<Recipient>[^\s]+)\s?:?(?<Args>.*)", RegexOptions.None);
Regex senderRegex = new Regex(@"^(?<Nick>[^\s]+)!(?<Realname>[^\s]+)@(?<Host>[^\s]+)", RegexOptions.None);
Regex pingRegex = new Regex(@"^PING :(?<Message>.+)", RegexOptions.None);
Regex pongRegex = new Regex(@"^PONG :(?<Message>.+)", RegexOptions.None);
Regex errorRegex = new Regex(@"^ERROR :(?<Message>.+)", RegexOptions.None);
string[] messages = tcpMessage.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string message in messages)
{
if (messageRegex.IsMatch(message))
{
Match match = messageRegex.Match(message);
string type = match.Groups["Type"].Value;
string sender = match.Groups["Sender"].Value;
string recipient = match.Groups["Recipient"].Value;
string args = match.Groups["Args"].Value;
Match senderMatch = senderRegex.Match(sender);
string senderNick = sender;
string senderRealname = sender;
string senderHost = sender;
if (senderMatch.Success)
{
senderNick = senderMatch.Groups["Nick"].Value;
senderRealname = senderMatch.Groups["Realname"].Value;
senderHost = senderMatch.Groups["Host"].Value;
}
int replyCode;
if (int.TryParse(type, out replyCode))
{
// The message was a reply to a command sent
if (Enum.IsDefined(typeof(IRCReplyCode), replyCode))
{
if (ServerReplyEvent != null)
{
ServerReplyEvent(this, new ServerReplyMessage() { TimeStamp = messageTime, ReplyCode = (IRCReplyCode)replyCode, Message = args });
}
}
else if (Enum.IsDefined(typeof(IRCErrorCode), replyCode))
{
if (ServerReplyEvent != null)
{
ServerReplyEvent(this, new ServerErrorMessage() { TimeStamp = messageTime, ErrorCode = (IRCErrorCode)replyCode, Message = args });
}
}
}
else
{
switch (type)
{
// The message was a private message to a channel or nick
case "PRIVMSG":
if (recipient.StartsWith("&") || recipient.StartsWith("#"))
{
ChannelMessage msg = new ChannelMessage();
msg.Channel = recipient;
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
if (ChannelMessageReceivedEvent != null)
{
ChannelMessageReceivedEvent(this, msg);
}
}
else
{
PrivateMessage msg = new PrivateMessage();
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
if (PrivateMessageReceivedEvent != null)
{
PrivateMessageReceivedEvent(this, msg);
}
}
break;
// The message was a notice to a channel or nick
case "NOTICE":
if (recipient.StartsWith("&") || recipient.StartsWith("#"))
{
ChannelNotice msg = new ChannelNotice();
msg.Channel = recipient;
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
if (ChannelNoticeReceivedEvent != null)
{
ChannelNoticeReceivedEvent(this, msg);
}
}
else
{
PrivateNotice msg = new PrivateNotice();
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
if (PrivateNoticeReceivedEvent != null)
{
PrivateNoticeReceivedEvent(this, msg);
}
}
break;
// The message was a mode change message for a channel or nick
case "MODE":
if (recipient.StartsWith("&") || recipient.StartsWith("#"))
{
ChannelModeChangeInfo modeMsg = new ChannelModeChangeInfo();
modeMsg.Modes = new List<ChannelModeInfo>();
modeMsg.Channel = recipient;
modeMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
string[] modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
char[] modeInfo = modeArgs[0].TrimStart(':').ToCharArray();
bool set = true;
int argIndex = 1;
foreach (char mode in modeInfo)
{
if (mode.Equals('-'))
{
set = false;
}
else if (mode.Equals('+'))
{
set = true;
}
else
{
ChannelModeInfo newMode = new ChannelModeInfo();
newMode.Set = set;
newMode.Mode = (ChannelMode)Enum.Parse(typeof(ChannelMode), mode.ToString());
if (modeArgs.GetUpperBound(0) >= argIndex)
{
switch (newMode.Mode)
{
case ChannelMode.k:
case ChannelMode.l:
case ChannelMode.v:
case ChannelMode.h:
case ChannelMode.o:
case ChannelMode.a:
case ChannelMode.q:
case ChannelMode.b:
case ChannelMode.e:
case ChannelMode.I:
newMode.Parameter = modeArgs[argIndex];
argIndex++;
break;
default:
newMode.Parameter = string.Empty;
break;
}
}
else
{
newMode.Parameter = string.Empty;
}
modeMsg.Modes.Add(newMode);
}
}
if (ChannelModeChangeEvent != null)
{
ChannelModeChangeEvent(this, modeMsg);
}
}
else
{
UserModeChangeInfo modeMsg = new UserModeChangeInfo();
modeMsg.Modes = new List<UserModeInfo>();
modeMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
string[] modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
char[] modeInfo = modeArgs[0].TrimStart(':').ToCharArray();
bool set = true;
foreach (char mode in modeInfo)
{
if (mode.Equals('-'))
{
set = false;
}
else if (mode.Equals('+'))
{
set = true;
}
else
{
UserModeInfo newMode = new UserModeInfo();
newMode.Set = set;
newMode.Mode = (UserMode)Enum.Parse(typeof(UserMode), mode.ToString());
modeMsg.Modes.Add(newMode);
}
}
if (UserModeChangeEvent != null)
{
UserModeChangeEvent(this, modeMsg);
}
}
break;
// The message was a topic change for a channel
case "TOPIC":
TopicChangeInfo topicMsg = new TopicChangeInfo();
topicMsg.Channel = recipient;
topicMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
topicMsg.Topic = args;
if (TopicChangeEvent != null)
{
TopicChangeEvent(this, topicMsg);
}
break;
// The message was a nick change
case "NICK":
NickChangeInfo nickMsg = new NickChangeInfo();
nickMsg.OldNick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
nickMsg.NewNick = new Nick() { Nickname = recipient.Remove(0, 1) };
if (NickChangeEvent != null)
{
NickChangeEvent(this, nickMsg);
}
break;
// The message was an invite to a channel
case "INVITE":
InviteChannelInfo inviteMsg = new InviteChannelInfo();
inviteMsg.Requester = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
inviteMsg.Recipient = new Nick() { Nickname = recipient };
inviteMsg.Channel = args;
if (InviteChannelEvent != null)
{
InviteChannelEvent(this, inviteMsg);
}
break;
// The message was a nick joining a channel
case "JOIN":
JoinChannelInfo joinMsg = new JoinChannelInfo();
joinMsg.Channel = recipient.TrimStart(':');
joinMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
if (JoinChannelEvent != null)
{
JoinChannelEvent(this, joinMsg);
}
break;
// The message was a nick parting a channel
case "PART":
PartChannelInfo partMsg = new PartChannelInfo();
partMsg.Channel = recipient;
partMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
if (PartChannelEvent != null)
{
PartChannelEvent(this, partMsg);
}
break;
// The message was a nick being kicked from a channel
case "KICK":
KickInfo kickMsg = new KickInfo();
kickMsg.Channel = recipient;
kickMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
string[] argSplit = args.Split(new char[] { ' ' }, StringSplitOptions.None);
kickMsg.KickedNick = new Nick() { Nickname = argSplit[0], Realname = argSplit[0], Host = argSplit[0] };
List<string> reasonArgs = argSplit.ToList<string>();
reasonArgs.RemoveAt(0);
kickMsg.Reason = string.Join(" ", reasonArgs.ToArray()).Remove(0, 1);
if (KickEvent != null)
{
KickEvent(this, kickMsg);
}
break;
// The message was a nick quiting the irc network
case "QUIT":
QuitInfo quitMsg = new QuitInfo();
quitMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
quitMsg.Message = recipient.Remove(0, 1);
if (QuitEvent != null)
{
QuitEvent(this, quitMsg);
}
break;
default:
break;
}
}
}
else if (pingRegex.IsMatch(message)) // The message was a PING
{
Match match = pingRegex.Match(message);
PingInfo ping = new PingInfo();
ping.Message = match.Groups["Message"].Value;
if (PingEvent != null)
{
PingEvent(this, ping);
}
}
else if (pongRegex.IsMatch(message)) // The message was a PONG
{
Match match = pongRegex.Match(message);
PongInfo pong = new PongInfo();
pong.Message = match.Groups["Message"].Value;
if (PongEvent != null)
{
PongEvent(this, pong);
}
}
else if (errorRegex.IsMatch(message)) // The message was a server error
{
Match match = errorRegex.Match(message);
ErrorMessage error = new ErrorMessage();
error.Message = match.Groups["Message"].Value;
if (ErrorMessageEvent != null)
{
ErrorMessageEvent(this, error);
}
}
if (RawMessageEvent != null)
{
RawMessageEvent(this, message);
}
}
}
internal bool GetReply(List<IRCReplyCode> ReplyCodes, List<IRCErrorCode> ErrorCodes)
{
GetReply reply = new GetReply();
reply.Replies = ReplyCodes;
reply.Errors = ErrorCodes;
ServerReplyEvent += (sender, e) => HandleReply(sender, e, reply);
reply.Ready.Wait(TimeSpan.FromMilliseconds(5000));
reply.Reattach = false;
return reply.Result;
}
private void HandleReply(object sender, IReply message, GetReply reply)
{
bool replyFound = false;
if (message.GetType() == typeof(ServerReplyMessage))
{
ServerReplyMessage msg = (ServerReplyMessage)message;
replyFound = reply.Replies.Contains(msg.ReplyCode);
}
else
{
ServerErrorMessage msg = (ServerErrorMessage)message;
replyFound = reply.Errors.Contains(msg.ErrorCode);
}
if (replyFound)
{
reply.Result = replyFound;
reply.Ready.Set();
}
else
{
if (reply.Reattach)
{
ServerReplyEvent += (obj, e) => HandleReply(obj, e, reply);
}
}
}
}
}