1
0
Fork 0
The easy to use and full featured Irc Bot everyone is talking about!
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

513 Zeilen
25 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<CTCPMessage> CTCPMessageReceivedEvent;
public event EventHandler<CTCPMessage> CTCPNoticeReceivedEvent;
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 async 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);
Regex CTCPRegex = new Regex(@"^\u0001(?<Command>[^\s]+)\s?(?<Args>.*)\u0001", 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))
{
await Task.Run(() =>
{
if (ServerReplyEvent != null)
{
ServerReplyEvent(this,
new ServerReplyMessage()
{
TimeStamp = messageTime,
ReplyCode = (IRCReplyCode) replyCode,
Message = args
});
}
});
}
else if (Enum.IsDefined(typeof(IRCErrorCode), replyCode))
{
await Task.Run(() =>
{
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 (CTCPRegex.IsMatch(args))
{
Match ctcpMatch = CTCPRegex.Match(args);
CTCPMessage ctcpMessage = new CTCPMessage();
ctcpMessage.Sender = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
ctcpMessage.Command = ctcpMatch.Groups["Command"].Value;
ctcpMessage.Arguments = ctcpMatch.Groups["Args"].Value;
await Task.Run(() =>
{
if (CTCPMessageReceivedEvent != null)
{
CTCPMessageReceivedEvent(this, ctcpMessage);
}
});
}
else
{
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;
await Task.Run(() =>
{
if (ChannelMessageReceivedEvent != null)
{
ChannelMessageReceivedEvent(this, msg);
}
});
}
else
{
PrivateMessage msg = new PrivateMessage();
msg.Sender = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
msg.Message = args;
await Task.Run(() =>
{
if (PrivateMessageReceivedEvent != null)
{
PrivateMessageReceivedEvent(this, msg);
}
});
}
}
break;
// The message was a notice to a channel or nick
case "NOTICE":
if (CTCPRegex.IsMatch(args))
{
Match ctcpMatch = CTCPRegex.Match(args);
CTCPMessage ctcpMessage = new CTCPMessage();
ctcpMessage.Sender = new Nick()
{
Nickname = senderNick,
Realname = senderRealname,
Host = senderHost
};
ctcpMessage.Command = ctcpMatch.Groups["Command"].Value;
ctcpMessage.Arguments = ctcpMatch.Groups["Args"].Value;
await Task.Run(() =>
{
if (CTCPNoticeReceivedEvent != null)
{
CTCPNoticeReceivedEvent(this, ctcpMessage);
}
});
}
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;
await Task.Run(() =>
{
if (ChannelNoticeReceivedEvent != null)
{
ChannelNoticeReceivedEvent(this, msg);
}
});
}
else
{
PrivateNotice msg = new PrivateNotice();
msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
msg.Message = args;
await Task.Run(() =>
{
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);
List<string> argList = modeArgs.ToList();
argList.RemoveAt(0);
modeMsg.Modes.AddRange(_IRC.ParseChannelModeString(modeArgs[0].TrimStart(':'), string.Join(" ", argList)));
await Task.Run(() =>
{
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 if (mode.ToString() != string.Empty)
{
UserModeInfo newMode = new UserModeInfo();
newMode.Set = set;
newMode.Mode = (UserMode)Enum.Parse(typeof(UserMode), mode.ToString());
modeMsg.Modes.Add(newMode);
}
}
await Task.Run(() =>
{
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;
await Task.Run(() =>
{
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.TrimStart(':') };
await Task.Run(() =>
{
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;
await Task.Run(() =>
{
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 };
await Task.Run(() =>
{
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 };
await Task.Run(() =>
{
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);
await Task.Run(() =>
{
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 = string.Join(" ", recipient.Remove(0, 1), args);
await Task.Run(() =>
{
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;
await Task.Run(() =>
{
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;
await Task.Run(() =>
{
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);
}
}
string rawMessage = message;
await Task.Run(() =>
{
if (RawMessageEvent != null)
{
RawMessageEvent(this, rawMessage);
}
});
}
}
public ServerReplyMessage GetServerReply(IRCReplyCode replyCode, string match)
{
GetReply reply = new GetReply();
reply.Reply = replyCode;
reply.Match = match;
ServerReplyEvent += (sender, e) => HandleReply(sender, e, reply);
reply.Ready.Wait(TimeSpan.FromMilliseconds(5000));
return reply.Result;
}
public ServerErrorMessage GetServerError(IRCErrorCode errorCode, string match)
{
GetError error = new GetError();
error.Error = errorCode;
error.Match = match;
ServerReplyEvent += (sender, e) => HandleError(sender, e, error);
error.Ready.Wait(TimeSpan.FromMilliseconds(5000));
return error.Result;
}
private void HandleReply(object sender, IReply message, GetReply reply)
{
bool replyFound = false;
Regex replyRegex = new Regex(reply.Match);
if (message.GetType() == typeof(ServerReplyMessage))
{
ServerReplyMessage msg = (ServerReplyMessage)message;
replyFound = reply.Reply.Equals(msg.ReplyCode);
if (replyFound && replyRegex.IsMatch(msg.Message))
{
reply.Result = msg;
reply.Ready.Set();
}
}
}
private void HandleError(object sender, IReply message, GetError error)
{
bool errorFound = false;
Regex errorRegex = new Regex(error.Match);
if (message.GetType() == typeof(ServerErrorMessage))
{
ServerErrorMessage msg = (ServerErrorMessage)message;
errorFound = error.Error.Equals(msg.ErrorCode);
if (errorFound && errorRegex.IsMatch(msg.Message))
{
error.Result = msg;
error.Ready.Set();
}
}
}
}
}