use of com.google.android.mms.pdu.PduParser in project android-aosp-mms by slvn.
the class SendTransaction method run.
public void run() {
try {
RateController rateCtlr = RateController.getInstance();
if (rateCtlr.isLimitSurpassed() && !rateCtlr.isAllowedByUser()) {
Log.e(TAG, "Sending rate limit surpassed.");
return;
}
// Load M-Send.req from outbox
PduPersister persister = PduPersister.getPduPersister(mContext);
SendReq sendReq = (SendReq) persister.load(mSendReqURI);
// Update the 'date' field of the PDU right before sending it.
long date = System.currentTimeMillis() / 1000L;
sendReq.setDate(date);
// Persist the new date value into database.
ContentValues values = new ContentValues(1);
values.put(Mms.DATE, date);
SqliteWrapper.update(mContext, mContext.getContentResolver(), mSendReqURI, values, null, null);
// fix bug 2100169: insert the 'from' address per spec
String lineNumber = MessageUtils.getLocalNumber();
if (!TextUtils.isEmpty(lineNumber)) {
sendReq.setFrom(new EncodedStringValue(lineNumber));
}
// Pack M-Send.req, send it, retrieve confirmation data, and parse it
long tokenKey = ContentUris.parseId(mSendReqURI);
byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), new PduComposer(mContext, sendReq).make());
SendingProgressTokenManager.remove(tokenKey);
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
String respStr = new String(response);
Log.d(TAG, "[SendTransaction] run: send mms msg (" + mId + "), resp=" + respStr);
}
SendConf conf = (SendConf) new PduParser(response).parse();
if (conf == null) {
Log.e(TAG, "No M-Send.conf received.");
}
// Check whether the responding Transaction-ID is consistent
// with the sent one.
byte[] reqId = sendReq.getTransactionId();
byte[] confId = conf.getTransactionId();
if (!Arrays.equals(reqId, confId)) {
Log.e(TAG, "Inconsistent Transaction-ID: req=" + new String(reqId) + ", conf=" + new String(confId));
return;
}
// From now on, we won't save the whole M-Send.conf into
// our database. Instead, we just save some interesting fields
// into the related M-Send.req.
values = new ContentValues(2);
int respStatus = conf.getResponseStatus();
values.put(Mms.RESPONSE_STATUS, respStatus);
if (respStatus != PduHeaders.RESPONSE_STATUS_OK) {
SqliteWrapper.update(mContext, mContext.getContentResolver(), mSendReqURI, values, null, null);
Log.e(TAG, "Server returned an error code: " + respStatus);
return;
}
String messageId = PduPersister.toIsoString(conf.getMessageId());
values.put(Mms.MESSAGE_ID, messageId);
SqliteWrapper.update(mContext, mContext.getContentResolver(), mSendReqURI, values, null, null);
// Move M-Send.req from Outbox into Sent.
Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI);
mTransactionState.setState(TransactionState.SUCCESS);
mTransactionState.setContentUri(uri);
} catch (Throwable t) {
Log.e(TAG, Log.getStackTraceString(t));
} finally {
if (mTransactionState.getState() != TransactionState.SUCCESS) {
mTransactionState.setState(TransactionState.FAILED);
mTransactionState.setContentUri(mSendReqURI);
Log.e(TAG, "Delivery failed.");
}
notifyObservers();
}
}
use of com.google.android.mms.pdu.PduParser in project android_frameworks_opt_telephony by LineageOS.
the class WapPushOverSms method decodeWapPdu.
/**
* Decodes the wap push pdu. The decoded result is wrapped inside the {@link DecodedResult}
* object. The caller of this method should check {@link DecodedResult#statusCode} for the
* decoding status. It can have the following values.
*
* Activity.RESULT_OK - the wap push pdu is successfully decoded and should be further processed
* Intents.RESULT_SMS_HANDLED - the wap push pdu should be ignored.
* Intents.RESULT_SMS_GENERIC_ERROR - the pdu is invalid.
*/
private DecodedResult decodeWapPdu(byte[] pdu, InboundSmsHandler handler) {
DecodedResult result = new DecodedResult();
if (DBG)
Rlog.d(TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
try {
int index = 0;
int transactionId = pdu[index++] & 0xFF;
int pduType = pdu[index++] & 0xFF;
// Should we "abort" if no subId for now just no supplying extra param below
int phoneId = handler.getPhone().getPhoneId();
if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
index = mContext.getResources().getInteger(com.android.internal.R.integer.config_valid_wappush_index);
if (index != -1) {
transactionId = pdu[index++] & 0xff;
pduType = pdu[index++] & 0xff;
if (DBG)
Rlog.d(TAG, "index = " + index + " PDU Type = " + pduType + " transactionID = " + transactionId);
// recheck wap push pduType
if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH) && (pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
if (DBG)
Rlog.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
result.statusCode = Intents.RESULT_SMS_HANDLED;
return result;
}
} else {
if (DBG)
Rlog.w(TAG, "Received non-PUSH WAP PDU. Type = " + pduType);
result.statusCode = Intents.RESULT_SMS_HANDLED;
return result;
}
}
WspTypeDecoder pduDecoder = TelephonyComponentFactory.getInstance().inject(WspTypeDecoder.class.getName()).makeWspTypeDecoder(pdu);
/**
* Parse HeaderLen(unsigned integer).
* From wap-230-wsp-20010705-a section 8.1.2
* The maximum size of a uintvar is 32 bits.
* So it will be encoded in no more than 5 octets.
*/
if (pduDecoder.decodeUintvarInteger(index) == false) {
if (DBG)
Rlog.w(TAG, "Received PDU. Header Length error.");
result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
return result;
}
int headerLength = (int) pduDecoder.getValue32();
index += pduDecoder.getDecodedDataLength();
int headerStartIndex = index;
/**
* Parse Content-Type.
* From wap-230-wsp-20010705-a section 8.4.2.24
*
* Content-type-value = Constrained-media | Content-general-form
* Content-general-form = Value-length Media-type
* Media-type = (Well-known-media | Extension-Media) *(Parameter)
* Value-length = Short-length | (Length-quote Length)
* Short-length = <Any octet 0-30> (octet <= WAP_PDU_SHORT_LENGTH_MAX)
* Length-quote = <Octet 31> (WAP_PDU_LENGTH_QUOTE)
* Length = Uintvar-integer
*/
if (pduDecoder.decodeContentType(index) == false) {
if (DBG)
Rlog.w(TAG, "Received PDU. Header Content-Type error.");
result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
return result;
}
String mimeType = pduDecoder.getValueString();
long binaryContentType = pduDecoder.getValue32();
index += pduDecoder.getDecodedDataLength();
byte[] header = new byte[headerLength];
System.arraycopy(pdu, headerStartIndex, header, 0, header.length);
byte[] intentData;
if (mimeType != null && mimeType.equals(WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO)) {
intentData = pdu;
} else {
int dataIndex = headerStartIndex + headerLength;
intentData = new byte[pdu.length - dataIndex];
System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length);
}
int[] subIds = SubscriptionManager.getSubId(phoneId);
int subId = (subIds != null) && (subIds.length > 0) ? subIds[0] : SmsManager.getDefaultSmsSubscriptionId();
// Continue if PDU parsing fails: the default messaging app may successfully parse the
// same PDU.
GenericPdu parsedPdu = null;
try {
parsedPdu = new PduParser(intentData, shouldParseContentDisposition(subId)).parse();
} catch (Exception e) {
Rlog.e(TAG, "Unable to parse PDU: " + e.toString());
}
if (parsedPdu != null && parsedPdu.getMessageType() == MESSAGE_TYPE_NOTIFICATION_IND) {
final NotificationInd nInd = (NotificationInd) parsedPdu;
if (nInd.getFrom() != null && BlockChecker.isBlocked(mContext, nInd.getFrom().getString(), null)) {
result.statusCode = Intents.RESULT_SMS_HANDLED;
return result;
}
}
/**
* Seek for application ID field in WSP header.
* If application ID is found, WapPushManager substitute the message
* processing. Since WapPushManager is optional module, if WapPushManager
* is not found, legacy message processing will be continued.
*/
if (pduDecoder.seekXWapApplicationId(index, index + headerLength - 1)) {
index = (int) pduDecoder.getValue32();
pduDecoder.decodeXWapApplicationId(index);
String wapAppId = pduDecoder.getValueString();
if (wapAppId == null) {
wapAppId = Integer.toString((int) pduDecoder.getValue32());
}
result.wapAppId = wapAppId;
String contentType = ((mimeType == null) ? Long.toString(binaryContentType) : mimeType);
result.contentType = contentType;
if (DBG)
Rlog.v(TAG, "appid found: " + wapAppId + ":" + contentType);
}
result.subId = subId;
result.phoneId = phoneId;
result.parsedPdu = parsedPdu;
result.mimeType = mimeType;
result.transactionId = transactionId;
result.pduType = pduType;
result.header = header;
result.intentData = intentData;
result.contentTypeParameters = pduDecoder.getContentParameters();
result.statusCode = Activity.RESULT_OK;
} catch (ArrayIndexOutOfBoundsException aie) {
// 0-byte WAP PDU or other unexpected WAP PDU contents can easily throw this;
// log exception string without stack trace and return false.
Rlog.e(TAG, "ignoring dispatchWapPdu() array index exception: " + aie);
result.statusCode = Intents.RESULT_SMS_GENERIC_ERROR;
}
return result;
}
use of com.google.android.mms.pdu.PduParser in project android-aosp-mms by slvn.
the class RetrieveTransaction method run.
public void run() {
try {
// Change the downloading state of the M-Notification.ind.
DownloadManager.getInstance().markState(mUri, DownloadManager.STATE_DOWNLOADING);
// Send GET request to MMSC and retrieve the response data.
byte[] resp = getPdu(mContentLocation);
// Parse M-Retrieve.conf
RetrieveConf retrieveConf = (RetrieveConf) new PduParser(resp).parse();
if (null == retrieveConf) {
throw new MmsException("Invalid M-Retrieve.conf PDU.");
}
Uri msgUri = null;
if (isDuplicateMessage(mContext, retrieveConf)) {
// Mark this transaction as failed to prevent duplicate
// notification to user.
mTransactionState.setState(TransactionState.FAILED);
mTransactionState.setContentUri(mUri);
} else {
// Store M-Retrieve.conf into Inbox
PduPersister persister = PduPersister.getPduPersister(mContext);
msgUri = persister.persist(retrieveConf, Inbox.CONTENT_URI, true, MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null);
// Use local time instead of PDU time
ContentValues values = new ContentValues(1);
values.put(Mms.DATE, System.currentTimeMillis() / 1000L);
SqliteWrapper.update(mContext, mContext.getContentResolver(), msgUri, values, null, null);
// The M-Retrieve.conf has been successfully downloaded.
mTransactionState.setState(TransactionState.SUCCESS);
mTransactionState.setContentUri(msgUri);
// Remember the location the message was downloaded from.
// Since it's not critical, it won't fail the transaction.
// Copy over the locked flag from the M-Notification.ind in case
// the user locked the message before activating the download.
updateContentLocation(mContext, msgUri, mContentLocation, mLocked);
}
// Delete the corresponding M-Notification.ind.
SqliteWrapper.delete(mContext, mContext.getContentResolver(), mUri, null, null);
if (msgUri != null) {
// Have to delete messages over limit *after* the delete above. Otherwise,
// it would be counted as part of the total.
Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, msgUri);
MmsWidgetProvider.notifyDatasetChanged(mContext);
}
// Send ACK to the Proxy-Relay to indicate we have fetched the
// MM successfully.
// Don't mark the transaction as failed if we failed to send it.
sendAcknowledgeInd(retrieveConf);
} catch (Throwable t) {
Log.e(TAG, Log.getStackTraceString(t));
} finally {
if (mTransactionState.getState() != TransactionState.SUCCESS) {
mTransactionState.setState(TransactionState.FAILED);
mTransactionState.setContentUri(mUri);
Log.e(TAG, "Retrieval failed.");
}
notifyObservers();
}
}
use of com.google.android.mms.pdu.PduParser in project android-aosp-mms by slvn.
the class NotificationTransaction method run.
public void run() {
DownloadManager downloadManager = DownloadManager.getInstance();
boolean autoDownload = allowAutoDownload();
try {
if (LOCAL_LOGV) {
Log.v(TAG, "Notification transaction launched: " + this);
}
// By default, we set status to STATUS_DEFERRED because we
// should response MMSC with STATUS_DEFERRED when we cannot
// download a MM immediately.
int status = STATUS_DEFERRED;
// Don't try to download when data is suspended, as it will fail, so defer download
if (!autoDownload) {
downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED);
sendNotifyRespInd(status);
return;
}
downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING);
if (LOCAL_LOGV) {
Log.v(TAG, "Content-Location: " + mContentLocation);
}
byte[] retrieveConfData = null;
// with STATUS_DEFERRED.
try {
retrieveConfData = getPdu(mContentLocation);
} catch (IOException e) {
mTransactionState.setState(FAILED);
}
if (retrieveConfData != null) {
GenericPdu pdu = new PduParser(retrieveConfData).parse();
if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) {
Log.e(TAG, "Invalid M-RETRIEVE.CONF PDU. " + (pdu != null ? "message type: " + pdu.getMessageType() : "null pdu"));
mTransactionState.setState(FAILED);
status = STATUS_UNRECOGNIZED;
} else {
// Save the received PDU (must be a M-RETRIEVE.CONF).
PduPersister p = PduPersister.getPduPersister(mContext);
Uri uri = p.persist(pdu, Inbox.CONTENT_URI, true, MessagingPreferenceActivity.getIsGroupMmsEnabled(mContext), null);
// Use local time instead of PDU time
ContentValues values = new ContentValues(1);
values.put(Mms.DATE, System.currentTimeMillis() / 1000L);
SqliteWrapper.update(mContext, mContext.getContentResolver(), uri, values, null, null);
// We have successfully downloaded the new MM. Delete the
// M-NotifyResp.ind from Inbox.
SqliteWrapper.delete(mContext, mContext.getContentResolver(), mUri, null, null);
Log.v(TAG, "NotificationTransaction received new mms message: " + uri);
// Delete obsolete threads
SqliteWrapper.delete(mContext, mContext.getContentResolver(), Threads.OBSOLETE_THREADS_URI, null, null);
// Notify observers with newly received MM.
mUri = uri;
status = STATUS_RETRIEVED;
}
}
if (LOCAL_LOGV) {
Log.v(TAG, "status=0x" + Integer.toHexString(status));
}
// Check the status and update the result state of this Transaction.
switch(status) {
case STATUS_RETRIEVED:
mTransactionState.setState(SUCCESS);
break;
case STATUS_DEFERRED:
// STATUS_DEFERRED, may be a failed immediate retrieval.
if (mTransactionState.getState() == INITIALIZED) {
mTransactionState.setState(SUCCESS);
}
break;
}
sendNotifyRespInd(status);
// Make sure this thread isn't over the limits in message count.
Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri);
MmsWidgetProvider.notifyDatasetChanged(mContext);
} catch (Throwable t) {
Log.e(TAG, Log.getStackTraceString(t));
} finally {
mTransactionState.setContentUri(mUri);
if (!autoDownload) {
// Always mark the transaction successful for deferred
// download since any error here doesn't make sense.
mTransactionState.setState(SUCCESS);
}
if (mTransactionState.getState() != SUCCESS) {
mTransactionState.setState(FAILED);
Log.e(TAG, "NotificationTransaction failed.");
}
notifyObservers();
}
}
Aggregations