1/*
2 * Copyright (C) 2021 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
16#include "call_number_utils.h"
17
18#include <regex>
19
20#include "phonenumbers/phonenumber.pb.h"
21#include "telephony_log_wrapper.h"
22#include "telephony_types.h"
23#include "call_manager_errors.h"
24#include "cellular_call_connection.h"
25#include "core_service_client.h"
26#include "cellular_data_client.h"
27#include "call_ability_report_proxy.h"
28#include "number_identity_data_base_helper.h"
29#include "asyoutypeformatter.h"
30
31namespace OHOS {
32namespace Telephony {
33CallNumberUtils::CallNumberUtils() {}
34
35CallNumberUtils::~CallNumberUtils() {}
36
37int32_t CallNumberUtils::FormatPhoneNumber(
38    const std::string &phoneNumber, const std::string &countryCode, std::string &formatNumber)
39{
40    if (phoneNumber.empty()) {
41        TELEPHONY_LOGE("phoneNumber is nullptr!");
42        return TELEPHONY_ERR_ARGUMENT_INVALID;
43    }
44    if (phoneNumber.front() == '#' || phoneNumber.front() == '*') {
45        formatNumber = phoneNumber;
46        return TELEPHONY_SUCCESS;
47    }
48    i18n::phonenumbers::PhoneNumberUtil *phoneUtils = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
49    if (phoneUtils == nullptr) {
50        TELEPHONY_LOGE("phoneUtils is nullptr");
51        return TELEPHONY_ERR_LOCAL_PTR_NULL;
52    }
53    std::string tmpCode = countryCode;
54    transform(tmpCode.begin(), tmpCode.end(), tmpCode.begin(), ::toupper);
55    i18n::phonenumbers::PhoneNumber parseResult;
56    phoneUtils->ParseAndKeepRawInput(phoneNumber, tmpCode, &parseResult);
57    phoneUtils->FormatInOriginalFormat(parseResult, tmpCode, &formatNumber);
58    if (formatNumber.empty() || formatNumber == "0") {
59        formatNumber = "";
60    }
61    return TELEPHONY_SUCCESS;
62}
63
64int32_t CallNumberUtils::FormatPhoneNumberToE164(
65    const std::string phoneNumber, const std::string countryCode, std::string &formatNumber)
66{
67    return FormatNumberBase(phoneNumber, countryCode, i18n::phonenumbers::PhoneNumberUtil::E164, formatNumber);
68}
69
70int32_t CallNumberUtils::FormatPhoneNumberToNational(
71    const std::string phoneNumber, const std::string countryCode, std::string &formatNumber)
72{
73    int32_t ret = FormatNumberBase(phoneNumber, countryCode,
74        i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::NATIONAL, formatNumber);
75    ProcessSpace(formatNumber);
76    return ret;
77}
78
79int32_t CallNumberUtils::FormatPhoneNumberToInternational(
80    const std::string phoneNumber, const std::string countryCode, std::string &formatNumber)
81{
82    int32_t ret = FormatNumberBase(phoneNumber, countryCode,
83        i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL, formatNumber);
84    ProcessSpace(formatNumber);
85    return ret;
86}
87
88int32_t CallNumberUtils::FormatNumberBase(const std::string phoneNumber, std::string countryCode,
89    const i18n::phonenumbers::PhoneNumberUtil::PhoneNumberFormat formatInfo, std::string &formatNumber)
90{
91    if (phoneNumber.empty()) {
92        TELEPHONY_LOGE("phoneNumber is nullptr!");
93        return TELEPHONY_ERR_ARGUMENT_INVALID;
94    }
95    i18n::phonenumbers::PhoneNumberUtil *phoneUtils = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
96    if (phoneUtils == nullptr) {
97        TELEPHONY_LOGE("phoneUtils is nullptr");
98        return TELEPHONY_ERR_LOCAL_PTR_NULL;
99    }
100    transform(countryCode.begin(), countryCode.end(), countryCode.begin(), ::toupper);
101    i18n::phonenumbers::PhoneNumber parseResult;
102    phoneUtils->Parse(phoneNumber, countryCode, &parseResult);
103    if (phoneUtils->IsValidNumber(parseResult) || HasBCPhoneNumber(phoneNumber)) {
104        phoneUtils->Format(parseResult, formatInfo, &formatNumber);
105    }
106    return TELEPHONY_SUCCESS;
107}
108
109int32_t CallNumberUtils::FormatPhoneNumberAsYouType(
110    const std::string &phoneNumber, const std::string &countryCode, std::string &formatNumber)
111{
112    if (phoneNumber.empty()) {
113        TELEPHONY_LOGE("phoneNumber is nullptr!");
114        return TELEPHONY_ERR_ARGUMENT_INVALID;
115    }
116    if (phoneNumber.front() == '#' || phoneNumber.front() == '*') {
117        formatNumber = phoneNumber;
118        return TELEPHONY_SUCCESS;
119    }
120    i18n::phonenumbers::PhoneNumberUtil *phoneUtils = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
121    if (phoneUtils == nullptr) {
122        TELEPHONY_LOGE("phoneUtils is nullptr");
123        return TELEPHONY_ERR_LOCAL_PTR_NULL;
124    }
125    std::string tmpCode = countryCode;
126    transform(tmpCode.begin(), tmpCode.end(), tmpCode.begin(), ::toupper);
127    std::unique_ptr<i18n::phonenumbers::AsYouTypeFormatter> formatter(phoneUtils->GetAsYouTypeFormatter(tmpCode));
128    if (formatter == nullptr) {
129        TELEPHONY_LOGE("formatter is nullptr");
130        return TELEPHONY_ERR_LOCAL_PTR_NULL;
131    }
132    formatter->Clear();
133    std::string result;
134    for (size_t i = 0; i < phoneNumber.length(); i++) {
135        char c = phoneNumber.at(i);
136        formatNumber = formatter->InputDigit(c, &result);
137    }
138    if (formatNumber.empty() || formatNumber == "0") {
139        formatNumber = "";
140    }
141    return TELEPHONY_SUCCESS;
142}
143
144void CallNumberUtils::ProcessSpace(std::string &number)
145{
146    std::string word;
147    std::stringstream streamNum(number);
148    std::string store;
149    while (streamNum >> word) {
150        store += word;
151    }
152    number = store;
153}
154
155int32_t CallNumberUtils::CheckNumberIsEmergency(const std::string &phoneNumber, const int32_t slotId, bool &enabled)
156{
157    return DelayedSingleton<CellularCallConnection>::GetInstance()->IsEmergencyPhoneNumber(
158        phoneNumber, slotId, enabled);
159}
160
161bool CallNumberUtils::IsValidSlotId(int32_t slotId) const
162{
163    if (SIM_SLOT_COUNT == HAS_A_SLOT) {
164        return slotId == SIM_SLOT_0;
165    }
166    if (SIM_SLOT_COUNT == HAS_TWO_SLOT) {
167        if (slotId == SIM_SLOT_0 || slotId == SIM_SLOT_1) {
168            return true;
169        }
170    }
171    return false;
172}
173
174bool CallNumberUtils::IsMMICode(const std::string &number)
175{
176    if (number.empty()) {
177        TELEPHONY_LOGE("number is empty.");
178        return false;
179    }
180    if (RegexMatchMmi(number)) {
181        return true;
182    }
183
184    if ((number.front() == '*' || number.front() == '#') && number.back() == '#') {
185        TELEPHONY_LOGI("number start with * or # and end with #");
186        return true;
187    }
188
189    return false;
190}
191
192bool CallNumberUtils::RegexMatchMmi(const std::string &number)
193{
194    std::string symbols =
195        "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)";
196    std::regex pattern(symbols);
197    std::smatch results;
198    if (regex_match(number, results, pattern)) {
199        TELEPHONY_LOGI("regex_match ture");
200        return true;
201    }
202    return false;
203}
204
205std::string CallNumberUtils::RemoveSeparatorsPhoneNumber(const std::string &phoneString)
206{
207    std::string newString;
208    if (phoneString.empty()) {
209        TELEPHONY_LOGE("RemoveSeparatorsPhoneNumber return, phoneStr is empty.");
210        return newString;
211    }
212    for (char c : phoneString) {
213        if ((c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == 'N' || c == ',' || c == ';') {
214            newString += c;
215        }
216    }
217
218    return newString;
219}
220
221std::string CallNumberUtils::RemovePostDialPhoneNumber(const std::string &phoneString)
222{
223    std::string newString = "";
224    if (phoneString.empty()) {
225        TELEPHONY_LOGE("RemovePostDialPhoneNumber return, phoneStr is empty.");
226        return newString;
227    }
228    for (char c : phoneString) {
229        if ((c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+' || c == 'N') {
230            newString += c;
231        } else if (c == ',' || c == ';') {
232            break;
233        }
234    }
235
236    return newString;
237}
238
239bool CallNumberUtils::HasAlphabetInPhoneNum(const std::string &inputValue)
240{
241    if (inputValue.empty()) {
242        TELEPHONY_LOGE("HasAlphabetInPhoneNum return, input is empty.");
243        return true;
244    }
245    for (char c : inputValue) {
246        if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) {
247            TELEPHONY_LOGE("The Phone Number contains letter");
248            return true;
249        }
250    }
251    TELEPHONY_LOGI("The Phone Number is valid");
252    return false;
253}
254
255bool CallNumberUtils::HasBCPhoneNumber(const std::string &phoneNumber)
256{
257    int32_t phoneNumberStart = 0;
258    int32_t phoneNumberStartLength = 3;
259    size_t bCNumberLength = 11;
260    std::string bCNumberStart = "192";
261    if (phoneNumber.length() == bCNumberLength &&
262        phoneNumber.substr(phoneNumberStart, phoneNumberStartLength) == bCNumberStart) {
263        return true;
264    }
265    return false;
266}
267
268bool CallNumberUtils::SelectAccountId(int32_t slotId, AppExecFwk::PacMap &extras)
269{
270    if (IsValidSlotId(slotId)) {
271        return true;
272    }
273    int32_t defaultVoiceSlotId = DelayedRefSingleton<CoreServiceClient>::GetInstance().GetDefaultVoiceSlotId();
274    if (defaultVoiceSlotId != TELEPHONY_ERR_IPC_CONNECT_STUB_FAIL && IsValidSlotId(defaultVoiceSlotId)) {
275        extras.PutIntValue("accountId", defaultVoiceSlotId);
276        TELEPHONY_LOGI("select accountId to defaultVoiceSlotId = %{public}d", defaultVoiceSlotId);
277        return true;
278    }
279#ifdef CELLULAR_DATA_SUPPORT
280    int32_t defaultDataSlotId = DelayedRefSingleton<CellularDataClient>::GetInstance().GetDefaultCellularDataSlotId();
281    if (defaultDataSlotId != TELEPHONY_ERR_IPC_CONNECT_STUB_FAIL && IsValidSlotId(defaultDataSlotId)) {
282        extras.PutIntValue("accountId", defaultDataSlotId);
283        TELEPHONY_LOGI("select accountId to defaultDataSlotId = %{public}d", defaultDataSlotId);
284        return true;
285    }
286#endif
287    return false;
288}
289
290int32_t CallNumberUtils::QueryNumberLocationInfo(std::string &numberLocation, std::string accountNumber)
291{
292    TELEPHONY_LOGI("QueryNumberLocationInfo");
293    if (accountNumber == "") {
294        TELEPHONY_LOGE("accountNumber is null");
295        return TELEPHONY_ERR_ARGUMENT_INVALID;
296    }
297    std::shared_ptr<NumberIdentityDataBaseHelper> callDataPtr =
298        DelayedSingleton<NumberIdentityDataBaseHelper>::GetInstance();
299    if (callDataPtr == nullptr) {
300        TELEPHONY_LOGE("callDataPtr is nullptr!");
301        return TELEPHONY_ERR_LOCAL_PTR_NULL;
302    }
303
304    DataShare::DataSharePredicates predicates;
305    std::vector<std::string> phoneNumber;
306    phoneNumber.push_back(accountNumber);
307    predicates.SetWhereArgs(phoneNumber);
308    bool ret = callDataPtr->Query(numberLocation, predicates);
309    if (!ret) {
310        TELEPHONY_LOGE("Query number location database fail!");
311        return TELEPHONY_ERR_DATABASE_READ_FAIL;
312    }
313    return TELEPHONY_SUCCESS;
314}
315
316void CallNumberUtils::NumberLocationUpdate(const sptr<CallBase> &callObjectPtr)
317{
318    CallAttributeInfo info;
319    callObjectPtr->GetCallAttributeBaseInfo(info);
320    TELEPHONY_LOGI("NumberLocationUpdate, callId[%{public}d]", info.callId);
321    std::string numberLocation = callObjectPtr->GetNumberLocation();
322    int32_t ret = QueryNumberLocationInfo(numberLocation, callObjectPtr->GetAccountNumber());
323    if (ret != TELEPHONY_SUCCESS) {
324        return;
325    }
326    sptr<CallBase> call = callObjectPtr;
327    if (info.callState == TelCallState::CALL_STATUS_DIALING) {
328        call = CallObjectManager::GetOneCallObject(info.callId);
329        if (call == nullptr) {
330            TELEPHONY_LOGE("call is nullptr");
331            return;
332        }
333    }
334    call->SetNumberLocation(numberLocation);
335    if (!CallObjectManager::IsCallExist(info.callId)) {
336        TELEPHONY_LOGE("call is not exist");
337        return;
338    }
339    if (numberLocation != "" && numberLocation != "default") {
340        TELEPHONY_LOGI("need report call info of numberLocation");
341        call->GetCallAttributeInfo(info);
342        DelayedSingleton<CallAbilityReportProxy>::GetInstance()->ReportCallStateInfo(info);
343    }
344}
345
346void CallNumberUtils::YellowPageAndMarkUpdate(const sptr<CallBase> &callObjectPtr)
347{
348    CallAttributeInfo info;
349    callObjectPtr->GetCallAttributeBaseInfo(info);
350    TELEPHONY_LOGI("YellowPageAndMarkUpdate, callId[%{public}d]", info.callId);
351    NumberMarkInfo numberMarkInfo;
352    int32_t ret = QueryYellowPageAndMarkInfo(numberMarkInfo, callObjectPtr->GetAccountNumber());
353    if (ret != TELEPHONY_SUCCESS) {
354        return;
355    }
356    sptr<CallBase> call = callObjectPtr;
357    if (info.callState == TelCallState::CALL_STATUS_DIALING) {
358        call = CallObjectManager::GetOneCallObject(info.callId);
359        if (call == nullptr) {
360            TELEPHONY_LOGE("call is nullptr");
361            return;
362        }
363    }
364    call->SetNumberMarkInfo(numberMarkInfo);
365    if (!CallObjectManager::IsCallExist(info.callId)) {
366        TELEPHONY_LOGE("call is not exist");
367        return;
368    }
369    if (numberMarkInfo.markType != MarkType::MARK_TYPE_NONE) {
370        call->GetCallAttributeInfo(info);
371        DelayedSingleton<CallAbilityReportProxy>::GetInstance()->ReportCallStateInfo(info);
372    }
373}
374
375int32_t CallNumberUtils::QueryYellowPageAndMarkInfo(NumberMarkInfo &numberMarkInfo, std::string accountNumber)
376{
377    TELEPHONY_LOGI("QueryYellowPageAndMarkInfo");
378    if (accountNumber == "") {
379        TELEPHONY_LOGE("accountNumber is null");
380        return TELEPHONY_ERR_ARGUMENT_INVALID;
381    }
382    std::shared_ptr<NumberIdentityDataBaseHelper> callDataPtr =
383        DelayedSingleton<NumberIdentityDataBaseHelper>::GetInstance();
384    if (callDataPtr == nullptr) {
385        TELEPHONY_LOGE("callDataPtr is nullptr!");
386        return TELEPHONY_ERR_LOCAL_PTR_NULL;
387    }
388
389    DataShare::DataSharePredicates predicates;
390    std::vector<std::string> phoneNumber;
391    phoneNumber.push_back(accountNumber);
392    predicates.SetWhereArgs(phoneNumber);
393    bool ret = callDataPtr->QueryYellowPageAndMark(numberMarkInfo, predicates);
394    if (!ret) {
395        TELEPHONY_LOGE("Query yellow page and mark fail!");
396        return TELEPHONY_ERR_DATABASE_READ_FAIL;
397    }
398    return TELEPHONY_SUCCESS;
399}
400} // namespace Telephony
401} // namespace OHOS
402