
package com.fsck.k9.mail.internet;

import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.K9MailLib;
import com.fsck.k9.mail.MessagingException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import android.support.annotation.Nullable;
import android.util.Log;

import com.fsck.k9.mail.filter.CountingOutputStream;
import com.fsck.k9.mail.filter.SignSafeOutputStream;

import org.apache.james.mime4j.codec.QuotedPrintableOutputStream;
import org.apache.james.mime4j.util.MimeUtil;

public class TextBody implements Body, SizeAware {
    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];


    private final String text;
    private String encoding;
    private String charset = "UTF-8";
    // Length of the message composed (as opposed to quoted). I don't like the name of this variable and am open to
    // suggestions as to what it should otherwise be. -achen 20101207
    @Nullable
    private Integer composedMessageLength;
    // Offset from position 0 where the composed message begins.
    @Nullable
    private Integer composedMessageOffset;

    public TextBody(String body) {
        this.text = body;
    }

    @Override
    public void writeTo(OutputStream out) throws IOException, MessagingException {
        if (text != null) {
            byte[] bytes = text.getBytes(charset);
            if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) {
                SignSafeOutputStream signSafeOutputStream = new SignSafeOutputStream(out);
                QuotedPrintableOutputStream signSafeQuotedPrintableOutputStream =
                        new QuotedPrintableOutputStream(signSafeOutputStream, false);
                signSafeQuotedPrintableOutputStream.write(bytes);
                signSafeQuotedPrintableOutputStream.flush();
                signSafeOutputStream.flush();
            } else if (MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding)) {
                out.write(bytes);
            } else {
                throw new IllegalStateException("Cannot get size for encoding!");
            }
        }
    }

    public String getRawText() {
        return text;
    }

    @Override
    public InputStream getInputStream() throws MessagingException {
        try {
            byte[] b;
            if (text != null) {
                b = text.getBytes(charset);
            } else {
                b = EMPTY_BYTE_ARRAY;
            }
            return new ByteArrayInputStream(b);
        } catch (UnsupportedEncodingException uee) {
            Log.e(K9MailLib.LOG_TAG, "Unsupported charset: " + charset, uee);
            return null;
        }
    }

    @Override
    public void setEncoding(String encoding) {
        boolean isSupportedEncoding = MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding) ||
                MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding);
        if (!isSupportedEncoding) {
            throw new IllegalArgumentException("Cannot encode to " + encoding);
        }

        this.encoding = encoding;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    @Nullable
    public Integer getComposedMessageLength() {
        return composedMessageLength;
    }

    public void setComposedMessageLength(@Nullable Integer composedMessageLength) {
        this.composedMessageLength = composedMessageLength;
    }

    @Nullable
    public Integer getComposedMessageOffset() {
        return composedMessageOffset;
    }

    public void setComposedMessageOffset(@Nullable Integer composedMessageOffset) {
        this.composedMessageOffset = composedMessageOffset;
    }

    @Override
    public long getSize() {
        try {
            byte[] bytes = text.getBytes(charset);

            if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) {
                return getLengthWhenQuotedPrintableEncoded(bytes);
            } else if (MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding)) {
                return bytes.length;
            } else {
                throw new IllegalStateException("Cannot get size for encoding!");
            }
        } catch (IOException e) {
            throw new RuntimeException("Couldn't get body size", e);
        }
    }

    private long getLengthWhenQuotedPrintableEncoded(byte[] bytes) throws IOException {
        CountingOutputStream countingOutputStream = new CountingOutputStream();
        OutputStream quotedPrintableOutputStream = new QuotedPrintableOutputStream(countingOutputStream, false);
        try {
            quotedPrintableOutputStream.write(bytes);
        } finally {
            try {
                quotedPrintableOutputStream.close();
            } catch (IOException e) { /* ignore */ }
        }

        return countingOutputStream.getCount();
    }

    public String getEncoding() {
        return encoding;
    }
}

@@ -34,117 +34,8 @@
 t;%0A%0A
-import com.fsck.k9.mail.Body;%0Aimport com.fsck.k9.mail.K9MailLib;%0Aimport com.fsck.k9.mail.MessagingException;%0A
 %0Aimp
@@ -269,16 +269,125 @@
 l.Log;%0A%0A
+import com.fsck.k9.mail.Body;%0Aimport com.fsck.k9.mail.K9MailLib;%0Aimport com.fsck.k9.mail.MessagingException;%0A
 import c
@@ -484,17 +484,16 @@
 Stream;%0A
-%0A
 import o
@@ -1518,421 +1518,47 @@
     
-SignSafeOutputStream signSafeOutputStream = new SignSafeOutputStream(out);%0A                QuotedPrintableOutputStream signSafeQuotedPrintableOutputStream =%0A                        new QuotedPrintableOutputStream(signSafeOutputStream, false);%0A                signSafeQuotedPrintableOutputStream.write(bytes);%0A                signSafeQuotedPrintableOutputStream.flush();%0A                signSafeOutputStream.flush(
+writeSignSafeQuotedPrintable(out, bytes
 );%0A 
@@ -4109,91 +4109,456 @@
     
-OutputStream quotedPrintableOutputStream = new QuotedPrintableOutputStream(counting
+writeSignSafeQuotedPrintable(countingOutputStream, bytes);%0A        return countingOutputStream.getCount();%0A    %7D%0A%0A    private void writeSignSafeQuotedPrintable(OutputStream out, byte%5B%5D bytes) throws IOException %7B%0A        SignSafeOutputStream signSafeOutputStream = new SignSafeOutputStream(out);%0A        try %7B%0A            QuotedPrintableOutputStream signSafeQuotedPrintableOutputStream =%0A                    new QuotedPrintableOutputStream(signSafe
 Outp
@@ -4575,32 +4575,36 @@
 false);%0A        
+   
+ 
 try %7B%0A          
@@ -4597,33 +4597,45 @@
 y %7B%0A            
-q
+    signSafeQ
 uotedPrintableOu
@@ -4667,16 +4667,20 @@
         
+    
 %7D finall
@@ -4699,31 +4699,21 @@
     
-try %7B%0A                q
+    signSafeQ
 uote
@@ -4761,106 +4761,80 @@
    %7D
- catch (IOException e) %7B /* ignore */ %7D%0A        %7D%0A%0A        return countingOutputStream.getCount();
+%0A        %7D finally %7B%0A            signSafeOutputStream.close();%0A        %7D
 %0A   

Fix bug in TextBody.getSize()