• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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