• 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");
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 
16 #include "vcard_utils.h"
17 
18 #include <algorithm>
19 #include <array>
20 #include <cctype>
21 #include <ctime>
22 #include <fstream>
23 #include <iconv.h>
24 #include <iomanip>
25 #include <numeric>
26 #include <sstream>
27 
28 #include "base64.h"
29 #include "map"
30 #include "telephony_errors.h"
31 #include "telephony_log_wrapper.h"
32 #include "vcard_configuration.h"
33 #include "vcard_constant.h"
34 
35 namespace OHOS {
36 namespace Telephony {
37 namespace {
38 std::map<ImType, std::string> imLabelIdToType = { { ImType::IM_AIM, VCARD_TYPE_X_AIM },
39     { ImType::IM_MSN, VCARD_TYPE_X_MSN }, { ImType::IM_YAHOO, VCARD_TYPE_X_YAHOO },
40     { ImType::IM_ICQ, VCARD_TYPE_X_ICQ }, { ImType::IM_JABBER, VCARD_TYPE_X_JABBER },
41     { ImType::IM_SKYPE, VCARD_TYPE_X_SKYPE_USERNAME }, { ImType::IM_QQ, VCARD_TYPE_X_QQ },
42     { ImType::IM_HUANLIAO, VCARD_TYPE_X_HUANLIAO} };
43 std::map<PhoneVcType, std::string> phoneLabelIdToType = { { PhoneVcType::NUM_HOME, VCARD_PARAM_TYPE_CELL },
44     { PhoneVcType::NUM_MOBILE, VCARD_PARAM_TYPE_HOME }, { PhoneVcType::NUM_WORK, VCARD_PARAM_TYPE_WORK },
45     { PhoneVcType::NUM_PAGER, VCARD_PARAM_TYPE_PAGER }, { PhoneVcType::NUM_OTHER, VCARD_PARAM_TYPE_VOICE },
46     { PhoneVcType::NUM_CALLBACK, VCARD_PARAM_PHONE_EXTRA_TYPE_CALLBACK },
47     { PhoneVcType::NUM_CAR, VCARD_PARAM_TYPE_CAR }, { PhoneVcType::NUM_COMPANY_MAIN, VCARD_PARAM_TYPE_WORK },
48     { PhoneVcType::NUM_ISDN, VCARD_PARAM_TYPE_ISDN }, { PhoneVcType::NUM_OTHER_FAX, VCARD_PARAM_TYPE_FAX },
49     { PhoneVcType::NUM_RADIO, VCARD_PARAM_PHONE_EXTRA_TYPE_RADIO }, { PhoneVcType::NUM_TELEX, VCARD_PARAM_TYPE_TLX },
50     { PhoneVcType::NUM_TTY_TDD, VCARD_PARAM_PHONE_EXTRA_TYPE_TTY_TDD },
51     { PhoneVcType::NUM_ASSISTANT, VCARD_PARAM_PHONE_EXTRA_TYPE_ASSISTANT },
52     { PhoneVcType::NUM_MMS, VCARD_PARAM_TYPE_MSG }, { PhoneVcType::NUM_MAIN, VCARD_PARAM_TYPE_PREF }};
53 std::map<std::string, PhoneVcType> typeToPhoneTypeMap = { { VCARD_PARAM_TYPE_CAR, PhoneVcType::NUM_CAR },
54     { VCARD_PARAM_TYPE_PAGER, PhoneVcType::NUM_PAGER }, { VCARD_PARAM_TYPE_ISDN, PhoneVcType::NUM_ISDN },
55     { VCARD_PARAM_TYPE_HOME, PhoneVcType::NUM_MOBILE }, { VCARD_PARAM_TYPE_WORK, PhoneVcType::NUM_WORK },
56     { VCARD_PARAM_TYPE_CELL, PhoneVcType::NUM_HOME },
57     { VCARD_PARAM_PHONE_EXTRA_TYPE_CALLBACK, PhoneVcType::NUM_CALLBACK },
58     { VCARD_PARAM_PHONE_EXTRA_TYPE_RADIO, PhoneVcType::NUM_RADIO },
59     { VCARD_PARAM_PHONE_EXTRA_TYPE_TTY_TDD, PhoneVcType::NUM_TTY_TDD },
60     { VCARD_PARAM_PHONE_EXTRA_TYPE_ASSISTANT, PhoneVcType::NUM_ASSISTANT },
61     { VCARD_PARAM_TYPE_VOICE, PhoneVcType::NUM_OTHER } };
62 } // namespace
63 
EncodeBase64(const std::string & input)64 std::string VCardUtils::EncodeBase64(const std::string &input)
65 {
66     std::vector<unsigned char> tempInput(input.begin(), input.end());
67     std::shared_ptr<std::string> encodedDataString = OHOS::Telephony::Base64::Encode(tempInput);
68     if (encodedDataString == nullptr) {
69         return "";
70     }
71     return *encodedDataString;
72 }
73 
DecodeBase64(const std::string & input)74 std::string VCardUtils::DecodeBase64(const std::string &input)
75 {
76     auto decodedDataString = OHOS::Telephony::Base64::Decode(input);
77     if (decodedDataString == nullptr) {
78         return "";
79     }
80     return std::string(decodedDataString->begin(), decodedDataString->end());
81 }
82 
DecodeBase64NoWrap(const std::string & input)83 std::string VCardUtils::DecodeBase64NoWrap(const std::string &input)
84 {
85     const std::string LF_SIGN = "\n";
86     std::string::size_type pos;
87     std::string rawStr = input;
88     while ((pos = rawStr.find(LF_SIGN)) != std::string::npos) {
89         rawStr.erase(pos, LF_SIGN.length());
90     }
91     return DecodeBase64(rawStr);
92 }
93 
EqualsIgnoreCase(const std::string & str1,const std::string & str2)94 bool VCardUtils::EqualsIgnoreCase(const std::string &str1, const std::string &str2)
95 {
96     std::string copy1 = str1;
97     std::string copy2 = str2;
98 
99     std::transform(copy1.begin(), copy1.end(), copy1.begin(), ::tolower);
100     std::transform(copy2.begin(), copy2.end(), copy2.begin(), ::tolower);
101 
102     return copy1 == copy2;
103 }
104 
Split(const std::string & input,const std::string & delimiter)105 std::vector<std::string> VCardUtils::Split(const std::string &input, const std::string &delimiter)
106 {
107     std::vector<std::string> result;
108     std::size_t pos = 0;
109     std::size_t delimiterPos;
110 
111     while ((delimiterPos = input.find(delimiter, pos)) != std::string::npos) {
112         std::string token = input.substr(pos, delimiterPos - pos);
113         result.push_back(token);
114         pos = delimiterPos + delimiter.size();
115     }
116 
117     if (pos < input.size()) {
118         std::string token = input.substr(pos);
119         result.push_back(token);
120     }
121 
122     return result;
123 }
124 
Trim(std::string & str)125 std::string VCardUtils::Trim(std::string &str)
126 {
127     std::string::size_type pos1 = str.find_first_not_of(" \t\n\r\f\v");
128     std::string::size_type pos2 = str.find_last_not_of(" \t\n\r\f\v");
129     if (pos1 != std::string::npos && pos2 != std::string::npos) {
130         str = str.substr(pos1, pos2 - pos1 + 1);
131     } else {
132         str.clear();
133     }
134 
135     return str;
136 }
137 
ToUpper(const std::string & str)138 std::string VCardUtils::ToUpper(const std::string &str)
139 {
140     std::string temp = str;
141     for (char &c : temp) {
142         c = std::toupper(c);
143     }
144     return temp;
145 }
146 
StartWith(const std::string & str,const std::string & prefix)147 bool VCardUtils::StartWith(const std::string &str, const std::string &prefix)
148 {
149     if (str.length() < prefix.length()) {
150         return false;
151     }
152     return str.substr(0, prefix.length()) == prefix;
153 }
154 
EndWith(const std::string & fullString,const std::string & ending)155 bool VCardUtils::EndWith(const std::string &fullString, const std::string &ending)
156 {
157     if (fullString.length() < ending.length()) {
158         return false;
159     }
160 
161     std::string extractedEnding = fullString.substr(fullString.length() - ending.length());
162 
163     return extractedEnding == ending;
164 }
165 
ConvertCharset(const std::string & input,const std::string & fromCharset,const std::string & toCharset,int32_t & errorCode)166 std::string VCardUtils::ConvertCharset(
167     const std::string &input, const std::string &fromCharset, const std::string &toCharset, int32_t &errorCode)
168 {
169     iconv_t converter = iconv_open(toCharset.c_str(), fromCharset.c_str());
170     if (converter == (iconv_t)(-1)) {
171         TELEPHONY_LOGE("ConvertCharset_old open fail");
172         errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID;
173         return "";
174     }
175 
176     size_t inBytes = input.size();
177     size_t outBytes = inBytes * 4; // Allocate enough space for the worst-case scenario
178     char *inBuf = const_cast<char *>(input.c_str());
179     char *outBuf = new char[outBytes];
180     char *outBufPtr = outBuf;
181     if (iconv(converter, &inBuf, &inBytes, &outBufPtr, &outBytes) == (size_t)(-1)) {
182         TELEPHONY_LOGE("ConvertCharset open fail");
183         errorCode = TELEPHONY_ERR_VCARD_FILE_INVALID;
184         delete[] outBuf;
185         iconv_close(converter);
186         return "";
187     }
188     std::string output(outBuf, outBufPtr - outBuf);
189     delete[] outBuf;
190     iconv_close(converter);
191     return output;
192 }
193 
CreateFileName()194 std::string VCardUtils::CreateFileName()
195 {
196     std::time_t now = std::time(nullptr);
197     std::tm *timeinfo = std::localtime(&now);
198     std::ostringstream oss;
199     oss << std::put_time(timeinfo, VCARD_TIME_FORMAT);
200     std::string fileName = oss.str() + ".vcf";
201     return fileName;
202 }
203 
SaveFile(const std::string & fileStr,const std::string & path)204 void VCardUtils::SaveFile(const std::string &fileStr, const std::string &path)
205 {
206     std::ofstream file(path, std::ios::trunc);
207     if (file.is_open()) {
208         std::stringstream ss(fileStr);
209         std::string line;
210 
211         while (std::getline(ss, line)) {
212             file << line << std::endl;
213         }
214         file.close();
215     }
216 }
217 
IsWrapPrintableAscii(std::vector<std::string> strs)218 bool VCardUtils::IsWrapPrintableAscii(std::vector<std::string> strs)
219 {
220     for (auto str : strs) {
221         for (char ch : str) {
222             if (!(IsPrintableAscii(ch) || ch == '\r' || ch == '\n')) {
223                 return false;
224             }
225         }
226     }
227     return true;
228 }
229 
IsPrintableAscii(std::vector<std::string> strs)230 bool VCardUtils::IsPrintableAscii(std::vector<std::string> strs)
231 {
232     for (auto it : strs) {
233         if (!IsPrintableAscii(it)) {
234             return false;
235         }
236     }
237     return true;
238 }
239 
IsPrintableAscii(const std::string & str)240 bool VCardUtils::IsPrintableAscii(const std::string &str)
241 {
242     for (char ch : str) {
243         if (!IsPrintableAscii(ch)) {
244             return false;
245         }
246     }
247     return true;
248 }
249 
IsPrintableAscii(char ch)250 bool VCardUtils::IsPrintableAscii(char ch)
251 {
252     return std::isprint(static_cast<unsigned char>(ch));
253 }
254 
IsNum(const std::string & str)255 bool VCardUtils::IsNum(const std::string &str)
256 {
257     if (str.empty()) {
258         return false;
259     }
260     for (char ch : str) {
261         if (!std::isdigit(ch)) {
262             return false;
263         }
264     }
265     return true;
266 }
267 
GetTypeFromImLabelId(std::string labelId)268 std::string VCardUtils::GetTypeFromImLabelId(std::string labelId)
269 {
270     if (!IsNum(labelId)) {
271         return "";
272     }
273     int32_t num = std::stoi(labelId);
274     auto it = imLabelIdToType.find(static_cast<ImType>(num));
275     if (it != imLabelIdToType.end()) {
276         return it->second;
277     }
278     return "";
279 }
280 
GetLabelIdFromImType(std::string type)281 int32_t VCardUtils::GetLabelIdFromImType(std::string type)
282 {
283     if (type.empty()) {
284         return static_cast<int32_t>(ImType::INVALID_LABEL_ID);
285     }
286     if (type == VCARD_TYPE_X_AIM) {
287         return static_cast<int32_t>(ImType::IM_AIM);
288     } else if (type == VCARD_TYPE_X_MSN) {
289         return static_cast<int32_t>(ImType::IM_MSN);
290     } else if (type == VCARD_TYPE_X_YAHOO) {
291         return static_cast<int32_t>(ImType::IM_YAHOO);
292     } else if (type == VCARD_TYPE_X_ICQ) {
293         return static_cast<int32_t>(ImType::IM_ICQ);
294     } else if (type == VCARD_TYPE_X_JABBER) {
295         return static_cast<int32_t>(ImType::IM_JABBER);
296     } else if (type == VCARD_TYPE_X_QQ) {
297         return static_cast<int32_t>(ImType::IM_QQ);
298     } else if (type == VCARD_TYPE_X_SKYPE_USERNAME) {
299         return static_cast<int32_t>(ImType::IM_SKYPE);
300     } else if (type == VCARD_TYPE_X_HUANLIAO) {
301         return static_cast<int32_t>(ImType::IM_HUANLIAO);
302     } else {
303         return static_cast<int32_t>(ImType::CUSTOM_LABEL);
304     }
305 }
306 
GetTypeFromPhoneLabelId(std::string labelId)307 std::vector<std::string> VCardUtils::GetTypeFromPhoneLabelId(std::string labelId)
308 {
309     std::vector<std::string> paramTypes = {};
310     if (!IsNum(labelId) || labelId.size() > INT_64_LENTGH) {
311         return paramTypes;
312     }
313     int64_t num = std::stoll(labelId);
314     auto phoneType = static_cast<PhoneVcType>(num);
315     auto it = phoneLabelIdToType.find(phoneType);
316     if (it != phoneLabelIdToType.end()) {
317         paramTypes.push_back(it->second);
318         return paramTypes;
319     }
320     switch (phoneType) {
321         case PhoneVcType::NUM_FAX_HOME: {
322             paramTypes.push_back(VCARD_PARAM_TYPE_HOME);
323             paramTypes.push_back(VCARD_PARAM_TYPE_FAX);
324             return paramTypes;
325         }
326         case PhoneVcType::NUM_FAX_WORK: {
327             paramTypes.push_back(VCARD_PARAM_TYPE_WORK);
328             paramTypes.push_back(VCARD_PARAM_TYPE_FAX);
329             return paramTypes;
330         }
331         case PhoneVcType::NUM_WORK_MOBILE: {
332             paramTypes.push_back(VCARD_PARAM_TYPE_WORK);
333             paramTypes.push_back(VCARD_PARAM_TYPE_CELL);
334             return paramTypes;
335         }
336         case PhoneVcType::NUM_WORK_PAGER: {
337             paramTypes.push_back(VCARD_PARAM_TYPE_WORK);
338             paramTypes.push_back(VCARD_PARAM_TYPE_PAGER);
339             return paramTypes;
340         }
341         default:
342             break;
343     }
344     return paramTypes;
345 }
346 
TrimListToString(const std::vector<std::string> & strs)347 std::string VCardUtils::TrimListToString(const std::vector<std::string> &strs)
348 {
349     int32_t size = static_cast<int32_t>(strs.size());
350     std::string result;
351     if (size > 1) {
352         std::string init = "";
353         result = std::accumulate(strs.begin(), strs.end(), init,
354             [](std::string &str, const std::string &element) { return str + element + ";"; });
355     } else if (size == 1) {
356         return strs[0];
357     } else {
358         return "";
359     }
360     return result;
361 }
362 
HandleCh(char nextCh,std::string vcardType)363 std::string VCardUtils::HandleCh(char nextCh, std::string vcardType)
364 {
365     std::string unescapedString = "";
366     if (vcardType == VERSION_40) {
367         if (nextCh == 'n' || nextCh == 'N') {
368             unescapedString = "\n";
369         } else {
370             unescapedString = nextCh;
371         }
372     } else if (vcardType == VERSION_30) {
373         if (nextCh == 'n' || nextCh == 'N') {
374             unescapedString = "\n";
375         } else {
376             unescapedString = nextCh;
377         }
378     } else {
379         if (nextCh == '\\' || nextCh == ';' || nextCh == ':' || nextCh == ',') {
380             unescapedString = nextCh;
381         } else {
382             unescapedString = "";
383         }
384     }
385     return unescapedString;
386 }
387 
ConstructListFromValue(const std::string & value,std::string vcardType)388 std::vector<std::string> VCardUtils::ConstructListFromValue(const std::string &value, std::string vcardType)
389 {
390     std::vector<std::string> result;
391     std::string builder;
392     int32_t length = static_cast<int32_t>(value.length());
393     for (int32_t i = 0; i < length; i++) {
394         char ch = value[i];
395         if (ch == '\\' && i < length - 1) {
396             char nextCh = value[i + 1];
397             std::string unescapedString = HandleCh(nextCh, vcardType);
398             if (!unescapedString.empty()) {
399                 builder += unescapedString;
400                 i++;
401             } else {
402                 builder += ch;
403             }
404         } else if (ch == ';') {
405             result.push_back(builder);
406         } else {
407             builder += ch;
408         }
409     }
410     result.push_back(builder);
411     return result;
412 }
413 
HandleTypeAndLabel(int32_t & type,std::string & label,std::string number,std::string labelCandidate)414 void VCardUtils::HandleTypeAndLabel(int32_t &type, std::string &label, std::string number, std::string labelCandidate)
415 {
416     std::map<std::string, PhoneVcType>::iterator iter = typeToPhoneTypeMap.find(labelCandidate);
417     if (iter != typeToPhoneTypeMap.end()) {
418         PhoneVcType phoneType = iter->second;
419         int32_t typeCandidate = static_cast<int32_t>(phoneType);
420 
421         std::size_t indexOfAt = -1;
422         std::size_t found = number.find("@");
423         if (found != std::string::npos) {
424             indexOfAt = found;
425         }
426 
427         if ((typeCandidate == static_cast<int32_t>(PhoneVcType::NUM_PAGER) && 0 < indexOfAt &&
428                 indexOfAt < number.length() - 1) ||
429             type < 0 || type == static_cast<int32_t>(PhoneVcType::CUSTOM_LABEL) ||
430             type == static_cast<int32_t>(PhoneVcType::NUM_OTHER)) {
431             type = typeCandidate;
432         }
433     } else if (type < 0) {
434         type = static_cast<int32_t>(PhoneVcType::CUSTOM_LABEL);
435         label = labelCandidate;
436     }
437 }
438 
GetPhoneTypeFromStrings(const std::vector<std::string> & types,std::string number,std::tuple<int32_t,std::string> & result)439 void VCardUtils::GetPhoneTypeFromStrings(
440     const std::vector<std::string> &types, std::string number, std::tuple<int32_t, std::string> &result)
441 {
442     int32_t type = -1;
443     std::string label;
444     bool isFax = false;
445     bool hasPref = false;
446 
447     for (std::string typeStringOrg : types) {
448         std::string typeStringUpperCase = ToUpper(typeStringOrg);
449         if (typeStringUpperCase == VCARD_PARAM_TYPE_PREF) {
450             hasPref = true;
451         } else if (typeStringUpperCase == VCARD_PARAM_TYPE_FAX) {
452             isFax = true;
453         } else {
454             std::string labelCandidate;
455             if (StartWith(typeStringUpperCase, "X-") && type < 0) {
456                 labelCandidate = typeStringOrg.substr(VALUE_INDEX_TWO);
457             } else {
458                 labelCandidate = typeStringOrg;
459                 label = labelCandidate;
460             }
461             if (labelCandidate.length() == 0) {
462                 continue;
463             }
464             HandleTypeAndLabel(type, label, number, labelCandidate);
465         }
466     }
467 
468     if (type < 0) {
469         if (hasPref) {
470             type = static_cast<int32_t>(PhoneVcType::NUM_MAIN);
471         } else {
472             type = static_cast<int32_t>(PhoneVcType::NUM_HOME);
473         }
474     }
475 
476     if (isFax) {
477         if (type == static_cast<int32_t>(PhoneVcType::NUM_MOBILE)) {
478             type = static_cast<int32_t>(PhoneVcType::NUM_FAX_HOME);
479         } else if (type == static_cast<int32_t>(PhoneVcType::NUM_WORK)) {
480             type = static_cast<int32_t>(PhoneVcType::NUM_FAX_WORK);
481         } else if (type == static_cast<int32_t>(PhoneVcType::NUM_OTHER)) {
482             type = static_cast<int32_t>(PhoneVcType::NUM_OTHER_FAX);
483         }
484     }
485 
486     if (type == static_cast<int32_t>(PhoneVcType::CUSTOM_LABEL)) {
487         std::get<0>(result) = -1;
488         std::get<1>(result) = label;
489     } else {
490         std::get<0>(result) = type;
491         std::get<1>(result) = "-1";
492     }
493 }
494 
VcardtypeToInt(const std::string & vcardType)495 int32_t VCardUtils::VcardtypeToInt(const std::string &vcardType)
496 {
497     if (vcardType == VERSION_21) {
498         return VERSION_21_NUM;
499     } else if (vcardType == VERSION_30) {
500         return VERSION_30_NUM;
501     } else if (vcardType == VERSION_40) {
502         return VERSION_40_NUM;
503     }
504     return -1;
505 }
506 
FormatNumber(std::string source)507 std::string VCardUtils::FormatNumber(std::string source)
508 {
509     return source;
510 }
511 
GetPhoneNumberFormat(const int32_t vcardType)512 int32_t VCardUtils::GetPhoneNumberFormat(const int32_t vcardType)
513 {
514     if (VCardConfiguration::IsJapaneseDevice(vcardType)) {
515         return VCARD_PHONE_NUM_FORMAT_JAPAN;
516     } else {
517         return VCARD_PHONE_NUM_FORMAT_NANP;
518     }
519 }
520 
GetImageType(std::string bytes)521 std::string VCardUtils::GetImageType(std::string bytes)
522 {
523     if (bytes.empty()) {
524         return "";
525     }
526     int32_t length = static_cast<int32_t>(bytes.length());
527     int32_t gifTypeLength = VALUE_LEN_THREE;
528     if (length >= gifTypeLength && bytes[VALUE_INDEX_ZERO] == 'G' && bytes[1] == 'I' && bytes[VALUE_INDEX_TWO] == 'F') {
529         return "GIF";
530     }
531     int32_t pngTypeLength = VALUE_LEN_FOUR;
532     if (length >= pngTypeLength && bytes[VALUE_INDEX_ZERO] == static_cast<char>(0x89) &&
533         bytes[VALUE_INDEX_ONE] == 'P' && bytes[VALUE_INDEX_TWO] == 'N' && bytes[VALUE_INDEX_THREE] == 'G') {
534         return "PNG";
535     }
536     int32_t jpgTypeLength = VALUE_LEN_TWO;
537     if (length >= jpgTypeLength && bytes[VALUE_INDEX_ZERO] == static_cast<char>(0xff) &&
538         bytes[VALUE_INDEX_ONE] == static_cast<char>(0xd8)) {
539         return "JPEG";
540     }
541     return "";
542 }
543 
IsAllEmpty(std::vector<std::string> values)544 bool VCardUtils::IsAllEmpty(std::vector<std::string> values)
545 {
546     for (auto value : values) {
547         if (!value.empty()) {
548             return false;
549         }
550     }
551     return true;
552 }
553 
554 } // namespace Telephony
555 } // namespace OHOS
556