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