mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
9.5 KiB
Matlab
267 lines
9.5 KiB
Matlab
8 years ago
|
//
|
||
|
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||
|
//
|
||
|
|
||
10 years ago
|
#import "NBAsYouTypeFormatter.h"
|
||
|
#import "NBPhoneNumber.h"
|
||
|
#import "PhoneNumber.h"
|
||
|
#import "PhoneNumberUtil.h"
|
||
|
|
||
|
static NSString *const RPDefaultsKeyPhoneNumberString = @"RPDefaultsKeyPhoneNumberString";
|
||
|
static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneNumberCanonical";
|
||
|
|
||
|
@implementation PhoneNumber
|
||
|
|
||
|
+ (PhoneNumber *)phoneNumberFromText:(NSString *)text andRegion:(NSString *)regionCode {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
|
OWSAssert(regionCode != nil);
|
||
10 years ago
|
|
||
8 years ago
|
PhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedUtil];
|
||
10 years ago
|
|
||
|
NSError *parseError = nil;
|
||
|
NBPhoneNumber *number = [phoneUtil parse:text defaultRegion:regionCode error:&parseError];
|
||
|
|
||
|
if (parseError) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
NSError *toE164Error;
|
||
|
NSString *e164 = [phoneUtil format:number numberFormat:NBEPhoneNumberFormatE164 error:&toE164Error];
|
||
|
if (toE164Error) {
|
||
8 years ago
|
DDLogDebug(@"Issue while formatting number: %@", [toE164Error description]);
|
||
10 years ago
|
return nil;
|
||
|
}
|
||
|
|
||
|
PhoneNumber *phoneNumber = [PhoneNumber new];
|
||
|
phoneNumber->phoneNumber = number;
|
||
|
phoneNumber->e164 = e164;
|
||
|
return phoneNumber;
|
||
|
}
|
||
|
|
||
|
+ (PhoneNumber *)phoneNumberFromUserSpecifiedText:(NSString *)text {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
10 years ago
|
|
||
|
return [PhoneNumber phoneNumberFromText:text andRegion:[self defaultRegionCode]];
|
||
|
}
|
||
|
|
||
|
+ (NSString *)defaultRegionCode {
|
||
|
NSString *defaultRegion;
|
||
|
#if TARGET_OS_IPHONE
|
||
|
defaultRegion = [[PhoneNumberUtil sharedUtil].nbPhoneNumberUtil countryCodeByCarrier];
|
||
|
|
||
|
if ([defaultRegion isEqualToString:@"ZZ"]) {
|
||
|
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||
|
}
|
||
|
#else
|
||
|
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||
|
#endif
|
||
|
return defaultRegion;
|
||
|
}
|
||
|
|
||
|
+ (PhoneNumber *)phoneNumberFromE164:(NSString *)text {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
|
OWSAssert([text hasPrefix:COUNTRY_CODE_PREFIX]);
|
||
10 years ago
|
PhoneNumber *number = [PhoneNumber phoneNumberFromText:text andRegion:@"ZZ"];
|
||
|
|
||
8 years ago
|
OWSAssert(number != nil);
|
||
10 years ago
|
return number;
|
||
|
}
|
||
|
|
||
|
+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input {
|
||
|
return [PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:input
|
||
|
withSpecifiedRegionCode:[self defaultRegionCode]];
|
||
|
}
|
||
|
|
||
|
+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input
|
||
|
withSpecifiedCountryCodeString:(NSString *)countryCodeString {
|
||
|
return [PhoneNumber
|
||
|
bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:input
|
||
|
withSpecifiedRegionCode:
|
||
|
[PhoneNumber regionCodeFromCountryCodeString:countryCodeString]];
|
||
|
}
|
||
|
|
||
|
+ (NSString *)bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:(NSString *)input
|
||
|
withSpecifiedRegionCode:(NSString *)regionCode {
|
||
|
NBAsYouTypeFormatter *formatter = [[NBAsYouTypeFormatter alloc] initWithRegionCode:regionCode];
|
||
|
|
||
|
NSString *result = input;
|
||
|
for (NSUInteger i = 0; i < input.length; i++) {
|
||
|
result = [formatter inputDigit:[input substringWithRange:NSMakeRange(i, 1)]];
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
+ (NSString *)regionCodeFromCountryCodeString:(NSString *)countryCodeString {
|
||
|
NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedUtil].nbPhoneNumberUtil;
|
||
|
NSString *regionCode =
|
||
|
[phoneUtil getRegionCodeForCountryCode:@([[countryCodeString substringFromIndex:1] integerValue])];
|
||
|
return regionCode;
|
||
|
}
|
||
|
|
||
|
|
||
|
+ (PhoneNumber *)tryParsePhoneNumberFromText:(NSString *)text fromRegion:(NSString *)regionCode {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
|
OWSAssert(regionCode != nil);
|
||
10 years ago
|
|
||
|
return [self phoneNumberFromText:text andRegion:regionCode];
|
||
|
}
|
||
|
|
||
|
+ (PhoneNumber *)tryParsePhoneNumberFromUserSpecifiedText:(NSString *)text {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
10 years ago
|
|
||
|
if ([text isEqualToString:@""]) {
|
||
|
return nil;
|
||
|
}
|
||
9 years ago
|
NSString *sanitizedString = [self removeFormattingCharacters:text];
|
||
|
|
||
|
return [self phoneNumberFromUserSpecifiedText:sanitizedString];
|
||
|
}
|
||
10 years ago
|
|
||
8 years ago
|
+ (NSArray<PhoneNumber *> *)tryParsePhoneNumbersFromsUserSpecifiedText:(NSString *)text
|
||
|
clientPhoneNumber:(NSString *)clientPhoneNumber
|
||
|
{
|
||
|
OWSAssert(text != nil);
|
||
|
|
||
8 years ago
|
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
||
|
if ([text isEqualToString:@""]) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
NSString *sanitizedString = [self removeFormattingCharacters:text];
|
||
8 years ago
|
OWSAssert(sanitizedString != nil);
|
||
|
|
||
8 years ago
|
NSMutableArray *result = [NSMutableArray new];
|
||
|
NSMutableSet *phoneNumberSet = [NSMutableSet new];
|
||
|
void (^tryParsingWithCountryCode)(NSString *, NSString *) = ^(NSString *text,
|
||
|
NSString *countryCode) {
|
||
|
PhoneNumber *phoneNumber = [PhoneNumber phoneNumberFromText:text
|
||
|
andRegion:countryCode];
|
||
8 years ago
|
if (phoneNumber && [phoneNumber toE164] && ![phoneNumberSet containsObject:[phoneNumber toE164]]) {
|
||
8 years ago
|
[result addObject:phoneNumber];
|
||
|
[phoneNumberSet addObject:[phoneNumber toE164]];
|
||
|
}
|
||
|
};
|
||
8 years ago
|
|
||
8 years ago
|
tryParsingWithCountryCode(sanitizedString, [self defaultRegionCode]);
|
||
8 years ago
|
|
||
8 years ago
|
if ([sanitizedString hasPrefix:@"+"]) {
|
||
|
// If the text starts with "+", don't try prepending
|
||
|
// anything else.
|
||
8 years ago
|
return result;
|
||
|
}
|
||
|
|
||
8 years ago
|
// Try just adding "+" and parsing it.
|
||
|
tryParsingWithCountryCode([NSString stringWithFormat:@"+%@", sanitizedString], [self defaultRegionCode]);
|
||
|
|
||
8 years ago
|
// Order matters; better results should appear first so prefer
|
||
|
// matches with the same country code as this client's phone number.
|
||
|
OWSAssert(clientPhoneNumber.length > 0);
|
||
8 years ago
|
if (clientPhoneNumber.length > 0) {
|
||
8 years ago
|
// Note that NBPhoneNumber uses "country code" to refer to what we call a
|
||
|
// "calling code" (i.e. 44 in +44123123). Within SSK we use "country code"
|
||
|
// (and sometimes "region code") to refer to a country's ISO 2-letter code
|
||
|
// (ISO 3166-1 alpha-2).
|
||
8 years ago
|
NSNumber *callingCodeForLocalNumber = [[PhoneNumber phoneNumberFromE164:clientPhoneNumber] getCountryCode];
|
||
|
if (callingCodeForLocalNumber != nil) {
|
||
8 years ago
|
NSString *callingCodePrefix = [NSString stringWithFormat:@"+%@", callingCodeForLocalNumber];
|
||
|
|
||
|
tryParsingWithCountryCode(
|
||
|
[callingCodePrefix stringByAppendingString:sanitizedString], [self defaultRegionCode]);
|
||
|
|
||
|
// Try to determine what the country code is for the local phone number
|
||
|
// and also try parsing the phone number using that country code if it
|
||
|
// differs from the device's region code.
|
||
|
//
|
||
|
// For example, a French person living in Italy might have an
|
||
|
// Italian phone number but use French region/language for their
|
||
|
// phone. They're likely to have both Italian and French contacts.
|
||
|
NSString *localCountryCode =
|
||
|
[PhoneNumberUtil.sharedUtil probableCountryCodeForCallingCode:callingCodePrefix];
|
||
|
if (localCountryCode && ![localCountryCode isEqualToString:[self defaultRegionCode]]) {
|
||
|
tryParsingWithCountryCode(
|
||
|
[callingCodePrefix stringByAppendingString:sanitizedString], localCountryCode);
|
||
|
}
|
||
8 years ago
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
9 years ago
|
+ (NSString *)removeFormattingCharacters:(NSString *)inputString {
|
||
|
char outputString[inputString.length + 1];
|
||
10 years ago
|
|
||
9 years ago
|
int outputLength = 0;
|
||
|
for (NSUInteger i = 0; i < inputString.length; i++) {
|
||
|
unichar c = [inputString characterAtIndex:i];
|
||
|
if (c == '+' || (c >= '0' && c <= '9')) {
|
||
|
outputString[outputLength++] = (char)c;
|
||
|
}
|
||
|
}
|
||
10 years ago
|
|
||
9 years ago
|
outputString[outputLength] = 0;
|
||
|
return [NSString stringWithUTF8String:(void *)outputString];
|
||
10 years ago
|
}
|
||
|
|
||
|
+ (PhoneNumber *)tryParsePhoneNumberFromE164:(NSString *)text {
|
||
8 years ago
|
OWSAssert(text != nil);
|
||
10 years ago
|
|
||
|
return [self phoneNumberFromE164:text];
|
||
|
}
|
||
|
|
||
|
- (NSURL *)toSystemDialerURL {
|
||
|
NSString *link = [NSString stringWithFormat:@"telprompt://%@", e164];
|
||
|
return [NSURL URLWithString:link];
|
||
|
}
|
||
|
|
||
|
- (NSString *)toE164 {
|
||
|
return e164;
|
||
|
}
|
||
|
|
||
|
- (NSNumber *)getCountryCode {
|
||
|
return phoneNumber.countryCode;
|
||
|
}
|
||
|
|
||
|
- (BOOL)isValid {
|
||
|
return [[PhoneNumberUtil sharedUtil].nbPhoneNumberUtil isValidNumber:phoneNumber];
|
||
|
}
|
||
|
|
||
|
- (NSString *)localizedDescriptionForUser {
|
||
|
NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedUtil].nbPhoneNumberUtil;
|
||
|
|
||
|
NSError *formatError = nil;
|
||
|
NSString *pretty = [phoneUtil format:phoneNumber numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&formatError];
|
||
|
|
||
|
if (formatError != nil)
|
||
|
return e164;
|
||
|
return pretty;
|
||
|
}
|
||
|
|
||
|
- (BOOL)resolvesInternationallyTo:(PhoneNumber *)otherPhoneNumber {
|
||
|
return [self.toE164 isEqualToString:otherPhoneNumber.toE164];
|
||
|
}
|
||
|
|
||
|
- (NSString *)description {
|
||
|
return e164;
|
||
|
}
|
||
|
|
||
|
- (void)encodeWithCoder:(NSCoder *)encoder {
|
||
|
[encoder encodeObject:phoneNumber forKey:RPDefaultsKeyPhoneNumberString];
|
||
|
[encoder encodeObject:e164 forKey:RPDefaultsKeyPhoneNumberCanonical];
|
||
|
}
|
||
|
|
||
|
- (id)initWithCoder:(NSCoder *)decoder {
|
||
|
if ((self = [super init])) {
|
||
|
phoneNumber = [decoder decodeObjectForKey:RPDefaultsKeyPhoneNumberString];
|
||
|
e164 = [decoder decodeObjectForKey:RPDefaultsKeyPhoneNumberCanonical];
|
||
|
}
|
||
|
return self;
|
||
|
}
|
||
|
|
||
8 years ago
|
- (NSComparisonResult)compare:(PhoneNumber *)other
|
||
|
{
|
||
|
return [self.toE164 compare:other.toE164];
|
||
|
}
|
||
|
|
||
10 years ago
|
@end
|