Extract code to encode/decode ImapStore URIs
This commit is contained in:
parent
06ee1ff1b9
commit
ad1e2caa9c
3 changed files with 199 additions and 168 deletions
|
@ -2,8 +2,6 @@
|
||||||
package com.fsck.k9.mail.store.imap;
|
package com.fsck.k9.mail.store.imap;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.nio.charset.CharacterCodingException;
|
import java.nio.charset.CharacterCodingException;
|
||||||
|
@ -34,7 +32,6 @@ import com.fsck.k9.mail.MessagingException;
|
||||||
import com.fsck.k9.mail.PushReceiver;
|
import com.fsck.k9.mail.PushReceiver;
|
||||||
import com.fsck.k9.mail.Pusher;
|
import com.fsck.k9.mail.Pusher;
|
||||||
import com.fsck.k9.mail.ServerSettings;
|
import com.fsck.k9.mail.ServerSettings;
|
||||||
import com.fsck.k9.mail.ServerSettings.Type;
|
|
||||||
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
|
import com.fsck.k9.mail.ssl.TrustedSocketFactory;
|
||||||
import com.fsck.k9.mail.store.RemoteStore;
|
import com.fsck.k9.mail.store.RemoteStore;
|
||||||
import com.fsck.k9.mail.store.StoreConfig;
|
import com.fsck.k9.mail.store.StoreConfig;
|
||||||
|
@ -42,8 +39,6 @@ import com.fsck.k9.mail.store.StoreConfig;
|
||||||
import com.beetstra.jutf7.CharsetProvider;
|
import com.beetstra.jutf7.CharsetProvider;
|
||||||
|
|
||||||
import static com.fsck.k9.mail.K9MailLib.LOG_TAG;
|
import static com.fsck.k9.mail.K9MailLib.LOG_TAG;
|
||||||
import static com.fsck.k9.mail.helper.UrlEncodingHelper.decodeUtf8;
|
|
||||||
import static com.fsck.k9.mail.helper.UrlEncodingHelper.encodeUtf8;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,173 +62,12 @@ public class ImapStore extends RemoteStore {
|
||||||
private String mCombinedPrefix = null;
|
private String mCombinedPrefix = null;
|
||||||
private String mPathDelimiter = null;
|
private String mPathDelimiter = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes an ImapStore URI.
|
|
||||||
*
|
|
||||||
* <p>Possible forms:</p>
|
|
||||||
* <pre>
|
|
||||||
* imap://auth:user:password@server:port ConnectionSecurity.NONE
|
|
||||||
* imap+tls+://auth:user:password@server:port ConnectionSecurity.STARTTLS_REQUIRED
|
|
||||||
* imap+ssl+://auth:user:password@server:port ConnectionSecurity.SSL_TLS_REQUIRED
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param uri the store uri. NOTE: this method expects the userinfo part of the uri to be
|
|
||||||
* encoded twice, due to a bug in {@link #createUri(ServerSettings)}.
|
|
||||||
*/
|
|
||||||
public static ImapStoreSettings decodeUri(String uri) {
|
public static ImapStoreSettings decodeUri(String uri) {
|
||||||
String host;
|
return ImapStoreUriDecoder.decode(uri);
|
||||||
int port;
|
|
||||||
ConnectionSecurity connectionSecurity;
|
|
||||||
AuthType authenticationType = null;
|
|
||||||
String username = null;
|
|
||||||
String password = null;
|
|
||||||
String clientCertificateAlias = null;
|
|
||||||
String pathPrefix = null;
|
|
||||||
boolean autoDetectNamespace = true;
|
|
||||||
|
|
||||||
URI imapUri;
|
|
||||||
try {
|
|
||||||
imapUri = new URI(uri);
|
|
||||||
} catch (URISyntaxException use) {
|
|
||||||
throw new IllegalArgumentException("Invalid ImapStore URI", use);
|
|
||||||
}
|
|
||||||
|
|
||||||
String scheme = imapUri.getScheme();
|
|
||||||
/*
|
|
||||||
* Currently available schemes are:
|
|
||||||
* imap
|
|
||||||
* imap+tls+
|
|
||||||
* imap+ssl+
|
|
||||||
*
|
|
||||||
* The following are obsolete schemes that may be found in pre-existing
|
|
||||||
* settings from earlier versions or that may be found when imported. We
|
|
||||||
* continue to recognize them and re-map them appropriately:
|
|
||||||
* imap+tls
|
|
||||||
* imap+ssl
|
|
||||||
*/
|
|
||||||
if (scheme.equals("imap")) {
|
|
||||||
connectionSecurity = ConnectionSecurity.NONE;
|
|
||||||
port = Type.IMAP.defaultPort;
|
|
||||||
} else if (scheme.startsWith("imap+tls")) {
|
|
||||||
connectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED;
|
|
||||||
port = Type.IMAP.defaultPort;
|
|
||||||
} else if (scheme.startsWith("imap+ssl")) {
|
|
||||||
connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED;
|
|
||||||
port = Type.IMAP.defaultTlsPort;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unsupported protocol (" + scheme + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
host = imapUri.getHost();
|
|
||||||
|
|
||||||
if (imapUri.getPort() != -1) {
|
|
||||||
port = imapUri.getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imapUri.getUserInfo() != null) {
|
|
||||||
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 = decodeUtf8(userInfoParts[1]);
|
|
||||||
} else if (userInfoParts.length == 2) {
|
|
||||||
authenticationType = AuthType.PLAIN;
|
|
||||||
username = decodeUtf8(userInfoParts[0]);
|
|
||||||
password = decodeUtf8(userInfoParts[1]);
|
|
||||||
} else if (userInfoParts.length == 3) {
|
|
||||||
authenticationType = AuthType.valueOf(userInfoParts[0]);
|
|
||||||
username = decodeUtf8(userInfoParts[1]);
|
|
||||||
|
|
||||||
if (AuthType.EXTERNAL == authenticationType) {
|
|
||||||
clientCertificateAlias = decodeUtf8(userInfoParts[2]);
|
|
||||||
} else {
|
|
||||||
password = decodeUtf8(userInfoParts[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = imapUri.getPath();
|
|
||||||
if (path != null && path.length() > 1) {
|
|
||||||
// Strip off the leading "/"
|
|
||||||
String cleanPath = path.substring(1);
|
|
||||||
|
|
||||||
if (cleanPath.length() >= 2 && cleanPath.charAt(1) == '|') {
|
|
||||||
autoDetectNamespace = cleanPath.charAt(0) == '1';
|
|
||||||
if (!autoDetectNamespace) {
|
|
||||||
pathPrefix = cleanPath.substring(2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (cleanPath.length() > 0) {
|
|
||||||
pathPrefix = cleanPath;
|
|
||||||
autoDetectNamespace = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ImapStoreSettings(host, port, connectionSecurity, authenticationType, username,
|
|
||||||
password, clientCertificateAlias, autoDetectNamespace, pathPrefix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an ImapStore URI with the supplied settings.
|
|
||||||
*
|
|
||||||
* @param server
|
|
||||||
* The {@link ServerSettings} object that holds the server settings.
|
|
||||||
*
|
|
||||||
* @return An ImapStore URI that holds the same information as the {@code server} parameter.
|
|
||||||
*
|
|
||||||
* @see com.fsck.k9.mail.store.StoreConfig#getStoreUri()
|
|
||||||
* @see ImapStore#decodeUri(String)
|
|
||||||
*/
|
|
||||||
public static String createUri(ServerSettings server) {
|
public static String createUri(ServerSettings server) {
|
||||||
String userEnc = encodeUtf8(server.username);
|
return ImapStoreUriCreator.create(server);
|
||||||
String passwordEnc = (server.password != null) ?
|
|
||||||
encodeUtf8(server.password) : "";
|
|
||||||
String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ?
|
|
||||||
encodeUtf8(server.clientCertificateAlias) : "";
|
|
||||||
|
|
||||||
String scheme;
|
|
||||||
switch (server.connectionSecurity) {
|
|
||||||
case SSL_TLS_REQUIRED:
|
|
||||||
scheme = "imap+ssl+";
|
|
||||||
break;
|
|
||||||
case STARTTLS_REQUIRED:
|
|
||||||
scheme = "imap+tls+";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case NONE:
|
|
||||||
scheme = "imap";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthType authType = server.authenticationType;
|
|
||||||
String userInfo;
|
|
||||||
if (authType == AuthType.EXTERNAL) {
|
|
||||||
userInfo = authType.name() + ":" + userEnc + ":" + clientCertificateAliasEnc;
|
|
||||||
} else {
|
|
||||||
userInfo = authType.name() + ":" + userEnc + ":" + passwordEnc;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Map<String, String> extra = server.getExtra();
|
|
||||||
String path;
|
|
||||||
if (extra != null) {
|
|
||||||
boolean autoDetectNamespace = Boolean.TRUE.toString().equals(
|
|
||||||
extra.get(ImapStoreSettings.AUTODETECT_NAMESPACE_KEY));
|
|
||||||
String pathPrefix = (autoDetectNamespace) ?
|
|
||||||
null : extra.get(ImapStoreSettings.PATH_PREFIX_KEY);
|
|
||||||
path = "/" + (autoDetectNamespace ? "1" : "0") + "|" +
|
|
||||||
((pathPrefix == null) ? "" : pathPrefix);
|
|
||||||
} else {
|
|
||||||
path = "/1|";
|
|
||||||
}
|
|
||||||
return new URI(scheme, userInfo, server.host, server.port,
|
|
||||||
path,
|
|
||||||
null, null).toString();
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new IllegalArgumentException("Can't create ImapStore URI", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.fsck.k9.mail.store.imap;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.AuthType;
|
||||||
|
import com.fsck.k9.mail.ServerSettings;
|
||||||
|
|
||||||
|
import static com.fsck.k9.mail.helper.UrlEncodingHelper.encodeUtf8;
|
||||||
|
|
||||||
|
|
||||||
|
class ImapStoreUriCreator {
|
||||||
|
/**
|
||||||
|
* Creates an ImapStore URI with the supplied settings.
|
||||||
|
*
|
||||||
|
* @param server
|
||||||
|
* The {@link ServerSettings} object that holds the server settings.
|
||||||
|
*
|
||||||
|
* @return An ImapStore URI that holds the same information as the {@code server} parameter.
|
||||||
|
*
|
||||||
|
* @see com.fsck.k9.mail.store.StoreConfig#getStoreUri()
|
||||||
|
* @see ImapStore#decodeUri(String)
|
||||||
|
*/
|
||||||
|
public static String create(ServerSettings server) {
|
||||||
|
String userEnc = encodeUtf8(server.username);
|
||||||
|
String passwordEnc = (server.password != null) ? encodeUtf8(server.password) : "";
|
||||||
|
String clientCertificateAliasEnc = (server.clientCertificateAlias != null) ?
|
||||||
|
encodeUtf8(server.clientCertificateAlias) : "";
|
||||||
|
|
||||||
|
String scheme;
|
||||||
|
switch (server.connectionSecurity) {
|
||||||
|
case SSL_TLS_REQUIRED:
|
||||||
|
scheme = "imap+ssl+";
|
||||||
|
break;
|
||||||
|
case STARTTLS_REQUIRED:
|
||||||
|
scheme = "imap+tls+";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case NONE:
|
||||||
|
scheme = "imap";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthType authType = server.authenticationType;
|
||||||
|
String userInfo;
|
||||||
|
if (authType == AuthType.EXTERNAL) {
|
||||||
|
userInfo = authType.name() + ":" + userEnc + ":" + clientCertificateAliasEnc;
|
||||||
|
} else {
|
||||||
|
userInfo = authType.name() + ":" + userEnc + ":" + passwordEnc;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map<String, String> extra = server.getExtra();
|
||||||
|
String path;
|
||||||
|
if (extra != null) {
|
||||||
|
boolean autoDetectNamespace = Boolean.TRUE.toString().equals(
|
||||||
|
extra.get(ImapStoreSettings.AUTODETECT_NAMESPACE_KEY));
|
||||||
|
String pathPrefix = (autoDetectNamespace) ?
|
||||||
|
null : extra.get(ImapStoreSettings.PATH_PREFIX_KEY);
|
||||||
|
path = "/" + (autoDetectNamespace ? "1" : "0") + "|" +
|
||||||
|
((pathPrefix == null) ? "" : pathPrefix);
|
||||||
|
} else {
|
||||||
|
path = "/1|";
|
||||||
|
}
|
||||||
|
return new URI(scheme, userInfo, server.host, server.port, path, null, null).toString();
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new IllegalArgumentException("Can't create ImapStore URI", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
package com.fsck.k9.mail.store.imap;
|
||||||
|
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.AuthType;
|
||||||
|
import com.fsck.k9.mail.ConnectionSecurity;
|
||||||
|
import com.fsck.k9.mail.ServerSettings;
|
||||||
|
import com.fsck.k9.mail.ServerSettings.Type;
|
||||||
|
|
||||||
|
import static com.fsck.k9.mail.helper.UrlEncodingHelper.decodeUtf8;
|
||||||
|
|
||||||
|
|
||||||
|
class ImapStoreUriDecoder {
|
||||||
|
/**
|
||||||
|
* Decodes an ImapStore URI.
|
||||||
|
*
|
||||||
|
* <p>Possible forms:</p>
|
||||||
|
* <pre>
|
||||||
|
* imap://auth:user:password@server:port ConnectionSecurity.NONE
|
||||||
|
* imap+tls+://auth:user:password@server:port ConnectionSecurity.STARTTLS_REQUIRED
|
||||||
|
* imap+ssl+://auth:user:password@server:port ConnectionSecurity.SSL_TLS_REQUIRED
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* NOTE: this method expects the userinfo part of the uri to be encoded twice, due to a bug in
|
||||||
|
* {@link ImapStoreUriCreator#create(ServerSettings)}.
|
||||||
|
*
|
||||||
|
* @param uri the store uri.
|
||||||
|
*/
|
||||||
|
public static ImapStoreSettings decode(String uri) {
|
||||||
|
String host;
|
||||||
|
int port;
|
||||||
|
ConnectionSecurity connectionSecurity;
|
||||||
|
AuthType authenticationType = null;
|
||||||
|
String username = null;
|
||||||
|
String password = null;
|
||||||
|
String clientCertificateAlias = null;
|
||||||
|
String pathPrefix = null;
|
||||||
|
boolean autoDetectNamespace = true;
|
||||||
|
|
||||||
|
URI imapUri;
|
||||||
|
try {
|
||||||
|
imapUri = new URI(uri);
|
||||||
|
} catch (URISyntaxException use) {
|
||||||
|
throw new IllegalArgumentException("Invalid ImapStore URI", use);
|
||||||
|
}
|
||||||
|
|
||||||
|
String scheme = imapUri.getScheme();
|
||||||
|
/*
|
||||||
|
* Currently available schemes are:
|
||||||
|
* imap
|
||||||
|
* imap+tls+
|
||||||
|
* imap+ssl+
|
||||||
|
*
|
||||||
|
* The following are obsolete schemes that may be found in pre-existing
|
||||||
|
* settings from earlier versions or that may be found when imported. We
|
||||||
|
* continue to recognize them and re-map them appropriately:
|
||||||
|
* imap+tls
|
||||||
|
* imap+ssl
|
||||||
|
*/
|
||||||
|
if (scheme.equals("imap")) {
|
||||||
|
connectionSecurity = ConnectionSecurity.NONE;
|
||||||
|
port = Type.IMAP.defaultPort;
|
||||||
|
} else if (scheme.startsWith("imap+tls")) {
|
||||||
|
connectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED;
|
||||||
|
port = Type.IMAP.defaultPort;
|
||||||
|
} else if (scheme.startsWith("imap+ssl")) {
|
||||||
|
connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED;
|
||||||
|
port = Type.IMAP.defaultTlsPort;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unsupported protocol (" + scheme + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
host = imapUri.getHost();
|
||||||
|
|
||||||
|
if (imapUri.getPort() != -1) {
|
||||||
|
port = imapUri.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imapUri.getUserInfo() != null) {
|
||||||
|
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 = decodeUtf8(userInfoParts[1]);
|
||||||
|
} else if (userInfoParts.length == 2) {
|
||||||
|
authenticationType = AuthType.PLAIN;
|
||||||
|
username = decodeUtf8(userInfoParts[0]);
|
||||||
|
password = decodeUtf8(userInfoParts[1]);
|
||||||
|
} else if (userInfoParts.length == 3) {
|
||||||
|
authenticationType = AuthType.valueOf(userInfoParts[0]);
|
||||||
|
username = decodeUtf8(userInfoParts[1]);
|
||||||
|
|
||||||
|
if (AuthType.EXTERNAL == authenticationType) {
|
||||||
|
clientCertificateAlias = decodeUtf8(userInfoParts[2]);
|
||||||
|
} else {
|
||||||
|
password = decodeUtf8(userInfoParts[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = imapUri.getPath();
|
||||||
|
if (path != null && path.length() > 1) {
|
||||||
|
// Strip off the leading "/"
|
||||||
|
String cleanPath = path.substring(1);
|
||||||
|
|
||||||
|
if (cleanPath.length() >= 2 && cleanPath.charAt(1) == '|') {
|
||||||
|
autoDetectNamespace = cleanPath.charAt(0) == '1';
|
||||||
|
if (!autoDetectNamespace) {
|
||||||
|
pathPrefix = cleanPath.substring(2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cleanPath.length() > 0) {
|
||||||
|
pathPrefix = cleanPath;
|
||||||
|
autoDetectNamespace = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImapStoreSettings(host, port, connectionSecurity, authenticationType, username,
|
||||||
|
password, clientCertificateAlias, autoDetectNamespace, pathPrefix);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue