/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ #include "msgCore.h" #include "nsSmtpProtocol.h" #include "nscore.h" #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" #include "nsIMsgHeaderParser.h" #include "nsFileStream.h" #include "nsIMsgMailNewsUrl.h" #include "nsMsgComposeStringBundle.h" #include "nsMsgBaseCID.h" #include "nsINetSupportDialogService.h" #include "nsIPrompt.h" #include "nsString.h" #include "nsTextFormatter.h" #include "nsIMsgIdentity.h" #include "nsINetPrompt.h" #include "nsISmtpServer.h" #include "prtime.h" #include "prlog.h" #include "prerror.h" #include "prprf.h" #include "plbase64.h" #include "nsEscape.h" #ifndef XP_UNIX #include #endif /* !XP_UNIX */ static PRLogModuleInfo *SMTPLogModule = nsnull; static NS_DEFINE_CID(kHeaderParserCID, NS_MSGHEADERPARSER_CID); static NS_DEFINE_CID(kCNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); extern "C" { char * NET_SACopy (char **destination, const char *source); char * NET_SACat (char **destination, const char *source); } /* the output_buffer_size must be larger than the largest possible line * 2000 seems good for news * * jwz: I increased this to 4k since it must be big enough to hold the * entire button-bar HTML, and with the new "mailto" format, that can * contain arbitrarily long header fields like "references". * * fortezza: proxy auth is huge, buffer increased to 8k (sigh). */ #define OUTPUT_BUFFER_SIZE (4096*2) //////////////////////////////////////////////////////////////////////////////////////////// // TEMPORARY HARD CODED FUNCTIONS /////////////////////////////////////////////////////////////////////////////////////////// #if defined (XP_WIN) || defined(XP_OS2) char *XP_AppCodeName = "Mozilla"; #else const char *XP_AppCodeName = "Mozilla"; #endif #define NET_IS_SPACE(x) ((((unsigned int) (x)) > 0x7f) ? 0 : isspace(x)) /* based on in NET_ExplainErrorDetails in mkmessag.c */ nsresult nsExplainErrorDetails(int code, ...) { nsresult rv; va_list args; NS_WITH_SERVICE(nsIPrompt, dialog, kCNetSupportDialogCID, &rv); PRUnichar *msg = nsnull; PRUnichar *eMsg = nsnull; va_start (args, code); switch (code) { case NS_ERROR_SMTP_SERVER_ERROR: case NS_ERROR_TCP_READ_ERROR: case NS_ERROR_SENDING_FROM_COMMAND: case NS_ERROR_SENDING_RCPT_COMMAND: case NS_ERROR_SENDING_DATA_COMMAND: case NS_ERROR_SENDING_MESSAGE: eMsg = ComposeGetStringByID(code); msg = nsTextFormatter::vsmprintf(eMsg, args); nsCRT::free(eMsg); break; default: eMsg = ComposeGetStringByID(NS_ERROR_COMMUNICATIONS_ERROR); msg = nsTextFormatter::smprintf(eMsg, code); nsCRT::free(eMsg); break; } if (msg) { rv = dialog->Alert(msg); nsTextFormatter::smprintf_free(msg); } va_end (args); return rv; } char * NET_SACopy (char **destination, const char *source) { if(*destination) { PR_Free(*destination); *destination = 0; } if (! source) { *destination = NULL; } else { *destination = (char *) PR_Malloc (PL_strlen(source) + 1); if (*destination == NULL) return(NULL); PL_strcpy (*destination, source); } return *destination; } /* Again like strdup but it concatinates and free's and uses Realloc */ char * NET_SACat (char **destination, const char *source) { if (source && *source) { if (*destination) { int length = PL_strlen (*destination); *destination = (char *) PR_Realloc (*destination, length + PL_strlen(source) + 1); if (*destination == NULL) return(NULL); PL_strcpy (*destination + length, source); } else { *destination = (char *) PR_Malloc (PL_strlen(source) + 1); if (*destination == NULL) return(NULL); PL_strcpy (*destination, source); } } return *destination; } /* RFC 1891 -- extended smtp value encoding scheme 5. Additional parameters for RCPT and MAIL commands The extended RCPT and MAIL commands are issued by a client when it wishes to request a DSN from the server, under certain conditions, for a particular recipient. The extended RCPT and MAIL commands are identical to the RCPT and MAIL commands defined in [1], except that one or more of the following parameters appear after the sender or recipient address, respectively. The general syntax for extended SMTP commands is defined in [4]. NOTE: Although RFC 822 ABNF is used to describe the syntax of these parameters, they are not, in the language of that document, "structured field bodies". Therefore, while parentheses MAY appear within an emstp-value, they are not recognized as comment delimiters. The syntax for "esmtp-value" in [4] does not allow SP, "=", control characters, or characters outside the traditional ASCII range of 1- 127 decimal to be transmitted in an esmtp-value. Because the ENVID and ORCPT parameters may need to convey values outside this range, the esmtp-values for these parameters are encoded as "xtext". "xtext" is formally defined as follows: xtext = *( xchar / hexchar ) xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive, except for "+" and "=". ; "hexchar"s are intended to encode octets that cannot appear ; as ASCII characters within an esmtp-value. hexchar = ASCII "+" immediately followed by two upper case hexadecimal digits When encoding an octet sequence as xtext: + Any ASCII CHAR between "!" and "~" inclusive, except for "+" and "=", MAY be encoded as itself. (A CHAR in this range MAY instead be encoded as a "hexchar", at the implementor's discretion.) + ASCII CHARs that fall outside the range above must be encoded as "hexchar". */ /* caller must free the return buffer */ PRIVATE char * esmtp_value_encode(char *addr) { char *buffer = (char *) PR_Malloc(512); /* esmpt ORCPT allow up to 500 chars encoded addresses */ char *bp = buffer, *bpEnd = buffer+500; int len, i; if (!buffer) return NULL; *bp=0; if (! addr || *addr == 0) /* this will never happen */ return buffer; for (i=0, len=PL_strlen(addr); i < len && bp < bpEnd; i++) { if (*addr >= 0x21 && *addr <= 0x7E && *addr != '+' && *addr != '=') { *bp++ = *addr++; } else { PR_snprintf(bp, bpEnd-bp, "+%.2X", ((int)*addr++)); bp += PL_strlen(bp); } } *bp=0; return buffer; } //////////////////////////////////////////////////////////////////////////////////////////// // END OF TEMPORARY HARD CODED FUNCTIONS /////////////////////////////////////////////////////////////////////////////////////////// NS_IMPL_ADDREF_INHERITED(nsSmtpProtocol, nsMsgProtocol) NS_IMPL_RELEASE_INHERITED(nsSmtpProtocol, nsMsgProtocol) NS_INTERFACE_MAP_BEGIN(nsSmtpProtocol) NS_INTERFACE_MAP_ENTRY(nsIMsgLogonRedirectionRequester) NS_INTERFACE_MAP_END_INHERITING(nsMsgProtocol) nsSmtpProtocol::nsSmtpProtocol(nsIURI * aURL) : nsMsgProtocol(aURL, aURL) { Initialize(aURL); } nsSmtpProtocol::~nsSmtpProtocol() { // free our local state PR_FREEIF(m_addressCopy); PR_FREEIF(m_verifyAddress); PR_FREEIF(m_dataBuf); } void nsSmtpProtocol::Initialize(nsIURI * aURL) { NS_PRECONDITION(aURL, "invalid URL passed into Smtp Protocol"); nsresult rv = NS_OK; m_flags = 0; m_port = SMTP_PORT; m_urlErrorState = NS_ERROR_FAILURE; if (!SMTPLogModule) SMTPLogModule = PR_NewLogModule("SMTP"); if (aURL) m_runningURL = do_QueryInterface(aURL); // extract out message feedback if there is any. nsCOMPtr mailnewsUrl = do_QueryInterface(aURL); if (mailnewsUrl) mailnewsUrl->GetStatusFeedback(getter_AddRefs(m_statusFeedback)); m_dataBuf = (char *) PR_Malloc(sizeof(char) * OUTPUT_BUFFER_SIZE); m_dataBufSize = OUTPUT_BUFFER_SIZE; m_nextState = SMTP_START_CONNECT; m_nextStateAfterResponse = SMTP_START_CONNECT; m_responseCode = 0; m_previousResponseCode = 0; m_continuationResponse = -1; m_tlsEnabled = PR_FALSE; m_addressCopy = nsnull; m_addresses = nsnull; m_addressesLeft = nsnull; m_verifyAddress = nsnull; m_totalAmountWritten = 0; m_totalMessageSize = 0; m_originalContentLength = 0; // ** may want to consider caching the server capability to save lots of // round trip communication between the client and server nsCOMPtr smtpServer; m_runningURL->GetSmtpServer(getter_AddRefs(smtpServer)); if (smtpServer) smtpServer->GetAuthMethod(&m_prefAuthMethod); else m_prefAuthMethod = PREF_AUTH_NONE; rv = RequestOverrideInfo(smtpServer); // if we aren't waiting for a login override, then go ahead an // open the network connection like we normally would have. if (NS_FAILED(rv) || !TestFlag(SMTP_WAIT_FOR_REDIRECTION)) rv = OpenNetworkSocket(aURL); } const char * nsSmtpProtocol::GetUserDomainName() { nsresult rv; NS_PRECONDITION(m_runningURL, "we must be running a url in order to get the user's domain..."); if (m_runningURL) { nsCOMPtr senderIdentity; rv = m_runningURL->GetSenderIdentity(getter_AddRefs(senderIdentity)); if (NS_FAILED(rv) || !senderIdentity) { return nsnull; } rv = senderIdentity->GetEmail(getter_Copies(m_mailAddr)); if (NS_FAILED(rv) || !((const char *)m_mailAddr)) { return nsnull; } const char *atSignMarker = nsnull; atSignMarker = PL_strchr(m_mailAddr, '@'); return atSignMarker ? atSignMarker+1 : (const char *) m_mailAddr; // return const ptr into buffer in running url... } return nsnull; } ///////////////////////////////////////////////////////////////////////////////////////////// // we suppport the nsIStreamListener interface //////////////////////////////////////////////////////////////////////////////////////////// // stop binding is a "notification" informing us that the stream associated with aURL is going away. NS_IMETHODIMP nsSmtpProtocol::OnStopRequest(nsIChannel * /* aChannel */, nsISupports *ctxt, nsresult aStatus, const PRUnichar *aMsg) { nsMsgProtocol::OnStopRequest(nsnull, ctxt, aStatus, aMsg); // okay, we've been told that the send is done and the connection is going away. So // we need to release all of our state return CloseSocket(); } ///////////////////////////////////////////////////////////////////////////////////////////// // End of nsIStreamListenerSupport ////////////////////////////////////////////////////////////////////////////////////////////// PRInt32 nsSmtpProtocol::ReadLine(nsIInputStream * inputStream, PRUint32 length, char ** line) { // I haven't looked into writing this yet. We have a couple of possibilities: // (1) insert ReadLine *yuck* into here or better yet into the nsIInputStream // then we can just turn around and call it here. // OR // (2) we write "protocol" specific code for news which looks for a CRLF in the incoming // stream. If it finds it, that's our new line that we put into @param line. We'd // need a buffer (m_dataBuf) to store extra info read in from the stream..... // read out everything we've gotten back and return it in line...this won't work for much but it does // get us going... // XXX: please don't hold this quick "algorithm" against me. I just want to read just one // line for the stream. I promise this is ONLY temporary to test out NNTP. We need a generic // way to read one line from a stream. For now I'm going to read out one character at a time. // (I said it was only temporary =)) and test for newline... PRUint32 numBytesToRead = 0; // MAX # bytes to read from the stream PRUint32 numBytesRead = 0; // total number bytes we have read from the stream during this call inputStream->Available(&length); // refresh the length in case it has changed... if (length > OUTPUT_BUFFER_SIZE) numBytesToRead = OUTPUT_BUFFER_SIZE; else numBytesToRead = length; m_dataBuf[0] = '\0'; PRUint32 numBytesLastRead = 0; // total number of bytes read in the last cycle... do { inputStream->Read(m_dataBuf + numBytesRead, 1 /* read just one byte */, &numBytesLastRead); numBytesRead += numBytesLastRead; } while (numBytesRead <= numBytesToRead && numBytesLastRead > 0 && m_dataBuf[numBytesRead-1] != '\n'); m_dataBuf[numBytesRead] = '\0'; // null terminate the string. // oops....we also want to eat up the '\n' and the \r'... if (numBytesRead > 1 && m_dataBuf[numBytesRead-2] == '\r') m_dataBuf[numBytesRead-2] = '\0'; // hit both cr and lf... else if (numBytesRead > 0 && (m_dataBuf[numBytesRead-1] == '\r' || m_dataBuf[numBytesRead-1] == '\n')) m_dataBuf[numBytesRead-1] = '\0'; if (line) *line = m_dataBuf; return numBytesRead; } void nsSmtpProtocol::UpdateStatus(PRInt32 aStatusID) { if (m_statusFeedback) { PRUnichar * statusString = ComposeGetStringByID(aStatusID); UpdateStatusWithString(statusString); nsCRT::free(statusString); } } void nsSmtpProtocol::UpdateStatusWithString(PRUnichar * aStatusString) { if (m_statusFeedback && aStatusString) m_statusFeedback->ShowStatusString(aStatusString); } ///////////////////////////////////////////////////////////////////////////////////////////// // Begin protocol state machine functions... ////////////////////////////////////////////////////////////////////////////////////////////// /* * gets the response code from the nntp server and the * response line * * returns the TCP return code from the read */ PRInt32 nsSmtpProtocol::SmtpResponse(nsIInputStream * inputStream, PRUint32 length) { char * line = nsnull; char cont_char; PRInt32 status = 0; status = ReadLine(inputStream, length, &line); if(status == 0) { m_nextState = SMTP_ERROR_DONE; ClearFlag(SMTP_PAUSE_FOR_READ); nsresult rv = nsExplainErrorDetails(NS_ERROR_SMTP_SERVER_ERROR, (const char*)m_responseText); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; return(NS_ERROR_SMTP_SERVER_ERROR); } /* if TCP error of if there is not a full line yet return */ if(status < 0) { nsresult rv = nsExplainErrorDetails(NS_ERROR_TCP_READ_ERROR, PR_GetOSError()); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; /* return TCP error */ return(NS_ERROR_TCP_READ_ERROR); } else if(!line) { return status; } PR_LOG(SMTPLogModule, PR_LOG_ALWAYS, ("SMTP Response: %s", line)); cont_char = ' '; /* default */ sscanf(line, "%d%c", &m_responseCode, &cont_char); if(m_continuationResponse == -1) { if (cont_char == '-') /* begin continuation */ m_continuationResponse = m_responseCode; if(PL_strlen(line) > 3) m_responseText = line+4; } else { /* have to continue */ if (m_continuationResponse == m_responseCode && cont_char == ' ') m_continuationResponse = -1; /* ended */ m_responseText += "\n"; if(PL_strlen(line) > 3) m_responseText += line+4; } if(m_continuationResponse == -1) /* all done with this response? */ { m_nextState = m_nextStateAfterResponse; ClearFlag(SMTP_PAUSE_FOR_READ); /* don't pause */ } else { inputStream->Available(&length); // refresh the length as it has changed... if (!length) SetFlag(SMTP_PAUSE_FOR_READ); } return(0); /* everything ok */ } PRInt32 nsSmtpProtocol::LoginResponse(nsIInputStream * inputStream, PRUint32 length) { PRInt32 status = 0; nsCAutoString buffer ("HELO "); if(m_responseCode != 220) { m_urlErrorState = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER; return(NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); } buffer += GetUserDomainName(); buffer += CRLF; nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_HELO_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return(status); } PRInt32 nsSmtpProtocol::ExtensionLoginResponse(nsIInputStream * inputStream, PRUint32 length) { PRInt32 status = 0; nsCAutoString buffer("EHLO "); if(m_responseCode != 220) { m_urlErrorState = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER; return(NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); } buffer += GetUserDomainName(); buffer += CRLF; nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_EHLO_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return(status); } PRInt32 nsSmtpProtocol::SendHeloResponse(nsIInputStream * inputStream, PRUint32 length) { PRInt32 status = 0; nsCAutoString buffer; nsresult rv; // extract the email address from the identity nsXPIDLCString emailAddress; nsCOMPtr senderIdentity; rv = m_runningURL->GetSenderIdentity(getter_AddRefs(senderIdentity)); if (NS_FAILED(rv) || !senderIdentity) { m_urlErrorState = NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS; return(NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS); } else { senderIdentity->GetEmail(getter_Copies(emailAddress)); } /* don't check for a HELO response because it can be bogus and * we don't care */ if(!((const char *)emailAddress)) { m_urlErrorState = NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS; return(NS_ERROR_COULD_NOT_GET_USERS_MAIL_ADDRESS); } if(m_verifyAddress) { buffer += "VRFY"; buffer += m_verifyAddress; buffer += CRLF; } else { /* else send the MAIL FROM: command */ nsCOMPtr parser = do_GetService(kHeaderParserCID); char *fullAddress = nsnull; if (parser) { // pass nsnull for the name, since we just want the email. // // seems a little weird that we are passing in the emailAddress // when that's the out parameter parser->MakeFullAddress(nsnull, nsnull /* name */, emailAddress /* address */, &fullAddress); } #ifdef UNREADY_CODE if (CE_URL_S->msg_pane) { if (MSG_RequestForReturnReceipt(CE_URL_S->msg_pane)) { if (TestFlag(SMTP_EHLO_DSN_ENABLED)) { PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s> RET=FULL ENVID=NS40112696JT" CRLF, fullAddress); } else { FE_Alert (CE_WINDOW_ID, XP_GetString(XP_RETURN_RECEIPT_NOT_SUPPORT)); PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, fullAddress); } } else if (MSG_SendingMDNInProgress(CE_URL_S->msg_pane)) { PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, ""); } else { PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, fullAddress); } } else #endif { buffer = "MAIL FROM:<"; buffer += fullAddress; buffer += ">" CRLF; } PR_FREEIF (fullAddress); } nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; if(m_verifyAddress) m_nextStateAfterResponse = SMTP_SEND_VRFY_RESPONSE; else m_nextStateAfterResponse = SMTP_SEND_MAIL_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return(status); } PRInt32 nsSmtpProtocol::SendEhloResponse(nsIInputStream * inputStream, PRUint32 length) { PRInt32 status = 0; nsCAutoString buffer; nsCOMPtr url = do_QueryInterface(m_runningURL); if (m_responseCode != 250) { if (m_prefAuthMethod == PREF_AUTH_ANY || m_prefAuthMethod == PREF_AUTH_TLS_ONLY || m_prefAuthMethod == PREF_AUTH_LOGIN) { m_nextState = SMTP_ERROR_DONE; m_urlErrorState = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER; return(NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); } buffer = "HELO "; buffer += GetUserDomainName(); buffer += CRLF; status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_HELO_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return (status); } else { char *ptr = NULL; ptr = PL_strcasestr(m_responseText, "DSN"); if (ptr && nsCRT::ToUpper(*(ptr-1)) != 'X') SetFlag(SMTP_EHLO_DSN_ENABLED); if (PL_strcasestr(m_responseText, " PLAIN") != 0) SetFlag(SMTP_AUTH_PLAIN_ENABLED); if (PL_strcasestr(m_responseText, "AUTH=LOGIN") != 0) SetFlag(SMTP_AUTH_LOGIN_ENABLED); /* old style */ if (PL_strcasestr(m_responseText, "STARTTLS") != 0) SetFlag(SMTP_EHLO_STARTTLS_ENABLED); if (PL_strcasestr(m_responseText, "EXTERNAL") != 0) SetFlag(SMTP_AUTH_EXTERNAL_ENABLED); } if (!m_tlsEnabled) { if(TestFlag(SMTP_EHLO_STARTTLS_ENABLED)) { if (m_prefAuthMethod == PREF_AUTH_ANY || m_prefAuthMethod == PREF_AUTH_TLS_TRY || m_prefAuthMethod == PREF_AUTH_TLS_ONLY) { buffer = "STARTTLS"; buffer += CRLF; status = SendData(url, buffer); m_flags = 0; // resetting the flags m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_TLS_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return status; } } else if (m_prefAuthMethod == PREF_AUTH_TLS_ONLY) { m_nextState = SMTP_ERROR_DONE; m_urlErrorState = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER; return(NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); } if ((TestFlag(SMTP_AUTH_PLAIN_ENABLED) || TestFlag(SMTP_AUTH_LOGIN_ENABLED)) && (m_prefAuthMethod == PREF_AUTH_ANY || m_prefAuthMethod == PREF_AUTH_LOGIN)) { m_nextState = SMTP_SEND_AUTH_LOGIN_USERNAME; m_nextStateAfterResponse = SMTP_AUTH_LOGIN_RESPONSE; return NS_OK; } m_nextState = SMTP_SEND_HELO_RESPONSE; return NS_OK; } else // TLS enabled { if (TestFlag(SMTP_AUTH_EXTERNAL_ENABLED)) { buffer = "AUTH EXTERNAL"; buffer += CRLF; SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_AUTH_EXTERNAL_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return NS_OK; } else if (TestFlag(SMTP_AUTH_LOGIN_ENABLED) || TestFlag(SMTP_AUTH_PLAIN_ENABLED)) { m_nextState = SMTP_SEND_AUTH_LOGIN_USERNAME; m_nextStateAfterResponse = SMTP_AUTH_LOGIN_RESPONSE; return NS_OK; } else { m_nextState = SMTP_SEND_HELO_RESPONSE; return NS_OK; } } } PRInt32 nsSmtpProtocol::AuthLoginResponse(nsIInputStream * stream, PRUint32 length) { PRInt32 status = 0; nsCOMPtr smtpServer; m_runningURL->GetSmtpServer(getter_AddRefs(smtpServer)); switch (m_responseCode/100) { case 2: m_nextState = SMTP_SEND_HELO_RESPONSE; break; case 3: m_nextState = SMTP_SEND_AUTH_LOGIN_PASSWORD; break; case 5: default: if (smtpServer) { smtpServer->ForgetPassword(); m_nextState = SMTP_SEND_AUTH_LOGIN_USERNAME; } else { status = NS_ERROR_SMTP_PASSWORD_UNDEFINED; } break; } return (status); } PRInt32 nsSmtpProtocol::AuthLoginUsername() { char buffer[512]; nsresult rv; PRInt32 status = 0; nsXPIDLCString username; char *base64Str = nsnull; nsXPIDLCString origPassword; nsCAutoString password; nsCOMPtr smtpServer; rv = m_runningURL->GetSmtpServer(getter_AddRefs(smtpServer)); if (NS_FAILED(rv)) return NS_ERROR_FAILURE; rv = smtpServer->GetUsername(getter_Copies(username)); if (!(const char*) username || nsCRT::strlen((const char*)username) == 0) return NS_ERROR_SMTP_USERNAME_UNDEFINED; if (!TestFlag(SMTP_USE_LOGIN_REDIRECTION)) { rv = GetPassword(getter_Copies(origPassword)); password = origPassword; if (password.IsEmpty()) return NS_ERROR_SMTP_PASSWORD_UNDEFINED; } else password = mLogonCookie; if (TestFlag(SMTP_AUTH_LOGIN_ENABLED)) { base64Str = PL_Base64Encode((const char *) username, nsCRT::strlen((const char*)username), nsnull); } else { char plain_string[512]; int len = 1; /* first char */ nsCRT::memset(plain_string, 0, 512); PR_snprintf(&plain_string[1], 510, "%s", (const char*)username); len += PL_strlen(username); len++; /* second char */ PR_snprintf(&plain_string[len], 511-len, "%s", (const char*)password); len += PL_strlen(password); base64Str = PL_Base64Encode(plain_string, len, nsnull); } if (base64Str) { if (TestFlag(SMTP_AUTH_LOGIN_ENABLED)) PR_snprintf(buffer, sizeof(buffer), "AUTH LOGIN %.256s" CRLF, base64Str); else if (TestFlag(SMTP_AUTH_PLAIN_ENABLED)) PR_snprintf(buffer, sizeof(buffer), "AUTH PLAIN %.256s" CRLF, base64Str); else return (NS_ERROR_COMMUNICATIONS_ERROR); nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_AUTH_LOGIN_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); nsCRT::free(base64Str); return (status); } return -1; } PRInt32 nsSmtpProtocol::AuthLoginPassword() { /* use cached smtp password first * if not then use cached pop password * if pop password undefined * sync with smtp password */ PRInt32 status = 0; nsresult rv; nsXPIDLCString origPassword; nsCAutoString password; if (!TestFlag(SMTP_USE_LOGIN_REDIRECTION)) { rv = GetPassword(getter_Copies(origPassword)); PRInt32 passwordLength = nsCRT::strlen((const char *) origPassword); if (!(const char*) origPassword || passwordLength == 0) return NS_ERROR_SMTP_USERNAME_UNDEFINED; } else password = mLogonCookie; if (!password.IsEmpty()) { char *base64Str = PL_Base64Encode((const char *)password, nsCRT::strlen(password), nsnull); char buffer[512]; PR_snprintf(buffer, sizeof(buffer), "%.256s" CRLF, base64Str); nsCRT::free(base64Str); nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_AUTH_LOGIN_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return (status); } return -1; } PRInt32 nsSmtpProtocol::SendVerifyResponse() { #if 0 PRInt32 status = 0; char buffer[512]; if(m_responseCode == 250 || m_responseCode == 251) return(NS_USER_VERIFIED_BY_SMTP); else return(NS_USER_NOT_VERIFIED_BY_SMTP); #else PR_ASSERT(0); return(-1); #endif } PRInt32 nsSmtpProtocol::SendMailResponse() { PRInt32 status = 0; nsCAutoString buffer; if(m_responseCode != 250) { nsresult rv = nsExplainErrorDetails(NS_ERROR_SENDING_FROM_COMMAND, (const char*)m_responseText); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; return(NS_ERROR_SENDING_FROM_COMMAND); } /* Send the RCPT TO: command */ #ifdef UNREADY_CODE if (TestFlag(SMTP_EHLO_DSN_ENABLED) && (CE_URL_S->msg_pane && MSG_RequestForReturnReceipt(CE_URL_S->msg_pane))) #else if (TestFlag(SMTP_EHLO_DSN_ENABLED) && PR_FALSE) #endif { char *encodedAddress = esmtp_value_encode(m_addresses); if (encodedAddress) { buffer = "RCPT TO:<"; buffer += m_addresses; buffer += "> NOTIFY=SUCCESS,FAILURE ORCPT=rfc822;"; buffer += encodedAddress; buffer += CRLF; PR_FREEIF(encodedAddress); } else { m_urlErrorState = NS_ERROR_OUT_OF_MEMORY; return (NS_ERROR_OUT_OF_MEMORY); } } else { buffer = "RCPT TO:<"; buffer += m_addresses; buffer += ">"; buffer += CRLF; } /* take the address we sent off the list (move the pointer to just past the terminating null.) */ m_addresses += PL_strlen (m_addresses) + 1; m_addressesLeft--; nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_RCPT_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return(status); } PRInt32 nsSmtpProtocol::SendRecipientResponse() { PRInt32 status = 0; nsCAutoString buffer; if(m_responseCode != 250 && m_responseCode != 251) { nsresult rv = nsExplainErrorDetails(NS_ERROR_SENDING_RCPT_COMMAND, (const char*)m_responseText); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; return(NS_ERROR_SENDING_RCPT_COMMAND); } if(m_addressesLeft > 0) { /* more senders to RCPT to */ m_nextState = SMTP_SEND_MAIL_RESPONSE; return(0); } /* else send the RCPT TO: command */ buffer = "DATA"; buffer += CRLF; nsCOMPtr url = do_QueryInterface(m_runningURL); status = SendData(url, buffer); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_DATA_RESPONSE; SetFlag(SMTP_PAUSE_FOR_READ); return(status); } PRInt32 nsSmtpProtocol::SendData(nsIURI *url, const char *dataBuffer) { if (!url || !dataBuffer) return -1; PR_LOG(SMTPLogModule, PR_LOG_ALWAYS, ("SMTP Send: %s", dataBuffer)); return nsMsgProtocol::SendData(url, dataBuffer); } PRInt32 nsSmtpProtocol::SendDataResponse() { PRInt32 status = 0; char * command=0; if(m_responseCode != 354) { nsresult rv = nsExplainErrorDetails(NS_ERROR_SENDING_DATA_COMMAND, (const char*)m_responseText); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; return(NS_ERROR_SENDING_DATA_COMMAND); } #ifdef UNREADY_CODE #ifdef XP_UNIX { const char * FE_UsersRealMailAddress(void); /* definition */ const char *real_name; char *s = 0; PRBool suppress_sender_header = PR_FALSE; PREF_GetBoolPref ("mail.suppress_sender_header", &suppress_sender_header); if (!suppress_sender_header) { real_name = FE_UsersRealMailAddress(); s = (real_name ? MSG_MakeFullAddress (NULL, real_name) : 0); if (real_name && !s) { m_urlErrorState = NS_ERROR_COULD_NOT_GET_UID; return(NS_ERROR_COULD_NOT_GET_UID); } if(real_name) { char buffer[512]; PR_snprintf(buffer, sizeof(buffer), "Sender: %.256s" CRLF, real_name); NET_SACat(command, buffer); if(!command) { m_urlErrorState = NS_ERROR_OUT_OF_MEMORY; return(NS_ERROR_OUT_OF_MEMORY); } status = (int) NET_BlockingWrite(CE_SOCK, command, PL_strlen(command)); if(status < 0) { } } } } #endif /* XP_UNIX */ #endif /* UNREADY_CODE */ PR_FREEIF(command); m_nextState = SMTP_SEND_POST_DATA; ClearFlag(SMTP_PAUSE_FOR_READ); /* send data directly */ UpdateStatus(SMTP_DELIV_MAIL); #ifdef UNREADY_CODE /* get the size of the message */ if(CE_URL_S->post_data_is_file) { XP_StatStruct stat_entry; if(-1 != XP_Stat(CE_URL_S->post_data, &stat_entry, xpFileToPost)) m_totalMessageSize = stat_entry.st_size; } else #endif /* UNREADY_CODE */ { // m_runningURL->GetBodySize(&m_totalMessageSize); } return(status); } PRInt32 nsSmtpProtocol::SendMessageInFile() { nsCOMPtr fileSpec; nsCOMPtr url = do_QueryInterface(m_runningURL); m_runningURL->GetPostMessageFile(getter_AddRefs(fileSpec)); if (url && fileSpec) PostMessage(url, fileSpec); SetFlag(SMTP_PAUSE_FOR_READ); // for now, we are always done at this point..we aren't making multiple calls // to post data... // always issue a '.' and CRLF when we are done... if (url) SendData(url, CRLF "." CRLF); UpdateStatus(SMTP_MESSAGE_SENT_WAITING_MAIL_REPLY); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_SEND_MESSAGE_RESPONSE; return(0); } PRInt32 nsSmtpProtocol::SendPostData() { // mscott: as a first pass, I'm writing everything at once and am not // doing it in chunks... PRInt32 status = 0; /* returns 0 on done and negative on error * positive if it needs to continue. */ // check to see if url is a file..if it is...call our file handler... PRBool postMessageInFile = PR_TRUE; m_runningURL->GetPostMessage(&postMessageInFile); if (postMessageInFile) { return SendMessageInFile(); } /* Update the thermo and the status bar. This is done by hand, rather than using the FE_GraphProgress* functions, because there seems to be no way to make FE_GraphProgress shut up and not display anything more when all the data has arrived. At the end, we want to show the "message sent; waiting for reply" status; FE_GraphProgress gets in the way of that. See bug #23414. */ #ifdef UNREADY_CODE unsigned long curtime; curtime = XP_TIME(); if (curtime != m_LastTime) { FE_Progress(CE_WINDOW_ID, XP_ProgressText(m_totalMessageSize, m_totalAmountWritten, 0, 0)); m_LastTime = curtime; } if(m_totalMessageSize) FE_SetProgressBarPercent(CE_WINDOW_ID, m_totalAmountWritten*100/m_totalMessageSize); #endif /* UNREADY_CODE */ return(status); } PRInt32 nsSmtpProtocol::SendMessageResponse() { if(m_responseCode != 250) { nsresult rv = nsExplainErrorDetails(NS_ERROR_SENDING_MESSAGE, (const char*)m_responseText); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to explain SMTP error"); m_urlErrorState = NS_ERROR_BUT_DONT_SHOW_ALERT; return(NS_ERROR_SENDING_MESSAGE); } UpdateStatus(SMTP_PROGRESS_MAILSENT); /* else */ nsCOMPtr url = do_QueryInterface(m_runningURL); SendData(url, "quit"CRLF); // send a quit command to close the connection with the server. m_nextState = SMTP_DONE; return(0); } nsresult nsSmtpProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer ) { nsresult rv = NS_OK; // if we are currently waiting for login redirection information // then hold off on loading the url....but be sure to remember // aConsumer so we can use it later... if (TestFlag(SMTP_WAIT_FOR_REDIRECTION)) { // mark a pending load... SetFlag(SMTP_LOAD_URL_PENDING); mPendingConsumer = aConsumer; return NS_OK; } else ClearFlag(SMTP_LOAD_URL_PENDING); // otherwise begin loading the url PRInt32 status = 0; m_continuationResponse = -1; /* init */ if (aURL) { m_runningURL = do_QueryInterface(aURL); // we had a bug where we failed to bring up an alert if the host // name was empty....so throw up an alert saying we don't have // a host name and inform the caller that we are not going to // run the url... nsXPIDLCString hostName; aURL->GetHost(getter_Copies(hostName)); if (!hostName) { nsCOMPtr aMsgUrl = do_QueryInterface(aURL); if (aMsgUrl) { aMsgUrl->SetUrlState(PR_TRUE, NS_OK); rv = aMsgUrl->SetUrlState(PR_FALSE /* we aren't running the url */, NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); // set the url as a url currently being run... } return NS_ERROR_BUT_DONT_SHOW_ALERT; } PRBool postMessage = PR_FALSE; m_runningURL->GetPostMessage(&postMessage); if(postMessage) { char *addrs1 = 0; char *addrs2 = 0; m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE; /* Remove duplicates from the list, to prevent people from getting more than one copy (the SMTP host may do this too, or it may not.) This causes the address list to be parsed twice; this probably doesn't matter. */ nsXPIDLCString addresses; nsCOMPtr parser = do_GetService(kHeaderParserCID); m_runningURL->GetRecipients(getter_Copies(addresses)); if (NS_SUCCEEDED(rv) && parser) { parser->RemoveDuplicateAddresses(nsnull, addresses, nsnull, PR_FALSE, &addrs1); /* Extract just the mailboxes from the full RFC822 address list. This means that people can post to mailto: URLs which contain full RFC822 address specs, and we will still send the right thing in the SMTP RCPT command. */ if (addrs1 && *addrs1) { rv = parser->ParseHeaderAddresses(nsnull, addrs1, nsnull, &addrs2, &m_addressesLeft); PR_FREEIF (addrs1); } if (m_addressesLeft == 0 || addrs2 == nsnull) // hmm no addresses to send message to... { m_nextState = SMTP_ERROR_DONE; ClearFlag(SMTP_PAUSE_FOR_READ); status = NS_MSG_NO_RECIPIENTS; m_urlErrorState = NS_MSG_NO_RECIPIENTS; return(status); } m_addressCopy = addrs2; m_addresses = m_addressCopy; } // if parser } // if post message rv = nsMsgProtocol::LoadUrl(aURL, aConsumer); } // if we received a url! return rv; } /* * returns negative if the transfer is finished or error'd out * * returns zero or more if the transfer needs to be continued. */ nsresult nsSmtpProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream, PRUint32 sourceOffset, PRUint32 length) { PRInt32 status = 0; ClearFlag(SMTP_PAUSE_FOR_READ); /* already paused; reset */ while(!TestFlag(SMTP_PAUSE_FOR_READ)) { PR_LOG(SMTPLogModule, PR_LOG_ALWAYS, ("SMTP entering state: %d", m_nextState)); switch(m_nextState) { case SMTP_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SmtpResponse(inputStream, length); break; case SMTP_START_CONNECT: SetFlag(SMTP_PAUSE_FOR_READ); m_nextState = SMTP_RESPONSE; m_nextStateAfterResponse = SMTP_EXTN_LOGIN_RESPONSE; break; case SMTP_FINISH_CONNECT: SetFlag(SMTP_PAUSE_FOR_READ); break; case SMTP_LOGIN_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = LoginResponse(inputStream, length); break; case SMTP_EXTN_LOGIN_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = ExtensionLoginResponse(inputStream, length); break; case SMTP_SEND_HELO_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendHeloResponse(inputStream, length); break; case SMTP_SEND_EHLO_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendEhloResponse(inputStream, length); break; case SMTP_AUTH_LOGIN_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = AuthLoginResponse(inputStream, length); break; case SMTP_SEND_AUTH_LOGIN_USERNAME: status = AuthLoginUsername(); break; case SMTP_SEND_AUTH_LOGIN_PASSWORD: status = AuthLoginPassword(); break; case SMTP_SEND_VRFY_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendVerifyResponse(); break; case SMTP_SEND_MAIL_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendMailResponse(); break; case SMTP_SEND_RCPT_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendRecipientResponse(); break; case SMTP_SEND_DATA_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendDataResponse(); break; case SMTP_SEND_POST_DATA: status = SendPostData(); break; case SMTP_SEND_MESSAGE_RESPONSE: if (inputStream == nsnull) SetFlag(SMTP_PAUSE_FOR_READ); else status = SendMessageResponse(); break; case SMTP_DONE: { nsCOMPtr mailNewsUrl = do_QueryInterface(m_runningURL); mailNewsUrl->SetUrlState(PR_FALSE, NS_OK); m_nextState = SMTP_FREE; } break; case SMTP_ERROR_DONE: { nsCOMPtr mailNewsUrl = do_QueryInterface(m_runningURL); // propagate the right error code mailNewsUrl->SetUrlState(PR_FALSE, m_urlErrorState); m_nextState = SMTP_FREE; } m_nextState = SMTP_FREE; break; case SMTP_FREE: // smtp is a one time use connection so kill it if we get here... CloseSocket(); return NS_OK; /* final end */ default: /* should never happen !!! */ m_nextState = SMTP_ERROR_DONE; break; } /* check for errors during load and call error * state if found */ if(status < 0 && m_nextState != SMTP_FREE) { m_nextState = SMTP_ERROR_DONE; /* don't exit! loop around again and do the free case */ ClearFlag(SMTP_PAUSE_FOR_READ); } } /* while(!SMTP_PAUSE_FOR_READ) */ return NS_OK; } nsresult nsSmtpProtocol::GetPassword(char **aPassword) { nsresult rv = NS_ERROR_NULL_POINTER; NS_ENSURE_ARG_POINTER(aPassword); nsCOMPtr smtpUrl = do_QueryInterface(m_runningURL, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr smtpServer; rv = smtpUrl->GetSmtpServer(getter_AddRefs(smtpServer)); if (NS_FAILED(rv)) return rv; rv = smtpServer->GetPassword(aPassword); if (NS_FAILED(rv)) return rv; if (PL_strlen(*aPassword) > 0) return rv; // empty password nsCRT::free(*aPassword); *aPassword = 0; nsCOMPtr netPrompt; rv = smtpUrl->GetNetPrompt(getter_AddRefs(netPrompt)); if (NS_FAILED(rv)) return rv; nsXPIDLCString username; nsXPIDLCString hostname; PRUnichar *passwordPromptString = nsnull; PRUnichar *passwordTemplate = ComposeGetStringByID(NS_SMTP_PASSWORD_PROMPT); if (!passwordTemplate) return NS_ERROR_NULL_POINTER; PRUnichar *passwordTitle = ComposeGetStringByID(NS_SMTP_PASSWORD_PROMPT_TITLE); if (!passwordTitle) { rv = NS_ERROR_NULL_POINTER; goto done; } rv = smtpServer->GetUsername(getter_Copies(username)); if (NS_FAILED(rv)) goto done; rv = smtpServer->GetHostname(getter_Copies(hostname)); if (NS_FAILED(rv)) goto done; passwordPromptString = nsTextFormatter::smprintf(passwordTemplate, (const char *) username, (const char *) hostname); if (!passwordPromptString) { rv = NS_ERROR_NULL_POINTER; goto done; } rv = smtpServer->GetPasswordWithUI(passwordPromptString, passwordTitle, netPrompt, aPassword); done: if (passwordTitle) nsCRT::free(passwordTitle); if (passwordTemplate) nsCRT::free(passwordTemplate); if (passwordPromptString) nsCRT::free(passwordPromptString); return rv; } nsresult nsSmtpProtocol::RequestOverrideInfo(nsISmtpServer * aSmtpServer) { NS_ENSURE_ARG(aSmtpServer); nsresult rv; nsCAutoString progID(NS_MSGLOGONREDIRECTORSERVICE_PROGID); // go get the redirection type... nsXPIDLCString redirectionTypeStr; aSmtpServer->GetRedirectorType(getter_Copies(redirectionTypeStr)); const char * redirectionType = (const char *) redirectionTypeStr; // if we don't have a redirection type, then get out and proceed normally. if (!redirectionType || !*redirectionType ) return NS_OK; progID.Append('/'); progID.Append(redirectionTypeStr); m_logonRedirector = do_GetService(progID.GetBuffer(), &rv); if (m_logonRedirector && NS_SUCCEEDED(rv)) { nsXPIDLCString password; nsXPIDLCString userName; aSmtpServer->GetUsername(getter_Copies(userName)); GetPassword(getter_Copies(password)); rv = m_logonRedirector->Logon(userName, password, NS_STATIC_CAST(nsIMsgLogonRedirectionRequester *, this), nsMsgLogonRedirectionServiceIDs::Smtp); } // this protocol instance now needs to wait until // we receive the login redirection information so set the appropriate state // flag SetFlag(SMTP_WAIT_FOR_REDIRECTION); SetFlag(SMTP_USE_LOGIN_REDIRECTION); // even though we haven't started to send the message yet, // we are going off and doing an asynch operation to get the redirection // information. So start the url as being run. nsCOMPtr mailNewsUrl = do_QueryInterface(m_runningURL); // this will cause another dialog to get thrown up.... mailNewsUrl->SetUrlState(PR_TRUE /* start running url */, NS_OK); UpdateStatus(NS_SMTP_CONNECTING_TO_SERVER); // and update the status return rv; } NS_IMETHODIMP nsSmtpProtocol::OnLogonRedirectionError(const PRUnichar *pErrMsg, PRBool aBadPassword) { nsCOMPtr smtpServer; m_runningURL->GetSmtpServer(getter_AddRefs(smtpServer)); NS_ENSURE_TRUE(smtpServer, NS_ERROR_FAILURE); NS_ENSURE_TRUE(m_logonRedirector, NS_ERROR_FAILURE); // step (1) force a log off... // logoff nsXPIDLCString userName; smtpServer->GetUsername(getter_Copies(userName)); m_logonRedirector->Logoff(userName); m_logonRedirector = nsnull; // we don't care about it anymore // step (2) alert the user about the error nsCOMPtr dialog (do_GetService(kCNetSupportDialogCID)); if (dialog && pErrMsg && pErrMsg[0]) dialog->Alert(pErrMsg); // step (3) if they entered a bad password, forget about it! if (aBadPassword && smtpServer) smtpServer->ForgetPassword(); // step (4) we need to let the originator of the send url request know that an // error occurred and we aren't sending the message...in our case, this will // force the user back into the compose window and they can try to send it // again. nsCOMPtr mailNewsUrl = do_QueryInterface(m_runningURL); // this will cause another dialog to get thrown up.... mailNewsUrl->SetUrlState(PR_FALSE /* stopped running url */, NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER); return NS_OK; } /* Logon Redirection Progress */ NS_IMETHODIMP nsSmtpProtocol::OnLogonRedirectionProgress(nsMsgLogonRedirectionState pState) { return NS_OK; } /* reply with logon redirection data. */ NS_IMETHODIMP nsSmtpProtocol::OnLogonRedirectionReply(const PRUnichar * aHost, unsigned short aPort, const char * aCookieData, unsigned short aCookieSize) { NS_ENSURE_ARG(aHost); nsresult rv = NS_OK; nsCOMPtr smtpServer; m_runningURL->GetSmtpServer(getter_AddRefs(smtpServer)); NS_ENSURE_TRUE(smtpServer, NS_ERROR_FAILURE); NS_ENSURE_TRUE(m_logonRedirector, NS_ERROR_FAILURE); // logoff nsXPIDLCString userName; smtpServer->GetUsername(getter_Copies(userName)); m_logonRedirector->Logoff(userName); m_logonRedirector = nsnull; // we don't care about it anymore // remember the logon cookie mLogonCookie.SetString(aCookieData, aCookieSize); //currently the server isn't returning a valid auth logon capability // this line is just a HACK to force us to use auth login. SetFlag(SMTP_AUTH_LOGIN_ENABLED); // currently the account manager isn't properly setting the authMethod // preference for servers which require redirectors. This is another // HACK ALERT....we'll force it to be set... m_prefAuthMethod = PREF_AUTH_LOGIN; // now that we have a host and port to connect to, // open up the channel... rv = OpenNetworkSocketWithInfo(nsCAutoString(aHost), aPort); // we are no longer waiting for a logon redirection reply ClearFlag(SMTP_WAIT_FOR_REDIRECTION); // check to see if we had a pending LoadUrl call...be sure to // do this after we clear the SMTP_WAIT_FOR_REDIRECTION flag =). nsCOMPtr url = do_QueryInterface(m_runningURL); if (TestFlag(SMTP_LOAD_URL_PENDING)) rv = LoadUrl(url , mPendingConsumer); mPendingConsumer = nsnull; // we don't need to remember this anymore... // since we are starting this url load out of the normal loading process, // we probably should stop the url from running and throw up an error dialog // if for some reason we didn't successfully load the url... // we may want to always return NS_OK regardless of an error return rv; }