mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 12:15:51 +00:00
1706 lines
46 KiB
C
1706 lines
46 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* 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):
|
|
*/
|
|
/*
|
|
* state machine to speak SMTP
|
|
*/
|
|
|
|
/* Please leave outside of ifdef for windows precompiled headers */
|
|
#include "rosetta.h"
|
|
#include "mkutils.h"
|
|
#include "netutils.h"
|
|
|
|
#if defined(MOZILLA_CLIENT) || defined(LIBNET_SMTP)
|
|
#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
|
|
#include "mkgeturl.h"
|
|
#include "mksmtp.h"
|
|
#include "mime.h"
|
|
#include "glhist.h"
|
|
#include "mktcp.h"
|
|
#include "mkparse.h"
|
|
#include "msgcom.h"
|
|
#include "msgnet.h"
|
|
#include "xp_time.h"
|
|
#include "xp_thrmo.h"
|
|
#include "merrors.h"
|
|
#include "ssl.h"
|
|
#include "imap.h"
|
|
|
|
#include "xp_error.h"
|
|
#include "prefapi.h"
|
|
#include "libi18n.h"
|
|
|
|
#ifdef AUTH_SKEY_DEFINED
|
|
extern int btoa8(char *out, char*in);
|
|
#endif
|
|
|
|
extern void NET_SetPopPassword2(const char *password);
|
|
extern void net_free_write_post_data_object(struct WritePostDataData *obj);
|
|
MODULE_PRIVATE char* NET_MailRelayHost(MWContext *context);
|
|
|
|
/* for XP_GetString() */
|
|
#include "xpgetstr.h"
|
|
extern int XP_PROGRESS_MAILSENT;
|
|
extern int MK_COULD_NOT_GET_USERS_MAIL_ADDRESS;
|
|
extern int MK_COULD_NOT_LOGIN_TO_SMTP_SERVER;
|
|
extern int MK_ERROR_SENDING_DATA_COMMAND;
|
|
extern int MK_ERROR_SENDING_FROM_COMMAND;
|
|
extern int MK_ERROR_SENDING_MESSAGE;
|
|
extern int MK_ERROR_SENDING_RCPT_COMMAND;
|
|
extern int MK_OUT_OF_MEMORY;
|
|
extern int MK_SMTP_SERVER_ERROR;
|
|
extern int MK_TCP_READ_ERROR;
|
|
extern int XP_MESSAGE_SENT_WAITING_MAIL_REPLY;
|
|
extern int MK_MSG_DELIV_MAIL;
|
|
extern int MK_MSG_NO_SMTP_HOST;
|
|
extern int MK_MIME_NO_RECIPIENTS;
|
|
|
|
extern int MK_POP3_USERNAME_UNDEFINED;
|
|
extern int MK_POP3_PASSWORD_UNDEFINED;
|
|
extern int XP_PASSWORD_FOR_POP3_USER;
|
|
extern int XP_RETURN_RECEIPT_NOT_SUPPORT;
|
|
extern int MK_SENDMAIL_BAD_TLS;
|
|
|
|
#define SMTP_PORT 25
|
|
|
|
/* definitions of state for the state machine design
|
|
*/
|
|
#define SMTP_RESPONSE 0
|
|
#define SMTP_START_CONNECT 1
|
|
#define SMTP_FINISH_CONNECT 2
|
|
#define SMTP_LOGIN_RESPONSE 3
|
|
#define SMTP_SEND_HELO_RESPONSE 4
|
|
#define SMTP_SEND_VRFY_RESPONSE 5
|
|
#define SMTP_SEND_MAIL_RESPONSE 6
|
|
#define SMTP_SEND_RCPT_RESPONSE 7
|
|
#define SMTP_SEND_DATA_RESPONSE 8
|
|
#define SMTP_SEND_POST_DATA 9
|
|
#define SMTP_SEND_MESSAGE_RESPONSE 10
|
|
#define SMTP_DONE 11
|
|
#define SMTP_ERROR_DONE 12
|
|
#define SMTP_FREE 13
|
|
#define SMTP_EXTN_LOGIN_RESPONSE 14
|
|
#define SMTP_SEND_EHLO_RESPONSE 15
|
|
|
|
#define SMTP_SEND_AUTH_LOGIN_USERNAME 16
|
|
#define SMTP_SEND_AUTH_LOGIN_PASSWORD 17
|
|
#define SMTP_AUTH_LOGIN_RESPONSE 18
|
|
#define SMTP_AUTH_RESPONSE 19
|
|
|
|
HG08747
|
|
|
|
/* structure to hold data pertaining to the active state of
|
|
* a transfer in progress.
|
|
*
|
|
*/
|
|
typedef struct _SMTPConData {
|
|
int next_state; /* the next state or action to be taken */
|
|
int next_state_after_response; /* the state after the response one */
|
|
Bool pause_for_read; /* Pause now for next read? */
|
|
#ifdef XP_WIN
|
|
Bool calling_netlib_all_the_time;
|
|
#endif
|
|
char *response_text;
|
|
int response_code;
|
|
char *data_buffer;
|
|
int32 data_buffer_size;
|
|
char *address_copy;
|
|
char *mail_to_address_ptr;
|
|
int mail_to_addresses_left;
|
|
TCP_ConData * tcp_con_data;
|
|
int continuation_response;
|
|
char *hostname;
|
|
char *verify_address;
|
|
void *write_post_data_data; /* a data object for the
|
|
* WritePostData function
|
|
*/
|
|
int32 total_amt_written;
|
|
uint32 total_message_size;
|
|
unsigned long last_time;
|
|
XP_Bool ehlo_dsn_enabled;
|
|
XP_Bool auth_login_enabled;
|
|
HG60917
|
|
} SMTPConData;
|
|
|
|
/* macro's to simplify variable names */
|
|
#define CD_NEXT_STATE cd->next_state
|
|
#define CD_NEXT_STATE_AFTER_RESPONSE cd->next_state_after_response
|
|
#define CD_PAUSE_FOR_READ cd->pause_for_read
|
|
#define CD_RESPONSE_TXT cd->response_text
|
|
#define CD_RESPONSE_CODE cd->response_code
|
|
#define CD_DATA_BUFFER cd->data_buffer
|
|
#define CD_DATA_BUFFER_SIZE cd->data_buffer_size
|
|
#define CD_ADDRESS_COPY cd->address_copy
|
|
#define CD_MAIL_TO_ADDRESS_PTR cd->mail_to_address_ptr
|
|
#define CD_MAIL_TO_ADDRESSES_LEFT cd->mail_to_addresses_left
|
|
#define CD_TCP_CON_DATA cd->tcp_con_data
|
|
#define CD_CONTINUATION_RESPONSE cd->continuation_response
|
|
#define CD_HOSTNAME cd->hostname
|
|
#define CD_VERIFY_ADDRESS cd->verify_address
|
|
#define CD_TOTAL_AMT_WRITTEN cd->total_amt_written
|
|
#define CD_TOTAL_MESSAGE_SIZE cd->total_message_size
|
|
#define CD_EHLO_DSN_ENABLED cd->ehlo_dsn_enabled
|
|
|
|
#define CD_AUTH_LOGIN_ENABLED cd->auth_login_enabled
|
|
HG82493
|
|
|
|
#define CE_URL_S cur_entry->URL_s
|
|
#define CE_SOCK cur_entry->socket
|
|
#define CE_CON_SOCK cur_entry->con_sock
|
|
#define CE_STATUS cur_entry->status
|
|
#define CE_WINDOW_ID cur_entry->window_id
|
|
#define CE_BYTES_RECEIVED cur_entry->bytes_received
|
|
#define CE_FORMAT_OUT cur_entry->format_out
|
|
|
|
PRIVATE char *net_smtp_relay_host=0;
|
|
PRIVATE char *net_smtp_password=0;
|
|
|
|
/* forward decl */
|
|
PRIVATE int32 net_ProcessMailto (ActiveEntry *cur_entry);
|
|
|
|
/* fix Mac warning of missing prototype */
|
|
MODULE_PRIVATE char *
|
|
NET_MailRelayHost(MWContext *context);
|
|
|
|
MODULE_PRIVATE char *
|
|
NET_MailRelayHost(MWContext *context)
|
|
{
|
|
if (net_smtp_relay_host)
|
|
return net_smtp_relay_host;
|
|
else
|
|
return ""; /* caller now checks for empty string and returns MK_MSG_NO_SMTP_HOST */
|
|
}
|
|
|
|
PUBLIC void
|
|
NET_SetMailRelayHost(char * host)
|
|
{
|
|
char * at = NULL;
|
|
|
|
/*
|
|
** If we are called with data like "fred@bedrock.com", then we will
|
|
** help the user by ignoring the stuff before the "@". People with
|
|
** @ signs in their host names will be hosed. They also can't possibly
|
|
** be current happy internet users.
|
|
*/
|
|
if (host) at = XP_STRCHR(host, '@');
|
|
if (at != NULL) host = at + 1;
|
|
StrAllocCopy(net_smtp_relay_host, host);
|
|
}
|
|
|
|
/*
|
|
* gets user domian name out from FE_UsersMailAddress()
|
|
*/
|
|
PRIVATE const char *
|
|
net_smtp_get_user_domain_name()
|
|
{
|
|
const char *mail_addr, *at_sign = NULL;
|
|
mail_addr = FE_UsersMailAddress();
|
|
at_sign = XP_STRCHR(mail_addr, '@');
|
|
return (at_sign ? at_sign+1 : mail_addr);
|
|
}
|
|
|
|
/* 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 = XP_ALLOC(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=XP_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 += XP_STRLEN(bp);
|
|
}
|
|
}
|
|
*bp=0;
|
|
return buffer;
|
|
}
|
|
|
|
/*
|
|
* gets the response code from the nntp server and the
|
|
* response line
|
|
*
|
|
* returns the TCP return code from the read
|
|
*/
|
|
PRIVATE int
|
|
net_smtp_response (ActiveEntry * cur_entry)
|
|
{
|
|
char * line;
|
|
char cont_char;
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
int err = 0;
|
|
|
|
CE_STATUS = NET_BufferedReadLine(CE_SOCK, &line, &CD_DATA_BUFFER,
|
|
&CD_DATA_BUFFER_SIZE, &CD_PAUSE_FOR_READ);
|
|
|
|
if(CE_STATUS == 0)
|
|
{
|
|
CD_NEXT_STATE = SMTP_ERROR_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_SMTP_SERVER_ERROR,
|
|
CD_RESPONSE_TXT);
|
|
CE_STATUS = MK_SMTP_SERVER_ERROR;
|
|
return(MK_SMTP_SERVER_ERROR);
|
|
}
|
|
|
|
/* if TCP error of if there is not a full line yet return
|
|
*/
|
|
if(CE_STATUS < 0)
|
|
{
|
|
HG22864
|
|
CE_URL_S->error_msg =
|
|
NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
|
|
|
|
/* return TCP error
|
|
*/
|
|
return MK_TCP_READ_ERROR;
|
|
}
|
|
else if(!line)
|
|
{
|
|
return CE_STATUS;
|
|
}
|
|
|
|
TRACEMSG(("SMTP Rx: %s\n", line));
|
|
|
|
cont_char = ' '; /* default */
|
|
sscanf(line, "%d%c", &CD_RESPONSE_CODE, &cont_char);
|
|
|
|
if(CD_CONTINUATION_RESPONSE == -1)
|
|
{
|
|
if (cont_char == '-') /* begin continuation */
|
|
CD_CONTINUATION_RESPONSE = CD_RESPONSE_CODE;
|
|
|
|
if(XP_STRLEN(line) > 3)
|
|
StrAllocCopy(CD_RESPONSE_TXT, line+4);
|
|
}
|
|
else
|
|
{ /* have to continue */
|
|
if (CD_CONTINUATION_RESPONSE == CD_RESPONSE_CODE && cont_char == ' ')
|
|
CD_CONTINUATION_RESPONSE = -1; /* ended */
|
|
|
|
StrAllocCat(CD_RESPONSE_TXT, "\n");
|
|
if(XP_STRLEN(line) > 3)
|
|
StrAllocCat(CD_RESPONSE_TXT, line+4);
|
|
}
|
|
|
|
if(CD_CONTINUATION_RESPONSE == -1) /* all done with this response? */
|
|
{
|
|
CD_NEXT_STATE = CD_NEXT_STATE_AFTER_RESPONSE;
|
|
CD_PAUSE_FOR_READ = FALSE; /* don't pause */
|
|
}
|
|
|
|
return(0); /* everything ok */
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_login_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[356];
|
|
|
|
if(CD_RESPONSE_CODE != 220)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
|
|
return(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
|
|
}
|
|
|
|
|
|
PR_snprintf(buffer, sizeof(buffer), "HELO %.256s" CRLF,
|
|
net_smtp_get_user_domain_name());
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_HELO_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
|
|
PRIVATE int
|
|
net_smtp_extension_login_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[356];
|
|
|
|
if(CD_RESPONSE_CODE != 220)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
|
|
return(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
|
|
}
|
|
|
|
PR_snprintf(buffer, sizeof(buffer), "EHLO %.256s" CRLF,
|
|
net_smtp_get_user_domain_name());
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_EHLO_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
|
|
PRIVATE int
|
|
net_smtp_send_helo_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[620];
|
|
const char *mail_add = FE_UsersMailAddress();
|
|
|
|
/* don't check for a HELO response because it can be bogus and
|
|
* we don't care
|
|
*/
|
|
|
|
if(!mail_add)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_GET_USERS_MAIL_ADDRESS);
|
|
return(MK_COULD_NOT_GET_USERS_MAIL_ADDRESS);
|
|
}
|
|
|
|
if(CD_VERIFY_ADDRESS)
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "VRFY %.256s" CRLF, CD_VERIFY_ADDRESS);
|
|
}
|
|
else
|
|
{
|
|
/* else send the MAIL FROM: command */
|
|
char *s = MSG_MakeFullAddress (NULL, mail_add);
|
|
if (!s)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
if (CE_URL_S->msg_pane) {
|
|
if (MSG_RequestForReturnReceipt(CE_URL_S->msg_pane)) {
|
|
if (CD_EHLO_DSN_ENABLED) {
|
|
PR_snprintf(buffer, sizeof(buffer),
|
|
"MAIL FROM:<%.256s> RET=FULL ENVID=NS40112696JT" CRLF,
|
|
s);
|
|
}
|
|
else {
|
|
FE_Alert (CE_WINDOW_ID, XP_GetString(XP_RETURN_RECEIPT_NOT_SUPPORT));
|
|
PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, s);
|
|
}
|
|
}
|
|
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, s);
|
|
}
|
|
}
|
|
else {
|
|
PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, s);
|
|
}
|
|
XP_FREE (s);
|
|
}
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
|
|
if(CD_VERIFY_ADDRESS)
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_VRFY_RESPONSE;
|
|
else
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_MAIL_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
|
|
PRIVATE int
|
|
net_smtp_send_ehlo_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
|
|
if (CD_RESPONSE_CODE != 250) {
|
|
/* EHLO not implemented */
|
|
char buffer[384];
|
|
|
|
HG85890
|
|
|
|
PR_snprintf(buffer, sizeof(buffer), "HELO %.256s" CRLF,
|
|
net_smtp_get_user_domain_name());
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_HELO_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
return (CE_STATUS);
|
|
}
|
|
else {
|
|
char *ptr = NULL;
|
|
HG09714
|
|
|
|
ptr = strcasestr(CD_RESPONSE_TXT, "DSN");
|
|
CD_EHLO_DSN_ENABLED = (ptr && XP_TO_UPPER(*(ptr-1)) != 'X');
|
|
/* should we use auth login */
|
|
PREF_GetBoolPref("mail.auth_login", &(CD_AUTH_LOGIN_ENABLED));
|
|
if (CD_AUTH_LOGIN_ENABLED) {
|
|
/* okay user has set to use skey
|
|
let's see does the server have the capability */
|
|
CD_AUTH_LOGIN_ENABLED = (NULL != strcasestr(CD_RESPONSE_TXT, "AUTH LOGIN"));
|
|
if (!CD_AUTH_LOGIN_ENABLED)
|
|
CD_AUTH_LOGIN_ENABLED = (NULL != strcasestr(CD_RESPONSE_TXT, "AUTH=LOGIN")); /* check old style */
|
|
}
|
|
|
|
HG90967
|
|
|
|
CD_NEXT_STATE = CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_RESPONSE;
|
|
|
|
HG59852
|
|
return (CE_STATUS);
|
|
}
|
|
}
|
|
|
|
|
|
PRIVATE int
|
|
net_smtp_auth_login_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
|
|
switch (CD_RESPONSE_CODE/100) {
|
|
case 2:
|
|
{
|
|
#ifdef MOZ_MAIL_NEWS
|
|
char *pop_password = (char *)NET_GetPopPassword();
|
|
CD_NEXT_STATE = SMTP_SEND_HELO_RESPONSE;
|
|
if (pop_password == NULL)
|
|
NET_SetPopPassword2(net_smtp_password);
|
|
if ( IMAP_GetPassword() == NULL )
|
|
IMAP_SetPassword(net_smtp_password);
|
|
XP_FREEIF(pop_password);
|
|
#else /* MOZ_MAIL_NEWS */
|
|
XP_ASSERT(0);
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
}
|
|
break;
|
|
case 3:
|
|
CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_PASSWORD;
|
|
break;
|
|
case 5:
|
|
default:
|
|
{
|
|
char* pop_username = (char *) NET_GetPopUsername();
|
|
#if defined(SingleSignon)
|
|
char *username = 0;
|
|
char host[256];
|
|
int len = 256;
|
|
#endif
|
|
/* NET_GetPopUsername () returns pointer to the cached
|
|
* username. It did *NOT* alloc a new string
|
|
*/
|
|
XP_FREEIF(net_smtp_password);
|
|
#if defined(SingleSignon)
|
|
/*
|
|
* need to alloc a new string for username because call to
|
|
* SI_PromptUsernameAndPassword below will attempt to free
|
|
* it if it is not null
|
|
*/
|
|
StrAllocCopy(username, pop_username); /* alloc a new string */
|
|
PREF_GetCharPref("network.hosts.smtp_server", host, &len);
|
|
SI_RemoveUser(host, pop_username, TRUE);
|
|
/* prefill prompt with previous username/passwords if any */
|
|
if (SI_PromptUsernameAndPassword
|
|
(cur_entry->window_id, " ",
|
|
&username, &net_smtp_password, host)) {
|
|
#else
|
|
if (FE_PromptUsernameAndPassword(cur_entry->window_id,
|
|
NULL, &pop_username, &net_smtp_password)) {
|
|
#endif
|
|
CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_USERNAME;
|
|
#if defined(SingleSignon)
|
|
XP_FREEIF(username);
|
|
#else
|
|
/* FE_PromptUsernameAndPassword() always alloc a new string
|
|
* for pop_username. The caller has to free it.
|
|
*/
|
|
XP_FREEIF(pop_username);
|
|
#endif
|
|
}
|
|
else {
|
|
/* User hit cancel, but since the client and server both say
|
|
* they want auth login we're just going to return an error
|
|
* and not let the msg be sent to the server
|
|
*/
|
|
CE_STATUS = MK_POP3_PASSWORD_UNDEFINED;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return (CE_STATUS);
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_auth_login_username(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[512];
|
|
char *pop_username = (char *) NET_GetPopUsername();
|
|
char *base64Str = NULL;
|
|
|
|
if (!pop_username || !*pop_username)
|
|
return (MK_POP3_USERNAME_UNDEFINED);
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
base64Str = NET_Base64Encode(pop_username,
|
|
XP_STRLEN(pop_username));
|
|
if (base64Str) {
|
|
PR_snprintf(buffer, sizeof(buffer), "AUTH LOGIN %.256s" CRLF, base64Str);
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
XP_FREEIF(base64Str);
|
|
|
|
return (CE_STATUS);
|
|
}
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
|
|
return -1;
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_auth_login_password(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[1024];
|
|
|
|
/* use cached smtp password first
|
|
* if not then use cached pop password
|
|
* if pop password undefined
|
|
* sync with smtp password
|
|
*/
|
|
|
|
if (!net_smtp_password || !*net_smtp_password) {
|
|
XP_FREEIF(net_smtp_password); /* in case its an empty string */
|
|
#ifdef MOZ_MAIL_NEWS
|
|
net_smtp_password = (char *) NET_GetPopPassword();
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
}
|
|
|
|
if (!net_smtp_password || !*net_smtp_password) {
|
|
char *fmt = XP_GetString (XP_PASSWORD_FOR_POP3_USER);
|
|
char host[256];
|
|
int len = 256;
|
|
#if defined(SingleSignon)
|
|
char *usernameAndHost=0;
|
|
#endif
|
|
|
|
XP_MEMSET(host, 0, 256);
|
|
PREF_GetCharPref("network.hosts.smtp_server", host, &len);
|
|
|
|
PR_snprintf(buffer, sizeof (buffer),
|
|
fmt, NET_GetPopUsername(), host);
|
|
XP_FREEIF(net_smtp_password);
|
|
#if defined(SingleSignon)
|
|
StrAllocCopy(usernameAndHost, NET_GetPopUsername());
|
|
StrAllocCat(usernameAndHost, "@");
|
|
StrAllocCat(usernameAndHost, host);
|
|
|
|
net_smtp_password = SI_PromptPassword(cur_entry->window_id, buffer,
|
|
usernameAndHost, FALSE);
|
|
XP_FREE(usernameAndHost);
|
|
#else
|
|
net_smtp_password = FE_PromptPassword(cur_entry->window_id, buffer);
|
|
#endif
|
|
if (!net_smtp_password)
|
|
return MK_POP3_PASSWORD_UNDEFINED;
|
|
}
|
|
|
|
XP_ASSERT(net_smtp_password);
|
|
|
|
if (net_smtp_password) {
|
|
char *base64Str = NULL;
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
base64Str = NET_Base64Encode(net_smtp_password, XP_STRLEN(net_smtp_password));
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
|
|
if (base64Str) {
|
|
PR_snprintf(buffer, sizeof(buffer), "%.256s" CRLF, base64Str);
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
XP_FREEIF(base64Str);
|
|
|
|
return (CE_STATUS);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_send_vrfy_response(ActiveEntry *cur_entry)
|
|
{
|
|
#if 0
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[512];
|
|
|
|
if(CD_RESPONSE_CODE == 250 || CD_RESPONSE_CODE == 251)
|
|
return(MK_USER_VERIFIED_BY_SMTP);
|
|
else
|
|
return(MK_USER_NOT_VERIFIED_BY_SMTP);
|
|
#else
|
|
XP_ASSERT(0);
|
|
return(-1);
|
|
#endif
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_send_mail_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[1024];
|
|
|
|
if(CD_RESPONSE_CODE != 250)
|
|
{
|
|
CE_URL_S->error_msg =
|
|
NET_ExplainErrorDetails(MK_ERROR_SENDING_FROM_COMMAND,
|
|
CD_RESPONSE_TXT);
|
|
return(MK_ERROR_SENDING_FROM_COMMAND);
|
|
}
|
|
|
|
/* Send the RCPT TO: command */
|
|
if (CD_EHLO_DSN_ENABLED &&
|
|
(CE_URL_S->msg_pane &&
|
|
MSG_RequestForReturnReceipt(CE_URL_S->msg_pane)))
|
|
{
|
|
char *encodedAddress = esmtp_value_encode(CD_MAIL_TO_ADDRESS_PTR);
|
|
|
|
if (encodedAddress) {
|
|
PR_snprintf(buffer, sizeof(buffer),
|
|
"RCPT TO:<%.256s> NOTIFY=SUCCESS,FAILURE ORCPT=rfc822;%.500s" CRLF,
|
|
CD_MAIL_TO_ADDRESS_PTR, encodedAddress);
|
|
XP_FREEIF(encodedAddress);
|
|
}
|
|
else {
|
|
CE_STATUS = MK_OUT_OF_MEMORY;
|
|
return (CE_STATUS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PR_snprintf(buffer, sizeof(buffer), "RCPT TO:<%.256s>" CRLF, CD_MAIL_TO_ADDRESS_PTR);
|
|
}
|
|
/* take the address we sent off the list (move the pointer to just
|
|
past the terminating null.) */
|
|
CD_MAIL_TO_ADDRESS_PTR += XP_STRLEN (CD_MAIL_TO_ADDRESS_PTR) + 1;
|
|
CD_MAIL_TO_ADDRESSES_LEFT--;
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_RCPT_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_send_rcpt_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char buffer[16];
|
|
|
|
if(CD_RESPONSE_CODE != 250 && CD_RESPONSE_CODE != 251)
|
|
{
|
|
CE_URL_S->error_msg =
|
|
NET_ExplainErrorDetails(MK_ERROR_SENDING_RCPT_COMMAND,
|
|
CD_RESPONSE_TXT);
|
|
return(MK_ERROR_SENDING_RCPT_COMMAND);
|
|
}
|
|
|
|
if(CD_MAIL_TO_ADDRESSES_LEFT > 0)
|
|
{
|
|
/* more senders to RCPT to
|
|
*/
|
|
CD_NEXT_STATE = SMTP_SEND_MAIL_RESPONSE;
|
|
return(0);
|
|
}
|
|
|
|
/* else send the RCPT TO: command */
|
|
XP_STRCPY(buffer, "DATA" CRLF);
|
|
|
|
TRACEMSG(("Tx: %s", buffer));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_DATA_RESPONSE;
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_send_data_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char * command=0;
|
|
|
|
if(CD_RESPONSE_CODE != 354)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(
|
|
MK_ERROR_SENDING_DATA_COMMAND,
|
|
CD_RESPONSE_TXT ? CD_RESPONSE_TXT : "");
|
|
return(MK_ERROR_SENDING_DATA_COMMAND);
|
|
}
|
|
|
|
#ifdef XP_UNIX
|
|
{
|
|
const char * FE_UsersRealMailAddress(void); /* definition */
|
|
const char *real_name;
|
|
char *s = 0;
|
|
XP_Bool suppress_sender_header = 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)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
if(real_name)
|
|
{
|
|
char buffer[512];
|
|
PR_snprintf(buffer, sizeof(buffer), "Sender: %.256s" CRLF, real_name);
|
|
StrAllocCat(command, buffer);
|
|
if(!command)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
return(MK_OUT_OF_MEMORY);
|
|
}
|
|
}
|
|
|
|
TRACEMSG(("sending extra unix header: %s", command));
|
|
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, command, XP_STRLEN(command));
|
|
if(CE_STATUS < 0)
|
|
{
|
|
TRACEMSG(("Error sending message"));
|
|
}
|
|
}
|
|
}
|
|
#endif /* XP_UNIX */
|
|
|
|
/* set connect select since we need to select on
|
|
* writes
|
|
*/
|
|
NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
NET_SetConnectSelect(CE_WINDOW_ID, CE_SOCK);
|
|
#ifdef XP_WIN
|
|
cd->calling_netlib_all_the_time = TRUE;
|
|
NET_SetCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
|
|
#endif
|
|
CE_CON_SOCK = CE_SOCK;
|
|
|
|
FREE(command);
|
|
|
|
CD_NEXT_STATE = SMTP_SEND_POST_DATA;
|
|
CD_PAUSE_FOR_READ = FALSE; /* send data directly */
|
|
|
|
NET_Progress(CE_WINDOW_ID, XP_GetString(MK_MSG_DELIV_MAIL));
|
|
|
|
/* 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))
|
|
CD_TOTAL_MESSAGE_SIZE = stat_entry.st_size;
|
|
}
|
|
else
|
|
{
|
|
CD_TOTAL_MESSAGE_SIZE = CE_URL_S->post_data_size;
|
|
}
|
|
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
PRIVATE int
|
|
net_smtp_send_post_data(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
unsigned long curtime;
|
|
|
|
/* returns 0 on done and negative on error
|
|
* positive if it needs to continue.
|
|
*/
|
|
CE_STATUS = NET_WritePostData(CE_WINDOW_ID, CE_URL_S,
|
|
CE_SOCK,
|
|
&cd->write_post_data_data,
|
|
TRUE);
|
|
|
|
cd->pause_for_read = TRUE;
|
|
|
|
if(CE_STATUS == 0)
|
|
{
|
|
/* normal done
|
|
*/
|
|
XP_STRCPY(cd->data_buffer, CRLF "." CRLF);
|
|
TRACEMSG(("sending %s", cd->data_buffer));
|
|
CE_STATUS = (int) NET_BlockingWrite(CE_SOCK,
|
|
cd->data_buffer,
|
|
XP_STRLEN(cd->data_buffer));
|
|
|
|
NET_Progress(CE_WINDOW_ID,
|
|
XP_GetString(XP_MESSAGE_SENT_WAITING_MAIL_REPLY));
|
|
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_SOCK);
|
|
#ifdef XP_WIN
|
|
if(cd->calling_netlib_all_the_time)
|
|
{
|
|
cd->calling_netlib_all_the_time = FALSE;
|
|
NET_ClearCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
|
|
}
|
|
#endif
|
|
NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
CE_CON_SOCK = 0;
|
|
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_MESSAGE_RESPONSE;
|
|
return(0);
|
|
}
|
|
|
|
CD_TOTAL_AMT_WRITTEN += CE_STATUS;
|
|
|
|
/* 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. */
|
|
|
|
curtime = XP_TIME();
|
|
if (curtime != cd->last_time) {
|
|
FE_Progress(CE_WINDOW_ID, XP_ProgressText(CD_TOTAL_MESSAGE_SIZE,
|
|
CD_TOTAL_AMT_WRITTEN,
|
|
0, 0));
|
|
cd->last_time = curtime;
|
|
}
|
|
|
|
if(CD_TOTAL_MESSAGE_SIZE)
|
|
FE_SetProgressBarPercent(CE_WINDOW_ID,
|
|
CD_TOTAL_AMT_WRITTEN*100/CD_TOTAL_MESSAGE_SIZE);
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
|
|
|
|
PRIVATE int
|
|
net_smtp_send_message_response(ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
|
|
if(CD_RESPONSE_CODE != 250)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_ERROR_SENDING_MESSAGE,
|
|
CD_RESPONSE_TXT);
|
|
return(MK_ERROR_SENDING_MESSAGE);
|
|
}
|
|
|
|
NET_Progress(CE_WINDOW_ID, XP_GetString(XP_PROGRESS_MAILSENT));
|
|
|
|
/* else */
|
|
CD_NEXT_STATE = SMTP_DONE;
|
|
return(MK_NO_DATA);
|
|
}
|
|
|
|
|
|
PRIVATE int32
|
|
net_MailtoLoad (ActiveEntry * cur_entry)
|
|
{
|
|
/* get memory for Connection Data */
|
|
SMTPConData * cd = XP_NEW(SMTPConData);
|
|
int32 pref = 0;
|
|
|
|
cur_entry->con_data = cd;
|
|
if(!cur_entry->con_data)
|
|
{
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
|
|
CE_STATUS = MK_OUT_OF_MEMORY;
|
|
return (CE_STATUS);
|
|
}
|
|
|
|
/* GH_UpdateGlobalHistory(cur_entry->URL_s); */
|
|
|
|
/* init */
|
|
XP_MEMSET(cd, 0, sizeof(SMTPConData));
|
|
|
|
CD_CONTINUATION_RESPONSE = -1; /* init */
|
|
|
|
CE_SOCK = NULL;
|
|
HG61365
|
|
|
|
|
|
/* make a copy of the address
|
|
*/
|
|
if(CE_URL_S->method == URL_POST_METHOD)
|
|
{
|
|
int status=0;
|
|
char *addrs1 = 0;
|
|
char *addrs2 = 0;
|
|
CD_NEXT_STATE = SMTP_START_CONNECT;
|
|
|
|
/* 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.
|
|
*/
|
|
addrs1 = MSG_RemoveDuplicateAddresses (CE_URL_S->address+7, 0, FALSE /*removeAliasesToMe*/);
|
|
|
|
/* 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)
|
|
{
|
|
status = MSG_ParseRFC822Addresses (addrs1, 0, &addrs2);
|
|
FREEIF (addrs1);
|
|
}
|
|
|
|
if (status < 0) return status;
|
|
|
|
if (status == 0 || addrs2 == 0)
|
|
{
|
|
CD_NEXT_STATE = SMTP_ERROR_DONE;
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
CE_STATUS = MK_MIME_NO_RECIPIENTS;
|
|
CE_URL_S->error_msg = NET_ExplainErrorDetails(CE_STATUS);
|
|
return CE_STATUS;
|
|
}
|
|
|
|
CD_ADDRESS_COPY = addrs2;
|
|
CD_MAIL_TO_ADDRESS_PTR = CD_ADDRESS_COPY;
|
|
CD_MAIL_TO_ADDRESSES_LEFT = status;
|
|
return(net_ProcessMailto(cur_entry));
|
|
}
|
|
else
|
|
{
|
|
/* parse special headers and stuff from the search data in the
|
|
URL address. This data is of the form
|
|
|
|
mailto:TO_FIELD?FIELD1=VALUE1&FIELD2=VALUE2
|
|
|
|
where TO_FIELD may be empty, VALUEn may (for now) only be
|
|
one of "cc", "bcc", "subject", "newsgroups", "references",
|
|
and "attachment".
|
|
|
|
"to" is allowed as a field/value pair as well, for consistency.
|
|
|
|
One additional parameter is allowed, which does not correspond
|
|
to a visible field: "newshost". This is the NNTP host (and port)
|
|
to connect to if newsgroups are specified.
|
|
|
|
Each parameter may appear only once, but the order doesn't
|
|
matter. All values must be URL-encoded.
|
|
*/
|
|
HG27655
|
|
|
|
char *parms = NET_ParseURL (CE_URL_S->address, GET_SEARCH_PART);
|
|
char *rest = parms;
|
|
char *from = 0; /* internal only */
|
|
char *reply_to = 0; /* internal only */
|
|
char *to = 0;
|
|
char *cc = 0;
|
|
char *bcc = 0;
|
|
char *fcc = 0; /* internal only */
|
|
char *newsgroups = 0;
|
|
char *followup_to = 0;
|
|
char *html_part = 0; /* internal only */
|
|
char *organization = 0; /* internal only */
|
|
char *subject = 0;
|
|
char *references = 0;
|
|
char *attachment = 0; /* internal only */
|
|
char *body = 0;
|
|
char *other_random_headers = 0; /* unused (for now) */
|
|
char *priority = 0;
|
|
char *newshost = 0; /* internal only */
|
|
XP_Bool encrypt_p = FALSE;
|
|
XP_Bool sign_p = FALSE; /* internal only */
|
|
|
|
char *newspost_url = 0;
|
|
XP_Bool force_plain_text = FALSE;
|
|
MSG_Pane *cpane = 0;
|
|
|
|
to = NET_ParseURL (CE_URL_S->address, GET_PATH_PART);
|
|
|
|
if (rest && *rest == '?')
|
|
{
|
|
/* start past the '?' */
|
|
rest++;
|
|
rest = XP_STRTOK (rest, "&");
|
|
while (rest && *rest)
|
|
{
|
|
char *token = rest;
|
|
char *value = 0;
|
|
char *eq = XP_STRCHR (token, '=');
|
|
if (eq)
|
|
{
|
|
value = eq+1;
|
|
*eq = 0;
|
|
}
|
|
switch (*token)
|
|
{
|
|
case 'A': case 'a':
|
|
if (!strcasecomp (token, "attachment") &&
|
|
CE_URL_S->internal_url)
|
|
StrAllocCopy (attachment, value);
|
|
break;
|
|
case 'B': case 'b':
|
|
if (!strcasecomp (token, "bcc"))
|
|
{
|
|
if (bcc && *bcc)
|
|
{
|
|
StrAllocCat (bcc, ", ");
|
|
StrAllocCat (bcc, value);
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy (bcc, value);
|
|
}
|
|
}
|
|
else if (!strcasecomp (token, "body"))
|
|
{
|
|
if (body && *body)
|
|
{
|
|
StrAllocCat (body, "\n");
|
|
StrAllocCat (body, value);
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy (body, value);
|
|
}
|
|
}
|
|
break;
|
|
case 'C': case 'c':
|
|
if (!strcasecomp (token, "cc"))
|
|
{
|
|
if (cc && *cc)
|
|
{
|
|
StrAllocCat (cc, ", ");
|
|
StrAllocCat (cc, value);
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy (cc, value);
|
|
}
|
|
}
|
|
break;
|
|
case 'E': case 'e':
|
|
if (!strcasecomp (token, "encrypt") ||
|
|
!strcasecomp (token, "encrypted"))
|
|
encrypt_p = (!strcasecomp(value, "true") ||
|
|
!strcasecomp(value, "yes"));
|
|
break;
|
|
case 'F': case 'f':
|
|
if (!strcasecomp (token, "followup-to"))
|
|
StrAllocCopy (followup_to, value);
|
|
else if (!strcasecomp (token, "from") &&
|
|
CE_URL_S->internal_url)
|
|
StrAllocCopy (from, value);
|
|
else if (!strcasecomp (token, "force-plain-text") &&
|
|
CE_URL_S->internal_url)
|
|
force_plain_text = TRUE;
|
|
break;
|
|
case 'H': case 'h':
|
|
if (!strcasecomp(token, "html-part") &&
|
|
CE_URL_S->internal_url) {
|
|
StrAllocCopy(html_part, value);
|
|
}
|
|
case 'N': case 'n':
|
|
if (!strcasecomp (token, "newsgroups"))
|
|
StrAllocCopy (newsgroups, value);
|
|
else if (!strcasecomp (token, "newshost") &&
|
|
CE_URL_S->internal_url)
|
|
StrAllocCopy (newshost, value);
|
|
break;
|
|
case 'O': case 'o':
|
|
if (!strcasecomp (token, "organization") &&
|
|
CE_URL_S->internal_url)
|
|
StrAllocCopy (organization, value);
|
|
break;
|
|
case 'R': case 'r':
|
|
if (!strcasecomp (token, "references"))
|
|
StrAllocCopy (references, value);
|
|
else if (!strcasecomp (token, "reply-to") &&
|
|
CE_URL_S->internal_url)
|
|
StrAllocCopy (reply_to, value);
|
|
break;
|
|
case 'S': case 's':
|
|
if(!strcasecomp (token, "subject"))
|
|
StrAllocCopy (subject, value);
|
|
else if ((!strcasecomp (token, "sign") ||
|
|
!strcasecomp (token, "signed")) &&
|
|
CE_URL_S->internal_url)
|
|
sign_p = (!strcasecomp(value, "true") ||
|
|
!strcasecomp(value, "yes"));
|
|
break;
|
|
case 'P': case 'p':
|
|
if (!strcasecomp (token, "priority"))
|
|
StrAllocCopy (priority, value);
|
|
break;
|
|
case 'T': case 't':
|
|
if (!strcasecomp (token, "to"))
|
|
{
|
|
if (to && *to)
|
|
{
|
|
StrAllocCat (to, ", ");
|
|
StrAllocCat (to, value);
|
|
}
|
|
else
|
|
{
|
|
StrAllocCopy (to, value);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (eq)
|
|
*eq = '='; /* put it back */
|
|
rest = XP_STRTOK (0, "&");
|
|
}
|
|
}
|
|
|
|
FREEIF (parms);
|
|
if (to)
|
|
NET_UnEscape (to);
|
|
if (cc)
|
|
NET_UnEscape (cc);
|
|
if (subject)
|
|
NET_UnEscape (subject);
|
|
if (newsgroups)
|
|
NET_UnEscape (newsgroups);
|
|
if (references)
|
|
NET_UnEscape (references);
|
|
if (attachment)
|
|
NET_UnEscape (attachment);
|
|
if (body)
|
|
NET_UnEscape (body);
|
|
if (newshost)
|
|
NET_UnEscape (newshost);
|
|
|
|
if(newshost)
|
|
{
|
|
char *prefix = "news://";
|
|
char *slash = XP_STRRCHR (newshost, '/');
|
|
HG83763
|
|
newspost_url = (char *) XP_ALLOC (XP_STRLEN (prefix) +
|
|
XP_STRLEN (newshost) + 10);
|
|
if (newspost_url)
|
|
{
|
|
XP_STRCPY (newspost_url, prefix);
|
|
XP_STRCAT (newspost_url, newshost);
|
|
XP_STRCAT (newspost_url, "/");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HG35353
|
|
newspost_url = XP_STRDUP ("news:");
|
|
}
|
|
|
|
/* Tell the message library and front end to pop up an edit window.
|
|
*/
|
|
#ifdef XP_UNIX
|
|
cpane = MSG_ComposeMessage (CE_WINDOW_ID,
|
|
from, reply_to, to, cc, bcc, fcc,
|
|
newsgroups, followup_to, organization,
|
|
subject, references, other_random_headers,
|
|
priority, attachment, newspost_url, body,
|
|
force_plain_text,
|
|
html_part);
|
|
#endif //XP_UNIX
|
|
|
|
#ifdef MOZ_MAIL_NEWS
|
|
if (cpane && CE_URL_S->fe_data) {
|
|
/* Tell libmsg what to do after deliver the message */
|
|
MSG_SetPostDeliveryActionInfo (cpane, CE_URL_S->fe_data);
|
|
}
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
|
|
FREEIF(from);
|
|
FREEIF(reply_to);
|
|
FREEIF(to);
|
|
FREEIF(cc);
|
|
FREEIF(bcc);
|
|
FREEIF(fcc);
|
|
FREEIF(newsgroups);
|
|
FREEIF(followup_to);
|
|
FREEIF(html_part);
|
|
FREEIF(organization);
|
|
FREEIF(subject);
|
|
FREEIF(references);
|
|
FREEIF(attachment);
|
|
FREEIF(body);
|
|
FREEIF(other_random_headers);
|
|
FREEIF(newshost);
|
|
FREEIF(priority);
|
|
FREEIF(newspost_url);
|
|
|
|
CE_STATUS = MK_NO_DATA;
|
|
XP_FREE(cd); /* no one else is gonna do it! */
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
We have connected to the mail relay and the type of authorization/login required
|
|
has been established. Before we actually send our name and password check
|
|
and see if we should or must turn the connection to safer mode.
|
|
*/
|
|
|
|
PRIVATE int
|
|
NET_CheckAuthResponse (ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
int err = 0;
|
|
HG54978
|
|
|
|
if (CD_AUTH_LOGIN_ENABLED)
|
|
{
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
|
|
CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_USERNAME;
|
|
return (CE_STATUS);
|
|
}
|
|
CD_NEXT_STATE = SMTP_SEND_HELO_RESPONSE;
|
|
return (CE_STATUS);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* returns negative if the transfer is finished or error'd out
|
|
*
|
|
* returns zero or more if the transfer needs to be continued.
|
|
*/
|
|
PRIVATE int32
|
|
net_ProcessMailto (ActiveEntry *cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
char *mail_relay_host;
|
|
|
|
TRACEMSG(("Entering NET_ProcessSMTP"));
|
|
|
|
CD_PAUSE_FOR_READ = FALSE; /* already paused; reset */
|
|
|
|
while(!CD_PAUSE_FOR_READ)
|
|
{
|
|
|
|
TRACEMSG(("In NET_ProcessSMTP with state: %d", CD_NEXT_STATE));
|
|
|
|
switch(CD_NEXT_STATE) {
|
|
|
|
case SMTP_RESPONSE:
|
|
net_smtp_response (cur_entry);
|
|
break;
|
|
|
|
case SMTP_START_CONNECT:
|
|
mail_relay_host = NET_MailRelayHost(CE_WINDOW_ID);
|
|
if (XP_STRLEN(mail_relay_host) == 0)
|
|
{
|
|
CE_STATUS = MK_MSG_NO_SMTP_HOST;
|
|
break;
|
|
}
|
|
CE_STATUS = NET_BeginConnect(NET_MailRelayHost(CE_WINDOW_ID),
|
|
NULL,
|
|
"SMTP",
|
|
SMTP_PORT,
|
|
&CE_SOCK,
|
|
FALSE,
|
|
&CD_TCP_CON_DATA,
|
|
CE_WINDOW_ID,
|
|
&CE_URL_S->error_msg,
|
|
cur_entry->socks_host,
|
|
cur_entry->socks_port,
|
|
CE_URL_S->localIP);
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
if(CE_STATUS == MK_CONNECTED)
|
|
{
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_EXTN_LOGIN_RESPONSE;
|
|
NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
}
|
|
else if(CE_STATUS > -1)
|
|
{
|
|
CE_CON_SOCK = CE_SOCK; /* set con_sock so we can select on it */
|
|
NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
CD_NEXT_STATE = SMTP_FINISH_CONNECT;
|
|
}
|
|
break;
|
|
|
|
case SMTP_FINISH_CONNECT:
|
|
CE_STATUS = NET_FinishConnect(NET_MailRelayHost(CE_WINDOW_ID),
|
|
"SMTP",
|
|
SMTP_PORT,
|
|
&CE_SOCK,
|
|
&CD_TCP_CON_DATA,
|
|
CE_WINDOW_ID,
|
|
&CE_URL_S->error_msg,
|
|
CE_URL_S->localIP);
|
|
|
|
CD_PAUSE_FOR_READ = TRUE;
|
|
HG18931
|
|
if(CE_STATUS == MK_CONNECTED)
|
|
{
|
|
CD_NEXT_STATE = SMTP_RESPONSE;
|
|
CD_NEXT_STATE_AFTER_RESPONSE = SMTP_EXTN_LOGIN_RESPONSE;
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
CE_CON_SOCK = NULL; /* reset con_sock so we don't select on it */
|
|
NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
}
|
|
else
|
|
{
|
|
/* unregister the old CE_SOCK from the select list
|
|
* and register the new value in the case that it changes
|
|
*/
|
|
if(CE_CON_SOCK != CE_SOCK)
|
|
{
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
CE_CON_SOCK = CE_SOCK;
|
|
NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SMTP_AUTH_RESPONSE:
|
|
CE_STATUS = NET_CheckAuthResponse(cur_entry);
|
|
break;
|
|
|
|
case SMTP_LOGIN_RESPONSE:
|
|
CE_STATUS = net_smtp_login_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_EXTN_LOGIN_RESPONSE:
|
|
CE_STATUS = net_smtp_extension_login_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_HELO_RESPONSE:
|
|
CE_STATUS = net_smtp_send_helo_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_EHLO_RESPONSE:
|
|
CE_STATUS = net_smtp_send_ehlo_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_AUTH_LOGIN_RESPONSE:
|
|
CE_STATUS = net_smtp_auth_login_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_AUTH_LOGIN_USERNAME:
|
|
CE_STATUS = net_smtp_auth_login_username(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_AUTH_LOGIN_PASSWORD:
|
|
CE_STATUS = net_smtp_auth_login_password(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_VRFY_RESPONSE:
|
|
CE_STATUS = net_smtp_send_vrfy_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_MAIL_RESPONSE:
|
|
CE_STATUS = net_smtp_send_mail_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_RCPT_RESPONSE:
|
|
CE_STATUS = net_smtp_send_rcpt_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_DATA_RESPONSE:
|
|
CE_STATUS = net_smtp_send_data_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_POST_DATA:
|
|
CE_STATUS = net_smtp_send_post_data(cur_entry);
|
|
break;
|
|
|
|
case SMTP_SEND_MESSAGE_RESPONSE:
|
|
CE_STATUS = net_smtp_send_message_response(cur_entry);
|
|
break;
|
|
|
|
case SMTP_DONE:
|
|
NET_BlockingWrite(CE_SOCK, "QUIT", 4);
|
|
NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
PR_Close(CE_SOCK);
|
|
CD_NEXT_STATE = SMTP_FREE;
|
|
break;
|
|
|
|
case SMTP_ERROR_DONE:
|
|
if(CE_SOCK != NULL)
|
|
{
|
|
/* we only send out quit if user interrupt
|
|
* else must be server error which may not be
|
|
* able to blocking write command
|
|
*/
|
|
if (CE_STATUS == MK_INTERRUPTED)
|
|
NET_BlockingWrite(CE_SOCK, "QUIT", 4);
|
|
NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
|
|
NET_ClearConnectSelect(CE_WINDOW_ID, CE_SOCK);
|
|
#ifdef XP_WIN
|
|
if(cd->calling_netlib_all_the_time)
|
|
{
|
|
cd->calling_netlib_all_the_time = FALSE;
|
|
NET_ClearCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
|
|
}
|
|
#endif /* XP_WIN */
|
|
NET_ClearDNSSelect(CE_WINDOW_ID, CE_SOCK);
|
|
PR_Close(CE_SOCK);
|
|
}
|
|
CD_NEXT_STATE = SMTP_FREE;
|
|
break;
|
|
|
|
case SMTP_FREE:
|
|
FREEIF(CD_DATA_BUFFER);
|
|
FREEIF(CD_ADDRESS_COPY);
|
|
FREEIF(CD_RESPONSE_TXT);
|
|
if(CD_TCP_CON_DATA)
|
|
NET_FreeTCPConData(CD_TCP_CON_DATA);
|
|
if (cd->write_post_data_data)
|
|
NET_free_write_post_data_object((struct WritePostDataData *)
|
|
cd->write_post_data_data);
|
|
FREE(cd);
|
|
|
|
return(-1); /* final end */
|
|
|
|
default: /* should never happen !!! */
|
|
TRACEMSG(("SMTP: BAD STATE!"));
|
|
CD_NEXT_STATE = SMTP_ERROR_DONE;
|
|
break;
|
|
}
|
|
|
|
/* check for errors during load and call error
|
|
* state if found
|
|
*/
|
|
if(CE_STATUS < 0 && CD_NEXT_STATE != SMTP_FREE)
|
|
{
|
|
CD_NEXT_STATE = SMTP_ERROR_DONE;
|
|
/* don't exit! loop around again and do the free case */
|
|
CD_PAUSE_FOR_READ = FALSE;
|
|
}
|
|
} /* while(!CD_PAUSE_FOR_READ) */
|
|
|
|
return(CE_STATUS);
|
|
}
|
|
|
|
/* abort the connection in progress
|
|
*/
|
|
PRIVATE int32
|
|
net_InterruptMailto(ActiveEntry * cur_entry)
|
|
{
|
|
SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
|
|
|
|
CD_NEXT_STATE = SMTP_ERROR_DONE;
|
|
CE_STATUS = MK_INTERRUPTED;
|
|
|
|
return(net_ProcessMailto(cur_entry));
|
|
}
|
|
|
|
/* Free any memory that might be used in caching etc.
|
|
*/
|
|
PRIVATE void
|
|
net_CleanupMailto(void)
|
|
{
|
|
/* nothing so far needs freeing */
|
|
return;
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
NET_InitMailtoProtocol(void)
|
|
{
|
|
static NET_ProtoImpl mailto_proto_impl;
|
|
|
|
mailto_proto_impl.init = net_MailtoLoad;
|
|
mailto_proto_impl.process = net_ProcessMailto;
|
|
mailto_proto_impl.interrupt = net_InterruptMailto;
|
|
mailto_proto_impl.resume = NULL;
|
|
mailto_proto_impl.cleanup = net_CleanupMailto;
|
|
|
|
NET_RegisterProtocolImplementation(&mailto_proto_impl, MAILTO_TYPE_URL);
|
|
}
|
|
|
|
#endif /* defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE) */
|
|
|
|
static void
|
|
MessageSendingDone(URL_Struct* url, int status, MWContext* context)
|
|
{
|
|
if (status < 0) {
|
|
char *error_msg = NET_ExplainErrorDetails(status, 0, 0, 0, 0);
|
|
if (error_msg) {
|
|
FE_Alert(context, error_msg);
|
|
}
|
|
XP_FREEIF(error_msg);
|
|
}
|
|
if (url->post_data) {
|
|
XP_FREE(url->post_data);
|
|
url->post_data = NULL;
|
|
}
|
|
if (url->post_headers) {
|
|
XP_FREE(url->post_headers);
|
|
url->post_headers = NULL;
|
|
}
|
|
NET_FreeURLStruct(url);
|
|
}
|
|
|
|
|
|
|
|
int
|
|
NET_SendMessageUnattended(MWContext* context, char* to, char* subject,
|
|
char* otherheaders, char* body)
|
|
{
|
|
char* urlstring;
|
|
URL_Struct* url;
|
|
int16 win_csid;
|
|
int16 csid;
|
|
char* convto;
|
|
char* convsub;
|
|
|
|
win_csid = INTL_DefaultWinCharSetID(context);
|
|
csid = INTL_DefaultMailCharSetID(win_csid);
|
|
convto = IntlEncodeMimePartIIStr(to, csid, TRUE);
|
|
convsub = IntlEncodeMimePartIIStr(subject, csid, TRUE);
|
|
|
|
urlstring = PR_smprintf("mailto:%s", convto ? convto : to);
|
|
|
|
if (!urlstring) return MK_OUT_OF_MEMORY;
|
|
url = NET_CreateURLStruct(urlstring, NET_DONT_RELOAD);
|
|
XP_FREE(urlstring);
|
|
if (!url) return MK_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
url->post_headers = PR_smprintf("To: %s\n\
|
|
Subject: %s\n\
|
|
%s\n",
|
|
convto ? convto : to,
|
|
convsub ? convsub : subject,
|
|
otherheaders);
|
|
if (convto) XP_FREE(convto);
|
|
if (convsub) XP_FREE(convsub);
|
|
if (!url->post_headers) return MK_OUT_OF_MEMORY;
|
|
url->post_data = XP_STRDUP(body);
|
|
if (!url->post_data) return MK_OUT_OF_MEMORY;
|
|
url->post_data_size = XP_STRLEN(url->post_data);
|
|
url->post_data_is_file = FALSE;
|
|
url->method = URL_POST_METHOD;
|
|
url->internal_url = TRUE;
|
|
return NET_GetURL(url, FO_PRESENT, context, MessageSendingDone);
|
|
|
|
}
|
|
|
|
#if !defined(MOZ_MAIL_NEWS) && !defined(SMART_MAIL)
|
|
PUBLIC const char*
|
|
NET_GetPopUsername ()
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* MOZ_MAIL_NEWS */
|
|
|
|
|
|
#endif /* defined(MOZILLA_CLIENT) || defined(LIBNET_SMTP) */
|