From 8f3f26d484757dfb92298ff7d84d1d31218c9048 Mon Sep 17 00:00:00 2001
From: Guillaume Carmel-Archambault
 <guillaume.carmel-archambault@savoirfairelinux.com>
Date: Mon, 3 Mar 2008 17:11:14 -0500
Subject: [PATCH] Presence and contacts in server

---
 configure.ac                 |   1 +
 src/Makefile.am              |   3 +-
 src/account.cpp              |  53 +++-
 src/account.h                |  28 ++-
 src/contact/Makefile.am      |  10 +
 src/contact/contact.cpp      |  38 +++
 src/contact/contact.h        |  53 ++++
 src/contact/presence.cpp     |  28 +++
 src/contact/presence.h       |  42 ++++
 src/contact/presencestatus.h |  56 +++++
 src/iaxvoiplink.h            |   1 +
 src/managerimpl.cpp          |  34 ++-
 src/sipvoiplink.cpp          | 462 +++++++++++++++++++++++------------
 src/sipvoiplink.h            |   8 +-
 src/voiplink.cpp             |  17 ++
 src/voiplink.h               |  20 +-
 16 files changed, 671 insertions(+), 183 deletions(-)
 create mode 100644 src/contact/Makefile.am
 create mode 100644 src/contact/contact.cpp
 create mode 100644 src/contact/contact.h
 create mode 100644 src/contact/presence.cpp
 create mode 100644 src/contact/presence.h
 create mode 100644 src/contact/presencestatus.h

diff --git a/configure.ac b/configure.ac
index e1aa6c9f99..ad50c0b016 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,7 @@ AC_CONFIG_FILES([src/Makefile \
   src/audio/codecs/Makefile
   src/audio/codecs/ilbc/Makefile \
   src/config/Makefile \
+  src/contact/Makefile \
   src/dbus/Makefile \
   src/zeroconf/Makefile])
   
diff --git a/src/Makefile.am b/src/Makefile.am
index bc9cb7aa7e..13df4134db 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,7 @@ IAXSOURCES =
 IAXHEADERS =
 endif
 
-SUBDIRS = audio config dbus $(ZEROCONFDIR)
+SUBDIRS = audio config contact dbus $(ZEROCONFDIR)
 
 sflphoned_SOURCES = eventthread.cpp 	main.cpp 	voiplink.cpp \
 		managerimpl.cpp	observer.cpp \
@@ -51,6 +51,7 @@ libsflphone_la_LIBADD = \
 	./audio/libaudio.la \
 	./dbus/libdbus.la \
 	./config/libconfig.la \
+	./contact/libcontact.la \
 	$(IAX_LIBS)
 
 libsflphone_la_SOURCES =
diff --git a/src/account.cpp b/src/account.cpp
index fa62554fce..67f89134e2 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -21,25 +21,60 @@
 #include "voiplink.h"
 #include "manager.h"
 
+#include <string>
+
 Account::Account(const AccountID& accountID) : _accountID(accountID)
 {
-  _link = NULL;
-
-  _enabled = false;
+	_link = NULL;
+	_enabled = false;
 }
 
-
 Account::~Account()
 {
-  // _link should be destroyed WHERE IT'S CREATED
-  //delete _link;
-  //_link = NULL;
 }
 
+void
+Account::loadConfig()
+{
+	_enabled = Manager::instance().getConfigInt(_accountID, CONFIG_ACCOUNT_ENABLE) ? true : false;
+}
 
+// NOW
 void
-Account::loadConfig() 
+Account::loadContacts()
 {
-  _enabled = Manager::instance().getConfigInt(_accountID, CONFIG_ACCOUNT_ENABLE) ? true : false;
+	// TMP
+	Contact* contact1 = new Contact("1223345", "Guillaume140", "<sip:140@asterix.inside.savoirfairelinux.net>");
+	_contacts.push_back(contact1);
+	Contact* contact2 = new Contact("9876543", "SFLphone131", "<sip:131@asterix.inside.savoirfairelinux.net>");
+	_contacts.push_back(contact2);
+	Contact* contact3 = new Contact("6867823", "Guillaume201", "<sip:201@192.168.1.202:5066>");
+	_contacts.push_back(contact3);
+	Contact* contact4 = new Contact("3417928", "SFLphone203", "<sip:203@192.168.1.202:5066>");
+	_contacts.push_back(contact4);
+	
+	// TODO Load contact file containing list of contacts
+	// or a configuration for LDAP contacts
 }
 
+void
+Account::subscribeContactsPresence()
+{
+	if(_link->isContactPresenceSupported())
+	{
+		// Subscribe to presence for each contact that presence is enabled
+		std::vector<Contact*>::iterator iter;
+		
+		for(iter = _contacts.begin(); iter != _contacts.end(); iter++)
+		{
+			_link->subscribePresenceForContact(*iter);
+		}
+	}
+}
+
+void
+Account::publishPresence(std::string presenceStatus)
+{
+	if(_link->isContactPresenceSupported())
+		_link->publishPresenceStatus(presenceStatus);
+}
diff --git a/src/account.h b/src/account.h
index 6d8cb2b6d9..ddf7775088 100644
--- a/src/account.h
+++ b/src/account.h
@@ -20,7 +20,9 @@
 #define ACCOUNT_H
 
 #include <string>
