Commit 27128f02 authored by PatrickKeroulas's avatar PatrickKeroulas

[Presence] Implement publish method, complete RPID in status, start

refactoring.
parent 96a2d299
......@@ -826,22 +826,18 @@
<arg type="s" name="buddySipUri" direction="in"/>
</method>
<method name="setPresenceOnline" tp:name-for-bindings="setPresenceOnline">
<tp:added version="0.9.7"/>
<arg type="s" name="accountID" direction="in"/>
</method>
<method name="setPresenceOffline" tp:name-for-bindings="setPresenceOffline">
<method name="sendPresence" tp:name-for-bindings="sendPresence">
<tp:added version="0.9.7"/>
<arg type="s" name="accountID" direction="in"/>
<arg type="s" name="status" direction="in"/>
<arg type="s" name="note" direction="in"/>
</method>
<signal name="newPresenceNotification" tp:name-for-bindings="newPresenceNotification">
<arg type="s" name="buddyUri"/>
<arg type="s" name="status"/>
<arg type="s" name="lineStatus"/>
</signal>
</signal>D
</interface>
</node>
......@@ -419,15 +419,9 @@ CallManager::unsubscribePresence(const std::string& accountID, const std::string
}
void
CallManager::setPresenceOnline(const std::string& accountID)
{
DEBUG("setPresenceOnline");
Manager::instance().setPresenceOnline(accountID);
}
void
CallManager::setPresenceOffline(const std::string& accountID)
CallManager::sendPresence(const std::string& accountID, const std::string& status, const std::string& note)
{
DEBUG("setPresenceOffline");
Manager::instance().setPresenceOffline(accountID);
DEBUG("sendPresence");
Manager::instance().sendPresence(accountID,status,note);
}
......@@ -130,9 +130,7 @@ class CallManager
/* Presence subscription */
void subscribePresence(const std::string& accountID, const std::string& buddySipUri);
void unsubscribePresence(const std::string& accountID, const std::string& buddySipUri);
/* Presence Publication for IP2IP */
void setPresenceOnline(const std::string& accountID);
void setPresenceOffline(const std::string& accountID);
void sendPresence(const std::string& accountID, const std::string& status, const std::string& note);
private:
#if HAVE_ZRTP
......
......@@ -2897,23 +2897,17 @@ void ManagerImpl::startAudioDriverStream()
void ManagerImpl::subscribePresence(const std::string& accountID, const std::string& buddySipUri)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
account->addBuddy(buddySipUri);
account->subscribeBuddy(buddySipUri);
}
void ManagerImpl::unsubscribePresence(const std::string& accountID, const std::string& buddySipUri)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
account->removeBuddy(buddySipUri);
account->unsubscribeBuddy(buddySipUri);
}
void ManagerImpl::setPresenceOnline(const std::string& accountID)
void ManagerImpl::sendPresence(const std::string& accountID, const std::string& status, const std::string& note)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
account->notifyServerSubscription("open","");
}
void ManagerImpl::setPresenceOffline(const std::string& accountID)
{
SIPAccount *account = Manager::instance().getSipAccount(accountID);
account->notifyServerSubscription ("close","");
account->sendPresence(status,note);
}
......@@ -1049,10 +1049,9 @@ class ManagerImpl {
/**
* push a presence for a account
* only used for IP2IP accounts
* Notify for IP2IP accounts and publish for PBX account
*/
void setPresenceOnline(const std::string& accountID);
void setPresenceOffline(const std::string& accountID);
void sendPresence(const std::string& accountID, const std::string& status, const std::string& note);
private:
NON_COPYABLE(ManagerImpl);
......
......@@ -19,8 +19,9 @@ libsiplink_la_SOURCES = \
sipbuddy.h \
sipvoip_pres.cpp \
sipvoip_pres.h \
presence_subscription.h
presence_subscription.h\
sippublish.cpp\
sippublish.h
if BUILD_SDES
libsiplink_la_SOURCES+= sdes_negotiator.cpp \
sdes_negotiator.h \
......
......@@ -13,6 +13,9 @@
#include <pjsip-simple/evsub.h>
#include"pjsip-simple/presence.h"
#include "manager.h"
#include "sipvoip_pres.h"
class PresenceSubscription {
public:
......@@ -24,63 +27,83 @@ public:
, expires (-1) {};
char *remote; /**< Remote URI. */
std::string accId; /**< Account ID. */
std::string accId; /**< Account ID. */
void setExpires(int ms) {
expires = ms;
}
/*bool operator==(const PresenceSubscription & s) const {
return (!(strcmp(remote,s.remote)));
}*/
bool match(PresenceSubscription * s){
int getExpires(){
return expires;
}
bool matches(PresenceSubscription * s){
// servers match if they have the same remote uri and the account ID.
return ((!(strcmp(remote,s->remote))) && (accId==s->accId));
}
bool isActive(){
if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE )
return true;
return false;
}
inline void notify(const std::string &newPresenceState, const std::string &newChannelState) {
DEBUG("################################################notifying %s", remote);
/**
* Send the tirst notification.
* FIXME : pjsip_pres_notify crash because the header can't be cloned
* So far, the first notify is sent in sipvoip_pres.c instead.
*/
void init(){
pjsip_tx_data *tdata = NULL;
pres_msg_data msg_data;
pj_str_t reason = pj_str("OK");
pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
pjsip_pres_set_status(sub, pres_get_data());
if (expires == 0)
ev_state = PJSIP_EVSUB_STATE_TERMINATED;
/* Create and send the the first NOTIFY to active subscription: */
pj_str_t stateStr = pj_str("");
pj_status_t status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata);
if (status == PJ_SUCCESS) {
pres_process_msg_data(tdata, &msg_data);
status = pjsip_pres_send_request(sub, tdata);
}
if (status != PJ_SUCCESS) {
WARN("Unable to create/send NOTIFY %d", status);
pjsip_pres_terminate(sub, PJ_FALSE);
}
}
/* Only send NOTIFY once subscription is active. Some subscriptions
void notify() {
/* Only send NOTIFY once subscription is active. Some subscriptions
* may still be in NULL (when app is adding a new buddy while in the
* on_incoming_subscribe() callback) or PENDING (when user approval is
* being requested) state and we don't send NOTIFY to these subs until
* the user accepted the request.
*/
if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE
/* && (pres_status.info[0].basic_open != getStatus()) */) {
DEBUG("Active");
if (isActive()) {
WARN("Notifying %s.", remote);
pjsip_tx_data *tdata;
pjsip_pres_status pres_status;
pjsip_pres_get_status(sub, &pres_status);
pres_status.info[0].basic_open = newPresenceState == "open"? true: false;
pjsip_pres_set_status(sub, &pres_status);
pjsip_pres_set_status(sub, pres_get_data());
if (pjsip_pres_current_notify(sub, &tdata) == PJ_SUCCESS) {
if (tdata->msg->type == PJSIP_REQUEST_MSG) {
const pj_str_t STR_USER_AGENT = {"User-Agent", 10};
pjsip_hdr *h;
pj_str_t ua = pj_str("SFLphone");
h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool,
&STR_USER_AGENT, &ua);
pjsip_msg_add_hdr(tdata->msg, h);
}
// add msg header and send
pres_process_msg_data(tdata, NULL);
pjsip_pres_send_request(sub, tdata);
}
}
else{
DEBUG("Inactive");
else{
WARN("Unable to create/send NOTIFY");
pjsip_pres_terminate(sub, PJ_FALSE);
}
}
}
friend void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event);
friend pj_bool_t my_pres_on_rx_request(pjsip_rx_data *rdata);
friend pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata);
private:
NON_COPYABLE(PresenceSubscription);
......
......@@ -111,13 +111,21 @@ SIPAccount::SIPAccount(const std::string& accountID)
, registrationStateDetailed_()
, keepAliveEnabled_(false)
, keepAliveTimer_()
, keepAliveTimerActive_(false)
, link_(SIPVoIPLink::instance())
, serverSubscriptions_ ()
, buddies_ ()
, receivedParameter_("")
, rPort_(-1)
, via_addr_()
, online_status()
, rpid({PJRPID_ELEMENT_TYPE_PERSON,
pj_str("20"),
PJRPID_ACTIVITY_BUSY,
pj_str("bla")})
, publish_sess()
, publish_state()
, publish_enabled(true)
{
via_addr_.host.ptr = 0;
via_addr_.host.slen = 0;
......@@ -662,6 +670,7 @@ void SIPAccount::registerVoIPLink()
} catch (const VoipLinkException &e) {
ERROR("%s", e.what());
}
}
void SIPAccount::unregisterVoIPLink()
......@@ -1210,42 +1219,58 @@ VoIPLink* SIPAccount::getVoIPLink()
}
void SIPAccount::sendPresence(const std::string &status, const std::string &note){
pres_update(status,note);
if (isIP2IP())
notifyServerSubscription();
else
pres_publish(this);
}
/*
* Buddy list management
*
*/
void SIPAccount::addBuddy(const std::string& buddySipUri){
void SIPAccount::subscribeBuddy(const std::string& buddySipUri){
std::list< SIPBuddy *>::iterator buddyIt;
for (buddyIt = buddies_.begin(); buddyIt != buddies_.end(); buddyIt++)
if((*buddyIt)->getURI()==buddySipUri){
DEBUG("Buddy:%s exist in the list, Resubscribe.",buddySipUri.c_str());
(*buddyIt)->subscribe(); // The buddy won't add the subscription if it allready exists.
return;
DEBUG("-Buddy:%s exist in the list. Replace it.",buddySipUri.c_str());
delete *buddyIt;
removeBuddy(*buddyIt);
break;
}
DEBUG("New buddy subscription added.");
SIPBuddy *b = new SIPBuddy(buddySipUri, this);
b->subscribe();
buddies_.push_back(b);
addBuddy(b);
}
void SIPAccount::removeBuddy(const std::string& buddySipUri){
void SIPAccount::unsubscribeBuddy(const std::string& buddySipUri){
std::list< SIPBuddy *>::iterator buddyIt;
for (buddyIt = buddies_.begin(); buddyIt != buddies_.end(); buddyIt++)
if((*buddyIt)->getURI()==buddySipUri){
DEBUG("Found buddy:%s in list. Unsubscribe.",buddySipUri.c_str());
(*buddyIt)->unsubscribe();
DEBUG("-Found buddy:%s in the buddy list.",buddySipUri.c_str());
delete *buddyIt;
removeBuddy(*buddyIt);
return;
}
}
void SIPAccount::addBuddy(SIPBuddy *b){
DEBUG("-New buddy subscription added in the buddy list.");
buddies_.push_back(b);
}
void SIPAccount::removeBuddy(SIPBuddy *b){
DEBUG("-Buddy subscription removed from the buddy list.");
buddies_.remove(b);
}
bool SIPAccount::isIP2IP() const
{
bool SIPAccount::isIP2IP() const{
return accountID_ == IP2IP_PROFILE;
}
/*
* Presence Management for IP2IP accounts
*
......@@ -1256,29 +1281,22 @@ bool SIPAccount::isIP2IP() const
/* Presence : Method used to add serverSubscription to PresenceSubscription list in case of IP2IP accounts */
void SIPAccount::addServerSubscription(PresenceSubscription *s) {
std::list< PresenceSubscription *>::iterator serverIt;
for (serverIt = serverSubscriptions_.begin(); serverIt != serverSubscriptions_.end(); serverIt++)
if((*serverIt)->match(s)){
DEBUG("Server already subscribed. Replace it with a new fresh uas.");
serverSubscriptions_.remove(*serverIt);
}
DEBUG("Server subscription added.");
DEBUG("-PresenceServer subscription added.");
serverSubscriptions_.push_back(s);
}
/* Presence : Method used to remove serverSubscription to PresenceSubscription list in: case of IP2IP accounts */
void SIPAccount::removeServerSubscription(PresenceSubscription *s) {
serverSubscriptions_.remove(s);
delete s;
DEBUG("server subscription removed");
DEBUG("-PresenceServer removed");
}
/* Presence : Method used to notify each serverSubscription of a new presencein case of IP2IP accounts */
void SIPAccount::notifyServerSubscription(const std::string &newPresenceStatus, const std::string &newChannelStatus) {
void SIPAccount::notifyServerSubscription() {
std::list< PresenceSubscription *>::iterator serverIt;
DEBUG("iterating through servers");
DEBUG("-Iterating through PresenceServers:");
for (serverIt = serverSubscriptions_.begin(); serverIt != serverSubscriptions_.end(); serverIt++)
(*serverIt)->notify(newPresenceStatus, newChannelStatus);
(*serverIt)->notify();
}
......
......@@ -45,6 +45,8 @@
#include "sipbuddy.h"
#include "presence_subscription.h"
#include "sippublish.h"
typedef std::vector<pj_ssl_cipher> CipherArray;
namespace Conf {
......@@ -517,13 +519,27 @@ class SIPAccount : public Account {
/* Returns true if the username and/or hostname match this account */
bool matches(const std::string &username, const std::string &hostname, pjsip_endpoint *endpt, pj_pool_t *pool) const;
//int getBuddy(const std::string& buddySipUri, SIPBuddy *b);
void addBuddy(const std::string& buddySipUri);
void removeBuddy(const std::string& buddySipUri);
/**
* Presence management
*/
void sendPresence(const std::string &status, const std::string &note);
void subscribeBuddy(const std::string& buddySipUri);
void unsubscribeBuddy(const std::string& buddySipUri);
void addBuddy(SIPBuddy *b);
void removeBuddy(SIPBuddy *b);
void addServerSubscription(PresenceSubscription *s);
void removeServerSubscription(PresenceSubscription *s);
void notifyServerSubscription(const std::string &newPresenceStatus, const std::string &newChannelStatus);
bool compareServerSubscription(PresenceSubscription *first, PresenceSubscription *second);
void notifyServerSubscription();
//void notifyServerSubscription(const std::string &newPresenceStatus, const std::string &newChannelStatus);
//bool compareServerSubscription(PresenceSubscription *first, PresenceSubscription *second);
pj_bool_t online_status; /**< Our online status. */
pjrpid_element rpid; /**< RPID element information.*/
pjsip_publishc *publish_sess; /**< Client publication session.*/
pj_bool_t publish_state; /**< Last published online status.*/
pj_bool_t publish_enabled; /**< Allow for status publish,*/
private:
NON_COPYABLE(SIPAccount);
......
......@@ -80,7 +80,6 @@ static void sflphoned_evsub_on_state(pjsip_evsub *sub, pjsip_event *event) {
buddy->incLock();
DEBUG("Presence subscription to '%s' is '%s'", buddy->getURI().c_str(),
pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null");
// pj_log_push_indent();
if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
int resub_delay = -1;
......@@ -148,9 +147,7 @@ static void sflphoned_evsub_on_state(pjsip_evsub *sub, pjsip_event *event) {
* into pending state.
*/
const pjsip_sub_state_hdr *sub_hdr;
pj_str_t sub_state = {
"Subscription-State",
18 };
pj_str_t sub_state = {"Subscription-State", 18 };
const pjsip_msg *msg;
msg = event->body.tsx_state.src.rdata->msg_info.msg;
......@@ -251,25 +248,11 @@ static void sflphoned_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata,
* lock, which we are currently holding!
*/
buddy = (SIPBuddy *) pjsip_evsub_get_mod_data(sub, modId);
if (!buddy) {
if (!buddy)
return;
}
buddy->incLock();
/* Update our info. */
pjsip_pres_get_status(sub, &buddy->status);
const std::string basic(buddy->status.info[0].basic_open ? "open" : "closed");
//ebail : TODO Call here the callback for presence changement
const std::string note(buddy->status.info[0].rpid.note.ptr ? buddy->status.info[0].rpid.note.ptr : "");
ERROR("\n-----------------\n"
"presenceStateChange for %s status=%s note=%s \n-----------------\n",
buddy->getURI().c_str(),
basic.c_str(),
note.c_str());
//ebail: edmit signal
Manager::instance().getDbusManager()->getCallManager()->newPresenceNotification(buddy->getURI(), basic, note);
pjsip_pres_get_status(sub, &buddy->status);
buddy->updatePresence();
/* The default is to send 200 response to NOTIFY.
* Just leave it there..
......@@ -286,16 +269,13 @@ static void sflphoned_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata,
SIPBuddy::SIPBuddy(const std::string& uri_, SIPAccount *acc_) :
acc(acc_),
uri(pj_str(strdup(uri_.c_str()))),
//buddy_id(-1)
contact(pj_str(strdup(acc->getFromUri().c_str()))),
display(),
dlg(NULL),
// host ()
monitor(false),
name(),
cp_(),
pool(0),
// port(0)
status(),
sub(NULL),
term_code(0),
......@@ -312,9 +292,8 @@ SIPBuddy::~SIPBuddy() {
usleep(200);
}
DEBUG("Destroying buddy object with uri %s", uri.ptr);
monitor = false;
rescheduleTimer(PJ_FALSE, 0);
updatePresence();
unsubscribe();
pj_pool_release(pool);
}
......@@ -343,7 +322,7 @@ void SIPBuddy::rescheduleTimer(bool reschedule, unsigned msec) {
if (reschedule) {
pj_time_val delay;
DEBUG("Resubscribing buddy %.*s in %u ms (reason: %.*s)",
WARN("Resubscribing buddy %.*s in %u ms (reason: %.*s)",
uri.slen, uri.ptr, msec, (int) term_reason.slen, term_reason.ptr);
monitor = PJ_TRUE;
pj_timer_entry_init(&timer, 0, this, &buddy_timer_cb);
......@@ -361,36 +340,49 @@ void SIPBuddy::rescheduleTimer(bool reschedule, unsigned msec) {
pj_status_t SIPBuddy::updatePresence() {
incLock();
/* Update our info. See pjsua_buddy_get_info() for additionnal idea*/
const std::string basic(status.info[0].basic_open ? "open" : "closed");
const std::string note(status.info[0].rpid.note.ptr,status.info[0].rpid.note.slen);
DEBUG(" Received presenceStateChange for %s status=%s note=%s",getURI().c_str(),basic.c_str(),note.c_str());
/* Transmit dbus signal */
Manager::instance().getDbusManager()->getCallManager()->newPresenceNotification(getURI(), basic, note);
decLock();
}
pj_status_t SIPBuddy::updateSubscription() {
if (!monitor) {
/* unsubscribe */
pjsip_tx_data *tdata;
pj_status_t retStatus;
if (sub == NULL) {
DEBUG("Buddy already unsubscribed sub=NULL.");
WARN("Buddy already unsubscribed sub=NULL.");
return PJ_SUCCESS;
}
if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
DEBUG("Buddy already unsubscribed sub=TERMINATED.");
pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL;
WARN("Buddy already unsubscribed sub=TERMINATED.");
//pjsip_evsub_terminate(sub, PJ_FALSE); //
sub = NULL;
return PJ_SUCCESS;
}
DEBUG("Buddy %s: unsubscribing..", uri.ptr);
retStatus = pjsip_pres_initiate(sub, 300, &tdata);
WARN("Buddy %s: unsubscribing..", uri.ptr);
retStatus = pjsip_pres_initiate(sub, 0, &tdata);
if (retStatus == PJ_SUCCESS) {
// pjsua_process_msg_data(tdata, NULL);
if (/*pjsua_var.ua_cfg.user_agent.slen &&*/
tdata->msg->type == PJSIP_REQUEST_MSG) {
const pj_str_t STR_USER_AGENT = {
"User-Agent",
10 };
pres_process_msg_data(tdata, NULL);
/*if (tdata->msg->type == PJSIP_REQUEST_MSG) {
const pj_str_t STR_USER_AGENT = {"User-Agent", 10};
pj_str_t ua = pj_str(strdup(acc->getUserAgentName().c_str()));
pjsip_hdr *h;
h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &ua);
pjsip_msg_add_hdr(tdata->msg, h);
}
}*/
retStatus = pjsip_pres_send_request(sub, tdata);
}
......@@ -399,16 +391,19 @@ pj_status_t SIPBuddy::updatePresence() {
pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL;
WARN("Unable to unsubscribe presence", status);
}
// pjsip_evsub_set_mod_data(sub, modId, NULL);
pjsip_evsub_set_mod_data(sub, modId, NULL); // Not interested with further events
return PJ_SUCCESS;
}
#if 0
if (sub && sub->dlg) { //do not bother if already subscribed
//#if 0
if (sub && dlg) { //do not bother if already subscribed
// return PJ_SUCCESS;
pjsip_evsub_terminate(sub, PJ_FALSE);
DEBUG("Terminate existing sub.");
}
#endif
//#endif
//subscribe
pjsip_evsub_user pres_callback;
......@@ -450,18 +445,13 @@ pj_status_t SIPBuddy::updatePresence() {
pj_str_t from = pj_str(strdup(acc->getFromUri().c_str()));
status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from, &contact, &uri, NULL, &dlg);
if (status != PJ_SUCCESS) {
//pjsua_perror(THIS_FILE, "Unable to create dialog",
// status);
ERROR("Unable to create dialog \n");
//if (tmp_pool) pj_pool_release(tmp_pool);
//pj_log_pop_indent();
return PJ_FALSE;
}
//ELOI add credential for auth - otherwise subscription was failing
// Add credential for auth.
if (acc->hasCredentials() and pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) {
ERROR("Could not initialize credentials for invite session authentication");
ERROR("Could not initialize credentials for subscribe session authentication");
}
// E.B add credential for auth
/* Increment the dialog's lock otherwise when presence session creation