• 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 "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(&currentTime, &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