From 9cc58d1352aca425f538db87072fcf4fdd1f4c46 Mon Sep 17 00:00:00 2001
From: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
Date: Tue, 25 Aug 2015 16:27:36 -0400
Subject: [PATCH] sip: fix display name parsing and saving
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch parses optional display name that can be seen in From
and Contact SIP headers, for incoming calls.
Fallback on Contact header is made if From header is empty.

This also send the local display name in From header for outgoing
calls.

Issue: #77375
Change-Id: Iaef5e0e728a74427f3ced7efd947d09be91c0ac3
---
 src/ringdht/ringaccount.cpp |  5 ++-
 src/sip/sip_utils.cpp       | 62 ++++++++++++-------------------------
 src/sip/sip_utils.h         |  4 ++-
 src/sip/sipaccount.cpp      |  5 ++-
 src/sip/sipvoiplink.cpp     | 18 ++++++++---
 5 files changed, 45 insertions(+), 49 deletions(-)

diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp
index f295d6dd9b..cc7a093092 100644
--- a/src/ringdht/ringaccount.cpp
+++ b/src/ringdht/ringaccount.cpp
@@ -1133,7 +1133,10 @@ RingAccount::matches(const std::string &userName, const std::string &server) con
 
 std::string RingAccount::getFromUri() const
 {
-    return "<sip:" + dht_.getId().toString() + "@ring.dht>";
+    const std::string uri = "<sip:" + dht_.getId().toString() + "@ring.dht>";
+    if (not displayName_.empty())
+        return "\"" + displayName_ + "\" " + uri;
+    return uri;
 }
 
 std::string RingAccount::getToUri(const std::string& to) const
diff --git a/src/sip/sip_utils.cpp b/src/sip/sip_utils.cpp
index 2ff159d575..c37674050f 100644
--- a/src/sip/sip_utils.cpp
+++ b/src/sip/sip_utils.cpp
@@ -101,58 +101,36 @@ createRouteSet(const std::string &route, pj_pool_t *hdr_pool)
     return route_set;
 }
 
-// FIXME: replace with regex
 std::string
-parseDisplayName(const char * buffer)
+parseDisplayName(const pjsip_name_addr* sip_name_addr)
 {
-    // Start in From: in short and long form
-    const char* from_header = strstr(buffer, "\nFrom: ");
-    if (!from_header)
-        from_header = strstr(buffer, "\nf: ");
-    if (!from_header)
-        return "";
+    if (not sip_name_addr->display.ptr or not sip_name_addr->display.slen)
+        return {};
 
-    std::string temp(from_header);
-
-    // Cut at end of line
-    temp = temp.substr(0, temp.find("\n", 1));
-
-    size_t begin_displayName = temp.find("\"");
-    size_t end_displayName;
-    if (begin_displayName != std::string::npos) {
-      // parse between quotes
-      end_displayName = temp.find("\"", begin_displayName + 1);
-      if (end_displayName == std::string::npos)
-          return "";
-    } else {
-      // parse without quotes
-      end_displayName = temp.find("<");
-      if (end_displayName != std::string::npos) {
-          begin_displayName = temp.find_first_not_of(" ", temp.find(":"));
-          if (begin_displayName == std::string::npos)
-              return "";
-
-          // omit trailing/leading spaces
-          begin_displayName++;
-          end_displayName--;
-          if (end_displayName == begin_displayName)
-              return "";
-      } else {
-          return "";
-      }
-    }
-
-    std::string displayName = temp.substr(begin_displayName + 1,
-                                          end_displayName - begin_displayName - 1);
+    std::string displayName {sip_name_addr->display.ptr,
+            static_cast<size_t>(sip_name_addr->display.slen)};
 
     // Filter out invalid UTF-8 characters to avoid getting kicked from D-Bus
-    if (not utf8_validate(displayName)) {
+    if (not utf8_validate(displayName))
         return utf8_make_valid(displayName);
-    }
 
     return displayName;
 }
 
