<?php
/**
 * PHPMailer SMTP class
 * @package PHPMailer
 * @author PHPMailer team
 * @license LGPL
 */

namespace PHPMailer\PHPMailer;

/**
 * PHPMailer SMTP class
 * @package PHPMailer
 * @author PHPMailer team
 * @license LGPL
 */
class SMTP
{
    /**
     * The SMTP host.
     * @var string
     */
    public $Host = 'localhost';

    /**
     * The SMTP port.
     * @var int
     */
    public $Port = 25;

    /**
     * The SMTP username.
     * @var string
     */
    public $Username = '';

    /**
     * The SMTP password.
     * @var string
     */
    public $Password = '';

    /**
     * Whether to use SMTP authentication.
     * @var bool
     */
    public $SMTPAuth = false;

    /**
     * The SMTP security type.
     * @var string
     */
    public $SMTPSecure = '';

    /**
     * The SMTP debug level.
     * @var int
     */
    public $SMTPDebug = 0;

    /**
     * The SMTP connection.
     * @var resource
     */
    private $connection;

    /**
     * The last response.
     * @var string
     */
    private $lastResponse = '';

    /**
     * The last error.
     * @var string
     */
    private $lastError = '';

    /**
     * Whether connected.
     * @var bool
     */
    private $connected = false;

    /**
     * Set the SMTP host.
     * @param string $host
     * @return $this
     */
    public function setHost($host)
    {
        $this->Host = $host;
        return $this;
    }

    /**
     * Set the SMTP port.
     * @param int $port
     * @return $this
     */
    public function setPort($port)
    {
        $this->Port = $port;
        return $this;
    }

    /**
     * Set the SMTP username.
     * @param string $username
     * @return $this
     */
    public function setUsername($username)
    {
        $this->Username = $username;
        return $this;
    }

    /**
     * Set the SMTP password.
     * @param string $password
     * @return $this
     */
    public function setPassword($password)
    {
        $this->Password = $password;
        return $this;
    }

    /**
     * Set SMTP authentication.
     * @param bool $auth
     * @return $this
     */
    public function setSMTPAuth($auth)
    {
        $this->SMTPAuth = $auth;
        return $this;
    }

    /**
     * Set the SMTP security.
     * @param string $secure
     * @return $this
     */
    public function setSMTPSecure($secure)
    {
        $this->SMTPSecure = $secure;
        return $this;
    }

    /**
     * Set the SMTP debug level.
     * @param int $debug
     * @return $this
     */
    public function setSMTPDebug($debug)
    {
        $this->SMTPDebug = $debug;
        return $this;
    }

    /**
     * Connect to SMTP server.
     * @return bool
     */
    public function connect()
    {
        $this->debug("Connecting to {$this->Host}:{$this->Port}");
        
        $this->connection = @fsockopen($this->Host, $this->Port, $errno, $errstr, 30);
        
        if (!$this->connection) {
            $this->lastError = "Connection failed: $errno $errstr";
            $this->debug($this->lastError);
            return false;
        }

        $this->connected = true;
        $this->readResponse();
        
        if ($this->SMTPSecure === 'tls') {
            $this->debug("Starting TLS");
            $this->sendCommand("STARTTLS");
            if (!$this->readResponse()) {
                return false;
            }
            
            if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                $this->lastError = "TLS encryption failed";
                $this->debug($this->lastError);
                return false;
            }
            $this->debug("TLS encryption enabled");
        }

        return true;
    }

    /**
     * Authenticate with SMTP server.
     * @return bool
     */
    public function authenticate()
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Authenticating with username: {$this->Username}");
        
        $this->sendCommand("AUTH LOGIN");
        if (!$this->readResponse()) {
            return false;
        }

        $this->sendCommand(base64_encode($this->Username));
        if (!$this->readResponse()) {
            return false;
        }

        $this->sendCommand(base64_encode($this->Password));
        if (!$this->readResponse()) {
            return false;
        }

        return true;
    }

    /**
     * Send MAIL command.
     * @param string $from
     * @return bool
     */
    public function mail($from)
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Sending MAIL FROM: $from");
        $this->sendCommand("MAIL FROM:<$from>");
        return $this->readResponse();
    }

    /**
     * Send RCPT command.
     * @param string $to
     * @return bool
     */
    public function recipient($to)
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Sending RCPT TO: $to");
        $this->sendCommand("RCPT TO:<$to>");
        return $this->readResponse();
    }

    /**
     * Send DATA command.
     * @return bool
     */
    public function data()
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Sending DATA command");
        $this->sendCommand("DATA");
        return $this->readResponse();
    }

    /**
     * Send message data.
     * @param string $data
     * @return bool
     */
    public function send($data)
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Sending message data");
        fwrite($this->connection, $data . "\r\n.\r\n");
        return $this->readResponse();
    }

    /**
     * Send QUIT command.
     * @return bool
     */
    public function quit()
    {
        if (!$this->connected) {
            return false;
        }

        $this->debug("Sending QUIT command");
        $this->sendCommand("QUIT");
        $this->readResponse();
        
        fclose($this->connection);
        $this->connected = false;
        return true;
    }

    /**
     * Send command to SMTP server.
     * @param string $command
     * @return void
     */
    private function sendCommand($command)
    {
        fwrite($this->connection, $command . "\r\n");
        $this->debug("> $command");
    }

    /**
     * Read response from SMTP server.
     * @return bool
     */
    private function readResponse()
    {
        $response = '';
        while (($line = fgets($this->connection, 515)) !== false) {
            $response .= $line;
            $this->debug("< $line");
            
            if (substr($line, 3, 1) === ' ') {
                break;
            }
        }

        $this->lastResponse = $response;
        
        $code = (int)substr($response, 0, 3);
        if ($code >= 200 && $code < 400) {
            return true;
        } else {
            $this->lastError = "SMTP Error: $response";
            return false;
        }
    }

    /**
     * Debug output.
     * @param string $message
     * @return void
     */
    private function debug($message)
    {
        if ($this->SMTPDebug > 0) {
            echo date('Y-m-d H:i:s') . " SMTP: $message\n";
        }
    }

    /**
     * Get last error.
     * @return string
     */
    public function getLastError()
    {
        return $this->lastError;
    }

    /**
     * Get last response.
     * @return string
     */
    public function getLastResponse()
    {
        return $this->lastResponse;
    }
}
?>
