Commit c04fcf0b authored by Simon Morlat's avatar Simon Morlat

Rework the way GRUU support is implemented.

* define two functions in RegistrarDb to convert a sip.instance to gr parameter and vice versa, used everywhere needed
* set the pub-gruu into the ExtendedContact, instead of synthetize when generating the 200 Ok response
* Fix an issue where the null character was accidentally inserted at the end of a c++ string, causing an ostringstream to stop (when printing ExtendedContact's paths).
* Eliminate useless code.

The initial goal of this rework is to allow a SIP client to REGISTER with a GRUU address as contact.
This wasn't possible because Flexisip was confusing the gr parameter it was computing and the gr parameter set by the client in the Contact header.
parent 4c858d94
Pipeline #4204 passed with stages
in 24 minutes and 43 seconds
......@@ -48,10 +48,10 @@ struct ExtendedContactCommon {
std::list<std::string> mPath;
ExtendedContactCommon(const char *contactId, const std::list<std::string> &path, const std::string &callId,
const char *lineValue) {
if (!callId.empty()) mCallId = callId;
const std::string &uniqueId) {
mCallId = callId;
mPath = path;
if (lineValue) mUniqueId = lineValue;
mUniqueId = uniqueId;
mContactId = contactId;
}
ExtendedContactCommon(const std::string &route) : mContactId(), mCallId(), mUniqueId(), mPath({route}) {
......@@ -255,8 +255,8 @@ class Record {
}
/*
* Synthetise the pub-gruu address from an extended contact belonging to this Record.
* FIXME: Unfortunately this function is not widely used in Flexisip, instead there are several
* places where pub-gruu address is synthesized.
* FIXME: of course this method should be directly attached to ExtendedContact.
* Unfortunately, because pub-gruu were not contained in the ExtendedContact, it shall remain in Record for compatibility.
*/
url_t *getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home);
/**
......@@ -373,7 +373,6 @@ class RegistrarDb {
void clear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener);
void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive = false);
void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool includingDomains, bool recursive);
void fetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener);
void fetchList(const std::vector<url_t *> urls, const std::shared_ptr<ListContactUpdateListener> &listener);
void notifyContactListener (const std::shared_ptr<Record> &r, const std::string &uid);
void updateRemoteExpireTime(const std::string &key, time_t expireat);
......@@ -401,6 +400,8 @@ class RegistrarDb {
void unsubscribeLocalRegExpire(LocalRegExpireListener *listener) {
mLocalRegExpire->unsubscribe(listener);
}
static std::string uniqueIdToGr(const std::string &uid);
static std::string grToUniqueId(const std::string &gr);
protected:
class LocalRegExpire {
std::map<std::string, time_t> mRegMap;
......@@ -429,7 +430,7 @@ class RegistrarDb {
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doMigration() = 0;
int count_sip_contacts(const sip_contact_t *contact);
......@@ -438,7 +439,7 @@ class RegistrarDb {
void fetchWithDomain(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive);
void notifyContactListener(const std::string &key, const std::string &uid);
void notifyStateListener () const;
RegistrarDb(Agent *ag);
virtual ~RegistrarDb();
std::multimap<std::string, std::shared_ptr<ContactRegisteredListener>> mContactListenersMap;
......
Subproject commit f46b9b1ea5f9a829639a3c563194fef17711762a
Subproject commit 2cc5ec84eead76112836aaae74f98e05dde9dc05
......@@ -37,13 +37,10 @@ ConferenceAddressGenerator::ConferenceAddressGenerator (
void ConferenceAddressGenerator::run () {
char token[17];
ostringstream os;
belle_sip_random_token(token, sizeof(token));
os.str("");
os << "chatroom-" << token;
mConferenceAddr->setUsername(os.str());
os.str("");
os << "\"<urn:uuid:" << mUuid << ">\"";
mConferenceAddr->setParam("+sip.instance", os.str());
url_t *url = url_make(mHome.home(), mConferenceAddr->asStringUriOnly().c_str());
RegistrarDb::get()->fetch(url, shared_from_this(), false, false);
......@@ -64,13 +61,20 @@ void ConferenceAddressGenerator::onRecordFound(const std::shared_ptr<Record> &r)
);
}
} else {
if (r->getExtendedContacts().empty()) {
LOGF("Conference address bind failed.");
return;
}
const shared_ptr<ExtendedContact> ec = r->getExtendedContacts().front();
string uri = ExtendedContact::urlToString(ec->mSipContact->m_url);
shared_ptr<linphone::Address> addr = linphone::Factory::get()->createAddress(uri);
url_t *pub_gruu = r->getPubGruu(ec, mHome.home());
if (!pub_gruu) {
LOGF("Conference does not have gruu address.");
return;
}
shared_ptr<linphone::Address> gruuAddr = linphone::Factory::get()->createAddress(
mConferenceAddr->asStringUriOnly()
);
gruuAddr->setUriParam("gr", addr->getUriParam("gr"));
url_as_string(mHome.home(), pub_gruu));
mChatRoom->setConferenceAddress(gruuAddr);
}
}
......
......@@ -164,6 +164,10 @@ void flexisip::ConferenceServer::bindAddresses () {
// Binding loaded chat room
for (const auto &chatRoom : mCore->getChatRooms()) {
if (chatRoom->getPeerAddress()->getUriParam("gr").empty()){
LOGE("Skipping chatroom %s with no gruu parameter.", chatRoom->getPeerAddress()->asString().c_str());
continue;
}
bindChatRoom(chatRoom->getPeerAddress()->asStringUriOnly(), mTransport, chatRoom->getPeerAddress()->getUriParam("gr"), nullptr);
}
......@@ -213,9 +217,8 @@ void ConferenceServer::bindChatRoom (
sip_contact_t* sipContact = sip_contact_create(mHome.home(),
reinterpret_cast<const url_string_t*>(url_make(mHome.home(), contact.c_str())),
su_strdup(mHome.home(), ("+sip.instance=\"<" + gruu + ">\"").c_str()), nullptr);
su_strdup(mHome.home(), ("+sip.instance=" + RegistrarDb::grToUniqueId(gruu) ).c_str()), nullptr);
url_t *from = url_make(mHome.home(), bindingUrl.c_str());
url_param_add(mHome.home(), from, ("gr=" + gruu).c_str());
parameter.callId = gruu;
parameter.path = mPath;
......
......@@ -88,9 +88,6 @@ void OwnRegistrationSubscription::stop(){
unsigned int OwnRegistrationSubscription::getContactCapabilities(const std::shared_ptr<ExtendedContact> &ec){
unsigned int mask = 0;
if (!url_has_param(ec->mSipContact->m_url, "gr")){
return 0; //eliminate contacts without gruu, there is nothing we can do with them
}
string specs = ec->getOrgLinphoneSpecs();
//Please excuse the following code that is a bit too basic in terms of parsing:
if (specs.find("groupchat") != string::npos) mask |= (unsigned int)ChatRoomCapabilities::Conference;
......
......@@ -463,20 +463,6 @@ void ModuleRegistrar::reply(shared_ptr<RequestSipEvent> &ev, int code, const cha
for (sip_contact_t *contact = modified_contacts; contact!=nullptr ; contact=contact->m_next) {
if(sip->sip_request->rq_method == sip_method_register && code == 200 && contact) {
if (url_has_param(contact->m_url, "gr")) {
string gruu;
char *buffer = new char[255];
isize_t result = url_param(contact->m_url->url_params, "gr", buffer, 255);
if (result > 0) {
su_home_t *home = ev->getHome();
stringstream stream;
gruu = string(buffer);
contact->m_url->url_params = url_strip_param_string((char *)contact->m_url->url_params,"gr");
stream << "\"" << url_as_string(home, sip->sip_from->a_url) << ";gr=" << gruu << "\"";
msg_header_replace_param(home, (msg_common_t *) contact, su_sprintf(home, "pub-gruu=%s", stream.str().c_str()));
}
delete[] buffer;
}
if (url_has_param(contact->m_url, "fs-conn-id")) {
contact->m_url->url_params = url_strip_param_string((char *)contact->m_url->url_params,"fs-conn-id");
}
......
......@@ -77,7 +77,7 @@ void RegistrarDbInternal::doFetch(const url_t *url, const shared_ptr<ContactUpda
listener->onRecordFound(r);
}
void RegistrarDbInternal::doFetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) {
void RegistrarDbInternal::doFetchInstance(const url_t *url, const string &uniqueId, const shared_ptr<ContactUpdateListener> &listener) {
string key(Record::defineKeyFromUrl(url));
SofiaAutoHome home;
......@@ -101,22 +101,11 @@ void RegistrarDbInternal::doFetchForGruu(const url_t *url, const string &gruu, c
const list<shared_ptr<ExtendedContact>> &contacts = r->getExtendedContacts();
shared_ptr<Record> retRecord = make_shared<Record>(url);
for (const auto &contact : contacts) {
if (!url_has_param(contact->mSipContact->m_url, "gr"))
continue;
char buffer[255] = {0};
isize_t result = url_param(contact->mSipContact->m_url->url_params, "gr", buffer, sizeof(buffer) - 1);
if (result <= 0)
continue;
stringstream streamGruu;
streamGruu << "\"<" << buffer << ">\"";
if (streamGruu.str() != gruu)
continue;
retRecord->pushContact(contact);
if (contact->mUniqueId == uniqueId){
retRecord->pushContact(contact);
break;
}
}
listener->onRecordFound(retRecord);
}
......
......@@ -30,12 +30,12 @@ class RegistrarDbInternal : public RegistrarDb {
void clearAll();
private:
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doMigration();
virtual void publish(const std::string &topic, const std::string &uid);
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doMigration()override;
virtual void publish(const std::string &topic, const std::string &uid)override;
std::map<std::string, std::shared_ptr<Record>> mRecords;
};
......
......@@ -42,7 +42,7 @@ using namespace std;
using namespace flexisip;
RegistrarUserData::RegistrarUserData(RegistrarDbRedisAsync *s, const url_t *url, shared_ptr<ContactUpdateListener> listener)
: self(s), listener(listener), token(0), mRetryTimer(nullptr), mRetryCount(0), mGruu(""), mUpdateExpire(false), mIsUnregister(false) {
: self(s), listener(listener), token(0), mRetryTimer(nullptr), mRetryCount(0), mUniqueId(""), mUpdateExpire(false), mIsUnregister(false) {
mRecord = make_shared<Record>(url);
}
RegistrarUserData::~RegistrarUserData() {
......@@ -819,7 +819,7 @@ void RegistrarDbRedisAsync::handleFetch(redisReply *reply, RegistrarUserData *da
}
} else {
// This is only when we want a contact matching a given gruu
const char *gruu = data->mGruu.c_str();
const char *gruu = data->mUniqueId.c_str();
if (reply->len > 0) {
LOGD("GOT fs:%s [%lu] for gruu %s --> %s", key, data->token, gruu, reply->str);
data->mRecord->updateFromUrlEncodedParams(key, gruu, reply->str, data->listener);
......@@ -851,10 +851,10 @@ void RegistrarDbRedisAsync::doFetch(const url_t *url, const shared_ptr<ContactUp
data, "HGETALL fs:%s", key), data);
}
void RegistrarDbRedisAsync::doFetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) {
void RegistrarDbRedisAsync::doFetchInstance(const url_t *url, const string &uniqueId, const shared_ptr<ContactUpdateListener> &listener) {
// fetch only the contact in the AOR (HGET) and call the onRecordFound of the listener
RegistrarUserData *data = new RegistrarUserData(this, url, listener);
data->mGruu = gruu;
data->mUniqueId = uniqueId;
if (!isConnected() && !connect()) {
LOGE("Not connected to redis server");
......@@ -864,8 +864,8 @@ void RegistrarDbRedisAsync::doFetchForGruu(const url_t *url, const string &gruu,
}
const char *key = data->mRecord->getKey().c_str();
const char *field = gruu.c_str();
LOGD("Fetching fs:%s [%lu] contact matching gruu %s", key, data->token, field);
const char *field = uniqueId.c_str();
LOGD("Fetching fs:%s [%lu] contact matching unique id %s", key, data->token, field);
check_redis_command(redisAsyncCommand(mContext, (void (*)(redisAsyncContext*, void*, void*))sHandleFetch,
data, "HGET fs:%s %s", key, field), data);
}
......
......@@ -88,7 +88,7 @@ struct RegistrarUserData {
unsigned long token;
su_timer_t *mRetryTimer;
int mRetryCount;
std::string mGruu;
std::string mUniqueId;
bool mUpdateExpire;
bool mIsUnregister;
......@@ -105,14 +105,14 @@ class RegistrarDbRedisAsync : public RegistrarDb {
bool disconnect();
protected:
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener);
virtual void doMigration();
virtual void subscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener);
virtual void unsubscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener);
virtual void publish(const std::string &topic, const std::string &uid);
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener) override;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doMigration()override;
virtual void subscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener)override;
virtual void unsubscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener)override;
virtual void publish(const std::string &topic, const std::string &uid)override;
private:
RegistrarDbRedisAsync(Agent *agent, RedisParameters params);
......
......@@ -35,6 +35,7 @@
#include <sofia-sip/sip_protos.h>
#include "recordserializer.hh"
#include <flexisip/module.hh>
#include "utils/string-utils.hh"
using namespace std;
using namespace flexisip;
......@@ -314,17 +315,20 @@ void ExtendedContact::extractInfoFromHeader(const char *urlHeaders) {
string valueStr;
string keyStr = reinterpret_cast<msg_common_t*>(headers)->h_class->hc_name;
valueStr.resize(reinterpret_cast<msg_common_t*>(headers)->h_len);
msg_header_field_e(&valueStr[0], reinterpret_cast<msg_common_t*>(headers)->h_len, headers, 0);
valueStr.resize(reinterpret_cast<msg_common_t*>(headers)->h_len + 1);
size_t written = msg_header_field_e(&valueStr[0], reinterpret_cast<msg_common_t*>(headers)->h_len, headers, 0);
valueStr.resize(written);
transform(keyStr.begin(), keyStr.end(), keyStr.begin(), [](unsigned char c){ return std::tolower(c); });
if (keyStr == "path") {
size_t bracket = valueStr.find('<');
if (bracket != string::npos) valueStr.erase(bracket, static_cast<size_t>(1));
bracket = valueStr.find('>');
if (bracket != string::npos) valueStr.erase(bracket, static_cast<size_t>(1));
mPath.push_back(valueStr);
// We want to keep only the uri part of the paths.
sip_path_t *path = sip_path_format(home.home(), "%s", valueStr.c_str());
if (path){
mPath.push_back(url_as_string(home.home(), path->r_url));
}else{
LOGE("ExtendedContact::extractInfoFromHeader(): bad path [%s]", valueStr.c_str());
}
} else if (keyStr == "accept") {
mAcceptHeader.push_back(valueStr);
} else if (keyStr == "user-agent") {
......@@ -352,8 +356,8 @@ void Record::applyMaxAor() {
}
}
static void defineContactId(ostringstream &oss, const url_t *url, const char *transport) {
if (transport != nullptr)
static void defineContactId(ostringstream &oss, const url_t *url, const string &transport) {
if (!transport.empty())
oss << transport << ":";
if (url->url_user != nullptr)
oss << url->url_user << ":";
......@@ -482,6 +486,11 @@ void ExtendedContact::extractInfoFromUrl(const char* full_url) {
} else {
url = temp_contact->m_url;
}
if (url == nullptr) {
LOGE("ExtendedContact::extractInfoFromUrl() url is null.");
return;
}
// CallId
mCallId = extractStringParam(url, "callid");
......@@ -545,22 +554,18 @@ void Record::update(const sip_t *sip, int globalExpire, bool alias, int version,
userAgent = (sip->sip_user_agent) ? sip->sip_user_agent->g_string : "";
while (contacts) {
char buffer[20];
char buffer[20]={0};
list<string> paramName;
char *transportPtr;
ostringstream contactId;
const char *lineValuePtr = nullptr;
string lineValue = extractUniqueId(contacts);
if (!lineValue.empty()) lineValuePtr = lineValue.c_str();
transportPtr = buffer;
if (!url_param(contacts->m_url[0].url_params, "transport", buffer, sizeof(buffer) - 1)) {
transportPtr = nullptr;
string transport;
string uniqueId = extractUniqueId(contacts);
if (url_param(contacts->m_url[0].url_params, "transport", buffer, sizeof(buffer) - 1) > 0) {
transport = buffer;
}
defineContactId(contactId, contacts->m_url, transportPtr);
ExtendedContactCommon ecc(contactId.str().c_str(), stlPath, sip->sip_call_id->i_id, lineValuePtr);
defineContactId(contactId, contacts->m_url, transport);
ExtendedContactCommon ecc(contactId.str().c_str(), stlPath, sip->sip_call_id->i_id, uniqueId);
auto exc = make_shared<ExtendedContact>(ecc, contacts, globalExpire, (sip->sip_cseq) ? sip->sip_cseq->cs_seq : 0, getCurrentTime(), alias, acceptHeaders, userAgent);
exc->mUsedAsRoute = sip->sip_from->a_url->url_user == nullptr;
insertOrUpdateBinding(exc, listener);
......@@ -629,9 +634,27 @@ const url_t *Record::getAor()const{
url_t *Record::getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home){
char gr_value[256] = {0};
url_t *gruu_addr = NULL;
const char *pub_gruu_value = msg_header_find_param((msg_common_t*)ec->mSipContact, "pub-gruu");
if (!ec->mSipContact->m_url->url_params) return NULL;
if (pub_gruu_value){
if (pub_gruu_value[0] == '\0'){
/*
* To preserve compatibility with previous storage of pub-gruu (where only a gr parameter was set in URI),
* a client that didn't requested a gruu address has now a "pub-gruu" contact parameter which is empty.
* This means that this client has no pub-gruu assigned by this server.
*/
return nullptr;
}
gruu_addr = url_make(home, StringUtils::unquote(pub_gruu_value).c_str());
return gruu_addr;
}
/*
* Compatibility code, when pub-gruu wasn't stored in RegistrarDb.
* In such case, we have to synthetize the gruu address from the address of record and the gr uri parameter.
*/
if (!ec->mSipContact->m_url->url_params) return NULL;
isize_t result = url_param(ec->mSipContact->m_url->url_params, "gr", gr_value, sizeof(gr_value)-1);
if (result > 0) {
......@@ -1049,10 +1072,8 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener
}
if(url_has_param(url, "gr")) {
char buffer[255] = {0};
if (url_param(url->url_params, "gr", buffer, sizeof(buffer)) > 0) {
stringstream gruu;
gruu << "\"<" << buffer << ">\"";
doFetchForGruu(url, gruu.str(), recursive
if (url_param(url->url_params, "gr", buffer, sizeof(buffer)-1) > 0) {
doFetchInstance(url, grToUniqueId(buffer), recursive
? make_shared<RecursiveRegistrarDbListener>(this, listener, url)
: listener);
return;
......@@ -1063,10 +1084,6 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener
: listener);
}
void RegistrarDb::fetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) {
doFetchForGruu(url, gruu, listener);
}
void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListContactUpdateListener> &listener) {
class InternalContactUpdateListener : public ContactUpdateListener {
public:
......@@ -1105,22 +1122,28 @@ void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListCon
void RegistrarDb::bind(const sip_t *sip, const BindingParameters &parameter, const shared_ptr<ContactUpdateListener> &listener) {
SofiaAutoHome home;
bool gruu_assigned = false;
if (sip->sip_supported && sip->sip_contact->m_params) {
if (msg_params_find(sip->sip_supported->k_items, "gruu") != nullptr){
const char *instance_param = msg_params_find(sip->sip_contact->m_params, "+sip.instance");
if (instance_param) {
string instance(instance_param);
if (instance.find("\"<") != string::npos) {
ostringstream stream;
instance = instance.substr(instance.find("\"<") + strlen("\"<"));
instance = instance.substr(0, instance.find(">"));
stream << "gr=" << instance;
url_param_add(home.home(), sip->sip_contact->m_url, stream.str().c_str());
string gr = uniqueIdToGr(instance_param);
if (!gr.empty()){/* assign a public gruu address to this contact */
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
su_sprintf(home.home(), "pub-gruu=\"%s;gr=%s\"", url_as_string(home.home(), sip->sip_from->a_url), gr.c_str() ) );
gruu_assigned = true;
}
}
}
}
if (!gruu_assigned){
/* Set an empty pub-gruu meaning that this client hasn't requested any pub-gruu from this server.
* This is to preserve compatibility with previous RegistrarDb storage, where only gr parameter was stored.
* This couldn't work because a client can use a "gr" parameter in its contact uri.*/
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
su_sprintf(home.home(), "pub-gruu"));
}
int countSipContacts = count_sip_contacts(sip->sip_contact);
if (countSipContacts > Record::getMaxContacts()) {
......@@ -1152,6 +1175,27 @@ void RegistrarDb::bind(const url_t *from, const sip_contact_t *contact, const Bi
msg_unref(msg);
}
/* Transforms the unique id to a "gr" parameter value. */
string RegistrarDb::uniqueIdToGr(const string &uid){
string ret;
size_t begin = uid.find('<');
if (begin != string::npos){
size_t end = uid.find('>', begin + 1);
if (end != string::npos){
begin++; //skip '<'
ret = uid.substr(begin, end - begin);
}
}
return ret;
}
string RegistrarDb::grToUniqueId(const string &gr){
ostringstream uid;
uid << "\"<" << gr << ">\"";
return uid.str();
}
class AgregatorRegistrarDbListener : public ContactUpdateListener {
private:
shared_ptr<ContactUpdateListener> mOriginalListener;
......
......@@ -26,6 +26,9 @@ class StringUtils {
public:
static std::vector<std::string> split (const std::string &str, const std::string &delimiter);
static std::string unquote(const std::string & str){
return strip(str, '"');
}
static std::string strip(const char *str, char c);
static std::string strip(const std::string &str, char c);
static void strip(std::string::const_iterator &start, std::string::const_iterator &end, char c);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment