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 
24 namespace OHOS {
25 namespace Telephony {
26 // 3GPP TS 22.030 V16.0.0 (2020-07) 6.5.3.2	Handling of not-implemented supplementary services
27 constexpr unsigned long long operator"" _hash(char const *p, size_t s)
28 {
29     return StandardizeUtils::HashCompileTime(p);
30 }
31 
IsNeedExecuteMmi(const std::string & analyseString,bool isNeedUseIms)32 bool 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 
InitCallTransferMmiCodeFunc(std::map<std::uint64_t,std::function<void (CellularCallSupplement * supplement,int32_t slotId,const MMIData & mmiData)>> & mmiCodeFunc)53 void 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 
InitCallRestrictionCodeFunc(std::map<std::uint64_t,std::function<void (CellularCallSupplement * supplement,int32_t slotId,const MMIData & mmiData)>> & mmiCodeFunc)84 void 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 
InitAdditionalMmiCodeFunc(std::map<std::uint64_t,std::function<void (CellularCallSupplement * supplement,int32_t slotId,const MMIData & mmiData)>> & mmiCodeFunc)124 void 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 
InitImsMmiCodeFunc(std::map<std::uint64_t,std::function<void (CellularCallSupplement * supplement,int32_t slotId,const MMIData & mmiData)>> & mmiCodeFunc)159 void 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 
ExecuteMmiCode(int32_t slotId)174 bool 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 
RegexMatchMmi(const std::string & analyseString)213 bool 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 
GetMMIData()261 MMIData MMICodeUtils::GetMMIData()
262 {
263     return mmiData_;
264 }
265 } // namespace Telephony
266 } // namespace OHOS
267