From 24733a06155d5a9a202cb6dca1b6a423fafcc6a5 Mon Sep 17 00:00:00 2001 From: Brieuc Viel Date: Wed, 8 Nov 2017 17:22:23 +0100 Subject: [PATCH] [CNContact] CNContact first implementation --- Classes/AssistantLinkView.m | 8 +- Classes/AssistantView.m | 27 +- Classes/Contact.h | 13 +- Classes/Contact.m | 976 +++++++++++++--------------- Classes/ContactDetailsTableView.m | 151 +++-- Classes/ContactDetailsView.m | 253 +++---- Classes/ContactsListTableView.m | 328 ++++++---- Classes/LinphoneAppDelegate.m | 87 +-- Classes/LinphoneCoreSettingsStore.m | 2 +- Classes/LinphoneManager.m | 6 +- Classes/Utils/FastAddressBook.h | 11 +- Classes/Utils/FastAddressBook.m | 392 ++++++----- TestsUI/LinphoneTestCase.m | 11 +- linphone.xcodeproj/project.pbxproj | 38 +- 14 files changed, 1184 insertions(+), 1119 deletions(-) diff --git a/Classes/AssistantLinkView.m b/Classes/AssistantLinkView.m index e268a8281..1b0bad163 100644 --- a/Classes/AssistantLinkView.m +++ b/Classes/AssistantLinkView.m @@ -199,10 +199,10 @@ void assistant_activate_phone_number_link(LinphoneAccountCreator *creator, Linph } [PhoneMainView.instance popToView:DialerView.compositeViewDescription]; [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneAddressBookUpdate object:NULL]; - [LinphoneManager.instance.fastAddressBook reload]; - } else { - [thiz showErrorPopup:resp]; - } + [LinphoneManager.instance.fastAddressBook reloadAllContacts]; + } else { + [thiz showErrorPopup:resp]; + } } #pragma mark - other diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index 7c625dca5..4ed9c7420 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] reloadAllContacts]; + } else { + [self displayAssistantConfigurationError]; + } } - (void)displayAssistantConfigurationError { @@ -1366,14 +1366,17 @@ 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]; - } else { - [self displayAssistantConfigurationError]; - } - } else { - [self displayAssistantConfigurationError]; - } + [[LinphoneManager.instance fastAddressBook] + reloadAllContacts]; + [PhoneMainView.instance + changeCurrentView: + DialerView.compositeViewDescription]; + } else { + [self displayAssistantConfigurationError]; + } + } else { + [self displayAssistantConfigurationError]; + } }); } 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..e143728fa 100644 --- a/Classes/Contact.m +++ b/Classes/Contact.m @@ -11,81 +11,96 @@ @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 +110,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 +130,401 @@ } 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]) { + normSip = + [FastAddressBook normalizeSipURI:[sip substringFromIndex:1]]; + CNInstantMessageAddress *cNSipMsgAddr = [ + [CNInstantMessageAddress alloc] + initWithUsername:[normSip componentsSeparatedByString:@"@"][0] + service:[normSip componentsSeparatedByString:@"@"][1]]; + CNLabeledValue *sipAddress = + [CNLabeledValue labeledValueWithLabel:NULL value:cNSipMsgAddr]; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress addObject:sipAddress]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + ret = TRUE; + _sipAddresses[index] = [sip substringFromIndex:1]; + } else { + 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 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) { + [_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 (ret) { - [_sipAddresses removeObjectAtIndex:index]; - } - return ret; + NSMutableArray *> + *tmpSipAddress = [_person.instantMessageAddresses mutableCopy]; + [tmpSipAddress removeObjectAtIndex:index]; + [_person setValue:tmpSipAddress + forKey:CNContactInstantMessageAddressesKey]; + 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]; + [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; + NSMutableArray *> *tmpEmailAddresses = + [_person.emailAddresses mutableCopy]; + [tmpEmailAddresses removeObjectAtIndex:index]; + [_person setValue:tmpEmailAddresses + forKey:CNContactEmailAddressesKey]; + ret = TRUE; + } 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]; - } - CFRelease(lMap); - } - return ret ? ret : value; -} - -- (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 +537,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 f22220acc..bf44219bd 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 { @@ -75,25 +77,30 @@ if (section == ContactSections_Number) { 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) { + 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 +126,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 +148,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 { @@ -169,26 +178,28 @@ 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]; + } - [cell setAddress:value]; + [cell setAddress:value]; - return cell; + return cell; } - (void)tableView:(UITableView *)tableView @@ -197,13 +208,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 @@ -371,19 +385,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 0fb0649e5..16bccb61d 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 { @@ -256,47 +267,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 @@ -397,55 +406,63 @@ 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]]; + // [_contact + // addPhoneNumber:((CNLabeledValue*)_tmpContact.phoneNumbers[nbPhone]).value.stringValue]; + nbEmail++; + } + } + [self saveData]; + //[self.tableController.tableView reloadData]; + } 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..29a713e50 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 { @@ -121,6 +127,7 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { return nil; } +// TODO - check this - (void)loadData { _ongoing = TRUE; LOGI(@"Load contact list"); @@ -136,67 +143,88 @@ static int ms_strcmpfuz(const char *fuzzy_word, const char *sentence) { // Reset Address book [addressBookMap removeAllObjects]; - for (NSString *addr in LinphoneManager.instance.fastAddressBook.addressBookMap) { - Contact *contact = [LinphoneManager.instance.fastAddressBook.addressBookMap objectForKey:addr]; - BOOL add = true; + @synchronized( + 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; + } - // 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; - } - - - if (!add && [ContactSelection emailFilterEnabled]) { - // Add this contact if it has an email - add = (contact.emails.count > 0); - } + if (!add && [ContactSelection emailFilterEnabled]) { + // Add this contact if it has an email + add = (contact.emails.count > 0); + } - NSMutableString *name = [self displayNameForContact:contact] - ? [[NSMutableString alloc] initWithString:[self displayNameForContact:contact]] - : nil; - if (add && name != nil) { - NSString *firstChar = [[name substringToIndex:1] uppercaseString]; + 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]; + // 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]; - } - } - }); - } - _ongoing = FALSE; + // 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]; + } + } + }); + } + _ongoing = FALSE; } - (void)loadSearchedData { @@ -218,66 +246,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 +421,20 @@ 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]; + [self loadData]; + } } - (void)removeSelectionUsing:(void (^)(NSIndexPath *))remover { @@ -391,12 +450,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/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index afafdb147..4e56fbac1 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 reloadAllContacts]; + 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" @@ -959,7 +968,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 reloadAllContacts]; } #pragma mark - Prevent ImagePickerView from rotating diff --git a/Classes/LinphoneCoreSettingsStore.m b/Classes/LinphoneCoreSettingsStore.m index 51909e9e1..c0d7e4d75 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] reloadAllContacts]; } - (void)synchronizeCodecs:(const MSList *)codecs { diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index fa3f3ed25..c0375b55e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -2166,10 +2166,10 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat [self destroyLinphoneCore]; [self createLinphoneCore]; // reload friends - [self.fastAddressBook reload]; + [self.fastAddressBook reloadAllContacts]; - // 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/Utils/FastAddressBook.h b/Classes/Utils/FastAddressBook.h index 4db2bebe4..606cf1576 100644 --- a/Classes/Utils/FastAddressBook.h +++ b/Classes/Utils/FastAddressBook.h @@ -28,16 +28,20 @@ @property(readonly, nonatomic) NSMutableDictionary *addressBookMap; @property BOOL needToUpdate; -- (void)reload; -- (void)saveAddressBook; -- (int)removeContact:(Contact *)contact; +- (BOOL)reloadAllContacts; +//- (void)saveAddressBook; +- (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 +56,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..754092fc8 100644 --- a/Classes/Utils/FastAddressBook.m +++ b/Classes/Utils/FastAddressBook.m @@ -25,11 +25,11 @@ #import "Utils.h" @implementation FastAddressBook { - ABAddressBookRef addressBook; CNContactStore* store; } -static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info, void *context); +// static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef +// info, void *context); + (UIImage *)imageForContact:(Contact *)contact { @synchronized(LinphoneManager.instance.fastAddressBook.addressBookMap) { @@ -108,150 +108,171 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info } + (BOOL)isAuthorized { - return ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized; + return [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; } - (FastAddressBook *)init { if ((self = [super init]) != nil) { - _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"); - } - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateAddressBook:) name:CNContactStoreDidChangeNotification object:nil]; - } - - return self; + store = [[CNContactStore alloc] init]; + _addressBookMap = [NSMutableDictionary dictionary]; + [self reloadAllContacts]; + } + self.needToUpdate = FALSE; + if (floor(NSFoundationVersionNumber) >= + NSFoundationVersionNumber_iOS_9_x_Max) { + if ([CNContactStore class]) { + // ios9 or later + if (store == NULL) + store = [[CNContactStore alloc] init]; + CNEntityType entityType = CNEntityTypeContacts; + if ([CNContactStore authorizationStatusForEntityType:entityType] == + CNAuthorizationStatusNotDetermined) { + LOGD(@"CNContactStore requesting authorization"); + [store requestAccessForEntityType:entityType + completionHandler:^(BOOL granted, + NSError *_Nullable error) { + LOGD(@"CNContactStore authorization granted"); + }]; + } else if ([CNContactStore + authorizationStatusForEntityType:entityType] == + CNAuthorizationStatusAuthorized) { + LOGD(@"CNContactStore authorization granted"); + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(updateAddressBook:) + name:CNContactStoreDidChangeNotification + object:nil]; + //[self reload]; + store = [[CNContactStore alloc] init]; + [self reloadAllContacts]; + } + } + return self; } -- (void)saveAddressBook { - if (addressBook != nil) { - if (!ABAddressBookSave(addressBook, nil)) { - LOGW(@"Couldn't save Address Book"); - } - } -} - -- (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; - } - - 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]); - } +/*- (void)saveAddressBook { + if (addressBook != nil) { + if (!ABAddressBookSave(addressBook, nil)) { + LOGW(@"Couldn't save Address Book"); + } + } } +*/ -(void) updateAddressBook:(NSNotification*) notif { LOGD(@"address book has changed"); self.needToUpdate = TRUE; + //[self reloadAllContacts]; +} + +/*- (void)reload { + [self getAllContacts]; + LOGE(@"Create AddressBook failed"); + +} +*/ +- (BOOL)reloadAllContacts { + BOOL success = FALSE; + if ([CNContactStore class]) { + [_addressBookMap removeAllObjects]; + // iOS 9 or later + NSError *contactError; + [store + containersMatchingPredicate:[CNContainer + predicateForContainersWithIdentifiers:@[ + store.defaultContainerIdentifier + ]] + error:&contactError]; + NSArray *keysToFetch = @[ + CNContactEmailAddressesKey, CNContactPhoneNumbersKey, + CNContactFamilyNameKey, CNContactGivenNameKey, + 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 { + Contact *newContact = [[Contact alloc] + initWithCNContact:contact]; + [_addressBookMap setObject:newContact + forKey:contact]; + [self registerAddrsFor:newContact]; + } + }]; + // 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]; + } + friends = friends->next; + } + linphone_friend_list_update_subscriptions(fl); + lists = lists->next; + } + } + [NSNotificationCenter.defaultCenter + postNotificationName:kLinphoneAddressBookUpdate + object:self]; + return success; } - (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]; - } - friends = friends->next; - } - linphone_friend_list_update_subscriptions(fl); - lists = lists->next; - } - } - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneAddressBookUpdate object:self]; + for (NSString *phone in contact.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) { + [_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 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); + [fastAddressBook reloadAllContacts]; } #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 +338,103 @@ 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 { + NSLog(@"Success %d", [store executeSaveRequest:saveRequest error:nil]); + [self reloadAllContacts]; + } @catch (NSException *exception) { + NSLog(@"description = %@", [exception description]); + return FALSE; + } + [self reloadAllContacts]; + 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", 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; - } - } + return [self saveCNContact:contact.person contact:contact]; +} - // 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]; +- (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]; + [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)]; - return error == NULL; - } + [saveRequest updateContact:mCNContact]; + NSError *saveError; + @try { + NSLog(@"Success %d", + [store executeSaveRequest:saveRequest error:&saveError]); + [_addressBookMap setObject:contact forKey:cNContact]; + } @catch (NSException *exception) { + NSLog(@"=====>>>>> CNContact SaveRequest failed : description = %@", + [exception description]); + return FALSE; + } + return TRUE; } @end diff --git a/TestsUI/LinphoneTestCase.m b/TestsUI/LinphoneTestCase.m index a016034c2..8c82a871f 100644 --- a/TestsUI/LinphoneTestCase.m +++ b/TestsUI/LinphoneTestCase.m @@ -150,11 +150,14 @@ 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] + reloadAllContacts]; - [self waitForRegistration]; - [[LinphoneManager instance] lpConfigSetInt:NO forKey:@"animations_preference"]; - } + [self waitForRegistration]; + [[LinphoneManager instance] + lpConfigSetInt:NO + forKey:@"animations_preference"]; + } } - (UITableView *)findTableView:(NSString *)table { diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index e7e66b662..f4e2c1c65 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 */; }; @@ -828,20 +827,6 @@ remoteGlobalIDString = FAB8A0141CAC546A00C6DFC1; remoteInfo = KIFFrameworkConsumerTests; }; - 8C90F57A1F94A621003B86C4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8CD87D4C1EF5105800ACA260; - remoteInfo = LinphoneManager; - }; - 8C90F57C1F94A621003B86C4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 630589F21B4E816900EFAE36 /* KIF.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8CD87D541EF5105900ACA260; - remoteInfo = LinphoneManagerTests; - }; F08F119119C09C6B007D70C2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -963,6 +948,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 = ""; }; @@ -1863,6 +1849,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 */, @@ -1878,8 +1865,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 */, @@ -2225,6 +2210,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 24E1C7B91F9A235500D3F981 /* Contacts.framework */, 8C3EAA191EB8D9C300B732B6 /* linphonetester.framework */, 8C5BCEC61EB3859200A9AAEF /* bctoolbox-tester.framework */, 8C3EA9EF1EB8A78C00B732B6 /* msx264.framework */, @@ -2316,8 +2302,6 @@ 63058A071B4E816A00EFAE36 /* KIF.framework */, 633FC7C81CD7466400774B8B /* KIFFrameworkConsumer.app */, 633FC7CA1CD7466400774B8B /* KIFFrameworkConsumerTests.xctest */, - 8C90F57B1F94A621003B86C4 /* LinphoneManager.framework */, - 8C90F57D1F94A621003B86C4 /* LinphoneManagerTests.xctest */, ); name = Products; sourceTree = ""; @@ -3242,20 +3226,6 @@ remoteRef = 633FC7C91CD7466400774B8B /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 8CA26B501F7D31E700411264 /* LinphoneManager.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = LinphoneManager.framework; - remoteRef = 8CA26B4F1F7D31E700411264 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 8CA26B521F7D31E700411264 /* LinphoneManagerTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = LinphoneManagerTests.xctest; - remoteRef = 8CA26B511F7D31E700411264 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */