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