• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "sms_cb_message.h"
18 
19 #include <string>
20 
21 #include "cdma_sms_types.h"
22 #include "msg_text_convert.h"
23 #include "securec.h"
24 #include "sms_common_utils.h"
25 #include "string_utils.h"
26 #include "telephony_log_wrapper.h"
27 
28 namespace OHOS {
29 namespace Telephony {
operator ==(const SmsCbMessage & other) const30 bool SmsCbMessage::operator==(const SmsCbMessage &other) const
31 {
32     if (cbHeader_ == nullptr || other.cbHeader_ == nullptr) {
33         TELEPHONY_LOGE("cbHeader_ is nullptr.");
34         return false;
35     }
36     return cbHeader_->serialNum.geoScope == other.cbHeader_->serialNum.geoScope &&
37         cbHeader_->serialNum.msgCode == other.cbHeader_->serialNum.msgCode &&
38         cbHeader_->msgId == other.cbHeader_->msgId;
39 }
40 
CreateCbMessage(const std::string & pdu)41 std::shared_ptr<SmsCbMessage> SmsCbMessage::CreateCbMessage(const std::string &pdu)
42 {
43     bool result = false;
44     std::shared_ptr<SmsCbMessage> message = std::make_shared<SmsCbMessage>();
45     if (message != nullptr) {
46         result = message->PduAnalysis(StringUtils::HexToByteVector(pdu));
47     }
48     return (result ? message : nullptr);
49 }
50 
CreateCbMessage(const std::vector<unsigned char> & pdu)51 std::shared_ptr<SmsCbMessage> SmsCbMessage::CreateCbMessage(const std::vector<unsigned char> &pdu)
52 {
53     bool result = false;
54     std::shared_ptr<SmsCbMessage> message = std::make_shared<SmsCbMessage>();
55     if (message != nullptr) {
56         result = message->PduAnalysis(pdu);
57     }
58     return (result ? message : nullptr);
59 }
60 
GetCbHeader() const61 std::shared_ptr<SmsCbMessage::SmsCbMessageHeader> SmsCbMessage::GetCbHeader() const
62 {
63     return cbHeader_;
64 }
65 
GetCbMessageRaw() const66 std::string SmsCbMessage::GetCbMessageRaw() const
67 {
68     return messageRaw_;
69 }
70 
IsSinglePageMsg() const71 bool SmsCbMessage::IsSinglePageMsg() const
72 {
73     return cbHeader_ != nullptr && (cbHeader_->totalPages == 1);
74 }
75 
76 /**
77  * @brief PduAnalysis Cell Broadcast Message
78  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.1.1 9.1.2 section Protocols and Protocol Architecture
79  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.3 Parameters
80  * @param pdu [in]
81  * @return true [out]
82  * @return false [out]
83  */
PduAnalysis(const std::vector<unsigned char> & pdu)84 bool SmsCbMessage::PduAnalysis(const std::vector<unsigned char> &pdu)
85 {
86     cbHeader_ = std::make_shared<SmsCbMessage::SmsCbMessageHeader>();
87     if (cbHeader_ == nullptr) {
88         TELEPHONY_LOGE("cbHeader_ is nullptr.");
89         return false;
90     }
91     int offset = 0;
92     // from 3GPP TS 23.041 V4.1.0 (2001-06) 9.1.1 9.1.2 section Protocols and Protocol Architecture
93     if (pdu.size() <= (MAX_CBMSG_PAGE_SIZE + SMS_CB_HEADER_SIZE)) {
94         cbHeader_->cbMsgType = SMS_CBMSG_TYPE_CBS;
95         cbHeader_->cbNetType = SMS_NETTEXT_CB_MSG_GSM;
96         offset = Decode2gHeader(pdu);
97     } else {
98         cbHeader_->cbMsgType = pdu[offset];
99         cbHeader_->cbNetType = SMS_NETTEXT_CB_MSG_UMTS;
100         offset = Decode3gHeader(pdu);
101     }
102     if (offset == 0 || pdu.size() <= (std::size_t)offset) {
103         TELEPHONY_LOGE("offset out of bound.");
104         return false;
105     }
106     TELEPHONY_LOGI("header offse = %{public}d", offset);
107     std::vector<unsigned char> bodyPdu(pdu.begin() + offset, pdu.end());
108     if (cbHeader_->bEtwsMessage && cbHeader_->cbEtwsType == SMS_NETTEXT_ETWS_PRIMARY) {
109         DecodeEtwsMsg(bodyPdu);
110         return true;
111     }
112     switch (cbHeader_->cbNetType) {
113         case SMS_NETTEXT_CB_MSG_GSM:
114             Decode2gCbMsg(bodyPdu);
115             break;
116         case SMS_NETTEXT_CB_MSG_UMTS:
117             Decode3gCbMsg(bodyPdu);
118             break;
119         default:
120             break;
121     }
122     return true;
123 }
124 
125 /**
126  * @brief Decode2gHeader GSM Cell Broadcast Message Header
127  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4 Message Format on the Radio Network  – MS/UE Interface
128  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4.1.2 Message Parameter
129  * @param pdu [in]
130  * @return int [out]
131  */
Decode2gHeader(const std::vector<unsigned char> & pdu)132 int SmsCbMessage::Decode2gHeader(const std::vector<unsigned char> &pdu)
133 {
134     int offset = 0;
135     unsigned char temp;
136     if (pdu.size() < SMS_CB_HEADER_SIZE) {
137         TELEPHONY_LOGE("pdu size less than min.");
138         return offset;
139     }
140     if (cbHeader_ == nullptr) {
141         TELEPHONY_LOGE("cbHeader_ is nullptr.");
142         return offset;
143     }
144     cbHeader_->bEtwsMessage = false;
145     temp = pdu[offset++];
146     cbHeader_->serialNum.geoScope = (temp & 0xC0) >> 0x06;
147     cbHeader_->serialNum.msgCode = (temp & 0x3F) << 0x04;
148 
149     temp = pdu[offset++];
150     cbHeader_->serialNum.msgCode |= (temp & 0xF0) >> 0x04;
151     cbHeader_->serialNum.updateNum = temp & 0x0F;
152 
153     temp = pdu[offset++];
154     cbHeader_->msgId = (temp << 0x08) | pdu[offset++];
155     if ((cbHeader_->msgId & 0xFFF8) == SMS_ETWS_BASE_MASK && pdu.size() <= MAX_ETWS_SIZE) {
156         cbHeader_->cbEtwsType = SMS_NETTEXT_ETWS_PRIMARY;
157         cbHeader_->bEtwsMessage = true;
158         temp = pdu[offset++];
159         cbHeader_->warningType = (temp << 0x08) | pdu[offset++];
160     } else {
161         unsigned char dcs = pdu[offset++];
162         temp = pdu[offset++];
163         cbHeader_->totalPages = temp & 0x0f;
164         cbHeader_->page = (temp & 0xF0) >> 0x04;
165 
166         unsigned short iosTemp = pdu[offset++];
167         iosTemp |= (pdu[offset++] << BYTE_BIT);
168         DecodeCbMsgDCS(dcs, iosTemp, cbHeader_->dcs);
169         cbHeader_->langType = cbHeader_->dcs.langType;
170         cbHeader_->recvTime = static_cast<time_t>(GetRecvTime());
171         if (cbHeader_->totalPages > MAX_CBMSG_PAGE_NUM) {
172             TELEPHONY_LOGE("CB Page Count is over MAX[%{public}d]", cbHeader_->totalPages);
173             offset = 0;
174         }
175         if ((cbHeader_->msgId & 0xFFF8) == SMS_ETWS_BASE_MASK) {
176             cbHeader_->bEtwsMessage = true;
177             cbHeader_->cbEtwsType = SMS_NETTEXT_ETWS_SECONDARY_GSM;
178             cbHeader_->warningType = cbHeader_->msgId - SMS_ETWS_BASE_MASK;
179         }
180         offset -= 0x02;
181     }
182     return offset;
183 }
184 
185 /**
186  * @brief Decode3gHeader UMTS Cell Broadcast Message Header
187  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4.2.1 General Description
188  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4.2.2 Message Parameter
189  * @param pdu [in]
190  * @return int [out]
191  */
Decode3gHeader(const std::vector<unsigned char> & pdu)192 int SmsCbMessage::Decode3gHeader(const std::vector<unsigned char> &pdu)
193 {
194     int offset = 0;
195     unsigned char temp;
196     if (pdu.size() < SMS_CB_HEADER_SIZE) {
197         TELEPHONY_LOGE("pdu size less than min.");
198         return offset;
199     }
200     if (cbHeader_ == nullptr) {
201         TELEPHONY_LOGE("cbHeader_ is nullptr.");
202         return offset;
203     }
204     offset++; // cbMsgType
205 
206     temp = pdu[offset++];
207     cbHeader_->msgId = (temp << 0x08) | pdu[offset++];
208 
209     temp = pdu[offset++];
210     cbHeader_->serialNum.geoScope = (temp & 0xC0) >> 0x06;
211     cbHeader_->serialNum.msgCode = (temp & 0x3F) << 0x04;
212 
213     temp = pdu[offset++];
214     cbHeader_->serialNum.msgCode |= (temp & 0xF0) >> 0x04;
215     cbHeader_->serialNum.updateNum = temp & 0x0F;
216 
217     unsigned char dcs = pdu[offset++];
218     cbHeader_->totalPages = pdu[offset++];
219 
220     unsigned short iosTemp = pdu[offset++];
221     iosTemp |= (pdu[offset++] << BYTE_BIT);
222     DecodeCbMsgDCS(dcs, iosTemp, cbHeader_->dcs);
223     cbHeader_->langType = cbHeader_->dcs.langType;
224     cbHeader_->recvTime = static_cast<time_t>(GetRecvTime());
225     offset -= 0x02;
226     return offset;
227 }
228 
229 /**
230  * @brief Decode2gCbMsg GSM Content of Message
231  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4.2.2 Message Parameter
232  * @param pdu [in]
233  */
Decode2gCbMsg(const std::vector<unsigned char> & pdu)234 void SmsCbMessage::Decode2gCbMsg(const std::vector<unsigned char> &pdu)
235 {
236     int offset = 0;
237     int dataLen = static_cast<int>(pdu.size());
238     if (cbHeader_ == nullptr) {
239         TELEPHONY_LOGE("decode2gCbMsg null header");
240         return;
241     }
242     TELEPHONY_LOGI("Decode2gCbMsg codingScheme ==%{public}d", cbHeader_->dcs.codingScheme);
243     switch (cbHeader_->dcs.codingScheme) {
244         case SMS_CODING_7BIT: {
245             dataLen = (dataLen * BYTE_BIT) / ENCODE_GSM_BIT;
246             unsigned char pageData[MAX_CBMSG_PAGE_SIZE * BYTE_BIT / ENCODE_GSM_BIT] = {0};
247             int unpackLen = SmsCommonUtils::Unpack7bitChar(pdu.data(), dataLen, 0x00, pageData,
248                 MAX_CBMSG_PAGE_SIZE * BYTE_BIT / ENCODE_GSM_BIT);
249 
250             if (cbHeader_->dcs.iso639Lang[0]) {
251                 unpackLen = unpackLen - SmsCbMessage::SMS_CB_IOS639LANG_SIZE;
252                 offset = SmsCbMessage::SMS_CB_IOS639LANG_SIZE;
253             }
254             messageRaw_.insert(0, (const char *)&pageData[offset], unpackLen);
255             break;
256         }
257         case SMS_CODING_8BIT:
258         case SMS_CODING_UCS2: {
259             if (cbHeader_->dcs.iso639Lang[0]) {
260                 offset = 0x02;
261                 dataLen -= offset;
262             }
263 
264             if (dataLen > 0) {
265                 messageRaw_.insert(0, (const char *)(pdu.data() + offset), dataLen);
266             }
267             break;
268         }
269         default:
270             break;
271     }
272 }
273 
274 /**
275  * @brief Decode3gCbMsg UMTS CB Data
276  * 3GPP TS 23.041 V4.1.0 (2001-06) 9.4.2.2.5 CB Data
277  * @param pdu [in]
278  */
Decode3gCbMsg(const std::vector<unsigned char> & pdu)279 void SmsCbMessage::Decode3gCbMsg(const std::vector<unsigned char> &pdu)
280 {
281     if (cbHeader_ == nullptr) {
282         TELEPHONY_LOGE("Decode3gCbMsg cbHeader null err.");
283         return;
284     }
285     switch (cbHeader_->dcs.codingScheme) {
286         case SMS_CODING_7BIT: {
287             TELEPHONY_LOGI("SMS_CODING_7BIT totalPages %{public}d", cbHeader_->totalPages);
288             Decode3g7Bit(pdu);
289             break;
290         }
291         case SMS_CODING_8BIT:
292         case SMS_CODING_UCS2: {
293             TELEPHONY_LOGI("SMS_CODING_UCS2 totalPages %{public}d", cbHeader_->totalPages);
294             Decode3gUCS2(pdu);
295             break;
296         }
297         default:
298             break;
299     }
300     cbHeader_->totalPages = 1;
301 }
302 
Decode3g7Bit(const std::vector<unsigned char> & pdu)303 void SmsCbMessage::Decode3g7Bit(const std::vector<unsigned char> &pdu)
304 {
305     if (pdu.size() <= 0) {
306         TELEPHONY_LOGE("pdu size is invalid.");
307         return;
308     }
309     unsigned int offset = 0;
310     int dataLen = 0;
311     const int pduLen = static_cast<int>(pdu.size());
312     const unsigned char *tpdu = pdu.data();
313     for (unsigned char i = 0; i < cbHeader_->totalPages; ++i) {
314         unsigned char pageLenOffset = (unsigned char)((i + 1) * MAX_CBMSG_PAGE_SIZE + i);
315         if (pduLen < pageLenOffset) {
316             TELEPHONY_LOGE("CB Msg Size err [%{pulbic}d]", pduLen);
317             messageRaw_.clear();
318             return;
319         }
320         dataLen = tpdu[pageLenOffset];
321         offset = static_cast<unsigned int>((i * MAX_CBMSG_PAGE_SIZE) + i);
322         if (dataLen > MAX_CBMSG_PAGE_SIZE) {
323             TELEPHONY_LOGE("CB Msg Size is over MAX [%{pulbic}d]", dataLen);
324             messageRaw_.clear();
325             return;
326         }
327         int unpackLen = 0;
328         dataLen = (dataLen * BYTE_BIT) / ENCODE_GSM_BIT;
329         unsigned char pageData[MAX_CBMSG_PAGE_SIZE * BYTE_BIT / ENCODE_GSM_BIT] = {0};
330         unpackLen = SmsCommonUtils::Unpack7bitChar(&tpdu[offset], dataLen, 0x00, pageData,
331             MAX_CBMSG_PAGE_SIZE * BYTE_BIT / ENCODE_GSM_BIT);
332         messageRaw_.insert(messageRaw_.size(), (const char *)pageData, unpackLen);
333     }
334 }
335 
Decode3gUCS2(const std::vector<unsigned char> & pdu)336 void SmsCbMessage::Decode3gUCS2(const std::vector<unsigned char> &pdu)
337 {
338     if (pdu.size() <= 0) {
339         TELEPHONY_LOGE("pdu size is invalid.");
340         return;
341     }
342     int dataLen = 0;
343     unsigned int offset = 0;
344     const int pduLen = static_cast<int>(pdu.size());
345     const unsigned char *tpdu = pdu.data();
346     for (unsigned char i = 0; i < cbHeader_->totalPages; ++i) {
347         unsigned char pageLenOffset = (unsigned char)((i + 1) * MAX_CBMSG_PAGE_SIZE + i);
348         if (pduLen < pageLenOffset) {
349             TELEPHONY_LOGE("CB Msg Size err [%{pulbic}d]", pduLen);
350             messageRaw_.clear();
351             return;
352         }
353         if (cbHeader_->dcs.iso639Lang[0]) {
354             dataLen = tpdu[pageLenOffset] - 0x02;
355             offset = (i * MAX_CBMSG_PAGE_SIZE) + i + 0x02;
356         } else {
357             dataLen = tpdu[pageLenOffset];
358             offset = static_cast<unsigned int>((i * MAX_CBMSG_PAGE_SIZE) + i);
359         }
360         if (dataLen > 0 && dataLen <= MAX_CBMSG_PAGE_SIZE) {
361             messageRaw_.insert(messageRaw_.size(), (const char *)&tpdu[offset], dataLen);
362         }
363     }
364 }
365 
DecodeEtwsMsg(const std::vector<unsigned char> & pdu)366 void SmsCbMessage::DecodeEtwsMsg(const std::vector<unsigned char> &pdu)
367 {
368     int offset = 0;
369     if (pdu.size() > MAX_ETWS_SIZE) {
370         TELEPHONY_LOGE("ETWS Msg Size is over MAX [%{public}zu]", pdu.size());
371         return;
372     }
373     messageRaw_.insert(0, (const char *)(pdu.data() + offset), static_cast<int>(pdu.size()) - offset);
374 }
375 
ConvertToUTF8(const std::string & raw,std::string & message) const376 void SmsCbMessage::ConvertToUTF8(const std::string &raw, std::string &message) const
377 {
378     if (cbHeader_ == nullptr) {
379         TELEPHONY_LOGE("ConvertToUTF8 cbHeader null err.");
380         return;
381     }
382     if (cbHeader_->bEtwsMessage && cbHeader_->cbEtwsType == SMS_NETTEXT_ETWS_PRIMARY) {
383         message.assign(raw);
384     } else {
385         MsgTextConvert *textCvt = MsgTextConvert::Instance();
386         if (textCvt == nullptr) {
387             TELEPHONY_LOGE("MsgTextConvert Instance nullptr");
388             return;
389         }
390         int codeSize = 0;
391         MsgLangInfo langInfo = {
392             0,
393         };
394         unsigned char outBuf[MAX_CB_MSG_TEXT_LEN + 1] = {0};
395         if (cbHeader_->dcs.codingScheme == SMS_CODING_7BIT) {
396             codeSize = textCvt->ConvertGSM7bitToUTF8(
397                 outBuf, sizeof(outBuf), (unsigned char *)raw.data(), raw.length(), &langInfo);
398         } else if (cbHeader_->dcs.codingScheme == SMS_CODING_UCS2) {
399             codeSize =
400                 textCvt->ConvertUCS2ToUTF8(outBuf, sizeof(outBuf), (unsigned char *)raw.data(), raw.length());
401         } else {
402             message.assign(raw);
403             return;
404         }
405         outBuf[codeSize] = '\0';
406         message.insert(0, (const char *)outBuf, codeSize);
407     }
408 }
409 
EncodeCbSerialNum(const SmsCBMessageSerialNum & snFields)410 unsigned short SmsCbMessage::EncodeCbSerialNum(const SmsCBMessageSerialNum &snFields)
411 {
412     unsigned short serialNum = 0;
413     serialNum = ((snFields.geoScope & 0x03) << 0x0E) | ((snFields.msgCode & 0x03FF) << 0x04) |
414         (snFields.updateNum & 0x0F);
415     return serialNum;
416 }
417 
CMASClass(const unsigned short messageId) const418 int SmsCbMessage::CMASClass(const unsigned short messageId) const
419 {
420     int ret = 0;
421     switch (messageId) {
422         case CMAS_PRESIDENTIAL_DEFUALT:
423         case CMAS_PRESIDENTIAL_SPANISH:
424             ret = MSG_CMAS_PRESIDENTIAL;
425             break;
426         case CMAS_EXTREME_OBSERVED_DEFUALT:
427         case CMAS_EXTREME_OBSERVED_SPANISH:
428         case CMAS_EXTREME_LIKELY_DEFUALT:
429         case CMAS_EXTREME_LIKELY_SPANISH:
430             ret = MSG_CMAS_EXTREME;
431             break;
432         case CMAS_SERVER_EXTERME_OBSERVED_DEFUALT:
433         case CMAS_SERVER_EXTREME_OBSERVED_SPANISH:
434         case CMAS_SERVER_EXTERME_LIKELY_DEFUALT:
435         case CMAS_SERVER_EXTERME_LIKELY_SPANISH:
436         case CMAS_SERVER_SERVER_OBSERVED_DEFUALT:
437         case CMAS_SERVER_SERVER_OBSERVED_SPANISH:
438         case CMAS_SERVER_SERVER_LIKELY_DEFUALT:
439         case CMAS_SERVER_SERVER_LIKELY_SPANISH:
440         case CMAS_SERVER_SERVER_EXPECTED_OBSERVED_DEFUALT:
441         case CMAS_SERVER_SERVER_EXPECTED_OBSERVED_SPANISH:
442         case CMAS_SERVER_SERVER_EXPECTED_LIKELY_DEFUALT:
443         case CMAS_SERVER_SERVER_EXPECTED_LIKELY_SPANISH:
444             ret = MSG_CMAS_SEVERE;
445             break;
446         case CMAS_AMBER_ALERT_DEFUALT:
447         case CMAS_AMBER_ALERT_SPANISH:
448             ret = MSG_CMAS_AMBER;
449             break;
450         case CMAS_RMT_ALERT_DEFUALT:
451         case CMAS_RMT_ALERT_SPANISH:
452             ret = MSG_CMAS_TEST;
453             break;
454         case CMAS_EXERCISE_ALERT_DEFUALT:
455         case CMAS_EXERCISE_ALERT_SPANISH:
456             ret = MSG_CMAS_EXERCISE;
457             break;
458         case CMAS_OPERATOR_ALERT_DEFUALT:
459         case CMAS_OPERATOR_ALERT_SPANISH:
460             ret = MSG_CMAS_OPERATOR_DEFINED;
461             break;
462         default:
463             break;
464     }
465     return ret;
466 }
467 
468 /**
469  * @brief DecodeIos639Dcs
470  *  from 3GPP TS 23.038 V4.3.0 (2001-09)  6.1.1 section
471  *  Control characters
472  * @param dcsData
473  * @param iosData
474  * @param pDcs
475  */
DecodeIos639Dcs(const unsigned char dcsData,const unsigned short iosData,SmsCbMessageDcs & pDcs) const476 void SmsCbMessage::DecodeIos639Dcs(
477     const unsigned char dcsData, const unsigned short iosData, SmsCbMessageDcs &pDcs) const
478 {
479     unsigned char dcsLow = (dcsData & 0x0F);
480     switch (dcsLow) {
481         case 0x00:
482         case 0x01: {
483             pDcs.codingGroup = SMS_CBMSG_CODGRP_GENERAL_DCS;
484             pDcs.codingScheme = (dcsData & 0x01) ? SMS_CODING_UCS2 : SMS_CODING_7BIT;
485             pDcs.langType = SMS_CBMSG_LANG_ISO639;
486             unsigned char hight = (iosData >> BYTE_BIT);
487             unsigned char low = iosData;
488             // from 3GPP TS 23.038 V4.3.0 (2001-09)  6.1.1 section Control characters
489             if (hight && low) {
490                 pDcs.iso639Lang[0x00] = hight & 0x7F;
491                 pDcs.iso639Lang[0x01] = (hight & 0X80) >> 0x07;
492                 pDcs.iso639Lang[0x01] |= (low & 0X3F) << 0x01;
493                 pDcs.iso639Lang[0x02] = 0x13; /* CR */
494             } else {
495                 pDcs.iso639Lang[0x00] = 0x45; /* E */
496                 pDcs.iso639Lang[0x01] = 0x4E; /* N */
497                 pDcs.iso639Lang[0x02] = 0x13; /* CR */
498             }
499             break;
500         }
501         default:
502             break;
503     }
504 }
505 
506 /**
507  * @brief DecodeGeneralDcs
508  *  from 3GPP TS 23.038 V4.3.0 (2001-09) 6 section
509  *  CBS Data Coding Scheme
510  * @param dcsData
511  * @param iosData
512  * @param pDcs
513  */
DecodeGeneralDcs(const unsigned char dcsData,SmsCbMessageDcs & pDcs) const514 void SmsCbMessage::DecodeGeneralDcs(const unsigned char dcsData, SmsCbMessageDcs &pDcs) const
515 {
516     pDcs.codingGroup = SMS_CBMSG_CODGRP_GENERAL_DCS;
517     pDcs.bCompressed = (dcsData & 0x20) ? true : false;
518     if (dcsData & 0x10) {
519         pDcs.classType = (dcsData & 0x03);
520     }
521     unsigned char tmpScheme = (dcsData & 0x0C) >> 0x02;
522     switch (tmpScheme) {
523         case 0x00:
524             pDcs.codingScheme = SMS_CODING_7BIT;
525             break;
526         case 0x01:
527             pDcs.codingScheme = SMS_CODING_8BIT;
528             break;
529         case 0x02:
530             pDcs.codingScheme = SMS_CODING_UCS2;
531             break;
532         default:
533             break;
534     }
535 }
536 
537 /**
538  * @brief DecodeCbMsgDCS
539  *  from 3GPP TS 23.038 V4.3.0 (2001-09) 6 section
540  *  CBS Data Coding Scheme
541  * @param dcsData
542  * @param iosData
543  * @param pDcs
544  */
DecodeCbMsgDCS(const unsigned char dcsData,const unsigned short iosData,SmsCbMessageDcs & pDcs) const545 void SmsCbMessage::DecodeCbMsgDCS(
546     const unsigned char dcsData, const unsigned short iosData, SmsCbMessageDcs &pDcs) const
547 {
548     pDcs.codingGroup = SMS_CBMSG_CODGRP_GENERAL_DCS;
549     pDcs.classType = SMS_CLASS_UNKNOWN;
550     pDcs.bCompressed = false;
551     pDcs.codingScheme = SMS_CODING_7BIT;
552     pDcs.langType = SMS_CBMSG_LANG_UNSPECIFIED;
553     (void)memset_s(pDcs.iso639Lang, sizeof(pDcs.iso639Lang), 0x00, sizeof(pDcs.iso639Lang));
554     pDcs.bUDH = false;
555     pDcs.rawData = dcsData;
556     unsigned char codingGroup = (dcsData & 0xF0) >> 0x04;
557     switch (codingGroup) {
558         case 0x00:
559         case 0x02:
560         case 0x03:
561             pDcs.codingGroup = SMS_CBMSG_CODGRP_GENERAL_DCS;
562             pDcs.langType = dcsData;
563             break;
564         case 0x01:
565             DecodeIos639Dcs(dcsData, iosData, pDcs);
566             break;
567         case 0x04:
568         case 0x05:
569         case 0x06:
570         case 0x07:
571             DecodeGeneralDcs(dcsData, pDcs);
572             break;
573         case 0x09:
574             pDcs.bUDH = true;
575             pDcs.classType = dcsData & 0x03;
576             pDcs.codingScheme = (dcsData & 0x0C) >> 0x02;
577             break;
578         case 0x0E:
579             pDcs.codingGroup = SMS_CBMSG_CODGRP_WAP;
580             break;
581         case 0x0F:
582             pDcs.codingGroup = SMS_CBMSG_CODGRP_CLASS_CODING;
583             pDcs.codingScheme = (dcsData & 0x04) ? SMS_CODING_8BIT : SMS_CODING_7BIT;
584             pDcs.classType = dcsData & 0x03;
585             break;
586         default:
587             TELEPHONY_LOGE("codingGrp: [0x%{public}x]", codingGroup);
588             break;
589     }
590 }
591 
GetRecvTime() const592 unsigned long SmsCbMessage::GetRecvTime() const
593 {
594     time_t recvTime = time(NULL);
595     return (unsigned long)recvTime;
596 }
597 
ToString() const598 std::string SmsCbMessage::ToString() const
599 {
600     if (cbHeader_ == nullptr) {
601         TELEPHONY_LOGE("cbHeader_ is nullptr");
602         return "SmsCbMessage Header nullptr";
603     }
604     std::string msgId("msgId:" + std::to_string(cbHeader_->msgId));
605     std::string langType("\nlangType:" + std::to_string(cbHeader_->langType));
606     std::string isEtwsMessage("\nisEtws:" + std::to_string(cbHeader_->bEtwsMessage));
607     std::string cbMsgType("\ncbMsgType:" + std::to_string(cbHeader_->cbMsgType));
608     std::string warningType("\nwarningType:" + std::to_string(cbHeader_->warningType));
609     std::string serialNum("\nserialNum: geoScope " + std::to_string(cbHeader_->serialNum.geoScope) +
610         "| updateNum " + std::to_string(cbHeader_->serialNum.updateNum) + "| msgCode " +
611         std::to_string(cbHeader_->serialNum.msgCode));
612     std::string page(
613         "\ntotalpage: " + std::to_string(cbHeader_->totalPages) + " page:" + std::to_string(cbHeader_->page));
614     std::string recvTime("\nrecvTime: " + std::to_string(cbHeader_->recvTime));
615     std::string dcsRaw("\ndcsRaw: " + std::to_string(cbHeader_->dcs.rawData));
616     std::string msgBody;
617     ConvertToUTF8(messageRaw_, msgBody);
618     return msgId.append(langType)
619         .append(isEtwsMessage)
620         .append(cbMsgType)
621         .append(warningType)
622         .append(serialNum)
623         .append(page)
624         .append(recvTime)
625         .append(dcsRaw)
626         .append("\nbody:")
627         .append(msgBody);
628 }
629 
GetFormat(int8_t & format) const630 bool SmsCbMessage::GetFormat(int8_t &format) const
631 {
632     if (cbHeader_ == nullptr) {
633         TELEPHONY_LOGE("cbHeader_ is nullptr");
634         return false;
635     }
636     constexpr uint8_t FORMAT_3GPP = 1;
637     format = FORMAT_3GPP;
638     return true;
639 }
640 
GetPriority(int8_t & priority) const641 bool SmsCbMessage::GetPriority(int8_t &priority) const
642 {
643     if (cbHeader_ == nullptr) {
644         TELEPHONY_LOGE("cbHeader_ is nullptr");
645         return false;
646     }
647     const uint16_t pwsFirstId = 0x1100;
648     const uint16_t pwsLastId = 0x18FF;
649     const int8_t SmsPriorityNormal = 0x00;
650     const int8_t SmsPriorityEmergency = 0x03;
651     if (cbHeader_->msgId >= pwsFirstId && cbHeader_->msgId <= pwsLastId) {
652         priority = SmsPriorityEmergency;
653     } else {
654         priority = SmsPriorityNormal;
655     }
656     return true;
657 }
658 
GetGeoScope(uint8_t & gs) const659 bool SmsCbMessage::GetGeoScope(uint8_t &gs) const
660 {
661     if (cbHeader_ == nullptr) {
662         TELEPHONY_LOGE("cbHeader_ is nullptr");
663         return false;
664     }
665     gs = cbHeader_->serialNum.geoScope;
666     return true;
667 }
668 
GetSerialNum(uint16_t & serial) const669 bool SmsCbMessage::GetSerialNum(uint16_t &serial) const
670 {
671     if (cbHeader_ == nullptr) {
672         TELEPHONY_LOGE("cbHeader_ is nullptr");
673         return false;
674     }
675     serial = ((cbHeader_->serialNum.geoScope & 0x03) << 0x0E) |
676         ((cbHeader_->serialNum.msgCode & 0x03FF) << 0x04) | (cbHeader_->serialNum.updateNum & 0x0F);
677     return true;
678 }
679 
GetServiceCategory(uint16_t & category) const680 bool SmsCbMessage::GetServiceCategory(uint16_t &category) const
681 {
682     if (cbHeader_ == nullptr) {
683         TELEPHONY_LOGE("cbHeader_ is nullptr");
684         return false;
685     }
686     category = cbHeader_->msgId;
687     return true;
688 }
689 
GetWarningType(uint16_t & warnType) const690 bool SmsCbMessage::GetWarningType(uint16_t &warnType) const
691 {
692     if (cbHeader_ == nullptr) {
693         TELEPHONY_LOGE("cbHeader_ is nullptr");
694         return false;
695     }
696     warnType = cbHeader_->warningType;
697     return true;
698 }
699 
IsEtwsPrimary(bool & isPrimary) const700 bool SmsCbMessage::IsEtwsPrimary(bool &isPrimary) const
701 {
702     if (cbHeader_ == nullptr) {
703         TELEPHONY_LOGE("cbHeader_ is nullptr");
704         return false;
705     }
706     isPrimary = (cbHeader_->cbEtwsType == SMS_NETTEXT_ETWS_PRIMARY);
707     return true;
708 }
709 
IsEtwsMessage(bool & isEtws) const710 bool SmsCbMessage::IsEtwsMessage(bool &isEtws) const
711 {
712     if (cbHeader_ == nullptr) {
713         TELEPHONY_LOGE("cbHeader_ is nullptr");
714         return false;
715     }
716     const uint16_t etwsType = 0x1100;
717     const uint16_t etwsTypeMask = 0xFFF8;
718     isEtws = ((cbHeader_->msgId & etwsTypeMask) == etwsType);
719     return true;
720 }
721 
IsCmasMessage(bool & isCmas) const722 bool SmsCbMessage::IsCmasMessage(bool &isCmas) const
723 {
724     if (cbHeader_ == nullptr) {
725         TELEPHONY_LOGE("cbHeader_ is nullptr");
726         return false;
727     }
728     const uint16_t cmasFirstId = 0x1112;
729     const uint16_t cmasLastId = 0x112F;
730     isCmas = ((cbHeader_->msgId >= cmasFirstId) && (cbHeader_->msgId <= cmasLastId));
731     return true;
732 }
733 
IsEtwsEmergencyUserAlert(bool & isUserAlert) const734 bool SmsCbMessage::IsEtwsEmergencyUserAlert(bool &isUserAlert) const
735 {
736     uint16_t serial = 0;
737     if (!GetSerialNum(serial)) {
738         TELEPHONY_LOGE("Get serial num fail.");
739         return false;
740     }
741     const uint16_t emergencyUserAlert = 0x2000;
742     isUserAlert = ((serial & emergencyUserAlert) != 0);
743     return true;
744 }
745 
IsEtwsPopupAlert(bool & isPopupAlert) const746 bool SmsCbMessage::IsEtwsPopupAlert(bool &isPopupAlert) const
747 {
748     uint16_t serial = 0;
749     if (!GetSerialNum(serial)) {
750         TELEPHONY_LOGE("Get serial num fail.");
751         return false;
752     }
753     const uint16_t etwsPopup = 0x1000;
754     isPopupAlert = ((serial & etwsPopup) != 0);
755     return true;
756 }
757 
GetCmasSeverity(int8_t & severity) const758 bool SmsCbMessage::GetCmasSeverity(int8_t &severity) const
759 {
760     uint16_t msgId = 0;
761     if (!GetMessageId(msgId)) {
762         TELEPHONY_LOGE("Get message id fail.");
763         return false;
764     }
765     switch (static_cast<SmsCmasMessageType>(msgId)) {
766         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_DEFUALT:
767         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_SPANISH:
768         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_DEFUALT:
769         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_SPANISH:
770         case SmsCmasMessageType::CMAS_SERVER_EXTERME_OBSERVED_DEFUALT:
771         case SmsCmasMessageType::CMAS_SERVER_EXTREME_OBSERVED_SPANISH:
772         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_DEFUALT:
773         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_SPANISH:
774             severity = SMS_CMAE_SEVERITY_EXTREME;
775             break;
776         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_DEFUALT:
777         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_SPANISH:
778         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_DEFUALT:
779         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_SPANISH:
780         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_DEFUALT:
781         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_SPANISH:
782         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_DEFUALT:
783         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_SPANISH:
784             severity =  SMS_CMAE_SEVERITY_SEVERE;
785             break;
786         default:
787             severity = SMS_CMAE_SEVERITY_RESERVED;
788             break;
789     }
790     return true;
791 }
792 
GetCmasUrgency(int8_t & urgency) const793 bool SmsCbMessage::GetCmasUrgency(int8_t &urgency) const
794 {
795     uint16_t msgId = 0;
796     if (!GetMessageId(msgId)) {
797         TELEPHONY_LOGE("Get message id fail.");
798         return false;
799     }
800     switch (static_cast<SmsCmasMessageType>(msgId)) {
801         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_DEFUALT:
802         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_SPANISH:
803         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_DEFUALT:
804         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_SPANISH:
805         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_DEFUALT:
806         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_SPANISH:
807         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_DEFUALT:
808         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_SPANISH:
809             urgency = SMS_CMAE_URGENCY_IMMEDIATE;
810             break;
811         case SmsCmasMessageType::CMAS_SERVER_EXTERME_OBSERVED_DEFUALT:
812         case SmsCmasMessageType::CMAS_SERVER_EXTREME_OBSERVED_SPANISH:
813         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_DEFUALT:
814         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_SPANISH:
815         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_DEFUALT:
816         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_SPANISH:
817         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_DEFUALT:
818         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_SPANISH:
819             urgency = SMS_CMAE_URGENCY_EXPECTED;
820             break;
821         default:
822             urgency = SMS_CMAE_URGENCY_RESERVED;
823             break;
824     }
825     return true;
826 }
827 
GetCmasCertainty(int8_t & certainty) const828 bool SmsCbMessage::GetCmasCertainty(int8_t &certainty) const
829 {
830     uint16_t msgId = 0;
831     if (!GetMessageId(msgId)) {
832         TELEPHONY_LOGE("Get message id fail.");
833         return false;
834     }
835     switch (static_cast<SmsCmasMessageType>(msgId)) {
836         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_DEFUALT:
837         case SmsCmasMessageType::CMAS_EXTREME_OBSERVED_SPANISH:
838         case SmsCmasMessageType::CMAS_SERVER_EXTERME_OBSERVED_DEFUALT:
839         case SmsCmasMessageType::CMAS_SERVER_EXTREME_OBSERVED_SPANISH:
840         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_DEFUALT:
841         case SmsCmasMessageType::CMAS_SERVER_SERVER_OBSERVED_SPANISH:
842         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_DEFUALT:
843         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_OBSERVED_SPANISH:
844             certainty = SMS_CMAE_CERTAINTY_OBSERVED;
845             break;
846         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_DEFUALT:
847         case SmsCmasMessageType::CMAS_EXTREME_LIKELY_SPANISH:
848         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_DEFUALT:
849         case SmsCmasMessageType::CMAS_SERVER_EXTERME_LIKELY_SPANISH:
850         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_DEFUALT:
851         case SmsCmasMessageType::CMAS_SERVER_SERVER_LIKELY_SPANISH:
852         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_DEFUALT:
853         case SmsCmasMessageType::CMAS_SERVER_SERVER_EXPECTED_LIKELY_SPANISH:
854             certainty = SMS_CMAE_CERTAINTY_LIKELY;
855             break;
856         default:
857             certainty = SMS_CMAE_CERTAINTY_RESERVED;
858             break;
859     }
860     return true;
861 }
862 
GetCmasCategory(int8_t & cmasCategory) const863 bool SmsCbMessage::GetCmasCategory(int8_t &cmasCategory) const
864 {
865     if (cbHeader_ == nullptr) {
866         TELEPHONY_LOGE("cbHeader_ is nullptr");
867         return false;
868     }
869     cmasCategory = SMS_CMAE_CTG_RESERVED;
870     return true;
871 }
872 
GetCmasResponseType(int8_t & cmasRes) const873 bool SmsCbMessage::GetCmasResponseType(int8_t &cmasRes) const
874 {
875     if (cbHeader_ == nullptr) {
876         TELEPHONY_LOGE("cbHeader_ is nullptr");
877         return false;
878     }
879     cmasRes = SMS_CMAE_RESP_TYPE_RESERVED;
880     return true;
881 }
882 
GetMessageId(uint16_t & msgId) const883 bool SmsCbMessage::GetMessageId(uint16_t &msgId) const
884 {
885     if (cbHeader_ == nullptr) {
886         TELEPHONY_LOGE("cbHeader_ is nullptr");
887         return false;
888     }
889     msgId = cbHeader_->msgId;
890     return true;
891 }
892 
GetCmasMessageClass(int8_t & cmasClass) const893 bool SmsCbMessage::GetCmasMessageClass(int8_t &cmasClass) const
894 {
895     uint16_t msgId = 0;
896     if (!GetMessageId(msgId)) {
897         TELEPHONY_LOGE("Get message id fail.");
898         return false;
899     }
900     cmasClass = CMASClass(msgId);
901     return true;
902 }
903 
GetMsgType(uint8_t & msgType) const904 bool SmsCbMessage::GetMsgType(uint8_t &msgType) const
905 {
906     if (cbHeader_ == nullptr) {
907         TELEPHONY_LOGE("cbHeader_ is nullptr");
908         return false;
909     }
910     msgType = cbHeader_->cbMsgType;
911     return true;
912 }
913 
GetLangType(uint8_t & lan) const914 bool SmsCbMessage::GetLangType(uint8_t &lan) const
915 {
916     if (cbHeader_ == nullptr) {
917         TELEPHONY_LOGE("cbHeader_ is nullptr");
918         return false;
919     }
920     lan = cbHeader_->langType;
921     return true;
922 }
923 
GetDcs(uint8_t & dcs) const924 bool SmsCbMessage::GetDcs(uint8_t &dcs) const
925 {
926     if (cbHeader_ == nullptr) {
927         TELEPHONY_LOGE("cbHeader_ is nullptr");
928         return false;
929     }
930     dcs = cbHeader_->dcs.codingScheme;
931     return true;
932 }
933 
GetReceiveTime(long & recvTime) const934 bool SmsCbMessage::GetReceiveTime(long &recvTime) const
935 {
936     if (cbHeader_ == nullptr) {
937         TELEPHONY_LOGE("cbHeader_ is nullptr");
938         return false;
939     }
940     recvTime = cbHeader_->recvTime;
941     return true;
942 }
943 } // namespace Telephony
944 } // namespace OHOS