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 mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

Messages.cs 24KB

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