mirror of
https://github.com/oxen-io/session-android.git
synced 2025-03-26 18:50:51 +00:00
further clean up unused connections
This commit is contained in:
parent
fcfaa32073
commit
861b4bf9c9
app/src/main/java/org/thoughtcrime/securesms
@ -1,174 +0,0 @@
|
||||
/**
|
||||
* 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.database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.text.TextUtils;
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.mms.LegacyMmsConnection.Apn;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
import org.session.libsignal.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Database to query APN and MMSC information
|
||||
*/
|
||||
public class ApnDatabase {
|
||||
private static final String TAG = ApnDatabase.class.getSimpleName();
|
||||
|
||||
private final SQLiteDatabase db;
|
||||
private final Context context;
|
||||
|
||||
private static final String DATABASE_NAME = "apns.db";
|
||||
private static final String ASSET_PATH = "databases" + File.separator + DATABASE_NAME;
|
||||
|
||||
private static final String TABLE_NAME = "apns";
|
||||
private static final String ID_COLUMN = "_id";
|
||||
private static final String MCC_MNC_COLUMN = "mccmnc";
|
||||
private static final String MCC_COLUMN = "mcc";
|
||||
private static final String MNC_COLUMN = "mnc";
|
||||
private static final String CARRIER_COLUMN = "carrier";
|
||||
private static final String APN_COLUMN = "apn";
|
||||
private static final String MMSC_COLUMN = "mmsc";
|
||||
private static final String PORT_COLUMN = "port";
|
||||
private static final String TYPE_COLUMN = "type";
|
||||
private static final String PROTOCOL_COLUMN = "protocol";
|
||||
private static final String BEARER_COLUMN = "bearer";
|
||||
private static final String ROAMING_PROTOCOL_COLUMN = "roaming_protocol";
|
||||
private static final String CARRIER_ENABLED_COLUMN = "carrier_enabled";
|
||||
private static final String MMS_PROXY_COLUMN = "mmsproxy";
|
||||
private static final String MMS_PORT_COLUMN = "mmsport";
|
||||
private static final String PROXY_COLUMN = "proxy";
|
||||
private static final String MVNO_MATCH_DATA_COLUMN = "mvno_match_data";
|
||||
private static final String MVNO_TYPE_COLUMN = "mvno";
|
||||
private static final String AUTH_TYPE_COLUMN = "authtype";
|
||||
private static final String USER_COLUMN = "user";
|
||||
private static final String PASSWORD_COLUMN = "password";
|
||||
private static final String SERVER_COLUMN = "server";
|
||||
|
||||
private static final String BASE_SELECTION = MCC_MNC_COLUMN + " = ?";
|
||||
|
||||
private static ApnDatabase instance = null;
|
||||
|
||||
public synchronized static ApnDatabase getInstance(Context context) throws IOException {
|
||||
if (instance == null) instance = new ApnDatabase(context.getApplicationContext());
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ApnDatabase(final Context context) throws IOException {
|
||||
this.context = context;
|
||||
|
||||
File dbFile = context.getDatabasePath(DATABASE_NAME);
|
||||
|
||||
if (!dbFile.getParentFile().exists() && !dbFile.getParentFile().mkdir()) {
|
||||
throw new IOException("couldn't make databases directory");
|
||||
}
|
||||
|
||||
Util.copy(context.getAssets().open(ASSET_PATH, AssetManager.ACCESS_STREAMING),
|
||||
new FileOutputStream(dbFile));
|
||||
|
||||
try {
|
||||
this.db = SQLiteDatabase.openDatabase(context.getDatabasePath(DATABASE_NAME).getPath(),
|
||||
null,
|
||||
SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
|
||||
} catch (SQLiteException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Apn getCustomApnParameters() {
|
||||
String mmsc = TextSecurePreferences.getMmscUrl(context).trim();
|
||||
|
||||
if (!TextUtils.isEmpty(mmsc) && !mmsc.startsWith("http"))
|
||||
mmsc = "http://" + mmsc;
|
||||
|
||||
String proxy = TextSecurePreferences.getMmscProxy(context);
|
||||
String port = TextSecurePreferences.getMmscProxyPort(context);
|
||||
String user = TextSecurePreferences.getMmscUsername(context);
|
||||
String pass = TextSecurePreferences.getMmscPassword(context);
|
||||
|
||||
return new Apn(mmsc, proxy, port, user, pass);
|
||||
}
|
||||
|
||||
public Apn getDefaultApnParameters(String mccmnc, String apn) {
|
||||
if (mccmnc == null) {
|
||||
Log.w(TAG, "mccmnc was null, returning null");
|
||||
return Apn.EMPTY;
|
||||
}
|
||||
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
if (apn != null) {
|
||||
Log.d(TAG, "Querying table for MCC+MNC " + mccmnc + " and APN name " + apn);
|
||||
cursor = db.query(TABLE_NAME, null,
|
||||
BASE_SELECTION + " AND " + APN_COLUMN + " = ?",
|
||||
new String[] {mccmnc, apn},
|
||||
null, null, null);
|
||||
}
|
||||
|
||||
if (cursor == null || !cursor.moveToFirst()) {
|
||||
if (cursor != null) cursor.close();
|
||||
Log.d(TAG, "Querying table for MCC+MNC " + mccmnc + " without APN name");
|
||||
cursor = db.query(TABLE_NAME, null,
|
||||
BASE_SELECTION,
|
||||
new String[] {mccmnc},
|
||||
null, null, null);
|
||||
}
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
Apn params = new Apn(cursor.getString(cursor.getColumnIndexOrThrow(MMSC_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PROXY_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(MMS_PORT_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(USER_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(PASSWORD_COLUMN)));
|
||||
Log.d(TAG, "Returning preferred APN " + params);
|
||||
return params;
|
||||
}
|
||||
|
||||
Log.w(TAG, "No matching APNs found, returning null");
|
||||
|
||||
return Apn.EMPTY;
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Optional<Apn> getMmsConnectionParameters(String mccmnc, String apn) {
|
||||
Apn customApn = getCustomApnParameters();
|
||||
Apn defaultApn = getDefaultApnParameters(mccmnc, apn);
|
||||
Apn result = new Apn(customApn, defaultApn,
|
||||
TextSecurePreferences.getUseCustomMmsc(context),
|
||||
TextSecurePreferences.getUseCustomMmscProxy(context),
|
||||
TextSecurePreferences.getUseCustomMmscProxyPort(context),
|
||||
TextSecurePreferences.getUseCustomMmscUsername(context),
|
||||
TextSecurePreferences.getUseCustomMmscPassword(context));
|
||||
|
||||
if (TextUtils.isEmpty(result.getMmsc())) return Optional.absent();
|
||||
else return Optional.of(result);
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2015 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.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.telephony.SmsManager;
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
|
||||
import com.google.android.mms.InvalidHeaderValueException;
|
||||
import com.google.android.mms.pdu_alt.NotifyRespInd;
|
||||
import com.google.android.mms.pdu_alt.PduComposer;
|
||||
import com.google.android.mms.pdu_alt.PduHeaders;
|
||||
import com.google.android.mms.pdu_alt.PduParser;
|
||||
import com.google.android.mms.pdu_alt.RetrieveConf;
|
||||
|
||||
import org.thoughtcrime.securesms.providers.MmsBodyProvider;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class IncomingLollipopMmsConnection extends LollipopMmsConnection implements IncomingMmsConnection {
|
||||
|
||||
public static final String ACTION = IncomingLollipopMmsConnection.class.getCanonicalName() + "MMS_DOWNLOADED_ACTION";
|
||||
private static final String TAG = IncomingLollipopMmsConnection.class.getSimpleName();
|
||||
|
||||
public IncomingLollipopMmsConnection(Context context) {
|
||||
super(context, ACTION);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public synchronized void onResult(Context context, Intent intent) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) {
|
||||
Log.i(TAG, "HTTP status: " + intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, -1));
|
||||
}
|
||||
Log.i(TAG, "code: " + getResultCode() + ", result string: " + getResultData());
|
||||
}
|
||||
|
||||
@Override
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public synchronized @Nullable RetrieveConf retrieve(@NonNull String contentLocation,
|
||||
byte[] transactionId,
|
||||
int subscriptionId) throws MmsException
|
||||
{
|
||||
beginTransaction();
|
||||
|
||||
try {
|
||||
MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext());
|
||||
|
||||
Log.i(TAG, "downloading multimedia from " + contentLocation + " to " + pointer.getUri());
|
||||
|
||||
SmsManager smsManager;
|
||||
|
||||
if (VERSION.SDK_INT >= 22 && subscriptionId != -1) {
|
||||
smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
|
||||
} else {
|
||||
smsManager = SmsManager.getDefault();
|
||||
}
|
||||
|
||||
smsManager.downloadMultimediaMessage(getContext(),
|
||||
contentLocation,
|
||||
pointer.getUri(),
|
||||
null,
|
||||
getPendingIntent());
|
||||
|
||||
waitForResult();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Util.copy(pointer.getInputStream(), baos);
|
||||
pointer.close();
|
||||
|
||||
Log.i(TAG, baos.size() + "-byte response: ");// + Hex.dump(baos.toByteArray()));
|
||||
|
||||
RetrieveConf retrieved = (RetrieveConf) new PduParser(baos.toByteArray()).parse();
|
||||
|
||||
if (retrieved == null) return null;
|
||||
|
||||
sendRetrievedAcknowledgement(transactionId, retrieved.getMmsVersion(), subscriptionId);
|
||||
return retrieved;
|
||||
} catch (IOException | TimeoutException e) {
|
||||
Log.w(TAG, e);
|
||||
throw new MmsException(e);
|
||||
} finally {
|
||||
endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendRetrievedAcknowledgement(byte[] transactionId, int mmsVersion, int subscriptionId) {
|
||||
try {
|
||||
NotifyRespInd retrieveResponse = new NotifyRespInd(mmsVersion, transactionId, PduHeaders.STATUS_RETRIEVED);
|
||||
new OutgoingLollipopMmsConnection(getContext()).send(new PduComposer(getContext(), retrieveResponse).make(), subscriptionId);
|
||||
} catch (UndeliverableMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (InvalidHeaderValueException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.mms.pdu_alt.RetrieveConf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface IncomingMmsConnection {
|
||||
@Nullable
|
||||
RetrieveConf retrieve(@NonNull String contentLocation, byte[] transactionId, int subscriptionId) throws MmsException, MmsRadioException, ApnUnavailableException, IOException;
|
||||
}
|
@ -1,314 +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.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
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.BasicCredentialsProvider;
|
||||
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.apache.http.message.BasicHeader;
|
||||
import org.thoughtcrime.securesms.database.ApnDatabase;
|
||||
import org.session.libsession.utilities.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TelephonyUtil;
|
||||
import org.session.libsignal.libsignal.util.guava.Optional;
|
||||
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class LegacyMmsConnection {
|
||||
|
||||
public static final String USER_AGENT = "Android-Mms/2.0";
|
||||
|
||||
private static final String TAG = LegacyMmsConnection.class.getSimpleName();
|
||||
|
||||
protected final Context context;
|
||||
protected final Apn apn;
|
||||
|
||||
protected LegacyMmsConnection(Context context) throws ApnUnavailableException {
|
||||
this.context = context;
|
||||
this.apn = getApn(context);
|
||||
}
|
||||
|
||||
public static Apn getApn(Context context) throws ApnUnavailableException {
|
||||
|
||||
try {
|
||||
Optional<Apn> params = ApnDatabase.getInstance(context)
|
||||
.getMmsConnectionParameters(TelephonyUtil.getMccMnc(context),
|
||||
TelephonyUtil.getApn(context));
|
||||
|
||||
if (!params.isPresent()) {
|
||||
throw new ApnUnavailableException("No parameters available from ApnDefaults.");
|
||||
}
|
||||
|
||||
return params.get();
|
||||
} catch (IOException ioe) {
|
||||
throw new ApnUnavailableException("ApnDatabase threw an IOException", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isDirectConnect() {
|
||||
// We think Sprint supports direct connection over wifi/data, but not Verizon
|
||||
Set<String> sprintMccMncs = new HashSet<String>() {{
|
||||
add("312530");
|
||||
add("311880");
|
||||
add("311870");
|
||||
add("311490");
|
||||
add("310120");
|
||||
add("316010");
|
||||
add("312190");
|
||||
}};
|
||||
|
||||
return ServiceUtil.getTelephonyManager(context).getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA &&
|
||||
sprintMccMncs.contains(TelephonyUtil.getMccMnc(context));
|
||||
}
|
||||
|
||||
@SuppressWarnings("TryWithIdenticalCatches")
|
||||
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;
|
||||
}
|
||||
|
||||
if (inetAddress == null) {
|
||||
throw new IOException("Unable to lookup host: InetAddress.getByName() returned null.");
|
||||
}
|
||||
|
||||
byte[] ipAddressBytes = inetAddress.getAddress();
|
||||
if (ipAddressBytes == null) {
|
||||
Log.w(TAG, "resolved IP address bytes are null, returning true to attempt a connection anyway.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Checking route to address: " + host + ", " + inetAddress.getHostAddress());
|
||||
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
try {
|
||||
final Method requestRouteMethod = manager.getClass().getMethod("requestRouteToHostAddress", Integer.TYPE, InetAddress.class);
|
||||
final boolean routeToHostObtained = (Boolean) requestRouteMethod.invoke(manager, MmsRadio.TYPE_MOBILE_MMS, inetAddress);
|
||||
Log.i(TAG, "requestRouteToHostAddress(" + inetAddress + ") -> " + routeToHostObtained);
|
||||
return routeToHostObtained;
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
Log.w(TAG, nsme);
|
||||
} catch (IllegalAccessException iae) {
|
||||
Log.w(TAG, iae);
|
||||
} catch (InvocationTargetException ite) {
|
||||
Log.w(TAG, ite);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static byte[] parseResponse(InputStream is) throws IOException {
|
||||
InputStream in = new BufferedInputStream(is);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Util.copy(in, baos);
|
||||
|
||||
Log.i(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();
|
||||
|
||||
URL mmsc = new URL(apn.getMmsc());
|
||||
CredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||
|
||||
if (apn.hasAuthentication()) {
|
||||
credsProvider.setCredentials(new AuthScope(mmsc.getHost(), mmsc.getPort() > -1 ? mmsc.getPort() : mmsc.getDefaultPort()),
|
||||
new UsernamePasswordCredentials(apn.getUsername(), apn.getPassword()));
|
||||
}
|
||||
|
||||
return HttpClients.custom()
|
||||
.setConnectionReuseStrategy(new NoConnectionReuseStrategyHC4())
|
||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
||||
.setUserAgent(TextSecurePreferences.getMmsUserAgent(context, USER_AGENT))
|
||||
.setConnectionManager(new BasicHttpClientConnectionManager())
|
||||
.setDefaultRequestConfig(config)
|
||||
.setDefaultCredentialsProvider(credsProvider)
|
||||
.build();
|
||||
}
|
||||
|
||||
protected byte[] execute(HttpUriRequest request) throws IOException {
|
||||
Log.i(TAG, "connecting to " + apn.getMmsc());
|
||||
|
||||
CloseableHttpClient client = null;
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
client = constructHttpClient();
|
||||
response = client.execute(request);
|
||||
|
||||
Log.i(TAG, "* response code: " + response.getStatusLine());
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
return parseResponse(response.getEntity().getContent());
|
||||
}
|
||||
} catch (NullPointerException npe) {
|
||||
// TODO determine root cause
|
||||
// see: https://github.com/signalapp/Signal-Android/issues/4379
|
||||
throw new IOException(npe);
|
||||
} finally {
|
||||
if (response != null) response.close();
|
||||
if (client != null) client.close();
|
||||
}
|
||||
|
||||
throw new IOException("unhandled response code");
|
||||
}
|
||||
|
||||
protected List<Header> getBaseHeaders() {
|
||||
final String number = getLine1Number(context);
|
||||
|
||||
return new LinkedList<Header>() {{
|
||||
add(new BasicHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"));
|
||||
add(new BasicHeader("x-wap-profile", "http://www.google.com/oha/rdf/ua-profile-kila.xml"));
|
||||
add(new BasicHeader("Content-Type", "application/vnd.wap.mms-message"));
|
||||
add(new BasicHeader("x-carrier-magic", "http://magic.google.com"));
|
||||
if (!TextUtils.isEmpty(number)) {
|
||||
add(new BasicHeader("x-up-calling-line-id", number));
|
||||
add(new BasicHeader("X-MDN", number));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
@SuppressLint("HardwareIds")
|
||||
private static String getLine1Number(@NonNull Context context) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED ||
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED ||
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
|
||||
return TelephonyUtil.getManager(context).getLine1Number();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Apn {
|
||||
|
||||
public static Apn EMPTY = new Apn("", "", "", "", "");
|
||||
|
||||
private final String mmsc;
|
||||
private final String proxy;
|
||||
private final String port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public Apn(String mmsc, String proxy, String port, String username, String password) {
|
||||
this.mmsc = mmsc;
|
||||
this.proxy = proxy;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Apn(Apn customApn, Apn defaultApn,
|
||||
boolean useCustomMmsc,
|
||||
boolean useCustomProxy,
|
||||
boolean useCustomProxyPort,
|
||||
boolean useCustomUsername,
|
||||
boolean useCustomPassword)
|
||||
{
|
||||
this.mmsc = useCustomMmsc ? customApn.mmsc : defaultApn.mmsc;
|
||||
this.proxy = useCustomProxy ? customApn.proxy : defaultApn.proxy;
|
||||
this.port = useCustomProxyPort ? customApn.port : defaultApn.port;
|
||||
this.username = useCustomUsername ? customApn.username : defaultApn.username;
|
||||
this.password = useCustomPassword ? customApn.password : defaultApn.password;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean hasAuthentication() {
|
||||
return !TextUtils.isEmpty(username);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return Apn.class.getSimpleName() +
|
||||
"{ mmsc: \"" + mmsc + "\"" +
|
||||
", proxy: " + (proxy == null ? "none" : '"' + proxy + '"') +
|
||||
", port: " + (port == null ? "(none)" : port) +
|
||||
", user: " + (username == null ? "none" : '"' + username + '"') +
|
||||
", pass: " + (password == null ? "none" : '"' + password + '"') + " }";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2015 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.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public abstract class LollipopMmsConnection extends BroadcastReceiver {
|
||||
private static final String TAG = LollipopMmsConnection.class.getSimpleName();
|
||||
|
||||
private final Context context;
|
||||
private final String action;
|
||||
|
||||
private boolean resultAvailable;
|
||||
|
||||
public abstract void onResult(Context context, Intent intent);
|
||||
|
||||
protected LollipopMmsConnection(Context context, String action) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onReceive(Context context, Intent intent) {
|
||||
Log.i(TAG, "onReceive()");
|
||||
if (!action.equals(intent.getAction())) {
|
||||
Log.w(TAG, "received broadcast with unexpected action " + intent.getAction());
|
||||
return;
|
||||
}
|
||||
|
||||
onResult(context, intent);
|
||||
|
||||
resultAvailable = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
protected void beginTransaction() {
|
||||
getContext().getApplicationContext().registerReceiver(this, new IntentFilter(action));
|
||||
}
|
||||
|
||||
protected void endTransaction() {
|
||||
getContext().getApplicationContext().unregisterReceiver(this);
|
||||
resultAvailable = false;
|
||||
}
|
||||
|
||||
protected void waitForResult() throws TimeoutException {
|
||||
long timeoutExpiration = System.currentTimeMillis() + 60000;
|
||||
while (!resultAvailable) {
|
||||
Util.wait(this, Math.max(1, timeoutExpiration - System.currentTimeMillis()));
|
||||
if (System.currentTimeMillis() >= timeoutExpiration) {
|
||||
throw new TimeoutException("timeout when waiting for MMS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected PendingIntent getPendingIntent() {
|
||||
return PendingIntent.getBroadcast(getContext(), 1, new Intent(action), PendingIntent.FLAG_ONE_SHOT);
|
||||
}
|
||||
|
||||
protected Context getContext() {
|
||||
return context;
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2015 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.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.telephony.SmsManager;
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
|
||||
import com.android.mms.service_alt.MmsConfig;
|
||||
import com.google.android.mms.pdu_alt.PduParser;
|
||||
import com.google.android.mms.pdu_alt.SendConf;
|
||||
|
||||
import org.thoughtcrime.securesms.providers.MmsBodyProvider;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
|
||||
import org.session.libsession.utilities.Util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class OutgoingLollipopMmsConnection extends LollipopMmsConnection implements OutgoingMmsConnection {
|
||||
private static final String TAG = OutgoingLollipopMmsConnection.class.getSimpleName();
|
||||
private static final String ACTION = OutgoingLollipopMmsConnection.class.getCanonicalName() + "MMS_SENT_ACTION";
|
||||
|
||||
private byte[] response;
|
||||
|
||||
public OutgoingLollipopMmsConnection(Context context) {
|
||||
super(context, ACTION);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP_MR1)
|
||||
@Override
|
||||
public synchronized void onResult(Context context, Intent intent) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) {
|
||||
Log.i(TAG, "HTTP status: " + intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, -1));
|
||||
}
|
||||
|
||||
response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
|
||||
}
|
||||
|
||||
@Override
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public @Nullable synchronized SendConf send(@NonNull byte[] pduBytes, int subscriptionId)
|
||||
throws UndeliverableMessageException
|
||||
{
|
||||
beginTransaction();
|
||||
try {
|
||||
MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext());
|
||||
Util.copy(new ByteArrayInputStream(pduBytes), pointer.getOutputStream());
|
||||
|
||||
SmsManager smsManager;
|
||||
|
||||
if (VERSION.SDK_INT >= 22 && subscriptionId != -1) {
|
||||
smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
|
||||
} else {
|
||||
smsManager = SmsManager.getDefault();
|
||||
}
|
||||
|
||||
Bundle configOverrides = new Bundle();
|
||||
configOverrides.putBoolean(SmsManager.MMS_CONFIG_GROUP_MMS_ENABLED, true);
|
||||
|
||||
MmsConfig mmsConfig = MmsConfigManager.getMmsConfig(getContext(), subscriptionId);
|
||||
|
||||
if (mmsConfig != null) {
|
||||
MmsConfig.Overridden overridden = new MmsConfig.Overridden(mmsConfig, new Bundle());
|
||||
configOverrides.putString(SmsManager.MMS_CONFIG_HTTP_PARAMS, overridden.getHttpParams());
|
||||
configOverrides.putInt(SmsManager.MMS_CONFIG_MAX_MESSAGE_SIZE, overridden.getMaxMessageSize());
|
||||
}
|
||||
|
||||
smsManager.sendMultimediaMessage(getContext(),
|
||||
pointer.getUri(),
|
||||
null,
|
||||
configOverrides,
|
||||
getPendingIntent());
|
||||
|
||||
waitForResult();
|
||||
|
||||
Log.i(TAG, "MMS broadcast received and processed.");
|
||||
pointer.close();
|
||||
|
||||
if (response == null) {
|
||||
throw new UndeliverableMessageException("Null response.");
|
||||
}
|
||||
|
||||
return (SendConf) new PduParser(response).parse();
|
||||
} catch (IOException | TimeoutException e) {
|
||||
throw new UndeliverableMessageException(e);
|
||||
} finally {
|
||||
endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.mms.pdu_alt.SendConf;
|
||||
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
|
||||
|
||||
public interface OutgoingMmsConnection {
|
||||
@Nullable
|
||||
SendConf send(@NonNull byte[] pduBytes, int subscriptionId) throws UndeliverableMessageException;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user