• 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 "cs_control.h"
17 
18 #include "cellular_call_hisysevent.h"
19 #include "cellular_call_register.h"
20 #include "cellular_call_service.h"
21 #include "module_service_utils.h"
22 #include "securec.h"
23 #include "standardize_utils.h"
24 
25 namespace OHOS {
26 namespace Telephony {
27 
~CSControl()28 CSControl::~CSControl()
29 {
30     ReleaseAllConnection();
31 }
32 
Dial(const CellularCallInfo & callInfo,bool isEcc)33 int32_t CSControl::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 
43     ModuleServiceUtils moduleServiceUtils;
44     RegServiceState regState = moduleServiceUtils.GetCsRegState(callInfo.slotId);
45     if (!(regState == RegServiceState::REG_STATE_IN_SERVICE || isEcc)) {
46         TELEPHONY_LOGE("can not dial.");
47         return TELEPHONY_ERR_NETWORK_NOT_IN_SERVICE;
48     }
49     PhoneType netType = moduleServiceUtils.GetNetworkStatus(callInfo.slotId);
50     if (netType == PhoneType::PHONE_TYPE_IS_GSM) {
51         return DialGsm(callInfo);
52     }
53     if (netType == PhoneType::PHONE_TYPE_IS_CDMA) {
54         return DialCdma(callInfo);
55     }
56     TELEPHONY_LOGE("Dial return, net type error.");
57     CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType),
58         callInfo.videoState, CALL_ERR_UNSUPPORTED_NETWORK_TYPE, "Network type error");
59     return CALL_ERR_UNSUPPORTED_NETWORK_TYPE;
60 }
61 
DialCdma(const CellularCallInfo & callInfo)62 int32_t CSControl::DialCdma(const CellularCallInfo &callInfo)
63 {
64     TELEPHONY_LOGI("DialCdma entry.");
65     StandardizeUtils standardizeUtils;
66     // Remove the phone number separator
67     std::string newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(callInfo.phoneNum);
68 
69     CLIRMode clirMode = CLIRMode::DEFAULT;
70     if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, false)) {
71         TELEPHONY_LOGI("DialCdma return, mmi code type.");
72         return RETURN_TYPE_MMI;
73     }
74 
75     if (!CanCall(connectionMap_)) {
76         TELEPHONY_LOGE("CSControl::DialCdma return, error type: call state error.");
77         CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType),
78             callInfo.videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "cs cdma dial call state error");
79         return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT;
80     }
81 
82     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
83         TELEPHONY_LOGI("DialCdma, CDMA is have connection in active state.");
84         CellularCallConnectionCS csConnection;
85         return csConnection.SendCDMAThreeWayDialRequest(callInfo.slotId);
86     }
87 
88     return EncapsulateDialCommon(callInfo.slotId, newPhoneNum, clirMode);
89 }
90 
DialGsm(const CellularCallInfo & callInfo)91 int32_t CSControl::DialGsm(const CellularCallInfo &callInfo)
92 {
93     TELEPHONY_LOGI("DialGsm entry.");
94     StandardizeUtils standardizeUtils;
95     // Remove the phone number separator
96     std::string newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(callInfo.phoneNum);
97 
98     CLIRMode clirMode = CLIRMode::DEFAULT;
99     if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, false)) {
100         TELEPHONY_LOGI("DialGsm return, mmi code type.");
101         return RETURN_TYPE_MMI;
102     }
103 
104     if (!CanCall(connectionMap_)) {
105         TELEPHONY_LOGE("DialGsm return, error type: call state error.");
106         CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType),
107             callInfo.videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "cs gsm dial call state error");
108         return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT;
109     }
110 
111     // Calls can be put on hold, recovered, released, added to conversation,
112     // and transferred similarly as defined in 3GPP TS 22.030 [19].
113     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
114         // New calls must be active, so other calls need to be hold
115         TELEPHONY_LOGI("DialGsm, GSM is have connection in active state.");
116         CellularCallConnectionCS pConnection;
117 
118         // Delay dialing to prevent failure to add a new call while making a multi-party call
119         // Will it block the main thread or other threads? Will the reception of messages be blocked during sleep?
120         // - a call can be temporarily disconnected from the ME but the connection is retained by the network
121         pConnection.SwitchCallRequest(callInfo.slotId);
122     }
123     return EncapsulateDialCommon(callInfo.slotId, newPhoneNum, clirMode);
124 }
125 
EncapsulateDialCommon(int32_t slotId,const std::string & phoneNum,CLIRMode & clirMode)126 int32_t CSControl::EncapsulateDialCommon(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode)
127 {
128     pendingPhoneNumber_ = phoneNum;
129     DialRequestStruct dialRequest;
130     /**
131      * <idx>: integer type;
132      * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
133      * this number can be used in +CHLD command operations
134      * <dir>:
135      */
136     dialRequest.phoneNum = phoneNum;
137 
138     /**
139      * <n> (parameter sets the adjustment for outgoing calls):
140      *  0	presentation indicator is used according to the subscription of the CLIR service
141      *  1	CLIR invocation
142      *  2	CLIR suppression
143      */
144     dialRequest.clirMode = clirMode;
145 
146     /**
147      * An example of voice group call service request usage:
148      * ATD*17*753#500; (originate voice group call with the priority level 3)
149      * OK (voice group call setup was successful)
150      */
151     CellularCallConnectionCS csConnection;
152     TELEPHONY_LOGI("Set Mute to false");
153     if (DelayedSingleton<CellularCallService>::GetInstance() == nullptr) {
154         TELEPHONY_LOGE("SetMute return, error type: GetInstance() is nullptr.");
155         return CALL_ERR_RESOURCE_UNAVAILABLE;
156     }
157     DelayedSingleton<CellularCallService>::GetInstance()->SetMute(slotId, false);
158     return csConnection.DialRequest(slotId, dialRequest);
159 }
160 
HangUp(const CellularCallInfo & callInfo,CallSupplementType type)161 int32_t CSControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type)
162 {
163     TELEPHONY_LOGI("HangUp start");
164     switch (type) {
165         case CallSupplementType::TYPE_DEFAULT: {
166             // Match the session connection according to the phone number string
167             auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(
168                 connectionMap_, callInfo.index);
169             if (pConnection == nullptr) {
170                 TELEPHONY_LOGE("CSControl::HangUp, error type: connection is null");
171                 CellularCallHiSysEvent::WriteHangUpFaultEvent(
172                     callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "HangUp pConnection is null");
173                 return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
174             }
175 
176             if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
177                 DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
178                     pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
179             }
180 
181             /**
182              * The "directory number" case shall be handled with dial command D,
183              * and the END case with hangup command H (or +CHUP).
184              * (e.g. +CHLD: (0,1,1x,2,2x,3)).
185              * NOTE: Call Hold, MultiParty and Explicit Call Transfer are only applicable to teleservice 11.
186              */
187             return pConnection->HangUpRequest(callInfo.slotId);
188         }
189         // 3GPP TS 27.007 V3.9.0 (2001-06) Call related supplementary services +CHLD
190         // 3GPP TS 27.007 V3.9.0 (2001-06) 7.22 Informative examples
191         case CallSupplementType::TYPE_HANG_UP_HOLD_WAIT:
192         // release the second (active) call and recover the first (held) call
193         case CallSupplementType::TYPE_HANG_UP_ACTIVE: {
194             CellularCallConnectionCS connection;
195             return connection.CallSupplementRequest(callInfo.slotId, type);
196         }
197         case CallSupplementType::TYPE_HANG_UP_ALL: {
198             TELEPHONY_LOGI("HangUp, hang up all call");
199             CellularCallConnectionCS connection;
200             // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
201             // so the reject interface is reused.
202             return connection.RejectRequest(callInfo.slotId);
203         }
204         default: {
205             TELEPHONY_LOGE("HangUp warring, type is invalid");
206             CellularCallHiSysEvent::WriteHangUpFaultEvent(
207                 callInfo.slotId, callInfo.callId, TELEPHONY_ERR_ARGUMENT_INVALID, "HangUp type is invalid");
208             return TELEPHONY_ERR_ARGUMENT_INVALID;
209         }
210     }
211 }
212 
Answer(const CellularCallInfo & callInfo)213 int32_t CSControl::Answer(const CellularCallInfo &callInfo)
214 {
215     auto pConnection =
216         FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index);
217     if (pConnection == nullptr) {
218         TELEPHONY_LOGE("Answer return, error type: connection is null");
219         CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
220             CALL_ERR_CALL_CONNECTION_NOT_EXIST, "get connection data is null");
221         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
222     }
223 
224     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_HOLDING) &&
225         IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE)) {
226         int32_t ret = CheckAndHangupHoldingCall();
227         if (ret != TELEPHONY_SUCCESS) {
228             TELEPHONY_LOGE("hangup holding call failed");
229             return ret;
230         }
231     }
232     /**
233      * <stat> (state of the call):
234      * 0 active
235      * 1 held
236      * 2 dialing (MO call)
237      * 3 alerting (MO call)
238      * 4 incoming (MT call)
239      * 5 waiting (MT call)
240      */
241     // There is an active call when you call, or third party call waiting
242     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE) ||
243         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
244         TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
245         auto con = FindConnectionByState<CsConnectionMap &, CellularCallConnectionCS *>(
246             connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
247         if (con != nullptr) {
248             /**
249              * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up
250              * the call. +CMOD and +FCLASS commands indicate the current settings before dialling or answering
251              * command, not that they shall be given just before D or A command.
252              */
253             TELEPHONY_LOGI("Answer: There is an active session currently, and it needs to hold");
254             con->SwitchCallRequest(callInfo.slotId);
255         } else {
256             TELEPHONY_LOGE("Answer return, error type: con is null, there are no active calls");
257         }
258     }
259 
260     if (pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
261         pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
262         pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
263         return pConnection->AnswerRequest(callInfo.slotId);
264     }
265 
266     TELEPHONY_LOGE("CSControl::Answer return, error type: call state error, phone not ringing.");
267     CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
268         CALL_ERR_CALL_STATE, "call state error phone not ringing");
269     return CALL_ERR_CALL_STATE;
270 }
271 
CheckAndHangupHoldingCall()272 int32_t CSControl::CheckAndHangupHoldingCall()
273 {
274     for (auto &it : connectionMap_) {
275         CellularCallConnectionCS holdConn = it.second;
276         if (holdConn.GetStatus() == TelCallState::CALL_STATUS_HOLDING) {
277             auto callReportInfo = holdConn.GetCallReportInfo();
278             int32_t result = holdConn.HangUpRequest(callReportInfo.accountId);
279             if (result != TELEPHONY_SUCCESS) {
280                 return result;
281             }
282         }
283     }
284     return TELEPHONY_SUCCESS;
285 }
286 
Reject(const CellularCallInfo & callInfo)287 int32_t CSControl::Reject(const CellularCallInfo &callInfo)
288 {
289     auto pConnection =
290         FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callInfo.index);
291     if (pConnection == nullptr) {
292         TELEPHONY_LOGE("CSControl::Reject, error type: connection is null");
293         CellularCallHiSysEvent::WriteHangUpFaultEvent(
294             callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "Reject pConnection is null");
295         return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
296     }
297 
298     /**
299      * shows commands to start the call, to switch from voice to data (In Call Modification) and to hang up the call.
300      * +CMOD and +FCLASS commands indicate the current settings before dialling or answering command,
301      * not that they shall be given just before D or A command.
302      */
303     if (!pConnection->IsRingingState()) {
304         TELEPHONY_LOGE("CSControl::Reject return, error type: call state error, phone not ringing.");
305         CellularCallHiSysEvent::WriteHangUpFaultEvent(
306             callInfo.slotId, callInfo.callId, CALL_ERR_CALL_STATE, "Reject call state error phone not ringing");
307         return CALL_ERR_CALL_STATE;
308     }
309     if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
310         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
311             pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
312     }
313     return pConnection->RejectRequest(callInfo.slotId);
314 }
315 
HoldCall(int32_t slotId)316 int32_t CSControl::HoldCall(int32_t slotId)
317 {
318     /**
319      * When the call hold service is invoked, communication is interrupted on the traffic channel and the traffic
320      * channel is released from the existing call. The traffic channel is reserved for the served mobile subscriber
321      * invoking the call hold service. The served mobile subscriber can only have one call on hold at a time.
322      */
323     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
324         TELEPHONY_LOGE("HoldCall return, error type: call state error.");
325         return CALL_ERR_CALL_STATE;
326     }
327     CellularCallConnectionCS connection;
328     return connection.HoldRequest(slotId);
329 }
330 
UnHoldCall(int32_t slotId)331 int32_t CSControl::UnHoldCall(int32_t slotId)
332 {
333     // A notification shall be send towards the previously held party that the call has been retrieved.
334     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
335         TELEPHONY_LOGE("UnHoldCall return, error type: call state error.");
336         return CALL_ERR_CALL_STATE;
337     }
338     CellularCallConnectionCS connection;
339     return connection.UnHoldCallRequest(slotId);
340 }
341 
SwitchCall(int32_t slotId)342 int32_t CSControl::SwitchCall(int32_t slotId)
343 {
344     /**
345      * If the served mobile subscriber is connected to an active call and has another call on hold, she can:
346      * 1) Alternate from one call to the other.
347      * 2) Disconnect the active call.
348      * 3) Disconnect the held call.
349      * 4) Disconnect both calls.
350      */
351     if (IsInState(connectionMap_, TelCallState::CALL_STATUS_INCOMING)) {
352         TELEPHONY_LOGE("SwitchCall return, error type: call state error.");
353         return CALL_ERR_CALL_STATE;
354     }
355     CellularCallConnectionCS connection;
356     return connection.SwitchCallRequest(slotId);
357 }
358 
359 /**
360  * Explicitly choose one remote party to have a private communication with.
361  * This results in that remote party being removed from the multiParty call which is placed on hold,
362  * and the conversation between the served mobile subscriber and the designated remote party being a normal
363  * active call. The remaining remote parties may have communication with each other in this state.
364  */
SeparateConference(int32_t slotId,const std::string & splitString,int32_t index)365 int32_t CSControl::SeparateConference(int32_t slotId, const std::string &splitString, int32_t index)
366 {
367     if (splitString.empty()) {
368         TELEPHONY_LOGW("SeparateConference, splitString is empty.");
369     }
370 
371     auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, index);
372     if (pConnection != nullptr) {
373         return pConnection->SeparateConferenceRequest(slotId, pConnection->GetIndex(), VOICE_CALL);
374     }
375 
376     TELEPHONY_LOGI("SeparateConference: connection cannot be matched, use index directly");
377     CellularCallConnectionCS connection;
378     return connection.SeparateConferenceRequest(slotId, index, VOICE_CALL);
379 }
380 
381 /**
382  * Add another remote party, to which a private communication has been established using
383  * the same procedures as in Section 1.3.8.1, if the number of remote parties does not then
384  * exceed the maximum number allowed, which results in an active multiParty call.
385  */
CombineConference(int32_t slotId)386 int32_t CSControl::CombineConference(int32_t slotId)
387 {
388     CellularCallConnectionCS connectionCs;
389     return connectionCs.CombineConferenceRequest(slotId, VOICE_CALL);
390 }
391 
HangUpAllConnection(int32_t slotId)392 int32_t CSControl::HangUpAllConnection(int32_t slotId)
393 {
394     TELEPHONY_LOGI("HangUpAllConnection entry");
395     CellularCallConnectionCS connection;
396     // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
397     // so the reject interface is reused.
398     return connection.RejectRequest(slotId);
399 }
400 
CalculateInternationalRoaming(int32_t slotId) const401 bool CSControl::CalculateInternationalRoaming(int32_t slotId) const
402 {
403     bool ret = true;
404     ModuleServiceUtils moduleServiceUtils;
405     std::string operatorCountryIso = moduleServiceUtils.GetNetworkCountryCode(slotId);
406     std::string simCountryIso = moduleServiceUtils.GetIsoCountryCode(slotId);
407     ret = !operatorCountryIso.empty() && !simCountryIso.empty() && (operatorCountryIso != simCountryIso);
408     if (ret) {
409         if (simCountryIso == "us") {
410             ret = operatorCountryIso != "vi";
411         } else if (simCountryIso == "vi") {
412             ret = operatorCountryIso != "us";
413         }
414     }
415     return ret;
416 }
417 
ReportCallsData(int32_t slotId,const CallInfoList & callInfoList)418 int32_t CSControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
419 {
420     if (callInfoList.callSize <= 0 && !connectionMap_.empty()) {
421         return ReportHangUpInfo(slotId);
422     } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
423         return ReportIncomingInfo(slotId, callInfoList);
424     } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
425         return ReportUpdateInfo(slotId, callInfoList);
426     }
427     return TELEPHONY_ERROR;
428 }
429 
ReportUpdateInfo(int32_t slotId,const CallInfoList & callInfoList)430 int32_t CSControl::ReportUpdateInfo(int32_t slotId, const CallInfoList &callInfoList)
431 {
432     TELEPHONY_LOGD("ReportUpdateInfo entry");
433     CallsReportInfo callsReportInfo;
434     for (int32_t i = 0; i < callInfoList.callSize; ++i) {
435         CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
436         if (callInfoList.callSize == 1 && reportInfo.state == TelCallState::CALL_STATUS_WAITING) {
437             TELEPHONY_LOGI("only one call, report incoming state instead of waiting state");
438             reportInfo.state = TelCallState::CALL_STATUS_INCOMING;
439         }
440         auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(
441             connectionMap_, callInfoList.calls[i].index);
442         if (pConnection == nullptr) {
443             CellularCallConnectionCS connection;
444             connection.SetOrUpdateCallReportInfo(reportInfo);
445             connection.SetFlag(true);
446             connection.SetIndex(callInfoList.calls[i].index);
447             connection.SetNumber(callInfoList.calls[i].number);
448             SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
449         } else {
450             TelCallState preCallState = pConnection->GetStatus();
451             pConnection->SetFlag(true);
452             pConnection->SetIndex(callInfoList.calls[i].index);
453             pConnection->SetOrUpdateCallReportInfo(reportInfo);
454             pConnection->SetNumber(callInfoList.calls[i].number);
455             TelCallState curCallState = pConnection->GetStatus();
456             if (IsConnectedOut(preCallState, curCallState)) {
457                 pConnection->UpdateCallNumber(pendingPhoneNumber_);
458                 pendingPhoneNumber_.clear();
459                 ExecutePostDial(slotId, pConnection->GetIndex());
460             }
461         }
462         callsReportInfo.callVec.push_back(reportInfo);
463     }
464     callsReportInfo.slotId = slotId;
465     DeleteConnection(callsReportInfo, callInfoList);
466     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
467         TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
468         return TELEPHONY_ERR_LOCAL_PTR_NULL;
469     }
470     if (!isIgnoredIncomingCall_) {
471         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
472     }
473     return TELEPHONY_SUCCESS;
474 }
475 
DeleteConnection(CallsReportInfo & callsReportInfo,const CallInfoList & callInfoList)476 void CSControl::DeleteConnection(CallsReportInfo &callsReportInfo, const CallInfoList &callInfoList)
477 {
478     auto it = connectionMap_.begin();
479     while (it != connectionMap_.end()) {
480         CallReportInfo callReportInfo = it->second.GetCallReportInfo();
481         if (!it->second.GetFlag()) {
482             callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
483             callsReportInfo.callVec.push_back(callReportInfo);
484             connectionMap_.erase(it++);
485             GetCallFailReason(callsReportInfo.slotId, connectionMap_);
486         } else {
487             it->second.SetFlag(false);
488             ++it;
489         }
490     }
491 }
492 
EncapsulationCallReportInfo(int32_t slotId,const CallInfo & callInfo)493 CallReportInfo CSControl::EncapsulationCallReportInfo(int32_t slotId, const CallInfo &callInfo)
494 {
495     CallReportInfo callReportInfo;
496     if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
497         TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
498         return callReportInfo;
499     }
500     StandardizeUtils standardizeUtils;
501     std::string newString = standardizeUtils.FormatNumberAndToa(callInfo.number, callInfo.type);
502 
503     /**
504      * <idx>: integer type;
505      * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
506      * this number can be used in +CHLD command operations
507      * <dir>:
508      */
509     size_t cpyLen = strlen(newString.c_str()) + 1;
510     if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
511         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
512         return callReportInfo;
513     }
514     if (strcpy_s(callReportInfo.accountNum, cpyLen, newString.c_str()) != EOK) {
515         TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
516         return callReportInfo;
517     }
518 
519     /**
520      * <stat> (state of the call):
521      * 0 active
522      * 1 held
523      * 2 dialing (MO call)
524      * 3 alerting (MO call)
525      * 4 incoming (MT call)
526      * 5 waiting (MT call)
527      */
528     callReportInfo.index = callInfo.index;
529     callReportInfo.accountId = slotId;
530     callReportInfo.voiceDomain = callInfo.voiceDomain;
531     callReportInfo.state = static_cast<TelCallState>(callInfo.state);
532     callReportInfo.callType = CallType::TYPE_CS;
533     callReportInfo.callMode = VideoStateType::TYPE_VOICE;
534     callReportInfo.mpty = callInfo.mpty;
535     return callReportInfo;
536 }
537 
ReportIncomingInfo(int32_t slotId,const CallInfoList & callInfoList)538 int32_t CSControl::ReportIncomingInfo(int32_t slotId, const CallInfoList &callInfoList)
539 {
540     TELEPHONY_LOGI("ReportIncomingInfo entry");
541     CallsReportInfo callsReportInfo;
542     for (int32_t i = 0; i < callInfoList.callSize; ++i) {
543         CallReportInfo cellularCallReportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
544 
545         CellularCallConnectionCS connection;
546         connection.SetStatus(static_cast<TelCallState>(callInfoList.calls[i].state));
547         connection.SetIndex(callInfoList.calls[i].index);
548         connection.SetOrUpdateCallReportInfo(cellularCallReportInfo);
549         connection.SetNumber(callInfoList.calls[i].number);
550         SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
551 
552         callsReportInfo.callVec.push_back(cellularCallReportInfo);
553     }
554     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
555         TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
556         return TELEPHONY_ERR_ARGUMENT_INVALID;
557     }
558     callsReportInfo.slotId = slotId;
559     if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
560         callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
561         isIgnoredIncomingCall_ = true;
562     } else {
563         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
564     }
565     return TELEPHONY_SUCCESS;
566 }
567 
ReportHangUpInfo(int32_t slotId)568 int32_t CSControl::ReportHangUpInfo(int32_t slotId)
569 {
570     TELEPHONY_LOGD("ReportHangUpInfo entry");
571     CallsReportInfo callsReportInfo;
572     for (auto &it : connectionMap_) {
573         CallReportInfo callReportInfo = it.second.GetCallReportInfo();
574         callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
575         callReportInfo.accountId = slotId;
576         callsReportInfo.callVec.push_back(callReportInfo);
577         GetCallFailReason(slotId, connectionMap_);
578     }
579     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
580         TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
581         return TELEPHONY_ERR_LOCAL_PTR_NULL;
582     }
583     callsReportInfo.slotId = slotId;
584     if (isIgnoredIncomingCall_) {
585         isIgnoredIncomingCall_ = false;
586     } else {
587         DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
588     }
589     ReleaseAllConnection();
590     return TELEPHONY_SUCCESS;
591 }
592 
ExecutePostDial(int32_t slotId,int64_t callId)593 int32_t CSControl::ExecutePostDial(int32_t slotId, int64_t callId)
594 {
595     if (connectionMap_.empty()) {
596         TELEPHONY_LOGE("connectionMap_ is empty.");
597         return TELEPHONY_ERROR;
598     }
599     auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(connectionMap_, callId);
600     if (pConnection == nullptr) {
601         return TELEPHONY_ERR_LOCAL_PTR_NULL;
602     }
603     char currentChar;
604     PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
605     switch (state) {
606         case PostDialCallState::POST_DIAL_CALL_STARTED:
607             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
608             break;
609         case PostDialCallState::POST_DIAL_CALL_DELAY:
610             DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
611                 pConnection->GetLeftPostDialCallString());
612             break;
613         default:
614             break;
615     }
616     return TELEPHONY_SUCCESS;
617 }
618 
PostDialProceed(const CellularCallInfo & callInfo,const bool proceed)619 int32_t CSControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
620 {
621     std::string networkAddress;
622     std::string postDialString;
623     StandardizeUtils standardizeUtils;
624     standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
625     auto pConnection = FindConnectionByIndex<CsConnectionMap &, CellularCallConnectionCS *>(
626         connectionMap_, callInfo.index);
627     if (pConnection == nullptr) {
628         TELEPHONY_LOGE("cs pConnection is nullptr!");
629         return TELEPHONY_ERR_LOCAL_PTR_NULL;
630     }
631     if (proceed) {
632         ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
633     } else {
634         pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
635     }
636     return TELEPHONY_SUCCESS;
637 }
638 
ReleaseAllConnection()639 void CSControl::ReleaseAllConnection()
640 {
641     connectionMap_.clear();
642 }
643 
GetConnectionMap()644 CsConnectionMap CSControl::GetConnectionMap()
645 {
646     return connectionMap_;
647 }
648 
ReportHangUp(const std::vector<CellularCallInfo> & infos,int32_t slotId)649 int32_t CSControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
650 {
651     CallsReportInfo callsReportInfo;
652     callsReportInfo.slotId = slotId;
653     for (const auto &info : infos) {
654         if (info.callType == CallType::TYPE_CS && info.slotId == slotId) {
655             CallReportInfo csCallReportInfo;
656             if (memset_s(csCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
657                 TELEPHONY_LOGE("memset_s fail");
658                 return TELEPHONY_ERR_MEMSET_FAIL;
659             }
660             if (memcpy_s(csCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
661                 TELEPHONY_LOGE("memcpy_s fail");
662                 return TELEPHONY_ERR_MEMCPY_FAIL;
663             }
664             csCallReportInfo.index = info.index;
665             csCallReportInfo.accountId = info.slotId;
666             csCallReportInfo.callType = CallType::TYPE_CS;
667             csCallReportInfo.callMode = VideoStateType::TYPE_VOICE;
668             csCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
669             callsReportInfo.callVec.push_back(csCallReportInfo);
670         }
671     }
672     if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
673         TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
674         return TELEPHONY_ERR_LOCAL_PTR_NULL;
675     }
676     DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
677     ReleaseAllConnection();
678     return TELEPHONY_SUCCESS;
679 }
680 } // namespace Telephony
681 } // namespace OHOS
682