diff --git a/Android.mk b/Android.mk index f1e3f85d2..794feec44 100644 --- a/Android.mk +++ b/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES += \ src/com/android/email/service/IEmailServiceCallback.aidl # EXCHANGE-REMOVE-SECTION-END +LOCAL_JAVA_STATIC_LIBRARIES := android-common LOCAL_PACKAGE_NAME := Email diff --git a/src/com/android/email/Utility.java b/src/com/android/email/Utility.java index 6e6012aa5..8d254a8f9 100644 --- a/src/com/android/email/Utility.java +++ b/src/com/android/email/Utility.java @@ -16,7 +16,7 @@ package com.android.email; -import com.android.email.provider.EmailContent; +import com.android.common.Base64; import com.android.email.provider.EmailContent.Account; import com.android.email.provider.EmailContent.AccountColumns; import com.android.email.provider.EmailContent.HostAuth; @@ -25,9 +25,15 @@ import com.android.email.provider.EmailContent.Mailbox; import com.android.email.provider.EmailContent.MailboxColumns; import com.android.email.provider.EmailContent.Message; import com.android.email.provider.EmailContent.MessageColumns; +import com.android.email.provider.EmailContent; import android.content.ContentResolver; +import android.content.Context; +import android.content.res.TypedArray; import android.database.Cursor; +import android.graphics.drawable.Drawable; +import android.text.Editable; +import android.widget.TextView; import java.io.IOException; import java.io.InputStream; @@ -35,14 +41,6 @@ import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.Date; -import com.android.email.codec.binary.Base64; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.text.Editable; -import android.widget.TextView; - public class Utility { public final static String readInputStream(InputStream in, String encoding) throws IOException { InputStreamReader reader = new InputStreamReader(in, encoding); @@ -91,7 +89,7 @@ public class Utility { if (encoded == null) { return null; } - byte[] decoded = new Base64().decode(encoded.getBytes()); + byte[] decoded = Base64.decode(encoded, Base64.DEFAULT); return new String(decoded); } @@ -99,8 +97,7 @@ public class Utility { if (s == null) { return s; } - byte[] encoded = new Base64().encode(s.getBytes()); - return new String(encoded); + return Base64.encodeToString(s.getBytes(), Base64.NO_WRAP); } public static boolean requiredFieldValid(TextView view) { @@ -114,9 +111,9 @@ public class Utility { /** * Ensures that the given string starts and ends with the double quote character. The string is not modified in any way except to add the * double quote character to start and end if it's not already there. - * + * * TODO: Rename this, because "quoteString()" can mean so many different things. - * + * * sample -> "sample" * "sample" -> "sample" * ""sample"" -> "sample" @@ -139,37 +136,37 @@ public class Utility { return s; } } - + /** - * Apply quoting rules per IMAP RFC, + * Apply quoting rules per IMAP RFC, * quoted = DQUOTE *QUOTED-CHAR DQUOTE * QUOTED-CHAR = / "\" quoted-specials * quoted-specials = DQUOTE / "\" - * + * * This is used primarily for IMAP login, but might be useful elsewhere. - * + * * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check * for trouble chars before calling the replace functions. - * + * * @param s The string to be quoted. * @return A copy of the string, having undergone quoting as described above */ public static String imapQuoted(String s) { - + // First, quote any backslashes by replacing \ with \\ // regex Pattern: \\ (Java string const = \\\\) // Substitute: \\\\ (Java string const = \\\\\\\\) String result = s.replaceAll("\\\\", "\\\\\\\\"); - + // Then, quote any double-quotes by replacing " with \" // regex Pattern: " (Java string const = \") // Substitute: \\" (Java string const = \\\\\") result = result.replaceAll("\"", "\\\\\""); - + // return string with quotes around it return "\"" + result + "\""; } - + /** * A fast version of URLDecoder.decode() that works only with UTF-8 and does only two * allocations. This version is around 3x as fast as the standard one and I'm using it diff --git a/src/com/android/email/codec/binary/Base64.java b/src/com/android/email/codec/binary/Base64.java index 21f51c968..043e614f2 100644 --- a/src/com/android/email/codec/binary/Base64.java +++ b/src/com/android/email/codec/binary/Base64.java @@ -33,7 +33,7 @@ import java.math.BigInteger; * @since 1.0-dev * @version $Id$ */ -public class Base64 { +/* package */ class Base64 { /** * Chunk size per RFC 2045 section 6.8. * diff --git a/src/com/android/email/mail/internet/TextBody.java b/src/com/android/email/mail/internet/TextBody.java index 6b620c435..33ee3a8ca 100644 --- a/src/com/android/email/mail/internet/TextBody.java +++ b/src/com/android/email/mail/internet/TextBody.java @@ -16,17 +16,16 @@ package com.android.email.mail.internet; +import com.android.common.Base64; +import com.android.email.mail.Body; +import com.android.email.mail.MessagingException; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; - -import com.android.email.codec.binary.Base64; -import com.android.email.mail.Body; -import com.android.email.mail.MessagingException; - public class TextBody implements Body { String mBody; @@ -36,11 +35,11 @@ public class TextBody implements Body { public void writeTo(OutputStream out) throws IOException, MessagingException { byte[] bytes = mBody.getBytes("UTF-8"); - out.write(Base64.encodeBase64Chunked(bytes)); + out.write(Base64.encode(bytes, Base64.CRLF)); } - + /** - * Get the text of the body in it's unencoded format. + * Get the text of the body in it's unencoded format. * @return */ public String getText() { diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index 2c3778e93..246d59648 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -16,11 +16,11 @@ package com.android.email.mail.store; +import com.android.common.Base64; import com.android.email.Email; import com.android.email.Preferences; import com.android.email.Utility; import com.android.email.VendorPolicyLoader; -import com.android.email.codec.binary.Base64; import com.android.email.mail.AuthenticationFailedException; import com.android.email.mail.CertificateValidationException; import com.android.email.mail.FetchProfile; @@ -167,7 +167,7 @@ public class ImapStore extends Store { mUsername = userInfoParts[0]; if (userInfoParts.length > 1) { mPassword = userInfoParts[1]; - + // build the LOGIN string once (instead of over-and-over again.) // apply the quoting here around the built-up password mLoginPhrase = "LOGIN " + mUsername + " " + Utility.imapQuoted(mPassword); @@ -191,8 +191,8 @@ public class ImapStore extends Store { } /** - * For testing only. Injects a different root transport (it will be copied using - * newInstanceWithConfiguration() each time IMAP sets up a new channel). The transport + * For testing only. Injects a different root transport (it will be copied using + * newInstanceWithConfiguration() each time IMAP sets up a new channel). The transport * should already be set up and ready to use. Do not use for real code. * @param testTransport The Transport to inject and use for all future communication. */ @@ -221,7 +221,7 @@ public class ImapStore extends Store { * * @param userName the username of the account * @param host the host (server) of the account - * @return a String for use in an IMAP ID message. + * @return a String for use in an IMAP ID message. */ public String getImapId(Context context, String userName, String host) { // The first section is global to all IMAP connections, and generates the fixed @@ -257,7 +257,7 @@ public class ImapStore extends Store { messageDigest.update(userName.getBytes()); messageDigest.update(devUID.getBytes()); byte[] uid = messageDigest.digest(); - String hexUid = new String(new Base64().encode(uid)); + String hexUid = Base64.encodeToString(uid, Base64.NO_WRAP); id.append(" \"AGUID\" \""); id.append(hexUid); id.append('\"'); @@ -644,7 +644,7 @@ public class ImapStore extends Store { } @Override - public void copyMessages(Message[] messages, Folder folder, + public void copyMessages(Message[] messages, Folder folder, MessageUpdateCallbacks callbacks) throws MessagingException { checkOpen(); String[] uids = new String[messages.length]; @@ -822,7 +822,7 @@ public class ImapStore extends Store { if (fp.contains(FetchProfile.Item.ENVELOPE)) { fetchFields.add("INTERNALDATE"); fetchFields.add("RFC822.SIZE"); - fetchFields.add("BODY.PEEK[HEADER.FIELDS " + + fetchFields.add("BODY.PEEK[HEADER.FIELDS " + "(date subject from content-type to cc message-id)]"); } if (fp.contains(FetchProfile.Item.STRUCTURE)) { @@ -1310,7 +1310,7 @@ public class ImapStore extends Store { if (mTransport == null) { mTransport = mRootTransport.newInstanceWithConfiguration(); } - + mTransport.open(); mTransport.setSoTimeout(MailTransport.SOCKET_READ_TIMEOUT); @@ -1405,10 +1405,10 @@ public class ImapStore extends Store { /** * Send a single command to the server. The command will be preceded by an IMAP command * tag and followed by \r\n (caller need not supply them). - * + * * @param command The command to send to the server * @param sensitive If true, the command will not be logged - * @return Returns the command tag that was sent + * @return Returns the command tag that was sent */ public String sendCommand(String command, boolean sensitive) throws MessagingException, IOException { diff --git a/src/com/android/email/mail/transport/Rfc822Output.java b/src/com/android/email/mail/transport/Rfc822Output.java index 6575c685a..5c611eb9d 100644 --- a/src/com/android/email/mail/transport/Rfc822Output.java +++ b/src/com/android/email/mail/transport/Rfc822Output.java @@ -16,7 +16,7 @@ package com.android.email.mail.transport; -import com.android.email.codec.binary.Base64; +import com.android.common.Base64; import com.android.email.codec.binary.Base64OutputStream; import com.android.email.mail.Address; import com.android.email.mail.MessagingException; @@ -323,6 +323,6 @@ public class Rfc822Output { writer.write("\r\n"); byte[] bytes = text.getBytes("UTF-8"); writer.flush(); - out.write(Base64.encodeBase64Chunked(bytes)); + out.write(Base64.encode(bytes, Base64.CRLF)); } } diff --git a/src/com/android/email/mail/transport/SmtpSender.java b/src/com/android/email/mail/transport/SmtpSender.java index c785e7f7c..c2de45b33 100644 --- a/src/com/android/email/mail/transport/SmtpSender.java +++ b/src/com/android/email/mail/transport/SmtpSender.java @@ -16,8 +16,8 @@ package com.android.email.mail.transport; +import com.android.common.Base64; import com.android.email.Email; -import com.android.email.codec.binary.Base64; import com.android.email.mail.Address; import com.android.email.mail.AuthenticationFailedException; import com.android.email.mail.CertificateValidationException; @@ -304,9 +304,11 @@ public class SmtpSender extends Sender { AuthenticationFailedException, IOException { try { executeSimpleCommand("AUTH LOGIN"); - executeSensitiveCommand(new String(Base64.encodeBase64(username.getBytes())), + executeSensitiveCommand( + Base64.encodeToString(username.getBytes(), Base64.NO_WRAP), "/username redacted/"); - executeSensitiveCommand(new String(Base64.encodeBase64(password.getBytes())), + executeSensitiveCommand( + Base64.encodeToString(password.getBytes(), Base64.NO_WRAP), "/password redacted/"); } catch (MessagingException me) { @@ -320,7 +322,7 @@ public class SmtpSender extends Sender { private void saslAuthPlain(String username, String password) throws MessagingException, AuthenticationFailedException, IOException { byte[] data = ("\000" + username + "\000" + password).getBytes(); - data = new Base64().encode(data); + data = Base64.encode(data, Base64.NO_WRAP); try { executeSensitiveCommand("AUTH PLAIN " + new String(data), "AUTH PLAIN /redacted/"); } diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java index 385883f42..82159600b 100644 --- a/src/com/android/exchange/EasSyncService.java +++ b/src/com/android/exchange/EasSyncService.java @@ -17,9 +17,9 @@ package com.android.exchange; -import com.android.email.SecurityPolicy; +import com.android.common.Base64; import com.android.email.SecurityPolicy.PolicySet; -import com.android.email.codec.binary.Base64; +import com.android.email.SecurityPolicy; import com.android.email.mail.AuthenticationFailedException; import com.android.email.mail.MessagingException; import com.android.email.provider.EmailContent.Account; @@ -39,11 +39,11 @@ import com.android.exchange.adapter.ContactsSyncAdapter; import com.android.exchange.adapter.EmailSyncAdapter; import com.android.exchange.adapter.FolderSyncParser; import com.android.exchange.adapter.MeetingResponseParser; +import com.android.exchange.adapter.Parser.EasParserException; import com.android.exchange.adapter.PingParser; import com.android.exchange.adapter.ProvisionParser; import com.android.exchange.adapter.Serializer; import com.android.exchange.adapter.Tags; -import com.android.exchange.adapter.Parser.EasParserException; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -792,7 +792,7 @@ public class EasSyncService extends AbstractSyncService { String safeUserName = URLEncoder.encode(mUserName); if (mAuthString == null) { String cs = mUserName + ':' + mPassword; - mAuthString = "Basic " + new String(Base64.encodeBase64(cs.getBytes())); + mAuthString = "Basic " + Base64.encodeToString(cs.getBytes(), Base64.NO_WRAP); mCmdString = "&User=" + safeUserName + "&DeviceId=" + mDeviceId + "&DeviceType=" + mDeviceType; } @@ -1206,7 +1206,7 @@ public class EasSyncService extends AbstractSyncService { ArrayList readyMailboxes = new ArrayList(); ArrayList notReadyMailboxes = new ArrayList(); int pingWaitCount = 0; - + while ((System.currentTimeMillis() < endTime) && !mStop) { // Count of pushable mailboxes int pushCount = 0; @@ -1214,7 +1214,7 @@ public class EasSyncService extends AbstractSyncService { int canPushCount = 0; // Count of uninitialized boxes int uninitCount = 0; - + Serializer s = new Serializer(); Cursor c = mContentResolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, MailboxColumns.ACCOUNT_KEY + '=' + mAccount.mId + @@ -1275,7 +1275,7 @@ public class EasSyncService extends AbstractSyncService { userLog("Ping ready for: " + readyMailboxes); } } - + // If we've waited 10 seconds or more, just ping with whatever boxes are ready // But use a shorter than normal heartbeat boolean forcePing = !notReadyMailboxes.isEmpty() && (pingWaitCount > 5); diff --git a/src/com/android/exchange/adapter/ContactsSyncAdapter.java b/src/com/android/exchange/adapter/ContactsSyncAdapter.java index b95e4756c..92521014a 100644 --- a/src/com/android/exchange/adapter/ContactsSyncAdapter.java +++ b/src/com/android/exchange/adapter/ContactsSyncAdapter.java @@ -17,7 +17,7 @@ package com.android.exchange.adapter; -import com.android.email.codec.binary.Base64; +import com.android.common.Base64; import com.android.email.provider.EmailContent.Mailbox; import com.android.exchange.Eas; import com.android.exchange.EasSyncService; @@ -1258,7 +1258,7 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter { RowBuilder builder = untypedRowBuilder(entity, Photo.CONTENT_ITEM_TYPE); // We're always going to add this; it's not worth trying to figure out whether the // picture is the same as the one stored. - byte[] pic = Base64.decodeBase64(photo.getBytes()); + byte[] pic = Base64.decode(photo, Base64.DEFAULT); builder.withValue(Photo.PHOTO, pic); add(builder.build()); } @@ -1636,8 +1636,7 @@ public class ContactsSyncAdapter extends AbstractSyncAdapter { private void sendPhoto(Serializer s, ContentValues cv) throws IOException { if (cv.containsKey(Photo.PHOTO)) { byte[] bytes = cv.getAsByteArray(Photo.PHOTO); - byte[] encodedBytes = Base64.encodeBase64(bytes); - String pic = new String(encodedBytes); + String pic = Base64.encodeToString(bytes, Base64.NO_WRAP); s.data(Tags.CONTACTS_PICTURE, pic); } }