Search in sources :

Example 1 with PduParser

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();
    }
}
Also used : ContentValues(android.content.ContentValues) SendConf(com.google.android.mms.pdu.SendConf) PduParser(com.google.android.mms.pdu.PduParser) EncodedStringValue(com.google.android.mms.pdu.EncodedStringValue) PduPersister(com.google.android.mms.pdu.PduPersister) RateController(com.android.mms.util.RateController) SendReq(com.google.android.mms.pdu.SendReq) Uri(android.net.Uri) PduComposer(com.google.android.mms.pdu.PduComposer)

Example 2 with PduParser

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;
}
Also used : PduParser(com.google.android.mms.pdu.PduParser) NotificationInd(com.google.android.mms.pdu.NotificationInd) GenericPdu(com.google.android.mms.pdu.GenericPdu) MmsException(com.google.android.mms.MmsException) RemoteException(android.os.RemoteException) SQLiteException(android.database.sqlite.SQLiteException)

Example 3 with PduParser

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();
    }
}
Also used : ContentValues(android.content.ContentValues) PduParser(com.google.android.mms.pdu.PduParser) MmsException(com.google.android.mms.MmsException) PduPersister(com.google.android.mms.pdu.PduPersister) Uri(android.net.Uri) RetrieveConf(com.google.android.mms.pdu.RetrieveConf)

Example 4 with PduParser

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();
    }
}
Also used : ContentValues(android.content.ContentValues) PduParser(com.google.android.mms.pdu.PduParser) PduPersister(com.google.android.mms.pdu.PduPersister) GenericPdu(com.google.android.mms.pdu.GenericPdu) IOException(java.io.IOException) DownloadManager(com.android.mms.util.DownloadManager) Uri(android.net.Uri)

Aggregations

PduParser (com.google.android.mms.pdu.PduParser)4 ContentValues (android.content.ContentValues)3 Uri (android.net.Uri)3 PduPersister (com.google.android.mms.pdu.PduPersister)3 MmsException (com.google.android.mms.MmsException)2 GenericPdu (com.google.android.mms.pdu.GenericPdu)2 SQLiteException (android.database.sqlite.SQLiteException)1 RemoteException (android.os.RemoteException)1 DownloadManager (com.android.mms.util.DownloadManager)1 RateController (com.android.mms.util.RateController)1 EncodedStringValue (com.google.android.mms.pdu.EncodedStringValue)1 NotificationInd (com.google.android.mms.pdu.NotificationInd)1 PduComposer (com.google.android.mms.pdu.PduComposer)1 RetrieveConf (com.google.android.mms.pdu.RetrieveConf)1 SendConf (com.google.android.mms.pdu.SendConf)1 SendReq (com.google.android.mms.pdu.SendReq)1 IOException (java.io.IOException)1