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