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,uint32_t nEntries)106 bool MmsBodyPart::DecodePart(MmsDecodeBuffer &decodeBuffer, uint32_t nEntries)
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 TELEPHONY_LOGE("header length: %{public}d", headerLength);
116 if (!decodeBuffer.DecodeUintvar(bodyLength, length)) {
117 TELEPHONY_LOGE("Decode Body Part Body Lenght Uintvar Error.");
118 return false;
119 }
120 TELEPHONY_LOGE("body length: %{public}d", bodyLength);
121 int32_t contentLength = 0;
122 if (!bodyPartContentType_.DecodeMmsContentType(decodeBuffer, contentLength)) {
123 TELEPHONY_LOGE("Decode Body Part ContentType Error.");
124 return false;
125 }
126 TELEPHONY_LOGE("content length: %{public}d", contentLength);
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(nEntries);
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 TELEPHONY_LOGE("part header onebyte:%{public}u", oneByte);
171 if (headerAccept <= oneByte && headerCacheControl >= oneByte) {
172 if (!mmsBodyPartHeader_.DecodeWellKnownHeader(decodeBuffer, headerLen)) {
173 TELEPHONY_LOGE("Decode Body Part DecodeWellKnownHeader Error.");
174 return false;
175 }
176 } else if ((oneByte >= textMin) && (oneByte <= textMax)) {
177 if (!mmsBodyPartHeader_.DecodeApplicationHeader(decodeBuffer, headerLen)) {
178 TELEPHONY_LOGE("Decode Body Part DecodeApplicationHeader Error.");
179 return false;
180 }
181 } else {
182 TELEPHONY_LOGE("Header Field[%{public}02X] is not support.", oneByte);
183 return false;
184 }
185 }
186 return true;
187 }
188
DecodePartBody(MmsDecodeBuffer & decodeBuffer,uint32_t bodyLength)189 bool MmsBodyPart::DecodePartBody(MmsDecodeBuffer &decodeBuffer, uint32_t bodyLength)
190 {
191 uint32_t offset = decodeBuffer.GetCurPosition();
192 if (offset + bodyLength > decodeBuffer.GetSize() || bodyLength > MMS_PDU_MAX_SIZE) {
193 TELEPHONY_LOGE("Decode Body Part buffer size err.");
194 return false;
195 }
196
197 std::unique_ptr<char[]> bodyPartBuffer = decodeBuffer.ReadDataBuffer(offset, bodyLength);
198 if (bodyPartBuffer == nullptr) {
199 TELEPHONY_LOGE("Decode Body Part buffer is null.");
200 return false;
201 }
202
203 std::string transferEncoding;
204 if (!mmsBodyPartHeader_.GetContentTransferEncoding(transferEncoding)) {
205 TELEPHONY_LOGE("bodyPartHeader GetContentTransferEncoding Error");
206 return false;
207 }
208
209 std::string encodebuffer = "";
210 std::string encodeString(bodyPartBuffer.get(), bodyLength);
211 if (transferEncoding == ENCODE_BASE64) {
212 encodebuffer = MmsBase64::Decode(encodeString);
213 } else if (transferEncoding == ENCODE_QUOTED_PRINTABLE) {
214 MmsQuotedPrintable::Decode(encodeString, encodebuffer);
215 }
216
217 if (encodebuffer.length()) {
218 bodyLen_ = 0;
219 uint32_t tempLen = encodebuffer.length();
220 if (tempLen > MMS_PDU_MAX_SIZE) {
221 TELEPHONY_LOGE("tempLen over size error");
222 return false;
223 }
224 pbodyPartBuffer_ = std::make_unique<char[]>(tempLen);
225 if (pbodyPartBuffer_ == nullptr) {
226 TELEPHONY_LOGE("pbodyPartBuffer_ nullptr Error");
227 return false;
228 }
229 if (memcpy_s(pbodyPartBuffer_.get(), tempLen, encodebuffer.data(), tempLen) != EOK) {
230 TELEPHONY_LOGE("Memcpy_s pbodyPartBuffer_ Error");
231 return false;
232 }
233 bodyLen_ = tempLen;
234 } else {
235 pbodyPartBuffer_ = std::move(bodyPartBuffer);
236 }
237 if (!decodeBuffer.IncreasePointer(bodyLength)) {
238 TELEPHONY_LOGE("Decode Body Part IncreasePointer err.");
239 return false;
240 }
241 return true;
242 }
243
SetAttachment(MmsAttachment & attachment)244 bool MmsBodyPart::SetAttachment(MmsAttachment &attachment)
245 {
246 std::string filePathName = attachment.GetAttachmentFilePath();
247 bool readFileRes = WriteBodyFromFile(filePathName);
248 if (readFileRes) {
249 std::string tempFileName = attachment.GetFileName();
250 if (tempFileName.empty()) {
251 std::size_t pos = filePathName.find_last_of('/');
252 if (pos != std::string::npos) {
253 tempFileName = filePathName.substr(pos + 1);
254 }
255 }
256 SetFileName(tempFileName);
257 }
258
259 /** If Read Attatemt Body Buffer From File Error Will Temp Read From Buffer **/
260 if (!readFileRes) {
261 if (!WriteBodyFromAttachmentBuffer(attachment)) {
262 TELEPHONY_LOGE("Attachment Not Any Body Data Error.");
263 return false;
264 }
265 SetFileName(attachment.GetFileName());
266 }
267
268 if (strFileName_.empty()) {
269 TELEPHONY_LOGE("Get Attachment FileName Invalid error!");
270 return false;
271 }
272 if (!SetContentType(attachment.GetContentType())) {
273 TELEPHONY_LOGE("Mms BodyPart SetContentType is fail!");
274 return false;
275 }
276 if (!SetContentId(attachment.GetContentId())) {
277 TELEPHONY_LOGE("Mms BodyPart GetContentId is fail!");
278 return false;
279 }
280 if (!SetContentLocation(attachment.GetContentLocation())) {
281 TELEPHONY_LOGE("Mms BodyPart SetContentLocation is fail!");
282 return false;
283 }
284 if (!mmsBodyPartHeader_.SetContentTransferEncoding(attachment.GetContentTransferEncoding())) {
285 TELEPHONY_LOGE("Mms BodyPartHeader SetContentTransferEncoding is fail!");
286 return false;
287 }
288 SetSmilFile(attachment.IsSmilFile());
289 SetContentDisposition(attachment.GetContentDisposition());
290 GetContentType().GetContentParam().SetFileName(strFileName_);
291 GetContentType().GetContentParam().SetCharSet(attachment.GetCharSet());
292 return true;
293 }
294
IsSmilFile()295 bool MmsBodyPart::IsSmilFile()
296 {
297 return isSmilFile_;
298 }
299
SetSmilFile(bool isSmil)300 void MmsBodyPart::SetSmilFile(bool isSmil)
301 {
302 isSmilFile_ = isSmil;
303 }
304
SetContentType(std::string strContentType)305 bool MmsBodyPart::SetContentType(std::string strContentType)
306 {
307 return bodyPartContentType_.SetContentType(strContentType);
308 }
309
GetContentType(std::string & strContentType)310 bool MmsBodyPart::GetContentType(std::string &strContentType)
311 {
312 return bodyPartContentType_.GetContentType(strContentType);
313 }
314
SetContentId(std::string contentId)315 bool MmsBodyPart::SetContentId(std::string contentId)
316 {
317 return mmsBodyPartHeader_.SetContentId(contentId);
318 }
319
GetContentId(std::string & contentId)320 bool MmsBodyPart::GetContentId(std::string &contentId)
321 {
322 return mmsBodyPartHeader_.GetContentId(contentId);
323 }
324
SetContentLocation(std::string contentLocation)325 bool MmsBodyPart::SetContentLocation(std::string contentLocation)
326 {
327 return mmsBodyPartHeader_.SetContentLocation(contentLocation);
328 }
329
GetContentLocation(std::string & contentLocation)330 bool MmsBodyPart::GetContentLocation(std::string &contentLocation)
331 {
332 return mmsBodyPartHeader_.GetContentLocation(contentLocation);
333 }
334
SetContentDisposition(std::string contentDisposition)335 bool MmsBodyPart::SetContentDisposition(std::string contentDisposition)
336 {
337 return mmsBodyPartHeader_.SetContentDisposition(contentDisposition);
338 }
339
GetContentDisposition(std::string & contentDisposition)340 bool MmsBodyPart::GetContentDisposition(std::string &contentDisposition)
341 {
342 return mmsBodyPartHeader_.GetContentDisposition(contentDisposition);
343 }
344
345 /**
346 * @brief EncodeMmsBodyPart
347 * wap-230-wsp-20010705-a section:8.5.3 Multipart Entry
348 * HeadersLen Uintvar
349 * DataLen Uintvar
350 * ContentType Multiple octets
351 * Headers (HeadersLen – length of ContentType) octets
352 * Data DataLen octets
353 * @param encodeBuffer
354 * @return true
355 * @return false
356 */
EncodeMmsBodyPart(MmsEncodeBuffer & encodeBuffer)357 bool MmsBodyPart::EncodeMmsBodyPart(MmsEncodeBuffer &encodeBuffer)
358 {
359 MmsEncodeBuffer tmpEncodeBuffer;
360 if (!bodyPartContentType_.EncodeMmsBodyPartContentType(tmpEncodeBuffer)) {
361 TELEPHONY_LOGE("Encode MmsBodyPart ContentType Error.");
362 return false;
363 }
364 if (!mmsBodyPartHeader_.EncodeMmsBodyPartHeader(tmpEncodeBuffer)) {
365 TELEPHONY_LOGE("Encode MmsBodyPart Header Error.");
366 return false;
367 }
368 if (!encodeBuffer.EncodeUintvar(tmpEncodeBuffer.GetCurPosition())) {
369 TELEPHONY_LOGE("Encode MmsBodyPart Body Uintvar Error.");
370 return false;
371 }
372 if (!encodeBuffer.EncodeUintvar(bodyLen_)) {
373 TELEPHONY_LOGE("Encode MmsBodyPart Body Len Uintvar Error.");
374 return false;
375 }
376 if (!encodeBuffer.WriteBuffer(tmpEncodeBuffer)) {
377 TELEPHONY_LOGE("Encode MmsBodyPart WriteBuffer Error.");
378 return false;
379 }
380 uint32_t bodyLen = 0;
381 std::unique_ptr<char[]> bodyBuff = ReadBodyPartBuffer(bodyLen);
382 if (bodyBuff == nullptr) {
383 TELEPHONY_LOGE("bodyBuff nullptr Error.");
384 return false;
385 }
386 if (!encodeBuffer.WriteBuffer(std::move(bodyBuff), bodyLen)) {
387 return false;
388 }
389 return true;
390 }
391
DecodeSetFileName(uint32_t nEntries)392 void MmsBodyPart::DecodeSetFileName(uint32_t nEntries)
393 {
394 std::string fileName = "";
395 GetContentType().GetContentParam().GetFileName(fileName);
396 if (fileName.length() > 0) {
397 strFileName_ = fileName;
398 return;
399 }
400 std::string contentLocation = "";
401 GetPartHeader().GetContentLocation(contentLocation);
402 if (contentLocation.length() > 0) {
403 strFileName_ = contentLocation;
404 return;
405 }
406 std::string contentId = "";
407 GetPartHeader().GetContentId(contentId);
408 if (contentId.length() > 0) {
409 strFileName_ = contentId;
410 return;
411 }
412
413 const unsigned char timeBufferLen = 64;
414 time_t currentTime = time(nullptr);
415 if (currentTime == -1) {
416 return;
417 }
418 char chCurrentTime[timeBufferLen] = {0};
419 struct tm tmInfo;
420 if (memset_s(&tmInfo, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
421 TELEPHONY_LOGE("DisplayTime memset fail.");
422 return;
423 }
424
425 tm *timeptr = localtime_r(¤tTime, &tmInfo);
426 if (currentTime == static_cast<time_t>(-1) || timeptr == nullptr) {
427 TELEPHONY_LOGI("obtain current time Error.");
428 }
429 if (timeptr != nullptr) {
430 (void)strftime(chCurrentTime, sizeof(chCurrentTime), "%Y%m%d%H%M%S", timeptr);
431 }
432 std::string finalFileName(chCurrentTime);
433 finalFileName += '_';
434 finalFileName += '0' + nEntries;
435 strFileName_ = finalFileName;
436 return;
437 }
438
WriteBodyFromFile(std::string path)439 bool MmsBodyPart::WriteBodyFromFile(std::string path)
440 {
441 FILE *pFile = nullptr;
442 char realPath[PATH_MAX] = { 0 };
443 if (path.empty() || realpath(path.c_str(), realPath) == NULL) {
444 TELEPHONY_LOGE("path or realPath is NULL");
445 return false;
446 }
447
448 std::string filePath = realPath;
449 std::string absDir = APP_SAND_ABSOLUTE_DIR;
450 std::string relDir = APP_SAND_RELATIVE_DIR;
451 if ((absDir.compare(filePath.substr(0, absDir.size())) != 0) &&
452 (relDir.compare(filePath.substr(0, relDir.size())) != 0)) {
453 TELEPHONY_LOGE("filePath no app sand box.");
454 return false;
455 }
456 pFile = fopen(realPath, "rb");
457 if (pFile == nullptr) {
458 TELEPHONY_LOGI("Write Body Part from File notFind, try to use buffer");
459 return false;
460 }
461 (void)fseek(pFile, 0, SEEK_END);
462 long fileLen = ftell(pFile);
463 if (fileLen <= 0 || fileLen > static_cast<long>(MMS_PDU_MAX_SIZE)) {
464 (void)fclose(pFile);
465 TELEPHONY_LOGE("fileLen is invalid [%{public}ld]", fileLen);
466 return false;
467 }
468 if (pbodyPartBuffer_) {
469 pbodyPartBuffer_.reset();
470 }
471 pbodyPartBuffer_ = std::make_unique<char[]>(fileLen);
472 if (!pbodyPartBuffer_) {
473 (void)fclose(pFile);
474 TELEPHONY_LOGE("Buffer initialize fail!");
475 return false;
476 }
477
478 (void)fseek(pFile, 0, SEEK_SET);
479 bodyLen_ = fread(pbodyPartBuffer_.get(), 1, fileLen, pFile);
480 (void)fclose(pFile);
481 return true;
482 }
483
WriteBodyFromAttachmentBuffer(MmsAttachment & attachment)484 bool MmsBodyPart::WriteBodyFromAttachmentBuffer(MmsAttachment &attachment)
485 {
486 if (attachment.GetFileName().empty()) {
487 TELEPHONY_LOGE("Attachment must set fileName, else error!");
488 return false;
489 }
490
491 uint32_t dataLen = 0;
492 std::unique_ptr<char[]> tempBuffer = nullptr;
493 tempBuffer = attachment.GetDataBuffer(dataLen);
494 if (tempBuffer == nullptr) {
495 TELEPHONY_LOGE("Read Attachment Data Buffer nullptr error.");
496 return false;
497 }
498
499 if (dataLen == 0 || dataLen > MMS_PDU_MAX_SIZE) {
500 TELEPHONY_LOGE("Attachment DataLen is invalid Error");
501 return false;
502 }
503
504 if (pbodyPartBuffer_) {
505 pbodyPartBuffer_.reset();
506 }
507 pbodyPartBuffer_ = std::make_unique<char[]>(dataLen);
508 if (!pbodyPartBuffer_) {
509 TELEPHONY_LOGE("Buffer initialize fail!");
510 return false;
511 }
512
513 if (memcpy_s(pbodyPartBuffer_.get(), dataLen, tempBuffer.get(), dataLen) != EOK) {
514 TELEPHONY_LOGE("Attachment Buffer MemCopy Error.");
515 bodyLen_ = 0;
516 return false;
517 }
518 bodyLen_ = dataLen;
519 return true;
520 }
521
GetPartFileName()522 std::string MmsBodyPart::GetPartFileName()
523 {
524 return strFileName_;
525 }
526
SetFileName(std::string fileName)527 void MmsBodyPart::SetFileName(std::string fileName)
528 {
529 strFileName_ = fileName;
530 }
531
GetContentType()532 MmsContentType &MmsBodyPart::GetContentType()
533 {
534 return bodyPartContentType_;
535 }
536
GetPartHeader()537 MmsBodyPartHeader &MmsBodyPart::GetPartHeader()
538 {
539 return mmsBodyPartHeader_;
540 }
541
ReadBodyPartBuffer(uint32_t & len)542 std::unique_ptr<char[]> MmsBodyPart::ReadBodyPartBuffer(uint32_t &len)
543 {
544 if (bodyLen_ > MMS_PDU_MAX_SIZE) {
545 TELEPHONY_LOGE("srcBodyPart.bodyLen_ over size error");
546 return nullptr;
547 }
548 std::unique_ptr<char[]> result = std::make_unique<char[]>(bodyLen_);
549 if (result == nullptr) {
550 TELEPHONY_LOGE("Read BodyPart Buffer MakeUnique Error.");
551 return nullptr;
552 }
553 if (memcpy_s(result.get(), bodyLen_, pbodyPartBuffer_.get(), bodyLen_) != EOK) {
554 TELEPHONY_LOGE("Read BodyPart Buffer Memcpy_s Error.");
555 return nullptr;
556 }
557 len = bodyLen_;
558 return result;
559 }
560 } // namespace Telephony
561 } // namespace OHOS
562