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