1/*
2 * Copyright (C) 2023 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 "satellite_control.h"
17
18#include "cellular_call_hisysevent.h"
19#include "cellular_call_register.h"
20#include "module_service_utils.h"
21#include "securec.h"
22#include "standardize_utils.h"
23
24namespace OHOS {
25namespace Telephony {
26
27SatelliteControl::~SatelliteControl()
28{
29    ReleaseAllConnection();
30}
31
32int32_t SatelliteControl::Dial(const CellularCallInfo &callInfo, bool isEcc)
33{
34    TELEPHONY_LOGI("DialSatellite start");
35    DelayedSingleton<CellularCallHiSysEvent>::GetInstance()->SetCallParameterInfo(
36        callInfo.slotId, static_cast<int32_t>(callInfo.callType), callInfo.videoState);
37    int32_t ret = DialPreJudgment(callInfo, false);
38    if (ret != TELEPHONY_SUCCESS) {
39        return ret;
40    }
41    StandardizeUtils standardizeUtils;
42    // Remove the phone number separator
43    std::string newPhoneNum = standardizeUtils.RemoveSeparatorsPhoneNumber(callInfo.phoneNum);
44
45    CLIRMode clirMode = CLIRMode::DEFAULT;
46    if (IsNeedExecuteMMI(callInfo.slotId, newPhoneNum, clirMode, false)) {
47        TELEPHONY_LOGI("DialSatellite return, mmi code type.");
48        return RETURN_TYPE_MMI;
49    }
50
51    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
52    if (!CanCall(connectionMap_)) {
53        TELEPHONY_LOGE("DialSatellite return, error type: call state error.");
54        CellularCallHiSysEvent::WriteDialCallFaultEvent(callInfo.slotId, static_cast<int32_t>(callInfo.callType),
55            callInfo.videoState, CALL_ERR_CALL_COUNTS_EXCEED_LIMIT, "DSatellite dial call state error");
56        return CALL_ERR_CALL_COUNTS_EXCEED_LIMIT;
57    }
58
59    return EncapsulateDialCommon(callInfo.slotId, newPhoneNum, clirMode);
60}
61
62int32_t SatelliteControl::EncapsulateDialCommon(int32_t slotId, const std::string &phoneNum, CLIRMode &clirMode)
63{
64    pendingPhoneNumber_ = phoneNum;
65    DialRequestStruct dialRequest;
66    /**
67     * <idx>: integer type;
68     * call identification number as described in 3GPP TS 22.030 [19] subclause 4.5.5.1
69     * this number can be used in +CHLD command operations
70     * <dir>:
71     */
72    dialRequest.phoneNum = phoneNum;
73
74    /**
75     * <n> (parameter sets the adjustment for outgoing calls):
76     *  0	presentation indicator is used according to the subscription of the CLIR service
77     *  1	CLIR invocation
78     *  2	CLIR suppression
79     */
80    dialRequest.clirMode = clirMode;
81
82    /**
83     * An example of voice group call service request usage:
84     * ATD*17*753#500; (originate voice group call with the priority level 3)
85     * OK (voice group call setup was successful)
86     */
87    CellularCallConnectionSatellite satelliteConnection;
88    return satelliteConnection.DialRequest(slotId, dialRequest);
89}
90
91int32_t SatelliteControl::HangUp(const CellularCallInfo &callInfo, CallSupplementType type)
92{
93    TELEPHONY_LOGI("HangUp start");
94    switch (type) {
95        case CallSupplementType::TYPE_DEFAULT: {
96            // Match the session connection according to the phone number string
97            std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
98            auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
99                connectionMap_, callInfo.index);
100            if (pConnection == nullptr) {
101                TELEPHONY_LOGE("HangUp, error type: connection is null");
102                CellularCallHiSysEvent::WriteHangUpFaultEvent(
103                    callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "HangUp pConnection is null");
104                return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
105            }
106
107            if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
108                DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
109                    pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
110            }
111            return pConnection->HangUpRequest(callInfo.slotId);
112        }
113        default: {
114            TELEPHONY_LOGE("HangUp warring, type is invalid");
115            CellularCallHiSysEvent::WriteHangUpFaultEvent(
116                callInfo.slotId, callInfo.callId, TELEPHONY_ERR_ARGUMENT_INVALID, "HangUp type is invalid");
117            return TELEPHONY_ERR_ARGUMENT_INVALID;
118        }
119    }
120}
121
122int32_t SatelliteControl::Answer(const CellularCallInfo &callInfo)
123{
124    TELEPHONY_LOGI("SatelliteControl::Answer start");
125    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
126    auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
127        connectionMap_, callInfo.index);
128    if (pConnection == nullptr) {
129        TELEPHONY_LOGE("Answer return, error type: connection is null");
130        CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
131            CALL_ERR_CALL_CONNECTION_NOT_EXIST, "get connection data is null");
132        return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
133    }
134    // There is an active call when you call, or third party call waiting
135    if (IsInState(connectionMap_, TelCallState::CALL_STATUS_ACTIVE) ||
136        pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
137        TELEPHONY_LOGI("Answer there is an active call when you call, or third party call waiting");
138        auto con = FindConnectionByState<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
139            connectionMap_, TelCallState::CALL_STATUS_ACTIVE);
140        if (con != nullptr) {
141            TELEPHONY_LOGI("Answer: There is an active session currently, and it needs to hold");
142            con->HangUpRequest(callInfo.slotId);
143        } else {
144            TELEPHONY_LOGE("Answer return, error type: con is null, there are no active calls");
145        }
146    }
147
148    if (pConnection->GetStatus() == TelCallState::CALL_STATUS_INCOMING ||
149        pConnection->GetStatus() == TelCallState::CALL_STATUS_ALERTING ||
150        pConnection->GetStatus() == TelCallState::CALL_STATUS_WAITING) {
151        return pConnection->AnswerRequest(callInfo.slotId);
152    }
153
154    TELEPHONY_LOGE("SatelliteControl::Answer return, error type: call state error, phone not ringing.");
155    CellularCallHiSysEvent::WriteAnswerCallFaultEvent(callInfo.slotId, callInfo.callId, callInfo.videoState,
156        CALL_ERR_CALL_STATE, "call state error phone not ringing");
157    return CALL_ERR_CALL_STATE;
158}
159
160int32_t SatelliteControl::Reject(const CellularCallInfo &callInfo)
161{
162    TELEPHONY_LOGI("SatelliteControl::Reject start");
163    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
164    auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
165        connectionMap_, callInfo.index);
166    if (pConnection == nullptr) {
167        TELEPHONY_LOGE("SatelliteControl::Reject, error type: connection is null");
168        CellularCallHiSysEvent::WriteHangUpFaultEvent(
169            callInfo.slotId, callInfo.callId, CALL_ERR_CALL_CONNECTION_NOT_EXIST, "Reject pConnection is null");
170        return CALL_ERR_CALL_CONNECTION_NOT_EXIST;
171    }
172    if (!pConnection->IsRingingState()) {
173        TELEPHONY_LOGE("CSControl::Reject return, error type: call state error, phone not ringing.");
174        CellularCallHiSysEvent::WriteHangUpFaultEvent(
175            callInfo.slotId, callInfo.callId, CALL_ERR_CALL_STATE, "Reject call state error phone not ringing");
176        return CALL_ERR_CALL_STATE;
177    }
178    if (DelayedSingleton<CellularCallRegister>::GetInstance() != nullptr) {
179        DelayedSingleton<CellularCallRegister>::GetInstance()->ReportSingleCallInfo(
180            pConnection->GetCallReportInfo(), TelCallState::CALL_STATUS_DISCONNECTING);
181    }
182    return pConnection->RejectRequest(callInfo.slotId);
183}
184
185int32_t SatelliteControl::ReportSatelliteCallsData(int32_t slotId, const SatelliteCurrentCallList &callInfoList)
186{
187    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
188    if (callInfoList.callSize <= 0) {
189        return ReportHangUpInfo(slotId);
190    } else if (callInfoList.callSize > 0 && connectionMap_.empty()) {
191        return ReportIncomingInfo(slotId, callInfoList);
192    } else if (callInfoList.callSize > 0 && !connectionMap_.empty()) {
193        return ReportUpdateInfo(slotId, callInfoList);
194    }
195    return TELEPHONY_ERROR;
196}
197
198int32_t SatelliteControl::ReportUpdateInfo(int32_t slotId, const SatelliteCurrentCallList &callInfoList)
199{
200    TELEPHONY_LOGD("ReportUpdateInfo entry");
201    CallsReportInfo callsReportInfo;
202    for (int32_t i = 0; i < callInfoList.callSize; ++i) {
203        CallReportInfo reportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
204
205        auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
206            connectionMap_, callInfoList.calls[i].index);
207        if (pConnection == nullptr) {
208            CellularCallConnectionSatellite connection;
209            connection.SetOrUpdateCallReportInfo(reportInfo);
210            connection.SetFlag(true);
211            connection.SetIndex(callInfoList.calls[i].index);
212            connection.SetNumber(callInfoList.calls[i].number);
213            SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
214        } else {
215            pConnection->SetFlag(true);
216            pConnection->SetIndex(callInfoList.calls[i].index);
217            pConnection->SetOrUpdateCallReportInfo(reportInfo);
218            pConnection->SetNumber(callInfoList.calls[i].number);
219        }
220        callsReportInfo.callVec.push_back(reportInfo);
221    }
222    callsReportInfo.slotId = slotId;
223    DeleteConnection(callsReportInfo, callInfoList);
224    if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
225        TELEPHONY_LOGE("ReportUpdateInfo return, GetInstance() is nullptr.");
226        return TELEPHONY_ERR_LOCAL_PTR_NULL;
227    }
228    if (!isIgnoredIncomingCall_) {
229        DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
230    }
231    return TELEPHONY_SUCCESS;
232}
233
234void SatelliteControl::DeleteConnection(CallsReportInfo &callsReportInfo, const SatelliteCurrentCallList &callInfoList)
235{
236    TELEPHONY_LOGI("DeleteConnection entry");
237    auto it = connectionMap_.begin();
238    while (it != connectionMap_.end()) {
239        CallReportInfo callReportInfo = it->second.GetCallReportInfo();
240        if (!it->second.GetFlag()) {
241            callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
242            callsReportInfo.callVec.push_back(callReportInfo);
243            it = connectionMap_.erase(it);
244            GetCallFailReason(callsReportInfo.slotId, connectionMap_);
245        } else {
246            it->second.SetFlag(false);
247            ++it;
248        }
249    }
250}
251
252CallReportInfo SatelliteControl::EncapsulationCallReportInfo(int32_t slotId, const SatelliteCurrentCall &callInfo)
253{
254    CallReportInfo callReportInfo;
255    if (memset_s(&callReportInfo, sizeof(callReportInfo), 0, sizeof(callReportInfo)) != EOK) {
256        TELEPHONY_LOGE("EncapsulationCallReportInfo return, memset_s fail.");
257        return callReportInfo;
258    }
259    size_t cpyLen = strlen(callInfo.number.c_str()) + 1;
260    if (cpyLen > static_cast<size_t>(kMaxNumberLen + 1)) {
261        TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
262        return callReportInfo;
263    }
264    if (strcpy_s(callReportInfo.accountNum, cpyLen, callInfo.number.c_str()) != EOK) {
265        TELEPHONY_LOGE("EncapsulationCallReportInfo return, strcpy_s fail.");
266        return callReportInfo;
267    }
268    callReportInfo.index = callInfo.index;
269    callReportInfo.accountId = slotId;
270    callReportInfo.voiceDomain = callInfo.voiceDomain;
271    callReportInfo.state = static_cast<TelCallState>(callInfo.state);
272    callReportInfo.callType = CallType::TYPE_SATELLITE;
273    callReportInfo.callMode = VideoStateType::TYPE_VOICE;
274    callReportInfo.mpty = callInfo.mpty;
275    return callReportInfo;
276}
277
278int32_t SatelliteControl::ReportIncomingInfo(int32_t slotId, const SatelliteCurrentCallList &callInfoList)
279{
280    TELEPHONY_LOGI("ReportIncomingInfo entry");
281    CallsReportInfo callsReportInfo;
282    for (int32_t i = 0; i < callInfoList.callSize; ++i) {
283        CallReportInfo cellularCallReportInfo = EncapsulationCallReportInfo(slotId, callInfoList.calls[i]);
284
285        CellularCallConnectionSatellite connection;
286        connection.SetStatus(static_cast<TelCallState>(callInfoList.calls[i].state));
287        connection.SetIndex(callInfoList.calls[i].index);
288        connection.SetOrUpdateCallReportInfo(cellularCallReportInfo);
289        connection.SetNumber(callInfoList.calls[i].number);
290        SetConnectionData(connectionMap_, callInfoList.calls[i].index, connection);
291
292        callsReportInfo.callVec.push_back(cellularCallReportInfo);
293    }
294    if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
295        TELEPHONY_LOGE("ReportIncomingInfo return, GetInstance() is nullptr.");
296        return TELEPHONY_ERR_ARGUMENT_INVALID;
297    }
298    callsReportInfo.slotId = slotId;
299    if (!DelayedSingleton<CellularCallRegister>::GetInstance()->IsCallManagerCallBackRegistered() &&
300        callsReportInfo.callVec.size() != 0 && callsReportInfo.callVec[0].state == TelCallState::CALL_STATUS_INCOMING) {
301        isIgnoredIncomingCall_ = true;
302    } else {
303        DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
304    }
305    return TELEPHONY_SUCCESS;
306}
307
308int32_t SatelliteControl::ReportHangUpInfo(int32_t slotId)
309{
310    TELEPHONY_LOGD("ReportHangUpInfo entry");
311    CallsReportInfo callsReportInfo;
312    for (auto &it : connectionMap_) {
313        CallReportInfo callReportInfo = it.second.GetCallReportInfo();
314        callReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
315        callReportInfo.accountId = slotId;
316        callsReportInfo.callVec.push_back(callReportInfo);
317        GetCallFailReason(slotId, connectionMap_);
318    }
319    if (connectionMap_.empty()) {
320        TELEPHONY_LOGI("connectionMap_ is empty");
321        CallReportInfo reportInfo;
322        reportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
323        reportInfo.accountId = slotId;
324        callsReportInfo.callVec.push_back(reportInfo);
325    }
326    if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
327        TELEPHONY_LOGE("ReportHangUpInfo return, GetInstance() is nullptr.");
328        return TELEPHONY_ERR_LOCAL_PTR_NULL;
329    }
330    callsReportInfo.slotId = slotId;
331    if (isIgnoredIncomingCall_) {
332        isIgnoredIncomingCall_ = false;
333    } else {
334        DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
335    }
336    ReleaseAllConnection();
337    return TELEPHONY_SUCCESS;
338}
339
340void SatelliteControl::ReleaseAllConnection()
341{
342    TELEPHONY_LOGI("ReleaseAllConnection entry");
343    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
344    connectionMap_.clear();
345}
346
347SatelliteConnectionMap SatelliteControl::GetConnectionMap()
348{
349    TELEPHONY_LOGI("GetConnectionMap entry");
350    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
351    return connectionMap_;
352}
353
354int32_t SatelliteControl::ReportHangUp(const std::vector<CellularCallInfo> &infos, int32_t slotId)
355{
356    CallsReportInfo callsReportInfo;
357    callsReportInfo.slotId = slotId;
358    for (const auto &info : infos) {
359        if (info.callType == CallType::TYPE_SATELLITE && info.slotId == slotId) {
360            CallReportInfo satelliteCallReportInfo;
361            if (memset_s(satelliteCallReportInfo.accountNum, kMaxNumberLen + 1, 0, kMaxNumberLen + 1) != EOK) {
362                TELEPHONY_LOGE("memset_s fail");
363                return TELEPHONY_ERR_MEMSET_FAIL;
364            }
365            if (memcpy_s(satelliteCallReportInfo.accountNum, kMaxNumberLen, info.phoneNum, kMaxNumberLen) != EOK) {
366                TELEPHONY_LOGE("memcpy_s fail");
367                return TELEPHONY_ERR_MEMCPY_FAIL;
368            }
369            satelliteCallReportInfo.index = info.index;
370            satelliteCallReportInfo.accountId = info.slotId;
371            satelliteCallReportInfo.callType = CallType::TYPE_SATELLITE;
372            satelliteCallReportInfo.callMode = VideoStateType::TYPE_VOICE;
373            satelliteCallReportInfo.state = TelCallState::CALL_STATUS_DISCONNECTED;
374            callsReportInfo.callVec.push_back(satelliteCallReportInfo);
375        }
376    }
377    if (DelayedSingleton<CellularCallRegister>::GetInstance() == nullptr) {
378        TELEPHONY_LOGE("CellularCallRegister instance is nullptr");
379        return TELEPHONY_ERR_LOCAL_PTR_NULL;
380    }
381    DelayedSingleton<CellularCallRegister>::GetInstance()->ReportCallsInfo(callsReportInfo);
382    ReleaseAllConnection();
383    return TELEPHONY_SUCCESS;
384}
385
386int32_t SatelliteControl::HoldCall(int32_t slotId)
387{
388    return TELEPHONY_ERROR;
389}
390
391int32_t SatelliteControl::UnHoldCall(int32_t slotId)
392{
393    return TELEPHONY_ERROR;
394}
395
396int32_t SatelliteControl::SwitchCall(int32_t slotId)
397{
398    return TELEPHONY_ERROR;
399}
400
401int32_t SatelliteControl::CombineConference(int32_t slotId)
402{
403    return TELEPHONY_ERROR;
404}
405
406int32_t SatelliteControl::HangUpAllConnection(int32_t slotId)
407{
408    TELEPHONY_LOGI("HangUpAllConnection entry");
409    CellularCallConnectionSatellite connection;
410    // The AT command for hanging up all calls is the same as the AT command for rejecting calls,
411    // so the reject interface is reused.
412    connection.RejectRequest(slotId);
413    return TELEPHONY_SUCCESS;
414}
415
416int32_t SatelliteControl::ReportCallsData(int32_t slotId, const CallInfoList &callInfoList)
417{
418    return TELEPHONY_ERROR;
419}
420
421int32_t SatelliteControl::ExecutePostDial(int32_t slotId, int64_t callId)
422{
423    TELEPHONY_LOGI("ExecutePostDial entry");
424    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
425    if (connectionMap_.empty()) {
426        TELEPHONY_LOGE("connectionMap_ is empty.");
427        return TELEPHONY_ERROR;
428    }
429    auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &,
430        CellularCallConnectionSatellite *>(connectionMap_, callId);
431    if (pConnection == nullptr) {
432        return TELEPHONY_ERR_LOCAL_PTR_NULL;
433    }
434    char currentChar;
435    PostDialCallState state = pConnection->ProcessNextChar(slotId, currentChar);
436    switch (state) {
437        case PostDialCallState::POST_DIAL_CALL_STARTED:
438            DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialChar(currentChar);
439            break;
440        case PostDialCallState::POST_DIAL_CALL_DELAY:
441            DelayedSingleton<CellularCallRegister>::GetInstance()->ReportPostDialDelay(
442                pConnection->GetLeftPostDialCallString());
443            break;
444        default:
445            break;
446    }
447    return TELEPHONY_SUCCESS;
448}
449
450int32_t SatelliteControl::PostDialProceed(const CellularCallInfo &callInfo, const bool proceed)
451{
452    TELEPHONY_LOGI("PostDialProceed entry");
453    std::string networkAddress;
454    std::string postDialString;
455    StandardizeUtils standardizeUtils;
456    standardizeUtils.ExtractAddressAndPostDial(callInfo.phoneNum, networkAddress, postDialString);
457    std::lock_guard<std::recursive_mutex> lock(connectionMapMutex_);
458    auto pConnection = FindConnectionByIndex<SatelliteConnectionMap &, CellularCallConnectionSatellite *>(
459        connectionMap_, callInfo.index);
460    if (pConnection == nullptr) {
461        TELEPHONY_LOGE("cs pConnection is nullptr!");
462        return TELEPHONY_ERR_LOCAL_PTR_NULL;
463    }
464    if (proceed) {
465        ExecutePostDial(callInfo.slotId, pConnection->GetIndex());
466    } else {
467        pConnection->SetPostDialCallState(PostDialCallState::POST_DIAL_CALL_CANCELED);
468    }
469    return TELEPHONY_SUCCESS;
470}
471} // namespace Telephony
472} // namespace OHOS
473