Thursday, October 24, 2013

Advanced Facebook Chat

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

As for now the last post regarding the topic Facebook I want to present you today a a little bit more advanced chat client.
It uses all the techniques presented in the previous posts and looks as follows:



Name and password are set in the source code. When starting the program it loads the friends list.
If the user starts inputting a name in the Combobox, it fills with matching friends. After a click on "Start Chat" a new chat window is opened.
In this incoming messages of the contact are shown, furthermore own messages can be send by clicking "Send" or pressing Enter. With "Ctrl + Tab" one can change between the chat windows.
Of course a window also opens when receiving a message. If a new message is received,a notification sound is played, also the name starts blinking and the icon in the taskbar changes.
Requirement for this is the inclusion of the Windows API Codepack.
If a chat contact is typing, this is shown by displaying a keyboard icon.

Now to the code, but first a download link, over which the complete source code including the executable file can be downloaded.


Form1.cs:



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;
using Microsoft.WindowsAPICodePack.Taskbar;

namespace WindowsFormsApplication1
{

    public partial class Form1 : Form
    {
        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");
        Dictionary<string, string> Friends = new Dictionary<string, string>();
        bool StartCollectingContacts = false;
        bool CollectingContacts = true;
        Dictionary<string, Chat> Chats = new Dictionary<string, Chat>();
        TaskbarManager tm = TaskbarManager.Instance;

        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            tabControl1.ImageList = new ImageList();
            tabControl1.ImageList.Images.Add(WindowsFormsApplication1.Properties.Resources.keyboard);
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("name", "password");

            while (CollectingContacts)
            {
                if (StartCollectingContacts)
                    CollectingContacts = false;
                System.Threading.Thread.Sleep(1000);
            }
        }

        private void OnLogin(object sender)
        {
            Presence p = new Presence(ShowType.chat, "Online");
            p.Type = PresenceType.available;
            xmpp.Send(p);
            xmpp.OnRosterItem += new XmppClientConnection.RosterHandler(xmpp_OnRosterItem);
        }

