1*a3141fd3SAndroid Build Coastguard Worker /*
2*a3141fd3SAndroid Build Coastguard Worker *
3*a3141fd3SAndroid Build Coastguard Worker * Copyright 2006, The Android Open Source Project
4*a3141fd3SAndroid Build Coastguard Worker *
5*a3141fd3SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*a3141fd3SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*a3141fd3SAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*a3141fd3SAndroid Build Coastguard Worker *
9*a3141fd3SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*a3141fd3SAndroid Build Coastguard Worker *
11*a3141fd3SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*a3141fd3SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*a3141fd3SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*a3141fd3SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*a3141fd3SAndroid Build Coastguard Worker * limitations under the License.
16*a3141fd3SAndroid Build Coastguard Worker */
17*a3141fd3SAndroid Build Coastguard Worker
18*a3141fd3SAndroid Build Coastguard Worker // Old implementation for phone_number_compare(), which has used in cupcake, but once replaced with
19*a3141fd3SAndroid Build Coastguard Worker // the new, more strict version, and reverted again.
20*a3141fd3SAndroid Build Coastguard Worker
21*a3141fd3SAndroid Build Coastguard Worker #include <string.h>
22*a3141fd3SAndroid Build Coastguard Worker
23*a3141fd3SAndroid Build Coastguard Worker namespace android {
24*a3141fd3SAndroid Build Coastguard Worker
25*a3141fd3SAndroid Build Coastguard Worker static int MIN_MATCH = 7;
26*a3141fd3SAndroid Build Coastguard Worker
27*a3141fd3SAndroid Build Coastguard Worker /** True if c is ISO-LATIN characters 0-9 */
isISODigit(char c)28*a3141fd3SAndroid Build Coastguard Worker static bool isISODigit (char c)
29*a3141fd3SAndroid Build Coastguard Worker {
30*a3141fd3SAndroid Build Coastguard Worker return c >= '0' && c <= '9';
31*a3141fd3SAndroid Build Coastguard Worker }
32*a3141fd3SAndroid Build Coastguard Worker
33*a3141fd3SAndroid Build Coastguard Worker /** True if c is ISO-LATIN characters 0-9, *, # , + */
isNonSeparator(char c)34*a3141fd3SAndroid Build Coastguard Worker static bool isNonSeparator(char c)
35*a3141fd3SAndroid Build Coastguard Worker {
36*a3141fd3SAndroid Build Coastguard Worker return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+';
37*a3141fd3SAndroid Build Coastguard Worker }
38*a3141fd3SAndroid Build Coastguard Worker
39*a3141fd3SAndroid Build Coastguard Worker /**
40*a3141fd3SAndroid Build Coastguard Worker * Phone numbers are stored in "lookup" form in the database
41*a3141fd3SAndroid Build Coastguard Worker * as reversed strings to allow for caller ID lookup
42*a3141fd3SAndroid Build Coastguard Worker *
43*a3141fd3SAndroid Build Coastguard Worker * This method takes a phone number and makes a valid SQL "LIKE"
44*a3141fd3SAndroid Build Coastguard Worker * string that will match the lookup form
45*a3141fd3SAndroid Build Coastguard Worker *
46*a3141fd3SAndroid Build Coastguard Worker */
47*a3141fd3SAndroid Build Coastguard Worker /** all of a up to len must be an international prefix or
48*a3141fd3SAndroid Build Coastguard Worker * separators/non-dialing digits
49*a3141fd3SAndroid Build Coastguard Worker */
matchIntlPrefix(const char * a,int len)50*a3141fd3SAndroid Build Coastguard Worker static bool matchIntlPrefix(const char* a, int len)
51*a3141fd3SAndroid Build Coastguard Worker {
52*a3141fd3SAndroid Build Coastguard Worker /* '([^0-9*#+]\+[^0-9*#+] | [^0-9*#+]0(0|11)[^0-9*#+] )$' */
53*a3141fd3SAndroid Build Coastguard Worker /* 0 1 2 3 45 */
54*a3141fd3SAndroid Build Coastguard Worker
55*a3141fd3SAndroid Build Coastguard Worker int state = 0;
56*a3141fd3SAndroid Build Coastguard Worker for (int i = 0 ; i < len ; i++) {
57*a3141fd3SAndroid Build Coastguard Worker char c = a[i];
58*a3141fd3SAndroid Build Coastguard Worker
59*a3141fd3SAndroid Build Coastguard Worker switch (state) {
60*a3141fd3SAndroid Build Coastguard Worker case 0:
61*a3141fd3SAndroid Build Coastguard Worker if (c == '+') state = 1;
62*a3141fd3SAndroid Build Coastguard Worker else if (c == '0') state = 2;
63*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
64*a3141fd3SAndroid Build Coastguard Worker break;
65*a3141fd3SAndroid Build Coastguard Worker
66*a3141fd3SAndroid Build Coastguard Worker case 2:
67*a3141fd3SAndroid Build Coastguard Worker if (c == '0') state = 3;
68*a3141fd3SAndroid Build Coastguard Worker else if (c == '1') state = 4;
69*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
70*a3141fd3SAndroid Build Coastguard Worker break;
71*a3141fd3SAndroid Build Coastguard Worker
72*a3141fd3SAndroid Build Coastguard Worker case 4:
73*a3141fd3SAndroid Build Coastguard Worker if (c == '1') state = 5;
74*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
75*a3141fd3SAndroid Build Coastguard Worker break;
76*a3141fd3SAndroid Build Coastguard Worker
77*a3141fd3SAndroid Build Coastguard Worker default:
78*a3141fd3SAndroid Build Coastguard Worker if (isNonSeparator(c)) return false;
79*a3141fd3SAndroid Build Coastguard Worker break;
80*a3141fd3SAndroid Build Coastguard Worker
81*a3141fd3SAndroid Build Coastguard Worker }
82*a3141fd3SAndroid Build Coastguard Worker }
83*a3141fd3SAndroid Build Coastguard Worker
84*a3141fd3SAndroid Build Coastguard Worker return state == 1 || state == 3 || state == 5;
85*a3141fd3SAndroid Build Coastguard Worker }
86*a3141fd3SAndroid Build Coastguard Worker
87*a3141fd3SAndroid Build Coastguard Worker /** all of 'a' up to len must match non-US trunk prefix ('0') */
matchTrunkPrefix(const char * a,int len)88*a3141fd3SAndroid Build Coastguard Worker static bool matchTrunkPrefix(const char* a, int len)
89*a3141fd3SAndroid Build Coastguard Worker {
90*a3141fd3SAndroid Build Coastguard Worker bool found;
91*a3141fd3SAndroid Build Coastguard Worker
92*a3141fd3SAndroid Build Coastguard Worker found = false;
93*a3141fd3SAndroid Build Coastguard Worker
94*a3141fd3SAndroid Build Coastguard Worker for (int i = 0 ; i < len ; i++) {
95*a3141fd3SAndroid Build Coastguard Worker char c = a[i];
96*a3141fd3SAndroid Build Coastguard Worker
97*a3141fd3SAndroid Build Coastguard Worker if (c == '0' && !found) {
98*a3141fd3SAndroid Build Coastguard Worker found = true;
99*a3141fd3SAndroid Build Coastguard Worker } else if (isNonSeparator(c)) {
100*a3141fd3SAndroid Build Coastguard Worker return false;
101*a3141fd3SAndroid Build Coastguard Worker }
102*a3141fd3SAndroid Build Coastguard Worker }
103*a3141fd3SAndroid Build Coastguard Worker
104*a3141fd3SAndroid Build Coastguard Worker return found;
105*a3141fd3SAndroid Build Coastguard Worker }
106*a3141fd3SAndroid Build Coastguard Worker
107*a3141fd3SAndroid Build Coastguard Worker /** all of 'a' up to len must be a (+|00|011)country code)
108*a3141fd3SAndroid Build Coastguard Worker * We're fast and loose with the country code. Any \d{1,3} matches */
matchIntlPrefixAndCC(const char * a,int len)109*a3141fd3SAndroid Build Coastguard Worker static bool matchIntlPrefixAndCC(const char* a, int len)
110*a3141fd3SAndroid Build Coastguard Worker {
111*a3141fd3SAndroid Build Coastguard Worker /* [^0-9*#+]*(\+|0(0|11)\d\d?\d? [^0-9*#+] $ */
112*a3141fd3SAndroid Build Coastguard Worker /* 0 1 2 3 45 6 7 8 */
113*a3141fd3SAndroid Build Coastguard Worker
114*a3141fd3SAndroid Build Coastguard Worker int state = 0;
115*a3141fd3SAndroid Build Coastguard Worker for (int i = 0 ; i < len ; i++ ) {
116*a3141fd3SAndroid Build Coastguard Worker char c = a[i];
117*a3141fd3SAndroid Build Coastguard Worker
118*a3141fd3SAndroid Build Coastguard Worker switch (state) {
119*a3141fd3SAndroid Build Coastguard Worker case 0:
120*a3141fd3SAndroid Build Coastguard Worker if (c == '+') state = 1;
121*a3141fd3SAndroid Build Coastguard Worker else if (c == '0') state = 2;
122*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
123*a3141fd3SAndroid Build Coastguard Worker break;
124*a3141fd3SAndroid Build Coastguard Worker
125*a3141fd3SAndroid Build Coastguard Worker case 2:
126*a3141fd3SAndroid Build Coastguard Worker if (c == '0') state = 3;
127*a3141fd3SAndroid Build Coastguard Worker else if (c == '1') state = 4;
128*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
129*a3141fd3SAndroid Build Coastguard Worker break;
130*a3141fd3SAndroid Build Coastguard Worker
131*a3141fd3SAndroid Build Coastguard Worker case 4:
132*a3141fd3SAndroid Build Coastguard Worker if (c == '1') state = 5;
133*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
134*a3141fd3SAndroid Build Coastguard Worker break;
135*a3141fd3SAndroid Build Coastguard Worker
136*a3141fd3SAndroid Build Coastguard Worker case 1:
137*a3141fd3SAndroid Build Coastguard Worker case 3:
138*a3141fd3SAndroid Build Coastguard Worker case 5:
139*a3141fd3SAndroid Build Coastguard Worker if (isISODigit(c)) state = 6;
140*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
141*a3141fd3SAndroid Build Coastguard Worker break;
142*a3141fd3SAndroid Build Coastguard Worker
143*a3141fd3SAndroid Build Coastguard Worker case 6:
144*a3141fd3SAndroid Build Coastguard Worker case 7:
145*a3141fd3SAndroid Build Coastguard Worker if (isISODigit(c)) state++;
146*a3141fd3SAndroid Build Coastguard Worker else if (isNonSeparator(c)) return false;
147*a3141fd3SAndroid Build Coastguard Worker break;
148*a3141fd3SAndroid Build Coastguard Worker
149*a3141fd3SAndroid Build Coastguard Worker default:
150*a3141fd3SAndroid Build Coastguard Worker if (isNonSeparator(c)) return false;
151*a3141fd3SAndroid Build Coastguard Worker }
152*a3141fd3SAndroid Build Coastguard Worker }
153*a3141fd3SAndroid Build Coastguard Worker
154*a3141fd3SAndroid Build Coastguard Worker return state == 6 || state == 7 || state == 8;
155*a3141fd3SAndroid Build Coastguard Worker }
156*a3141fd3SAndroid Build Coastguard Worker
157*a3141fd3SAndroid Build Coastguard Worker /**
158*a3141fd3SAndroid Build Coastguard Worker * Compare phone numbers a and b, return true if they're identical
159*a3141fd3SAndroid Build Coastguard Worker * enough for caller ID purposes.
160*a3141fd3SAndroid Build Coastguard Worker *
161*a3141fd3SAndroid Build Coastguard Worker * - Compares from right to left
162*a3141fd3SAndroid Build Coastguard Worker * - requires minimum characters to match
163*a3141fd3SAndroid Build Coastguard Worker * - handles common trunk prefixes and international prefixes
164*a3141fd3SAndroid Build Coastguard Worker * (basically, everything except the Russian trunk prefix)
165*a3141fd3SAndroid Build Coastguard Worker *
166*a3141fd3SAndroid Build Coastguard Worker * Tolerates nulls
167*a3141fd3SAndroid Build Coastguard Worker */
phone_number_compare_loose_with_minmatch(const char * a,const char * b,int min_match)168*a3141fd3SAndroid Build Coastguard Worker bool phone_number_compare_loose_with_minmatch(const char* a, const char* b, int min_match)
169*a3141fd3SAndroid Build Coastguard Worker {
170*a3141fd3SAndroid Build Coastguard Worker int ia, ib;
171*a3141fd3SAndroid Build Coastguard Worker int matched;
172*a3141fd3SAndroid Build Coastguard Worker int numSeparatorCharsInA = 0;
173*a3141fd3SAndroid Build Coastguard Worker int numSeparatorCharsInB = 0;
174*a3141fd3SAndroid Build Coastguard Worker
175*a3141fd3SAndroid Build Coastguard Worker if (a == NULL || b == NULL) {
176*a3141fd3SAndroid Build Coastguard Worker return false;
177*a3141fd3SAndroid Build Coastguard Worker }
178*a3141fd3SAndroid Build Coastguard Worker
179*a3141fd3SAndroid Build Coastguard Worker ia = strlen(a);
180*a3141fd3SAndroid Build Coastguard Worker ib = strlen(b);
181*a3141fd3SAndroid Build Coastguard Worker if (ia == 0 || ib == 0) {
182*a3141fd3SAndroid Build Coastguard Worker return false;
183*a3141fd3SAndroid Build Coastguard Worker }
184*a3141fd3SAndroid Build Coastguard Worker
185*a3141fd3SAndroid Build Coastguard Worker // Compare from right to left
186*a3141fd3SAndroid Build Coastguard Worker ia--;
187*a3141fd3SAndroid Build Coastguard Worker ib--;
188*a3141fd3SAndroid Build Coastguard Worker
189*a3141fd3SAndroid Build Coastguard Worker matched = 0;
190*a3141fd3SAndroid Build Coastguard Worker
191*a3141fd3SAndroid Build Coastguard Worker while (ia >= 0 && ib >=0) {
192*a3141fd3SAndroid Build Coastguard Worker char ca, cb;
193*a3141fd3SAndroid Build Coastguard Worker bool skipCmp = false;
194*a3141fd3SAndroid Build Coastguard Worker
195*a3141fd3SAndroid Build Coastguard Worker ca = a[ia];
196*a3141fd3SAndroid Build Coastguard Worker
197*a3141fd3SAndroid Build Coastguard Worker if (!isNonSeparator(ca)) {
198*a3141fd3SAndroid Build Coastguard Worker ia--;
199*a3141fd3SAndroid Build Coastguard Worker skipCmp = true;
200*a3141fd3SAndroid Build Coastguard Worker numSeparatorCharsInA++;
201*a3141fd3SAndroid Build Coastguard Worker }
202*a3141fd3SAndroid Build Coastguard Worker
203*a3141fd3SAndroid Build Coastguard Worker cb = b[ib];
204*a3141fd3SAndroid Build Coastguard Worker
205*a3141fd3SAndroid Build Coastguard Worker if (!isNonSeparator(cb)) {
206*a3141fd3SAndroid Build Coastguard Worker ib--;
207*a3141fd3SAndroid Build Coastguard Worker skipCmp = true;
208*a3141fd3SAndroid Build Coastguard Worker numSeparatorCharsInB++;
209*a3141fd3SAndroid Build Coastguard Worker }
210*a3141fd3SAndroid Build Coastguard Worker
211*a3141fd3SAndroid Build Coastguard Worker if (!skipCmp) {
212*a3141fd3SAndroid Build Coastguard Worker if (cb != ca) {
213*a3141fd3SAndroid Build Coastguard Worker break;
214*a3141fd3SAndroid Build Coastguard Worker }
215*a3141fd3SAndroid Build Coastguard Worker ia--; ib--; matched++;
216*a3141fd3SAndroid Build Coastguard Worker }
217*a3141fd3SAndroid Build Coastguard Worker }
218*a3141fd3SAndroid Build Coastguard Worker
219*a3141fd3SAndroid Build Coastguard Worker if (matched < min_match) {
220*a3141fd3SAndroid Build Coastguard Worker const int effectiveALen = strlen(a) - numSeparatorCharsInA;
221*a3141fd3SAndroid Build Coastguard Worker const int effectiveBLen = strlen(b) - numSeparatorCharsInB;
222*a3141fd3SAndroid Build Coastguard Worker
223*a3141fd3SAndroid Build Coastguard Worker // if the number of dialable chars in a and b match, but the matched chars < min_match,
224*a3141fd3SAndroid Build Coastguard Worker // treat them as equal (i.e. 404-04 and 40404)
225*a3141fd3SAndroid Build Coastguard Worker if (effectiveALen == effectiveBLen && effectiveALen == matched) {
226*a3141fd3SAndroid Build Coastguard Worker return true;
227*a3141fd3SAndroid Build Coastguard Worker }
228*a3141fd3SAndroid Build Coastguard Worker
229*a3141fd3SAndroid Build Coastguard Worker return false;
230*a3141fd3SAndroid Build Coastguard Worker }
231*a3141fd3SAndroid Build Coastguard Worker
232*a3141fd3SAndroid Build Coastguard Worker // At least one string has matched completely;
233*a3141fd3SAndroid Build Coastguard Worker if (matched >= min_match && (ia < 0 || ib < 0)) {
234*a3141fd3SAndroid Build Coastguard Worker return true;
235*a3141fd3SAndroid Build Coastguard Worker }
236*a3141fd3SAndroid Build Coastguard Worker
237*a3141fd3SAndroid Build Coastguard Worker /*
238*a3141fd3SAndroid Build Coastguard Worker * Now, what remains must be one of the following for a
239*a3141fd3SAndroid Build Coastguard Worker * match:
240*a3141fd3SAndroid Build Coastguard Worker *
241*a3141fd3SAndroid Build Coastguard Worker * - a '+' on one and a '00' or a '011' on the other
242*a3141fd3SAndroid Build Coastguard Worker * - a '0' on one and a (+,00)<country code> on the other
243*a3141fd3SAndroid Build Coastguard Worker * (for this, a '0' and a '00' prefix would have succeeded above)
244*a3141fd3SAndroid Build Coastguard Worker */
245*a3141fd3SAndroid Build Coastguard Worker
246*a3141fd3SAndroid Build Coastguard Worker if (matchIntlPrefix(a, ia + 1) && matchIntlPrefix(b, ib + 1)) {
247*a3141fd3SAndroid Build Coastguard Worker return true;
248*a3141fd3SAndroid Build Coastguard Worker }
249*a3141fd3SAndroid Build Coastguard Worker
250*a3141fd3SAndroid Build Coastguard Worker if (matchTrunkPrefix(a, ia + 1) && matchIntlPrefixAndCC(b, ib + 1)) {
251*a3141fd3SAndroid Build Coastguard Worker return true;
252*a3141fd3SAndroid Build Coastguard Worker }
253*a3141fd3SAndroid Build Coastguard Worker
254*a3141fd3SAndroid Build Coastguard Worker if (matchTrunkPrefix(b, ib + 1) && matchIntlPrefixAndCC(a, ia + 1)) {
255*a3141fd3SAndroid Build Coastguard Worker return true;
256*a3141fd3SAndroid Build Coastguard Worker }
257*a3141fd3SAndroid Build Coastguard Worker
258*a3141fd3SAndroid Build Coastguard Worker /*
259*a3141fd3SAndroid Build Coastguard Worker * Last resort: if the number of unmatched characters on both sides is less than or equal
260*a3141fd3SAndroid Build Coastguard Worker * to the length of the longest country code and only one number starts with a + accept
261*a3141fd3SAndroid Build Coastguard Worker * the match. This is because some countries like France and Russia have an extra prefix
262*a3141fd3SAndroid Build Coastguard Worker * digit that is used when dialing locally in country that does not show up when you dial
263*a3141fd3SAndroid Build Coastguard Worker * the number using the country code. In France this prefix digit is used to determine
264*a3141fd3SAndroid Build Coastguard Worker * which land line carrier to route the call over.
265*a3141fd3SAndroid Build Coastguard Worker */
266*a3141fd3SAndroid Build Coastguard Worker bool aPlusFirst = (*a == '+');
267*a3141fd3SAndroid Build Coastguard Worker bool bPlusFirst = (*b == '+');
268*a3141fd3SAndroid Build Coastguard Worker bool aIgnoreUnmatched = aPlusFirst && (ia - ib) >= 0 && (ia - ib) <= 1;
269*a3141fd3SAndroid Build Coastguard Worker bool bIgnoreUnmatched = bPlusFirst && (ib - ia) >= 0 && (ib - ia) <= 1;
270*a3141fd3SAndroid Build Coastguard Worker if (ia < 4 && ib < 4 && (aIgnoreUnmatched || bIgnoreUnmatched) && !(aPlusFirst && bPlusFirst)) {
271*a3141fd3SAndroid Build Coastguard Worker return true;
272*a3141fd3SAndroid Build Coastguard Worker }
273*a3141fd3SAndroid Build Coastguard Worker
274*a3141fd3SAndroid Build Coastguard Worker return false;
275*a3141fd3SAndroid Build Coastguard Worker }
276*a3141fd3SAndroid Build Coastguard Worker
phone_number_compare_loose(const char * a,const char * b)277*a3141fd3SAndroid Build Coastguard Worker bool phone_number_compare_loose(const char* a, const char* b)
278*a3141fd3SAndroid Build Coastguard Worker {
279*a3141fd3SAndroid Build Coastguard Worker return phone_number_compare_loose_with_minmatch(a, b, MIN_MATCH);
280*a3141fd3SAndroid Build Coastguard Worker }
281*a3141fd3SAndroid Build Coastguard Worker
282*a3141fd3SAndroid Build Coastguard Worker } // namespace android
283