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