mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Initial fixes for MMS retrieval.
1) Parse the APN information based on what the ConnectionManager tells us. 2) Accept email addresses as a valid Recipient format.
This commit is contained in:
parent
59e7226183
commit
cf9dc51f31
@ -421,9 +421,9 @@ public class MmsDatabase extends Database {
|
||||
database.delete(TABLE_NAME, null, null);
|
||||
}
|
||||
|
||||
public Cursor getCarrierMmsInformation() {
|
||||
public Cursor getCarrierMmsInformation(String apn) {
|
||||
Uri uri = Uri.withAppendedPath(Uri.parse("content://telephony/carriers"), "current");
|
||||
String selection = "type = 'mms'";
|
||||
String selection = (apn == null || apn.trim().length() == 0) ? null : String.format("apn = '%s'", apn.trim());
|
||||
|
||||
return context.getContentResolver().query(uri, null, selection, null, null);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,15 +10,16 @@
|
||||
* 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 java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
@ -42,57 +43,58 @@ import org.thoughtcrime.securesms.util.Conversions;
|
||||
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Uri;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class MmsCommunication {
|
||||
|
||||
protected static MmsConnectionParameters getMmsConnectionParameters(Context context) throws MmsException {
|
||||
Cursor cursor = DatabaseFactory.getMmsDatabase(context).getCarrierMmsInformation();
|
||||
|
||||
protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn)
|
||||
throws MmsException
|
||||
{
|
||||
Cursor cursor = DatabaseFactory.getMmsDatabase(context).getCarrierMmsInformation(apn);
|
||||
|
||||
try {
|
||||
if (cursor == null || !cursor.moveToFirst())
|
||||
throw new MmsException("No carrier MMS information available.");
|
||||
|
||||
throw new MmsException("No carrier MMS information available.");
|
||||
|
||||
do {
|
||||
String mmsc = cursor.getString(cursor.getColumnIndexOrThrow("mmsc"));
|
||||
String proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy"));
|
||||
String port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport"));
|
||||
|
||||
|
||||
if (mmsc != null && !mmsc.equals(""))
|
||||
return new MmsConnectionParameters(mmsc, proxy, port);
|
||||
|
||||
|
||||
} while (cursor.moveToNext());
|
||||
|
||||
|
||||
throw new MmsException("No carrier MMS information available.");
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static void checkRouteToHost(Context context, MmsConnectionParameters parameters, String url) throws IOException {
|
||||
if (parameters == null || !parameters.hasProxy())
|
||||
checkRouteToHost(context, Uri.parse(url).getHost());
|
||||
else
|
||||
checkRouteToHost(context, parameters.getProxy());
|
||||
}
|
||||
|
||||
|
||||
private static void checkRouteToHost(Context context, String host) throws IOException {
|
||||
InetAddress inetAddress = InetAddress.getByName(host);
|
||||
byte[] ipAddressBytes = inetAddress.getAddress();
|
||||
int ipAddress = Conversions.byteArrayToIntLittleEndian(ipAddressBytes, 0);
|
||||
ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
|
||||
if (!manager.requestRouteToHost(MmsDownloader.TYPE_MOBILE_MMS, ipAddress))
|
||||
throw new IOException("Connection manager could not obtain route to host.");
|
||||
throw new IOException("Connection manager could not obtain route to host.");
|
||||
// if (!manager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE, ipAddress))
|
||||
// throw new IOException("Connection manager could not obtain route to host.");
|
||||
// throw new IOException("Connection manager could not obtain route to host.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected static HttpClient constructHttpClient(MmsConnectionParameters mmsConfig) {
|
||||
HttpParams params = new BasicHttpParams();
|
||||
HttpConnectionParams.setStaleCheckingEnabled(params, false);
|
||||
@ -102,11 +104,11 @@ public class MmsCommunication {
|
||||
HttpClientParams.setRedirecting(params, false);
|
||||
HttpProtocolParams.setUserAgent(params, "TextSecure/0.1");
|
||||
HttpProtocolParams.setContentCharset(params, "UTF-8");
|
||||
|
||||
|
||||
if (mmsConfig.hasProxy()) {
|
||||
ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsConfig.getProxy(), mmsConfig.getPort()));
|
||||
}
|
||||
|
||||
|
||||
SchemeRegistry schemeRegistry = new SchemeRegistry();
|
||||
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
|
||||
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
|
||||
@ -114,47 +116,47 @@ public class MmsCommunication {
|
||||
ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
|
||||
return new DefaultHttpClient(manager, params);
|
||||
}
|
||||
|
||||
|
||||
protected static byte[] parseResponse(HttpEntity entity) throws IOException {
|
||||
if (entity == null || entity.getContentLength() == 0)
|
||||
throw new IOException("Null response");
|
||||
|
||||
|
||||
byte[] responseBytes = new byte[(int)entity.getContentLength()];
|
||||
DataInputStream dataInputStream = new DataInputStream(entity.getContent());
|
||||
dataInputStream.readFully(responseBytes);
|
||||
dataInputStream.close();
|
||||
|
||||
|
||||
entity.consumeContent();
|
||||
return responseBytes;
|
||||
return responseBytes;
|
||||
}
|
||||
|
||||
|
||||
protected static class MmsConnectionParameters {
|
||||
private final String mmsc;
|
||||
private final String proxy;
|
||||
private final String port;
|
||||
|
||||
|
||||
public MmsConnectionParameters(String mmsc, String proxy, String port) {
|
||||
this.mmsc = mmsc;
|
||||
this.proxy = proxy;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
|
||||
public boolean hasProxy() {
|
||||
return proxy != null && proxy.trim().length() != 0;
|
||||
}
|
||||
|
||||
|
||||
public String getMmsc() {
|
||||
return mmsc;
|
||||
}
|
||||
|
||||
|
||||
public String getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
public int getPort() {
|
||||
if (port == null || port.trim().length() == 0)
|
||||
return 80;
|
||||
|
||||
|
||||
return Integer.parseInt(port);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,15 +10,14 @@
|
||||
* 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 java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
@ -30,38 +29,41 @@ import org.apache.http.client.methods.HttpGet;
|
||||
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class MmsDownloadHelper extends MmsCommunication {
|
||||
|
||||
private static byte[] makeRequest(MmsConnectionParameters connectionParameters, String url) throws ClientProtocolException, IOException {
|
||||
|
||||
private static byte[] makeRequest(MmsConnectionParameters connectionParameters, String url)
|
||||
throws ClientProtocolException, IOException
|
||||
{
|
||||
try {
|
||||
HttpClient client = constructHttpClient(connectionParameters);
|
||||
HttpClient client = constructHttpClient(connectionParameters);
|
||||
URI hostUrl = new URI(url);
|
||||
HttpHost target = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
|
||||
HttpRequest request = new HttpGet(url);
|
||||
|
||||
|
||||
request.setParams(client.getParams());
|
||||
request.addHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
||||
|
||||
|
||||
HttpResponse response = client.execute(target, request);
|
||||
StatusLine status = response.getStatusLine();
|
||||
|
||||
|
||||
if (status.getStatusCode() != 200)
|
||||
throw new IOException("Non-successful HTTP response: " + status.getReasonPhrase());
|
||||
|
||||
|
||||
return parseResponse(response.getEntity());
|
||||
} catch (URISyntaxException use) {
|
||||
Log.w("MmsDownlader", use);
|
||||
throw new IOException("Bad URI syntax");
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] retrieveMms(Context context, String url) throws IOException {
|
||||
|
||||
public static byte[] retrieveMms(Context context, String url, String apn) throws IOException {
|
||||
try {
|
||||
MmsConnectionParameters connectionParameters = getMmsConnectionParameters(context);
|
||||
|
||||
MmsConnectionParameters connectionParameters = getMmsConnectionParameters(context, apn);
|
||||
|
||||
checkRouteToHost(context, connectionParameters, url);
|
||||
return makeRequest(connectionParameters, url);
|
||||
} catch (MmsException me) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,15 +10,14 @@
|
||||
* 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 java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
@ -27,14 +26,15 @@ import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
public class MmsSendHelper extends MmsCommunication {
|
||||
|
||||
|
||||
private static byte[] makePost(MmsConnectionParameters parameters, byte[] mms) throws ClientProtocolException, IOException {
|
||||
Log.w("MmsSender", "Sending MMS1 of length: " + mms.length);
|
||||
try {
|
||||
@ -43,30 +43,30 @@ public class MmsSendHelper extends MmsCommunication {
|
||||
HttpHost target = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
|
||||
HttpPost request = new HttpPost(parameters.getMmsc());
|
||||
ByteArrayEntity entity = new ByteArrayEntity(mms);
|
||||
|
||||
|
||||
entity.setContentType("application/vnd.wap.mms-message");
|
||||
|
||||
|
||||
request.setEntity(entity);
|
||||
request.setParams(client.getParams());
|
||||
request.addHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic");
|
||||
|
||||
|
||||
HttpResponse response = client.execute(target, request);
|
||||
StatusLine status = response.getStatusLine();
|
||||
|
||||
|
||||
if (status.getStatusCode() != 200)
|
||||
throw new IOException("Non-successful HTTP response: " + status.getReasonPhrase());
|
||||
|
||||
|
||||
return parseResponse(response.getEntity());
|
||||
} catch (URISyntaxException use) {
|
||||
Log.w("MmsDownlader", use);
|
||||
throw new IOException("Bad URI syntax");
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] sendMms(Context context, byte[] mms) throws IOException {
|
||||
|
||||
public static byte[] sendMms(Context context, byte[] mms, String apn) throws IOException {
|
||||
Log.w("MmsSender", "Sending MMS of length: " + mms.length);
|
||||
try {
|
||||
MmsConnectionParameters parameters = getMmsConnectionParameters(context);
|
||||
MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn);
|
||||
checkRouteToHost(context, parameters, parameters.getMmsc());
|
||||
return makePost(parameters, mms);
|
||||
} catch (MmsException me) {
|
||||
|
@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.recipients;
|
||||
import android.content.Context;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@ -146,7 +145,7 @@ public class RecipientFactory {
|
||||
int end = recipient.indexOf('>');
|
||||
String value = recipient.substring(begin + 1, end);
|
||||
|
||||
if (PhoneNumberUtils.isWellFormedSmsAddress(value))
|
||||
if (NumberUtil.isValidSmsOrEmail(value))
|
||||
return value;
|
||||
else
|
||||
throw new RecipientFormattingException("Bracketed value: " + value + " is not valid.");
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,14 +10,15 @@
|
||||
* 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.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingQueue;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
@ -29,20 +30,20 @@ import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.PduParser;
|
||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class MmsDownloader extends MmscProcessor {
|
||||
|
||||
private final LinkedList<DownloadItem> pendingMessages = new LinkedList<DownloadItem>();
|
||||
private final SendReceiveService.ToastHandler toastHandler;
|
||||
|
||||
|
||||
public MmsDownloader(Context context, SendReceiveService.ToastHandler toastHandler) {
|
||||
super(context);
|
||||
this.toastHandler = toastHandler;
|
||||
}
|
||||
|
||||
|
||||
private void handleDownloadMms(DownloadItem item) {
|
||||
if (!isConnectivityPossible()) {
|
||||
DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_NO_CONNECTIVITY);
|
||||
@ -54,37 +55,38 @@ public class MmsDownloader extends MmscProcessor {
|
||||
issueConnectivityRequest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleDownloadMmsContinued(DownloadItem item) {
|
||||
Log.w("MmsDownloadService", "Handling MMS download continuation...");
|
||||
MmsDatabase mmsDatabase;
|
||||
|
||||
|
||||
if (item.getMasterSecret() == null)
|
||||
mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||
else
|
||||
mmsDatabase = DatabaseFactory.getEncryptingMmsDatabase(context, item.getMasterSecret());
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
byte[] pdu = MmsDownloadHelper.retrieveMms(context, item.getContentLocation());
|
||||
byte[] pdu = MmsDownloadHelper.retrieveMms(context, item.getContentLocation(),
|
||||
getApnInformation());
|
||||
RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse();
|
||||
|
||||
for (int i=0;i<retrieved.getBody().getPartsNum();i++) {
|
||||
Log.w("MmsDownloader", "Sent MMS part of content-type: " + new String(retrieved.getBody().getPart(i).getContentType()));
|
||||
Log.w("MmsDownloader", "Sent MMS part of content-type: " + new String(retrieved.getBody().getPart(i).getContentType()));
|
||||
}
|
||||
|
||||
if (retrieved == null)
|
||||
throw new IOException("Bad retrieved PDU");
|
||||
|
||||
|
||||
|
||||
if (retrieved.getSubject() != null && WirePrefix.isEncryptedMmsSubject(retrieved.getSubject().getString())) {
|
||||
long messageId = mmsDatabase.insertSecureMessageReceived(retrieved, item.getContentLocation(), item.getThreadId());
|
||||
if (item.getMasterSecret() != null)
|
||||
DecryptingQueue.scheduleDecryption(context, item.getMasterSecret(), messageId, item.getThreadId(), retrieved);
|
||||
} else {
|
||||
mmsDatabase.insertMessageReceived(retrieved, item.getContentLocation(), item.getThreadId());
|
||||
mmsDatabase.insertMessageReceived(retrieved, item.getContentLocation(), item.getThreadId());
|
||||
}
|
||||
|
||||
|
||||
mmsDatabase.delete(item.getMessageId());
|
||||
|
||||
// NotifyRespInd notifyResponse = new NotifyRespInd(PduHeaders.CURRENT_MMS_VERSION, item.getTransactionId(), PduHeaders.STATUS_RETRIEVED);
|
||||
@ -92,7 +94,7 @@ public class MmsDownloader extends MmscProcessor {
|
||||
|
||||
if (this.pendingMessages.isEmpty())
|
||||
finishConnectivity();
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_SOFT_FAILURE);
|
||||
toastHandler.makeToast("Error connecting to MMS provider...");
|
||||
@ -103,7 +105,7 @@ public class MmsDownloader extends MmscProcessor {
|
||||
Log.w("MmsDownloader", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void handleConnectivityChange() {
|
||||
if (!isConnected()) {
|
||||
if (!isConnectivityPossible() && !pendingMessages.isEmpty()) {
|
||||
@ -112,36 +114,36 @@ public class MmsDownloader extends MmscProcessor {
|
||||
Log.w("MmsDownloadService", "Unable to download MMS, please try again later.");
|
||||
finishConnectivity();
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!pendingMessages.isEmpty()) handleDownloadMmsContinued(pendingMessages.remove());
|
||||
else finishConnectivity();
|
||||
}
|
||||
|
||||
|
||||
public void process(MasterSecret masterSecret, Intent intent) {
|
||||
if (intent.getAction().equals(SendReceiveService.DOWNLOAD_MMS_ACTION)) {
|
||||
DownloadItem item = new DownloadItem(intent.getLongExtra("message_id", -1),
|
||||
DownloadItem item = new DownloadItem(intent.getLongExtra("message_id", -1),
|
||||
intent.getLongExtra("thread_id", -1),
|
||||
intent.getStringExtra("content_location"),
|
||||
intent.getByteArrayExtra("transaction_id"),
|
||||
masterSecret);
|
||||
|
||||
handleDownloadMms(item);
|
||||
handleDownloadMms(item);
|
||||
} else if (intent.getAction().equals(SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION)) {
|
||||
handleConnectivityChange();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class DownloadItem {
|
||||
private long threadId;
|
||||
private long messageId;
|
||||
private byte[] transactionId;
|
||||
private String contentLocation;
|
||||
private MasterSecret masterSecret;
|
||||
|
||||
|
||||
public DownloadItem(long messageId, long threadId, String contentLocation, byte[] transactionId, MasterSecret masterSecret) {
|
||||
this.threadId = threadId;
|
||||
this.messageId = messageId;
|
||||
@ -149,23 +151,23 @@ public class MmsDownloader extends MmscProcessor {
|
||||
this.masterSecret = masterSecret;
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
|
||||
public long getThreadId() {
|
||||
return threadId;
|
||||
}
|
||||
|
||||
|
||||
public long getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
|
||||
public String getContentLocation() {
|
||||
return contentLocation;
|
||||
}
|
||||
|
||||
|
||||
public byte[] getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
|
||||
public MasterSecret getMasterSecret() {
|
||||
return masterSecret;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,12 +10,16 @@
|
||||
* 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.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@ -24,18 +28,15 @@ import ws.com.google.android.mms.pdu.GenericPdu;
|
||||
import ws.com.google.android.mms.pdu.NotificationInd;
|
||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||
import ws.com.google.android.mms.pdu.PduParser;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public class MmsReceiver {
|
||||
|
||||
|
||||
private final Context context;
|
||||
|
||||
|
||||
public MmsReceiver(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
private void scheduleDownload(NotificationInd pdu, long messageId) {
|
||||
Intent intent = new Intent(SendReceiveService.DOWNLOAD_MMS_ACTION, null, context, SendReceiveService.class);
|
||||
intent.putExtra("content_location", new String(pdu.getContentLocation()));
|
||||
@ -45,7 +46,7 @@ public class MmsReceiver {
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
|
||||
public void process(MasterSecret masterSecret, Intent intent) {
|
||||
byte[] mmsData = intent.getByteArrayExtra("data");
|
||||
PduParser parser = new PduParser(mmsData);
|
||||
@ -53,17 +54,17 @@ public class MmsReceiver {
|
||||
|
||||
if (pdu.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
|
||||
MmsDatabase database;
|
||||
|
||||
|
||||
if (masterSecret != null)
|
||||
database = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret);
|
||||
database = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret);
|
||||
else
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
long messageId = database.insertMessageReceived((NotificationInd)pdu);
|
||||
MessageNotifier.updateNotification(context, true);
|
||||
scheduleDownload((NotificationInd)pdu, messageId);
|
||||
Log.w("MmsReceiverService", "Inserted received notification...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,22 +10,22 @@
|
||||
* 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.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.SessionCipher;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.mms.MmsSendHelper;
|
||||
import org.thoughtcrime.securesms.mms.PngTransport;
|
||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||
import org.thoughtcrime.securesms.protocol.WirePrefix;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -33,7 +33,6 @@ import org.thoughtcrime.securesms.util.Hex;
|
||||
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.CharacterSets;
|
||||
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
||||
import ws.com.google.android.mms.pdu.PduBody;
|
||||
import ws.com.google.android.mms.pdu.PduComposer;
|
||||
@ -42,51 +41,51 @@ import ws.com.google.android.mms.pdu.PduParser;
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
import ws.com.google.android.mms.pdu.SendConf;
|
||||
import ws.com.google.android.mms.pdu.SendReq;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class MmsSender extends MmscProcessor {
|
||||
|
||||
private final LinkedList<SendReq[]> pendingMessages = new LinkedList<SendReq[]>();
|
||||
|
||||
|
||||
public MmsSender(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void process(MasterSecret masterSecret, Intent intent) {
|
||||
if (intent.getAction().equals(SendReceiveService.SEND_MMS_ACTION)) {
|
||||
long messageId = intent.getLongExtra("message_id", -1);
|
||||
long messageId = intent.getLongExtra("message_id", -1);
|
||||
MmsDatabase database = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret);
|
||||
|
||||
try {
|
||||
SendReq[] sendRequests;
|
||||
|
||||
if (messageId == -1) {
|
||||
sendRequests = database.getOutgoingMessages();
|
||||
} else {
|
||||
sendRequests = new SendReq[1];
|
||||
sendRequests[0] = database.getSendRequest(messageId);
|
||||
}
|
||||
|
||||
if (sendRequests.length > 0)
|
||||
handleSendMms(sendRequests);
|
||||
|
||||
SendReq[] sendRequests;
|
||||
|
||||
if (messageId == -1) {
|
||||
sendRequests = database.getOutgoingMessages();
|
||||
} else {
|
||||
sendRequests = new SendReq[1];
|
||||
sendRequests[0] = database.getSendRequest(messageId);
|
||||
}
|
||||
|
||||
if (sendRequests.length > 0)
|
||||
handleSendMms(sendRequests);
|
||||
|
||||
} catch (MmsException me) {
|
||||
Log.w("MmsSender", me);
|
||||
if (messageId != -1)
|
||||
database.markAsSentFailed(messageId);
|
||||
}
|
||||
Log.w("MmsSender", me);
|
||||
if (messageId != -1)
|
||||
database.markAsSentFailed(messageId);
|
||||
}
|
||||
} else if (intent.getAction().equals(SendReceiveService.SEND_MMS_CONNECTIVITY_ACTION)) {
|
||||
handleConnectivityChange(masterSecret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void handleConnectivityChange(MasterSecret masterSecret) {
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
|
||||
if (!pendingMessages.isEmpty()) handleSendMmsContinued(masterSecret, pendingMessages.remove());
|
||||
else finishConnectivity();
|
||||
}
|
||||
@ -94,13 +93,13 @@ public class MmsSender extends MmscProcessor {
|
||||
private void handleSendMms(SendReq[] sendRequests) {
|
||||
if (!isConnectivityPossible()) {
|
||||
for (int i=0;i<sendRequests.length;i++)
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(sendRequests[i].getDatabaseMessageId());
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(sendRequests[i].getDatabaseMessageId());
|
||||
} else {
|
||||
pendingMessages.add(sendRequests);
|
||||
issueConnectivityRequest();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean isInconsistentResponse(SendReq send, SendConf response) {
|
||||
Log.w("MmsSenderService", "Comparing: " + Hex.toString(send.getTransactionId()));
|
||||
Log.w("MmsSenderService", "With: " + Hex.toString(response.getTransactionId()));
|
||||
@ -113,7 +112,7 @@ public class MmsSender extends MmscProcessor {
|
||||
return cipher.encryptMessage(pduBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private SendReq getEncryptedMms(MasterSecret masterSecret, SendReq pdu, long messageId) {
|
||||
Log.w("MmsSender", "Sending Secure MMS.");
|
||||
EncodedStringValue[] encodedRecipient = pdu.getTo();
|
||||
@ -131,51 +130,51 @@ public class MmsSender extends MmscProcessor {
|
||||
body.addPart(part);
|
||||
pdu.setSubject(new EncodedStringValue(WirePrefix.calculateEncryptedMmsSubject()));
|
||||
pdu.setBody(body);
|
||||
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
|
||||
private void sendMms(MmsDatabase db, SendReq pdu, String number, long messageId, boolean secure) {
|
||||
try {
|
||||
if (number != null && number.trim().length() != 0)
|
||||
pdu.setFrom(new EncodedStringValue(number));
|
||||
|
||||
byte[] response = MmsSendHelper.sendMms(context, new PduComposer(context, pdu).make());
|
||||
pdu.setFrom(new EncodedStringValue(number));
|
||||
|
||||
byte[] response = MmsSendHelper.sendMms(context, new PduComposer(context, pdu).make(), getApnInformation());
|
||||
SendConf conf = (SendConf) new PduParser(response).parse();
|
||||
|
||||
|
||||
for (int i=0;i<pdu.getBody().getPartsNum();i++) {
|
||||
Log.w("MmsSender", "Sent MMS part of content-type: " + new String(pdu.getBody().getPart(i).getContentType()));
|
||||
Log.w("MmsSender", "Sent MMS part of content-type: " + new String(pdu.getBody().getPart(i).getContentType()));
|
||||
}
|
||||
|
||||
|
||||
if (conf == null) {
|
||||
db.markAsSentFailed(messageId);
|
||||
Log.w("MmsSender", "No M-Send.conf received in response to send.");
|
||||
return;
|
||||
db.markAsSentFailed(messageId);
|
||||
Log.w("MmsSender", "No M-Send.conf received in response to send.");
|
||||
return;
|
||||
} else if (conf.getResponseStatus() != PduHeaders.RESPONSE_STATUS_OK) {
|
||||
Log.w("MmsSender", "Got bad response: " + conf.getResponseStatus());
|
||||
db.updateResponseStatus(messageId, conf.getResponseStatus());
|
||||
db.markAsSentFailed(messageId);
|
||||
return;
|
||||
Log.w("MmsSender", "Got bad response: " + conf.getResponseStatus());
|
||||
db.updateResponseStatus(messageId, conf.getResponseStatus());
|
||||
db.markAsSentFailed(messageId);
|
||||
return;
|
||||
} else if (isInconsistentResponse(pdu, conf)) {
|
||||
db.markAsSentFailed(messageId);
|
||||
Log.w("MmsSender", "Got a response for the wrong transaction?");
|
||||
return;
|
||||
} else {
|
||||
Log.w("MmsSender", "Successful send! " + messageId);
|
||||
if (!secure)
|
||||
db.markAsSent(messageId, conf.getMessageId(), conf.getResponseStatus());
|
||||
else
|
||||
db.markAsSecureSent(messageId, conf.getMessageId(), conf.getResponseStatus());
|
||||
}
|
||||
db.markAsSentFailed(messageId);
|
||||
Log.w("MmsSender", "Got a response for the wrong transaction?");
|
||||
return;
|
||||
} else {
|
||||
Log.w("MmsSender", "Successful send! " + messageId);
|
||||
if (!secure)
|
||||
db.markAsSent(messageId, conf.getMessageId(), conf.getResponseStatus());
|
||||
else
|
||||
db.markAsSecureSent(messageId, conf.getMessageId(), conf.getResponseStatus());
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Log.w("MmsSender", ioe);
|
||||
db.markAsSentFailed(messageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void handleSendMmsContinued(MasterSecret masterSecret, SendReq[] requests) {
|
||||
Log.w("MmsSenderService", "Handling MMS send continuation...");
|
||||
|
||||
|
||||
MmsDatabase db = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret);
|
||||
String number = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();
|
||||
|
||||
@ -183,19 +182,19 @@ public class MmsSender extends MmscProcessor {
|
||||
SendReq request = requests[i];
|
||||
long messageId = request.getDatabaseMessageId();
|
||||
long messageBox = request.getDatabaseMessageBox();
|
||||
|
||||
|
||||
if (MmsDatabase.Types.isSecureMmsBox(messageBox))
|
||||
request = getEncryptedMms(masterSecret, request, messageId);
|
||||
|
||||
request = getEncryptedMms(masterSecret, request, messageId);
|
||||
|
||||
sendMms(db, request, number, messageId, MmsDatabase.Types.isSecureMmsBox(messageBox));
|
||||
}
|
||||
|
||||
|
||||
if (this.pendingMessages.isEmpty())
|
||||
finishConnectivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConnectivityAction() {
|
||||
protected String getConnectivityAction() {
|
||||
return SendReceiveService.SEND_MMS_CONNECTIVITY_ACTION;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@ -10,14 +10,12 @@
|
||||
* 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.service;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -36,34 +34,38 @@ public abstract class MmscProcessor {
|
||||
|
||||
private ConnectivityManager connectivityManager;
|
||||
private ConnectivityListener connectivityListener;
|
||||
private WakeLock wakeLock;
|
||||
|
||||
private WakeLock wakeLock;
|
||||
|
||||
protected final Context context;
|
||||
|
||||
|
||||
public MmscProcessor(Context context) {
|
||||
this.context = context;
|
||||
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
||||
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
|
||||
this.connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MMS Connection");
|
||||
this.wakeLock.setReferenceCounted(false);
|
||||
}
|
||||
|
||||
|
||||
protected String getApnInformation() {
|
||||
return connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS).getExtraInfo();
|
||||
}
|
||||
|
||||
protected boolean isConnected() {
|
||||
NetworkInfo info = connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS);
|
||||
|
||||
|
||||
Log.w("MmsService", "NetworkInfo: " + info);
|
||||
|
||||
|
||||
if ((info == null) || (info.getType() != TYPE_MOBILE_MMS) || !info.isConnected())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected abstract String getConnectivityAction();
|
||||
|
||||
|
||||
protected void issueConnectivityRequest() {
|
||||
int status = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_MMS);
|
||||
|
||||
|
||||
if (status == APN_ALREADY_ACTIVE) {
|
||||
issueConnectivityChange();
|
||||
} else if (connectivityListener == null) {
|
||||
@ -74,7 +76,7 @@ public abstract class MmscProcessor {
|
||||
wakeLock.acquire();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean isConnectivityPossible() {
|
||||
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(TYPE_MOBILE_MMS);
|
||||
Log.w("MmsService", "Got network info: " + networkInfo);
|
||||
@ -84,25 +86,25 @@ public abstract class MmscProcessor {
|
||||
protected void finishConnectivity() {
|
||||
Log.w("MmsService", "Calling stop using network feature!");
|
||||
connectivityManager.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, FEATURE_ENABLE_MMS);
|
||||
|
||||
|
||||
if (connectivityListener != null) {
|
||||
context.unregisterReceiver(connectivityListener);
|
||||
connectivityListener = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.wakeLock.isHeld())
|
||||
this.wakeLock.release();
|
||||
}
|
||||
|
||||
|
||||
private void issueConnectivityChange() {
|
||||
Intent intent = new Intent(context, SendReceiveService.class);
|
||||
intent.setAction(getConnectivityAction());
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
|
||||
private class ConnectivityListener extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.w("MmsService", "Dispatching connectivity change...");
|
||||
issueConnectivityChange();
|
||||
Log.w("MmsService", "Dispatched...");
|
||||
|
Loading…
Reference in New Issue
Block a user