123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- 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);
- }
- }
- }
- }
- }
|