/**
   * Creates a Pop3Store URI with the supplied settings.
   *
   * @param server The {@link ServerSettings} object that holds the server settings.
   * @return A Pop3Store URI that holds the same information as the {@code server} parameter.
   * @see StoreConfig#getStoreUri()
   * @see Pop3Store#decodeUri(String)
   */
  public static String createUri(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 = "pop3+ssl+";
        break;
      case STARTTLS_REQUIRED:
        scheme = "pop3+tls+";
        break;
      default:
      case NONE:
        scheme = "pop3";
        break;
    }

    AuthType authType = server.authenticationType;
    String userInfo;
    if (AuthType.EXTERNAL == authType) {
      userInfo = authType.name() + ":" + userEnc + ":" + clientCertificateAliasEnc;
    } else {
      userInfo = authType.name() + ":" + userEnc + ":" + passwordEnc;
    }

    try {
      return new URI(scheme, userInfo, server.host, server.port, null, null, null).toString();
    } catch (URISyntaxException e) {
      throw new IllegalArgumentException("Can't create Pop3Store URI", e);
    }
  }
  /**
   * Decodes a Pop3Store URI.
   *
   * <p>Possible forms:
   *
   * <pre>
   * pop3://authType:user:password@server:port
   *      ConnectionSecurity.NONE
   * pop3+tls+://authType:user:password@server:port
   *      ConnectionSecurity.STARTTLS_REQUIRED
   * pop3+ssl+://authType:user:password@server:port
   *      ConnectionSecurity.SSL_TLS_REQUIRED
   * </pre>
   *
   * e.g.
   *
   * <pre>pop3://PLAIN:admin:[email protected]:12345</pre>
   */
  public static ServerSettings decodeUri(String uri) {
    String host;
    int port;
    ConnectionSecurity connectionSecurity;
    String username = null;
    String password = null;
    String clientCertificateAlias = null;

    URI pop3Uri;
    try {
      pop3Uri = new URI(uri);
    } catch (URISyntaxException use) {
      throw new IllegalArgumentException("Invalid Pop3Store URI", use);
    }

    String scheme = pop3Uri.getScheme();
    /*
     * Currently available schemes are:
     * pop3
     * pop3+tls+
     * pop3+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:
     * pop3+tls
     * pop3+ssl
     */
    if (scheme.equals("pop3")) {
      connectionSecurity = ConnectionSecurity.NONE;
      port = Type.POP3.defaultPort;
    } else if (scheme.startsWith("pop3+tls")) {
      connectionSecurity = ConnectionSecurity.STARTTLS_REQUIRED;
      port = Type.POP3.defaultPort;
    } else if (scheme.startsWith("pop3+ssl")) {
      connectionSecurity = ConnectionSecurity.SSL_TLS_REQUIRED;
      port = Type.POP3.defaultTlsPort;
    } else {
      throw new IllegalArgumentException("Unsupported protocol (" + scheme + ")");
    }

    host = pop3Uri.getHost();

    if (pop3Uri.getPort() != -1) {
      port = pop3Uri.getPort();
    }

    AuthType authType = AuthType.PLAIN;
    if (pop3Uri.getUserInfo() != null) {
      int userIndex = 0, passwordIndex = 1;
      String userinfo = pop3Uri.getUserInfo();
      String[] userInfoParts = userinfo.split(":");
      if (userInfoParts.length > 2 || userinfo.endsWith(":")) {
        // If 'userinfo' ends with ":" the password is empty. This can only happen
        // after an account was imported (so authType and username are present).
        userIndex++;
        passwordIndex++;
        authType = AuthType.valueOf(userInfoParts[0]);
      }
      username = decodeUtf8(userInfoParts[userIndex]);
      if (userInfoParts.length > passwordIndex) {
        if (authType == AuthType.EXTERNAL) {
          clientCertificateAlias = decodeUtf8(userInfoParts[passwordIndex]);
        } else {
          password = decodeUtf8(userInfoParts[passwordIndex]);
        }
      }
    }

    return new ServerSettings(
        ServerSettings.Type.POP3,
        host,
        port,
        connectionSecurity,
        authType,
        username,
        password,
        clientCertificateAlias);
  }