+std::string
+parseDisplayName(const pjsip_from_hdr* header)
+{
+    // PJSIP return a pjsip_name_addr for To, From and Contact headers
+    return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
+}
+
+std::string
+parseDisplayName(const pjsip_contact_hdr* header)
+{
+    // PJSIP return a pjsip_name_addr for To, From and Contact headers
+    return parseDisplayName(reinterpret_cast<pjsip_name_addr*>(header->uri));
+}
+
 void
 stripSipUriPrefix(std::string& sipUri)
 {
diff --git a/src/sip/sip_utils.h b/src/sip/sip_utils.h
index aa5df501f9..51030aea78 100644
--- a/src/sip/sip_utils.h
+++ b/src/sip/sip_utils.h
@@ -73,7 +73,9 @@ createRouteSet(const std::string &route, pj_pool_t *hdr_pool);
 
 void stripSipUriPrefix(std::string& sipUri);
 
-std::string parseDisplayName(const char * buffer);
+std::string parseDisplayName(const pjsip_name_addr* sip_name_addr);
+std::string parseDisplayName(const pjsip_from_hdr* header);
+std::string parseDisplayName(const pjsip_contact_hdr* header);
 
 std::string getHostFromUri(const std::string& sipUri);
 
diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp
index 0331e5821a..83f7791e20 100644
--- a/src/sip/sipaccount.cpp
+++ b/src/sip/sipaccount.cpp
@@ -1355,7 +1355,10 @@ std::string SIPAccount::getFromUri() const
         hostname = IpAddr(hostname).toString(false, true);
 #endif
 
-    return "<" + scheme + username + "@" + hostname + transport + ">";
+    const std::string uri = "<" + scheme + username + "@" + hostname + transport + ">";
+    if (not displayName_.empty())
+        return "\"" + displayName_ + "\" " + uri;
+    return uri;
 }
 
 std::string SIPAccount::getToUri(const std::string& username) const
diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp
index 1953497cb9..347a682d1a 100644
--- a/src/sip/sipvoiplink.cpp
+++ b/src/sip/sipvoiplink.cpp
@@ -194,14 +194,16 @@ transaction_request_cb(pjsip_rx_data *rdata)
         RING_ERR("Missing From, To or Via fields");
         return PJ_FALSE;
     }
-    const pjsip_sip_uri *sip_to_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(rdata->msg_info.to->uri);
-    const pjsip_sip_uri *sip_from_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(rdata->msg_info.from->uri);
+
+    const auto sip_to_uri = reinterpret_cast<pjsip_sip_uri*>(pjsip_uri_get_uri(rdata->msg_info.to->uri));
+    const auto sip_from_uri = reinterpret_cast<pjsip_sip_uri*>(pjsip_uri_get_uri(rdata->msg_info.from->uri));
     const pjsip_host_port& sip_via = rdata->msg_info.via->sent_by;
 
     if (!sip_to_uri or !sip_from_uri or !sip_via.host.ptr) {
         RING_ERR("NULL uri");
         return PJ_FALSE;
     }
+
     std::string toUsername(sip_to_uri->user.ptr, sip_to_uri->user.slen);
     std::string toHost(sip_to_uri->host.ptr, sip_to_uri->host.slen);
     std::string viaHostname(sip_via.host.ptr, sip_via.host.slen);
@@ -225,7 +227,6 @@ transaction_request_cb(pjsip_rx_data *rdata)
     }
 
     const auto& account_id = account->getAccountID();
-    auto peerDisplayName = sip_utils::parseDisplayName(rdata->msg_info.msg_buf);
     pjsip_msg_body *body = rdata->msg_info.msg->body;
 
     if (method->id == PJSIP_OTHER_METHOD) {
@@ -286,7 +287,6 @@ transaction_request_cb(pjsip_rx_data *rdata)
         return PJ_FALSE;
     }
 
-
     if (not remote_user.empty() and not remote_hostname.empty())
         peerNumber = remote_user + "@" + remote_hostname;
 
@@ -324,6 +324,16 @@ transaction_request_cb(pjsip_rx_data *rdata)
     /* fallback on local address */
     if (not addrSdp) addrSdp = addrToUse;
 
+    // Try to obtain display name from From: header first, fallback on Contact:
+    auto peerDisplayName = sip_utils::parseDisplayName(rdata->msg_info.from);
+    if (peerDisplayName.empty()) {
+        if (auto hdr = static_cast<const pjsip_contact_hdr*>(pjsip_msg_find_hdr(rdata->msg_info.msg,
+                                                                                PJSIP_H_CONTACT,
+                                                                                nullptr))) {
+            peerDisplayName = sip_utils::parseDisplayName(hdr);
+        }
+    }
+
     call->setState(Call::ConnectionState::PROGRESSING);
     call->setPeerNumber(peerNumber);
     call->setPeerDisplayName(peerDisplayName);
-- 
GitLab