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_content_type.h"
16 
17 #include "telephony_log_wrapper.h"
18 #include "mms_decode_buffer.h"
19 #include "mms_charset.h"
20 
21 namespace OHOS {
22 namespace Telephony {
DumpMmsContentType()23 void MmsContentType::DumpMmsContentType()
24 {
25     TELEPHONY_LOGI("contentType : %{public}s", contentType_.c_str());
26     msgContentParm_.DumpContentParam();
27 }
28 
MmsContentType(const MmsContentType & srcContentType)29 MmsContentType::MmsContentType(const MmsContentType &srcContentType)
30 {
31     contentType_ = srcContentType.contentType_;
32     msgContentParm_ = srcContentType.msgContentParm_;
33 }
34 
operator =(const MmsContentType & srcContentType)35 MmsContentType &MmsContentType::operator=(const MmsContentType &srcContentType)
36 {
37     if (this != &srcContentType) {
38         contentType_ = srcContentType.contentType_;
39         msgContentParm_ = srcContentType.msgContentParm_;
40     }
41     return *this;
42 }
43 
44 /**
45  * @brief DecodeMmsContentType
46  * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
47  * Content-type-value = Constrained-media | Content-general-form
48  * Constrained-media = Constrained-encoding
49  * Constrained-encoding = Extension-Media | Short-integer
50  * Extension-media = *TEXT End-of-string
51  * Content-general-form = Value-length Media-type
52  * Media-type = (Well-known-media | Extension-Media) *(Parameter)
53  * Well-known-media = Integer-value
54  * Parameter = Typed-parameter | Untyped-parameter
55  * @param decodeBuffer
56  * @param contentLength
57  * @return true
58  * @return false
59  */
DecodeMmsContentType(MmsDecodeBuffer & decodeBuffer,int32_t & contentLength)60 bool MmsContentType::DecodeMmsContentType(MmsDecodeBuffer &decodeBuffer, int32_t &contentLength)
61 {
62     const uint8_t setHighestBitZero = 0x7f;
63     uint8_t oneByte = 0;
64     if (decodeBuffer.DecodeIsShortInt()) {
65         if (!decodeBuffer.GetOneByte(oneByte)) {
66             TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
67             return false;
68         }
69         contentType_ = GetContentTypeFromInt(oneByte & setHighestBitZero);
70         contentLength = 1;
71         return true;
72     }
73 
74     if (decodeBuffer.DecodeIsString()) {
75         std::string sType = "";
76         uint32_t len = 0;
77         decodeBuffer.DecodeText(sType, len);
78         contentLength = static_cast<int32_t>(len + 1);
79         contentType_ = sType;
80         return true; // 2
81     }
82 
83     if (!DecodeMmsCTGeneralForm(decodeBuffer, contentLength)) {
84         TELEPHONY_LOGE("Decode contentType DecodeMmsCTGeneralForm fail.");
85         return false;
86     }
87     return true;
88 }
89 
90 /**
91  * @brief DecodeMmsCTGeneralForm
92  * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
93  * Content-type-value = Constrained-media | Content-general-form
94  * Constrained-media = Constrained-encoding
95  * Constrained-encoding = Extension-Media | Short-integer
96  * Extension-media = *TEXT End-of-string
97  * Content-general-form = Value-length Media-type
98  * Media-type = (Well-known-media | Extension-Media) *(Parameter)
99  * Well-known-media = Integer-value
100  * Parameter = Typed-parameter | Untyped-parameter
101  * @param decodeBuffer
102  * @param contentLength
103  * @return true
104  * @return false
105  */
DecodeMmsCTGeneralForm(MmsDecodeBuffer & decodeBuffer,int32_t & contentLength)106 bool MmsContentType::DecodeMmsCTGeneralForm(MmsDecodeBuffer &decodeBuffer, int32_t &contentLength)
107 {
108     const uint8_t setHighestBitZero = 0x7f;
109 
110    /** false indicated no more data */
111     if (!decodeBuffer.DecodeIsValueLength()) {
112         TELEPHONY_LOGE("Decode contentType DecodeIsValueLength fail.");
113         return false;
114     }
115 
116     uint32_t valueLength = 0;
117     uint32_t returnLength = 0;
118     if (!decodeBuffer.DecodeValueLengthReturnLen(valueLength, returnLength)) {
119         TELEPHONY_LOGE("Decode contentType DecodeValueLengthReturnLen fail.");
120         return false;
121     }
122     contentLength = static_cast<int32_t>(valueLength + returnLength);
123 
124     uint8_t oneByte = 0;
125     if (!decodeBuffer.PeekOneByte(oneByte)) {
126         TELEPHONY_LOGE("Decode contentType PeekOneByte fail.");
127         return false;
128     }
129     if (decodeBuffer.DecodeIsShortInt()) {
130         contentType_ = GetContentTypeFromInt(oneByte & setHighestBitZero);
131         if (!decodeBuffer.IncreasePointer(1)) {
132             TELEPHONY_LOGE("Decode contentType IncreasePointer fail.");
133             return false;
134         }
135         if (valueLength == 0) {
136             TELEPHONY_LOGE("Decode contentType valueLength empty.");
137             return false;
138         }
139         valueLength--;
140     } else if (decodeBuffer.DecodeIsString()) {
141         std::string sType = "";
142         uint32_t len = 0;
143         decodeBuffer.DecodeText(sType, len);
144         valueLength -= len + 1;
145         contentType_ = sType;
146     } else {
147         TELEPHONY_LOGE("Decode contentType DecodeMmsContentType fail.");
148         return false;
149     }
150 
151     if (!DecodeParameter(decodeBuffer, valueLength)) {
152         TELEPHONY_LOGE("Decode contentType DecodeParameter fail.");
153         return false;
154     }
155     return true;
156 }
157 
GetContentTypeFromInt(uint8_t type)158 std::string MmsContentType::GetContentTypeFromInt(uint8_t type)
159 {
160     for (unsigned int i = 0; i < sizeof(mmsContentNames) / sizeof(mmsContentNames[0]); i++) {
161         if (type == static_cast<uint8_t>(mmsContentNames[i].key)) {
162             return mmsContentNames[i].value;
163         }
164     }
165     return "*/*";
166 }
167 
GetContentTypeFromString(std::string str)168 int8_t MmsContentType::GetContentTypeFromString(std::string str)
169 {
170     for (unsigned int i = 0; i < sizeof(mmsContentNames) / sizeof(mmsContentNames[0]); i++) {
171         if (str == std::string(mmsContentNames[i].value)) {
172             return i;
173         }
174     }
175     return -1;
176 }
177 
178 /**
179  * @brief DecodeParameter
180  * wap-230-wsp-20010705-a   section:8.4.2.4 Parameter
181  * Parameter = Typed-parameter | Untyped-parameter
182  * Typed-parameter = Well-known-parameter-token Typed-value
183  * Well-known-parameter-token = Integer-value
184  * Typed-value = Compact-value | Text-value
185  * Compact-value = Integer-value |
186  *                 Date-value | Delta-seconds-value | Q-value | Version-value |
187  *                 Uri-value
188  * Untyped-parameter = Token-text Untyped-value
189  * Untyped-value = Integer-value | Text-value
190  * Delta-seconds-value = Long-integer
191  * Q-value = 1*2 OCTET
192  * @param decodeBuffer
193  * @param valueLength
194  * @return true
195  * @return false
196  */
DecodeParameter(MmsDecodeBuffer & decodeBuffer,int32_t valueLength)197 bool MmsContentType::DecodeParameter(MmsDecodeBuffer &decodeBuffer, int32_t valueLength)
198 {
199     uint8_t paramCode = 0;
200     while (valueLength > 0) {
201         if (!decodeBuffer.GetOneByte(paramCode)) {
202             TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
203             return false;
204         }
205         valueLength--;
206         switch (static_cast<ContentParam>(paramCode)) {
207             case ContentParam::CT_P_CHARSET: {
208                 /* charset */
209                 if (!DecodeCharsetField(decodeBuffer, valueLength)) {
210                     TELEPHONY_LOGE("Decode contentType DecodeCharsetField fail.");
211                     return false;
212                 }
213                 break;
214             }
215             case ContentParam::CT_P_FILENAME:
216             case ContentParam::CT_P_FILENAME_VALUE:
217             case ContentParam::CT_P_START_VALUE:
218             case ContentParam::CT_P_START:
219             case ContentParam::CT_P_NAME:
220             case ContentParam::CT_P_NAME_VALUE:
221             case ContentParam::CT_P_START_INFO:
222             case ContentParam::CT_P_START_INFO_VALUE: {
223                 if (!DecodeTextField(decodeBuffer, paramCode, valueLength)) {
224                     TELEPHONY_LOGE("Decode contentType DecodeTextField fail.");
225                     return false;
226                 }
227                 break;
228             }
229             case ContentParam::CT_P_TYPE:
230             case ContentParam::CT_P_TYPE_STRING: {
231                 if (!DecodeTypeField(decodeBuffer, valueLength)) {
232                     TELEPHONY_LOGE("Decode contentType DecodeTypeField fail.");
233                     return false;
234                 }
235                 break;
236             }
237             default: {
238                 if (!decodeBuffer.IncreasePointer(valueLength)) {
239                     TELEPHONY_LOGE("Decode contentType IncreasePointer fail.");
240                     return false;
241                 }
242                 valueLength = 0;
243             }
244         }
245     }
246     return true;
247 }
248 
GetContentType(std::string & str)249 bool MmsContentType::GetContentType(std::string &str)
250 {
251     str = contentType_;
252     return true;
253 }
254 
SetContentType(std::string str)255 bool MmsContentType::SetContentType(std::string str)
256 {
257     contentType_ = str;
258     return true;
259 }
260 
SetContentParam(MmsContentParam & contentParam)261 bool MmsContentType::SetContentParam(MmsContentParam &contentParam)
262 {
263     msgContentParm_ = contentParam;
264     return true;
265 }
266 
267 /**
268  * @brief DecodeTextField
269  * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
270  * Text-string = [Quote] *TEXT End-of-string
271  * Quote = <Octet 127>
272  * End-of-string = <Octet 0>
273  * @param decodeBuffer
274  * @param field
275  * @param valueLength
276  * @return true
277  * @return false
278  */
DecodeTextField(MmsDecodeBuffer & decodeBuffer,uint8_t field,int32_t & valueLength)279 bool MmsContentType::DecodeTextField(MmsDecodeBuffer &decodeBuffer, uint8_t field, int32_t &valueLength)
280 {
281     std::string str = "";
282     uint32_t len = 0;
283     if (!decodeBuffer.DecodeText(str, len)) {
284         TELEPHONY_LOGE("Decode contentType DecodeText fail.");
285         return false;
286     }
287     msgContentParm_.GetParamMap().insert(std::make_pair(field, str));
288     valueLength -= static_cast<int32_t>(len);
289     valueLength -= 1;
290     return true;
291 }
292 
293 /**
294  * @brief DecodeCharsetField
295  * wap-230-wsp-20010705-a   section:8.4.2.8 Accept charset field
296  * Well-known-charset = Any-charset | Integer-value
297  * Any-charset = <Octet 128>
298  * @param decodeBuffer
299  * @param valueLength
300  * @return true
301  * @return false
302  */
DecodeCharsetField(MmsDecodeBuffer & decodeBuffer,int32_t & valueLength)303 bool MmsContentType::DecodeCharsetField(MmsDecodeBuffer &decodeBuffer, int32_t &valueLength)
304 {
305     int32_t charset = 0;
306     uint8_t oneByte = 0;
307     const uint8_t textMinValue = 32;
308     const uint8_t textMaxValue = 127;
309     if (decodeBuffer.PeekOneByte(oneByte) == false) {
310         TELEPHONY_LOGE("Decode contentType PeekOneByte fail.");
311         return false;
312     }
313     if (((oneByte > textMinValue) && (oneByte < textMaxValue)) || (oneByte == 0)) {
314         std::string sCharset = "";
315         uint32_t len = 0;
316         if (!decodeBuffer.DecodeText(sCharset, len)) {
317             TELEPHONY_LOGE("Decode contentType DecodeText fail.");
318             return false;
319         }
320         valueLength -= static_cast<int32_t>(len + 1);
321         uint32_t tmpCharSet = 0;
322         auto charSetInstance = DelayedSingleton<MmsCharSet>::GetInstance();
323         if (charSetInstance == nullptr || (!charSetInstance->GetCharSetIntFromString(tmpCharSet, sCharset))) {
324             TELEPHONY_LOGE("Decode contentType GetInstance or GetCharSetIntFromString fail.");
325             return false;
326         }
327         charset = static_cast<int32_t>(tmpCharSet);
328     } else {
329         uint32_t startPosition = decodeBuffer.GetCurPosition();
330         uint64_t tmp = 0;
331         if (!decodeBuffer.DecodeInteger(tmp)) {
332             TELEPHONY_LOGE("Decode contentType DecodeInteger fail.");
333             return false;
334         }
335         charset = (int32_t)tmp;
336         uint32_t endPosition = decodeBuffer.GetCurPosition();
337         if (endPosition >= startPosition) {
338             valueLength -= static_cast<int32_t>(endPosition - startPosition);
339         }
340     }
341     msgContentParm_.SetCharSet(charset);
342     return true;
343 }
344 
345 /**
346  * @brief DecodeTypeField
347  * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
348  * Constrained-encoding = Extension-Media | Short-integer
349  * Extension-media = *TEXT End-of-string
350  * @param decodeBuffer
351  * @param valueLength
352  * @return true
353  * @return false
354  */
DecodeTypeField(MmsDecodeBuffer & decodeBuffer,int32_t & valueLength)355 bool MmsContentType::DecodeTypeField(MmsDecodeBuffer &decodeBuffer, int32_t &valueLength)
356 {
357     uint8_t oneByte = 0;
358     if (decodeBuffer.GetOneByte(oneByte) == false) {
359         TELEPHONY_LOGE("Decode contentType GetOneByte fail.");
360         return false;
361     }
362 
363     if (oneByte > 0x7f) {
364         msgContentParm_.SetType(GetContentTypeFromInt(oneByte & 0x7f));
365         valueLength -= 1;
366     } else {
367         if (!decodeBuffer.DecreasePointer(1)) {
368             TELEPHONY_LOGE("Decode contentType DecreasePointer fail.");
369             return false;
370         }
371 
372         std::string sType = "";
373         uint32_t len = 0;
374         if (!decodeBuffer.DecodeText(sType, len)) {
375             TELEPHONY_LOGE("Decode contentType DecodeText fail.");
376             return false;
377         }
378         valueLength -= static_cast<int32_t>(len);
379         valueLength -= 1;
380         msgContentParm_.SetType(sType);
381     }
382     return true;
383 }
384 
385 /**
386  * @brief EncodeTextField
387  * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
388  * Text-string = [Quote] *TEXT End-of-string
389  * Quote = <Octet 127>
390  * End-of-string = <Octet 0>
391  * @param encodeBuffer
392  * @return true
393  * @return false
394  */
EncodeTextField(MmsEncodeBuffer & encodeBuffer)395 bool MmsContentType::EncodeTextField(MmsEncodeBuffer &encodeBuffer)
396 {
397     const uint8_t textParamLen = 8;
398     uint8_t fields[textParamLen] = {static_cast<uint8_t>(ContentParam::CT_P_FILENAME),
399         static_cast<uint8_t>(ContentParam::CT_P_FILENAME_VALUE),
400         static_cast<uint8_t>(ContentParam::CT_P_START_VALUE), static_cast<uint8_t>(ContentParam::CT_P_START),
401         static_cast<uint8_t>(ContentParam::CT_P_NAME), static_cast<uint8_t>(ContentParam::CT_P_NAME_VALUE),
402         static_cast<uint8_t>(ContentParam::CT_P_START_INFO),
403         static_cast<uint8_t>(ContentParam::CT_P_START_INFO_VALUE)};
404 
405     for (size_t i = 0; i < sizeof(fields); i++) {
406         if (msgContentParm_.GetParamMap().find(fields[i]) != msgContentParm_.GetParamMap().end()) {
407             if (!encodeBuffer.WriteByte(fields[i])) {
408                 TELEPHONY_LOGE("Encode contentType WriteByte fail.");
409                 return false;
410             }
411             if (!encodeBuffer.EncodeText(msgContentParm_.GetParamMap()[fields[i]])) {
412                 TELEPHONY_LOGE("Encode contentType EncodeText fail.");
413                 return false;
414             }
415         }
416     }
417     return true;
418 }
419 
420 /**
421  * @brief EncodeCharsetField
422  * wap-230-wsp-20010705-a   section:8.4.2.8 Accept charset field
423  * Well-known-charset = Any-charset | Integer-value
424  * Any-charset = <Octet 128>
425  * @param encodeBuffer
426  * @return true
427  * @return false
428  */
EncodeCharsetField(MmsEncodeBuffer & encodeBuffer)429 bool MmsContentType::EncodeCharsetField(MmsEncodeBuffer &encodeBuffer)
430 {
431     if (msgContentParm_.GetCharSet() == 0) {
432         return true;
433     }
434     if (!encodeBuffer.WriteByte(static_cast<uint8_t>(ContentParam::CT_P_CHARSET))) {
435         TELEPHONY_LOGE("Encode contentType WriteByte fail.");
436         return false;
437     }
438     if (!encodeBuffer.EncodeLongInteger(msgContentParm_.GetCharSet())) {
439         TELEPHONY_LOGE("Encode contentType EncodeLongInteger fail.");
440         return false;
441     }
442     return true;
443 }
444 
445 /**
446  * @brief EncodeTypeField
447  * wap-230-wsp-20010705-a   section:8.4.2.1 Basic rules
448  * Constrained-encoding = Extension-Media | Short-integer
449  * Extension-media = *TEXT End-of-string
450  * @param encodeBuffer
451  * @return true
452  * @return false
453  */
EncodeTypeField(MmsEncodeBuffer & encodeBuffer)454 bool MmsContentType::EncodeTypeField(MmsEncodeBuffer &encodeBuffer)
455 {
456     if (msgContentParm_.GetType().empty()) {
457         return true;
458     }
459     if (!encodeBuffer.WriteByte(static_cast<uint8_t>(ContentParam::CT_P_TYPE))) {
460         TELEPHONY_LOGE("Encode contentType WriteByte fail.");
461         return false;
462     }
463     if (!encodeBuffer.EncodeText(msgContentParm_.GetType())) {
464         TELEPHONY_LOGE("Encode contentType EncodeText fail.");
465         return false;
466     }
467     return true;
468 }
469 
470 /**
471  * @brief EncodeMmsBodyPartContentParam
472  * wap-230-wsp-20010705-a   section:8.4.2.4 Parameter
473  * Parameter = Typed-parameter | Untyped-parameter
474  * Typed-parameter = Well-known-parameter-token Typed-value
475  * Well-known-parameter-token = Integer-value
476  * Typed-value = Compact-value | Text-value
477  * Compact-value = Integer-value |
478  *                 Date-value | Delta-seconds-value | Q-value | Version-value |
479  *                 Uri-value
480  * Untyped-parameter = Token-text Untyped-value
481  * Untyped-value = Integer-value | Text-value
482  * @param encodeBuffer
483  * @return true
484  * @return false
485  */
EncodeMmsBodyPartContentParam(MmsEncodeBuffer & encodeBuffer)486 bool MmsContentType::EncodeMmsBodyPartContentParam(MmsEncodeBuffer &encodeBuffer)
487 {
488     if (!EncodeTextField(encodeBuffer)) {
489         TELEPHONY_LOGE("Encode contentType EncodeTextField fail.");
490         return false;
491     }
492     if (!EncodeCharsetField(encodeBuffer)) {
493         TELEPHONY_LOGE("Encode contentType EncodeCharsetField fail.");
494         return false;
495     }
496     if (!EncodeTypeField(encodeBuffer)) {
497         TELEPHONY_LOGE("Encode contentType EncodeTypeField fail.");
498         return false;
499     }
500     return true;
501 }
502 
503 /**
504  * @brief EncodeMmsBodyPartContentType
505  * wap-230-wsp-20010705-a   section:8.4.2.24 Content type field section:8.4.2.1 Basic rules
506  * Content-type-value = Constrained-media | Content-general-form
507  * Constrained-media = Constrained-encoding
508  * Constrained-encoding = Extension-Media | Short-integer
509  * Extension-media = *TEXT End-of-string
510  * Content-general-form = Value-length Media-type
511  * Media-type = (Well-known-media | Extension-Media) *(Parameter)
512  * Well-known-media = Integer-value
513  * Parameter = Typed-parameter | Untyped-parameter
514  * @param encodeBuffer
515  * @return true
516  * @return false
517  */
EncodeMmsBodyPartContentType(MmsEncodeBuffer & encodeBuffer)518 bool MmsContentType::EncodeMmsBodyPartContentType(MmsEncodeBuffer &encodeBuffer)
519 {
520     MmsEncodeBuffer tmpEncodeBuffer;
521     int8_t u8ContentType = 0;
522     u8ContentType = GetContentTypeFromString(contentType_);
523     if (u8ContentType < 0) {
524         if (!tmpEncodeBuffer.EncodeText(contentType_)) {
525             TELEPHONY_LOGE("Encode contentType EncodeText fail.");
526             return false;
527         }
528     } else {
529         if (!tmpEncodeBuffer.WriteByte(static_cast<uint8_t>(u8ContentType) | 0x80)) {
530             TELEPHONY_LOGE("Encode contentType WriteByte fail.");
531             return false;
532         }
533     }
534     if (!EncodeMmsBodyPartContentParam(tmpEncodeBuffer)) {
535         TELEPHONY_LOGE("Encode contentType EncodeMmsBodyPartContentParam fail.");
536         return false;
537     }
538     if (!encodeBuffer.EncodeValueLength(tmpEncodeBuffer.GetCurPosition())) {
539         TELEPHONY_LOGE("Encode contentType EncodeValueLength fail.");
540         return false;
541     }
542     if (!encodeBuffer.WriteBuffer(tmpEncodeBuffer)) {
543         TELEPHONY_LOGE("Encode contentType WriteBuffer fail.");
544         return false;
545     }
546     return true;
547 }
548 
GetContentParam()549 MmsContentParam& MmsContentType::GetContentParam()
550 {
551     return msgContentParm_;
552 }
553 } // namespace Telephony
554 } // namespace OHOS
555