From febba5bba6c71cf9d9bec3f7b90a67901626e291 Mon Sep 17 00:00:00 2001 From: Andrew Stadler Date: Wed, 25 Aug 2010 16:46:00 -0700 Subject: [PATCH 1/2] Block oversize attachments from being sent * Attachments that come in with a file:// URI do not support the complete set of OpenableColumns columns. To handle this better: 1. Obtain the openable values in two separate queries, in case one or the other is supported (but not both). 2. If the size is not reported but it is a file:// URI, attempt to measure it directly. 3. If the size cannot be obtained, do not upload the attachment Bug: 2948965 Change-Id: Ic5160d39efd65eaca40ceba0dd93c3b035d2871e --- .../email/activity/MessageCompose.java | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/com/android/email/activity/MessageCompose.java b/src/com/android/email/activity/MessageCompose.java index e35864acc..eb1d3110f 100644 --- a/src/com/android/email/activity/MessageCompose.java +++ b/src/com/android/email/activity/MessageCompose.java @@ -60,9 +60,9 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.Window; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; +import android.view.Window; import android.webkit.WebView; import android.widget.Button; import android.widget.EditText; @@ -72,6 +72,7 @@ import android.widget.MultiAutoCompleteTextView; import android.widget.TextView; import android.widget.Toast; +import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; @@ -103,10 +104,15 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1; - private static final String[] ATTACHMENT_META_COLUMNS = { - OpenableColumns.DISPLAY_NAME, + private static final String[] ATTACHMENT_META_NAME_PROJECTION = { + OpenableColumns.DISPLAY_NAME + }; + private static final int ATTACHMENT_META_NAME_COLUMN_DISPLAY_NAME = 0; + + private static final String[] ATTACHMENT_META_SIZE_PROJECTION = { OpenableColumns.SIZE }; + private static final int ATTACHMENT_META_SIZE_COLUMN_SIZE = 0; // Is set while the draft is saved by a background thread. // Is static in order to be shared between the two activity instances @@ -1008,24 +1014,55 @@ public class MessageCompose extends Activity implements OnClickListener, OnFocus } private Attachment loadAttachmentInfo(Uri uri) { - int size = -1; + long size = -1; String name = null; ContentResolver contentResolver = getContentResolver(); - Cursor metadataCursor = contentResolver.query(uri, - ATTACHMENT_META_COLUMNS, null, null, null); + + // Load name & size independently, because not all providers support both + Cursor metadataCursor = contentResolver.query(uri, ATTACHMENT_META_NAME_PROJECTION, + null, null, null); if (metadataCursor != null) { try { if (metadataCursor.moveToFirst()) { - name = metadataCursor.getString(0); - size = metadataCursor.getInt(1); + name = metadataCursor.getString(ATTACHMENT_META_NAME_COLUMN_DISPLAY_NAME); } } finally { metadataCursor.close(); } } + metadataCursor = contentResolver.query(uri, ATTACHMENT_META_SIZE_PROJECTION, + null, null, null); + if (metadataCursor != null) { + try { + if (metadataCursor.moveToFirst()) { + size = metadataCursor.getLong(ATTACHMENT_META_SIZE_COLUMN_SIZE); + } + } finally { + metadataCursor.close(); + } + } + + // When the name or size are not provided, we need to generate them locally. if (name == null) { name = uri.getLastPathSegment(); } + if (size < 0) { + // if the URI is a file: URI, ask file system for its size + if ("file".equalsIgnoreCase(uri.getScheme())) { + String path = uri.getPath(); + if (path != null) { + File file = new File(path); + size = file.length(); // Returns 0 for file not found + } + } + + if (size <= 0) { + // The size was not measurable; This attachment is not safe to use. + // Quick hack to force a relevant error into the UI + // TODO: A proper announcement of the problem + size = Email.MAX_ATTACHMENT_UPLOAD_SIZE + 1; + } + } String contentType = contentResolver.getType(uri); if (contentType == null) { From 6c6c38728c1363ef71c7c02b2e7520feaea80ecd Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Sat, 18 Sep 2010 11:50:47 -0700 Subject: [PATCH 2/2] Increase EmailServiceProxy timeout for validation attempts * Use 90 seconds (instead of 45 seconds) Bug: 3008626 Change-Id: I31258a5fbcca1f489c8bf6fb2ed8f3dcad5d2e26 --- src/com/android/email/mail/store/ExchangeStore.java | 12 ++++++++++-- src/com/android/exchange/EasSyncService.java | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/com/android/email/mail/store/ExchangeStore.java b/src/com/android/email/mail/store/ExchangeStore.java index 9935d50ea..4eaab2496 100644 --- a/src/com/android/email/mail/store/ExchangeStore.java +++ b/src/com/android/email/mail/store/ExchangeStore.java @@ -25,6 +25,8 @@ import com.android.email.mail.Store; import com.android.email.mail.StoreSynchronizer; import com.android.email.provider.EmailContent.Account; import com.android.email.service.EasAuthenticatorService; +import com.android.email.service.EmailServiceProxy; +import com.android.email.service.IEmailService; import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; @@ -238,8 +240,14 @@ public class ExchangeStore extends Store { boolean tssl = uri.getScheme().contains("+trustallcerts"); try { int port = ssl ? 443 : 80; - int result = ExchangeUtils.getExchangeEmailService(mContext, null) - .validate("eas", mHost, mUsername, mPassword, port, ssl, tssl); + + IEmailService svc = ExchangeUtils.getExchangeEmailService(mContext, null); + // Use a longer timeout for the validate command. Note that the instanceof check + // shouldn't be necessary; we'll do it anyway, just to be safe + if (svc instanceof EmailServiceProxy) { + ((EmailServiceProxy)svc).setTimeout(90); + } + int result = svc.validate("eas", mHost, mUsername, mPassword, port, ssl, tssl); if (result != MessagingException.NO_ERROR) { if (result == MessagingException.AUTHENTICATION_FAILED) { throw new AuthenticationFailedException("Authentication failed."); diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java index 1feaf01f6..f09be95f9 100644 --- a/src/com/android/exchange/EasSyncService.java +++ b/src/com/android/exchange/EasSyncService.java @@ -410,7 +410,7 @@ public class EasSyncService extends AbstractSyncService { // Run second test here for provisioning failures... Serializer s = new Serializer(); - userLog("Try folder sync"); + userLog("Validate: try folder sync"); s.start(Tags.FOLDER_FOLDER_SYNC).start(Tags.FOLDER_SYNC_KEY).text("0") .end().end().done(); resp = svc.sendHttpClientPost("FolderSync", s.toByteArray()); @@ -418,14 +418,18 @@ public class EasSyncService extends AbstractSyncService { // We'll get one of the following responses if policies are required by the server if (code == HttpStatus.SC_FORBIDDEN || code == HTTP_NEED_PROVISIONING) { // Get the policies and see if we are able to support them + userLog("Validate: provisioning required"); if (svc.canProvision() != null) { // If so, send the advisory Exception (the account may be created later) + userLog("Validate: provisioning is possible"); throw new MessagingException(MessagingException.SECURITY_POLICIES_REQUIRED); } else + userLog("Validate: provisioning not possible"); // If not, send the unsupported Exception (the account won't be created) throw new MessagingException( MessagingException.SECURITY_POLICIES_UNSUPPORTED); } else if (code == HttpStatus.SC_NOT_FOUND) { + userLog("Wrong address or bad protocol version"); // We get a 404 from OWA addresses (which are NOT EAS addresses) throw new MessagingException(MessagingException.PROTOCOL_VERSION_UNSUPPORTED); } else if (code != HttpStatus.SC_OK) {