|
|
@ -24,12 +24,16 @@ import android.content.SharedPreferences;
|
|
|
|
import android.net.MailTo;
|
|
|
|
import android.net.MailTo;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
|
|
|
|
import android.util.Base64;
|
|
|
|
|
|
|
|
|
|
|
|
import androidx.documentfile.provider.DocumentFile;
|
|
|
|
import androidx.documentfile.provider.DocumentFile;
|
|
|
|
import androidx.preference.PreferenceManager;
|
|
|
|
import androidx.preference.PreferenceManager;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.sun.mail.util.ASCIIUtility;
|
|
|
|
|
|
|
|
import com.sun.mail.util.BASE64DecoderStream;
|
|
|
|
import com.sun.mail.util.FolderClosedIOException;
|
|
|
|
import com.sun.mail.util.FolderClosedIOException;
|
|
|
|
import com.sun.mail.util.MessageRemovedIOException;
|
|
|
|
import com.sun.mail.util.MessageRemovedIOException;
|
|
|
|
|
|
|
|
import com.sun.mail.util.QDecoderStream;
|
|
|
|
|
|
|
|
|
|
|
|
import org.jsoup.nodes.Document;
|
|
|
|
import org.jsoup.nodes.Document;
|
|
|
|
import org.jsoup.nodes.Element;
|
|
|
|
import org.jsoup.nodes.Element;
|
|
|
@ -37,6 +41,7 @@ import org.jsoup.nodes.Element;
|
|
|
|
import java.io.BufferedInputStream;
|
|
|
|
import java.io.BufferedInputStream;
|
|
|
|
import java.io.BufferedOutputStream;
|
|
|
|
import java.io.BufferedOutputStream;
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileInputStream;
|
|
|
@ -1186,11 +1191,11 @@ public class MessageHelper {
|
|
|
|
if (text == null)
|
|
|
|
if (text == null)
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://tools.ietf.org/html/rfc2045
|
|
|
|
// https://tools.ietf.org/html/rfc2047
|
|
|
|
// https://tools.ietf.org/html/rfc2047
|
|
|
|
// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
|
|
|
|
// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
|
|
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
int i = 0;
|
|
|
|
boolean first = true;
|
|
|
|
|
|
|
|
List<MimeTextPart> parts = new ArrayList<>();
|
|
|
|
List<MimeTextPart> parts = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
while (i < text.length()) {
|
|
|
|
while (i < text.length()) {
|
|
|
@ -1211,8 +1216,6 @@ public class MessageHelper {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
String plain = text.substring(i, s);
|
|
|
|
String plain = text.substring(i, s);
|
|
|
|
if (!first)
|
|
|
|
|
|
|
|
plain = plain.replaceAll("[ \t\n\r]$", "");
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(plain))
|
|
|
|
if (!TextUtils.isEmpty(plain))
|
|
|
|
parts.add(new MimeTextPart(plain));
|
|
|
|
parts.add(new MimeTextPart(plain));
|
|
|
|
|
|
|
|
|
|
|
@ -1222,7 +1225,6 @@ public class MessageHelper {
|
|
|
|
text.substring(q2 + 1, e)));
|
|
|
|
text.substring(q2 + 1, e)));
|
|
|
|
|
|
|
|
|
|
|
|
i = e + 2;
|
|
|
|
i = e + 2;
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (i < text.length())
|
|
|
|
if (i < text.length())
|
|
|
@ -1235,6 +1237,20 @@ public class MessageHelper {
|
|
|
|
MimeTextPart p2 = parts.get(p + 1);
|
|
|
|
MimeTextPart p2 = parts.get(p + 1);
|
|
|
|
if (p1.charset != null && p1.charset.equalsIgnoreCase(p2.charset) &&
|
|
|
|
if (p1.charset != null && p1.charset.equalsIgnoreCase(p2.charset) &&
|
|
|
|
p1.encoding != null && p1.encoding.equalsIgnoreCase(p2.encoding)) {
|
|
|
|
p1.encoding != null && p1.encoding.equalsIgnoreCase(p2.encoding)) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
byte[] b1 = decodeWord(p1.text, p1.encoding);
|
|
|
|
|
|
|
|
byte[] b2 = decodeWord(p2.text, p2.encoding);
|
|
|
|
|
|
|
|
byte[] b = new byte[b1.length + b2.length];
|
|
|
|
|
|
|
|
System.arraycopy(b1, 0, b, 0, b1.length);
|
|
|
|
|
|
|
|
System.arraycopy(b2, 0, b, b1.length, b2.length);
|
|
|
|
|
|
|
|
p1.text = new String(b, p1.charset);
|
|
|
|
|
|
|
|
p1.charset = null;
|
|
|
|
|
|
|
|
p2.encoding = null;
|
|
|
|
|
|
|
|
parts.remove(p + 1);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
Log.w(ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
p1.text += p2.text;
|
|
|
|
p1.text += p2.text;
|
|
|
|
parts.remove(p + 1);
|
|
|
|
parts.remove(p + 1);
|
|
|
|
} else
|
|
|
|
} else
|
|
|
@ -1247,6 +1263,24 @@ public class MessageHelper {
|
|
|
|
return sb.toString();
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static byte[] decodeWord(String word, String encoding) throws IOException {
|
|
|
|
|
|
|
|
ByteArrayInputStream bis = new ByteArrayInputStream(ASCIIUtility.getBytes(word));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InputStream is;
|
|
|
|
|
|
|
|
if (encoding.equalsIgnoreCase("B"))
|
|
|
|
|
|
|
|
is = new BASE64DecoderStream(bis);
|
|
|
|
|
|
|
|
else if (encoding.equalsIgnoreCase("Q"))
|
|
|
|
|
|
|
|
is = new QDecoderStream(bis);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
throw new UnsupportedEncodingException("Encoding=" + encoding);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int count = bis.available();
|
|
|
|
|
|
|
|
byte[] bytes = new byte[count];
|
|
|
|
|
|
|
|
count = is.read(bytes, 0, count);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Arrays.copyOf(bytes, count);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static class MimeTextPart {
|
|
|
|
private static class MimeTextPart {
|
|
|
|
String charset;
|
|
|
|
String charset;
|
|
|
|
String encoding;
|
|
|
|
String encoding;
|
|
|
@ -1267,10 +1301,10 @@ public class MessageHelper {
|
|
|
|
if (charset == null)
|
|
|
|
if (charset == null)
|
|
|
|
return text;
|
|
|
|
return text;
|
|
|
|
|
|
|
|
|
|
|
|
String word = "=?" + charset + "?" + encoding + "?" + text + "?=";
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
return decodeMime(MimeUtility.decodeWord(word));
|
|
|
|
return decodeMime(new String(decodeWord(text, encoding), charset));
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
|
|
|
|
String word = "=?" + charset + "?" + encoding + "?" + text + "?=";
|
|
|
|
Log.w(new IllegalArgumentException(word, ex));
|
|
|
|
Log.w(new IllegalArgumentException(word, ex));
|
|
|
|
return word;
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
}
|
|
|
|