        private void xmpp_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
        {
            try
            {
                StartCollectingContacts = true;
                CollectingContacts = true;
                Friends.Add(item.GetAttribute("jid").ToString(), item.GetAttribute("name").ToString());
                xmpp.MessageGrabber.Add(new Jid(item.GetAttribute("jid").ToString()), new BareJidComparer(), new MessageCB(MessageCallBack), null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
        {
            string JidSender = msg.From.ToString();
            string NameSender = Friends[JidSender];
            Chat Dummy;
            bool ChatExisting = Chats.TryGetValue(NameSender, out Dummy);

            if (msg.Body != null)
            {
                if (!ChatExisting || !Chats[NameSender].Active)
                {
                    ProvideChat(NameSender);
                }

                Chats[NameSender].NewMessage = true;
                Chats[NameSender].ChatWindow.Invoke(new Action(() =>
                    {
                        Chats[NameSender].ChatWindow.Text += NameSender + ": " + msg.Body + Environment.NewLine;
                        Chats[NameSender].ChatWindow.SelectionStart = Chats[NameSender].ChatWindow.TextLength;
                        Chats[NameSender].ChatWindow.ScrollToCaret();
                    }));
                Notify();
            }
            else if (msg.Chatstate == agsXMPP.protocol.extensions.chatstates.Chatstate.composing && ChatExisting)
            {
                Chats[NameSender].ChatWindow.Invoke(new Action(() =>
                {
                    Chats[NameSender].ChatPage.ImageIndex = 0;
                    Chats[NameSender].Composing = true;
                }));
            }
            else if (msg.Chatstate == agsXMPP.protocol.extensions.chatstates.Chatstate.active && ChatExisting)
            {
                Chats[NameSender].ChatWindow.Invoke(new Action(() =>
                {
                    Chats[NameSender].ChatPage.ImageIndex = -1;
                }));
            }
        }

        public void Notify()
        {
            System.Media.SoundPlayer ExamplePlayer = new System.Media.SoundPlayer(Properties.Resources.cell_phone_flip_1);
            ExamplePlayer.Play();
        }

        public void SendMessage(string msg, string receiverName)
        {
            xmpp.Send(new agsXMPP.protocol.client.Message(new Jid(receiverName), agsXMPP.protocol.client.MessageType.chat, msg));
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ProvideChat(comboBox1.Text);
        }

        private void ProvideChat(string name)
        {
            int Matches = Friends.Where(pair => pair.Value.ToLower().Contains(name.ToLower())).Count();

            Chat Dummy;
            if (Matches > 0 && !Chats.TryGetValue(name, out Dummy))
            {
                TabPage NewPage = new TabPage(name);

                TextBox ChatWindow = new TextBox();
                ChatWindow.Left = 10;
                ChatWindow.Top = 10;
                ChatWindow.Width = 532;
                ChatWindow.Height = 180;
                ChatWindow.Multiline = true;
                ChatWindow.ScrollBars = ScrollBars.Vertical;
                ChatWindow.ReadOnly = false;
                NewPage.Controls.Add(ChatWindow);

                TextBox SendBox = new TextBox();
                SendBox.Left = 10;
                SendBox.Top = 200;
                SendBox.Width = 450;
                NewPage.Controls.Add(SendBox);
                SendBox.Name = "snd" + name;
                SendBox.Click += new EventHandler(SendBox_Click);
                SendBox.TextChanged += new EventHandler(SendBox_TextChanged);

                Button SendButton = new Button();
                SendButton.Left = 470;
                SendButton.Top = 200;
                SendButton.Text = "Send";
                SendButton.Name = "btn" + name;
                SendButton.Click += new EventHandler(SendButton_Click);
                NewPage.Controls.Add(SendButton);

                Chat NewChat = new Chat();
                NewChat.ChatWindow = ChatWindow;
                NewChat.SendBox = SendBox;
                NewChat.ChatPage = NewPage;
                NewChat.Partner = name;
                NewChat.SendButton = SendButton;

                NewPage.Name = "tpg" + name;
                tabControl1.SelectedIndexChanged += new EventHandler(tabControl1_SelectedIndexChanged);

                Chats.Add(name, NewChat);

                this.AcceptButton = NewChat.SendButton;

                if (tabControl1.InvokeRequired)
                {
                    tabControl1.Invoke(new Action(() =>
                        {
                            tabControl1.TabPages.Add(NewPage);
                            tabControl1.SelectedTab = NewPage;
                        }));
                }
                else
                {
                    tabControl1.TabPages.Add(NewPage);
                    tabControl1.SelectedTab = NewPage;
                }

                this.ActiveControl = NewChat.SendBox;
            }
            else if (Chats.TryGetValue(name, out Dummy) && !Dummy.Active)
            {
                if (tabControl1.InvokeRequired)
                {
                    tabControl1.Invoke(new Action(() =>
                        {
                            tabControl1.TabPages.Add(Dummy.ChatPage);
                            tabControl1.SelectedTab = Dummy.ChatPage;
                        }));
                }
                else
                {
                    tabControl1.TabPages.Add(Dummy.ChatPage);
                    tabControl1.SelectedTab = Dummy.ChatPage;
                }
            }
        }

        private void tabControl1_SelectedIndexChanged(Object sender, EventArgs e)
        {
            if (((TabControl)sender).SelectedIndex != -1)
            {
                string Receiver = ((TabControl)sender).TabPages[((TabControl)sender).SelectedIndex].Name.ToString().Substring(3, ((TabControl)sender).TabPages[((TabControl)sender).SelectedIndex].Name.ToString().Length - 3);
                this.AcceptButton = Chats[Receiver].SendButton;
                this.ActiveControl = Chats[Receiver].SendBox;
            }
        }

        private void SendBox_Click(Object sender, EventArgs e)
        {
            string Receiver = ((TextBox)sender).Name.Substring(3, ((TextBox)sender).Name.Length - 3);
            Chat CurrentChat = Chats[Receiver];
            CurrentChat.NewMessage = false;
            CurrentChat.ChatPage.Text = CurrentChat.Partner;
        }

        private void SendBox_TextChanged(Object sender, EventArgs e)
        {
            string Receiver = ((TextBox)sender).Name.Substring(3, ((TextBox)sender).Name.Length - 3);
            Chat CurrentChat = Chats[Receiver];
            CurrentChat.NewMessage = false;
            CurrentChat.ChatPage.Text = CurrentChat.Partner;
        }

        private void SendButton_Click(Object sender, EventArgs e)
        {
            string Receiver = ((Button)sender).Name.Substring(3, ((Button)sender).Name.Length - 3);
            Chat CurrentChat = Chats[Receiver];
            SendMessage(CurrentChat.SendBox.Text, Friends.First(x => x.Value == Receiver).Key);
            CurrentChat.ChatWindow.Text += "Ich: " + CurrentChat.SendBox.Text + Environment.NewLine;
            CurrentChat.SendBox.Text = "";
            Chats[Receiver].ChatWindow.SelectionStart = Chats[Receiver].ChatWindow.TextLength;
            Chats[Receiver].ChatWindow.ScrollToCaret();
        }

        private void comboBox1_TextUpdate(object sender, EventArgs e)
        {
            var Matches = Friends.Where(pair => pair.Value.ToLower().Contains(comboBox1.Text.ToLower())).Select(pair => pair.Value);
            comboBox1.Items.Clear();
            foreach (string s in Matches)
            {
                comboBox1.Items.Add(s);
            }
            comboBox1.Select(comboBox1.Text.Length, 0);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            bool NewMessages = false;
            foreach (Chat c in Chats.Values)
            {
                if (c.NewMessage)
                {
                    NewMessages = true;
                    string BlankName = "";
                    BlankName = BlankName.PadLeft(c.Partner.Length, ' ');
                    if (c.ChatPage.Text == BlankName)
                        c.ChatPage.Text = c.Partner;
                    else
                        c.ChatPage.Text = BlankName;
                }
            }
            if (NewMessages)
            {
                tm.SetOverlayIcon(WindowsFormsApplication1.Properties.Resources.newmessage, "New Messages");  
            }
            else
            {
                tm.SetOverlayIcon(null, null);
            }
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == (Keys.Control | Keys.Tab))
            {
                int NextIndex = tabControl1.SelectedIndex + 1;
                if (NextIndex > tabControl1.TabCount )
                    NextIndex = 0;
                tabControl1.SelectedIndex = NextIndex;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (tabControl1.SelectedIndex != -1)
            {
                string Current = tabControl1.TabPages[tabControl1.SelectedIndex].Name.ToString().Substring(3, tabControl1.TabPages[tabControl1.SelectedIndex].Name.ToString().Length - 3);
                Chats[Current].Active = false;
                tabControl1.TabPages.RemoveAt(tabControl1.SelectedIndex);
            }
        }

    }

    public class Chat
    {
        public TextBox ChatWindow;
        public TextBox SendBox;
        public bool NewMessage = false;
        public TabPage ChatPage;
        public string Partner;
        public bool Composing = false;
        public Button SendButton;
        public bool Active = true;
    }
}

Form1.Designer.cs:

namespace WindowsFormsApplication1
{
    partial class Form1
    {
        /// <summary>
       /// Erforderliche Designervariable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
       /// Verwendete Ressourcen bereinigen.
        /// </summary>
        /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Vom Windows Form-Designer generierter Code

        /// <summary>
       /// Erforderliche Methode für die Designerunterstützung.
       /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.button2 = new System.Windows.Forms.Button();
            this.comboBox1 = new System.Windows.Forms.ComboBox();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // tabControl1
            //
            this.tabControl1.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.tabControl1.Location = new System.Drawing.Point(0, 52);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(562, 259);
            this.tabControl1.TabIndex = 0;
            //
            // button2
            //
            this.button2.Location = new System.Drawing.Point(153, 9);
            this.button2.Name = "button2";
            this.button2.Size = new System.Drawing.Size(110, 23);
            this.button2.TabIndex = 2;
            this.button2.Text = "Start Chat";
            this.button2.UseVisualStyleBackColor = true;
            this.button2.Click += new System.EventHandler(this.button2_Click);
            //
            // comboBox1
            //
            this.comboBox1.FormattingEnabled = true;
            this.comboBox1.Location = new System.Drawing.Point(12, 11);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Size = new System.Drawing.Size(121, 21);
            this.comboBox1.TabIndex = 3;
            this.comboBox1.TextUpdate += new System.EventHandler(this.comboBox1_TextUpdate);
            //
            // timer1
            //
            this.timer1.Enabled = true;
            this.timer1.Interval = 1000;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            //
            // button1
            //
            this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.button1.Location = new System.Drawing.Point(528, 9);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(22, 23);
            this.button1.TabIndex = 4;
            this.button1.Text = "X";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            //
            // Form1
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(562, 311);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.comboBox1);
            this.Controls.Add(this.button2);
            this.Controls.Add(this.tabControl1);
            this.DoubleBuffered = true;
            this.KeyPreview = true;
            this.Name = "Form1";
            this.Text = "Facebook Chat";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.TabControl tabControl1;
        private System.Windows.Forms.Button button2;
        private System.Windows.Forms.ComboBox comboBox1;
        private System.Windows.Forms.Timer timer1;
        private System.Windows.Forms.Button button1;
    }
}

Wednesday, October 23, 2013

Determine Whether Chat Partner is Typing in Facebook Chat

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

Today I just want to show briefly, how to determine with C#, when a chat partner in the Facebook chat is typing - as it is for example also shown on Facebook.
This post is based upon the previous one about receiving messages. From that only a tiny bit has to be changed, since the "typing" event is send like a chat message: The message then has no Body, but the property Chatstate is then equal to Composing. If the user stops typing, a message with Chatstate active is send.
An exemplary MessageCallback function could look as follows:

private void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
{
    if (msg.Body != null)
    {
        MessageBox.Show(msg.From + ": " + msg.Body);
    }
    else
    {
        if (msg.Chatstate == agsXMPP.protocol.extensions.chatstates.Chatstate.composing)
            MessageBox.Show(msg.From + ": Started Typing");
        if (msg.Chatstate == agsXMPP.protocol.extensions.chatstates.Chatstate.active)
            MessageBox.Show(msg.From + ": Stopped Typing");
    }
}
I should mention though, that this function unfortunately does not work very well. The start of the composition of a message is send without problems, but the end of it often not.
Therefore, I thought about using a timer to reset the "composing" status. If someone has a better advice, I would be happy about a comment.

Tuesday, October 22, 2013

Rudimentary Facebook Chat Client

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

Today I want to combine the previous posts and present you a basic client for the Facebook chat.
When loading the form the connection is established and all friends from the contact list are saved in the dictionary Friends. Additionally, for each one a MessageCallback is created, so that any incoming message is received.
If this process is done, the form is shown.
It contains 2 text boxes and 1 button. In textBox1 the receiver can be specified, in textBox2 the message text. By clicking the button the message is send. Incoming messages are displayed in message boxes.
As receiver the complete Facebook name has to be specified, which means the name what is shown for example in the chat bar.
The program then converts this name to the corresponding Jid using the dictionary Friends, for incoming messages it converts the Jid to a name.

Since all code parts are known from previous posts, here directly the code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

using System.Net;
using System.IO;
using Newtonsoft.Json.Linq;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");
        Dictionary<string, string> Friends = new Dictionary<string, string>();
        bool StartCollectingContacts = false;
        bool CollectingContacts = true;

