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