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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using System.Net;
  8. using Combot.IRCServices.Messaging;
  9. using Combot.IRCServices.TCP;
  10. namespace Combot.IRCServices
  11. {
  12. public partial class IRC
  13. {
  14. public List<Channel> Channels = new List<Channel>();
  15. public Messages Message;
  16. public event Action ConnectEvent;
  17. public event Action DisconnectEvent;
  18. public event Action<TCPError> TCPErrorEvent;
  19. public string Nickname { get; set; }
  20. public Dictionary<string, PrivilegeMode> PrivilegeMapping = new Dictionary<string, PrivilegeMode>() { { "+", PrivilegeMode.v }, { "%", PrivilegeMode.h }, { "@", PrivilegeMode.o }, { "&", PrivilegeMode.a }, { "~", PrivilegeMode.q } };
  21. private Thread TCPReader;
  22. private event Action<string> TCPMessageEvent;
  23. private readonly TCPInterface _TCP;
  24. private readonly ReaderWriterLockSlim ChannelRWLock;
  25. public IRC()
  26. {
  27. _TCP = new TCPInterface();
  28. Message = new Messages(this);
  29. Nickname = string.Empty;
  30. ChannelRWLock = new ReaderWriterLockSlim();
  31. TCPMessageEvent += Message.ParseTCPMessage;
  32. _TCP.TCPConnectionEvent += HandleTCPConnection;
  33. _TCP.TCPErrorEvent += HandleTCPError;
  34. Message.ErrorMessageEvent += HandleErrorMessage;
  35. Message.PingEvent += HandlePing;
  36. Message.ServerReplyEvent += HandleReply;
  37. Message.ChannelModeChangeEvent += HandleChannelModeChange;
  38. Message.UserModeChangeEvent += HandleUserModeChange;
  39. Message.NickChangeEvent += HandleNickChange;
  40. Message.JoinChannelEvent += HandleJoin;
  41. Message.PartChannelEvent += HandlePart;
  42. Message.KickEvent += HandleKick;
  43. Message.QuitEvent += HandleQuit;
  44. }
  45. /// <summary>
  46. /// Starts a TCP connection to the specified host.
  47. /// </summary>
  48. /// <param name="IP">The IP address of the host.</param>
  49. /// <param name="port">The port for the tcp connection.</param>
  50. /// <param name="readTimeout">The timeout for read operations in milliseconds.</param>
  51. /// <param name="allowedFailedCount">Number of times a read can fail before disconnecting.</param>
  52. /// <returns></returns>
  53. public bool Connect(IPAddress IP, int port, int readTimeout = 5000, int allowedFailedCount = 0)
  54. {
  55. bool result = false;
  56. if (!_TCP.Connected)
  57. {
  58. result = _TCP.Connect(IP, port, readTimeout, allowedFailedCount);
  59. if (result)
  60. {
  61. TCPReader = new Thread(ReadTCPMessages);
  62. TCPReader.IsBackground = true;
  63. TCPReader.Start();
  64. if (ConnectEvent != null)
  65. {
  66. ConnectEvent();
  67. }
  68. }
  69. }
  70. return result;
  71. }
  72. /// <summary>
  73. /// Disconencts from the active TCP connection.
  74. /// </summary>
  75. /// <returns></returns>
  76. public bool Disconnect()
  77. {
  78. bool result = false;
  79. if (_TCP.Connected)
  80. {
  81. _TCP.Disconnect();
  82. }
  83. ChannelRWLock.EnterWriteLock();
  84. Channels = new List<Channel>();
  85. ChannelRWLock.ExitWriteLock();
  86. if (DisconnectEvent != null)
  87. {
  88. DisconnectEvent();
  89. }
  90. return result;
  91. }
  92. /// <summary>
  93. /// Logs in the specified nick using their Username and Realname.
  94. /// </summary>
  95. /// <param name="serverName">The server's name.</param>
  96. /// <param name="nick">The nick information for the login.</param>
  97. public void Login(string serverName, Nick nick)
  98. {
  99. Nickname = nick.Nickname;
  100. SendNick(nick.Nickname);
  101. SendUser(nick.Username, nick.Host, serverName, nick.Realname);
  102. }
  103. private void ReadTCPMessages()
  104. {
  105. while (_TCP.Connected)
  106. {
  107. string response = ReadTCPMessage();
  108. if (TCPMessageEvent != null && response != null && response != string.Empty)
  109. {
  110. TCPMessageEvent(response);
  111. }
  112. Thread.Sleep(10);
  113. }
  114. }
  115. private string ReadTCPMessage()
  116. {
  117. if (_TCP.Connected)
  118. {
  119. return _TCP.Read();
  120. }
  121. return null;
  122. }
  123. private void SendTCPMessage(string message)
  124. {
  125. if (_TCP.Connected)
  126. {
  127. _TCP.Write(message);
  128. }
  129. }
  130. private void HandleTCPConnection(int e)
  131. {
  132. if (DisconnectEvent != null)
  133. {
  134. DisconnectEvent();
  135. }
  136. }
  137. private void HandleTCPError(TCPError e)
  138. {
  139. if (TCPErrorEvent != null)
  140. {
  141. TCPErrorEvent(e);
  142. }
  143. }
  144. private void HandleErrorMessage(object sender, ErrorMessage e)
  145. {
  146. Disconnect();
  147. }
  148. /// <summary>
  149. /// Responds with PONG on a PING with the specified arguments.
  150. /// </summary>
  151. /// <param name="sender"></param>
  152. /// <param name="e"></param>
  153. private void HandlePing(object sender, PingInfo e)
  154. {
  155. SendPong(e.Message);
  156. }
  157. private void HandleReply(object sender, IReply e)
  158. {
  159. if (e.GetType() == typeof(ServerReplyMessage))
  160. {
  161. ServerReplyMessage msg = (ServerReplyMessage)e;
  162. switch (msg.ReplyCode)
  163. {
  164. // If we get a WHO response, we parse and add the nicks to the specified channel if they are not there already.
  165. case IRCReplyCode.RPL_WHOREPLY:
  166. ChannelRWLock.EnterWriteLock();
  167. string[] msgSplit = msg.Message.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  168. string target = msgSplit[0];
  169. if (target.StartsWith("&") || target.StartsWith("#"))
  170. {
  171. if (msgSplit.GetUpperBound(0) >= 7)
  172. {
  173. string nickname = msgSplit[4];
  174. string realname = msgSplit[7];
  175. string username = msgSplit[1];
  176. string host = msgSplit[2];
  177. string modeString = msgSplit[5];
  178. Channel channel = Channels.Find(chan => chan.Name == target);
  179. if (channel != null)
  180. {
  181. Nick nick = channel.GetNick(nickname);
  182. bool nickFound = true;
  183. if (nick == null)
  184. {
  185. nickFound = false;
  186. nick = new Nick();
  187. }
  188. nick.Nickname = nickname;
  189. nick.Host = host;
  190. nick.Realname = realname;
  191. nick.Username = username;
  192. nick.Modes = new List<UserMode>();
  193. nick.Privileges = new List<PrivilegeMode>();
  194. char[] modeArr = modeString.ToCharArray();
  195. for (int i = 1; i <= modeArr.GetUpperBound(0); i++)
  196. {
  197. if (PrivilegeMapping.ContainsKey(modeArr[i].ToString()))
  198. {
  199. nick.Privileges.Add(PrivilegeMapping[modeArr[i].ToString()]);
  200. }
  201. else if (modeArr[i].ToString() == "*")
  202. {
  203. nick.Modes.Add(UserMode.o);
  204. }
  205. else
  206. {
  207. nick.Modes.Add((UserMode)Enum.Parse(typeof(UserMode), modeArr[i].ToString()));
  208. }
  209. }
  210. if (!nickFound)
  211. {
  212. channel.AddNick(nick);
  213. }
  214. }
  215. }
  216. }
  217. ChannelRWLock.ExitWriteLock();
  218. break;
  219. // On a topic reply, update the channel's topic
  220. case IRCReplyCode.RPL_TOPIC:
  221. ChannelRWLock.EnterWriteLock();
  222. string[] topicSplit = msg.Message.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  223. string topicChan = topicSplit[0];
  224. Channel topicChannel = Channels.Find(chan => chan.Name == topicChan);
  225. if (topicChannel != null)
  226. {
  227. topicChannel.Topic = topicSplit[1].Remove(0, 1);
  228. }
  229. ChannelRWLock.ExitWriteLock();
  230. break;
  231. default:
  232. break;
  233. }
  234. }
  235. else
  236. {
  237. ServerErrorMessage msg = (ServerErrorMessage)e;
  238. }
  239. }
  240. /// <summary>
  241. /// Update a channel's mode.
  242. /// </summary>
  243. /// <param name="sender"></param>
  244. /// <param name="e"></param>
  245. private void HandleChannelModeChange(object sender, ChannelModeChangeInfo e)
  246. {
  247. ChannelRWLock.EnterWriteLock();
  248. Channel channel = Channels.Find(chan => chan.Name == e.Channel);
  249. if (channel != null)
  250. {
  251. foreach (ChannelModeInfo mode in e.Modes)
  252. {
  253. switch (mode.Mode)
  254. {
  255. case ChannelMode.v:
  256. case ChannelMode.h:
  257. case ChannelMode.o:
  258. case ChannelMode.a:
  259. case ChannelMode.q:
  260. Nick changedNick = channel.GetNick(mode.Parameter);
  261. if (mode.Set)
  262. {
  263. changedNick.AddPrivilege((PrivilegeMode)Enum.Parse(typeof(PrivilegeMode), mode.Mode.ToString()));
  264. }
  265. else
  266. {
  267. changedNick.RemovePrivilege((PrivilegeMode)Enum.Parse(typeof(PrivilegeMode), mode.Mode.ToString()));
  268. }
  269. break;
  270. case ChannelMode.b:
  271. if (mode.Set)
  272. {
  273. channel.AddBan(mode.Parameter);
  274. }
  275. else
  276. {
  277. channel.RemoveBan(mode.Parameter);
  278. }
  279. break;
  280. case ChannelMode.k:
  281. if (mode.Set)
  282. {
  283. channel.AddMode(mode.Mode);
  284. channel.Key = mode.Parameter;
  285. }
  286. else
  287. {
  288. channel.RemoveMode(mode.Mode);
  289. channel.Key = string.Empty;
  290. }
  291. break;
  292. default:
  293. if (mode.Set)
  294. {
  295. channel.AddMode(mode.Mode);
  296. }
  297. else
  298. {
  299. channel.RemoveMode(mode.Mode);
  300. }
  301. break;
  302. }
  303. }
  304. }
  305. ChannelRWLock.ExitWriteLock();
  306. }
  307. /// <summary>
  308. /// Update a nick's mode.
  309. /// </summary>
  310. /// <param name="sender"></param>
  311. /// <param name="e"></param>
  312. private void HandleUserModeChange(object sender, UserModeChangeInfo e)
  313. {
  314. ChannelRWLock.EnterWriteLock();
  315. for (int i = 0; i < Channels.Count; i++)
  316. {
  317. Nick changedNick = Channels[i].GetNick(e.Nick.Nickname);
  318. if (changedNick != null)
  319. {
  320. foreach (UserModeInfo mode in e.Modes)
  321. {
  322. if (mode.Set)
  323. {
  324. changedNick.AddMode(mode.Mode);
  325. }
  326. else
  327. {
  328. changedNick.RemoveMode(mode.Mode);
  329. }
  330. }
  331. }
  332. }
  333. ChannelRWLock.ExitWriteLock();
  334. }
  335. /// <summary>
  336. /// Update a nick to use their new nickname.
  337. /// </summary>
  338. /// <param name="sender"></param>
  339. /// <param name="e"></param>
  340. private void HandleNickChange(object sender, NickChangeInfo e)
  341. {
  342. ChannelRWLock.EnterWriteLock();
  343. for (int i = 0; i < Channels.Count; i++)
  344. {
  345. Nick newNick = Channels[i].GetNick(e.OldNick.Nickname);
  346. if (newNick != null)
  347. {
  348. newNick.Nickname = e.NewNick.Nickname;
  349. }
  350. }
  351. ChannelRWLock.ExitWriteLock();
  352. }
  353. /// <summary>
  354. /// Add a nick to a channel on join.
  355. /// </summary>
  356. /// <param name="sender"></param>
  357. /// <param name="e"></param>
  358. private void HandleJoin(object sender, JoinChannelInfo e)
  359. {
  360. ChannelRWLock.EnterWriteLock();
  361. Channel channel = Channels.Find(chan => chan.Name == e.Channel);
  362. if (channel != null)
  363. {
  364. channel.AddNick(e.Nick);
  365. }
  366. else
  367. {
  368. Channel newChannel = new Channel();
  369. newChannel.Name = e.Channel;
  370. if (e.Nick.Nickname == Nickname)
  371. {
  372. newChannel.Joined = true;
  373. }
  374. newChannel.Nicks.Add(e.Nick);
  375. Channels.Add(newChannel);
  376. SendWho(newChannel.Name);
  377. }
  378. ChannelRWLock.ExitWriteLock();
  379. }
  380. /// <summary>
  381. /// Remove a nick from a channel on part.
  382. /// </summary>
  383. /// <param name="sender"></param>
  384. /// <param name="e"></param>
  385. private void HandlePart(object sender, PartChannelInfo e)
  386. {
  387. ChannelRWLock.EnterWriteLock();
  388. Channel channel = Channels.Find(chan => chan.Name == e.Channel);
  389. if (channel != null)
  390. {
  391. channel.RemoveNick(e.Nick.Nickname);
  392. }
  393. ChannelRWLock.ExitWriteLock();
  394. }
  395. /// <summary>
  396. /// Remove a nick from a channel on kick.
  397. /// </summary>
  398. /// <param name="sender"></param>
  399. /// <param name="e"></param>
  400. private void HandleKick(object sender, KickInfo e)
  401. {
  402. ChannelRWLock.EnterWriteLock();
  403. Channel channel = Channels.Find(chan => chan.Name == e.Channel);
  404. if (channel != null)
  405. {
  406. channel.RemoveNick(e.Nick.Nickname);
  407. }
  408. ChannelRWLock.ExitWriteLock();
  409. }
  410. /// <summary>
  411. /// Remove a nick from all channels on quit.
  412. /// </summary>
  413. /// <param name="sender"></param>
  414. /// <param name="e"></param>
  415. private void HandleQuit(object sender, QuitInfo e)
  416. {
  417. ChannelRWLock.EnterWriteLock();
  418. for (int i = 0; i < Channels.Count; i++)
  419. {
  420. Channels[i].RemoveNick(e.Nick.Nickname);
  421. }
  422. ChannelRWLock.ExitWriteLock();
  423. }
  424. }
  425. }