function login($username, $password, $host, $sm_caps = array(), &$errno, &$errmsg)
 {
     if (!isset($this->capability)) {
         $aCaps = $this->capability($sm_caps);
     } else {
         $aCaps = $this->capability;
     }
     /* supported authentication methods */
     $aAuth = array('CRAM-MD5' => false, 'DIGEST-MD5' => false);
     //,'PLAIN'=>false);
     $aResult = false;
     /* get the authentication methods */
     foreach ($aCaps as $key => $value) {
         if (substr($key, 0, 5) == 'AUTH=') {
             $aAuth[substr($key, 5)] = true;
         }
     }
     /* start with the save authentication methods */
     switch ($aAuth) {
         case $aAuth['DIGEST-MD5']:
             $query = "AUTHENTICATE DIGEST-MD5";
             $sTag = $this->sqimap_run_command($query);
             /* we expect a command continuation request with challenge*/
             $aRes = explode(' ', $this->_sqimap_process_stream($sTag));
             $challenge = $aRes[0];
             /* create the digest-md5 response */
             $reply = digest_md5_response($username, $password, $challenge, 'imap', $host);
             fputs($this->resource, $reply);
             /* we expect a command continuation request */
             $this->_sqimap_process_stream($sTag);
             /* need testing !! probably just check for the OK response */
             $aresult = $this->_sqimap_process_stream($sTag);
             if ($aResult['RESPONSE'] == 'OK') {
                 break;
             }
         case $aAuth['CRAM-MD5']:
             $query = "AUTHENTICATE CRAM-MD5";
             $sTag = $this->sqimap_run_command($query);
             /* we expect a command continuation request with challenge*/
             $aRes = explode(' ', $this->_sqimap_process_stream($sTag));
             $challenge = $aRes[0];
             /* create the cram-md5 reply */
             $reply = cram_md5_response($username, $password, $challenge, 'imap', $host);
             fputs($this->resource, $reply);
             /* need testing !! probably just check for the OK response */
             $aResult = $this->_sqimap_process_stream($sTag);
             if ($aResult['RESPONSE'] == 'OK') {
                 break;
             }
             //case $aAuth['PLAIN']:
         //case $aAuth['PLAIN']:
         default:
             if (isset($aCaps['LOGINDISABLED']) && $aCaps['LOGINDISABLED']) {
                 /* we need to do a STARTTLS which isn't supported on a normal socket */
                 /* error handling */
                 $errmsg = _("Notify your system administrator, no authentication mechanism found");
                 $errno = 0;
                 /* TODO fatal error */
                 return false;
             } else {
                 /* use normal login */
                 /* escaping  ??? */
                 $user = ereg_replace('(["\\])', '\\\\1', $username);
                 $pass = ereg_replace('(["\\])', '\\\\1', $password);
                 $query = 'LOGIN "' . $user . '" "' . $pass . '"';
                 $sTag = $this->sqimap_run_command($query);
                 $aResult = $this->_sqimap_process_stream($sTag);
             }
             break;
     }
     if ($aResult['RESPONSE'] == 'OK') {
         return $aResult;
     } else {
         /* error handling */
         if ($aResult) {
             $errmsg = $aResult['MESSAGE'];
             /* optional, check response for NO, BAD or BYE */
             $errno = 0;
             /* TODO */
         } else {
             /* something went terrible wrong, notify the user */
             /* TODO */
             /* optionally try to initiate a tls connection if PHP version > 4.3 */
             /* reconnect and call $this->login again from here and return the result */
         }
     }
     return false;
 }
