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