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