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 "pbap_pse_vcard_manager.h"
17 #include <algorithm>
18 #include <cstring>
19 #include <exception>
20 #include <functional>
21 #include <set>
22 #include <sstream>
23 #include "../obex/obex_utils.h"
24 #include "data_access.h"
25 #include "log.h"
26 #include "pbap_pse_def.h"
27 #include "stub/vcard_util.h"
28
29 using namespace stub;
30
31 namespace OHOS {
32 namespace bluetooth {
33 class PbapPseVcardDataAccess {
34 public:
35 struct SetPullvCardEntryParam {
36 std::u16string folderId = u"";
37 std::u16string entryId = u"";
38 uint32_t supportedFeatures = 0;
39 };
SetPullvCardListingSize(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result,const PbapPseAppParams & pbapAppParams)40 static void SetPullvCardListingSize(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
41 PbapPseVcardManager::PhoneBookResult &result, const PbapPseAppParams &pbapAppParams)
42 {
43 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
44 std::string select = "select count(distinct vcard_uid) from vcard_view t where folder_id = ? ";
45 select += GetVcardSelectorWhere(pbapAppParams);
46 if (pbapAppParams.GetSearchValueUtf8().size() > 0) {
47 select += GetVcardSearchPropertyWhere(pbapAppParams);
48 }
49 auto stmt = dataAccess->CreateStatement(select);
50 if (!stmt) {
51 result.rspCode_ = ObexRspCode::INTERNAL_SERVER_ERROR;
52 return;
53 }
54 int pIndex = 1;
55 stmt->SetParam16String(pIndex++, folderId);
56 if (pbapAppParams.GetSearchValueUtf8().size() > 0) {
57 const uint8_t *data = pbapAppParams.GetSearchValueUtf8().data();
58 std::string searchValue(data, data + pbapAppParams.GetSearchValueUtf8().size());
59 stmt->SetParamString(pIndex++, searchValue);
60 }
61 auto dataResult = stmt->Query();
62 int count = 0;
63 if (dataResult->Next()) {
64 count = dataResult->GetInt(0);
65 }
66 result.phoneBookSize_ = count;
67 }
68
SetPullvCardListing(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result,const PbapPseAppParams & pbapAppParams)69 static void SetPullvCardListing(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
70 PbapPseVcardManager::PhoneBookResult &result, const PbapPseAppParams &pbapAppParams)
71 {
72 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
73 auto vcardListing = SelectPullvCardListing(dataAccess, folderId, pbapAppParams);
74 if (vcardListing.size() == 0) {
75 PBAP_PSE_LOG_DEBUG("SetPullvCardListing size is 0");
76 return;
77 }
78 std::stringstream ss;
79 ss << "<?xml version=\"1.0\"?>";
80 ss << "<!DOCTYPE vcard-listing SYSTEM \"vcard-listing.dtd\">";
81 ss << "<vCard-listing version=\"1.0\">";
82 for (auto &item : vcardListing) {
83 ss << "<card handle=\"";
84 ss << std::hex << item.first;
85 ss << ".vcf\" name=\"";
86 ss << NameEncodeForXml(item.second);
87 ss << "\"/>";
88 }
89 ss << "</vCard-listing>";
90 std::string xml = ss.str();
91 result.result_.insert(result.result_.end(), xml.begin(), xml.end());
92 }
93
NameEncodeForXml(const std::string & name)94 static std::string NameEncodeForXml(const std::string &name)
95 {
96 std::stringstream ss;
97 for (char c : name) {
98 switch (c) {
99 case '<':
100 ss << "<";
101 break;
102 case '>':
103 ss << ">";
104 break;
105 case '\"':
106 ss << """;
107 break;
108 case '\'':
109 ss << "'";
110 break;
111 case '&':
112 ss << "&";
113 break;
114
115 default:
116 ss << c;
117 break;
118 }
119 }
120 return ss.str();
121 }
122
SetNewMissedCalls(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result)123 static void SetNewMissedCalls(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
124 PbapPseVcardManager::PhoneBookResult &result)
125 {
126 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
127 std::string select =
128 "select count(vcard_uid) from vcard where vcard_folder_id = ? and vcard_new_missed_call = 1";
129 auto stmt = dataAccess->CreateStatement(select);
130 if (!stmt) {
131 result.rspCode_ = ObexRspCode::INTERNAL_SERVER_ERROR;
132 return;
133 }
134 stmt->SetParam16String(1, folderId);
135 auto dataResult = stmt->Query();
136 int count = 0;
137 if (dataResult->Next()) {
138 count = dataResult->GetInt(0);
139 }
140 result.newMissedCallsSize_ = count;
141 }
142
SetPhoneBookSize(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result,const PbapPseAppParams & pbapAppParams)143 static void SetPhoneBookSize(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
144 PbapPseVcardManager::PhoneBookResult &result, const PbapPseAppParams &pbapAppParams)
145 {
146 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
147 std::string select = "select count(distinct vcard_uid) from vcard_view t where folder_id = ? ";
148 select += GetVcardSelectorWhere(pbapAppParams);
149
150 auto stmt = dataAccess->CreateStatement(select);
151 if (!stmt) {
152 result.rspCode_ = ObexRspCode::INTERNAL_SERVER_ERROR;
153 return;
154 }
155 stmt->SetParam16String(1, folderId);
156 auto dataResult = stmt->Query();
157 int count = 0;
158 if (dataResult->Next()) {
159 count = dataResult->GetInt(0);
160 }
161 result.phoneBookSize_ = count;
162 }
163
SetPhoneBook(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result,const PbapPseAppParams & pbapAppParams,const uint32_t & supportedFeatures)164 static void SetPhoneBook(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
165 PbapPseVcardManager::PhoneBookResult &result, const PbapPseAppParams &pbapAppParams,
166 const uint32_t &supportedFeatures)
167 {
168 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
169 auto vcardUids = SelectPhoneBookVcardUids(dataAccess, folderId, pbapAppParams);
170
171 // 5.1.4.2 Format :vCard2.1, vCard3.0
172 bool isOutVcard21 = true; // The format vCard 2.1 shall be the default format if this header is not specified.
173 if (pbapAppParams.GetFormat()) {
174 // 0x00 = 2.1 0x01 = 3.0
175 isOutVcard21 = (*pbapAppParams.GetFormat() == 0x00);
176 }
177 // 5.1.4.11 ResetNewMissedCalls :not support in this impl
178
179 // 5.1.4.1 PropertySelector :PropertyMask (64-bit value)
180 std::vector<std::string> includeProperties;
181 // Mandatory properties for vCard 2.1 are VERSION ,N and TEL.
182 // Mandatory properties for vCard 3.0 are VERSION, N, FN and TEL.
183 std::vector<std::string> mandatoryProperties;
184 mandatoryProperties.push_back("VERSION");
185 mandatoryProperties.push_back("N");
186 if (!isOutVcard21) {
187 mandatoryProperties.push_back("FN");
188 }
189 mandatoryProperties.push_back("TEL");
190 if (pbapAppParams.GetPropertySelector()) {
191 includeProperties = PbapPseVcardManager::GetIncludeProperties(*pbapAppParams.GetPropertySelector());
192 if (includeProperties.size() > 0) {
193 includeProperties.insert(
194 includeProperties.end(), mandatoryProperties.begin(), mandatoryProperties.end());
195 }
196 }
197 const VCardVersion outVer = isOutVcard21 ? VCardVersion::VER_2_1 : VCardVersion::VER_3_0;
198
199 std::function<void(VCard &)> fun = [&mandatoryProperties, &result, &outVer](VCard &vcard) {
200 // 5.1.4.1 all Mandatory here means that the PSE shall always return the properties VERSION, N and TEL
201 // vCard 2.1 or VERSION, N, FN and TEL for a vCard 3.0.
202 AddMissProperties(vcard, mandatoryProperties);
203
204 if (vcard.Properties().size() > 0) {
205 std::vector<uint8_t> vcardBytes = VCardUtil::Build(vcard, outVer);
206 result.result_.insert(result.result_.end(), vcardBytes.begin(), vcardBytes.end());
207 }
208 };
209 SelectPhoneBookVcardList(
210 dataAccess, vcardUids, GetPropertySelectorWhere(includeProperties), supportedFeatures, fun);
211 }
212
SetPullvCardEntry(const std::unique_ptr<DataAccess> & dataAccess,const SetPullvCardEntryParam & param,const PbapPseAppParams & pbapAppParams,PbapPseVcardManager::PhoneBookResult & result)213 static void SetPullvCardEntry(
214 const std::unique_ptr<DataAccess> &dataAccess,
215 const SetPullvCardEntryParam& param,
216 const PbapPseAppParams &pbapAppParams, PbapPseVcardManager::PhoneBookResult &result)
217 {
218 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
219 auto vcardUids = SelectVcardEntryUid(dataAccess, param.folderId, param.entryId, pbapAppParams);
220 if (vcardUids.size() == 0) {
221 PBAP_PSE_LOG_DEBUG("SelectPhoneBookVcardUids size = 0");
222 result.rspCode_ = ObexRspCode::NOT_FOUND;
223 return;
224 }
225 // 5.1.4.2 Format :vCard2.1, vCard3.0
226 bool isOutVcard21 = true; // The format vCard 2.1 shall be the default format if this header is not specified.
227 if (pbapAppParams.GetFormat()) {
228 // 0x00 = 2.1 0x01 = 3.0
229 isOutVcard21 = (*pbapAppParams.GetFormat() == 0x00);
230 }
231
232 // 5.1.4.1 PropertySelector :PropertyMask (64-bit value)
233 std::vector<std::string> includeProperties;
234 // Mandatory properties for vCard 2.1 are VERSION ,N and TEL.
235 // Mandatory properties for vCard 3.0 are VERSION, N, FN and TEL.
236 std::vector<std::string> mandatoryProperties;
237 mandatoryProperties.push_back("VERSION");
238 mandatoryProperties.push_back("N");
239 if (!isOutVcard21) {
240 mandatoryProperties.push_back("FN");
241 }
242 mandatoryProperties.push_back("TEL");
243 if (pbapAppParams.GetPropertySelector()) {
244 includeProperties = PbapPseVcardManager::GetIncludeProperties(*pbapAppParams.GetPropertySelector());
245 if (includeProperties.size() > 0) {
246 includeProperties.insert(
247 includeProperties.end(), mandatoryProperties.begin(), mandatoryProperties.end());
248 }
249 }
250 const VCardVersion outVer = isOutVcard21 ? VCardVersion::VER_2_1 : VCardVersion::VER_3_0;
251 std::function<void(VCard &)> fun = [&mandatoryProperties, &result, &outVer](VCard &vcard) {
252 // 5.1.4.1 all Mandatory here means that the PSE shall always return the properties VERSION, N and TEL
253 // vCard 2.1 or VERSION, N, FN and TEL for a vCard 3.0.
254 AddMissProperties(vcard, mandatoryProperties);
255
256 if (vcard.Properties().size() > 0) {
257 std::vector<uint8_t> vcardBytes = VCardUtil::Build(vcard, outVer);
258 result.result_.insert(result.result_.end(), vcardBytes.begin(), vcardBytes.end());
259 }
260 };
261 SelectPhoneBookVcardList(
262 dataAccess, vcardUids, GetPropertySelectorWhere(includeProperties), param.supportedFeatures, fun);
263 }
264
SetDbId(const std::unique_ptr<DataAccess> & dataAccess,PbapPseVcardManager::PhoneBookResult & result)265 static void SetDbId(const std::unique_ptr<DataAccess> &dataAccess, PbapPseVcardManager::PhoneBookResult &result)
266 {
267 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
268 std::string select = "select db_id from vcard_db_id limit 1";
269
270 auto stmt = dataAccess->CreateStatement(select);
271 if (!stmt) {
272 result.rspCode_ = ObexRspCode::INTERNAL_SERVER_ERROR;
273 return;
274 }
275
276 auto dataResult = stmt->Query();
277 if (dataResult->Next()) {
278 std::string dbId = dataResult->GetString(0);
279 if (dbId.size() > 0) {
280 std::vector<uint8_t> tmpPv(dbId.c_str(), dbId.c_str() + dbId.size());
281 result.databaseIdentifier_ = tmpPv;
282 FitListToSize(result.databaseIdentifier_, 0x10);
283 }
284 }
285 }
286
SetFolderVersion(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result)287 static void SetFolderVersion(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
288 PbapPseVcardManager::PhoneBookResult &result)
289 {
290 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
291 std::string select =
292 "select folder_id, primary_folder_version, secondary_folder_version from vcard_folder where folder_id = ?";
293
294 auto stmt = dataAccess->CreateStatement(select);
295 if (!stmt) {
296 result.rspCode_ = ObexRspCode::INTERNAL_SERVER_ERROR;
297 return;
298 }
299 stmt->SetParam16String(1, folderId);
300 auto dataResult = stmt->Query();
301 if (dataResult->Next()) {
302 std::string pv = dataResult->GetString(0x01);
303 if (pv.size() > 0) {
304 std::vector<uint8_t> tmpPv(pv.c_str(), pv.c_str() + pv.size());
305 result.primaryFolderVersion_ = tmpPv;
306 FitListToSize(result.primaryFolderVersion_, 0x10);
307 }
308 std::string sv = dataResult->GetString(0x02);
309 if (sv.size() > 0) {
310 std::vector<uint8_t> tmpSv(sv.c_str(), sv.c_str() + sv.size());
311 result.secondaryFolderVersion_ = tmpSv;
312 FitListToSize(result.secondaryFolderVersion_, 0x10);
313 }
314 }
315 }
316
SetCommonResult(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,PbapPseVcardManager::PhoneBookResult & result,const uint32_t & supportedFeatures)317 static void SetCommonResult(const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
318 PbapPseVcardManager::PhoneBookResult &result, const uint32_t &supportedFeatures)
319 {
320 if (folderId == u"mch") {
321 // 5.1.4.6 NewMissedCalls
322 // This application parameter shall be used in the response when the phone book object is mch. It shall
323 // indicate the number of undismissed missed calls on the PSE at the point of the request. This value is the
324 // same for mch and cch objects.
325 result.newMissedCalls_ = true;
326 SetNewMissedCalls(dataAccess, folderId, result);
327 if (result.rspCode_ != ObexRspCode::SUCCESS) {
328 return;
329 }
330 }
331 if (PbapPseVcardManager::IsSupportedDbVer(supportedFeatures)) {
332 SetFolderVersion(dataAccess, folderId, result);
333 if (result.rspCode_ != ObexRspCode::SUCCESS) {
334 return;
335 }
336 }
337 if (PbapPseVcardManager::IsSupportedDbVer(supportedFeatures)) {
338 SetDbId(dataAccess, result);
339 if (result.rspCode_ != ObexRspCode::SUCCESS) {
340 return;
341 }
342 }
343 }
344
FitListToSize(std::vector<uint8_t> & list,size_t size)345 static void FitListToSize(std::vector<uint8_t> &list, size_t size)
346 {
347 if (list.size() == size) {
348 return;
349 }
350 if (list.size() > size) {
351 while (list.size() > size) {
352 list.pop_back();
353 }
354 } else {
355 size_t fitSize = size - list.size();
356 list.insert(list.begin(), fitSize, 0x00);
357 }
358 }
359
360 private:
GetSelectPullvCardListingSql(const PbapPseAppParams & pbapAppParams)361 static std::string GetSelectPullvCardListingSql(const PbapPseAppParams &pbapAppParams)
362 {
363 std::string select = "select distinct t.vcard_handle_id, t.property_value as name from vcard_view t ";
364 std::string where = " where t.folder_id = ? and t.property_id ='N' ";
365 where += GetVcardSelectorWhere(pbapAppParams);
366 if (pbapAppParams.GetSearchValueUtf8().size() > 0) {
367 where += GetVcardSearchPropertyWhere(pbapAppParams);
368 }
369 // If this application parameter is not specified, the default order is “Indexed”.
370 std::string orderBy = " order by t.vcard_handle_id asc ";
371 // 5.3.4.1 Order : Alphabetical, Indexed, Phonetical
372 if (pbapAppParams.GetOrder()) {
373 switch (*pbapAppParams.GetOrder()) {
374 case 0x01: // alphanumeric
375 orderBy = " order by t.property_value asc, t.vcard_handle_id asc";
376 break;
377 case 0x02: // phonetic
378 orderBy = " order by (select property_value from vcard_view where vcard_uid = t.vcard_uid and "
379 "property_id = "
380 "'SOUND' limit 1) is null asc ";
381 orderBy +=
382 ", (select property_value from vcard_view where vcard_uid = t.vcard_uid and property_id = "
383 "'SOUND' limit 1) asc ";
384 orderBy += ", t.vcard_handle_id asc ";
385 break;
386 default:
387 // default indexed
388 break;
389 }
390 }
391 select += where;
392 select += orderBy;
393 select += " limit ? offset ?";
394 return select;
395 }
396
SelectPullvCardListing(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,const PbapPseAppParams & pbapAppParams)397 static std::vector<std::pair<int, std::string>> SelectPullvCardListing(
398 const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
399 const PbapPseAppParams &pbapAppParams)
400 {
401 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
402 std::string select = GetSelectPullvCardListingSql(pbapAppParams);
403 // 5.1.4.3 MaxListCount default max is 65535
404 uint16_t maxListCount = 0xFFFF;
405 if (pbapAppParams.GetMaxListCount()) {
406 maxListCount = *pbapAppParams.GetMaxListCount();
407 }
408 // 5.1.4.4 ListStartOffset
409 uint16_t listStartOffset = 0; // The offset shall be 0 if this header is not specified
410 if (pbapAppParams.GetListStartOffset()) {
411 listStartOffset = *pbapAppParams.GetListStartOffset();
412 }
413 std::vector<std::pair<int, std::string>> vcardUids;
414 auto stmtVcardIds = dataAccess->CreateStatement(select);
415 if (!stmtVcardIds) {
416 return vcardUids;
417 }
418 int paramIndex = 1;
419 stmtVcardIds->SetParam16String(paramIndex++, folderId);
420 if (pbapAppParams.GetSearchValueUtf8().size() > 0) {
421 const uint8_t *data = pbapAppParams.GetSearchValueUtf8().data();
422 std::string searchValue(data, data + pbapAppParams.GetSearchValueUtf8().size());
423 stmtVcardIds->SetParamString(paramIndex++, searchValue);
424 }
425 stmtVcardIds->SetParamInt(paramIndex++, maxListCount);
426 stmtVcardIds->SetParamInt(paramIndex++, listStartOffset);
427 auto dataResult = stmtVcardIds->Query();
428 while (dataResult->Next()) {
429 int index = 0;
430 int vcardUid = dataResult->GetInt(index++);
431 std::string name = dataResult->GetString(index++);
432 vcardUids.push_back(std::make_pair(vcardUid, name));
433 }
434 return vcardUids;
435 }
436
SelectPhoneBookVcardUids(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,const PbapPseAppParams & pbapAppParams)437 static std::vector<std::pair<int64_t, int>> SelectPhoneBookVcardUids(
438 const std::unique_ptr<DataAccess> &dataAccess, const std::u16string &folderId,
439 const PbapPseAppParams &pbapAppParams)
440 {
441 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
442 std::string select = "select distinct vcard_uid, vcard_version from vcard_view t where folder_id = ? ";
443 select += GetVcardSelectorWhere(pbapAppParams);
444 select += " order by vcard_handle_id asc";
445 select += " limit ? offset ?";
446
447 // 5.1.4.3 MaxListCount default max is 65535
448 uint16_t maxListCount = 0xFFFF;
449 if (pbapAppParams.GetMaxListCount()) {
450 maxListCount = *pbapAppParams.GetMaxListCount();
451 }
452 // 5.1.4.4 ListStartOffset
453 uint16_t listStartOffset = 0; // The offset shall be 0 if this header is not specified
454 if (pbapAppParams.GetListStartOffset()) {
455 listStartOffset = *pbapAppParams.GetListStartOffset();
456 }
457 std::vector<std::pair<int64_t, int>> vcardUids;
458 auto stmtVcardIds = dataAccess->CreateStatement(select);
459 if (!stmtVcardIds) {
460 return vcardUids;
461 }
462 int pIndex = 1;
463 stmtVcardIds->SetParam16String(pIndex++, folderId);
464 stmtVcardIds->SetParamInt(pIndex++, maxListCount);
465 stmtVcardIds->SetParamInt(pIndex++, listStartOffset);
466 auto dataResult = stmtVcardIds->Query();
467 while (dataResult->Next()) {
468 int index = 0;
469 int64_t vcardUid = dataResult->GetInt64(index++);
470 int vcardVer = dataResult->GetInt(index++);
471 vcardUids.push_back(std::make_pair(vcardUid, vcardVer));
472 }
473 return vcardUids;
474 }
475
GetSelectPhoneBookVcardListSql(const std::string & whereSql)476 static std::string GetSelectPhoneBookVcardListSql(const std::string &whereSql)
477 {
478 std::string sql = "select"
479 " vcard_handle_id"
480 " , vcard_version"
481 " , property_group"
482 " , property_id"
483 " , property_details"
484 " , property_value "
485 "from"
486 " vcard_view t "
487 "where"
488 " vcard_uid = ? " +
489 whereSql +
490 "order by"
491 " profile_property_order is null asc"
492 " , profile_property_order asc";
493 return sql;
494 }
495
IsNeedInclude(const std::string & propertyId,const uint32_t & supportedFeatures)496 static bool IsNeedInclude(const std::string &propertyId, const uint32_t &supportedFeatures)
497 {
498 if (propertyId == "X-BT-UCI" && !PbapPseVcardManager::IsSupportedXBtUCI(supportedFeatures)) {
499 return false;
500 }
501 if (propertyId == "X-BT-UID" && !PbapPseVcardManager::IsSupportedXBtUID(supportedFeatures)) {
502 return false;
503 }
504 return true;
505 }
506
SelectPhoneBookVcardList(const std::unique_ptr<DataAccess> & dataAccess,const std::vector<std::pair<int64_t,int>> & vcardUids,const std::string whereSql,const uint32_t & supportedFeatures,const std::function<void (VCard &)> & handleFun)507 static bool SelectPhoneBookVcardList(const std::unique_ptr<DataAccess> &dataAccess,
508 const std::vector<std::pair<int64_t, int>> &vcardUids, const std::string whereSql,
509 const uint32_t &supportedFeatures, const std::function<void(VCard &)> &handleFun)
510 {
511 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
512 std::string select = GetSelectPhoneBookVcardListSql(whereSql);
513 auto stmt = dataAccess->CreateStatement(select);
514 if (!stmt) {
515 PBAP_PSE_LOG_ERROR("Error in CreateStatement");
516 return false;
517 }
518 for (size_t i = 0; i < vcardUids.size(); i++) {
519 auto pair = vcardUids.at(i);
520 int64_t vcardUid = pair.first;
521 int vcardVer = pair.second;
522 stmt->ClearParams();
523 stmt->SetParamInt64(1, vcardUid);
524 bool isCurVcard21 = (vcardVer == 0);
525 auto dataResult = stmt->Query();
526 VCard vcard;
527 const VCardVersion curVer = isCurVcard21 ? VCardVersion::VER_2_1 : VCardVersion::VER_3_0;
528 while (dataResult->Next()) {
529 int index = 0;
530 int vcardHandleId = dataResult->GetInt(index++);
531 int vcardVersion = dataResult->GetInt(index++);
532 std::string propertyGroup = dataResult->GetString(index++);
533 std::string propertyId = dataResult->GetString(index++);
534 if (!IsNeedInclude(propertyId, supportedFeatures)) {
535 continue;
536 }
537 std::string propertyDetails = dataResult->GetString(index++);
538 std::string propertyValue = dataResult->GetString(index++);
539 PBAP_PSE_LOG_DEBUG("[%{public}zu]: %jd\t%{public}d\t%{public}d\t%{public}s\t%{public}s\t%{public}s",
540 i,
541 vcardUid,
542 vcardHandleId,
543 vcardVersion,
544 propertyId.c_str(),
545 propertyDetails.c_str(),
546 propertyValue.c_str());
547 vcard.AddProperty(VCardProperty(curVer, propertyGroup, propertyId, propertyValue, propertyDetails));
548 }
549 handleFun(vcard);
550 }
551 return true;
552 }
553
SelectVcardEntryUid(const std::unique_ptr<DataAccess> & dataAccess,const std::u16string & folderId,std::u16string entryId,const PbapPseAppParams & pbapAppParams)554 static std::vector<std::pair<int64_t, int>> SelectVcardEntryUid(const std::unique_ptr<DataAccess> &dataAccess,
555 const std::u16string &folderId, std::u16string entryId, const PbapPseAppParams &pbapAppParams)
556 {
557 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
558 std::string select = "select distinct t.vcard_uid, t.vcard_version from vcard_view t where 1 = 1 ";
559 std::string where = "";
560 bool isXBtUid = entryId.find(PBAP_PSE_X_BT_UID_PREFIX) == 0;
561 if (isXBtUid) {
562 where += "and exists (";
563 where += "select 1 from vcard_view s where s.vcard_uid = t.vcard_uid and "
564 "s.property_id = 'X-BT-UID' and s.property_value = ? ";
565 where += ")";
566 } else {
567 where += "and t.folder_id = ? and t.vcard_handle_id = ? ";
568 }
569 where += GetVcardSelectorWhere(pbapAppParams);
570 select += where;
571 select += " limit 1";
572
573 std::vector<std::pair<int64_t, int>> vcardUids;
574 auto stmtVcardIds = dataAccess->CreateStatement(select);
575 if (!stmtVcardIds) {
576 return vcardUids;
577 }
578 int pIndex = 1;
579 if (isXBtUid) {
580 entryId = entryId.substr(PBAP_PSE_X_BT_UID_PREFIX.size());
581 stmtVcardIds->SetParam16String(pIndex++, entryId);
582 } else {
583 entryId = entryId.substr(0, entryId.size() - PBAP_PSE_VCARD_SUFFIX.size());
584 stmtVcardIds->SetParam16String(pIndex++, folderId);
585 int handleId = PbapPseVcardManager::VcardHandleId2Int(entryId);
586 stmtVcardIds->SetParamInt(pIndex++, handleId);
587 }
588
589 auto dataResult = stmtVcardIds->Query();
590 while (dataResult->Next()) {
591 int index = 0;
592 int64_t vcardUid = dataResult->GetInt64(index++);
593 int vcardVer = dataResult->GetInt(index++);
594 vcardUids.push_back(std::make_pair(vcardUid, vcardVer));
595 }
596 return vcardUids;
597 }
598
GetPropertySelectorWhere(const std::vector<std::string> & includeProperties)599 static std::string GetPropertySelectorWhere(const std::vector<std::string> &includeProperties)
600 {
601 std::string inSection = "";
602 if (includeProperties.size() > 0) {
603 inSection += " and property_id in (";
604 for (size_t i = 0; i < includeProperties.size(); i++) {
605 if (i > 0) {
606 inSection += ",";
607 }
608 inSection += "'" + includeProperties.at(i) + "'";
609 }
610 inSection += ") ";
611 }
612
613 return inSection;
614 }
615
GetVcardSearchPropertyWhere(const PbapPseAppParams & pbapAppParams)616 static std::string GetVcardSearchPropertyWhere(const PbapPseAppParams &pbapAppParams)
617 {
618 std::string andSection = "";
619 // 5.3.4.3 SearchValue :<text string>
620 if (pbapAppParams.GetSearchValueUtf8().size() > 0) {
621 andSection += "and exists (";
622 andSection += "select 1 from vcard_view s where s.vcard_uid = t.vcard_uid and "
623 "s.property_id = '";
624
625 // 5.3.4.2 SearchProperty :Name, Number, Sound
626 std::string searchPropertyId = "N";
627 if (pbapAppParams.GetSearchProperty()) {
628 switch (*pbapAppParams.GetSearchProperty()) {
629 case 0x01: // Number
630 searchPropertyId = "TEL";
631 break;
632 case 0x02: // Sound
633 searchPropertyId = "SOUND";
634 break;
635 default:
636 searchPropertyId = "N"; // default Name
637 break;
638 }
639 }
640 andSection += searchPropertyId + "' and s.property_value like '%' || ? || '%'";
641 andSection += ")";
642 }
643 return andSection;
644 }
645
GetVcardSelectorWhere(const PbapPseAppParams & pbapAppParams)646 static std::string GetVcardSelectorWhere(const PbapPseAppParams &pbapAppParams)
647 {
648 std::string andSection = "";
649 // 5.1.4.7 vCardSelector
650 if (!pbapAppParams.GetVcardSelector()) {
651 return andSection;
652 }
653 uint64_t vcardSelector = *pbapAppParams.GetVcardSelector();
654 // 5.1.4.8 vCardSelectorOperator
655 // All vCards shall be returned if contains all zeros.
656 if (vcardSelector == 0) {
657 return andSection;
658 }
659 auto selectorProperties = PbapPseVcardManager::GetIncludeProperties(vcardSelector);
660 if (selectorProperties.size() == 0) {
661 return andSection;
662 }
663 std::string relations = "or";
664 if (pbapAppParams.GetVcardSelectorOperator()) {
665 if (*pbapAppParams.GetVcardSelectorOperator() == 0x01) {
666 relations = "and";
667 }
668 }
669 andSection += " and (";
670 for (size_t i = 0; i < selectorProperties.size(); i++) {
671 if (i > 0) {
672 andSection += " " + relations + " ";
673 }
674 andSection += " exists (";
675 andSection += "select 1 from vcard_view s where s.vcard_uid = t.vcard_uid and "
676 "s.property_id = '" +
677 selectorProperties.at(i) + "' and s.property_value != ''";
678 andSection += ")";
679 }
680 andSection += ") ";
681 return andSection;
682 }
683
AddMissProperties(VCard & vcard,const std::vector<std::string> & properties)684 static void AddMissProperties(VCard &vcard, const std::vector<std::string> &properties)
685 {
686 for (auto propertyId : properties) {
687 if (!vcard.HasProperty(propertyId)) {
688 vcard.AddProperty(VCardProperty(vcard.GetVersion(), "", propertyId, "", ""));
689 }
690 }
691 }
692 };
693
694 const std::map<char16_t, uint8_t> PbapPseVcardManager::VCARD_HANDLE_CHAR_MAP = {
695 {'0', 0},
696 {'1', 1},
697 {'2', 2},
698 {'3', 3},
699 {'4', 4},
700 {'5', 5},
701 {'6', 6},
702 {'7', 7},
703 {'8', 8},
704 {'9', 9},
705 {'A', 10},
706 {'B', 11},
707 {'C', 12},
708 {'D', 13},
709 {'E', 14},
710 {'F', 15},
711 {'a', 10},
712 {'b', 11},
713 {'c', 12},
714 {'d', 13},
715 {'e', 14},
716 {'f', 15}
717 };
718
719 const std::map<std::u16string, std::u16string> PbapPseVcardManager::VIRTUAL_VCF_FOLDER_MAP = {
720 {u"/telecom/pb.vcf", u"pb"},
721 {u"/telecom/ich.vcf", u"ich"},
722 {u"/telecom/och.vcf", u"och"},
723 {u"/telecom/mch.vcf", u"mch"},
724 {u"/telecom/cch.vcf", u"cch"},
725 {u"/telecom/spd.vcf", u"spd"},
726 {u"/telecom/fav.vcf", u"fav"},
727 {u"/SIM1/telecom/pb.vcf", u"pb1"},
728 {u"/SIM1/telecom/ich.vcf", u"ich1"},
729 {u"/SIM1/telecom/och.vcf", u"och1"},
730 {u"/SIM1/telecom/mch.vcf", u"mch1"},
731 {u"/SIM1/telecom/cch.vcf", u"cch1"},
732 };
733
734 const std::map<uint64_t, std::string> PbapPseVcardManager::PROPERTY_MASK_MAP = {
735 {uint64_t(1) << 0, "VERSION"},
736 {uint64_t(1) << 1, "FN"},
737 {uint64_t(1) << 2, "N"},
738 {uint64_t(1) << 3, "PHOTO"},
739 {uint64_t(1) << 4, "BDAY"},
740 {uint64_t(1) << 5, "ADR"},
741 {uint64_t(1) << 6, "LABEL"},
742 {uint64_t(1) << 7, "TEL"},
743 {uint64_t(1) << 8, "EMAIL"},
744 {uint64_t(1) << 9, "MAILER"},
745 {uint64_t(1) << 10, "TZ"},
746 {uint64_t(1) << 11, "GEO"},
747 {uint64_t(1) << 12, "TITLE"},
748 {uint64_t(1) << 13, "ROLE"},
749 {uint64_t(1) << 14, "LOGO"},
750 {uint64_t(1) << 15, "AGENT"},
751 {uint64_t(1) << 16, "ORG"},
752 {uint64_t(1) << 17, "NOTE"},
753 {uint64_t(1) << 18, "REV"},
754 {uint64_t(1) << 19, "SOUND"},
755 {uint64_t(1) << 20, "URL"},
756 {uint64_t(1) << 21, "UID"},
757 {uint64_t(1) << 22, "KEY"},
758 {uint64_t(1) << 23, "NICKNAME"},
759 {uint64_t(1) << 24, "CATEGORIES"},
760 {uint64_t(1) << 25, "PROID"},
761 {uint64_t(1) << 26, "CLASS"},
762 {uint64_t(1) << 27, "SORT-STRING"},
763 {uint64_t(1) << 28, "X-IRMC-CALL-DATETIME"},
764 {uint64_t(1) << 29, "X-BT-SPEEDDIALKEY"},
765 {uint64_t(1) << 30, "X-BT-UCI"},
766 {uint64_t(1) << 31, "X-BT-UID"}
767 };
768
769 std::string PbapPseVcardManager::g_pbapDbFile = PBAP_PSE_DEFAULT_DB_FILE;
770
SetDbFile(const std::string dbFile)771 void PbapPseVcardManager::SetDbFile(const std::string dbFile)
772 {
773 g_pbapDbFile = dbFile;
774 }
775
PullPhoneBook(std::u16string nameWithFolder,const PbapPseAppParams & pbapAppParams,const uint32_t & supportedFeatures,PhoneBookResult & result)776 void PbapPseVcardManager::PullPhoneBook(std::u16string nameWithFolder, const PbapPseAppParams &pbapAppParams,
777 const uint32_t &supportedFeatures, PhoneBookResult &result)
778 {
779 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
780 if (nameWithFolder.at(0) != '/') {
781 nameWithFolder = u"/" + nameWithFolder;
782 }
783 auto target = VIRTUAL_VCF_FOLDER_MAP.find(nameWithFolder);
784 // not find folder
785 if (target == VIRTUAL_VCF_FOLDER_MAP.end()) {
786 PBAP_PSE_LOG_ERROR("can't find vcard %{public}s", ObexUtils::UnicodeToUtf8(nameWithFolder).c_str());
787 result.rspCode_ = ObexRspCode::NOT_FOUND;
788 return;
789 }
790
791 auto dataAccess = DataAccess::GetConnection(g_pbapDbFile);
792 if (!dataAccess) {
793 result.rspCode_ = ObexRspCode::NOT_FOUND;
794 return;
795 }
796
797 const std::u16string &folderId = target->second;
798 if (pbapAppParams.GetMaxListCount()) {
799 uint16_t maxListCount = *pbapAppParams.GetMaxListCount();
800 // PBAP_v1.2.3-5.1.4.3 MaxListCount
801 result.phoneBookSizeOnly_ = maxListCount == 0;
802 }
803 if (result.phoneBookSizeOnly_) {
804 PBAP_PSE_LOG_DEBUG("GetPhoneBookSizeOnly");
805 PbapPseVcardDataAccess::SetPhoneBookSize(dataAccess, folderId, result, pbapAppParams);
806 if (result.rspCode_ != ObexRspCode::SUCCESS) {
807 return;
808 }
809 }
810 PbapPseVcardDataAccess::SetCommonResult(dataAccess, folderId, result, supportedFeatures);
811 if (result.rspCode_ != ObexRspCode::SUCCESS) {
812 return;
813 }
814 if (!result.phoneBookSizeOnly_) {
815 PBAP_PSE_LOG_DEBUG("GetPhoneBook");
816 PbapPseVcardDataAccess::SetPhoneBook(dataAccess, folderId, result, pbapAppParams, supportedFeatures);
817 }
818 }
819
PullvCardListing(std::u16string currentPath,std::u16string folderName,const PbapPseAppParams & pbapAppParams,const uint32_t & supportedFeatures,PhoneBookResult & result)820 void PbapPseVcardManager::PullvCardListing(std::u16string currentPath, std::u16string folderName,
821 const PbapPseAppParams &pbapAppParams, const uint32_t &supportedFeatures, PhoneBookResult &result)
822 {
823 PBAP_PSE_LOG_INFO("%{public}s ", __PRETTY_FUNCTION__);
824 std::u16string nameWithFolder = currentPath;
825 if (folderName.size() > 0) {
826 nameWithFolder += u"/" + folderName;
827 }
828 nameWithFolder += PBAP_PSE_VCARD_SUFFIX;
829 auto target = VIRTUAL_VCF_FOLDER_MAP.find(nameWithFolder);
830 // not find folder
831 if (target == VIRTUAL_VCF_FOLDER_MAP.end()) {
832 PBAP_PSE_LOG_ERROR("can't find folder [%{public}s] in [%{public}s]",
833 ObexUtils::UnicodeToUtf8(folderName).c_str(),
834 ObexUtils::UnicodeToUtf8(currentPath).c_str());
835 result.rspCode_ = ObexRspCode::NOT_FOUND;
836 return;
837 }
838 auto dataAccess = DataAccess::GetConnection(g_pbapDbFile);
839 if (!dataAccess) {
840 result.rspCode_ = ObexRspCode::NOT_FOUND;
841 return;
842 }
843 const std::u16string &folderId = target->second;
844
845 if (pbapAppParams.GetMaxListCount()) {
846 uint16_t maxListCount = *pbapAppParams.GetMaxListCount();
847 // PBAP_v1.2.3-5.1.4.3 MaxListCount
848 result.phoneBookSizeOnly_ = maxListCount == 0;
849 }
850 if (result.phoneBookSizeOnly_) {
851 PbapPseVcardDataAccess::SetPullvCardListingSize(dataAccess, folderId, result, pbapAppParams);
852 if (result.rspCode_ != ObexRspCode::SUCCESS) {
853 return;
854 }
855 }
856
857 PbapPseVcardDataAccess::SetCommonResult(dataAccess, folderId, result, supportedFeatures);
858
859 if (result.rspCode_ != ObexRspCode::SUCCESS) {
860 return;
861 }
862
863 if (!result.phoneBookSizeOnly_) {
864 PbapPseVcardDataAccess::SetPullvCardListing(dataAccess, folderId, result, pbapAppParams);
865 }
866 }
867
PullvCardEntry(std::u16string currentPath,std::u16string entryId,const PbapPseAppParams & pbapAppParams,const uint32_t & supportedFeatures,PhoneBookResult & result)868 void PbapPseVcardManager::PullvCardEntry(std::u16string currentPath, std::u16string entryId,
869 const PbapPseAppParams &pbapAppParams, const uint32_t &supportedFeatures, PhoneBookResult &result)
870 {
871 std::u16string folderId = u"";
872 if (entryId.find(PBAP_PSE_X_BT_UID_PREFIX) == std::string::npos) {
873 // not find folder
874 std::u16string nameWithFolder = currentPath + PBAP_PSE_VCARD_SUFFIX;
875 auto target = VIRTUAL_VCF_FOLDER_MAP.find(nameWithFolder);
876 if (target == VIRTUAL_VCF_FOLDER_MAP.end()) {
877 PBAP_PSE_LOG_ERROR("can't find folder [%{public}s] ", ObexUtils::UnicodeToUtf8(currentPath).c_str());
878 result.rspCode_ = ObexRspCode::NOT_FOUND;
879 return;
880 }
881 folderId = target->second;
882 }
883 auto dataAccess = DataAccess::GetConnection(g_pbapDbFile);
884 if (!dataAccess) {
885 result.rspCode_ = ObexRspCode::NOT_FOUND;
886 return;
887 }
888 if (IsSupportedDbVer(supportedFeatures)) {
889 PbapPseVcardDataAccess::SetDbId(dataAccess, result);
890 if (result.rspCode_ != ObexRspCode::SUCCESS) {
891 return;
892 }
893 }
894
895 PbapPseVcardDataAccess::SetPullvCardEntryParam param = {
896 folderId, entryId, supportedFeatures
897 };
898 PbapPseVcardDataAccess::SetPullvCardEntry(dataAccess, param, pbapAppParams, result);
899 }
900
CheckPhoneBookPath(std::u16string path)901 bool PbapPseVcardManager::CheckPhoneBookPath(std::u16string path)
902 {
903 if (path.size() == 0) {
904 return true;
905 }
906 if (path.at(0) != '/') {
907 path = u"/" + path;
908 }
909 if (path.back() != '/') {
910 path += u"/";
911 }
912 for (auto &item : VIRTUAL_VCF_FOLDER_MAP) {
913 std::u16string fullPath = item.first;
914 fullPath = fullPath.substr(0, fullPath.size() - PBAP_PSE_VCARD_SUFFIX.size()) + u"/";
915 if (fullPath.find(path) == 0) {
916 return true;
917 }
918 }
919 return false;
920 }
921
CheckVcardHandleId(const std::u16string & handleId)922 bool PbapPseVcardManager::CheckVcardHandleId(const std::u16string &handleId)
923 {
924 if (handleId.size() == 0) {
925 return false;
926 }
927 for (char16_t c : handleId) {
928 if (VCARD_HANDLE_CHAR_MAP.find(c) == VCARD_HANDLE_CHAR_MAP.end()) {
929 return false;
930 }
931 }
932 return true;
933 }
934
VcardHandleId2Int(const std::u16string & handleId)935 int PbapPseVcardManager::VcardHandleId2Int(const std::u16string &handleId)
936 {
937 size_t size = handleId.size();
938 if (size == 0) {
939 return -1;
940 }
941 int dec = 0;
942 for (size_t index = 0; index < size; index++) {
943 char16_t c = handleId.at(index);
944 if (VCARD_HANDLE_CHAR_MAP.find(c) == VCARD_HANDLE_CHAR_MAP.end()) {
945 return -1;
946 }
947 uint8_t num = VCARD_HANDLE_CHAR_MAP.find(c)->second;
948 if (num == 0) {
949 continue;
950 }
951 int m = 1;
952 for (size_t count = 0; count < size - index - 1; count++) {
953 m *= 0x10;
954 }
955 dec += (num * m);
956 }
957 return dec;
958 }
959
GetIncludeProperties(uint64_t propertySelector)960 std::vector<std::string> PbapPseVcardManager::GetIncludeProperties(uint64_t propertySelector)
961 {
962 std::vector<std::string> list;
963 for (auto item : PROPERTY_MASK_MAP) {
964 if ((propertySelector & item.first) != 0) {
965 list.push_back(item.second);
966 }
967 }
968 return list;
969 }
970
IsSupportedFolderVer(const uint32_t & supportedFeatures)971 bool PbapPseVcardManager::IsSupportedFolderVer(const uint32_t &supportedFeatures)
972 {
973 return (PBAP_FEATURES_FOLDER_VERSION_COUNTERS & supportedFeatures) != 0;
974 }
975
IsSupportedDbVer(const uint32_t & supportedFeatures)976 bool PbapPseVcardManager::IsSupportedDbVer(const uint32_t &supportedFeatures)
977 {
978 return (PBAP_FEATURES_DATABASE_IDENTIFIER & supportedFeatures) != 0;
979 }
980
IsSupportedXBtUCI(const uint32_t & supportedFeatures)981 bool PbapPseVcardManager::IsSupportedXBtUCI(const uint32_t &supportedFeatures)
982 {
983 return (PBAP_FEATURES_X_BT_UCI_VCARD_PROPERTY & supportedFeatures) != 0;
984 }
985
IsSupportedXBtUID(const uint32_t & supportedFeatures)986 bool PbapPseVcardManager::IsSupportedXBtUID(const uint32_t &supportedFeatures)
987 {
988 return (PBAP_FEATURES_X_BT_UID_VCARD_PROPERTY & supportedFeatures) != 0;
989 }
990 } // namespace bluetooth
991 } // namespace OHOS
992