• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentTime, &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