// _____ _ // |_ _| |_ _ _ ___ ___ _ __ __ _ // | | | ' \| '_/ -_) -_) ' \/ _` |_ // |_| |_||_|_| \___\___|_|_|_\__,_(_) // // Threema iOS Client // Copyright (c) 2013-2020 Threema GmbH // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License, version 3, // as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #import "PhoneNumberNormalizer.h" #import "NBPhoneNumberUtil.h" #import #import #import "NBMetadataHelper.h" @interface PhoneNumberNormalizer () @property NBPhoneNumberUtil *phoneNumberUtil; @end @implementation PhoneNumberNormalizer + (PhoneNumberNormalizer*)sharedInstance { static PhoneNumberNormalizer *sharedInstance; static dispatch_once_t pred; dispatch_once(&pred, ^{ sharedInstance = [[PhoneNumberNormalizer alloc] init]; sharedInstance.phoneNumberUtil = [NBPhoneNumberUtil sharedInstance]; }); return sharedInstance; } - (NSString*)phoneNumberToE164:(NSString*)phoneNumber withDefaultRegion:(NSString*)defaultRegion prettyFormat:(NSString**)prettyFormat { NSError *error = nil; NBPhoneNumber *parsed = [_phoneNumberUtil parse:phoneNumber defaultRegion:defaultRegion error:&error]; if (parsed == nil) return nil; NSString *e164WithPlus = [_phoneNumberUtil format:parsed numberFormat:NBEPhoneNumberFormatE164 error:&error]; if (e164WithPlus == nil) return nil; NSString *result = [e164WithPlus stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"+"]]; if (prettyFormat != nil) *prettyFormat = [_phoneNumberUtil format:parsed numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&error]; return result; } - (NSString *)examplePhoneNumberForRegion:(NSString *)region { NSError *error = nil; NBPhoneNumber *exampleNumber = [_phoneNumberUtil getExampleNumber:region error:&error]; if (exampleNumber == nil) return nil; return [_phoneNumberUtil format:exampleNumber numberFormat:NBEPhoneNumberFormatNATIONAL error:&error]; } - (NSString *)exampleRegionalPhoneNumberForRegion:(NSString *)region { NSError *error = nil; NBPhoneNumber *exampleNumber = [_phoneNumberUtil getExampleNumber:region error:&error]; if (exampleNumber == nil) { return nil; } NSString *number = [_phoneNumberUtil format:exampleNumber numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&error]; return [self regionalPartForPhoneNumber:number]; } - (NSString *)regionalPartForPhoneNumber:(NSString *)phoneNumber { NSString *region = [self regionForPhoneNumber:phoneNumber]; if (region) { NSString *code = [NBMetadataHelper.CCode2CNMap objectForKey:region]; NSRange codeRange = [phoneNumber rangeOfString:code]; if (codeRange.location != NSNotFound) { return [phoneNumber substringFromIndex:codeRange.location + codeRange.length]; } } return phoneNumber; } - (NSString *)regionForPhoneNumber:(NSString *)phoneNumber { NSError *error = nil; NSString *defaultRegion = [PhoneNumberNormalizer userRegion]; NBPhoneNumber *parsed = [_phoneNumberUtil parse:phoneNumber defaultRegion:defaultRegion error:&error]; if (parsed == nil) { return nil; } return [_phoneNumberUtil getRegionCodeForNumber:parsed]; } + (NSString*)userRegion { /* try CTCarrier first as it's probably more reliable (who knows what the user's country setting may be) */ CTTelephonyNetworkInfo *netInfo = [[CTTelephonyNetworkInfo alloc] init]; CTCarrier *carrier = [netInfo subscriberCellularProvider]; if (carrier.isoCountryCode != nil) return [carrier.isoCountryCode uppercaseString]; /* fall back to NSLocale */ return [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode]; } @end