diff --git a/res/values/strings.xml b/res/values/strings.xml index 48a2d8eadb..eacd477392 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -103,6 +103,11 @@ No scanned key found! + + + No connectivity available for MMS download, try again later... + Error storing MMS! + Error connecting to MMS provider... Passphrases Don\'t Match! diff --git a/src/org/thoughtcrime/securesms/mms/MmsCommunication.java b/src/org/thoughtcrime/securesms/mms/MmsCommunication.java index da150c6352..4174ff34e0 100644 --- a/src/org/thoughtcrime/securesms/mms/MmsCommunication.java +++ b/src/org/thoughtcrime/securesms/mms/MmsCommunication.java @@ -63,7 +63,8 @@ public class MmsCommunication { throw new ApnUnavailableException("No locally configured parameters available"); } - protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn) + protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn, + boolean proxyIfPossible) throws ApnUnavailableException { Cursor cursor = null; @@ -76,8 +77,13 @@ public class MmsCommunication { do { String mmsc = cursor.getString(cursor.getColumnIndexOrThrow("mmsc")); - String proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy")); - String port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport")); + String proxy = null; + String port = null; + + if (proxyIfPossible) { + proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy")); + port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport")); + } if (mmsc != null && !mmsc.equals("")) return new MmsConnectionParameters(mmsc, proxy, port); @@ -97,15 +103,29 @@ public class MmsCommunication { } } - protected static void checkRouteToHost(Context context, MmsConnectionParameters parameters, String url) throws IOException { + protected static void checkRouteToHost(Context context, MmsConnectionParameters parameters, + String url, boolean usingMmsRadio) + throws IOException + { if (parameters == null || !parameters.hasProxy()) - checkRouteToHost(context, Uri.parse(url).getHost()); + checkRouteToHost(context, Uri.parse(url).getHost(), usingMmsRadio); else - checkRouteToHost(context, parameters.getProxy()); + checkRouteToHost(context, parameters.getProxy(), usingMmsRadio); } - private static void checkRouteToHost(Context context, String host) throws IOException { - InetAddress inetAddress = InetAddress.getByName(host); + private static void 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; + } + byte[] ipAddressBytes = inetAddress.getAddress(); int ipAddress = Conversions.byteArrayToIntLittleEndian(ipAddressBytes, 0); ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); diff --git a/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java b/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java index 0e380a911b..c32227cbb5 100644 --- a/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java +++ b/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java @@ -26,6 +26,9 @@ import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; +import ws.com.google.android.mms.pdu.PduParser; +import ws.com.google.android.mms.pdu.RetrieveConf; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -46,15 +49,6 @@ public class MmsDownloadHelper extends MmsCommunication { request.setParams(client.getParams()); request.addHeader("Accept", "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"); -// java.util.logging.Logger.getLogger("org.apache.http.wire").setLevel(java.util.logging.Level.FINEST); -// java.util.logging.Logger.getLogger("org.apache.http.headers").setLevel(java.util.logging.Level.FINEST); -// -// System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); -// System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true"); -// System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug"); -// System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug"); -// System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.headers", "debug"); - HttpResponse response = client.execute(target, request); StatusLine status = response.getStatusLine(); @@ -71,17 +65,29 @@ public class MmsDownloadHelper extends MmsCommunication { } } - public static byte[] retrieveMms(Context context, String url, String apn) throws IOException { + public static RetrieveConf retrieveMms(Context context, String url, String apn, + boolean usingMmsRadio, boolean proxyIfPossible) + throws IOException + { MmsConnectionParameters connectionParameters; try { - connectionParameters = getMmsConnectionParameters(context, apn); + connectionParameters = getMmsConnectionParameters(context, apn, proxyIfPossible); } catch (ApnUnavailableException aue) { Log.w("MmsDownloadHelper", aue); connectionParameters = new MmsConnectionParameters(null, null, null); } - checkRouteToHost(context, connectionParameters, url); - return makeRequest(context, connectionParameters, url); + checkRouteToHost(context, connectionParameters, url, usingMmsRadio); + + byte[] pdu = makeRequest(context, connectionParameters, url); + + RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse(); + + if (retrieved == null) { + throw new IOException("Bad retrieved PDU"); + } + + return retrieved; } } diff --git a/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java b/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java index 8197629365..225b61f671 100644 --- a/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java +++ b/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java @@ -27,6 +27,9 @@ import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; +import ws.com.google.android.mms.pdu.PduParser; +import ws.com.google.android.mms.pdu.SendConf; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -66,12 +69,16 @@ public class MmsSendHelper extends MmsCommunication { } } - public static byte[] sendMms(Context context, byte[] mms, String apn) throws IOException { + public static SendConf sendMms(Context context, byte[] mms, String apn, + boolean usingMmsRadio, boolean useProxyIfAvailable) + throws IOException + { Log.w("MmsSender", "Sending MMS of length: " + mms.length); try { - MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn); - checkRouteToHost(context, parameters, parameters.getMmsc()); - return makePost(context, parameters, mms); + MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn, useProxyIfAvailable); + checkRouteToHost(context, parameters, parameters.getMmsc(), usingMmsRadio); + byte[] response = makePost(context, parameters, mms); + return (SendConf) new PduParser(response).parse(); } catch (ApnUnavailableException aue) { Log.w("MmsSender", aue); throw new IOException("Failed to get MMSC information..."); diff --git a/src/org/thoughtcrime/securesms/service/MmsDownloader.java b/src/org/thoughtcrime/securesms/service/MmsDownloader.java index ef9981ed78..668831c420 100644 --- a/src/org/thoughtcrime/securesms/service/MmsDownloader.java +++ b/src/org/thoughtcrime/securesms/service/MmsDownloader.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.util.Log; +import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -28,7 +29,6 @@ import org.thoughtcrime.securesms.mms.MmsDownloadHelper; 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 java.io.IOException; @@ -44,73 +44,105 @@ public class MmsDownloader extends MmscProcessor { this.toastHandler = toastHandler; } - private void handleDownloadMms(DownloadItem item) { - if (!isConnectivityPossible()) { - DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_NO_CONNECTIVITY); - toastHandler.makeToast("No connectivity available for MMS download, try again later..."); - Log.w("MmsDownloadService", "Unable to download MMS, please try again later."); - } else { - DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_CONNECTING); - pendingMessages.add(item); - issueConnectivityRequest(); + public void process(MasterSecret masterSecret, Intent intent) { + if (intent.getAction().equals(SendReceiveService.DOWNLOAD_MMS_ACTION)) { + DownloadItem item = new DownloadItem(masterSecret, false, false, + intent.getLongExtra("message_id", -1), + intent.getLongExtra("thread_id", -1), + intent.getStringExtra("content_location"), + intent.getByteArrayExtra("transaction_id")); + + handleDownloadMmsAction(item); + } else if (intent.getAction().equals(SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION)) { + handleConnectivityChange(); } } - private void handleDownloadMmsContinued(DownloadItem item) { - Log.w("MmsDownloadService", "Handling MMS download continuation..."); + private void handleDownloadMmsAction(DownloadItem item) { + if (!isConnectivityPossible()) { + Log.w("MmsDownloader", "No MMS connectivity available!"); + DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_NO_CONNECTIVITY); + toastHandler.makeToast(context.getString(R.string.MmsDownloader_no_connectivity_available_for_mms_download_try_again_later)); + return; + } + + DatabaseFactory.getMmsDatabase(context).markDownloadState(item.getMessageId(), MmsDatabase.Types.DOWNLOAD_CONNECTING); + + if (item.useMmsRadioMode()) downloadMmsWithRadioChange(item); + else downloadMms(item); + } + + private void downloadMmsWithRadioChange(DownloadItem item) { + Log.w("MmsDownloader", "Handling MMS download with radio change..."); + pendingMessages.add(item); + issueConnectivityRequest(); + } + + private void downloadMms(DownloadItem item) { + Log.w("MmsDownloadService", "Handling actual MMS download..."); MmsDatabase mmsDatabase; - if (item.getMasterSecret() == null) + if (item.getMasterSecret() == null) { mmsDatabase = DatabaseFactory.getMmsDatabase(context); - else + } else { mmsDatabase = DatabaseFactory.getEncryptingMmsDatabase(context, item.getMasterSecret()); - + } try { - byte[] pdu = MmsDownloadHelper.retrieveMms(context, item.getContentLocation(), - getApnInformation()); - RetrieveConf retrieved = (RetrieveConf)new PduParser(pdu).parse(); - - if (retrieved == null) - throw new IOException("Bad retrieved PDU"); + RetrieveConf retrieved = MmsDownloadHelper.retrieveMms(context, item.getContentLocation(), + getApnInformation(), + item.useMmsRadioMode(), + item.proxyRequestIfPossible()); for (int i=0;i pendingMessages = new LinkedList(); - private final Handler toastHandler; + private final LinkedList pendingMessages = new LinkedList(); + private final ToastHandler toastHandler; - public MmsSender(Context context, Handler toastHandler) { + public MmsSender(Context context, ToastHandler toastHandler) { super(context); this.toastHandler = toastHandler; } @@ -66,49 +67,137 @@ public class MmsSender extends MmscProcessor { MmsDatabase database = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret); try { - SendReq[] sendRequests; + List sendRequests = getOutgoingMessages(masterSecret, messageId); - if (messageId == -1) { - sendRequests = database.getOutgoingMessages(); - } else { - sendRequests = new SendReq[1]; - sendRequests[0] = database.getSendRequest(messageId); + for (SendReq sendRequest : sendRequests) { + handleSendMmsAction(new SendItem(masterSecret, sendRequest, messageId != -1, false, false)); } - if (sendRequests != null && sendRequests.length > 0) - handleSendMms(sendRequests, messageId != -1); - } catch (MmsException me) { Log.w("MmsSender", me); if (messageId != -1) database.markAsSentFailed(messageId); } } else if (intent.getAction().equals(SendReceiveService.SEND_MMS_CONNECTIVITY_ACTION)) { - handleConnectivityChange(masterSecret); + handleConnectivityChange(); } } - protected void handleConnectivityChange(MasterSecret masterSecret) { - if (!isConnected()) - return; - - if (!pendingMessages.isEmpty()) handleSendMmsContinued(masterSecret, pendingMessages.remove()); - else finishConnectivity(); - } - - private void handleSendMms(SendReq[] sendRequests, boolean targeted) { + private void handleSendMmsAction(SendItem item) { if (!isConnectivityPossible()) { - if (targeted) { + if (item.targeted) { toastHandler .obtainMessage(0, context.getString(R.string.MmsSender_currently_unable_to_send_your_mms_message)) .sendToTarget(); } -// for (int i=0;i getOutgoingMessages(MasterSecret masterSecret, long messageId) + throws MmsException + { + MmsDatabase database = DatabaseFactory.getEncryptingMmsDatabase(context, masterSecret); + List sendRequests; + + if (messageId == -1) { + sendRequests = Arrays.asList(database.getOutgoingMessages()); + } else { + sendRequests = new ArrayList(1); + sendRequests.add(database.getSendRequest(messageId)); + } + + return sendRequests; + } + + protected void handleConnectivityChange() { + if (!isConnected()) { + if (!isConnectivityPossible() && !pendingMessages.isEmpty()) { + DatabaseFactory.getMmsDatabase(context).markAsSentFailed(pendingMessages.remove().request.getDatabaseMessageId()); + toastHandler.makeToast(context.getString(R.string.MmsSender_currently_unable_to_send_your_mms_message)); + Log.w("MmsSender", "Unable to send MMS."); + finishConnectivity(); + } + + return; + } + + for (SendItem item : pendingMessages) { + sendMmsMessage(item); + } + + pendingMessages.clear(); + finishConnectivity(); } private boolean isInconsistentResponse(SendReq send, SendConf response) { @@ -145,69 +234,15 @@ public class MmsSender extends MmscProcessor { 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(), getApnInformation()); - SendConf conf = (SendConf) new PduParser(response).parse(); - - for (int i=0;i