Skip to content

Commit

Permalink
Change builder and add shortnumber emergency functions
Browse files Browse the repository at this point in the history
  • Loading branch information
S4more committed Jan 17, 2025
1 parent b99b59b commit 1068d24
Showing 7 changed files with 70 additions and 7 deletions.
7 changes: 4 additions & 3 deletions builder.go
Original file line number Diff line number Diff line change
@@ -575,8 +575,9 @@ type PhoneNumberMetadataE struct {
}

// <!ELEMENT territory (references?, availableFormats?, generalDesc, noInternationalDialling?,
// fixedLine?, mobile?, pager?, tollFree?, premiumRate?,
// sharedCost?, personalNumber?, voip?, uan?, voicemail?)>
//
// fixedLine?, mobile?, pager?, tollFree?, premiumRate?,
// sharedCost?, personalNumber?, voip?, uan?, voicemail?)>
type TerritoryE struct {
// <!ATTLIST territory id CDATA #REQUIRED>
ID string `xml:"id,attr"`
@@ -670,7 +671,7 @@ type TerritoryE struct {
ShortCode *PhoneNumberDescE `xml:"shortCode"`

// <!ELEMENT uan (nationalNumberPattern, possibleLengths, exampleNumber)>
Emergency *PhoneNumberDescE `xml:"Emergency"`
Emergency *PhoneNumberDescE `xml:"emergency"`

// <!ELEMENT voicemail (nationalNumberPattern, possibleLengths, exampleNumber)>
CarrierSpecific *PhoneNumberDescE `xml:"carrierSpecific"`
2 changes: 1 addition & 1 deletion gen/metadata_bin.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gen/prefix_to_carriers_bin.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gen/prefix_to_timezone_bin.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gen/shortnumber_metadata_bin.go

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions shortnumber_info.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package phonenumbers

import (
"slices"

"github.com/nyaruka/phonenumbers/gen"
"google.golang.org/protobuf/proto"
)
@@ -183,3 +185,57 @@ func matchesPossibleNumberAndNationalNumber(number string, numberDesc *PhoneNumb
}
return MatchNationalNumber(number, *numberDesc, false)
}

// In these countries, if extra digits are added to an emergency number, it no longer connects
// to the emergency service.
var REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT = []string{"BR", "CL", "NI"}

func matchesEmergencyNumber(number string, regionCode string, allowPrefixMatch bool) bool {
possibleNumber := extractPossibleNumber(number)
// Returns false if the number starts with a plus sign. We don't believe dialing the country
// code before emergency numbers (e.g. +1911) works, but later, if that proves to work, we can
// add additional logic here to handle it.
if PLUS_CHARS_PATTERN.MatchString(possibleNumber) {
return false
}

phoneMetadata := getShortNumberMetadataForRegion(regionCode)
if phoneMetadata == nil || phoneMetadata.GetEmergency() == nil {
return false
}

normalizedNumber := NormalizeDigitsOnly(possibleNumber)

allowPrefixMatchForRegion := allowPrefixMatch && !slices.Contains(REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT, regionCode)
return MatchNationalNumber(normalizedNumber, *phoneMetadata.GetEmergency(), allowPrefixMatchForRegion)
}

// Returns true if the given number exactly matches an emergency service number in the given
// region.
//
// This method takes into account cases where the number might contain formatting, but doesn't
// allow additional digits to be appended. Note that isEmergencyNumber(number, region)
// implies connectsToEmergencyNumber(number, region).
//
// number: the phone number to test
// regionCode: the region where the phone number is being dialed
// return: whether the number exactly matches an emergency services number in the given region
func isEmergencyNumber(number string, regionCode string) bool {
return matchesEmergencyNumber(number, regionCode, false)
}

// Returns true if the given number, exactly as dialed, might be used to connect to an emergency
// service in the given region.
//
// This method accepts a string, rather than a PhoneNumber, because it needs to distinguish
// cases such as "+1 911" and "911", where the former may not connect to an emergency service in
// all cases but the latter would. This method takes into account cases where the number might
// contain formatting, or might have additional digits appended (when it is okay to do that in
// the specified region).
//
// number: the phone number to test
// regionCode: the region where the phone number is being dialed
// return: whether the number might be used to connect to an emergency service in the given region
func connectsToEmergencyNumber(number string, regionCode string) bool {
return matchesEmergencyNumber(number, regionCode, true)
}
6 changes: 6 additions & 0 deletions shortnumber_info_test.go
Original file line number Diff line number Diff line change
@@ -72,3 +72,9 @@ func TestIsValidShortNumber(t *testing.T) {
}
assert.False(t, IsValidShortNumberForRegion(invalidNumber, "FR"))
}

func TestConnectsToEmergencyNumber_US(t *testing.T) {
assert.True(t, connectsToEmergencyNumber("911", "US"))
assert.True(t, connectsToEmergencyNumber("112", "US"))
assert.False(t, connectsToEmergencyNumber("999", "US"))
}

0 comments on commit 1068d24

Please sign in to comment.