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