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     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 
EncapsulateDial( int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode, int32_t videoState) const92 int32_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 
HangUp(const CellularCallInfo &callInfo, CallSupplementType type)127 int32_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 
Answer(const CellularCallInfo &callInfo)166 int32_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 
CheckAndHangupHoldingCall()201 int32_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 
Reject(const CellularCallInfo &callInfo)217 int32_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 
HoldCall(int32_t slotId)238 int32_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 
UnHoldCall(int32_t slotId)250 int32_t IMSControl::UnHoldCall(int32_t slotId)
251 {
252     TELEPHONY_LOGI("UnHoldCall start");
253     CellularCallConnectionIMS cellularCallConnectionIms;
254     return cellularCallConnectionIms.UnHoldCallRequest(slotId);
255 }
256 
SwitchCall(int32_t slotId)257 int32_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  */
CombineConference(int32_t slotId)269 int32_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 
HangUpAllConnection(int32_t slotId)277 int32_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 
InviteToConference(int32_t slotId, const std::vector<std::string> &numberList)296 int32_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 
KickOutFromConference(int32_t slotId, const std::string &KickOutString, int32_t index)303 int32_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 
StartRtt(int32_t slotId, const std::string &msg)321 int32_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 
StopRtt(int32_t slotId)328 int32_t IMSControl::StopRtt(int32_t slotId)
329 {
330     TELEPHONY_LOGI("StopRtt entry");
331     CellularCallConnectionIMS connection;
332     return connection.StopRttRequest(slotId);
333 }
334 
ReleaseAllConnection()335 void IMSControl::ReleaseAllConnection()
336 {
337     TELEPHONY_LOGI("ReleaseAllConnection entry");
338     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
339     connectionMap_.clear();
340 }
341 
GetConnectionMap()342 ImsConnectionMap IMSControl::GetConnectionMap()
343 {
344     TELEPHONY_LOGI("GetConnectionMap entry");
345     std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
346     return connectionMap_;
347 }
348 
ReportImsCallsData(int32_t slotId, const ImsCurrentCallList &callInfoList)349 int32_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 
ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)362 int32_t IMSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
363 {
364     return TELEPHONY_ERROR;
365 }
366 
ReportHangUpInfo(int32_t slotId)367 int32_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 
ReportIncomingInfo(int32_t slotId, const ImsCurrentCallList &imsCurrentCallInfoList)399 int32_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 
ReportUpdateInfo(int32_t slotId, const ImsCurrentCallList &callInfoList)429 int32_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 
EncapsulationCallReportInfo(int32_t slotId, const ImsCurrentCall &callInfo)477 CallReportInfo 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 
DeleteConnection(CallsReportInfo &callsReportInfo, const ImsCurrentCallList &callInfoList)526 void 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 
ExecutePostDial(int32_t slotId, int64_t callId)544 int32_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 
PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)572 int32_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 
RestoreConnection(const std::vector<CellularCallInfo> &infos, int32_t slotId)594 int32_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 
ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)609 int32_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 
DialAfterHold(int32_t slotId)641 void 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 
RecoverPendingHold()656 void 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