// // openmapi.org - IRC <--> Jabber bridge - irc2jabber.cs // // (C) 2009 by Johannes Roith // // Author: Johannes Roith // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. // namespace Jonfo.Jabber.IRC { using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Reflection; using jabber; using jabber.client; using jabber.protocol.client; using Meebey.SmartIrc4net; /// /// A gateway to connect to an IRC channel from Jabber/XMPP. /// public sealed class IRCJabberBridge { private object lastEventLock = new object (); private DateTime lastEvent = DateTime.Now; private Config config; private IrcClient irc; private Logger logger; private JabberClient jc; private RosterManager rosterManager; private PresenceManager presenceManager; private List silentUsers; private List commands; /// /// Instance of the Jabber bot /// public JabberClient JabberClient { get { return jc; } } /// /// Instance of the IRC Bot. /// public IrcClient IRCClient { get { return irc; } } /// /// Name of the IRC channel. /// public string IRCChannel { get { return config.IRCChannel; } } /// /// /// public List Commands { get { return commands; } } public static void Main (string[] args) { new IRCJabberBridge (args); } public IRCJabberBridge (string[] args) { UpdateLastEvent (); this.silentUsers = new List (); this.config = Config.Load ("irc2jabber.cfg"); this.logger = new Logger ("irc2jabber.log"); AutoRegisterCommands (); logger.StartLogging (); jc = new JabberClient (); // jc.OnReadText += (sender, txt) => // { if (txt != " ") Console.WriteLine ("RECV: " + txt); } // jc.OnWriteText += (sender, txt) => // { if (txt != " ") Console.WriteLine ("SENT: " + txt); } jc.OnMessage += OnJabberMessage; jc.OnError += OnJabberError; jc.OnStreamError += OnJabberStreamError; jc.AutoReconnect = 3f; jc.User = config.JabberUser; jc.Server = config.JabberServer; jc.NetworkHost = config.JabberNetworkHost; jc.Port = config.JabberPort; jc.Resource = config.JabberResource; jc.Password = config.JabberPassword; jc.AutoStartTLS = false; jc.AutoPresence = true; rosterManager = new RosterManager (); rosterManager.Stream = jc; rosterManager.AutoSubscribe = config.JabberAutoSubscribe; rosterManager.AutoAllow = jabber.client.AutoSubscriptionHanding.AllowAll; presenceManager = new PresenceManager (); presenceManager.Stream = jc; jc.Connect (); // send presence on new thread Thread t = new Thread (new ThreadStart (this.JabberPresenceThread)); t.Start (); while (!t.IsAlive); // wait until alive ... irc = new IrcClient (); irc.Encoding = Encoding.UTF8; irc.OnChannelMessage += new IrcEventHandler (OnIRCChannelMessage); irc.Connect (config.IRCHost, config.IRCPort); irc.Login (config.IRCNick, config.IRCName, 0, config.IRCNick); irc.RfcJoin (IRCChannel); irc.Listen (); } private void UpdateLastEvent () { lock (lastEventLock) { lastEvent = DateTime.Now; } } public bool IsSilentUser (JID from) { return silentUsers.Contains (Helper.MakeJabberUserName (from)); } public void AddSilentUser (JID from) { silentUsers.Add (Helper.MakeJabberUserName (from)); } public void RemoveSilentUser (JID from) { silentUsers.Remove (Helper.MakeJabberUserName (from)); } private void JabberPresenceThread () { while (true) { if (jc.IsAuthenticated) { string lastEventStr = null; lock (lastEventLock) { lastEventStr = lastEvent.ToString (); } jc.Presence (PresenceType.available, "Last Event: " + lastEventStr, "available", 1); } Thread.Sleep (10000); } } private void AutoRegisterCommands () { this.commands = new List (); Assembly asm = Assembly.GetExecutingAssembly (); foreach (Type current in asm.GetTypes ()) { if (current.BaseType == typeof (Command)) { var cmd = (Command) Activator.CreateInstance ( current, new object[] {this}, null); RegisterCommand (cmd); } } } private void RegisterCommand (Command cmd) { commands.Add (cmd); } public JID[] GetAvailableJabberBuddies () { return Helper.GetAvailableJabberBuddies ( rosterManager, presenceManager); } private void SendMessage (List blocked, string msg) { foreach (JID jid in GetAvailableJabberBuddies ()) { bool isBlocked = (blocked != null && blocked.Contains (Helper.MakeJabberUserName (jid))); if (IsSilentUser (jid)) isBlocked = true; if (!isBlocked) jc.Message (jid, msg); } } private void SendJabberMessage (string msg) { logger.Log ("IRC -> JABBER: " + msg); SendMessage (new List (), msg); } private void SendIRCMessage (JID from, string msg) { logger.Log ("JABBER -> IRC: " + msg); irc.SendMessage (SendType.Message, IRCChannel, msg); // we need to send this to everyone jabber user as well, // EXCEPT the user who was sending the message himself ... var blocked = new List (); blocked.Add (Helper.MakeJabberUserName (from)); SendMessage (blocked, msg); } private void OnJabberError (object sender, Exception ex) { Console.WriteLine ("ERROR: " + ex.ToString()); Environment.Exit (1); } private void OnJabberStreamError (object sender, System.Xml.XmlElement rp) { Console.WriteLine ("Stream ERROR: " + rp.OuterXml); Environment.Exit (1); } private void ExecCommand (JID from, string input) { var cmd = new StringBuilder (); var args = new StringBuilder (); StringBuilder target = cmd; foreach (char c in input) { if (Char.IsWhiteSpace (c)) target = args; target.Append (c); } bool found = false; foreach (var command in commands) { if (command.Match (cmd.ToString ())) { found = true; command.Run (from, args.ToString ()); } } if (!found) jc.Message (from, "error: unknown command!"); } private void OnIRCChannelMessage (object sender, IrcEventArgs e) { UpdateLastEvent (); SendJabberMessage (e.Data.Nick + "[irc]: " + e.Data.Message); } private void OnJabberMessage (object sender, Message msg) { if (msg.Body == null || msg.Body == String.Empty) return; UpdateLastEvent (); if (msg.Body [0] == '@') ExecCommand (msg.From, msg.Body.Substring (1)); else { string prefix = Helper.MakeJabberUserName (msg.From) + "[xmpp]: "; if (msg.From.Server == "gmail.com" || msg.From.Server == "googlemail.com") prefix = msg.From.User + "[gtalk]: "; SendIRCMessage (msg.From, prefix + msg.Body); } } } }