1/*
2 * Copyright (C) 2021-2022 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 "mmi_code_utils.h"
17
18#include <regex>
19
20#include "cellular_call_supplement.h"
21#include "standardize_utils.h"
22#include "telephony_log_wrapper.h"
23
24namespace OHOS {
25namespace Telephony {
26// 3GPP TS 22.030 V16.0.0 (2020-07) 6.5.3.2	Handling of not-implemented supplementary services
27constexpr unsigned long long operator"" _hash(char const *p, size_t s)
28{
29    return StandardizeUtils::HashCompileTime(p);
30}
31
32bool MMICodeUtils::IsNeedExecuteMmi(const std::string &analyseString, bool isNeedUseIms)
33{
34    isNeedUseIms_ = isNeedUseIms;
35    if (analyseString.empty()) {
36        TELEPHONY_LOGE("analyseString is empty.");
37        return false;
38    }
39    if (RegexMatchMmi(analyseString)) {
40        return true;
41    }
42
43    // 3GPP TS 22.030 V16.0.0 (2020-07) 6.5.3.2	Handling of not-implemented supplementary services
44    if ((analyseString.front() == '*' || analyseString.front() == '#') && analyseString.back() == '#') {
45        TELEPHONY_LOGI("analyseString start with * or # and end with #");
46        mmiData_.fullString = analyseString;
47        return true;
48    }
49
50    return false;
51}
52
53void InitCallTransferMmiCodeFunc(std::map<std::uint64_t,
54    std::function<void(CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData)>> &mmiCodeFunc)
55{
56    /**
57     * "21" Deal with unconditional transfer
58     * "61" Handling no answer transfer
59     * "62" Handling no signal transfer
60     * "67" Deal with busy transfer
61     * "002" Process all transfers
62     * "004" Handle transfer under all conditions
63     */
64    mmiCodeFunc["21"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
65        supplement->HandleCallTransfer(slotId, mmiData);
66    };
67    mmiCodeFunc["61"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
68        supplement->HandleCallTransfer(slotId, mmiData);
69    };
70    mmiCodeFunc["62"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
71        supplement->HandleCallTransfer(slotId, mmiData);
72    };
73    mmiCodeFunc["67"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
74        supplement->HandleCallTransfer(slotId, mmiData);
75    };
76    mmiCodeFunc["002"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
77        supplement->HandleCallTransfer(slotId, mmiData);
78    };
79    mmiCodeFunc["004"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
80        supplement->HandleCallTransfer(slotId, mmiData);
81    };
82}
83
84void InitCallRestrictionCodeFunc(std::map<std::uint64_t,
85    std::function<void(CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData)>> &mmiCodeFunc)
86{
87    /**
88     * "33" Processing limits all outgoing calls
89     * "330" Processing all restrictions
90     * "331" Processing limits all international calls
91     * "332" Handling international outgoing calls belonging to foreign countries when roaming is
92     * restricted
93     * "333" Processing limits outgoing calls
94     * "35" Processing limits all incoming calls
95     * "351" Handle all incoming calls when roaming is restricted
96     * "353" Processing limits incoming calls
97     */
98    mmiCodeFunc["33"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
99        supplement->HandleCallRestriction(slotId, mmiData);
100    };
101    mmiCodeFunc["330"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
102        supplement->HandleCallRestriction(slotId, mmiData);
103    };
104    mmiCodeFunc["331"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
105        supplement->HandleCallRestriction(slotId, mmiData);
106    };
107    mmiCodeFunc["332"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
108        supplement->HandleCallRestriction(slotId, mmiData);
109    };
110    mmiCodeFunc["333"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
111        supplement->HandleCallRestriction(slotId, mmiData);
112    };
113    mmiCodeFunc["35"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
114        supplement->HandleCallRestriction(slotId, mmiData);
115    };
116    mmiCodeFunc["351"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
117        supplement->HandleCallRestriction(slotId, mmiData);
118    };
119    mmiCodeFunc["353"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
120        supplement->HandleCallRestriction(slotId, mmiData);
121    };
122}
123
124void InitAdditionalMmiCodeFunc(std::map<std::uint64_t,
125    std::function<void(CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData)>> &mmiCodeFunc)
126{
127    /**
128     * "30" Processing caller ID
129     * "31" Processing calling number display
130     * "04" Change pin password
131     * "05" Use puk unlock sim and change pin password
132     * "042" Change pin2 password
133     * "052" Use puk2 unlock sim and change pin2 password
134     * "43" Handling call waiting
135     */
136    mmiCodeFunc["30"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
137        supplement->HandleClip(slotId, mmiData);
138    };
139    mmiCodeFunc["31"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
140        supplement->HandleClir(slotId, mmiData);
141    };
142    mmiCodeFunc["04"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
143        supplement->AlterPinPassword(slotId, mmiData);
144    };
145    mmiCodeFunc["05"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
146        supplement->UnlockPuk(slotId, mmiData);
147    };
148    mmiCodeFunc["042"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
149        supplement->AlterPin2Password(slotId, mmiData);
150    };
151    mmiCodeFunc["052"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
152        supplement->UnlockPuk2(slotId, mmiData);
153    };
154    mmiCodeFunc["43"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
155        supplement->HandleCallWaiting(slotId, mmiData);
156    };
157}
158
159void InitImsMmiCodeFunc(std::map<std::uint64_t,
160    std::function<void(CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData)>> &mmiCodeFunc)
161{
162    /**
163     * "76" Connected line identification presentation
164     * "77" Connected line identification restriction
165     */
166    mmiCodeFunc["76"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
167        supplement->HandleColp(slotId, mmiData);
168    };
169    mmiCodeFunc["77"_hash] = [](CellularCallSupplement *supplement, int32_t slotId, const MMIData &mmiData) {
170        supplement->HandleColr(slotId, mmiData);
171    };
172}
173
174bool MMICodeUtils::ExecuteMmiCode(int32_t slotId)
175{
176    using MmiCodeFunc =
177        std::function<void(CellularCallSupplement * supplement, int32_t slotId, const MMIData &mmiData)>;
178    std::map<std::uint64_t, MmiCodeFunc> mmiCodeFunc;
179    InitCallTransferMmiCodeFunc(mmiCodeFunc);
180    InitCallRestrictionCodeFunc(mmiCodeFunc);
181    InitAdditionalMmiCodeFunc(mmiCodeFunc);
182    if (isNeedUseIms_) {
183        InitImsMmiCodeFunc(mmiCodeFunc);
184    }
185
186    CellularCallSupplement supplement;
187    if (!mmiData_.serviceCode.empty()) {
188        auto serviceCode = StandardizeUtils::Hash_(mmiData_.serviceCode.c_str());
189        // "03" Processing network password
190        if (serviceCode == "03"_hash) {
191            return true;
192        }
193        auto itFunc = mmiCodeFunc.find(serviceCode);
194        if (itFunc != mmiCodeFunc.end()) {
195            auto func = itFunc->second;
196            if (func != nullptr) {
197                func(&supplement, slotId, mmiData_);
198                return true;
199            }
200        }
201        TELEPHONY_LOGI("Function not found, need check serviceCode.");
202    }
203    if (!mmiData_.fullString.empty()) {
204        TELEPHONY_LOGD("fullString is not empty.");
205        supplement.SendUssd(slotId, mmiData_.fullString);
206        return true;
207    }
208
209    TELEPHONY_LOGW("default case, need check.");
210    return false;
211}
212
213bool MMICodeUtils::RegexMatchMmi(const std::string &analyseString)
214{
215    std::string symbols =
216        "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)";
217    std::regex pattern(symbols);
218    std::smatch results;
219    if (regex_match(analyseString, results, pattern)) {
220        TELEPHONY_LOGD("regex_match ture");
221
222        /**
223         * The following sequence of functions shall be used for the control of Supplementary Services:
224         *  SELECT:	Entry of the procedure information (may be a digit or a sequence of characters).
225         *  SEND: Transmission of the information to the network.
226         *  INDICATION:	Call progress indications.
227         */
228        int32_t fullString = 1;
229        int32_t action = 2;
230        // 3GPP TS 22.030 V4.0.0 (2001-03)  6.5.2 Structure of the MMI
231        // This structure consists of the following parts:
232        //     Service Code, SC( (2 or 3 digits)
233        //     Supplementary Information, SI (variable length).
234        int32_t serviceCode = 3;
235        int32_t sia = 5;
236        int32_t sib = 7;
237        int32_t sic = 9;
238        int32_t pwdConfirm = 11;
239        int32_t dialingNumber = 12;
240        mmiData_.fullString = results.str(fullString);
241        mmiData_.actionString = results.str(action);
242        mmiData_.serviceCode = results.str(serviceCode);
243        mmiData_.serviceInfoA = results.str(sia);
244        mmiData_.serviceInfoB = results.str(sib);
245        mmiData_.serviceInfoC = results.str(sic);
246        mmiData_.pwdString = results.str(pwdConfirm);
247        mmiData_.dialString = results.str(dialingNumber);
248
249        /* 3GPP TS 22.030 V4.0.0 (2001-03)  6.5.2 Structure of the MMI
250         * The procedure always starts with *, #, **, ## or *# and is finished by #.
251         * Each part within the procedure is separated by *.
252         */
253        if (analyseString.back() == '#' && !mmiData_.dialString.empty() && mmiData_.dialString.back() == '#') {
254            mmiData_.fullString = analyseString;
255        }
256        return true;
257    }
258    return false;
259}
260
261MMIData MMICodeUtils::GetMMIData()
262{
263    return mmiData_;
264}
265} // namespace Telephony
266} // namespace OHOS
267