+#include <vector>
 #include "config/config.h"
+#include "contact/contact.h"
 #include "voiplink.h"
 
 class VoIPLink;
@@ -46,9 +48,6 @@ typedef std::string AccountID;
 #define SIP_STUN_SERVER       "STUN.STUNserver"
 #define SIP_USE_STUN          "STUN.useStun"
 
-
-
-
 /**
  * Class account is an interface to protocol account (SIPAccount, IAXAccount)
  * It can be enable on loading or activate after.
@@ -65,7 +64,7 @@ class Account{
    * Load the settings for this account.
    */
   virtual void loadConfig();
-
+  
   /**
    * Get the account ID
    * @return constant account id
@@ -106,6 +105,21 @@ class Account{
    */
   VoIPLink::RegistrationState getRegistrationState() { return _link->getRegistrationState(); }
 
+  /**
+   * Load all contacts
+   */
+  void loadContacts();
+  
+  /**
+   * Suscribe presence information for selected contacts if supported
+   */
+  void subscribeContactsPresence();
+  
+  /**
+   * Publish our presence information to the server
+   */
+  void publishPresence(std::string presenceStatus);
+
 private:
 
 protected:
@@ -127,7 +141,11 @@ protected:
    * Modified by the configuration (key: ENABLED)
    */
   bool _enabled;
-
+  
+  /**
+   * Contacts related to account that can have presence information
+   */
+  std::vector<Contact*> _contacts;
 };
 
 #endif
diff --git a/src/contact/Makefile.am b/src/contact/Makefile.am
new file mode 100644
index 0000000000..6fe167a9e4
--- /dev/null
+++ b/src/contact/Makefile.am
@@ -0,0 +1,10 @@
+SUBDIRS = 
+
+noinst_LTLIBRARIES = \
+	libcontact.la
+
+libcontact_la_SOURCES = \
+	contact.h \
+	presence.h \
+	contact.cpp \
+	presence.cpp
diff --git a/src/contact/contact.cpp b/src/contact/contact.cpp
new file mode 100644
index 0000000000..de73810c6b
--- /dev/null
+++ b/src/contact/contact.cpp
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *
+ *  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 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "contact.h"
+#include <string>
+
+Contact::Contact()
+{
+}
+
+Contact::Contact(const std::string contactID, const std::string name, const std::string url)
+{
+	_contactID = contactID;
+	_name = name;
+	_url = url;
+	_suscribeToPresence = true;
+	_presence = NULL;
+}
+
+Contact::~Contact()
+{
+}
diff --git a/src/contact/contact.h b/src/contact/contact.h
new file mode 100644
index 0000000000..0672742d91
--- /dev/null
+++ b/src/contact/contact.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *                                                                              
+ *  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 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CONTACT_H
+#define CONTACT_H
+
+#include "presence.h"
+
+#include <string>
+
+typedef std::string ContactID;
+
+/**
+ * TOCOMMENT
+ * @author Guillaume Carmel-Archambault
+ */
+class Contact {
+public:
+	Contact();
+	Contact(const std::string contactID, const std::string name, const std::string url);
+	virtual ~Contact();
+	
+	std::string getUrl() { return _url; }
+	
+protected:
+	
+private:
+	ContactID _contactID;
+	std::string _name;
+	std::string _url;
+	bool _suscribeToPresence;
+	
+	// Presence information, can be null
+	Presence* _presence;
+};
+
+#endif
diff --git a/src/contact/presence.cpp b/src/contact/presence.cpp
new file mode 100644
index 0000000000..993ee2b0d2
--- /dev/null
+++ b/src/contact/presence.cpp
@@ -0,0 +1,28 @@
+/*
+ *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *
+ *  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 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "presence.h"
+
+Presence::Presence()
+{
+}
+
+Presence::~Presence()
+{
+}
diff --git a/src/contact/presence.h b/src/contact/presence.h
new file mode 100644
index 0000000000..8514001c5e
--- /dev/null
+++ b/src/contact/presence.h
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *                                                                              
+ *  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 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PRESENCE_H
+#define PRESENCE_H
+
+#include <string>
+
+/**
+ * TOCOMMENT
+ * @author Guillaume Carmel-Archambault
+ */
+class Presence {
+	
+public:
+	Presence();
+	virtual ~Presence();
+		
+protected:
+	
+private:
+	std::string _state;
+	std::string _capabalities;
+};
+
+#endif
diff --git a/src/contact/presencestatus.h b/src/contact/presencestatus.h
new file mode 100644
index 0000000000..f0169b1c49
--- /dev/null
+++ b/src/contact/presencestatus.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *                                                                              
+ *  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 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PRESENCE_STATUS_H
+#define PRESENCE_STATUS_H
+
+/* Definition of all presence status used by the deamon and the GUI
+ * The deamon knows how to identify tags coming from presence servers
+ * and cast them in a defined presence status presented here. 
+ * The presence information is transmitted along DBus by those strings.
+ * The GUI can format and translate these strings for presentation. 
+ * 
+ * If a presence status identified by a string cannot be identified
+ * when sent from a presence server, we directly use the raw string
+ * without any formating or translation process possible
+ */
+// Same presence status as defined in Asterisk
+#define PRESENCE_UNKNOWN			"UNKNOWN"
+#define PRESENCE_NOT_IN_USE			"NOT_IN_USE"
+#define PRESENCE_INUSE				"INUSE"
+#define PRESENCE_BUSY				"BUSY"
+#define PRESENCE_INVALID			"INVALID"
+#define PRESENCE_UNAVAILABLE		"UNAVAILABLE"
+#define PRESENCE_RINGING			"RINGING"
+#define PRESENCE_RING_IN_USE		"RING_IN_USE"
+#define PRESENCE_HOLD_IN_USE		"HOLD_IN_USE"
+#define PRESENCE_ON_HOLD			"ON_HOLD"
+// Presence status defined on some hardware phones
+#define PRESENCE_ONLINE				"ONLINE"
+#define PRESENCE_BUSY				"BUSY"
+#define PRESENCE_BE_RIGHT_BACK		"BE_RIGHT_BACK"
+#define PRESENCE_AWAY				"AWAY"
+#define PRESENCE_OUT_TO_LUNCH		"OUT_TO_LUNCH"
+#define PRESENCE_OFFLINE			"OFFLINE"
+#define PRESENCE_DO_NOT_DISTURB		"DO_NOT_DISTURB"
+// Other presence status defined supported
+#define PRESENCE_IN_REUNION			"IN_REUNION"
+#define PRESENCE_IN_CONFERENCE_CALL	"IN_CONFERENCE_CALL"
+
+#endif
diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h
index c0fe8c30a8..938415edb5 100644
--- a/src/iaxvoiplink.h
+++ b/src/iaxvoiplink.h
@@ -82,6 +82,7 @@ public:
   bool refuse (const CallID& id);
   bool carryingDTMFdigits(const CallID& id, char code);
   bool sendMessage(const std::string& to, const std::string& body) { return false; }
