check max http file size when attaching files

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/persistance/FileBackend.java        | 22 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 11 
src/main/java/eu/siacs/conversations/ui/ConversationActivity.java        | 30 
src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java           | 11 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                |  4 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java            | 17 
6 files changed, 83 insertions(+), 12 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/persistance/FileBackend.java 🔗

@@ -1,6 +1,8 @@
 package eu.siacs.conversations.persistance;
 
+import android.content.Context;
 import android.content.Intent;
+import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -8,6 +10,7 @@ import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.net.Uri;
 import android.os.Environment;
+import android.provider.OpenableColumns;
 import android.util.Base64;
 import android.util.Base64OutputStream;
 import android.util.Log;
@@ -28,6 +31,7 @@ import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.List;
 import java.util.Locale;
 
 import eu.siacs.conversations.Config;
@@ -110,6 +114,24 @@ public class FileBackend {
 		}
 	}
 
+	public static long getFileSize(Context context, Uri uri) {
+		Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
+		if (cursor != null && cursor.moveToFirst()) {
+			return cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
+		} else {
+			return -1;
+		}
+	}
+
+	public static boolean allFilesUnderSize(Context context, List<Uri> uris, long max) {
+		for(Uri uri : uris) {
+			if (FileBackend.getFileSize(context, uri) > max) {
+				return false;
+			}
+		}
+		return true;
+	}
+
 	public static String getConversationsFileDirectory() {
 		return  Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/";
 	}

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -847,7 +847,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 	private void sendFileMessage(final Message message, final boolean delay) {
 		Log.d(Config.LOGTAG, "send file message");
 		final Account account = message.getConversation().getAccount();
-		if (account.httpUploadAvailable()) {
+		if (account.httpUploadAvailable(fileBackend.getFile(message,false).getSize())) {
 			mHttpConnectionManager.createNewUploadConnection(message, delay);
 		} else {
 			mJingleConnectionManager.createNewConnection(message);
@@ -884,7 +884,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 			switch (message.getEncryption()) {
 				case Message.ENCRYPTION_NONE:
 					if (message.needsUploading()) {
-						if (account.httpUploadAvailable() || message.fixCounterpart()) {
+						if (account.httpUploadAvailable(fileBackend.getFile(message,false).getSize())
+								|| message.fixCounterpart()) {
 							this.sendFileMessage(message, delay);
 						} else {
 							break;
@@ -896,7 +897,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				case Message.ENCRYPTION_PGP:
 				case Message.ENCRYPTION_DECRYPTED:
 					if (message.needsUploading()) {
-						if (account.httpUploadAvailable() || message.fixCounterpart()) {
+						if (account.httpUploadAvailable(fileBackend.getFile(message,false).getSize())
+								|| message.fixCounterpart()) {
 							this.sendFileMessage(message, delay);
 						} else {
 							break;
@@ -932,7 +934,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
 				case Message.ENCRYPTION_AXOLOTL:
 					message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
 					if (message.needsUploading()) {
-						if (account.httpUploadAvailable() || message.fixCounterpart()) {
+						if (account.httpUploadAvailable(fileBackend.getFile(message,false).getSize())
+								|| message.fixCounterpart()) {
 							this.sendFileMessage(message, delay);
 						} else {
 							break;

src/main/java/eu/siacs/conversations/ui/ConversationActivity.java 🔗

@@ -54,6 +54,7 @@ import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
@@ -1298,12 +1299,31 @@ public class ConversationActivity extends XmppActivity
 					}
 				}
 			} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) {
-				mPendingFileUris.clear();
-				mPendingFileUris.addAll(extractUriFromIntent(data));
-				if (xmppConnectionServiceBound) {
-					for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
-						attachFileToConversation(getSelectedConversation(), i.next());
+				final List<Uri> uris = extractUriFromIntent(data);
+				final Conversation c = getSelectedConversation();
+				final long max = c.getAccount()
+						.getXmppConnection()
+						.getFeatures()
+						.getMaxHttpUploadSize();
+				final OnPresenceSelected callback = new OnPresenceSelected() {
+					@Override
+					public void onPresenceSelected() {
+						mPendingFileUris.clear();
+						mPendingFileUris.addAll(uris);
+						if (xmppConnectionServiceBound) {
+							for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
+								attachFileToConversation(c, i.next());
+							}
+						}
 					}
+				};
+				if (max <= 0
+						|| c.getMode() == Conversation.MODE_MULTI
+						|| FileBackend.allFilesUnderSize(this, uris, max)
+						|| c.getNextEncryption() == Message.ENCRYPTION_OTR) {
+					callback.onPresenceSelected();
+				} else {
+					selectPresence(c, callback);
 				}
 			} else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
 				if (mPendingImageUris.size() == 1) {

src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java 🔗

@@ -24,6 +24,7 @@ import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.adapter.ConversationAdapter;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@@ -259,6 +260,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
 	}
 
 	private void share(final Conversation conversation) {
+		final Account account = conversation.getAccount();
 		mListView.setEnabled(false);
 		if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) {
 			if (share.uuid == null) {
@@ -270,6 +272,9 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
 			return;
 		}
 		if (share.uris.size() != 0) {
+			final long max = account.getXmppConnection()
+					.getFeatures()
+					.getMaxHttpUploadSize();
 			OnPresenceSelected callback = new OnPresenceSelected() {
 				@Override
 				public void onPresenceSelected() {
@@ -290,7 +295,11 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
 					}
 				}
 			};
-			if (conversation.getAccount().httpUploadAvailable()) {
+			if (account.httpUploadAvailable()
+					&& (
+					(share.image && !neverCompressPictures())
+					|| conversation.getMode() == Conversation.MODE_MULTI
+					|| FileBackend.allFilesUnderSize(this, share.uris, max))) {
 				callback.onPresenceSelected();
 			} else {
 				selectPresence(conversation, callback);

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -1002,6 +1002,10 @@ public abstract class XmppActivity extends Activity {
 		}
 	}
 
+	protected boolean neverCompressPictures() {
+		return getPreferences().getString("picture_compression", "auto").equals("never");
+	}
+
 	protected void unregisterNdefPushMessageCallback() {
 		NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
 		if (nfcAdapter != null && nfcAdapter.isEnabled()) {

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -1541,15 +1541,28 @@ public class XmppConnection implements Runnable {
 				if (items.size() > 0) {
 					try {
 						long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Xmlns.HTTP_UPLOAD, "max-file-size"));
-						return maxsize <= filesize;
+						return filesize <= maxsize;
 					} catch (Exception e) {
-						return filesize <= 0;
+						return true;
 					}
 				} else {
 					return false;
 				}
 			}
 		}
+
+		public long getMaxHttpUploadSize() {
+			List<Entry<Jid, ServiceDiscoveryResult>> items = findDiscoItemsByFeature(Xmlns.HTTP_UPLOAD);
+				if (items.size() > 0) {
+					try {
+						return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Xmlns.HTTP_UPLOAD, "max-file-size"));
+					} catch (Exception e) {
+						return -1;
+					}
+				} else {
+					return -1;
+				}
+		}
 	}
 
 	private IqGenerator getIqGenerator() {