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