+  bool isContactPresenceSupported() { return false; }
 
 public: // iaxvoiplink only
   void setHost(const std::string& host) { _host = host; }
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index ecad7b0880..bbb3a90013 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -47,6 +47,8 @@
 
 #include "user_cfg.h"
 
+#include "contact/presencestatus.h"
+
 #ifdef USE_ZEROCONF
 #include "zeroconf/DNSService.h"
 #include "zeroconf/DNSServiceTXTRecord.h"
@@ -428,18 +430,22 @@ ManagerImpl::saveConfig (void)
 bool
 ManagerImpl::initRegisterAccounts() 
 {
-  _debugInit("Initiate VoIP Links Registration");
-  AccountMap::iterator iter = _accountMap.begin();
-  while( iter != _accountMap.end() ) {
-    if ( iter->second) {
-      iter->second->loadConfig();
-      if ( iter->second->isEnabled() ) {
-	iter->second->registerVoIPLink();
-      }
-    }
-    iter++;
-  }
-  return true;
+	_debugInit("Initiate VoIP Links Registration");
+	AccountMap::iterator iter = _accountMap.begin();
+	while( iter != _accountMap.end() ) {
+		if ( iter->second) {
+			iter->second->loadConfig();
+			if ( iter->second->isEnabled() ) {
+				// NOW
+				iter->second->registerVoIPLink();
+				iter->second->loadContacts();
+				iter->second->publishPresence(PRESENCE_ONLINE);
+				iter->second->subscribeContactsPresence();
+			}
+		}
+		iter++;
+	}
+	return true;
 }
 
 //THREAD=Main
@@ -460,7 +466,11 @@ ManagerImpl::registerAccount(const AccountID& accountId)
       }
       iter++;
     }
+    // NOW
     account->registerVoIPLink();
