1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License") { return TELEPHONY_SUCCESS; }
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 #include "vcard_constructor.h"
16
17 #include <iomanip>
18 #include <set>
19 #include <map>
20
21 #include "telephony_errors.h"
22 #include "telephony_log_wrapper.h"
23 #include "vcard_constant.h"
24 #include "vcard_utils.h"
25
26 namespace OHOS {
27 namespace Telephony {
28
VCardConstructor(int32_t cardType,const std::string & charset)29 VCardConstructor::VCardConstructor(int32_t cardType, const std::string &charset)
30 : cardType_(cardType), charset_(charset)
31 {
32 charsetParam_ = "CHARSET=" + charset;
33 if (charset.empty()) {
34 charsetParam_ = "CHARSET=UTF-8";
35 }
36 isV30OrV40_ = VCardConfiguration::IsVer30(cardType_) || VCardConfiguration::IsVer40(cardType_);
37 needCharsetParam_ = !(VCardConfiguration::IsVer30(cardType) && VCardUtils::EqualsIgnoreCase("UTF-8", charset));
38 needQP_ = !VCardConfiguration::IsVer30(cardType_);
39 headLength_ = 0;
40 }
41
ContactVCard(std::shared_ptr<VCardContact> contact)42 std::string VCardConstructor::ContactVCard(std::shared_ptr<VCardContact> contact)
43 {
44 result_.str("");
45 ContactBegin();
46 ConstructName(contact);
47 ConstructPhones(contact);
48 ConstructRelation(contact);
49 ConstructIms(contact);
50 ConstructSipAddresses(contact);
51 ConstructNickNames(contact);
52 ConstructEmails(contact);
53 ConstructPostals(contact);
54 ConstructOrganizations(contact);
55 ConstructWebsites(contact);
56 ConstructPhotos(contact);
57 ConstructNotes(contact);
58 ConstructEvents(contact);
59 ConstructGroups(contact);
60 ContactEnd();
61 return result_.str();
62 }
63
ContactBegin()64 void VCardConstructor::ContactBegin()
65 {
66 AddLine(VCARD_TYPE_BEGIN, DATA_VCARD);
67 if (VCardConfiguration::IsVer40(cardType_)) {
68 AddLine(VCARD_TYPE_VERSION, VERSION_40);
69 } else if (VCardConfiguration::IsVer30(cardType_)) {
70 AddLine(VCARD_TYPE_VERSION, VERSION_30);
71 } else {
72 AddLine(VCARD_TYPE_VERSION, VERSION_21);
73 }
74 headLength_ = VCardUtils::GetOStreamSize(result_);
75 }
76
ContactEnd()77 void VCardConstructor::ContactEnd()
78 {
79 const size_t resultSize = VCardUtils::GetOStreamSize(result_);
80 if (headLength_ == resultSize) {
81 TELEPHONY_LOGW("empty content");
82 result_.str("");
83 return;
84 }
85 AddLine(VCARD_TYPE_END, DATA_VCARD);
86 }
87
SetPhoneNumberEncodedCallback(std::shared_ptr<PhoneNumberEncodedCallback> phoneNumberEncodedCallback)88 void VCardConstructor::SetPhoneNumberEncodedCallback(
89 std::shared_ptr<PhoneNumberEncodedCallback> phoneNumberEncodedCallback)
90 {
91 phoneNumberEncodedCallback_ = phoneNumberEncodedCallback;
92 }
93
IsNeedCharsetParam(std::vector<std::string> strs)94 bool VCardConstructor::IsNeedCharsetParam(std::vector<std::string> strs)
95 {
96 if (!needCharsetParam_) {
97 return false;
98 }
99 return !VCardUtils::IsWrapPrintableAscii(strs);
100 }
101
FormatFullName(const std::string & givenName,const std::string & middleName,const std::string & familyName)102 std::string VCardConstructor::FormatFullName(
103 const std::string &givenName, const std::string &middleName, const std::string &familyName)
104 {
105 std::ostringstream fullName;
106 fullName << givenName;
107 if (!middleName.empty()) {
108 fullName << " " << middleName << ".";
109 }
110 fullName << " " << familyName;
111 return fullName.str();
112 }
113
ConstructNameV40(std::shared_ptr<VCardContact> contact)114 int32_t VCardConstructor::ConstructNameV40(std::shared_ptr<VCardContact> contact)
115 {
116 auto nameDatas = contact->GetNames();
117 if (nameDatas.empty()) {
118 AddLine(VCARD_TYPE_FN, "");
119 return TELEPHONY_SUCCESS;
120 }
121 auto nameData = nameDatas[0];
122 if (nameData == nullptr) {
123 return TELEPHONY_ERR_LOCAL_PTR_NULL;
124 }
125 std::string familyName = nameData->GetFamily();
126 std::string middleName = nameData->GetMiddle();
127 std::string givenName = nameData->GetGiven();
128 std::string prefix = nameData->GetPrefix();
129 std::string suffix = nameData->GetSuffix();
130 std::string formattedName = nameData->GetDisplayName();
131 if (familyName.empty() && givenName.empty() && middleName.empty() && prefix.empty() && suffix.empty()) {
132 if (formattedName.empty()) {
133 AddLine(VCARD_TYPE_FN, "");
134 return TELEPHONY_SUCCESS;
135 }
136 familyName = formattedName;
137 }
138 std::string phoneticFamilyName = nameData->GetPhoneticFamily();
139 std::string phoneticMiddleName = nameData->GetPhoneticMiddle();
140 std::string phoneticGivenName = nameData->GetPhoneticGiven();
141 std::string escapedFamily = DealCharacters(familyName);
142 std::string escapedGiven = DealCharacters(givenName);
143 std::string escapedMiddle = DealCharacters(middleName);
144 std::string escapedPrefix = DealCharacters(prefix);
145 std::string escapedSuffix = DealCharacters(suffix);
146 result_ << VCARD_TYPE_N;
147 if (!(phoneticFamilyName.empty() && phoneticMiddleName.empty() && phoneticGivenName.empty())) {
148 std::string sortAs = DealCharacters(phoneticFamilyName) + ';' + DealCharacters(phoneticGivenName) + ';' +
149 DealCharacters(phoneticMiddleName);
150 result_ << PARAM_SEPARATOR << "SORT-AS=" << sortAs;
151 }
152 AddNameData(escapedFamily, escapedGiven, escapedMiddle, escapedPrefix, escapedSuffix);
153 if (formattedName.empty()) {
154 std::string name = DealCharacters(FormatFullName(givenName, middleName, familyName));
155 AddLine(VCARD_TYPE_FN, name);
156 } else {
157 std::string formatted = DealCharacters(formattedName);
158 result_ << VCARD_TYPE_FN;
159 result_ << DATA_SEPARATOR << formatted;
160 result_ << END_OF_LINE;
161 }
162 ConstructPhoneticNameFields(nameData);
163 return TELEPHONY_SUCCESS;
164 }
165
AddNameData(const std::string & family,const std::string & given,const std::string & middle,const std::string & prefix,const std::string & suffix)166 void VCardConstructor::AddNameData(const std::string &family, const std::string &given, const std::string &middle,
167 const std::string &prefix, const std::string &suffix)
168 {
169 result_ << DATA_SEPARATOR << family;
170 result_ << ITEM_SEPARATOR << given;
171 result_ << ITEM_SEPARATOR << middle;
172 result_ << ITEM_SEPARATOR << prefix;
173 result_ << ITEM_SEPARATOR << suffix;
174 result_ << END_OF_LINE;
175 }
176
ConstructPhoneticNameFields(std::shared_ptr<VCardNameData> nameData)177 int32_t VCardConstructor::ConstructPhoneticNameFields(std::shared_ptr<VCardNameData> nameData)
178 {
179 std::string phoneticFamilyName = nameData->GetPhoneticFamily();
180 std::string phoneticMiddleName = nameData->GetPhoneticMiddle();
181 std::string phoneticGivenName = nameData->GetPhoneticGiven();
182 if (phoneticFamilyName.empty() && phoneticMiddleName.empty() && phoneticGivenName.empty()) {
183 return TELEPHONY_SUCCESS;
184 }
185 if (VCardConfiguration::IsVer30(cardType_)) {
186 std::string fullName = FormatFullName(phoneticFamilyName, phoneticMiddleName, phoneticGivenName);
187 result_ << VCARD_TYPE_SORT_STRING;
188 if (IsNeedCharsetParam({ fullName })) {
189 result_ << PARAM_SEPARATOR << charsetParam_;
190 }
191 result_ << DATA_SEPARATOR << DealCharacters(fullName);
192 result_ << END_OF_LINE;
193 }
194 AddPhoneticName(VCARD_TYPE_X_PHONETIC_FIRST_NAME, phoneticGivenName);
195 AddPhoneticName(VCARD_TYPE_X_PHONETIC_MIDDLE_NAME, phoneticMiddleName);
196 AddPhoneticName(VCARD_TYPE_X_PHONETIC_LAST_NAME, phoneticFamilyName);
197 return TELEPHONY_SUCCESS;
198 }
199
AddPhoneticName(const std::string & phoneticType,const std::string & phoneticName)200 int32_t VCardConstructor::AddPhoneticName(const std::string &phoneticType, const std::string &phoneticName)
201 {
202 if (phoneticName.empty()) {
203 return TELEPHONY_SUCCESS;
204 }
205 bool needAddCharset = IsNeedCharsetParam({ phoneticName });
206 bool needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii({ phoneticName });
207 std::string encodedPhoneticName =
208 (needAddQuotedPrintable ? EncodeQuotedPrintable(phoneticName) : DealCharacters(phoneticName));
209 result_ << phoneticType;
210 AddCharsetOrQuotedPrintable(needAddCharset, needAddQuotedPrintable);
211 result_ << DATA_SEPARATOR << encodedPhoneticName;
212 result_ << END_OF_LINE;
213 return TELEPHONY_SUCCESS;
214 }
215
ConstructName(std::shared_ptr<VCardContact> contact)216 int32_t VCardConstructor::ConstructName(std::shared_ptr<VCardContact> contact)
217 {
218 if (contact == nullptr) {
219 TELEPHONY_LOGI("contact is null");
220 return TELEPHONY_ERR_LOCAL_PTR_NULL;
221 }
222
223 if (VCardConfiguration::IsVer40(cardType_)) {
224 return ConstructNameV40(contact);
225 }
226
227 auto nameDatas = contact->GetNames();
228 if (nameDatas.empty()) {
229 if (VCardConfiguration::IsVer30(cardType_)) {
230 AddLine(VCARD_TYPE_N, "");
231 AddLine(VCARD_TYPE_FN, "");
232 }
233 return TELEPHONY_SUCCESS;
234 }
235
236 auto nameData = nameDatas[0];
237 if (nameData == nullptr) {
238 return TELEPHONY_ERR_LOCAL_PTR_NULL;
239 }
240 std::string familyName = nameData->GetFamily();
241 std::string middleName = nameData->GetMiddle();
242 std::string givenName = nameData->GetGiven();
243 std::string prefix = nameData->GetPrefix();
244 std::string suffix = nameData->GetSuffix();
245 std::string displayName = nameData->GetDisplayName();
246
247 if (!familyName.empty() || !givenName.empty()) {
248 DealNoEmptyFamilyOrGivenName(familyName, givenName, middleName, prefix, suffix, displayName);
249 } else if (!displayName.empty()) {
250 AddSinglePartNameField(VCARD_TYPE_N, displayName);
251 result_ << ITEM_SEPARATOR;
252 result_ << ITEM_SEPARATOR;
253 result_ << ITEM_SEPARATOR;
254 result_ << END_OF_LINE;
255 AddSinglePartNameField(VCARD_TYPE_FN, displayName);
256 result_ << END_OF_LINE;
257 } else if (VCardConfiguration::IsVer30(cardType_)) {
258 AddLine(VCARD_TYPE_N, "");
259 AddLine(VCARD_TYPE_FN, "");
260 } else {
261 TELEPHONY_LOGI("No need to do anything");
262 }
263 ConstructPhoneticNameFields(nameData);
264 return TELEPHONY_SUCCESS;
265 }
266
DealNoEmptyFamilyOrGivenName(const std::string & familyName,const std::string & givenName,const std::string & middleName,const std::string & prefix,const std::string & suffix,const std::string & displayName)267 void VCardConstructor::DealNoEmptyFamilyOrGivenName(const std::string &familyName, const std::string &givenName,
268 const std::string &middleName, const std::string &prefix, const std::string &suffix, const std::string &displayName)
269 {
270 bool needAddCharset = IsNeedCharsetParam({ familyName, givenName, middleName, prefix, suffix });
271 bool needAddQuotedPrintable =
272 needQP_ && !VCardUtils::IsPrintableAscii({ familyName, givenName, middleName, prefix, suffix });
273 std::string formattedName;
274 if (!displayName.empty()) {
275 formattedName = displayName;
276 } else {
277 formattedName = FormatFullName(givenName, middleName, familyName);
278 }
279 bool needAddCharsetToFN = IsNeedCharsetParam({ formattedName });
280 bool needAddQuotedPrintableToFN = needQP_ && !VCardUtils::IsPrintableAscii({ formattedName });
281 std::string encodedFamily =
282 (needAddQuotedPrintable ? EncodeQuotedPrintable(familyName) : DealCharacters(familyName));
283 std::string encodedGiven = (needAddQuotedPrintable ? EncodeQuotedPrintable(givenName) : DealCharacters(givenName));
284 std::string encodedMiddle =
285 (needAddQuotedPrintable ? EncodeQuotedPrintable(middleName) : DealCharacters(middleName));
286 std::string encodedPrefix = (needAddQuotedPrintable ? EncodeQuotedPrintable(prefix) : DealCharacters(prefix));
287 std::string encodedSuffix = (needAddQuotedPrintable ? EncodeQuotedPrintable(suffix) : DealCharacters(suffix));
288 std::string encodedFormattedname =
289 (needAddQuotedPrintableToFN ? EncodeQuotedPrintable(formattedName) : DealCharacters(formattedName));
290 // if (familyName + middleName + givenName) equals prefix, do not export prefix/suffix to avoid repeat
291 std::string combinedName = "";
292 combinedName.append(familyName).append(middleName).append(givenName);
293 if (combinedName == prefix) {
294 encodedPrefix = "";
295 }
296 if (combinedName == suffix) {
297 encodedSuffix = "";
298 }
299 result_ << VCARD_TYPE_N;
300 AddCharsetOrQuotedPrintable(needAddCharset, needAddQuotedPrintable);
301 AddNameData(encodedFamily, encodedGiven, encodedMiddle, encodedPrefix, encodedSuffix);
302
303 result_ << VCARD_TYPE_FN;
304 AddCharsetOrQuotedPrintable(needAddCharsetToFN, needAddQuotedPrintableToFN);
305 result_ << DATA_SEPARATOR << encodedFormattedname;
306 result_ << END_OF_LINE;
307 }
308
AddCharsetOrQuotedPrintable(bool needAddCharset,bool needAddQuotedPrintable)309 void VCardConstructor::AddCharsetOrQuotedPrintable(bool needAddCharset, bool needAddQuotedPrintable)
310 {
311 if (needAddCharset) {
312 result_ << PARAM_SEPARATOR << charsetParam_;
313 }
314 if (needAddQuotedPrintable) {
315 result_ << PARAM_SEPARATOR << PARAM_ENCODING_QP;
316 }
317 }
318
AddSinglePartNameField(std::string property,std::string part)319 void VCardConstructor::AddSinglePartNameField(std::string property, std::string part)
320 {
321 bool needQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii({ part });
322 std::string encodedPart = needQuotedPrintable ? EncodeQuotedPrintable(part) : DealCharacters(part);
323 result_ << property;
324 AddCharsetOrQuotedPrintable(IsNeedCharsetParam({ part }), needQuotedPrintable);
325 if (property == VCARD_TYPE_N) {
326 result_ << DATA_SEPARATOR << ITEM_SEPARATOR << encodedPart;
327 return;
328 }
329 result_ << DATA_SEPARATOR << encodedPart;
330 }
331
ConstructPhones(std::shared_ptr<VCardContact> contact)332 int32_t VCardConstructor::ConstructPhones(std::shared_ptr<VCardContact> contact)
333 {
334 if (contact == nullptr) {
335 TELEPHONY_LOGI("contact is null");
336 return TELEPHONY_ERR_LOCAL_PTR_NULL;
337 }
338
339 auto phoneDatas = contact->GetPhones();
340 if (phoneDatas.empty()) {
341 return TELEPHONY_SUCCESS;
342 }
343 std::set<std::string> phoneSet;
344 for (auto data : phoneDatas) {
345 if (data == nullptr) {
346 continue;
347 }
348 std::string number = data->GetNumber();
349 VCardUtils::Trim(number);
350 if (number.empty()) {
351 continue;
352 }
353 std::string labelId = data->GetLabelId();
354 std::string labelName = data->GetLabelName();
355 int64_t type = static_cast<int64_t>(PhoneVcType::NUM_HOME);
356 if (VCardUtils::IsNum(labelId) && labelId.size() < INT_64_LENTGH + 1) {
357 type = std::stoll(labelId);
358 }
359 if (phoneNumberEncodedCallback_ != nullptr) {
360 phoneNumberEncodedCallback_->onCallback(number, type, labelName, false);
361 }
362
363 auto it = phoneSet.find(number);
364 if (it != phoneSet.end()) {
365 continue;
366 }
367 phoneSet.insert(number);
368 AddTelLine(labelId, labelName, number);
369 }
370 return TELEPHONY_SUCCESS;
371 }
372
ConstructRelation(std::shared_ptr<VCardContact> contact)373 int32_t VCardConstructor::ConstructRelation(std::shared_ptr<VCardContact> contact)
374 {
375 if (contact == nullptr) {
376 TELEPHONY_LOGI("contact is null");
377 return TELEPHONY_ERR_LOCAL_PTR_NULL;
378 }
379 for (auto relationData : contact->GetRelations()) {
380 if (relationData == nullptr) {
381 continue;
382 }
383 std::string labelId = relationData->GetLabelId();
384 if (labelId == std::to_string(static_cast<int32_t>(RelationType::CUSTOM_LABEL))) {
385 labelId = std::to_string(VALUE_INDEX_ZERO);
386 }
387 AddCustomType(VCARD_TYPE_X_MOBILE_RELATION,
388 { relationData->GetRelationName(), labelId, relationData->GetLabelName() });
389 }
390 return TELEPHONY_SUCCESS;
391 }
392
AddCustomType(const std::string & type,std::vector<std::string> values)393 void VCardConstructor::AddCustomType(const std::string &type, std::vector<std::string> values)
394 {
395 bool needAddCharset = IsNeedCharsetParam(values);
396 bool needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii(values);
397 result_ << VCARD_TYPE_X_MOBILE_CUSTOM;
398 AddCharsetOrQuotedPrintable(needAddCharset, needAddQuotedPrintable);
399 result_ << DATA_SEPARATOR << type;
400 for (auto value : values) {
401 std::string encodedValue = needAddQuotedPrintable ? EncodeQuotedPrintable(value) : DealCharacters(value);
402 result_ << ITEM_SEPARATOR << encodedValue;
403 }
404 result_ << END_OF_LINE;
405 }
406
ConstructIms(std::shared_ptr<VCardContact> contact)407 int32_t VCardConstructor::ConstructIms(std::shared_ptr<VCardContact> contact)
408 {
409 if (contact == nullptr) {
410 TELEPHONY_LOGI("contact is null");
411 return TELEPHONY_ERR_LOCAL_PTR_NULL;
412 }
413 for (auto imsData : contact->GetIms()) {
414 if (imsData == nullptr) {
415 continue;
416 }
417 auto labelId = imsData->GetLabelId();
418 auto type = VCardUtils::GetTypeFromImLabelId(labelId);
419 if (type.empty()) {
420 continue;
421 }
422 AddLineWithCharsetAndQP(type, { imsData->GetAddress() });
423 }
424 return TELEPHONY_SUCCESS;
425 }
426
ConstructSipAddresses(std::shared_ptr<VCardContact> contact)427 int32_t VCardConstructor::ConstructSipAddresses(std::shared_ptr<VCardContact> contact)
428 {
429 if (contact == nullptr) {
430 TELEPHONY_LOGI("contact is null");
431 return TELEPHONY_ERR_LOCAL_PTR_NULL;
432 }
433 for (auto sipData : contact->GetSips()) {
434 if (sipData == nullptr) {
435 continue;
436 }
437 auto address = sipData->GetAddress();
438 if (address.empty()) {
439 continue;
440 }
441 if (!VCardUtils::StartWith(address, "sip:")) {
442 address = "sip:" + address;
443 }
444 auto type = std::string(VCARD_TYPE_X_SIP);
445 if (VCardConfiguration::IsVer40(cardType_)) {
446 type = VCARD_TYPE_IMPP;
447 }
448 AddLineWithCharsetAndQP(type, { address, sipData->GetLabelId(), sipData->GetLabelName() });
449 }
450 return TELEPHONY_SUCCESS;
451 }
452
ConstructNickNames(std::shared_ptr<VCardContact> contact)453 int32_t VCardConstructor::ConstructNickNames(std::shared_ptr<VCardContact> contact)
454 {
455 if (contact == nullptr) {
456 TELEPHONY_LOGI("contact is null");
457 return TELEPHONY_ERR_LOCAL_PTR_NULL;
458 }
459 for (auto nicknameData : contact->GetNicknames()) {
460 if (nicknameData == nullptr) {
461 continue;
462 }
463 if (nicknameData->GetNickName().empty()) {
464 continue;
465 }
466 AddCustomType(TypeData::NICKNAME, { nicknameData->GetNickName() });
467 }
468 return TELEPHONY_SUCCESS;
469 }
470
ConstructEmails(std::shared_ptr<VCardContact> contact)471 int32_t VCardConstructor::ConstructEmails(std::shared_ptr<VCardContact> contact)
472 {
473 if (contact == nullptr) {
474 TELEPHONY_LOGI("contact is null");
475 return TELEPHONY_ERR_LOCAL_PTR_NULL;
476 }
477
478 std::set<std::string> emailSet;
479 for (auto data : contact->GetEmails()) {
480 std::string email = data->GetAddress();
481 VCardUtils::Trim(email);
482 if (email.empty()) {
483 continue;
484 }
485 int32_t labelId = static_cast<int32_t>(EmailType::EMAIL_OTHER);
486 std::string labelIdStr = data->GetLabelId();
487 if (!labelIdStr.empty() && VCardUtils::IsNum(labelIdStr)) {
488 labelId = std::stoi(labelIdStr);
489 }
490 auto it = emailSet.find(email);
491 if (it != emailSet.end()) {
492 continue;
493 }
494 AddEmailLine(labelId, data->GetLabelName(), email, data->GetDisplayName());
495 emailSet.insert(email);
496 }
497 return TELEPHONY_SUCCESS;
498 }
499
ConstructPostals(std::shared_ptr<VCardContact> contact)500 int32_t VCardConstructor::ConstructPostals(std::shared_ptr<VCardContact> contact)
501 {
502 if (contact == nullptr) {
503 TELEPHONY_LOGI("contact is null");
504 return TELEPHONY_ERR_LOCAL_PTR_NULL;
505 }
506
507 for (auto data : contact->GetPostalDatas()) {
508 if (data == nullptr) {
509 continue;
510 }
511 int32_t labelId = static_cast<int32_t>(PostalType::ADDR_HOME);
512 if (VCardUtils::IsNum(data->GetLabelId())) {
513 labelId = std::stoi(data->GetLabelId());
514 }
515 AddPostalLine(data, labelId, data->GetLabelName());
516 }
517 return TELEPHONY_SUCCESS;
518 }
519
AddPostalLine(std::shared_ptr<VCardPostalData> postalData,int32_t postalType,const std::string & labelName)520 void VCardConstructor::AddPostalLine(
521 std::shared_ptr<VCardPostalData> postalData, int32_t postalType, const std::string &labelName)
522 {
523 bool needCharset = false;
524 bool needAddQuotedPrintable = false;
525 std::ostringstream postalLine;
526 ConstructPostalLine(postalData, postalLine, needCharset, needAddQuotedPrintable);
527 if (postalLine.str().empty()) {
528 return;
529 }
530 std::vector<std::string> paramTypes;
531 std::string postalTypeStr = "";
532 if (postalType == static_cast<int32_t>(PostalType::ADDR_HOME)) {
533 postalTypeStr = VCARD_PARAM_TYPE_HOME;
534 }
535 if (postalType == static_cast<int32_t>(PostalType::ADDR_WORK)) {
536 postalTypeStr = VCARD_PARAM_TYPE_WORK;
537 }
538 if (postalType == static_cast<int32_t>(PostalType::CUSTOM_LABEL) &&
539 !VCardUtils::IsContainsInvisibleChar(labelName)) {
540 postalTypeStr = "X-" + labelName;
541 }
542 if (postalType == static_cast<int32_t>(PostalType::ADDR_OTHER)) {
543 postalTypeStr = "";
544 }
545 if (!postalTypeStr.empty()) {
546 paramTypes.push_back(postalTypeStr);
547 }
548 result_ << VCARD_TYPE_ADR;
549 if (!paramTypes.empty()) {
550 result_ << PARAM_SEPARATOR;
551 AddParamTypes(paramTypes);
552 }
553 AddCharsetOrQuotedPrintable(needCharset, needAddQuotedPrintable);
554 result_ << DATA_SEPARATOR;
555 result_ << postalLine.str() << END_OF_LINE;
556 }
557
ConstructPostalLine(std::shared_ptr<VCardPostalData> postalData,std::ostringstream & postalLine,bool & needCharset,bool & needAddQuotedPrintable)558 void VCardConstructor::ConstructPostalLine(std::shared_ptr<VCardPostalData> postalData, std::ostringstream &postalLine,
559 bool &needCharset, bool &needAddQuotedPrintable)
560 {
561 if (postalData == nullptr) {
562 TELEPHONY_LOGI("postalData is nullptr!");
563 return;
564 }
565 std::string poBox = postalData->GetPOBox();
566 std::string street = postalData->GetStreet();
567 std::string city = postalData->GetCity();
568 std::string region = postalData->GetRegion();
569 std::string postalCode = postalData->GetPostCode();
570 std::string country = postalData->GetCountry();
571 std::vector<std::string> addresses = { poBox, street, city, region, postalCode, country };
572 if (!VCardUtils::IsAllEmpty(addresses)) {
573 needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii(addresses);
574 needCharset = !VCardUtils::IsWrapPrintableAscii({ addresses });
575 std::string encodedPoBox = (needAddQuotedPrintable ? EncodeQuotedPrintable(poBox) : DealCharacters(poBox));
576 std::string encodedStreet = (needAddQuotedPrintable ? EncodeQuotedPrintable(street) : DealCharacters(street));
577 std::string encodedCity = (needAddQuotedPrintable ? EncodeQuotedPrintable(city) : DealCharacters(city));
578 std::string encodedRegion = (needAddQuotedPrintable ? EncodeQuotedPrintable(region) : DealCharacters(region));
579 std::string encodedPostalCode =
580 (needAddQuotedPrintable ? EncodeQuotedPrintable(postalCode) : DealCharacters(postalCode));
581 std::string encodedCountry =
582 (needAddQuotedPrintable ? EncodeQuotedPrintable(country) : DealCharacters(country));
583 postalLine << encodedPoBox << ITEM_SEPARATOR;
584 postalLine << encodedStreet << ITEM_SEPARATOR;
585 postalLine << encodedCity << ITEM_SEPARATOR;
586 postalLine << encodedRegion << ITEM_SEPARATOR;
587 postalLine << encodedPostalCode << ITEM_SEPARATOR;
588 postalLine << encodedCountry;
589 return;
590 }
591 auto postalAddress = postalData->GetPostalAddress();
592 if (postalAddress.empty()) {
593 return;
594 }
595 needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii({ postalAddress });
596 needCharset = IsNeedCharsetParam({ postalAddress });
597 std::string encodedPostalAddress =
598 (needAddQuotedPrintable ? EncodeQuotedPrintable(postalAddress) : DealCharacters(postalAddress));
599 postalLine << ITEM_SEPARATOR;
600 postalLine << encodedPostalAddress;
601 postalLine << ITEM_SEPARATOR;
602 postalLine << ITEM_SEPARATOR;
603 postalLine << ITEM_SEPARATOR;
604 postalLine << ITEM_SEPARATOR;
605 }
606
ConstructOrganizations(std::shared_ptr<VCardContact> contact)607 int32_t VCardConstructor::ConstructOrganizations(std::shared_ptr<VCardContact> contact)
608 {
609 if (contact == nullptr) {
610 TELEPHONY_LOGI("contact is null");
611 return TELEPHONY_ERR_LOCAL_PTR_NULL;
612 }
613 for (auto organizationData : contact->GetOrganizations()) {
614 if (organizationData == nullptr) {
615 continue;
616 }
617 std::string company = organizationData->GetCompany();
618 std::string orgLine = "";
619 VCardUtils::Trim(company);
620 if (!company.empty()) {
621 orgLine += company;
622 }
623 AddLine(VCARD_TYPE_ORG, orgLine, !VCardUtils::IsWrapPrintableAscii({ orgLine }),
624 needQP_ && !VCardUtils::IsPrintableAscii({ orgLine }));
625 std::string title = organizationData->GetTitle();
626 VCardUtils::Trim(title);
627 if (!title.empty()) {
628 AddLine(VCARD_TYPE_TITLE, title, !VCardUtils::IsWrapPrintableAscii({ title }),
629 needQP_ && !VCardUtils::IsPrintableAscii({ title }));
630 }
631 }
632 return TELEPHONY_SUCCESS;
633 }
634
ConstructWebsites(std::shared_ptr<VCardContact> contact)635 int32_t VCardConstructor::ConstructWebsites(std::shared_ptr<VCardContact> contact)
636 {
637 if (contact == nullptr) {
638 TELEPHONY_LOGI("contact is null");
639 return TELEPHONY_ERR_LOCAL_PTR_NULL;
640 }
641 for (auto websiteData : contact->GetWebsites()) {
642 if (websiteData == nullptr) {
643 continue;
644 }
645 auto website = websiteData->GetWebsite();
646 VCardUtils::Trim(website);
647 if (website.empty()) {
648 continue;
649 }
650 AddLineWithCharsetAndQP(VCARD_TYPE_URL, { website });
651 }
652 return TELEPHONY_SUCCESS;
653 }
654
ConstructPhotos(std::shared_ptr<VCardContact> contact)655 int32_t VCardConstructor::ConstructPhotos(std::shared_ptr<VCardContact> contact)
656 {
657 if (contact == nullptr) {
658 TELEPHONY_LOGI("contact is null");
659 return TELEPHONY_ERR_LOCAL_PTR_NULL;
660 }
661 for (auto photoData : contact->GetPhotos()) {
662 if (photoData == nullptr) {
663 continue;
664 }
665 auto bytes = photoData->GetBytes();
666 if (bytes.empty()) {
667 continue;
668 }
669 auto phoneType = VCardUtils::GetImageType(bytes);
670 if (phoneType.empty()) {
671 continue;
672 }
673 auto encodeValue = VCardUtils::EncodeBase64(bytes);
674 if (encodeValue.empty()) {
675 continue;
676 }
677 AddPhotoLine(encodeValue, phoneType);
678 }
679 return TELEPHONY_SUCCESS;
680 }
681
ConstructNotes(std::shared_ptr<VCardContact> contact)682 int32_t VCardConstructor::ConstructNotes(std::shared_ptr<VCardContact> contact)
683 {
684 if (contact == nullptr) {
685 TELEPHONY_LOGI("contact is null");
686 return TELEPHONY_ERR_LOCAL_PTR_NULL;
687 }
688 for (auto noteData : contact->GetNotes()) {
689 if (noteData == nullptr) {
690 continue;
691 }
692 auto note = noteData->GetNote();
693 VCardUtils::Trim(note);
694 if (note.empty()) {
695 continue;
696 }
697 AddLineWithCharsetAndQP(VCARD_TYPE_NOTE, { note });
698 }
699 return TELEPHONY_SUCCESS;
700 }
701
ConstructEvents(std::shared_ptr<VCardContact> contact)702 int32_t VCardConstructor::ConstructEvents(std::shared_ptr<VCardContact> contact)
703 {
704 if (contact == nullptr) {
705 TELEPHONY_LOGI("contact is null");
706 return TELEPHONY_ERR_LOCAL_PTR_NULL;
707 }
708 std::string birthdayDate = "";
709 std::map<int32_t, int32_t> eventMap = {
710 {static_cast<int32_t>(EventType::EVENT_ANNIVERSARY), static_cast<int32_t>(EventHM4Type::EVENT_HM4_ANNIVERSARY)},
711 {static_cast<int32_t>(EventType::EVENT_LUNAR_BIRTHDAY),
712 static_cast<int32_t>(EventHM4Type::EVENT_HM4_LUNAR_BIRTHDAY)},
713 {static_cast<int32_t>(EventType::CUSTOM_LABEL), static_cast<int32_t>(EventHM4Type::EVENT_HM4_OTHER)},
714 {static_cast<int32_t>(EventType::EVENT_BIRTHDAY), static_cast<int32_t>(EventHM4Type::EVENT_HM4_BIRTHDAY)}
715 };
716 for (auto eventData : contact->GetEventDatas()) {
717 if (eventData == nullptr) {
718 continue;
719 }
720 int32_t labelId = static_cast<int32_t>(EventType::EVENT_OTHER);
721 if (VCardUtils::IsNum(eventData->GetLabelId())) {
722 labelId = eventMap[std::stoi(eventData->GetLabelId())];
723 }
724 if (labelId == static_cast<int32_t>(EventHM4Type::EVENT_HM4_BIRTHDAY)) {
725 if (eventData->GetEventDate().empty()) {
726 continue;
727 }
728 birthdayDate = eventData->GetEventDate();
729 continue;
730 }
731 AddCustomType(VCARD_TYPE_X_MOBILE_EVENTS,
732 { eventData->GetEventDate(), std::to_string(labelId), eventData->GetLabelName() });
733 }
734 VCardUtils::Trim(birthdayDate);
735 if (!birthdayDate.empty()) {
736 AddLineWithCharsetAndQP(VCARD_TYPE_BDAY, { birthdayDate });
737 }
738 return TELEPHONY_SUCCESS;
739 }
740
ConstructGroups(std::shared_ptr<VCardContact> contact)741 int32_t VCardConstructor::ConstructGroups(std::shared_ptr<VCardContact> contact)
742 {
743 if (contact == nullptr) {
744 TELEPHONY_LOGE("contact is null");
745 return TELEPHONY_ERR_LOCAL_PTR_NULL;
746 }
747 for (auto groupData : contact->GetGroups()) {
748 if (groupData == nullptr) {
749 continue;
750 }
751 auto groupName = groupData->GetGroupName();
752 VCardUtils::Trim(groupName);
753 if (groupName.empty()) {
754 continue;
755 }
756 AddLineWithCharsetAndQP(VCARD_TYPE_X_GROUP, { groupName });
757 }
758 return TELEPHONY_SUCCESS;
759 }
760
AddTelLine(const std::string & labelId,const std::string & labelName,const std::string & number)761 void VCardConstructor::AddTelLine(const std::string &labelId, const std::string &labelName, const std::string &number)
762 {
763 result_ << VCARD_TYPE_TEL << PARAM_SEPARATOR;
764 auto paramTypes = VCardUtils::GetTypeFromPhoneLabelId(labelId);
765 if (!paramTypes.empty()) {
766 AddParamTypes(paramTypes);
767 } else if (VCardUtils::IsNum(labelId) && labelId.size() < INT_64_LENTGH + 1) {
768 auto phoneType = static_cast<PhoneVcType>(std::stoll(labelId));
769 if (phoneType == PhoneVcType::CUSTOM_LABEL && VCardUtils::IsPrintableAscii({ labelName })) {
770 paramTypes.push_back("X-" + labelName);
771 AddParamTypes(paramTypes);
772 }
773 } else if (labelId.empty()) {
774 paramTypes.push_back(VCARD_PARAM_TYPE_CELL);
775 AddParamTypes(paramTypes);
776 }
777 result_ << DATA_SEPARATOR << number;
778 result_ << END_OF_LINE;
779 }
780
AddPhotoLine(const std::string & encodedValue,const std::string & photoType)781 void VCardConstructor::AddPhotoLine(const std::string &encodedValue, const std::string &photoType)
782 {
783 const size_t encodingSize = isV30OrV40_ ? std::string_view(PARAM_ENCODING_BASE64_AS_B).size() :
784 std::string_view(PARAM_ENCODING_BASE64_V21).size();
785 const size_t endLineSize = std::string_view(END_OF_LINE).size();
786 const size_t wsSize = std::string_view(WS).size();
787
788 const size_t hasTypeSize = isV30OrV40_ ? VALUE_LEN_FIVE : VALUE_LEN_ZERO;
789 const size_t typeSize = photoType.empty() ? VALUE_LEN_ZERO : hasTypeSize + photoType.size();
790 const size_t prefixLen = std::string_view(VCARD_TYPE_PHOTO).size() + VALUE_LEN_ONE + encodingSize +
791 VALUE_LEN_ONE + typeSize + VALUE_LEN_ONE;
792
793 const size_t firstLineCap = MAX_LINE_NUMS_BASE64_V30 - endLineSize + VALUE_LEN_ONE;
794 const size_t secondOnCap = firstLineCap - wsSize;
795
796 result_ << VCARD_TYPE_PHOTO << PARAM_SEPARATOR << (isV30OrV40_ ? PARAM_ENCODING_BASE64_AS_B :
797 PARAM_ENCODING_BASE64_V21);
798 if (!photoType.empty()) {
799 result_ << PARAM_SEPARATOR;
800 AddParamType(result_, photoType);
801 }
802 result_ << DATA_SEPARATOR;
803
804 size_t off = 0;
805 size_t remaining = encodedValue.size();
806 size_t leftOnLine = firstLineCap - prefixLen;
807
808 auto emitLine = [&](size_t len) {
809 result_.write(encodedValue.data() + off, static_cast<std::streamsize>(len));
810 off += len;
811 remaining -= len;
812 leftOnLine -= len;
813 };
814
815 while (remaining > 0) {
816 const size_t chunk = std::min(leftOnLine, remaining);
817 emitLine(chunk);
818 if (remaining == 0) {
819 break;
820 }
821
822 result_ << END_OF_LINE << WS;
823 leftOnLine = secondOnCap;
824 }
825 result_ << END_OF_LINE << END_OF_LINE;
826 }
827
AddEmailLine(int32_t emailType,const std::string & labelName,const std::string & email,const std::string & displayName)828 void VCardConstructor::AddEmailLine(
829 int32_t emailType, const std::string &labelName, const std::string &email, const std::string &displayName)
830 {
831 std::vector<std::string> paramTypes;
832 std::string postalTypeStr = "";
833 if (emailType == static_cast<int32_t>(EmailType::EMAIL_HOME)) {
834 postalTypeStr = VCARD_PARAM_TYPE_HOME;
835 }
836 if (emailType == static_cast<int32_t>(EmailType::EMAIL_WORK)) {
837 postalTypeStr = VCARD_PARAM_TYPE_WORK;
838 }
839 if (emailType == static_cast<int32_t>(EmailType::CUSTOM_LABEL) &&
840 !VCardUtils::IsContainsInvisibleChar(labelName)) {
841 postalTypeStr = "X-" + labelName;
842 }
843 if (emailType == static_cast<int32_t>(EmailType::EMAIL_OTHER)) {
844 postalTypeStr = "";
845 }
846 if (!postalTypeStr.empty()) {
847 paramTypes.push_back(postalTypeStr);
848 }
849 std::vector<std::string> valueList = { email };
850 bool needAddCharset = IsNeedCharsetParam(valueList);
851 bool needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii(valueList);
852 AddLine(VCARD_TYPE_EMAIL, paramTypes, valueList, needAddCharset, needAddQuotedPrintable);
853 }
854
AddLine(const std::string & type,const std::string & rawValue)855 void VCardConstructor::AddLine(const std::string &type, const std::string &rawValue)
856 {
857 AddLine(type, rawValue, false, false);
858 }
859
AddLine(const std::string & type,std::vector<std::string> valueList)860 void VCardConstructor::AddLine(const std::string &type, std::vector<std::string> valueList)
861 {
862 AddLine(type, valueList, false, false);
863 }
864
AddLine(const std::string & type,const std::string & rawValue,bool needCharset,bool needQuotedPrintable)865 void VCardConstructor::AddLine(
866 const std::string &type, const std::string &rawValue, bool needCharset, bool needQuotedPrintable)
867 {
868 AddLine(type, {}, rawValue, needCharset, needQuotedPrintable);
869 }
870
AddLine(const std::string & type,const std::vector<std::string> & paramList,const std::string & rawValue)871 void VCardConstructor::AddLine(
872 const std::string &type, const std::vector<std::string> ¶mList, const std::string &rawValue)
873 {
874 AddLine(type, paramList, rawValue, false, false);
875 }
876
AddLine(const std::string & type,const std::vector<std::string> & paramList,const std::string & rawValue,bool needCharset,bool needQuotedPrintable)877 void VCardConstructor::AddLine(const std::string &type, const std::vector<std::string> ¶mList,
878 const std::string &rawValue, bool needCharset, bool needQuotedPrintable)
879 {
880 result_ << type;
881 if (paramList.size() > 0) {
882 result_ << PARAM_SEPARATOR;
883 AddParamTypes(paramList);
884 }
885 std::string encodedValue = needQuotedPrintable ? EncodeQuotedPrintable(rawValue) : DealCharacters(rawValue);
886 AddCharsetOrQuotedPrintable(needCharset, needQuotedPrintable);
887 result_ << DATA_SEPARATOR;
888 result_ << encodedValue;
889 result_ << END_OF_LINE;
890 }
AddLineWithCharsetAndQP(const std::string & type,std::vector<std::string> valueList)891 void VCardConstructor::AddLineWithCharsetAndQP(const std::string &type, std::vector<std::string> valueList)
892 {
893 bool needAddCharset = IsNeedCharsetParam(valueList);
894 bool needAddQuotedPrintable = needQP_ && !VCardUtils::IsPrintableAscii({ valueList });
895 AddLine(type, valueList, needAddCharset, needAddQuotedPrintable);
896 }
897
AddLine(const std::string & type,std::vector<std::string> valueList,bool needCharset,bool needQuotedPrintable)898 void VCardConstructor::AddLine(
899 const std::string &type, std::vector<std::string> valueList, bool needCharset, bool needQuotedPrintable)
900 {
901 AddLine(type, {}, valueList, needCharset, needQuotedPrintable);
902 }
903
AddLine(const std::string & type,const std::vector<std::string> & paramList,std::vector<std::string> valueList,bool needCharset,bool needQuotedPrintable)904 void VCardConstructor::AddLine(const std::string &type, const std::vector<std::string> ¶mList,
905 std::vector<std::string> valueList, bool needCharset, bool needQuotedPrintable)
906 {
907 result_ << type;
908 if (paramList.size() > 0) {
909 result_ << PARAM_SEPARATOR;
910 AddParamTypes(paramList);
911 }
912 AddCharsetOrQuotedPrintable(needCharset, needQuotedPrintable);
913
914 result_ << DATA_SEPARATOR;
915 bool first = true;
916 for (std::string rawValue : valueList) {
917 std::string encodedValue;
918 if (needQuotedPrintable) {
919 encodedValue = EncodeQuotedPrintable(rawValue);
920 } else {
921 encodedValue = DealCharacters(rawValue);
922 }
923
924 if (first) {
925 first = false;
926 } else {
927 result_ << ITEM_SEPARATOR;
928 }
929 result_ << encodedValue;
930 }
931 result_ << END_OF_LINE;
932 }
933
HandleCharacter(int i,int32_t length,std::string value,std::string & temp)934 void VCardConstructor::HandleCharacter(int i, int32_t length, std::string value, std::string &temp)
935 {
936 auto ch = value[i];
937 switch (ch) {
938 case ';': {
939 temp += "\\;";
940 break;
941 }
942 case '\r': {
943 if (i + 1 < length) {
944 auto nextChar = value[i + 1];
945 if (nextChar == '\n') {
946 break;
947 }
948 }
949 [[fallthrough]]; // fall_through
950 }
951 case '\n': {
952 temp += "\\n";
953 break;
954 }
955 case '\\': {
956 if (isV30OrV40_) {
957 temp += "\\\\";
958 break;
959 }
960 [[fallthrough]]; // fall_through
961 }
962 case ',': {
963 if (isV30OrV40_) {
964 temp += "\\,";
965 } else {
966 temp += ch;
967 }
968 break;
969 }
970 default: {
971 temp += ch;
972 break;
973 }
974 }
975 }
976
DealCharacters(std::string value)977 std::string VCardConstructor::DealCharacters(std::string value)
978 {
979 if (value.empty()) {
980 return "";
981 }
982
983 std::string temp;
984 int32_t length = static_cast<int32_t>(value.length());
985 for (int32_t i = 0; i < length; i++) {
986 HandleCharacter(i, length, value, temp);
987 }
988 return temp;
989 }
990
EncodeQuotedPrintable(const std::string & input)991 std::string VCardConstructor::EncodeQuotedPrintable(const std::string &input)
992 {
993 size_t inputSize = input.size();
994 size_t maxEncodedLen = (inputSize * 3) + // 3: one byte encode three char
995 3 * (inputSize * 3 / ENCODEN_QUOTED_PRIN_MAX_LEN); // 3: size of "=\r\n"
996 std::string encoded;
997 encoded.reserve(maxEncodedLen);
998
999 int lineCount = 0;
1000 for (unsigned char ch : input) {
1001 encoded.append(1, '=');
1002 encoded.append(1, VCARD_HEX_TABLE[(ch >> VCARD_HALF_BYTE) & 0xF]);
1003 encoded.append(1, VCARD_HEX_TABLE[ch & 0xF]);
1004 lineCount += VALUE_LEN_THREE;
1005
1006 if (lineCount >= ENCODEN_QUOTED_PRIN_MAX_LEN) {
1007 encoded.append("=\r\n");
1008 lineCount = 0;
1009 }
1010 }
1011 return encoded;
1012 }
1013
AddParamTypes(std::vector<std::string> types)1014 void VCardConstructor::AddParamTypes(std::vector<std::string> types)
1015 {
1016 if (VCardConfiguration::IsVer40(cardType_) || VCardConfiguration::IsVer30(cardType_)) {
1017 if (types.empty()) {
1018 return;
1019 }
1020 bool first = true;
1021 for (auto typeValue : types) {
1022 if (first) {
1023 first = false;
1024 AddParamType(typeValue);
1025 } else {
1026 result_ << PARAM_SEPARATOR_V3_V4 << typeValue;
1027 }
1028 }
1029 return;
1030 }
1031 bool first = true;
1032 for (auto typeValue : types) {
1033 if (first) {
1034 first = false;
1035 } else {
1036 result_ << PARAM_SEPARATOR;
1037 }
1038 AddParamType(typeValue);
1039 }
1040 }
1041
AddParamType(const std::string & paramType)1042 void VCardConstructor::AddParamType(const std::string ¶mType)
1043 {
1044 AddParamType(result_, paramType);
1045 }
1046
AddParamType(std::ostringstream & result,const std::string & paramType)1047 void VCardConstructor::AddParamType(std::ostringstream &result, const std::string ¶mType)
1048 {
1049 if (isV30OrV40_) {
1050 result << VCARD_PARAM_TYPE;
1051 result << PARAM_EQUAL;
1052 }
1053 result << paramType;
1054 }
1055
ToString()1056 std::string VCardConstructor::ToString()
1057 {
1058 return result_.str();
1059 }
1060
1061 } // namespace Telephony
1062 } // namespace OHOS
1063