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