// Copyright (C) 2009 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 org.apache.commons.net.smtp;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.gerrit.util.ssl.BlindSSLSocketFactory;

import org.apache.commons.codec.binary.Base64;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLSocketFactory;

public class AuthSMTPClient extends SMTPClient {
  private String authTypes;

  public AuthSMTPClient(final String charset) {
    super(charset);
  }

  public void enableSSL(final boolean verify) {
    _socketFactory_ = sslFactory(verify);
  }

  public boolean startTLS(final String hostname, final int port, final boolean verify)
      throws SocketException, IOException {
    if (sendCommand("STARTTLS") != 220) {
      return false;
    }

    _socket_ = sslFactory(verify).createSocket(_socket_, hostname, port, true);

    // XXX: Can't call _connectAction_() because SMTP server doesn't
    // give banner information again after STARTTLS, thus SMTP._connectAction_()
    // will wait on __getReply() forever, see source code of commons-net-2.2.
    //
    // The lines below are copied from SocketClient._connectAction_() and
    // SMTP._connectAction_() in commons-net-2.2.
    _socket_.setSoTimeout(_timeout_);
    _input_ = _socket_.getInputStream();
    _output_ = _socket_.getOutputStream();
    _reader =
        new BufferedReader(new InputStreamReader(_input_, UTF_8));
    _writer =
        new BufferedWriter(new OutputStreamWriter(_output_, UTF_8));
    return true;
  }

  private static SSLSocketFactory sslFactory(final boolean verify) {
    if (verify) {
      return (SSLSocketFactory) SSLSocketFactory.getDefault();
    } else {
      return (SSLSocketFactory) BlindSSLSocketFactory.getDefault();
    }
  }

  @Override
  public String[] getReplyStrings() {
    return _replyLines.toArray(new String[_replyLines.size()]);
  }

  @Override
  public boolean login() throws IOException {
    final String name = getLocalAddress().getHostName();
    if (name == null) {
      return false;
    }

    boolean ok = SMTPReply.isPositiveCompletion(sendCommand("EHLO", name));
    authTypes = "";
    for (String line : getReplyStrings()) {
      if (line != null && (line.startsWith("250 AUTH ") || line.startsWith("250-AUTH "))) {
        authTypes = line;
        break;
      }
    }

    return ok;
  }

  public boolean auth(String smtpUser, String smtpPass) throws IOException {
    List<String> types = Arrays.asList(authTypes.split(" "));
    if ("".equals(authTypes)) {
      // Server didn't advertise authentication support.
      //
      return true;
    }

    if (smtpPass == null) {
      smtpPass = "";
    }
    if (types.contains("CRAM-SHA1")) {
      return authCram(smtpUser, smtpPass, "SHA1");
    }
    if (types.contains("CRAM-MD5")) {
      return authCram(smtpUser, smtpPass, "MD5");
    }
    if (types.contains("LOGIN")) {
      return authLogin(smtpUser, smtpPass);
    }
    if (types.contains("PLAIN")) {
      return authPlain(smtpUser, smtpPass);
    }
    throw new IOException("Unsupported AUTH: " + authTypes);
  }

  private boolean authCram(String smtpUser, String smtpPass, String alg)
      throws UnsupportedEncodingException, IOException {
    final String macName = "Hmac" + alg;
    if (sendCommand("AUTH", "CRAM-" + alg) != 334) {
      return false;
    }

    final String enc = getReplyStrings()[0].split(" ", 2)[1];
    final byte[] nonce = Base64.decodeBase64(enc.getBytes(UTF_8));
    final String sec;
    try {
      Mac mac = Mac.getInstance(macName);
      mac.init(new SecretKeySpec(smtpPass.getBytes(UTF_8), macName));
      sec = toHex(mac.doFinal(nonce));
    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
      throw new IOException("Cannot use CRAM-" + alg, e);
    }

    String token = smtpUser + ' ' + sec;
    String cmd = encodeBase64(token.getBytes(UTF_8));
    return SMTPReply.isPositiveCompletion(sendCommand(cmd));
  }

  private boolean authLogin(String smtpUser, String smtpPass) throws UnsupportedEncodingException,
      IOException {
    if (sendCommand("AUTH", "LOGIN") != 334) {
      return false;
    }

    String cmd = encodeBase64(smtpUser.getBytes(UTF_8));
    if(sendCommand(cmd) != 334) {
      return false;
    }

    cmd = encodeBase64(smtpPass.getBytes(UTF_8));
    return SMTPReply.isPositiveCompletion(sendCommand(cmd));
  }

  private static final char[] hexchar =
      {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

  private String toHex(final byte[] b) {
    final StringBuilder sec = new StringBuilder();
    for (byte c : b) {
      final int u = (c >> 4) & 0xf;
      final int l = c & 0xf;
      sec.append(hexchar[u]);
      sec.append(hexchar[l]);
    }
    return sec.toString();
  }

  private boolean authPlain(String smtpUser, String smtpPass) throws UnsupportedEncodingException,
      IOException {
    String token = '\0' + smtpUser + '\0' + smtpPass;
    String cmd = "PLAIN " + encodeBase64(token.getBytes(UTF_8));
    return SMTPReply.isPositiveCompletion(sendCommand("AUTH", cmd));
  }

  private static String encodeBase64(final byte[] data) {
    return new String(Base64.encodeBase64(data), UTF_8);
  }
}
