| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <memory> |
| #include <iostream> |
| #include <numeric> |
| using namespace std; |
| |
| #include <log/log.h> |
| |
| #include "SmsMessage.h" |
| #include "BearerData.h" |
| #include "HexDump.h"; |
| |
| #undef LOG_TAG |
| #define LOG_TAG "DEMO_CDMA_SMS" |
| |
| uint32_t SmsMessage::mPos = 0; |
| SmsMessage::SmsMessage(std::shared_ptr<SmsAddress> addr,std::shared_ptr<SmsEnvelope> env) { |
| mOriginatingAddress = addr; |
| mEnvelope = env; |
| createPdu(); |
| } |
| |
| SmsMessage::SmsMessage() { |
| // TODO Auto-generated constructor stub |
| |
| } |
| |
| SmsMessage::~SmsMessage() { |
| // TODO Auto-generated destructor stub |
| } |
| |
| uint8_t SmsMessage::convertDtmfToAscii(uint8_t dtmfDigit) { |
| uint8_t asciiDigit; |
| |
| switch (dtmfDigit) { |
| case 0: |
| asciiDigit = 68; |
| break; // 'D' |
| case 1: |
| asciiDigit = 49; |
| break; // '1' |
| case 2: |
| asciiDigit = 50; |
| break; // '2' |
| case 3: |
| asciiDigit = 51; |
| break; // '3' |
| case 4: |
| asciiDigit = 52; |
| break; // '4' |
| case 5: |
| asciiDigit = 53; |
| break; // '5' |
| case 6: |
| asciiDigit = 54; |
| break; // '6' |
| case 7: |
| asciiDigit = 55; |
| break; // '7' |
| case 8: |
| asciiDigit = 56; |
| break; // '8' |
| case 9: |
| asciiDigit = 57; |
| break; // '9' |
| case 10: |
| asciiDigit = 48; |
| break; // '0' |
| case 11: |
| asciiDigit = 42; |
| break; // '*' |
| case 12: |
| asciiDigit = 35; |
| break; // '#' |
| case 13: |
| asciiDigit = 65; |
| break; // 'A' |
| case 14: |
| asciiDigit = 66; |
| break; // 'B' |
| case 15: |
| asciiDigit = 67; |
| break; // 'C' |
| default: |
| asciiDigit = 32; // Invalid DTMF code |
| break; |
| } |
| |
| return asciiDigit; |
| } |
| |
| void SmsMessage::writeInt(uint32_t data) { |
| mPdu.push_back((data >> 24) & 0xFF); |
| mPdu.push_back((data >> 16) & 0xFF); |
| mPdu.push_back((data >> 8) & 0xFF); |
| mPdu.push_back((data >> 0) & 0xFF); |
| } |
| |
| uint32_t SmsMessage::readInt(std::vector<uint8_t> pdu) { |
| uint32_t temp = 0; |
| temp = (pdu[mPos++] << 24) & 0xFF000000; |
| temp |= (pdu[mPos++] << 16) & 0xFF0000; |
| temp |= (pdu[mPos++] << 8) & 0xFF00; |
| temp |= (pdu[mPos++] << 0) & 0xFF; |
| return temp; |
| } |
| |
| void SmsMessage::writeVector(std::vector<uint8_t> v) { |
| mPdu.insert(mPdu.end(), v.begin(), v.end()); |
| } |
| |
| std::vector<uint8_t> SmsMessage::readVector(std::vector<uint8_t> v, |
| int length) { |
| std::vector<uint8_t> temp; |
| temp.insert(temp.end(), v.begin() + mPos, v.begin() + mPos + length); |
| mPos += length; |
| return temp; |
| } |
| |
| void SmsMessage::writeByte(uint8_t data) { |
| mPdu.push_back(data); |
| } |
| |
| uint8_t SmsMessage::readByte(std::vector<uint8_t> pdu) { |
| return mPdu[mPos++]; |
| } |
| |
| void SmsMessage::createPdu() { |
| auto env = mEnvelope; |
| auto addr = env->origAddress; |
| //ByteArrayOutputStream baos = new ByteArrayOutputStream(100); |
| //DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); |
| |
| writeInt(env->messageType); |
| writeInt(env->teleService); |
| writeInt(env->serviceCategory); |
| |
| writeByte(addr->digitMode); |
| writeByte(addr->numberMode); |
| writeByte(addr->ton); |
| writeByte(addr->numberPlan); |
| writeByte(addr->numberOfDigits); |
| writeVector(addr->origBytes); // digits |
| |
| writeInt(env->bearerReply); |
| // CauseCode values: |
| writeByte(env->replySeqNo); |
| writeByte(env->errorClass); |
| writeByte(env->causeCode); |
| //encoded BearerData: |
| writeInt(env->bearerData.size()); |
| writeVector(env->bearerData); |
| } |
| |
| void SmsMessage::parsePdu(std::vector<uint8_t> pdu) { |
| int length; |
| int bearerDataLength; |
| auto env = std::make_shared<SmsEnvelope>(); |
| auto addr = std::make_shared<CdmaSmsAddress>(); |
| // We currently do not parse subaddress in PDU, but it is required when determining |
| // fingerprint (see getIncomingSmsFingerprint()). |
| auto subaddr = std::make_shared<CdmaSmsSubaddress>(); |
| mPos = 0; |
| env->messageType = readInt(pdu); |
| env->teleService = readInt(pdu); |
| env->serviceCategory = readInt(pdu); |
| |
| addr->digitMode = readByte(pdu); |
| addr->numberMode = readByte(pdu); |
| addr->ton = readByte(pdu); |
| addr->numberPlan = readByte(pdu); |
| |
| length = readByte(pdu); |
| addr->numberOfDigits = length; |
| |
| // sanity check on the length |
| if (length > pdu.size()) { |
| throw runtime_error( |
| "createFromPdu: Invalid pdu, addr.numberOfDigits " |
| + std::to_string(length) + " > pdu len " |
| + std::to_string(pdu.size())); |
| } |
| addr->origBytes = readVector(pdu, length); // digits |
| env->bearerReply = readInt(pdu); |
| // CauseCode values: |
| env->replySeqNo = readByte(pdu); |
| env->errorClass = readByte(pdu); |
| env->causeCode = readByte(pdu); |
| |
| //encoded BearerData: |
| bearerDataLength = readInt(pdu); |
| // sanity check on the length |
| if (bearerDataLength > pdu.size()) { |
| throw runtime_error( |
| "createFromPdu: Invalid pdu, bearerDataLength " |
| + std::to_string(bearerDataLength) + " > pdu len " |
| + std::to_string(pdu.size())); |
| } |
| env->bearerData = readVector(pdu, bearerDataLength); |
| mPos = 0; // reset |
| // link the filled objects to this SMS |
| mOriginatingAddress = addr; |
| env->origAddress = addr; |
| env->origSubaddress = subaddr; |
| mEnvelope = env; |
| mPdu = pdu; |
| |
| parseSms(); |
| } |
| std::shared_ptr<SmsMessage> SmsMessage::createFromPdu( |
| std::vector<uint8_t> pdu) { |
| shared_ptr<SmsMessage> msg = make_shared<SmsMessage>(); |
| |
| msg->parsePdu(pdu); |
| return msg; |
| // try { |
| // } catch (RuntimeException ex) { |
| // Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex); |
| // return null; |
| // } catch (OutOfMemoryError e) { |
| // Log.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e); |
| // return null; |
| // } |
| } |
| |
| SmsConstants::MessageClass SmsMessage::getMessageClass() { |
| if (BearerData::DISPLAY_MODE_IMMEDIATE == mBearerData->displayMode) { |
| return SmsConstants::MessageClass::CLASS_0; |
| } else { |
| return SmsConstants::MessageClass::UNKNOWN; |
| } |
| } |
| |
| int SmsMessage::getMessageType() { |
| // NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs. |
| // Use the service category parameter to detect CMAS and other cell broadcast messages. |
| if (mEnvelope->serviceCategory != 0) { |
| return SmsEnvelope::MESSAGE_TYPE_BROADCAST; |
| } else { |
| return SmsEnvelope::MESSAGE_TYPE_POINT_TO_POINT; |
| } |
| } |
| |
| /** |
| * Note: This function is a GSM specific functionality which is not supported in CDMA mode. |
| */ |
| int SmsMessage::getProtocolIdentifier() { |
| //Rlog.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode."); |
| // (3GPP TS 23.040): "no interworking, but SME to SME protocol": |
| return 0; |
| } |
| |
| /** |
| * Note: This function is a GSM specific functionality which is not supported in CDMA mode. |
| */ |
| bool SmsMessage::isReplace() { |
| //Rlog.w(LOG_TAG, "isReplace: is not supported in CDMA mode."); |
| return false; |
| } |
| |
| /** |
| * Note: This function is a GSM specific functionality which is not supported in CDMA mode. |
| */ |
| bool SmsMessage::isCphsMwiMessage() { |
| //Rlog.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode."); |
| return false; |
| } |
| |
| bool SmsMessage::isMWIClearMessage() { |
| return ((mBearerData != nullptr) && (mBearerData->numberOfMessages == 0)); |
| } |
| |
| bool SmsMessage::isMWISetMessage() { |
| return ((mBearerData != nullptr) && (mBearerData->numberOfMessages > 0)); |
| } |
| |
| bool SmsMessage::isMwiDontStore() { |
| return ((mBearerData != nullptr) && (mBearerData->numberOfMessages > 0) |
| && (mBearerData->userData == nullptr)); |
| } |
| |
| /** |
| * Returns the status for a previously submitted message. |
| * For not interfering with status codes from GSM, this status code is |
| * shifted to the bits 31-16. |
| */ |
| int SmsMessage::getStatus() { |
| return (status << 16); |
| } |
| |
| /** Return true iff the bearer data message type is DELIVERY_ACK. */ |
| bool SmsMessage::isStatusReportMessage() { |
| return (mBearerData->messageType == BearerData::MESSAGE_TYPE_DELIVERY_ACK); |
| } |
| |
| /** |
| * Note: This function is a GSM specific functionality which is not supported in CDMA mode. |
| */ |
| bool SmsMessage::isReplyPathPresent() { |
| //Rlog.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode."); |
| return false; |
| } |
| void SmsMessage::parseSms() { |
| // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6 |
| // It contains only an 8-bit number with the number of messages waiting |
| if (mEnvelope->teleService == SmsEnvelope::TELESERVICE_MWI) { |
| mBearerData = make_shared<BearerData>(); |
| if (mEnvelope->bearerData.empty()) { |
| mBearerData->numberOfMessages = 0x000000FF & mEnvelope->bearerData[0]; |
| } |
| std::cout << "parseSms: get MWI " << mBearerData->numberOfMessages << endl; |
| /* if (VDBG) { |
| Rlog.d(LOG_TAG, "parseSms: get MWI " + |
| Integer.toString(mBearerData.numberOfMessages)); |
| }*/ |
| return; |
| } |
| mBearerData = BearerData::decode(mEnvelope->bearerData); |
| RLOGD("MT raw BearerData = '%s'", (HexDump::toHexString(mEnvelope->bearerData)).c_str()); |
| RLOGD("MT raw BearerData = '%s'",(mBearerData->toString()).c_str()); |
| //std::cout << "MT raw BearerData = '" |
| // << HexDump::toHexString(mEnvelope->bearerData) << "'" << endl; |
| //std::cout << "MT (decoded) BearerData = " << mBearerData->toString() << endl; |
| // if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) { |
| // Rlog.d(LOG_TAG, "MT raw BearerData = '" + |
| // HexDump.toHexString(mEnvelope.bearerData) + "'"); |
| // Rlog.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData); |
| // } |
| mMessageRef = mBearerData->messageId; |
| if (mBearerData->userData != nullptr) { |
| mUserData = mBearerData->userData->payload; |
| mUserDataHeader = mBearerData->userData->userDataHeader; |
| mMessageBody = mBearerData->userData->payloadStr; |
| } |
| |
| if (mOriginatingAddress != nullptr) { |
| for(auto c: mOriginatingAddress->origBytes) { |
| mOriginatingAddress->address.push_back(c); |
| } |
| //std::accumulate(mOriginatingAddress->origBytes.begin(), mOriginatingAddress->origBytes.end(), mOriginatingAddress->address); |
| //mOriginatingAddress->address = HexDump::toHexString(mOriginatingAddress->origBytes); // modify |
| if (mOriginatingAddress->ton == CdmaSmsAddress::TON_INTERNATIONAL_OR_IP) { |
| if (mOriginatingAddress->address.at(0) != '+') { |
| mOriginatingAddress->address = "+" + mOriginatingAddress->address; |
| } |
| } |
| //std::cout << "SMS originating address: " << mOriginatingAddress->address<< endl; |
| // if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: " |
| // + mOriginatingAddress.address); |
| } |
| |
| //if (mBearerData->msgCenterTimeStamp != nullptr) { |
| //mScTimeMillis = mBearerData->msgCenterTimeStamp.toMillis(true); |
| //} |
| |
| //if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis); |
| |
| // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1) |
| if (mBearerData->messageType == BearerData::MESSAGE_TYPE_DELIVERY_ACK) { |
| // The BearerData MsgStatus subparameter should only be |
| // included for DELIVERY_ACK messages. If it occurred for |
| // other messages, it would be unclear what the status |
| // being reported refers to. The MsgStatus subparameter |
| // is primarily useful to indicate error conditions -- a |
| // message without this subparameter is assumed to |
| // indicate successful delivery (status == 0). |
| if (!mBearerData->messageStatusSet) { |
| std::cout << "DELIVERY_ACK message without msgStatus (" |
| << (mUserData.empty() ? "also missing" : "does have") << " userData)." |
| << endl; |
| // Rlog.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" + |
| // (mUserData == null ? "also missing" : "does have") + |
| // " userData)."); |
| status = 0; |
| } else { |
| status = mBearerData->errorClass << 8; |
| status |= mBearerData->messageStatus; |
| } |
| } else if (mBearerData->messageType != BearerData::MESSAGE_TYPE_DELIVER) { |
| throw runtime_error( |
| "Unsupported message type: " + mBearerData->messageType); |
| } |
| |
| if (!mMessageBody.empty()) { |
| //std::cout << "SMS message body: '" << mMessageBody << "'" << endl; |
| //if (VDBG) Rlog.v(LOG_TAG, "SMS message body: '" + mMessageBody + "'"); |
| parseMessageBody(); |
| } |
| } |
| |
| std::vector<std::uint8_t> SmsMessage::getIncomingSmsFingerprint() { |
| RLOGD("getIncomingSmsFingerprint: category=%d, teleservices=%d", mEnvelope->serviceCategory, mEnvelope->teleService); |
| std::vector<uint8_t> output; |
| output.push_back(static_cast<uint8_t> (mEnvelope->serviceCategory)); |
| output.push_back(static_cast<uint8_t> (mEnvelope->teleService)); |
| output.insert(output.end(), (mEnvelope->origAddress->origBytes).begin(), (mEnvelope->origAddress->origBytes).end()); |
| output.insert(output.end(), (mEnvelope->bearerData).begin(), (mEnvelope->bearerData).end()); |
| if(mEnvelope->origSubaddress && (!(mEnvelope->origSubaddress->origBytes).empty())) { |
| output.insert(output.end(), (mEnvelope->origSubaddress->origBytes).begin(), (mEnvelope->origSubaddress->origBytes).end()); |
| } |
| return output; |
| } |