        private void Form1_Load(object sender, EventArgs e)
        {
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("name", "password");

            while (CollectingContacts)
            {
                if (StartCollectingContacts)
                    CollectingContacts = false;
                System.Threading.Thread.Sleep(1000);
            }
        }

        private void OnLogin(object sender)
        {
            Presence p = new Presence(ShowType.chat, "Online");
            p.Type = PresenceType.available;
            xmpp.Send(p);
            xmpp.OnRosterItem += new XmppClientConnection.RosterHandler(xmpp_OnRosterItem);
        }

        private void xmpp_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
        {
            try
            {
                StartCollectingContacts = true;
                CollectingContacts = true;
                Friends.Add(item.GetAttribute("jid").ToString(), item.GetAttribute("name").ToString());
                xmpp.MessageGrabber.Add(new Jid(item.GetAttribute("jid").ToString()), new BareJidComparer(), new MessageCB(MessageCallBack), null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
        {
            if (msg.Body != null)
            {
                MessageBox.Show(Friends[msg.From.ToString()] + ": " + msg.Body);
            }
        }

        public void SendMessage(string msg, string receiverName) {
            xmpp.Send(new agsXMPP.protocol.client.Message(new Jid(receiverName), agsXMPP.protocol.client.MessageType.chat, msg));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string ReceiverId = Friends.First(x => x.Value == textBox1.Text).Key;
            SendMessage(textBox2.Text, ReceiverId);
        }

    }
}

Monday, October 21, 2013

Receive Facebook Messages

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

In this post I want to show, how to receive messages over the Facebook chat using C#. Since "normal" messages and chat messages are sent using the same principle, with this not only chat messages can be received.
Requirement is a connection to the Facebook chat with XMPP, furthermore the previous post could be useful, in which is shown, how to read the Jids of the friends, which are needed for receiving.

To receive messages from contacts, for each a so called MessageCallback has to be created:

xmpp.MessageGrabber.Add(new Jid("-100006476847029@chat.facebook.com"), new BareJidComparer(), new MessageCB(MessageCallBack), null);

If now a message is received from the corresponding contact, the function MessageCallBack() is called.
This could look for example as follows:

private void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
{
    if (msg.Body != null)
    {
        MessageBox.Show(msg.From + ": " + msg.Body);
    }
}

The complete code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");

        private void Form1_Load(object sender, EventArgs e)
        {
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("name""password");
        }

        private void OnLogin(object sender)
        {
            xmpp.MessageGrabber.Add(new Jid("-100006476847029@chat.facebook.com"), new BareJidComparer(), new MessageCB(MessageCallBack), null);
        }

        private void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
        {
            if (msg.Body != null)
            {
                MessageBox.Show(msg.From + ": " + msg.Body);
            }
        }
    }
}