+    account->loadContacts();
+    account->publishPresence(PRESENCE_ONLINE);
+    account->subscribeContactsPresence();
   }
   return true;
 }
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index 4ee45841bd..eda68f4871 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -212,158 +212,229 @@ SIPVoIPLink::loadSIPLocalIP()
 void
 SIPVoIPLink::getEvent()
 {
-  eXosip_event_t* event = eXosip_event_wait(0, 50);
-  eXosip_lock();
-  eXosip_automatic_action();
-  eXosip_unlock();
-
-  if (event == NULL) {
-    return;
-  }
-
-  _debug("> SIP Event: [cdt=%4d:%4d:%4d] type=#%03d %s \n", event->cid, event->did, event->tid, event->type, event->textinfo);
-  switch (event->type) {
-     /* REGISTER related events */
-     case EXOSIP_REGISTRATION_NEW:         /** 00 < announce new registration.       */
-       _debug(" !EXOSIP_REGISTRATION_NEW event is not implemented\n");
-       break;
-     case EXOSIP_REGISTRATION_SUCCESS:     /** 01 < user is successfully registred.  */
-       setRegistrationState(Registered);
-       //Manager::instance().registrationSucceed(getAccountID());
-       break;
-     case EXOSIP_REGISTRATION_FAILURE:     /** 02 < user is not registred.           */
-       setRegistrationState(Error, "SIP registration failure.");
-       //Manager::instance().registrationFailed(getAccountID());
-       break;
-     case EXOSIP_REGISTRATION_REFRESHED:   /** 03 < registration has been refreshed. */
-       _debug(" !EXOSIP_REGISTRATION_REFRESHED event is not implemented\n");
-       break;
-     case EXOSIP_REGISTRATION_TERMINATED:  /** 04 < UA is not registred any more.    */
-       setRegistrationState(Unregistered, "Registration terminated by remote host");
-       _debug(" !EXOSIP_REGISTRATION_TERMINATED event is not implemented\n");
-       break;
-      
-      /* INVITE related events within calls */
-     case EXOSIP_CALL_INVITE:          /** 05 < announce a new call                   */
-       SIPCallInvite(event);
-       break;
-     case EXOSIP_CALL_REINVITE:        /** 06 < announce a new INVITE within call     */
-       SIPCallReinvite(event);
-       break;
-
-     case EXOSIP_CALL_NOANSWER:        /** 07 < announce no answer within the timeout */
-       _debug("  !EXOSIP_CALL_NOANSWER event is not implemented\n");
-       break;
-     case EXOSIP_CALL_PROCEEDING:      /** 08 < announce processing by a remote app   */
-       _debug("  !EXOSIP_CALL_PROCEEDING event is not implemented\n");
-       break;
-     case EXOSIP_CALL_RINGING:         /** 09 < announce ringback                     */
-       SIPCallRinging(event);
-       break;
-     case EXOSIP_CALL_ANSWERED:        /** 10 < announce start of call                */
-       SIPCallAnswered(event);
-       break;
-     case EXOSIP_CALL_REDIRECTED:      /** 11 < announce a redirection                */
-       _debug(" !EXOSIP_CALL_REDIRECTED event is not implemented\n");
-       break;
-     case EXOSIP_CALL_REQUESTFAILURE:  /** 12 < announce a request failure            */
-       SIPCallRequestFailure(event);
-       break;
-     case EXOSIP_CALL_SERVERFAILURE:   /** 13 < announce a server failure             */
-       SIPCallServerFailure(event);
-       break;
-     case EXOSIP_CALL_GLOBALFAILURE:   /** 14 < announce a global failure             */
-       SIPCallServerFailure(event);
-       break;
-     case EXOSIP_CALL_ACK:             /** 15 < ACK received for 200ok to INVITE      */
-       SIPCallAck(event);
-       break;
-      
-     case EXOSIP_CALL_CANCELLED:       /** 16 < announce that call has been cancelled */
-     case EXOSIP_CALL_TIMEOUT:         /** 17 < announce that call has failed         */
-       Manager::instance().displayError(" !EXOSIP Call Error not implemented yet");
-       break;
-
-      /* request related events within calls (except INVITE) */
-     case EXOSIP_CALL_MESSAGE_NEW:            /** 18 < announce new incoming MESSAGE. */
-      SIPCallMessageNew(event);
-      break;
-     case EXOSIP_CALL_MESSAGE_PROCEEDING:     /** 19 < announce a 1xx for MESSAGE. */
-     case EXOSIP_CALL_MESSAGE_ANSWERED:       /** 20 < announce a 200ok  */
-       // 200 OK
-     case EXOSIP_CALL_MESSAGE_REDIRECTED:     /** 21 < announce a failure. */
-     case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: /** 22 < announce a failure. */
-     case EXOSIP_CALL_MESSAGE_SERVERFAILURE:  /** 23 < announce a failure. */
-     case EXOSIP_CALL_MESSAGE_GLOBALFAILURE:  /** 24 < announce a failure. */
-       Manager::instance().displayError(" !EXOSIP Call Message not implemented yet");
-       break;
-
-     case EXOSIP_CALL_CLOSED:          /** 25 < a BYE was received for this call      */
-       SIPCallClosed(event);
-       break;
-
-      /* for both UAS & UAC events */
-     case EXOSIP_CALL_RELEASED:           /** 26 < call context is cleared.            */
-       SIPCallReleased(event);
-       break;
-     
-      /* response received for request outside calls */
-     case EXOSIP_MESSAGE_NEW:            /** 27 < announce new incoming MESSAGE. */
-       if (event->request == NULL) { break; }
-       SIPMessageNew(event);
-       break;
-     case EXOSIP_MESSAGE_PROCEEDING:     /** 28 < announce a 1xx for MESSAGE. */
-     case EXOSIP_MESSAGE_ANSWERED:       /** 29 < announce a 200ok  */
-     case EXOSIP_MESSAGE_REDIRECTED:     /** 30 < announce a failure. */
-       Manager::instance().displayError(" !EXOSIP Message not implemented yet");
-     break;
-
-     case EXOSIP_MESSAGE_REQUESTFAILURE: /** 31 < announce a failure. */
-       if (event->response !=0 && event->response->status_code == SIP_METHOD_NOT_ALLOWED) {
-         Manager::instance().incomingMessage(getAccountID(), "Message are not allowed");
-       } else {
-         Manager::instance().displayError(" !EXOSIP_MESSAGE_REQUESTFAILURE not implemented yet");
-       }
-     break;
-     case EXOSIP_MESSAGE_SERVERFAILURE:  /** 32 < announce a failure. */
-     case EXOSIP_MESSAGE_GLOBALFAILURE:  /** 33 < announce a failure. */
-       Manager::instance().displayError(" !EXOSIP Message not implemented yet");
-       break;
-      
-      /* Presence and Instant Messaging */
-     case EXOSIP_SUBSCRIPTION_UPDATE:       /** 34 < announce incoming SUBSCRIBE.      */
-     case EXOSIP_SUBSCRIPTION_CLOSED:       /** 35 < announce end of subscription.     */
-       Manager::instance().displayError(" !EXOSIP Subscription not implemented yet");
-       break;
-      
-     case EXOSIP_SUBSCRIPTION_NOANSWER:        /** 37 < announce no answer              */
-     case EXOSIP_SUBSCRIPTION_PROCEEDING:      /** 38 < announce a 1xx                  */
-       Manager::instance().displayError(" !EXOSIP Subscription resposne not implemented yet");
-       break;
-     case EXOSIP_SUBSCRIPTION_ANSWERED:        /** 39 < announce a 200ok                */
-       eXosip_lock();
-       eXosip_automatic_action();
-       eXosip_unlock();
-     break;
-
-     case EXOSIP_SUBSCRIPTION_REDIRECTED:      /** 40 < announce a redirection          */
-     case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:  /** 41 < announce a request failure      */
-     case EXOSIP_SUBSCRIPTION_SERVERFAILURE:   /** 42 < announce a server failure       */
-     case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:   /** 43 < announce a global failure       */
-     case EXOSIP_SUBSCRIPTION_NOTIFY:          /** 44 < announce new NOTIFY request     */
-     case EXOSIP_SUBSCRIPTION_RELEASED:        /** 45 < call context is cleared.        */
-       Manager::instance().displayError(" !EXOSIP Subscription response not implemented yet.");
-       break;
-      
-     case EXOSIP_IN_SUBSCRIPTION_NEW:          /** 46 < announce new incoming SUBSCRIBE.*/
-     case EXOSIP_IN_SUBSCRIPTION_RELEASED:     /** 47 < announce end of subscription.   */
-       Manager::instance().displayError(" !EXOSIP Subscription not implemented yet");
-       break;
-      
-     case EXOSIP_EVENT_COUNT:               /** 48 < MAX number of events  */
-      break;
-  }  
-  eXosip_event_free(event);
+	char* tmp2;
+	eXosip_event_t* event = eXosip_event_wait(0, 50);
+	eXosip_lock();
+	eXosip_automatic_action();
+	eXosip_unlock();
+	
+	if (event == NULL) {
+		return;
+	}
+
+	_debug("> SIP Event: [cdt=%4d:%4d:%4d] type=#%03d %s \n", event->cid, event->did, event->tid, event->type, event->textinfo);
+	switch (event->type) {
+	
+	/* REGISTER related events */
+	case EXOSIP_REGISTRATION_NEW:         /** 00 < announce new registration.       */
+		_debug(" !EXOSIP_REGISTRATION_NEW event is not implemented\n");
+		break;
+	case EXOSIP_REGISTRATION_SUCCESS:     /** 01 < user is successfully registred.  */
+		setRegistrationState(Registered);
+		_debug(" !EXOSIP_REGISTRATION_SUCCES\n");// TMP
+		//Manager::instance().registrationSucceed(getAccountID());
+		break;
+	case EXOSIP_REGISTRATION_FAILURE:     /** 02 < user is not registred.           */
+		setRegistrationState(Error, "SIP registration failure.");
+		_debug(" !EXOSIP_REGISTRATION_FAILURE\n");// TMP
+		//Manager::instance().registrationFailed(getAccountID());
+		break;
+	case EXOSIP_REGISTRATION_REFRESHED:   /** 03 < registration has been refreshed. */
+		_debug(" !EXOSIP_REGISTRATION_REFRESHED event is not implemented\n");
+		break;
+	case EXOSIP_REGISTRATION_TERMINATED:  /** 04 < UA is not registred any more.    */
+		setRegistrationState(Unregistered, "Registration terminated by remote host");
+		_debug(" !EXOSIP_REGISTRATION_TERMINATED event is not implemented\n");
+		break;
+
+	/* INVITE related events within calls */
+	case EXOSIP_CALL_INVITE:          /** 05 < announce a new call                   */
+		SIPCallInvite(event);
+		break;
+	case EXOSIP_CALL_REINVITE:        /** 06 < announce a new INVITE within call     */
+		SIPCallReinvite(event);
+		break;
+
+	/* CALL related events */
+	case EXOSIP_CALL_NOANSWER:        /** 07 < announce no answer within the timeout */
+		_debug(" !EXOSIP_CALL_NOANSWER event is not implemented\n");
+		break;
+	case EXOSIP_CALL_PROCEEDING:      /** 08 < announce processing by a remote app   */
+		_debug(" !EXOSIP_CALL_PROCEEDING event is not implemented\n");
+		break;
+	case EXOSIP_CALL_RINGING:         /** 09 < announce ringback                     */
+		_debug(" !EXOSIP_CALL_RINGING\n");// TMP
+		SIPCallRinging(event);
+		break;
+	case EXOSIP_CALL_ANSWERED:        /** 10 < announce start of call                */
+		_debug(" !EXOSIP_CALL_ANSWERED\n");// TMP
+		SIPCallAnswered(event);
+		break;
+	case EXOSIP_CALL_REDIRECTED:      /** 11 < announce a redirection                */
+		_debug(" !EXOSIP_CALL_REDIRECTED event is not implemented\n");
+		break;
+	case EXOSIP_CALL_REQUESTFAILURE:  /** 12 < announce a request failure            */
+		_debug(" !EXOSIP_CALL_REQUESTFAILURE");// TMP
+		SIPCallRequestFailure(event);
+		break;
+	case EXOSIP_CALL_SERVERFAILURE:   /** 13 < announce a server failure             */
+		_debug(" !EXOSIP_CALL_SERVERFAILURE");// TMP
+		SIPCallServerFailure(event);
+		break;
+	case EXOSIP_CALL_GLOBALFAILURE:   /** 14 < announce a global failure             */
+		_debug(" !EXOSIP_CALL_GLOBALFAILURE\n");// TMP
+		SIPCallServerFailure(event);
+		break;
+	case EXOSIP_CALL_ACK:             /** 15 < ACK received for 200ok to INVITE      */
+		_debug(" !EXOSIP_CALL_ACK\n");// TMP
+		SIPCallAck(event);
+		break;
+	case EXOSIP_CALL_CANCELLED:       /** 16 < announce that call has been cancelled */
+		_debug(" !EXOSIP_CALL_CANCELLED\n");// TMP
+		break;
+	case EXOSIP_CALL_TIMEOUT:         /** 17 < announce that call has failed         */
+		_debug(" !EXOSIP_CALL_TIMEOUT\n");// TMP
+		Manager::instance().displayError(" !EXOSIP Call Error not implemented yet");
+		break;
+
+	/* Request related events within calls (except INVITE) */
+	case EXOSIP_CALL_MESSAGE_NEW:            /** 18 < announce new incoming MESSAGE. */
+		_debug(" !EXOSIP_CALL_MESSAGE_NEW\n");// TMP
+		SIPCallMessageNew(event);
+		break;
+	case EXOSIP_CALL_MESSAGE_PROCEEDING:     /** 19 < announce a 1xx for MESSAGE. */
+		_debug(" !EXOSIP_CALL_MESSAGE_PROCEEDING\n");// TMP
+		break;
+	case EXOSIP_CALL_MESSAGE_ANSWERED:       /** 20 < announce a 200ok  */
+		// 200 OK
+		_debug(" !EXOSIP_CALL_MESSAGE_ANSWERED\n");// TMP
+		break;
+	case EXOSIP_CALL_MESSAGE_REDIRECTED:     /** 21 < announce a failure. */
+		_debug(" !EXOSIP_CALL_MESSAGE_REDIRECTED\n");// TMP
+		break;
+	case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: /** 22 < announce a failure. */
+		_debug(" !EXOSIP_CALL_MESSAGE_REQUESTFAILURE\n");// TMP
+		break;
+	case EXOSIP_CALL_MESSAGE_SERVERFAILURE:  /** 23 < announce a failure. */
+		_debug(" !EXOSIP_CALL_MESSAGE_SERVERFAILURE\n");// TMP
+		break;
+	case EXOSIP_CALL_MESSAGE_GLOBALFAILURE:  /** 24 < announce a failure. */
+		_debug(" !EXOSIP_CALL_MESSAGE_GLOBALFAILURE\n");// TMP
+		Manager::instance().displayError(" !EXOSIP Call Message not implemented yet");
+		break;
+
+	case EXOSIP_CALL_CLOSED:          /** 25 < a BYE was received for this call */
+		_debug(" !EXOSIP_CALL_CLOSED\n");// TMP
+		SIPCallClosed(event);
+		break;
+
+	/* For both UAS & UAC events */
+	case EXOSIP_CALL_RELEASED:           /** 26 < call context is cleared. */
+		_debug(" !EXOSIP_CALL_RELEASED\n");// TMP
+		SIPCallReleased(event);
+		break;
+
+	/* Response received for request outside calls */
+	case EXOSIP_MESSAGE_NEW:            /** 27 < announce new incoming MESSAGE. */
+		_debug(" !EXOSIP_MESSAGE_NEW\n");// TMP
+		if (event->request == NULL) { break; }
+		SIPMessageNew(event);
+		break;
+	case EXOSIP_MESSAGE_PROCEEDING:     /** 28 < announce a 1xx for MESSAGE. */
+		_debug(" !EXOSIP_MESSAGE_PROCEEDING\n");// TMP
+		break;
+	case EXOSIP_MESSAGE_ANSWERED:       /** 29 < announce a 200ok  */
+		_debug(" !EXOSIP_MESSAGE_ANSWERED\n");// TMP
+		break;
+	case EXOSIP_MESSAGE_REDIRECTED:     /** 30 < announce a failure. */
+		_debug(" !EXOSIP_MESSAGE_REDIRECTED\n");// TMP
+		Manager::instance().displayError(" !EXOSIP Message not implemented yet");
+		break;
+
+	case EXOSIP_MESSAGE_REQUESTFAILURE: /** 31 < announce a failure. */
+		_debug(" !EXOSIP_MESSAGE_REQUESTFAILURE\n");// TMP
+		if (event->response !=0 && event->response->status_code == SIP_METHOD_NOT_ALLOWED) {
+			Manager::instance().incomingMessage(getAccountID(), "Message are not allowed");
+		} else {
+			Manager::instance().displayError(" !EXOSIP_MESSAGE_REQUESTFAILURE not implemented yet");
+		}
+		break;
+	case EXOSIP_MESSAGE_SERVERFAILURE:  /** 32 < announce a failure. */
+		_debug(" !EXOSIP_MESSAGE_SERVERFAILURE\n");// TMP
+		break;
+	case EXOSIP_MESSAGE_GLOBALFAILURE:  /** 33 < announce a failure. */
+		_debug(" !EXOSIP_MESSAGE_GLOBALFAILURE\n");// TMP
+		Manager::instance().displayError(" !EXOSIP Message not implemented yet");
+		break;
+
+	/* Presence and Instant Messaging */
+	case EXOSIP_SUBSCRIPTION_UPDATE:       /** 34 < announce incoming SUBSCRIBE.      */
+		_debug(" !EXOSIP_SUBSCRIPTION_UPDATE\n");
+		break;
+	case EXOSIP_SUBSCRIPTION_CLOSED:       /** 35 < announce end of subscription.     */
+		_debug(" !EXOSIP_SUBSCRIPTION_CLOSED\n");
+		Manager::instance().displayError(" !EXOSIP Subscription not implemented yet");
+		break;
+
+	case EXOSIP_SUBSCRIPTION_NOANSWER:        /** 37 < announce no answer              */
+		_debug(" !EXOSIP_SUBSCRIPTION_NOANSWER\n");
+		break;
+	case EXOSIP_SUBSCRIPTION_PROCEEDING:      /** 38 < announce a 1xx                  */
+		_debug(" !EXOSIP_SUBSCRIPTION_PROCEEDING\n");
+		Manager::instance().displayError(" !EXOSIP Subscription response not implemented yet");
+		break;
+	case EXOSIP_SUBSCRIPTION_ANSWERED:        /** 39 < announce a 200ok                */
+		_debug(" !EXOSIP_SUBSCRIPTION_ANSWERED\n");
+		eXosip_lock();
+		eXosip_automatic_action();
+		eXosip_unlock();
+		break;
+
+	case EXOSIP_SUBSCRIPTION_REDIRECTED:      /** 40 < announce a redirection          */
+		_debug(" !EXOSIP_SUBSCRIPTION_REDIRECTED\n");// TMP
+		break;
+	case EXOSIP_SUBSCRIPTION_REQUESTFAILURE:  /** 41 < announce a request failure      */
+		_debug(" !EXOSIP_SUBSCRIPTION_REQUESTFAILURE\n");// TMP
+		break;
+	case EXOSIP_SUBSCRIPTION_SERVERFAILURE:   /** 42 < announce a server failure       */
+		_debug(" !EXOSIP_SUBSCRIPTION_REQUESTFAILURE\n");// TMP
+		break;
+	case EXOSIP_SUBSCRIPTION_GLOBALFAILURE:   /** 43 < announce a global failure       */
+		_debug(" !EXOSIP_SUBSCRIPTION_GLOBALFAILURE\n");// TMP
+		break;
+	case EXOSIP_SUBSCRIPTION_NOTIFY:          /** 44 < announce new NOTIFY request     */
+		_debug(" !EXOSIP_SUBSCRIPTION_NOTIFY\n");
+		osip_body_t* body;
+		osip_from_to_str(event->request->from, &tmp2);
+		osip_message_get_body(event->request, 0, &body);
+		if (body != NULL && body->body != NULL) {
+			printf("\n---------------------------------\n");
+			printf ("(%i) from: %s\n  %s\n", event->tid, tmp2, body->body);
+			printf("---------------------------------\n");
+			osip_free(tmp2);
+		}
+		break;
+	case EXOSIP_SUBSCRIPTION_RELEASED:        /** 45 < call context is cleared.        */
+		_debug(" !EXOSIP_SUBSCRIPTION_RELEASED\n");
+		Manager::instance().displayError(" !EXOSIP Subscription response not implemented yet.");
+		break;
+
+	case EXOSIP_IN_SUBSCRIPTION_NEW:          /** 46 < announce new incoming SUBSCRIBE.*/
+		_debug(" !EXOSIP_IN_SUBSCRIPTION_NEW\n");
+		break;
+	case EXOSIP_IN_SUBSCRIPTION_RELEASED:     /** 47 < announce end of subscription.   */
+		_debug(" !EXOSIP_IN_SUBSCRIPTION_RELEASED\n");
+		Manager::instance().displayError(" !EXOSIP Subscription not implemented yet");
+		break;
+
+	case EXOSIP_EVENT_COUNT:               /** 48 < MAX number of events  */
+		_debug(" !EXOSIP_EVENT_COUNT : SHOULD NEVER HAPPEN!!!!!\n"); // TMP
+		break;
+	default:
+		printf("received eXosip event (type, did, cid) = (%d, %d, %d)", event->type, event->did, event->cid);
+		break;
+	}  
+	eXosip_event_free(event);
 }
 
 bool
