1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "code_rule.h"
16 #include "i18n_hilog.h"
17 #include "phonenumbers/phonenumberutil.h"
18 #include "phonenumbers/phonenumber.h"
19 #include "phonenumbers/shortnumberinfo.h"
20 
21 namespace OHOS {
22 namespace Global {
23 namespace I18n {
24 using i18n::phonenumbers::PhoneNumberMatch;
25 using i18n::phonenumbers::PhoneNumber;
26 using i18n::phonenumbers::PhoneNumberUtil;
27 using i18n::phonenumbers::ShortNumberInfo;
28 
CodeRule(std::string & isValidType)29 CodeRule::CodeRule(std::string& isValidType)
30 {
31     this->isValidType = isValidType;
32 }
33 
CountDigits(icu::UnicodeString & str)34 int CodeRule::CountDigits(icu::UnicodeString& str)
35 {
36     int count = 0;
37     int len = str.length();
38     for (int i = 0; i < len; i++) {
39         if (u_isdigit(str[i])) {
40             count++;
41         }
42     }
43     return count;
44 }
IsValid(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)45 PhoneNumberMatch* CodeRule::IsValid(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
46 {
47     if (isValidType == "PreSuf") {
48         return IsValidPreSuf(possibleNumber, message);
49     } else if (isValidType == "Code") {
50         return IsValidCode(possibleNumber, message);
51     } else if (isValidType == "Rawstr") {
52         return IsValidRawstr(possibleNumber, message);
53     }
54     return IsValidDefault(possibleNumber, message);
55 }
56 
57 // Check the preifx or suffix of possibleNumber
IsValidPreSuf(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)58 PhoneNumberMatch* CodeRule::IsValidPreSuf(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
59 {
60     if (possibleNumber->start() - 1 >= 0) {
61         return IsValidStart(possibleNumber, message);
62     }
63     if (possibleNumber->end() <= message.length() - 1) {
64         return IsValidEnd(possibleNumber, message);
65     }
66     return possibleNumber;
67 }
68 
69 // check the suffix of possibleNumber
IsValidEnd(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)70 PhoneNumberMatch* CodeRule::IsValidEnd(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
71 {
72     icu::UnicodeString after = message.tempSubString(possibleNumber->end());
73     bool isTwo = true;
74     int len = after.length();
75     // check the 1st and 2nd char of the suffix.
76     for (int i = 0; i < len; i++) {
77         UChar32 afterChar = after[i];
78         if (i == 0 && !u_isUUppercase(afterChar)) {
79             isTwo = false;
80             break;
81         }
82         // 2 is the third position in the string.
83         if (i < 2 && u_isUAlphabetic(afterChar)) {
84             if (u_isUUppercase(afterChar)) {
85                 continue;
86             } else {
87                 isTwo = false;
88                 break;
89             }
90         }
91         // 1 and 2 are the second and third position in the string, respectively.
92         if (i == 1 || i == 2) {
93             if (afterChar == '-' || afterChar == '\'') {
94                 isTwo = false;
95                 break;
96             } else if (u_isdigit(afterChar) || u_isspace(afterChar)) {
97                 break;
98             } else if (!u_isUAlphabetic(afterChar)) {
99                 break;
100             } else {
101                 isTwo = false;
102                 break;
103             }
104         }
105     }
106     if (!isTwo) {
107         return possibleNumber;
108     } else {
109         return nullptr;
110     }
111 }
112 
113 // check the prefix of possibleNumber
IsValidStart(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)114 PhoneNumberMatch* CodeRule::IsValidStart(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
115 {
116     icu::UnicodeString before = message.tempSubString(0, possibleNumber->start());
117     bool isTwo = true;
118     int len = before.length();
119     for (int i = 0; i < len; i++) {
120         char beforeChar = before[len - 1 - i];
121         if (i == 0 && !u_isUUppercase(beforeChar)) {
122             isTwo = false;
123             break;
124         }
125         // 2 is the third position in the string.
126         if (i < 2 && u_isUAlphabetic(beforeChar)) {
127             if (u_isUUppercase(beforeChar)) {
128                 continue;
129             } else {
130                 isTwo = false;
131                 break;
132             }
133         }
134         if (beforeChar == '-' || beforeChar == '\'') {
135             isTwo = false;
136             break;
137         } else if (u_isdigit(beforeChar) || u_isspace(beforeChar)) {
138             break;
139         } else if (!u_isUAlphabetic(beforeChar)) {
140             break;
141         } else {
142             isTwo = false;
143             break;
144         }
145     }
146     if (!isTwo) {
147         return possibleNumber;
148     } else {
149         return nullptr;
150     }
151 }
152 
IsValidDefault(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)153 PhoneNumberMatch* CodeRule::IsValidDefault(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
154 {
155     return possibleNumber;
156 }
157 
PrefixValid(icu::UnicodeString & number,int length)158 bool CodeRule::PrefixValid(icu::UnicodeString& number, int length)
159 {
160     icu::UnicodeString preNumber = number.tempSubString(0, length);
161     if (length == 1) {
162         if (number[0] == '0' || number[0] == '1' || number[0] == '+') {
163             return true;
164         }
165     // 3 indicates the first three digits of a phone number.
166     } else if (length == 3) {
167         if (preNumber == "400" || preNumber == "800") {
168             return true;
169         }
170     // 5 indicates the first five digits of a phone number.
171     } else if (length == 5) {
172         if (preNumber == "11808" || preNumber == "17909" || preNumber == "12593" ||
173             preNumber == "17951" || preNumber == "17911") {
174             return true;
175         }
176     }
177     return false;
178 }
179 
NumberValid(icu::UnicodeString & number)180 bool CodeRule::NumberValid(icu::UnicodeString& number)
181 {
182     int lengthOne = 1;
183     // 3 indicates the first three digits of a phone number.
184     int lengthThree = 3;
185     // 11 is the number of digits in the phone number.
186     if (number[0] == '1' && CountDigits(number) > 11) {
187         // 5 indicates the first five digits of a phone number.
188         int lengthFive = 5;
189         if (!PrefixValid(number, lengthFive)) {
190             return false;
191         }
192     // 12 is the number of digits, 0 and 1 indicate the first and second position, respectively.
193     } else if (number[0] == '0' && CountDigits(number) > 12 && number[1] != '0') {
194         return false;
195     // 10 is the number of digits in the phone number.
196     } else if (PrefixValid(number, lengthThree) && CountDigits(number) != 10) {
197         return false;
198     // 9 is the number of digits in the phone number.
199     } else if (!PrefixValid(number, lengthOne) && !PrefixValid(number, lengthThree) && CountDigits(number) >= 9) {
200         if (number.trim()[0] != '9' && number.trim()[0] != '1') {
201             return false;
202         }
203     // 4 is the number of digits in the phone number.
204     } else if (CountDigits(number) <= 4) {
205         return false;
206     }
207     return true;
208 }
209 
IsValidCode(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)210 PhoneNumberMatch* CodeRule::IsValidCode(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
211 {
212     bool isValid = true;
213     icu::UnicodeString number = possibleNumber->raw_string().c_str();
214     // Processes the ;ext= extention number format
215     int32_t ind = number.trim().indexOf(";ext=");
216     if (ind != -1) {
217         number = number.trim().tempSubString(0, ind);
218     }
219     if (number[0] == '(' || number[0] == '[') {
220         StartWithBrackets(number);
221     }
222     isValid = NumberValid(number);
223     if (isValid) {
224         return possibleNumber;
225     } else {
226         return nullptr;
227     }
228 }
229 
IsValidRawstr(PhoneNumberMatch * possibleNumber,icu::UnicodeString & message)230 PhoneNumberMatch* CodeRule::IsValidRawstr(PhoneNumberMatch* possibleNumber, icu::UnicodeString& message)
231 {
232     bool isValid = true;
233     icu::UnicodeString number = possibleNumber->raw_string().c_str();
234     // Processes the ;ext= extention number format
235     int32_t ind = number.trim().indexOf(";ext=");
236     if (ind != -1) {
237         number = number.trim().tempSubString(0, ind);
238     }
239     if (number[0] == '(' || number[0] == '[') {
240         number = number.tempSubString(1);
241     }
242     // 8 is the number of digits in the phone number.
243     if (number[0] != '0' && CountDigits(number) == 8) {
244         isValid = false;
245     }
246     // 4 is the number of digits in the phone number.
247     if (CountDigits(number) <= 4) {
248         isValid = false;
249     }
250     if (isValid) {
251         return possibleNumber;
252     } else {
253         return nullptr;
254     }
255 }
256 
257 // Handle phone number starting with '(' or '['
StartWithBrackets(icu::UnicodeString & number)258 void CodeRule::StartWithBrackets(icu::UnicodeString& number)
259 {
260     icu::UnicodeString right = "";
261     if (number[0] == '(') {
262         right = ')';
263     }
264     if (number[0] == '[') {
265         right = ']';
266     }
267     int neind = number.indexOf(right);
268     if (neind != -1) {
269         icu::UnicodeString phoneStr = number.tempSubString(0, neind);
270         int phoneLength = CountDigits(phoneStr);
271         icu::UnicodeString extraStr = number.tempSubString(neind);
272         int extra = CountDigits(extraStr);
273         // 4 is the number of numbers in parentheses, 1 and 2 are the number of numbers outside parentheses.
274         if ((phoneLength > 4) && (extra == 1 || extra == 2)) {
275             number = number.tempSubString(1, neind - 1);
276         } else {
277             number = number.tempSubString(1);
278         }
279     } else {
280         number = number.tempSubString(1);
281     }
282 }
283 
Handle(PhoneNumberMatch * phoneNumberMatch,icu::UnicodeString & message)284 PhoneNumberMatch* CodeRule::Handle(PhoneNumberMatch* phoneNumberMatch, icu::UnicodeString& message)
285 {
286     if (phoneNumberMatch == nullptr) {
287         return nullptr;
288     }
289     return IsValid(phoneNumberMatch, message);
290 }
291 } // namespace I18n
292 } // namespace Global
293 } // namespace OHOS