content: /*
   * Copyright (C) 2015 Jacob Klinker
   *
   * 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.
   */
  
  package com.android.mms.service_alt;
  
  import android.app.Activity;
  import android.app.PendingIntent;
  import android.content.ContentValues;
  import android.content.Context;
  import android.content.Intent;
  import android.net.Uri;
  import android.os.Binder;
  import android.os.Build;
  import android.os.Bundle;
  import android.provider.Telephony;
  import android.telephony.SmsManager;
  import android.text.TextUtils;
  import com.klinker.android.logger.Log;
  
  import com.android.mms.service_alt.exception.MmsHttpException;
  
  import com.google.android.mms.MmsException;
  import com.google.android.mms.pdu_alt.GenericPdu;
  import com.google.android.mms.pdu_alt.PduHeaders;
  import com.google.android.mms.pdu_alt.PduParser;
  import com.google.android.mms.pdu_alt.PduPersister;
  import com.google.android.mms.pdu_alt.SendConf;
  import com.google.android.mms.pdu_alt.SendReq;
  import com.google.android.mms.util_alt.SqliteWrapper;
  
  /**
   * Request to send an MMS
   */
  public class SendRequest extends MmsRequest {
      private static final String TAG = "SendRequest";
  
      private final Uri mPduUri;
      private byte[] mPduData;
      private final String mLocationUrl;
      private final PendingIntent mSentIntent;
  
      public SendRequest(RequestManager manager, int subId, Uri contentUri, String locationUrl,
              PendingIntent sentIntent, String creator, Bundle configOverrides) {
          super(manager, subId, creator, configOverrides);
          mPduUri = contentUri;
          mPduData = null;
          mLocationUrl = locationUrl;
          mSentIntent = sentIntent;
      }
  
      @Override
      protected byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn)
              throws MmsHttpException {
          final MmsHttpClient mmsHttpClient = netMgr.getOrCreateHttpClient();
          if (mmsHttpClient == null) {
              Log.e(TAG, "MMS network is not ready!");
              throw new MmsHttpException(0/*statusCode*/, "MMS network is not ready");
          }
          return mmsHttpClient.execute(
                  mLocationUrl != null ? mLocationUrl : apn.getMmscUrl(),
                  mPduData,
                  MmsHttpClient.METHOD_POST,
                  apn.isProxySet(),
                  apn.getProxyAddress(),
                  apn.getProxyPort(),
                  mMmsConfig);
      }
  
      @Override
      protected PendingIntent getPendingIntent() {
          return mSentIntent;
      }
  
      @Override
      protected int getQueueType() {
          return 0;
      }
  
      @Override
      protected Uri persistIfRequired(Context context, int result, byte[] response) {
          Log.d(TAG, "SendRequest.persistIfRequired");
          if (mPduData == null) {
              Log.e(TAG, "SendRequest.persistIfRequired: empty PDU");
              return null;
          }
          final long identity = Binder.clearCallingIdentity();
          try {
              final boolean supportContentDisposition = mMmsConfig.getSupportMmsContentDisposition();
              // Persist the request PDU first
              GenericPdu pdu = (new PduParser(mPduData, supportContentDisposition)).parse();
              if (pdu == null) {
                  Log.e(TAG, "SendRequest.persistIfRequired: can't parse input PDU");
                  return null;
              }
              if (!(pdu instanceof SendReq)) {
                  Log.d(TAG, "SendRequest.persistIfRequired: not SendReq");
                  return null;
              }
  //            final PduPersister persister = PduPersister.getPduPersister(context);
  //            final Uri messageUri = persister.persist(
  //                    pdu,
  //                    Telephony.Mms.Sent.CONTENT_URI,
  //                    true/*createThreadId*/,
  //                    true/*groupMmsEnabled*/,
  //                    null/*preOpenedFiles*/);
  //            if (messageUri == null) {
  //                Log.e(TAG, "SendRequest.persistIfRequired: can not persist message");
  //                return null;
  //            }
              // Update the additional columns based on the send result
              final ContentValues values = new ContentValues();
              SendConf sendConf = null;
              if (response != null && response.length > 0) {
                  pdu = (new PduParser(response, supportContentDisposition)).parse();
                  if (pdu != null && pdu instanceof SendConf) {
                      sendConf = (SendConf) pdu;
                  }
              }
              if (result != Activity.RESULT_OK
                      || sendConf == null
                      || sendConf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
                  // Since we can't persist a message directly into FAILED box,
                  // we have to update the column after we persist it into SENT box.
                  // The gap between the state change is tiny so I would not expect
                  // it to cause any serious problem
                  // TODO: we should add a "failed" URI for this in MmsProvider?
                  values.put(Telephony.Mms.MESSAGE_BOX, Telephony.Mms.MESSAGE_BOX_FAILED);
              } else {
                  values.put(Telephony.Mms.MESSAGE_BOX, Telephony.Mms.MESSAGE_BOX_SENT);
              }
              if (sendConf != null) {
                  values.put(Telephony.Mms.RESPONSE_STATUS, sendConf.getResponseStatus());
                  Log.v(TAG, "response status: " + sendConf.getResponseStatus());
                  values.put(Telephony.Mms.MESSAGE_ID,
                          PduPersister.toIsoString(sendConf.getMessageId()));
              }
              values.put(Telephony.Mms.DATE, System.currentTimeMillis() / 1000L);
              values.put(Telephony.Mms.READ, 1);
              values.put(Telephony.Mms.SEEN, 1);
              if (!TextUtils.isEmpty(mCreator)) {
                  values.put(Telephony.Mms.CREATOR, mCreator);
              }
              if (SubscriptionIdChecker.getInstance(context).canUseSubscriptionId()) {
                  values.put(Telephony.Mms.SUBSCRIPTION_ID, mSubId);
              }
              if (SqliteWrapper.update(context, context.getContentResolver(), mPduUri, values,
                      null/*where*/, null/*selectionArg*/) != 1) {
                  Log.e(TAG, "SendRequest.persistIfRequired: failed to update message");
              }
              return mPduUri;
  //        } catch (MmsException e) {
  //            Log.e(TAG, "SendRequest.persistIfRequired: can not persist message", e);
          } catch (RuntimeException e) {
              Log.e(TAG, "SendRequest.persistIfRequired: unexpected parsing failure", e);
          } finally {
              Binder.restoreCallingIdentity(identity);
          }
          return null;
      }
  
      /**
       * Read the pdu from the file descriptor and cache pdu bytes in request
       * @return true if pdu read successfully
       */
      private boolean readPduFromContentUri() {
          if (mPduData != null) {
              return true;
          }
          final int bytesTobeRead = mMmsConfig.getMaxMessageSize();
          mPduData = mRequestManager.readPduFromContentUri(mPduUri, bytesTobeRead);
          return (mPduData != null);
      }
  
      /**
       * Transfer the received response to the caller (for send requests the pdu is small and can
       *  just include bytes as extra in the "returned" intent).
       *
       * @param fillIn the intent that will be returned to the caller
       * @param response the pdu to transfer
       */
      @Override
      protected boolean transferResponse(Intent fillIn, byte[] response) {
          // SendConf pdus are always small and can be included in the intent
          if (response != null) {
              fillIn.putExtra(SmsManager.EXTRA_MMS_DATA, response);
          }
          return true;
      }
  
      /**
       * Read the data from the file descriptor if not yet done
       * @return whether data successfully read
       */
      @Override
      protected boolean prepareForHttpRequest() {
          return readPduFromContentUri();
      }
  
      /**
       * Try sending via the carrier app
       *
       * @param context the context
       * @param carrierMessagingServicePackage the carrier messaging service sending the MMS
       */
      public void trySendingByCarrierApp(Context context, String carrierMessagingServicePackage) {
  //        final CarrierSendManager carrierSendManger = new CarrierSendManager();
  //        final CarrierSendCompleteCallback sendCallback = new CarrierSendCompleteCallback(
  //                context, carrierSendManger);
  //        carrierSendManger.sendMms(context, carrierMessagingServicePackage, sendCallback);
      }
  
      @Override
      protected void revokeUriPermission(Context context) {
          try {
              context.revokeUriPermission(mPduUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
          } catch (NullPointerException e) {
              Log.e(TAG, "error revoking permissions", e);
          }
      }
  }
  