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 "mms_persist_helper.h"
17
18#include "gsm_pdu_hex_value.h"
19#include "telephony_log_wrapper.h"
20
21namespace OHOS {
22namespace Telephony {
23const std::string SMS_PROFILE_URI = "datashare:///com.ohos.smsmmsability";
24const std::string SMS_PROFILE_MMS_PDU_URI = "datashare:///com.ohos.smsmmsability/sms_mms/mms_pdu";
25static constexpr const char *PDU_CONTENT = "pdu_content";
26static constexpr const char *ID = "id";
27static constexpr uint8_t SLIDE_STEP = 2;
28static constexpr uint32_t SPLIT_PDU_LENGTH = 195 * 1024;
29
30std::shared_ptr<DataShare::DataShareHelper> MmsPersistHelper::CreateSmsHelper()
31{
32    if (mmsPduDataShareHelper_ == nullptr) {
33        mmsPduDataShareHelper_ = CreateDataAHelper(TELEPHONY_SMS_MMS_SYS_ABILITY_ID, SMS_PROFILE_URI);
34    }
35    return mmsPduDataShareHelper_;
36}
37
38std::shared_ptr<DataShare::DataShareHelper> MmsPersistHelper::CreateDataAHelper(
39    int32_t systemAbilityId, const std::string &dataAbilityUri) const
40{
41    auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
42    if (saManager == nullptr) {
43        TELEPHONY_LOGE("Get system ability mgr failed");
44        return nullptr;
45    }
46    auto remoteObj = saManager->GetSystemAbility(systemAbilityId);
47    if (remoteObj == nullptr) {
48        TELEPHONY_LOGE("GetSystemAbility Service Failed");
49        return nullptr;
50    }
51    return DataShare::DataShareHelper::Creator(remoteObj, dataAbilityUri);
52}
53
54void MmsPersistHelper::DeleteMmsPdu(const std::string &dbUrl)
55{
56    std::shared_ptr<DataShare::DataShareHelper> helper = CreateSmsHelper();
57    if (helper == nullptr) {
58        TELEPHONY_LOGE("helper is nullptr");
59        return;
60    }
61
62    Uri uri(SMS_PROFILE_MMS_PDU_URI);
63    DataShare::DataSharePredicates predicates;
64    std::vector<std::string> dbUrls = SplitUrl(dbUrl);
65    int32_t result = -1;
66    for (std::string url : dbUrls) {
67        predicates.EqualTo("id", url);
68        result = helper->Delete(uri, predicates);
69        if (result < 0) {
70            TELEPHONY_LOGE("delete mms pdu fail");
71            helper->Release();
72            return;
73        }
74    }
75    helper->Release();
76    mmsPdu_ = "";
77    TELEPHONY_LOGI("result:%{public}d", result);
78}
79
80bool MmsPersistHelper::InsertMmsPdu(const std::string &mmsPdu, std::string &dbUrl)
81{
82    std::shared_ptr<DataShare::DataShareHelper> helper = CreateSmsHelper();
83    if (helper == nullptr) {
84        TELEPHONY_LOGE("helper is nullptr");
85        return false;
86    }
87    Uri uri(SMS_PROFILE_MMS_PDU_URI);
88
89    std::vector<std::string> mmsPdus = SplitPdu(mmsPdu);
90    for (std::string mmsPdu : mmsPdus) {
91        DataShare::DataShareValuesBucket bucket;
92        bucket.Put(PDU_CONTENT, mmsPdu);
93        int32_t result = helper->Insert(uri, bucket);
94        if (result < 0) {
95            TELEPHONY_LOGE("mms pdu insert fail");
96            return false;
97        }
98        dbUrl += std::to_string(result) + ',';
99    }
100    helper->Release();
101    TELEPHONY_LOGI("download mms insert db, dbUrl:%{public}s", dbUrl.c_str());
102    return dbUrl.empty() ? false : true;
103}
104
105std::vector<std::string> MmsPersistHelper::SplitPdu(const std::string &mmsPdu)
106{
107    std::string targetMmsPdu;
108    for (size_t i = 0; i < mmsPdu.size(); i++) {
109        targetMmsPdu += static_cast<char>((mmsPdu[i] & HEX_VALUE_0F) | HEX_VALUE_F0);
110        targetMmsPdu += static_cast<char>((mmsPdu[i] & HEX_VALUE_F0) | HEX_VALUE_0F);
111    }
112
113    std::vector<std::string> mmsPdus;
114    for (uint32_t locate = 0; locate * SPLIT_PDU_LENGTH < targetMmsPdu.size(); locate++) {
115        std::string mmsPduData;
116        if ((locate + 1) * SPLIT_PDU_LENGTH < targetMmsPdu.size()) {
117            mmsPduData = targetMmsPdu.substr(locate * SPLIT_PDU_LENGTH, SPLIT_PDU_LENGTH);
118            mmsPdus.push_back(mmsPduData);
119        } else {
120            mmsPduData = targetMmsPdu.substr(locate * SPLIT_PDU_LENGTH);
121            mmsPdus.push_back(mmsPduData);
122            break;
123        }
124    }
125    TELEPHONY_LOGI("pduLen:%{public}zu,target:%{public}zu,pageLen:%{public}zu", mmsPdu.size(), targetMmsPdu.size(),
126        mmsPdus.size());
127    return mmsPdus;
128}
129
130std::string MmsPersistHelper::GetMmsPdu(const std::string &dbUrl)
131{
132    if (!QueryMmsPdu(dbUrl)) {
133        return "";
134    }
135    return mmsPdu_;
136}
137
138void MmsPersistHelper::SetMmsPdu(const std::string &mmsPdu)
139{
140    mmsPdu_ = mmsPdu;
141}
142
143std::vector<std::string> MmsPersistHelper::SplitUrl(std::string url)
144{
145    std::vector<std::string> dbUrls;
146    while (url.size() > 0) {
147        size_t locate = url.find_first_of(',');
148        if (locate == 0 || locate == std::string::npos) {
149            break;
150        }
151        dbUrls.push_back(url.substr(0, locate));
152        url = url.substr(locate + 1);
153    }
154    return dbUrls;
155}
156
157bool MmsPersistHelper::QueryMmsPdu(const std::string &dbUrl)
158{
159    std::shared_ptr<DataShare::DataShareHelper> helper = CreateSmsHelper();
160    if (helper == nullptr) {
161        TELEPHONY_LOGE("helper is nullptr");
162        return false;
163    }
164
165    std::vector<std::string> dbUrls = SplitUrl(dbUrl);
166    std::string mmsPdu;
167    for (std::string url : dbUrls) {
168        Uri uri(SMS_PROFILE_MMS_PDU_URI);
169        std::vector<std::string> colume;
170        DataShare::DataSharePredicates predicates;
171        predicates.EqualTo(ID, url);
172        auto resultSet = helper->Query(uri, predicates, colume);
173        if (resultSet == nullptr) {
174            TELEPHONY_LOGE("Query Result Set nullptr Failed.");
175            helper->Release();
176            return false;
177        }
178        int count = 0;
179        resultSet->GetRowCount(count);
180        if (count <= 0) {
181            TELEPHONY_LOGE("MmsPdu count: %{public}d error", count);
182            resultSet->Close();
183            helper->Release();
184            return false;
185        }
186        int columnIndex;
187        std::vector<uint8_t> blobValue;
188        resultSet->GoToFirstRow();
189        resultSet->GetColumnIndex(PDU_CONTENT, columnIndex);
190        resultSet->GetBlob(columnIndex, blobValue);
191        blobValue.pop_back();
192        for (size_t i = 0; i + 1 < blobValue.size(); i = i + SLIDE_STEP) {
193            char pduChar = (blobValue[i] & HEX_VALUE_0F) | (blobValue[i + 1] & HEX_VALUE_F0);
194            mmsPdu += static_cast<char>(pduChar);
195        }
196        TELEPHONY_LOGI("blob len:%{public}zu, ", blobValue.size());
197        resultSet->Close();
198    }
199    helper->Release();
200    TELEPHONY_LOGI("mmsPdu len:%{public}zu", mmsPdu.size());
201    SetMmsPdu(mmsPdu);
202    return true;
203}
204} // namespace Telephony
205} // namespace OHOS