Wednesday, September 18, 2013

Написание бота для icq или как работать xmpp протоколом используя gateway openfire сервера.

Решил я сделать бота для работы с аськой, основной задачей которого было бы делать рассылки менеджерам, а также напоминание и возможно формирования дополнительных ""плюшек". Основной проблемой стало то, что в организации повально используется icq как основное средство общения. В начале было решил работать с с протоколом oscar, но само время icq уже подходит на нет - реализацию через прямой протокол я прекратил, тем более в памяти возникали воспоминания, про то как icq меняла свой протокол и возникавшими проблемами у других клиентов.
Сейчас пытаюсь понять какой веб портал было бы оптимально использовать для работы, перерывая куча документации по порталам и всяким плюшкам к ним, я заметил, что большая часть чатов порталов работает с xmpp серверами и по xmpp протоколу.
Итого после долгих изучений и разговоров был поднят Openfire как xmpp сервер под AD, спасибо habr-у.
Следующий шаг поиск библиотеки под c#. Честно была шальная мысля все прикрутить к самой 1С, но опять обратившись к самому how-to и погуглив в нете, понял что занятие бесперспективное и опасное, основная проблема заключается как раз в работе icq. Поднятие несколько раз соединения для отправки письма клиенту icq будет проблемно, так как сервер icq начнет блокировать соединения.
Поэтому начал смотреть список библиотек под c#, так как было реализовано много проектов на c#.
Первая из них agxmpp имеет 2 типа лицензий и в принципе подходит. На сайте производителя есть также библиотека matrix, но она полностью коммерческая.

итого краткая история формирования:
1. Часть это не сильно долгий по времени, но слабо описанный в нете процесс подключение к openfire, методом научного тыка и перебора удалось подключиться и начать отправлять сообщения внутри сервера.
2. Самая большая проблема это отправка сообщения через транспорт(или же gateway), вот тут пришлось очень сильно повозиться,четкого и грамотного описания как это сделать нет, на сайте разработчиков, в теме с вопросом есть только несколько невнятных ответов без примеров(Тема1, Тема2), и очень скудная документация, зародившая желания написать библиотеку самому.
В итоге после пару дней поиска решения и возникшего желания перейти на другой протокол, нормальных протоколов по c# не было, а вот java были SMACK, после небольшого гугления было найдено решение.


Ну а теперь код под c# с использование библиотеки agxmpp:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using agsXMPP;
using agsXMPP.protocol;
using agsXMPP.protocol.iq;
using agsXMPP.protocol.client;
using agsXMPP.sasl;


using System.Threading;

namespace ConsoleApplicationJabber
{
    class Program
    {
        static XmppClientConnection xmpp;
        static bool _wait;

        [STAThread]
        static void Main(string[] args)
        {
            
            string user = "user";
            string pass = "password";

            //Console.WriteLine("Press Key!");
            //Console.ReadLine();
            Jid jid = new Jid(user+"@domain");
            xmpp = new XmppClientConnection();
            xmpp.Server = jid.Server;
            xmpp.Username = jid.User;
            xmpp.ConnectServer = "NameServer.domain";
            xmpp.UseSSL = false;
            
            xmpp.AutoResolveConnectServer = false;
            xmpp.AutoPresence = false;
            xmpp.AutoRoster = false;
            xmpp.AutoAgents = false;


            xmpp.OnReadXml += new agsXMPP.XmlHandler(xmpp_OnReadXml);
            xmpp.OnWriteXml += new agsXMPP.XmlHandler(xmpp_OnWriteXml);
            xmpp.OnLogin += new ObjectHandler(xmpp_OnLogin);
            xmpp.OnError += new agsXMPP.ErrorHandler(xmpp_OnError);
            xmpp.OnSaslStart += new SaslEventHandler(XmppCon_OnSaslStart);
            xmpp.OnPresence += new PresenceHandler(xmpp_OnPresence);
            xmpp.OnMessage += new MessageHandler(xmpp_OnMessage);
            xmpp.OnAgentStart += new ObjectHandler(XmppCon_OnAgentStart);
            xmpp.OnAgentEnd += new ObjectHandler(XmppCon_OnAgentEnd);
            xmpp.OnAgentItem += new agsXMPP.XmppClientConnection.AgentHandler(XmppCon_OnAgentItem);
            xmpp.OnIq+= new IqHandler(xmpp_onIQ);

            try
            {
                xmpp.Open(user, pass, "ConsoleClient", 5);
             }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Write("Wait for Login ");
            _wait = true;
            int i=0;
            do
            {
                Console.Write(".");
                i++;
                if (i == 10)
                    _wait = false;
                Thread.Sleep(500);
            } while (_wait); 


            Presence p = new Presence(ShowType.chat, "Online");
            p.Type = PresenceType.available;
            
            xmpp.Send(p);

        
            xmpp.AutoAgents = false;

            IQ iq = new IQ();
            iq.Type = IqType.set;
            iq.To = new Jid("icq.domain"); // тут название трансопрта
            
            iq.SetAttribute("username","NumberICQ"); // номер icq
            iq.SetAttribute("password", "PasswordICQ"); 
            xmpp.Send(iq);

            Thread.Sleep(5000);

            xmpp.Send(new Message(new Jid("UserToICQ@icq.domain"), MessageType.chat, "Hello, how are you?" + DateTime.Now.ToLongTimeString()));

            

            //while (true)
            //{
            //    System.Threading.Thread.Sleep(100);
            //};

            Console.WriteLine("End work. Press Key!");
            
            xmpp.Close();
            Console.ReadLine();
        }



        static void xmpp_onIQ(object sender, IQ iq)
        {
          
        }


        static void XmppCon_OnAgentStart(object sender)
        {

        }

        static void XmppCon_OnAgentEnd(object sender)
        {

        }

        static void XmppCon_OnAgentItem(object sender, agsXMPP.protocol.iq.agent.Agent agent)
        {

        }


        static void xmpp_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
        {
            if (msg.Body != null)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine("{0}>> {1}", msg.From.User, msg.Body);                
                Console.ResetColor();                
            }
        }

        static void xmpp_OnPresence(object sender, Presence pres)
        {
            Console.WriteLine("Available Contacts: ");
            Console.WriteLine("{0}@{1}  {2}",        pres.From.User,pres.From.Server,pres.Type);
            Console.WriteLine();            
        }

        static void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
        {
            if (msg.Body != null)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("{0}>> {1}", msg.From.User, msg.Body);
                Console.ResetColor();
                
               
                //Console.ForegroundColor = ConsoleColor.Green;
            }
        } 


        private static void XmppCon_OnSaslStart(object sender, SaslEventArgs args)
        {
            args.Auto = false;
            args.Mechanism = agsXMPP.protocol.sasl.Mechanism.GetMechanismName(agsXMPP.protocol.sasl.MechanismType.PLAIN);
        }

        private static void xmpp_OnLogin(object sender)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("ok");
            Console.WriteLine("we are logged in to the server now");
            Console.ResetColor();
            xmpp.SendMyPresence();
            
            _wait = false;
        }

        private static void xmpp_OnError(object sender, Exception ex)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(ex.Message);
            Console.ResetColor();
        }

        private static void xmpp_OnReadXml(object sender, string xml)
        {
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine("RECV XML: " + xml);
            Console.ResetColor();
        }

        private static void xmpp_OnWriteXml(object sender, string xml)
        {
            Console.ForegroundColor = ConsoleColor.DarkMagenta;
            Console.WriteLine("SEND XML: " + xml);
            Console.ResetColor();
        }
    }
}

No comments:

Post a Comment