context: /*
  WikiFunctions
  Copyright (C) 2007 Martin Richards
  
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
  
  using System;
  using System.Net.Sockets;
  using System.IO;
  using System.Threading;
  using System.Text.RegularExpressions;
  
  namespace WikiFunctions.IRC
  {
      public delegate void OtherMessagesDel(object sender, EventArgs e, string IrcCommand);
      public delegate void ConnectEnabledDel(object sender, EventArgs e);
      public delegate void DisconnectDel(object sender, EventArgs e);
      public delegate void EditDel(object sender, EventArgs e, string Article, string Minor, string DiffLink, string User, int plusminus, string comment);
      public delegate void NewArticleDel(object sender, EventArgs e, string Artice, string User, int PlusMinus, string Comment);
      public delegate void NewUserDel(object sender, EventArgs e, string User);
      public delegate void PageMoveDel(object sender, EventArgs e, string OldName, string NewName, string User, string Comment);
      public delegate void UploadDel(object sender, EventArgs e, string File, string User, string Comment);
      public delegate void DeleteDel(object sender, EventArgs e, string Admin, string Article, string Comment);
      public delegate void RestoreDel(object sender, EventArgs e, string Admin, string Article, string Comment);
      public delegate void BlockDel(object sender, EventArgs e, string Admin, string Article, string Comment, string time);
      public delegate void UnblockDel(object sender, EventArgs e, string Admin, string Article, string Comment);
      public delegate void ProtectDel(object sender, EventArgs e, string Admin, string Article, string Comment);
      public delegate void UnprotectDel(object sender, EventArgs e, string Admin, string Article, string Comment);
  
      /// <summary>
      /// Contains functions to monitor IRC channels.
      /// </summary>
      public class WikiIRC
      {
          /// <summary>
          /// Initialises the class, accepting the necessary variables.
          /// </summary>
          /// <param name="Ircserver">The IRC server e.g. "irc.wikimedia.org".</param>
          /// <param name="Ircport">The port to use e.g. 6667.</param>
          /// <param name="Ircnick">The IRC nickname to use.</param>
          /// <param name="Ircchannel">The IRC channel to use e.g. "#en.wikipedia".</param>
          public WikiIRC(string Ircserver, int Ircport, string Ircnick, string Ircchannel)
          {
              IrcNick = Ircnick;
              IrcUser = Ircnick;
              IrcRealName = Ircnick;
              IrcChannel = Ircchannel;
              IsInvisble = false;
              IrcServer = Ircserver;
              IrcPort = Ircport;
  
              SOPC = new SendOrPostCallback(Process);
          }
  
          /// <summary>
          /// Listen to this event to receive the raw IRC messages.
          /// </summary>
          public event OtherMessagesDel OtherMessages;
          public event ConnectEnabledDel ConnectEvent;
          /// <summary>
          /// IRC disconnected
          /// </summary>
          public event DisconnectDel DisconnectEvent;
  
          public event EditDel Edit;
          public event NewArticleDel NewArticle;
          public event PageMoveDel PageMove;
          public event NewUserDel NewUser;
          public event UploadDel Upload;
          public event DeleteDel Delete;
          public event RestoreDel Restore;
          public event BlockDel Block;
          public event UnblockDel Unblock;
          public event ProtectDel Protect;
          public event UnprotectDel Unprotect;
  
          readonly Regex editRegex = new Regex(":14\\[\\[07(.*?)14\\]\\]4 (M?)10 02(.*?) 5\\* 03(.*?) 5\\* \\((.*?)\\) 10(.*?)$", RegexOptions.Compiled);
          readonly Regex newArticleRegex = new Regex(":14\\[\\[07(.*?)14\\]\\]4 M?N10 02(.*?) 5\\* 03(.*?) 5\\* \\((.*?)\\) 10(.*?)$", RegexOptions.Compiled);
          readonly Regex movePageRegex = new Regex(":14\\[\\[07Special:Log/move14\\]\\]4 move(_redir)?10 02 5\\* 03(.*?) 5\\*  10moved \\[\\[02(.*?)10\\]\\] to \\[\\[(.*?)\\]\\](.*?)$", RegexOptions.Compiled);
          
          readonly Regex newUserRegex = new Regex(":14\\[\\[07Special:Log/newusers14\\]\\]4 create10 02 5\\* 03(.*?) 5\\*  10\\(New user account\\)$", RegexOptions.Compiled);
          readonly Regex uploadRegex = new Regex(":14\\[\\[07Special:Log/upload14\\]\\]4 upload10 02 5\\* 03(.*?) 5\\*  10uploaded \"\\[\\[02(.*?)10\\]\\]\"(.*?)$", RegexOptions.Compiled);
  
          readonly Regex deleteRegex = new Regex(":14\\[\\[07Special:Log/delete14\\]\\]4 delete10 02 5\\* 03(.*?) 5\\*  10deleted \"02(.*?)10\":(.*?)$", RegexOptions.Compiled);
          readonly Regex restoreRegex = new Regex(":14\\[\\[07Special:Log/delete14\\]\\]4 restore10 02 5\\* 03(.*?) 5\\*  10restored \"\\[\\[02(.*?)10\\]\\]\":(.*?)$", RegexOptions.Compiled);
  
          readonly Regex blockRegex = new Regex(":14\\[\\[07Special:Log/block14\\]\\]4 block10 02 5\\* 03(.*?) 5\\*  10blocked \"02(.*?)10\" with an expiry time of (.*?):(.*?)$", RegexOptions.Compiled);
          readonly Regex unblockRegex = new Regex(":14\\[\\[07Special:Log/block14\\]\\]4 unblock10 02 5\\* 03(.*?) 5\\*  10unblocked 02(.*?)10:(.*?)", RegexOptions.Compiled);
  
          readonly Regex protectRegex = new Regex(":14\\[\\[07Special:Log/protect14\\]\\]4 protect10 02 5\\* 03(.*?) 5\\*  10protected 02(.*?)10:(.*?\\[(edit=.*?):(move=.*?)\\])$", RegexOptions.Compiled);
          readonly Regex unprotectRegex = new Regex(":14\\[\\[07Special:Log/protect14\\]\\]4 unprotect10 02 5\\* 03(.*?) 5\\*  10unprotected 02(.*?)10:(.*?)$", RegexOptions.Compiled);
  
          SendOrPostCallback SOPC;
          private SynchronizationContext context;
          Thread IRCThread;
  
          private void Process(object s)
          {//process messages here, fire off events
              if (Pause)
                  return;
  
              string msg = s.ToString();
  
              if (msg == "DISCONNECTED")//disconnected
              {
                  this.DisconnectEvent(null, null);
                  return;
              }
       
              if (editRegex.IsMatch(msg))//edit
              {
                  Match m = editRegex.Match(msg);
  
                  int plusminus = intFromMessage(m.Groups[5].Value);
  
                  this.Edit(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value, m.Groups[4].Value, plusminus, m.Groups[6].Value);
              }
              else if (newArticleRegex.IsMatch(msg))//new article
              {
                  Match m = newArticleRegex.Match(msg);
                  int plusmin = intFromMessage(m.Groups[4].Value);
  
                  this.NewArticle(null, null, m.Groups[1].Value, m.Groups[3].Value, plusmin, m.Groups[5].Value);
              }
              else if (newUserRegex.IsMatch(msg))//new user
              {
                  Match m = newUserRegex.Match(msg);
  
                  this.NewUser(null, null, m.Groups[1].Value);
              }
              else if (movePageRegex.IsMatch(msg))//move
              {
                  Match m = movePageRegex.Match(msg);
  
                  string newName = removeSyntax(m.Groups[4].Value);
  
                  this.PageMove(null, null, m.Groups[3].Value, newName, m.Groups[2].Value, m.Groups[5].Value);
              }
              else if (uploadRegex.IsMatch(msg))//upload
              {
                  Match m = uploadRegex.Match(msg);
  
                  this.Upload(null, null, m.Groups[2].Value, m.Groups[1].Value, m.Groups[3].Value);
              }
              else if (deleteRegex.IsMatch(msg))//delete
              {
                  Match m = deleteRegex.Match(msg);
  
                  this.Delete(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
              }
              else if (restoreRegex.IsMatch(msg))//delete
              {
                  Match m = restoreRegex.Match(msg);
  
                  this.Restore(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
              }
              else if (blockRegex.IsMatch(msg))//block
              {
                  Match m = blockRegex.Match(msg);
  
                  this.Block(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[4].Value, m.Groups[3].Value);
              }
              else if (unblockRegex.IsMatch(msg))//block
              {
                  Match m = unblockRegex.Match(msg);
  
                  this.Unblock(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
              }            
              else if (protectRegex.IsMatch(msg))//protection
              {
                  Match m = protectRegex.Match(msg);
  
                  this.Protect(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
              }
              else if (unprotectRegex.IsMatch(msg))//unprotection
              {
                  Match m = unprotectRegex.Match(msg);
  
                  this.Unprotect(null, null, m.Groups[1].Value, m.Groups[2].Value, m.Groups[3].Value);
              }
              else
              {
                  if (OtherMessages != null)
                      this.OtherMessages(null, null, msg);
              }
          }
  
          public string removeSyntax(string s)
          {
              s = s.Replace("02", "").Replace("10", "");
              return s;
          }
  
          private int intFromMessage(string s)
          {
              string z = s;
              int i = 0;
  
              s = s.Trim('');
              s = s.TrimStart('-', '+');
              i = Int32.Parse(s);
  
              if (z.StartsWith("-"))
  
gt:                 i = i * -1;