diff --git a/admin/post/settings_mail.php b/admin/post/settings_mail.php
index e515e75d..34d9dc0e 100644
--- a/admin/post/settings_mail.php
+++ b/admin/post/settings_mail.php
@@ -160,27 +160,128 @@ if (isset($_POST['test_email_smtp'])) {
}
if (isset($_POST['test_email_imap'])) {
-
+
validateCSRFToken($_POST['csrf_token']);
- // Setup your IMAP connection parameters
- $hostname = "{" . $config_imap_host . ":" . $config_imap_port . "/" . $config_imap_encryption . "/novalidate-cert}INBOX";
- $username = $config_imap_username;
- $password = $config_imap_password;
+ $host = $config_imap_host;
+ $port = (int) $config_imap_port;
+ $encryption = strtolower(trim($config_imap_encryption)); // e.g. "ssl", "tls", "none"
+ $username = $config_imap_username;
+ $password = $config_imap_password;
+
+ // Build remote socket (implicit SSL vs plain TCP)
+ $transport = 'tcp';
+ if ($encryption === 'ssl') {
+ $transport = 'ssl';
+ }
+
+ $remote_socket = $transport . '://' . $host . ':' . $port;
+
+ // Stream context (you can tighten these if you want strict validation)
+ $contextOptions = [];
+ if (in_array($encryption, ['ssl', 'tls'], true)) {
+ $contextOptions['ssl'] = [
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true,
+ ];
+ }
+
+ $context = stream_context_create($contextOptions);
try {
- $inbox = @imap_open($hostname, $username, $password);
+ $errno = 0;
+ $errstr = '';
- if ($inbox) {
- imap_close($inbox);
+ // 10-second timeout, adjust as needed
+ $fp = @stream_socket_client(
+ $remote_socket,
+ $errno,
+ $errstr,
+ 10,
+ STREAM_CLIENT_CONNECT,
+ $context
+ );
+
+ if (!$fp) {
+ throw new Exception("Could not connect to IMAP server: [$errno] $errstr");
+ }
+
+ stream_set_timeout($fp, 10);
+
+ // Read server greeting (IMAP servers send something like: * OK Dovecot ready)
+ $greeting = fgets($fp, 1024);
+ if ($greeting === false || strpos($greeting, '* OK') !== 0) {
+ fclose($fp);
+ throw new Exception("Invalid IMAP greeting: " . trim((string) $greeting));
+ }
+
+ // If you really want STARTTLS for "tls" (port 143), you can do it here
+ if ($encryption === 'tls' && stripos($greeting, 'STARTTLS') !== false) {
+ // Request STARTTLS
+ fwrite($fp, "A0001 STARTTLS\r\n");
+ $line = fgets($fp, 1024);
+ if ($line === false || stripos($line, 'A0001 OK') !== 0) {
+ fclose($fp);
+ throw new Exception("STARTTLS failed: " . trim((string) $line));
+ }
+
+ // Enable crypto on the stream
+ if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
+ fclose($fp);
+ throw new Exception("Unable to enable TLS encryption on IMAP connection.");
+ }
+ }
+
+ // --- Do LOGIN command ---
+ $tag = 'A0002';
+
+ // Simple quoting; this may fail with some special chars in username/password.
+ $loginCmd = sprintf(
+ "%s LOGIN \"%s\" \"%s\"\r\n",
+ $tag,
+ addcslashes($username, "\\\""),
+ addcslashes($password, "\\\"")
+ );
+
+ fwrite($fp, $loginCmd);
+
+ $success = false;
+ $errorLine = '';
+
+ while (!feof($fp)) {
+ $line = fgets($fp, 2048);
+ if ($line === false) {
+ break;
+ }
+
+ // Look for tagged response for our LOGIN
+ if (strpos($line, $tag . ' ') === 0) {
+ if (stripos($line, $tag . ' OK') === 0) {
+ $success = true;
+ } else {
+ $errorLine = trim($line);
+ }
+ break;
+ }
+ }
+
+ // Always logout / close
+ fwrite($fp, "A0003 LOGOUT\r\n");
+ fclose($fp);
+
+ if ($success) {
flash_alert("Connected successfully");
} else {
- throw new Exception(imap_last_error());
+ if (!$errorLine) {
+ $errorLine = 'Unknown IMAP authentication error';
+ }
+ throw new Exception($errorLine);
}
+
} catch (Exception $e) {
- flash_alert("IMAP connection failed: " . $e->getMessage(), 'error');
+ flash_alert("IMAP connection failed: " . htmlspecialchars($e->getMessage()), 'error');
}
redirect();
-
}