diff --git a/src/com/fsck/k9/K9.java b/src/com/fsck/k9/K9.java index d45e8f72e..9eead455a 100644 --- a/src/com/fsck/k9/K9.java +++ b/src/com/fsck/k9/K9.java @@ -88,7 +88,7 @@ public class K9 extends Application { * * @see ApplicationAware */ - private static List observers = new ArrayList(); + private static final List observers = new ArrayList(); /** * This will be {@code true} once the initialization is complete and {@link #notifyObservers()} diff --git a/src/com/fsck/k9/PRNGFixes.java b/src/com/fsck/k9/PRNGFixes.java index e1b20d23b..33d4ff6c9 100644 --- a/src/com/fsck/k9/PRNGFixes.java +++ b/src/com/fsck/k9/PRNGFixes.java @@ -19,7 +19,7 @@ import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; @@ -284,10 +284,7 @@ public final class PRNGFixes { if (serial != null) { result.append(serial); } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } + + return result.toString().getBytes(Charset.forName("UTF-8")); } } diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java index 1bda6cb47..05170db2e 100644 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ b/src/com/fsck/k9/activity/MessageCompose.java @@ -5,6 +5,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -1890,13 +1891,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, private InputStream getOpenPgpInputStream() { String text = buildText(false).getText(); - InputStream is = null; - try { - is = new ByteArrayInputStream(text.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - Log.e(K9.LOG_TAG, "UnsupportedEncodingException.", e); - } - return is; + return new ByteArrayInputStream(text.getBytes(Charset.forName("UTF-8"))); } private void executeOpenPgpMethod(Intent intent) { diff --git a/src/com/fsck/k9/activity/setup/AccountSetupBasics.java b/src/com/fsck/k9/activity/setup/AccountSetupBasics.java index 861edea53..56d409743 100644 --- a/src/com/fsck/k9/activity/setup/AccountSetupBasics.java +++ b/src/com/fsck/k9/activity/setup/AccountSetupBasics.java @@ -3,10 +3,8 @@ package com.fsck.k9.activity.setup; import java.io.Serializable; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLEncoder; import java.util.Locale; import android.app.AlertDialog; @@ -35,6 +33,7 @@ import com.fsck.k9.Preferences; import com.fsck.k9.R; import com.fsck.k9.activity.K9Activity; import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.AuthType; import com.fsck.k9.mail.ConnectionSecurity; @@ -281,8 +280,8 @@ public class AccountSetupBasics extends K9Activity URI incomingUri = null; URI outgoingUri = null; try { - String userEnc = URLEncoder.encode(user, "UTF-8"); - String passwordEnc = URLEncoder.encode(password, "UTF-8"); + String userEnc = UrlEncodingHelper.encodeUtf8(user); + String passwordEnc = UrlEncodingHelper.encodeUtf8(password); String incomingUsername = mProvider.incomingUsernameTemplate; incomingUsername = incomingUsername.replaceAll("\\$email", email); @@ -338,9 +337,6 @@ public class AccountSetupBasics extends K9Activity } // Check incoming here. Then check outgoing in onActivityResult() AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING); - } catch (UnsupportedEncodingException enc) { - // This really shouldn't happen since the encoding is hardcoded to UTF-8 - Log.e(K9.LOG_TAG, "Couldn't urlencode username or password.", enc); } catch (URISyntaxException use) { /* * If there is some problem with the URI we give up and go on to diff --git a/src/com/fsck/k9/cache/EmailProviderCache.java b/src/com/fsck/k9/cache/EmailProviderCache.java index ba3741f49..972d3abdb 100644 --- a/src/com/fsck/k9/cache/EmailProviderCache.java +++ b/src/com/fsck/k9/cache/EmailProviderCache.java @@ -42,9 +42,9 @@ public class EmailProviderCache { private String mAccountUuid; - private Map> mMessageCache = new HashMap>(); - private Map> mThreadCache = new HashMap>(); - private Map mHiddenMessageCache = new HashMap(); + private final Map> mMessageCache = new HashMap>(); + private final Map> mThreadCache = new HashMap>(); + private final Map mHiddenMessageCache = new HashMap(); private EmailProviderCache(String accountUuid) { diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 7b979371b..d71c06997 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -319,7 +319,7 @@ public class MessagingController implements Runnable { }; // Key is accountNumber - private ConcurrentHashMap notificationData = new ConcurrentHashMap(); + private final ConcurrentMap notificationData = new ConcurrentHashMap(); private static final Flag[] SYNC_FLAGS = new Flag[] { Flag.SEEN, Flag.FLAGGED, Flag.ANSWERED, Flag.FORWARDED }; diff --git a/src/com/fsck/k9/helper/UrlEncodingHelper.java b/src/com/fsck/k9/helper/UrlEncodingHelper.java new file mode 100644 index 000000000..2e6f1d591 --- /dev/null +++ b/src/com/fsck/k9/helper/UrlEncodingHelper.java @@ -0,0 +1,33 @@ +package com.fsck.k9.helper; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +/** + * Wraps the java.net.URLDecoder to avoid unhelpful checked exceptions. + */ +public class UrlEncodingHelper { + + public static String decodeUtf8(String s) { + try { + return URLDecoder.decode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + /* + * This is impossible, UTF-8 is always supported + */ + throw new RuntimeException("UTF-8 not found"); + } + } + + public static String encodeUtf8(String s) { + try { + return URLEncoder.encode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + /* + * This is impossible, UTF-8 is always supported + */ + throw new RuntimeException("UTF-8 not found"); + } + } +} diff --git a/src/com/fsck/k9/helper/Utility.java b/src/com/fsck/k9/helper/Utility.java index a5bea3448..ae8d9bb71 100644 --- a/src/com/fsck/k9/helper/Utility.java +++ b/src/com/fsck/k9/helper/Utility.java @@ -20,7 +20,7 @@ import com.fsck.k9.mail.filter.Base64; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -189,8 +189,8 @@ public class Utility { * hundreds of times in places that slow down the UI, so it helps. */ public static String fastUrlDecode(String s) { - try { - byte[] bytes = s.getBytes("UTF-8"); + + byte[] bytes = s.getBytes(Charset.forName("UTF-8")); byte ch; int length = 0; for (int i = 0, count = bytes.length; i < count; i++) { @@ -213,10 +213,8 @@ public class Utility { } length++; } - return new String(bytes, 0, length, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - return null; - } + return new String(bytes, 0, length, Charset.forName("UTF-8")); + } /* diff --git a/src/com/fsck/k9/mail/filter/Base64.java b/src/com/fsck/k9/mail/filter/Base64.java index ffc7abf94..934c3b222 100644 --- a/src/com/fsck/k9/mail/filter/Base64.java +++ b/src/com/fsck/k9/mail/filter/Base64.java @@ -17,8 +17,8 @@ package com.fsck.k9.mail.filter; -import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.nio.charset.Charset; /** * Provides Base64 encoding and decoding as defined by RFC 2045. @@ -225,12 +225,8 @@ public class Base64 { } this.decodeSize = encodeSize - 1; if (containsBase64Byte(lineSeparator)) { - String sep; - try { - sep = new String(lineSeparator, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - sep = new String(lineSeparator); - } + String sep = new String(lineSeparator, Charset.forName("UTF-8")); + throw new IllegalArgumentException("lineSeperator must not contain base64 characters: [" + sep + "]"); } } diff --git a/src/com/fsck/k9/mail/internet/DecoderUtil.java b/src/com/fsck/k9/mail/internet/DecoderUtil.java index 5c7d5034f..80d5b573e 100644 --- a/src/com/fsck/k9/mail/internet/DecoderUtil.java +++ b/src/com/fsck/k9/mail/internet/DecoderUtil.java @@ -7,7 +7,8 @@ import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; + import org.apache.james.mime4j.codec.Base64InputStream; import org.apache.james.mime4j.codec.QuotedPrintableInputStream; import org.apache.james.mime4j.util.CharsetUtil; @@ -30,12 +31,7 @@ public class DecoderUtil { * @return the decoded string. */ private static String decodeB(String encodedWord, String charset) { - byte[] bytes; - try { - bytes = encodedWord.getBytes("US-ASCII"); - } catch (UnsupportedEncodingException e) { - return null; - } + byte[] bytes = encodedWord.getBytes(Charset.forName("US-ASCII")); Base64InputStream is = new Base64InputStream(new ByteArrayInputStream(bytes)); try { @@ -68,12 +64,7 @@ public class DecoderUtil { } } - byte[] bytes; - try { - bytes = sb.toString().getBytes("US-ASCII"); - } catch (UnsupportedEncodingException e) { - return null; - } + byte[] bytes = sb.toString().getBytes(Charset.forName("US-ASCII")); QuotedPrintableInputStream is = new QuotedPrintableInputStream(new ByteArrayInputStream(bytes)); try { diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 2dba608ea..f66215e0b 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -16,8 +15,6 @@ import java.net.SocketAddress; import java.net.SocketException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; -import java.net.URLEncoder; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; @@ -31,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -64,6 +62,7 @@ import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.controller.MessageRetrievalListener; import com.fsck.k9.helper.StringUtils; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.helper.power.TracingPowerManager; import com.fsck.k9.helper.power.TracingPowerManager.TracingWakeLock; @@ -198,31 +197,26 @@ public class ImapStore extends Store { } if (imapUri.getUserInfo() != null) { - try { - String userinfo = imapUri.getUserInfo(); - String[] userInfoParts = userinfo.split(":"); + String userinfo = imapUri.getUserInfo(); + String[] userInfoParts = userinfo.split(":"); - if (userinfo.endsWith(":")) { - // Password is empty. This can only happen after an account was imported. - authenticationType = AuthType.valueOf(userInfoParts[0]); - username = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } else if (userInfoParts.length == 2) { - authenticationType = AuthType.PLAIN; - username = URLDecoder.decode(userInfoParts[0], "UTF-8"); - password = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } else if (userInfoParts.length == 3) { - authenticationType = AuthType.valueOf(userInfoParts[0]); - username = URLDecoder.decode(userInfoParts[1], "UTF-8"); + if (userinfo.endsWith(":")) { + // Password is empty. This can only happen after an account was imported. + authenticationType = AuthType.valueOf(userInfoParts[0]); + username = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); + } else if (userInfoParts.length == 2) { + authenticationType = AuthType.PLAIN; + username = UrlEncodingHelper.decodeUtf8(userInfoParts[0]); + password = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); + } else if (userInfoParts.length == 3) { + authenticationType = AuthType.valueOf(userInfoParts[0]); + username = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); - if (AuthType.EXTERNAL == authenticationType) { - clientCertificateAlias = URLDecoder.decode(userInfoParts[2], "UTF-8"); - } else { - password = URLDecoder.decode(userInfoParts[2], "UTF-8"); - } + if (AuthType.EXTERNAL == authenticationType) { + clientCertificateAlias = UrlEncodingHelper.decodeUtf8(userInfoParts[2]); + } else { + password = UrlEncodingHelper.decodeUtf8(userInfoParts[2]); } - } catch (UnsupportedEncodingException enc) { - // This shouldn't happen since the encoding is hardcoded to UTF-8 - throw new IllegalArgumentException("Couldn't urldecode username or password.", enc); } } @@ -260,19 +254,11 @@ public class ImapStore extends Store { * @see ImapStore#decodeUri(String) */ public static String createUri(ServerSettings server) { - String userEnc; - String passwordEnc; - String clientCertificateAliasEnc; - try { - userEnc = URLEncoder.encode(server.username, "UTF-8"); - passwordEnc = (server.password != null) ? - URLEncoder.encode(server.password, "UTF-8") : ""; - clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? - URLEncoder.encode(server.clientCertificateAlias, "UTF-8") : ""; - } - catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Could not encode username or password", e); - } + String userEnc = UrlEncodingHelper.encodeUtf8(server.username); + String passwordEnc = (server.password != null) ? + UrlEncodingHelper.encodeUtf8(server.password) : ""; + String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? + UrlEncodingHelper.encodeUtf8(server.clientCertificateAlias) : ""; String scheme; switch (server.connectionSecurity) { @@ -439,7 +425,7 @@ public class ImapStore extends Store { private static final SimpleDateFormat RFC3501_DATE = new SimpleDateFormat("dd-MMM-yyyy", Locale.US); - private LinkedList mConnections = + private final Deque mConnections = new LinkedList(); /** @@ -453,7 +439,7 @@ public class ImapStore extends Store { * requests. This cache lets us make sure we always reuse, if possible, for a given * folder name. */ - private HashMap mFolderCache = new HashMap(); + private final Map mFolderCache = new HashMap(); public ImapStore(Account account) throws MessagingException { super(account); @@ -756,18 +742,10 @@ public class ImapStore extends Store { } private String encodeFolderName(String name) { - try { - ByteBuffer bb = mModifiedUtf7Charset.encode(name); - byte[] b = new byte[bb.limit()]; - bb.get(b); - return new String(b, "US-ASCII"); - } catch (UnsupportedEncodingException uee) { - /* - * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't - * exist we're totally screwed. - */ - throw new RuntimeException("Unable to encode folder name: " + name, uee); - } + ByteBuffer bb = mModifiedUtf7Charset.encode(name); + byte[] b = new byte[bb.limit()]; + bb.get(b); + return new String(b, Charset.forName("US-ASCII")); } private String decodeFolderName(String name) throws CharacterCodingException { @@ -775,18 +753,11 @@ public class ImapStore extends Store { * Convert the encoded name to US-ASCII, then pass it through the modified UTF-7 * decoder and return the Unicode String. */ - try { - // Make sure the decoder throws an exception if it encounters an invalid encoding. - CharsetDecoder decoder = mModifiedUtf7Charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT); - CharBuffer cb = decoder.decode(ByteBuffer.wrap(name.getBytes("US-ASCII"))); - return cb.toString(); - } catch (UnsupportedEncodingException uee) { - /* - * The only thing that can throw this is getBytes("US-ASCII") and if US-ASCII doesn't - * exist we're totally screwed. - */ - throw new RuntimeException("Unable to decode folder name: " + name, uee); - } + // Make sure the decoder throws an exception if it encounters an invalid encoding. + CharsetDecoder decoder = mModifiedUtf7Charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT); + CharBuffer cb = decoder.decode(ByteBuffer.wrap(name.getBytes(Charset.forName("US-ASCII")))); + return cb.toString(); + } @Override @@ -3467,7 +3438,7 @@ public class ImapStore extends Store { final PushReceiver mReceiver; private long lastRefresh = -1; - HashMap folderPushers = new HashMap(); + final Map folderPushers = new HashMap(); public ImapPusher(ImapStore store, PushReceiver receiver) { mStore = store; diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java index e34354b15..fa2c7049c 100644 --- a/src/com/fsck/k9/mail/store/Pop3Store.java +++ b/src/com/fsck/k9/mail/store/Pop3Store.java @@ -7,6 +7,7 @@ import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.R; import com.fsck.k9.controller.MessageRetrievalListener; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.*; import com.fsck.k9.mail.filter.Base64; @@ -115,28 +116,23 @@ public class Pop3Store extends Store { AuthType authType = AuthType.PLAIN; if (pop3Uri.getUserInfo() != null) { - try { - int userIndex = 0, passwordIndex = 1; - String userinfo = pop3Uri.getUserInfo(); - String[] userInfoParts = userinfo.split(":"); - if (userInfoParts.length > 2 || userinfo.endsWith(":") ) { - // If 'userinfo' ends with ":" the password is empty. This can only happen - // after an account was imported (so authType and username are present). - userIndex++; - passwordIndex++; - authType = AuthType.valueOf(userInfoParts[0]); + int userIndex = 0, passwordIndex = 1; + String userinfo = pop3Uri.getUserInfo(); + String[] userInfoParts = userinfo.split(":"); + if (userInfoParts.length > 2 || userinfo.endsWith(":") ) { + // If 'userinfo' ends with ":" the password is empty. This can only happen + // after an account was imported (so authType and username are present). + userIndex++; + passwordIndex++; + authType = AuthType.valueOf(userInfoParts[0]); + } + username = UrlEncodingHelper.decodeUtf8(userInfoParts[userIndex]); + if (userInfoParts.length > passwordIndex) { + if (authType == AuthType.EXTERNAL) { + clientCertificateAlias = UrlEncodingHelper.decodeUtf8(userInfoParts[passwordIndex]); + } else { + password = UrlEncodingHelper.decodeUtf8(userInfoParts[passwordIndex]); } - username = URLDecoder.decode(userInfoParts[userIndex], "UTF-8"); - if (userInfoParts.length > passwordIndex) { - if (authType == AuthType.EXTERNAL) { - clientCertificateAlias = URLDecoder.decode(userInfoParts[passwordIndex], "UTF-8"); - } else { - password = URLDecoder.decode(userInfoParts[passwordIndex], "UTF-8"); - } - } - } catch (UnsupportedEncodingException enc) { - // This shouldn't happen since the encoding is hardcoded to UTF-8 - throw new IllegalArgumentException("Couldn't urldecode username or password.", enc); } } @@ -156,19 +152,11 @@ public class Pop3Store extends Store { * @see Pop3Store#decodeUri(String) */ public static String createUri(ServerSettings server) { - String userEnc; - String passwordEnc; - String clientCertificateAliasEnc; - try { - userEnc = URLEncoder.encode(server.username, "UTF-8"); - passwordEnc = (server.password != null) ? - URLEncoder.encode(server.password, "UTF-8") : ""; - clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? - URLEncoder.encode(server.clientCertificateAlias, "UTF-8") : ""; - } - catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Could not encode username or password", e); - } + String userEnc = UrlEncodingHelper.encodeUtf8(server.username); + String passwordEnc = (server.password != null) ? + UrlEncodingHelper.encodeUtf8(server.password) : ""; + String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? + UrlEncodingHelper.encodeUtf8(server.clientCertificateAlias) : ""; String scheme; switch (server.connectionSecurity) { diff --git a/src/com/fsck/k9/mail/store/WebDavStore.java b/src/com/fsck/k9/mail/store/WebDavStore.java index 6e21aef9f..1148927bb 100644 --- a/src/com/fsck/k9/mail/store/WebDavStore.java +++ b/src/com/fsck/k9/mail/store/WebDavStore.java @@ -5,6 +5,8 @@ import android.util.Log; import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.controller.MessageRetrievalListener; + +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.*; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; @@ -40,8 +42,6 @@ import javax.xml.parsers.SAXParserFactory; import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; -import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; @@ -139,22 +139,17 @@ public class WebDavStore extends Store { String userInfo = webDavUri.getUserInfo(); if (userInfo != null) { - try { - String[] userInfoParts = userInfo.split(":"); - username = URLDecoder.decode(userInfoParts[0], "UTF-8"); - String userParts[] = username.split("\\\\", 2); + String[] userInfoParts = userInfo.split(":"); + username = UrlEncodingHelper.decodeUtf8(userInfoParts[0]); + String userParts[] = username.split("\\\\", 2); - if (userParts.length > 1) { - alias = userParts[1]; - } else { - alias = username; - } - if (userInfoParts.length > 1) { - password = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } - } catch (UnsupportedEncodingException enc) { - // This shouldn't happen since the encoding is hardcoded to UTF-8 - throw new IllegalArgumentException("Couldn't urldecode username or password.", enc); + if (userParts.length > 1) { + alias = userParts[1]; + } else { + alias = username; + } + if (userInfoParts.length > 1) { + password = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); } } @@ -194,16 +189,9 @@ public class WebDavStore extends Store { * @see WebDavStore#decodeUri(String) */ public static String createUri(ServerSettings server) { - String userEnc; - String passwordEnc; - try { - userEnc = URLEncoder.encode(server.username, "UTF-8"); - passwordEnc = (server.password != null) ? - URLEncoder.encode(server.password, "UTF-8") : ""; - } - catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Could not encode username or password", e); - } + String userEnc = UrlEncodingHelper.encodeUtf8(server.username); + String passwordEnc = (server.password != null) ? + UrlEncodingHelper.encodeUtf8(server.password) : ""; String scheme; switch (server.connectionSecurity) { @@ -479,7 +467,6 @@ public class WebDavStore extends Store { } if (folderSlash > 0) { - String folderName; String fullPathName; // Removes the final slash if present @@ -489,17 +476,8 @@ public class WebDavStore extends Store { fullPathName = folderUrl.substring(folderSlash + 1); // Decodes the url-encoded folder name (i.e. "My%20folder" => "My Folder" - try { - folderName = java.net.URLDecoder.decode(fullPathName, "UTF-8"); - } catch (UnsupportedEncodingException uee) { - /** - * If we don't support UTF-8 there's a problem, don't decode - * it then - */ - folderName = fullPathName; - } - return folderName; + return UrlEncodingHelper.decodeUtf8(fullPathName); } return null; @@ -1258,21 +1236,16 @@ public class WebDavStore extends Store { this.mName = name; String encodedName = ""; - try { - String[] urlParts = name.split("/"); - String url = ""; - for (int i = 0, count = urlParts.length; i < count; i++) { - if (i != 0) { - url = url + "/" + java.net.URLEncoder.encode(urlParts[i], "UTF-8"); - } else { - url = java.net.URLEncoder.encode(urlParts[i], "UTF-8"); - } + String[] urlParts = name.split("/"); + String url = ""; + for (int i = 0, count = urlParts.length; i < count; i++) { + if (i != 0) { + url = url + "/" + UrlEncodingHelper.encodeUtf8(urlParts[i]); + } else { + url = UrlEncodingHelper.encodeUtf8(urlParts[i]); } - encodedName = url; - } catch (UnsupportedEncodingException uee) { - Log.e(K9.LOG_TAG, "UnsupportedEncodingException URLEncoding folder name, skipping encoded"); - encodedName = name; } + encodedName = url; encodedName = encodedName.replaceAll("\\+", "%20"); @@ -1910,7 +1883,7 @@ public class WebDavStore extends Store { if (!messageURL.endsWith("/")) { messageURL += "/"; } - messageURL += URLEncoder.encode(message.getUid() + ":" + System.currentTimeMillis() + ".eml", "UTF-8"); + messageURL += UrlEncodingHelper.encodeUtf8(message.getUid() + ":" + System.currentTimeMillis() + ".eml"); Log.i(K9.LOG_TAG, "Uploading message as " + messageURL); @@ -1997,12 +1970,9 @@ public class WebDavStore extends Store { * We have to decode, then encode the URL because Exchange likes to not properly encode all characters */ try { - end = java.net.URLDecoder.decode(end, "UTF-8"); - end = java.net.URLEncoder.encode(end, "UTF-8"); + end = UrlEncodingHelper.decodeUtf8(end); + end = UrlEncodingHelper.encodeUtf8(end); end = end.replaceAll("\\+", "%20"); - } catch (UnsupportedEncodingException uee) { - Log.e(K9.LOG_TAG, "UnsupportedEncodingException caught in setUrl: " + uee + "\nTrace: " - + processException(uee)); } catch (IllegalArgumentException iae) { Log.e(K9.LOG_TAG, "IllegalArgumentException caught in setUrl: " + iae + "\nTrace: " + processException(iae)); @@ -2405,13 +2375,10 @@ public class WebDavStore extends Store { */ try { if (length > 3) { - end = java.net.URLDecoder.decode(end, "UTF-8"); - end = java.net.URLEncoder.encode(end, "UTF-8"); + end = UrlEncodingHelper.decodeUtf8(end); + end = UrlEncodingHelper.encodeUtf8(end); end = end.replaceAll("\\+", "%20"); } - } catch (UnsupportedEncodingException uee) { - Log.e(K9.LOG_TAG, "UnsupportedEncodingException caught in HttpGeneric(String uri): " + uee - + "\nTrace: " + processException(uee)); } catch (IllegalArgumentException iae) { Log.e(K9.LOG_TAG, "IllegalArgumentException caught in HttpGeneric(String uri): " + iae + "\nTrace: " + processException(iae)); diff --git a/src/com/fsck/k9/mail/store/local/LocalStore.java b/src/com/fsck/k9/mail/store/local/LocalStore.java index 9119831c1..17b9fac68 100644 --- a/src/com/fsck/k9/mail/store/local/LocalStore.java +++ b/src/com/fsck/k9/mail/store/local/LocalStore.java @@ -3,8 +3,6 @@ package com.fsck.k9.mail.store.local; import java.io.File; import java.io.Serializable; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; @@ -28,6 +26,7 @@ import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.controller.MessageRetrievalListener; import com.fsck.k9.helper.StringUtils; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; @@ -101,7 +100,7 @@ public class LocalStore extends Store implements Serializable { /** * Maximum number of messages to perform flag updates on at once. * - * @see #setFlag(List, Flag, boolean, boolean) + * @see #setFlag(List, Flag, boolean) */ private static final int FLAG_UPDATE_BATCH_SIZE = 500; @@ -460,23 +459,19 @@ public class LocalStore extends Store implements Serializable { } public void addPendingCommand(PendingCommand command) throws UnavailableStorageException { - try { - for (int i = 0; i < command.arguments.length; i++) { - command.arguments[i] = URLEncoder.encode(command.arguments[i], "UTF-8"); - } - final ContentValues cv = new ContentValues(); - cv.put("command", command.command); - cv.put("arguments", Utility.combine(command.arguments, ',')); - database.execute(false, new DbCallback() { - @Override - public Void doDbWork(final SQLiteDatabase db) throws WrappedException { - db.insert("pending_commands", "command", cv); - return null; - } - }); - } catch (UnsupportedEncodingException uee) { - throw new Error("Aparently UTF-8 has been lost to the annals of history."); + for (int i = 0; i < command.arguments.length; i++) { + command.arguments[i] = UrlEncodingHelper.encodeUtf8(command.arguments[i]); } + final ContentValues cv = new ContentValues(); + cv.put("command", command.command); + cv.put("arguments", Utility.combine(command.arguments, ',')); + database.execute(false, new DbCallback() { + @Override + public Void doDbWork(final SQLiteDatabase db) throws WrappedException { + db.insert("pending_commands", "command", cv); + return null; + } + }); } public void removePendingCommand(final PendingCommand command) throws UnavailableStorageException { diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java index eb381bd83..bd50419f1 100644 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/src/com/fsck/k9/mail/transport/SmtpTransport.java @@ -6,6 +6,7 @@ import android.util.Log; import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.R; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.*; import com.fsck.k9.mail.Message.RecipientType; @@ -23,7 +24,6 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.net.*; import java.security.GeneralSecurityException; import java.util.*; @@ -92,28 +92,23 @@ public class SmtpTransport extends Transport { } if (smtpUri.getUserInfo() != null) { - try { - String[] userInfoParts = smtpUri.getUserInfo().split(":"); - if (userInfoParts.length == 1) { - authType = AuthType.PLAIN; - username = URLDecoder.decode(userInfoParts[0], "UTF-8"); - } else if (userInfoParts.length == 2) { - authType = AuthType.PLAIN; - username = URLDecoder.decode(userInfoParts[0], "UTF-8"); - password = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } else if (userInfoParts.length == 3) { - // NOTE: In SmptTransport URIs, the authType comes last! - authType = AuthType.valueOf(userInfoParts[2]); - username = URLDecoder.decode(userInfoParts[0], "UTF-8"); - if (authType == AuthType.EXTERNAL) { - clientCertificateAlias = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } else { - password = URLDecoder.decode(userInfoParts[1], "UTF-8"); - } + String[] userInfoParts = smtpUri.getUserInfo().split(":"); + if (userInfoParts.length == 1) { + authType = AuthType.PLAIN; + username = UrlEncodingHelper.decodeUtf8(userInfoParts[0]); + } else if (userInfoParts.length == 2) { + authType = AuthType.PLAIN; + username = UrlEncodingHelper.decodeUtf8(userInfoParts[0]); + password = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); + } else if (userInfoParts.length == 3) { + // NOTE: In SmptTransport URIs, the authType comes last! + authType = AuthType.valueOf(userInfoParts[2]); + username = UrlEncodingHelper.decodeUtf8(userInfoParts[0]); + if (authType == AuthType.EXTERNAL) { + clientCertificateAlias = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); + } else { + password = UrlEncodingHelper.decodeUtf8(userInfoParts[1]); } - } catch (UnsupportedEncodingException enc) { - // This shouldn't happen since the encoding is hardcoded to UTF-8 - throw new IllegalArgumentException("Couldn't urldecode username or password.", enc); } } @@ -133,20 +128,12 @@ public class SmtpTransport extends Transport { * @see SmtpTransport#decodeUri(String) */ public static String createUri(ServerSettings server) { - String userEnc; - String passwordEnc; - String clientCertificateAliasEnc; - try { - userEnc = (server.username != null) ? - URLEncoder.encode(server.username, "UTF-8") : ""; - passwordEnc = (server.password != null) ? - URLEncoder.encode(server.password, "UTF-8") : ""; - clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? - URLEncoder.encode(server.clientCertificateAlias, "UTF-8") : ""; - } - catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Could not encode username or password", e); - } + String userEnc = (server.username != null) ? + UrlEncodingHelper.encodeUtf8(server.username) : ""; + String passwordEnc = (server.password != null) ? + UrlEncodingHelper.encodeUtf8(server.password) : ""; + String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ? + UrlEncodingHelper.encodeUtf8(server.clientCertificateAlias) : ""; String scheme; switch (server.connectionSecurity) { diff --git a/src/com/fsck/k9/preferences/Storage.java b/src/com/fsck/k9/preferences/Storage.java index e4a624847..e88a9b6c3 100644 --- a/src/com/fsck/k9/preferences/Storage.java +++ b/src/com/fsck/k9/preferences/Storage.java @@ -9,6 +9,7 @@ import android.database.sqlite.SQLiteStatement; import android.util.Log; import com.fsck.k9.K9; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import java.net.URI; @@ -59,11 +60,11 @@ public class Storage implements SharedPreferences { if (transportUriStr != null) { String[] userInfoParts = uri.getUserInfo().split(":"); - String usernameEnc = URLEncoder.encode(userInfoParts[0], "UTF-8"); + String usernameEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[0]); String passwordEnc = ""; String authType = ""; if (userInfoParts.length > 1) { - passwordEnc = ":" + URLEncoder.encode(userInfoParts[1], "UTF-8"); + passwordEnc = ":" + UrlEncodingHelper.encodeUtf8(userInfoParts[1]); } if (userInfoParts.length > 2) { authType = ":" + userInfoParts[2]; @@ -83,34 +84,34 @@ public class Storage implements SharedPreferences { if (storeUriStr.startsWith("imap")) { String[] userInfoParts = uri.getUserInfo().split(":"); if (userInfoParts.length == 2) { - String usernameEnc = URLEncoder.encode(userInfoParts[0], "UTF-8"); - String passwordEnc = URLEncoder.encode(userInfoParts[1], "UTF-8"); + String usernameEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[0]); + String passwordEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[1]); newUserInfo = usernameEnc + ":" + passwordEnc; } else { String authType = userInfoParts[0]; - String usernameEnc = URLEncoder.encode(userInfoParts[1], "UTF-8"); - String passwordEnc = URLEncoder.encode(userInfoParts[2], "UTF-8"); + String usernameEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[1]); + String passwordEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[2]); newUserInfo = authType + ":" + usernameEnc + ":" + passwordEnc; } } else if (storeUriStr.startsWith("pop3")) { String[] userInfoParts = uri.getUserInfo().split(":", 2); - String usernameEnc = URLEncoder.encode(userInfoParts[0], "UTF-8"); + String usernameEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[0]); String passwordEnc = ""; if (userInfoParts.length > 1) { - passwordEnc = ":" + URLEncoder.encode(userInfoParts[1], "UTF-8"); + passwordEnc = ":" + UrlEncodingHelper.encodeUtf8(userInfoParts[1]); } newUserInfo = usernameEnc + passwordEnc; } else if (storeUriStr.startsWith("webdav")) { String[] userInfoParts = uri.getUserInfo().split(":", 2); - String usernameEnc = URLEncoder.encode(userInfoParts[0], "UTF-8"); + String usernameEnc = UrlEncodingHelper.encodeUtf8(userInfoParts[0]); String passwordEnc = ""; if (userInfoParts.length > 1) { - passwordEnc = ":" + URLEncoder.encode(userInfoParts[1], "UTF-8"); + passwordEnc = ":" + UrlEncodingHelper.encodeUtf8(userInfoParts[1]); } newUserInfo = usernameEnc + passwordEnc; diff --git a/src/com/fsck/k9/view/MessageOpenPgpView.java b/src/com/fsck/k9/view/MessageOpenPgpView.java index dd2cbb40b..1b224112f 100644 --- a/src/com/fsck/k9/view/MessageOpenPgpView.java +++ b/src/com/fsck/k9/view/MessageOpenPgpView.java @@ -5,6 +5,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import android.app.Activity; import android.app.Fragment; @@ -279,12 +280,7 @@ public class MessageOpenPgpView extends LinearLayout { String accName = OpenPgpApiHelper.buildAccountName(identity); intent.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, accName); - InputStream is = null; - try { - is = new ByteArrayInputStream(mData.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - Log.e(K9.LOG_TAG, "UnsupportedEncodingException.", e); - } + InputStream is = new ByteArrayInputStream(mData.getBytes(Charset.forName("UTF-8"))); final ByteArrayOutputStream os = new ByteArrayOutputStream(); DecryptVerifyCallback callback = new DecryptVerifyCallback(os, REQUEST_CODE_DECRYPT_VERIFY); diff --git a/src/com/fsck/k9/view/SingleMessageView.java b/src/com/fsck/k9/view/SingleMessageView.java index f9e1cdda1..bca3eef0d 100644 --- a/src/com/fsck/k9/view/SingleMessageView.java +++ b/src/com/fsck/k9/view/SingleMessageView.java @@ -47,6 +47,7 @@ import com.fsck.k9.fragment.MessageViewFragment; import com.fsck.k9.helper.ClipboardManager; import com.fsck.k9.helper.Contacts; import com.fsck.k9.helper.HtmlConverter; +import com.fsck.k9.helper.UrlEncodingHelper; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Flag; @@ -790,7 +791,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener, // Try to get the filename from the URL int start = path.lastIndexOf("/"); if (start != -1 && start + 1 < path.length()) { - filename = URLDecoder.decode(path.substring(start + 1), "UTF-8"); + filename = UrlEncodingHelper.decodeUtf8(path.substring(start + 1)); } else { // Use a dummy filename if necessary filename = "saved_image";