function sqimap_login($username, $password, $imap_server_address, $imap_port, $hide)
{
    global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech;
    if (!isset($onetimepad) || empty($onetimepad)) {
        sqgetglobalvar('onetimepad', $onetimepad, SQ_SESSION);
    }
    $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
    $host = $imap_server_address;
    if ($use_imap_tls == true and check_php_version(4, 3) and extension_loaded('openssl')) {
        /* Use TLS by prefixing "tls://" to the hostname */
        $imap_server_address = 'tls://' . $imap_server_address;
    }
    $imap_stream = fsockopen($imap_server_address, $imap_port, $error_number, $error_string, 15);
    /* Do some error correction */
    if (!$imap_stream) {
        if (!$hide) {
            set_up_language($squirrelmail_language, true);
            require_once SM_PATH . 'functions/display_messages.php';
            $string = sprintf(_("Error connecting to IMAP server: %s.") . "<br>\r\n", $imap_server_address) . "{$error_number} : {$error_string}<br>\r\n";
            logout_error($string, $color);
        }
        exit;
    }
    $server_info = fgets($imap_stream, 1024);
    /* Decrypt the password */
    $password = OneTimePadDecrypt($password, $onetimepad);
    if ($imap_auth_mech == 'cram-md5' or $imap_auth_mech == 'digest-md5') {
        // We're using some sort of authentication OTHER than plain or login
        $tag = sqimap_session_id(false);
        if ($imap_auth_mech == 'digest-md5') {
            $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
        } elseif ($imap_auth_mech == 'cram-md5') {
            $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
        }
        fputs($imap_stream, $query);
        $answer = sqimap_fgets($imap_stream);
        // Trim the "+ " off the front
        $response = explode(" ", $answer, 3);
        if ($response[0] == '+') {
            // Got a challenge back
            $challenge = $response[1];
            if ($imap_auth_mech == 'digest-md5') {
                $reply = digest_md5_response($username, $password, $challenge, 'imap', $host);
            } elseif ($imap_auth_mech == 'cram-md5') {
                $reply = cram_md5_response($username, $password, $challenge);
            }
            fputs($imap_stream, $reply);
            $read = sqimap_fgets($imap_stream);
            if ($imap_auth_mech == 'digest-md5') {
                // DIGEST-MD5 has an extra step..
                if (substr($read, 0, 1) == '+') {
                    // OK so far..
                    fputs($imap_stream, "\r\n");
                    $read = sqimap_fgets($imap_stream);
                }
            }
            $results = explode(" ", $read, 3);
            $response = $results[1];
            $message = $results[2];
        } else {
            // Fake the response, so the error trap at the bottom will work
            $response = "BAD";
            $message = 'IMAP server does not appear to support the authentication method selected.';
            $message .= '  Please contact your system administrator.';
        }
    } elseif ($imap_auth_mech == 'login') {
        // Original IMAP login code
        $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
        $read = sqimap_run_command($imap_stream, $query, false, $response, $message);
    } elseif ($imap_auth_mech == 'plain') {
        /* Replace this with SASL PLAIN if it ever gets implemented */
        $response = "BAD";
        $message = 'SquirrelMail does not support SASL PLAIN yet. Rerun conf.pl and use login instead.';
    } else {
        $response = "BAD";
        $message = "Internal SquirrelMail error - unknown IMAP authentication method chosen.  Please contact the developers.";
    }
    /* If the connection was not successful, lets see why */
    if ($response != 'OK') {
        if (!$hide) {
            if ($response != 'NO') {
                /* "BAD" and anything else gets reported here. */
                $message = htmlspecialchars($message);
                set_up_language($squirrelmail_language, true);
                require_once SM_PATH . 'functions/display_messages.php';
                if ($response == 'BAD') {
                    $string = sprintf(_("Bad request: %s") . "<br>\r\n", $message);
                } else {
                    $string = sprintf(_("Unknown error: %s") . "<br>\n", $message);
                }
                if (isset($read) && is_array($read)) {
                    $string .= '<br>' . _("Read data:") . "<br>\n";
                    foreach ($read as $line) {
                        $string .= htmlspecialchars($line) . "<br>\n";
                    }
                }
                error_box($string, $color);
                exit;
            } else {
                /*
                 * If the user does not log in with the correct
                 * username and password it is not possible to get the
                 * correct locale from the user's preferences.
                 * Therefore, apply the same hack as on the login
                 * screen.
                 *
                 * $squirrelmail_language is set by a cookie when
                 * the user selects language and logs out
                 */
                set_up_language($squirrelmail_language, true);
                include_once SM_PATH . 'functions/display_messages.php';
                sqsession_destroy();
                logout_error(_("Unknown user or password incorrect."));
                exit;
            }
        } else {
            exit;
        }
    }
    return $imap_stream;
}
 function initStream($message, $domain, $length = 0, $host = '', $port = '', $user = '', $pass = '', $authpop = false)
 {
     global $use_smtp_tls, $smtp_auth_mech, $username, $key, $onetimepad;
     if ($authpop) {
         $this->authPop($host, '', $username, $pass);
     }
     $rfc822_header = $message->rfc822_header;
     $from = $rfc822_header->from[0];
     $to = $rfc822_header->to;
     $cc = $rfc822_header->cc;
     $bcc = $rfc822_header->bcc;
     if ($use_smtp_tls == true and check_php_version(4, 3) and extension_loaded('openssl')) {
         $stream = fsockopen('tls://' . $host, $port, $errorNumber, $errorString);
     } else {
         $stream = fsockopen($host, $port, $errorNumber, $errorString);
     }
     if (!$stream) {
         $this->dlv_msg = $errorString;
         $this->dlv_ret_nr = $errorNumber;
         return 0;
     }
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /* If $_SERVER['HTTP_HOST'] is set, use that in our HELO to the SMTP
        server.  This should fix the DNS issues some people have had */
     if (sqgetGlobalVar('HTTP_HOST', $HTTP_HOST, SQ_SERVER)) {
         // HTTP_HOST is set
         $helohost = $HTTP_HOST;
     } else {
         // For some reason, HTTP_HOST is not set - revert to old behavior
         $helohost = $domain;
     }
     /* Lets introduce ourselves */
     if ($smtp_auth_mech == 'cram-md5' or $smtp_auth_mech == 'digest-md5') {
         // Doing some form of non-plain auth
         fputs($stream, "EHLO {$helohost}\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         if ($smtp_auth_mech == 'cram-md5') {
             fputs($stream, "AUTH CRAM-MD5\r\n");
         } elseif ($smtp_auth_mech == 'digest-md5') {
             fputs($stream, "AUTH DIGEST-MD5\r\n");
         }
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         // At this point, $tmp should hold "334 <challenge string>"
         $chall = substr($tmp, 4);
         // Depending on mechanism, generate response string
         if ($smtp_auth_mech == 'cram-md5') {
             $response = cram_md5_response($username, $pass, $chall);
         } elseif ($smtp_auth_mech == 'digest-md5') {
             $response = digest_md5_response($username, $pass, $chall, 'smtp', $host);
         }
         fputs($stream, $response);
         // Let's see what the server had to say about that
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         // CRAM-MD5 is done at this point.  If DIGEST-MD5, there's a bit more to go
         if ($smtp_auth_mech == 'digest-md5') {
             // $tmp contains rspauth, but I don't store that yet. (No need yet)
             fputs($stream, "\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
         // CRAM-MD5 and DIGEST-MD5 code ends here
     } elseif ($smtp_auth_mech == 'none') {
         // No auth at all, just send helo and then send the mail
         fputs($stream, "HELO {$helohost}\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
     } elseif ($smtp_auth_mech == 'login') {
         // The LOGIN method
         fputs($stream, "EHLO {$helohost}\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         fputs($stream, "AUTH LOGIN\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         fputs($stream, base64_encode($username) . "\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         fputs($stream, base64_encode($pass) . "\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
     } else {
         /* Right here, they've reached an unsupported auth mechanism.
            This is the ugliest hack I've ever done, but it'll do till I can fix
            things up better tomorrow.  So tired... */
         if ($this->errorCheck("535 Unable to use this auth type", $stream)) {
             return 0;
         }
     }
     /* Ok, who is sending the message? */
     fputs($stream, 'MAIL FROM: <' . $from->mailbox . '@' . $from->host . ">\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /* send who the recipients are */
     for ($i = 0, $cnt = count($to); $i < $cnt; $i++) {
         if (!$to[$i]->host) {
             $to[$i]->host = $domain;
         }
         if ($to[$i]->mailbox) {
             fputs($stream, 'RCPT TO: <' . $to[$i]->mailbox . '@' . $to[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) {
         if (!$cc[$i]->host) {
             $cc[$i]->host = $domain;
         }
         if ($cc[$i]->mailbox) {
             fputs($stream, 'RCPT TO: <' . $cc[$i]->mailbox . '@' . $cc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) {
         if (!$bcc[$i]->host) {
             $bcc[$i]->host = $domain;
         }
         if ($bcc[$i]->mailbox) {
             fputs($stream, 'RCPT TO: <' . $bcc[$i]->mailbox . '@' . $bcc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     /* Lets start sending the actual message */
     fputs($stream, "DATA\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     return $stream;
 }
 function initStream($message, $domain, $length = 0, $host = '', $port = '', $user = '', $pass = '', $authpop = false, $pop_host = '', $stream_options = array())
 {
     global $use_smtp_tls, $smtp_auth_mech;
     if ($authpop) {
         $this->authPop($pop_host, '', $user, $pass);
     }
     $rfc822_header = $message->rfc822_header;
     $from = $rfc822_header->from[0];
     $to = $rfc822_header->to;
     $cc = $rfc822_header->cc;
     $bcc = $rfc822_header->bcc;
     $content_type = $rfc822_header->content_type;
     // MAIL FROM: <from address> MUST be empty in cae of MDN (RFC2298)
     if ($content_type->type0 == 'multipart' && $content_type->type1 == 'report' && isset($content_type->properties['report-type']) && $content_type->properties['report-type'] == 'disposition-notification') {
         // reinitialize the from object because otherwise the from header somehow
         // is affected. This $from var is used for smtp command MAIL FROM which
         // is not the same as what we put in the rfc822 header.
         $from = new AddressStructure();
         $from->host = '';
         $from->mailbox = '';
     }
     // NB: Using "ssl://" ensures the highest possible TLS version
     // will be negotiated with the server (whereas "tls://" only
     // uses TLS version 1.0)
     //
     if ($use_smtp_tls == 1) {
         if (check_php_version(4, 3) && extension_loaded('openssl')) {
             if (function_exists('stream_socket_client')) {
                 $server_address = 'ssl://' . $host . ':' . $port;
                 $ssl_context = @stream_context_create($stream_options);
                 $connect_timeout = ini_get('default_socket_timeout');
                 // null timeout is broken
                 if ($connect_timeout == 0) {
                     $connect_timeout = 30;
                 }
                 $stream = @stream_socket_client($server_address, $errorNumber, $errorString, $connect_timeout, STREAM_CLIENT_CONNECT, $ssl_context);
             } else {
                 $stream = @fsockopen('ssl://' . $host, $port, $errorNumber, $errorString);
             }
             $this->tls_enabled = true;
         } else {
             /**
              * don't connect to server when user asks for smtps and 
              * PHP does not support it.
              */
             $errorNumber = '';
             $errorString = _("Secure SMTP (TLS) is enabled in SquirrelMail configuration, but used PHP version does not support it.");
         }
     } else {
         $stream = @fsockopen($host, $port, $errorNumber, $errorString);
     }
     if (!$stream) {
         // reset tls state var to default value, if connection fails
         $this->tls_enabled = false;
         // set error messages
         $this->dlv_msg = $errorString;
         $this->dlv_ret_nr = $errorNumber;
         $this->dlv_server_msg = _("Can't open SMTP stream.");
         return 0;
     }
     // get server greeting
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /*
      * If $_SERVER['HTTP_HOST'] is set, use that in our HELO to the SMTP
      * server.  This should fix the DNS issues some people have had
      */
     if (sqgetGlobalVar('HTTP_HOST', $HTTP_HOST, SQ_SERVER)) {
         // HTTP_HOST is set
         // optionally trim off port number
         if ($p = strrpos($HTTP_HOST, ':')) {
             $HTTP_HOST = substr($HTTP_HOST, 0, $p);
         }
         $helohost = $HTTP_HOST;
     } else {
         // For some reason, HTTP_HOST is not set - revert to old behavior
         $helohost = $domain;
     }
     // if the host is an IPv4 address, enclose it in brackets
     //
     if (preg_match('/^\\d+\\.\\d+\\.\\d+\\.\\d+$/', $helohost)) {
         $helohost = '[' . $helohost . ']';
     }
     $hook_result = do_hook('smtp_helo_override', $helohost);
     if (!empty($hook_result)) {
         $helohost = $hook_result;
     }
     /* Lets introduce ourselves */
     fputs($stream, "EHLO {$helohost}\r\n");
     // Read ehlo response
     $tmp = $this->parse_ehlo_response($stream);
     if ($this->errorCheck($tmp, $stream)) {
         // fall back to HELO if EHLO is not supported (error 5xx)
         if ($this->dlv_ret_nr[0] == '5') {
             fputs($stream, "HELO {$helohost}\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         } else {
             return 0;
         }
     }
     /**
      * Implementing SMTP STARTTLS (rfc2487) in php 5.1.0+
      * http://www.php.net/stream-socket-enable-crypto
      */
     if ($use_smtp_tls === 2) {
         if (function_exists('stream_socket_enable_crypto')) {
             // don't try starting tls, when client thinks that it is already active
             if ($this->tls_enabled) {
                 $this->dlv_msg = _("TLS session is already activated.");
                 return 0;
             } elseif (!array_key_exists('STARTTLS', $this->ehlo)) {
                 // check for starttls in ehlo response
                 $this->dlv_msg = _("SMTP STARTTLS is enabled in SquirrelMail configuration, but used SMTP server does not support it");
                 return 0;
             }
             // issue starttls command
             fputs($stream, "STARTTLS\r\n");
             // get response
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
             // start crypto on connection. suppress function errors.
             if (@stream_socket_enable_crypto($stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                 // starttls was successful (rfc2487 5.2 Result of the STARTTLS Command)
                 // get new EHLO response
                 fputs($stream, "EHLO {$helohost}\r\n");
                 // Read ehlo response
                 $tmp = $this->parse_ehlo_response($stream);
                 if ($this->errorCheck($tmp, $stream)) {
                     // don't revert to helo here. server must support ESMTP
                     return 0;
                 }
                 // set information about started tls
                 $this->tls_enabled = true;
             } else {
                 /**
                  * stream_socket_enable_crypto() call failed.
                  */
                 $this->dlv_msg = _("Unable to start TLS.");
                 return 0;
                 // Bug: can't get error message. See comments in sqimap_create_stream().
             }
         } else {
             // php install does not support stream_socket_enable_crypto() function
             $this->dlv_msg = _("SMTP STARTTLS is enabled in SquirrelMail configuration, but used PHP version does not support functions that allow to enable encryption on open socket.");
             return 0;
         }
     }
     // FIXME: check ehlo response before using authentication
     // Try authentication by a plugin
     //
     // NOTE: there is another hook in functions/auth.php called "smtp_auth"
     // that allows a plugin to specify a different set of login credentials
     // (so is slightly mis-named, but is too old to change), so be careful
     // that you do not confuse your hook names.
     //
     $smtp_auth_args = array('auth_mech' => $smtp_auth_mech, 'user' => $user, 'pass' => $pass, 'host' => $host, 'port' => $port, 'stream' => $stream);
     if (boolean_hook_function('smtp_authenticate', $smtp_auth_args, 1)) {
         // authentication succeeded
     } else {
         if ($smtp_auth_mech == 'cram-md5' or $smtp_auth_mech == 'digest-md5') {
             // Doing some form of non-plain auth
             if ($smtp_auth_mech == 'cram-md5') {
                 fputs($stream, "AUTH CRAM-MD5\r\n");
             } elseif ($smtp_auth_mech == 'digest-md5') {
                 fputs($stream, "AUTH DIGEST-MD5\r\n");
             }
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
             // At this point, $tmp should hold "334 <challenge string>"
             $chall = substr($tmp, 4);
             // Depending on mechanism, generate response string
             if ($smtp_auth_mech == 'cram-md5') {
                 $response = cram_md5_response($user, $pass, $chall);
             } elseif ($smtp_auth_mech == 'digest-md5') {
                 $response = digest_md5_response($user, $pass, $chall, 'smtp', $host);
             }
             fputs($stream, $response);
             // Let's see what the server had to say about that
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
             // CRAM-MD5 is done at this point.  If DIGEST-MD5, there's a bit more to go
             if ($smtp_auth_mech == 'digest-md5') {
                 // $tmp contains rspauth, but I don't store that yet. (No need yet)
                 fputs($stream, "\r\n");
                 $tmp = fgets($stream, 1024);
                 if ($this->errorCheck($tmp, $stream)) {
                     return 0;
                 }
             }
             // CRAM-MD5 and DIGEST-MD5 code ends here
         } elseif ($smtp_auth_mech == 'none') {
             // No auth at all, just send helo and then send the mail
             // We already said hi earlier, nothing more is needed.
         } elseif ($smtp_auth_mech == 'login') {
             // The LOGIN method
             fputs($stream, "AUTH LOGIN\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
             fputs($stream, base64_encode($user) . "\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
             fputs($stream, base64_encode($pass) . "\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         } elseif ($smtp_auth_mech == "plain") {
             /* SASL Plain */
             $auth = base64_encode("{$user}{$user}{$pass}");
             $query = "AUTH PLAIN\r\n";
             fputs($stream, $query);
             $read = fgets($stream, 1024);
             if (substr($read, 0, 3) == '334') {
                 // OK so far..
                 fputs($stream, "{$auth}\r\n");
                 $read = fgets($stream, 1024);
             }
             $results = explode(" ", $read, 3);
             $response = $results[1];
             $message = $results[2];
         } else {
             /* Right here, they've reached an unsupported auth mechanism.
                This is the ugliest hack I've ever done, but it'll do till I can fix
                things up better tomorrow.  So tired... */
             if ($this->errorCheck("535 Unable to use this auth type", $stream)) {
                 return 0;
             }
         }
     }
     /* Ok, who is sending the message? */
     $fromaddress = strlen($from->mailbox) && $from->host ? $from->mailbox . '@' . $from->host : '';
     fputs($stream, 'MAIL FROM:<' . $fromaddress . ">\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /* send who the recipients are */
     for ($i = 0, $cnt = count($to); $i < $cnt; $i++) {
         if (!$to[$i]->host) {
             $to[$i]->host = $domain;
         }
         if (strlen($to[$i]->mailbox)) {
             fputs($stream, 'RCPT TO:<' . $to[$i]->mailbox . '@' . $to[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) {
         if (!$cc[$i]->host) {
             $cc[$i]->host = $domain;
         }
         if (strlen($cc[$i]->mailbox)) {
             fputs($stream, 'RCPT TO:<' . $cc[$i]->mailbox . '@' . $cc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) {
         if (!$bcc[$i]->host) {
             $bcc[$i]->host = $domain;
         }
         if (strlen($bcc[$i]->mailbox)) {
             fputs($stream, 'RCPT TO:<' . $bcc[$i]->mailbox . '@' . $bcc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     /* Lets start sending the actual message */
     fputs($stream, "DATA\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     return $stream;
 }
/**
 * Logs the user into the imap server.  If $hide is set, no error messages
 * will be displayed.  This function returns the imap connection handle.
 */
function sqimap_login($username, $password, $imap_server_address, $imap_port, $hide)
{
    global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech, $sqimap_capabilities;
    if (!isset($onetimepad) || empty($onetimepad)) {
        sqgetglobalvar('onetimepad', $onetimepad, SQ_SESSION);
    }
    if (!isset($sqimap_capabilities)) {
        sqgetglobalvar('sqimap_capabilities', $capability, SQ_SESSION);
    }
    $host = $imap_server_address;
    $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
    $imap_stream = sqimap_create_stream($imap_server_address, $imap_port, $use_imap_tls);
    /* Decrypt the password */
    //$password = OneTimePadDecrypt($password, $onetimepad);
    if ($imap_auth_mech == 'cram-md5' or $imap_auth_mech == 'digest-md5') {
        // We're using some sort of authentication OTHER than plain or login
        $tag = sqimap_session_id(false);
        if ($imap_auth_mech == 'digest-md5') {
            $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
        } elseif ($imap_auth_mech == 'cram-md5') {
            $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
        }
        fputs($imap_stream, $query);
        $answer = sqimap_fgets($imap_stream);
        // Trim the "+ " off the front
        $response = explode(" ", $answer, 3);
        if ($response[0] == '+') {
            // Got a challenge back
            $challenge = $response[1];
            if ($imap_auth_mech == 'digest-md5') {
                $reply = digest_md5_response($username, $password, $challenge, 'imap', $host);
            } elseif ($imap_auth_mech == 'cram-md5') {
                $reply = cram_md5_response($username, $password, $challenge);
            }
            fputs($imap_stream, $reply);
            $read = sqimap_fgets($imap_stream);
            if ($imap_auth_mech == 'digest-md5') {
                // DIGEST-MD5 has an extra step..
                if (substr($read, 0, 1) == '+') {
                    // OK so far..
                    fputs($imap_stream, "\r\n");
                    $read = sqimap_fgets($imap_stream);
                }
            }
            $results = explode(" ", $read, 3);
            $response = $results[1];
            $message = $results[2];
        } else {
            // Fake the response, so the error trap at the bottom will work
            $response = "BAD";
            $message = 'IMAP server does not appear to support the authentication method selected.';
            $message .= '  Please contact your system administrator.';
        }
    } elseif ($imap_auth_mech == 'login') {
        // Original IMAP login code
        $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
        $read = sqimap_run_command($imap_stream, $query, false, $response, $message);
    } elseif ($imap_auth_mech == 'plain') {
        /***
         * SASL PLAIN
         *
         *  RFC 2595 Chapter 6
         *
         *  The mechanism consists of a single message from the client to the
         *  server.  The client sends the authorization identity (identity to
         *  login as), followed by a US-ASCII NUL character, followed by the
         *  authentication identity (identity whose password will be used),
         *  followed by a US-ASCII NUL character, followed by the clear-text
         *  password.  The client may leave the authorization identity empty to
         *  indicate that it is the same as the authentication identity.
         *
         **/
        $tag = sqimap_session_id(false);
        $sasl = isset($capability['SASL-IR']) && $capability['SASL-IR'] ? true : false;
        $auth = base64_encode("{$username}{$username}{$password}");
        if ($sasl) {
            // IMAP Extension for SASL Initial Client Response
            // <draft-siemborski-imap-sasl-initial-response-01b.txt>
            $query = $tag . " AUTHENTICATE PLAIN {$auth}\r\n";
            fputs($imap_stream, $query);
            $read = sqimap_fgets($imap_stream);
        } else {
            $query = $tag . " AUTHENTICATE PLAIN\r\n";
            fputs($imap_stream, $query);
            $read = sqimap_fgets($imap_stream);
            if (substr($read, 0, 1) == '+') {
                // OK so far..
                fputs($imap_stream, "{$auth}\r\n");
                $read = sqimap_fgets($imap_stream);
            }
        }
        $results = explode(" ", $read, 3);
        $response = $results[1];
        $message = $results[2];
    } else {
        $response = "BAD";
        $message = "Internal SquirrelMail error - unknown IMAP authentication method chosen.  Please contact the developers.";
    }
    /* If the connection was not successful, lets see why */
    if ($response != 'OK') {
        if (!$hide) {
            if ($response != 'NO') {
                /* "BAD" and anything else gets reported here. */
                $message = htmlspecialchars($message);
                set_up_language($squirrelmail_language, true);
                require_once SM_PATH . 'functions/display_messages.php';
                if ($response == 'BAD') {
                    $string = sprintf(_("Bad request: %s") . "<br />\r\n", $message);
                } else {
                    $string = sprintf(_("Unknown error: %s") . "<br />\n", $message);
                }
                if (isset($read) && is_array($read)) {
                    $string .= '<br />' . _("Read data:") . "<br />\n";
                    foreach ($read as $line) {
                        $string .= htmlspecialchars($line) . "<br />\n";
                    }
                }
                error_box($string, $color);
                exit;
            } else {
                /*
                 * If the user does not log in with the correct
                 * username and password it is not possible to get the
                 * correct locale from the user's preferences.
                 * Therefore, apply the same hack as on the login
                 * screen.
                 *
                 * $squirrelmail_language is set by a cookie when
                 * the user selects language and logs out
                 */
                set_up_language($squirrelmail_language, true);
                include_once SM_PATH . 'functions/display_messages.php';
                sqsession_destroy();
                /* terminate the session nicely */
                sqimap_logout($imap_stream);
                logout_error(_("Unknown user or password incorrect."));
                exit;
            }
        } else {
            exit;
        }
    }
    return $imap_stream;
}
 function initStream($message, $domain, $length = 0, $host = '', $port = '', $user = '', $pass = '', $authpop = false)
 {
     global $use_smtp_tls, $smtp_auth_mech;
     if ($authpop) {
         $this->authPop($host, '', $user, $pass);
     }
     $rfc822_header = $message->rfc822_header;
     $from = $rfc822_header->from[0];
     $to = $rfc822_header->to;
     $cc = $rfc822_header->cc;
     $bcc = $rfc822_header->bcc;
     $content_type = $rfc822_header->content_type;
     // MAIL FROM: <from address> MUST be empty in cae of MDN (RFC2298)
     if ($content_type->type0 == 'multipart' && $content_type->type1 == 'report' && isset($content_type->properties['report-type']) && $content_type->properties['report-type'] == 'disposition-notification') {
         $from->host = '';
         $from->mailbox = '';
     }
     if ($use_smtp_tls == true and check_php_version(4, 3) and extension_loaded('openssl')) {
         $stream = fsockopen('tls://' . $host, $port, $errorNumber, $errorString);
     } else {
         $stream = fsockopen($host, $port, $errorNumber, $errorString);
     }
     if (!$stream) {
         $this->dlv_msg = $errorString;
         $this->dlv_ret_nr = $errorNumber;
         return 0;
     }
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /* 
      * If $_SERVER['HTTP_HOST'] is set, use that in our HELO to the SMTP
      * server.  This should fix the DNS issues some people have had 
      */
     if (sqgetGlobalVar('HTTP_HOST', $HTTP_HOST, SQ_SERVER)) {
         // HTTP_HOST is set
         // optionally trim off port number
         if ($p = strrpos($HTTP_HOST, ':')) {
             $HTTP_HOST = substr($HTTP_HOST, 0, $p);
         }
         $helohost = $HTTP_HOST;
     } else {
         // For some reason, HTTP_HOST is not set - revert to old behavior
         $helohost = $domain;
     }
     /* Lets introduce ourselves */
     fputs($stream, "EHLO {$helohost}\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         // fall back to HELO if EHLO is not supported
         if ($this->dlv_ret_nr == '500') {
             fputs($stream, "HELO {$helohost}\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         } else {
             return 0;
         }
     }
     if ($smtp_auth_mech == 'cram-md5' or $smtp_auth_mech == 'digest-md5') {
         // Doing some form of non-plain auth
         if ($smtp_auth_mech == 'cram-md5') {
             fputs($stream, "AUTH CRAM-MD5\r\n");
         } elseif ($smtp_auth_mech == 'digest-md5') {
             fputs($stream, "AUTH DIGEST-MD5\r\n");
         }
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         // At this point, $tmp should hold "334 <challenge string>"
         $chall = substr($tmp, 4);
         // Depending on mechanism, generate response string
         if ($smtp_auth_mech == 'cram-md5') {
             $response = cram_md5_response($user, $pass, $chall);
         } elseif ($smtp_auth_mech == 'digest-md5') {
             $response = digest_md5_response($user, $pass, $chall, 'smtp', $host);
         }
         fputs($stream, $response);
         // Let's see what the server had to say about that
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         // CRAM-MD5 is done at this point.  If DIGEST-MD5, there's a bit more to go
         if ($smtp_auth_mech == 'digest-md5') {
             // $tmp contains rspauth, but I don't store that yet. (No need yet)
             fputs($stream, "\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
         // CRAM-MD5 and DIGEST-MD5 code ends here
     } elseif ($smtp_auth_mech == 'none') {
         // No auth at all, just send helo and then send the mail
         // We already said hi earlier, nothing more is needed.
     } elseif ($smtp_auth_mech == 'login') {
         // The LOGIN method
         fputs($stream, "AUTH LOGIN\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         fputs($stream, base64_encode($user) . "\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
         fputs($stream, base64_encode($pass) . "\r\n");
         $tmp = fgets($stream, 1024);
         if ($this->errorCheck($tmp, $stream)) {
             return 0;
         }
     } elseif ($smtp_auth_mech == "plain") {
         /* SASL Plain */
         $auth = base64_encode("{$user}{$user}{$pass}");
         $query = "AUTH PLAIN\r\n";
         fputs($stream, $query);
         $read = fgets($stream, 1024);
         if (substr($read, 0, 3) == '334') {
             // OK so far..
             fputs($stream, "{$auth}\r\n");
             $read = fgets($stream, 1024);
         }
         $results = explode(" ", $read, 3);
         $response = $results[1];
         $message = $results[2];
     } else {
         /* Right here, they've reached an unsupported auth mechanism.
            This is the ugliest hack I've ever done, but it'll do till I can fix
            things up better tomorrow.  So tired... */
         if ($this->errorCheck("535 Unable to use this auth type", $stream)) {
             return 0;
         }
     }
     /* Ok, who is sending the message? */
     $fromaddress = $from->mailbox && $from->host ? $from->mailbox . '@' . $from->host : '';
     fputs($stream, 'MAIL FROM:<' . $fromaddress . ">\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     /* send who the recipients are */
     for ($i = 0, $cnt = count($to); $i < $cnt; $i++) {
         if (!$to[$i]->host) {
             $to[$i]->host = $domain;
         }
         if ($to[$i]->mailbox) {
             fputs($stream, 'RCPT TO:<' . $to[$i]->mailbox . '@' . $to[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) {
         if (!$cc[$i]->host) {
             $cc[$i]->host = $domain;
         }
         if ($cc[$i]->mailbox) {
             fputs($stream, 'RCPT TO:<' . $cc[$i]->mailbox . '@' . $cc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) {
         if (!$bcc[$i]->host) {
             $bcc[$i]->host = $domain;
         }
         if ($bcc[$i]->mailbox) {
             fputs($stream, 'RCPT TO:<' . $bcc[$i]->mailbox . '@' . $bcc[$i]->host . ">\r\n");
             $tmp = fgets($stream, 1024);
             if ($this->errorCheck($tmp, $stream)) {
                 return 0;
             }
         }
     }
     /* Lets start sending the actual message */
     fputs($stream, "DATA\r\n");
     $tmp = fgets($stream, 1024);
     if ($this->errorCheck($tmp, $stream)) {
         return 0;
     }
     return $stream;
 }
Example #7
0
/**
 * Logs the user into the IMAP server.  If $hide is set, no error messages
 * will be displayed (if set to 1, just exits, if set to 2, returns FALSE).
 * This function returns the IMAP connection handle.
 * @param string $username user name
 * @param string $password password encrypted with onetimepad. Since 1.5.2
 *  function can use internal password functions, if parameter is set to
 *  boolean false.
 * @param string $imap_server_address address of imap server
 * @param integer $imap_port port of imap server
 * @param int $hide controls display connection errors:
 *                  0 = do not hide
 *                  1 = show no errors (just exit)
 *                  2 = show no errors (return FALSE)
 *                  3 = show no errors (return error string)
 * @param array $stream_options Stream context options, see config_local.php
 *                           for more details (OPTIONAL)
 * @return mixed The IMAP connection stream, or if the connection fails,
 *               FALSE if $hide is set to 2 or an error string if $hide
 *               is set to 3.
 */
function sqimap_login($username, $password, $imap_server_address, $imap_port, $hide, $stream_options = array())
{
    global $color, $squirrelmail_language, $onetimepad, $use_imap_tls, $imap_auth_mech, $sqimap_capabilities, $display_imap_login_error;
    // Note/TODO: This hack grabs the $authz argument from the session. In the short future,
    // a new argument in function sqimap_login() will be used instead.
    $authz = '';
    global $authz;
    sqgetglobalvar('authz', $authz, SQ_SESSION);
    if (!empty($authz)) {
        /* authz plugin - specific:
         * Get proxy login parameters from authz plugin configuration. If they
         * exist, they will override the current ones.
         * This is useful if we want to use different SASL authentication mechanism
         * and/or different TLS settings for proxy logins. */
        global $authz_imap_auth_mech, $authz_use_imap_tls, $authz_imapPort_tls;
        $imap_auth_mech = !empty($authz_imap_auth_mech) ? strtolower($authz_imap_auth_mech) : $imap_auth_mech;
        $use_imap_tls = !empty($authz_use_imap_tls) ? $authz_use_imap_tls : $use_imap_tls;
        $imap_port = !empty($authz_use_imap_tls) ? $authz_imapPort_tls : $imap_port;
        if ($imap_auth_mech == 'login' || $imap_auth_mech == 'cram-md5') {
            logout_error("Misconfigured Plugin (authz or equivalent):<br/>" . "The LOGIN and CRAM-MD5 authentication mechanisms cannot be used when attempting proxy login.");
            exit;
        }
    }
    /* get imap login password */
    if ($password === false) {
        /* standard functions */
        $password = sqauth_read_password();
    } else {
        /* old way. $key must be extracted from cookie */
        if (!isset($onetimepad) || empty($onetimepad)) {
            sqgetglobalvar('onetimepad', $onetimepad, SQ_SESSION);
        }
        /* Decrypt the password */
        $password = OneTimePadDecrypt($password, $onetimepad);
    }
    if (!isset($sqimap_capabilities)) {
        sqgetglobalvar('sqimap_capabilities', $sqimap_capabilities, SQ_SESSION);
    }
    $host = $imap_server_address;
    $imap_server_address = sqimap_get_user_server($imap_server_address, $username);
    $imap_stream = sqimap_create_stream($imap_server_address, $imap_port, $use_imap_tls, $stream_options);
    if ($imap_auth_mech == 'cram-md5' or $imap_auth_mech == 'digest-md5') {
        // We're using some sort of authentication OTHER than plain or login
        $tag = sqimap_session_id(false);
        if ($imap_auth_mech == 'digest-md5') {
            $query = $tag . " AUTHENTICATE DIGEST-MD5\r\n";
        } elseif ($imap_auth_mech == 'cram-md5') {
            $query = $tag . " AUTHENTICATE CRAM-MD5\r\n";
        }
        fputs($imap_stream, $query);
        $answer = sqimap_fgets($imap_stream);
        // Trim the "+ " off the front
        $response = explode(" ", $answer, 3);
        if ($response[0] == '+') {
            // Got a challenge back
            $challenge = $response[1];
            if ($imap_auth_mech == 'digest-md5') {
                $reply = digest_md5_response($username, $password, $challenge, 'imap', $host, $authz);
            } elseif ($imap_auth_mech == 'cram-md5') {
                $reply = cram_md5_response($username, $password, $challenge);
            }
            fputs($imap_stream, $reply);
            $read = sqimap_fgets($imap_stream);
            if ($imap_auth_mech == 'digest-md5') {
                // DIGEST-MD5 has an extra step..
                if (substr($read, 0, 1) == '+') {
                    // OK so far..
                    fputs($imap_stream, "\r\n");
                    $read = sqimap_fgets($imap_stream);
                }
            }
            $results = explode(" ", $read, 3);
            $response = $results[1];
            $message = $results[2];
        } else {
            // Fake the response, so the error trap at the bottom will work
            $response = "BAD";
            $message = 'IMAP server does not appear to support the authentication method selected.';
            $message .= '  Please contact your system administrator.';
        }
    } elseif ($imap_auth_mech == 'login') {
        // Original IMAP login code
        $query = 'LOGIN "' . quoteimap($username) . '" "' . quoteimap($password) . '"';
        $read = sqimap_run_command($imap_stream, $query, false, $response, $message);
    } elseif ($imap_auth_mech == 'plain') {
        /***
         * SASL PLAIN, RFC 4616 (updates 2595)
         *
         * The mechanism consists of a single message, a string of [UTF-8]
         * encoded [Unicode] characters, from the client to the server.  The
         * client presents the authorization identity (identity to act as),
         * followed by a NUL (U+0000) character, followed by the authentication
         * identity (identity whose password will be used), followed by a NUL
         * (U+0000) character, followed by the clear-text password.  As with
         * other SASL mechanisms, the client does not provide an authorization
         * identity when it wishes the server to derive an identity from the
         * credentials and use that as the authorization identity.
         */
        $tag = sqimap_session_id(false);
        $sasl = isset($sqimap_capabilities['SASL-IR']) && $sqimap_capabilities['SASL-IR'] ? true : false;
        if (!empty($authz)) {
            $auth = base64_encode("{$username}{$authz}{$password}");
        } else {
            $auth = base64_encode("{$username}{$username}{$password}");
        }
        if ($sasl) {
            // IMAP Extension for SASL Initial Client Response
            // <draft-siemborski-imap-sasl-initial-response-01b.txt>
            $query = $tag . " AUTHENTICATE PLAIN {$auth}\r\n";
            fputs($imap_stream, $query);
            $read = sqimap_fgets($imap_stream);
        } else {
            $query = $tag . " AUTHENTICATE PLAIN\r\n";
            fputs($imap_stream, $query);
            $read = sqimap_fgets($imap_stream);
            if (substr($read, 0, 1) == '+') {
                // OK so far..
                fputs($imap_stream, "{$auth}\r\n");
                $read = sqimap_fgets($imap_stream);
            }
        }
        $results = explode(" ", $read, 3);
        $response = $results[1];
        $message = $results[2];
    } else {
        $response = "BAD";
        $message = "Internal SquirrelMail error - unknown IMAP authentication method chosen.  Please contact the developers.";
    }
    /* If the connection was not successful, lets see why */
    if ($response != 'OK') {
        if (!$hide || $hide == 3) {
            //FIXME: UUURG... We don't want HTML in error messages, should also do html sanitizing of error messages elsewhere; should't assume output is destined for an HTML browser here
            if ($response != 'NO') {
                /* "BAD" and anything else gets reported here. */
                $message = sm_encode_html_special_chars($message);
                set_up_language($squirrelmail_language, true);
                if ($response == 'BAD') {
                    if ($hide == 3) {
                        return sprintf(_("Bad request: %s"), $message);
                    }
                    $string = sprintf(_("Bad request: %s") . "<br />\r\n", $message);
                } else {
                    if ($hide == 3) {
                        return sprintf(_("Unknown error: %s"), $message);
                    }
                    $string = sprintf(_("Unknown error: %s") . "<br />\n", $message);
                }
                if (isset($read) && is_array($read)) {
                    $string .= '<br />' . _("Read data:") . "<br />\n";
                    foreach ($read as $line) {
                        $string .= sm_encode_html_special_chars($line) . "<br />\n";
                    }
                }
                error_box($string);
                exit;
            } else {
                /*
                 * If the user does not log in with the correct
                 * username and password it is not possible to get the
                 * correct locale from the user's preferences.
                 * Therefore, apply the same hack as on the login
                 * screen.
                 *
                 * $squirrelmail_language is set by a cookie when
                 * the user selects language and logs out
                 */
                set_up_language($squirrelmail_language, true);
                sqsession_destroy();
                /* terminate the session nicely */
                sqimap_logout($imap_stream);
                // determine what error message to use
                //
                $fail_msg = _("Unknown user or password incorrect.");
                if ($display_imap_login_error) {
                    // See if there is an error message from the server
                    // Skip any rfc5530 response code: '[something]' at the
                    // start of the message
                    if (!empty($message) && $message[0] == '[' && ($end = strstr($message, ']')) && $end != ']') {
                        $message = substr($end, 1);
                    }
                    // Remove surrounding spaces and if there
                    // is anything left, display that as the
                    // error message:
                    $message = trim($message);
                    if (strlen($message)) {
                        $fail_msg = _($message);
                    }
                }
                if ($hide == 3) {
                    return $fail_msg;
                }
                logout_error($fail_msg);
                exit;
            }
        } else {
            if ($hide == 2) {
                return FALSE;
            }
            exit;
        }
    }
    /* Special error case:
     * Login referrals. The server returns:
     * ? OK [REFERRAL <imap url>]
     * Check RFC 2221 for details. Since we do not support login referrals yet
     * we log the user out.
     */
    if (stristr($message, 'REFERRAL imap') === TRUE) {
        sqimap_logout($imap_stream);
        set_up_language($squirrelmail_language, true);
        sqsession_destroy();
        logout_error(_("Your mailbox is not located at this server. Try a different server or consult your system administrator"));
        exit;
    }
    return $imap_stream;
}