1/*
2 * Copyright (C) 2021-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 "sms_misc_manager.h"
17
18#include "core_manager_inner.h"
19#include "short_message.h"
20#include "sms_mms_errors.h"
21#include "string_utils.h"
22#include "telephony_common_utils.h"
23#include "telephony_log_wrapper.h"
24
25namespace OHOS {
26namespace Telephony {
27static constexpr int32_t WAIT_TIME_SECOND = 1;
28static constexpr int32_t TIME_OUT_SECOND = 3;
29static constexpr uint8_t GSM_TYPE = 1;
30static constexpr uint8_t MIN_SMSC_LEN = 2;
31static constexpr uint32_t RANG_MAX = 65535;
32bool SmsMiscManager::hasGotCbRange_ = false;
33
34SmsMiscManager::SmsMiscManager(int32_t slotId) : TelEventHandler("SmsMiscManager"), slotId_(slotId) {}
35
36int32_t SmsMiscManager::SetCBConfig(bool enable, uint32_t fromMsgId, uint32_t toMsgId, uint8_t netType)
37{
38    bool ret = false;
39    if ((toMsgId > RANG_MAX) || (fromMsgId > toMsgId) || (netType != GSM_TYPE)) {
40        TELEPHONY_LOGI("cb channel invalid");
41        return TELEPHONY_ERR_ARGUMENT_INVALID;
42    }
43    std::unique_lock<std::mutex> lock(cbMutex_);
44    if (!hasGotCbRange_) {
45        GetModemCBRange();
46        if (mdRangeList_.size() != 0) {
47            if (!SendDataToRil(false, mdRangeList_)) {
48                return TELEPHONY_ERR_RIL_CMD_FAIL;
49            }
50            mdRangeList_.clear();
51        }
52    }
53    std::list<gsmCBRangeInfo> oldRangeList = rangeList_;
54    if (enable) {
55        ret = OpenCBRange(fromMsgId, toMsgId);
56    } else {
57        ret = CloseCBRange(fromMsgId, toMsgId);
58    }
59    if (ret) {
60        if (!SendDataToRil(false, oldRangeList)) {
61            rangeList_ = oldRangeList;
62            return TELEPHONY_ERR_RIL_CMD_FAIL;
63        }
64        if (!SendDataToRil(true, rangeList_)) {
65            rangeList_ = oldRangeList;
66            return TELEPHONY_ERR_RIL_CMD_FAIL;
67        }
68    } else {
69        rangeList_ = oldRangeList;
70    }
71    return TELEPHONY_ERR_SUCCESS;
72}
73
74std::list<SmsMiscManager::gsmCBRangeInfo> SmsMiscManager::GetRangeInfo() const
75{
76    return rangeList_;
77}
78
79// from 3GPP TS 27.005 3.3.4 Select Cell Broadcast Message Types
80bool SmsMiscManager::OpenCBRange(uint32_t fromMsgId, uint32_t toMsgId)
81{
82    infoData data(fromMsgId, toMsgId);
83    rangeList_.emplace_back(fromMsgId, toMsgId);
84    CombineCBRange();
85    return true;
86}
87
88void SmsMiscManager::SplitMsgId(
89    uint32_t fromMsgId, uint32_t toMsgId, const std::list<gsmCBRangeInfo>::iterator &oldIter)
90{
91    auto &info = *oldIter;
92    if (fromMsgId == UINT32_MAX || fromMsgId < 1) {
93        return;
94    }
95    rangeList_.emplace_back(info.fromMsgId, fromMsgId - 1);
96    rangeList_.emplace_back(toMsgId + 1, info.toMsgId);
97    rangeList_.erase(oldIter);
98}
99
100// from 3GPP TS 27.005 3.3.4 Select Cell Broadcast Message Types
101bool SmsMiscManager::CloseCBRange(uint32_t fromMsgId, uint32_t toMsgId)
102{
103    if (fromMsgId == UINT32_MAX || fromMsgId < 1) {
104        return false;
105    }
106
107    auto iter = rangeList_.begin();
108    while (iter != rangeList_.end()) {
109        auto oldIter = iter++;
110        auto &info = *oldIter;
111        if (fromMsgId == info.fromMsgId && toMsgId == info.toMsgId) {
112            rangeList_.erase(oldIter);
113            continue;
114        } else if (fromMsgId == info.fromMsgId && toMsgId > info.toMsgId) {
115            rangeList_.erase(oldIter);
116            continue;
117        } else if (fromMsgId == info.fromMsgId && toMsgId < info.toMsgId) {
118            rangeList_.emplace_back(toMsgId + 1, info.toMsgId);
119            rangeList_.erase(oldIter);
120            continue;
121        } else if (fromMsgId < info.fromMsgId && toMsgId == info.toMsgId) {
122            rangeList_.erase(oldIter);
123            continue;
124        } else if (fromMsgId > info.fromMsgId && toMsgId == info.toMsgId) {
125            rangeList_.emplace_back(info.fromMsgId, fromMsgId - 1);
126            rangeList_.erase(oldIter);
127            continue;
128        } else if (fromMsgId > info.fromMsgId && toMsgId < info.toMsgId) {
129            SplitMsgId(fromMsgId, toMsgId, oldIter);
130            continue;
131        } else if (fromMsgId > info.fromMsgId && fromMsgId <= info.toMsgId) {
132            rangeList_.emplace_back(info.fromMsgId, fromMsgId - 1);
133            rangeList_.erase(oldIter);
134            continue;
135        } else if (fromMsgId < info.fromMsgId && toMsgId > info.toMsgId) {
136            rangeList_.erase(oldIter);
137            continue;
138        } else if (toMsgId < info.toMsgId && toMsgId >= info.fromMsgId) {
139            rangeList_.emplace_back(toMsgId + 1, info.toMsgId);
140            rangeList_.erase(oldIter);
141            continue;
142        }
143    }
144    CombineCBRange();
145    return true;
146}
147
148void SmsMiscManager::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
149{
150    if (event == nullptr) {
151        TELEPHONY_LOGE("SmsMiscManager ProcessEvent event == nullptr");
152        return;
153    }
154
155    uint32_t eventId = 0;
156    eventId = event->GetInnerEventId();
157    switch (eventId) {
158        case SET_CB_CONFIG_FINISH: {
159            TELEPHONY_LOGD("SmsMiscManager::ProcessEvent Set cb config finish");
160            isSuccess_ = true;
161            std::shared_ptr<RadioResponseInfo> res = event->GetSharedObject<RadioResponseInfo>();
162            if (res != nullptr) {
163                isSuccess_ = (res->error == ErrType::NONE);
164            }
165            NotifyHasResponse();
166            break;
167        }
168        case GET_CB_CONFIG_FINISH: {
169            TELEPHONY_LOGI("SmsMiscManager::ProcessEvent Get cb config finish");
170            GetCBConfigFinish(event);
171            break;
172        }
173        case SET_SMSC_ADDR_FINISH: {
174            TELEPHONY_LOGI("SmsMiscManager::ProcessEvent Set smsc addr finish");
175            isSuccess_ = true;
176            std::shared_ptr<RadioResponseInfo> res = event->GetSharedObject<RadioResponseInfo>();
177            if (res != nullptr) {
178                isSuccess_ = (res->error == ErrType::NONE);
179            }
180            NotifyHasResponse();
181            break;
182        }
183        case GET_SMSC_ADDR_FINISH: {
184            TELEPHONY_LOGI("SmsMiscManager::ProcessEvent Get smsc addr finish");
185            isSuccess_ = true;
186            std::shared_ptr<ServiceCenterAddress> addr = event->GetSharedObject<ServiceCenterAddress>();
187            if (addr != nullptr) {
188                smscAddr_ = addr->address;
189            }
190            NotifyHasResponse();
191            break;
192        }
193        default:
194            TELEPHONY_LOGI("SmsMiscManager::ProcessEvent default!");
195            break;
196    }
197}
198
199void SmsMiscManager::GetCBConfigFinish(const AppExecFwk::InnerEvent::Pointer &event)
200{
201    isSuccess_ = true;
202    std::shared_ptr<CBConfigInfo> res = event->GetSharedObject<CBConfigInfo>();
203    if (res == nullptr) {
204        isSuccess_ = false;
205    } else {
206        UpdateCbRangList(res);
207    }
208    NotifyHasResponse();
209}
210
211bool SmsMiscManager::IsEmpty() const
212{
213    return rangeList_.empty();
214}
215
216void SmsMiscManager::NotifyHasResponse()
217{
218    std::unique_lock<std::mutex> lock(mutex_);
219    if (fairList_.size() > 0) {
220        fairVar_ = fairList_.front();
221        fairList_.pop_front();
222    } else {
223        return;
224    }
225    condVar_.notify_all();
226}
227
228void SmsMiscManager::UpdateCbRangList(std::shared_ptr<CBConfigInfo> res)
229{
230    mdRangeList_.clear();
231    if (res->mids.empty()) {
232        return;
233    }
234    std::vector<std::string> dest;
235    SplitMids(res->mids, dest, ",");
236    for (auto v : dest) {
237        std::string start;
238        std::string end;
239        if (!SplitMidValue(v, start, end, "-")) {
240            continue;
241        }
242        if (!IsValidDecValue(start) || !IsValidDecValue(end)) {
243            TELEPHONY_LOGE("start or end not decimal");
244            return;
245        }
246        if (std::stoi(start) <= std::stoi(end)) {
247            infoData data(std::stoi(start), std::stoi(end));
248            mdRangeList_.emplace_back(data.startPos, data.endPos);
249        }
250    }
251    rangeList_ = mdRangeList_;
252    CombineCBRange();
253}
254
255void SmsMiscManager::CombineCBRange()
256{
257    rangeList_.sort();
258    rangeList_.unique();
259    auto iter = rangeList_.begin();
260    while (iter != rangeList_.end()) {
261        auto OtherIter = iter;
262        OtherIter++;
263        bool eraseFlag = false;
264        while (OtherIter != rangeList_.end()) {
265            if (OtherIter->fromMsgId == iter->fromMsgId) {
266                eraseFlag = true;
267                break;
268            } else if (OtherIter->toMsgId <= iter->toMsgId) {
269                OtherIter = rangeList_.erase(OtherIter);
270                continue;
271            } else if (OtherIter->fromMsgId <= static_cast<uint32_t>(iter->toMsgId + 1)) {
272                iter->toMsgId = OtherIter->toMsgId;
273                OtherIter = rangeList_.erase(OtherIter);
274                continue;
275            }
276            OtherIter++;
277        }
278        if (eraseFlag) {
279            iter = rangeList_.erase(iter);
280        } else {
281            iter++;
282        }
283    }
284}
285
286void SmsMiscManager::SplitMids(std::string src, std::vector<std::string> &dest, const std::string delimiter)
287{
288    size_t pos = src.find(delimiter);
289    while (pos != std::string::npos) {
290        dest.push_back(src.substr(0, pos));
291        src.erase(0, pos + delimiter.length());
292        pos = src.find(delimiter);
293    }
294    dest.push_back(src);
295}
296
297bool SmsMiscManager::SplitMidValue(std::string value, std::string &start, std::string &end, const std::string delimiter)
298{
299    if (value.empty()) {
300        return false;
301    }
302    size_t pos = value.find(delimiter);
303    if (value.size() == 0) {
304        return false;
305    }
306    if (pos == 0 || pos == value.size() - 1) {
307        return false;
308    } else if (pos == std::string::npos) {
309        start = value;
310        end = value;
311        return true;
312    }
313    start = value.substr(0, pos);
314    end = value.substr(pos + 1);
315    return true;
316}
317
318std::string SmsMiscManager::RangeListToString(const std::list<gsmCBRangeInfo> rangeList)
319{
320    std::string ret;
321    bool isFirst = true;
322    for (const auto &item : rangeList) {
323        if (isFirst) {
324            isFirst = false;
325        } else {
326            ret += ",";
327        }
328        if (item.fromMsgId == item.toMsgId) {
329            ret += std::to_string(item.fromMsgId);
330        } else {
331            ret += std::to_string(item.fromMsgId) + "-" + std::to_string(item.toMsgId);
332        }
333    }
334    return ret;
335}
336
337bool SmsMiscManager::SendDataToRil(bool enable, std::list<gsmCBRangeInfo> list)
338{
339    TELEPHONY_LOGI("enable CB channel:%{public}d", enable);
340    for (auto item : list) {
341        TELEPHONY_LOGD("[%{public}d-%{public}d]", item.fromMsgId, item.toMsgId);
342    }
343    std::unique_lock<std::mutex> lock(mutex_);
344    if (!list.empty()) {
345        isSuccess_ = false;
346        int32_t condition = conditonVar_++;
347        fairList_.push_back(condition);
348        CBConfigParam cbData;
349        cbData.mode = enable ? 1 : 0;
350        cbData.idList = RangeListToString(list);
351        cbData.dcsList = codeScheme_;
352        CoreManagerInner::GetInstance().SetCBConfig(
353            slotId_, SmsMiscManager::SET_CB_CONFIG_FINISH, cbData, shared_from_this());
354        while (!isSuccess_) {
355            TELEPHONY_LOGD("SendDataToRil::wait(), isSuccess_ = false");
356            if (condVar_.wait_for(lock, std::chrono::seconds(WAIT_TIME_SECOND)) == std::cv_status::timeout) {
357                break;
358            }
359        }
360        return isSuccess_;
361    } else {
362        return true;
363    }
364}
365
366void SmsMiscManager::GetModemCBRange()
367{
368    std::unique_lock<std::mutex> lock(mutex_);
369    if (!hasGotCbRange_) {
370        isSuccess_ = false;
371        int32_t condition = conditonVar_++;
372        fairList_.push_back(condition);
373        CoreManagerInner::GetInstance().GetCBConfig(slotId_, SmsMiscManager::GET_CB_CONFIG_FINISH, shared_from_this());
374        while (!isSuccess_) {
375            TELEPHONY_LOGI("GetCBConfig::wait(), isSuccess_ = false");
376            if (condVar_.wait_for(lock, std::chrono::seconds(WAIT_TIME_SECOND)) == std::cv_status::timeout) {
377                break;
378            }
379        }
380        hasGotCbRange_ = true;
381    }
382}
383
384int32_t SmsMiscManager::AddSimMessage(
385    const std::string &smsc, const std::string &pdu, ISmsServiceInterface::SimMessageStatus status)
386{
387    std::vector<ShortMessage> message;
388    int32_t result = GetAllSimMessages(message);
389    if (result != TELEPHONY_ERR_SUCCESS) {
390        TELEPHONY_LOGE("SmsMiscManager::AddSimMessage get result fail");
391        return result;
392    }
393    int32_t smsCountCurrent = static_cast<int32_t>(message.size());
394    TELEPHONY_LOGI("smsCountCurrent = %{public}d smsCapacityOfSim_ = %{public}d", smsCountCurrent, smsCapacityOfSim_);
395    if (smsCountCurrent >= smsCapacityOfSim_) {
396        TELEPHONY_LOGE("AddSimMessage sim card is full");
397        return TELEPHONY_ERR_FAIL;
398    }
399
400    TELEPHONY_LOGI("smscLen = %{public}zu pudLen = %{public}zu status = %{public}d", smsc.size(), pdu.size(), status);
401    std::string smscAddr(smsc);
402    if (smsc.length() <= MIN_SMSC_LEN) {
403        smscAddr.clear();
404        smscAddr.insert(0, "00");
405    }
406    TELEPHONY_LOGD("smscAddr = %{private}s", smscAddr.c_str());
407    return CoreManagerInner::GetInstance().AddSmsToIcc(
408        slotId_, static_cast<int>(status), const_cast<std::string &>(pdu), smscAddr);
409}
410
411int32_t SmsMiscManager::DelSimMessage(uint32_t msgIndex)
412{
413    TELEPHONY_LOGI("messageIndex = %{public}d", msgIndex);
414    bool hasSimCard = false;
415    CoreManagerInner::GetInstance().HasSimCard(slotId_, hasSimCard);
416    if (!hasSimCard) {
417        TELEPHONY_LOGE("no sim card");
418        return TELEPHONY_ERR_SLOTID_INVALID;
419    }
420    return CoreManagerInner::GetInstance().DelSmsIcc(slotId_, msgIndex);
421}
422
423int32_t SmsMiscManager::UpdateSimMessage(uint32_t msgIndex, ISmsServiceInterface::SimMessageStatus newStatus,
424    const std::string &pdu, const std::string &smsc)
425{
426    std::string smscAddr(smsc);
427    if (smsc.length() <= MIN_SMSC_LEN) {
428        smscAddr.clear();
429        smscAddr.insert(0, "00");
430    }
431    return CoreManagerInner::GetInstance().UpdateSmsIcc(
432        slotId_, msgIndex, static_cast<int>(newStatus), const_cast<std::string &>(pdu), smscAddr);
433}
434
435int32_t SmsMiscManager::GetAllSimMessages(std::vector<ShortMessage> &message)
436{
437    bool hasSimCard = false;
438    CoreManagerInner::GetInstance().HasSimCard(slotId_, hasSimCard);
439    if (!hasSimCard) {
440        TELEPHONY_LOGE("no sim card");
441        return TELEPHONY_ERR_SLOTID_INVALID;
442    }
443    std::vector<std::string> pdus = CoreManagerInner::GetInstance().ObtainAllSmsOfIcc(slotId_);
444    smsCapacityOfSim_ = static_cast<int32_t>(pdus.size());
445    TELEPHONY_LOGI("smsCapacityOfSim_[%{public}d]", smsCapacityOfSim_);
446    int index = 1;
447    PhoneType type = CoreManagerInner::GetInstance().GetPhoneType(slotId_);
448    std::string specification;
449    if (PhoneType::PHONE_TYPE_IS_GSM == type) {
450        specification = "3gpp";
451    } else if (PhoneType::PHONE_TYPE_IS_CDMA == type) {
452        specification = "3gpp2";
453    } else {
454        return TELEPHONY_ERR_UNKNOWN_NETWORK_TYPE;
455    }
456    for (auto &v : pdus) {
457        v = v.substr(0, v.find("FFFFF"));
458        if (v.compare("00") == 0) {
459            index++;
460            continue;
461        }
462        std::vector<unsigned char> pdu = StringUtils::HexToByteVector(v);
463        ShortMessage item = ShortMessage::CreateIccMessage(pdu, specification, index);
464        if (item.GetIccMessageStatus() != ShortMessage::SMS_SIM_MESSAGE_STATUS_FREE) {
465            message.emplace_back(item);
466        }
467        index++;
468    }
469    return TELEPHONY_ERR_SUCCESS;
470}
471
472int32_t SmsMiscManager::SetSmscAddr(const std::string &scAddr)
473{
474    TELEPHONY_LOGI("SmsMiscManager::SetSmscAddr [%{private}s]", scAddr.c_str());
475    std::unique_lock<std::mutex> lock(mutex_);
476    isSuccess_ = false;
477    int32_t condition = conditonVar_++;
478    fairList_.push_back(condition);
479    CoreManagerInner::GetInstance().SetSmscAddr(
480        slotId_, SmsMiscManager::SET_SMSC_ADDR_FINISH, 0, scAddr, shared_from_this());
481    while (!isSuccess_) {
482        TELEPHONY_LOGI("SetSmscAddr::wait(), isSuccess_ = false");
483        if (condVar_.wait_for(lock, std::chrono::seconds(TIME_OUT_SECOND)) == std::cv_status::timeout) {
484            break;
485        }
486    }
487
488    if (isSuccess_ == false) {
489        return TELEPHONY_ERR_RIL_CMD_FAIL;
490    }
491    return TELEPHONY_ERR_SUCCESS;
492}
493
494int32_t SmsMiscManager::GetSmscAddr(std::u16string &smscAddress)
495{
496    TELEPHONY_LOGI("SmsMiscManager::GetSmscAddr");
497    std::unique_lock<std::mutex> lock(mutex_);
498    smscAddr_.clear();
499    isSuccess_ = false;
500    int32_t condition = conditonVar_++;
501    fairList_.push_back(condition);
502    CoreManagerInner::GetInstance().GetSmscAddr(slotId_, SmsMiscManager::GET_SMSC_ADDR_FINISH, shared_from_this());
503    while (!isSuccess_) {
504        TELEPHONY_LOGI("GetSmscAddr::wait(), isSuccess_ = false");
505        if (condVar_.wait_for(lock, std::chrono::seconds(TIME_OUT_SECOND)) == std::cv_status::timeout) {
506            break;
507        }
508    }
509    smscAddress = StringUtils::ToUtf16(smscAddr_);
510    return TELEPHONY_ERR_SUCCESS;
511}
512
513int32_t SmsMiscManager::SetDefaultSmsSlotId(int32_t slotId)
514{
515    TELEPHONY_LOGI("SetDefaultSmsSlotId slotId = %{public}d", slotId);
516    return CoreManagerInner::GetInstance().SetDefaultSmsSlotId(slotId);
517}
518
519int32_t SmsMiscManager::GetDefaultSmsSlotId()
520{
521    TELEPHONY_LOGI("GetDefaultSmsSlotId");
522    return CoreManagerInner::GetInstance().GetDefaultSmsSlotId();
523}
524
525int32_t SmsMiscManager::GetDefaultSmsSimId(int32_t &simId)
526{
527    TELEPHONY_LOGI("GetDefaultSmsSimId");
528    return CoreManagerInner::GetInstance().GetDefaultSmsSimId(simId);
529}
530} // namespace Telephony
531} // namespace OHOS
532