Sunday, October 20, 2013

Send Facebook Message

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

In this post I want to show, how to send messages over the Facebook chat using C#. Since "normal" messages and chat messages are sent using the same principle, with this not only chat messages can be send.
Requirement is a connection to the Facebook chat with XMPP, furthermore the previous post could be useful, in which is shown, how to read the Jids of the friends, which are needed for sending.

Once the connection to Facebook is established, messages can be send with one line of code, we encapsulate it in a function:

public void SendMessage(string msg, string receiverName)
{
    xmpp.Send(new agsXMPP.protocol.client.Message(new Jid(receiverName), agsXMPP.protocol.client.MessageType.chat, msg));
}

Note, that the Jid of the receiver starts with a "-". The following line for example sends a message to me:

SendMessage("Hello Oliver.", "-100006476847029@chat.facebook.com");

The complete code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");

        private void Form1_Load(object sender, EventArgs e)
        {
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("name""password");
        }

        private void OnLogin(object sender)
        {
            SendMessage("Hello Oliver.""-100006476847029@chat.facebook.com");
        }

        public void SendMessage(string msg, string receiverName)
        {
            xmpp.Send(new agsXMPP.protocol.client.Message(new Jid(receiverName), agsXMPP.protocol.client.MessageType.chat, msg));
        }
    }
}

