1 /*
2 * Copyright (C) 2021 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 #include "mms_body_part.h"
16
17 #include <ctime>
18
19 #include "securec.h"
20 #include "utils/mms_base64.h"
21 #include "utils/mms_quoted_printable.h"
22 #include "telephony_log_wrapper.h"
23
24 namespace OHOS {
25 namespace Telephony {
26 static constexpr uint32_t MAX_MMS_MSG_PART_LEN = 300 * 1024;
27 const std::string ENCODE_BINARY = "binary";
28 const std::string ENCODE_BASE64 = "base64";
29 const std::string ENCODE_QUOTED_PRINTABLE = "quoted-printable";
30 using namespace std;
31 static constexpr const char *APP_SAND_ABSOLUTE_DIR = "/data/app";
32 static constexpr const char *APP_SAND_RELATIVE_DIR = "/data/storage";
33
MmsBodyPart()34 MmsBodyPart::MmsBodyPart() : headerLen_(0), bodyLen_(0) {}
35
MmsBodyPart(const MmsBodyPart & srcBodyPart)36 MmsBodyPart::MmsBodyPart(const MmsBodyPart &srcBodyPart) : headerLen_(0), bodyLen_(0)
37 {
38 *this = srcBodyPart;
39 }
40
~MmsBodyPart()41 MmsBodyPart::~MmsBodyPart()
42 {
43 if (pbodyPartBuffer_ != nullptr) {
44 pbodyPartBuffer_.reset();
45 }
46 }
47
DumpMmsBodyPart()48 void MmsBodyPart::DumpMmsBodyPart()
49 {
50 TELEPHONY_LOGI("============== Start BodyPart Info ==========");
51 std::string isSmil = isSmilFile_ ? "ture" : "false";
52 TELEPHONY_LOGI("isSmilFile : %{public}s", isSmil.c_str());
53 TELEPHONY_LOGI("strFileName : %{public}s", strFileName_.c_str());
54 TELEPHONY_LOGI("headerLen : %{public}u", headerLen_);
55 TELEPHONY_LOGI("bodyPartLen : %{public}u", bodyLen_);
56 bodyPartContentType_.DumpMmsContentType();
57 mmsBodyPartHeader_.DumpBodyPartHeader();
58 TELEPHONY_LOGI("============== End BodyPart Info ==========");
59 }
60
operator =(const MmsBodyPart & srcBodyPart)61 MmsBodyPart &MmsBodyPart::operator=(const MmsBodyPart &srcBodyPart)
62 {
63 if (this == &srcBodyPart) {
64 return *this;
65 }
66
67 if (srcBodyPart.bodyLen_ > MAX_MMS_MSG_PART_LEN) {
68 TELEPHONY_LOGE("srcBodyPart.bodyLen_ over size error");
69 return *this;
70 }
71 bodyLen_ = srcBodyPart.bodyLen_;
72 pbodyPartBuffer_ = std::make_unique<char[]>(bodyLen_);
73 if (pbodyPartBuffer_ == nullptr || srcBodyPart.pbodyPartBuffer_ == nullptr) {
74 bodyLen_ = 0;
75 AssignBodyPart(srcBodyPart);
76 TELEPHONY_LOGE("Assignment Buffer Nullptr Error.");
77 return *this;
78 }
79
80 if (memcpy_s(pbodyPartBuffer_.get(), bodyLen_, srcBodyPart.pbodyPartBuffer_.get(), bodyLen_) != EOK) {
81 bodyLen_ = 0;
82 TELEPHONY_LOGE("Copy BodyPart Buffer Memory Error.");
83 }
84 AssignBodyPart(srcBodyPart);
85 return *this;
86 }
87
AssignBodyPart(const MmsBodyPart & obj)88 void MmsBodyPart::AssignBodyPart(const MmsBodyPart &obj)
89 {
90 headerLen_ = obj.headerLen_;
91 mmsBodyPartHeader_ = obj.mmsBodyPartHeader_;
92 strFileName_ = obj.strFileName_;
93 bodyPartContentType_ = obj.bodyPartContentType_;
94 }
95
96 /**
97 * @brief DecodePart
98 * wap-230-wsp-20010705-a section:8.5.3 Multipart Entry
99 * HeadersLen Uintvar
100 * DataLen Uintvar
101 * ContentType Multiple octets
102 * Headers (HeadersLen – length of ContentType) octets
103 * Data DataLen octets
104 * @param decodeBuffer
105 * @return true
106 * @return false
107 */
DecodePart(MmsDecodeBuffer & decodeBuffer)108 bool MmsBodyPart::DecodePart(MmsDecodeBuffer &decodeBuffer)
109 {
110 uint32_t headerLength = 0;
111 uint32_t bodyLength = 0;
112 uint32_t length = 0;
113 if (!decodeBuffer.DecodeUintvar(headerLength, length)) {
114 TELEPHONY_LOGE("Decode Body Part Header Uintvar Error.");
115 return false;
116 }
117 if (!decodeBuffer.DecodeUintvar(bodyLength, length)) {
118 TELEPHONY_LOGE("Decode Body Part Body Lenght Uintvar Error.");
119 return false;
120 }
121 int32_t contentLength = 0;
122 if (!bodyPartContentType_.DecodeMmsContentType(decodeBuffer, contentLength)) {
123 TELEPHONY_LOGE("Decode Body Part ContentType Error.");
124 return false;
125 }
126
127 headerLen_ = headerLength;
128 bodyLen_ = bodyLength;
129 if (headerLen_ < static_cast<uint32_t>(contentLength)) {
130 TELEPHONY_LOGE("Decode Body Part HeaderLen Less Than ContentLength Error.");
131 return false;
132 }
133 if (!DecodePartHeader(decodeBuffer, headerLen_ - static_cast<uint32_t>(contentLength))) {
134 TELEPHONY_LOGE("Decode Body Part Header Error.");
135 return false;
136 }
137 if (!DecodePartBody(decodeBuffer, bodyLen_)) {
138 TELEPHONY_LOGE("Decode Body Part Body Error.");
139 return false;
140 }
141 DecodeSetFileName();
142 return true;
143 }
144
145 /**
146 * @brief DecodePartHeader
147 * wap-230-wsp-20010705-a section:8.4.2.6 Header
148 * Message-header = Well-known-header | Application-header
149 * Application-header = Token-text Application-specific-value
150 * Well-known-field-name = Short-integer
151 * Application-specific-value = Text-string
152 * @param decodeBuffer
153 * @param headerLen
154 * @return true
155 * @return false
156 */
DecodePartHeader(MmsDecodeBuffer & decodeBuffer,uint32_t headerLen)157 bool MmsBodyPart::DecodePartHeader(MmsDecodeBuffer &decodeBuffer, uint32_t headerLen)
158 {
159 const uint8_t headerAccept = 0x80;
160 const uint8_t headerCacheControl = 0xC7;
161 const uint8_t textMin = 32;
162 const uint8_t textMax = 127;
163
164 uint8_t oneByte = 0;
165 while (headerLen > 0) {
166 if (!decodeBuffer.PeekOneByte(oneByte)) {
167 TELEPHONY_LOGE("Decode Body Part PeekOneByte Error.");
168 return false;
169 }
170 if (headerAccept <= oneByte && headerCacheControl >= oneByte) {
171 if (!mmsBodyPartHeader_.DecodeWellKnownHeader(decodeBuffer, headerLen)) {
172 TELEPHONY_LOGE("Decode Body Part DecodeWellKnownHeader Error.");
173 return false;
174 }
175 } else if ((oneByte >= textMin) && (oneByte <= textMax)) {
176 if (!mmsBodyPartHeader_.DecodeApplicationHeader(decodeBuffer, headerLen)) {
177 TELEPHONY_LOGE("Decode Body Part DecodeApplicationHeader Error.");
178 return false;
179 }
180 } else {
181 TELEPHONY_LOGE("Header Field[%{pulbic}02X] is not support.", oneByte);
182 return false;
183 }
184 }
185 return true;
186 }
187
DecodePartBody(MmsDecodeBuffer & decodeBuffer,uint32_t bodyLength)188 bool MmsBodyPart::DecodePartBody(MmsDecodeBuffer &decodeBuffer, uint32_t bodyLength)
189 {
190 uint32_t offset = decodeBuffer.GetCurPosition();
191 if (offset + bodyLength > decodeBuffer.GetSize() || bodyLength > MAX_MMS_MSG_PART_LEN) {
192 TELEPHONY_LOGE("Decode Body Part buffer size err.");
193 return false;
194 }
195
196 std::unique_ptr<char[]> bodyPartBuffer = decodeBuffer.ReadDataBuffer(offset, bodyLength);
197 if (bodyPartBuffer == nullptr) {
198 TELEPHONY_LOGE("Decode Body Part buffer is null.");
199 return false;
200 }
201
202 std::string transferEncoding;
203 if (!mmsBodyPartHeader_.GetContentTransferEncoding(transferEncoding)) {
204 TELEPHONY_LOGE("bodyPartHeader GetContentTransferEncoding Error");
205 return false;
206 }
207
208 std::string encodebuffer = "";
209 std::string encodeString(bodyPartBuffer.get(), bodyLength);
210 if (transferEncoding == ENCODE_BASE64) {
211 encodebuffer = MmsBase64::Decode(encodeString);
212 } else if (transferEncoding == ENCODE_QUOTED_PRINTABLE) {
213 MmsQuotedPrintable::Decode(encodeString, encodebuffer);
214 }
215
216 if (encodebuffer.length()) {
217 bodyLen_ = 0;
218 uint32_t tempLen = encodebuffer.length();
219 if (tempLen > MAX_MMS_MSG_PART_LEN) {
220 TELEPHONY_LOGE("tempLen over size error");
221 return false;
222 }
223 pbodyPartBuffer_ = std::make_unique<char[]>(tempLen);
224 if (pbodyPartBuffer_ == nullptr) {
225 TELEPHONY_LOGE("pbodyPartBuffer_ nullptr Error");
226 return false;
227 }
228 if (memcpy_s(pbodyPartBuffer_.get(), tempLen, encodebuffer.data(), tempLen) != EOK) {
229 TELEPHONY_LOGE("Memcpy_s pbodyPartBuffer_ Error");
230 return false;
231 }
232 bodyLen_ = tempLen;
233 } else {
234 pbodyPartBuffer_ = std::move(bodyPartBuffer);
235 }
236 if (!decodeBuffer.IncreasePointer(bodyLength)) {
237 TELEPHONY_LOGE("Decode Body Part IncreasePointer err.");
238 return false;
239 }
240 return true;
241 }
242
SetAttachment(MmsAttachment & attachment)243 bool MmsBodyPart::SetAttachment(MmsAttachment &attachment)
244 {
245 std::string filePathName = attachment.GetAttachmentFilePath();
246 bool readFileRes = WriteBodyFromFile(filePathName);
247 if (readFileRes) {
248 std::string tempFileName = attachment.GetFileName();
249 if (tempFileName.empty()) {
250 std::size_t pos = filePathName.find_last_of('/');
251 if (pos != std::string::npos) {
252 tempFileName = filePathName.substr(pos + 1);
253 }
254 }
255 SetFileName(tempFileName);
256 }
257
258 /** If Read Attatemt Body Buffer From File Error Will Temp Read From Buffer **/
259 if (!readFileRes) {
260 if (!WriteBodyFromAttachmentBuffer(attachment)) {
261 TELEPHONY_LOGE("Attachment Not Any Body Data Error.");
262 return false;
263 }
264 SetFileName(attachment.GetFileName());
265 }
266
267 if (strFileName_.empty()) {
268 TELEPHONY_LOGE("Get Attachment FileName Invalid error!");
269 return false;
270 }
271 if (!SetContentType(attachment.GetContentType())) {
272 TELEPHONY_LOGE("Mms BodyPart SetContentType is fail!");
273 return false;
274 }
275 if (!SetContentId(attachment.GetContentId())) {
276 TELEPHONY_LOGE("Mms BodyPart GetContentId is fail!");
277 return false;
278 }
279 if (!SetContentLocation(attachment.GetContentLocation())) {
280 TELEPHONY_LOGE("Mms BodyPart SetContentLocation is fail!");
281 return false;
282 }
283 if (!mmsBodyPartHeader_.SetContentTransferEncoding(attachment.GetContentTransferEncoding())) {
284 TELEPHONY_LOGE("Mms BodyPartHeader SetContentTransferEncoding is fail!");
285 return false;
286 }
287 SetSmilFile(attachment.IsSmilFile());
288 SetContentDisposition(attachment.GetContentDisposition());
289 GetContentType().GetContentParam().SetFileName(strFileName_);
290 GetContentType().GetContentParam().SetCharSet(attachment.GetCharSet());
291 return true;
292 }
293
IsSmilFile()294 bool MmsBodyPart::IsSmilFile()
295 {
296 return isSmilFile_;
297 }
298
SetSmilFile(bool isSmil)299 void MmsBodyPart::SetSmilFile(bool isSmil)
300 {
301 isSmilFile_ = isSmil;
302 }
303
SetContentType(std::string strContentType)304 bool MmsBodyPart::SetContentType(std::string strContentType)
305 {
306 return bodyPartContentType_.SetContentType(strContentType);
307 }
308
GetContentType(std::string & strContentType)309 bool MmsBodyPart::GetContentType(std::string &strContentType)
310 {
311 return bodyPartContentType_.GetContentType(strContentType);
312 }
313
SetContentId(std::string contentId)314 bool MmsBodyPart::SetContentId(std::string contentId)
315 {
316 return mmsBodyPartHeader_.SetContentId(contentId);
317 }
318
GetContentId(std::string & contentId)319 bool MmsBodyPart::GetContentId(std::string &contentId)
320 {
321 return mmsBodyPartHeader_.GetContentId(contentId);
322 }
323
SetContentLocation(std::string contentLocation)324 bool MmsBodyPart::SetContentLocation(std::string contentLocation)
325 {
326 return mmsBodyPartHeader_.SetContentLocation(contentLocation);
327 }
328
GetContentLocation(std::string & contentLocation)329 bool MmsBodyPart::GetContentLocation(std::string &contentLocation)
330 {
331 return mmsBodyPartHeader_.GetContentLocation(contentLocation);
332 }
333
SetContentDisposition(std::string contentDisposition)334 bool MmsBodyPart::SetContentDisposition(std::string contentDisposition)
335 {
336 return mmsBodyPartHeader_.SetContentDisposition(contentDisposition);
337 }
338
GetContentDisposition(std::string & contentDisposition)339 bool MmsBodyPart::GetContentDisposition(std::string &contentDisposition)
340 {
341 return mmsBodyPartHeader_.GetContentDisposition(contentDisposition);
342 }
343
344 /**
345 * @brief EncodeMmsBodyPart
346 * wap-230-wsp-20010705-a section:8.5.3 Multipart Entry
347 * HeadersLen Uintvar
348 * DataLen Uintvar
349 * ContentType Multiple octets
350 * Headers (HeadersLen – length of ContentType) octets
351 * Data DataLen octets
352 * @param encodeBuffer
353 * @return true
354 * @return false
355 */
EncodeMmsBodyPart(MmsEncodeBuffer & encodeBuffer)356 bool MmsBodyPart::EncodeMmsBodyPart(MmsEncodeBuffer &encodeBuffer)
357 {
358 MmsEncodeBuffer tmpEncodeBuffer;
359 if (!bodyPartContentType_.EncodeMmsBodyPartContentType(tmpEncodeBuffer)) {
360 TELEPHONY_LOGE("Encode MmsBodyPart ContentType Error.");
361 return false;
362 }
363 if (!mmsBodyPartHeader_.EncodeMmsBodyPartHeader(tmpEncodeBuffer)) {
364 TELEPHONY_LOGE("Encode MmsBodyPart Header Error.");
365 return false;
366 }
367 if (!encodeBuffer.EncodeUintvar(tmpEncodeBuffer.GetCurPosition())) {
368 TELEPHONY_LOGE("Encode MmsBodyPart Body Uintvar Error.");
369 return false;
370 }
371 if (!encodeBuffer.EncodeUintvar(bodyLen_)) {
372 TELEPHONY_LOGE("Encode MmsBodyPart Body Len Uintvar Error.");
373 return false;
374 }
375 if (!encodeBuffer.WriteBuffer(tmpEncodeBuffer)) {
376 TELEPHONY_LOGE("Encode MmsBodyPart WriteBuffer Error.");
377 return false;
378 }
379 uint32_t bodyLen = 0;
380 std::unique_ptr<char[]> bodyBuff = ReadBodyPartBuffer(bodyLen);
381 if (bodyBuff == nullptr) {
382 TELEPHONY_LOGE("bodyBuff nullptr Error.");
383 return false;
384 }
385 if (!encodeBuffer.WriteBuffer(std::move(bodyBuff), bodyLen)) {
386 return false;
387 }
388 return true;
389 }
390
DecodeSetFileName()391 void MmsBodyPart::DecodeSetFileName()
392 {
393 std::string fileName = "";
394 GetContentType().GetContentParam().GetFileName(fileName);
395 if (fileName.length() > 0) {
396 strFileName_ = fileName;
397 return;
398 }
399 std::string contentLocation = "";
400 GetPartHeader().GetContentLocation(contentLocation);
401 if (contentLocation.length() > 0) {
402 strFileName_ = contentLocation;
403 return;
404 }
405 std::string contentId = "";
406 GetPartHeader().GetContentId(contentId);
407 if (contentId.length() > 0) {
408 strFileName_ = contentId;
409 return;
410 }
411
412 const unsigned char timeBufferLen = 64;
413 time_t currentTime = time(nullptr);
414 if (currentTime == -1) {
415 return;
416 }
417 char chCurrentTime[timeBufferLen] = {0};
418 struct tm tmInfo;
419 if (memset_s(&tmInfo, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
420 TELEPHONY_LOGE("DisplayTime memset fail.");
421 return;
422 }
423
424 tm *timeptr = localtime_r(¤tTime, &tmInfo);
425 if (currentTime == static_cast<time_t>(-1) || timeptr == nullptr) {
426 TELEPHONY_LOGI("obtain current time Error.");
427 }
428 if (timeptr != nullptr) {
429 (void)strftime(chCurrentTime, sizeof(chCurrentTime), "%Y%m%d%H%M%S", timeptr);
430 }
431 strFileName_ = chCurrentTime;
432 return;
433 }
434
WriteBodyFromFile(std::string path)435 bool MmsBodyPart::WriteBodyFromFile(std::string path)
436 {
437 FILE *pFile = nullptr;
438 char realPath[PATH_MAX] = { 0 };
439 if (path.empty() || realpath(path.c_str(), realPath) == NULL) {
440 TELEPHONY_LOGE("path or realPath is NULL");
441 return false;
442 }
443
444 std::string filePath = realPath;
445 std::string absDir = APP_SAND_ABSOLUTE_DIR;
446 std::string relDir = APP_SAND_RELATIVE_DIR;
447 if ((absDir.compare(filePath.substr(0, absDir.size())) != 0) &&
448 (relDir.compare(filePath.substr(0, relDir.size())) != 0)) {
449 TELEPHONY_LOGE("filePath no app sand box.");
450 return false;
451 }
452 pFile = fopen(realPath, "rb");
453 if (pFile == nullptr) {
454 TELEPHONY_LOGI("Write Body Part from File notFind, try to use buffer");
455 return false;
456 }
457 (void)fseek(pFile, 0, SEEK_END);
458 long fileLen = ftell(pFile);
459 if (fileLen <= 0 || fileLen > static_cast<long>(MAX_MMS_MSG_PART_LEN)) {
460 (void)fclose(pFile);
461 TELEPHONY_LOGE("fileLen is invalid [%{public}ld]", fileLen);
462 return false;
463 }
464 if (pbodyPartBuffer_) {
465 pbodyPartBuffer_.reset();
466 }
467 pbodyPartBuffer_ = std::make_unique<char[]>(fileLen);
468 if (!pbodyPartBuffer_) {
469 (void)fclose(pFile);
470 TELEPHONY_LOGE("Buffer initialize fail!");
471 return false;
472 }
473
474 (void)fseek(pFile, 0, SEEK_SET);
475 bodyLen_ = fread(pbodyPartBuffer_.get(), 1, fileLen, pFile);
476 (void)fclose(pFile);
477 return true;
478 }
479
WriteBodyFromAttachmentBuffer(MmsAttachment & attachment)480 bool MmsBodyPart::WriteBodyFromAttachmentBuffer(MmsAttachment &attachment)
481 {
482 if (attachment.GetFileName().empty()) {
483 TELEPHONY_LOGE("Attachment must set fileName, else error!");
484 return false;
485 }
486
487 uint32_t dataLen = 0;
488 std::unique_ptr<char[]> tempBuffer = nullptr;
489 tempBuffer = attachment.GetDataBuffer(dataLen);
490 if (tempBuffer == nullptr) {
491 TELEPHONY_LOGE("Read Attachment Data Buffer nullptr error.");
492 return false;
493 }
494
495 if (dataLen == 0 || dataLen > MAX_MMS_MSG_PART_LEN) {
496 TELEPHONY_LOGE("Attachment DataLen is invalid Error");
497 return false;
498 }
499
500 if (pbodyPartBuffer_) {
501 pbodyPartBuffer_.reset();
502 }
503 pbodyPartBuffer_ = std::make_unique<char[]>(dataLen);
504 if (!pbodyPartBuffer_) {
505 TELEPHONY_LOGE("Buffer initialize fail!");
506 return false;
507 }
508
509 if (memcpy_s(pbodyPartBuffer_.get(), dataLen, tempBuffer.get(), dataLen) != EOK) {
510 TELEPHONY_LOGE("Attachment Buffer MemCopy Error.");
511 bodyLen_ = 0;
512 return false;
513 }
514 bodyLen_ = dataLen;
515 return true;
516 }
517
GetPartFileName()518 std::string MmsBodyPart::GetPartFileName()
519 {
520 return strFileName_;
521 }
522
SetFileName(std::string fileName)523 void MmsBodyPart::SetFileName(std::string fileName)
524 {
525 strFileName_ = fileName;
526 }
527
GetContentType()528 MmsContentType &MmsBodyPart::GetContentType()
529 {
530 return bodyPartContentType_;
531 }
532
GetPartHeader()533 MmsBodyPartHeader &MmsBodyPart::GetPartHeader()
534 {
535 return mmsBodyPartHeader_;
536 }
537
ReadBodyPartBuffer(uint32_t & len)538 std::unique_ptr<char[]> MmsBodyPart::ReadBodyPartBuffer(uint32_t &len)
539 {
540 if (bodyLen_ > MAX_MMS_MSG_PART_LEN) {
541 TELEPHONY_LOGE("srcBodyPart.bodyLen_ over size error");
542 return nullptr;
543 }
544 std::unique_ptr<char[]> result = std::make_unique<char[]>(bodyLen_);
545 if (result == nullptr) {
546 TELEPHONY_LOGE("Read BodyPart Buffer MakeUnique Error.");
547 return nullptr;
548 }
549 if (memcpy_s(result.get(), bodyLen_, pbodyPartBuffer_.get(), bodyLen_) != EOK) {
550 TELEPHONY_LOGE("Read BodyPart Buffer Memcpy_s Error.");
551 return nullptr;
552 }
553 len = bodyLen_;
554 return result;
555 }
556 } // namespace Telephony
557 } // namespace OHOS
558