From 3b55da7ba60bafaae5b20e0e39a3d6304001d08a Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Mon, 16 Jun 2014 14:13:58 +0200 Subject: Add config option to specify IMAP connection socket parameters - imap_conn_options (#1489948) Conflicts: CHANGELOG --- program/lib/Roundcube/rcube.php | 19 +-- program/lib/Roundcube/rcube_imap.php | 12 +- program/lib/Roundcube/rcube_imap_generic.php | 181 +++++++++++++++------------ 3 files changed, 119 insertions(+), 93 deletions(-) (limited to 'program') diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php index 87103be93..8f39c7a70 100644 --- a/program/lib/Roundcube/rcube.php +++ b/program/lib/Roundcube/rcube.php @@ -373,15 +373,16 @@ class rcube // set class options $options = array( - 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'), - 'auth_cid' => $this->config->get("{$driver}_auth_cid"), - 'auth_pw' => $this->config->get("{$driver}_auth_pw"), - 'debug' => (bool) $this->config->get("{$driver}_debug"), - 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), - 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"), - 'timeout' => (int) $this->config->get("{$driver}_timeout"), - 'skip_deleted' => (bool) $this->config->get('skip_deleted'), - 'driver' => $driver, + 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'), + 'auth_cid' => $this->config->get("{$driver}_auth_cid"), + 'auth_pw' => $this->config->get("{$driver}_auth_pw"), + 'debug' => (bool) $this->config->get("{$driver}_debug"), + 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"), + 'disabled_caps' => $this->config->get("{$driver}_disabled_caps"), + 'socket_options' => $this->config->get("{$driver}_conn_options"), + 'timeout' => (int) $this->config->get("{$driver}_timeout"), + 'skip_deleted' => (bool) $this->config->get('skip_deleted'), + 'driver' => $driver, ); if (!empty($_SESSION['storage_host'])) { diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index 18cf46d58..83fdab9e2 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -110,13 +110,13 @@ class rcube_imap extends rcube_storage /** * Connect to an IMAP server * - * @param string $host Host to connect - * @param string $user Username for IMAP account - * @param string $pass Password for IMAP account - * @param integer $port Port to connect to - * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection + * @param string $host Host to connect + * @param string $user Username for IMAP account + * @param string $pass Password for IMAP account + * @param integer $port Port to connect to + * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection * - * @return boolean TRUE on success, FALSE on failure + * @return boolean True on success, False on failure */ public function connect($host, $user, $pass, $port=143, $use_ssl=null) { diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index 08d220bcd..4809c8b11 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -723,110 +723,38 @@ class rcube_imap_generic // configure $this->set_prefs($options); - $auth_method = $this->prefs['auth_type']; - $result = false; - - // initialize connection - $this->error = ''; - $this->errornum = self::ERROR_OK; - $this->selected = null; - $this->user = $user; $this->host = $host; + $this->user = $user; $this->logged = false; + $this->selected = null; // check input if (empty($host)) { $this->setError(self::ERROR_BAD, "Empty host"); return false; } + if (empty($user)) { $this->setError(self::ERROR_NO, "Empty user"); return false; } + if (empty($password)) { $this->setError(self::ERROR_NO, "Empty password"); return false; } - if (!$this->prefs['port']) { - $this->prefs['port'] = 143; - } - // check for SSL - if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { - $host = $this->prefs['ssl_mode'] . '://' . $host; - } - - if ($this->prefs['timeout'] <= 0) { - $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); - } - // Connect - $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); - - if (!$this->fp) { - if (!$errstr) { - $errstr = "Unknown reason (fsockopen() function disabled?)"; - } - $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr)); - return false; - } - - if ($this->prefs['timeout'] > 0) { - stream_set_timeout($this->fp, $this->prefs['timeout']); - } - - $line = trim(fgets($this->fp, 8192)); - - if ($this->_debug) { - // set connection identifier for debug output - preg_match('/#([0-9]+)/', (string)$this->fp, $m); - $this->resourceid = strtoupper(substr(md5($m[1].$this->user.microtime()), 0, 4)); - - if ($line) - $this->debug('S: '. $line); - } - - // Connected to wrong port or connection error? - if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { - if ($line) - $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); - else - $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); - - $this->setError(self::ERROR_BAD, $error); - $this->closeConnection(); + if (!$this->_connect($host)) { return false; } - // RFC3501 [7.1] optional CAPABILITY response - if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { - $this->parseCapability($matches[1], true); - } - - // TLS connection - if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { - $res = $this->execute('STARTTLS'); - - if ($res[0] != self::ERROR_OK) { - $this->closeConnection(); - return false; - } - - if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { - $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); - $this->closeConnection(); - return false; - } - - // Now we're secure, capabilities need to be reread - $this->clearCapability(); - } - // Send ID info if (!empty($this->prefs['ident']) && $this->getCapability('ID')) { $this->id($this->prefs['ident']); } + $auth_method = $this->prefs['auth_type']; $auth_methods = array(); $result = null; @@ -900,6 +828,103 @@ class rcube_imap_generic return false; } + /** + * Connects to IMAP server. + * + * @param string $host Server hostname or IP + * + * @return bool True on success, False on failure + */ + protected function _connect($host) + { + // initialize connection + $this->error = ''; + $this->errornum = self::ERROR_OK; + + if (!$this->prefs['port']) { + $this->prefs['port'] = 143; + } + + // check for SSL + if ($this->prefs['ssl_mode'] && $this->prefs['ssl_mode'] != 'tls') { + $host = $this->prefs['ssl_mode'] . '://' . $host; + } + + if ($this->prefs['timeout'] <= 0) { + $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); + } + + if (!empty($this->prefs['socket_options'])) { + $context = stream_context_create($this->prefs['socket_options']); + $this->fp = stream_socket_client($host . ':' . $this->prefs['port'], $errno, $errstr, + $this->prefs['timeout'], STREAM_CLIENT_CONNECT, $context); + } + else { + $this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']); + } + + if (!$this->fp) { + $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", + $host, $this->prefs['port'], $errstr ?: "Unknown reason")); + + return false; + } + + if ($this->prefs['timeout'] > 0) { + stream_set_timeout($this->fp, $this->prefs['timeout']); + } + + $line = trim(fgets($this->fp, 8192)); + + if ($this->_debug) { + // set connection identifier for debug output + preg_match('/#([0-9]+)/', (string) $this->fp, $m); + $this->resourceid = strtoupper(substr(md5($m[1].$this->user.microtime()), 0, 4)); + + if ($line) { + $this->debug('S: '. $line); + } + } + + // Connected to wrong port or connection error? + if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { + if ($line) + $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $this->prefs['port'], $line); + else + $error = sprintf("Empty startup greeting (%s:%d)", $host, $this->prefs['port']); + + $this->setError(self::ERROR_BAD, $error); + $this->closeConnection(); + return false; + } + + // RFC3501 [7.1] optional CAPABILITY response + if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { + $this->parseCapability($matches[1], true); + } + + // TLS connection + if ($this->prefs['ssl_mode'] == 'tls' && $this->getCapability('STARTTLS')) { + $res = $this->execute('STARTTLS'); + + if ($res[0] != self::ERROR_OK) { + $this->closeConnection(); + return false; + } + + if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); + $this->closeConnection(); + return false; + } + + // Now we're secure, capabilities need to be reread + $this->clearCapability(); + } + + return true; + } + /** * Initializes environment */ -- cgit v1.2.3