Saturday, October 19, 2013

Read-out Facebook Friend List

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

One could request the Facebook friend list with the Graph API, similiar to the principle in this post. For that though one needs an access token, which expires from time to time and has to work with JSON objects.
Therefore I use a function of the XMPP protocoll. A requirement for this is a connection to the Facebook chat, like I described in the previous post.
Now we just have to add a handler for the OnRosterItem event, which occurs once for every contact in the contact list, so we can read-out all friends.
We can do this for example on login:

private void OnLogin(object sender)
{
    xmpp.OnRosterItem += new XmppClientConnection.RosterHandler(xmpp_OnRosterItem);
}

For saving the friends a Dictionary is suited:

Dictionary<string, string> Friends = new Dictionary<string, string>();

In the handling of OnRosterItem we then save all contacts in the dictionary:

private void xmpp_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
{
    Friends.Add(item.GetAttribute("jid").ToString(), item.GetAttribute("name").ToString());
}

For sending / receiving messages we need the Jid of the partner, which is why we save that, we use the name for converting it to the known name.
Jid and name can then be accessed as follows:

string JidBloggeroliver = Friends.First(x => x.Value == "Olli Michael").Key;
string NameBloggeroliver = Friends["-100006476847029@chat.facebook.com"];

Now the complete code. I added a loop after opening the connection, which waits, until all contacts are loaded.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.IO;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");
        bool StartCollectingContacts = false;
        bool CollectingContacts = true;
        Dictionary<string, string> Friends = new Dictionary<string, string>();

        private void Form1_Load(object sender, EventArgs e)
        {
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("name", "password");

            while (CollectingContacts)
            {
                if (StartCollectingContacts)
                    CollectingContacts = false;
                System.Threading.Thread.Sleep(1000);
            }

            string JidBloggeroliver = Friends.First(x => x.Value == "Olli Michael").Key;
            string NameBloggeroliver = Friends["-100006476847029@chat.facebook.com"];
        }

        private void OnLogin(object sender)
        {
            xmpp.OnRosterItem += new XmppClientConnection.RosterHandler(xmpp_OnRosterItem);
        }

        private void xmpp_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
        {
            StartCollectingContacts = true;
            CollectingContacts = true;
            Friends.Add(item.GetAttribute("jid").ToString(), item.GetAttribute("name").ToString());
        }
    }

}

