PhoneNumberNormalizer.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2013-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "PhoneNumberNormalizer.h"
  21. #import "NBPhoneNumberUtil.h"
  22. #import <CoreTelephony/CTTelephonyNetworkInfo.h>
  23. #import <CoreTelephony/CTCarrier.h>
  24. #import "NBMetadataHelper.h"
  25. @interface PhoneNumberNormalizer ()
  26. @property NBPhoneNumberUtil *phoneNumberUtil;
  27. @end
  28. @implementation PhoneNumberNormalizer
  29. + (PhoneNumberNormalizer*)sharedInstance {
  30. static PhoneNumberNormalizer *sharedInstance;
  31. static dispatch_once_t pred;
  32. dispatch_once(&pred, ^{
  33. sharedInstance = [[PhoneNumberNormalizer alloc] init];
  34. sharedInstance.phoneNumberUtil = [NBPhoneNumberUtil sharedInstance];
  35. });
  36. return sharedInstance;
  37. }
  38. - (NSString*)phoneNumberToE164:(NSString*)phoneNumber withDefaultRegion:(NSString*)defaultRegion prettyFormat:(NSString**)prettyFormat {
  39. NSError *error = nil;
  40. NBPhoneNumber *parsed = [_phoneNumberUtil parse:phoneNumber defaultRegion:defaultRegion error:&error];
  41. if (parsed == nil)
  42. return nil;
  43. NSString *e164WithPlus = [_phoneNumberUtil format:parsed numberFormat:NBEPhoneNumberFormatE164 error:&error];
  44. if (e164WithPlus == nil)
  45. return nil;
  46. NSString *result = [e164WithPlus stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"+"]];
  47. if (prettyFormat != nil)
  48. *prettyFormat = [_phoneNumberUtil format:parsed numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&error];
  49. return result;
  50. }
  51. - (NSString *)examplePhoneNumberForRegion:(NSString *)region {
  52. NSError *error = nil;
  53. NBPhoneNumber *exampleNumber = [_phoneNumberUtil getExampleNumber:region error:&error];
  54. if (exampleNumber == nil)
  55. return nil;
  56. return [_phoneNumberUtil format:exampleNumber numberFormat:NBEPhoneNumberFormatNATIONAL error:&error];
  57. }
  58. - (NSString *)exampleRegionalPhoneNumberForRegion:(NSString *)region {
  59. NSError *error = nil;
  60. NBPhoneNumber *exampleNumber = [_phoneNumberUtil getExampleNumber:region error:&error];
  61. if (exampleNumber == nil) {
  62. return nil;
  63. }
  64. NSString *number = [_phoneNumberUtil format:exampleNumber numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&error];
  65. return [self regionalPartForPhoneNumber:number];
  66. }
  67. - (NSString *)regionalPartForPhoneNumber:(NSString *)phoneNumber {
  68. NSString *region = [self regionForPhoneNumber:phoneNumber];
  69. if (region) {
  70. NSString *code = [NBMetadataHelper.CCode2CNMap objectForKey:region];
  71. NSRange codeRange = [phoneNumber rangeOfString:code];
  72. if (codeRange.location != NSNotFound) {
  73. return [phoneNumber substringFromIndex:codeRange.location + codeRange.length];
  74. }
  75. }
  76. return phoneNumber;
  77. }
  78. - (NSString *)regionForPhoneNumber:(NSString *)phoneNumber {
  79. NSError *error = nil;
  80. NSString *defaultRegion = [PhoneNumberNormalizer userRegion];
  81. NBPhoneNumber *parsed = [_phoneNumberUtil parse:phoneNumber defaultRegion:defaultRegion error:&error];
  82. if (parsed == nil) {
  83. return nil;
  84. }
  85. return [_phoneNumberUtil getRegionCodeForNumber:parsed];
  86. }
  87. + (NSString*)userRegion {
  88. /* try CTCarrier first as it's probably more reliable (who knows what the user's country setting may be) */
  89. CTTelephonyNetworkInfo *netInfo = [[CTTelephonyNetworkInfo alloc] init];
  90. CTCarrier *carrier = [netInfo subscriberCellularProvider];
  91. if (carrier.isoCountryCode != nil)
  92. return [carrier.isoCountryCode uppercaseString];
  93. /* fall back to NSLocale */
  94. return [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
  95. }
  96. @end