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> &paramList, 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> &paramList,
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> &paramList,
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 &paramType)
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 &paramType)
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