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