blob: 771e861466cc6e4c0ab95c73a51cb899d0929f7d [file] [log] [blame]
/*
* 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;
}