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 "ims_control.h" 17 18#include "cellular_call_hisysevent.h" 19#include "cellular_call_register.h" 20#include "emergency_utils.h" 21#include "module_service_utils.h" 22#include "securec.h" 23#include "standardize_utils.h" 24 25namespace OHOS { 26namespace Telephony { 27IMSControl::~IMSControl() 28{ 29 TELEPHONY_LOGI("~IMSControl start"); 30 ReleaseAllConnection(); 31} 32 33int32_t IMSControl::Dial(const CellularCallInfo &callInfo, bool isEcc) 34{ 35 TELEPHONY_LOGI("Dial start"); 36 DelayedSingleton<CellularCallHiSysEvent>::GetInstance()->SetCallParameterInfo( 37 callInfo.slotId, static_cast<int32_t>(callInfo.callType), callInfo.videoState); 38 int32_t ret = DialPreJudgment(callInfo, isEcc); 39 if (ret != TELEPHONY_SUCCESS) { 40 return ret; 41 } 42 ModuleServiceUtils moduleServiceUtils; 43 RegServiceState regState = moduleServiceUtils.GetPsRegState(callInfo.slotId); 44 if (!(regState == RegServiceState::REG_STATE_IN_SERVICE || isEcc)) { 45 TELEPHONY_LOGE("can not dial."); 46 return TELEPHONY_ERR_NETWORK_NOT_IN_SERVICE; 47 } 48 // sip uri needs to remove separator 49 std::string newPhoneNum(callInfo.phoneNum); 50 StandardizeUtils standardizeUtils; 51 if (newPhoneNum.find('@') != std::string::npos || newPhoneNum.find("%40") != std::string::npos) { 52 newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(newPhoneNum); 53 } 54 55 CLIRMode clirMode = CLIRMode::DEFAULT; 56 if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, true)) { 57 TELEPHONY_LOGI("Dial return, mmi code type."); 58 return RETURN_TYPE_MMI; 59 } 60 return DialJudgment(callInfo.slotId, newPhoneNum, clirMode, callInfo.videoState); 61} 62 63int32_t IMSControl::DialJudgment(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) 64{ 65 TELEPHONY_LOGI("DialJudgment entry."); 66 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 67 if (!CanCall(connectionMap_)) { 68 TELEPHONY_LOGE("DialJudgment return, error type: call state error."); 69 CellularCallHiSysEvent::WriteDialCallFaultEvent( 70 slotId, INVALID_PARAMETER, videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "ims dial call state error"); 71 return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT; 72 } 73 pendingPhoneNumber_ = phoneNum; 74 // Calls can be put on hold, recovered, released, added to conversation, 75 // and transferred similarly as defined in 3GPP TS 22.030 [19]. 76 for (auto &connection : connectionMap_) { 77 if (connection.second.GetStatus() == TelCallState::CALL_STATUS_ACTIVE && 78 !connection.second.IsPendingHangup()) { 79 TELEPHONY_LOGI("DialJudgment, have connection in active state."); 80 EmergencyUtils emergencyUtils; 81 bool isEmergency = false; 82 emergencyUtils.IsEmergencyCall(slotId, phoneNum, isEmergency); 83 connection.second.SetHoldToDialInfo(phoneNum, clirMode, videoState, isEmergency); 84 connection.second.SetDialFlag(true); 85 // - a call can be temporarily disconnected from the ME but the connection is retained by the network 86 return connection.second.SwitchCallRequest(slotId); 87 } 88 } 89 return EncapsulateDial(slotId, phoneNum, clirMode, videoState); 90} 91 92int32_t IMSControl::EncapsulateDial( 93 int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) const 94{ 95 TELEPHONY_LOGI("EncapsulateDial start"); 96 97 ImsDialInfoStruct dialInfo; 98 dialInfo.videoState = videoState; 99 dialInfo.bEmergencyCall = false; 100 EmergencyUtils emergencyUtils; 101 emergencyUtils.IsEmergencyCall(slotId, phoneNum, dialInfo.bEmergencyCall); 102 103 /** 104 * <idx>: integer type; 105 * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1 106 * this number can be used in +CHLD command operations 107 * <dir>: 108 */ 109 dialInfo.phoneNum = phoneNum; 110 /** 111 * <n> (parameter sets the adjustment for outgoing calls): 112 * 0 presentation indicator is used according to the subscription of the CLIR service 113 * 1 CLIR invocation 114 * 2 CLIR suppression 115 */ 116 dialInfo.clirMode = clirMode; 117 /** 118 * An example of voice group call service request usage: 119 * ATD*17*753#500; (originate voice group call with the priority level 3) 120 * OK (voice group call setup was successful) 121 */ 122 123 CellularCallConnectionIMS cellularCallConnectionIms; 124 return cellularCallConnectionIms.DialRequest(slotId, dialInfo); 125} 126 127int32_t IMSControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type) 128{ 129 TELEPHONY_LOGI("HangUp start"); 130 switch (type) { 131 case CallSupplementType::TYPE_DEFAULT: { 132 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 133 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>( 134 connectionMap_, callInfo.index); 135 if (pConnection == nullptr) { 136 TELEPHONY_LOGE("HangUp return, error type: connection is null"); 137 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 138 } 139 pConnection->SetHangupFlag(true); 140 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) { 141 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo( 142 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING); 143 } 144 return pConnection->HangUpRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index); 145 } 146 case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT: 147 // release the second (active) call and recover the first (held) call 148 case CallSupplementType::TYPE_HANG_UP_ACTIVE: { 149 CellularCallConnectionIMS connection; 150 return connection.CallSupplementRequest(callInfo.slotId, type); 151 } 152 case CallSupplementType::TYPE_HANG_UP_ALL: { 153 TELEPHONY_LOGI("HangUp, hang up all call"); 154 CellularCallConnectionIMS connection; 155 // The AT command for hanging up all calls is the same as the AT command for rejecting calls, 156 // so the reject interface is reused. 157 return connection.RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index); 158 } 159 default: { 160 TELEPHONY_LOGE("HangUp warring, type is invalid"); 161 return TELEPHONY_ERR_ARGUMENT_INVALID; 162 } 163 } 164} 165 166int32_t IMSControl::Answer(const CellularCallInfo &callInfo) 167{ 168 TELEPHONY_LOGI("IMSControl::Answer start"); 169 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 170 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>( 171 connectionMap_, callInfo.index); 172 if (pConnection == nullptr) { 173 TELEPHONY_LOGE("HangUp return, error type: connection is null"); 174 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 175 } 176 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) && 177 IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) { 178 TELEPHONY_LOGD("already threeway mode. hangup holding call and pickup new call"); 179 int32_t ret = CheckAndHangupHoldingCall(); 180 if (ret != TELEPHONY_SUCCESS) { 181 TELEPHONY_LOGE("hangup holding call failed"); 182 return ret; 183 } 184 } 185 auto con = FindConnectionByState<ImsConnectionMap &, CellularCallConnectionIMS *>( 186 connectionMap_, TelCallState::CALL_STATUS_ACTIVE); 187 if (con != nullptr && !con->IsPendingHold() && 188 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) { 189 TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting"); 190 return con->SwitchCallRequest(callInfo.slotId); 191 } 192 if (pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING || 193 pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING || 194 pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) { 195 return pConnection->AnswerRequest(callInfo.slotId, callInfo.phoneNum, callInfo.videoState, callInfo.index); 196 } 197 TELEPHONY_LOGE("IMSControl::Answer return, error type: call state error, phone not ringing."); 198 return CALL_ERR_CALL_STATE; 199} 200 201int32_t IMSControl::CheckAndHangupHoldingCall() 202{ 203 for (auto &it : connectionMap_) { 204 CellularCallConnectionIMS holdConn = it.second; 205 if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) { 206 auto callReportInfo = holdConn.GetCallReportInfo(); 207 int32_t result = holdConn.HangUpRequest(callReportInfo.accountId, 208 callReportInfo.accountNum, callReportInfo.index); 209 if (result != TELEPHONY_SUCCESS) { 210 return result; 211 } 212 } 213 } 214 return TELEPHONY_SUCCESS; 215} 216 217int32_t IMSControl::Reject(const CellularCallInfo &callInfo) 218{ 219 TELEPHONY_LOGI("IMSControl::Reject start"); 220 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 221 auto pConnection = 222 FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callInfo.index); 223 if (pConnection == nullptr) { 224 TELEPHONY_LOGE("IMSControl::Reject, error type: connection is null"); 225 return CALL_ERR_CALL_CONNECTION_NOT_EXIST; 226 } 227 if (!pConnection->IsRingingState()) { 228 TELEPHONY_LOGE("IMSControl::Reject return, error type: call state error, phone not ringing."); 229 return CALL_ERR_CALL_STATE; 230 } 231 if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) { 232 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo( 233 pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING); 234 } 235 return pConnection->RejectRequest(callInfo.slotId, callInfo.phoneNum, callInfo.index); 236} 237 238int32_t IMSControl::HoldCall(int32_t slotId) 239{ 240 TELEPHONY_LOGI("HoldCall start"); 241 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 242 if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) { 243 TELEPHONY_LOGE("HoldCall return, error type: call state error."); 244 return CALL_ERR_CALL_STATE; 245 } 246 CellularCallConnectionIMS cellularCallConnectionIms; 247 return cellularCallConnectionIms.HoldCallRequest(slotId); 248} 249 250int32_t IMSControl::UnHoldCall(int32_t slotId) 251{ 252 TELEPHONY_LOGI("UnHoldCall start"); 253 CellularCallConnectionIMS cellularCallConnectionIms; 254 return cellularCallConnectionIms.UnHoldCallRequest(slotId); 255} 256 257int32_t IMSControl::SwitchCall(int32_t slotId) 258{ 259 TELEPHONY_LOGI("SwitchCall start"); 260 CellularCallConnectionIMS cellularCallConnectionIms; 261 return cellularCallConnectionIms.SwitchCallRequest(slotId); 262} 263 264/** 265 * Add another remote party, to which a private communication has been established using 266 * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then 267 * exceed the maximum number allowed, which results in an active multiParty call. 268 */ 269int32_t IMSControl::CombineConference(int32_t slotId) 270{ 271 TELEPHONY_LOGI("CombineConference entry"); 272 CellularCallConnectionIMS connection; 273 int32_t voiceCall = 0; 274 return connection.CombineConferenceRequest(slotId, voiceCall); 275} 276 277int32_t IMSControl::HangUpAllConnection(int32_t slotId) 278{ 279 TELEPHONY_LOGI("HangUpAllConnection entry"); 280 CellularCallConnectionIMS connection; 281 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 282 if (connectionMap_.empty()) { 283 TELEPHONY_LOGI("connectionMap_ is empty."); 284 return TELEPHONY_ERROR; 285 } 286 for (auto &it : connectionMap_) { 287 int32_t index = it.second.GetIndex(); 288 std::string number = it.second.GetNumber(); 289 connection.RejectRequest(slotId, number, index); 290 } 291 // The AT command for hanging up all calls is the same as the AT command for rejecting calls, 292 // so the reject interface is reused. 293 return TELEPHONY_SUCCESS; 294} 295 296int32_t IMSControl::InviteToConference(int32_t slotId, const std::vector<std::string> &numberList) 297{ 298 TELEPHONY_LOGI("InviteToConference entry"); 299 CellularCallConnectionIMS connection; 300 return connection.InviteToConferenceRequest(slotId, numberList); 301} 302 303int32_t IMSControl::KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index) 304{ 305 TELEPHONY_LOGI("KickOutFromConference entry"); 306 if (KickOutString.empty()) { 307 TELEPHONY_LOGW("KickOutFromConference, splitString is empty."); 308 } 309 310 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 311 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, index); 312 if (pConnection != nullptr) { 313 return pConnection->KickOutFromConferenceRequest(slotId, pConnection->GetIndex()); 314 } 315 316 TELEPHONY_LOGI("KickOutFromConference: connection cannot be matched, use index directly"); 317 CellularCallConnectionIMS connection; 318 return connection.KickOutFromConferenceRequest(slotId, index); 319} 320 321int32_t IMSControl::StartRtt(int32_t slotId, const std::string &msg) 322{ 323 TELEPHONY_LOGI("StartRtt entry"); 324 CellularCallConnectionIMS connection; 325 return connection.StartRttRequest(slotId, msg); 326} 327 328int32_t IMSControl::StopRtt(int32_t slotId) 329{ 330 TELEPHONY_LOGI("StopRtt entry"); 331 CellularCallConnectionIMS connection; 332 return connection.StopRttRequest(slotId); 333} 334 335void IMSControl::ReleaseAllConnection() 336{ 337 TELEPHONY_LOGI("ReleaseAllConnection entry"); 338 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 339 connectionMap_.clear(); 340} 341 342ImsConnectionMap IMSControl::GetConnectionMap() 343{ 344 TELEPHONY_LOGI("GetConnectionMap entry"); 345 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 346 return connectionMap_; 347} 348 349int32_t IMSControl::ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList) 350{ 351 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 352 if (callInfoList.callSize <= 0) { 353 return ReportHangUpInfo(slotId); 354 } else if (callInfoList.callSize > 0 && connectionMap_.empty()) { 355 return ReportIncomingInfo(slotId, callInfoList); 356 } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) { 357 return ReportUpdateInfo(slotId, callInfoList); 358 } 359 return TELEPHONY_ERROR; 360} 361 362int32_t IMSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList) 363{ 364 return TELEPHONY_ERROR; 365} 366 367int32_t IMSControl::ReportHangUpInfo(int32_t slotId) 368{ 369 TELEPHONY_LOGI("ReportHangUpInfo entry"); 370 CallsReportInfo callsReportInfo; 371 for (auto &it : connectionMap_) { 372 CallReportInfo reportInfo = it.second.GetCallReportInfo(); 373 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 374 reportInfo.accountId = slotId; 375 callsReportInfo.callVec.push_back(reportInfo); 376 GetCallFailReason(slotId, connectionMap_); 377 } 378 if (connectionMap_.empty()) { 379 TELEPHONY_LOGI("connectionMap_ is empty"); 380 CallReportInfo reportInfo; 381 reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 382 reportInfo.accountId = slotId; 383 callsReportInfo.callVec.push_back(reportInfo); 384 } 385 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 386 TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr."); 387 return TELEPHONY_ERR_LOCAL_PTR_NULL; 388 } 389 callsReportInfo.slotId = slotId; 390 if (isIgnoredIncomingCall_) { 391 isIgnoredIncomingCall_ = false; 392 } else { 393 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 394 } 395 ReleaseAllConnection(); 396 return TELEPHONY_SUCCESS; 397} 398 399int32_t IMSControl::ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList) 400{ 401 TELEPHONY_LOGI("ReportIncomingInfo entry"); 402 CallsReportInfo callsReportInfo; 403 for (int32_t i = 0; i < imsCurrentCallInfoList.callSize; ++i) { 404 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, imsCurrentCallInfoList.calls[i]); 405 406 CellularCallConnectionIMS connection; 407 connection.SetStatus(static_cast<TelCallState>(imsCurrentCallInfoList.calls[i].state)); 408 connection.SetIndex(imsCurrentCallInfoList.calls[i].index); 409 connection.SetNumber(imsCurrentCallInfoList.calls[i].number); 410 connection.SetOrUpdateCallReportInfo(reportInfo); 411 SetConnectionData(connectionMap_, imsCurrentCallInfoList.calls[i].index, connection); 412 413 callsReportInfo.callVec.push_back(reportInfo); 414 } 415 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 416 TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr."); 417 return TELEPHONY_ERR_ARGUMENT_INVALID; 418 } 419 callsReportInfo.slotId = slotId; 420 if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() && 421 callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) { 422 isIgnoredIncomingCall_ = true; 423 } else { 424 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 425 } 426 return TELEPHONY_SUCCESS; 427} 428 429int32_t IMSControl::ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList) 430{ 431 TELEPHONY_LOGD("ReportUpdateInfo entry"); 432 CallsReportInfo callsReportInfo; 433 for (int32_t i = 0; i < callInfoList.callSize; ++i) { 434 CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]); 435 if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) { 436 TELEPHONY_LOGI("only one call, report incoming state instead of waiting state"); 437 reportInfo.state = TelCallState::CALL_STATUS_INCOMING; 438 } 439 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>( 440 connectionMap_, callInfoList.calls[i].index); 441 if (pConnection == nullptr) { 442 CellularCallConnectionIMS connection; 443 connection.SetOrUpdateCallReportInfo(reportInfo); 444 connection.SetFlag(true); 445 connection.SetIndex(callInfoList.calls[i].index); 446 connection.SetNumber(callInfoList.calls[i].number); 447 SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection); 448 } else { 449 TelCallState preCallState = pConnection->GetStatus(); 450 pConnection->SetFlag(true); 451 pConnection->SetIndex(callInfoList.calls[i].index); 452 pConnection->SetNumber(callInfoList.calls[i].number); 453 pConnection->SetOrUpdateCallReportInfo(reportInfo); 454 TelCallState curCallState = pConnection->GetStatus(); 455 if (IsConnectedOut(preCallState, curCallState)) { 456 pConnection->UpdateCallNumber(pendingPhoneNumber_); 457 pendingPhoneNumber_.clear(); 458 ExecutePostDial(slotId, pConnection->GetIndex()); 459 } 460 } 461 callsReportInfo.callVec.push_back(reportInfo); 462 } 463 callsReportInfo.slotId = slotId; 464 DeleteConnection(callsReportInfo, callInfoList); 465 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 466 TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr."); 467 return TELEPHONY_ERR_LOCAL_PTR_NULL; 468 } 469 if (isIgnoredIncomingCall_) { 470 isIgnoredIncomingCall_ = false; 471 } else { 472 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 473 } 474 return TELEPHONY_SUCCESS; 475} 476 477CallReportInfo IMSControl::EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo) 478{ 479 TELEPHONY_LOGD("EncapsulationCallReportInfo entry"); 480 CallReportInfo callReportInfo; 481 if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) { 482 TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail."); 483 return callReportInfo; 484 } 485 486 StandardizeUtils standardizeUtils; 487 std::string phoneNumber = callInfo.number.empty() ? callInfo.name : callInfo.number; 488 std::string newString = standardizeUtils.FormatNumberAndToa(phoneNumber, callInfo.toa); 489 size_t cpyLen = strlen(newString.c_str()) + 1; 490 if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) { 491 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail."); 492 return callReportInfo; 493 } 494 if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) { 495 TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail."); 496 return callReportInfo; 497 } 498 callReportInfo.index = callInfo.index; 499 callReportInfo.accountId = slotId; 500 callReportInfo.state = static_cast<TelCallState>(callInfo.state); 501 callReportInfo.voiceDomain = callInfo.voiceDomain; 502 callReportInfo.callType = CallType::TYPE_IMS; 503 switch (callInfo.callType) { 504 case ImsCallType::TEL_IMS_CALL_TYPE_VOICE: 505 callReportInfo.callMode = VideoStateType::TYPE_VOICE; 506 break; 507 case ImsCallType::TEL_IMS_CALL_TYPE_VT_TX: 508 callReportInfo.callMode = VideoStateType::TYPE_SEND_ONLY; 509 break; 510 case ImsCallType::TEL_IMS_CALL_TYPE_VT_RX: 511 callReportInfo.callMode = VideoStateType::TYPE_RECEIVE_ONLY; 512 break; 513 case ImsCallType::TEL_IMS_CALL_TYPE_VT: 514 callReportInfo.callMode = VideoStateType::TYPE_VIDEO; 515 break; 516 default: 517 callReportInfo.callMode = VideoStateType::TYPE_VOICE; 518 break; 519 } 520 callReportInfo.mpty = callInfo.mpty; 521 callReportInfo.crsType = callInfo.toneType; 522 callReportInfo.originalCallType = callInfo.callInitialType; 523 return callReportInfo; 524} 525 526void IMSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList) 527{ 528 TELEPHONY_LOGI("DeleteConnection entry"); 529 auto it = connectionMap_.begin(); 530 while (it != connectionMap_.end()) { 531 if (!it->second.GetFlag()) { 532 CallReportInfo callReportInfo = it->second.GetCallReportInfo(); 533 callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 534 callsReportInfo.callVec.push_back(callReportInfo); 535 it = connectionMap_.erase(it); 536 GetCallFailReason(callsReportInfo.slotId, connectionMap_); 537 } else { 538 it->second.SetFlag(false); 539 ++it; 540 } 541 } 542} 543 544int32_t IMSControl::ExecutePostDial(int32_t slotId, int64_t callId) 545{ 546 TELEPHONY_LOGI("ExecutePostDial entry"); 547 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 548 if (connectionMap_.empty()) { 549 TELEPHONY_LOGE("connectionMap_ is empty."); 550 return TELEPHONY_ERROR; 551 } 552 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, callId); 553 if (pConnection == nullptr) { 554 return TELEPHONY_ERR_LOCAL_PTR_NULL; 555 } 556 char currentChar; 557 PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar); 558 switch (state) { 559 case PostDialCallState::POST_DIAL_CALL_STARTED: 560 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar); 561 break; 562 case PostDialCallState::POST_DIAL_CALL_DELAY: 563 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay( 564 pConnection->GetLeftPostDialCallString()); 565 break; 566 default: 567 break; 568 } 569 return TELEPHONY_SUCCESS; 570} 571 572int32_t IMSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed) 573{ 574 TELEPHONY_LOGI("PostDialProceed entry"); 575 std::string networkAddress; 576 std::string postDialString; 577 StandardizeUtils standardizeUtils; 578 standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString); 579 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 580 auto pConnection = FindConnectionByIndex<ImsConnectionMap &, CellularCallConnectionIMS *>(connectionMap_, 581 callInfo.index); 582 if (pConnection == nullptr) { 583 TELEPHONY_LOGE("ims pConnection is nullptr!"); 584 return TELEPHONY_ERR_LOCAL_PTR_NULL; 585 } 586 if (proceed) { 587 ExecutePostDial(callInfo.slotId, pConnection->GetIndex()); 588 } else { 589 pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED); 590 } 591 return TELEPHONY_SUCCESS; 592} 593 594int32_t IMSControl::RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId) 595{ 596 TELEPHONY_LOGI("RestoreConnection entry"); 597 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 598 for (auto &info : infos) { 599 if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) { 600 CellularCallConnectionIMS connectionIMS; 601 connectionIMS.SetIndex(info.index); 602 connectionIMS.SetNumber(info.phoneNum); 603 SetConnectionData(connectionMap_, info.index, connectionIMS); 604 } 605 } 606 return TELEPHONY_SUCCESS; 607} 608 609int32_t IMSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId) 610{ 611 CallsReportInfo callsReportInfo; 612 callsReportInfo.slotId = slotId; 613 for (const auto &info : infos) { 614 if (info.callType == CallType::TYPE_IMS && info.slotId == slotId) { 615 CallReportInfo imsCallReportInfo; 616 if (memset_s(imsCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) { 617 TELEPHONY_LOGE("memset_s fail"); 618 return TELEPHONY_ERR_MEMSET_FAIL; 619 } 620 if (memcpy_s(imsCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) { 621 TELEPHONY_LOGE("memcpy_s fail"); 622 return TELEPHONY_ERR_MEMCPY_FAIL; 623 } 624 imsCallReportInfo.index = info.index; 625 imsCallReportInfo.accountId = info.slotId; 626 imsCallReportInfo.callType = CallType::TYPE_IMS; 627 imsCallReportInfo.callMode = 628 static_cast<bool>(info.callType) ? VideoStateType::TYPE_VIDEO : VideoStateType::TYPE_VOICE; 629 imsCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED; 630 callsReportInfo.callVec.push_back(imsCallReportInfo); 631 } 632 } 633 if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) { 634 TELEPHONY_LOGE("CellularCallRegister instance is nullptr"); 635 return TELEPHONY_ERR_LOCAL_PTR_NULL; 636 } 637 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo); 638 return TELEPHONY_SUCCESS; 639} 640 641void IMSControl::DialAfterHold(int32_t slotId) 642{ 643 TELEPHONY_LOGI("DialAfterHold entry"); 644 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 645 for (auto &connection : connectionMap_) { 646 if (connection.second.IsNeedToDial()) { 647 ImsDialInfoStruct holdToDialInfo = connection.second.GetHoldToDialInfo(); 648 CellularCallConnectionIMS cellularCallConnectionIms; 649 cellularCallConnectionIms.DialRequest(slotId, holdToDialInfo); 650 connection.second.SetDialFlag(false); 651 break; 652 } 653 } 654} 655 656void IMSControl::RecoverPendingHold() 657{ 658 TELEPHONY_LOGI("RecoverPendingHold entry"); 659 std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_); 660 for (auto &connection : connectionMap_) { 661 if (connection.second.IsPendingHold()) { 662 connection.second.UpdatePendingHoldFlag(false); 663 break; 664 } 665 } 666} 667} // namespace Telephony 668} // namespace OHOS 669