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