Friday, October 18, 2013

Connect to the Facebook Chat

Notice: Since the release of the Facebook API 2.0 in April 2014 the chat function is disabled, which means that this code unfortunately is no longer runnable.

In the previous two posts (Read Data from Facebook and Publish Facebook Posts) the topic was the connection to Facebook using the Graph API. This is a simple HTTP based API, over which via HTTP requests data of Facebook can be accessed.
Today I want to explain, how to connect to the Facebook Chat via C#, which is based upon the XMPP (earlier Jabber) protocol.
XMPP is a communication protocol basing upon XMP, which is mainly used for instant messaging.
Some known programs, like Google Talk and WhatsApp use this protocol, many others, e.g. ICQ, Skype and Facebook offer a possibility for connecting.
The XMPP protocol is easy to understand and very structured, so that we can connect without much code to the Facebook chat and send and recceive messages.
Since the chat and the "normal" messaging function are not separated as earlier anymore, we can also send and receive conventional messages with the code.
Reading out the contact list is also possible.
I will introduce the chat step by step. Today I will show the inclusion of XMPP and the logging in to the Facebook service.
In the next days the following posts will come online:

Reading Out the Contact List
Sending Messages
Receiving Messages
Complete Chat Client
Determine Status "Typing"
Advanced Chat Client

Now let us come to the first part. In theory we can write our own XMPP framework, which then transmits data via sockets etc.
I will use an external libary though, nameley agsXMPP, which saves us from a lot of work.
Please install this first and install it.
If we want to use it in the project, we have to add a reference to it. For that we click on "Add Reference - Browse" and select in the installation directory \agsxmpp\bin\(matching .Net Version, probably 3.5)\(Debug | Release)\agsXMPP.dll.
In the next posts we will need the following using directives:

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

Then we can prepare the connection to the Facebook server (chat.facebook.com) with:

XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");

Before the actual logging in we store a function as reaction to the OnLogin event. This is, because the logging in occurs asynchronous, as soon as it is done the event occurs:

xmpp.OnLogin += new ObjectHandler(OnLogin);

The function looks as follows, basically all commands it are optional, the last 3 lines of codes change our login status to online:

private void OnLogin(object sender)
{
    MessageBox.Show("Login successful.");
    Presence p = new Presence(ShowType.chat, "Online");
    p.Type = PresenceType.available;
    xmpp.Send(p);
}

After that we can connect with our data. Here the Facebook name (the name in the URL of the profile, e.g. for https://www.facebook.com/hans.wurst hans.wurst) and the password is needed:

xmpp.Open("name""password");

The complete code could look as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.protocol.iq.roster;
using agsXMPP.Collections;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        XmppClientConnection xmpp = new XmppClientConnection("chat.facebook.com");

        private void Form1_Load(object sender, EventArgs e)
        {
            xmpp.OnLogin += new ObjectHandler(OnLogin);
            xmpp.Open("""");
        }

        private void OnLogin(object sender)
        {
            MessageBox.Show("Login successful.");
            Presence p = new Presence(ShowType.chat, "Online");
            p.Type = PresenceType.available;
            xmpp.Send(p);
        }
    }
}

Monday, October 14, 2013

Calculate Binomial Coefficient

In this post I want to publish code for calculating the binomial coefficient, which is for example used frequently in combinatorics.
The binomial coefficient of two numbers n and k is written as

and is calculated by n!/(k! * (n-k)!), where x! denotes the factorial.
Instead of implementing this form directly in C#, I first calculate the part n!/k! = n * (n - 1) * ... * (k + 1), which dramatically decreased the used numbers, increases the speed and lets overflows occur only later.
The code, I use the function Factorial() from the previous post for calculating factorials:

        public ulong BinC(ulong n, ulong k)
        {
            if (n < k)
                return 0;

            ulong Numerator = 1;
            for (ulong i = n; i > k; i--)
            {
                Numerator *= i;
            }
            ulong Demoninator = Factorial(n - k);
            return (Numerator / Demoninator);
        }

        public ulong Factorial(ulong n)
        {
            ulong Result = 1;
            for (ulong i = 1; i <= n; i++)
            {
                Result *= i;
            }
            return Result;
        }