mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1444 lines
43 KiB
1444 lines
43 KiB
/*
|
|
Enhanced NCSA Mosaic from Spyglass
|
|
"Guitar"
|
|
|
|
Copyright 1994 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
Author(s):
|
|
Darald Trinka [email protected]
|
|
*/
|
|
|
|
#include "all.h"
|
|
#include "sh_sid.h"
|
|
|
|
#ifdef FEATURE_INLINE_MAIL
|
|
|
|
#include "htmail.h"
|
|
#include "chars.h"
|
|
|
|
/* Private Prototypes */
|
|
static int Mail_Command_Async(struct Mwin *tw, int nState, void **ppInfo);
|
|
static int MAIL_DoInit(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_MakeConnection(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_SendMyName(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_SendRecptName(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_SendData(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_SendQuit(struct Mwin *tw, void **ppInfo);
|
|
static int MAIL_Abort(struct Mwin *tw, void **ppInfo);
|
|
static void Mail_CleanUp(struct Mwin *tw, struct Data_SendMail *pData);
|
|
static void Mail_CloseAndCleanUp(struct Mwin *tw, struct Data_SendMail *pData);
|
|
static int MailDoCmd(struct Mwin *tw, struct Data_SendMail *pData, char *cmd);
|
|
static int MailDoCmdNoReply(struct Mwin *tw, struct Data_SendMail *pData, char *cmd);
|
|
static char *ProcessText(char *block, long size);
|
|
static char *GetRcpt(char *header, char **newHeader, int *rSize);
|
|
static void FreeRcpt(RcptList *rList);
|
|
|
|
/************************* States ************************/
|
|
#define STATE_COMMAND_SENT (STATE_OTHER)
|
|
#define STATE_COMMAND_GOTDATA (STATE_OTHER+1)
|
|
|
|
#define STATE_MAIL_RESOLVE_SERVER_NAME (STATE_OTHER + 0)
|
|
|
|
#define STATE_MAIL_MAKE_CONNECTION (STATE_OTHER + 1)
|
|
#define STATE_MAIL_MAKE_CONNECTION_RESPONCE (STATE_OTHER + 2)
|
|
|
|
#define STATE_MAIL_SEND_MY_IP (STATE_OTHER + 3)
|
|
#define STATE_MAIL_SEND_MY_IP_RESPONCE (STATE_OTHER + 4)
|
|
|
|
#define STATE_MAIL_SEND_SENDER_NAME (STATE_OTHER + 5)
|
|
#define STATE_MAIL_SEND_SENDER_NAME_RESPONCE (STATE_OTHER + 6)
|
|
|
|
#define STATE_MAIL_SEND_RECPT_NAME (STATE_OTHER + 7)
|
|
#define STATE_MAIL_SEND_RECPT_NAME_RESPONCE (STATE_OTHER + 8)
|
|
|
|
#define STATE_MAIL_SEND_DATA (STATE_OTHER + 9)
|
|
#define STATE_MAIL_SEND_DATA_RESPONCE (STATE_OTHER + 10)
|
|
|
|
#define STATE_MAIL_SEND_MESSAGE (STATE_OTHER + 11)
|
|
#define STATE_MAIL_SEND_MESSAGE_RESPONCE (STATE_OTHER + 12)
|
|
|
|
#define STATE_MAIL_QUIT (STATE_OTHER + 13)
|
|
#define STATE_CLEAN_AND_CLOSE (STATE_OTHER + 14)
|
|
|
|
#define BLOCK_SIZE 30000
|
|
|
|
/* This buffer is used to hold a block of data to be sent */
|
|
static char gBuffer[BLOCK_SIZE];
|
|
|
|
/****************************************************************************/
|
|
/* This routine sends a SMTP command and retrieves the status return, */
|
|
/* as per RFC xxx */
|
|
/****************************************************************************/
|
|
static int Mail_Command_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_Mail_Command *pParams;
|
|
char ch;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->index = 0;
|
|
|
|
/* Send command */
|
|
if (pParams->cmd)
|
|
{
|
|
struct Params_Send *pps;
|
|
|
|
XX_DMsg(DBG_LOAD, ("Mail: sending command %s", pParams->cmd));
|
|
|
|
pps = GTR_CALLOC(sizeof(struct Params_Send), 1);
|
|
if (pps)
|
|
{
|
|
pps->socket = pParams->isoc->input_file_number;
|
|
pps->pBuf = pParams->cmd;
|
|
pps->nBufLen = strlen(pParams->cmd);
|
|
pps->pStatus = &pParams->net_status;
|
|
Async_DoCall(Net_Send_Async, pps);
|
|
return STATE_COMMAND_SENT;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
/* Otherwise we're just reading response.
|
|
Fall through */
|
|
|
|
case STATE_COMMAND_SENT:
|
|
if (pParams->cmd)
|
|
{
|
|
GTR_FREE(pParams->cmd);
|
|
pParams->cmd = NULL;
|
|
if (pParams->net_status < 0)
|
|
{
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
}
|
|
pParams->net_status = 0;
|
|
/* fall through */
|
|
|
|
case STATE_COMMAND_GOTDATA:
|
|
if (pParams->net_status < 0)
|
|
{
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
ch = 0;
|
|
for ( ; pParams->isoc->input_pointer < pParams->isoc->input_limit; pParams->isoc->input_pointer++)
|
|
{
|
|
ch = *pParams->isoc->input_pointer;
|
|
if (ch == CR)
|
|
continue;
|
|
else if (ch == LF)
|
|
break;
|
|
else if (pParams->index < MAIL_LINE_LENGTH)
|
|
{
|
|
pParams->text[pParams->index++] = ch;
|
|
}
|
|
}
|
|
/* Step past the character we just read in the isoc */
|
|
pParams->isoc->input_pointer++;
|
|
|
|
/* If we didn't quit the loop because of finding an LF, get more */
|
|
if (ch != LF)
|
|
{
|
|
struct Params_Isoc_Fill *pif;
|
|
|
|
pif = GTR_CALLOC(sizeof(struct Params_Isoc_Fill), 1);
|
|
if (pif)
|
|
{
|
|
pif->isoc = pParams->isoc;
|
|
pif->pStatus = &pParams->net_status;
|
|
Async_DoCall(Isoc_Fill_Async, pif);
|
|
return STATE_COMMAND_GOTDATA;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
|
|
/* Terminate this line of stuff */
|
|
pParams->text[pParams->index] = '\0';
|
|
if (pParams->ppResText)
|
|
{
|
|
*pParams->ppResText = GTR_CALLOC(pParams->index + 1, 1);
|
|
if (*pParams->ppResText)
|
|
{
|
|
strcpy(*pParams->ppResText, pParams->text);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
XX_DMsg(DBG_LOAD, ("Mail: Other side sent %s\n", pParams->text));
|
|
*pParams->pResult = atoi(pParams->text);
|
|
if (*pParams->pResult == 0)
|
|
{
|
|
/* Something must be wrong */
|
|
*pParams->pResult = -1;
|
|
}
|
|
return STATE_DONE;
|
|
|
|
case STATE_ABORT:
|
|
if (pParams->cmd)
|
|
{
|
|
GTR_FREE(pParams->cmd);
|
|
}
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* This routine sends a SMTP command and retrieves the status return, */
|
|
/* as per PFC xxx */
|
|
/****************************************************************************/
|
|
static int Mail_Command_Async_No_Reply(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_Mail_Command *pParams;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->index = 0;
|
|
|
|
/* Send command */
|
|
if (pParams->cmd)
|
|
{
|
|
struct Params_Send *pps;
|
|
|
|
XX_DMsg(DBG_LOAD, ("Mail: sending command %s", pParams->cmd));
|
|
|
|
pps = GTR_CALLOC(sizeof(struct Params_Send), 1);
|
|
if (pps)
|
|
{
|
|
pps->socket = pParams->isoc->input_file_number;
|
|
pps->pBuf = pParams->cmd;
|
|
pps->nBufLen = strlen(pParams->cmd);
|
|
pps->pStatus = &pParams->net_status;
|
|
Async_DoCall(Net_Send_Async, pps);
|
|
return STATE_COMMAND_SENT;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
/* Otherwise we're just reading response.
|
|
Fall through */
|
|
|
|
case STATE_COMMAND_SENT:
|
|
if (pParams->cmd)
|
|
{
|
|
GTR_FREE(pParams->cmd);
|
|
pParams->cmd = NULL;
|
|
if (pParams->net_status < 0)
|
|
{
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
}
|
|
pParams->net_status = 0;
|
|
return STATE_DONE;
|
|
|
|
case STATE_ABORT:
|
|
if (pParams->cmd)
|
|
{
|
|
GTR_FREE(pParams->cmd);
|
|
}
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/* ********************************************************************** */
|
|
/* MAIL_DoInit */
|
|
/* ********************************************************************** */
|
|
static int MAIL_DoInit(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Params_LoadAsync *pParams;
|
|
struct Data_SendMail *pData;
|
|
struct Params_MultiParseInet *ppi;
|
|
|
|
pParams = *ppInfo;
|
|
|
|
/* Copy the parameters we were passed into our own, larger structure. */
|
|
pData = GTR_CALLOC(sizeof(struct Data_SendMail), 1);
|
|
if (pData)
|
|
{
|
|
memset(pData, 0, sizeof(struct Data_SendMail));
|
|
pData->request = pParams->request;
|
|
pData->pStatus = pParams->pStatus;
|
|
|
|
/* copy the info about the transaction */
|
|
pData->username = ((struct Data_SendMail *) pParams)->username;
|
|
pData->pszHost = ((struct Data_SendMail *) pParams)->pszHost;
|
|
pData->theMessage = ((struct Data_SendMail *) pParams)->theMessage;
|
|
pData->theRcpts = ((struct Data_SendMail *) pParams)->theRcpts;
|
|
pData->attachment = ((struct Data_SendMail *) pParams)->attachment;
|
|
pData->attachmentFilePtr = ((struct Data_SendMail *) pParams)->attachmentFilePtr;
|
|
pData->dlgInfo = ((struct Data_SendMail *) pParams)->dlgInfo;
|
|
|
|
GTR_FREE(pParams);
|
|
*ppInfo = pData;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
if (! ((struct Data_SendMail *) pParams)->pszHost[0])
|
|
{
|
|
/* We have no SMTP server configured */
|
|
ERR_ReportError(tw, SID_ERR_NO_MAIL_SERVER_CONFIGURED, NULL, NULL);
|
|
*pData->pStatus = -1;
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
/* See if we have a cached SMTP connection whose socket is still open.
|
|
We don't really check here to see if it's the correct host, since
|
|
we assume that the host changes rarely, if ever. */
|
|
if (tw)
|
|
if (tw->cached_conn.type == CONN_SMTP)
|
|
{
|
|
if (!Net_FlushSocket(tw->cached_conn.socket))
|
|
{
|
|
/* Great! Let's go with it... */
|
|
pData->isoc = HTInputSocket_new(tw->cached_conn.socket);
|
|
return STATE_MAIL_SEND_MY_IP;
|
|
}
|
|
else
|
|
{
|
|
/* We had a mail connection, but it shut down. */
|
|
TW_DisposeConnection(&tw->cached_conn);
|
|
}
|
|
}
|
|
|
|
/* Figure out address for SMTP host. */
|
|
pData->port = WS_HTONS(MAIL_PORT);
|
|
ppi = GTR_CALLOC(sizeof(struct Params_MultiParseInet), 1);
|
|
if (ppi)
|
|
{
|
|
ppi->pAddress = &pData->address;
|
|
ppi->pPort = &pData->port;
|
|
ppi->str = pData->pszHost;
|
|
ppi->pStatus = &pData->net_status;
|
|
Async_DoCall(Net_MultiParse_Async, ppi);
|
|
return STATE_MAIL_RESOLVE_SERVER_NAME;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
|
|
|
|
/* MAIL_ResolveServerName, not only resolves the name, it also make the connection */
|
|
static int MAIL_ResolveServerName(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
|
|
pData = *ppInfo;
|
|
|
|
if (pData->net_status < 0)
|
|
{
|
|
XX_DMsg(DBG_LOAD, ("Net_Parse_Async returned %d\n", pData->net_status));
|
|
*pData->pStatus = -1;
|
|
Mail_CleanUp(tw, pData);
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/* Try to establish a new connection */
|
|
MAIL_SetStatus(pData->dlgInfo, GTR_GetString(SID_INF_CONNECTING_TO_MAIL_SERVER));
|
|
pData->bWaiting = TRUE;
|
|
{
|
|
/* Do connect call */
|
|
struct Params_MultiConnect *ppc;
|
|
|
|
ppc = GTR_CALLOC(sizeof(struct Params_MultiConnect), 1);
|
|
if (ppc)
|
|
{
|
|
ppc->pSocket = &pData->s;
|
|
ppc->pAddress = &pData->address;
|
|
ppc->nPort = pData->port;
|
|
ppc->pWhere = &pData->where;
|
|
ppc->pStatus = &pData->net_status;
|
|
|
|
#ifdef FEATURE_SOCKS_LOW_LEVEL
|
|
/**
|
|
ppc->bUseSocksProxy = pData->request->destination->bUseSocksProxy;
|
|
**/
|
|
#endif
|
|
|
|
Async_DoCall(Net_MultiConnect_Async, ppc);
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
}
|
|
return STATE_MAIL_MAKE_CONNECTION;
|
|
}
|
|
|
|
|
|
/* MAIL_MakeConnection, gives the SMTP server the opportunity to send its greeting */
|
|
static int MAIL_MakeConnection(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
|
|
pData = *ppInfo;
|
|
|
|
if (pData->bWaiting)
|
|
{
|
|
WAIT_Pop(tw);
|
|
pData->bWaiting = FALSE;
|
|
}
|
|
|
|
if (pData->net_status < 0)
|
|
{
|
|
*pData->pStatus = -1;
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
pData->isoc = HTInputSocket_new(pData->s);
|
|
|
|
/* Get initial response from server */
|
|
if (MailDoCmd(tw, pData, NULL))
|
|
return(STATE_MAIL_MAKE_CONNECTION_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
static int MAIL_MakeConnection_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 220: /* The connection was successfull */
|
|
state = STATE_MAIL_SEND_MY_IP;
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_BAD_SEVER_NAME_S, pData->pszHost, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
state = STATE_ABORT;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
/* Send the HELO my computer is cmd */
|
|
static int MAIL_SendMyIP(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd;
|
|
|
|
pData = *ppInfo;
|
|
|
|
/* Dispose our old cached connection and cache this one instead */
|
|
if (tw)
|
|
{
|
|
TW_DisposeConnection(&tw->cached_conn);
|
|
tw->cached_conn.type = CONN_SMTP;
|
|
tw->cached_conn.addr = pData->where;
|
|
tw->cached_conn.socket = pData->s;
|
|
}
|
|
/* Now that we've cached it, we don't want to close the socket
|
|
independently of the cached connection. */
|
|
pData->s = 0;
|
|
|
|
cmd = GTR_MALLOC(strlen(HTHostName()) + 10);
|
|
if (! cmd)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, GTR_GetString(SID_INF_SEND_HELLO_MESSAGE));
|
|
sprintf(cmd, "HELO %s%c%c", HTHostName(), CH_CR, CH_LF);
|
|
if (MailDoCmd(tw, pData, cmd))
|
|
return(STATE_MAIL_SEND_MY_IP_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/* React to the responce from the HELO cmd */
|
|
static int MAIL_SendMyIP_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 220: /* Server sent us more connect information */
|
|
if (MailDoCmd(tw, pData, NULL))
|
|
state = STATE_MAIL_SEND_MY_IP_RESPONCE;
|
|
else
|
|
state = STATE_ABORT;
|
|
break;
|
|
|
|
case 250: /* The data block was send successfully */
|
|
state = STATE_MAIL_SEND_SENDER_NAME;
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_BAD_CONNECTION_S, pData->pszHost, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
Mail_CloseAndCleanUp(tw, pData);
|
|
state = STATE_DONE;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
/* Send the sender's name to the server */
|
|
static int MAIL_SendMyName(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd;
|
|
|
|
pData = *ppInfo;
|
|
|
|
cmd = GTR_MALLOC(strlen(pData->username) + 20);
|
|
if (! cmd)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, GTR_GetString(SID_INF_SEND_USER_NAME));
|
|
sprintf(cmd, "MAIL FROM:<%s>%c%c", pData->username, CH_CR, CH_LF);
|
|
if (MailDoCmd(tw, pData, cmd))
|
|
return(STATE_MAIL_SEND_SENDER_NAME_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/* React to the responce from the Mail from cmd */
|
|
static int MAIL_SendMyName_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 250: /* The data block was send successfully */
|
|
state = STATE_MAIL_SEND_RECPT_NAME;
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_BAD_SENDER_NAME_S, pData->username, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
state = STATE_ABORT;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
/* Send the rcpt name to the server */
|
|
static int MAIL_SendRecptName(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd;
|
|
|
|
pData = *ppInfo;
|
|
|
|
if (pData->theRcpts == NULL) /* no more rcpt's send data */
|
|
return(STATE_MAIL_SEND_DATA);
|
|
|
|
cmd = GTR_MALLOC(strlen(pData->theRcpts->name) + 20);
|
|
if (! cmd)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, GTR_GetString(SID_INF_SEND_RCPT_NAME));
|
|
sprintf(cmd, "RCPT TO:<%s>%c%c", pData->theRcpts->name, CH_CR, CH_LF);
|
|
if (MailDoCmd(tw, pData, cmd))
|
|
return(STATE_MAIL_SEND_RECPT_NAME_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/* React to the responce from the send rcpt cmd */
|
|
static int MAIL_SendRecptName_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 250: /* The RCPT was valid */
|
|
case 251: /* The RCPT was not local, will forward */
|
|
state = STATE_MAIL_SEND_RECPT_NAME; /* is there another one to send */
|
|
/* get ready to send the next rcpt */
|
|
pData->theRcpts = pData->theRcpts->next;
|
|
break;
|
|
|
|
case 551: /* The RCPT was not local, try ... */
|
|
case 550: /* The RCPT was unknown */
|
|
case 554: /* This responce will happen if -> "To: dtrinka <Hello there", note: no ">" */
|
|
ERR_ReportError(tw, SID_ERR_RCPT_UNKNOWN_S, pData->theRcpts->name, NULL);
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_RCPT_UNKNOWN_S, pData->theRcpts->name, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
state = STATE_ABORT;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
/* Send the DATA cmd */
|
|
static int MAIL_SendData(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd;
|
|
|
|
pData = *ppInfo;
|
|
|
|
cmd = GTR_MALLOC(10);
|
|
if (! cmd)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, GTR_GetString(SID_INF_SEND_DATA));
|
|
sprintf(cmd, "DATA%c%c", CH_CR, CH_LF);
|
|
if (MailDoCmd(tw, pData, cmd))
|
|
return(STATE_MAIL_SEND_DATA_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/* React to the responce from the DATA cmd */
|
|
static int MAIL_SendData_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 354: /* OK to send the data */
|
|
state = STATE_MAIL_SEND_MESSAGE;
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_BAD_CONNECTION_S, pData->pszHost, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
state = STATE_ABORT;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
/* Send a data block this may be called several times */
|
|
static int MAIL_SendMessage(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd = NULL;
|
|
size_t count;
|
|
|
|
pData = *ppInfo;
|
|
|
|
/* send the body of the message */
|
|
if (pData->theMessage)
|
|
{
|
|
cmd = ProcessText(pData->theMessage, strlen(pData->theMessage));
|
|
|
|
GTR_FREE(pData->theMessage);
|
|
pData->theMessage = NULL;
|
|
}
|
|
else if ((pData->attachment) && (pData->attachment[0] != '\0')) /* send an attached file */
|
|
{
|
|
/* open the file */
|
|
if (pData->attachmentFilePtr == NULL)
|
|
pData->attachmentFilePtr = fopen(pData->attachment, "rb");
|
|
|
|
if (pData->attachmentFilePtr != NULL)
|
|
{
|
|
/* Read in the block */
|
|
count = fread(gBuffer, 1, BLOCK_SIZE, pData->attachmentFilePtr);
|
|
if (count > 0)
|
|
{
|
|
cmd = ProcessText(gBuffer, count);
|
|
}
|
|
else /* all done close the file */
|
|
fclose(pData->attachmentFilePtr);
|
|
}
|
|
}
|
|
|
|
/* The message has been sent goto the next state */
|
|
if (cmd == NULL)
|
|
return(STATE_MAIL_QUIT);
|
|
|
|
/* Send the block */
|
|
if (MailDoCmdNoReply(tw, pData, cmd))
|
|
return(STATE_MAIL_SEND_MESSAGE_RESPONCE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/* React to the responce from sending a block of data */
|
|
static int MAIL_SendMessage_Responce(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
int state;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (pData->response)
|
|
{
|
|
case 354: /* The data block was send successfully */
|
|
state = STATE_MAIL_SEND_MESSAGE; /* send another block */
|
|
break;
|
|
|
|
default: /* Received some unexpected error */
|
|
ERR_ReportError(tw, SID_ERR_BAD_CONNECTION_S, pData->pszHost, NULL);
|
|
pData->response = 500;
|
|
break;
|
|
}
|
|
|
|
if (pData->response >= 500) /* an error occurred, close the connection */
|
|
{
|
|
*pData->pStatus = -1;
|
|
state = STATE_ABORT;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
|
|
static int MAIL_SendQuit(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
char *cmd;
|
|
|
|
pData = *ppInfo;
|
|
|
|
cmd = GTR_MALLOC(15);
|
|
if (! cmd)
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return STATE_ABORT;
|
|
}
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, "");
|
|
sprintf(cmd, "%c%c.%c%cQUIT%c%c", CH_CR, CH_LF, CH_CR, CH_LF, CH_CR, CH_LF);
|
|
if (MailDoCmd(tw, pData, cmd))
|
|
return(STATE_CLEAN_AND_CLOSE);
|
|
else
|
|
return(STATE_ABORT);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
HTSendMailTo_Async, is the main state engine of mailto. Following is what it does
|
|
|
|
< Open connection to SMTP >
|
|
HELO CRLF
|
|
MAIL FROM <user> CRLF
|
|
RCPT TO:<rcpt 1> CRLF
|
|
...
|
|
RCPT TO:<rcpt n> CRLF
|
|
DATA CRLF
|
|
< send the body of the message >
|
|
. CRLF
|
|
QUIT CRLF
|
|
**********************************************************************************/
|
|
int HTSendMailTo_Async(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
|
|
pData = *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
return MAIL_DoInit(tw, ppInfo);
|
|
|
|
case STATE_MAIL_RESOLVE_SERVER_NAME:
|
|
return MAIL_ResolveServerName(tw, ppInfo);
|
|
|
|
case STATE_MAIL_MAKE_CONNECTION:
|
|
return MAIL_MakeConnection(tw, ppInfo);
|
|
case STATE_MAIL_MAKE_CONNECTION_RESPONCE:
|
|
return MAIL_MakeConnection_Responce(tw, ppInfo);
|
|
|
|
case STATE_MAIL_SEND_MY_IP:
|
|
return MAIL_SendMyIP(tw, ppInfo);
|
|
case STATE_MAIL_SEND_MY_IP_RESPONCE:
|
|
return MAIL_SendMyIP_Responce(tw, ppInfo);
|
|
|
|
case STATE_MAIL_SEND_SENDER_NAME:
|
|
return MAIL_SendMyName(tw, ppInfo);
|
|
case STATE_MAIL_SEND_SENDER_NAME_RESPONCE:
|
|
return MAIL_SendMyName_Responce(tw, ppInfo);
|
|
|
|
/* This state set will loop if there are multiple rcpt's */
|
|
case STATE_MAIL_SEND_RECPT_NAME:
|
|
return MAIL_SendRecptName(tw, ppInfo);
|
|
case STATE_MAIL_SEND_RECPT_NAME_RESPONCE:
|
|
return MAIL_SendRecptName_Responce(tw, ppInfo);
|
|
|
|
case STATE_MAIL_SEND_DATA:
|
|
return MAIL_SendData(tw, ppInfo);
|
|
case STATE_MAIL_SEND_DATA_RESPONCE:
|
|
return MAIL_SendData_Responce(tw, ppInfo);
|
|
|
|
/* This state set will loop if the message is > BLOCK_SIZE */
|
|
case STATE_MAIL_SEND_MESSAGE:
|
|
return MAIL_SendMessage(tw, ppInfo);
|
|
case STATE_MAIL_SEND_MESSAGE_RESPONCE:
|
|
return MAIL_SendMessage_Responce(tw, ppInfo);
|
|
|
|
case STATE_MAIL_QUIT:
|
|
return MAIL_SendQuit(tw, ppInfo);
|
|
|
|
case STATE_CLEAN_AND_CLOSE:
|
|
*pData->pStatus = HT_LOADED;
|
|
DlgMail_CloseDialog(pData->dlgInfo);
|
|
Mail_CloseAndCleanUp(tw, pData);
|
|
return(STATE_DONE);
|
|
|
|
case STATE_ABORT:
|
|
return MAIL_Abort(tw, ppInfo);
|
|
}
|
|
XX_Assert((0), ("Function called with illegal state: %d", nState));
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
This sends a command to the mail server. And ask for a responce from the
|
|
server. This way the server can report errors and etc.
|
|
**********************************************************************************/
|
|
static int MailDoCmd(struct Mwin *tw, struct Data_SendMail *pData, char *cmd)
|
|
{
|
|
struct Params_Mail_Command *pc;
|
|
|
|
pc = GTR_CALLOC(sizeof(struct Params_Mail_Command), 1);
|
|
if (pc)
|
|
{
|
|
pc->isoc = pData->isoc;
|
|
pc->cmd = cmd;
|
|
pc->pResult = &pData->response;
|
|
pc->ppResText = NULL;
|
|
Async_DoCall(Mail_Command_Async, pc);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
This sends a command to the mail server. MailDoCmdNoReply is different from
|
|
MailDoCmd because it doesn't wait for a reply from the SMTP server. This is
|
|
useful while the body of a message is sent, because the server doesn't reply
|
|
until all of the data is sent.
|
|
**********************************************************************************/
|
|
static int MailDoCmdNoReply(struct Mwin *tw, struct Data_SendMail *pData, char *cmd)
|
|
{
|
|
struct Params_Mail_Command *pc;
|
|
|
|
pc = GTR_CALLOC(sizeof(struct Params_Mail_Command), 1);
|
|
if (pc)
|
|
{
|
|
pc->isoc = pData->isoc;
|
|
pc->cmd = cmd;
|
|
pc->pResult = &pData->response;
|
|
pc->ppResText = NULL;
|
|
Async_DoCall(Mail_Command_Async_No_Reply, pc);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(tw, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
Abort a send
|
|
**********************************************************************************/
|
|
static int MAIL_Abort(struct Mwin *tw, void **ppInfo)
|
|
{
|
|
struct Data_SendMail *pData;
|
|
|
|
pData = *ppInfo;
|
|
|
|
Mail_CloseAndCleanUp(tw, pData);
|
|
|
|
MAIL_SetStatus(pData->dlgInfo, "");
|
|
*pData->pStatus = -1;
|
|
return STATE_DONE;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
Free the data struct's used during a send
|
|
**********************************************************************************/
|
|
static void Mail_CleanUp(struct Mwin *tw, struct Data_SendMail *pData)
|
|
{
|
|
if (!pData)
|
|
return;
|
|
|
|
XX_Assert((!pData->target), ("Mail_CleanUp: target not freed!"));
|
|
if (pData->bWaiting && tw)
|
|
WAIT_Pop(tw);
|
|
if (pData->pResText)
|
|
GTR_FREE(pData->pResText);
|
|
if (pData->isoc)
|
|
HTInputSocket_free(pData->isoc);
|
|
|
|
if (pData->pStatus)
|
|
GTR_FREE(pData->pStatus);
|
|
if (pData->request)
|
|
GTR_FREE(pData->request);
|
|
|
|
if (pData->username)
|
|
GTR_FREE(pData->username);
|
|
if (pData->pszHost)
|
|
GTR_FREE(pData->pszHost);
|
|
if (pData->theMessage)
|
|
GTR_FREE(pData->theMessage);
|
|
if (pData->theRcpts)
|
|
FreeRcpt(pData->theRcpts);
|
|
if (pData->attachment)
|
|
GTR_FREE(pData->attachment);
|
|
|
|
pData->username = NULL;
|
|
pData->pszHost = NULL;
|
|
pData->theMessage = NULL;
|
|
pData->theRcpts = NULL;
|
|
pData->attachment = NULL;
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
Clean up the mail connection
|
|
**********************************************************************************/
|
|
void Mail_DisposeMailConnection(struct _CachedConn *pCon)
|
|
{
|
|
XX_Assert((pCon->type == CONN_SMTP), ("Mail_DisposeMailConnection: connection type is %d!", pCon->type));
|
|
XX_Assert((pCon->addr != 0), ("Mail_DisposeMailConnection: connection has no address!"));
|
|
pCon->addr = 0;
|
|
Net_Close(pCon->socket);
|
|
pCon->socket = -1;
|
|
pCon->type = CONN_NONE;
|
|
}
|
|
|
|
|
|
static void Mail_CloseAndCleanUp(struct Mwin *tw, struct Data_SendMail *pData)
|
|
{
|
|
if (tw)
|
|
TW_DisposeConnection(&tw->cached_conn);
|
|
|
|
Mail_CleanUp(tw, pData);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
Given a buffer of names where they are separated by commas, ExtractRcpts generates
|
|
a list of rcpts. The header must be null terminated. Is GetRcpt for further
|
|
comment...
|
|
**********************************************************************************/
|
|
RcptList *ExtractRcpts(char *header)
|
|
{
|
|
RcptList *rLink, *rList;
|
|
char *rcpt, *newHeader;
|
|
int rSize;
|
|
|
|
rList = NULL;
|
|
while (rcpt = GetRcpt(header, &newHeader, &rSize))
|
|
{
|
|
/* Malformed rcpt */
|
|
if (rcpt == (char *) -1)
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_BAD_RCPT_NAME_S, header, NULL);
|
|
FreeRcpt(rList);
|
|
return((RcptList *) -1);
|
|
}
|
|
|
|
rLink = GTR_MALLOC(sizeof(RcptList));
|
|
if (! rLink)
|
|
return(NULL);
|
|
|
|
rLink->name = GTR_strndup(rcpt, rSize);
|
|
if (! rLink->name)
|
|
return(NULL);
|
|
|
|
rLink->next = rList;
|
|
rList = rLink;
|
|
header = newHeader;
|
|
}
|
|
|
|
return(rList);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
Free the space used by the rcpt list.
|
|
**********************************************************************************/
|
|
static void FreeRcpt(RcptList *rList)
|
|
{
|
|
RcptList *temp;
|
|
|
|
/*if (rList)
|
|
for (temp = rList; temp = temp->next; temp)
|
|
GTR_FREE(temp->name);*/
|
|
|
|
if (! rList)
|
|
return;
|
|
|
|
while (rList)
|
|
{
|
|
temp = rList;
|
|
rList = rList->next;
|
|
GTR_FREE(temp->name);
|
|
GTR_FREE(temp);
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
GetRcpt, returns the next name out of a buffer of names. Names which are
|
|
excepted are: dtrinka, [email protected], dtrinka <Darald Trinka>,
|
|
[email protected] (Darald Trinka). Words in () or <> are discarded
|
|
|
|
Header has to be null terminated!!!
|
|
**********************************************************************************/
|
|
static char *GetRcpt(char *header, char **newHeader, int *rSize)
|
|
{
|
|
int rEnd, rStart = 0;
|
|
char balanceChar;
|
|
|
|
if (header[0] == '\0')
|
|
return(NULL);
|
|
|
|
/* skip leading spaces and commas */
|
|
while ((header[rStart] != '\0') && ((isspace(header[rStart])) || (header[rStart] == ',')))
|
|
rStart++;
|
|
|
|
/* Find either the first comma or the end of the buffer */
|
|
rEnd = rStart;
|
|
while ((header[rEnd] != ',') && (header[rEnd] != '\0'))
|
|
rEnd++;
|
|
|
|
/* rEnd + 1 now points to the starting point for the next call to GetRcpt */
|
|
if (header[rEnd] == '\0')
|
|
*newHeader = &header[rEnd];
|
|
else
|
|
*newHeader = &header[rEnd] + 1;
|
|
|
|
/* BackTrack rEnd over trailing spaces */
|
|
while ((rEnd != rStart) && (isspace(header[rEnd]) || (header[rEnd] == ',') || (header[rEnd] == '\0')))
|
|
rEnd--;
|
|
|
|
/* BackTrack rEnd to remove either (Name...) or <Name...> */
|
|
if ((header[rEnd] == ')') || (header[rEnd] == '>'))
|
|
{
|
|
if (header[rEnd] == ')')
|
|
balanceChar = '(';
|
|
else
|
|
balanceChar = '<';
|
|
|
|
while ((rEnd != rStart) && (header[rEnd] != balanceChar))
|
|
rEnd--;
|
|
|
|
/* the ()'s or <>'s don't balance */
|
|
if (rEnd == rStart)
|
|
return((char *) -1);
|
|
|
|
/* BackTrack rEnd over trailing spaces */
|
|
rEnd--;
|
|
while ((rEnd != rStart) && (isspace(header[rEnd])))
|
|
rEnd--;
|
|
}
|
|
|
|
/* Return the answer */
|
|
*rSize = rEnd - rStart + 1;
|
|
if (*rSize > 0)
|
|
return(&header[rStart]);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
ProcessText, coverts all of the \r's and \n's into \r\n's pairs. This must be
|
|
done before a message is sent using SMTP.
|
|
**********************************************************************************/
|
|
static char *ProcessText(char *block, long size)
|
|
{
|
|
char *newBlock;
|
|
|
|
#ifdef WIN32
|
|
/* Windows does not need CRLF translation */
|
|
|
|
newBlock = GTR_strdup(block);
|
|
#else
|
|
|
|
register long i, offset = 0, nLines = 0;
|
|
long newSize;
|
|
|
|
for (i = 0; i < size; i++)
|
|
if ((block[i] == '\n') || (block[i] == '\r'))
|
|
nLines++;
|
|
|
|
newSize = (long) ((double) size + nLines + 10);
|
|
|
|
newBlock = GTR_CALLOC(sizeof(char), newSize);
|
|
if (! newBlock)
|
|
return(NULL);
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
if ((block[i] == '\n') || (block[i] == '\r'))
|
|
{
|
|
newBlock[i + offset] = '\r';
|
|
offset++;
|
|
newBlock[i + offset] = '\n';
|
|
}
|
|
else
|
|
newBlock[i + offset] = block[i];
|
|
}
|
|
#endif
|
|
|
|
return(newBlock);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
HTLoadMailTo is the starting point for mailto.
|
|
HTLoadMailTo extracts who the message is to be sent to and then calls a platform
|
|
specific function which opens the mailto window. When the send button is pressed
|
|
in this mail window it starts a anyc thread which uses the code above.
|
|
**********************************************************************************/
|
|
PRIVATE int HTLoadMailTo(HTRequest * request, struct Mwin *tw)
|
|
{
|
|
char *dest;
|
|
|
|
/* Get the destination address */
|
|
if (strncmp(request->destination->szActualURL, "mailto:", 7) == 0)
|
|
dest = &request->destination->szActualURL[7];
|
|
else
|
|
return(HT_LOADED);
|
|
|
|
/* Run the dialog */
|
|
DlgMail_RunDialog(tw, dest);
|
|
|
|
return(HT_LOADED);
|
|
}
|
|
|
|
GLOBALDEF PUBLIC HTProtocol HTMailTo = {"mailto", HTLoadMailTo, NULL};
|
|
|
|
#endif /* FEATURE_INLINE_MAIL*/
|
|
|
|
#ifdef _USE_MAPI
|
|
|
|
#include <mapi.h>
|
|
|
|
const char cszMAPISection[] = "Mail";
|
|
const char cszMAPIKey[] = "CMCDLLName32";
|
|
const char cszMAPISendMail[] = "MAPISendMail";
|
|
|
|
typedef ULONG (FAR PASCAL *PFNMAPISENDMAIL)(LHANDLE, ULONG, lpMapiMessage, FLAGS, ULONG);
|
|
typedef ULONG (FAR PASCAL *PFNMAPILOGON)(ULONG, LPSTR, LPSTR, FLAGS, ULONG, LPLHANDLE);
|
|
typedef ULONG (FAR PASCAL *PFNMAPILOGOFF)(LHANDLE, ULONG, FLAGS,ULONG);
|
|
|
|
typedef struct THREAD_DATA
|
|
{
|
|
HWND hWndParent;
|
|
LPSTR lpRecipient;
|
|
ThreadID tid;
|
|
PFNMAPISENDMAIL pfnMAPISendMail;
|
|
MapiRecipDesc recip;
|
|
MapiMessage mmMessage;
|
|
|
|
} THREAD_DATA, FAR * PTHREAD_DATA;
|
|
|
|
//
|
|
// Do the actual work of sending the mail
|
|
//
|
|
ULONG WINAPI
|
|
MapiSendMailThread(
|
|
LPVOID lpThreadData
|
|
)
|
|
{
|
|
ULONG ulResult = MAPI_E_FAILURE;
|
|
LHANDLE lhSession = 0L;
|
|
FLAGS flFlags = (MAPI_LOGON_UI | MAPI_DIALOG);
|
|
ULONG ulReserved = 0L;
|
|
PTHREAD_DATA lpData = (PTHREAD_DATA)lpThreadData;
|
|
HANDLE hMailMutex = NULL;
|
|
|
|
if (!wg.fWin32s)
|
|
{
|
|
hMailMutex = CreateMutex(NULL, FALSE, "IEXPLORE.MAILMUTEX");
|
|
}
|
|
|
|
//
|
|
// Allow only one message at the time to go out.
|
|
//
|
|
if ( hMailMutex == NULL || GetLastError() != ERROR_ALREADY_EXISTS )
|
|
{
|
|
if (lpData == NULL || lpData->pfnMAPISendMail == NULL)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ulResult = (*lpData->pfnMAPISendMail)(
|
|
lhSession,
|
|
(ULONG)lpData->hWndParent,
|
|
&(lpData->mmMessage),
|
|
flFlags,
|
|
ulReserved
|
|
);
|
|
|
|
if (ulResult != SUCCESS_SUCCESS && ulResult != MAPI_USER_ABORT)
|
|
{
|
|
//
|
|
// No error in NT/Win 95, 'cause we're a thread
|
|
//
|
|
if (wg.fWin32s)
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_MAPI_NO_SEND, NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageBeep(MB_ICONHAND);
|
|
}
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
if (wg.fWin32s)
|
|
{
|
|
Async_UnblockThread(lpData->tid);
|
|
}
|
|
|
|
if (hMailMutex)
|
|
{
|
|
CloseHandle(hMailMutex);
|
|
}
|
|
|
|
if (lpData->lpRecipient)
|
|
{
|
|
GlobalFree(lpData->lpRecipient);
|
|
}
|
|
|
|
GlobalFree(lpData);
|
|
|
|
return ulResult;
|
|
}
|
|
|
|
//
|
|
// MapiSendMail()
|
|
//
|
|
// Wrapper to load MAPI provider DLL, and call MapiSendMail().
|
|
//
|
|
ULONG
|
|
MapiSendMail(
|
|
HWND hWndParent,
|
|
LPSTR lpRecipient // NULL for no repicient, string otherwise.
|
|
)
|
|
{
|
|
DWORD dwThreadID;
|
|
PTHREAD_DATA lpData;
|
|
ULONG err = 0;
|
|
char szMAPIDLL[MAX_PATH+1];
|
|
|
|
lpData = GlobalAlloc(GMEM_ZEROINIT, sizeof(*lpData) );
|
|
if (lpData == NULL)
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return GetLastError();
|
|
}
|
|
|
|
lpData->hWndParent = hWndParent;
|
|
if (lpRecipient)
|
|
{
|
|
lpData->lpRecipient = GlobalAlloc(GMEM_ZEROINIT, lstrlen(lpRecipient)+1 );
|
|
if (lpData->lpRecipient == NULL)
|
|
{
|
|
GlobalFree(lpData);
|
|
ERR_ReportError(NULL, SID_ERR_OUT_OF_MEMORY, NULL, NULL);
|
|
return GetLastError();
|
|
}
|
|
strcpy(lpData->lpRecipient, lpRecipient);
|
|
}
|
|
else
|
|
{
|
|
lpData->lpRecipient = lpRecipient;
|
|
}
|
|
|
|
if (GetProfileString(cszMAPISection, cszMAPIKey, "", szMAPIDLL, sizeof(szMAPIDLL)) > 0)
|
|
{
|
|
wg.hinstMAPI = LoadLibrary(szMAPIDLL);
|
|
|
|
if (wg.hinstMAPI)
|
|
{
|
|
MapiRecipDesc recip = { 0, MAPI_TO, lpData->lpRecipient, NULL, 0, NULL };
|
|
MapiMessage mmMessage = { 0L, "", " ", NULL, NULL, NULL, 0, NULL, 0L, NULL, 0L, NULL };
|
|
|
|
lpData->recip = recip;
|
|
lpData->mmMessage = mmMessage;
|
|
|
|
if (lpData->lpRecipient)
|
|
{
|
|
lpData->mmMessage.nRecipCount = 1;
|
|
lpData->mmMessage.lpRecips = &(lpData->recip);
|
|
}
|
|
|
|
lpData->pfnMAPISendMail = (PFNMAPISENDMAIL)GetProcAddress(wg.hinstMAPI, cszMAPISendMail);
|
|
|
|
if (lpData->pfnMAPISendMail)
|
|
{
|
|
if (wg.fWin32s)
|
|
{
|
|
lpData->tid = Async_GetCurrentThread();
|
|
Async_BlockThread(lpData->tid);
|
|
err = MapiSendMailThread((LPVOID)lpData);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Use 'em if you got 'em
|
|
//
|
|
CreateThread( NULL, 2048, MapiSendMailThread, (LPVOID)lpData, 0, &dwThreadID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_MAPI_NO_PROCADDRESS, cszMAPISendMail, szMAPIDLL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_MAPI_NO_LOAD, szMAPIDLL, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERR_ReportError(NULL, SID_ERR_MAPI_NO_PROVIDER, szMAPIDLL, NULL);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
PRIVATE int
|
|
HTLoadMailTo(
|
|
HTRequest * request,
|
|
struct Mwin *tw
|
|
)
|
|
{
|
|
char *dest = "";
|
|
|
|
//
|
|
// Get the destination address
|
|
//
|
|
if (strncmp(request->destination->szActualURL, "mailto:", 7) == 0)
|
|
{
|
|
dest = &request->destination->szActualURL[7];
|
|
while (*dest == ' ')
|
|
{
|
|
++dest;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return HT_LOADED;
|
|
}
|
|
|
|
MapiSendMail(tw->win, dest);
|
|
|
|
return HT_LOADED;
|
|
}
|
|
|
|
GLOBALDEF PUBLIC HTProtocol HTMailTo = {"mailto", HTLoadMailTo, NULL};
|
|
|
|
#endif // _USE_MAPI
|