Don't rely on "chunked" mode for sending EAS 14 email

* Some reverse-proxies in front of Exchange servers don't handle
  "chunked" data; this appears fairly common and causes an HTTP
  411 (Length required) error when sending mail
* To fix this, we calculate/send the content length and send that
  explicitly
* Tested on our Exchange 2010 server; the calculated length is
  demonstrated to be correct in all tested cases (i.e. any other
  length sent will result in failure)

Bug: 5796904
Change-Id: I802de90764422a608d4ed2c752a791074febed85
diff --git a/src/com/android/exchange/EasOutboxService.java b/src/com/android/exchange/EasOutboxService.java
index f2bc8ca..6f7a27f 100644
--- a/src/com/android/exchange/EasOutboxService.java
+++ b/src/com/android/exchange/EasOutboxService.java
@@ -49,6 +49,7 @@
 import org.apache.http.HttpStatus;
 import org.apache.http.entity.InputStreamEntity;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -113,11 +114,37 @@
          */
         @Override
         public long getContentLength() {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            try {
+                // Calculate the overhead for the WBXML data
+                writeTo(baos, false);
+                // Return the actual size that will be sent
+                return baos.size() + mFileLength;
+            } catch (IOException e) {
+                // Just return -1 (unknown)
+            } finally {
+                try {
+                    baos.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
             return -1;
         }
 
         @Override
         public void writeTo(OutputStream outstream) throws IOException {
+            writeTo(outstream, true);
+        }
+
+        /**
+         * Write the message to the output stream
+         * @param outstream the output stream to write
+         * @param withData whether or not the actual data is to be written; true when sending
+         *   mail; false when calculating size only
+         * @throws IOException
+         */
+        public void writeTo(OutputStream outstream, boolean withData) throws IOException {
             // Not sure if this is possible; the check is taken from the superclass
             if (outstream == null) {
                 throw new IllegalArgumentException("Output stream may not be null");
@@ -153,7 +180,11 @@
             // Start the MIME tag; this is followed by "opaque" data (byte array)
             s.start(Tags.COMPOSE_MIME);
             // Send opaque data from the file stream
-            s.opaque(mFileStream, (int)mFileLength);
+            if (withData) {
+                s.opaque(mFileStream, (int)mFileLength);
+            } else {
+                s.opaqueWithoutData((int)mFileLength);
+            }
             // And we're done
             s.end().end().done();
         }
diff --git a/src/com/android/exchange/adapter/Serializer.java b/src/com/android/exchange/adapter/Serializer.java
index 1fb851c..bc79603 100644
--- a/src/com/android/exchange/adapter/Serializer.java
+++ b/src/com/android/exchange/adapter/Serializer.java
@@ -192,6 +192,13 @@
         return this;
     }
 
+    public Serializer opaqueWithoutData(int length) throws IOException {
+        checkPendingTag(false);
+        mOutput.write(Wbxml.OPAQUE);
+        writeInteger(mOutput, length);
+        return this;
+    }
+
     void writeInteger(OutputStream out, int i) throws IOException {
         byte[] buf = new byte[5];
         int idx = 0;