Programming

How to Display Caller ID in Calls Between Sipgate Participants and Asterisk (Instead of Internal Sipgate ID)?

3 minute read

This post is from February 2012. The screenshots show the interface as it was then; today it looks slightly different in places.

AsteriskCalls between Sipgate participants are automatically routed as SIP calls, even when dialing the “external” phone number. This offers the advantage that calls between Sipgate participants are free, as the calls are processed over the internet. However, it would also be nice to know who is calling 😉

Problem:
The From-Header then contains not the caller’s phone number but the SIP URL (e.g., <sip:12345e0@sipgate.de>). The variable CALLERID(num) set by Asterisk then only includes the Sipgate SIP User ID, such as 12345e0. Most phones connected to Asterisk cannot do anything with this. If the ID contains a letter (here, in the example, ‘e‘), it causes some older phones not to display any caller ID at all. It is particularly annoying when a call has been missed, and the caller ID can no longer be associated with who actually called.

Solution Approach:
If you examine the SIP headers, you will notice that the desired information is contained in the header element “P-Asserted-Identity“:

INVITE sip:5000@10.0.0.33 SIP/2.0
...
From: <sip:12345e0@sipgate.de>;tag=CAFEBABE
To: <sip:072198765432@sipgate.de>
Contact: <sip:12345e0@12.34.56.78;uniq=CAFEAFFE23>
...
P-Asserted-Identity: <sip:072112345678@sipgate.de>

The format may vary with other providers. More information can be found in http://www.ietf.org/rfc/rfc3325.txt.

For demonstration purposes, I have written a small dialplan for Asterisk:

; debug
exten => 5000,1,NoOp(Caller-ID: ${CALLERID(all)})
exten => 5000,2,NoOp(SIP From: ${SIP_HEADER(From)})
exten => 5000,3,NoOp(SIP To : ${SIP_HEADER(TO)})
exten => 5000,4,NoOp(SIP PAI : ${SIP_HEADER(P-Asserted-Identity)})

; try to extract phone number from sip header P-Asserted-Identity
exten => 5000,5,Set(FON=$["${SIP_HEADER(P-Asserted-Identity)}" : " 5000,6,ExecIf($[${ISNULL(${FON})}=0]?Set(CALLERID(num)=${FON}))

; debug
exten => 5000,7,NoOp(Caller-ID: ${CALLERID(all)})
...

Explanation:
5: We extract the number using RegExp and save the result to the variable FON.
6: If FON is not null, we replace CALLERID(num) with the value of FON.

Here are two use cases and Asterisk output:
Participants for the example (phone numbers, IPs, and all TAGs are obscured).
Called Party (Asterisk with Sipgate account):
– Phone number = 072198765432
Caller 1 (Fritzbox with Sipgate account):
– Sipgate ID = 12345e0
– Phone number = 072112345678
Caller 2 (Mobile):
– Phone number = 017112345678

Case 1: Caller 1 (Sipgate -> Sipgate):

-- Exec...1] NoOp("SIP/sipgate.de-000000b6", "Caller-ID: "" <12345e0>") in new stack
-- Exec...2] NoOp("S..b6", "SIP From: <sip:12345e0@sipgate.de>;tag=CAFEBABE") in new stack
-- Exec...3] NoOp("S..b6", "SIP To : <sip:072198765432@sipgate.de>") in new stack
-- Exec...4] NoOp("S..b6", "SIP PAI : <sip:072112345678@sipgate.de>") in new stack
-- Exec...5] Set("S..b6", "FON=072112345678") in new stack
-- Exec...6] ExecIf("S..b6", "1?Set(CALLERID(num)=072112345678)") in new stack
-- Exec...7] NoOp("S..b6", "Caller-ID: "" <072112345678>") in new stack
-- Exec...8] ...

Exec…5: The caller’s external phone number was written to FON
Exec…6: 1? => Condition met => replace CALLERID(num)
Exec…7: Verification that the number was replaced (cf. Exec…1)

Case 2: Caller 2 (mobile -> Sipgate):

-- Exec...1] NoOp("S..b8", "Caller-ID: "017112345678" <017112345678>") in new stack
-- Exec...2] NoOp("S..b8", "SIP From: "017112345678" <sip:017112345678@sipgate.de>;tag=cafebabe") in new stack
-- Exec...3] NoOp("S..b8", "SIP To : <sip:004972198765432@sipgate.de>") in new stack
-- Exec...4] NoOp("S..b8", "SIP PAI : ") in new stack
-- Exec...5] Set("S..b8", "FON=") in new stack
-- Exec...6] ExecIf("S..b8", "0?Set(CALLERID(num)=)") in new stack
-- Exec...7] NoOp("S..b8", "Caller-ID: "017112345678" <017112345678>") in new stack
-- Exec...8] ...

Exec…5: Pattern matching fails because the header is not set, so the variable FON is null.
Exec…6: 0? => Condition not met => do nothing
Exec…7: Verification that the number remained unchanged (cf. Exec…1)

The end devices now always display the caller’s external phone number. This allows the caller to be called back even if a call is missed.

Have fun,

= C. | SaaS Web Tech Lab =

P.S.: It’s funny that the Sipgate app also only shows the internal ID (“Call from 12345e0”), and you’re confused about who is actually calling…