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