@@ -895,6 +966,93 @@ SIPVoIPLink::sendMessage(const std::string& to, const std::string& body)
   return returnValue;
 }
 
+// NOW
+bool
+SIPVoIPLink::isContactPresenceSupported()
+{
+	return true;
+}
+
+void
+SIPVoIPLink::subscribePresenceForContact(Contact* contact)
+{
+	osip_message_t* subscription;
+	
+	int i;
+	
+	std::string to   = contact->getUrl().data();
+	std::ostringstream from;
+	
+	// Build URL of sender
+	from << "sip:" << _userpart.data() << "@" << getHostName().data();
+
+	// Subscribe for changes on server but also polls at every 5000 interval
+	i = eXosip_subscribe_build_initial_request(&subscription,
+			to.data(),
+			from.str().c_str(),
+			NULL,
+			"presence", 5000);
+	if(i!=0) return;
+	
+	// We want to receive presence in the PIDF XML format in SIP messages
+	osip_message_set_accept(subscription, "application/pidf+xml");
+	
+	// Send subscription
+	eXosip_lock();
+	i = eXosip_subscribe_send_initial_request(subscription);
+	if(i!=0) _debug("Sending of subscription tp %s failed\n", to.data());
+	eXosip_unlock();
+}
+
+void
+SIPVoIPLink::publishPresenceStatus(std::string status)
+{
+	_debug("PUBLISH PRESENCE\n");
+	char buf[4096];
+	int i;
+	osip_message_t* publication;
+	
+	std::ostringstream url;
+	std::string basic;
+	std::string note;
+	
+	// Build URL of sender
+	url << "sip:" << _userpart.data() << "@" << getHostName().data();
+	
+	// TODO
+	// Call function to convert status in basic and note
+	// tags that are integrated in the publication
+	basic = "open";
+	note = "ready";
+	
+	snprintf(buf, 4096,
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
+<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\
+          xmlns:es=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n\
+          entity=\"%s\">\n\
+	<tuple id=\"sg89ae\">\n\
+		<status>\n\
+			<basic>%s</basic>\n\
+			<es:activities>\n\
+				<es:activity>in-transit</es:activity>\n\
+			</es:activities>\n\
+		</status>\n\
+		<contact priority=\"0.8\">%s</contact>\n\
+		<note>%s</note>\n\
+	</tuple>\n\
+</presence>"
+			, url.str().c_str(), basic.data(), url.str().c_str(), note.data());
+		
+	// TMP
+	printf("%s\n", buf);
+	
+	i = eXosip_build_publish(&publication, url.str().c_str(), url.str().c_str(), NULL, "presence", "1800", "application/pidf+xml", buf);
+	
+	eXosip_lock();
+	i = eXosip_publish(publication, url.str().c_str());
+	eXosip_unlock();
+}
+
 bool
 SIPVoIPLink::SIPOutgoingInvite(SIPCall* call) 
 {
diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h
index f6f30268e0..d25553c7db 100644
--- a/src/sipvoiplink.h
+++ b/src/sipvoiplink.h
@@ -60,8 +60,12 @@ public:
   bool refuse (const CallID& id);
   bool carryingDTMFdigits(const CallID& id, char code);
   bool sendMessage(const std::string& to, const std::string& body);
-
-
+  bool isContactPresenceSupported();
+  void subscribePresenceForContact(Contact* contact);
+  void publishPresenceStatus(std::string status);
+  
+  // TODO Not used yet
+  void sendMessageToContact(const CallID& id, const std::string& message);
 
   // SIP Specific
 
diff --git a/src/voiplink.cpp b/src/voiplink.cpp
index bf678333e4..7da85fa6f5 100644
--- a/src/voiplink.cpp
+++ b/src/voiplink.cpp
@@ -108,3 +108,20 @@ VoIPLink::setRegistrationState(const enum RegistrationState state)
 {
   setRegistrationState(state, "");
 }
+
+// NOW
+void
+VoIPLink::subscribePresenceForContact(Contact* contact)
+{
+	// Nothing to do if presence is not supported
+	// or the function will be overidden
+	_debug("Presence subscription not supported for account\n");
+}
+
+void
+VoIPLink::publishPresenceStatus(std::string status)
+{
+	// Nothing to do if presence is not supported
+	// or the function will be overidden
+	_debug("Presence publication not supported for account\n");
+}
diff --git a/src/voiplink.h b/src/voiplink.h
index a64c2abefa..73c16896b5 100644
--- a/src/voiplink.h
+++ b/src/voiplink.h
@@ -24,6 +24,7 @@
 
 #include <string>
 #include "call.h"
+#include "contact/contact.h"
 #include <map>
 #include <cc++/thread.h> // for mutex
 
@@ -94,6 +95,22 @@ public:
    */
   virtual bool sendMessage(const std::string& to, const std::string& body) = 0;
 
+  // NOW
+  /**
+   * Determine if link supports presence information
+   */
+  virtual bool isContactPresenceSupported() = 0;
+  
+  /**
+   * Register contacts for presence information if supported
+   */
+  virtual void subscribePresenceForContact(Contact* contact);
+  
+  /**
+   * Publish presence status to server
+   */
+  virtual void publishPresenceStatus(std::string status);
+  
   // these method are set only with 'Account init'  and can be get by everyone
   void setFullName (const std::string& fullname) { _fullname = fullname; }
   std::string& getFullName (void) { return _fullname; }
@@ -134,8 +151,7 @@ public:
    * Same, but with default error value to ""
    */
   void setRegistrationState(const enum RegistrationState state);
-
-
+  
 private:
   /**
    * Full name used as outgoing Caller ID
-- 
GitLab