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