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 "vcard_manager.h"
17 
18 #include "telephony_errors.h"
19 #include "telephony_log_wrapper.h"
20 #include "vcard_constant.h"
21 #include "vcard_encoder.h"
22 #include "vcard_file_utils.h"
23 #include "vcard_rdb_helper.h"
24 #include "vcard_utils.h"
25 
26 namespace OHOS {
27 namespace Telephony {
VCardManager()28 VCardManager::VCardManager()
29 {
30     listener_ = std::make_shared<VCardManager::DecodeListener>();
31 }
32 
GetContacts()33 std::vector<std::shared_ptr<VCardContact>> &VCardManager::DecodeListener::GetContacts()
34 {
35     return contacts_;
36 }
37 
OnStarted()38 void VCardManager::DecodeListener::OnStarted()
39 {
40     contacts_.clear();
41 }
42 
OnEnded()43 void VCardManager::DecodeListener::OnEnded()
44 {
45     TELEPHONY_LOGI("OnEnded contact size %{public}d", static_cast<int32_t>(contacts_.size()));
46     VCardDecoder::Close();
47 }
48 
OnOneContactStarted()49 void VCardManager::DecodeListener::OnOneContactStarted()
50 {
51     TELEPHONY_LOGI("OnOneContactStarted index %{public}d", static_cast<int32_t>(contacts_.size()));
52     currentContact_ = std::make_shared<VCardContact>();
53 }
54 
OnOneContactEnded()55 void VCardManager::DecodeListener::OnOneContactEnded()
56 {
57     TELEPHONY_LOGI("OnOneContactEnded index %{public}d", static_cast<int32_t>(contacts_.size()));
58     contacts_.push_back(currentContact_);
59     currentContact_ = nullptr;
60 }
61 
OnRawDataCreated(std::shared_ptr<VCardRawData> rawData)62 void VCardManager::DecodeListener::OnRawDataCreated(std::shared_ptr<VCardRawData> rawData)
63 {
64     if (rawData == nullptr || currentContact_ == nullptr) {
65         return;
66     }
67     int32_t errorCode = TELEPHONY_SUCCESS;
68     currentContact_->AddRawData(rawData, errorCode);
69 }
70 
ImportLock( const std::string &path, std::shared_ptr<DataShare::DataShareHelper> dataShareHelper, int32_t accountId)71 int32_t VCardManager::ImportLock(
72     const std::string &path, std::shared_ptr<DataShare::DataShareHelper> dataShareHelper, int32_t accountId)
73 {
74     std::lock_guard<std::mutex> lock(mutex_);
75     if (dataShareHelper == nullptr) {
76         TELEPHONY_LOGE("DataShareHelper is nullptr");
77         return TELEPHONY_ERR_LOCAL_PTR_NULL;
78     }
79     SetDataHelper(dataShareHelper);
80     int32_t errorCode = Import(path, accountId);
81     Release();
82     TELEPHONY_LOGI("ImportLock errorCode : %{public}d finish", errorCode);
83     return errorCode;
84 }
85 
Import(const std::string &path, int32_t accountId)86 int32_t VCardManager::Import(const std::string &path, int32_t accountId)
87 {
88     int32_t errorCode = TELEPHONY_SUCCESS;
89     Decode(path, errorCode);
90     if (errorCode != TELEPHONY_SUCCESS) {
91         TELEPHONY_LOGE("Failed to decode");
92         return errorCode;
93     }
94     BatchInsertContactDbAbility(accountId, errorCode);
95     if (errorCode != TELEPHONY_SUCCESS) {
96         TELEPHONY_LOGE("Failed to insert ability");
97         return errorCode;
98     }
99     TELEPHONY_LOGI("Import size %{public}d success", static_cast<int32_t>(listener_->GetContacts().size()));
100     return errorCode;
101 }
102 
Decode(const std::string &path, int32_t &errorCode)103 void VCardManager::Decode(const std::string &path, int32_t &errorCode)
104 {
105     std::shared_ptr<VCardDecoder> decoder = VCardDecoder::Create(path, errorCode);
106     if (decoder == nullptr || errorCode != TELEPHONY_SUCCESS) {
107         TELEPHONY_LOGE("Failed to get decoder");
108         return;
109     }
110     decoder->AddVCardDecodeListener(listener_);
111     decoder->Decode(errorCode);
112     if (errorCode != TELEPHONY_SUCCESS) {
113         TELEPHONY_LOGE("Failed to decode");
114     }
115 }
116 
InsertContactDbAbility(int32_t accountId, int32_t &errorCode)117 void VCardManager::InsertContactDbAbility(int32_t accountId, int32_t &errorCode)
118 {
119     if (listener_ == nullptr) {
120         errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
121         return;
122     }
123     if (listener_->GetContacts().size() == 0) {
124         errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID;
125         return;
126     }
127     for (std::shared_ptr<VCardContact> contact : listener_->GetContacts()) {
128         auto rawId = InsertRawContact(accountId);
129         if (rawId <= 0) {
130             TELEPHONY_LOGE("Failed to insert raw contact");
131             errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
132             continue;
133         }
134         if (InsertContactData(rawId, contact) == TELEPHONY_ERROR) {
135             TELEPHONY_LOGE("Insert contactData failed");
136             errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
137         }
138     }
139 }
140 
BatchInsertContactDbAbility(int32_t accountId, int32_t &errorCode)141 void VCardManager::BatchInsertContactDbAbility(int32_t accountId, int32_t &errorCode)
142 {
143     if (listener_ == nullptr) {
144         errorCode = TELEPHONY_ERR_LOCAL_PTR_NULL;
145         return;
146     }
147     if (listener_->GetContacts().size() < BATCH_INSERT_MAX_SIZE) {
148         TELEPHONY_LOGI("contactData < BATCH_INSERT_MAX_SIZE");
149         InsertContactDbAbility(accountId, errorCode);
150         return;
151     }
152     if (listener_->GetContacts().size() == 0) {
153         errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID;
154         return;
155     }
156     std::vector<std::vector<std::shared_ptr<VCardContact>>> splitList =
157         SplitContactsVector(listener_->GetContacts(), BATCH_INSERT_MAX_SIZE);
158     TELEPHONY_LOGI(
159         "contactData > BATCH_INSERT_MAX_SIZE, split List size %{public}d", static_cast<int32_t>(splitList.size()));
160     for (std::vector<std::shared_ptr<VCardContact>> list : splitList) {
161         TELEPHONY_LOGI("List size %{public}d", static_cast<int32_t>(list.size()));
162         std::vector<int32_t> rawIds;
163         BatchInsertRawContact(accountId, list.size(), rawIds, errorCode);
164         if (errorCode == TELEPHONY_ERROR) {
165             TELEPHONY_LOGE("Failed to batch insert raw contact");
166             continue;
167         }
168         BatchInsertContactData(rawIds, list, errorCode);
169         if (errorCode == TELEPHONY_ERROR) {
170             TELEPHONY_LOGE("Failed to batch insert contactData");
171             continue;
172         }
173     }
174 }
175 
BatchInsertRawContact( int32_t accountId, uint32_t size, std::vector<int32_t> &rawIds, int32_t &errorCode)176 void VCardManager::BatchInsertRawContact(
177     int32_t accountId, uint32_t size, std::vector<int32_t> &rawIds, int32_t &errorCode)
178 {
179     int32_t rawContactMaxId = VCardRdbHelper::GetInstance().QueryRawContactMaxId();
180     std::vector<DataShare::DataShareValuesBucket> rawContactValues;
181     for (uint32_t i = 0; i < size; i++) {
182         OHOS::DataShare::DataShareValuesBucket valuesBucket;
183         valuesBucket.Put(RawContact::ACCOUNT_ID, GetAccountId());
184         if (IsContactsIdExit(accountId)) {
185             valuesBucket.Put(RawContact::CONTACT_ID, accountId);
186         }
187         rawContactValues.push_back(valuesBucket);
188         rawIds.push_back(rawContactMaxId + i + 1);
189     }
190     VCardRdbHelper::GetInstance().BatchInsertRawContact(rawContactValues);
191 }
192 
BatchInsertContactData( std::vector<int32_t> &rawIds, const std::vector<std::shared_ptr<VCardContact>> &contactList, int32_t &errorCode)193 void VCardManager::BatchInsertContactData(
194     std::vector<int32_t> &rawIds, const std::vector<std::shared_ptr<VCardContact>> &contactList, int32_t &errorCode)
195 {
196     std::vector<DataShare::DataShareValuesBucket> contactDataValues;
197     for (size_t i = 0; i < rawIds.size(); i++) {
198         int32_t rawId = rawIds[i];
199         TELEPHONY_LOGI("rawId %{public}d", rawId);
200         std::shared_ptr<VCardContact> contact = contactList[i];
201         if (contact == nullptr) {
202             errorCode = TELEPHONY_ERROR;
203             TELEPHONY_LOGE("contact is nullptr");
204             continue;
205         }
206         contact->BuildContactData(rawId, contactDataValues);
207         if (contactDataValues.empty()) {
208             TELEPHONY_LOGE("no contactData insert");
209             errorCode = TELEPHONY_ERROR;
210         }
211     }
212     int ret = VCardRdbHelper::GetInstance().BatchInsertContactData(contactDataValues);
213     if (ret == TELEPHONY_ERROR) {
214         TELEPHONY_LOGE("batch insert contactDatat failed");
215         errorCode = TELEPHONY_ERROR;
216     }
217 }
218 
SplitContactsVector( std::vector<std::shared_ptr<VCardContact>> list, size_t step)219 std::vector<std::vector<std::shared_ptr<VCardContact>>> VCardManager::SplitContactsVector(
220     std::vector<std::shared_ptr<VCardContact>> list, size_t step)
221 {
222     std::vector<std::vector<std::shared_ptr<VCardContact>>> result;
223     if (step >= list.size()) {
224         result.push_back(list);
225     } else {
226         std::vector<std::shared_ptr<VCardContact>>::iterator curPtr = list.begin();
227         std::vector<std::shared_ptr<VCardContact>>::iterator endPtr = list.end();
228         std::vector<std::shared_ptr<VCardContact>>::iterator end;
229         while (curPtr < endPtr) {
230             end = static_cast<size_t>(endPtr - curPtr) > step ? (step + curPtr) : endPtr;
231             step = static_cast<size_t>(endPtr - curPtr) > step ? step : static_cast<size_t>(endPtr - curPtr);
232             result.push_back(std::vector<std::shared_ptr<VCardContact>>(curPtr, end));
233             curPtr += step;
234         }
235     }
236     return result;
237 }
238 
InsertRawContact(int32_t accountId)239 int32_t VCardManager::InsertRawContact(int32_t accountId)
240 {
241     OHOS::DataShare::DataShareValuesBucket ValuesBucket;
242     ValuesBucket.Put(RawContact::ACCOUNT_ID, GetAccountId());
243     if (IsContactsIdExit(accountId)) {
244         ValuesBucket.Put(RawContact::CONTACT_ID, accountId);
245     }
246     return VCardRdbHelper::GetInstance().InsertRawContact(ValuesBucket);
247 }
248 
IsContactsIdExit(int32_t accountId)249 bool VCardManager::IsContactsIdExit(int32_t accountId)
250 {
251     std::vector<std::string> columns;
252     OHOS::DataShare::DataSharePredicates predicates;
253     predicates.EqualTo(Contact::ID, std::to_string(accountId));
254     auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates);
255     if (resultSet == nullptr) {
256         return false;
257     }
258     bool result = (resultSet->GoToFirstRow() == DataShare::E_OK);
259     resultSet->Close();
260     return result;
261 }
262 
GetAccountId()263 int32_t VCardManager::GetAccountId()
264 {
265     std::vector<std::string> columns;
266     OHOS::DataShare::DataSharePredicates predicates;
267     predicates.EqualTo(Account::ACCOUNT_TYPE, "com.ohos.contacts");
268     auto resultSet = VCardRdbHelper::GetInstance().QueryAccount(columns, predicates);
269     if (resultSet == nullptr) {
270         return -1;
271     }
272     resultSet->GoToFirstRow();
273     int32_t index = 0;
274     int32_t id = 0;
275     resultSet->GetColumnIndex(Account::ID, index);
276     resultSet->GetInt(index, id);
277     resultSet->Close();
278     return id;
279 }
280 
IsAccountIdExit(int32_t accountId)281 bool VCardManager::IsAccountIdExit(int32_t accountId)
282 {
283     std::vector<std::string> columns;
284     OHOS::DataShare::DataSharePredicates predicates;
285     predicates.EqualTo(Account::ID, std::to_string(accountId));
286     auto resultSet = VCardRdbHelper::GetInstance().QueryAccount(columns, predicates);
287     if (resultSet == nullptr) {
288         return false;
289     }
290     bool result = (resultSet->GoToFirstRow() == DataShare::E_OK);
291     resultSet->Close();
292     return result;
293 }
294 
InsertContactData(int32_t rawId, std::shared_ptr<VCardContact> contact)295 int32_t VCardManager::InsertContactData(int32_t rawId, std::shared_ptr<VCardContact> contact)
296 {
297     if (contact == nullptr) {
298         return TELEPHONY_ERROR;
299     }
300     std::vector<DataShare::DataShareValuesBucket> contactDataValues;
301     contact->BuildContactData(rawId, contactDataValues);
302     if (contactDataValues.empty()) {
303         TELEPHONY_LOGI("no data insert");
304         return TELEPHONY_ERROR;
305     }
306     int ret = VCardRdbHelper::GetInstance().InsertContactData(contactDataValues);
307     if (ret == TELEPHONY_ERROR) {
308         TELEPHONY_LOGE("insert failed");
309         return TELEPHONY_ERROR;
310     }
311     return TELEPHONY_SUCCESS;
312 }
313 
ParameterTypeAndCharsetCheck(int32_t cardType, std::string charset, int32_t &errorCode)314 bool VCardManager::ParameterTypeAndCharsetCheck(int32_t cardType, std::string charset, int32_t &errorCode)
315 {
316     if (cardType < VERSION_21_NUM || cardType > VERSION_40_NUM) {
317         errorCode = TELEPHONY_ERR_ARGUMENT_INVALID;
318         return false;
319     }
320     if (!charset.empty() && !VCardUtils::EqualsIgnoreCase(DEFAULT_CHARSET, charset)) {
321         errorCode = TELEPHONY_ERR_ARGUMENT_INVALID;
322         return false;
323     }
324     errorCode = TELEPHONY_SUCCESS;
325     return true;
326 }
327 
ExportLock(std::string &path, std::shared_ptr<DataShare::DataShareHelper> dataShareHelper, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)328 int32_t VCardManager::ExportLock(std::string &path, std::shared_ptr<DataShare::DataShareHelper> dataShareHelper,
329     const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)
330 {
331     std::lock_guard<std::mutex> lock(mutex_);
332     if (dataShareHelper == nullptr) {
333         TELEPHONY_LOGE("DataShareHelper is nullptr");
334         return TELEPHONY_ERR_LOCAL_PTR_NULL;
335     }
336     SetDataHelper(dataShareHelper);
337     int32_t errorCode = Export(path, predicates, cardType, charset);
338     Release();
339     TELEPHONY_LOGI("ExportLock errorCode : %{public}d finish", errorCode);
340     return errorCode;
341 }
342 
Export( std::string &path, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)343 int32_t VCardManager::Export(
344     std::string &path, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)
345 {
346     int32_t errorCode = TELEPHONY_SUCCESS;
347     if (!ParameterTypeAndCharsetCheck(cardType, charset, errorCode)) {
348         return errorCode;
349     }
350     std::vector<std::string> columns;
351     auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates);
352     if (resultSet == nullptr) {
353         TELEPHONY_LOGE("QueryContact failed");
354         return TELEPHONY_ERR_LOCAL_PTR_NULL;
355     }
356     int32_t resultSetNum = resultSet->GoToFirstRow();
357     std::string result = "";
358     VCardEncoder encoder { cardType, charset };
359     while (resultSetNum == 0 && errorCode == TELEPHONY_SUCCESS) {
360         result += encoder.ContructVCard(resultSet, errorCode);
361         resultSetNum = resultSet->GoToNextRow();
362     }
363     if (errorCode != TELEPHONY_SUCCESS) {
364         TELEPHONY_LOGE("Export data failed");
365         resultSet->Close();
366         return errorCode;
367     }
368     if (path.empty()) {
369         std::string fileName = VCardUtils::CreateFileName();
370         path = VCARD_EXPORT_FILE_PATH + fileName;
371     } else {
372         path = path + VCardUtils::CreateFileName();
373     }
374     if (!result.empty()) {
375         VCardUtils::SaveFile(result, path);
376         resultSet->Close();
377     } else {
378         resultSet->Close();
379         return TELEPHONY_ERROR;
380     }
381     return TELEPHONY_SUCCESS;
382 }
383 
ExportToStr( std::string &str, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)384 int32_t VCardManager::ExportToStr(
385     std::string &str, const DataShare::DataSharePredicates &predicates, int32_t cardType, const std::string &charset)
386 {
387     std::vector<std::string> columns;
388     auto resultSet = VCardRdbHelper::GetInstance().QueryContact(columns, predicates);
389     if (resultSet == nullptr) {
390         TELEPHONY_LOGE("QueryContact failed");
391         return TELEPHONY_ERR_LOCAL_PTR_NULL;
392     }
393     int32_t resultSetNum = resultSet->GoToFirstRow();
394     VCardEncoder encoder { cardType, charset };
395     int32_t errorCode = TELEPHONY_SUCCESS;
396     str = "";
397     while (resultSetNum == 0 && errorCode == TELEPHONY_SUCCESS) {
398         str += encoder.ContructVCard(resultSet, errorCode);
399         resultSetNum = resultSet->GoToNextRow();
400     }
401     if (errorCode != TELEPHONY_SUCCESS) {
402         TELEPHONY_LOGE("Export data failed");
403         resultSet->Close();
404         return errorCode;
405     }
406     resultSet->Close();
407     return TELEPHONY_SUCCESS;
408 }
409 
SetDataHelper(std::shared_ptr<DataShare::DataShareHelper> dataShareHelper)410 void VCardManager::SetDataHelper(std::shared_ptr<DataShare::DataShareHelper> dataShareHelper)
411 {
412     VCardRdbHelper::GetInstance().SetDataHelper(dataShareHelper);
413 }
414 
GetInstance()415 VCardManager &VCardManager::GetInstance()
416 {
417     static VCardManager instance;
418     return instance;
419 }
420 
Release()421 void VCardManager::Release()
422 {
423     VCardRdbHelper::GetInstance().Release();
424     if (listener_ != nullptr) {
425         listener_->GetContacts().clear();
426     }
427 }
428 } // namespace Telephony
429 } // namespace OHOS
430