1/*
2 * Copyright (C) 2023 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
16#include "sms_common_utils.h"
17
18#include <ctime>
19#include "securec.h"
20#include "telephony_log_wrapper.h"
21
22namespace OHOS {
23namespace Telephony {
24static constexpr uint8_t SMS_ENCODE_GSM_BIT = 7;
25static constexpr uint8_t MAX_GSM_7BIT_DATA_LEN = 160;
26static constexpr uint8_t SMS_BYTE_BIT = 8;
27static constexpr uint16_t SEC_PER_HOUR = 3600;
28static constexpr uint8_t BASE_GSM_YEAR = 100;
29static constexpr uint8_t MAX_ABS_TIME_LEN = 32;
30static constexpr uint8_t HEX_NUM_A = 0x0A;
31static constexpr uint8_t HEX_NUM_B = 0x0B;
32static constexpr uint8_t HEX_NUM_C = 0x0C;
33static constexpr uint8_t MIN_PRINTABLE_CHAR = 32;
34static constexpr uint8_t MAX_PRINTABLE_CHAR = 127;
35
36uint16_t SmsCommonUtils::Pack7bitChar(
37    const uint8_t *userData, uint16_t dataLen, uint8_t fillBits, uint8_t *packData, uint16_t packLen)
38{
39    uint16_t dstIdx = 0;
40    if (userData == nullptr || packData == nullptr || dataLen > MAX_GSM_7BIT_DATA_LEN) {
41        TELEPHONY_LOGE("userData error.");
42        return dstIdx;
43    }
44
45    auto shift = fillBits;
46    if (shift > 0) {
47        dstIdx = 1;
48    }
49    uint16_t srcIdx = 0;
50    while (srcIdx < dataLen && dstIdx < packLen) {
51        if (shift == 0) {
52            packData[dstIdx] = userData[srcIdx];
53            shift = SMS_ENCODE_GSM_BIT;
54            srcIdx++;
55            dstIdx++;
56            if (srcIdx >= dataLen) {
57                break;
58            }
59        }
60        if (shift > 1) {
61            packData[dstIdx - 1] |= userData[srcIdx] << shift;
62            packData[dstIdx] = userData[srcIdx] >> (SMS_BYTE_BIT - shift);
63            srcIdx++;
64            dstIdx++;
65            shift--;
66        } else if (shift == 1) {
67            packData[dstIdx - 1] |= userData[srcIdx] << shift;
68            shift--;
69            srcIdx++;
70        }
71    }
72    return dstIdx;
73}
74
75uint16_t SmsCommonUtils::Unpack7bitChar(
76    const uint8_t *tpdu, uint16_t dataLen, uint8_t fillBits, uint8_t *unpackData, uint16_t unpackDataLen)
77{
78    uint16_t srcIdx = 0;
79    uint16_t dstIdx = 0;
80    auto shift = fillBits;
81    if (unpackData == nullptr || tpdu == nullptr || dataLen == 0 || unpackDataLen == 0 || dataLen > unpackDataLen) {
82        TELEPHONY_LOGE("userData error.");
83        return dstIdx;
84    }
85    if (shift > 0) {
86        srcIdx = 1;
87    }
88    for (; srcIdx < dataLen && dstIdx < unpackDataLen; dstIdx++) {
89        if (shift == 0) {
90            unpackData[dstIdx] = tpdu[srcIdx] & 0x7F;
91            shift = SMS_ENCODE_GSM_BIT;
92            srcIdx++;
93            dstIdx++;
94            if (dstIdx >= dataLen) {
95                dstIdx--;
96                break;
97            }
98        }
99        if (shift > 0 && srcIdx < dataLen && dstIdx < unpackDataLen) {
100            unpackData[dstIdx] = ((unsigned int)tpdu[srcIdx - 1] >> shift) + (tpdu[srcIdx] << (SMS_BYTE_BIT - shift));
101            unpackData[dstIdx] &= 0x7F;
102            shift--;
103            if (shift > 0) {
104                srcIdx++;
105            }
106        }
107    }
108    return dstIdx;
109}
110
111uint16_t SmsCommonUtils::Unpack7bitCharForCBPdu(
112    const uint8_t *tpdu, uint16_t dataLen, uint8_t fillBits, uint8_t *unpackData, uint16_t unpackDataLen)
113{
114    uint16_t srcIdx = 0;
115    uint16_t dstIdx = 0;
116    auto shift = fillBits;
117    if (unpackData == nullptr || tpdu == nullptr || dataLen == 0 || unpackDataLen == 0 || dataLen > unpackDataLen) {
118        TELEPHONY_LOGE("userData error.");
119        return dstIdx;
120    }
121    if (shift > 0) {
122        srcIdx = 1;
123    }
124    for (; srcIdx < dataLen && dstIdx < unpackDataLen;) {
125        if (shift == 0) {
126            unpackData[dstIdx] = tpdu[srcIdx] & 0x7F;
127            shift = SMS_ENCODE_GSM_BIT;
128            srcIdx++;
129            dstIdx++;
130        }
131        if (shift > 0 && srcIdx < dataLen && dstIdx < unpackDataLen) {
132            unpackData[dstIdx] = ((unsigned int)tpdu[srcIdx - 1] >> shift) + (tpdu[srcIdx] << (SMS_BYTE_BIT - shift));
133            unpackData[dstIdx] &= 0x7F;
134            shift--;
135            if (shift > 0) {
136                srcIdx++;
137            }
138            dstIdx++;
139        }
140    }
141    if (dstIdx >= unpackDataLen) {
142        TELEPHONY_LOGE("dstIdx:%{public}d", dstIdx);
143        return 0;
144    }
145    uint8_t value = 0;
146    if (shift == 0) {
147        value = tpdu[srcIdx] >> shift;
148    } else if (srcIdx > 1) {
149        value = tpdu[srcIdx - 1] >> shift;
150    }
151    if (value >= MIN_PRINTABLE_CHAR && value <= MAX_PRINTABLE_CHAR) {
152        unpackData[dstIdx] = value;
153        dstIdx++;
154    }
155    TELEPHONY_LOGI("dstIdx:%{public}d", dstIdx);
156    return dstIdx;
157}
158
159uint8_t SmsCommonUtils::DigitToDtmfChar(const uint8_t c)
160{
161    if (c == '0') {
162        return HEX_NUM_A;
163    } else if (c == '*') {
164        return HEX_NUM_B;
165    } else if (c == '#') {
166        return HEX_NUM_C;
167    } else {
168        return (c - '0');
169    }
170}
171
172uint8_t SmsCommonUtils::DtmfCharToDigit(const uint8_t c)
173{
174    switch (c) {
175        case HEX_NUM_B:
176            return '*';
177        case HEX_NUM_C:
178            return '#';
179        case HEX_NUM_A:
180            return '0';
181        default:
182            return (c + '0');
183    }
184}
185
186int64_t SmsCommonUtils::ConvertTime(const struct SmsTimeAbs &timeAbs)
187{
188    time_t rawtime;
189    struct tm tmObj;
190    if (memset_s(&tmObj, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
191        return time(nullptr);
192    }
193    tmObj.tm_year = (timeAbs.year + BASE_GSM_YEAR);
194    tmObj.tm_mon = (timeAbs.month - 0x01);
195    tmObj.tm_mday = timeAbs.day;
196    tmObj.tm_hour = timeAbs.hour;
197    tmObj.tm_min = timeAbs.minute;
198    tmObj.tm_sec = timeAbs.second;
199    tmObj.tm_isdst = 0;
200    rawtime = mktime(&tmObj);
201    GetDisplayTime(rawtime);
202    rawtime -= (timeAbs.timeZone * (SEC_PER_HOUR / 0x04));
203    GetDisplayTime(rawtime);
204    /* timezone value is tiemzone + daylight. So should not add daylight */
205    rawtime -= timezone;
206    GetDisplayTime(rawtime);
207    return rawtime;
208}
209
210void SmsCommonUtils::GetDisplayTime(const time_t &rawtime)
211{
212    struct tm tmObj;
213    char displayTime[MAX_ABS_TIME_LEN];
214    if (memset_s(&tmObj, sizeof(struct tm), 0x00, sizeof(tm)) != EOK) {
215        TELEPHONY_LOGE("GetDisplayTime memset fail.");
216        return;
217    }
218
219    if (memset_s(displayTime, sizeof(displayTime), 0x00, sizeof(displayTime)) != EOK) {
220        TELEPHONY_LOGE("GetDisplayTime memset fail.");
221        return;
222    }
223
224    localtime_r(&rawtime, &tmObj);
225    if (strftime(displayTime, MAX_ABS_TIME_LEN, "%Y-%02m-%02d %T %z", &tmObj) <= 0) {
226        TELEPHONY_LOGE("strftime error.");
227        return;
228    }
229}
230} // namespace Telephony
231} // namespace OHOS
232