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.

Messages.cs 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Threading.Tasks;
  7. namespace Combot.IRCServices.Messaging
  8. {
  9. public class Messages
  10. {
  11. public event EventHandler<IReply> ServerReplyEvent;
  12. public event EventHandler<ErrorMessage> ErrorMessageEvent;
  13. public event EventHandler<ChannelMessage> ChannelMessageReceivedEvent;
  14. public event EventHandler<PrivateMessage> PrivateMessageReceivedEvent;
  15. public event EventHandler<ServerNotice> ServerNoticeReceivedEvent;
  16. public event EventHandler<ChannelNotice> ChannelNoticeReceivedEvent;
  17. public event EventHandler<PrivateNotice> PrivateNoticeReceivedEvent;
  18. public event EventHandler<TopicChangeInfo> TopicChangeEvent;
  19. public event EventHandler<ChannelModeChangeInfo> ChannelModeChangeEvent;
  20. public event EventHandler<UserModeChangeInfo> UserModeChangeEvent;
  21. public event EventHandler<JoinChannelInfo> JoinChannelEvent;
  22. public event EventHandler<PartChannelInfo> PartChannelEvent;
  23. public event EventHandler<KickInfo> KickEvent;
  24. public event EventHandler<QuitInfo> QuitEvent;
  25. public event EventHandler<PingInfo> PingEvent;
  26. public event EventHandler<PongInfo> PongEvent;
  27. private IRC _IRC;
  28. internal Messages(IRC irc)
  29. {
  30. _IRC = irc;
  31. }
  32. internal void ParseTCPMessage(string tcpMessage)
  33. {
  34. DateTime messageTime = DateTime.Now;
  35. Regex messageRegex = new Regex(@"^:(?<Sender>[^\s]+)\s(?<Type>[^\s]+)\s(?<Recipient>[^\s]+)\s(?<Args>.*)", RegexOptions.None);
  36. Regex senderRegex = new Regex(@"^:(?<Nick>[^\s]+)!(?<Realname>[^\s]+)@(?<Host>[^\s]+)", RegexOptions.None);
  37. Regex pingRegex = new Regex(@"^PING :(?<Message>.+)", RegexOptions.None);
  38. Regex pongRegex = new Regex(@"^PONG :(?<Message>.+)", RegexOptions.None);
  39. Regex errorRegex = new Regex(@"^ERROR :(?<Message>.+)", RegexOptions.None);
  40. string[] messages = tcpMessage.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
  41. foreach (string message in messages)
  42. {
  43. if (messageRegex.IsMatch(message))
  44. {
  45. Match match = messageRegex.Match(message);
  46. string type = match.Groups["Type"].Value;
  47. string sender = match.Groups["Sender"].Value;
  48. string recipient = match.Groups["Recipient"].Value;
  49. string args = match.Groups["Args"].Value;
  50. Match senderMatch = senderRegex.Match(sender);
  51. string senderNick = sender;
  52. string senderRealname = sender;
  53. string senderHost = sender;
  54. if (senderMatch.Success)
  55. {
  56. senderNick = senderMatch.Groups["Nick"].Value;
  57. senderRealname = senderMatch.Groups["Realname"].Value;
  58. senderHost = senderMatch.Groups["Nick"].Value;
  59. }
  60. int replyCode;
  61. if (int.TryParse(type, out replyCode))
  62. {
  63. // The message was a reply to a command sent
  64. if (Enum.IsDefined(typeof(IRCReplyCode), replyCode))
  65. {
  66. if (ServerReplyEvent != null)
  67. {
  68. ServerReplyEvent(this, new ServerReplyMessage() { TimeStamp = messageTime, ReplyCode = (IRCReplyCode)replyCode, Message = args.Remove(0, 1) });
  69. }
  70. }
  71. else if (Enum.IsDefined(typeof(IRCErrorCode), replyCode))
  72. {
  73. if (ServerReplyEvent != null)
  74. {
  75. ServerReplyEvent(this, new ServerErrorMessage() { TimeStamp = messageTime, ErrorCode = (IRCErrorCode)replyCode, Message = args.Remove(0, 1) });
  76. }
  77. }
  78. }
  79. else
  80. {
  81. switch (type)
  82. {
  83. case "PRIVMSG":
  84. if (recipient.StartsWith("&") || recipient.StartsWith("#"))
  85. {
  86. ChannelMessage msg = new ChannelMessage();
  87. msg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  88. if (msg.Channel != null && msg.Channel.Modes != null && msg.Channel.Modes.Contains(ChannelMode.n))
  89. {
  90. msg.Sender = msg.Channel.Nicks.Find(nick => nick.Nickname == senderNick);
  91. }
  92. else
  93. {
  94. msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  95. }
  96. msg.Message = args.Remove(0, 1);
  97. if (ChannelMessageReceivedEvent != null)
  98. {
  99. ChannelMessageReceivedEvent(this, msg);
  100. }
  101. }
  102. else
  103. {
  104. PrivateMessage msg = new PrivateMessage();
  105. msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  106. msg.Message = args.Remove(0, 1);
  107. if (PrivateMessageReceivedEvent != null)
  108. {
  109. PrivateMessageReceivedEvent(this, msg);
  110. }
  111. }
  112. break;
  113. case "NOTICE":
  114. if (recipient.StartsWith("&") || recipient.StartsWith("#"))
  115. {
  116. ChannelNotice msg = new ChannelNotice();
  117. msg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  118. if (msg.Channel != null && msg.Channel.Modes != null && msg.Channel.Modes.Contains(ChannelMode.n))
  119. {
  120. msg.Sender = msg.Channel.Nicks.Find(nick => nick.Nickname == senderNick);
  121. }
  122. else
  123. {
  124. msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  125. }
  126. msg.Message = args.Remove(0, 1);
  127. if (ChannelNoticeReceivedEvent != null)
  128. {
  129. ChannelNoticeReceivedEvent(this, msg);
  130. }
  131. }
  132. else
  133. {
  134. PrivateNotice msg = new PrivateNotice();
  135. msg.Sender = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  136. msg.Message = args.Remove(0, 1);
  137. if (PrivateNoticeReceivedEvent != null)
  138. {
  139. PrivateNoticeReceivedEvent(this, msg);
  140. }
  141. }
  142. break;
  143. case "MODE":
  144. if (recipient.StartsWith("&") || recipient.StartsWith("#"))
  145. {
  146. ChannelModeChangeInfo modeMsg = new ChannelModeChangeInfo();
  147. modeMsg.Modes = new List<ChannelModeInfo>();
  148. modeMsg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  149. if (modeMsg.Channel != null && modeMsg.Channel.Nicks != null && modeMsg.Channel.Nicks.Exists(nick => nick.Nickname == senderNick))
  150. {
  151. modeMsg.Nick = modeMsg.Channel.Nicks.Find(nick => nick.Nickname == senderNick);
  152. }
  153. else
  154. {
  155. modeMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  156. }
  157. string[] modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  158. char[] modeInfo = modeArgs[0].TrimStart(':').ToCharArray();
  159. bool set = true;
  160. int argIndex = 1;
  161. foreach (char mode in modeInfo)
  162. {
  163. if (mode.Equals('-'))
  164. {
  165. set = false;
  166. }
  167. else if (mode.Equals('+'))
  168. {
  169. set = true;
  170. }
  171. else
  172. {
  173. ChannelModeInfo newMode = new ChannelModeInfo();
  174. newMode.Set = set;
  175. newMode.Mode = (ChannelMode)Enum.Parse(typeof(ChannelMode), mode.ToString());
  176. if (modeArgs.GetUpperBound(0) > argIndex)
  177. {
  178. switch (newMode.Mode)
  179. {
  180. case ChannelMode.k:
  181. case ChannelMode.l:
  182. case ChannelMode.v:
  183. case ChannelMode.h:
  184. case ChannelMode.o:
  185. case ChannelMode.a:
  186. case ChannelMode.q:
  187. case ChannelMode.b:
  188. case ChannelMode.e:
  189. case ChannelMode.I:
  190. newMode.Parameter = modeArgs[argIndex];
  191. argIndex++;
  192. break;
  193. default:
  194. newMode.Parameter = string.Empty;
  195. break;
  196. }
  197. }
  198. else
  199. {
  200. newMode.Parameter = string.Empty;
  201. }
  202. modeMsg.Modes.Add(newMode);
  203. }
  204. }
  205. if (ChannelModeChangeEvent != null)
  206. {
  207. ChannelModeChangeEvent(this, modeMsg);
  208. }
  209. }
  210. else
  211. {
  212. UserModeChangeInfo modeMsg = new UserModeChangeInfo();
  213. modeMsg.Modes = new List<UserModeInfo>();
  214. string[] modeArgs = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  215. char[] modeInfo = modeArgs[0].TrimStart(':').ToCharArray();
  216. bool set = true;
  217. foreach (char mode in modeInfo)
  218. {
  219. if (mode.Equals('-'))
  220. {
  221. set = false;
  222. }
  223. else if (mode.Equals('+'))
  224. {
  225. set = true;
  226. }
  227. else
  228. {
  229. UserModeInfo newMode = new UserModeInfo();
  230. newMode.Set = set;
  231. newMode.Mode = (UserMode)Enum.Parse(typeof(UserMode), mode.ToString());
  232. modeMsg.Modes.Add(newMode);
  233. }
  234. }
  235. if (UserModeChangeEvent != null)
  236. {
  237. UserModeChangeEvent(this, modeMsg);
  238. }
  239. }
  240. break;
  241. case "TOPIC":
  242. TopicChangeInfo topicMsg = new TopicChangeInfo();
  243. topicMsg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  244. if (topicMsg.Channel != null && topicMsg.Channel.Nicks != null && topicMsg.Channel.Nicks.Exists(nick => nick.Nickname == senderNick))
  245. {
  246. topicMsg.Nick = topicMsg.Channel.Nicks.Find(nick => nick.Nickname == senderNick);
  247. }
  248. else
  249. {
  250. topicMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  251. }
  252. topicMsg.Topic = args.Remove(0, 1);
  253. if (TopicChangeEvent != null)
  254. {
  255. TopicChangeEvent(this, topicMsg);
  256. }
  257. break;
  258. case "JOIN":
  259. JoinChannelInfo joinMsg = new JoinChannelInfo();
  260. joinMsg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient.TrimStart(':'));
  261. joinMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  262. if (JoinChannelEvent != null)
  263. {
  264. JoinChannelEvent(this, joinMsg);
  265. }
  266. break;
  267. case "PART":
  268. PartChannelInfo partMsg = new PartChannelInfo();
  269. partMsg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  270. partMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  271. if (PartChannelEvent != null)
  272. {
  273. PartChannelEvent(this, partMsg);
  274. }
  275. break;
  276. case "KICK":
  277. KickInfo kickMsg = new KickInfo();
  278. kickMsg.Channel = _IRC.Channels.Find(channel => channel.Name == recipient);
  279. kickMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  280. string[] argSplit = args.Split(new char[] { ' ' }, StringSplitOptions.None);
  281. kickMsg.KickedNick = kickMsg.Channel.Nicks.Find(nick => nick.Nickname == argSplit[0]);
  282. List<string> reasonArgs = argSplit.ToList<string>();
  283. reasonArgs.RemoveAt(0);
  284. kickMsg.Reason = string.Join(" ", reasonArgs.ToArray()).Remove(0, 1);
  285. if (KickEvent != null)
  286. {
  287. KickEvent(this, kickMsg);
  288. }
  289. break;
  290. case "QUIT":
  291. QuitInfo quitMsg = new QuitInfo();
  292. quitMsg.Nick = new Nick() { Nickname = senderNick, Realname = senderRealname, Host = senderHost };
  293. quitMsg.Message = recipient.Remove(0, 1);
  294. if (QuitEvent != null)
  295. {
  296. QuitEvent(this, quitMsg);
  297. }
  298. break;
  299. default:
  300. break;
  301. }
  302. }
  303. }
  304. else if (pingRegex.IsMatch(message))
  305. {
  306. Match match = pingRegex.Match(message);
  307. PingInfo ping = new PingInfo();
  308. ping.Message = match.Groups["Message"].Value;
  309. if (PingEvent != null)
  310. {
  311. PingEvent(this, ping);
  312. }
  313. }
  314. else if (pongRegex.IsMatch(message))
  315. {
  316. Match match = pongRegex.Match(message);
  317. PongInfo pong = new PongInfo();
  318. pong.Message = match.Groups["Message"].Value;
  319. if (PongEvent != null)
  320. {
  321. PongEvent(this, pong);
  322. }
  323. }
  324. else if (errorRegex.IsMatch(message))
  325. {
  326. Match match = errorRegex.Match(message);
  327. ErrorMessage error = new ErrorMessage();
  328. error.Message = match.Groups["Message"].Value;
  329. if (ErrorMessageEvent != null)
  330. {
  331. ErrorMessageEvent(this, error);
  332. }
  333. }
  334. }
  335. }
  336. internal bool GetReply(List<IRCReplyCode> ReplyCodes, List<IRCErrorCode> ErrorCodes)
  337. {
  338. GetReply reply = new GetReply();
  339. reply.Replies = ReplyCodes;
  340. reply.Errors = ErrorCodes;
  341. ServerReplyEvent += (sender, e) => HandleReply(sender, e, reply);
  342. reply.Ready.Wait(TimeSpan.FromMilliseconds(5000));
  343. reply.Reattach = false;
  344. return reply.Result;
  345. }
  346. private void HandleReply(object sender, IReply message, GetReply reply)
  347. {
  348. bool replyFound = false;
  349. if (message.GetType() == typeof(ServerReplyMessage))
  350. {
  351. ServerReplyMessage msg = (ServerReplyMessage)message;
  352. replyFound = reply.Replies.Contains(msg.ReplyCode);
  353. }
  354. else
  355. {
  356. ServerErrorMessage msg = (ServerErrorMessage)message;
  357. replyFound = reply.Errors.Contains(msg.ErrorCode);
  358. }
  359. if (replyFound)
  360. {
  361. reply.Result = replyFound;
  362. reply.Ready.Set();
  363. }
  364. else
  365. {
  366. if (reply.Reattach)
  367. {
  368. ServerReplyEvent += (obj, e) => HandleReply(obj, e, reply);
  369. }
  370. }
  371. }
  372. }
  373. }