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