From 67f395e9d20a8b87e6f4f778b8cb93606c324996 Mon Sep 17 00:00:00 2001 From: Jeremy Norman Date: Thu, 27 Dec 2018 13:54:12 +0100 Subject: [PATCH 1/2] VIALI-3438: Use Remote-Party-Id header --- Pod/Classes/SipInvite.h | 55 +++++++++++++++++++++ Pod/Classes/SipInvite.m | 100 ++++++++++++++++++++++++++++++++++++++ Pod/Classes/VSLCall.h | 14 ++++++ Pod/Classes/VSLCall.m | 21 +++++++- Pod/Classes/VSLEndpoint.m | 5 +- 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 Pod/Classes/SipInvite.h create mode 100644 Pod/Classes/SipInvite.m diff --git a/Pod/Classes/SipInvite.h b/Pod/Classes/SipInvite.h new file mode 100644 index 00000000..628c2481 --- /dev/null +++ b/Pod/Classes/SipInvite.h @@ -0,0 +1,55 @@ +#import + +@interface SipInvite : NSObject + +/** + Create this SipInvite object using the full INVITE packet. + + @param packet The full SIP INVITE packet. + @return An instance of SipInvite + */ +- (instancetype _Nullable)initWithInvitePacket:(char*_Nonnull)packet; + +/** + Check if this INVITE contained a REMOTE-PARTY-ID SIP header. + + @return TRUE if the INVITE contained the header, otherwise FALSE. + */ +- (bool) hasRemotePartyId; + +/** + Get the caller id from the REMOTE-PARTY-ID SIP header. + + @return The caller id from the REMOTE-PARTY-ID SIP header. + */ +- (NSString *_Nullable) getRemotePartyIdNumber; + +/** + Get the name from the REMOTE-PARTY-ID SIP header. + + @return The name from the REMOTE-PARTY-ID SIP header. + */ +- (NSString *_Nullable) getRemotePartyIdName; + +/** + Check if this INVITE contained a P-ASSERTED-IDENTITY SIP header. + + @return TRUE if the INVITE contained the header, otherwise FALSE. + */ +- (bool) hasPAssertedIdentity; + +/** + Get the caller id from the P-ASSERTED-IDENTITY SIP header. + + @return The caller id from the P-ASSERTED-IDENTITY SIP header. + */ +- (NSString *_Nullable) getPAssertedIdentityNumber; + +/** + Get the name from the P-ASSERTED-IDENTITY SIP header. + + @return The name from the P-ASSERTED-IDENTITY SIP header. + */ +- (NSString *_Nullable) getPAssertedIdentityName; + +@end diff --git a/Pod/Classes/SipInvite.m b/Pod/Classes/SipInvite.m new file mode 100644 index 00000000..a7a3b200 --- /dev/null +++ b/Pod/Classes/SipInvite.m @@ -0,0 +1,100 @@ +#import +#import "SipInvite.h" +#import "VSLCall.h" + +static NSString *const REMOTE_PARTY_ID_KEY = @"Remote-Party-ID"; +static NSString *const P_ASSERTED_IDENTITY_KEY = @"P-Asserted-Identity"; + +@interface SipInvite() +@property (readwrite, nonatomic) NSDictionary *remotePartyId; +@property (readwrite, nonatomic) NSDictionary *pAssertedIdentity; +@end + +@implementation SipInvite + +- (instancetype _Nullable)initWithInvitePacket:(char*)packet { + self.remotePartyId = [self extractFromLikeHeader:REMOTE_PARTY_ID_KEY FromPacket:packet]; + self.pAssertedIdentity = [self extractFromLikeHeader:P_ASSERTED_IDENTITY_KEY FromPacket:packet]; + + return self; +} + +- (bool) hasRemotePartyId { + return [self.remotePartyId objectForKey:@"caller_number"] != nil; +} + +- (NSString *) getRemotePartyIdNumber { + return self.remotePartyId[@"caller_number"]; +} + +- (NSString *) getRemotePartyIdName { + return self.remotePartyId[@"caller_name"]; +} + +- (bool) hasPAssertedIdentity { + return [self.pAssertedIdentity objectForKey:@"caller_number"] != nil; +} + +- (NSString *_Nullable) getPAssertedIdentityNumber { + return self.pAssertedIdentity[@"caller_number"]; +} + +- (NSString *_Nullable) getPAssertedIdentityName { + return self.pAssertedIdentity[@"caller_name"]; +} + +/** + Finds the FROM-like header (i.e. a header that contains information similar to the FROM field) in the invite and extracts the relevant data from it. + + @param packet The full INVITE packet. + */ +- (NSDictionary *) extractFromLikeHeader:(NSString *)header FromPacket:(char *)packet { + NSArray *remotePartyId = [self extractValueForKey:header fromPacket:packet]; + + if ([remotePartyId count] <= 0) { + return nil; + } + + NSString *remotePartyIdAddress = remotePartyId[0]; + + return [VSLCall getCallerInfoFromRemoteUri:remotePartyIdAddress]; +} + +/** + Extract the specific key given, terminated by a semi-colon. + + @param key The key to search for, this should appear at the start of the line. + @param packet The entire packet to search. + @return return The value of the key, up to the semi-colon. + */ +- (NSArray *) extractValueForKey:(NSString *)key fromPacket:(char*)packet { + NSString *line = [self findLineContaining:key inPacket:packet]; + + if (line == nil) { + return nil; + } + + return [line componentsSeparatedByString:@";"]; +} + +/** + Searches the SIP INVITE for the line with a given key. + + @param key The key to search for, this should appear at the start of the line. + @param packet The entire packet to search. + @return return The entire line relevant to the given key, nil if this line is not found. + */ +- (NSString *) findLineContaining:(NSString *)key inPacket:(char*) packet { + NSString *packetAsString = [NSString stringWithUTF8String:packet]; + NSArray *lines = [packetAsString componentsSeparatedByString:@"\n"]; + + for (id line in lines) { + if ([line hasPrefix:key]) { + return [line stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@: ", key] withString:@""]; + } + } + + return nil; +} + +@end diff --git a/Pod/Classes/VSLCall.h b/Pod/Classes/VSLCall.h index 20bfdb6c..847fe3b8 100644 --- a/Pod/Classes/VSLCall.h +++ b/Pod/Classes/VSLCall.h @@ -7,6 +7,7 @@ #import "VSLAccount.h" #import "VSLCallStats.h" #import +#import "SipInvite.h" /** * Notification which is posted when the call's state changes. @@ -371,6 +372,17 @@ typedef NS_ENUM(NSInteger, VSLCallTerminateReason) { * @return VSLCall instance */ - (instancetype _Nullable)initInboundCallWithCallId:(NSUInteger)callId account:(VSLAccount * _Nonnull)account; + +/** + * When PJSIP receives an incoming call, this initializer is called. + * + * @param callId The call ID generated by PJSIP. + * @param account The account being used to call + * @param invite An instance of SipInvite that has been created using the INVITE packet. + * @return VSLCall instance + */ +- (instancetype _Nullable)initInboundCallWithCallId:(NSUInteger)callId account:(VSLAccount * _Nonnull)account andInvite:(SipInvite *_Nonnull)invite; + - (instancetype _Nullable)initWithCallId:(NSUInteger)callId accountId:(NSInteger)accountId __attribute__((unavailable("Deprecated, use -initWithCallID: andAccount: instead"))); /* @@ -494,4 +506,6 @@ typedef NS_ENUM(NSInteger, VSLCallTerminateReason) { * Will sent the UPDATE message to the call. */ - (void)update; + ++ (NSDictionary *)getCallerInfoFromRemoteUri:(NSString *)string; @end diff --git a/Pod/Classes/VSLCall.m b/Pod/Classes/VSLCall.m index c1842438..096082ec 100644 --- a/Pod/Classes/VSLCall.m +++ b/Pod/Classes/VSLCall.m @@ -59,6 +59,7 @@ @interface VSLCall() @property (readwrite, nonatomic) VSLCallAudioState callAudioState; @property (readwrite, nonatomic) int previousRxPkt; @property (readwrite, nonatomic) int previousTxPkt; +@property (readwrite, nonatomic) SipInvite *invite; /** * Stats */ @@ -105,6 +106,12 @@ - (instancetype)initOutboundCallWithNumberToCall:(NSString *)number account:(VSL return self; } +- (instancetype _Nullable)initInboundCallWithCallId:(NSUInteger)callId account:(VSLAccount * _Nonnull)account andInvite:(SipInvite *)invite { + self.invite = invite; + + return [self initInboundCallWithCallId:callId account:account]; +} + - (void)dealloc { [[NSNotificationCenter defaultCenter] postNotificationName:VSLCallDeallocNotification object:nil @@ -390,10 +397,20 @@ - (void)updateCallInfo:(pjsua_call_info)callInfo { self.localURI = [NSString stringWithPJString:callInfo.local_info]; self.remoteURI = [NSString stringWithPJString:callInfo.remote_info]; if (self.remoteURI) { - NSDictionary *callerInfo = [self getCallerInfoFromRemoteUri:self.remoteURI]; + NSDictionary *callerInfo = [VSLCall getCallerInfoFromRemoteUri:self.remoteURI]; self.callerName = callerInfo[@"caller_name"]; self.callerNumber = callerInfo[@"caller_number"]; } + + if (self.invite != nil) { + if ([self.invite hasPAssertedIdentity]) { + self.callerName = [self.invite getPAssertedIdentityName]; + self.callerNumber = [self.invite getPAssertedIdentityNumber]; + } else if ([self.invite hasRemotePartyId]) { + self.callerName = [self.invite getRemotePartyIdName]; + self.callerNumber = [self.invite getRemotePartyIdNumber]; + } + } } } @@ -694,7 +711,7 @@ + (BOOL)automaticallyNotifiesObserversOfTransferStatus { * * @return NSDictionary output like @{"caller_name: name, "caller_number": 42}. */ -- (NSDictionary *)getCallerInfoFromRemoteUri:(NSString *)string { ++ (NSDictionary *)getCallerInfoFromRemoteUri:(NSString *)string { NSString *callerName = @""; NSString *callerNumber = @""; NSString *callerHost; diff --git a/Pod/Classes/VSLEndpoint.m b/Pod/Classes/VSLEndpoint.m index 7b6d3341..1fd29327 100644 --- a/Pod/Classes/VSLEndpoint.m +++ b/Pod/Classes/VSLEndpoint.m @@ -678,7 +678,10 @@ static void onIncomingCall(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_ VSLAccount *account = [endpoint lookupAccount:acc_id]; if (account) { VSLLogInfo(@"Detected inbound call(%d) for account:%d", call_id, acc_id); - VSLCall *call = [[VSLCall alloc] initInboundCallWithCallId:call_id account:account]; + VSLCall *call = [[VSLCall alloc] + initInboundCallWithCallId:call_id + account:account + andInvite:[[SipInvite alloc] initWithInvitePacket:rdata->pkt_info.packet]]; if (call) { [[[VialerSIPLib sharedInstance] callManager] addCall:call]; if ([VSLEndpoint sharedEndpoint].incomingCallBlock) { From 72a49a9fe951870b583028e0a924f225d7e7ecb6 Mon Sep 17 00:00:00 2001 From: "jeremy.norman" Date: Thu, 27 Dec 2018 14:22:40 +0100 Subject: [PATCH 2/2] Updated CHANGELOG.md --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e8d743e..4b478b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. --- +## [3.5.0](https://github.com/VoIPGRID/VialerSIPLib/tree/3.5.0) (27/12/2018) + +Released on Thursday, December 27, 2018 + +### Added +- The caller name and number will now be taken from the P-Asserted-Identity or Remote-Party-ID headers if they are present. + ## [3.4.2](https://github.com/VoIPGRID/VialerSIPLib/tree/3.4.2) (11/22/2018) Released on Thursday, November 22, 2018