public function connect($host = null, $port = null, $context = null, $secure = null)
{
if (isset($host)) {
$this->_params['host'] = $host;
}
if (isset($port)) {
$this->_params['port'] = $port;
}
if (isset($context)) {
$this->_params['context'] = array_merge_recursive($this->_params['context'], $context);
}
if (isset($secure)) {
$this->_params['secure'] = $secure;
}
if (self::STATE_DISCONNECTED != $this->_state) {
throw new Exception\NotDisconnected();
}
try {
$this->_sock = new Client($this->_params['host'], $this->_params['port'], $this->_params['timeout'], $this->_params['secure'], $this->_params['context']);
} catch (Client\Exception $e) {
throw new Exception\ConnectionFailed($e);
}
if ($this->_params['bypassauth']) {
$this->_state = self::STATE_AUTHENTICATED;
} else {
$this->_state = self::STATE_NON_AUTHENTICATED;
$this->_doCmd();
}
// Explicitly ask for the capabilities in case the connection is
// picked up from an existing connection.
try {
$this->_cmdCapability();
} catch (Exception $e) {
throw new Exception\ConnectionFailed($e);
}
// Check if we can enable TLS via STARTTLS.
if ($this->_params['secure'] === 'tls' || $this->_params['secure'] === true && !empty($this->_capability['starttls'])) {
$this->_doCmd('STARTTLS');
if (!$this->_sock->startTls()) {
throw new Exception('Failed to establish TLS connection');
}
// The server should be sending a CAPABILITY response after
// negotiating TLS. Read it, and ignore if it doesn't.
// Unfortunately old Cyrus versions are broken and don't send a
// CAPABILITY response, thus we would wait here forever. Parse the
// Cyrus version and work around this broken behavior.
if (!preg_match('/^CYRUS TIMSIEVED V([0-9.]+)/', $this->_capability['implementation'], $matches) || version_compare($matches[1], '2.3.10', '>=')) {
$this->_doCmd();
}
// Query the server capabilities again now that we are under
// encryption.
try {
$this->_cmdCapability();
} catch (Exception $e) {
throw new Exception\ConnectionFailed($e);
}
}
}