mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-04 14:17:44 +00:00
MmsConnection refactor
- Use Apache HttpClient v4.x, only library that seems to like HTTP proxies - Remove custom redirect logic in favor of library's Fixes #1904 // FREEBIE
This commit is contained in:
parent
f1d230ce6e
commit
89fb80fcc5
@ -35,6 +35,7 @@ dependencies {
|
|||||||
compile 'com.google.android.gms:play-services:5.0.89'
|
compile 'com.google.android.gms:play-services:5.0.89'
|
||||||
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
|
compile 'com.astuetz:pagerslidingtabstrip:1.0.1'
|
||||||
compile 'org.w3c:smil:1.0.0'
|
compile 'org.w3c:smil:1.0.0'
|
||||||
|
compile 'org.apache.httpcomponents:httpclient-android:4.3.5'
|
||||||
|
|
||||||
androidTestCompile 'com.squareup:fest-android:1.0.8'
|
androidTestCompile 'com.squareup:fest-android:1.0.8'
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ dependencyVerification {
|
|||||||
'com.google.android.gms:play-services:38f326e525830f1d70f60f594ceafcbdf5b312287ddbecd338fd1ed7958a4b1e',
|
'com.google.android.gms:play-services:38f326e525830f1d70f60f594ceafcbdf5b312287ddbecd338fd1ed7958a4b1e',
|
||||||
'com.astuetz:pagerslidingtabstrip:f1641396732c7132a7abb837e482e5ee2b0ebb8d10813fc52bbaec2c15c184c2',
|
'com.astuetz:pagerslidingtabstrip:f1641396732c7132a7abb837e482e5ee2b0ebb8d10813fc52bbaec2c15c184c2',
|
||||||
'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b',
|
'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b',
|
||||||
|
'org.apache.httpcomponents:httpclient-android:6f56466a9bd0d42934b90bfbfe9977a8b654c058bf44a12bdc2877c4e1f033f1',
|
||||||
'com.google.protobuf:protobuf-java:ad9769a22989e688a46af4d3accc348cc501ced22118033230542bc916e33f0b',
|
'com.google.protobuf:protobuf-java:ad9769a22989e688a46af4d3accc348cc501ced22118033230542bc916e33f0b',
|
||||||
'com.madgag:sc-light-jdk15on:931f39d351429fb96c2f749e7ecb1a256a8ebbf5edca7995c9cc085b94d1841d',
|
'com.madgag:sc-light-jdk15on:931f39d351429fb96c2f749e7ecb1a256a8ebbf5edca7995c9cc085b94d1841d',
|
||||||
'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab',
|
'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab',
|
||||||
|
@ -73,9 +73,9 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|||||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||||
import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter;
|
import org.thoughtcrime.securesms.mms.AttachmentTypeSelectorAdapter;
|
||||||
import org.thoughtcrime.securesms.mms.MediaTooLargeException;
|
import org.thoughtcrime.securesms.mms.MediaTooLargeException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsSendHelper;
|
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
|
import org.thoughtcrime.securesms.mms.OutgoingMmsConnection;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
@ -736,7 +736,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
|
|||||||
new AsyncTask<Void, Void, Boolean>() {
|
new AsyncTask<Void, Void, Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... params) {
|
protected Boolean doInBackground(Void... params) {
|
||||||
return MmsSendHelper.hasNecessaryApnDetails(ConversationActivity.this);
|
return OutgoingMmsConnection.isConnectionPossible(ConversationActivity.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,11 +20,11 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.EditTextPreference;
|
import android.preference.EditTextPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.actionbarsherlock.view.MenuItem;
|
import com.actionbarsherlock.view.MenuItem;
|
||||||
import org.thoughtcrime.securesms.mms.MmsDownloadHelper;
|
|
||||||
|
import org.thoughtcrime.securesms.mms.IncomingMmsConnection;
|
||||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
@ -86,7 +86,7 @@ public class MmsPreferencesActivity extends PassphraseRequiredSherlockPreference
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializePreferences() {
|
private void initializePreferences() {
|
||||||
if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(this, null)) {
|
if (!IncomingMmsConnection.isConnectionPossible(this, null)) {
|
||||||
TextSecurePreferences.setUseLocalApnsEnabled(this, true);
|
TextSecurePreferences.setUseLocalApnsEnabled(this, true);
|
||||||
addPreferencesFromResource(R.xml.mms_preferences);
|
addPreferencesFromResource(R.xml.mms_preferences);
|
||||||
this.findPreference(TextSecurePreferences.ENABLE_MANUAL_MMS_PREF).setOnPreferenceChangeListener(new OverrideMmsChangeListener());
|
this.findPreference(TextSecurePreferences.ENABLE_MANUAL_MMS_PREF).setOnPreferenceChangeListener(new OverrideMmsChangeListener());
|
||||||
|
@ -20,17 +20,16 @@ import android.content.Context;
|
|||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsCommunication;
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsCommunication.MmsConnectionParameters;
|
import org.thoughtcrime.securesms.mms.MmsConnection.Apn;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.textsecure.util.Util;
|
import org.whispersystems.textsecure.util.Util;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidParameterException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database to query APN and MMSC information
|
* Database to query APN and MMSC information
|
||||||
@ -39,6 +38,7 @@ public class ApnDatabase {
|
|||||||
private static final String TAG = ApnDatabase.class.getSimpleName();
|
private static final String TAG = ApnDatabase.class.getSimpleName();
|
||||||
|
|
||||||
private final SQLiteDatabase db;
|
private final SQLiteDatabase db;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "apns.db";
|
private static final String DATABASE_NAME = "apns.db";
|
||||||
private static final String ASSET_PATH = "databases" + File.separator + DATABASE_NAME;
|
private static final String ASSET_PATH = "databases" + File.separator + DATABASE_NAME;
|
||||||
@ -77,6 +77,8 @@ public class ApnDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ApnDatabase(final Context context) throws IOException {
|
private ApnDatabase(final Context context) throws IOException {
|
||||||
|
this.context = context;
|
||||||
|
|
||||||
File dbFile = context.getDatabasePath(DATABASE_NAME);
|
File dbFile = context.getDatabasePath(DATABASE_NAME);
|
||||||
|
|
||||||
if (!dbFile.getParentFile().exists() && !dbFile.getParentFile().mkdir()) {
|
if (!dbFile.getParentFile().exists() && !dbFile.getParentFile().mkdir()) {
|
||||||
@ -90,10 +92,36 @@ public class ApnDatabase {
|
|||||||
null,
|
null,
|
||||||
SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
|
SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
|
||||||
}
|
}
|
||||||
|
protected Apn getLocallyConfiguredMmsConnectionParameters() throws ApnUnavailableException {
|
||||||
|
if (TextSecurePreferences.isUseLocalApnsEnabled(context)) {
|
||||||
|
String mmsc = TextSecurePreferences.getMmscUrl(context);
|
||||||
|
|
||||||
public MmsCommunication.MmsConnectionParameters getMmsConnectionParameters(final String mccmnc,
|
if (mmsc == null)
|
||||||
final String apn)
|
throw new ApnUnavailableException("Malformed locally configured MMSC.");
|
||||||
{
|
|
||||||
|
if (!mmsc.startsWith("http"))
|
||||||
|
mmsc = "http://" + mmsc;
|
||||||
|
|
||||||
|
String proxy = TextSecurePreferences.getMmscProxy(context);
|
||||||
|
String port = TextSecurePreferences.getMmscProxyPort(context);
|
||||||
|
|
||||||
|
return new Apn(mmsc, proxy, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApnUnavailableException("No locally configured parameters available");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Apn getMmsConnectionParameters(final String mccmnc, final String apn) {
|
||||||
|
|
||||||
|
if (TextSecurePreferences.isUseLocalApnsEnabled(context)) {
|
||||||
|
Log.w(TAG, "Choosing locally-overridden MMS settings");
|
||||||
|
try {
|
||||||
|
return getLocallyConfiguredMmsConnectionParameters();
|
||||||
|
} catch (ApnUnavailableException aue) {
|
||||||
|
Log.w(TAG, "preference to use local apn set, but no parameters avaiable. falling back.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mccmnc == null) {
|
if (mccmnc == null) {
|
||||||
Log.w(TAG, "mccmnc was null, returning null");
|
Log.w(TAG, "mccmnc was null, returning null");
|
||||||
@ -121,10 +149,10 @@ public class ApnDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
MmsConnectionParameters params = new MmsConnectionParameters(cursor.getString(cursor.getColumnIndexOrThrow(MMSC_COLUMN)),
|
Apn params = new Apn(cursor.getString(cursor.getColumnIndexOrThrow(MMSC_COLUMN)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PROXY_COLUMN)),
|
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PROXY_COLUMN)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PORT_COLUMN)));
|
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PORT_COLUMN)));
|
||||||
Log.w(TAG, "Returning preferred APN " + params.get().get(0));
|
Log.w(TAG, "Returning preferred APN " + params);
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2014 Open Whisper Systems
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.HttpGetHC4;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import ws.com.google.android.mms.pdu.PduParser;
|
||||||
|
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||||
|
|
||||||
|
public class IncomingMmsConnection extends MmsConnection {
|
||||||
|
private static final String TAG = IncomingMmsConnection.class.getSimpleName();
|
||||||
|
|
||||||
|
public IncomingMmsConnection(Context context, Apn apn) {
|
||||||
|
super(context, apn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpUriRequest constructRequest(boolean useProxy) throws IOException {
|
||||||
|
HttpGetHC4 request = new HttpGetHC4(apn.getMmsc());
|
||||||
|
request.addHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
||||||
|
if (useProxy) {
|
||||||
|
HttpHost proxy = new HttpHost(apn.getProxy(), apn.getPort());
|
||||||
|
request.setConfig(RequestConfig.custom().setProxy(proxy).build());
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isConnectionPossible(Context context, String apn) {
|
||||||
|
try {
|
||||||
|
getApn(context, apn);
|
||||||
|
return true;
|
||||||
|
} catch (ApnUnavailableException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public RetrieveConf retrieve(boolean usingMmsRadio, boolean useProxyIfAvailable)
|
||||||
|
throws IOException, ApnUnavailableException
|
||||||
|
{
|
||||||
|
byte[] pdu = null;
|
||||||
|
|
||||||
|
final boolean useProxy = useProxyIfAvailable && apn.hasProxy();
|
||||||
|
final String targetHost = useProxy
|
||||||
|
? apn.getProxy()
|
||||||
|
: Uri.parse(apn.getMmsc()).getHost();
|
||||||
|
try {
|
||||||
|
if (checkRouteToHost(context, targetHost, usingMmsRadio)) {
|
||||||
|
Log.w(TAG, "got successful route to host " + targetHost);
|
||||||
|
pdu = makeRequest(useProxy);
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.w(TAG, ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdu == null) {
|
||||||
|
throw new IOException("Connection manager could not obtain route to host.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse();
|
||||||
|
|
||||||
|
if (retrieved == null) {
|
||||||
|
Log.w(TAG, "Couldn't parse PDU, byte response: " + Arrays.toString(pdu));
|
||||||
|
Log.w(TAG, "Couldn't parse PDU, ASCII: " + new String(pdu));
|
||||||
|
throw new IOException("Bad retrieved PDU");
|
||||||
|
}
|
||||||
|
|
||||||
|
return retrieved;
|
||||||
|
}
|
||||||
|
}
|
@ -1,254 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011 Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.mms;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteException;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.ApnDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.TelephonyUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.textsecure.util.Conversions;
|
|
||||||
import org.whispersystems.textsecure.util.Util;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MmsCommunication {
|
|
||||||
private static final String TAG = "MmsCommunication";
|
|
||||||
|
|
||||||
public static final int MAX_REDIRECTS = 10;
|
|
||||||
|
|
||||||
protected static MmsConnectionParameters getLocallyConfiguredMmsConnectionParameters(Context context)
|
|
||||||
throws ApnUnavailableException
|
|
||||||
{
|
|
||||||
if (TextSecurePreferences.isUseLocalApnsEnabled(context)) {
|
|
||||||
String mmsc = TextSecurePreferences.getMmscUrl(context);
|
|
||||||
|
|
||||||
if (mmsc == null)
|
|
||||||
throw new ApnUnavailableException("Malformed locally configured MMSC.");
|
|
||||||
|
|
||||||
if (!mmsc.startsWith("http"))
|
|
||||||
mmsc = "http://" + mmsc;
|
|
||||||
|
|
||||||
String proxy = TextSecurePreferences.getMmscProxy(context);
|
|
||||||
String port = TextSecurePreferences.getMmscProxyPort(context);
|
|
||||||
|
|
||||||
return new MmsConnectionParameters(mmsc, proxy, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ApnUnavailableException("No locally configured parameters available");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MmsConnectionParameters getLocalMmsConnectionParameters(Context context)
|
|
||||||
throws ApnUnavailableException
|
|
||||||
{
|
|
||||||
if (TextSecurePreferences.isUseLocalApnsEnabled(context)) {
|
|
||||||
return getLocallyConfiguredMmsConnectionParameters(context);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
MmsConnectionParameters params = ApnDatabase.getInstance(context)
|
|
||||||
.getMmsConnectionParameters(TelephonyUtil.getMccMnc(context),
|
|
||||||
TelephonyUtil.getApn(context));
|
|
||||||
|
|
||||||
if (params == null) {
|
|
||||||
throw new ApnUnavailableException("No parameters available from ApnDefaults.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return params;
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new ApnUnavailableException("ApnDatabase threw an IOException", ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn)
|
|
||||||
throws ApnUnavailableException
|
|
||||||
{
|
|
||||||
Log.w(TAG, "Getting MMSC params for apn " + apn);
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cursor = DatabaseFactory.getMmsDatabase(context).getCarrierMmsInformation(apn);
|
|
||||||
|
|
||||||
if (cursor == null || !cursor.moveToFirst()) {
|
|
||||||
Log.w(TAG, "Android didn't have a result, querying local parameters.");
|
|
||||||
return getLocalMmsConnectionParameters(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
String mmsc = cursor.getString(cursor.getColumnIndexOrThrow("mmsc"));
|
|
||||||
String proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy"));
|
|
||||||
String port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport"));
|
|
||||||
|
|
||||||
if (!Util.isEmpty(mmsc)) {
|
|
||||||
Log.w(TAG, "Using Android-provided MMSC parameters.");
|
|
||||||
return new MmsConnectionParameters(mmsc, proxy, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
|
|
||||||
Log.w(TAG, "Android provided results were empty, querying local parameters.");
|
|
||||||
return getLocalMmsConnectionParameters(context);
|
|
||||||
} catch (SQLiteException sqe) {
|
|
||||||
Log.w(TAG, sqe);
|
|
||||||
} catch (SecurityException se) {
|
|
||||||
Log.w(TAG, "Android won't let us query the APN database.");
|
|
||||||
return getLocalMmsConnectionParameters(context);
|
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
Log.w(TAG, iae);
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
return getLocalMmsConnectionParameters(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean checkRouteToHost(Context context, String host, boolean usingMmsRadio)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
InetAddress inetAddress = InetAddress.getByName(host);
|
|
||||||
|
|
||||||
if (!usingMmsRadio) {
|
|
||||||
if (inetAddress.isSiteLocalAddress()) {
|
|
||||||
throw new IOException("RFC1918 address in non-MMS radio situation!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.w(TAG, "Checking route to address: " + host + " , " + inetAddress.getHostAddress());
|
|
||||||
|
|
||||||
byte[] ipAddressBytes = inetAddress.getAddress();
|
|
||||||
|
|
||||||
if (ipAddressBytes != null && ipAddressBytes.length == 4) {
|
|
||||||
int ipAddress = Conversions.byteArrayToIntLittleEndian(ipAddressBytes, 0);
|
|
||||||
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
|
|
||||||
return manager.requestRouteToHost(MmsRadio.TYPE_MOBILE_MMS, ipAddress);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static byte[] parseResponse(InputStream is) throws IOException {
|
|
||||||
InputStream in = new BufferedInputStream(is);
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
Util.copy(in, baos);
|
|
||||||
|
|
||||||
Log.w(TAG, "Received full server response, " + baos.size() + " bytes");
|
|
||||||
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static HttpURLConnection constructHttpClient(String urlString, String proxy, int port)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
HttpURLConnection urlConnection;
|
|
||||||
URL url = new URL(urlString);
|
|
||||||
|
|
||||||
if (proxy != null) {
|
|
||||||
Log.w(TAG, String.format("Constructing http client using a proxy: (%s:%d)", proxy, port));
|
|
||||||
Proxy proxyRoute = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxy, port));
|
|
||||||
urlConnection = (HttpURLConnection) url.openConnection(proxyRoute);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Constructing http client without proxy");
|
|
||||||
urlConnection = (HttpURLConnection) url.openConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
urlConnection.setInstanceFollowRedirects(false);
|
|
||||||
urlConnection.setConnectTimeout(20*1000);
|
|
||||||
urlConnection.setReadTimeout(20*1000);
|
|
||||||
urlConnection.setUseCaches(false);
|
|
||||||
urlConnection.setRequestProperty("User-Agent", "Android-Mms/2.0");
|
|
||||||
urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
|
|
||||||
return urlConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MmsConnectionParameters {
|
|
||||||
|
|
||||||
public class Apn {
|
|
||||||
private final String mmsc;
|
|
||||||
private final String proxy;
|
|
||||||
private final String port;
|
|
||||||
|
|
||||||
public Apn(String mmsc, String proxy, String port) {
|
|
||||||
this.mmsc = mmsc;
|
|
||||||
this.proxy = proxy;
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasProxy() {
|
|
||||||
return !Util.isEmpty(proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMmsc() {
|
|
||||||
return mmsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProxy() {
|
|
||||||
if (!hasProxy())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
|
||||||
if (Util.isEmpty(port))
|
|
||||||
return 80;
|
|
||||||
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return MmsConnectionParameters.class.getSimpleName() +
|
|
||||||
"{ mmsc: \"" + mmsc + "\"" +
|
|
||||||
", proxy: " + (proxy == null ? "none" : '"' + proxy + '"') +
|
|
||||||
", port: " + (port == null ? "none" : port) + " }";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Apn> apn = new ArrayList<Apn>();
|
|
||||||
|
|
||||||
public MmsConnectionParameters(String mmsc, String proxy, String port) {
|
|
||||||
apn.add(new Apn(mmsc, proxy, port));
|
|
||||||
}
|
|
||||||
|
|
||||||
public MmsConnectionParameters add(String mmsc, String proxy, String port) {
|
|
||||||
apn.add(new Apn(mmsc, proxy, port));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Apn> get() {
|
|
||||||
return apn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
189
src/org/thoughtcrime/securesms/mms/MmsConnection.java
Normal file
189
src/org/thoughtcrime/securesms/mms/MmsConnection.java
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2011 Whisper Systems
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.impl.NoConnectionReuseStrategyHC4;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.impl.client.LaxRedirectStrategy;
|
||||||
|
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
||||||
|
import org.thoughtcrime.securesms.database.ApnDatabase;
|
||||||
|
import org.thoughtcrime.securesms.util.TelephonyUtil;
|
||||||
|
import org.whispersystems.textsecure.util.Conversions;
|
||||||
|
import org.whispersystems.textsecure.util.Util;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
public abstract class MmsConnection {
|
||||||
|
private static final String TAG = "MmsCommunication";
|
||||||
|
|
||||||
|
protected final Context context;
|
||||||
|
protected final Apn apn;
|
||||||
|
|
||||||
|
protected MmsConnection(Context context, Apn apn) {
|
||||||
|
this.context = context;
|
||||||
|
this.apn = apn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Apn getLocalApn(Context context) throws ApnUnavailableException {
|
||||||
|
try {
|
||||||
|
Apn params = ApnDatabase.getInstance(context)
|
||||||
|
.getMmsConnectionParameters(TelephonyUtil.getMccMnc(context),
|
||||||
|
TelephonyUtil.getApn(context));
|
||||||
|
|
||||||
|
if (params == null) {
|
||||||
|
throw new ApnUnavailableException("No parameters available from ApnDefaults.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ApnUnavailableException("ApnDatabase threw an IOException", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Apn getApn(Context context, String apnName) throws ApnUnavailableException {
|
||||||
|
Log.w(TAG, "Getting MMSC params for apn " + apnName);
|
||||||
|
return getLocalApn(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean checkRouteToHost(Context context, String host, boolean usingMmsRadio)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
InetAddress inetAddress = InetAddress.getByName(host);
|
||||||
|
if (!usingMmsRadio) {
|
||||||
|
if (inetAddress.isSiteLocalAddress()) {
|
||||||
|
throw new IOException("RFC1918 address in non-MMS radio situation!");
|
||||||
|
}
|
||||||
|
Log.w(TAG, "returning vacuous success since MMS radio is not in use");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
byte[] ipAddressBytes = inetAddress.getAddress();
|
||||||
|
if (ipAddressBytes == null || ipAddressBytes.length != 4) {
|
||||||
|
Log.w(TAG, "returning vacuous success since android.net package doesn't support IPv6");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.w(TAG, "Checking route to address: " + host + ", " + inetAddress.getHostAddress());
|
||||||
|
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
int ipAddress = Conversions.byteArrayToIntLittleEndian(ipAddressBytes, 0);
|
||||||
|
boolean routeToHostObtained = manager.requestRouteToHost(MmsRadio.TYPE_MOBILE_MMS, ipAddress);
|
||||||
|
Log.w(TAG, "requestRouteToHost result: " + routeToHostObtained);
|
||||||
|
return routeToHostObtained;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static byte[] parseResponse(InputStream is) throws IOException {
|
||||||
|
InputStream in = new BufferedInputStream(is);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
Util.copy(in, baos);
|
||||||
|
|
||||||
|
Log.w(TAG, "Received full server response, " + baos.size() + " bytes");
|
||||||
|
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CloseableHttpClient constructHttpClient()
|
||||||
|
throws IOException {
|
||||||
|
RequestConfig config = RequestConfig.custom()
|
||||||
|
.setConnectTimeout(20 * 1000)
|
||||||
|
.setConnectionRequestTimeout(20 * 1000)
|
||||||
|
.setSocketTimeout(20 * 1000)
|
||||||
|
.setMaxRedirects(20)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return HttpClients.custom()
|
||||||
|
.setConnectionReuseStrategy(new NoConnectionReuseStrategyHC4())
|
||||||
|
.setRedirectStrategy(new LaxRedirectStrategy())
|
||||||
|
.setUserAgent("Android-Mms/2.0")
|
||||||
|
.setConnectionManager(new BasicHttpClientConnectionManager())
|
||||||
|
.setDefaultRequestConfig(config)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] makeRequest(boolean useProxy) throws IOException {
|
||||||
|
Log.w(TAG, "connecting to " + apn.getMmsc() + (useProxy ? " using proxy" : ""));
|
||||||
|
|
||||||
|
HttpUriRequest request;
|
||||||
|
CloseableHttpClient client = null;
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
try {
|
||||||
|
request = constructRequest(useProxy);
|
||||||
|
client = constructHttpClient();
|
||||||
|
response = client.execute(request);
|
||||||
|
|
||||||
|
Log.w(TAG, "* response code: " + response.getStatusLine());
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() == 200) {
|
||||||
|
return parseResponse(response.getEntity().getContent());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (response != null) response.close();
|
||||||
|
if (client != null) client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException("unhandled response code");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract HttpUriRequest constructRequest(boolean useProxy) throws IOException;
|
||||||
|
|
||||||
|
public static class Apn {
|
||||||
|
private final String mmsc;
|
||||||
|
private final String proxy;
|
||||||
|
private final String port;
|
||||||
|
|
||||||
|
public Apn(String mmsc, String proxy, String port) {
|
||||||
|
this.mmsc = mmsc;
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasProxy() {
|
||||||
|
return !TextUtils.isEmpty(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMmsc() {
|
||||||
|
return mmsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxy() {
|
||||||
|
return hasProxy() ? proxy : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPort() {
|
||||||
|
return TextUtils.isEmpty(port) ? 80 : Integer.parseInt(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Apn.class.getSimpleName() +
|
||||||
|
"{ mmsc: \"" + mmsc + "\"" +
|
||||||
|
", proxy: " + (proxy == null ? "none" : '"' + proxy + '"') +
|
||||||
|
", port: " + (port == null ? "none" : port) + " }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,130 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011 Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.mms;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import ws.com.google.android.mms.pdu.PduParser;
|
|
||||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
|
||||||
|
|
||||||
public class MmsDownloadHelper extends MmsCommunication {
|
|
||||||
private static final String TAG = MmsDownloadHelper.class.getSimpleName();
|
|
||||||
|
|
||||||
private static byte[] makeRequest(String url, String proxy, int proxyPort)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
HttpURLConnection client = null;
|
|
||||||
|
|
||||||
int redirects = MAX_REDIRECTS;
|
|
||||||
final Set<String> previousUrls = new HashSet<String>();
|
|
||||||
String currentUrl = url;
|
|
||||||
while (redirects-- > 0) {
|
|
||||||
if (previousUrls.contains(currentUrl)) {
|
|
||||||
throw new IOException("redirect loop detected");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
client = constructHttpClient(currentUrl, proxy, proxyPort);
|
|
||||||
|
|
||||||
client.setDoInput(true);
|
|
||||||
client.setRequestMethod("GET");
|
|
||||||
client.setRequestProperty("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
|
||||||
|
|
||||||
Log.w(TAG, "connecting to " + currentUrl);
|
|
||||||
client.connect();
|
|
||||||
|
|
||||||
int responseCode = client.getResponseCode();
|
|
||||||
Log.w(TAG, "* response code: " + responseCode + "/" + client.getResponseMessage());
|
|
||||||
|
|
||||||
if (responseCode == 301 || responseCode == 302) {
|
|
||||||
final String redirectUrl = client.getHeaderField("Location");
|
|
||||||
Log.w(TAG, "* Location: " + redirectUrl);
|
|
||||||
if (TextUtils.isEmpty(redirectUrl)) {
|
|
||||||
throw new IOException("Got redirect response code, but Location header was empty or missing");
|
|
||||||
}
|
|
||||||
previousUrls.add(currentUrl);
|
|
||||||
currentUrl = redirectUrl;
|
|
||||||
} else if (responseCode == 200) {
|
|
||||||
final InputStream is = client.getInputStream();
|
|
||||||
return parseResponse(is);
|
|
||||||
} else {
|
|
||||||
throw new IOException("unhandled response code");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (client != null) client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IOException("max redirects hit");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isMmsConnectionParametersAvailable(Context context, String apn) {
|
|
||||||
try {
|
|
||||||
getMmsConnectionParameters(context, apn);
|
|
||||||
return true;
|
|
||||||
} catch (ApnUnavailableException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RetrieveConf retrieveMms(Context context, String url, String apn,
|
|
||||||
boolean usingMmsRadio, boolean proxyIfPossible)
|
|
||||||
throws IOException, ApnUnavailableException
|
|
||||||
{
|
|
||||||
MmsConnectionParameters connectionParameters = getMmsConnectionParameters(context, apn);
|
|
||||||
byte[] pdu = null;
|
|
||||||
|
|
||||||
for (MmsConnectionParameters.Apn param : connectionParameters.get()) {
|
|
||||||
try {
|
|
||||||
if (proxyIfPossible && param.hasProxy()) {
|
|
||||||
if (checkRouteToHost(context, param.getProxy(), usingMmsRadio)) {
|
|
||||||
pdu = makeRequest(url, param.getProxy(), param.getPort());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (checkRouteToHost(context, Uri.parse(url).getHost(), usingMmsRadio)) {
|
|
||||||
pdu = makeRequest(url, null, -1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdu != null) break;
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.w(TAG, ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdu == null) {
|
|
||||||
throw new IOException("Connection manager could not obtain route to host.");
|
|
||||||
}
|
|
||||||
|
|
||||||
RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse();
|
|
||||||
|
|
||||||
if (retrieved == null) {
|
|
||||||
Log.w(TAG, "Couldn't parse PDU, raw server response: " + Arrays.toString(pdu));
|
|
||||||
throw new IOException("Bad retrieved PDU");
|
|
||||||
}
|
|
||||||
|
|
||||||
return retrieved;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,163 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011 Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.mms;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import ws.com.google.android.mms.pdu.PduParser;
|
|
||||||
import ws.com.google.android.mms.pdu.SendConf;
|
|
||||||
|
|
||||||
public class MmsSendHelper extends MmsCommunication {
|
|
||||||
private final static String TAG = MmsSendHelper.class.getSimpleName();
|
|
||||||
|
|
||||||
private static byte[] makePost(String url, String proxy, int proxyPort, byte[] mms)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
if (mms == null) return null;
|
|
||||||
|
|
||||||
HttpURLConnection client = null;
|
|
||||||
|
|
||||||
int redirects = MAX_REDIRECTS;
|
|
||||||
final Set<String> previousUrls = new HashSet<String>();
|
|
||||||
String currentUrl = url;
|
|
||||||
while (redirects-- > 0) {
|
|
||||||
if (previousUrls.contains(currentUrl)) {
|
|
||||||
throw new IOException("redirect loop detected");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
client = constructHttpClient(currentUrl, proxy, proxyPort);
|
|
||||||
client.setFixedLengthStreamingMode(mms.length);
|
|
||||||
client.setDoInput(true);
|
|
||||||
client.setDoOutput(true);
|
|
||||||
client.setRequestMethod("POST");
|
|
||||||
client.setRequestProperty("Content-Type", "application/vnd.wap.mms-message");
|
|
||||||
client.setRequestProperty("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
|
||||||
client.setRequestProperty("x-wap-profile", "http://www.google.com/oha/rdf/ua-profile-kila.xml");
|
|
||||||
|
|
||||||
Log.w(TAG, "connecting to " + currentUrl);
|
|
||||||
client.connect();
|
|
||||||
|
|
||||||
Log.w(TAG, "* writing mms payload, " + mms.length + " bytes");
|
|
||||||
OutputStream out = client.getOutputStream();
|
|
||||||
out.write(mms);
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
Log.w(TAG, "* payload sent");
|
|
||||||
|
|
||||||
int responseCode = client.getResponseCode();
|
|
||||||
Log.w(TAG, "* response code: " + responseCode + "/" + client.getResponseMessage());
|
|
||||||
|
|
||||||
if (responseCode == 301 || responseCode == 302) {
|
|
||||||
final String redirectUrl = client.getHeaderField("Location");
|
|
||||||
Log.w(TAG, "* Location: " + redirectUrl);
|
|
||||||
if (TextUtils.isEmpty(redirectUrl)) {
|
|
||||||
throw new IOException("Got redirect response code, but Location header was empty or missing");
|
|
||||||
}
|
|
||||||
previousUrls.add(currentUrl);
|
|
||||||
currentUrl = redirectUrl;
|
|
||||||
} else if (responseCode == 200) {
|
|
||||||
final InputStream is = client.getInputStream();
|
|
||||||
return parseResponse(is);
|
|
||||||
} else {
|
|
||||||
throw new IOException("unhandled response code");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (client != null) client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IOException("max redirects hit");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendNotificationReceived(Context context, byte[] mms, String apn,
|
|
||||||
boolean usingMmsRadio, boolean useProxyIfAvailable)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
sendBytes(context, mms, apn, usingMmsRadio, useProxyIfAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SendConf sendMms(Context context, byte[] mms, String apn,
|
|
||||||
boolean usingMmsRadio, boolean useProxyIfAvailable)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
byte[] response = sendBytes(context, mms, apn, usingMmsRadio, useProxyIfAvailable);
|
|
||||||
return (SendConf) new PduParser(response).parse();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] sendBytes(Context context, byte[] mms, String apn,
|
|
||||||
boolean usingMmsRadio, boolean useProxyIfAvailable)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
Log.w(TAG, "Sending MMS of length: " + mms.length + "." + (usingMmsRadio ? " using mms radio" : ""));
|
|
||||||
try {
|
|
||||||
MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn);
|
|
||||||
|
|
||||||
for (MmsConnectionParameters.Apn param : parameters.get()) {
|
|
||||||
try {
|
|
||||||
if (useProxyIfAvailable && param.hasProxy()) {
|
|
||||||
if (checkRouteToHost(context, param.getProxy(), usingMmsRadio)) {
|
|
||||||
byte[] response = makePost(param.getMmsc(), param.getProxy(), param.getPort(), mms);
|
|
||||||
if (response != null) return response;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (checkRouteToHost(context, Uri.parse(param.getMmsc()).getHost(), usingMmsRadio)) {
|
|
||||||
byte[] response = makePost(param.getMmsc(), null, -1, mms);
|
|
||||||
if (response != null) return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.w(TAG, ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IOException("Connection manager could not obtain route to host.");
|
|
||||||
} catch (ApnUnavailableException aue) {
|
|
||||||
Log.w(TAG, aue);
|
|
||||||
throw new IOException("Failed to get MMSC information...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasNecessaryApnDetails(Context context) {
|
|
||||||
try {
|
|
||||||
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(MmsRadio.TYPE_MOBILE_MMS);
|
|
||||||
if (networkInfo == null) {
|
|
||||||
Log.w(TAG, "MMS network info was null, unsupported by this device");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String apn = networkInfo.getExtraInfo();
|
|
||||||
|
|
||||||
MmsCommunication.getMmsConnectionParameters(context, apn);
|
|
||||||
return true;
|
|
||||||
} catch (ApnUnavailableException e) {
|
|
||||||
Log.w("MmsSendHelper", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
111
src/org/thoughtcrime/securesms/mms/OutgoingMmsConnection.java
Normal file
111
src/org/thoughtcrime/securesms/mms/OutgoingMmsConnection.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (C) 2014 Open Whisper Systems
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.HttpPostHC4;
|
||||||
|
import org.apache.http.client.methods.HttpUriRequest;
|
||||||
|
import org.apache.http.entity.ByteArrayEntityHC4;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ws.com.google.android.mms.pdu.PduParser;
|
||||||
|
import ws.com.google.android.mms.pdu.SendConf;
|
||||||
|
|
||||||
|
public class OutgoingMmsConnection extends MmsConnection {
|
||||||
|
private final static String TAG = OutgoingMmsConnection.class.getSimpleName();
|
||||||
|
|
||||||
|
private final byte[] mms;
|
||||||
|
|
||||||
|
public OutgoingMmsConnection(Context context, String apnName, byte[] mms) throws ApnUnavailableException {
|
||||||
|
super(context, getApn(context, apnName));
|
||||||
|
this.mms = mms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpUriRequest constructRequest(boolean useProxy)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
HttpPostHC4 request = new HttpPostHC4(apn.getMmsc());
|
||||||
|
request.addHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
||||||
|
request.addHeader("x-wap-profile", "http://www.google.com/oha/rdf/ua-profile-kila.xml");
|
||||||
|
request.addHeader("Content-Type", "application/vnd.wap.mms-message");
|
||||||
|
request.setEntity(new ByteArrayEntityHC4(mms));
|
||||||
|
if (useProxy) {
|
||||||
|
HttpHost proxy = new HttpHost(apn.getProxy(), apn.getPort());
|
||||||
|
request.setConfig(RequestConfig.custom().setProxy(proxy).build());
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendNotificationReceived(boolean usingMmsRadio, boolean useProxyIfAvailable)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
sendBytes(usingMmsRadio, useProxyIfAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendConf send(boolean useMmsRadio, boolean useProxyIfAvailable) throws IOException {
|
||||||
|
byte[] response = sendBytes(useMmsRadio, useProxyIfAvailable);
|
||||||
|
return (SendConf) new PduParser(response).parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] sendBytes(boolean useMmsRadio, boolean useProxyIfAvailable) throws IOException {
|
||||||
|
final boolean useProxy = useProxyIfAvailable && apn.hasProxy();
|
||||||
|
final String targetHost = useProxy
|
||||||
|
? apn.getProxy()
|
||||||
|
: Uri.parse(apn.getMmsc()).getHost();
|
||||||
|
|
||||||
|
Log.w(TAG, "Sending MMS of length: " + mms.length
|
||||||
|
+ (useMmsRadio ? ", using mms radio" : "")
|
||||||
|
+ (useProxy ? ", using proxy" : ""));
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (checkRouteToHost(context, targetHost, useMmsRadio)) {
|
||||||
|
Log.w(TAG, "got successful route to host " + targetHost);
|
||||||
|
byte[] response = makeRequest(useProxy);
|
||||||
|
if (response != null) return response;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.w(TAG, ioe);
|
||||||
|
}
|
||||||
|
throw new IOException("Connection manager could not obtain route to host.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isConnectionPossible(Context context) {
|
||||||
|
try {
|
||||||
|
ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(MmsRadio.TYPE_MOBILE_MMS);
|
||||||
|
if (networkInfo == null) {
|
||||||
|
Log.w(TAG, "MMS network info was null, unsupported by this device");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getApn(context, networkInfo.getExtraInfo());
|
||||||
|
return true;
|
||||||
|
} catch (ApnUnavailableException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,22 +25,22 @@ import android.util.Pair;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||||
|
import org.thoughtcrime.securesms.mms.IncomingMmsConnection;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsConnection;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsConnection.Apn;
|
||||||
|
import org.thoughtcrime.securesms.mms.OutgoingMmsConnection;
|
||||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.MmsDownloadHelper;
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsSendHelper;
|
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ws.com.google.android.mms.InvalidHeaderValueException;
|
import ws.com.google.android.mms.InvalidHeaderValueException;
|
||||||
import ws.com.google.android.mms.MmsException;
|
import ws.com.google.android.mms.MmsException;
|
||||||
@ -70,7 +70,7 @@ public class MmsDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleMmsPendingApnDownloads(MasterSecret masterSecret) {
|
private void handleMmsPendingApnDownloads(MasterSecret masterSecret) {
|
||||||
if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(context, null))
|
if (!IncomingMmsConnection.isConnectionPossible(context, null))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
@ -135,7 +135,6 @@ public class MmsDownloader {
|
|||||||
retrieveAndStore(masterSecret, messageId, threadId,
|
retrieveAndStore(masterSecret, messageId, threadId,
|
||||||
contentLocation, transactionId, true, false);
|
contentLocation, transactionId, true, false);
|
||||||
radio.disconnect();
|
radio.disconnect();
|
||||||
return;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("MmsDownloader", e);
|
Log.w("MmsDownloader", e);
|
||||||
radio.disconnect();
|
radio.disconnect();
|
||||||
@ -169,9 +168,10 @@ public class MmsDownloader {
|
|||||||
boolean radioEnabled, boolean useProxy)
|
boolean radioEnabled, boolean useProxy)
|
||||||
throws IOException, MmsException, ApnUnavailableException
|
throws IOException, MmsException, ApnUnavailableException
|
||||||
{
|
{
|
||||||
RetrieveConf retrieved = MmsDownloadHelper.retrieveMms(context, contentLocation,
|
Apn dbApn = MmsConnection.getApn(context, radio.getApnInformation());
|
||||||
radio.getApnInformation(),
|
Apn contentApn = new Apn(contentLocation, dbApn.getProxy(), Integer.toString(dbApn.getPort()));
|
||||||
radioEnabled, useProxy);
|
IncomingMmsConnection connection = new IncomingMmsConnection(context, contentApn);
|
||||||
|
RetrieveConf retrieved = connection.retrieve(radioEnabled, useProxy);
|
||||||
|
|
||||||
storeRetrievedMms(masterSecret, contentLocation, messageId, threadId, retrieved);
|
storeRetrievedMms(masterSecret, contentLocation, messageId, threadId, retrieved);
|
||||||
sendRetrievedAcknowledgement(transactionId, radioEnabled, useProxy);
|
sendRetrievedAcknowledgement(transactionId, radioEnabled, useProxy);
|
||||||
@ -206,14 +206,15 @@ public class MmsDownloader {
|
|||||||
private void sendRetrievedAcknowledgement(byte[] transactionId,
|
private void sendRetrievedAcknowledgement(byte[] transactionId,
|
||||||
boolean usingRadio,
|
boolean usingRadio,
|
||||||
boolean useProxy)
|
boolean useProxy)
|
||||||
|
throws ApnUnavailableException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
NotifyRespInd notifyResponse = new NotifyRespInd(PduHeaders.CURRENT_MMS_VERSION,
|
NotifyRespInd notifyResponse = new NotifyRespInd(PduHeaders.CURRENT_MMS_VERSION,
|
||||||
transactionId,
|
transactionId,
|
||||||
PduHeaders.STATUS_RETRIEVED);
|
PduHeaders.STATUS_RETRIEVED);
|
||||||
|
|
||||||
MmsSendHelper.sendNotificationReceived(context, new PduComposer(context, notifyResponse).make(),
|
OutgoingMmsConnection connection = new OutgoingMmsConnection(context, radio.getApnInformation(), new PduComposer(context, notifyResponse).make());
|
||||||
radio.getApnInformation(), usingRadio, useProxy);
|
connection.sendNotificationReceived(usingRadio, useProxy);
|
||||||
} catch (InvalidHeaderValueException e) {
|
} catch (InvalidHeaderValueException e) {
|
||||||
Log.w("MmsDownloader", e);
|
Log.w("MmsDownloader", e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -22,17 +22,17 @@ import android.telephony.TelephonyManager;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsSendHelper;
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsSendResult;
|
import org.thoughtcrime.securesms.mms.MmsSendResult;
|
||||||
|
import org.thoughtcrime.securesms.mms.OutgoingMmsConnection;
|
||||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||||
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||||
import org.whispersystems.textsecure.crypto.SessionCipher;
|
import org.whispersystems.textsecure.crypto.SessionCipher;
|
||||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||||
@ -124,21 +124,25 @@ public class MmsTransport {
|
|||||||
message.setFrom(new EncodedStringValue(number));
|
message.setFrom(new EncodedStringValue(number));
|
||||||
}
|
}
|
||||||
|
|
||||||
SendConf conf = MmsSendHelper.sendMms(context, new PduComposer(context, message).make(),
|
try {
|
||||||
radio.getApnInformation(), usingMmsRadio, useProxy);
|
OutgoingMmsConnection connection = new OutgoingMmsConnection(context, radio.getApnInformation(), new PduComposer(context, message).make());
|
||||||
|
SendConf conf = connection.send(usingMmsRadio, useProxy);
|
||||||
|
|
||||||
for (int i=0;i<message.getBody().getPartsNum();i++) {
|
for (int i=0;i<message.getBody().getPartsNum();i++) {
|
||||||
Log.w("MmsSender", "Sent MMS part of content-type: " + new String(message.getBody().getPart(i).getContentType()));
|
Log.w("MmsSender", "Sent MMS part of content-type: " + new String(message.getBody().getPart(i).getContentType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf == null) {
|
if (conf == null) {
|
||||||
throw new UndeliverableMessageException("No M-Send.conf received in response to send.");
|
throw new UndeliverableMessageException("No M-Send.conf received in response to send.");
|
||||||
} else if (conf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
|
} else if (conf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
|
||||||
throw new UndeliverableMessageException("Got bad response: " + conf.getResponseStatus());
|
throw new UndeliverableMessageException("Got bad response: " + conf.getResponseStatus());
|
||||||
} else if (isInconsistentResponse(message, conf)) {
|
} else if (isInconsistentResponse(message, conf)) {
|
||||||
throw new UndeliverableMessageException("Mismatched response!");
|
throw new UndeliverableMessageException("Mismatched response!");
|
||||||
} else {
|
} else {
|
||||||
return new MmsSendResult(conf.getMessageId(), conf.getResponseStatus(), upgradedSecure, false);
|
return new MmsSendResult(conf.getMessageId(), conf.getResponseStatus(), upgradedSecure, false);
|
||||||
|
}
|
||||||
|
} catch (ApnUnavailableException aue) {
|
||||||
|
throw new IOException("no APN was retrievable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user