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