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