diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e55ecb0..da549f8e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,21 @@ Group changes to describe their impact on the project, as follows: Fixed for any bug fixes. Security to invite users to upgrade in case of vulnerabilities. +## [3.16.5] - 2017-11-28 + +### Added +- Support of IOS 11 + +### Changed +- Contact, CNContact implmentation. +- Contacts loading optimization. +- Sound management updated + +### Fixed +- Chat file resend fixed +- Minor bugs fixes +- Audio fixed on conference call + ## [3.16.3] - 2017-05-03 ### Added diff --git a/Classes/AssistantLinkView.m b/Classes/AssistantLinkView.m index e268a8281..06a1d7082 100644 --- a/Classes/AssistantLinkView.m +++ b/Classes/AssistantLinkView.m @@ -199,7 +199,7 @@ void assistant_activate_phone_number_link(LinphoneAccountCreator *creator, Linph } [PhoneMainView.instance popToView:DialerView.compositeViewDescription]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:NULL]; - [LinphoneManager.instance.fastAddressBook reload]; + [LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread]; } else { [thiz showErrorPopup:resp]; } diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index 45d6f8dd2..40711d036 100644 --- a/Classes/AssistantView.m +++ b/Classes/AssistantView.m @@ -412,10 +412,10 @@ static UICompositeViewDescription *compositeDescription = nil; linphone_core_set_default_proxy_config(LC, new_config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] reload]; - } else { - [self displayAssistantConfigurationError]; - } + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; + } else { + [self displayAssistantConfigurationError]; + } } - (void)displayAssistantConfigurationError { @@ -1324,8 +1324,10 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun NSString *pwd = [self findTextField:ViewElement_Password].text; LinphoneProxyConfig *config = linphone_core_create_proxy_config(LC); LinphoneAddress *addr = linphone_address_new(NULL); + LinphoneAddress *tmpAddr = linphone_address_new([NSString stringWithFormat:@"sip:%@",domain].UTF8String); linphone_address_set_username(addr, username.UTF8String); - linphone_address_set_domain(addr, domain.UTF8String); + linphone_address_set_port(addr, linphone_address_get_port(tmpAddr)); + linphone_address_set_domain(addr, linphone_address_get_domain(tmpAddr)); if (displayName && ![displayName isEqualToString:@""]) { linphone_address_set_display_name(addr, displayName.UTF8String); } @@ -1359,6 +1361,7 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun ); linphone_core_add_auth_info(LC, info); linphone_address_unref(addr); + linphone_address_unref(tmpAddr); if (config) { [[LinphoneManager instance] configurePushTokenForProxyConfig:config]; @@ -1366,13 +1369,13 @@ void assistant_is_account_linked(LinphoneAccountCreator *creator, LinphoneAccoun linphone_core_set_default_proxy_config(LC, config); // reload address book to prepend proxy config domain to contacts' phone number // todo: STOP doing that! - [[LinphoneManager.instance fastAddressBook] reload]; - [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; + [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; } else { - [self displayAssistantConfigurationError]; + [self displayAssistantConfigurationError]; } } else { - [self displayAssistantConfigurationError]; + [self displayAssistantConfigurationError]; } }); } diff --git a/Classes/CallOutgoingView.m b/Classes/CallOutgoingView.m index e8afaa1dd..4d6d6958f 100644 --- a/Classes/CallOutgoingView.m +++ b/Classes/CallOutgoingView.m @@ -150,7 +150,9 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)bluetoothAvailabilityUpdateEvent:(NSNotification *)notif { bool available = [[notif.userInfo objectForKey:@"available"] intValue]; - [self hideSpeaker:available]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self hideSpeaker:available]; + }); } @end diff --git a/Classes/Contact.h b/Classes/Contact.h index bd7cdbfad..292260607 100644 --- a/Classes/Contact.h +++ b/Classes/Contact.h @@ -6,28 +6,31 @@ // // -#import #import - +#import +#import #include @interface Contact : NSObject -@property(nonatomic, readonly) ABRecordRef person; +//@property(nonatomic, readonly) ABRecordRef person; +@property(nonatomic, readonly) CNContact *person; @property(nonatomic, readonly) LinphoneFriend *friend; +@property(nonatomic, retain) NSString *identifier; @property(nonatomic, retain) NSString *firstName; @property(nonatomic, retain) NSString *lastName; +@property(nonatomic, retain) NSString *displayName; @property(nonatomic, strong) NSMutableArray *sipAddresses; @property(nonatomic, strong) NSMutableArray *emails; -@property(nonatomic, strong) NSMutableArray *phoneNumbers; +@property(nonatomic, strong) NSMutableArray *phones; @property BOOL added; - (void)setAvatar:(UIImage *)avatar; - (UIImage *)avatar; - (NSString *)displayName; -- (instancetype)initWithPerson:(ABRecordRef)person; +- (instancetype)initWithCNContact:(CNContact *)contact; - (instancetype)initWithFriend:(LinphoneFriend *) friend; - (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index; diff --git a/Classes/Contact.m b/Classes/Contact.m index 74435fa9c..b377b2d54 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -11,81 +11,82 @@ @implementation Contact -- (instancetype)initWithPerson:(ABRecordRef)aperson { - return [self initWithPerson:aperson andFriend:NULL]; +- (instancetype)initWithCNContact:(CNContact *)acncontact { + return [self initWithPerson:acncontact andFriend:NULL]; } - (instancetype)initWithFriend:(LinphoneFriend *)afriend { return [self initWithPerson:NULL andFriend:afriend]; } -- (instancetype)initWithPerson:(ABRecordRef)aperson andFriend:(LinphoneFriend *)afriend { - self = [super init]; - _person = aperson; - _friend = afriend ? linphone_friend_ref(afriend) : NULL; - _added = FALSE; - if (_person) { - [self loadProperties]; +- (instancetype)initWithPerson:(CNContact *)acncontact + andFriend:(LinphoneFriend *)afriend { + self = [super init]; + _person = acncontact; + _friend = afriend ? linphone_friend_ref(afriend) : NULL; + _added = FALSE; + _phones = [[NSMutableArray alloc] init]; + _sipAddresses = [[NSMutableArray alloc] init]; + _emails = [[NSMutableArray alloc] init]; + if (_person) { + _identifier = _person.identifier; + _firstName = _person.givenName; + _lastName = _person.familyName; + _displayName = [NSString stringWithFormat:@"%@ %@", _firstName, _lastName]; + for (CNLabeledValue *phoneNumber in _person.phoneNumbers) { + [_phones addObject:phoneNumber.value.stringValue]; + } + if ([_person respondsToSelector:NSSelectorFromString( CNInstantMessageAddressUsernameKey)] || [_person respondsToSelector:NSSelectorFromString(CNContactInstantMessageAddressesKey)]) { + if (_person.instantMessageAddresses != NULL) { + for (CNLabeledValue *sipAddr in _person.instantMessageAddresses) { + [_sipAddresses addObject:sipAddr.value.username]; + } + } + } + for (CNLabeledValue *email in _person.emailAddresses) { + [_emails addObject:email.value]; + } + const char *key = [NSString stringWithFormat:@"ab%@", acncontact.identifier].UTF8String; + // try to find friend associated with that person + _friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key); + if (!_friend) { + _friend = linphone_friend_ref(linphone_core_create_friend(LC)); + linphone_friend_set_ref_key(_friend, key); + linphone_friend_set_name(_friend, [NSString stringWithFormat:@"%@%@", _firstName ? _firstName : @"", _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] .UTF8String); + for (NSString *sipAddr in _sipAddresses) { + LinphoneAddress *addr = linphone_core_interpret_url(LC, sipAddr.UTF8String); + if (addr) { + linphone_address_set_display_name(addr, [self displayName].UTF8String); + linphone_friend_add_address(_friend, addr); + linphone_address_destroy(addr); + } + } + for (NSString *phone in _phones) { + linphone_friend_add_phone_number(_friend, phone.UTF8String); + } + if (_friend) { + linphone_friend_enable_subscribes(_friend, FALSE); + linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); + linphone_core_add_friend(LC, _friend); + } + } + linphone_friend_ref(_friend); + + } else if (_friend) { + [self loadFriend]; + } else { + LOGE(@"Contact cannot be initialized"); + return nil; + } - const char* key = [NSString stringWithFormat:@"ab%d", ABRecordGetRecordID(aperson)].UTF8String; - // try to find friend associated with that person - _friend = linphone_friend_list_find_friend_by_ref_key(linphone_core_get_default_friend_list(LC), key); - if (!_friend) { - _friend = linphone_friend_ref(linphone_core_create_friend(LC)); - linphone_friend_set_ref_key(_friend, key); - linphone_friend_set_name( - _friend, - [NSString - stringWithFormat:@"%@%@", _firstName ? _firstName : @"", - _lastName ? [_firstName ? @" " : @"" stringByAppendingString:_lastName] : @""] - .UTF8String); - for (NSString* sipAddr in _sipAddresses) { - LinphoneAddress* addr = linphone_core_interpret_url(LC, sipAddr.UTF8String); - if (addr) { - linphone_address_set_display_name(addr, [self displayName].UTF8String); - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - } - } - for (NSString* phone in _phoneNumbers) { -#if 0 - char* normalized_phone = linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); - if (normalized_phone) { - LinphoneAddress* addr = linphone_core_interpret_url(LC, normalized_phone); - if (addr) { - linphone_address_set_display_name(addr, [self displayName].UTF8String); - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - } - ms_free(normalized_phone); - } -#else - linphone_friend_add_phone_number(_friend, phone.UTF8String); -#endif - } - if (_friend) { - linphone_friend_enable_subscribes(_friend, FALSE); - linphone_friend_set_inc_subscribe_policy(_friend, LinphoneSPDeny); - linphone_core_add_friend(LC, _friend); - } - } - linphone_friend_ref(_friend); - } else if (_friend) { - [self loadFriend]; - } else { - LOGE(@"Contact cannot be initialized"); - return nil; - } - - LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", self.firstName ?: @"", self.lastName ?: @"", - self.phoneNumbers.count, self.sipAddresses.count, self.emails.count); - return self; + /* LOGI(@"Contact %@ %@ initialized with %d phones, %d sip, %d emails", + self.firstName ?: @"", self.lastName ?: @"", self.phones.count, + self.sipAddresses.count, self.emails.count); + */ + return self; } - (void)dealloc { - if (_person != nil && ABRecordGetRecordID(_person) == kABRecordInvalidID) { - CFRelease(_person); - } if (_friend) { linphone_friend_unref(_friend); } @@ -95,11 +96,15 @@ #pragma mark - Getters - (UIImage *)avatar { - if (_person && ABPersonHasImageData(_person)) { - NSData *imgData = CFBridgingRelease(ABPersonCopyImageDataWithFormat(_person, kABPersonImageFormatThumbnail)); - return [UIImage imageWithData:imgData]; - } - return nil; + if (_person) { + @try { + return [UIImage imageWithData:_person.imageData]; + } @catch (NSException *e) { + LOGE(@"CNContact imageData CNPropertyNotFetchedException : %@", e); + return nil; + } + } + return nil; } - (NSString *)displayName { @@ -111,506 +116,416 @@ } if (_person != nil) { - NSString *lFirstName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty)); - NSString *lLocalizedFirstName = [FastAddressBook localizedLabel:lFirstName]; - NSString *compositeName = CFBridgingRelease(ABRecordCopyCompositeName(_person)); + NSString *lFirstName = _person.givenName; + NSString *lLocalizedFirstName = + [FastAddressBook localizedLabel:lFirstName]; - NSString *lLastName = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty)); - NSString *lLocalizedLastName = [FastAddressBook localizedLabel:lLastName]; + NSString *compositeName = _person.nickname; - NSString *lOrganization = CFBridgingRelease(ABRecordCopyValue(_person, kABPersonOrganizationProperty)); - NSString *lLocalizedOrganization = [FastAddressBook localizedLabel:lOrganization]; + NSString *lLastName = _person.familyName; + NSString *lLocalizedLastName = + [FastAddressBook localizedLabel:lLastName]; - if (compositeName) { - return compositeName; - } else if (lLocalizedFirstName || lLocalizedLastName) { - return [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, lLocalizedLastName]; - } else { - return (NSString *)lLocalizedOrganization; - } - } + NSString *lOrganization = _person.organizationName; + NSString *lLocalizedOrganization = + [FastAddressBook localizedLabel:lOrganization]; - if (_lastName || _firstName) { - NSMutableString *str; - if (_firstName) - [str appendString:_firstName]; - if (_firstName && _lastName) - [str appendString:@" "]; - if (_lastName) - [str appendString:_lastName]; - } + if (compositeName) { + return compositeName; + } else if (lLocalizedFirstName || lLocalizedLastName) { + return [NSString stringWithFormat:@"%@ %@", lLocalizedFirstName, + lLocalizedLastName]; + } else { + return (NSString *)lLocalizedOrganization; + } + } - return NSLocalizedString(@"Unknown", nil); + if (_lastName || _firstName) { + NSMutableString *str; + if (_firstName) + [str appendString:_firstName]; + if (_firstName && _lastName) + [str appendString:@" "]; + if (_lastName) + [str appendString:_lastName]; + } + + return NSLocalizedString(@"Unknown", nil); } #pragma mark - Setters - (void)setAvatar:(UIImage *)avatar { - if (_person) { - CFErrorRef error = NULL; - if (!ABPersonRemoveImageData(_person, &error)) { - LOGW(@"Can't remove entry: %@", [(__bridge NSError *)error localizedDescription]); - } - NSData *dataRef = UIImageJPEGRepresentation(avatar, 0.9f); - CFDataRef cfdata = CFDataCreate(NULL, [dataRef bytes], [dataRef length]); - - if (!ABPersonSetImageData(_person, cfdata, &error)) { - LOGW(@"Can't add entry: %@", [(__bridge NSError *)error localizedDescription]); - } - - CFRelease(cfdata); - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } + BOOL ret = FALSE; + if (_person) { + NSData *imageAvatar = UIImageJPEGRepresentation(avatar, 0.9f); + [_person setValue:imageAvatar forKey:CNContactImageDataKey]; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); + } } - (void)setFirstName:(NSString *)firstName { BOOL ret = FALSE; - if (_person) { - ret = ([self replaceInProperty:kABPersonFirstNameProperty value:(__bridge CFTypeRef)(firstName)]); - } else { - ret = (linphone_friend_set_name(_friend, firstName.UTF8String) == 0); - } - - if (ret) { - _firstName = firstName; - } + if (![firstName isEqualToString:_firstName]) { + if (_friend) + ret = linphone_friend_set_name( + _friend, [NSString stringWithFormat:@"%@ %@", firstName, + _person.familyName] + .UTF8String); + if (_person) { + [_person setValue:firstName forKey:CNContactGivenNameKey]; + [_person setValue:[NSString stringWithFormat:@"%@ %@", firstName, + _person.familyName] + forKey:CNContactNicknameKey]; + ret = TRUE; + } + if (ret) { + _firstName = firstName; + _displayName = [NSString + stringWithFormat:@"%@ %@", firstName, _person.familyName]; + } + } } - (void)setLastName:(NSString *)lastName { BOOL ret = FALSE; - if (_person) { - ret = ([self replaceInProperty:kABPersonLastNameProperty value:(__bridge CFTypeRef)(lastName)]); - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - - if (ret) { - _lastName = lastName; - } + if (_friend) + ret = linphone_friend_set_name( + _friend, + [NSString stringWithFormat:@"%@ %@", _person.givenName, lastName] + .UTF8String); + if (_person) { + [_person setValue:lastName forKey:CNContactFamilyNameKey]; + [_person + setValue:[NSString stringWithFormat:@"%@ %@", _person.givenName, + lastName] + forKey:CNContactNicknameKey]; + ret = TRUE; + } + if (ret) { + _lastName = lastName; + _displayName = + [NSString stringWithFormat:@"%@ %@", _person.givenName, lastName]; + } } - (BOOL)setSipAddress:(NSString *)sip atIndex:(NSInteger)index { BOOL ret = FALSE; NSString *normSip = NULL; - if (_person) { - normSip = [self setOrCreateSipContactEntry:index withValue:sip]; - NSDictionary *lDict = @{ - (NSString *)kABPersonInstantMessageUsernameKey : normSip ? normSip : sip, - (NSString *)kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField - }; + if (_person && ![sip isEqualToString:@" "]) { + if ((index + 1) > [_person.instantMessageAddresses count]) { + if ([sip hasPrefix:@" "]) + normSip = [sip substringFromIndex:1]; + else + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([normSip containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:normSip service:[normSip componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress addObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + _sipAddresses[index] = normSip; + } else { + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([[FastAddressBook normalizeSipURI:normSip] containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:sip + service:[[FastAddressBook normalizeSipURI:normSip] + componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress replaceObjectAtIndex:index withObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } - ret = [self replaceInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict) atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - - if (ret) { - _sipAddresses[index] = sip; - } - return ret; + if (ret) { + _sipAddresses[index] = sip; + } + return ret; } - (BOOL)setPhoneNumber:(NSString *)phone atIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self replaceInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone) atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - _phoneNumbers[index] = phone; - } - return ret; + if ((index + 1) > [_person.phoneNumbers count]) { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers addObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } else { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers replaceObjectAtIndex:index + withObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) + _phones[index] = phone; + return ret; } - (BOOL)setEmail:(NSString *)email atIndex:(NSInteger)index { BOOL ret = FALSE; if (_person) { - ret = [self replaceInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email) atIndex:index]; - } else { - } - if (ret) { - _emails[index] = email; - } - return ret; + if ((index + 1) > [_person.emailAddresses count]) { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress addObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } else { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress replaceObjectAtIndex:index + withObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) + _emails[index] = email; + return ret; } - (BOOL)addSipAddress:(NSString *)sip { BOOL ret = FALSE; - if (_person) { - NSDictionary *lDict = @{ - (NSString *) kABPersonInstantMessageUsernameKey : sip, (NSString *) - kABPersonInstantMessageServiceKey : LinphoneManager.instance.contactSipField - }; - - ret = [self addInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict)]; - } else { - LinphoneAddress *addr = linphone_core_interpret_url(LC, sip.UTF8String) ?: linphone_address_new(sip.UTF8String); - if (addr) { - ret = TRUE; - linphone_friend_add_address(_friend, addr); - linphone_address_destroy(addr); - // ensure that it was added by checking list size - ret = (bctbx_list_size(linphone_friend_get_addresses(_friend)) == _sipAddresses.count + 1); - } - } - if (ret) { - [_sipAddresses addObject:sip]; - } - return ret; + NSString *normSip = NULL; + if (sip != NULL && ![sip isEqualToString:@""]) { + if ([sip isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + normSip = sip; + CNInstantMessageAddress *cNSipMsgAddr; + if ([normSip containsString:@"@"]) + cNSipMsgAddr = [[CNInstantMessageAddress alloc] + initWithUsername:[normSip + componentsSeparatedByString:@"@"][0] + service:[normSip + componentsSeparatedByString:@"@"][1]]; + else + cNSipMsgAddr = + [[CNInstantMessageAddress alloc] initWithUsername:normSip + service:normSip]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL + value:cNSipMsgAddr]; + NSMutableArray *> * + tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress addObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + } else { + LinphoneAddress *addr = + linphone_core_interpret_url(LC, sip.UTF8String) + ?: linphone_address_new(sip.UTF8String); + if (addr) { + ret = TRUE; + linphone_friend_add_address(_friend, addr); + linphone_address_destroy(addr); + // ensure that it was added by checking list size + ret = + (bctbx_list_size(linphone_friend_get_addresses(_friend)) == + _sipAddresses.count + 1); + } + } + } + } + if (ret) { + if ([sip hasPrefix:@" "]) + [_sipAddresses addObject:[sip substringFromIndex:1]]; + else + [_sipAddresses addObject:sip]; + } + return ret; } - (BOOL)addPhoneNumber:(NSString *)phone { BOOL ret = FALSE; - if (_person) { - ret = [self addInProperty:kABPersonPhoneProperty value:(__bridge CFTypeRef)(phone)]; - } else { - char *cphone = ms_strdup(phone.UTF8String); - // linphone_proxy_config_normalize_phone_number(NULL, phone.UTF8String) ?: ms_strdup(phone.UTF8String); - if (cphone) { - linphone_friend_add_phone_number(_friend, cphone); - phone = [NSString stringWithUTF8String:cphone]; - ms_free(cphone); - // ensure that it was added by checking list size - ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) == _phoneNumbers.count + 1); - } - } - if (ret) { - [_phoneNumbers addObject:phone]; - } - return ret; + if (phone != NULL && ![phone isEqualToString:@""]) { + if ([phone isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + CNLabeledValue *mobileNumber = [CNLabeledValue + labeledValueWithLabel:CNLabelPhoneNumberMobile + value:[CNPhoneNumber + phoneNumberWithStringValue:phone]]; + NSMutableArray *> + *tmpPhoneNumbers = [_person.phoneNumbers mutableCopy]; + [tmpPhoneNumbers addObject:mobileNumber]; + [_person setValue:tmpPhoneNumbers + forKey:CNContactPhoneNumbersKey]; + ret = TRUE; + } else { + char *cphone = ms_strdup(phone.UTF8String); + if (cphone) { + linphone_friend_add_phone_number(_friend, cphone); + phone = [NSString stringWithUTF8String:cphone]; + ms_free(cphone); + // ensure that it was added by checking list size + ret = (bctbx_list_size(linphone_friend_get_phone_numbers( + _friend)) == _phones.count + 1); + } + } + } + } + if (ret) { + [_phones addObject:phone]; + } + return ret; } - (BOOL)addEmail:(NSString *)email { BOOL ret = FALSE; - if (_person) { - ret = [self addInProperty:kABPersonEmailProperty value:(__bridge CFTypeRef)(email)]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - [_emails addObject:email]; - } - return ret; + if (email != NULL && ![email isEqualToString:@""]) { + if ([email isEqualToString:@" "]) + ret = TRUE; + else { + if (_person) { + CNLabeledValue *emailAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:email]; + NSMutableArray *> *tmpEmailAddress = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddress addObject:emailAddress]; + [_person setValue:tmpEmailAddress + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + } + } + if (ret) { + [_emails addObject:email]; + } + return ret; } - (BOOL)removeSipAddressAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { - ret = [self removeInProperty:kABPersonInstantMessageProperty atIndex:index]; - } else { - LinphoneAddress *addr = linphone_core_interpret_url(LC, ((NSString *)_sipAddresses[index]).UTF8String); - if (addr) { - linphone_friend_remove_address(_friend, addr); - linphone_address_destroy(addr); - // ensure that it was destroyed by checking list size - ret = (bctbx_list_size(linphone_friend_get_addresses(_friend)) + 1 == _sipAddresses.count); + if (_person ) { + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + if([tmpSipAddress count] > index){ + [tmpSipAddress removeObjectAtIndex:index]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; } - } - if (ret) { - [_sipAddresses removeObjectAtIndex:index]; - } - return ret; + ret = TRUE; + } else { + LinphoneAddress *addr = linphone_core_interpret_url( + LC, ((NSString *)_sipAddresses[index]).UTF8String); + if (addr) { + linphone_friend_remove_address(_friend, addr); + linphone_address_destroy(addr); + // ensure that it was destroyed by checking list size + ret = + (bctbx_list_size(linphone_friend_get_addresses(_friend)) + 1 == + _sipAddresses.count); + } + } + if (ret) { + [_sipAddresses removeObjectAtIndex:index]; + } + return ret; } - (BOOL)removePhoneNumberAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { - ret = [self removeInProperty:kABPersonPhoneProperty atIndex:index]; - } else { - const char *phone = ((NSString *)_phoneNumbers[index]).UTF8String; - linphone_friend_remove_phone_number(_friend, phone); - // ensure that it was destroyed by checking list size - ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) + 1 == _phoneNumbers.count); - } - if (ret) { - [_phoneNumbers removeObjectAtIndex:index]; - } - return ret; + if (_person && _person.phoneNumbers.count > 0) { + NSMutableArray *> *tmpPhoneNumbers = + [_person.phoneNumbers mutableCopy]; + if([tmpPhoneNumbers count] > index){ + [tmpPhoneNumbers removeObjectAtIndex:index]; + [_person setValue:tmpPhoneNumbers forKey:CNContactPhoneNumbersKey]; + } + ret = TRUE; + } else { + const char *phone = ((NSString *)_phones[index]).UTF8String; + linphone_friend_remove_phone_number(_friend, phone); + // ensure that it was destroyed by checking list size + // ret = (bctbx_list_size(linphone_friend_get_phone_numbers(_friend)) + // + 1 == _phoneNumbers.count); + ret = TRUE; + } + if (ret) { + [_phones removeObjectAtIndex:index]; + } + return ret; } - (BOOL)removeEmailAtIndex:(NSInteger)index { BOOL ret = FALSE; - if (_person) { - ret = [self removeInProperty:kABPersonEmailProperty atIndex:index]; - } else { - LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", __FUNCTION__); - } - if (ret) { - [_emails removeObjectAtIndex:index]; - } - return ret; -} - -#pragma mark - ABPerson utils -- (NSString *)setOrCreateSipContactEntry:(NSInteger)index withValue:(NSString *)value { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - ABMutableMultiValueRef lMap; - NSString *ret = NULL; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - CFErrorRef error = NULL; - - NSDictionary *lDict = @{ - (NSString *)kABPersonInstantMessageUsernameKey : value, - (NSString *)kABPersonInstantMessageServiceKey : [LinphoneManager instance].contactSipField - }; - - if (![self replaceInProperty:kABPersonInstantMessageProperty value:(__bridge CFTypeRef)(lDict) atIndex:index]) { - LOGI(@"Can't set contact with value [%@] cause [%@]", value, [(__bridge NSError *)error localizedDescription]); - CFRelease(lMap); - } else { - CFRelease(lMap); - - /*check if message type is kept or not*/ - lcMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - lDict = CFBridgingRelease(ABMultiValueCopyValueAtIndex(lMap, index)); - - if ([lDict objectForKey:(__bridge NSString *)kABPersonInstantMessageServiceKey] == nil) { - /*too bad probably a gtalk number, storing uri*/ - ret = [FastAddressBook normalizeSipURI:value]; - } else if (!_added) { - _added = TRUE; - [LinphoneManager.instance.fastAddressBook saveContact:self]; + if (_person && _person.phoneNumbers.count > 0) { + NSMutableArray *> *tmpEmailAddresses = + [_person.emailAddresses mutableCopy]; + if([tmpEmailAddresses count] > index){ + [tmpEmailAddresses removeObjectAtIndex:index]; + [_person setValue:tmpEmailAddresses + forKey:CNContactEmailAddressesKey]; } - CFRelease(lMap); - } - return ret ? ret : value; + ret = TRUE; + } else { + LOGW(@"%s: Cannot do it when using LinphoneFriend, skipping", + __FUNCTION__); + } + if (ret) { + [_emails removeObjectAtIndex:index]; + } + return ret; } -- (void)loadProperties { - // First and Last name - { - _firstName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonFirstNameProperty)); - _lastName = (NSString *)CFBridgingRelease(ABRecordCopyValue(_person, kABPersonLastNameProperty)); - } - - // Phone numbers - { - _phoneNumbers = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonPhoneProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i); - NSInteger index = ABMultiValueGetIndexForIdentifier(map, identifier); - if (index != -1) { - NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(map, index)); - // char *normalizedPhone = linphone_proxy_config_normalize_phone_number( - // linphone_core_get_default_proxy_config(LC), valueRef.UTF8String); - // if (normalizedPhone) { - // valueRef = [NSString stringWithUTF8String:normalizedPhone]; - // ms_free(normalizedPhone); - //} - - [_phoneNumbers addObject:valueRef]; - } - } - CFRelease(map); - } - } - - // SIP (IM) - /*{ - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(map, i); - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey)); - CFRelease(lDict); - if (value != NULL) { - [_sipAddresses addObject:value]; - } - } - } - } - CFRelease(map); - } - }*/ - - // SIP (IM) - { - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef lMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (lMap) { - for (int i = 0; i < ABMultiValueGetCount(lMap); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i); - BOOL add = false; - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)[LinphoneManager instance].contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - add = true; - } - } else { - // check domain - LinphoneAddress *address = linphone_address_new( - [(NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey) UTF8String]); - if (address) { - if ([[ContactSelection getSipFilter] compare:@"*" options:NSCaseInsensitiveSearch] == - NSOrderedSame) { - add = true; - } else { - NSString *domain = [NSString stringWithCString:linphone_address_get_domain(address) - encoding:[NSString defaultCStringEncoding]]; - add = [domain compare:[ContactSelection getSipFilter] options:NSCaseInsensitiveSearch] == - NSOrderedSame; - } - linphone_address_destroy(address); - } else { - add = false; - } - } - if (add) { - NSString *value = (NSString *)(CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey)); - if (value != NULL) { - [_sipAddresses addObject:value]; - } - } - CFRelease(lDict); - } - CFRelease(lMap); - } - } - - // SIP - /*{ - _sipAddresses = [[NSMutableArray alloc] init]; - ABMultiValueRef lMap = ABRecordCopyValue(_person, kABPersonInstantMessageProperty); - if (lMap) { - for (int i = 0; i < ABMultiValueGetCount(lMap); ++i) { - CFDictionaryRef lDict = ABMultiValueCopyValueAtIndex(lMap, i); - BOOL add = false; - if (CFDictionaryContainsKey(lDict, kABPersonInstantMessageServiceKey)) { - if (CFStringCompare((CFStringRef)LinphoneManager.instance.contactSipField, - CFDictionaryGetValue(lDict, kABPersonInstantMessageServiceKey), - kCFCompareCaseInsensitive) == 0) { - add = true; - } - } else { - add = true; - } - if (add) { - NSString *lValue = - (__bridge NSString *)CFDictionaryGetValue(lDict, kABPersonInstantMessageUsernameKey); - if(lValue) { - NSString *lNormalizedKey = [FastAddressBook normalizeSipURI:lValue]; - if (lNormalizedKey != NULL) { - [_sipAddresses addObject:lNormalizedKey]; - } else { - [_sipAddresses addObject:lValue]; - } - } - } - CFRelease(lDict); - } - CFRelease(lMap); - } - }*/ - - // Email - { - _emails = [[NSMutableArray alloc] init]; - ABMultiValueRef map = ABRecordCopyValue(_person, kABPersonEmailProperty); - if (map) { - for (int i = 0; i < ABMultiValueGetCount(map); ++i) { - ABMultiValueIdentifier identifier = ABMultiValueGetIdentifierAtIndex(map, i); - NSInteger index = ABMultiValueGetIndexForIdentifier(map, identifier); - if (index != -1) { - NSString *valueRef = CFBridgingRelease(ABMultiValueCopyValueAtIndex(map, index)); - if (valueRef != NULL) { - [_emails addObject:valueRef]; - } - } - } - CFRelease(map); - } - } -} - -- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value { - CFErrorRef error = NULL; - if (!ABRecordSetValue(_person, property, value, &error)) { - LOGE(@"Error when saving property %d in contact %p: Fail(%@)", property, _person, error); - return NO; - } - return YES; -} - -- (BOOL)replaceInProperty:(ABPropertyID)property value:(CFTypeRef)value atIndex:(NSInteger)index { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - BOOL ret = ABMultiValueReplaceValueAtIndex(lMap, value, index); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not replace %@ at index %d from property %d", value, index, property); - } - - CFRelease(lMap); - return ret; -} - -- (BOOL)addInProperty:(ABPropertyID)property value:(CFTypeRef)value { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - // will display this field with our application name - CFStringRef label = (__bridge CFStringRef)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - BOOL ret = ABMultiValueAddValueAndLabel(lMap, value, label, nil); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not add %@ to property %d", value, property); - } - CFRelease(lMap); - return ret; -} - -- (BOOL)removeInProperty:(ABPropertyID)property atIndex:(NSInteger)index { - ABMultiValueRef lcMap = ABRecordCopyValue(_person, property); - ABMutableMultiValueRef lMap; - if (lcMap != NULL) { - lMap = ABMultiValueCreateMutableCopy(lcMap); - CFRelease(lcMap); - } else { - lMap = ABMultiValueCreateMutable(kABStringPropertyType); - } - - BOOL ret = ABMultiValueRemoveValueAndLabelAtIndex(lMap, index); - if (ret) { - ret = [self replaceInProperty:property value:lMap]; - } else { - LOGW(@"Could not remove at index %d from property %d", index, property); - } - - CFRelease(lMap); - return ret; -} #pragma mark - LinphoneFriend utils @@ -623,32 +538,32 @@ // Phone numbers { - _phoneNumbers = [[NSMutableArray alloc] init]; - MSList *numbers = linphone_friend_get_phone_numbers(_friend); - while (numbers) { - NSString *phone = [NSString stringWithUTF8String:numbers->data]; - [_phoneNumbers addObject:phone]; - numbers = numbers->next; - } - } + _phones = [[NSMutableArray alloc] init]; + MSList *numbers = linphone_friend_get_phone_numbers(_friend); + while (numbers) { + NSString *phone = [NSString stringWithUTF8String:numbers->data]; + [_phones addObject:phone]; + numbers = numbers->next; + } + } - // SIP (IM) - { - _sipAddresses = [[NSMutableArray alloc] init]; - const MSList *sips = linphone_friend_get_addresses(_friend); - while (sips) { - LinphoneAddress *addr = sips->data; - char *uri = linphone_address_as_string_uri_only(addr); - NSString *sipaddr = [NSString stringWithUTF8String:uri]; - [_sipAddresses addObject:sipaddr]; - ms_free(uri); + // SIP (IM) + { + _sipAddresses = [[NSMutableArray alloc] init]; + const MSList *sips = linphone_friend_get_addresses(_friend); + while (sips) { + LinphoneAddress *addr = sips->data; + char *uri = linphone_address_as_string_uri_only(addr); + NSString *sipaddr = [NSString stringWithUTF8String:uri]; + [_sipAddresses addObject:sipaddr]; + ms_free(uri); - sips = sips->next; - } - } + sips = sips->next; + } + } - // Email - no support for LinphoneFriend - { _emails = [[NSMutableArray alloc] init]; } + // Email - no support for LinphoneFriend + { _emails = [[NSMutableArray alloc] init]; } } @end diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index 630508ea4..b771f340c 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -29,15 +29,17 @@ - (NSMutableArray *)getSectionData:(NSInteger)section { if (section == ContactSections_Number) { - return _contact.phoneNumbers; - } else if (section == ContactSections_Sip) { - return _contact.sipAddresses; - } else if (section == ContactSections_Email) { - if ([LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) { - return _contact.emails; - } - } - return nil; + return _contact.phones; + } else if (section == ContactSections_Sip) { + return _contact.sipAddresses; + } else if (section == ContactSections_Email) { + if ([LinphoneManager.instance + lpConfigBoolForKey:@"show_contacts_emails_preference"] == + true) { + return _contact.emails; + } + } + return nil; } - (void)removeEmptyEntry:(UITableView *)tableview section:(NSInteger)section animated:(BOOL)animated { @@ -73,27 +75,36 @@ - (void)addEntry:(UITableView *)tableview section:(NSInteger)section animated:(BOOL)animated value:(NSString *)value { bool added = FALSE; if (section == ContactSections_Number) { + if ([_contact.phones count] == + [_contact.person.phoneNumbers count]) added = [_contact addPhoneNumber:value]; } else if (section == ContactSections_Sip) { - added = [_contact addSipAddress:value]; - } else if (section == ContactSections_Email) { - added = [_contact addEmail:value]; - } - - if (added) { - NSUInteger count = [self getSectionData:section].count; - [tableview insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 inSection:section] ] - withRowAnimation:animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone]; - } else { - LOGW(@"Cannot add entry '%@' in section %d, skipping", value, section); - } + if ([_contact.sipAddresses count] == + [_contact.person.instantMessageAddresses count]) + added = [_contact addSipAddress:value]; + } else if (section == ContactSections_Email) { + if ([_contact.emails count] == + [_contact.person.emailAddresses count]) + added = [_contact addEmail:value]; + } + if (added) { + NSUInteger count = [self getSectionData:section].count; + [tableview + insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:count - 1 + inSection:section] ] + withRowAnimation:animated ? UITableViewRowAnimationFade + : UITableViewRowAnimationNone]; + } else { + LOGW(@"Cannot add entry '%@' in section %d, skipping", value, + section); + } } - (void)setContact:(Contact *)acontact { - if (acontact == _contact) - return; - _contact = acontact; - [self loadData]; + // if (acontact == _contact) + // return; + _contact = acontact; + [self loadData]; } - (void)addPhoneField:(NSString *)number { @@ -119,8 +130,9 @@ - (BOOL)isValid { BOOL hasName = (_contact.firstName.length + _contact.lastName.length > 0); - BOOL hasAddr = (_contact.phoneNumbers.count + _contact.sipAddresses.count) > 0; - return hasName && hasAddr; + BOOL hasAddr = + (_contact.phones.count + _contact.sipAddresses.count) > 0; + return hasName && hasAddr; } #pragma mark - UITableViewDataSource Functions @@ -140,12 +152,13 @@ } else if (section == ContactSections_Sip) { return _contact.sipAddresses.count; } else if (section == ContactSections_Number) { - return _contact.phoneNumbers.count; - } else if (section == ContactSections_Email) { - BOOL showEmails = [LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"]; - return showEmails ? _contact.emails.count : 0; - } - return 0; + return _contact.phones.count; + } else if (section == ContactSections_Email) { + BOOL showEmails = [LinphoneManager.instance + lpConfigBoolForKey:@"show_contacts_emails_preference"]; + return showEmails ? _contact.emails.count : 0; + } + return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -170,26 +183,29 @@ value = _contact.lastName; [cell hideDeleteButton:YES]; } else if ([indexPath section] == ContactSections_Number) { - value = _contact.phoneNumbers[indexPath.row]; - [cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad]; - } else if ([indexPath section] == ContactSections_Sip) { - value = _contact.sipAddresses[indexPath.row]; - LinphoneAddress *addr = NULL; - if ([LinphoneManager.instance lpConfigBoolForKey:@"contact_display_username_only"] && - (addr = linphone_core_interpret_url(LC, [value UTF8String]))) { - value = [NSString stringWithCString:linphone_address_get_username(addr) - encoding:[NSString defaultCStringEncoding]]; - linphone_address_destroy(addr); - } - [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; - } else if ([indexPath section] == ContactSections_Email) { - value = _contact.emails[indexPath.row]; - [cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress]; - } + value = _contact.phones[indexPath.row]; + [cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad]; + } else if ([indexPath section] == ContactSections_Sip) { + value = _contact.sipAddresses[indexPath.row]; + LinphoneAddress *addr = NULL; + if ([LinphoneManager.instance + lpConfigBoolForKey:@"contact_display_username_only"] && + (addr = linphone_core_interpret_url(LC, [value UTF8String]))) { + value = + [NSString stringWithCString:linphone_address_get_username(addr) + encoding:[NSString defaultCStringEncoding]]; + linphone_address_destroy(addr); + } + [cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable]; + } else if ([indexPath section] == ContactSections_Email) { + value = _contact.emails[indexPath.row]; + [cell.editTextfield setKeyboardType:UIKeyboardTypeEmailAddress]; + } + if ([value hasPrefix:@" "]) + value = [value substringFromIndex:1]; + [cell setAddress:value]; - [cell setAddress:value]; - - return cell; + return cell; } - (void)tableView:(UITableView *)tableView @@ -198,13 +214,16 @@ [LinphoneUtils findAndResignFirstResponder:[self tableView]]; if (editingStyle == UITableViewCellEditingStyleInsert) { [tableView beginUpdates]; - [self addEntry:tableView section:[indexPath section] animated:TRUE value:@""]; - [tableView endUpdates]; - } else if (editingStyle == UITableViewCellEditingStyleDelete) { - [tableView beginUpdates]; - [self removeEntry:tableView indexPath:indexPath animated:TRUE]; - [tableView endUpdates]; - } + [self addEntry:tableView + section:[indexPath section] + animated:TRUE + value:@" "]; + [tableView endUpdates]; + } else if (editingStyle == UITableViewCellEditingStyleDelete) { + [tableView beginUpdates]; + [self removeEntry:tableView indexPath:indexPath animated:TRUE]; + [tableView endUpdates]; + } } #pragma mark - UITableViewDelegate Functions @@ -372,19 +391,22 @@ break; case ContactSections_Number: [_contact setPhoneNumber:value atIndex:path.row]; - value = _contact.phoneNumbers[path.row]; // in case of reformatting - break; - case ContactSections_MAX: - case ContactSections_None: - break; - } - cell.editTextfield.text = value; - _editButton.enabled = [self isValid]; - } + value = + _contact.phones[path.row]; // in case of + // reformatting + break; + case ContactSections_MAX: + case ContactSections_None: + break; + } + cell.editTextfield.text = value; + _editButton.enabled = [self isValid]; + } } - (void)textFieldDidEndEditing:(UITextField *)textField { [self textFieldUpdated:textField]; + // TODO reload current contact } - (BOOL)textField:(UITextField *)textField diff --git a/Classes/ContactDetailsView.m b/Classes/ContactDetailsView.m index 35d4b044b..f88ecfd2a 100644 --- a/Classes/ContactDetailsView.m +++ b/Classes/ContactDetailsView.m @@ -29,12 +29,18 @@ self = [super initWithNibName:NSStringFromClass(self.class) bundle:[NSBundle mainBundle]]; if (self != nil) { inhibUpdate = FALSE; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; - } - return self; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:CNContactStoreDidChangeNotification + object:nil]; + } + return self; } - (void)dealloc { @@ -44,11 +50,12 @@ #pragma mark - - (void)onAddressBookUpdate:(NSNotification *)k { - if (!inhibUpdate && ![_tableController isEditing] && - (PhoneMainView.instance.currentView == self.compositeViewDescription) && - (_nameLabel.text == PhoneMainView.instance.currentName)) { - [self resetData]; - } + + if (!inhibUpdate && ![_tableController isEditing] && + (PhoneMainView.instance.currentView == self.compositeViewDescription) && + (_nameLabel.text == PhoneMainView.instance.currentName)) { + [self resetData]; + } } - (void)resetData { @@ -67,9 +74,9 @@ - (void)removeContact { inhibUpdate = TRUE; - [[LinphoneManager.instance fastAddressBook] removeContact:_contact]; - inhibUpdate = FALSE; - [PhoneMainView.instance popCurrentView]; + [[LinphoneManager.instance fastAddressBook] deleteContact:_contact]; + inhibUpdate = FALSE; + [PhoneMainView.instance popCurrentView]; } - (void)saveData { @@ -77,9 +84,9 @@ [PhoneMainView.instance popCurrentView]; return; } - - // Add contact to book - [LinphoneManager.instance.fastAddressBook saveContact:_contact]; + PhoneMainView.instance.currentName = _contact.displayName; + _nameLabel.text = PhoneMainView.instance.currentName; + [LinphoneManager.instance.fastAddressBook saveContact:_contact]; } - (void)selectContact:(Contact *)acontact andReload:(BOOL)reload { @@ -109,12 +116,11 @@ if (!acontact) { return; } - _tmpContact = [[Contact alloc] initWithPerson:ABPersonCreate()]; - _tmpContact.firstName = acontact.firstName.copy; - _tmpContact.lastName = acontact.lastName.copy; - _tmpContact.sipAddresses = acontact.sipAddresses.copy; - _tmpContact.emails = acontact.emails.copy; - _tmpContact.phoneNumbers = acontact.phoneNumbers.copy; + @synchronized(LinphoneManager.instance.fastAddressBook) { + _tmpContact = [[Contact alloc] + initWithCNContact:[LinphoneManager.instance.fastAddressBook + getCNContactFromContact:acontact]]; + } } - (void)addCurrentContactContactField:(NSString *)address { @@ -140,14 +146,19 @@ - (void)newContact { _isAdding = TRUE; - [self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:YES]; + CNContact *contact = [[CNContact alloc] init]; + [self selectContact:[[Contact alloc] initWithCNContact:contact] + andReload:YES]; } - (void)newContact:(NSString *)address { - [self selectContact:[[Contact alloc] initWithPerson:ABPersonCreate()] andReload:NO]; - [self addCurrentContactContactField:address]; - // force to restart server subscription to add new contact into the list - [LinphoneManager.instance becomeActive]; + CNContact *contact = [[CNContact alloc] init]; + Contact *mContact = [[Contact alloc] initWithCNContact:contact]; + [mContact setSipAddress:address atIndex:0]; + [self selectContact:mContact andReload:NO]; + [self addCurrentContactContactField:address]; + // force to restart server subscription to add new contact into the list + [LinphoneManager.instance becomeActive]; } - (void)editContact:(Contact *)acontact { @@ -258,47 +269,45 @@ [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; nbSipAd++; } - - while (_contact.phoneNumbers.count > 0) { - [_contact removePhoneNumberAtIndex:0]; - - } - NSInteger nbPhone = 0; - while (_tmpContact.phoneNumbers.count> nbPhone) { - [_contact addPhoneNumber:_tmpContact.phoneNumbers[nbPhone]]; - nbPhone++; - } - - while (_contact.emails.count > 0) { - [_contact removeEmailAtIndex:0]; - - } - NSInteger nbEmail = 0; - while (_tmpContact.emails.count> nbEmail) { - [_contact addEmail:_tmpContact.emails[nbEmail]]; - nbEmail++; - } - self.tmpContact = NULL; - [self saveData]; - } - BOOL rm = TRUE; - for (NSString *sip in _contact.sipAddresses) { - if (![sip isEqualToString:@""]) { - rm = FALSE; - break; - } - } - if (rm) { - for (NSString *phone in _contact.phoneNumbers) { - if (![phone isEqualToString:@""]) { - rm = FALSE; - break; - } - } - } - if (rm) { - [LinphoneManager.instance.fastAddressBook removeContact:_contact]; - } + + while (_contact.phones.count > 0) { + [_contact removePhoneNumberAtIndex:0]; + } + NSInteger nbPhone = 0; + while (_tmpContact.phones.count > nbPhone) { + [_contact addPhoneNumber:_tmpContact.phones[nbPhone]]; + nbPhone++; + } + + while (_contact.emails.count > 0) { + [_contact removeEmailAtIndex:0]; + } + NSInteger nbEmail = 0; + while (_tmpContact.emails.count > nbEmail) { + [_contact addEmail:_tmpContact.emails[nbEmail]]; + nbEmail++; + } + self.tmpContact = NULL; + [self saveData]; + } + BOOL rm = TRUE; + for (NSString *sip in _contact.sipAddresses) { + if (![sip isEqualToString:@""]) { + rm = FALSE; + break; + } + } + if (rm) { + for (NSString *phone in _contact.phones) { + if (![phone isEqualToString:@""]) { + rm = FALSE; + break; + } + } + } + if (rm) { + [LinphoneManager.instance.fastAddressBook deleteContact:_contact]; + } } #pragma mark - UICompositeViewDelegate Functions @@ -399,55 +408,60 @@ static UICompositeViewDescription *compositeDescription = nil; [_contact removeSipAddressAtIndex:0]; } NSInteger nbSipAd = 0; - while (_tmpContact.sipAddresses.count > nbSipAd) { - [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; - nbSipAd++; - } - - while (_contact.phoneNumbers.count > 0) { - [_contact removePhoneNumberAtIndex:0]; - } - NSInteger nbPhone = 0; - while (_tmpContact.phoneNumbers.count> nbPhone) { - [_contact addPhoneNumber:_tmpContact.phoneNumbers[nbPhone]]; - nbPhone++; - } - - while (_contact.emails.count > 0) { - [_contact removeEmailAtIndex:0]; - } - NSInteger nbEmail = 0; - while (_tmpContact.emails.count> nbEmail) { - [_contact addEmail:_tmpContact.emails[nbEmail]]; - nbEmail++; - } - [self saveData]; - [self.tableController.tableView reloadData]; - } else { - [LinphoneManager.instance.fastAddressBook removeContact:_contact]; - } - - [self setEditing:FALSE]; - if (IPAD) { - _emptyLabel.hidden = !_isAdding; - _avatarImage.hidden = !_emptyLabel.hidden; - _deleteButton.hidden = !_emptyLabel.hidden; - _editButton.hidden = !_emptyLabel.hidden; - } else { - if (_isAdding) { - [PhoneMainView.instance popCurrentView]; - } else { - _avatarImage.hidden = FALSE; - _deleteButton.hidden = FALSE; - _editButton.hidden = FALSE; - } - } - - self.tmpContact = NULL; - if (_isAdding) { - [PhoneMainView.instance popToView:ContactsListView.compositeViewDescription]; - _isAdding = FALSE; - } + if (_tmpContact.sipAddresses) { + while (_tmpContact.sipAddresses.count > nbSipAd) { + [_contact addSipAddress:_tmpContact.sipAddresses[nbSipAd]]; + nbSipAd++; + } + } + while (_contact.phones.count > 0 && + _contact.phones[0] != NULL) { + [_contact removePhoneNumberAtIndex:0]; + } + NSInteger nbPhone = 0; + if (_tmpContact.phones != NULL) { + while (_tmpContact.phones.count > nbPhone) { + [_contact addPhoneNumber:_tmpContact.phones[nbPhone]]; + nbPhone++; + } + } + while (_contact.emails.count > 0) { + [_contact removeEmailAtIndex:0]; + } + NSInteger nbEmail = 0; + if (_tmpContact.emails != NULL) { + while (_tmpContact.emails.count > nbEmail) { + [_contact addEmail:_tmpContact.emails[nbEmail]]; + nbEmail++; + } + } + // [self saveData]; + } else { + [LinphoneManager.instance.fastAddressBook deleteContact:_contact]; + } + + [self setEditing:FALSE]; + if (IPAD) { + _emptyLabel.hidden = !_isAdding; + _avatarImage.hidden = !_emptyLabel.hidden; + _deleteButton.hidden = !_emptyLabel.hidden; + _editButton.hidden = !_emptyLabel.hidden; + } else { + if (_isAdding) { + [PhoneMainView.instance popCurrentView]; + } else { + _avatarImage.hidden = FALSE; + _deleteButton.hidden = FALSE; + _editButton.hidden = FALSE; + } + } + + self.tmpContact = NULL; + if (_isAdding) { + [PhoneMainView.instance + popToView:ContactsListView.compositeViewDescription]; + _isAdding = FALSE; + } } - (IBAction)onBackClick:(id)event { diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 21b045b35..a9c8b55b4 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -29,10 +29,16 @@ - (void)initContactsTableViewController { addressBookMap = [[OrderedDictionary alloc] init]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:CNContactStoreDidChangeNotification + object:nil]; } - (void)onAddressBookUpdate:(NSNotification *)k { @@ -104,7 +110,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } - (NSString *)displayNameForContact:(Contact *)person { - NSString *name = [FastAddressBook displayNameForContact:person]; + NSString *name = person.displayName; if (name != nil && [name length] > 0 && ![name isEqualToString:NSLocalizedString(@"Unknown", nil)]) { // Add the contact only if it fuzzy match filter too (if any) if ([ContactSelection getNameOrEmailFilter] == nil || @@ -124,77 +130,83 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { - (void)loadData { _ongoing = TRUE; LOGI(@"Load contact list"); - @synchronized(addressBookMap) { - //Set all contacts from ContactCell to nil - for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j) - { - for (NSInteger i = 0; i < [self.tableView numberOfRowsInSection:j]; ++i) + NSString* previous = [PhoneMainView.instance getPreviousViewName]; + addressBookMap = [LinphoneManager.instance getLinphoneManagerAddressBookMap]; + BOOL updated = [LinphoneManager.instance getContactsUpdated]; + if(([previous isEqualToString:@"ContactsDetailsView"] && updated) || updated || [addressBookMap count] == 0){ + [LinphoneManager.instance setContactsUpdated:FALSE]; + @synchronized(addressBookMap) { + //Set all contacts from ContactCell to nil + for (NSInteger j = 0; j < [self.tableView numberOfSections]; ++j) { - [[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]] setContact:nil]; - } - } - - // Reset Address book - [addressBookMap removeAllObjects]; - - for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; - BOOL add = true; - - // Do not add the contact directly if we set some filter - if ([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) { - add = false; - } - if ([FastAddressBook contactHasValidSipDomain:contact]) { - add = true; - } - if (contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(contact.friend)) == LinphonePresenceBasicStatusOpen){ - add = true; + for (NSInteger i = 0; i < [self.tableView numberOfRowsInSection:j]; ++i) + { + [[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]] setContact:nil]; + } } - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } + // Reset Address book + [addressBookMap removeAllObjects]; + for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = nil; + @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { + contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; + } + BOOL add = true; + // Do not add the contact directly if we set some filter + if ([ContactSelection getSipFilter] || + [ContactSelection emailFilterEnabled]) { + add = false; + }else if ([FastAddressBook contactHasValidSipDomain:contact]) { + add = true; + }else if (contact.friend && + linphone_presence_model_get_basic_status( + linphone_friend_get_presence_model( + contact.friend)) == + LinphonePresenceBasicStatusOpen) { + add = true; + } - NSMutableString *name = [self displayNameForContact:contact] - ? [[NSMutableString alloc] initWithString:[self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - NSString *firstChar = [[name substringToIndex:1] uppercaseString]; + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } - // Put in correct subAr - if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') { - firstChar = @"#"; - } - NSMutableArray *subAr = [addressBookMap objectForKey:firstChar]; - if (subAr == nil) { - subAr = [[NSMutableArray alloc] init]; - [addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)]; - } - NSUInteger idx = [subAr indexOfObject:contact - inSortedRange:(NSRange){0, subAr.count} - options:NSBinarySearchingInsertionIndex - usingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; - if (![subAr containsObject:contact]) { - [subAr insertObject:contact atIndex:idx]; + NSMutableString *name = [self displayNameForContact:contact] ? [[NSMutableString alloc] initWithString: [self displayNameForContact:contact]] : nil; + if (add && name != nil) { + NSString *firstChar = [[name substringToIndex:1] uppercaseString]; + // Put in correct subAr + if ([firstChar characterAtIndex:0] < 'A' || [firstChar characterAtIndex:0] > 'Z') { + firstChar = @"#"; + } + NSMutableArray *subAr = [addressBookMap objectForKey:firstChar]; + if (subAr == nil) { + subAr = [[NSMutableArray alloc] init]; + [addressBookMap insertObject:subAr forKey:firstChar selector:@selector(caseInsensitiveCompare:)]; + } + NSUInteger idx = [subAr indexOfObject:contact inSortedRange:(NSRange){0, subAr.count} options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult( Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2] options:NSCaseInsensitiveSearch]; + }]; + if (![subAr containsObject:contact]) { + [subAr insertObject:contact atIndex:idx]; + } } + //} } + [super loadData]; + + // since we refresh the tableview, we must perform this on main + // thread + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (IPAD) { + if (!([self totalNumberOfItems] > 0)) { + ContactDetailsView *view = VIEW(ContactDetailsView); + [view setContact:nil]; + } + } + }); } - [super loadData]; - - // since we refresh the tableview, we must perform this on main thread - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (IPAD) { - if (!([self totalNumberOfItems] > 0)) { - ContactDetailsView *view = VIEW(ContactDetailsView); - [view setContact:nil]; - } - } - }); + [LinphoneManager.instance setLinphoneManagerAddressBookMap:addressBookMap]; } _ongoing = FALSE; } @@ -218,66 +230,94 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { NSMutableArray *subArContain = [NSMutableArray new]; [addressBookMap insertObject:subAr forKey:@"" selector:@selector(caseInsensitiveCompare:)]; for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; - BOOL add = true; - // Do not add the contact directly if we set some filter - if ([ContactSelection getSipFilter] || [ContactSelection emailFilterEnabled]) { - add = false; - } - NSString* filter = [ContactSelection getNameOrEmailFilter]; - if ([FastAddressBook contactHasValidSipDomain:contact]) { - add = true; - } - if (contact.friend && linphone_presence_model_get_basic_status(linphone_friend_get_presence_model(contact.friend)) == LinphonePresenceBasicStatusOpen){ - add = true; - } - - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } - NSInteger idx_begin = -1; - NSInteger idx_sort = - 1; - NSMutableString *name = [self displayNameForContact:contact] - ? [[NSMutableString alloc] initWithString:[self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - if ([[contact displayName] rangeOfString:filter options:NSCaseInsensitiveSearch].location == 0) { - if(![subArBegin containsObject:contact]) { - idx_begin = idx_begin + 1; - [subArBegin insertObject:contact atIndex:idx_begin]; - } - } else if([[contact displayName] rangeOfString:filter options:NSCaseInsensitiveSearch].location != NSNotFound) { - if(![subArContain containsObject:contact]) { - idx_sort = idx_sort + 1; - [subArContain insertObject:contact atIndex:idx_sort]; - } - } - } - } - [subArBegin sortUsingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; - - [subArContain sortUsingComparator:^NSComparisonResult(Contact* _Nonnull obj1, Contact* _Nonnull obj2) { - return [[self displayNameForContact:obj1] compare:[self displayNameForContact:obj2]options:NSCaseInsensitiveSearch]; - }]; + @synchronized( + LinphoneManager.instance.fastAddressBook.addressBookMap) { + Contact *contact = + [LinphoneManager.instance.fastAddressBook.addressBookMap + objectForKey:addr]; - [subAr addObjectsFromArray:subArBegin]; - [subAr addObjectsFromArray:subArContain]; - [super loadData]; - - // since we refresh the tableview, we must perform this on main thread - dispatch_async(dispatch_get_main_queue(), ^(void) { - if (IPAD) { - if (!([self totalNumberOfItems] > 0)) { - ContactDetailsView *view = VIEW(ContactDetailsView); - [view setContact:nil]; - } - } - }); - } + BOOL add = true; + // Do not add the contact directly if we set some filter + if ([ContactSelection getSipFilter] || + [ContactSelection emailFilterEnabled]) { + add = false; + } + NSString *filter = [ContactSelection getNameOrEmailFilter]; + if ([FastAddressBook contactHasValidSipDomain:contact]) { + add = true; + } + if (contact.friend && + linphone_presence_model_get_basic_status( + linphone_friend_get_presence_model( + contact.friend)) == + LinphonePresenceBasicStatusOpen) { + add = true; + } + + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } + NSInteger idx_begin = -1; + NSInteger idx_sort = -1; + NSMutableString *name = + [self displayNameForContact:contact] + ? [[NSMutableString alloc] + initWithString: + [self displayNameForContact:contact]] + : nil; + if (add && name != nil) { + if ([[contact displayName] + rangeOfString:filter + options:NSCaseInsensitiveSearch] + .location == 0) { + if (![subArBegin containsObject:contact]) { + idx_begin = idx_begin + 1; + [subArBegin insertObject:contact atIndex:idx_begin]; + } + } else if ([[contact displayName] + rangeOfString:filter + options:NSCaseInsensitiveSearch] + .location != NSNotFound) { + if (![subArContain containsObject:contact]) { + idx_sort = idx_sort + 1; + [subArContain insertObject:contact atIndex:idx_sort]; + } + } + } + } + } + [subArBegin + sortUsingComparator:^NSComparisonResult( + Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] + compare:[self displayNameForContact:obj2] + options:NSCaseInsensitiveSearch]; + }]; + + [subArContain + sortUsingComparator:^NSComparisonResult( + Contact *_Nonnull obj1, Contact *_Nonnull obj2) { + return [[self displayNameForContact:obj1] + compare:[self displayNameForContact:obj2] + options:NSCaseInsensitiveSearch]; + }]; + + [subAr addObjectsFromArray:subArBegin]; + [subAr addObjectsFromArray:subArContain]; + [super loadData]; + + // since we refresh the tableview, we must perform this on main + // thread + dispatch_async(dispatch_get_main_queue(), ^(void) { + if (IPAD) { + if (!([self totalNumberOfItems] > 0)) { + ContactDetailsView *view = VIEW(ContactDetailsView); + [view setContact:nil]; + } + } + }); + } } @@ -365,17 +405,23 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } UIContactCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell setContact:NULL]; - [[LinphoneManager.instance fastAddressBook] removeContact:contact]; - [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] - withRowAnimation:UITableViewRowAnimationFade]; - [tableView endUpdates]; + [[LinphoneManager.instance fastAddressBook] + deleteContact:contact]; + [tableView + deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] + withRowAnimation:UITableViewRowAnimationFade]; + [tableView endUpdates]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; - [self loadData]; - } + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; + dispatch_async(dispatch_get_main_queue(), + ^{ + [self loadData]; + }); + } } - (void)removeSelectionUsing:(void (^)(NSIndexPath *))remover { @@ -391,12 +437,13 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { } UIContactCell* cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell setContact:NULL]; - [[LinphoneManager.instance fastAddressBook] removeContact:contact]; + [[LinphoneManager.instance fastAddressBook] deleteContact:contact]; - [NSNotificationCenter.defaultCenter addObserver:self - selector:@selector(onAddressBookUpdate:) - name:kLinphoneAddressBookUpdate - object:nil]; + [NSNotificationCenter.defaultCenter + addObserver:self + selector:@selector(onAddressBookUpdate:) + name:kLinphoneAddressBookUpdate + object:nil]; }]; } diff --git a/Classes/ContactsListView.m b/Classes/ContactsListView.m index a102d74b9..ea3c5b52b 100644 --- a/Classes/ContactsListView.m +++ b/Classes/ContactsListView.m @@ -158,6 +158,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)changeView:(ContactsCategory)view { CGRect frame = _selectedButtonImage.frame; if (view == ContactsAll && !allButton.selected) { + [LinphoneManager.instance setContactsUpdated:TRUE]; frame.origin.x = allButton.frame.origin.x; [ContactSelection setSipFilter:nil]; [ContactSelection enableEmailFilter:FALSE]; @@ -165,6 +166,7 @@ static UICompositeViewDescription *compositeDescription = nil; linphoneButton.selected = FALSE; [tableController loadData]; } else if (view == ContactsLinphone && !linphoneButton.selected) { + [LinphoneManager.instance setContactsUpdated:TRUE]; frame.origin.x = linphoneButton.frame.origin.x; [ContactSelection setSipFilter:LinphoneManager.instance.contactFilter]; [ContactSelection enableEmailFilter:FALSE]; diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 0971fbe02..442de7ffb 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -91,47 +91,56 @@ if (PhoneMainView.instance.currentView == ContactsListView.compositeViewDescription || PhoneMainView.instance.currentView == ContactDetailsView.compositeViewDescription) { [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription]; } - [instance.fastAddressBook reload]; - instance.fastAddressBook.needToUpdate = FALSE; - const MSList *lists = linphone_core_get_friends_lists(LC); - while (lists) { - linphone_friend_list_update_subscriptions(lists->data); - lists = lists->next; - } - } + [instance.fastAddressBook fetchContactsInBackGroundThread]; + instance.fastAddressBook.needToUpdate = FALSE; + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + linphone_friend_list_update_subscriptions(lists->data); + lists = lists->next; + } + } - LinphoneCall *call = linphone_core_get_current_call(LC); + LinphoneCall *call = linphone_core_get_current_call(LC); - if (call) { - if (call == instance->currentCallContextBeforeGoingBackground.call) { - const LinphoneCallParams *params = linphone_call_get_current_params(call); - if (linphone_call_params_video_enabled(params)) { - linphone_call_enable_camera(call, instance->currentCallContextBeforeGoingBackground.cameraIsEnabled); - } - instance->currentCallContextBeforeGoingBackground.call = 0; - } else if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) { - LinphoneCallAppData *data = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call); - if (data && data->timer) { - [data->timer invalidate]; - data->timer = nil; - } - if ((floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_9_x_Max)) { - if ([LinphoneManager.instance lpConfigBoolForKey:@"autoanswer_notif_preference"]) { - linphone_call_accept(call); - [PhoneMainView.instance changeCurrentView:CallView.compositeViewDescription]; - } else { - [PhoneMainView.instance displayIncomingCall:call]; - } - } else if (linphone_core_get_calls_nb(LC) > 1) { - [PhoneMainView.instance displayIncomingCall:call]; - } + if (call) { + if (call == instance->currentCallContextBeforeGoingBackground.call) { + const LinphoneCallParams *params = + linphone_call_get_current_params(call); + if (linphone_call_params_video_enabled(params)) { + linphone_call_enable_camera( + call, instance->currentCallContextBeforeGoingBackground + .cameraIsEnabled); + } + instance->currentCallContextBeforeGoingBackground.call = 0; + } else if (linphone_call_get_state(call) == + LinphoneCallIncomingReceived) { + LinphoneCallAppData *data = + (__bridge LinphoneCallAppData *)linphone_call_get_user_data( + call); + if (data && data->timer) { + [data->timer invalidate]; + data->timer = nil; + } + if ((floor(NSFoundationVersionNumber) <= + NSFoundationVersionNumber_iOS_9_x_Max)) { + if ([LinphoneManager.instance + lpConfigBoolForKey:@"autoanswer_notif_preference"]) { + linphone_call_accept(call); + [PhoneMainView.instance + changeCurrentView:CallView.compositeViewDescription]; + } else { + [PhoneMainView.instance displayIncomingCall:call]; + } + } else if (linphone_core_get_calls_nb(LC) > 1) { + [PhoneMainView.instance displayIncomingCall:call]; + } - // in this case, the ringing sound comes from the notification. - // To stop it we have to do the iOS7 ring fix... - [self fixRing]; - } - } - [LinphoneManager.instance.iapManager check]; + // in this case, the ringing sound comes from the notification. + // To stop it we have to do the iOS7 ring fix... + [self fixRing]; + } + } + [LinphoneManager.instance.iapManager check]; } #pragma deploymate push "ignored-api-availability" @@ -978,7 +987,7 @@ didInvalidatePushTokenForType:(NSString *)type { linphone_core_set_provisioning_uri(LC, [configURL UTF8String]); [LinphoneManager.instance destroyLinphoneCore]; [LinphoneManager.instance startLinphoneCore]; - [LinphoneManager.instance.fastAddressBook reload]; + [LinphoneManager.instance.fastAddressBook fetchContactsInBackGroundThread]; } #pragma mark - Prevent ImagePickerView from rotating diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 012fac885..3d4659bc6 100644 --- a/Classes/LinphoneCoreSettingsStore.m +++ b/Classes/LinphoneCoreSettingsStore.m @@ -636,7 +636,7 @@ } } // reload address book to prepend proxy config domain to contacts' phone number - [[LinphoneManager.instance fastAddressBook] reload]; + [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread]; } - (void)synchronizeCodecs:(const MSList *)codecs { @@ -722,34 +722,27 @@ NSString *videoPreset = [self stringForKey:@"video_preset_preference"]; linphone_core_set_video_preset(LC, [videoPreset UTF8String]); - int bw; MSVideoSize vsize; switch ([self integerForKey:@"video_preferred_size_preference"]) { case 0: MS_VIDEO_SIZE_ASSIGN(vsize, 720P); - // 128 = margin for audio, the BW includes both video and audio - bw = 1024 + 128; break; case 1: MS_VIDEO_SIZE_ASSIGN(vsize, VGA); - // no margin for VGA or QVGA, because video encoders can encode the - // target resulution in less than the asked bandwidth - bw = 660; break; case 2: default: MS_VIDEO_SIZE_ASSIGN(vsize, QVGA); - bw = 380; break; } linphone_core_set_preferred_video_size(LC, vsize); if (![videoPreset isEqualToString:@"custom"]) { [self setInteger:0 forKey:@"video_preferred_fps_preference"]; - [self setInteger:bw forKey:@"download_bandwidth_preference"]; + [self setInteger:0 forKey:@"download_bandwidth_preference"]; } linphone_core_set_preferred_framerate(LC, [self integerForKey:@"video_preferred_fps_preference"]); - linphone_core_set_download_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); - linphone_core_set_upload_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); + linphone_core_set_download_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); + linphone_core_set_upload_bandwidth(LC, [self integerForKey:@"download_bandwidth_preference"]); } // call section diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 67d1114f2..7f5f66259 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -33,7 +33,7 @@ #include "linphone/linphonecore.h" #include "bctoolbox/list.h" - +#import "OrderedDictionary.h" #import "ProviderDelegate.h" extern NSString *const LINPHONERC_APPLICATION_KEY; @@ -197,6 +197,13 @@ typedef struct _LinphoneManagerSounds { - (void)shouldPresentLinkPopup; - (void)setProviderDelegate:(ProviderDelegate *)del; + +- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook; +- (OrderedDictionary*) getLinphoneManagerAddressBookMap; + +- (void) setContactsUpdated:(BOOL) updated; +- (BOOL) getContactsUpdated; + @property ProviderDelegate *providerDelegate; @property (readonly) BOOL isTesting; @@ -225,5 +232,7 @@ typedef struct _LinphoneManagerSounds { @property BOOL nextCallIsTransfer; @property BOOL conf; @property NSDictionary *pushDict; +@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap; +@property (nonatomic, assign) BOOL contactsUpdated; @end diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 9fa6c114d..ea1b8370f 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -83,6 +83,7 @@ extern void libmsx264_init(MSFactory *factory); extern void libmsopenh264_init(MSFactory *factory); extern void libmssilk_init(MSFactory *factory); extern void libmswebrtc_init(MSFactory *factory); +extern void libmscodec2_init(MSFactory *factory); #define FRONT_CAM_NAME \ "AV Capture: com.apple.avfoundation.avcapturedevice.built-in_video:1" /*"AV Capture: Front Camera"*/ @@ -141,6 +142,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre {"mpeg4-generic", 48000, "aaceld_48k_preference"}, {"opus", 48000, "opus_preference"}, {"BV16", 8000, "bv16_preference"}, + {"CODEC2", 8000, "codec2_preference"}, {NULL, 0, Nil}}; + (NSString *)getPreferenceForCodec:(const char *)name withRate:(int)rate { @@ -257,7 +259,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre _bluetoothEnabled = FALSE; _conf = FALSE; _fileTransferDelegates = [[NSMutableArray alloc] init]; - + _linphoneManagerAddressBookMap = [[OrderedDictionary alloc] init]; pushCallIDs = [[NSMutableArray alloc] init]; _photoLibrary = [[ALAssetsLibrary alloc] init]; _isTesting = [LinphoneManager isRunningTests]; @@ -292,6 +294,23 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre [NSNotificationCenter.defaultCenter removeObserver:self]; } +#pragma mark - AddressBookMap + +- (void) setLinphoneManagerAddressBookMap:(OrderedDictionary*) addressBook{ + _linphoneManagerAddressBookMap = addressBook; +} + +- (OrderedDictionary*) getLinphoneManagerAddressBookMap{ + return _linphoneManagerAddressBookMap; +} + +- (void) setContactsUpdated:(BOOL) updated{ + _contactsUpdated = updated; +} +- (BOOL) getContactsUpdated{ + return _contactsUpdated; +} + #pragma deploymate push "ignored-api-availability" - (void)silentPushFailed:(NSTimer *)timer { if (_silentPushCompletion) { @@ -580,7 +599,7 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char video = ([UIApplication sharedApplication].applicationState == UIApplicationStateActive && linphone_core_get_video_policy(LC)->automatically_accept && linphone_call_params_video_enabled(linphone_call_get_remote_params(call))); - [LinphoneManager.instance.providerDelegate reportIncomingCallwithUUID:uuid handle:address video:video]; + [LinphoneManager.instance.providerDelegate reportIncomingCall:call withUUID:uuid handle:address video:video]; #else [PhoneMainView.instance displayIncomingCall:call]; #endif @@ -697,8 +716,6 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char // furthermore it introduces a bug when calling multiple times since route may not be // reconfigured between cause leading to bluetooth being disabled while it should not _bluetoothEnabled = FALSE; - /*IOS specific*/ - linphone_core_start_dtmf_stream(theLinphoneCore); } if (incallBgTask) { @@ -1983,6 +2000,8 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat libmsx264_init(f); libmsopenh264_init(f); libmswebrtc_init(f); + libmscodec2_init(f); + linphone_core_reload_ms_plugins(theLinphoneCore, NULL); [self migrationAllPost]; @@ -2052,10 +2071,10 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat [self destroyLinphoneCore]; [self createLinphoneCore]; // reload friends - [self.fastAddressBook reload]; + [self.fastAddressBook fetchContactsInBackGroundThread]; - // reset network state to trigger a new network connectivity assessment - linphone_core_set_network_reachable(theLinphoneCore, FALSE); + // reset network state to trigger a new network connectivity assessment + linphone_core_set_network_reachable(theLinphoneCore, FALSE); } static int comp_call_id(const LinphoneCall *call, const char *callid) { diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings index bbc940d42..ba11c1c50 100644 Binary files a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings and b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.strings differ diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib index 409ea31d6..f6e957883 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib @@ -1,11 +1,11 @@ - - + + - + @@ -26,7 +26,6 @@ - @@ -113,11 +112,6 @@ - - - - - @@ -163,7 +157,6 @@ - @@ -172,9 +165,4 @@ - - - - - diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.strings b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.strings index 36cc75de9..473d68b03 100644 Binary files a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.strings and b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.strings differ diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib index b37bdc9a4..f9eca9b79 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib @@ -20,17 +20,10 @@ - - - - - - - @@ -59,11 +52,6 @@ - - - - - @@ -94,12 +82,11 @@ - + + + - - - @@ -110,7 +97,6 @@ - diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index 719df4a63..c7b3cda28 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -179,7 +179,7 @@ } else if (_cancelButton.hidden == NO) { [self onCancelClick:event]; } else { - [super onResendClick:event]; + [super onResend]; } } diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h index c9836f5d8..75e8db501 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.h +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h @@ -30,7 +30,6 @@ @property(nonatomic, weak) IBOutlet UIImageView *backgroundColorImage; @property(nonatomic, weak) IBOutlet UIRoundedImageView *avatarImage; @property(nonatomic, weak) IBOutlet UILabel *contactDateLabel; -@property(nonatomic, weak) IBOutlet UIImageView *statusErrorImage; @property(weak, nonatomic) IBOutlet UIActivityIndicatorView *statusInProgressSpinner; @property(nonatomic, weak) IBOutlet UITextViewNoDefine *messageText; @property(weak, nonatomic) IBOutlet UIImageView *bottomBarColor; @@ -46,8 +45,9 @@ - (void)setEvent:(LinphoneEventLog *)event; - (void)setChatMessage:(LinphoneChatMessage *)message; -- (IBAction)onDeleteClick:(id)event; -- (IBAction)onResendClick:(id)event; +- (void)onDelete; +- (void)onResend; +- (void)onLime; - (void)update; - (void)displayImdmStatus:(LinphoneChatMessageState)state; diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m index 0285e557c..bd110792b 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.m +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m @@ -40,6 +40,23 @@ [self addSubview:sub]; } } + + UITapGestureRecognizer *limeRecognizer = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onLime)]; + limeRecognizer.numberOfTapsRequired = 1; + [_LIMEKO addGestureRecognizer:limeRecognizer]; + _LIMEKO.userInteractionEnabled = YES; + UITapGestureRecognizer *resendRecognizer = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)]; + resendRecognizer.numberOfTapsRequired = 1; + [_imdmIcon addGestureRecognizer:resendRecognizer]; + _imdmIcon.userInteractionEnabled = YES; + UITapGestureRecognizer *resendRecognizer2 = + [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)]; + resendRecognizer2.numberOfTapsRequired = 1; + [_imdmLabel addGestureRecognizer:resendRecognizer2]; + _imdmLabel.userInteractionEnabled = YES; + return self; } @@ -150,13 +167,10 @@ _contactDateLabel.textColor = [UIColor colorWithPatternImage:_backgroundColorImage.image]; if (outgoing && state == LinphoneChatMessageStateInProgress) { - _statusErrorImage.hidden = YES; [_statusInProgressSpinner startAnimating]; } else if (!outgoing && state == LinphoneChatMessageStateFileTransferError) { - _statusErrorImage.hidden = NO; [_statusInProgressSpinner stopAnimating]; } else { - _statusErrorImage.hidden = YES; [_statusInProgressSpinner stopAnimating]; } @@ -210,7 +224,7 @@ #pragma mark - Action Functions -- (IBAction)onDeleteClick:(id)event { +- (void)onDelete { if (_message != NULL) { UITableView *tableView = VIEW(ChatConversationView).tableController.tableView; NSIndexPath *indexPath = [tableView indexPathForCell:self]; @@ -220,45 +234,42 @@ } } -- (IBAction)onResendClick:(id)event { - if (!_LIMEKO.hidden) { +- (void)onLime { + if (!_LIMEKO.hidden) [self displayLIMEWarning]; - return; - } +} +- (void)onResend { if (_message == nil || !linphone_chat_message_is_outgoing(_message)) return; LinphoneChatMessageState state = linphone_chat_message_get_state(_message); - if (state == LinphoneChatMessageStateNotDelivered || state == LinphoneChatMessageStateFileTransferError) { - if (linphone_chat_message_get_file_transfer_information(_message) != NULL) { - NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message]; - NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message]; - - NSURL *imageUrl = [NSURL URLWithString:localImage]; + if (state != LinphoneChatMessageStateNotDelivered && state != LinphoneChatMessageStateFileTransferError) + return; - [self onDeleteClick:nil]; - - [LinphoneManager.instance.photoLibrary assetForURL:imageUrl - resultBlock:^(ALAsset *asset) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), - ^(void) { - UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; - [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; - }); - } - failureBlock:^(NSError *error) { - LOGE(@"Can't read image"); - }]; - } else { - [self onDeleteClick:nil]; - - double delayInSeconds = 0.4; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { - [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; - }); - } + if (linphone_chat_message_get_file_transfer_information(_message) != NULL) { + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message]; + NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message]; + NSURL *imageUrl = [NSURL URLWithString:localImage]; + [self onDelete]; + [LinphoneManager.instance.photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]]; + [_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)]; + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } else { + [self onDelete]; + double delayInSeconds = 0.4; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { + [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil]; + }); } } #pragma mark - State changed handling diff --git a/Classes/LinphoneUI/UISpeakerButton.m b/Classes/LinphoneUI/UISpeakerButton.m index b845885fe..54985014d 100644 --- a/Classes/LinphoneUI/UISpeakerButton.m +++ b/Classes/LinphoneUI/UISpeakerButton.m @@ -42,7 +42,8 @@ INIT_WITH_COMMON_CF { #pragma mark - UIToggleButtonDelegate Functions - (void)audioRouteChangeListenerCallback:(NSNotification *)notif { - [self update]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self update];}); } - (void)onOn { diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h index c8254fa4f..c50068483 100644 --- a/Classes/PhoneMainView.h +++ b/Classes/PhoneMainView.h @@ -82,6 +82,7 @@ @property(nonatomic, strong) IBOutlet UICompositeView *mainViewController; @property(nonatomic, strong) NSString *currentName; +@property(nonatomic, strong) NSString *previousView; @property(nonatomic, strong) NSString *name; @property(weak, readonly) UICompositeViewDescription *currentView; @property LinphoneChatRoom* currentRoom; @@ -91,6 +92,9 @@ - (void)changeCurrentView:(UICompositeViewDescription *)view; - (UIViewController*)popCurrentView; - (UIViewController *)popToView:(UICompositeViewDescription *)currentView; +- (void) setPreviousViewName:(NSString*)previous; +- (NSString*) getPreviousViewName; ++ (NSString*) getPreviousViewName; - (UICompositeViewDescription *)firstView; - (void)hideStatusBar:(BOOL)hide; - (void)hideTabBar:(BOOL)hide; diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index ab6c95b36..5cf6497cb 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -128,6 +128,7 @@ static RootViewManager *rootViewManagerInstance = nil; currentView = nil; _currentRoom = NULL; _currentName = NULL; + _previousView = nil; inhibitedEvents = [[NSMutableArray alloc] init]; } @@ -656,6 +657,7 @@ static RootViewManager *rootViewManagerInstance = nil; PhoneMainView *vc = [[RootViewManager instance] setViewControllerForDescription:view]; if (![view equal:vc.currentView] || vc != self) { LOGI(@"Change current view to %@", view.name); + [self setPreviousViewName:vc.currentView.name]; NSMutableArray *viewStack = [RootViewManager instance].viewDescriptionStack; [viewStack addObject:view]; if (animated && transition == nil) @@ -682,6 +684,19 @@ static RootViewManager *rootViewManagerInstance = nil; return [self _changeCurrentView:view transition:[PhoneMainView getBackwardTransition] animated:ANIMATED]; } +- (void) setPreviousViewName:(NSString*)previous{ + _previousView = previous; +} + +- (NSString*) getPreviousViewName { + return _previousView; +} + ++ (NSString*) getPreviousViewName { + return [self getPreviousViewName]; +} + + - (UICompositeViewDescription *)firstView { UICompositeViewDescription *view = nil; NSArray *viewStack = [RootViewManager instance].viewDescriptionStack; diff --git a/Classes/ProviderDelegate.h b/Classes/ProviderDelegate.h index 488a4316e..964aac680 100644 --- a/Classes/ProviderDelegate.h +++ b/Classes/ProviderDelegate.h @@ -23,7 +23,7 @@ @property BOOL pendingCallVideo; @property int callKitCalls; -- (void)reportIncomingCallwithUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; +- (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; - (void)config; - (void)configAudioSession:(AVAudioSession *)audioSession; @end diff --git a/Classes/ProviderDelegate.m b/Classes/ProviderDelegate.m index 3479aaaee..276273131 100644 --- a/Classes/ProviderDelegate.m +++ b/Classes/ProviderDelegate.m @@ -71,7 +71,7 @@ } } -- (void)reportIncomingCallwithUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video { +- (void)reportIncomingCall:(LinphoneCall *) call withUUID:(NSUUID *)uuid handle:(NSString *)handle video:(BOOL)video; { // Create update to describe the incoming call and caller CXCallUpdate *update = [[CXCallUpdate alloc] init]; update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle]; @@ -80,13 +80,24 @@ update.supportsGrouping = TRUE; update.supportsUngrouping = TRUE; update.hasVideo = video; - + linphone_call_ref(call); // Report incoming call to system LOGD(@"CallKit: report new incoming call"); + [self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError *error) { - }]; + if (error) { + LOGE(@"CallKit: cannot complete incoming call from [%@] caused by [%@]",handle,[error localizedDescription]); + if ( [error code] == CXErrorCodeIncomingCallErrorFilteredByDoNotDisturb + || [error code] == CXErrorCodeIncomingCallErrorFilteredByBlockList) { + linphone_call_decline(call,LinphoneReasonBusy); /*to give a chance for other devices to answer*/ + } else { + linphone_call_decline(call,LinphoneReasonUnknown); + } + } + linphone_call_unref(call); + }]; } - (void)setPendingCall:(LinphoneCall *)pendingCall { @@ -198,11 +209,12 @@ LinphoneManager.instance.speakerBeforePause = LinphoneManager.instance.speakerEnabled; linphone_call_pause((LinphoneCall *)call); } else { - [self configAudioSession:[AVAudioSession sharedInstance]]; + if (linphone_core_get_conference(LC)) { linphone_core_enter_conference(LC); [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneCallUpdate object:self]; } else { + [self configAudioSession:[AVAudioSession sharedInstance]]; self.pendingCall = call; } } diff --git a/Classes/SideMenuTableView.m b/Classes/SideMenuTableView.m index 0f7e82630..223908d4e 100644 --- a/Classes/SideMenuTableView.m +++ b/Classes/SideMenuTableView.m @@ -6,6 +6,8 @@ // // +#import "linphone/core_utils.h" + #import "SideMenuTableView.h" #import "Utils.h" @@ -37,7 +39,7 @@ } - (void)viewWillAppear:(BOOL)animated { - linphone_core_stop_dtmf(LC); + linphone_core_stop_dtmf_stream(LC); [super viewWillAppear:animated]; _sideMenuEntries = [[NSMutableArray alloc] init]; diff --git a/Classes/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 4db2bebe4..2c7224830 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -28,16 +28,19 @@ @property(readonly, nonatomic) NSMutableDictionary *addressBookMap; @property BOOL needToUpdate; -- (void)reload; -- (void)saveAddressBook; -- (int)removeContact:(Contact *)contact; +- (void) fetchContactsInBackGroundThread; +- (BOOL)deleteContact:(Contact *)contact; +- (BOOL)deleteCNContact:(CNContact *)CNContact; +- (BOOL)deleteAllContacts; - (BOOL)saveContact:(Contact *)contact; +- (BOOL)saveCNContact:(CNContact *)CNContact contact:(Contact *)Contact; + (BOOL)isAuthorized; // TOOLS + (Contact *)getContactWithAddress:(const LinphoneAddress *)address; +- (CNContact *)getCNContactFromContact:(Contact *)acontact; + (UIImage *)imageForContact:(Contact *)contact; + (UIImage *)imageForAddress:(const LinphoneAddress *)addr; @@ -52,5 +55,6 @@ + (NSString *)normalizeSipURI:(NSString *)address; // should be removed + (NSString *)localizedLabel:(NSString *)label; +- (void)registerAddrsFor:(Contact *)contact; @end diff --git a/Classes/Utils/FastAddressBook.m b/Classes/Utils/FastAddressBook.m index e9cf29f9d..23a47cb51 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -25,12 +25,9 @@ #import "Utils.h" @implementation FastAddressBook { - ABAddressBookRef addressBook; CNContactStore* store; } -static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context); - + (UIImage *)imageForContact:(Contact *)contact { @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { UIImage *retImage = [contact avatar]; @@ -57,7 +54,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info return [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:address]; } } - return nil; + return nil; } + (Contact *)getContactWithAddress:(const LinphoneAddress *)address { @@ -94,8 +91,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info + (NSString *)normalizeSipURI:(NSString *)address { // replace all whitespaces (non-breakable, utf8 nbsp etc.) by the "classical" whitespace - NSString *normalizedSipAddress = [[address - componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@" "]; + NSString *normalizedSipAddress = nil; LinphoneAddress *addr = linphone_core_interpret_url(LC, [address UTF8String]); if (addr != NULL) { linphone_address_clean(addr); @@ -103,72 +99,92 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info normalizedSipAddress = [NSString stringWithUTF8String:tmp]; ms_free(tmp); linphone_address_destroy(addr); + return normalizedSipAddress; + }else { + normalizedSipAddress = [[address componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@" "]; + return normalizedSipAddress; } - return normalizedSipAddress; } + (BOOL)isAuthorized { - return ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized; + return [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; } - (FastAddressBook *)init { if ((self = [super init]) != nil) { + store = [[CNContactStore alloc] init]; _addressBookMap = [NSMutableDictionary dictionary]; - addressBook = nil; - [self reload]; } self.needToUpdate = FALSE; - if ([CNContactStore class]) { - //ios9 or later - CNEntityType entityType = CNEntityTypeContacts; - if([CNContactStore authorizationStatusForEntityType:entityType] == CNAuthorizationStatusNotDetermined) { - CNContactStore * contactStore = [[CNContactStore alloc] init]; - LOGD(@"CNContactStore requesting authorization"); - [contactStore requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError * _Nullable error) { - LOGD(@"CNContactStore authorization granted"); - }]; - } else if([CNContactStore authorizationStatusForEntityType:entityType]== CNAuthorizationStatusAuthorized) { - LOGD(@"CNContactStore authorization granted"); + if (floor(NSFoundationVersionNumber) >= NSFoundationVersionNumber_iOS_9_x_Max) { + if ([CNContactStore class]) { + // ios9 or later + if (store == NULL) + store = [[CNContactStore alloc] init]; + [self fetchContactsInBackGroundThread]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; } - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; } - return self; } -- (void)saveAddressBook { - if (addressBook != nil) { - if (!ABAddressBookSave(addressBook, nil)) { - LOGW(@"Couldn't save Address Book"); +- (void) fetchContactsInBackGroundThread{ + + CNEntityType entityType = CNEntityTypeContacts; + [store requestAccessForEntityType:entityType completionHandler:^(BOOL granted, NSError *_Nullable error) { + BOOL success = FALSE; + if(granted){ + LOGD(@"CNContactStore authorization granted"); + + NSError *contactError; + CNContactStore* store = [[CNContactStore alloc] init]; + [store containersMatchingPredicate:[CNContainer predicateForContainersWithIdentifiers:@[ store.defaultContainerIdentifier]] error:&contactError]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey, + CNContactPostalAddressesKey, CNContactIdentifierKey, + CNInstantMessageAddressUsernameKey, CNContactInstantMessageAddressesKey, + CNInstantMessageAddressUsernameKey, CNContactImageDataKey + ]; + CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + + success = [store enumerateContactsWithFetchRequest:request error:&contactError usingBlock:^(CNContact *__nonnull contact, BOOL *__nonnull stop) { + if (contactError) { + NSLog(@"error fetching contacts %@", + contactError); + } else { + + dispatch_async(dispatch_get_main_queue(), ^{ + Contact *newContact = [[Contact alloc] initWithCNContact:contact]; + [self registerAddrsFor:newContact]; + }); + + } + }]; } - } -} -- (void)reload { - CFErrorRef error; - - // create if it doesn't exist - if (addressBook == nil) { - addressBook = ABAddressBookCreateWithOptions(NULL, &error); - } - - if (addressBook != nil) { - __weak FastAddressBook *weakSelf = self; - ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { - if (!granted) { - LOGE(@"Permission for address book acces was denied: %@", [(__bridge NSError *)error description]); - return; + }]; + // load Linphone friends + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + LinphoneFriendList *fl = lists->data; + const MSList *friends = linphone_friend_list_get_friends(fl); + while (friends) { + LinphoneFriend *f = friends->data; + // only append friends that are not native contacts (already added + // above) + if (linphone_friend_get_ref_key(f) == NULL) { + Contact *contact = [[Contact alloc] initWithFriend:f]; + [self registerAddrsFor:contact]; } - - ABAddressBookRegisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(weakSelf)); - dispatch_async(dispatch_get_main_queue(), ^(void) { - [weakSelf loadData]; - }); - - }); - } else { - LOGE(@"Create AddressBook failed, reason: %@", [(__bridge NSError *)error localizedDescription]); + friends = friends->next; + } + linphone_friend_list_update_subscriptions(fl); + lists = lists->next; } + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneAddressBookUpdate + object:self]; } -(void) updateAddressBook:(NSNotification*) notif { @@ -177,81 +193,41 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info } - (void)registerAddrsFor:(Contact *)contact { - for (NSString *phone in contact.phoneNumbers) { - char *normalizedPhone = - linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); - NSString *name = - [FastAddressBook normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : phone]; - if (phone != NULL) { - [_addressBookMap setObject:contact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; - } - if (normalizedPhone) - ms_free(normalizedPhone); - } - for (NSString *sip in contact.sipAddresses) { - [_addressBookMap setObject:contact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; - } -} - -- (void)loadData { - @synchronized(_addressBookMap) { - ABAddressBookRevert(addressBook); - [_addressBookMap removeAllObjects]; - - // load native contacts - CFArrayRef lContacts = ABAddressBookCopyArrayOfAllPeople(addressBook); - CFIndex count = CFArrayGetCount(lContacts); - for (CFIndex idx = 0; idx < count; idx++) { - ABRecordRef lPerson = CFArrayGetValueAtIndex(lContacts, idx); - Contact *contact = [[Contact alloc] initWithPerson:lPerson]; - [self registerAddrsFor:contact]; - } - CFRelease(lContacts); - - // load Linphone friends - const MSList *lists = linphone_core_get_friends_lists(LC); - while (lists) { - LinphoneFriendList *fl = lists->data; - const MSList *friends = linphone_friend_list_get_friends(fl); - while (friends) { - LinphoneFriend *f = friends->data; - // only append friends that are not native contacts (already added above) - if (linphone_friend_get_ref_key(f) == NULL) { - Contact *contact = [[Contact alloc] initWithFriend:f]; - [self registerAddrsFor:contact]; + Contact* mContact = contact; + for (NSString *phone in mContact.phones) { + char *normalizedPhone = linphone_proxy_config_normalize_phone_number(linphone_core_get_default_proxy_config(LC), phone.UTF8String); + NSString *name = [FastAddressBook normalizeSipURI:normalizedPhone ? [NSString stringWithUTF8String:normalizedPhone] : phone]; + if (phone != NULL) { + if(_addressBookMap){ + if(mContact){ + [_addressBookMap setObject:mContact forKey:(name ?: [FastAddressBook localizedLabel:phone])]; + }else{ + // Dosomte + } + } - friends = friends->next; + } - linphone_friend_list_update_subscriptions(fl); - lists = lists->next; + if (normalizedPhone) + ms_free(normalizedPhone); + } + for (NSString *sip in mContact.sipAddresses) { + [_addressBookMap setObject:mContact forKey:([FastAddressBook normalizeSipURI:sip] ?: sip)]; } - } - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneAddressBookUpdate object:self]; -} - -void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context) { - FastAddressBook *fastAddressBook = (__bridge FastAddressBook *)context; - [fastAddressBook loadData]; -} - -- (void)dealloc { - ABAddressBookUnregisterExternalChangeCallback(addressBook, sync_address_book, (__bridge void *)(self)); - CFRelease(addressBook); } #pragma mark - Tools + (NSString *)localizedLabel:(NSString *)label { if (label != nil) { - return CFBridgingRelease(ABAddressBookCopyLocalizedLabel((__bridge CFStringRef)(label))); - } - return @""; + return [CNLabeledValue localizedStringForLabel:label]; + } + return @""; } + (BOOL)contactHasValidSipDomain:(Contact *)contact { if (contact == nil) return NO; - // Check if one of the contact' sip URI matches the expected SIP filter NSString *domain = LinphoneManager.instance.contactFilter; @@ -317,60 +293,127 @@ void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void return ret; } -- (int)removeContact:(Contact *)contact { - // Remove contact from book - @synchronized(_addressBookMap) { - if (contact.person && ABRecordGetRecordID(contact.person) != kABRecordInvalidID) { - CFErrorRef error = NULL; - ABAddressBookRemoveRecord(addressBook, contact.person, (CFErrorRef *)&error); - if (error != NULL) { - LOGE(@"Remove contact %p: Fail(%@)", contact, [(__bridge NSError *)error localizedDescription]); - } else { - LOGI(@"Remove contact %p: Success!", contact); - } - contact = NULL; - // Save address book - error = NULL; - ABAddressBookSave(addressBook, (CFErrorRef *)&error); +- (BOOL)deleteContact:(Contact *)contact { + return [self deleteCNContact:contact.person]; +} - // TODO: stop reloading the whole address book but just clear the removed entries! - [self loadData]; +- (CNContact *)getCNContactFromContact:(Contact *)acontact { + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey, + CNContactIdentifierKey, CNContactInstantMessageAddressesKey, + CNInstantMessageAddressUsernameKey, CNContactImageDataKey + ]; + CNMutableContact *mCNContact = + [[store unifiedContactWithIdentifier:acontact.identifier + keysToFetch:keysToFetch + error:nil] mutableCopy]; + return mCNContact; +} - if (error != NULL) { - LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]); - } else { - LOGI(@"Save AddressBook: Success!"); - } - return error ? -1 : 0; - } - return -2; +- (BOOL)deleteCNContact:(CNContact *)contact { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + [saveRequest deleteContact:[contact mutableCopy]]; + @try { + BOOL success = [store executeSaveRequest:saveRequest error:nil]; + NSLog(@"Success %d", success); + if(success) + [self fetchContactsInBackGroundThread]; + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; } + return TRUE; +} + +- (BOOL)deleteAllContacts { + NSArray *keys = @[ CNContactPhoneNumbersKey ]; + NSString *containerId = store.defaultContainerIdentifier; + NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId]; + NSError *error; + NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate + keysToFetch:keys + error:&error]; + if (error) { + NSLog(@"error fetching contacts %@", error); + return FALSE; + } else { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + for (CNContact *contact in cnContacts) { + [saveRequest deleteContact:[contact mutableCopy]]; + } + @try { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } + NSLog(@"Deleted contacts %lu", (unsigned long)cnContacts.count); + } + return TRUE; } - (BOOL)saveContact:(Contact *)contact { - @synchronized(_addressBookMap) { - CFErrorRef error = NULL; - if (ABRecordGetRecordID(contact.person) == kABRecordInvalidID) { - if (ABAddressBookAddRecord(addressBook, contact.person, (CFErrorRef *)&error)) { - LOGI(@"Add contact %p: Success!", contact.person); - } else { - LOGE(@"Add contact %p: Fail(%@)", contact.person, [(__bridge NSError *)error localizedDescription]); - return FALSE; - } - } - - // Save address book - error = NULL; - if (ABAddressBookSave(addressBook, &error)) { - LOGI(@"Save AddressBook: Success!"); - } else { - LOGE(@"Save AddressBook: Fail(%@)", [(__bridge NSError *)error localizedDescription]); - return FALSE; - } - [self reload]; - - return error == NULL; - } + return [self saveCNContact:contact.person contact:contact]; } +- (BOOL)saveCNContact:(CNContact *)cNContact contact:(Contact *)contact { + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactInstantMessageAddressesKey, CNInstantMessageAddressUsernameKey, + CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPostalAddressesKey, + CNContactIdentifierKey, CNContactImageDataKey, CNContactNicknameKey + ]; + CNMutableContact *mCNContact = + [[store unifiedContactWithIdentifier:contact.identifier + keysToFetch:keysToFetch + error:nil] mutableCopy]; + if(mCNContact == NULL){ + [saveRequest addContact:[cNContact mutableCopy] toContainerWithIdentifier:nil]; + }else{ + [mCNContact setGivenName:contact.firstName]; + [mCNContact setFamilyName:contact.lastName]; + [mCNContact setNickname:contact.displayName]; + [mCNContact setPhoneNumbers:contact.person.phoneNumbers]; + [mCNContact setEmailAddresses:contact.person.emailAddresses]; + [mCNContact + setInstantMessageAddresses:contact.person.instantMessageAddresses]; + [mCNContact setImageData:UIImageJPEGRepresentation(contact.avatar, 0.9f)]; + + [saveRequest updateContact:mCNContact]; + } + NSError *saveError; + @try { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:&saveError]); + [self updateFriend:contact]; + [LinphoneManager.instance setContactsUpdated:TRUE]; + } @catch (NSException *exception) { + NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", [exception description]); + return FALSE; + } + [self fetchContactsInBackGroundThread]; + return TRUE; +} + +-(void)updateFriend:(Contact*) contact{ + bctbx_list_t *phonesList = linphone_friend_get_phone_numbers(contact.friend); + for (NSString *phone in contact.phones) { + if(!(bctbx_list_find(phonesList, [phone UTF8String]))){ + linphone_friend_edit(contact.friend); + linphone_friend_add_phone_number(contact.friend, [phone UTF8String]); + linphone_friend_enable_subscribes(contact.friend, TRUE); + linphone_friend_done(contact.friend); + } + } + + BOOL enabled = [LinphoneManager.instance lpConfigBoolForKey:@"use_rls_presence"]; + const MSList *lists = linphone_core_get_friends_lists(LC); + while (lists) { + linphone_friend_list_enable_subscriptions(lists->data, FALSE); + linphone_friend_list_enable_subscriptions(lists->data, enabled); + linphone_friend_list_update_subscriptions(lists->data); + lists = lists->next; + } +} @end diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index 843ed7313..5aaa54dcc 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -454,48 +454,53 @@ } + (LinphoneAddress *)normalizeSipOrPhoneAddress:(NSString *)value { - if (!value) { - return NULL; - } - LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC); - const char * normvalue; - if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { - normvalue = linphone_proxy_config_normalize_phone_number(cfg, value.UTF8String); - } else { - normvalue = value.UTF8String; - } - LinphoneAddress *addr = linphone_proxy_config_normalize_sip_uri(cfg, normvalue); - - // first try to find a friend with the given address - Contact *c = [FastAddressBook getContactWithAddress:addr]; - if (c && c.friend) { - LinphoneFriend *f = c.friend; - const LinphonePresenceModel *m = - f ? linphone_friend_get_presence_model_for_uri_or_tel(f, value.UTF8String) : NULL; - const char *contact = m ? linphone_presence_model_get_contact(m) : NULL; - if (contact) { - LinphoneAddress *contact_addr = linphone_address_new(contact); - if (contact_addr) { - linphone_address_destroy(addr); - return contact_addr; - } - } - } + if (!value || [value isEqualToString:@""]) { + return NULL; + } + LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC); + const char *normvalue; + if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { + normvalue = + linphone_proxy_config_normalize_phone_number(cfg, value.UTF8String); + } else { + normvalue = value.UTF8String; + } + LinphoneAddress *addr = + linphone_proxy_config_normalize_sip_uri(cfg, normvalue); + // first try to find a friend with the given address + Contact *c = [FastAddressBook getContactWithAddress:addr]; - // since user wants to escape plus, we assume it expects to have phone numbers by default - if (addr) { - if (cfg && (linphone_proxy_config_get_dial_escape_plus(cfg))) { - if (linphone_proxy_config_is_phone_number(cfg, normvalue)) { - linphone_address_set_username(addr, normvalue); - } - } else { - if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { - linphone_address_set_username(addr, value.UTF8String); - } - } - } + if (c && c.friend) { + LinphoneFriend *f = c.friend; + const LinphonePresenceModel *m = + f ? linphone_friend_get_presence_model_for_uri_or_tel(f, + value.UTF8String) + : NULL; + const char *contact = m ? linphone_presence_model_get_contact(m) : NULL; + if (contact) { + LinphoneAddress *contact_addr = linphone_address_new(contact); + if (contact_addr) { + linphone_address_destroy(addr); + return contact_addr; + } + } + } - return addr; + // since user wants to escape plus, we assume it expects to have phone + // numbers by default + if (addr) { + if (cfg && (linphone_proxy_config_get_dial_escape_plus(cfg))) { + if (linphone_proxy_config_is_phone_number(cfg, normvalue)) { + linphone_address_set_username(addr, normvalue); + } + } else { + if (linphone_proxy_config_is_phone_number(cfg, value.UTF8String)) { + linphone_address_set_username(addr, value.UTF8String); + } + } + } + + return addr; } @end diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 27ff2b32b..2154467a9 100644 Binary files a/Resources/en.lproj/Localizable.strings and b/Resources/en.lproj/Localizable.strings differ diff --git a/Resources/linphonerc b/Resources/linphonerc index e75cdba56..9fe2fff69 100644 --- a/Resources/linphonerc +++ b/Resources/linphonerc @@ -48,13 +48,11 @@ max_calls=3 real_early_media=1 [net] -download_bw=380 edge_bw=10 edge_ping_time=10 firewall_policy=ice mtu=1300 stun_server=stun.linphone.org -upload_bw=380 [rtp] audio_jitt_comp=60 @@ -93,5 +91,5 @@ capture=1 display=1 enabled=1 show_local=0 -size=qvga +size=vga diff --git a/Resources/linphonerc-factory b/Resources/linphonerc-factory index ba7cec73e..5c5903db1 100644 --- a/Resources/linphonerc-factory +++ b/Resources/linphonerc-factory @@ -21,6 +21,10 @@ publish_presence=0 password_length=-1 username_length=-1 +[net] +download_bw=0 +upload_bw=0 + [sip] sip_random_port=0 #whether SIP passwords must be encrypted in configuration storage file diff --git a/Resources/linphonerc~ipad b/Resources/linphonerc~ipad index 965c48c1c..1eaec502d 100644 --- a/Resources/linphonerc~ipad +++ b/Resources/linphonerc~ipad @@ -22,13 +22,11 @@ file_transfer_server_url=https://www.linphone.org:444/lft.php max_calls=3 [net] -download_bw=512 edge_bw=10 edge_ping_time=10 firewall_policy=ice mtu=1300 stun_server=stun.linphone.org -upload_bw=512 [rtp] audio_jitt_comp=60 diff --git a/Settings/InAppSettings.bundle/Audio.plist b/Settings/InAppSettings.bundle/Audio.plist index e9abc8db7..6a2b70e36 100644 --- a/Settings/InAppSettings.bundle/Audio.plist +++ b/Settings/InAppSettings.bundle/Audio.plist @@ -202,6 +202,16 @@ Type PSToggleSwitchSpecifier + + Key + codec2_preference + Title + codec2 + Type + PSToggleSwitchSpecifier + DefaultValue + + Key audio_advanced_group diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index ac2bb896e..5ca6f0da5 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -127,8 +127,7 @@ linphone_address_set_header(testAddr, "X-Create-Account", "yes"); linphone_address_set_transport(testAddr, LinphoneTransportTcp); linphone_address_set_port(testAddr, 0); - - LinphoneProxyConfig *testProxy = linphone_core_create_proxy_config(LC); + LinphoneProxyConfig *testProxy = linphone_core_create_proxy_config(lc); linphone_proxy_config_set_identity_address(testProxy, testAddr); linphone_proxy_config_set_server_addr(testProxy, [self accountProxyRoute].UTF8String); linphone_proxy_config_set_route(testProxy, [self accountProxyRoute].UTF8String); @@ -151,7 +150,7 @@ linphone_core_set_file_transfer_server(lc, "https://www.linphone.org:444/lft.php"); // reload address book to prepend proxy config domain to contacts' phone number - [[[LinphoneManager instance] fastAddressBook] reload]; + [[[LinphoneManager instance] fastAddressBook] fetchContactsInBackGroundThread]; [self waitForRegistration]; [[LinphoneManager instance] lpConfigSetInt:NO forKey:@"animations_preference"]; diff --git a/linphone-Info.plist b/linphone-Info.plist index dba791aa9..f2a5accec 100644 --- a/linphone-Info.plist +++ b/linphone-Info.plist @@ -53,7 +53,7 @@ CFBundleVersion - 3 + 9 ITSAppUsesNonExemptEncryption ITSEncryptionExportComplianceCode diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index b26bc4dee..d1e4c46ef 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -29,8 +29,6 @@ 228697C411AC29B800E9E0CA /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 228697C311AC29B800E9E0CA /* CFNetwork.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 22968A5F12F875C600588287 /* UISpeakerButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22968A5E12F875C600588287 /* UISpeakerButton.m */; }; 22AA8B0113D83F6300B30535 /* UICamSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 22AA8B0013D83F6300B30535 /* UICamSwitch.m */; }; - 22B5EFA310CE50BD00777D97 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B5EFA210CE50BD00777D97 /* AddressBookUI.framework */; }; - 22B5F03510CE6B2F00777D97 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B5F03410CE6B2F00777D97 /* AddressBook.framework */; }; 22C755601317E59C007BC101 /* UIBluetoothButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 22C7555F1317E59C007BC101 /* UIBluetoothButton.m */; }; 22D1B68112A3E0BE001AE361 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 22D1B68012A3E0BE001AE361 /* libresolv.dylib */; }; 22E0A822111C44E100B04932 /* AboutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 22E0A81C111C44E100B04932 /* AboutView.m */; }; @@ -41,6 +39,7 @@ 244523BE1E8D3A6C0037A187 /* chat_unsecure.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523BC1E8D3A6C0037A187 /* chat_unsecure.png */; }; 24A3459E1D95797700881A5C /* UIShopTableCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24A3459D1D95797700881A5C /* UIShopTableCell.xib */; }; 24A345A61D95798A00881A5C /* UIShopTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 24A345A51D95798A00881A5C /* UIShopTableCell.m */; }; + 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1C7B91F9A235500D3F981 /* Contacts.framework */; }; 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; 340751971506459A00B89C47 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 340751961506459A00B89C47 /* CoreTelephony.framework */; }; 340751E7150F38FD00B89C47 /* UIVideoButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 340751E6150F38FD00B89C47 /* UIVideoButton.m */; }; @@ -987,6 +986,7 @@ 24A3459D1D95797700881A5C /* UIShopTableCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UIShopTableCell.xib; sourceTree = ""; }; 24A345A51D95798A00881A5C /* UIShopTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIShopTableCell.m; sourceTree = ""; }; 24A345A71D95799900881A5C /* UIShopTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIShopTableCell.h; sourceTree = ""; }; + 24E1C7B91F9A235500D3F981 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* linphone_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linphone_Prefix.pch; sourceTree = ""; }; @@ -1920,6 +1920,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 24E1C7C01F9A235600D3F981 /* Contacts.framework in Frameworks */, 8C5BCED61EB3859300A9AAEF /* mediastreamer_voip.framework in Frameworks */, 8C2595DF1DEDCC8E007A6424 /* CallKit.framework in Frameworks */, 8C5BCED81EB3859300A9AAEF /* mssilk.framework in Frameworks */, @@ -1935,8 +1936,6 @@ 6334DDFA1BBAC97C00631900 /* libsqlite3.dylib in Frameworks */, 152F22361B15E889008C0621 /* libxml2.dylib in Frameworks */, 570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */, - 22B5F03510CE6B2F00777D97 /* AddressBook.framework in Frameworks */, - 22B5EFA310CE50BD00777D97 /* AddressBookUI.framework in Frameworks */, 22405EEE1600B4E400B92522 /* AssetsLibrary.framework in Frameworks */, 2274402F106F335E006EC466 /* AudioToolbox.framework in Frameworks */, 224567C2107B968500F10948 /* AVFoundation.framework in Frameworks */, @@ -2299,6 +2298,7 @@ 8C1A1F7C1FA331D40064BE00 /* libsoci_sqlite3.a */, 8CD0B3C81FA2357B008FEB16 /* libsqlite3.a */, 8CD0B3BE1FA22CBA008FEB16 /* libsoci_core.a */, + 24E1C7B91F9A235500D3F981 /* Contacts.framework */, 8C3EAA191EB8D9C300B732B6 /* linphonetester.framework */, 8C5BCEC61EB3859200A9AAEF /* bctoolbox-tester.framework */, 8C3EA9EF1EB8A78C00B732B6 /* msx264.framework */, @@ -4657,15 +4657,10 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4760,15 +4755,10 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4863,15 +4853,10 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -4966,15 +4951,10 @@ ); INFOPLIST_FILE = "linphone-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(BUILT_PRODUCTS_DIR)", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - "$(SRCROOT)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; LINK_WITH_STANDARD_LIBRARIES = YES; ORDER_FILE = ""; + OTHER_CFLAGS = "-DBCTBX_LOG_DOMAIN=\\\"ios\\\""; OTHER_LDFLAGS = "-ObjC"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; PRODUCT_NAME = linphone; @@ -5284,11 +5264,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5339,11 +5315,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -5394,11 +5366,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -5449,11 +5417,7 @@ ); INFOPLIST_FILE = "LiblinphoneTester/LinphoneTester-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib", - "$(PROJECT_DIR)/liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins", - ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.belledonne-communications.tester.liblinphoneTester"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; diff --git a/submodules/linphone b/submodules/linphone index d2fd296e8..91196256c 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit d2fd296e8c8ba84c9f192dbb7b59e22e9080a8f6 +Subproject commit 91196256ce3aed92870e2291558cc796b9c7f4d4