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