From 6f14294164b94d25fa00038a5c2d544ddf195b4e Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Thu, 21 Aug 2014 16:16:19 -0400 Subject: [PATCH 01/16] Remove SslHelper. Don't use SecureRandom. SslHelper has been removed, and its functionality has been transferred into TrustedSocketFactory. The added layer of indirection wasn't really simplifying anything. It's now easier to see what happens when createSocket() is invoked. A new instance of SecureRandom is no longer passed to SSLContext.init(). Instead, null is passed. The (default) provider of the TLS SSLContext used is OpenSSLProvider, which provides an SSLSocket instance of type OpenSSLSocketImpl. The only use of SecureRandom is in OpenSSLSocketImpl.startHandshake(), where it is used to seed the OpenSSL PRNG with additional random data. But if SecureRandom is null, then /dev/urandom is used for seeding instead. Meanwhile, the default provider for the SecureRandom service is OpenSSLRandom, which uses the OpenSSL PRNG as its data source. So we were effectively seeding the OpenSSL PRNG with itself. That's probably okay (we trust that the OpenSSL PRNG was properly initialized with random data before first use), but using /dev/urandom would seem like a better source (or at least as good a source) for the additional seed data added with each new connection. Note that our PRNGFixes class replaces the default SecureRandom service with one whose data source is /dev/urandom for certain vulnerable API levels anyway. (It also makes sure that the OpenSSL PRNG is properly seeded before first use for certain vulnerable API levels.) --- src/com/fsck/k9/mail/store/ImapStore.java | 8 +- src/com/fsck/k9/mail/store/Pop3Store.java | 6 +- .../fsck/k9/mail/transport/SmtpTransport.java | 6 +- src/com/fsck/k9/net/ssl/SslHelper.java | 81 ------------------- .../fsck/k9/net/ssl/TrustedSocketFactory.java | 44 +++++++--- 5 files changed, 42 insertions(+), 103 deletions(-) delete mode 100644 src/com/fsck/k9/net/ssl/SslHelper.java diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 5f9dd1079..f2c002e05 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -96,7 +96,7 @@ import com.fsck.k9.mail.store.ImapResponseParser.ImapList; import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse; import com.fsck.k9.mail.store.imap.ImapUtility; import com.fsck.k9.mail.transport.imap.ImapSettings; -import com.fsck.k9.net.ssl.SslHelper; +import com.fsck.k9.net.ssl.TrustedSocketFactory; import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.ZOutputStream; @@ -2435,7 +2435,7 @@ public class ImapStore extends Store { mSettings.getPort()); if (connectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) { - mSocket = SslHelper.createSslSocket(mSettings.getHost(), + mSocket = TrustedSocketFactory.createSocket(mSettings.getHost(), mSettings.getPort(), mSettings.getClientCertificateAlias()); } else { mSocket = new Socket(); @@ -2485,8 +2485,8 @@ public class ImapStore extends Store { // STARTTLS executeSimpleCommand("STARTTLS"); - mSocket = SslHelper.createStartTlsSocket(mSocket, - mSettings.getHost(), mSettings.getPort(), true, + mSocket = TrustedSocketFactory.createSocket(mSocket, + mSettings.getHost(), mSettings.getPort(), mSettings.getClientCertificateAlias()); mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); mIn = new PeekableInputStream(new BufferedInputStream(mSocket diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java index a66bca2ac..37c9b8efe 100644 --- a/src/com/fsck/k9/mail/store/Pop3Store.java +++ b/src/com/fsck/k9/mail/store/Pop3Store.java @@ -12,7 +12,7 @@ import com.fsck.k9.mail.*; import com.fsck.k9.mail.filter.Base64; import com.fsck.k9.mail.filter.Hex; import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.net.ssl.SslHelper; +import com.fsck.k9.net.ssl.TrustedSocketFactory; import javax.net.ssl.SSLException; @@ -314,7 +314,7 @@ public class Pop3Store extends Store { try { SocketAddress socketAddress = new InetSocketAddress(mHost, mPort); if (mConnectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) { - mSocket = SslHelper.createSslSocket(mHost, mPort, mClientCertificateAlias); + mSocket = TrustedSocketFactory.createSocket(mHost, mPort, mClientCertificateAlias); } else { mSocket = new Socket(); } @@ -336,7 +336,7 @@ public class Pop3Store extends Store { if (mCapabilities.stls) { executeSimpleCommand(STLS_COMMAND); - mSocket = SslHelper.createStartTlsSocket(mSocket, mHost, mPort, true, + mSocket = TrustedSocketFactory.createSocket(mSocket, mHost, mPort, mClientCertificateAlias); mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT); mIn = new BufferedInputStream(mSocket.getInputStream(), 1024); diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java index cedfaeaf5..cd8423c07 100644 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/src/com/fsck/k9/mail/transport/SmtpTransport.java @@ -15,7 +15,7 @@ import com.fsck.k9.mail.filter.PeekableInputStream; import com.fsck.k9.mail.filter.SmtpDataStuffing; import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mail.store.LocalStore.LocalMessage; -import com.fsck.k9.net.ssl.SslHelper; +import com.fsck.k9.net.ssl.TrustedSocketFactory; import javax.net.ssl.SSLException; @@ -224,7 +224,7 @@ public class SmtpTransport extends Transport { try { SocketAddress socketAddress = new InetSocketAddress(addresses[i], mPort); if (mConnectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) { - mSocket = SslHelper.createSslSocket(mHost, mPort, mClientCertificateAlias); + mSocket = TrustedSocketFactory.createSocket(mHost, mPort, mClientCertificateAlias); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); secureConnection = true; } else { @@ -278,7 +278,7 @@ public class SmtpTransport extends Transport { if (extensions.containsKey("STARTTLS")) { executeSimpleCommand("STARTTLS"); - mSocket = SslHelper.createStartTlsSocket(mSocket, mHost, mPort, true, + mSocket = TrustedSocketFactory.createSocket(mSocket, mHost, mPort, mClientCertificateAlias); mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(), diff --git a/src/com/fsck/k9/net/ssl/SslHelper.java b/src/com/fsck/k9/net/ssl/SslHelper.java deleted file mode 100644 index 38e281bf0..000000000 --- a/src/com/fsck/k9/net/ssl/SslHelper.java +++ /dev/null @@ -1,81 +0,0 @@ - -package com.fsck.k9.net.ssl; - -import java.io.IOException; -import java.net.Socket; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -import android.util.Log; - -import com.fsck.k9.K9; -import com.fsck.k9.mail.MessagingException; - -/** - * Helper class to create SSL sockets with support for client certificate - * authentication - */ -public class SslHelper { - - private static SSLContext createSslContext(String host, int port, String clientCertificateAlias) - throws NoSuchAlgorithmException, KeyManagementException, MessagingException { - if (K9.DEBUG) - Log.d(K9.LOG_TAG, "createSslContext: Client certificate alias: " - + clientCertificateAlias); - - KeyManager[] keyManagers; - if (clientCertificateAlias == null || clientCertificateAlias.isEmpty()) { - keyManagers = null; - } else { - keyManagers = new KeyManager[] { new KeyChainKeyManager(K9.app, clientCertificateAlias) }; - } - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagers, - new TrustManager[] { - TrustManagerFactory.get( - host, port) - }, - new SecureRandom()); - - return sslContext; - } - - /** - * Create SSL socket - * - * @param host - * @param port - * @param clientCertificateAlias if not null, uses client certificate - * retrieved by this alias for authentication - */ - public static Socket createSslSocket(String host, int port, String clientCertificateAlias) - throws NoSuchAlgorithmException, KeyManagementException, IOException, - MessagingException { - SSLContext sslContext = createSslContext(host, port, clientCertificateAlias); - return TrustedSocketFactory.createSocket(sslContext); - } - - /** - * Create socket for START_TLS. autoClose = true - * - * @param socket - * @param host - * @param port - * @param secure - * @param clientCertificateAlias if not null, uses client certificate - * retrieved by this alias for authentication - */ - public static Socket createStartTlsSocket(Socket socket, String host, int port, boolean secure, - String clientCertificateAlias) throws NoSuchAlgorithmException, - KeyManagementException, IOException, MessagingException { - SSLContext sslContext = createSslContext(host, port, clientCertificateAlias); - boolean autoClose = true; - return TrustedSocketFactory.createSocket(sslContext, socket, host, port, autoClose); - } -} diff --git a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java index 030bf4910..6b7bad9a0 100644 --- a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java +++ b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java @@ -3,14 +3,21 @@ package com.fsck.k9.net.ssl; import android.util.Log; import com.fsck.k9.K9; +import com.fsck.k9.mail.MessagingException; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + import java.io.IOException; import java.net.Socket; -import java.security.SecureRandom; -import java.util.*; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** @@ -71,7 +78,7 @@ public class TrustedSocketFactory { try { SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, null, new SecureRandom()); + sslContext.init(null, null, null); SSLSocketFactory sf = sslContext.getSocketFactory(); SSLSocket sock = (SSLSocket) sf.createSocket(); enabledCiphers = sock.getEnabledCipherSuites(); @@ -114,19 +121,32 @@ public class TrustedSocketFactory { return result.toArray(new String[result.size()]); } - public static Socket createSocket(SSLContext sslContext) throws IOException { - SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(); - hardenSocket(socket); + public static Socket createSocket(String host, int port, String clientCertificateAlias) + throws IOException, MessagingException, KeyManagementException, NoSuchAlgorithmException { - return socket; + return createSocket(null, host, port, clientCertificateAlias); } - public static Socket createSocket(SSLContext sslContext, Socket s, String host, int port, - boolean autoClose) throws IOException { - SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(s, host, port, autoClose); - hardenSocket(socket); + public static Socket createSocket(Socket socket, String host, int port, String clientCertificateAlias) + throws NoSuchAlgorithmException, KeyManagementException, MessagingException, IOException { - return socket; + TrustManager[] trustManagers = new TrustManager[] { TrustManagerFactory.get(host, port) }; + KeyManager[] keyManagers = null; + if (clientCertificateAlias != null && !clientCertificateAlias.isEmpty()) { + keyManagers = new KeyManager[] { new KeyChainKeyManager(K9.app, clientCertificateAlias) }; + } + + SSLContext context = SSLContext.getInstance("TLS"); + context.init(keyManagers, trustManagers, null); + SSLSocketFactory socketFactory = context.getSocketFactory(); + Socket trustedSocket; + if (socket == null) { + trustedSocket = socketFactory.createSocket(); + } else { + trustedSocket = socketFactory.createSocket(socket, host, port, true); + } + hardenSocket((SSLSocket) trustedSocket); + return trustedSocket; } private static void hardenSocket(SSLSocket sock) { From 7dfbd906c92f280e9cce47389a2280d2064df15c Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Fri, 22 Aug 2014 10:02:45 -0400 Subject: [PATCH 02/16] Eliminate DomainNameChecker There's no need to maintain our own implementation when comparable classes already exist in the Android API. StrictHostnameVerifier is used instead. --- src/com/fsck/k9/helper/DomainNameChecker.java | 280 ------------------ .../fsck/k9/net/ssl/TrustManagerFactory.java | 31 +- 2 files changed, 14 insertions(+), 297 deletions(-) delete mode 100644 src/com/fsck/k9/helper/DomainNameChecker.java diff --git a/src/com/fsck/k9/helper/DomainNameChecker.java b/src/com/fsck/k9/helper/DomainNameChecker.java deleted file mode 100644 index 6731de648..000000000 --- a/src/com/fsck/k9/helper/DomainNameChecker.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.fsck.k9.helper; - -import android.net.http.SslCertificate; -import android.util.Log; -import com.fsck.k9.K9; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateParsingException; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Implements basic domain-name validation as specified by RFC2818. - */ -public class DomainNameChecker { - private static Pattern QUICK_IP_PATTERN; - static { - try { - QUICK_IP_PATTERN = Pattern.compile("^[a-f0-9\\.:]+$"); - } catch (PatternSyntaxException e) { - } - } - - private static final int ALT_DNS_NAME = 2; - private static final int ALT_IPA_NAME = 7; - - /** - * Checks the site certificate against the domain name of the site being - * visited - * - * @param certificate - * The certificate to check - * @param thisDomain - * The domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - public static boolean match(X509Certificate certificate, String thisDomain) { - if ((certificate == null) || (thisDomain == null) - || thisDomain.isEmpty()) { - return false; - } - - thisDomain = thisDomain.toLowerCase(Locale.US); - if (!isIpAddress(thisDomain)) { - return matchDns(certificate, thisDomain); - } else { - return matchIpAddress(certificate, thisDomain); - } - } - - /** - * @return True iff the domain name is specified as an IP address - */ - private static boolean isIpAddress(String domain) { - if ((domain == null) || domain.isEmpty()) { - return false; - } - - boolean rval; - try { - // do a quick-dirty IP match first to avoid DNS lookup - rval = QUICK_IP_PATTERN.matcher(domain).matches(); - if (rval) { - rval = domain.equals(InetAddress.getByName(domain) - .getHostAddress()); - } - } catch (UnknownHostException e) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "unknown host exception"; - } - - if (K9.DEBUG) { - Log.v(K9.LOG_TAG, "DomainNameChecker.isIpAddress(): " - + errorMessage); - } - - rval = false; - } - - return rval; - } - - /** - * Checks the site certificate against the IP domain name of the site being - * visited - * - * @param certificate - * The certificate to check - * @param thisDomain - * The DNS domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - private static boolean matchIpAddress(X509Certificate certificate, String thisDomain) { - if (K9.DEBUG) { - Log.v(K9.LOG_TAG, "DomainNameChecker.matchIpAddress(): this domain: " + thisDomain); - } - - try { - Collection> subjectAltNames = certificate.getSubjectAlternativeNames(); - if (subjectAltNames != null) { - for (List altNameEntry : subjectAltNames) { - if ((altNameEntry != null) && (2 <= altNameEntry.size())) { - Integer altNameType = (Integer)(altNameEntry.get(0)); - if (altNameType != null && altNameType.intValue() == ALT_IPA_NAME) { - String altName = (String)(altNameEntry.get(1)); - if (altName != null) { - if (K9.DEBUG) { - Log.v(K9.LOG_TAG, "alternative IP: " + altName); - } - if (thisDomain.equalsIgnoreCase(altName)) { - return true; - } - } - } - } - } - } - } catch (CertificateParsingException e) { - } - - return false; - } - - /** - * Checks the site certificate against the DNS domain name of the site being - * visited - * - * @param certificate - * The certificate to check - * @param thisDomain - * The DNS domain name of the site being visited - * @return True iff if there is a domain match as specified by RFC2818 - */ - private static boolean matchDns(X509Certificate certificate, String thisDomain) { - boolean hasDns = false; - try { - Collection> subjectAltNames = certificate.getSubjectAlternativeNames(); - if (subjectAltNames != null) { - for (List altNameEntry : subjectAltNames) { - if ((altNameEntry != null) && (2 <= altNameEntry.size())) { - Integer altNameType = (Integer)(altNameEntry.get(0)); - if (altNameType != null && altNameType.intValue() == ALT_DNS_NAME) { - hasDns = true; - String altName = (String)(altNameEntry.get(1)); - if (altName != null && matchDns(thisDomain, altName)) { - return true; - } - } - } - } - } - } catch (CertificateParsingException e) { - // one way we can get here is if an alternative name starts with - // '*' character, which is contrary to one interpretation of the - // spec (a valid DNS name must start with a letter); there is no - // good way around this, and in order to be compatible we proceed - // to check the common name (ie, ignore alternative names) - if (K9.DEBUG) { - String errorMessage = e.getMessage(); - if (errorMessage == null) { - errorMessage = "failed to parse certificate"; - } - - Log.v(K9.LOG_TAG, "DomainNameChecker.matchDns(): " - + errorMessage); - } - } - - if (!hasDns) { - SslCertificate sslCertificate = new SslCertificate(certificate); - return matchDns(thisDomain, sslCertificate.getIssuedTo().getCName()); - } - - return false; - } - - /** - * @param thisDomain - * The domain name of the site being visited - * @param thatDomain - * The domain name from the certificate - * @return True iff thisDomain matches thatDomain as specified by RFC2818 - */ - private static boolean matchDns(String thisDomain, String thatDomain) { - if (K9.DEBUG) { - Log.v(K9.LOG_TAG, "DomainNameChecker.matchDns():" - + " this domain: " + thisDomain + " that domain: " - + thatDomain); - } - - if ((thisDomain == null) || thisDomain.isEmpty() - || (thatDomain == null) || thatDomain.isEmpty()) { - return false; - } - - thatDomain = thatDomain.toLowerCase(Locale.US); - - // (a) domain name strings are equal, ignoring case: X matches X - boolean rval = thisDomain.equals(thatDomain); - if (!rval) { - String[] thisDomainTokens = thisDomain.split("\\."); - String[] thatDomainTokens = thatDomain.split("\\."); - - int thisDomainTokensNum = thisDomainTokens.length; - int thatDomainTokensNum = thatDomainTokens.length; - - // (b) OR thatHost is a '.'-suffix of thisHost: Z.Y.X matches X - if (thisDomainTokensNum >= thatDomainTokensNum) { - for (int i = thatDomainTokensNum - 1; i >= 0; --i) { - rval = thisDomainTokens[i].equals(thatDomainTokens[i]); - if (!rval) { - // (c) OR we have a special *-match: - // Z.Y.X matches *.Y.X but does not match *.X - rval = ((i == 0) && (thisDomainTokensNum == thatDomainTokensNum)); - if (rval) { - rval = thatDomainTokens[0].equals("*"); - if (!rval) { - // (d) OR we have a *-component match: - // f*.com matches foo.com but not bar.com - rval = domainTokenMatch(thisDomainTokens[0], - thatDomainTokens[0]); - } - } - - break; - } - } - } - } - - return rval; - } - - /** - * @param thisDomainToken - * The domain token from the current domain name - * @param thatDomainToken - * The domain token from the certificate - * @return True iff thisDomainToken matches thatDomainToken, using the - * wildcard match as specified by RFC2818-3.1. For example, f*.com - * must match foo.com but not bar.com - */ - private static boolean domainTokenMatch(String thisDomainToken, String thatDomainToken) { - if ((thisDomainToken != null) && (thatDomainToken != null)) { - int starIndex = thatDomainToken.indexOf('*'); - if (starIndex >= 0) { - if (thatDomainToken.length() - 1 <= thisDomainToken.length()) { - String prefix = thatDomainToken.substring(0, starIndex); - String suffix = thatDomainToken.substring(starIndex + 1); - - return thisDomainToken.startsWith(prefix) - && thisDomainToken.endsWith(suffix); - } - } - } - - return false; - } -} diff --git a/src/com/fsck/k9/net/ssl/TrustManagerFactory.java b/src/com/fsck/k9/net/ssl/TrustManagerFactory.java index 27b2c70bb..4a2c7206a 100644 --- a/src/com/fsck/k9/net/ssl/TrustManagerFactory.java +++ b/src/com/fsck/k9/net/ssl/TrustManagerFactory.java @@ -3,12 +3,15 @@ package com.fsck.k9.net.ssl; import android.util.Log; -import com.fsck.k9.helper.DomainNameChecker; import com.fsck.k9.mail.CertificateChainException; import com.fsck.k9.security.LocalKeyStore; +import javax.net.ssl.SSLException; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; + +import org.apache.http.conn.ssl.StrictHostnameVerifier; + import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -58,31 +61,25 @@ public final class TrustManagerFactory { public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { String message = null; - boolean foundInGlobalKeyStore = false; + X509Certificate certificate = chain[0]; + try { defaultTrustManager.checkServerTrusted(chain, authType); - foundInGlobalKeyStore = true; + new StrictHostnameVerifier().verify(mHost, certificate); + return; } catch (CertificateException e) { + // cert. chain can't be validated + message = e.getMessage(); + } catch (SSLException e) { + // host name doesn't match certificate message = e.getMessage(); } - X509Certificate certificate = chain[0]; - // Check the local key store if we couldn't verify the certificate using the global // key store or if the host name doesn't match the certificate name - if (foundInGlobalKeyStore - && DomainNameChecker.match(certificate, mHost) - || keyStore.isValidCertificate(certificate, mHost, mPort)) { - return; + if (!keyStore.isValidCertificate(certificate, mHost, mPort)) { + throw new CertificateChainException(message, chain); } - - if (message == null) { - message = (foundInGlobalKeyStore) ? - "Certificate domain name does not match " + mHost : - "Couldn't find certificate in local key store"; - } - - throw new CertificateChainException(message, chain); } public X509Certificate[] getAcceptedIssuers() { From 43c38a047feedda4720af5bfbc188a33f8dfaced Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Sat, 6 Sep 2014 16:35:48 -0400 Subject: [PATCH 03/16] Implement SSL file-based session caching Caching is beneficial because it can eliminate redundant cryptographic computations and network traffic when re-establishing a connection to the same server, thus saving time and conserving power. --- .../k9/net/ssl/SslSessionCacheHelper.java | 89 +++++++++++++++++++ .../fsck/k9/net/ssl/TrustedSocketFactory.java | 1 + 2 files changed, 90 insertions(+) create mode 100644 src/com/fsck/k9/net/ssl/SslSessionCacheHelper.java diff --git a/src/com/fsck/k9/net/ssl/SslSessionCacheHelper.java b/src/com/fsck/k9/net/ssl/SslSessionCacheHelper.java new file mode 100644 index 000000000..20439c4ff --- /dev/null +++ b/src/com/fsck/k9/net/ssl/SslSessionCacheHelper.java @@ -0,0 +1,89 @@ +package com.fsck.k9.net.ssl; + +import java.io.File; +import java.lang.reflect.Method; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSessionContext; + +import com.fsck.k9.K9; + +import android.content.Context; +import android.os.Build; +import android.util.Log; + +/** + * A class to help with associating an {@code SSLContext} with a persistent + * file-based cache of SSL sessions. + *

+ * This uses reflection to achieve its task. + *

+ * The alternative to this would be to use {@link SSLCertificateSocketFactory} + * which also provides session caching. The problem with using that occurs when + * using STARTTLS in combination with + * {@code TrustedSocketFactory.hardenSocket(SSLSocket)}. The result is that + * {@code hardenSocket()} fails to change anything because by the time it is + * applied to the socket, the SSL handshake has already been completed. (This is + * because of another feature of {@link SSLCertificateSocketFactory} whereby it + * performs host name verification which necessitates initiating the SSL + * handshake immediately on socket creation.) + *

+ * If eventually the use of hardenSocket() should become unnecessary, then + * switching to using {@link SSLCertificateSocketFactory} would be a better + * solution. + */ +public class SslSessionCacheHelper { + private static Object sSessionCache; + private static Method sSetPersistentCacheMethod; + private static boolean sIsDisabled = false; + + static { + final String packageName; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + packageName = "org.apache.harmony.xnet.provider.jsse"; + } else { + packageName = "com.android.org.conscrypt"; + } + final File cacheDirectory = K9.app.getDir("sslcache", Context.MODE_PRIVATE); + try { + Class fileClientSessionCacheClass = Class.forName(packageName + + ".FileClientSessionCache"); + Method usingDirectoryMethod = fileClientSessionCacheClass + .getMethod("usingDirectory", File.class); + sSessionCache = usingDirectoryMethod.invoke(null, cacheDirectory); + + Class sslClientSessionCacheClass = Class.forName(packageName + + ".SSLClientSessionCache"); + Class clientSessionContextClass = Class.forName(packageName + + ".ClientSessionContext"); + sSetPersistentCacheMethod = clientSessionContextClass.getMethod( + "setPersistentCache", sslClientSessionCacheClass); + } catch (Exception e) { + // Something went wrong. Proceed without a session cache. + Log.e(K9.LOG_TAG, "Failed to initialize SslSessionCacheHelper: " + e); + sIsDisabled = true; + } + } + + /** + * Associate an {@code SSLContext} with a persistent file-based cache of SSL + * sessions which can be used when re-establishing a connection to the same + * server. + *

+ * This is beneficial because it can eliminate redundant cryptographic + * computations and network traffic, thus saving time and conserving power. + */ + public static void setPersistentCache(SSLContext sslContext) { + if (sIsDisabled) { + return; + } + try { + SSLSessionContext sessionContext = sslContext.getClientSessionContext(); + sSetPersistentCacheMethod.invoke(sessionContext, sSessionCache); + } catch (Exception e) { + // Something went wrong. Proceed without a session cache. + Log.e(K9.LOG_TAG, "Failed to initialize persistent SSL cache: " + e); + sIsDisabled = true; + } + } +} diff --git a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java index 6b7bad9a0..7d2438cda 100644 --- a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java +++ b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java @@ -138,6 +138,7 @@ public class TrustedSocketFactory { SSLContext context = SSLContext.getInstance("TLS"); context.init(keyManagers, trustManagers, null); + SslSessionCacheHelper.setPersistentCache(context); SSLSocketFactory socketFactory = context.getSocketFactory(); Socket trustedSocket; if (socket == null) { From 9e203b75ccdd0de87fbd3279966c0e694e9ded41 Mon Sep 17 00:00:00 2001 From: cketti Date: Sun, 7 Sep 2014 23:08:40 +0200 Subject: [PATCH 04/16] Remove gallery bug work-around This bug was present in the Gallery app shipped with Android 2.0. The time has come to say good-bye. We will never forget you! But only because you're part of our Git history. --- res/menu/message_compose_option.xml | 12 ------ res/values-ca/strings.xml | 8 ---- res/values-cs/strings.xml | 8 ---- res/values-da/strings.xml | 8 ---- res/values-de/strings.xml | 8 ---- res/values-el/strings.xml | 8 ---- res/values-es/strings.xml | 8 ---- res/values-eu/strings.xml | 8 ---- res/values-fi/strings.xml | 8 ---- res/values-fr/strings.xml | 8 ---- res/values-gl/strings.xml | 8 ---- res/values-hu/strings.xml | 8 ---- res/values-it/strings.xml | 8 ---- res/values-iw/strings.xml | 8 ---- res/values-ja/strings.xml | 8 ---- res/values-ko/strings.xml | 8 ---- res/values-lt/strings.xml | 8 ---- res/values-nl/strings.xml | 8 ---- res/values-pl/strings.xml | 8 ---- res/values-pt-rBR/strings.xml | 8 ---- res/values-ru/strings.xml | 8 ---- res/values-sk/strings.xml | 8 ---- res/values-sv/strings.xml | 8 ---- res/values-tr/strings.xml | 8 ---- res/values-uk/strings.xml | 8 ---- res/values-zh-rCN/strings.xml | 8 ---- res/values-zh-rTW/strings.xml | 8 ---- res/values/strings.xml | 10 ----- res/xml/global_preferences.xml | 6 --- src/com/fsck/k9/K9.java | 39 ------------------- src/com/fsck/k9/activity/MessageCompose.java | 25 ------------ src/com/fsck/k9/activity/setup/Prefs.java | 6 --- .../fsck/k9/preferences/GlobalSettings.java | 24 ------------ src/com/fsck/k9/preferences/Settings.java | 2 +- 34 files changed, 1 insertion(+), 331 deletions(-) diff --git a/res/menu/message_compose_option.xml b/res/menu/message_compose_option.xml index 06cf7ac68..4d3d4e37a 100644 --- a/res/menu/message_compose_option.xml +++ b/res/menu/message_compose_option.xml @@ -39,16 +39,4 @@ android:title="@string/read_receipt" android:icon="?attr/iconActionRequestReadReceipt" /> - - diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index d6f7f24ac..ce6912d8c 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -137,8 +137,6 @@ Si us plau, envia\'ns els errors, contribueix a millorar-lo a Es farà una petició per la confirmació de lectura No es faran més peticions per les confirmacions de lectura Afegeix adjunt - Afegeix adjunt (Imatge) - Afegeix adjunt (Vídeo) Buida paperera Elimina Neteja missatges locals @@ -715,13 +713,7 @@ Si us plau, envia\'ns els errors, contribueix a millorar-lo a Mitjà Gran Més gran - - Comprova \"Configuració\" -> \"Utilitza la galeria la Galeria d\'errors\" per poder adjuntar imatges o vídeos utilitzant la Galeria 3D. - - Utilitza \"Afegeix adjunt (Imatge)\" or \"Afegeix adjunt (Vídeo)\" per afegir imatges o vídeos amb la Galeria 3D. Miscel·lània - Utilitza la Galeria d\'errors - Mostra els botons per afegir adjunts d\'imatge/vídeo (per treballar amb els errors de la Galeria 3D) No s\'ha trobat cap aplicació idònia per a aquesta acció. Versió APG instal·lada no suportada. diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 57a482a7e..b5b18459a 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -137,8 +137,6 @@ Posílejte prosím chybová hlášení, přispívejte novými funkcemi a ptejte Potvrzení o přečtení bude vyžadováno Potvrzení o přečtení nebude vyžadováno Přidat přílohu - Přidat přílohu (obrázek) - Přidat přílohu (video) Vysypat koš Vymazat Vyčistit místní zprávy @@ -715,13 +713,7 @@ Posílejte prosím chybová hlášení, přispívejte novými funkcemi a ptejte Střední Velký Největší - - Zaškrtněte \"Možnosti\" -> \"Obejít chybu Galerie\", abyste byli schopni připojit obrázky nebo video pomocí Galerie 3D. - - Použijte \"Přidat přílohu (obrázek)\" nebo \"Přidat přílohu (video)\" k připojení obrázků a videa pomocí Galerie 3D. Různé - Obejít chybu Galerie - Zobrazit tlačítka k připojení obrázku/videa jako přílohy (kvůli chybě v Galerie 3D) Pro tuto akci nebyla nalezena žádná vhodná aplikace. Nainstalovaná verze APG není podporována. diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index 0f786d008..382ca2925 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -134,8 +134,6 @@ Vær venlig at sende fejlrapporter, anmodning om nye funktioner, og spørgsmål Der vil blive anmodet om kvittering for modtagelse Der vil ikke blive anmodet om kvittering for modtagelse Vedhæft fil - Vedhæft (billede) - Vedhæft (Video) Tøm papirkurv Ryd helt Fjern lokalt lagrede mails @@ -709,13 +707,7 @@ Vær venlig at sende fejlrapporter, anmodning om nye funktioner, og spørgsmål Stor Større Størst - - Kontroller \"Indstillinger\" -> \"Benyt Gallery bug work-around\" for at kunne vedhæfte billeder og videoer med Gallery 3D. - - Benyt \"Tilføj vedhæft (billede)\" eller \"Tilføj vedhæftning (video)\" for at kunne vedhæfte billeder eller videoer med Gallery 3D. Diverse - Benyt Gallery bug work-around - Vis knapper til vedhæftning af billede/video (måde at omgå fejl i Gallery 3D) Kunne ikke finde noget program som kan udføre denne handling. Den installerede version af APG understørttes ikke. diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index be1d0b14a..16da07efd 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -136,8 +136,6 @@ Um Fehler zu melden, neue Funktionen vorzuschlagen oder Fragen zu stellen, besuc Eine Empfangsbestätigung wird angefordert Es wird keine Empfangsbestätigung angefordert Anhang hinzufügen - Anhang hinzufügen (Bild) - Anhang hinzufügen (Video) Papierkorb leeren Bereinigen (Expunge) Lokale Nachrichten löschen @@ -724,13 +722,7 @@ Um Fehler zu melden, neue Funktionen vorzuschlagen oder Fragen zu stellen, besuc Mittel Groß Größer - - Wählen Sie \'Einstellungen\' -> \'Galerie-Workaround aktivieren\', um Bilder oder Videos mit Hilfe der 3D-Galerie hinzufügen zu können. - - Verwenden Sie \'Anhang hinzufügen (Bild)\' oder \'Anhang hinzufügen (Video)\', um Bilder oder Videos mit der 3D-Galerie hinzuzufügen. Verschiedenes - Galerie-Workaround - Schaltflächen zum Hinzufügen von Bild- und Video-Anhängen anzeigen (um Fehler in 3D-Galerie zu umgehen) Keine geeignete Anwendung für diese Aktion gefunden. Die installierte APG-Version wird nicht unterstützt. diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index ee2792485..c64d631ce 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -136,8 +136,6 @@ Θα ζητηθεί απόδειξη ανάγνωσης Δεν θα ζητηθεί απόδειξη ανάγνωσης Προσθήκη συνημμένου - Προσθήκη συνημμένης εικόνας - Προσθήκη συνημμένου βίντεο Άδειασμα σκουπιδιών Εξάλειψη Καθαρισμός τοπικών μηνυμάτων @@ -714,13 +712,7 @@ Μεσαίο Μεγάλο Μεγαλύτερο - - Ελέγξτε \'Ρυθμίσεις\' -> \'Παράκαμψη σφάλματος πινακοθήκης\' για να μπορείτε να συνάψετε εικόνες ή βίντεο με το Gallery 3D. - - Χρήση \'Προσθήκη συνημμένου (Εικόνα)\' ή \'Προσθήκη συνημμένου (Βίντεο)\' για να συνάψετε εικόνες ή βίντεο με το Gallery 3D. Διάφορα - Παράκαμψη σφάλματος πινακοθήκης - Προβολή πλήκτρων για προσθήκη συνημμένων εικόνας/βίντεο (παράκαμψη του σφάλματος Gallery 3D) Δεν βρέθηκε κατάλληλη εφαρμογή για αυτή την ενέργεια. Η εγκατεστημένη έκδοση APG δεν υποστηρίζεται. diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 2a7ee8e57..2ebfa623c 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -137,8 +137,6 @@ Por favor, envía los errores detectados, contribuye con nuevas funcionalidades Se solicitará confirmación de lectura No se solicitará confirmación de lectura Añadir adjunto - Añadir adjunto (imagen) - Añadir adjunto (vídeo) Vaciar Papelera Purgar Borrar mensajes locales @@ -726,13 +724,7 @@ Por favor, envía los errores detectados, contribuye con nuevas funcionalidades Mediana Grande Muy Grande - - Comprobar \"Configuración\" -> \"Usar Galería\" para poder adjuntar imágenes y vídeos utilizando la Galería 3D. - - Usar \"Añadir adjunto (Imagen)\" o \"Añadir adjunto (Vídeo)\" para Añadir imágenes o Vídeos con Galería 3D Varios - Usar galería - Mostrar botones para Añadir adjuntos de imagen/vídeo No existe aplicación para realizar esta acción. No se admite esta versión de APG. diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index dd0a4dd23..c6da6da19 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -137,8 +137,6 @@ Arazoen berri emateko, ezaugarri berriak gehitzeko eta galderak egiteko Irakurragiria eskatuko da Ez da irakurragiria eskatuko Eranskina gehitu - Eranskina gehitu (Irudia) - Eranskina gehitu (Bideoa) Zakarrontzia hustu Suntsitu Mezu lokalak garbitu @@ -715,13 +713,7 @@ Arazoen berri emateko, ezaugarri berriak gehitzeko eta galderak egiteko Ertaina Handia Handiagoa - - \"Ezarpenak\" -> \"Galeriako arazoa sahiestu\" gaitu 3D galeriako irudi edo bideoak erantsi ahal izateko. - - \"Eranskina gehitu (Irudia)\" edo \"Eranskina gehitu (Video)\" erabili 3D galeriatik irudi edo bideoak eransteko. Bestelakoak - Galeriako arazoa sahiestu - Irudi/bideoak eransteko botoiak ikusi (3D galeriako arazoa sahiesteko) Ez da honetarako aplikaziorik topatu. Instalatutako APG bertsioa ezin da erabili. diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 29e87bccc..03748912c 100755 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -138,8 +138,6 @@ Virheraportit, osallistuminen projektiin ja kysymykset: Mene osoitteeseen Vastaanottokuittaus pyydetään Ei pyydä lukukuittausta Lisää liite - Lisää liite (Kuva) - Video Tyhjennä roskakori Poista Poista paikalliset viestit @@ -726,13 +724,7 @@ Virheraportit, osallistuminen projektiin ja kysymykset: Mene osoitteeseen Keskikoko Suuri Suurin - - Tarkista Asetukset -> Ota käyttöön Gallery-ohjelmavirheen kierto mahdollistaaksesi kuvien tai videoiden liittämisen Gallery 3D -ohjelmalla. - - Käytä Lisää liite (kuva)- tai Lisää liite (video) -toimintoa Gallery 3D:n kuvan tai videon liittämiseksi. Muut - Ota käyttöön Gallery -ohjelmavirheen kierto - Näytä painikkeet liitteen (video/kuva) lisäämiseksi (Gallery 3D -ohjelmavirheen kiertäminen) Toiminnolle ei löytynyt sopivaa ohjelmaa. Asennettua APG-versiota ei tueta. diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 60f90e61c..ba9390549 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -135,8 +135,6 @@ Veuillez envoyer les rapports de bogues, suggérer de nouvelles fonctions et pos Un accusé de lecture sera demandé Un accusé de lecture ne sera pas demandé Ajouter une pièce jointe - Joindre une image - Joindre une vidéo Vider la corbeille Supprimer Effacer les messages locaux @@ -725,13 +723,7 @@ jusqu\'à %d de plus Moyen Grand Plus grand - - Cochez «\u00A0Paramètres\u00A0» > «\u00A0Utiliser le contournement du bogue de la Galerie\u00A0» pour être capable d\'attacher des images ou des vidéos en utilisant Galerie 3D. - - Utiliser «\u00A0Joindre une image\u00A0» ou «\u00A0Joindre une vidéo\u00A0» pour joindre des images ou vidéos avec Galerie 3D Divers - Utiliser le contournement du bogue de la Galerie - Afficher les boutons pour joindre des images ou des vidéos (pour contourner le bogue de la Galerie 3D) Aucune application adéquate n\'a été trouvée pour cette action. La version installée d\'APG n\'est pas prise en charge. diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml index 7400b8f13..5c80f42a9 100644 --- a/res/values-gl/strings.xml +++ b/res/values-gl/strings.xml @@ -117,8 +117,6 @@ Por favor, envía os erros detectados, contribúe con novas funcionalidas e preg Marcar Non Lido Engadir Cc/Bcc Engadir adxunto - Engadir adxunto (Imaxe) - Engadir adxunto (Vídeo) Valeirar Papelera Erradicar Borrar mensaxes locais @@ -643,13 +641,7 @@ Por favor, envía os erros detectados, contribúe con novas funcionalidas e preg Mediana Grande Moi Grande - - Comprobar \"Configuración\" -> \"Usar Galería\" para poder adxuntar imaxes e videos usando a Galería 3D. - - Usar \"Engadir adxunto (Imaxe)\" oo \"Engadir adxunto (Vídeo)\" para Engadir imaxes ou Vídeos con Galería 3D Varios - Usar galería - Amosar botóns para Engadir adxuntos de imaxe/vídeo Non existe aplicación para executar esta acción Non se soporta esta versión de APG diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index b916dca44..7257120e9 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -136,8 +136,6 @@ Hibajelentéseivel hozzájárul az újabb verziók tökéletesítéséhez, kérd Olvasási jelentés lesz kérve Nem lesz Olvasási jelentés lesz kérve Melléklet - Kép-melléklet csatolása - Videó-melléklet csatolása Lomtár ürítése Biztonságos törlés Helyi üzenetek törlése @@ -703,13 +701,7 @@ Hibajelentéseivel hozzájárul az újabb verziók tökéletesítéséhez, kérd Közepes Nagy Nagyobb - - Kapcsolja be a \"Beállítások\" -> \"Galéria hiba\" ha 3D galériából akar képet mellékelni. - - Használja a \"Kép csatolása\" vagy \"Videó csatolása\" opciót ha 3D galériából szeretne választani. Egyéb - Galéria hiba kikerülése - Gombok megjelenítése a kép/videó csatoláshoz (a 3D Galéria hiba kikerülése érdekében) Nincs megfelelő alkalmazás ehhez a művelethez. A telepített APG verzió nem támogatott. diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 5356720f3..adc3c5a0d 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -137,8 +137,6 @@ Invia le tue segnalazioni, suggerisci nuove funzionalità e chiedi informazioni Notifica di lettura attiva Non richiederà la notifica di lettura Aggiungi allegato - Aggiungi allegato (Immagine) - Aggiungi allegato (Video) Svuota cestino Rimuovi messaggi eliminati Cancella messaggi locali @@ -726,13 +724,7 @@ Invia le tue segnalazioni, suggerisci nuove funzionalità e chiedi informazioni Medio Grande Più grande - - Controlla \"Impostazioni\" -> \"Aggira bug Galleria immagini\" per allegare immagini o video usando Galleria 3D. - - Utilizza \"Aggiungi allegato (Immagini)\" o \"Aggiungi allegato (Video)\" per allegare immagini o video con Galleria 3D. Varie - Aggira bug Galleria immagini - Visualizza i pulsanti per allegare immagini/video (evita bug della Galleria 3D) Nessuna applicazione trovata per questa azione. La versione di APG installata non è supportata. diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 5089bcf0a..ca2f05ccc 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -114,8 +114,6 @@ נדרש אישור לקריאה לא נדרש אישור קריאה צרף קובץ - הוסף קובץ (תמונה) - הוסף קובת (וידאו) רוקן אשפה רוקן נקה הודעות מקומיות @@ -610,13 +608,7 @@ בינוני גדול ענק - - סמן \"הגדרות\" -> \"השתמש בעקיפת באג הגלריה\" כדי שתוכל לצרף תמונות או קטעי וידאו לגלריית 3D. - - השתמש ב \ "הוסף קובץ מצורף (תמונה) \" או \ "הוסף קובץ מצורף (וידאו) \" כדי לצרף תמונות או קטעי וידאו באמצעות גלריית 3D. שונות - השתמש בעקיפת באג הגלריה - הצג כפתורים כדי להוסיף קבצי תמונה / וידאו (כדי לעקוף את באג גלריית 3D) לא נמצא ישום שיכול לבצע פעולה זו. גרסת APG המותקנת אינה נתמכת. diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 81f185a1d..d62d12bf2 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -137,8 +137,6 @@ K-9 は大多数のメールクライアントと同様に、ほとんどのフ 開封確認を要求 開封確認を要求しない 添付追加 - 添付ファイル追加 (画像) - 添付ファイル追加 (動画) ゴミ箱を空に 完全削除(Expunge) ローカルのメッセージをクリア @@ -726,13 +724,7 @@ K-9 は大多数のメールクライアントと同様に、ほとんどのフ 極大 - - ギャラリ3Dを使って画像/動画を添付するには\"設定\" -> \"ギャラリのバグ回避\"をチェックしてください - - ギャラリ3Dで画像/動画を添付するには\"添付ファイル追加 (画像)\"や\"添付ファイル追加 (動画)\" を使ってください その他 - ギャラリのバグ回避 - 添付ファイルに画像/動画を追加するボタンを表示する(ギャラリ3Dバグを回避するため) この操作のためのアプリケーションが見つかりません インストールされているAPGは、サポートされていないバージョンです diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index dcf66cdac..f37869ae0 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -136,8 +136,6 @@ K-9 메일은 대부분의 무료 hotmail 계정을 지원하지 않으며, 다 읽음 확인을 요청함 읽음 확인을 요청하지 않음 첨부 추가 - 첨부 추가 (이미지) - 첨부 추가 (비디오) 휴지통 비우기 폐기 로컬 메시지 삭제 @@ -713,13 +711,7 @@ K-9 메일은 대부분의 무료 hotmail 계정을 지원하지 않으며, 다 중간 크게 더 크게 - - 갤러리 3D에서 이미지나 비디오를 첨부하려면 \"설정\" -> \"갤러리 버그 회피\"를 확인하십시오. - - 갤러리 3D에서 \"첨부 추가 (이미지)\" 혹은 \"첨부 추가 (비디오)\"를 통해 이미지나 비디오를 첨부할 수 있습니다. 기타 설정 - 갤러리 버그 회피 - 이미지/비디오 첨부 파일을 추가하는 버튼을 보여 줍니다 (갤러리 3D 버그를 회피할 수 있음) 이 작동에 대해 적절한 애플리케이션을 찾을 수 없습니다. 설치된 APG 버전을 지원하지 않습니다. diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index 78f406586..77df9c458 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -137,8 +137,6 @@ Praneškite apie klaidas, pridėkite naujų galimybių ir užduokite klausimus m Prašys perskaitymo patvirtinimo Neprašys perskaitymo patvirtinimo Priedo priedą - Pridėti priedą (paveikslėlis) - Pridėti priedą (Video) Išvalyti šiukšliadėžę Išvalyti Išvalyti vietinius laiškus @@ -716,13 +714,7 @@ Praneškite apie klaidas, pridėkite naujų galimybių ir užduokite klausimus m Vidutinis Didelis Didesnis - - Norėdami pridėti paveikslėlius ir video naudojant Gallery 3D, pažymėkite „Nustatymai“ -> „Naudoti galerijos klaidos apėjimą“ - - Norėdami pridėti paveikslėlius ir video naudojant Gallery 3D naudokite „Pridėti priedą (paveikslėlis)“ ar „Pridėti priedą (Video)“. Kita - Naudoti galerijos klaidos apėjimą - Rodyti mygtukus kurie prideda vaizdo/video priedus (Gallery 3D klaidos apėjimas) Šiai programai nerasta tinkamo veiksmo. Įdiegta APG versija nepalaikoma. diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 6921411ca..c01d3b494 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -137,8 +137,6 @@ Graag foutrapporten, bijdrage nieuwe functies en vragen stellen op Lees rapport vragen Geen lees rapport vragen Voeg bijlage toe - Voeg bijlage toe (Afbeelding) - Voeg bijlage toe (Video) Prullenbak legen Wissen Lokale berichten wissen @@ -714,13 +712,7 @@ Graag foutrapporten, bijdrage nieuwe functies en vragen stellen op Gemiddeld Groot Groter - - Controleer \"Instellingen\" -> \"Use Gallery bug work-around\" to be able to attach images or videos using Gallery 3D. - - Gebruik \"Bijlage toevoegen (Afbeelding)\" of \"Bijlage toevoegen (Video)\" to attach images or videos with Gallery 3D. Diversen - Gebruik Gallery bug work-around - Laat knoppen zien om afbeelding/video bijlage toe te voegen (to work around a Gallery 3D bug) Geen geschikte applicatie gevonden voor deze aktie. De geïnstalleerde APG versie wordt niet ondersteund. diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 205ead7f1..152843898 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -137,8 +137,6 @@ Wszelkie zgłoszenia usterek, zapytania oraz nowe pomysły prosimy przesyłać z Żadaj powiadomienia o przeczytaniu Nie wymagaj powiadomienia o przeczytaniu Dodaj załącznik - Dodaj załącznik (Zdjęcie) - Dodaj załącznik (Film) Opróżnij kosz Wyczyść Wyczyść wiadomości lokalne @@ -714,13 +712,7 @@ Wszelkie zgłoszenia usterek, zapytania oraz nowe pomysły prosimy przesyłać z Średnia Duża Wielka - - Włącz \"Obejdź błędy w Galerii\" aby móc załączać zdjęcia oraz filmy używając Galerii 3D. - - Użyj \"Dodaj załącznik (Zdjęcie)\" lub \"Dodaj załącznik (Film)\" aby je dodać używając Galerii 3D. Różne - Obejdź błędy w Galerii - Wyświetla przyciski dodawania zdjęć oraz filmów jako załączników Nie znaleiono odpowiedniej aplikacji. Zainstalowana wersja APG nie jest wspierana. diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 248f17c24..d288520eb 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -136,8 +136,6 @@ Por favor, nos envie relatórios de bugs, contribua para novas melhorias e faça Confirmação de leitura será requisitada Confirmação de leitura não será requisitada Incluir anexo - Incluir anexo (Imagem) - Incluir anexo (Video) Esvaziar Lixeira Expurgar Limpar mensagens locais @@ -710,13 +708,7 @@ Por favor, nos envie relatórios de bugs, contribua para novas melhorias e faça Médio Maior Grande - - Ativar em \"Configurações\" a opção \"Solução do bug da Galeria\" para poder anexar imagens ou vídeos utilizando a Galeria 3D. - - Usar \"Incluir anexo (Imagem)\" ou \"Incluir anexo (Video)\" para anexar imagens ou videos da Galeria 3D. Diversos - Solução do bug da Galeria - Mostrar botões para incluir anexos de imagem/video (para contornar problemas utilizando Gallery 3D) Nenhum aplicativo adequado para esta ação foi encontrado. A versão da APG instalada não é suportada. diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 76e36030d..f7201c360 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -137,8 +137,6 @@ K-9 Mail — почтовый клиент для Android. Запросить уведомление о прочтении Без уведомления о прочтении Вложение - Изображение - Видео Очистить корзину Стереть Стереть локальные @@ -725,13 +723,7 @@ K-9 Mail — почтовый клиент для Android. Большой Огромный Гигантский - - Включите в настройках \"Обход ошибки Галереи 3D\" для её использования - - Используйте дествия \"Изображение\" или \"Видео\" для вложения с помощью Галереи 3D Разное - Обход ошибки Галереи 3D - Показать действия вложения изображений и видео Подходящее приложение не найдено Установленная версия APG не поддерживается diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index c3373dce9..3d286cb1b 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -137,8 +137,6 @@ Prosím, nahlasujte prípadné chyby, prispievajte novými funkciami a pýtajte Potvrdenie o prečítaní bude vyžadované Potvrdenie o prečítaní nebude vyžadované Pridať prílohu - Pridať prílohu (obrázok) - Pridať prílohu (video) Vyprázdniť kôš Vymazať Vymazať správy @@ -725,13 +723,7 @@ Prosím, nahlasujte prípadné chyby, prispievajte novými funkciami a pýtajte Stredné Veľké Väčšie - - Skontrolujte \"Nastavenia\" -> \"Používať riešenie chyby pre Galériu\", aby ste boli schopný pripojiť obrázky alebo videá pomocou Galérie 3D. - - Použite \"Pridať prílohu (obrázok)\" alebo \"Pridať prílohu (video)\" pre pridanie obrázkov a videí pomocou Galérie 3D. Rôzne - Používať riešenie chyby pre Galériu - Zobraziť tlačidlá pre pridanie príloh (obrázky, videá) pre riešenie chyby Galérie 3D Nebola nájdená žiadna vhodná aplikácia pre túto akciu. Nainštalovaná verzia APG nie je podporovaná. diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 68e41c360..1872f7d3a 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -137,8 +137,6 @@ Vänligen skicka felrapporter, hjälp till med nya funktioner och ställ frågor Kommer att begära läskvitto Kommer inte att begära läskvitto Lägg till bilaga - Lägg till bilaga (Bild) - Lägg till bilaga (Video) Töm papperskorg Utplåna Rensa lokalt lagrade meddelanden @@ -715,13 +713,7 @@ Vänligen skicka felrapporter, hjälp till med nya funktioner och ställ frågor Stor Större Störst - - Kontrollera \"Inställningar\" -> \"Använd work-adound för bug i Gallery\" för att kunna bifoga bilder och filmer med Gallery 3D. - - Använd \"Lägg till bilaga (Bild)\" eller \"Lägg till bilaga (Video)\" för att bifoga bilder eller video med Gallery 3D. Diverse - Använd workadound för bug i Gallery - Visa knappar för att bifoga image/video (to work around a Gallery 3D bug) Ingen passande applikation för denna åtgärd funnen. Den installerade versionen av APG stöds inte. diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index b67e088c5..837387f8d 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -125,8 +125,6 @@ Lütfen hata raporlarınızı, istediğiniz yeni özellikleri ve sorularınızı Okundu raporu istenecek Okundu raporu istenmeyecek Ekle - Ekle (Resim) - Ekle (Video) Çöpü Boşalt Silmek Yerel mesajları temizle @@ -664,13 +662,7 @@ Lütfen hata raporlarınızı, istediğiniz yeni özellikleri ve sorularınızı Orta Büyük Daha büyük - - \"Ayarlar\" -> \"Galeri hata çalışması kullan\" işaretleyerek 3D Galeri kullanarak resimler veya videoları ekleyin. - - \"Ek Ekle (Resim)\" veya \"Ek Ekle (Video)\" kullanarak 3D Galeri ile resimleri ve videoları ekleyin. Çeşitli - Geçici çözüm galeri hatasını kullan - Resim/Video ekleri ekleme butonlarını göster (Bir galeri 3D hatası geçici çözümüne) Bu eylem için uygun program bulunamadı. Kurulu APG versiyon desteklenmiyor. diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 6ed5c3a56..90dc13d10 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -136,8 +136,6 @@ K-9 Mail це поштовий клієнт з відкритим вихідни Включити запит повідомлень про прочитання Вимкнути запит повідомлень про прочитання Додати вкладення - Додати вкладення (зображення) - Додати вкладення (Відео) Очистити Кошик Витерти Видалити локальні повідомлення @@ -712,13 +710,7 @@ K-9 Mail це поштовий клієнт з відкритим вихідни Середній Великий Найбільший - - Виберіть \"Налаштування\" -> \"Використовувати обхід помилок Галереї\" для вкладень зображень та відео з допомогою Gallery 3D. - - Виберіть \"Додати вкладення (зображення)\" або \"Додати вкладення (відео)\" для вкладень зображень та відео з допомогою Gallery 3D. Різне - Використовувати обхід помилок Галереї - Показувати кнопки для додавання зображень та відео вкладень (щоб обійти проблему з Gallery 3D) Відсутня програма для цієї дії. Встановлена версія APG не підтримується. diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index da8abb05d..f55ae272c 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -136,8 +136,6 @@ K-9改进的功能包括: 要求已读回执 不要求已读回执 添加附件 - 添加图片附件 - 添加视频附件 清空垃圾箱 删除 清空本地邮件 @@ -713,13 +711,7 @@ K-9改进的功能包括: 中等 更大 - - 选择“设置”->“避免画册发生错误”来启用使用3D画册模式添加附件或视频。 - - 利用“添加附件(图片)”或“添加附件(视频)”来使用3D画册添加图片或视频。 杂项 - 避免画册发生错误 - 显示按钮来添加图片/视频附件(以避免3D画册发生错误) 没有找到可以用于这一操作的程序。 不支持所安装版本的APG。 diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 8fe6f6fc8..f46efd9a5 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -108,8 +108,6 @@ 要求讀取回條 取消讀取回條 新增附件 - 新增圖片附件 - 新增影片附件 清空垃圾桶 刪除 清除本地郵件 @@ -685,13 +683,7 @@ 中等 最大 - - 選擇「設定」->「避免相簿發生錯誤」來啟用3D相簿模式新增附件或影片。 - - 利用「新增附件(圖片)」或「新增附件(影片)」來使用3D相簿新增圖片或影片。 偏好設定 - 避免相簿發生錯誤 - 顯示按鈕來新增圖片/影片為附件(以避免3D相簿發生錯誤) 沒有找到可以用於此操作的程式。 尚未支援所安裝的APG版本。 diff --git a/res/values/strings.xml b/res/values/strings.xml index afa6335ce..32c764a1f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -170,8 +170,6 @@ Please submit bug reports, contribute new features and ask questions at Will request read receipt Will not request read receipt Add attachment - Add attachment (Image) - Add attachment (Video) Empty Trash Expunge Clear local messages @@ -908,15 +906,7 @@ Please submit bug reports, contribute new features and ask questions at Large Larger - - Check \"Settings\" -> \"Use Gallery bug work-around\" to be able to attach images or videos using Gallery 3D. - - - Use \"Add attachment (Image)\" or \"Add attachment (Video)\" to attach images or videos with Gallery 3D. - Miscellaneous - Use Gallery bug work-around - Show buttons to add image/video attachments (to work around a Gallery 3D bug) No suitable application for this action found. diff --git a/res/xml/global_preferences.xml b/res/xml/global_preferences.xml index 5ceed2db6..f06afa116 100644 --- a/res/xml/global_preferences.xml +++ b/res/xml/global_preferences.xml @@ -348,12 +348,6 @@ android:title="@string/miscellaneous_preferences" android:key="misc_preferences"> - - mSortAscending = new HashMap(); @@ -543,7 +540,6 @@ public class K9 extends Application { editor.putInt("messageViewTheme", messageViewTheme.ordinal()); editor.putInt("messageComposeTheme", composerTheme.ordinal()); editor.putBoolean("fixedMessageViewTheme", useFixedMessageTheme); - editor.putBoolean("useGalleryBugWorkaround", useGalleryBugWorkaround); editor.putBoolean("confirmDelete", mConfirmDelete); editor.putBoolean("confirmDeleteStarred", mConfirmDeleteStarred); @@ -582,8 +578,6 @@ public class K9 extends Application { super.onCreate(); app = this; - galleryBuggy = checkForBuggyGallery(); - sIsDebuggable = ((getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); checkCachedDatabaseVersion(); @@ -749,8 +743,6 @@ public class K9 extends Application { mHideUserAgent = sprefs.getBoolean("hideUserAgent", false); mHideTimeZone = sprefs.getBoolean("hideTimeZone", false); - useGalleryBugWorkaround = sprefs.getBoolean("useGalleryBugWorkaround", K9.isGalleryBuggy()); - mConfirmDelete = sprefs.getBoolean("confirmDelete", false); mConfirmDeleteStarred = sprefs.getBoolean("confirmDeleteStarred", false); mConfirmSpam = sprefs.getBoolean("confirmSpam", false); @@ -1185,18 +1177,6 @@ public class K9 extends Application { mHideSpecialAccounts = hideSpecialAccounts; } - public static boolean useGalleryBugWorkaround() { - return useGalleryBugWorkaround; - } - - public static void setUseGalleryBugWorkaround(boolean useGalleryBugWorkaround) { - K9.useGalleryBugWorkaround = useGalleryBugWorkaround; - } - - public static boolean isGalleryBuggy() { - return galleryBuggy; - } - public static boolean confirmDelete() { return mConfirmDelete; } @@ -1245,25 +1225,6 @@ public class K9 extends Application { sNotificationQuickDelete = mode; } - /** - * Check if this system contains a buggy Gallery 3D package. - * - * We have to work around the fact that those Gallery versions won't show - * any images or videos when the pick intent is used with a MIME type other - * than image/* or video/*. See issue 1186. - * - * @return true, if a buggy Gallery 3D package was found. False, otherwise. - */ - private boolean checkForBuggyGallery() { - try { - PackageInfo pi = getPackageManager().getPackageInfo("com.cooliris.media", 0); - - return (pi.versionCode == 30682); - } catch (NameNotFoundException e) { - return false; - } - } - public static boolean wrapFolderNames() { return mWrapFolderNames; } diff --git a/src/com/fsck/k9/activity/MessageCompose.java b/src/com/fsck/k9/activity/MessageCompose.java index f27e334fc..9c473629a 100644 --- a/src/com/fsck/k9/activity/MessageCompose.java +++ b/src/com/fsck/k9/activity/MessageCompose.java @@ -2042,18 +2042,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, * Kick off a picker for whatever kind of MIME types we'll accept and let Android take over. */ private void onAddAttachment() { - if (K9.isGalleryBuggy()) { - if (K9.useGalleryBugWorkaround()) { - Toast.makeText(MessageCompose.this, - getString(R.string.message_compose_use_workaround), - Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(MessageCompose.this, - getString(R.string.message_compose_buggy_gallery), - Toast.LENGTH_LONG).show(); - } - } - onAddAttachment2("*/*"); } @@ -2549,12 +2537,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, case R.id.add_attachment: onAddAttachment(); break; - case R.id.add_attachment_image: - onAddAttachment2("image/*"); - break; - case R.id.add_attachment_video: - onAddAttachment2("video/*"); - break; case R.id.read_receipt: onReadReceipt(); default: @@ -2575,13 +2557,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, menu.findItem(R.id.save).setEnabled(false); } - /* - * Show the menu items "Add attachment (Image)" and "Add attachment (Video)" - * if the work-around for the Gallery bug is enabled (see Issue 1186). - */ - menu.findItem(R.id.add_attachment_image).setVisible(K9.useGalleryBugWorkaround()); - menu.findItem(R.id.add_attachment_video).setVisible(K9.useGalleryBugWorkaround()); - return true; } diff --git a/src/com/fsck/k9/activity/setup/Prefs.java b/src/com/fsck/k9/activity/setup/Prefs.java index b3e0d0416..f2d574557 100644 --- a/src/com/fsck/k9/activity/setup/Prefs.java +++ b/src/com/fsck/k9/activity/setup/Prefs.java @@ -87,7 +87,6 @@ public class Prefs extends K9PreferenceActivity { private static final String PREFERENCE_AUTOFIT_WIDTH = "messageview_autofit_width"; private static final String PREFERENCE_BACKGROUND_OPS = "background_ops"; - private static final String PREFERENCE_GALLERY_BUG_WORKAROUND = "use_gallery_bug_workaround"; private static final String PREFERENCE_DEBUG_LOGGING = "debug_logging"; private static final String PREFERENCE_SENSITIVE_LOGGING = "sensitive_logging"; @@ -134,7 +133,6 @@ public class Prefs extends K9PreferenceActivity { private CheckBoxPreference mShowNext; private CheckBoxPreference mAutofitWidth; private ListPreference mBackgroundOps; - private CheckBoxPreference mUseGalleryBugWorkaround; private CheckBoxPreference mDebugLogging; private CheckBoxPreference mSensitiveLogging; private CheckBoxPreference mHideUserAgent; @@ -341,9 +339,6 @@ public class Prefs extends K9PreferenceActivity { mBackgroundOps = setupListPreference(PREFERENCE_BACKGROUND_OPS, K9.getBackgroundOps().name()); - mUseGalleryBugWorkaround = (CheckBoxPreference)findPreference(PREFERENCE_GALLERY_BUG_WORKAROUND); - mUseGalleryBugWorkaround.setChecked(K9.useGalleryBugWorkaround()); - mDebugLogging = (CheckBoxPreference)findPreference(PREFERENCE_DEBUG_LOGGING); mSensitiveLogging = (CheckBoxPreference)findPreference(PREFERENCE_SENSITIVE_LOGGING); mHideUserAgent = (CheckBoxPreference)findPreference(PREFERENCE_HIDE_USERAGENT); @@ -492,7 +487,6 @@ public class Prefs extends K9PreferenceActivity { K9.setSplitViewMode(SplitViewMode.valueOf(mSplitViewMode.getValue())); K9.setAttachmentDefaultPath(mAttachmentPathPreference.getSummary().toString()); boolean needsRefresh = K9.setBackgroundOps(mBackgroundOps.getValue()); - K9.setUseGalleryBugWorkaround(mUseGalleryBugWorkaround.isChecked()); if (!K9.DEBUG && mDebugLogging.isChecked()) { Toast.makeText(this, R.string.debug_logging_enabled, Toast.LENGTH_LONG).show(); diff --git a/src/com/fsck/k9/preferences/GlobalSettings.java b/src/com/fsck/k9/preferences/GlobalSettings.java index be13bbe01..38d134a8f 100644 --- a/src/com/fsck/k9/preferences/GlobalSettings.java +++ b/src/com/fsck/k9/preferences/GlobalSettings.java @@ -188,9 +188,6 @@ public class GlobalSettings { new V(16, new ThemeSetting(K9.Theme.LIGHT)), new V(24, new SubThemeSetting(K9.Theme.USE_GLOBAL)) )); - s.put("useGalleryBugWorkaround", Settings.versions( - new V(1, new GalleryBugWorkaroundSetting()) - )); s.put("useVolumeKeysForListNavigation", Settings.versions( new V(1, new BooleanSetting(false)) )); @@ -372,27 +369,6 @@ public class GlobalSettings { } } - /** - * The gallery bug work-around setting. - * - *

- * The default value varies depending on whether you have a version of Gallery 3D installed - * that contains the bug we work around. - *

- * - * @see K9#isGalleryBuggy() - */ - public static class GalleryBugWorkaroundSetting extends BooleanSetting { - public GalleryBugWorkaroundSetting() { - super(false); - } - - @Override - public Object getDefaultValue() { - return K9.isGalleryBuggy(); - } - } - /** * The language setting. * diff --git a/src/com/fsck/k9/preferences/Settings.java b/src/com/fsck/k9/preferences/Settings.java index 694730673..1d06b7fd2 100644 --- a/src/com/fsck/k9/preferences/Settings.java +++ b/src/com/fsck/k9/preferences/Settings.java @@ -35,7 +35,7 @@ public class Settings { * * @see SettingsExporter */ - public static final int VERSION = 34; + public static final int VERSION = 35; public static Map validate(int version, Map> settings, From 094feced0c04ca99f4c8c610ab0163015ba5b88e Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Tue, 9 Sep 2014 18:56:36 -0400 Subject: [PATCH 05/16] Remove unused imports --- src/com/fsck/k9/K9.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/com/fsck/k9/K9.java b/src/com/fsck/k9/K9.java index aa0030f0e..593bc07a9 100644 --- a/src/com/fsck/k9/K9.java +++ b/src/com/fsck/k9/K9.java @@ -16,9 +16,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Debug; import android.os.Environment; From 0f6719387c9615e8420e5724b9580299f23a2ef8 Mon Sep 17 00:00:00 2001 From: Joe Steele Date: Wed, 10 Sep 2014 11:34:37 -0400 Subject: [PATCH 06/16] Re-enable TLSv1.1/1.2 support Was disabled in 3fd7470d. Issue 6238. Related Android change for API 20: https://android.googlesource.com/platform/external/conscrypt/+/1f63d2c22326b989105366d2907a83b848dcd29e%5E!/ --- src/com/fsck/k9/net/ssl/TrustedSocketFactory.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java index 7d2438cda..a4949fa17 100644 --- a/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java +++ b/src/com/fsck/k9/net/ssl/TrustedSocketFactory.java @@ -74,7 +74,7 @@ public class TrustedSocketFactory { static { String[] enabledCiphers = null; - String[] enabledProtocols = null; + String[] supportedProtocols = null; try { SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -82,7 +82,13 @@ public class TrustedSocketFactory { SSLSocketFactory sf = sslContext.getSocketFactory(); SSLSocket sock = (SSLSocket) sf.createSocket(); enabledCiphers = sock.getEnabledCipherSuites(); - enabledProtocols = sock.getEnabledProtocols(); + + /* + * Retrieve all supported protocols, not just the (default) enabled + * ones. TLSv1.1 & TLSv1.2 are supported on API levels 16+, but are + * only enabled by default on API levels 20+. + */ + supportedProtocols = sock.getSupportedProtocols(); } catch (Exception e) { Log.e(K9.LOG_TAG, "Error getting information about available SSL/TLS ciphers and " + "protocols", e); @@ -91,8 +97,8 @@ public class TrustedSocketFactory { ENABLED_CIPHERS = (enabledCiphers == null) ? null : reorder(enabledCiphers, ORDERED_KNOWN_CIPHERS, BLACKLISTED_CIPHERS); - ENABLED_PROTOCOLS = (enabledProtocols == null) ? null : - reorder(enabledProtocols, ORDERED_KNOWN_PROTOCOLS, null); + ENABLED_PROTOCOLS = (supportedProtocols == null) ? null : + reorder(supportedProtocols, ORDERED_KNOWN_PROTOCOLS, null); } protected static String[] reorder(String[] enabled, String[] known, String[] blacklisted) { From 47cedef85c915b5f2d013124dde0bfe021d66a09 Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 10 Sep 2014 20:58:46 +0200 Subject: [PATCH 07/16] Update changelog for 4.905 --- res/xml/changelog_master.xml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/res/xml/changelog_master.xml b/res/xml/changelog_master.xml index 30b5c77eb..b3431139c 100644 --- a/res/xml/changelog_master.xml +++ b/res/xml/changelog_master.xml @@ -8,6 +8,21 @@ They are automatically updated with "ant bump-version". --> + + Dropped support for Android versions older than 4.0.3 + Added ability to use client certificates for authentication + Enabled support for TLSv1.1 and TLSv1.2 + Added SSL/TLS session caching + Finer grained control for notifications + Added support for delete confirmations in the message list + Added the option to show the password when setting up new accounts + Added privacy setting to omit the User-Agent header + Added privacy setting to use UTC as timezone in mail headers + Added auto configuration settings for various providers + Fixed HELO/EHLO with IPv6 address literals + Various bug fixes + Added translations: Latvian, Estonian, Norwegian Bokmål, Galician (Spain) + Added support for OpenPGP API v3 Fixed problems with IMAP login @@ -66,7 +81,6 @@ Better cleanup of old data when deleting an account Worked around a bug in KitKat that stopped settings import from working Updated German, Greek, Japanese, Korean, Lithuanian, Portugese, Russian and Slovak translations - Code cleanups From 5ddfe4b58e1109708c9f17a614440e2abeb1ae0d Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 10 Sep 2014 21:12:12 +0200 Subject: [PATCH 08/16] Bumped manifest to 4.905 --- AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9becd0870..d8044e1ed 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@ Date: Wed, 10 Sep 2014 21:49:44 +0200 Subject: [PATCH 09/16] Add Play Store feature graphic assets --- images/feature_graphic.png | Bin 0 -> 70436 bytes images/feature_graphic.svg | 1474 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1474 insertions(+) create mode 100644 images/feature_graphic.png create mode 100644 images/feature_graphic.svg diff --git a/images/feature_graphic.png b/images/feature_graphic.png new file mode 100644 index 0000000000000000000000000000000000000000..fdef6de7667e5780ba1bf481ec74b9ce9f9c5249 GIT binary patch literal 70436 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 JBE*e@{vRLxA6x(c literal 0 HcmV?d00001 diff --git a/images/feature_graphic.svg b/images/feature_graphic.svg new file mode 100644 index 000000000..fc8709384 --- /dev/null +++ b/images/feature_graphic.svg @@ -0,0 +1,1474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + K-9 Mail + Advanced Emailing + + + From a2a9e751e490c15a4ddb57f12cedf7b1897ce700 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 29 Aug 2014 06:09:56 +0200 Subject: [PATCH 10/16] Use android-sdk-manager to fetch Android SDK dependencies --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 07d0e49b6..0e6070813 100644 --- a/build.gradle +++ b/build.gradle @@ -5,11 +5,17 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:0.12.2' + classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' } } +apply plugin: 'android-sdk-manager' apply plugin: 'com.android.application' +repositories { + jcenter() +} + dependencies { compile project(':plugins:Android-PullToRefresh:library') compile project(':plugins:ckChangeLog:library') From 87a912610761c5869e214abe5377d9edaf8fb10e Mon Sep 17 00:00:00 2001 From: cketti Date: Sun, 31 Aug 2014 00:56:21 +0200 Subject: [PATCH 11/16] Update HoloColorPicker to use build tools 20.0.0 --- plugins/HoloColorPicker/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/HoloColorPicker/build.gradle b/plugins/HoloColorPicker/build.gradle index 7c966604e..610b12133 100644 --- a/plugins/HoloColorPicker/build.gradle +++ b/plugins/HoloColorPicker/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.library' android { compileSdkVersion 19 - buildToolsVersion '19.1.0' + buildToolsVersion '20.0.0' sourceSets { main { From 98559900c2c2b9d670ba19d34c2d5de17f218d07 Mon Sep 17 00:00:00 2001 From: cketti Date: Sun, 31 Aug 2014 01:10:13 +0200 Subject: [PATCH 12/16] Add support for disabling pre-dexing --- build.gradle | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/build.gradle b/build.gradle index 0e6070813..4c57f3c49 100644 --- a/build.gradle +++ b/build.gradle @@ -25,10 +25,25 @@ dependencies { compile fileTree(dir: 'libs', include: '*.jar') } +project.ext.preDexLibs = !project.hasProperty('disablePreDex') + +subprojects { + project.plugins.whenPluginAdded { plugin -> + if ("com.android.build.gradle.AppPlugin".equals(plugin.class.name) || + "com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) { + project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs + } + } +} + android { compileSdkVersion 19 buildToolsVersion '20.0.0' + dexOptions { + preDexLibraries = rootProject.ext.preDexLibs + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' From 471f1df160d247e742b265adc136570792d2cd2d Mon Sep 17 00:00:00 2001 From: cketti Date: Mon, 1 Sep 2014 00:29:48 +0200 Subject: [PATCH 13/16] Use checkstyle to monitor code quality --- build.gradle | 11 +++ config/checkstyle/checkstyle.xml | 149 +++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/build.gradle b/build.gradle index 4c57f3c49..331d3fc76 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ buildscript { apply plugin: 'android-sdk-manager' apply plugin: 'com.android.application' +apply plugin: 'checkstyle' repositories { jcenter() @@ -72,6 +73,16 @@ android { } } +check.dependsOn 'checkstyle' +task checkstyle(type: Checkstyle) { + ignoreFailures = true + configFile file("config/checkstyle/checkstyle.xml") + + source 'src' + include '**/*.java' + classpath = files() +} + task testsOnJVM(type :GradleBuild, dependsOn: assemble) { buildFile = 'tests-on-jvm/build.gradle' tasks = ['test'] diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..7b0a8b796 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From b31660c63e07ca065f8e1e1027114daa4267dfda Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 12 Sep 2014 05:54:38 +0200 Subject: [PATCH 14/16] Remove unused strings --- res/values-et/strings.xml | 4 ---- res/values-gl-rES/strings.xml | 6 ------ res/values-lv/strings.xml | 8 -------- res/values-nb/strings.xml | 4 ---- 4 files changed, 22 deletions(-) diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index aa1d5cf81..feb7591e9 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -137,8 +137,6 @@ Palun saada infot probleemidest, soovitavatest lisafunktsioonidest ja küsi küs Taotleb lugemise kinnitust Ei taotle lugemise kinnitust Lisa manus - Lisa manus (pilt) - Lisa manus (video) Tühjenda prügikast Pühi ära Puhasta kohalikud sõnumid @@ -704,8 +702,6 @@ Palun saada infot probleemidest, soovitavatest lisafunktsioonidest ja küsi küs Keskmine Suur Suurem - - Muu Installitud APG versioon ei ole toetatud. diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml index 4c737e097..df0051bb9 100644 --- a/res/values-gl-rES/strings.xml +++ b/res/values-gl-rES/strings.xml @@ -134,8 +134,6 @@ Envía informes de erro, contribúe con novas funcionalidades e pregunta o que d Pedirase confirmación de lectura Non se pedirá confirmación de lectura Engadir anexo - Engadir anexo (imaxe) - Engadir anexo (vídeo) Baleirar papeleira Purgar Limpar mensaxes locais @@ -695,11 +693,7 @@ Envía informes de erro, contribúe con novas funcionalidades e pregunta o que d Mediana Grande Moi grande - - - Usar \"Engadir anexo (imaxe)\" ou \"Engadir anexo (vídeo)\" para anexar imaxes ou vídeos con Galería 3D. Miscelánea - Mostrar botóns para engadir anexos de imaxe e vídeo Non hai un aplicativo para executar esta acción. Non se admite a versión instalada de APG. diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 69f0795a7..d986fffa1 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -138,8 +138,6 @@ Lūdzu sūtiet kļūdu ziņojumus, iesakiet uzlabojumus un uzdodiet jautājumus Pieprasīt izlasīšanas atskaiti Neprasīt izlasīšanas atskaiti Pievienot pielikumu - Pievienot pielikumu (bildi) - Pievienot pielikumu (video) Iztukšot miskasti Izmest Izdzēst ierīcē esošās vēstules @@ -731,13 +729,7 @@ pat %d vairāk Vidējs Liels Lielāks - - Pārbaudiet \"Iestatījumi\" -> \"Izmantot galerijas kļūdu apvedceļu\", lai varētu pievienotu bildes vai video, izmantojot Gallery 3D. - - Izmantot \"Pievienot pielikumu (bildi)\" vai \"Pievienot pielikumu (video)\", lai pievienotu bildes vai videoklipus ar Gallery 3D. Dažādi - Izmantot galerijas kļūdu apvedceļu - Rādīt pogas, lai pievienotu bildi/video kā pielikumus (izmantojot Gallery 3D kļūdu apvedceļu) Šai darbībai nav atrasta atbilstoša aplikācija. Instalētā APG versija netiek atbalstīta. diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index f748e8665..b0b738b2b 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -137,8 +137,6 @@ Vennligst send feilmeldinger, forbedringer og still spørsmål hos Kommer til å be om lesekvittering Kommer ikke til å be om lesekvittering Legg til vedlegg - Legg til vedlegg (bilde) - Legg til vedlegg (video) Tøm søppeldunk Tilintetgjør Fjern lokale meldinger @@ -661,8 +659,6 @@ Vis neste melding som standard etter meldingssletting Medium Stor Større - - Diverse Ingen egnede program ble funnet for denne handlingen. From 3e4beae63153957cf8384c80240068a57f2de094 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 12 Sep 2014 06:26:03 +0200 Subject: [PATCH 15/16] Remove unused 'check mark' color chip --- src/com/fsck/k9/Account.java | 10 ---------- src/com/fsck/k9/view/ColorChip.java | 17 +++-------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/com/fsck/k9/Account.java b/src/com/fsck/k9/Account.java index a497e1124..54297b580 100644 --- a/src/com/fsck/k9/Account.java +++ b/src/com/fsck/k9/Account.java @@ -221,7 +221,6 @@ public class Account implements BaseAccount { private ColorChip mFlaggedUnreadColorChip; private ColorChip mFlaggedReadColorChip; - private ColorChip mCheckmarkChip; /** @@ -862,11 +861,6 @@ public class Account implements BaseAccount { mUnreadColorChip = new ColorChip(mChipColor, false, ColorChip.CIRCULAR); mFlaggedReadColorChip = new ColorChip(mChipColor, true, ColorChip.STAR); mFlaggedUnreadColorChip = new ColorChip(mChipColor, false, ColorChip.STAR); - mCheckmarkChip = new ColorChip(mChipColor, true, ColorChip.CHECKMARK); - } - - public ColorChip getCheckmarkChip() { - return mCheckmarkChip; } public synchronized int getChipColor() { @@ -895,10 +889,6 @@ public class Account implements BaseAccount { return chip; } - public ColorChip generateColorChip() { - return new ColorChip(mChipColor, false, ColorChip.CIRCULAR); - } - @Override public String getUuid() { return mUuid; diff --git a/src/com/fsck/k9/view/ColorChip.java b/src/com/fsck/k9/view/ColorChip.java index 3dcbeddc7..c07de65ac 100644 --- a/src/com/fsck/k9/view/ColorChip.java +++ b/src/com/fsck/k9/view/ColorChip.java @@ -12,7 +12,6 @@ public class ColorChip { public static final Path RIGHT_POINTING = new Path(); public static final Path RIGHT_NOTCH = new Path(); public static final Path STAR = new Path(); - public static final Path CHECKMARK = new Path(); static { @@ -47,12 +46,6 @@ public class ColorChip { STAR.lineTo(110f,110f); STAR.lineTo(140f,60f); STAR.close(); - - - CHECKMARK.moveTo(10f,160f); - CHECKMARK.lineTo(120f,280f); - CHECKMARK.lineTo(300f,40f); - } private ShapeDrawable mDrawable; @@ -66,11 +59,7 @@ public class ColorChip { } else { mDrawable = new ShapeDrawable(new PathShape(shape, 320f, 320f)); } - if (shape.equals(CHECKMARK)) { - mDrawable.getPaint().setStrokeWidth(50); - } else { - mDrawable.getPaint().setStrokeWidth(20); - } + if (messageRead) { // Read messages get an outlined circle mDrawable.getPaint().setStyle(Paint.Style.STROKE); @@ -79,9 +68,9 @@ public class ColorChip { mDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE); } + + mDrawable.getPaint().setStrokeWidth(20); mDrawable.getPaint().setColor(color); - - } public ShapeDrawable drawable() { From a6fc06f7f943ae2d6c46bc62f7c3d9718eeba163 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 12 Sep 2014 06:35:07 +0200 Subject: [PATCH 16/16] Fix code style --- src/com/fsck/k9/view/ColorChip.java | 53 +++++++++++++---------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/com/fsck/k9/view/ColorChip.java b/src/com/fsck/k9/view/ColorChip.java index c07de65ac..a20b8ff50 100644 --- a/src/com/fsck/k9/view/ColorChip.java +++ b/src/com/fsck/k9/view/ColorChip.java @@ -1,11 +1,13 @@ package com.fsck.k9.view; + import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.PathShape; + public class ColorChip { public static final Path CIRCULAR = new Path(); public static final Path LEFT_POINTING = new Path(); @@ -13,49 +15,45 @@ public class ColorChip { public static final Path RIGHT_NOTCH = new Path(); public static final Path STAR = new Path(); - static { - - CIRCULAR.addCircle(160,160,70f,Path.Direction.CW); + CIRCULAR.addCircle(160, 160, 70f, Path.Direction.CW); CIRCULAR.close(); - RIGHT_POINTING.addArc(new RectF(80f,80f,240f,240f) , 90, 180); - RIGHT_POINTING.arcTo(new RectF(160f,0f,320f,160f), 180, -90); - RIGHT_POINTING.arcTo(new RectF(160f,160f,320f,320f), 270,-90); + RIGHT_POINTING.addArc(new RectF(80f, 80f, 240f, 240f), 90, 180); + RIGHT_POINTING.arcTo(new RectF(160f, 0f, 320f, 160f), 180, -90); + RIGHT_POINTING.arcTo(new RectF(160f, 160f, 320f, 320f), 270, -90); RIGHT_POINTING.close(); - RIGHT_NOTCH.addArc(new RectF(80f,80f,240f,240f) , 90, 180); - RIGHT_NOTCH.arcTo(new RectF(160f,0f,320f,160f), 180, -90); - RIGHT_NOTCH.arcTo(new RectF(160f,160f,320f,320f), 270,-90); + RIGHT_NOTCH.addArc(new RectF(80f, 80f, 240f, 240f), 90, 180); + RIGHT_NOTCH.arcTo(new RectF(160f, 0f, 320f, 160f), 180, -90); + RIGHT_NOTCH.arcTo(new RectF(160f, 160f, 320f, 320f), 270, -90); RIGHT_NOTCH.close(); - LEFT_POINTING.addArc(new RectF(80f,80f,240f,240f) , 90, -180); - LEFT_POINTING.arcTo(new RectF(00f,00f,160f,160f), 0, 90); - LEFT_POINTING.arcTo(new RectF(00f,160f,160f,320f), 270,90); + LEFT_POINTING.addArc(new RectF(80f, 80f, 240f, 240f), 90, -180); + LEFT_POINTING.arcTo(new RectF(00f, 00f, 160f, 160f), 0, 90); + LEFT_POINTING.arcTo(new RectF(00f, 160f, 160f, 320f), 270, 90); LEFT_POINTING.close(); - STAR.moveTo(140f,60f); - STAR.lineTo(170f,110f); - STAR.lineTo(220f,120f); - STAR.lineTo(180f,160f); - STAR.lineTo(200f,220f); - STAR.lineTo(140f,190f); - STAR.lineTo(80f,220f); - STAR.lineTo(100f,160f); - STAR.lineTo(60f,120f); - STAR.lineTo(110f,110f); - STAR.lineTo(140f,60f); + STAR.moveTo(140f, 60f); + STAR.lineTo(170f, 110f); + STAR.lineTo(220f, 120f); + STAR.lineTo(180f, 160f); + STAR.lineTo(200f, 220f); + STAR.lineTo(140f, 190f); + STAR.lineTo(80f, 220f); + STAR.lineTo(100f, 160f); + STAR.lineTo(60f, 120f); + STAR.lineTo(110f, 110f); + STAR.lineTo(140f, 60f); STAR.close(); } + private ShapeDrawable mDrawable; - public ColorChip(int color, boolean messageRead, Path shape) { - if (shape.equals(STAR)) { mDrawable = new ShapeDrawable(new PathShape(shape, 280f, 280f)); - } else { mDrawable = new ShapeDrawable(new PathShape(shape, 320f, 320f)); } @@ -66,7 +64,6 @@ public class ColorChip { } else { // Unread messages get filled, while retaining the outline, so that they stay the same size mDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE); - } mDrawable.getPaint().setStrokeWidth(20); @@ -76,6 +73,4 @@ public class ColorChip { public ShapeDrawable drawable() { return mDrawable; } - - }